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