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