/*
- * "$Id: subscriptions.c 6649 2007-07-11 21:46:42Z mike $"
+ * "$Id$"
*
- * Subscription routines for the Common UNIX Printing System (CUPS) scheduler.
+ * Subscription routines for the CUPS scheduler.
*
- * Copyright 2007 by Apple Inc.
- * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2014 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * Contents:
- *
- * cupsdAddEvent() - Add an event to the global event cache.
- * cupsdAddSubscription() - Add a new subscription object.
- * cupsdDeleteAllSubscriptions() - Delete all subscriptions.
- * cupsdDeleteSubscription() - Delete a subscription object.
- * cupsdEventName() - Return a single event name.
- * cupsdEventValue() - Return the event mask value for a name.
- * cupsdExpireSubscriptions() - Expire old subscription objects.
- * cupsdFindSubscription() - Find a subscription by ID.
- * cupsdLoadAllSubscriptions() - Load all subscriptions from the .conf file.
- * cupsdSaveAllSubscriptions() - Save all subscriptions to the .conf file.
- * cupsdStopAllNotifiers() - Stop all notifier processes.
- * cupsd_compare_subscriptions() - Compare two subscriptions.
- * cupsd_delete_event() - Delete a single event...
- * cupsd_send_dbus() - Send a DBUS notification...
- * cupsd_send_notification() - Send a notification for the specified
- * event.
- * cupsd_start_notifier() - Start a notifier subprocess...
- * cupsd_update_notifier() - Read messages from notifiers.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*/
/*
* Check if this subscription requires this event...
*/
- if ((sub->mask & event) != 0 &&
- (sub->dest == dest || !sub->dest) &&
- (sub->job == job || !sub->job))
+ if ((sub->mask & event) != 0 && (sub->dest == dest || !sub->dest || sub->job == job))
{
/*
* Need this event, so create a new event record...
temp->time = time(NULL);
temp->attrs = ippNew();
temp->job = job;
- temp->dest = dest;
+
+ if (dest)
+ temp->dest = dest;
+ else if (job)
+ temp->dest = dest = cupsdFindPrinter(job->dest);
/*
* Add common event notification attributes...
"notify-charset", NULL, "utf-8");
ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_LANGUAGE,
- "notify-natural-langugage", NULL, "en-US");
+ "notify-natural-language", NULL, "en-US");
ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
"notify-subscription-id", sub->id);
(const char * const *)dest->reasons);
ippAddBoolean(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
- "printer-is-accepting-jobs", dest->accepting);
+ "printer-is-accepting-jobs", (char)dest->accepting);
}
if (job)
}
if (temp)
- cupsdSaveAllSubscriptions();
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
else
cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...",
cupsdEventName(event));
"cupsdAddSubscription(mask=%x, dest=%p(%s), job=%p(%d), "
"uri=\"%s\")",
mask, dest, dest ? dest->name : "", job, job ? job->id : 0,
- uri);
+ uri ? uri : "(null)");
if (!Subscriptions)
Subscriptions = cupsArrayNew((cups_array_func_t)cupsd_compare_subscriptions,
* Limit the number of subscriptions...
*/
- if (cupsArrayCount(Subscriptions) >= MaxSubscriptions)
+ if (MaxSubscriptions > 0 && cupsArrayCount(Subscriptions) >= MaxSubscriptions)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAddSubscription: Reached MaxSubscriptions %d "
+ "(count=%d)", MaxSubscriptions,
+ cupsArrayCount(Subscriptions));
return (NULL);
+ }
+
+ if (MaxSubscriptionsPerJob > 0 && job)
+ {
+ int count; /* Number of job subscriptions */
+
+ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions),
+ count = 0;
+ temp;
+ temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if (temp->job == job)
+ count ++;
+
+ if (count >= MaxSubscriptionsPerJob)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAddSubscription: Reached MaxSubscriptionsPerJob %d "
+ "for job #%d (count=%d)", MaxSubscriptionsPerJob,
+ job->id, count);
+ return (NULL);
+ }
+ }
+
+ if (MaxSubscriptionsPerPrinter > 0 && dest)
+ {
+ int count; /* Number of printer subscriptions */
+
+ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions),
+ count = 0;
+ temp;
+ temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if (temp->dest == dest)
+ count ++;
+
+ if (count >= MaxSubscriptionsPerPrinter)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAddSubscription: Reached "
+ "MaxSubscriptionsPerPrinter %d for %s (count=%d)",
+ MaxSubscriptionsPerPrinter, dest->name, count);
+ return (NULL);
+ }
+ }
/*
* Allocate memory for this subscription...
cupsArrayAdd(Subscriptions, temp);
+ /*
+ * For RSS subscriptions, run the notifier immediately...
+ */
+
+ if (uri && !strncmp(uri, "rss:", 4))
+ cupsd_start_notifier(temp);
+
return (temp);
}
cupsd_subscription_t *sub, /* I - Subscription object */
int update) /* I - 1 = update subscriptions.conf */
{
- int i; /* Looping var */
-
-
/*
* Close the pipe to the notifier as needed...
*/
cupsdClearString(&(sub->owner));
cupsdClearString(&(sub->recipient));
- if (sub->events)
- {
- for (i = 0; i < sub->num_events; i ++)
- cupsd_delete_event(sub->events[i]);
-
- free(sub->events);
- }
+ cupsArrayDelete(sub->events);
free(sub);
*/
if (update)
- cupsdSaveAllSubscriptions();
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
}
case CUPSD_EVENT_PRINTER_MODIFIED :
return ("printer-modified");
+ case CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED :
+ return ("printer-queue-order-changed");
+
+ case CUPSD_EVENT_PRINTER_STATE :
case CUPSD_EVENT_PRINTER_STATE_CHANGED :
return ("printer-state-changed");
+ case CUPSD_EVENT_PRINTER_CONFIG :
case CUPSD_EVENT_PRINTER_CONFIG_CHANGED :
return ("printer-config-changed");
return ("job-progress");
case CUPSD_EVENT_JOB_STATE :
- return ("job-state");
-
case CUPSD_EVENT_JOB_STATE_CHANGED :
return ("job-state-changed");
return (CUPSD_EVENT_PRINTER_DELETED);
else if (!strcmp(name, "printer-modified"))
return (CUPSD_EVENT_PRINTER_MODIFIED);
+ else if (!strcmp(name, "printer-queue-order-changed"))
+ return (CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED);
else if (!strcmp(name, "printer-state-changed"))
return (CUPSD_EVENT_PRINTER_STATE_CHANGED);
else if (!strcmp(name, "printer-config-changed"))
return (CUPSD_EVENT_PRINTER_CONFIG_CHANGED);
else if (!strcmp(name, "printer-changed"))
return (CUPSD_EVENT_PRINTER_CHANGED);
- else if (!strcmp(name, "job-state"))
- return (CUPSD_EVENT_JOB_STATE);
else if (!strcmp(name, "job-created"))
return (CUPSD_EVENT_JOB_CREATED);
else if (!strcmp(name, "job-completed"))
curtime = time(NULL);
update = 0;
+ cupsdLogMessage(CUPSD_LOG_INFO, "Expiring subscriptions...");
+
for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
sub;
sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
}
if (update)
- cupsdSaveAllSubscriptions();
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
}
*/
snprintf(line, sizeof(line), "%s/subscriptions.conf", ServerRoot);
- if ((fp = cupsFileOpen(line, "r")) == NULL)
- {
- if (errno != ENOENT)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LoadAllSubscriptions: Unable to open %s - %s", line,
- strerror(errno));
+ if ((fp = cupsdOpenConfFile(line)) == NULL)
return;
- }
/*
* Read all of the lines from the file...
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
{
- if (!strcasecmp(line, "NextSubscriptionId") && value)
+ if (!_cups_strcasecmp(line, "NextSubscriptionId") && value)
{
/*
* NextSubscriptionId NNN
if (i >= NextSubscriptionId && i > 0)
NextSubscriptionId = i;
}
- else if (!strcasecmp(line, "<Subscription"))
+ else if (!_cups_strcasecmp(line, "<Subscription"))
{
/*
* <Subscription #>
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "</Subscription>"))
+ else if (!_cups_strcasecmp(line, "</Subscription>"))
{
if (!sub)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
if (delete_sub)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
}
- else if (!strcasecmp(line, "Events"))
+ else if (!_cups_strcasecmp(line, "Events"))
{
/*
* Events name
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
while (*value)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unknown event name \'%s\' on line %d of subscriptions.conf.",
value, linenum);
- return;
+ break;
}
value = valueptr;
}
}
- else if (!strcasecmp(line, "Owner"))
+ else if (!_cups_strcasecmp(line, "Owner"))
{
/*
* Owner
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "Recipient"))
+ else if (!_cups_strcasecmp(line, "Recipient"))
{
/*
* Recipient uri
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "JobId"))
+ else if (!_cups_strcasecmp(line, "JobId"))
{
/*
* JobId #
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "PrinterName"))
+ else if (!_cups_strcasecmp(line, "PrinterName"))
{
/*
* PrinterName name
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "UserData"))
+ else if (!_cups_strcasecmp(line, "UserData"))
{
/*
* UserData encoded-string
if (isxdigit(valueptr[0]) && isxdigit(valueptr[1]))
{
if (isdigit(valueptr[0]))
- sub->user_data[i] = (valueptr[0] - '0') << 4;
+ sub->user_data[i] = (unsigned char)((valueptr[0] - '0') << 4);
else
- sub->user_data[i] = (tolower(valueptr[0]) - 'a' + 10) << 4;
+ sub->user_data[i] = (unsigned char)((tolower(valueptr[0]) - 'a' + 10) << 4);
if (isdigit(valueptr[1]))
sub->user_data[i] |= valueptr[1] - '0';
break;
}
else
- sub->user_data[i] = *valueptr++;
+ sub->user_data[i] = (unsigned char)*valueptr++;
}
if (*valueptr)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "LeaseDuration"))
+ else if (!_cups_strcasecmp(line, "LeaseDuration"))
{
/*
* LeaseDuration #
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "Interval"))
+ else if (!_cups_strcasecmp(line, "Interval"))
{
/*
* Interval #
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "ExpirationTime"))
+ else if (!_cups_strcasecmp(line, "ExpirationTime"))
{
/*
* ExpirationTime #
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
- else if (!strcasecmp(line, "NextEventId"))
+ else if (!_cups_strcasecmp(line, "NextEventId"))
{
/*
* NextEventId #
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of subscriptions.conf.",
linenum);
- return;
+ break;
}
}
else
{
int i; /* Looping var */
cups_file_t *fp; /* subscriptions.conf file */
- char temp[1024]; /* Temporary string */
- char backup[1024]; /* subscriptions.conf.O file */
+ char filename[1024], /* subscriptions.conf filename */
+ temp[1024]; /* Temporary string */
cupsd_subscription_t *sub; /* Current subscription */
time_t curtime; /* Current time */
struct tm *curdate; /* Current date */
* Create the subscriptions.conf file...
*/
- snprintf(temp, sizeof(temp), "%s/subscriptions.conf", ServerRoot);
- snprintf(backup, sizeof(backup), "%s/subscriptions.conf.O", ServerRoot);
+ snprintf(filename, sizeof(filename), "%s/subscriptions.conf", ServerRoot);
- if (rename(temp, backup))
- {
- if (errno != ENOENT)
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup subscriptions.conf - %s",
- strerror(errno));
- }
-
- if ((fp = cupsFileOpen(temp, "w")) == NULL)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save subscriptions.conf - %s",
- strerror(errno));
-
- if (rename(backup, temp))
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to restore subscriptions.conf - %s",
- strerror(errno));
+ if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
return;
- }
- else
- cupsdLogMessage(CUPSD_LOG_INFO, "Saving subscriptions.conf...");
- /*
- * Restrict access to the file...
- */
-
- fchown(cupsFileNumber(fp), getuid(), Group);
- fchmod(cupsFileNumber(fp), ConfigFilePerm);
+ cupsdLogMessage(CUPSD_LOG_INFO, "Saving subscriptions.conf...");
/*
* Write a small header to the file...
cupsFilePuts(fp, "</Subscription>\n");
}
- cupsFileClose(fp);
+ cupsdCloseCreatedConfFile(fp, filename);
}
cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsd_send_notification(sub=%p(%d), event=%p(%s))\n",
+ "cupsd_send_notification(sub=%p(%d), event=%p(%s))",
sub, sub->id, event, cupsdEventName(event->event));
/*
if (!sub->events)
{
- sub->events = calloc(MaxEvents, sizeof(cupsd_event_t *));
+ sub->events = cupsArrayNew3((cups_array_func_t)NULL, NULL,
+ (cups_ahash_func_t)NULL, 0,
+ (cups_acopy_func_t)NULL,
+ (cups_afree_func_t)cupsd_delete_event);
if (!sub->events)
{
* Purge an old event as needed...
*/
- if (sub->num_events >= MaxEvents)
+ if (cupsArrayCount(sub->events) >= MaxEvents)
{
/*
* Purge the oldest event in the cache...
*/
- cupsd_delete_event(sub->events[0]);
+ cupsArrayRemove(sub->events, cupsArrayFirst(sub->events));
- sub->num_events --;
sub->first_event_id ++;
-
- memmove(sub->events, sub->events + 1,
- sub->num_events * sizeof(cupsd_event_t *));
}
/*
* event cache limit, we don't need to check for overflow here...
*/
- sub->events[sub->num_events] = event;
- sub->num_events ++;
+ cupsArrayAdd(sub->events, event);
/*
* Deliver the event...
*/
if (cupsdStartProcess(command, argv, envp, fds[0], -1, NotifierPipes[1],
- -1, -1, 0, DefaultProfile, &pid) < 0)
+ -1, -1, 0, DefaultProfile, NULL, &pid) < 0)
{
/*
* Error - can't fork!
while (cupsdStatBufUpdate(NotifierStatusBuffer, &loglevel,
message, sizeof(message)))
+ {
+ if (loglevel == CUPSD_LOG_INFO)
+ cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
+
if (!strchr(NotifierStatusBuffer->buffer, '\n'))
break;
+ }
}
/*
- * End of "$Id: subscriptions.c 6649 2007-07-11 21:46:42Z mike $".
+ * End of "$Id$".
*/