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