From: mike Date: Wed, 29 Dec 1999 02:15:43 +0000 (+0000) Subject: Changes to support multiple files per job. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bd84e0d14075c3216a40160da98718ff7f9d724e;p=thirdparty%2Fcups.git Changes to support multiple files per job. Added support for job persistence. Added support for create-job, send-document operations. Added start of get-devices and get-ppds. git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@833 7a7537e8-13f0-0310-91df-b6672ffda945 --- diff --git a/config.h.in b/config.h.in index d5da9906ef..e625a2557a 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,5 @@ /* - * "$Id: config.h.in,v 1.13 1999/12/15 15:18:04 mike Exp $" + * "$Id: config.h.in,v 1.14 1999/12/29 02:15:39 mike Exp $" * * Configuration file for the Common UNIX Printing System (CUPS). * @@ -35,8 +35,12 @@ */ #define CUPS_LOCALEDIR "/usr/lib/locale" -#define CUPS_SERVERROOT "/var/cups" +#define CUPS_SERVERROOT "/etc/cups" +#define CUPS_REQUESTS "/var/spool/cups" +#define CUPS_SERVERBIN "/var/cups" #define CUPS_DATADIR "/usr/share/cups" +#define CUPS_DOCDIR "/usr/share/doc/cups" + /* * Do we have various image libraries? @@ -112,5 +116,5 @@ #undef HAVE_WAIT3 /* - * End of "$Id: config.h.in,v 1.13 1999/12/15 15:18:04 mike Exp $". + * End of "$Id: config.h.in,v 1.14 1999/12/29 02:15:39 mike Exp $". */ diff --git a/cups/ipp.c b/cups/ipp.c index 9f8fdb1352..5e6f3a32d5 100644 --- a/cups/ipp.c +++ b/cups/ipp.c @@ -1,5 +1,5 @@ /* - * "$Id: ipp.c,v 1.27 1999/12/21 02:26:45 mike Exp $" + * "$Id: ipp.c,v 1.28 1999/12/29 02:15:40 mike Exp $" * * Internet Printing Protocol support functions for the Common UNIX * Printing System (CUPS). @@ -1206,6 +1206,17 @@ ippWrite(http_t *http, /* I - HTTP data */ DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n, attr->values[i].string.text)); + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + *bufptr++ = n >> 8; *bufptr++ = n; memcpy(bufptr, attr->values[i].string.text, n); @@ -1309,12 +1320,36 @@ ippWrite(http_t *http, /* I - HTTP data */ } n = strlen(attr->values[i].string.charset); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + *bufptr++ = n >> 8; *bufptr++ = n; memcpy(bufptr, attr->values[i].string.charset, n); bufptr += n; n = strlen(attr->values[i].string.text); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + *bufptr++ = n >> 8; *bufptr++ = n; memcpy(bufptr, attr->values[i].string.text, n); @@ -1453,5 +1488,5 @@ ipp_read(http_t *http, /* I - Client connection */ /* - * End of "$Id: ipp.c,v 1.27 1999/12/21 02:26:45 mike Exp $". + * End of "$Id: ipp.c,v 1.28 1999/12/29 02:15:40 mike Exp $". */ diff --git a/cups/ipp.h b/cups/ipp.h index e0090eb6a0..b182851f1f 100644 --- a/cups/ipp.h +++ b/cups/ipp.h @@ -1,5 +1,5 @@ /* - * "$Id: ipp.h,v 1.19 1999/10/12 17:10:04 mike Exp $" + * "$Id: ipp.h,v 1.20 1999/12/29 02:15:40 mike Exp $" * * Internet Printing Protocol definitions for the Common UNIX Printing * System (CUPS). @@ -193,7 +193,9 @@ typedef enum /**** IPP operations... ****/ CUPS_DELETE_CLASS, CUPS_ACCEPT_JOBS, CUPS_REJECT_JOBS, - CUPS_SET_DEFAULT + CUPS_SET_DEFAULT, + CUPS_GET_DEVICES, + CUPS_GET_PPDS } ipp_op_t; typedef enum /**** IPP status codes... ****/ @@ -339,5 +341,5 @@ extern int ippPort(void); #endif /* !_CUPS_IPP_H_ */ /* - * End of "$Id: ipp.h,v 1.19 1999/10/12 17:10:04 mike Exp $". + * End of "$Id: ipp.h,v 1.20 1999/12/29 02:15:40 mike Exp $". */ diff --git a/scheduler/client.c b/scheduler/client.c index 53dc27c2aa..1acc6b397b 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1,5 +1,5 @@ /* - * "$Id: client.c,v 1.40 1999/12/08 13:15:30 mike Exp $" + * "$Id: client.c,v 1.41 1999/12/29 02:15:40 mike Exp $" * * Client routines for the Common UNIX Printing System (CUPS) scheduler. * @@ -407,7 +407,7 @@ ReadClient(client_t *con) /* I - Client to read from */ return (0); } } - else if (strncmp(con->uri, "..", 2) == 0) + else if (strstr(con->uri, "..") != NULL) { /* * Protect against malicious users! @@ -464,7 +464,8 @@ ReadClient(client_t *con) /* I - Client to read from */ } } - if (strncmp(con->uri, "/printers", 9) == 0 || + if (strncmp(con->uri, "/admin", 6) == 0 || + strncmp(con->uri, "/printers", 9) == 0 || strncmp(con->uri, "/classes", 8) == 0 || strncmp(con->uri, "/jobs", 5) == 0) { @@ -472,19 +473,24 @@ ReadClient(client_t *con) /* I - Client to read from */ * Send CGI output... */ - if (strncmp(con->uri, "/printers", 9) == 0) + if (strncmp(con->uri, "/admin", 6) == 0) { - snprintf(command, sizeof(command), "%s/cgi-bin/printers.cgi", ServerRoot); + snprintf(command, sizeof(command), "%s/cgi-bin/admin.cgi", ServerBin); + options = con->uri + 9; + } + else if (strncmp(con->uri, "/printers", 9) == 0) + { + snprintf(command, sizeof(command), "%s/cgi-bin/printers.cgi", ServerBin); options = con->uri + 9; } else if (strncmp(con->uri, "/classes", 8) == 0) { - snprintf(command, sizeof(command), "%s/cgi-bin/classes.cgi", ServerRoot); + snprintf(command, sizeof(command), "%s/cgi-bin/classes.cgi", ServerBin); options = con->uri + 8; } else { - snprintf(command, sizeof(command), "%s/cgi-bin/jobs.cgi", ServerRoot); + snprintf(command, sizeof(command), "%s/cgi-bin/jobs.cgi", ServerBin); options = con->uri + 5; } @@ -575,7 +581,8 @@ ReadClient(client_t *con) /* I - Client to read from */ if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/ipp") == 0) con->request = ippNew(); else if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/x-www-form-urlencoded") == 0 && - (strncmp(con->uri, "/printers", 9) == 0 || + (strncmp(con->uri, "/admin", 6) == 0 || + strncmp(con->uri, "/printers", 9) == 0 || strncmp(con->uri, "/classes", 8) == 0 || strncmp(con->uri, "/jobs", 5) == 0)) { @@ -583,19 +590,24 @@ ReadClient(client_t *con) /* I - Client to read from */ * CGI request... */ - if (strncmp(con->uri, "/printers", 9) == 0) + if (strncmp(con->uri, "/admin", 9) == 0) + { + snprintf(command, sizeof(command), "%s/cgi-bin/admin.cgi", ServerBin); + options = con->uri + 9; + } + else if (strncmp(con->uri, "/printers", 9) == 0) { - snprintf(command, sizeof(command), "%s/cgi-bin/printers", ServerRoot); + snprintf(command, sizeof(command), "%s/cgi-bin/printers.cgi", ServerBin); options = con->uri + 9; } else if (strncmp(con->uri, "/classes", 8) == 0) { - snprintf(command, sizeof(command), "%s/cgi-bin/classes", ServerRoot); + snprintf(command, sizeof(command), "%s/cgi-bin/classes.cgi", ServerBin); options = con->uri + 8; } else { - snprintf(command, sizeof(command), "%s/cgi-bin/jobs", ServerRoot); + snprintf(command, sizeof(command), "%s/cgi-bin/jobs.cgi", ServerBin); options = con->uri + 5; } @@ -644,7 +656,8 @@ ReadClient(client_t *con) /* I - Client to read from */ strcpy(con->uri, command); } - if (strncmp(con->uri, "/printers/", 10) == 0 || + if (strncmp(con->uri, "/admin/", 7) == 0 || + strncmp(con->uri, "/printers/", 10) == 0 || strncmp(con->uri, "/classes/", 9) == 0 || strncmp(con->uri, "/jobs/", 6) == 0) { @@ -773,7 +786,7 @@ ReadClient(client_t *con) /* I - Client to read from */ * Create a file as needed for the request data... */ - snprintf(con->filename, sizeof(con->filename), "%s/requests/XXXXXX", ServerRoot); + snprintf(con->filename, sizeof(con->filename), "%s/XXXXXX", RequestRoot); con->file = mkstemp(con->filename); fchmod(con->file, 0640); fchown(con->file, User, Group); @@ -1044,7 +1057,7 @@ SendHeader(client_t *con, /* I - Client to send to */ return (0); if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0) return (0); - if (httpPrintf(HTTP(con), "Server: CUPS/1.0\r\n") < 0) + if (httpPrintf(HTTP(con), "Server: CUPS/1.1\r\n") < 0) return (0); if (con->http.keep_alive && con->http.version >= HTTP_1_0) { @@ -1429,7 +1442,7 @@ pipe_command(client_t *con, /* I - Client connection */ sprintf(tmpdir, "TMPDIR=%s", TempDir); envp[0] = "PATH=/bin:/usr/bin"; - envp[1] = "SERVER_SOFTWARE=CUPS/1.0"; + envp[1] = "SERVER_SOFTWARE=CUPS/1.1"; envp[2] = "GATEWAY_INTERFACE=CGI/1.1"; envp[3] = "SERVER_PROTOCOL=HTTP/1.1"; envp[4] = ipp_port; @@ -1533,5 +1546,5 @@ pipe_command(client_t *con, /* I - Client connection */ /* - * End of "$Id: client.c,v 1.40 1999/12/08 13:15:30 mike Exp $". + * End of "$Id: client.c,v 1.41 1999/12/29 02:15:40 mike Exp $". */ diff --git a/scheduler/conf.c b/scheduler/conf.c index bf433f82e8..44c1a3e6fd 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1,5 +1,5 @@ /* - * "$Id: conf.c,v 1.35 1999/12/07 18:10:18 mike Exp $" + * "$Id: conf.c,v 1.36 1999/12/29 02:15:41 mike Exp $" * * Configuration routines for the Common UNIX Printing System (CUPS). * @@ -75,7 +75,9 @@ static var_t variables[] = { "ServerName", ServerName, VAR_STRING, sizeof(ServerName) }, { "ServerAdmin", ServerAdmin, VAR_STRING, sizeof(ServerAdmin) }, { "ServerRoot", ServerRoot, VAR_STRING, sizeof(ServerRoot) }, + { "ServerBin", ServerBin, VAR_STRING, sizeof(ServerBin) }, { "DocumentRoot", DocumentRoot, VAR_STRING, sizeof(DocumentRoot) }, + { "RequestRoot", RequestRoot, VAR_STRING, sizeof(RequestRoot) }, { "SystemGroup", SystemGroup, VAR_STRING, sizeof(SystemGroup) }, { "AccessLog", AccessLog, VAR_STRING, sizeof(AccessLog) }, { "ErrorLog", ErrorLog, VAR_STRING, sizeof(ErrorLog) }, @@ -95,7 +97,9 @@ static var_t variables[] = { "BrowseTimeout", &BrowseTimeout, VAR_INTEGER, 0 }, { "MaxClients", &MaxClients, VAR_INTEGER, 0 }, { "MaxLogSize", &MaxLogSize, VAR_INTEGER, 0 }, - { "MaxRequestSize", &MaxRequestSize, VAR_INTEGER, 0 } + { "MaxRequestSize", &MaxRequestSize, VAR_INTEGER, 0 }, + { "PreserveJobHistory", &JobHistory, VAR_BOOLEAN, 0 }, + { "PreserveJobFiles", &JobFiles, VAR_BOOLEAN, 0 } }; #define NUM_VARS (sizeof(variables) / sizeof(variables[0])) @@ -140,6 +144,8 @@ ReadConfiguration(void) Clients = NULL; } + StopAllJobs(); + if (AccessFile != NULL) { fclose(AccessFile); @@ -170,7 +176,9 @@ ReadConfiguration(void) gethostname(ServerName, sizeof(ServerName)); sprintf(ServerAdmin, "root@%s", ServerName); strcpy(ServerRoot, CUPS_SERVERROOT); - strcpy(DocumentRoot, CUPS_DATADIR "/doc"); + strcpy(ServerBin, CUPS_SERVERBIN); + strcpy(RequestRoot, CUPS_REQUESTS); + strcpy(DocumentRoot, CUPS_DOCDIR); strcpy(AccessLog, "logs/access_log"); strcpy(ErrorLog, "logs/error_log"); @@ -270,6 +278,9 @@ ReadConfiguration(void) if (MimeDatabase != NULL) mimeDelete(MimeDatabase); + JobHistory = DEFAULT_HISTORY; + JobFiles = DEFAULT_FILES; + if ((fp = fopen(ConfigurationFile, "r")) == NULL) return (0); @@ -280,6 +291,24 @@ ReadConfiguration(void) if (!status) return (0); + if (DocumentRoot[0] != '/') + { + snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, DocumentRoot); + strcpy(DocumentRoot, directory); + } + + if (RequestRoot[0] != '/') + { + snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, RequestRoot); + strcpy(RequestRoot, directory); + } + + if (ServerBin[0] != '/') + { + snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, ServerBin); + strcpy(ServerBin, directory); + } + LogMessage(LOG_DEBUG, "ReadConfiguration() ConfigurationFile=\"%s\"", ConfigurationFile); @@ -306,17 +335,18 @@ ReadConfiguration(void) * Read the MIME type and conversion database... */ - sprintf(directory, "%s/conf", ServerRoot); + snprintf(directory, sizeof(directory), "%s/conf", ServerRoot); MimeDatabase = mimeNew(); mimeMerge(MimeDatabase, directory); /* - * Load printers and classes... + * Load printers, classes, and jobs... */ LoadAllPrinters(); LoadAllClasses(); + LoadAllJobs(); /* * Add a default browser if browsing is enabled and no browser addresses @@ -344,6 +374,7 @@ ReadConfiguration(void) * Check for queued jobs... */ + LoadJobs(); CheckJobs(); return (1); @@ -941,5 +972,5 @@ get_address(char *value, /* I - Value string */ /* - * End of "$Id: conf.c,v 1.35 1999/12/07 18:10:18 mike Exp $". + * End of "$Id: conf.c,v 1.36 1999/12/29 02:15:41 mike Exp $". */ diff --git a/scheduler/conf.h b/scheduler/conf.h index 047764163c..5e2513dbe9 100644 --- a/scheduler/conf.h +++ b/scheduler/conf.h @@ -1,5 +1,5 @@ /* - * "$Id: conf.h,v 1.16 1999/12/07 18:26:15 mike Exp $" + * "$Id: conf.h,v 1.17 1999/12/29 02:15:41 mike Exp $" * * Configuration file definitions for the Common UNIX Printing System (CUPS) * scheduler. @@ -47,6 +47,10 @@ VAR char ConfigurationFile[256] VALUE(CUPS_SERVERROOT "/conf/cupsd.conf"), /* Administrator's email */ ServerRoot[1024] VALUE(CUPS_SERVERROOT), /* Root directory for scheduler */ + ServerBin[1024] VALUE(CUPS_SERVERBIN), + /* Root directory for binaries */ + RequestRoot[1024] VALUE(CUPS_REQUESTS), + /* Directory for request files */ DocumentRoot[1024] VALUE(CUPS_DATADIR "/doc"), /* Root directory for documents */ SystemGroup[32], @@ -108,5 +112,5 @@ extern int LogPage(job_t *job, char *page); /* - * End of "$Id: conf.h,v 1.16 1999/12/07 18:26:15 mike Exp $". + * End of "$Id: conf.h,v 1.17 1999/12/29 02:15:41 mike Exp $". */ diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h index 7c7ed10b0f..8572d4c2b4 100644 --- a/scheduler/cupsd.h +++ b/scheduler/cupsd.h @@ -1,5 +1,5 @@ /* - * "$Id: cupsd.h,v 1.15 1999/12/07 18:26:15 mike Exp $" + * "$Id: cupsd.h,v 1.16 1999/12/29 02:15:41 mike Exp $" * * Main header file for the Common UNIX Printing System (CUPS) scheduler. * @@ -73,10 +73,13 @@ #define MAX_USERPASS 16 /* Maximum size of username/password */ #define MAX_FILTERS 20 /* Maximum number of filters */ + /* * Defaults... */ +#define DEFAULT_HISTORY 1 /* Preserve job history? */ +#define DEFAULT_FILES 0 /* Preserve job files? */ #define DEFAULT_TIMEOUT 300 /* Timeout during requests/updates */ #define DEFAULT_KEEPALIVE 60 /* Timeout between requests */ #define DEFAULT_INTERVAL 30 /* Interval between browse updates */ @@ -129,6 +132,11 @@ VAR int NeedReload VALUE(TRUE); VAR char TZ[1024] VALUE("TZ=GMT"); /* Timezone configuration */ +VAR ipp_t *Devices VALUE(NULL), + /* Available devices */ + *PPDs VALUE(NULL); + /* Available PPDs */ + /* * Prototypes... @@ -136,5 +144,5 @@ VAR char TZ[1024] VALUE("TZ=GMT"); /* - * End of "$Id: cupsd.h,v 1.15 1999/12/07 18:26:15 mike Exp $". + * End of "$Id: cupsd.h,v 1.16 1999/12/29 02:15:41 mike Exp $". */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c index ba2d8d043f..f1fa392afd 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,5 +1,5 @@ /* - * "$Id: ipp.c,v 1.37 1999/12/14 20:41:27 mike Exp $" + * "$Id: ipp.c,v 1.38 1999/12/29 02:15:41 mike Exp $" * * IPP routines for the Common UNIX Printing System (CUPS) scheduler. * @@ -64,14 +64,20 @@ static void add_printer(client_t *con, ipp_attribute_t *uri); static void cancel_all_jobs(client_t *con, ipp_attribute_t *uri); static void cancel_job(client_t *con, ipp_attribute_t *uri); static void copy_attrs(ipp_t *to, ipp_t *from, ipp_attribute_t *req); +static void create_job(client_t *con, ipp_attribute_t *uri); static void delete_printer(client_t *con, ipp_attribute_t *uri); static void get_default(client_t *con); +static void get_devices(client_t *con); static void get_jobs(client_t *con, ipp_attribute_t *uri); static void get_job_attrs(client_t *con, ipp_attribute_t *uri); +static void get_ppds(client_t *con); static void get_printers(client_t *con, int type); static void get_printer_attrs(client_t *con, ipp_attribute_t *uri); +static void hold_job(client_t *con, ipp_attribute_t *uri); static void print_job(client_t *con, ipp_attribute_t *uri); static void reject_jobs(client_t *con, ipp_attribute_t *uri); +static void restart_job(client_t *con, ipp_attribute_t *uri); +static void send_document(client_t *con, ipp_attribute_t *uri); static void send_ipp_error(client_t *con, ipp_status_t status); static void set_default(client_t *con, ipp_attribute_t *uri); static void start_printer(client_t *con, ipp_attribute_t *uri); @@ -136,7 +142,7 @@ ProcessIPPRequest(client_t *con) /* I - Client connection */ * Out of order; return an error... */ - DEBUG_puts("ProcessIPPRequest: attribute groups are out of order!"); + LogMessage(LOG_ERROR, "ProcessIPPRequest: attribute groups are out of order!"); send_ipp_error(con, IPP_BAD_REQUEST); break; } @@ -193,8 +199,15 @@ ProcessIPPRequest(client_t *con) /* I - Client connection */ * for all operations. */ - DEBUG_printf(("ProcessIPPRequest: missing attributes (%08x, %08x, %08x)!\n", - charset, language, uri)); + if (charset == NULL) + LogMessage(LOG_ERROR, "ProcessIPPRequest: missing attributes-charset attribute!"); + + if (language == NULL) + LogMessage(LOG_ERROR, "ProcessIPPRequest: missing attributes-natural-language attribute!"); + + if (uri == NULL) + LogMessage(LOG_ERROR, "ProcessIPPRequest: missing printer-uri or job-uri attribute!"); + send_ipp_error(con, IPP_BAD_REQUEST); } else @@ -213,6 +226,14 @@ ProcessIPPRequest(client_t *con) /* I - Client connection */ validate_job(con, uri); break; + case IPP_CREATE_JOB : + create_job(con, uri); + break; + + case IPP_SEND_DOCUMENT : + send_document(con, uri); + break; + case IPP_CANCEL_JOB : cancel_job(con, uri); break; @@ -229,6 +250,14 @@ ProcessIPPRequest(client_t *con) /* I - Client connection */ get_printer_attrs(con, uri); break; + case IPP_HOLD_JOB : + hold_job(con, uri); + break; + + case IPP_RESTART_JOB : + restart_job(con, uri); + break; + case IPP_PAUSE_PRINTER : stop_printer(con, uri); break; @@ -281,6 +310,14 @@ ProcessIPPRequest(client_t *con) /* I - Client connection */ set_default(con, uri); break; + case CUPS_GET_DEVICES : + get_devices(con); + break; + + case CUPS_GET_PPDS : + get_ppds(con); + break; + default : send_ipp_error(con, IPP_OPERATION_NOT_SUPPORTED); } @@ -929,8 +966,8 @@ cancel_all_jobs(client_t *con, /* I - Client connection */ if (strcmp(uri->name, "printer-uri") != 0) { - DEBUG_printf(("cancel_all_jobs: bad %s attribute \'%s\'!\n", - uri->name, uri->values[0].string.text)); + LogMessage(LOG_ERROR, "cancel_all_jobs: bad %s attribute \'%s\'!", + uri->name, uri->values[0].string.text); send_ipp_error(con, IPP_BAD_REQUEST); return; } @@ -1018,7 +1055,7 @@ cancel_job(client_t *con, /* I - Client connection */ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) { - DEBUG_puts("cancel_job: got a printer-uri attribute but no job-id!"); + LogMessage(LOG_ERROR, "cancel_job: got a printer-uri attribute but no job-id!"); send_ipp_error(con, IPP_BAD_REQUEST); return; } @@ -1039,8 +1076,8 @@ cancel_job(client_t *con, /* I - Client connection */ * Not a valid URI! */ - DEBUG_printf(("cancel_job: bad job-uri attribute \'%s\'!\n", - uri->values[0].string.text)); + LogMessage(LOG_ERROR, "cancel_job: bad job-uri attribute \'%s\'!", + uri->values[0].string.text); send_ipp_error(con, IPP_BAD_REQUEST); return; } @@ -1252,6 +1289,143 @@ copy_attrs(ipp_t *to, /* I - Destination request */ } +/* + * 'create_job()' - Print a file to a printer or class. + */ + +static void +create_job(client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + ipp_attribute_t *attr; /* Current attribute */ + char *dest; /* Destination */ + cups_ptype_t dtype; /* Destination type (printer or class) */ + int priority; /* Job priority */ + char *title; /* Job name/title */ + job_t *job; /* Current job */ + char job_uri[HTTP_MAX_URI], + /* Job URI */ + method[HTTP_MAX_URI], + /* Method portion of URI */ + username[HTTP_MAX_URI], + /* Username portion of URI */ + host[HTTP_MAX_URI], + /* Host portion of URI */ + resource[HTTP_MAX_URI]; + /* Resource portion of URI */ + int port; /* Port portion of URI */ + printer_t *printer; /* Printer data */ + + + DEBUG_printf(("create_job(%08x, %08x)\n", con, uri)); + + /* + * Verify that the POST operation was done to a valid URI. + */ + + if (strncmp(con->uri, "/classes/", 9) != 0 && + strncmp(con->uri, "/printers/", 10) != 0) + { + LogMessage(LOG_ERROR, "create_job: cancel request on bad resource \'%s\'!", + con->uri); + send_ipp_error(con, IPP_NOT_AUTHORIZED); + return; + } + + /* + * Is the destination valid? + */ + + httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); + + if ((dest = validate_dest(resource, &dtype)) == NULL) + { + /* + * Bad URI... + */ + + LogMessage(LOG_ERROR, "create_job: resource name \'%s\' no good!", resource); + send_ipp_error(con, IPP_NOT_FOUND); + return; + } + + /* + * See if the printer is accepting jobs... + */ + + if (dtype == CUPS_PRINTER_CLASS) + printer = FindClass(dest); + else + printer = FindPrinter(dest); + + if (!printer->accepting) + { + LogMessage(LOG_INFO, "create_job: destination \'%s\' is not accepting jobs.", + dest); + send_ipp_error(con, IPP_NOT_ACCEPTING); + return; + } + + /* + * Create the job and set things up... + */ + + if ((attr = ippFindAttribute(con->request, "job-priority", IPP_TAG_INTEGER)) != NULL) + priority = attr->values[0].integer; + else + priority = 50; + + if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL) + title = attr->values[0].string.text; + else + title = "Untitled"; + + if ((job = AddJob(priority, printer->name)) == NULL) + { + LogMessage(LOG_ERROR, "create_job: unable to add job for destination \'%s\'!", + dest); + send_ipp_error(con, IPP_INTERNAL_ERROR); + return; + } + + job->dtype = dtype; + job->attrs = con->request; + con->request = NULL; + + strncpy(job->title, title, sizeof(job->title) - 1); + + strcpy(job->username, con->username); + if ((attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME)) != NULL) + { + LogMessage(LOG_DEBUG, "create_job: requesting-user-name = \'%s\'", + attr->values[0].string.text); + + strncpy(job->username, attr->values[0].string.text, sizeof(job->username) - 1); + job->username[sizeof(job->username) - 1] = '\0'; + } + + if (job->username[0] == '\0') + strcpy(job->username, "guest"); + + LogMessage(LOG_INFO, "Job %d created on \'%s\' by \'%s\'.", job->id, + job->dest, job->username); + + /* + * Fill in the response info... + */ + + sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, + ntohs(con->http.hostaddr.sin_port), job->id); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); + + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); + + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state); + + con->response->request.status.status_code = IPP_OK; +} + + /* * 'delete_printer()' - Remove a printer or class from the system. */ @@ -1366,6 +1540,26 @@ get_default(client_t *con) /* I - Client connection */ } +/* + * 'get_devices()' - Get the list of available devices on the local system. + */ + +static void +get_devices(client_t *con) /* I - Client connection */ +{ + /* + * Copy the device attributes to the response using the requested-attributes + * attribute that may be provided by the client. + */ + + copy_attrs(con->response, Devices, + ippFindAttribute(con->request, "requested-attributes", + IPP_TAG_KEYWORD)); + + con->response->request.status.status_code = IPP_OK; +} + + /* * 'get_jobs()' - Get a list of jobs for the specified printer. */ @@ -1386,6 +1580,7 @@ get_jobs(client_t *con, /* I - Client connection */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ + int completed; /* Completed jobs? */ int limit; /* Maximum number of jobs to return */ int count; /* Number of jobs that match */ job_t *job; /* Current job pointer */ @@ -1433,10 +1628,9 @@ get_jobs(client_t *con, /* I - Client connection */ if ((attr = ippFindAttribute(con->request, "which-jobs", IPP_TAG_KEYWORD)) != NULL && strcmp(attr->values[0].string.text, "completed") == 0) - { - con->response->request.status.status_code = IPP_OK; - return; - } + completed = 1; + else + completed = 0; /* * See if they want to limit the number of jobs reported; if not, limit @@ -1486,6 +1680,11 @@ get_jobs(client_t *con, /* I - Client connection */ if (username[0] != '\0' && strcmp(username, job->username) != 0) continue; + if (completed && job->state <= IPP_JOB_STOPPED) + continue; + if (!completed && job->state > IPP_JOB_STOPPED) + continue; + count ++; DEBUG_printf(("get_jobs: count = %d\n", count)); @@ -1596,7 +1795,7 @@ get_job_attrs(client_t *con, /* I - Client connection */ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) { - DEBUG_puts("get_job_attrs: got a printer-uri attribute but no job-id!"); + LogMessage(LOG_ERROR, "get_job_attrs: got a printer-uri attribute but no job-id!"); send_ipp_error(con, IPP_BAD_REQUEST); return; } @@ -1617,8 +1816,8 @@ get_job_attrs(client_t *con, /* I - Client connection */ * Not a valid URI! */ - DEBUG_printf(("get_job_attrs: bad job-uri attribute \'%s\'!\n", - uri->values[0].string.text)); + LogMessage(LOG_ERROR, "get_job_attrs: bad job-uri attribute \'%s\'!\n", + uri->values[0].string.text); send_ipp_error(con, IPP_BAD_REQUEST); return; } @@ -1636,7 +1835,7 @@ get_job_attrs(client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - DEBUG_printf(("get_job_attrs: job #%d doesn't exist!\n", jobid)); + LogMessage(LOG_ERROR, "get_job_attrs: job #%d doesn't exist!", jobid); send_ipp_error(con, IPP_NOT_FOUND); return; } @@ -1692,6 +1891,26 @@ get_job_attrs(client_t *con, /* I - Client connection */ } +/* + * 'get_ppds()' - Get the list of PPD files on the local system. + */ + +static void +get_ppds(client_t *con) /* I - Client connection */ +{ + /* + * Copy the PPD attributes to the response using the requested-attributes + * attribute that may be provided by the client. + */ + + copy_attrs(con->response, PPDs, + ippFindAttribute(con->request, "requested-attributes", + IPP_TAG_KEYWORD)); + + con->response->request.status.status_code = IPP_OK; +} + + /* * 'get_printers()' - Get a list of printers. */ @@ -1843,23 +2062,17 @@ get_printer_attrs(client_t *con, /* I - Client connection */ /* - * 'print_job()' - Print a file to a printer or class. + * 'hold_job()' - Cancel a print job. */ static void -print_job(client_t *con, /* I - Client connection */ - ipp_attribute_t *uri) /* I - Printer URI */ +hold_job(client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job or Printer URI */ { + int i; /* Looping var */ ipp_attribute_t *attr; /* Current attribute */ - ipp_attribute_t *format; /* Document-format attribute */ - char *dest; /* Destination */ - cups_ptype_t dtype; /* Destination type (printer or class) */ - int priority; /* Job priority */ - char *title; /* Job name/title */ - job_t *job; /* Current job */ - char job_uri[HTTP_MAX_URI], - /* Job URI */ - method[HTTP_MAX_URI], + int jobid; /* Job ID */ + char method[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ @@ -1868,98 +2081,264 @@ print_job(client_t *con, /* I - Client connection */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ - mime_type_t *filetype; /* Type of file */ - char super[MIME_MAX_SUPER], - /* Supertype of file */ - type[MIME_MAX_TYPE], - /* Subtype of file */ - mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; - /* Textual name of mime type */ - printer_t *printer; /* Printer data */ + job_t *job; /* Job information */ + struct passwd *user; /* User info */ + struct group *group; /* System group info */ - DEBUG_printf(("print_job(%08x, %08x)\n", con, uri)); + DEBUG_printf(("hold_job(%08x, %08x)\n", con, uri)); /* * Verify that the POST operation was done to a valid URI. */ if (strncmp(con->uri, "/classes/", 9) != 0 && + strncmp(con->uri, "/jobs/", 5) != 0 && strncmp(con->uri, "/printers/", 10) != 0) { - LogMessage(LOG_ERROR, "print_job: cancel request on bad resource \'%s\'!", + LogMessage(LOG_ERROR, "hold_job: hold request on bad resource \'%s\'!", con->uri); send_ipp_error(con, IPP_NOT_AUTHORIZED); return; } /* - * OK, see if the client is sending the document compressed - CUPS - * doesn't support compression yet... - */ - - if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) - { - DEBUG_puts("print_job: Unsupported compression attribute!"); - send_ipp_error(con, IPP_ATTRIBUTES); - attr = ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, - "compression", NULL, attr->values[0].string.text); - return; - } - - /* - * Do we have a file to print? - */ - - if (con->filename[0] == '\0') - { - DEBUG_puts("print_job: No filename!?!"); - send_ipp_error(con, IPP_BAD_REQUEST); - return; - } - - /* - * Is it a format we support? + * See if we have a job URI or a printer URI... */ - if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) + if (strcmp(uri->name, "printer-uri") == 0) { /* - * Grab format from client... + * Got a printer URI; see if we also have a job-id attribute... */ - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) { - DEBUG_printf(("print_job: could not scan type \'%s\'!\n", - format->values[0].string.text)); + LogMessage(LOG_ERROR, "hold_job: got a printer-uri attribute but no job-id!"); send_ipp_error(con, IPP_BAD_REQUEST); return; } - } - else - { - /* - * No document format attribute? Auto-type it! - */ - strcpy(super, "application"); - strcpy(type, "octet-stream"); + jobid = attr->values[0].integer; } - - if (strcmp(super, "application") == 0 && - strcmp(type, "octet-stream") == 0) + else { /* - * Auto-type the file... + * Got a job URI; parse it to get the job ID... */ - DEBUG_puts("print_job: auto-typing request using magic rules."); - filetype = mimeFileType(MimeDatabase, con->filename); - - if (filetype != NULL) + httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); + + if (strncmp(resource, "/jobs/", 6) != 0) { /* - * Replace the document-format attribute value with the auto-typed one. + * Not a valid URI! + */ + + LogMessage(LOG_ERROR, "hold_job: bad job-uri attribute \'%s\'!", + uri->values[0].string.text); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = FindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + LogMessage(LOG_ERROR, "hold_job: job #%d doesn't exist!", jobid); + send_ipp_error(con, IPP_NOT_FOUND); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) + { + strncpy(username, attr->values[0].string.text, sizeof(username) - 1); + username[sizeof(username) - 1] = '\0'; + } + else if (con->username[0]) + strcpy(username, con->username); + else + username[0] = '\0'; + + if (strcmp(username, job->username) != 0 && strcmp(username, "root") != 0) + { + /* + * Not the owner or root; check to see if the user is a member of the + * system group... + */ + + user = getpwnam(username); + endpwent(); + + group = getgrnam(SystemGroup); + endgrent(); + + if (group != NULL) + for (i = 0; group->gr_mem[i]; i ++) + if (strcmp(username, group->gr_mem[i]) == 0) + break; + + if (user == NULL || group == NULL || + (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid)) + { + /* + * Username not found, group not found, or user is not part of the + * system group... + */ + + LogMessage(LOG_ERROR, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!", + username, jobid, job->username); + send_ipp_error(con, IPP_FORBIDDEN); + return; + } + } + + /* + * Hold the job and return... + */ + + HoldJob(jobid); + + LogMessage(LOG_INFO, "Job %d was held by \'%s\'.", jobid, + con->username[0] ? con->username : "unknown"); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'print_job()' - Print a file to a printer or class. + */ + +static void +print_job(client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + ipp_attribute_t *attr; /* Current attribute */ + ipp_attribute_t *format; /* Document-format attribute */ + char *dest; /* Destination */ + cups_ptype_t dtype; /* Destination type (printer or class) */ + int priority; /* Job priority */ + char *title; /* Job name/title */ + job_t *job; /* Current job */ + char job_uri[HTTP_MAX_URI], + /* Job URI */ + method[HTTP_MAX_URI], + /* Method portion of URI */ + username[HTTP_MAX_URI], + /* Username portion of URI */ + host[HTTP_MAX_URI], + /* Host portion of URI */ + resource[HTTP_MAX_URI], + /* Resource portion of URI */ + filename[1024]; /* Job filename */ + int port; /* Port portion of URI */ + mime_type_t *filetype; /* Type of file */ + char super[MIME_MAX_SUPER], + /* Supertype of file */ + type[MIME_MAX_TYPE], + /* Subtype of file */ + mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; + /* Textual name of mime type */ + printer_t *printer; /* Printer data */ + + + DEBUG_printf(("print_job(%08x, %08x)\n", con, uri)); + + /* + * Verify that the POST operation was done to a valid URI. + */ + + if (strncmp(con->uri, "/classes/", 9) != 0 && + strncmp(con->uri, "/printers/", 10) != 0) + { + LogMessage(LOG_ERROR, "print_job: cancel request on bad resource \'%s\'!", + con->uri); + send_ipp_error(con, IPP_NOT_AUTHORIZED); + return; + } + + /* + * OK, see if the client is sending the document compressed - CUPS + * doesn't support compression yet... + */ + + if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) + { + LogMessage(LOG_ERROR, "print_job: Unsupported compression attribute!"); + send_ipp_error(con, IPP_ATTRIBUTES); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, + "compression", NULL, attr->values[0].string.text); + return; + } + + /* + * Do we have a file to print? + */ + + if (con->filename[0] == '\0') + { + LogMessage(LOG_ERROR, "print_job: No file!?!"); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + + /* + * Is it a format we support? + */ + + if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) + { + /* + * Grab format from client... + */ + + if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) + { + LogMessage(LOG_ERROR, "print_job: could not scan type \'%s\'!", + format->values[0].string.text); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + } + else + { + /* + * No document format attribute? Auto-type it! + */ + + strcpy(super, "application"); + strcpy(type, "octet-stream"); + } + + if (strcmp(super, "application") == 0 && + strcmp(type, "octet-stream") == 0) + { + /* + * Auto-type the file... + */ + + LogMessage(LOG_DEBUG, "print_job: auto-typing file..."); + + filetype = mimeFileType(MimeDatabase, con->filename); + + if (filetype != NULL) + { + /* + * Replace the document-format attribute value with the auto-typed one. */ sprintf(mimetype, "%s/%s", filetype->super, filetype->type); @@ -1979,16 +2358,16 @@ print_job(client_t *con, /* I - Client connection */ if (filetype == NULL) { - DEBUG_printf(("print_job: Unsupported format \'%s\'!\n", - format->values[0].string.text)); + LogMessage(LOG_ERROR, "print_job: Unsupported format \'%s\'!", + format->values[0].string.text); send_ipp_error(con, IPP_DOCUMENT_FORMAT); - attr = ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, - "document-format", NULL, format->values[0].string.text); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, + "document-format", NULL, format->values[0].string.text); return; } - DEBUG_printf(("print_job: request file type is %s/%s.\n", - filetype->super, filetype->type)); + LogMessage(LOG_DEBUG, "print_job: request file type is %s/%s.", + filetype->super, filetype->type); /* * Is the destination valid? @@ -2048,11 +2427,24 @@ print_job(client_t *con, /* I - Client connection */ job->dtype = dtype; job->state = IPP_JOB_PENDING; - job->filetype = filetype; job->attrs = con->request; con->request = NULL; - strcpy(job->filename, con->filename); + if ((filetypes = (mimetype_t **)malloc(sizeof(mimetype_t *))) == NULL) + { + CancelJob(job->id); + LogMessage(LOG_ERROR, "print_job: unable to allocate memory for file types!"); + send_ipp_error(con, IPP_INTERNAL_ERROR); + return; + } + + job->filetypes = filetypes; + job->filetypes[job->num_files] = filetype; + + job->num_files ++; + sprintf(filename, "%s/d%05d-%03d", RequestRoot, job->id, job->num_files); + rename(con->filename, filename); + strncpy(job->title, title, sizeof(job->title) - 1); con->filename[0] = '\0'; @@ -2060,8 +2452,8 @@ print_job(client_t *con, /* I - Client connection */ strcpy(job->username, con->username); if ((attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME)) != NULL) { - DEBUG_printf(("print_job: requesting-user-name = \'%s\'\n", - attr->values[0].string.text)); + LogMessage(LOG_DEBUG, "print_job: requesting-user-name = \'%s\'", + attr->values[0].string.text); strncpy(job->username, attr->values[0].string.text, sizeof(job->username) - 1); job->username[sizeof(job->username) - 1] = '\0'; @@ -2070,8 +2462,8 @@ print_job(client_t *con, /* I - Client connection */ if (job->username[0] == '\0') strcpy(job->username, "guest"); - DEBUG_printf(("print_job: job->username = \'%s\', attr = %08x\n", - job->username, attr)); + LogMessage(LOG_INFO, "Job %d queued on \'%s\' by \'%s\'.", job->id, + job->dest, job->username); /* * Start the job if possible... @@ -2079,23 +2471,17 @@ print_job(client_t *con, /* I - Client connection */ CheckJobs(); - LogMessage(LOG_INFO, "Job %d queued on \'%s\' by \'%s\'.", job->id, - job->dest, job->username); - /* * Fill in the response info... */ sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, ntohs(con->http.hostaddr.sin_port), job->id); - attr = ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", - NULL, job_uri); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); - attr = ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "job-id", job->id); + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); - attr = ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, - "job-state", job->state); + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state); con->response->request.status.status_code = IPP_OK; } @@ -2191,6 +2577,469 @@ reject_jobs(client_t *con, /* I - Client connection */ } +/* + * 'restart_job()' - Cancel a print job. + */ + +static void +restart_job(client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job or Printer URI */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* Current attribute */ + int jobid; /* Job ID */ + char method[HTTP_MAX_URI], + /* Method portion of URI */ + username[HTTP_MAX_URI], + /* Username portion of URI */ + host[HTTP_MAX_URI], + /* Host portion of URI */ + resource[HTTP_MAX_URI]; + /* Resource portion of URI */ + int port; /* Port portion of URI */ + job_t *job; /* Job information */ + struct passwd *user; /* User info */ + struct group *group; /* System group info */ + + + DEBUG_printf(("restart_job(%08x, %08x)\n", con, uri)); + + /* + * Verify that the POST operation was done to a valid URI. + */ + + if (strncmp(con->uri, "/classes/", 9) != 0 && + strncmp(con->uri, "/jobs/", 5) != 0 && + strncmp(con->uri, "/printers/", 10) != 0) + { + LogMessage(LOG_ERROR, "restart_job: restart request on bad resource \'%s\'!", + con->uri); + send_ipp_error(con, IPP_NOT_AUTHORIZED); + return; + } + + /* + * See if we have a job URI or a printer URI... + */ + + if (strcmp(uri->name, "printer-uri") == 0) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + LogMessage(LOG_ERROR, "restart_job: got a printer-uri attribute but no job-id!"); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); + + if (strncmp(resource, "/jobs/", 6) != 0) + { + /* + * Not a valid URI! + */ + + LogMessage(LOG_ERROR, "restart_job: bad job-uri attribute \'%s\'!", + uri->values[0].string.text); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = FindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + LogMessage(LOG_ERROR, "restart_job: job #%d doesn't exist!", jobid); + send_ipp_error(con, IPP_NOT_FOUND); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) + { + strncpy(username, attr->values[0].string.text, sizeof(username) - 1); + username[sizeof(username) - 1] = '\0'; + } + else if (con->username[0]) + strcpy(username, con->username); + else + username[0] = '\0'; + + if (strcmp(username, job->username) != 0 && strcmp(username, "root") != 0) + { + /* + * Not the owner or root; check to see if the user is a member of the + * system group... + */ + + user = getpwnam(username); + endpwent(); + + group = getgrnam(SystemGroup); + endgrent(); + + if (group != NULL) + for (i = 0; group->gr_mem[i]; i ++) + if (strcmp(username, group->gr_mem[i]) == 0) + break; + + if (user == NULL || group == NULL || + (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid)) + { + /* + * Username not found, group not found, or user is not part of the + * system group... + */ + + LogMessage(LOG_ERROR, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!", + username, jobid, job->username); + send_ipp_error(con, IPP_FORBIDDEN); + return; + } + } + + /* + * Restart the job and return... + */ + + RestartJob(jobid); + + LogMessage(LOG_INFO, "Job %d was restarted by \'%s\'.", jobid, + con->username[0] ? con->username : "unknown"); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'send_document()' - Send a file to a printer or class. + */ + +static void +send_document(client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + ipp_attribute_t *attr; /* Current attribute */ + ipp_attribute_t *format; /* Document-format attribute */ + char *dest; /* Destination */ + cups_ptype_t dtype; /* Destination type (printer or class) */ + int priority; /* Job priority */ + char *title; /* Job name/title */ + int jobid; /* Job ID number */ + job_t *job; /* Current job */ + char job_uri[HTTP_MAX_URI], + /* Job URI */ + method[HTTP_MAX_URI], + /* Method portion of URI */ + username[HTTP_MAX_URI], + /* Username portion of URI */ + host[HTTP_MAX_URI], + /* Host portion of URI */ + resource[HTTP_MAX_URI]; + /* Resource portion of URI */ + int port; /* Port portion of URI */ + mime_type_t *filetype, /* Type of file */ + **filetypes; /* File types array */ + char super[MIME_MAX_SUPER], + /* Supertype of file */ + type[MIME_MAX_TYPE], + /* Subtype of file */ + mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; + /* Textual name of mime type */ + printer_t *printer; /* Printer data */ + + + DEBUG_printf(("send_document(%08x, %08x)\n", con, uri)); + + /* + * Verify that the POST operation was done to a valid URI. + */ + + if (strncmp(con->uri, "/classes/", 9) != 0 && + strncmp(con->uri, "/jobs/", 6) != 0 && + strncmp(con->uri, "/printers/", 10) != 0) + { + LogMessage(LOG_ERROR, "send_document: print request on bad resource \'%s\'!", + con->uri); + send_ipp_error(con, IPP_NOT_AUTHORIZED); + return; + } + + /* + * See if we have a job URI or a printer URI... + */ + + if (strcmp(uri->name, "printer-uri") == 0) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + LogMessage(LOG_ERROR, "send_document: got a printer-uri attribute but no job-id!"); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); + + if (strncmp(resource, "/jobs/", 6) != 0) + { + /* + * Not a valid URI! + */ + + LogMessage(LOG_ERROR, "send_document: bad job-uri attribute \'%s\'!", + uri->values[0].string.text); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = FindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + LogMessage(LOG_ERROR, "send_document: job #%d doesn't exist!", jobid); + send_ipp_error(con, IPP_NOT_FOUND); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) + { + strncpy(username, attr->values[0].string.text, sizeof(username) - 1); + username[sizeof(username) - 1] = '\0'; + } + else if (con->username[0]) + strcpy(username, con->username); + else + username[0] = '\0'; + + if (strcmp(username, job->username) != 0 && strcmp(username, "root") != 0) + { + /* + * Not the owner or root; check to see if the user is a member of the + * system group... + */ + + user = getpwnam(username); + endpwent(); + + group = getgrnam(SystemGroup); + endgrent(); + + if (group != NULL) + for (i = 0; group->gr_mem[i]; i ++) + if (strcmp(username, group->gr_mem[i]) == 0) + break; + + if (user == NULL || group == NULL || + (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid)) + { + /* + * Username not found, group not found, or user is not part of the + * system group... + */ + + LogMessage(LOG_ERROR, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!", + username, jobid, job->username); + send_ipp_error(con, IPP_FORBIDDEN); + return; + } + } + + /* + * OK, see if the client is sending the document compressed - CUPS + * doesn't support compression yet... + */ + + if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) + { + LogMessage(LOG_ERROR, "send_document: Unsupported compression attribute!"); + send_ipp_error(con, IPP_ATTRIBUTES); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, + "compression", NULL, attr->values[0].string.text); + return; + } + + /* + * Do we have a file to print? + */ + + if (con->filename[0] == '\0') + { + LogMessage(LOG_ERROR, "send_document: No file!?!"); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + + /* + * Is it a format we support? + */ + + if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) + { + /* + * Grab format from client... + */ + + if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) + { + LogMessage(LOG_ERROR, "send_document: could not scan type \'%s\'!", + format->values[0].string.text); + send_ipp_error(con, IPP_BAD_REQUEST); + return; + } + } + else + { + /* + * No document format attribute? Auto-type it! + */ + + strcpy(super, "application"); + strcpy(type, "octet-stream"); + } + + if (strcmp(super, "application") == 0 && + strcmp(type, "octet-stream") == 0) + { + /* + * Auto-type the file... + */ + + LogMessage(LOG_DEBUG, "send_document: auto-typing file..."); + + filetype = mimeFileType(MimeDatabase, con->filename); + + if (filetype != NULL) + { + /* + * Replace the document-format attribute value with the auto-typed one. + */ + + sprintf(mimetype, "%s/%s", filetype->super, filetype->type); + + if (format != NULL) + { + free(format->values[0].string.text); + format->values[0].string.text = strdup(mimetype); + } + else + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, + "document-format", NULL, mimetype); + } + } + else + filetype = mimeType(MimeDatabase, super, type); + + if (filetype == NULL) + { + LogMessage(LOG_ERROR, "send_document: Unsupported format \'%s\'!", + format->values[0].string.text); + send_ipp_error(con, IPP_DOCUMENT_FORMAT); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, + "document-format", NULL, format->values[0].string.text); + return; + } + + LogMessage(LOG_DEBUG, "send_document: request file type is %s/%s.", + filetype->super, filetype->type); + + /* + * Add the file to the job... + */ + + if (job->num_files == 0) + filetypes = (mimetype_t **)malloc(sizeof(mimetype_t *)); + else + filetypes = (mimetype_t **)realloc(job->filetypes, + (job->num_files + 1) * + sizeof(mimetype_t)); + + if (filetypes == NULL) + { + CancelJob(job->id); + LogMessage(LOG_ERROR, "send_document: unable to allocate memory for file types!"); + send_ipp_error(con, IPP_INTERNAL_ERROR); + return; + } + + job->filetypes = filetypes; + job->filetypes[job->num_files] = filetype; + + job->num_files ++; + sprintf(filename, "%s/d%05d-%03d", RequestRoot, job->id, job->num_files); + rename(con->filename, filename); + + strncpy(job->title, title, sizeof(job->title) - 1); + + con->filename[0] = '\0'; + + LogMessage(LOG_INFO, "File queued in job #%d by \'%s\'.", job->id, + job->username); + + /* + * Fill in the response info... + */ + + sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, + ntohs(con->http.hostaddr.sin_port), job->id); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); + + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); + + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state); + + con->response->request.status.status_code = IPP_OK; +} + + /* * 'send_ipp_error()' - Send an error status back to the IPP client. */ @@ -2557,10 +3406,10 @@ validate_job(client_t *con, /* I - Client connection */ if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) { - DEBUG_puts("validate_job: Unsupported compression attribute!"); + LogMessage(LOG_ERROR, "validate_job: Unsupported compression attribute!"); send_ipp_error(con, IPP_ATTRIBUTES); - attr = ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, - "compression", NULL, attr->values[0].string.text); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, + "compression", NULL, attr->values[0].string.text); return; } @@ -2570,15 +3419,15 @@ validate_job(client_t *con, /* I - Client connection */ if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) == NULL) { - DEBUG_puts("validate_job: missing document-format attribute!"); + LogError(LOG_ERROR, "validate_job: missing document-format attribute!"); send_ipp_error(con, IPP_BAD_REQUEST); return; } if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) { - DEBUG_printf(("validate_job: could not scan type \'%s\'!\n", - format->values[0].string.text)); + LogMessage(LOG_ERROR, "validate_job: could not scan type \'%s\'!\n", + format->values[0].string.text); send_ipp_error(con, IPP_BAD_REQUEST); return; } @@ -2587,11 +3436,11 @@ validate_job(client_t *con, /* I - Client connection */ strcmp(type, "octet-stream") != 0) && mimeType(MimeDatabase, super, type) == NULL) { - DEBUG_printf(("validate_job: Unsupported format \'%s\'!\n", - format->values[0].string.text)); + LogMessage(LOG_ERROR, "validate_job: Unsupported format \'%s\'!\n", + format->values[0].string.text); send_ipp_error(con, IPP_DOCUMENT_FORMAT); - attr = ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, - "document-format", NULL, format->values[0].string.text); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, + "document-format", NULL, format->values[0].string.text); return; } @@ -2621,5 +3470,5 @@ validate_job(client_t *con, /* I - Client connection */ /* - * End of "$Id: ipp.c,v 1.37 1999/12/14 20:41:27 mike Exp $". + * End of "$Id: ipp.c,v 1.38 1999/12/29 02:15:41 mike Exp $". */ diff --git a/scheduler/job.c b/scheduler/job.c index 82ad65b9cb..23ad091e56 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1,5 +1,5 @@ /* - * "$Id: job.c,v 1.43 1999/12/21 02:26:48 mike Exp $" + * "$Id: job.c,v 1.44 1999/12/29 02:15:42 mike Exp $" * * Job management routines for the Common UNIX Printing System (CUPS). * @@ -23,17 +23,25 @@ * * Contents: * - * AddJob() - Add a new job to the job queue... - * CancelJob() - Cancel the specified print job. - * CancelJobs() - Cancel all jobs on the given printer or class. - * CheckJobs() - Check the pending jobs and start any if the destination - * is available. - * FindJob() - Find the specified job. - * MoveJob() - Move the specified job to a different destination. - * StartJob() - Start a print job. - * StopJob() - Stop a print job. - * UpdateJob() - Read a status update from a job's filters. - * start_process() - Start a background process. + * AddJob() - Add a new job to the job queue... + * CancelJob() - Cancel the specified print job. + * CancelJobs() - Cancel all jobs on the given printer or class. + * CheckJobs() - Check the pending jobs and start any if the destination + * is available. + * FindJob() - Find the specified job. + * HoldJob() - Hold the specified job. + * LoadAllJobs() - Load all jobs from disk. + * LoadJob() - Load a job from disk. + * MoveJob() - Move the specified job to a different destination. + * RestartJob() - Resume the specified job. + * SaveJob() - Save a job to disk. + * StartJob() - Start a print job. + * StopAllJobs() - Stop all print jobs. + * StopJob() - Stop a print job. + * UpdateJob() - Read a status update from a job's filters. + * ipp_read_file() - Read an IPP request from a file. + * ipp_write_file() - Write an IPP request to a file. + * start_process() - Start a background process. */ /* @@ -47,21 +55,23 @@ * Local functions... */ -static int start_process(char *command, char *argv[], char *envp[], - int in, int out, int err); +static ipp_state_t ipp_read_file(const char *filename, ipp_t *request); +static ipp_state_t ipp_write_file(const char *filename, ipp_t *request); +static int start_process(const char *command, const char *argv[], + const char *envp[], int in, int out, int err); /* * 'AddJob()' - Add a new job to the job queue... */ -job_t * /* O - New job record */ -AddJob(int priority, /* I - Job priority */ - char *dest) /* I - Job destination */ +job_t * /* O - New job record */ +AddJob(int priority, /* I - Job priority */ + const char *dest) /* I - Job destination */ { - job_t *job, /* New job record */ - *current, /* Current job in queue */ - *prev; /* Previous job in queue */ + job_t *job, /* New job record */ + *current, /* Current job in queue */ + *prev; /* Previous job in queue */ job = calloc(sizeof(job_t), 1); @@ -92,10 +102,12 @@ AddJob(int priority, /* I - Job priority */ */ void -CancelJob(int id) /* I - Job to cancel */ +CancelJob(int id) /* I - Job to cancel */ { - job_t *current, /* Current job */ - *prev; /* Previous job in list */ + int i; /* Looping var */ + job_t *current, /* Current job */ + *prev; /* Previous job in list */ + char filename[1024]; /* Job filename */ DEBUG_printf(("CancelJob(%d)\n", id)); @@ -110,30 +122,53 @@ CancelJob(int id) /* I - Job to cancel */ DEBUG_puts("CancelJob: found job in list."); if (current->state == IPP_JOB_PROCESSING) + { StopJob(current->id); + current->state = IPP_JOB_CANCELLED; + } /* - * Update pointers... + * Remove the print file for good if we aren't preserving jobs or + * files... */ - if (prev == NULL) - Jobs = current->next; + if (!JobHistory || !JobFiles) + for (i = 1; i <= current->num_files; i ++) + { + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, + current->id, i); + unlink(filename); + } + + if (JobHistory) + { + /* + * Save job state info... + */ + + SaveJob(current->id); + } else - prev->next = current->next; + { + /* + * Update pointers if we aren't preserving jobs... + */ - /* - * Free all memory used... - */ + if (prev == NULL) + Jobs = current->next; + else + prev->next = current->next; - if (current->attrs != NULL) - ippDelete(current->attrs); + /* + * Free all memory used... + */ - /* - * Remove the print file for good... - */ + if (current->attrs != NULL) + ippDelete(current->attrs); + + free(current); + } - unlink(current->filename); - free(current); return; } } @@ -144,10 +179,10 @@ CancelJob(int id) /* I - Job to cancel */ */ void -CancelJobs(char *dest) /* I - Destination to cancel */ +CancelJobs(const char *dest) /* I - Destination to cancel */ { - job_t *current, /* Current job */ - *prev; /* Previous job in list */ + job_t *current, /* Current job */ + *prev; /* Previous job in list */ for (current = Jobs, prev = NULL; current != NULL; prev = current) @@ -179,9 +214,9 @@ CancelJobs(char *dest) /* I - Destination to cancel */ void CheckJobs(void) { - job_t *current, - *prev; - printer_t *printer; + job_t *current, /* Current job in queue */ + *prev; /* Previous job in queue */ + printer_t *printer; /* Printer/class destination */ DEBUG_puts("CheckJobs()"); @@ -190,7 +225,11 @@ CheckJobs(void) { DEBUG_printf(("CheckJobs: current->state = %d\n", current->state)); - if (current->state != IPP_JOB_PROCESSING) + /* + * Start pending jobs if the destination is available... + */ + + if (current->state == IPP_JOB_PENDING) { DEBUG_printf(("CheckJobs: current->dest = \'%s\'\n", current->dest)); @@ -241,10 +280,10 @@ CheckJobs(void) * 'FindJob()' - Find the specified job. */ -job_t * /* O - Job data */ -FindJob(int id) /* I - Job ID */ +job_t * /* O - Job data */ +FindJob(int id) /* I - Job ID */ { - job_t *current; /* Current job */ + job_t *current; /* Current job */ for (current = Jobs; current != NULL; current = current->next) @@ -255,14 +294,57 @@ FindJob(int id) /* I - Job ID */ } +/* + * 'HoldJob()' - Hold the specified job. + */ + +void +HoldJob(int id) /* I - Job ID */ +{ + job_t *job; /* Job data */ + + + if ((job = FindJob(id)) == NULL) + return; + + if (job->state == IPP_JOB_PROCESSING) + StopJob(id); + + job->state = IPP_JOB_HELD; + + CheckJobs(); +} + + +/* + * 'LoadAllJobs()' - Load all jobs from disk. + */ + +void +LoadAllJobs(void) +{ +} + + +/* + * 'LoadJob()' - Load a job from disk. + */ + +void +LoadJob(int id) /* I - Job ID */ +{ +} + + /* * 'MoveJob()' - Move the specified job to a different destination. */ void -MoveJob(int id, char *dest) +MoveJob(int id, /* I - Job ID */ + const char *dest) /* I - Destination */ { - job_t *current; /* Current job */ + job_t *current; /* Current job */ for (current = Jobs; current != NULL; current = current->next) @@ -276,6 +358,37 @@ MoveJob(int id, char *dest) } +/* + * 'RestartJob()' - Resume the specified job. + */ + +void +RestartJob(int id) /* I - Job ID */ +{ + job_t *job; /* Job data */ + + + if ((job = FindJob(id)) == NULL) + return; + + if (job->state == IPP_JOB_HELD) + { + job->state = IPP_JOB_PENDING; + CheckJobs(); + } +} + + +/* + * 'SaveJob()' - Save a job to disk. + */ + +void +SaveJob(int id) /* I - Job ID */ +{ +} + + /* * 'StartJob()' - Start a print job. */ @@ -540,7 +653,7 @@ StartJob(int id, /* I - Job ID */ sprintf(tmpdir, "TMPDIR=%s", TempDir); envp[0] = "PATH=/bin:/usr/bin"; - envp[1] = "SOFTWARE=CUPS/1.0"; + envp[1] = "SOFTWARE=CUPS/1.1"; envp[2] = "TZ=GMT"; envp[3] = "USER=root"; envp[4] = charset; @@ -718,15 +831,25 @@ StartJob(int id, /* I - Job ID */ } +/* + * 'StopAllJobs()' - Stop all print jobs. + */ + +void +StopAllJobs(void) +{ +} + + /* * 'StopJob()' - Stop a print job. */ void -StopJob(int id) +StopJob(int id) /* I - Job ID */ { - int i; /* Looping var */ - job_t *current; /* Current job */ + int i; /* Looping var */ + job_t *current; /* Current job */ DEBUG_printf(("StopJob(%d)\n", id)); @@ -877,13 +1000,27 @@ UpdateJob(job_t *job) /* I - Job to check */ { DEBUG_printf(("UpdateJob: job %d is complete.\n", job->id)); - if (job->status) + if (job->status > 0) { /* - * Job had errors; stop it... + * Backend had errors; stop it... */ StopJob(job->id); + job->state = IPP_JOB_PENDING; + } + else if (job->status > 0) + { + /* + * Filter had errors; cancel it... + */ + + CancelJob(job->id); + + if (JobHistory) + job->state = IPP_JOB_ABORTED; + + CheckJobs(); } else { @@ -894,26 +1031,729 @@ UpdateJob(job_t *job) /* I - Job to check */ job->printer->state_message[0] = '\0'; CancelJob(job->id); + + if (JobHistory) + job->state = IPP_JOB_COMPLETED; + CheckJobs(); } } } +/* + * 'ipp_read_file()' - Read an IPP request from a file. + */ + +static ipp_state_t /* O - State */ +ipp_read_file(const char *filename, /* I - File to read from */ + ipp_t *request) /* I - Request to read into */ +{ + int fd; /* File descriptor for file */ + int n; /* Length of data */ + unsigned char buffer[8192]; /* Data buffer */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_tag_t tag; /* Current tag */ + + + /* + * Open the file if possible... + */ + + if (filename == NULL || request == NULL) + return (IPP_ERROR); + + if ((fd = open(filename, O_RDONLY)) == -1) + return (IPP_ERROR); + + /* + * Read the IPP request... + */ + + ipp->state = IPP_IDLE; + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + /* + * Get the request header... + */ + + if ((n = read(fd, buffer, 8)) < 8) + { + DEBUG_printf(("ippRead: Unable to read header (%d bytes read)!\n", n)); + close(fd); + return (n == 0 ? IPP_IDLE : IPP_ERROR); + } + + /* + * Verify the major version number... + */ + + if (buffer[0] != 1) + { + DEBUG_printf(("ippRead: version number (%d.%d) is bad.\n", buffer[0], + buffer[1])); + close(fd); + return (IPP_ERROR); + } + + /* + * Then copy the request header over... + */ + + ipp->request.any.version[0] = buffer[0]; + ipp->request.any.version[1] = buffer[1]; + ipp->request.any.op_status = (buffer[2] << 8) | buffer[3]; + ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) | + buffer[6]) << 8) | buffer[7]; + + ipp->state = IPP_ATTRIBUTE; + ipp->current = NULL; + ipp->curtag = IPP_TAG_ZERO; + + case IPP_ATTRIBUTE : + while (read(fd, buffer, 1) > 0) + { + /* + * Read this attribute... + */ + + tag = (ipp_tag_t)buffer[0]; + + if (tag == IPP_TAG_END) + { + /* + * No more attributes left... + */ + + DEBUG_puts("ippRead: IPP_TAG_END!"); + + ipp->state = IPP_DATA; + break; + } + else if (tag < IPP_TAG_UNSUPPORTED_VALUE) + { + /* + * Group tag... Set the current group and continue... + */ + + if (ipp->curtag == tag) + ippAddSeparator(ipp); + + ipp->curtag = tag; + ipp->current = NULL; + DEBUG_printf(("ippRead: group tag = %x\n", tag)); + continue; + } + + DEBUG_printf(("ippRead: value tag = %x\n", tag)); + + /* + * Get the name... + */ + + if (read(fd, buffer, 2) < 2) + { + DEBUG_puts("ippRead: unable to read name length!"); + close(fd); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + + DEBUG_printf(("ippRead: name length = %d\n", n)); + + if (n == 0) + { + /* + * More values for current attribute... + */ + + if (ipp->current == NULL) + { + close(fd); + return (IPP_ERROR); + } + + attr = ipp->current; + + if (attr->num_values >= IPP_MAX_VALUES) + { + close(fd); + return (IPP_ERROR); + } + } + else + { + /* + * New attribute; read the name and add it... + */ + + if (read(fd, buffer, n) < n) + { + DEBUG_puts("ippRead: unable to read name!"); + close(fd); + return (IPP_ERROR); + } + + buffer[n] = '\0'; + DEBUG_printf(("ippRead: name = \'%s\'\n", buffer)); + + attr = ipp->current = add_attr(ipp, IPP_MAX_VALUES); + + attr->group_tag = ipp->curtag; + attr->value_tag = tag; + attr->name = strdup((char *)buffer); + attr->num_values = 0; + } + + if (read(fd, buffer, 2) < 2) + { + DEBUG_puts("ippRead: unable to read value length!"); + close(fd); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + DEBUG_printf(("ippRead: value length = %d\n", n)); + + switch (tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if (read(fd, buffer, 4) < 4) + { + close(fd); + return (IPP_ERROR); + } + + n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | + buffer[3]; + + attr->values[attr->num_values].integer = n; + break; + case IPP_TAG_BOOLEAN : + if (read(fd, buffer, 1) < 1) + { + close(fd); + return (IPP_ERROR); + } + + attr->values[attr->num_values].boolean = buffer[0]; + break; + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_STRING : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + if (read(fd, buffer, n) < n) + { + close(fd); + return (IPP_ERROR); + } + + buffer[n] = '\0'; + DEBUG_printf(("ippRead: value = \'%s\'\n", buffer)); + + attr->values[attr->num_values].string.text = strdup((char *)buffer); + break; + case IPP_TAG_DATE : + if (read(fd, buffer, 11) < 11) + { + close(fd); + return (IPP_ERROR); + } + + memcpy(attr->values[attr->num_values].date, buffer, 11); + break; + case IPP_TAG_RESOLUTION : + if (read(fd, buffer, 9) < 9) + { + close(fd); + return (IPP_ERROR); + } + + attr->values[attr->num_values].resolution.xres = + (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | + buffer[3]; + attr->values[attr->num_values].resolution.yres = + (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | + buffer[7]; + attr->values[attr->num_values].resolution.units = + (ipp_res_t)buffer[8]; + break; + case IPP_TAG_RANGE : + if (read(fd, buffer, 8) < 8) + { + close(fd); + return (IPP_ERROR); + } + + attr->values[attr->num_values].range.lower = + (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | + buffer[3]; + attr->values[attr->num_values].range.upper = + (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | + buffer[7]; + break; + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + if (read(fd, buffer, n) < n) + { + close(fd); + return (IPP_ERROR); + } + + buffer[n] = '\0'; + + attr->values[attr->num_values].string.charset = strdup((char *)buffer); + + if (read(fd, buffer, 2) < 2) + { + close(fd); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + + if (read(fd, buffer, n) < n) + { + close(fd); + return (IPP_ERROR); + } + + buffer[n] = '\0'; + + attr->values[attr->num_values].string.text = strdup((char *)buffer); + break; + } + + attr->num_values ++; + } + break; + + case IPP_DATA : + break; + } + + /* + * Close the file and return... + */ + + close(fd); + + return (ipp->state); +} + + +/* + * 'ipp_write_file()' - Write an IPP request to a file. + */ + +static ipp_state_t /* O - State */ +ipp_write_file(const char *filename, /* I - File to write to */ + ipp_t *request) /* I - Request to write */ +{ + int fd; /* File descriptor */ + int i; /* Looping var */ + int n; /* Length of data */ + unsigned char buffer[8192], /* Data buffer */ + *bufptr; /* Pointer into buffer */ + ipp_attribute_t *attr; /* Current attribute */ + + + /* + * Open the file if possible... + */ + + if (filename == NULL || request == NULL) + return (IPP_ERROR); + + if ((fd = open(filename, O_WRONLY | O_CREATE | O_TRUNC, 0640)) == -1) + return (IPP_ERROR); + + fchmod(fd, 0640); + fchown(fd, User, Group); + + /* + * Write the IPP request... + */ + + ipp->state = IPP_IDLE; + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + /* + * Send the request header... + */ + + bufptr = buffer; + + *bufptr++ = 1; + *bufptr++ = 0; + *bufptr++ = ipp->request.any.op_status >> 8; + *bufptr++ = ipp->request.any.op_status; + *bufptr++ = ipp->request.any.request_id >> 24; + *bufptr++ = ipp->request.any.request_id >> 16; + *bufptr++ = ipp->request.any.request_id >> 8; + *bufptr++ = ipp->request.any.request_id; + + if (write(fd, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP header..."); + close(fd); + return (IPP_ERROR); + } + + ipp->state = IPP_ATTRIBUTE; + ipp->current = ipp->attrs; + ipp->curtag = IPP_TAG_ZERO; + + case IPP_ATTRIBUTE : + while (ipp->current != NULL) + { + /* + * Write this attribute... + */ + + bufptr = buffer; + attr = ipp->current; + + ipp->current = ipp->current->next; + + if (ipp->curtag != attr->group_tag) + { + /* + * Send a group operation tag... + */ + + ipp->curtag = attr->group_tag; + + if (attr->group_tag == IPP_TAG_ZERO) + continue; + + DEBUG_printf(("ippWrite: wrote group tag = %x\n", attr->group_tag)); + *bufptr++ = attr->group_tag; + } + + n = strlen(attr->name); + + DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag)); + DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name)); + + *bufptr++ = attr->value_tag; + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->name, n); + bufptr += n; + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 4; + *bufptr++ = attr->values[i].integer >> 24; + *bufptr++ = attr->values[i].integer >> 16; + *bufptr++ = attr->values[i].integer >> 8; + *bufptr++ = attr->values[i].integer; + } + break; + + case IPP_TAG_BOOLEAN : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 1; + *bufptr++ = attr->values[i].boolean; + } + break; + + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_STRING : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + DEBUG_printf(("ippWrite: writing value tag = %x\n", + attr->value_tag)); + DEBUG_printf(("ippWrite: writing name = 0, \'\'\n")); + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = strlen(attr->values[i].string.text); + + DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n, + attr->values[i].string.text)); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (write(fd, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + close(fd); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->values[i].string.text, n); + bufptr += n; + } + break; + + case IPP_TAG_DATE : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 11; + memcpy(bufptr, attr->values[i].date, 11); + bufptr += 11; + } + break; + + case IPP_TAG_RESOLUTION : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 9; + *bufptr++ = attr->values[i].resolution.xres >> 24; + *bufptr++ = attr->values[i].resolution.xres >> 16; + *bufptr++ = attr->values[i].resolution.xres >> 8; + *bufptr++ = attr->values[i].resolution.xres; + *bufptr++ = attr->values[i].resolution.yres >> 24; + *bufptr++ = attr->values[i].resolution.yres >> 16; + *bufptr++ = attr->values[i].resolution.yres >> 8; + *bufptr++ = attr->values[i].resolution.yres; + *bufptr++ = attr->values[i].resolution.units; + } + break; + + case IPP_TAG_RANGE : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 8; + *bufptr++ = attr->values[i].range.lower >> 24; + *bufptr++ = attr->values[i].range.lower >> 16; + *bufptr++ = attr->values[i].range.lower >> 8; + *bufptr++ = attr->values[i].range.lower; + *bufptr++ = attr->values[i].range.upper >> 24; + *bufptr++ = attr->values[i].range.upper >> 16; + *bufptr++ = attr->values[i].range.upper >> 8; + *bufptr++ = attr->values[i].range.upper; + } + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = strlen(attr->values[i].string.charset); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (write(fd, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + close(fd); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->values[i].string.charset, n); + bufptr += n; + + n = strlen(attr->values[i].string.text); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (write(fd, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + close(fd); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->values[i].string.text, n); + bufptr += n; + } + break; + } + + /* + * Write the data out... + */ + + if (write(fd, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + close(fd); + return (IPP_ERROR); + } + + DEBUG_printf(("ippWrite: wrote %d bytes\n", bufptr - buffer)); + } + + if (ipp->current == NULL) + { + /* + * Done with all of the attributes; add the end-of-attributes tag... + */ + + buffer[0] = IPP_TAG_END; + if (write(fd, (char *)buffer, 1) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP end-tag..."); + close(fd); + return (IPP_ERROR); + } + + ipp->state = IPP_DATA; + } + break; + + case IPP_DATA : + break; + } + + /* + * Close the file and return... + */ + + close(fd); + + return (ipp->state); +} + + /* * 'start_process()' - Start a background process. */ -static int /* O - Process ID or 0 */ -start_process(char *command, /* I - Full path to command */ - char *argv[], /* I - Command-line arguments */ - char *envp[], /* I - Environment */ - int infd, /* I - Standard input file descriptor */ - int outfd, /* I - Standard output file descriptor */ - int errfd) /* I - Standard error file descriptor */ +static int /* O - Process ID or 0 */ +start_process(const char *command, /* I - Full path to command */ + const char *argv[], /* I - Command-line arguments */ + const char *envp[], /* I - Environment */ + int infd, /* I - Standard input file descriptor */ + int outfd, /* I - Standard output file descriptor */ + int errfd) /* I - Standard error file descriptor */ { - int fd; /* Looping var */ - int pid; /* Process ID */ + int fd; /* Looping var */ + int pid; /* Process ID */ DEBUG_printf(("start_process(\"%s\", %08x, %08x, %d, %d, %d)\n", @@ -979,5 +1819,5 @@ start_process(char *command, /* I - Full path to command */ /* - * End of "$Id: job.c,v 1.43 1999/12/21 02:26:48 mike Exp $". + * End of "$Id: job.c,v 1.44 1999/12/29 02:15:42 mike Exp $". */ diff --git a/scheduler/job.h b/scheduler/job.h index d5eb7cd167..3f164e3ecc 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -1,5 +1,5 @@ /* - * "$Id: job.h,v 1.9 1999/06/18 18:36:48 mike Exp $" + * "$Id: job.h,v 1.10 1999/12/29 02:15:43 mike Exp $" * * Print job definitions for the Common UNIX Printing System (CUPS) scheduler. * @@ -36,8 +36,9 @@ typedef struct job_str char dest[IPP_MAX_NAME]; /* Destination printer or class */ char title[IPP_MAX_NAME]; /* Job name/title */ cups_ptype_t dtype; /* Destination type (class/remote bits) */ - char filename[HTTP_MAX_URI]; /* Name of job file */ - mime_type_t *filetype; /* File type */ + int num_files; /* Number of files in job */ + int current_file; /* Current file in job */ + mime_type_t **filetypes; /* File types */ ipp_t *attrs; /* Job attributes */ int pipe; /* Status pipe for this job */ int procs[MAX_FILTERS + 2]; /* Process IDs, 0 terminated */ @@ -50,26 +51,34 @@ typedef struct job_str * Globals... */ +VAR int JobHistory VALUE(1); /* Preserve job history? */ +VAR int JobFiles VALUE(0); /* Preserve job files? */ VAR int NumJobs VALUE(0); /* Number of jobs in queue */ VAR job_t *Jobs VALUE(NULL); /* List of current jobs */ VAR int NextJobId VALUE(1); /* Next job ID to use */ + /* * Prototypes... */ -extern job_t *AddJob(int priority, char *dest); +extern job_t *AddJob(int priority, const char *dest); extern void CancelJob(int id); -extern void CancelJobs(char *dest); +extern void CancelJobs(const char *dest); extern void CheckJobs(void); extern void DeleteJob(int id); extern job_t *FindJob(int id); -extern void LoadJobs(void); -extern void MoveJob(int id, char *dest); +extern void HoldJob(int id); +extern void LoadAllJobs(void); +extern void LoadJob(int id); +extern void MoveJob(int id, const char *dest); +extern void RestartJob(int id); +extern void SaveJob(int id); extern void StartJob(int id, printer_t *printer); +extern void StopAllJobs(void); extern void StopJob(int id); extern void UpdateJob(job_t *job); /* - * End of "$Id: job.h,v 1.9 1999/06/18 18:36:48 mike Exp $". + * End of "$Id: job.h,v 1.10 1999/12/29 02:15:43 mike Exp $". */ diff --git a/scheduler/main.c b/scheduler/main.c index 4ecaf601d0..57c6d3e168 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -1,5 +1,5 @@ /* - * "$Id: main.c,v 1.30 1999/12/07 18:10:18 mike Exp $" + * "$Id: main.c,v 1.31 1999/12/29 02:15:43 mike Exp $" * * Scheduler main loop for the Common UNIX Printing System (CUPS). * @@ -391,14 +391,20 @@ sigchld_handler(int sig) /* I - Signal number */ job->procs[i] = -pid; - if (status && !job->procs[i + 1]) + if (status && job->status >= 0) { /* - * A fatal error occurred; save the exit status so we know to stop - * the printer when all of the filters finish... + * An error occurred; save the exit status so we know to stop + * the printer or cancel the job when all of the filters finish... + * + * A negative status indicates that the backend failed and the + * printer needs to be stopped. */ - job->status = status; + if (!job->procs[i + 1]) + job->status = -status; /* Backend failed */ + else + job->status = status; /* Filter failed */ } break; } @@ -439,5 +445,5 @@ usage(void) /* - * End of "$Id: main.c,v 1.30 1999/12/07 18:10:18 mike Exp $". + * End of "$Id: main.c,v 1.31 1999/12/29 02:15:43 mike Exp $". */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 7cd0b2ca56..a314135365 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1,5 +1,5 @@ /* - * "$Id: printers.c,v 1.46 1999/12/14 23:19:11 mike Exp $" + * "$Id: printers.c,v 1.47 1999/12/29 02:15:43 mike Exp $" * * Printer routines for the Common UNIX Printing System (CUPS). * @@ -660,10 +660,14 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */ { IPP_PRINT_JOB, IPP_VALIDATE_JOB, + IPP_CREATE_JOB, + IPP_SEND_DOCUMENT, IPP_CANCEL_JOB, IPP_GET_JOB_ATTRIBUTES, IPP_GET_JOBS, IPP_GET_PRINTER_ATTRIBUTES, + IPP_HOLD_JOB, + IPP_RELEASE_JOB, IPP_PAUSE_PRINTER, IPP_RESUME_PRINTER, IPP_PURGE_JOBS, @@ -675,7 +679,9 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */ CUPS_ADD_CLASS, CUPS_DELETE_CLASS, CUPS_ACCEPT_JOBS, - CUPS_REJECT_JOBS + CUPS_REJECT_JOBS, + CUPS_GET_DEVICES, + CUPS_GET_PPDS }; const char *charsets[] = /* charset-supported values */ { @@ -1233,5 +1239,5 @@ write_printcap(void) /* - * End of "$Id: printers.c,v 1.46 1999/12/14 23:19:11 mike Exp $". + * End of "$Id: printers.c,v 1.47 1999/12/29 02:15:43 mike Exp $". */