void cupsdAddEvent( cupsd_eventmask_t event, /* I - Event */ cupsd_printer_t *dest, /* I - Printer associated with event */ cupsd_job_t *job, /* I - Job associated with event */ const char *text, /* I - Notification text */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to additional arguments */ char ftext[1024]; /* Formatted text buffer */ ipp_attribute_t *attr; /* Printer/job attribute */ cupsd_event_t *temp; /* New event pointer */ cupsd_subscription_t *sub; /* Current subscription */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddEvent(event=%s, dest=%p(%s), job=%p(%d), text=\"%s\", ...)", cupsdEventName(event), dest, dest ? dest->name : "", job, job ? job->id : 0, text); /* * Keep track of events with any OS-supplied notification mechanisms... */ LastEvent |= event; #ifdef HAVE_DBUS cupsd_send_dbus(event, dest, job); #endif /* HAVE_DBUS */ /* * Return if we aren't keeping events... */ if (MaxEvents <= 0) { cupsdLogMessage(CUPSD_LOG_WARN, "cupsdAddEvent: Discarding %s event since MaxEvents is %d!", cupsdEventName(event), MaxEvents); return; } /* * Then loop through the subscriptions and add the event to the corresponding * caches... */ for (temp = NULL, sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); sub; sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) { /* * Check if this subscription requires this event... */ if ((sub->mask & event) != 0 && (sub->dest == dest || !sub->dest) && (sub->job == job || !sub->job)) { /* * Need this event, so create a new event record... */ if ((temp = (cupsd_event_t *)calloc(1, sizeof(cupsd_event_t))) == NULL) { cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for event - %s", strerror(errno)); return; } temp->event = event; temp->time = time(NULL); temp->attrs = ippNew(); temp->job = job; if (dest) temp->dest = dest; else if (job) temp->dest = dest = cupsdFindPrinter(job->dest); /* * Add common event notification attributes... */ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_CHARSET, "notify-charset", NULL, "utf-8"); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_LANGUAGE, "notify-natural-language", NULL, "en-US"); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-sequence-number", sub->next_event_id); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "notify-subscribed-event", NULL, cupsdEventName(event)); if (sub->user_data_len > 0) ippAddOctetString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, "notify-user-data", sub->user_data, sub->user_data_len); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "printer-up-time", time(NULL)); va_start(ap, text); vsnprintf(ftext, sizeof(ftext), text, ap); va_end(ap); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_TEXT, "notify-text", NULL, ftext); if (dest) { /* * Add printer attributes... */ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, "notify-printer-uri", NULL, dest->uri); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "printer-name", NULL, dest->name); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, "printer-state", dest->state); if (dest->num_reasons == 0) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "printer-state-reasons", NULL, dest->state == IPP_PRINTER_STOPPED ? "paused" : "none"); else ippAddStrings(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "printer-state-reasons", dest->num_reasons, NULL, (const char * const *)dest->reasons); ippAddBoolean(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, "printer-is-accepting-jobs", (char)dest->accepting); } if (job) { /* * Add job attributes... */ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-job-id", job->id); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, "job-state", job->state_value); if ((attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-name", NULL, attr->values[0].string.text); switch (job->state_value) { case IPP_JOB_PENDING : if (dest && dest->state == IPP_PRINTER_STOPPED) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "printer-stopped"); else ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "none"); break; case IPP_JOB_HELD : if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD) != NULL || ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME) != NULL) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-hold-until-specified"); else ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-incoming"); break; case IPP_JOB_PROCESSING : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-printing"); break; case IPP_JOB_STOPPED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-stopped"); break; case IPP_JOB_CANCELED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-canceled-by-user"); break; case IPP_JOB_ABORTED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "aborted-by-system"); break; case IPP_JOB_COMPLETED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-completed-successfully"); break; } ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "job-impressions-completed", job->sheets ? job->sheets->values[0].integer : 0); } /* * Send the notification for this subscription... */ cupsd_send_notification(sub, temp); } } if (temp) cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); else cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...", cupsdEventName(event)); }
void cupsdLoadAllClasses(void) { int i; /* Looping var */ cups_file_t *fp; /* classes.conf file */ int linenum; /* Current line number */ char line[4096], /* Line from file */ *value, /* Pointer to value */ *valueptr; /* Pointer into value */ cupsd_printer_t *p, /* Current printer class */ *temp; /* Temporary pointer to printer */ /* * Open the classes.conf file... */ snprintf(line, sizeof(line), "%s/classes.conf", ServerRoot); if ((fp = cupsFileOpen(line, "r")) == NULL) { if (errno != ENOENT) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line, strerror(errno)); return; } /* * Read class configurations until we hit EOF... */ linenum = 0; p = NULL; while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) { /* * Decode the directive... */ if (!strcasecmp(line, "<Class") || !strcasecmp(line, "<DefaultClass")) { /* * <Class name> or <DefaultClass name> */ if (p == NULL && value) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading class %s...", value); /* * Since prior classes may have implicitly defined this class, * see if it already exists... */ if ((p = cupsdFindDest(value)) != NULL) { p->type = CUPS_PRINTER_CLASS; cupsdSetStringf(&p->uri, "ipp://%s:%d/classes/%s", ServerName, LocalPort, value); cupsdSetString(&p->error_policy, "retry-job"); } else p = cupsdAddClass(value); p->accepting = 1; p->state = IPP_PRINTER_IDLE; if (!strcasecmp(line, "<DefaultClass")) DefaultPrinter = p; } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "</Class>")) { if (p != NULL) { cupsdSetPrinterAttrs(p); p = NULL; } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!p) { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "AuthInfoRequired")) { if (!cupsdSetAuthInfoRequired(p, value, NULL)) cupsdLogMessage(CUPSD_LOG_ERROR, "Bad AuthInfoRequired on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "Info")) { if (value) cupsdSetString(&p->info, value); } else if (!strcasecmp(line, "Location")) { if (value) cupsdSetString(&p->location, value); } else if (!strcasecmp(line, "Option") && value) { /* * Option name value */ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); if (!*valueptr) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); else { for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0'); p->num_options = cupsAddOption(value, valueptr, p->num_options, &(p->options)); } } else if (!strcasecmp(line, "Printer")) { if (!value) { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); continue; } else if ((temp = cupsdFindPrinter(value)) == NULL) { cupsdLogMessage(CUPSD_LOG_WARN, "Unknown printer %s on line %d of classes.conf.", value, linenum); /* * Add the missing remote printer... */ if ((temp = cupsdAddPrinter(value)) != NULL) { cupsdSetString(&temp->make_model, "Remote Printer on unknown"); temp->state = IPP_PRINTER_STOPPED; temp->type |= CUPS_PRINTER_REMOTE; temp->browse_time = 2147483647; cupsdSetString(&temp->location, "Location Unknown"); cupsdSetString(&temp->info, "No Information Available"); temp->hostname[0] = '\0'; cupsdSetPrinterAttrs(temp); } } if (temp) cupsdAddPrinterToClass(p, temp); } else if (!strcasecmp(line, "State")) { /* * Set the initial queue state... */ if (!strcasecmp(value, "idle")) p->state = IPP_PRINTER_IDLE; else if (!strcasecmp(value, "stopped")) { p->state = IPP_PRINTER_STOPPED; for (i = 0 ; i < p->num_reasons; i ++) if (!strcmp("paused", p->reasons[i])) break; if (i >= p->num_reasons && p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) { p->reasons[p->num_reasons] = _cupsStrAlloc("paused"); p->num_reasons ++; } } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "StateMessage")) { /* * Set the initial queue state message... */ if (value) strlcpy(p->state_message, value, sizeof(p->state_message)); } else if (!strcasecmp(line, "StateTime")) { /* * Set the state time... */ if (value) p->state_time = atoi(value); } else if (!strcasecmp(line, "Accepting")) { /* * Set the initial accepting state... */ if (value && (!strcasecmp(value, "yes") || !strcasecmp(value, "on") || !strcasecmp(value, "true"))) p->accepting = 1; else if (value && (!strcasecmp(value, "no") || !strcasecmp(value, "off") || !strcasecmp(value, "false"))) p->accepting = 0; else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "Shared")) { /* * Set the initial shared state... */ if (value && (!strcasecmp(value, "yes") || !strcasecmp(value, "on") || !strcasecmp(value, "true"))) p->shared = 1; else if (value && (!strcasecmp(value, "no") || !strcasecmp(value, "off") || !strcasecmp(value, "false"))) p->shared = 0; else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "JobSheets")) { /* * Set the initial job sheets... */ if (value) { for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); if (*valueptr) *valueptr++ = '\0'; cupsdSetString(&p->job_sheets[0], value); while (isspace(*valueptr & 255)) valueptr ++; if (*valueptr) { for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++); if (*valueptr) *valueptr = '\0'; cupsdSetString(&p->job_sheets[1], value); } } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "AllowUser")) { if (value) { p->deny_users = 0; cupsdAddPrinterUser(p, value); } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "DenyUser")) { if (value) { p->deny_users = 1; cupsdAddPrinterUser(p, value); } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "QuotaPeriod")) { if (value) p->quota_period = atoi(value); else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "PageLimit")) { if (value) p->page_limit = atoi(value); else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "KLimit")) { if (value) p->k_limit = atoi(value); else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "OpPolicy")) { if (value) { cupsd_policy_t *pol; /* Policy */ if ((pol = cupsdFindPolicy(value)) != NULL) { cupsdSetString(&p->op_policy, value); p->op_policy_ptr = pol; } else cupsdLogMessage(CUPSD_LOG_ERROR, "Bad policy \"%s\" on line %d of classes.conf", value, linenum); } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else if (!strcasecmp(line, "ErrorPolicy")) { if (value) { if (strcmp(value, "retry-current-job") && strcmp(value, "retry-job")) cupsdLogMessage(CUPSD_LOG_WARN, "ErrorPolicy %s ignored on line %d of classes.conf", value, linenum); } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of classes.conf.", linenum); } else { /* * Something else we don't understand... */ cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown configuration directive %s on line %d of classes.conf.", line, linenum); } } cupsFileClose(fp); }