]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/subscriptions.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / subscriptions.c
CommitLineData
ef416fc2 1/*
d09495fa 2 * "$Id: subscriptions.c 5878 2006-08-24 15:55:42Z mike $"
ef416fc2 3 *
4 * Subscription routines for the Common UNIX Printing System (CUPS) scheduler.
5 *
fa73b229 6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * cupsdAddEvent() - Add an event to the global event cache.
27 * cupsdAddSubscription() - Add a new subscription object.
ef416fc2 28 * cupsdDeleteAllSubscriptions() - Delete all subscriptions.
29 * cupsdDeleteSubscription() - Delete a subscription object.
30 * cupsdEventName() - Return a single event name.
31 * cupsdEventValue() - Return the event mask value for a name.
32 * cupsdExpireSubscriptions() - Expire old subscription objects.
33 * cupsdFindSubscription() - Find a subscription by ID.
34 * cupsdLoadAllSubscriptions() - Load all subscriptions from the .conf file.
35 * cupsdSaveAllSubscriptions() - Save all subscriptions to the .conf file.
ef416fc2 36 * cupsdStopAllNotifiers() - Stop all notifier processes.
37 * cupsdUpdateNotifierStatus() - Read messages from notifiers.
38 * cupsd_compare_subscriptions() - Compare two subscriptions.
39 * cupsd_delete_event() - Delete a single event...
e00b005a 40 * cupsd_send_dbus() - Send a DBUS notification...
e1d6a774 41 * cupsd_send_notification() - Send a notification for the specified
42 * event.
ef416fc2 43 * cupsd_start_notifier() - Start a notifier subprocess...
44 */
45
46/*
47 * Include necessary headers...
48 */
49
50#include "cupsd.h"
e00b005a 51#ifdef HAVE_DBUS
52# include <dbus/dbus.h>
53#endif /* HAVE_DBUS */
ef416fc2 54
55
56/*
57 * Local functions...
58 */
59
60static int cupsd_compare_subscriptions(cupsd_subscription_t *first,
61 cupsd_subscription_t *second,
62 void *unused);
63static void cupsd_delete_event(cupsd_event_t *event);
e00b005a 64#ifdef HAVE_DBUS
65static void cupsd_send_dbus(cupsd_eventmask_t event, cupsd_printer_t *dest,
66 cupsd_job_t *job);
67#endif /* HAVE_DBUS */
e1d6a774 68static void cupsd_send_notification(cupsd_subscription_t *sub,
69 cupsd_event_t *event);
ef416fc2 70static void cupsd_start_notifier(cupsd_subscription_t *sub);
71
72
73/*
74 * 'cupsdAddEvent()' - Add an event to the global event cache.
75 */
76
77void
78cupsdAddEvent(
79 cupsd_eventmask_t event, /* I - Event */
80 cupsd_printer_t *dest, /* I - Printer associated with event */
81 cupsd_job_t *job, /* I - Job associated with event */
82 const char *text, /* I - Notification text */
83 ...) /* I - Additional arguments as needed */
84{
85 va_list ap; /* Pointer to additional arguments */
86 char ftext[1024]; /* Formatted text buffer */
fa73b229 87 ipp_attribute_t *attr; /* Printer/job attribute */
ef416fc2 88 cupsd_event_t *temp; /* New event pointer */
89 cupsd_subscription_t *sub; /* Current subscription */
90
91
8ca02f3c 92 cupsdLogMessage(CUPSD_LOG_DEBUG2,
93 "cupsdAddEvent(event=%s, dest=%p(%s), job=%p(%d), text=\"%s\", ...)",
94 cupsdEventName(event), dest, dest ? dest->name : "",
95 job, job ? job->id : 0, text);
96
e00b005a 97 /*
98 * Keep track of events with any OS-supplied notification mechanisms...
99 */
100
fa73b229 101 LastEvent |= event;
102
e00b005a 103#ifdef HAVE_DBUS
104 cupsd_send_dbus(event, dest, job);
105#endif /* HAVE_DBUS */
106
ef416fc2 107 /*
108 * Return if we aren't keeping events...
109 */
110
111 if (MaxEvents <= 0)
112 {
113 cupsdLogMessage(CUPSD_LOG_WARN,
114 "cupsdAddEvent: Discarding %s event since MaxEvents is %d!",
115 cupsdEventName(event), MaxEvents);
116 return;
117 }
118
ef416fc2 119 /*
120 * Then loop through the subscriptions and add the event to the corresponding
121 * caches...
122 */
123
ed486911 124 for (temp = NULL, sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
ef416fc2 125 sub;
126 sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
127 {
128 /*
129 * Check if this subscription requires this event...
130 */
131
132 if ((sub->mask & event) != 0 &&
133 (sub->dest == dest || !sub->dest) &&
134 (sub->job == job || !sub->job))
135 {
136 /*
ed486911 137 * Need this event, so create a new event record...
ef416fc2 138 */
139
ed486911 140 if ((temp = (cupsd_event_t *)calloc(1, sizeof(cupsd_event_t))) == NULL)
ef416fc2 141 {
ed486911 142 cupsdLogMessage(CUPSD_LOG_CRIT,
143 "Unable to allocate memory for event - %s",
144 strerror(errno));
145 return;
146 }
ef416fc2 147
ed486911 148 temp->event = event;
149 temp->time = time(NULL);
150 temp->attrs = ippNew();
151 temp->job = job;
152 temp->dest = dest;
ef416fc2 153
ed486911 154 /*
155 * Add common event notification attributes...
156 */
ef416fc2 157
ed486911 158 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_CHARSET,
159 "notify-charset", NULL, "utf-8");
ef416fc2 160
ed486911 161 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_LANGUAGE,
162 "notify-natural-langugage", NULL, "en-US");
ef416fc2 163
ed486911 164 ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
165 "notify-subscription-id", sub->id);
ef416fc2 166
ed486911 167 ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
168 "notify-sequence-number", sub->next_event_id);
ef416fc2 169
ed486911 170 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD,
171 "notify-subscribed-event", NULL, cupsdEventName(event));
ef416fc2 172
ed486911 173 if (sub->user_data_len > 0)
174 ippAddOctetString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
175 "notify-user-data", sub->user_data,
176 sub->user_data_len);
ef416fc2 177
ed486911 178 ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
179 "printer-up-time", time(NULL));
ef416fc2 180
ed486911 181 va_start(ap, text);
182 vsnprintf(ftext, sizeof(ftext), text, ap);
183 va_end(ap);
ef416fc2 184
ed486911 185 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_TEXT,
186 "notify-text", NULL, ftext);
ef416fc2 187
ed486911 188 if (dest)
189 {
190 /*
191 * Add printer attributes...
192 */
ef416fc2 193
ed486911 194 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI,
195 "notify-printer-uri", NULL, dest->uri);
ef416fc2 196
ed486911 197 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME,
198 "printer-name", NULL, dest->name);
ef416fc2 199
ed486911 200 ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM,
201 "printer-state", dest->state);
ef416fc2 202
ed486911 203 if (dest->num_reasons == 0)
204 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
205 IPP_TAG_KEYWORD, "printer-state-reasons", NULL,
206 dest->state == IPP_PRINTER_STOPPED ? "paused" : "none");
207 else
208 ippAddStrings(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
209 IPP_TAG_KEYWORD, "printer-state-reasons",
210 dest->num_reasons, NULL,
211 (const char * const *)dest->reasons);
ef416fc2 212
ed486911 213 ippAddBoolean(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
214 "printer-is-accepting-jobs", dest->accepting);
215 }
fa73b229 216
ed486911 217 if (job)
218 {
219 /*
220 * Add job attributes...
221 */
ef416fc2 222
ed486911 223 ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
224 "notify-job-id", job->id);
225 ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM,
226 "job-state", job->state_value);
227
228 if ((attr = ippFindAttribute(job->attrs, "job-name",
229 IPP_TAG_NAME)) != NULL)
230 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME,
231 "job-name", NULL, attr->values[0].string.text);
232
233 switch (job->state_value)
234 {
235 case IPP_JOB_PENDING :
236 if (dest && dest->state == IPP_PRINTER_STOPPED)
ef416fc2 237 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
238 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
ed486911 239 "printer-stopped");
240 else
ef416fc2 241 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
242 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
ed486911 243 "none");
244 break;
ef416fc2 245
ed486911 246 case IPP_JOB_HELD :
247 if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD) != NULL ||
248 ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME) != NULL)
ef416fc2 249 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
250 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
ed486911 251 "job-hold-until-specified");
252 else
ef416fc2 253 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
254 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
ed486911 255 "job-incoming");
256 break;
257
258 case IPP_JOB_PROCESSING :
259 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
260 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
261 "job-printing");
262 break;
263
264 case IPP_JOB_STOPPED :
265 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
266 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
267 "job-stopped");
268 break;
269
d09495fa 270 case IPP_JOB_CANCELED :
ed486911 271 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
272 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
273 "job-canceled-by-user");
274 break;
275
276 case IPP_JOB_ABORTED :
277 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
278 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
279 "aborted-by-system");
280 break;
281
282 case IPP_JOB_COMPLETED :
283 ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
284 IPP_TAG_KEYWORD, "job-state-reasons", NULL,
285 "job-completed-successfully");
286 break;
ef416fc2 287 }
288
ed486911 289 ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
290 "job-impressions-completed",
291 job->sheets ? job->sheets->values[0].integer : 0);
8ca02f3c 292 }
ef416fc2 293
8ca02f3c 294 /*
295 * Send the notification for this subscription...
296 */
ef416fc2 297
8ca02f3c 298 cupsd_send_notification(sub, temp);
ef416fc2 299 }
300 }
301
302 if (temp)
303 cupsdSaveAllSubscriptions();
304 else
305 cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...",
306 cupsdEventName(event));
307}
308
309
310/*
311 * 'cupsdAddSubscription()' - Add a new subscription object.
312 */
313
314cupsd_subscription_t * /* O - New subscription object */
315cupsdAddSubscription(
316 unsigned mask, /* I - Event mask */
317 cupsd_printer_t *dest, /* I - Printer, if any */
318 cupsd_job_t *job, /* I - Job, if any */
319 const char *uri, /* I - notify-recipient-uri, if any */
320 int sub_id) /* I - notify-subscription-id or 0 */
321{
322 cupsd_subscription_t *temp; /* New subscription object */
323
324
325 cupsdLogMessage(CUPSD_LOG_DEBUG,
e1d6a774 326 "cupsdAddSubscription(mask=%x, dest=%p(%s), job=%p(%d), "
327 "uri=\"%s\")",
328 mask, dest, dest ? dest->name : "", job, job ? job->id : 0,
329 uri);
ef416fc2 330
331 if (!Subscriptions)
332 Subscriptions = cupsArrayNew((cups_array_func_t)cupsd_compare_subscriptions,
333 NULL);
334
335 if (!Subscriptions)
336 {
337 cupsdLogMessage(CUPSD_LOG_CRIT,
338 "Unable to allocate memory for subscriptions - %s",
339 strerror(errno));
340 return (NULL);
341 }
342
343 /*
344 * Limit the number of subscriptions...
345 */
346
347 if (cupsArrayCount(Subscriptions) >= MaxSubscriptions)
348 return (NULL);
349
350 /*
351 * Allocate memory for this subscription...
352 */
353
354 if ((temp = calloc(1, sizeof(cupsd_subscription_t))) == NULL)
355 {
356 cupsdLogMessage(CUPSD_LOG_CRIT,
357 "Unable to allocate memory for subscription object - %s",
358 strerror(errno));
359 return (NULL);
360 }
361
362 /*
363 * Fill in common data...
364 */
365
366 if (sub_id)
367 {
368 temp->id = sub_id;
369
370 if (sub_id >= NextSubscriptionId)
371 NextSubscriptionId = sub_id + 1;
372 }
373 else
374 {
375 temp->id = NextSubscriptionId;
376
377 NextSubscriptionId ++;
378 }
379
380 temp->mask = mask;
381 temp->dest = dest;
382 temp->job = job;
383 temp->pipe = -1;
384 temp->first_event_id = 1;
385 temp->next_event_id = 1;
386
387 cupsdSetString(&(temp->recipient), uri);
388
389 /*
390 * Add the subscription to the array...
391 */
392
393 cupsArrayAdd(Subscriptions, temp);
394
395 return (temp);
396}
397
398
ef416fc2 399/*
400 * 'cupsdDeleteAllSubscriptions()' - Delete all subscriptions.
401 */
402
403void
404cupsdDeleteAllSubscriptions(void)
405{
406 cupsd_subscription_t *sub; /* Subscription */
407
408
409 if (!Subscriptions)
410 return;
411
412 for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
413 sub;
414 sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
415 cupsdDeleteSubscription(sub, 0);
416
417 cupsArrayDelete(Subscriptions);
418 Subscriptions = NULL;
419}
420
421
422/*
423 * 'cupsdDeleteSubscription()' - Delete a subscription object.
424 */
425
426void
427cupsdDeleteSubscription(
428 cupsd_subscription_t *sub, /* I - Subscription object */
429 int update) /* I - 1 = update subscriptions.conf */
430{
ed486911 431 int i; /* Looping var */
432
433
ef416fc2 434 /*
435 * Close the pipe to the notifier as needed...
436 */
437
438 if (sub->pipe >= 0)
439 close(sub->pipe);
440
441 /*
442 * Remove subscription from array...
443 */
444
445 cupsArrayRemove(Subscriptions, sub);
446
447 /*
448 * Free memory...
449 */
450
451 cupsdClearString(&(sub->owner));
452 cupsdClearString(&(sub->recipient));
453
454 if (sub->events)
ed486911 455 {
456 for (i = 0; i < sub->num_events; i ++)
457 cupsd_delete_event(sub->events[i]);
458
ef416fc2 459 free(sub->events);
ed486911 460 }
ef416fc2 461
462 free(sub);
463
464 /*
465 * Update the subscriptions as needed...
466 */
467
468 if (update)
469 cupsdSaveAllSubscriptions();
470}
471
472
473/*
474 * 'cupsdEventName()' - Return a single event name.
475 */
476
477const char * /* O - Event name */
478cupsdEventName(
479 cupsd_eventmask_t event) /* I - Event value */
480{
481 switch (event)
482 {
483 default :
484 return (NULL);
485
486 case CUPSD_EVENT_PRINTER_RESTARTED :
487 return ("printer-restarted");
488
489 case CUPSD_EVENT_PRINTER_SHUTDOWN :
490 return ("printer-shutdown");
491
492 case CUPSD_EVENT_PRINTER_STOPPED :
493 return ("printer-stopped");
494
495 case CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED :
496 return ("printer-finishings-changed");
497
498 case CUPSD_EVENT_PRINTER_MEDIA_CHANGED :
499 return ("printer-media-changed");
500
501 case CUPSD_EVENT_PRINTER_ADDED :
502 return ("printer-added");
503
504 case CUPSD_EVENT_PRINTER_DELETED :
505 return ("printer-deleted");
506
507 case CUPSD_EVENT_PRINTER_MODIFIED :
508 return ("printer-modified");
509
510 case CUPSD_EVENT_PRINTER_STATE_CHANGED :
511 return ("printer-state-changed");
512
513 case CUPSD_EVENT_PRINTER_CONFIG_CHANGED :
514 return ("printer-config-changed");
515
516 case CUPSD_EVENT_PRINTER_CHANGED :
517 return ("printer-changed");
518
519 case CUPSD_EVENT_JOB_CREATED :
520 return ("job-created");
521
522 case CUPSD_EVENT_JOB_COMPLETED :
523 return ("job-completed");
524
525 case CUPSD_EVENT_JOB_STOPPED :
526 return ("job-stopped");
527
528 case CUPSD_EVENT_JOB_CONFIG_CHANGED :
529 return ("job-config-changed");
530
531 case CUPSD_EVENT_JOB_PROGRESS :
532 return ("job-progress");
533
e1d6a774 534 case CUPSD_EVENT_JOB_STATE :
535 return ("job-state");
536
ef416fc2 537 case CUPSD_EVENT_JOB_STATE_CHANGED :
538 return ("job-state-changed");
539
540 case CUPSD_EVENT_SERVER_RESTARTED :
541 return ("server-restarted");
542
543 case CUPSD_EVENT_SERVER_STARTED :
544 return ("server-started");
545
546 case CUPSD_EVENT_SERVER_STOPPED :
547 return ("server-stopped");
548
549 case CUPSD_EVENT_SERVER_AUDIT :
550 return ("server-audit");
551
552 case CUPSD_EVENT_ALL :
553 return ("all");
554 }
555}
556
557
558/*
559 * 'cupsdEventValue()' - Return the event mask value for a name.
560 */
561
562cupsd_eventmask_t /* O - Event mask value */
563cupsdEventValue(const char *name) /* I - Name of event */
564{
565 if (!strcmp(name, "all"))
566 return (CUPSD_EVENT_ALL);
567 else if (!strcmp(name, "printer-restarted"))
568 return (CUPSD_EVENT_PRINTER_RESTARTED);
569 else if (!strcmp(name, "printer-shutdown"))
570 return (CUPSD_EVENT_PRINTER_SHUTDOWN);
571 else if (!strcmp(name, "printer-stopped"))
572 return (CUPSD_EVENT_PRINTER_STOPPED);
573 else if (!strcmp(name, "printer-finishings-changed"))
574 return (CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED);
575 else if (!strcmp(name, "printer-media-changed"))
576 return (CUPSD_EVENT_PRINTER_MEDIA_CHANGED);
577 else if (!strcmp(name, "printer-added"))
578 return (CUPSD_EVENT_PRINTER_ADDED);
579 else if (!strcmp(name, "printer-deleted"))
580 return (CUPSD_EVENT_PRINTER_DELETED);
581 else if (!strcmp(name, "printer-modified"))
582 return (CUPSD_EVENT_PRINTER_MODIFIED);
583 else if (!strcmp(name, "printer-state-changed"))
584 return (CUPSD_EVENT_PRINTER_STATE_CHANGED);
585 else if (!strcmp(name, "printer-config-changed"))
586 return (CUPSD_EVENT_PRINTER_CONFIG_CHANGED);
587 else if (!strcmp(name, "printer-changed"))
588 return (CUPSD_EVENT_PRINTER_CHANGED);
e1d6a774 589 else if (!strcmp(name, "job-state"))
590 return (CUPSD_EVENT_JOB_STATE);
ef416fc2 591 else if (!strcmp(name, "job-created"))
592 return (CUPSD_EVENT_JOB_CREATED);
593 else if (!strcmp(name, "job-completed"))
594 return (CUPSD_EVENT_JOB_COMPLETED);
595 else if (!strcmp(name, "job-stopped"))
596 return (CUPSD_EVENT_JOB_STOPPED);
597 else if (!strcmp(name, "job-config-changed"))
598 return (CUPSD_EVENT_JOB_CONFIG_CHANGED);
599 else if (!strcmp(name, "job-progress"))
600 return (CUPSD_EVENT_JOB_PROGRESS);
601 else if (!strcmp(name, "job-state-changed"))
602 return (CUPSD_EVENT_JOB_STATE_CHANGED);
603 else if (!strcmp(name, "server-restarted"))
604 return (CUPSD_EVENT_SERVER_RESTARTED);
605 else if (!strcmp(name, "server-started"))
606 return (CUPSD_EVENT_SERVER_STARTED);
607 else if (!strcmp(name, "server-stopped"))
608 return (CUPSD_EVENT_SERVER_STOPPED);
609 else if (!strcmp(name, "server-audit"))
610 return (CUPSD_EVENT_SERVER_AUDIT);
611 else
612 return (CUPSD_EVENT_NONE);
613}
614
615
616/*
617 * 'cupsdExpireSubscriptions()' - Expire old subscription objects.
618 */
619
620void
621cupsdExpireSubscriptions(
622 cupsd_printer_t *dest, /* I - Printer, if any */
623 cupsd_job_t *job) /* I - Job, if any */
624{
625 cupsd_subscription_t *sub; /* Current subscription */
626 int update; /* Update subscriptions.conf? */
627 time_t curtime; /* Current time */
628
629
630 curtime = time(NULL);
631 update = 0;
632
633 for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
634 sub;
635 sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
bd7854cb 636 if ((!sub->job && !dest && sub->expire && sub->expire <= curtime) ||
637 (dest && sub->dest == dest) ||
ef416fc2 638 (job && sub->job == job))
639 {
bd7854cb 640 cupsdLogMessage(CUPSD_LOG_INFO, "Subscription %d has expired...",
641 sub->id);
ef416fc2 642
643 cupsdDeleteSubscription(sub, 0);
644
645 update = 1;
646 }
647
648 if (update)
649 cupsdSaveAllSubscriptions();
650}
651
652
653/*
654 * 'cupsdFindSubscription()' - Find a subscription by ID.
655 */
656
657cupsd_subscription_t * /* O - Subscription object */
658cupsdFindSubscription(int id) /* I - Subscription ID */
659{
660 cupsd_subscription_t sub; /* Subscription template */
661
662
663 sub.id = id;
664
665 return ((cupsd_subscription_t *)cupsArrayFind(Subscriptions, &sub));
666}
667
668
669/*
670 * 'cupsdLoadAllSubscriptions()' - Load all subscriptions from the .conf file.
671 */
672
673void
674cupsdLoadAllSubscriptions(void)
675{
676 int i; /* Looping var */
677 cups_file_t *fp; /* subscriptions.conf file */
678 int linenum; /* Current line number */
679 char line[1024], /* Line from file */
680 *value, /* Pointer to value */
681 *valueptr; /* Pointer into value */
682 cupsd_subscription_t *sub; /* Current subscription */
683 int hex; /* Non-zero if reading hex data */
684 int delete_sub; /* Delete subscription? */
685
686
687 /*
688 * Open the subscriptions.conf file...
689 */
690
691 snprintf(line, sizeof(line), "%s/subscriptions.conf", ServerRoot);
692 if ((fp = cupsFileOpen(line, "r")) == NULL)
693 {
fa73b229 694 if (errno != ENOENT)
695 cupsdLogMessage(CUPSD_LOG_ERROR,
696 "LoadAllSubscriptions: Unable to open %s - %s", line,
697 strerror(errno));
ef416fc2 698 return;
699 }
700
701 /*
702 * Read all of the lines from the file...
703 */
704
705 linenum = 0;
706 sub = NULL;
707 delete_sub = 0;
708
709 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
710 {
480ef0fe 711 if (!strcasecmp(line, "NextSubscriptionId") && value)
712 {
713 /*
714 * NextSubscriptionId NNN
715 */
716
717 i = atoi(value);
718 if (i >= NextSubscriptionId && i > 0)
719 NextSubscriptionId = i;
720 }
721 else if (!strcasecmp(line, "<Subscription"))
ef416fc2 722 {
723 /*
724 * <Subscription #>
725 */
726
727 if (!sub && value && isdigit(value[0] & 255))
728 {
729 sub = cupsdAddSubscription(CUPSD_EVENT_NONE, NULL, NULL, NULL,
730 atoi(value));
731 }
732 else
733 {
734 cupsdLogMessage(CUPSD_LOG_ERROR,
735 "Syntax error on line %d of subscriptions.conf.",
736 linenum);
737 return;
738 }
739 }
740 else if (!strcasecmp(line, "</Subscription>"))
741 {
742 if (!sub)
743 {
744 cupsdLogMessage(CUPSD_LOG_ERROR,
745 "Syntax error on line %d of subscriptions.conf.",
746 linenum);
747 return;
748 }
749
750 if (delete_sub)
751 cupsdDeleteSubscription(sub, 0);
752
753 sub = NULL;
754 delete_sub = 0;
755 }
756 else if (!sub)
757 {
758 cupsdLogMessage(CUPSD_LOG_ERROR,
759 "Syntax error on line %d of subscriptions.conf.",
760 linenum);
761 return;
762 }
763 else if (!strcasecmp(line, "Events"))
764 {
765 /*
766 * Events name
767 * Events name name name ...
768 */
769
770 if (!value)
771 {
772 cupsdLogMessage(CUPSD_LOG_ERROR,
773 "Syntax error on line %d of subscriptions.conf.",
774 linenum);
775 return;
776 }
777
778 while (*value)
779 {
780 /*
781 * Separate event names...
782 */
783
784 for (valueptr = value; !isspace(*valueptr) && *valueptr; valueptr ++);
785
786 while (isspace(*valueptr & 255))
787 *valueptr++ = '\0';
788
789 /*
790 * See if the name exists...
791 */
792
793 if ((sub->mask |= cupsdEventValue(value)) == CUPSD_EVENT_NONE)
794 {
795 cupsdLogMessage(CUPSD_LOG_ERROR,
796 "Unknown event name \'%s\' on line %d of subscriptions.conf.",
797 value, linenum);
798 return;
799 }
800
801 value = valueptr;
802 }
803 }
804 else if (!strcasecmp(line, "Owner"))
805 {
806 /*
807 * Owner
808 */
809
810 if (value)
811 cupsdSetString(&sub->owner, value);
812 else
813 {
814 cupsdLogMessage(CUPSD_LOG_ERROR,
815 "Syntax error on line %d of subscriptions.conf.",
816 linenum);
817 return;
818 }
819 }
820 else if (!strcasecmp(line, "Recipient"))
821 {
822 /*
823 * Recipient uri
824 */
825
826 if (value)
827 cupsdSetString(&sub->recipient, value);
828 else
829 {
830 cupsdLogMessage(CUPSD_LOG_ERROR,
831 "Syntax error on line %d of subscriptions.conf.",
832 linenum);
833 return;
834 }
835 }
836 else if (!strcasecmp(line, "JobId"))
837 {
838 /*
839 * JobId #
840 */
841
842 if (value && isdigit(*value & 255))
843 {
844 if ((sub->job = cupsdFindJob(atoi(value))) == NULL)
845 {
846 cupsdLogMessage(CUPSD_LOG_ERROR,
847 "Job %s not found on line %d of subscriptions.conf.",
848 value, linenum);
849 delete_sub = 1;
850 }
851 }
852 else
853 {
854 cupsdLogMessage(CUPSD_LOG_ERROR,
855 "Syntax error on line %d of subscriptions.conf.",
856 linenum);
857 return;
858 }
859 }
860 else if (!strcasecmp(line, "PrinterName"))
861 {
862 /*
863 * PrinterName name
864 */
865
866 if (value)
867 {
868 if ((sub->dest = cupsdFindDest(value)) == NULL)
869 {
870 cupsdLogMessage(CUPSD_LOG_ERROR,
871 "Printer \'%s\' not found on line %d of subscriptions.conf.",
872 value, linenum);
873 delete_sub = 1;
874 }
875 }
876 else
877 {
878 cupsdLogMessage(CUPSD_LOG_ERROR,
879 "Syntax error on line %d of subscriptions.conf.",
880 linenum);
881 return;
882 }
883 }
884 else if (!strcasecmp(line, "UserData"))
885 {
886 /*
887 * UserData encoded-string
888 */
889
890 if (value)
891 {
892 for (i = 0, valueptr = value, hex = 0; i < 63 && *valueptr; i ++)
893 {
894 if (*valueptr == '<' && !hex)
895 {
896 hex = 1;
897 valueptr ++;
898 }
899
900 if (hex)
901 {
902 if (isxdigit(valueptr[0]) && isxdigit(valueptr[1]))
903 {
904 if (isdigit(valueptr[0]))
905 sub->user_data[i] = (valueptr[0] - '0') << 4;
906 else
907 sub->user_data[i] = (tolower(valueptr[0]) - 'a' + 10) << 4;
908
909 if (isdigit(valueptr[1]))
910 sub->user_data[i] |= valueptr[1] - '0';
911 else
912 sub->user_data[i] |= tolower(valueptr[1]) - 'a' + 10;
913
914 valueptr += 2;
915
916 if (*valueptr == '>')
917 {
918 hex = 0;
919 valueptr ++;
920 }
921 }
922 else
923 break;
924 }
925 else
926 sub->user_data[i] = *valueptr++;
927 }
928
929 if (*valueptr)
930 {
931 cupsdLogMessage(CUPSD_LOG_ERROR,
932 "Bad UserData \'%s\' on line %d of subscriptions.conf.",
933 value, linenum);
934 }
935 else
936 sub->user_data_len = i;
937 }
938 else
939 {
940 cupsdLogMessage(CUPSD_LOG_ERROR,
941 "Syntax error on line %d of subscriptions.conf.",
942 linenum);
943 return;
944 }
945 }
946 else if (!strcasecmp(line, "LeaseDuration"))
947 {
948 /*
949 * LeaseDuration #
950 */
951
952 if (value && isdigit(*value & 255))
bd7854cb 953 {
954 sub->lease = atoi(value);
955 sub->expire = sub->lease ? time(NULL) + sub->lease : 0;
956 }
ef416fc2 957 else
958 {
959 cupsdLogMessage(CUPSD_LOG_ERROR,
960 "Syntax error on line %d of subscriptions.conf.",
961 linenum);
962 return;
963 }
964 }
965 else if (!strcasecmp(line, "Interval"))
966 {
967 /*
968 * Interval #
969 */
970
971 if (value && isdigit(*value & 255))
972 sub->interval = atoi(value);
973 else
974 {
975 cupsdLogMessage(CUPSD_LOG_ERROR,
976 "Syntax error on line %d of subscriptions.conf.",
977 linenum);
978 return;
979 }
980 }
981 else if (!strcasecmp(line, "ExpirationTime"))
982 {
983 /*
984 * ExpirationTime #
985 */
986
987 if (value && isdigit(*value & 255))
988 sub->expire = atoi(value);
989 else
990 {
991 cupsdLogMessage(CUPSD_LOG_ERROR,
992 "Syntax error on line %d of subscriptions.conf.",
993 linenum);
994 return;
995 }
996 }
997 else if (!strcasecmp(line, "NextEventId"))
998 {
999 /*
1000 * NextEventId #
1001 */
1002
1003 if (value && isdigit(*value & 255))
1004 sub->next_event_id = sub->first_event_id = atoi(value);
1005 else
1006 {
1007 cupsdLogMessage(CUPSD_LOG_ERROR,
1008 "Syntax error on line %d of subscriptions.conf.",
1009 linenum);
1010 return;
1011 }
1012 }
1013 else
1014 {
1015 /*
1016 * Something else we don't understand...
1017 */
1018
1019 cupsdLogMessage(CUPSD_LOG_ERROR,
1020 "Unknown configuration directive %s on line %d of subscriptions.conf.",
1021 line, linenum);
1022 }
1023 }
1024
1025 cupsFileClose(fp);
1026}
1027
1028
1029/*
1030 * 'cupsdSaveAllSubscriptions()' - Save all subscriptions to the .conf file.
1031 */
1032
1033void
1034cupsdSaveAllSubscriptions(void)
1035{
1036 int i; /* Looping var */
1037 cups_file_t *fp; /* subscriptions.conf file */
1038 char temp[1024]; /* Temporary string */
1039 char backup[1024]; /* subscriptions.conf.O file */
1040 cupsd_subscription_t *sub; /* Current subscription */
1041 time_t curtime; /* Current time */
1042 struct tm *curdate; /* Current date */
1043 unsigned mask; /* Current event mask */
1044 const char *name; /* Current event name */
1045 int hex; /* Non-zero if we are writing hex data */
1046
1047
1048 /*
1049 * Create the subscriptions.conf file...
1050 */
1051
1052 snprintf(temp, sizeof(temp), "%s/subscriptions.conf", ServerRoot);
1053 snprintf(backup, sizeof(backup), "%s/subscriptions.conf.O", ServerRoot);
1054
1055 if (rename(temp, backup))
1056 {
1057 if (errno != ENOENT)
1058 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup subscriptions.conf - %s",
1059 strerror(errno));
1060 }
1061
1062 if ((fp = cupsFileOpen(temp, "w")) == NULL)
1063 {
1064 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save subscriptions.conf - %s",
1065 strerror(errno));
1066
1067 if (rename(backup, temp))
1068 cupsdLogMessage(CUPSD_LOG_ERROR,
1069 "Unable to restore subscriptions.conf - %s",
1070 strerror(errno));
1071 return;
1072 }
1073 else
1074 cupsdLogMessage(CUPSD_LOG_INFO, "Saving subscriptions.conf...");
1075
1076 /*
1077 * Restrict access to the file...
1078 */
1079
1080 fchown(cupsFileNumber(fp), getuid(), Group);
1081 fchmod(cupsFileNumber(fp), ConfigFilePerm);
1082
1083 /*
1084 * Write a small header to the file...
1085 */
1086
1087 curtime = time(NULL);
1088 curdate = localtime(&curtime);
1089 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
1090
1091 cupsFilePuts(fp, "# Subscription configuration file for " CUPS_SVERSION "\n");
1092 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
1093
480ef0fe 1094 cupsFilePrintf(fp, "NextSubscriptionId %d\n", NextSubscriptionId);
1095
ef416fc2 1096 /*
1097 * Write every subscription known to the system...
1098 */
1099
1100 for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
1101 sub;
1102 sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
1103 {
1104 cupsFilePrintf(fp, "<Subscription %d>\n", sub->id);
1105
1106 if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
1107 {
1108 /*
1109 * Simple event list...
1110 */
1111
1112 cupsFilePrintf(fp, "Events %s\n", name);
1113 }
1114 else
1115 {
1116 /*
1117 * Complex event list...
1118 */
1119
1120 cupsFilePuts(fp, "Events");
1121
1122 for (mask = 1; mask < CUPSD_EVENT_ALL; mask <<= 1)
1123 if (sub->mask & mask)
1124 cupsFilePrintf(fp, " %s", cupsdEventName((cupsd_eventmask_t)mask));
1125
1126 cupsFilePuts(fp, "\n");
1127 }
1128
1129 if (sub->owner)
1130 cupsFilePrintf(fp, "Owner %s\n", sub->owner);
1131 if (sub->recipient)
1132 cupsFilePrintf(fp, "Recipient %s\n", sub->recipient);
1133 if (sub->job)
1134 cupsFilePrintf(fp, "JobId %d\n", sub->job->id);
1135 if (sub->dest)
1136 cupsFilePrintf(fp, "PrinterName %s\n", sub->dest->name);
1137
1138 if (sub->user_data_len > 0)
1139 {
1140 cupsFilePuts(fp, "UserData ");
1141
1142 for (i = 0, hex = 0; i < sub->user_data_len; i ++)
1143 {
1144 if (sub->user_data[i] < ' ' ||
1145 sub->user_data[i] > 0x7f ||
1146 sub->user_data[i] == '<')
1147 {
1148 if (!hex)
1149 {
1150 cupsFilePrintf(fp, "<%02X", sub->user_data[i]);
1151 hex = 1;
1152 }
1153 else
1154 cupsFilePrintf(fp, "%02X", sub->user_data[i]);
1155 }
1156 else
1157 {
1158 if (hex)
1159 {
1160 cupsFilePrintf(fp, ">%c", sub->user_data[i]);
1161 hex = 0;
1162 }
1163 else
1164 cupsFilePutChar(fp, sub->user_data[i]);
1165 }
1166 }
1167
1168 if (hex)
1169 cupsFilePuts(fp, ">\n");
1170 else
1171 cupsFilePutChar(fp, '\n');
1172 }
1173
1174 cupsFilePrintf(fp, "LeaseDuration %d\n", sub->lease);
1175 cupsFilePrintf(fp, "Interval %d\n", sub->interval);
1176 cupsFilePrintf(fp, "ExpirationTime %ld\n", (long)sub->expire);
1177 cupsFilePrintf(fp, "NextEventId %d\n", sub->next_event_id);
1178
1179 cupsFilePuts(fp, "</Subscription>\n");
1180 }
1181
1182 cupsFileClose(fp);
1183}
1184
1185
ef416fc2 1186/*
1187 * 'cupsdStopAllNotifiers()' - Stop all notifier processes.
1188 */
1189
1190void
1191cupsdStopAllNotifiers(void)
1192{
1193 cupsd_subscription_t *sub; /* Current subscription */
1194
1195
1196 /*
1197 * See if we have started any notifiers...
1198 */
1199
1200 if (!NotifierStatusBuffer)
1201 return;
1202
1203 /*
fa73b229 1204 * Yes, kill any processes that are left...
ef416fc2 1205 */
1206
1207 for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
1208 sub;
1209 sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
1210 if (sub->pid)
1211 {
1212 cupsdEndProcess(sub->pid, 0);
1213
1214 close(sub->pipe);
1215 sub->pipe = -1;
1216 }
1217
1218 /*
1219 * Close the status pipes...
1220 */
1221
1222 if (NotifierPipes[0] >= 0)
1223 {
1224 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1225 "cupsdStopAllNotifiers: Removing fd %d from InputSet...",
1226 NotifierPipes[0]);
1227 FD_CLR(NotifierPipes[0], InputSet);
1228
1229 cupsdStatBufDelete(NotifierStatusBuffer);
1230
1231 close(NotifierPipes[0]);
1232 close(NotifierPipes[1]);
1233
1234 NotifierPipes[0] = -1;
1235 NotifierPipes[1] = -1;
1236 NotifierStatusBuffer = NULL;
1237 }
1238}
1239
1240
1241/*
1242 * 'cupsdUpdateNotifierStatus()' - Read messages from notifiers.
1243 */
1244
1245void
1246cupsdUpdateNotifierStatus(void)
1247{
d09495fa 1248 char message[1024]; /* Pointer to message text */
ef416fc2 1249 int loglevel; /* Log level for message */
1250
1251
d09495fa 1252 while (cupsdStatBufUpdate(NotifierStatusBuffer, &loglevel,
1253 message, sizeof(message)))
ef416fc2 1254 if (!strchr(NotifierStatusBuffer->buffer, '\n'))
1255 break;
1256}
1257
1258
1259/*
1260 * 'cupsd_compare_subscriptions()' - Compare two subscriptions.
1261 */
1262
1263static int /* O - Result of comparison */
1264cupsd_compare_subscriptions(
1265 cupsd_subscription_t *first, /* I - First subscription object */
1266 cupsd_subscription_t *second, /* I - Second subscription object */
1267 void *unused) /* I - Unused user data pointer */
1268{
1269 (void)unused;
1270
1271 return (first->id - second->id);
1272}
1273
1274
1275/*
1276 * 'cupsd_delete_event()' - Delete a single event...
1277 *
1278 * Oldest events must be deleted first, otherwise the subscription cache
1279 * flushing code will not work properly.
1280 */
1281
1282static void
1283cupsd_delete_event(cupsd_event_t *event)/* I - Event to delete */
1284{
ef416fc2 1285 /*
1286 * Free memory...
1287 */
1288
1289 ippDelete(event->attrs);
1290 free(event);
1291}
1292
1293
e00b005a 1294#ifdef HAVE_DBUS
1295/*
1296 * 'cupsd_send_dbus()' - Send a DBUS notification...
1297 */
1298
1299static void
1300cupsd_send_dbus(cupsd_eventmask_t event,/* I - Event to send */
1301 cupsd_printer_t *dest,/* I - Destination, if any */
1302 cupsd_job_t *job) /* I - Job, if any */
1303{
1304 DBusError error; /* Error, if any */
1305 DBusMessage *message; /* Message to send */
1306 DBusMessageIter iter; /* Iterator for message data */
1307 const char *what; /* What to send */
1308 static DBusConnection *con = NULL; /* Connection to DBUS server */
1309
1310
1311 /*
1312 * Figure out what to send, if anything...
1313 */
1314
1315 if (event & CUPSD_EVENT_PRINTER_ADDED)
1316 what = "PrinterAdded";
1317 else if (event & CUPSD_EVENT_PRINTER_DELETED)
1318 what = "PrinterRemoved";
1319 else if (event & CUPSD_EVENT_PRINTER_CHANGED)
1320 what = "QueueChanged";
1321 else if (event & CUPSD_EVENT_JOB_CREATED)
1322 what = "JobQueuedLocal";
1323 else if ((event & CUPSD_EVENT_JOB_STATE) && job &&
bd7854cb 1324 job->state_value == IPP_JOB_PROCESSING)
e00b005a 1325 what = "JobStartedLocal";
1326 else
1327 return;
1328
1329 /*
1330 * Verify connection to DBUS server...
1331 */
1332
1333 if (con && !dbus_connection_get_is_connected(con))
1334 {
1335 dbus_connection_unref(con);
1336 con = NULL;
1337 }
1338
1339 if (!con)
1340 {
1341 dbus_error_init(&error);
1342
1343 con = dbus_bus_get(getuid() ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error);
1344 if (!con)
1345 {
1346 dbus_error_free(&error);
1347 return;
1348 }
1349 }
1350
1351 /*
1352 * Create and send the new message...
1353 */
1354
1355 message = dbus_message_new_signal("/com/redhat/PrinterSpooler",
1356 "com.redhat.PrinterSpooler", what);
1357
1358 dbus_message_iter_init_append(message, &iter);
1359 if (dest)
1360 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &(dest->name));
1361 if (job)
1362 {
1363 dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &(job->id));
1364 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &(job->username));
1365 }
1366
1367 dbus_connection_send(con, message, NULL);
1368 dbus_connection_flush(con);
1369 dbus_message_unref(message);
1370}
1371#endif /* HAVE_DBUS */
1372
1373
e1d6a774 1374/*
1375 * 'cupsd_send_notification()' - Send a notification for the specified event.
1376 */
1377
1378static void
1379cupsd_send_notification(
1380 cupsd_subscription_t *sub, /* I - Subscription object */
1381 cupsd_event_t *event) /* I - Event to send */
1382{
1383 ipp_state_t state; /* IPP event state */
1384
1385
8ca02f3c 1386 cupsdLogMessage(CUPSD_LOG_DEBUG2,
e1d6a774 1387 "cupsd_send_notification(sub=%p(%d), event=%p(%s))\n",
1388 sub, sub->id, event, cupsdEventName(event->event));
1389
1390 /*
1391 * Allocate the events array as needed...
1392 */
1393
1394 if (!sub->events)
1395 {
1396 sub->events = calloc(MaxEvents, sizeof(cupsd_event_t *));
1397
1398 if (!sub->events)
1399 {
1400 cupsdLogMessage(CUPSD_LOG_CRIT,
1401 "Unable to allocate memory for subscription #%d!",
1402 sub->id);
1403 return;
1404 }
1405 }
1406
ed486911 1407 /*
1408 * Purge an old event as needed...
1409 */
1410
1411 if (sub->num_events >= MaxEvents)
1412 {
1413 /*
1414 * Purge the oldest event in the cache...
1415 */
1416
1417 cupsd_delete_event(sub->events[0]);
1418
1419 sub->num_events --;
1420 sub->first_event_id ++;
1421
1422 memmove(sub->events, sub->events + 1,
1423 sub->num_events * sizeof(cupsd_event_t *));
1424 }
1425
e1d6a774 1426 /*
1427 * Add the event to the subscription. Since the events array is
1428 * always MaxEvents in length, and since we will have already
1429 * removed an event from the subscription cache if we hit the
1430 * event cache limit, we don't need to check for overflow here...
1431 */
1432
1433 sub->events[sub->num_events] = event;
1434 sub->num_events ++;
1435
1436 /*
1437 * Deliver the event...
1438 */
1439
1440 if (sub->recipient)
1441 {
8ca02f3c 1442 for (;;)
1443 {
1444 if (sub->pipe < 0)
1445 cupsd_start_notifier(sub);
e1d6a774 1446
8ca02f3c 1447 cupsdLogMessage(CUPSD_LOG_DEBUG2, "sub->pipe=%d", sub->pipe);
1448
1449 if (sub->pipe < 0)
1450 break;
e1d6a774 1451
e1d6a774 1452 event->attrs->state = IPP_IDLE;
1453
1454 while ((state = ippWriteFile(sub->pipe, event->attrs)) != IPP_DATA)
1455 if (state == IPP_ERROR)
1456 break;
1457
1458 if (state == IPP_ERROR)
8ca02f3c 1459 {
1460 if (errno == EPIPE)
1461 {
1462 /*
1463 * Notifier died, try restarting it...
1464 */
1465
1466 cupsdLogMessage(CUPSD_LOG_WARN,
1467 "Notifier for subscription %d (%s) went away, "
1468 "retrying!",
1469 sub->id, sub->recipient);
1470 cupsdEndProcess(sub->pid, 0);
1471
1472 close(sub->pipe);
1473 sub->pipe = -1;
1474 continue;
1475 }
1476
e1d6a774 1477 cupsdLogMessage(CUPSD_LOG_ERROR,
1478 "Unable to send event for subscription %d (%s)!",
1479 sub->id, sub->recipient);
8ca02f3c 1480 }
1481
1482 /*
1483 * If we get this far, break out of the loop...
1484 */
1485
1486 break;
e1d6a774 1487 }
1488 }
1489
1490 /*
1491 * Bump the event sequence number...
1492 */
1493
1494 sub->next_event_id ++;
1495}
1496
1497
ef416fc2 1498/*
1499 * 'cupsd_start_notifier()' - Start a notifier subprocess...
1500 */
1501
1502static void
1503cupsd_start_notifier(
1504 cupsd_subscription_t *sub) /* I - Subscription object */
1505{
1506 int pid; /* Notifier process ID */
1507 int fds[2]; /* Pipe file descriptors */
ef416fc2 1508 char *argv[4], /* Command-line arguments */
e00b005a 1509 *envp[MAX_ENV], /* Environment variables */
ef416fc2 1510 user_data[128], /* Base-64 encoded user data */
1511 scheme[256], /* notify-recipient-uri scheme */
1512 *ptr, /* Pointer into scheme */
1513 command[1024]; /* Notifier command */
1514
1515
1516 /*
1517 * Extract the scheme name from the recipient URI and point to the
1518 * notifier program...
1519 */
1520
1521 strlcpy(scheme, sub->recipient, sizeof(scheme));
1522 if ((ptr = strchr(scheme, ':')) != NULL)
1523 *ptr = '\0';
1524
1525 snprintf(command, sizeof(command), "%s/notifier/%s", ServerBin, scheme);
1526
1527 /*
1528 * Base-64 encode the user data...
1529 */
1530
1531 httpEncode64_2(user_data, sizeof(user_data), (char *)sub->user_data,
1532 sub->user_data_len);
1533
1534 /*
1535 * Setup the argument array...
1536 */
1537
1538 argv[0] = command;
1539 argv[1] = sub->recipient;
1540 argv[2] = user_data;
1541 argv[3] = NULL;
1542
1543 /*
1544 * Setup the environment...
1545 */
1546
d09495fa 1547 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
ef416fc2 1548
1549 /*
1550 * Create pipes as needed...
1551 */
1552
1553 if (!NotifierStatusBuffer)
1554 {
1555 /*
1556 * Create the status pipe...
1557 */
1558
1559 if (cupsdOpenPipe(NotifierPipes))
1560 {
1561 cupsdLogMessage(CUPSD_LOG_ERROR,
1562 "Unable to create pipes for notifier status - %s",
1563 strerror(errno));
1564 return;
1565 }
1566
1567 NotifierStatusBuffer = cupsdStatBufNew(NotifierPipes[0], "[Notifier]");
1568
1569 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1570 "start_notifier: Adding fd %d to InputSet...",
1571 NotifierPipes[0]);
1572
1573 FD_SET(NotifierPipes[0], InputSet);
1574 }
1575
1576 if (cupsdOpenPipe(fds))
1577 {
1578 cupsdLogMessage(CUPSD_LOG_ERROR,
1579 "Unable to create pipes for notifier %s - %s",
1580 scheme, strerror(errno));
1581 return;
1582 }
1583
1584 /*
1585 * Make sure the delivery pipe is non-blocking...
1586 */
1587
1588 fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK);
1589
1590 /*
1591 * Create the notifier process...
1592 */
1593
1594 if (cupsdStartProcess(command, argv, envp, fds[0], -1, NotifierPipes[1],
1595 -1, 0, &pid) < 0)
1596 {
1597 /*
1598 * Error - can't fork!
1599 */
1600
1601 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork for notifier %s - %s",
1602 scheme, strerror(errno));
1603
1604 cupsdClosePipe(fds);
1605 }
1606 else
1607 {
1608 /*
1609 * Fork successful - return the PID...
1610 */
1611
1612 cupsdLogMessage(CUPSD_LOG_DEBUG, "Notifier %s started - PID = %d",
1613 scheme, pid);
1614
1615 sub->pid = pid;
1616 sub->pipe = fds[1];
1617 sub->status = 0;
1618
1619 close(fds[0]);
1620 }
1621}
1622
1623
1624/*
d09495fa 1625 * End of "$Id: subscriptions.c 5878 2006-08-24 15:55:42Z mike $".
ef416fc2 1626 */