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