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