Index: berkeley/lpr.c =================================================================== --- berkeley/lpr.c (revision 7169) +++ berkeley/lpr.c (working copy) @@ -14,8 +14,7 @@ * * Contents: * - * main() - Parse options and send files for printing. - * sighandler() - Signal catcher for when we print from stdin... + * main() - Parse options and send files for printing. */ /* @@ -30,27 +29,8 @@ #include #include -#ifndef WIN32 -# include -# include - /* - * Local functions. - */ - -void sighandler(int); -#endif /* !WIN32 */ - - -/* - * Globals... - */ - -char tempfile[1024]; /* Temporary file for printing from stdin */ - - -/* * 'main()' - Parse options and send files for printing. */ @@ -73,13 +53,6 @@ cups_option_t *options; /* Options */ int deletefile; /* Delete file after print? */ char buffer[8192]; /* Copy buffer */ - ssize_t bytes; /* Bytes copied */ - off_t filesize; /* Size of temp file */ - int temp; /* Temporary file descriptor */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Signal action */ - struct sigaction oldaction; /* Old signal action */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ _cupsSetLocale(argv); @@ -409,72 +382,38 @@ unlink(files[i]); } } - else + else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer, + title ? title : "(stdin)", + num_options, options)) > 0) { - num_files = 1; + http_status_t status; /* Write status */ + const char *format; /* Document format */ + ssize_t bytes; /* Bytes read */ -#ifndef WIN32 -# if defined(HAVE_SIGSET) - sigset(SIGHUP, sighandler); - if (sigset(SIGINT, sighandler) == SIG_IGN) - sigset(SIGINT, SIG_IGN); - sigset(SIGTERM, sighandler); -# elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - action.sa_handler = sighandler; - sigaction(SIGHUP, &action, NULL); - sigaction(SIGINT, NULL, &oldaction); - if (oldaction.sa_handler != SIG_IGN) - sigaction(SIGINT, &action, NULL); - sigaction(SIGTERM, &action, NULL); -# else - signal(SIGHUP, sighandler); - if (signal(SIGINT, sighandler) == SIG_IGN) - signal(SIGINT, SIG_IGN); - signal(SIGTERM, sighandler); -# endif -#endif /* !WIN32 */ + if (cupsGetOption("raw", num_options, options)) + format = CUPS_FORMAT_RAW; + else if ((format = cupsGetOption("document-format", num_options, + options)) == NULL) + format = CUPS_FORMAT_AUTO; - if ((temp = cupsTempFd(tempfile, sizeof(tempfile))) < 0) - { - _cupsLangPrintf(stderr, - _("%s: Error - unable to create temporary file " - "\"%s\" - %s\n"), - argv[0], tempfile, strerror(errno)); - return (1); - } + status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL, + format, 1); - while ((bytes = read(0, buffer, sizeof(buffer))) > 0) - if (write(temp, buffer, bytes) < 0) - { - _cupsLangPrintf(stderr, - _("%s: Error - unable to write to temporary file " - "\"%s\" - %s\n"), - argv[0], tempfile, strerror(errno)); - close(temp); - unlink(tempfile); - return (1); - } + while (status == HTTP_CONTINUE && + (bytes = read(0, buffer, sizeof(buffer))) > 0) + status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes); - filesize = lseek(temp, 0, SEEK_CUR); - close(temp); - - if (filesize <= 0) + if (status != HTTP_CONTINUE) { _cupsLangPrintf(stderr, - _("%s: Error - stdin is empty, so no job has been sent.\n"), - argv[0]); - unlink(tempfile); + _("%s: Error - unable to queue from stdin - %s\n"), + argv[0], httpStatus(status)); return (1); } - if (title) - job_id = cupsPrintFile(printer, tempfile, title, num_options, options); - else - job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options); - - unlink(tempfile); + if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK) + job_id = 0; } if (job_id < 1) @@ -487,29 +426,6 @@ } -#ifndef WIN32 /* - * 'sighandler()' - Signal catcher for when we print from stdin... - */ - -void -sighandler(int s) /* I - Signal number */ -{ - /* - * Remove the temporary file we're using to print from stdin... - */ - - unlink(tempfile); - - /* - * Exit... - */ - - exit(s); -} -#endif /* !WIN32 */ - - -/* * End of "$Id$". */ Index: cups/util.c =================================================================== --- cups/util.c (revision 7169) +++ cups/util.c (working copy) @@ -3,7 +3,7 @@ * * Printing utilities for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -17,18 +17,21 @@ * Contents: * * cupsCancelJob() - Cancel a print job on the default server. + * cupsCancelJob2() - Cancel or purge a print job. + * cupsCreateJob() - Create an empty job. + * cupsFinishDocument() - Finish sending a document. * cupsFreeJobs() - Free memory used by job data. * cupsGetClasses() - Get a list of printer classes from the default * server. - * cupsGetDefault() - Get the default printer or class from the default + * cupsGetDefault() - Get the default printer or class for the default * server. - * cupsGetDefault2() - Get the default printer or class from the - * specified server. + * cupsGetDefault2() - Get the default printer or class for the specified + * server. * cupsGetJobs() - Get the jobs from the default server. * cupsGetJobs2() - Get the jobs from the specified server. * cupsGetPPD() - Get the PPD file for a printer on the default * server. - * cupsGetPPD2() - Get the PPD file for a printer on the specified + * cupsGetPPD2() - Get the PPD file for a printer from the specified * server. * cupsGetPPD3() - Get the PPD file for a printer on the specified * server if it has changed. @@ -44,7 +47,9 @@ * the default server. * cupsPrintFiles2() - Print one or more files to a printer or class on * the specified server. - * cups_connect() - Connect to the specified host... + * cupsStartDocument() - Add a document to a job created with + * cupsCreateJob(). + * _cupsConnect() - Get the default server connection... * cups_get_printer_uri() - Get the printer-uri-supported attribute for the * first printer in a class. */ @@ -70,7 +75,6 @@ * Local functions... */ -static char *cups_connect(const char *name, char *printer, char *hostname); static int cups_get_printer_uri(http_t *http, const char *name, char *host, int hostsize, int *port, char *resource, int resourcesize, @@ -86,72 +90,186 @@ int /* O - 1 on success, 0 on failure */ cupsCancelJob(const char *name, /* I - Name of printer or class */ - int job) /* I - Job ID */ + int job_id) /* I - Job ID */ { - char printer[HTTP_MAX_URI], /* Printer name */ - hostname[HTTP_MAX_URI], /* Hostname */ - uri[HTTP_MAX_URI]; /* Printer URI */ - ipp_t *request, /* IPP request */ - *response; /* IPP response */ - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + return (cupsCancelJob2(CUPS_HTTP_DEFAULT, job_id, 0) + < IPP_REDIRECTION_OTHER_SITE); +} +/* + * 'cupsCancelJob2()' - Cancel or purge a print job. + * + * Canceled jobs remain in the job history while purged jobs are removed + * from the job history. + * + * Use the cupsLastError() and cupsLastErrorString() functions to get + * the cause of any failure. + * + * @since CUPS 1.4@ + */ + +ipp_status_t /* O - IPP status */ +cupsCancelJob2(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + int job_id, /* I - Job ID */ + int purge) /* I - 1 to purge, 0 to cancel */ +{ + char uri[HTTP_MAX_URI]; /* Job URI */ + ipp_t *request; /* IPP request */ + + /* - * See if we can connect to the server... + * Range check input... */ - if (!cups_connect(name, printer, hostname)) + if (job_id <= 0) { - DEBUG_puts("Unable to connect to server!"); - + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL)); return (0); } /* - * Create a printer URI... + * Connect to the default server as needed... */ - if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, - "localhost", 0, "/printers/%s", printer) != HTTP_URI_OK) - { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + if (!http) + if ((http = _cupsConnect()) == NULL) + return (IPP_SERVICE_UNAVAILABLE); - return (0); - } - /* * Build an IPP_CANCEL_JOB request, which requires the following * attributes: * * attributes-charset * attributes-natural-language - * printer-uri - * job-id - * [requesting-user-name] + * job-uri + * requesting-user-name + * [purge-job] */ request = ippNewRequest(IPP_CANCEL_JOB); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id); - ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job); - + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + if (purge) + ippAddBoolean(request, IPP_TAG_OPERATION, "purge-job", 1); /* * Do the request... */ - if ((response = cupsDoRequest(cg->http, request, "/jobs/")) != NULL) - ippDelete(response); + ippDelete(cupsDoRequest(http, request, "/jobs/")); - return (cg->last_error < IPP_REDIRECTION_OTHER_SITE); + return (cupsLastError()); } /* + * 'cupsCreateJob()' - Create an empty job. + * + * Submit files for printing to the job using the cupsStartDocument(), + * cupsWriteRequestData(), and cupsFinishDocument() functions. + * + * @since CUPS 1.4@ + */ + +int /* O - Job ID or 0 on error */ +cupsCreateJob( + http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + const char *name, /* I - Printer or class name */ + const char *title, /* I - Title of job */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + char printer_uri[1024], /* Printer URI */ + resource[1024]; /* Printer resource */ + ipp_t *request, /* Create-Job request */ + *response; /* Create-Job response */ + ipp_attribute_t *attr; /* job-id attribute */ + int job_id = 0; /* job-id value */ + + + DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", " + "num_options=%d, options=%p)\n", + http, name, title, num_options, options)); + + /* + * Range check input... + */ + + if (!name) + { + _cupsSetError(IPP_INTERNAL_ERROR, NULL); + return (0); + } + + /* + * Build a Create-Job request... + */ + + if ((request = ippNewRequest(IPP_CREATE_JOB)) == NULL) + { + _cupsSetError(IPP_INTERNAL_ERROR, NULL); + return (0); + } + + httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp", + NULL, "localhost", ippPort(), "/printers/%s", name); + snprintf(resource, sizeof(resource), "/printers/%s", name); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, printer_uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + if (title) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, + title); + cupsEncodeOptions(request, num_options, options); + + /* + * Send the request and get the job-id... + */ + + response = cupsDoRequest(http, request, resource); + + if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) + job_id = attr->values[0].integer; + + ippDelete(response); + + /* + * Return it... + */ + + return (job_id); +} + + +/* + * 'cupsFinishDocument()' - Finish sending a document. + * + * @since CUPS 1.4@ + */ + +ipp_status_t /* O - Status of document submission */ +cupsFinishDocument(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + const char *name) /* I - Printer or class name */ +{ + char resource[1024]; /* Printer resource */ + + + snprintf(resource, sizeof(resource), "/printers/%s", name); + + ippDelete(cupsGetResponse(http, resource)); + + return (cupsLastError()); +} + + +/* * 'cupsFreeJobs()' - Free memory used by job data. */ @@ -159,18 +277,19 @@ cupsFreeJobs(int num_jobs, /* I - Number of jobs */ cups_job_t *jobs) /* I - Jobs */ { - int i; /* Looping var */ + int i; /* Looping var */ + cups_job_t *job; /* Current job */ - if (num_jobs <= 0 || jobs == NULL) + if (num_jobs <= 0 || !jobs) return; - for (i = 0; i < num_jobs; i ++) + for (i = num_jobs, job = jobs; i > 0; i --, job ++) { - free(jobs[i].dest); - free(jobs[i].user); - free(jobs[i].format); - free(jobs[i].title); + _cupsStrFree(job->dest); + _cupsStrFree(job->user); + _cupsStrFree(job->format); + _cupsStrFree(job->title); } free(jobs); @@ -193,26 +312,20 @@ *response; /* IPP Response */ ipp_attribute_t *attr; /* Current attribute */ char **temp; /* Temporary pointer */ - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + http_t *http; /* Connection to server */ - if (classes == NULL) + if (!classes) { _cupsSetError(IPP_INTERNAL_ERROR, NULL); return (0); } - /* - * Try to connect to the server... - */ + *classes = NULL; - if (!cups_connect("default", NULL, NULL)) - { - DEBUG_puts("Unable to connect to server!"); - + if ((http = _cupsConnect()) == NULL) return (0); - } /* * Build a CUPS_GET_CLASSES request, which requires the following @@ -232,10 +345,9 @@ * Do the request and get back a response... */ - n = 0; - *classes = NULL; + n = 0; - if ((response = cupsDoRequest(cg->http, request, "/")) != NULL) + if ((response = cupsDoRequest(http, request, "/")) != NULL) { for (attr = response->attrs; attr != NULL; attr = attr->next) if (attr->name != NULL && @@ -290,38 +402,11 @@ const char * /* O - Default printer or NULL */ cupsGetDefault(void) { - const char *var; /* Environment variable */ - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - - /* - * First see if the LPDEST or PRINTER environment variables are - * set... However, if PRINTER is set to "lp", ignore it to work - * around a "feature" in most Linux distributions - the default - * user login scripts set PRINTER to "lp"... - */ - - if ((var = getenv("LPDEST")) != NULL) - return (var); - else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0) - return (var); - - /* - * Try to connect to the server... - */ - - if (!cups_connect("default", NULL, NULL)) - { - DEBUG_puts("Unable to connect to server!"); - - return (NULL); - } - - /* * Return the default printer... */ - return (cupsGetDefault2(cg->http)); + return (cupsGetDefault2(CUPS_HTTP_DEFAULT)); } @@ -361,11 +446,12 @@ return (var); /* - * Range check input... + * Connect to the server as needed... */ if (!http) - return (NULL); + if ((http = _cupsConnect()) == NULL) + return (NULL); /* * Build a CUPS_GET_DEFAULT request, which requires the following @@ -383,9 +469,11 @@ if ((response = cupsDoRequest(http, request, "/")) != NULL) { - if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) + if ((attr = ippFindAttribute(response, "printer-name", + IPP_TAG_NAME)) != NULL) { - strlcpy(cg->def_printer, attr->values[0].string.text, sizeof(cg->def_printer)); + strlcpy(cg->def_printer, attr->values[0].string.text, + sizeof(cg->def_printer)); ippDelete(response); return (cg->def_printer); } @@ -409,24 +497,11 @@ int completed) /* I - -1 = show all, 0 = active, * * 1 = completed jobs */ { - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - /* - * Try to connect to the server... - */ - - if (!cups_connect("default", NULL, NULL)) - { - DEBUG_puts("Unable to connect to server!"); - - return (-1); - } - - /* * Return the jobs... */ - return (cupsGetJobs2(cg->http, jobs, mydest, myjobs, completed)); + return (cupsGetJobs2(CUPS_HTTP_DEFAULT, jobs, mydest, myjobs, completed)); } @@ -438,7 +513,7 @@ */ int /* O - Number of jobs */ -cupsGetJobs2(http_t *http, /* I - HTTP connection */ +cupsGetJobs2(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ cups_job_t **jobs, /* O - Job data */ const char *mydest, /* I - NULL = all destinations, * * otherwise show jobs for mydest */ @@ -484,7 +559,7 @@ * Range check input... */ - if (!http || !jobs) + if (!jobs) { _cupsSetError(IPP_INTERNAL_ERROR, NULL); @@ -508,6 +583,9 @@ else strcpy(uri, "ipp://localhost/jobs"); + if (!http) + if ((http = _cupsConnect()) == NULL) + return (-1); /* * Build an IPP_GET_JOBS request, which requires the following @@ -553,16 +631,16 @@ if ((response = cupsDoRequest(http, request, "/")) != NULL) { - for (attr = response->attrs; attr != NULL; attr = attr->next) + for (attr = response->attrs; attr; attr = attr->next) { /* * Skip leading attributes until we hit a job... */ - while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + while (attr && attr->group_tag != IPP_TAG_JOB) attr = attr->next; - if (attr == NULL) + if (!attr) break; /* @@ -581,42 +659,42 @@ completed_time = 0; processing_time = 0; - while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + while (attr && attr->group_tag == IPP_TAG_JOB) { - if (strcmp(attr->name, "job-id") == 0 && + if (!strcmp(attr->name, "job-id") && attr->value_tag == IPP_TAG_INTEGER) id = attr->values[0].integer; - else if (strcmp(attr->name, "job-state") == 0 && + else if (!strcmp(attr->name, "job-state") && attr->value_tag == IPP_TAG_ENUM) state = (ipp_jstate_t)attr->values[0].integer; - else if (strcmp(attr->name, "job-priority") == 0 && + else if (!strcmp(attr->name, "job-priority") && attr->value_tag == IPP_TAG_INTEGER) priority = attr->values[0].integer; - else if (strcmp(attr->name, "job-k-octets") == 0 && + else if (!strcmp(attr->name, "job-k-octets") && attr->value_tag == IPP_TAG_INTEGER) size = attr->values[0].integer; - else if (strcmp(attr->name, "time-at-completed") == 0 && + else if (!strcmp(attr->name, "time-at-completed") && attr->value_tag == IPP_TAG_INTEGER) completed_time = attr->values[0].integer; - else if (strcmp(attr->name, "time-at-creation") == 0 && + else if (!strcmp(attr->name, "time-at-creation") && attr->value_tag == IPP_TAG_INTEGER) creation_time = attr->values[0].integer; - else if (strcmp(attr->name, "time-at-processing") == 0 && + else if (!strcmp(attr->name, "time-at-processing") && attr->value_tag == IPP_TAG_INTEGER) processing_time = attr->values[0].integer; - else if (strcmp(attr->name, "job-printer-uri") == 0 && + else if (!strcmp(attr->name, "job-printer-uri") && attr->value_tag == IPP_TAG_URI) { if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL) dest ++; } - else if (strcmp(attr->name, "job-originating-user-name") == 0 && + else if (!strcmp(attr->name, "job-originating-user-name") && attr->value_tag == IPP_TAG_NAME) user = attr->values[0].string.text; - else if (strcmp(attr->name, "document-format") == 0 && + else if (!strcmp(attr->name, "document-format") && attr->value_tag == IPP_TAG_MIMETYPE) format = attr->values[0].string.text; - else if (strcmp(attr->name, "job-name") == 0 && + else if (!strcmp(attr->name, "job-name") && (attr->value_tag == IPP_TAG_TEXT || attr->value_tag == IPP_TAG_NAME)) title = attr->values[0].string.text; @@ -628,9 +706,9 @@ * See if we have everything needed... */ - if (dest == NULL || id == 0) + if (!dest || !id) { - if (attr == NULL) + if (!attr) break; else continue; @@ -645,17 +723,20 @@ else temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1)); - if (temp == NULL) + if (!temp) { /* * Ran out of memory! */ + _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); + cupsFreeJobs(n, *jobs); *jobs = NULL; ippDelete(response); - return (0); + + return (-1); } *jobs = temp; @@ -666,10 +747,10 @@ * Copy the data over... */ - temp->dest = strdup(dest); - temp->user = strdup(user); - temp->format = strdup(format); - temp->title = strdup(title); + temp->dest = _cupsStrAlloc(dest); + temp->user = _cupsStrAlloc(user); + temp->format = _cupsStrAlloc(format); + temp->title = _cupsStrAlloc(title); temp->id = id; temp->priority = priority; temp->state = state; @@ -678,7 +759,7 @@ temp->creation_time = creation_time; temp->processing_time = processing_time; - if (attr == NULL) + if (!attr) break; } @@ -707,23 +788,12 @@ /* - * See if we can connect to the server... - */ - - if (!cups_connect(name, NULL, NULL)) - { - DEBUG_puts("Unable to connect to server!"); - - return (NULL); - } - - /* * Return the PPD file... */ cg->ppd_filename[0] = '\0'; - if (cupsGetPPD3(cg->http, name, &modtime, cg->ppd_filename, + if (cupsGetPPD3(CUPS_HTTP_DEFAULT, name, &modtime, cg->ppd_filename, sizeof(cg->ppd_filename)) == HTTP_OK) return (cg->ppd_filename); else @@ -741,7 +811,7 @@ */ const char * /* O - Filename for PPD file */ -cupsGetPPD2(http_t *http, /* I - HTTP connection */ +cupsGetPPD2(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ const char *name) /* I - Printer name */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ @@ -775,7 +845,7 @@ */ http_status_t /* O - HTTP status */ -cupsGetPPD3(http_t *http, /* I - HTTP connection */ +cupsGetPPD3(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ const char *name, /* I - Printer name */ time_t *modtime, /* IO - Modification time */ char *buffer, /* I - Filename buffer */ @@ -802,12 +872,6 @@ "bufsize=%d)\n", http, name ? name : "(null)", modtime, modtime ? *modtime : 0, buffer, (int)bufsize)); - if (!http) - { - _cupsSetError(IPP_INTERNAL_ERROR, "No HTTP connection!"); - return (HTTP_NOT_ACCEPTABLE); - } - if (!name) { _cupsSetError(IPP_INTERNAL_ERROR, "No printer name!"); @@ -830,6 +894,9 @@ * Try finding a printer URI for this printer... */ + if (!http) + http = _cupsConnect(); + if (!cups_get_printer_uri(http, name, hostname, sizeof(hostname), &port, resource, sizeof(resource), 0)) return (HTTP_NOT_FOUND); @@ -972,26 +1039,28 @@ *response; /* IPP Response */ ipp_attribute_t *attr; /* Current attribute */ char **temp; /* Temporary pointer */ - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + http_t *http; /* Connection to server */ - if (printers == NULL) + /* + * Range check input... + */ + + if (!printers) { _cupsSetError(IPP_INTERNAL_ERROR, NULL); return (0); } + *printers = NULL; + /* * Try to connect to the server... */ - if (!cups_connect("default", NULL, NULL)) - { - DEBUG_puts("Unable to connect to server!"); - + if ((http = _cupsConnect()) == NULL) return (0); - } /* * Build a CUPS_GET_PRINTERS request, which requires the following @@ -1017,10 +1086,9 @@ * Do the request and get back a response... */ - n = 0; - *printers = NULL; + n = 0; - if ((response = cupsDoRequest(cg->http, request, "/")) != NULL) + if ((response = cupsDoRequest(http, request, "/")) != NULL) { for (attr = response->attrs; attr != NULL; attr = attr->next) if (attr->name != NULL && @@ -1077,7 +1145,7 @@ */ char * /* O - Name of PPD file or NULL on error */ -cupsGetServerPPD(http_t *http, /* I - HTTP connection */ +cupsGetServerPPD(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ const char *name) /* I - Name of PPD file ("ppd-name") */ { int fd; /* PPD file descriptor */ @@ -1090,16 +1158,17 @@ * Range check input... */ - if (!http || !name) + if (!name) { - if (!http) - _cupsSetError(IPP_INTERNAL_ERROR, "No HTTP connection!"); - else - _cupsSetError(IPP_INTERNAL_ERROR, "No PPD name!"); + _cupsSetError(IPP_INTERNAL_ERROR, "No PPD name!"); return (NULL); } + if (!http) + if ((http = _cupsConnect()) == NULL) + return (NULL); + /* * Get a temp file... */ @@ -1176,7 +1245,8 @@ "title=\"%s\", num_options=%d, options=%p)\n", name, filename, title, num_options, options)); - return (cupsPrintFiles(name, 1, &filename, title, num_options, options)); + return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, 1, &filename, title, + num_options, options)); } @@ -1187,19 +1257,20 @@ */ int /* O - Job ID */ -cupsPrintFile2(http_t *http, /* I - HTTP connection */ - const char *name, /* I - Printer or class name */ - const char *filename, /* I - File to print */ - const char *title, /* I - Title of job */ - int num_options, - /* I - Number of options */ - cups_option_t *options) /* I - Options */ +cupsPrintFile2( + http_t *http, /* I - HTTP connection */ + const char *name, /* I - Printer or class name */ + const char *filename, /* I - File to print */ + const char *title, /* I - Title of job */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ { DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", " "title=\"%s\", num_options=%d, options=%p)\n", http, name, filename, title, num_options, options)); - return (cupsPrintFiles2(http, name, 1, &filename, title, num_options, options)); + return (cupsPrintFiles2(http, name, 1, &filename, title, num_options, + options)); } @@ -1209,44 +1280,28 @@ */ int /* O - Job ID */ -cupsPrintFiles(const char *name, /* I - Printer or class name */ - int num_files, /* I - Number of files */ - const char **files, /* I - File(s) to print */ - const char *title, /* I - Title of job */ - int num_options, - /* I - Number of options */ - cups_option_t *options) /* I - Options */ +cupsPrintFiles( + const char *name, /* I - Printer or class name */ + int num_files, /* I - Number of files */ + const char **files, /* I - File(s) to print */ + const char *title, /* I - Title of job */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ { - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, " "files=%p, title=\"%s\", num_options=%d, options=%p)\n", name, num_files, files, title, num_options, options)); /* - * Setup a connection and request data... - */ - - if (!cups_connect(name, NULL, NULL)) - { - DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n", - strerror(errno))); - DEBUG_puts("Unable to connect to server!"); - - return (0); - } - - /* * Print the file(s)... */ - return (cupsPrintFiles2(cg->http, name, num_files, files, title, + return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, num_files, files, title, num_options, options)); } - /* * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the * specified server. @@ -1255,26 +1310,26 @@ */ int /* O - Job ID */ -cupsPrintFiles2(http_t *http, /* I - HTTP connection */ - const char *name, /* I - Printer or class name */ - int num_files,/* I - Number of files */ - const char **files, /* I - File(s) to print */ - const char *title, /* I - Title of job */ - int num_options, - /* I - Number of options */ - cups_option_t *options) /* I - Options */ +cupsPrintFiles2( + http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + const char *name, /* I - Printer or class name */ + int num_files, /* I - Number of files */ + const char **files, /* I - File(s) to print */ + const char *title, /* I - Title of job */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ { int i; /* Looping var */ - const char *val; /* Pointer to option value */ - ipp_t *request; /* IPP request */ - ipp_t *response; /* IPP response */ - ipp_attribute_t *attr; /* IPP job-id attribute */ - char uri[HTTP_MAX_URI]; /* Printer URI */ - int jobid; /* New job ID */ - const char *base; /* Basename of current filename */ + int job_id; /* New job ID */ + const char *docname; /* Basename of current filename */ + const char *format; /* Document format */ + cups_file_t *fp; /* Current file */ + char buffer[8192]; /* Copy buffer */ + ssize_t bytes; /* Bytes in buffer */ + http_status_t status; /* Status of write */ - DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, " + DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, " "files=%p, title=\"%s\", num_options=%d, options=%p)\n", http, name, num_files, files, title, num_options, options)); @@ -1282,7 +1337,7 @@ * Range check input... */ - if (!http || !name || num_files < 1 || files == NULL) + if (!name || num_files < 1 || !files) { _cupsSetError(IPP_INTERNAL_ERROR, NULL); @@ -1290,215 +1345,204 @@ } /* - * Setup the printer URI... + * Create the print job... */ - if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, - "localhost", 0, "/printers/%s", name) != HTTP_URI_OK) - { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); - + if ((job_id = cupsCreateJob(http, name, title, num_options, options)) == 0) return (0); - } /* - * Build a standard CUPS URI for the printer and fill the standard IPP - * attributes... + * Send each of the files... */ - if ((request = ippNewRequest(num_files == 1 ? IPP_PRINT_JOB : - IPP_CREATE_JOB)) == NULL) + if (cupsGetOption("raw", num_options, options)) + format = CUPS_FORMAT_RAW; + else if ((format = cupsGetOption("document-format", num_options, + options)) == NULL) + format = CUPS_FORMAT_AUTO; + + for (i = 0; i < num_files; i ++) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + /* + * Start the next file... + */ - return (0); - } + if ((docname = strrchr(files[i], '/')) != NULL) + docname ++; + else + docname = files[i]; - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + if ((fp = cupsFileOpen(files[i], "rb")) == NULL) + { + /* + * Unable to open print file, cancel the job and return... + */ - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", - NULL, cupsUser()); + cupsCancelJob2(http, job_id, 0); + return (0); + } - if (title) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, - title); + status = cupsStartDocument(http, name, job_id, docname, format, + i == (num_files - 1)); - /* - * Then add all options... - */ + while (status == HTTP_CONTINUE && + (bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0) + status = cupsWriteRequestData(http, buffer, bytes); - cupsEncodeOptions(request, num_options, options); + cupsFileClose(fp); - /* - * Do the request... - */ - - snprintf(uri, sizeof(uri), "/printers/%s", name); - - if (num_files == 1) - response = cupsDoFileRequest(http, request, uri, *files); - else - response = cupsDoRequest(http, request, uri); - - if (response == NULL) - jobid = 0; - else if (response->request.status.status_code > IPP_OK_CONFLICT) - { - DEBUG_printf(("IPP response code was 0x%x!\n", - response->request.status.status_code)); - jobid = 0; - } - else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) - { - DEBUG_puts("No job ID!"); - - _cupsSetError(IPP_INTERNAL_ERROR, NULL); - - jobid = 0; - } - else - jobid = attr->values[0].integer; - - if (response != NULL) - ippDelete(response); - - /* - * Handle multiple file jobs if the create-job operation worked... - */ - - if (jobid > 0 && num_files > 1) - for (i = 0; i < num_files; i ++) + if (status != HTTP_CONTINUE || cupsFinishDocument(http, name) != IPP_OK) { /* - * Build a standard CUPS URI for the job and fill the standard IPP - * attributes... + * Unable to queue, cancel the job and return... */ - if ((request = ippNewRequest(IPP_SEND_DOCUMENT)) == NULL) - return (0); + cupsCancelJob2(http, job_id, 0); + return (0); + } + } - snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", jobid); + return (job_id); +} - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", - NULL, uri); - /* - * Handle raw print files... - */ +/* + * 'cupsStartDocument()' - Add a document to a job created with cupsCreateJob(). + * + * Use cupsWriteRequestData() to write data for the document and + * cupsFinishDocument() to finish the document and get the submission status. + * + * The MIME type constants CUPS_FORMAT_AUTO, CUPS_FORMAT_PDF, + * CUPS_FORMAT_POSTSCRIPT, CUPS_FORMAT_RAW, and CUPS_FORMAT_TEXT are provided + * for the "format" argument, although any supported MIME type string can be + * supplied. + * + * @since CUPS 1.4@ + */ - if (cupsGetOption("raw", num_options, options)) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, - "document-format", NULL, "application/vnd.cups-raw"); - else if ((val = cupsGetOption("document-format", num_options, - options)) != NULL) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, - "document-format", NULL, val); - else - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, - "document-format", NULL, "application/octet-stream"); +http_status_t /* O - HTTP status of request */ +cupsStartDocument( + http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + const char *name, /* I - Printer or class name */ + int job_id, /* I - Job ID from cupsCreateJob() */ + const char *docname, /* I - Name of document */ + const char *format, /* I - MIME type or CUPS_FORMAT_foo */ + int last_document) /* I - 1 for last document in job, 0 otherwise */ +{ + char resource[1024], /* Resource for destinatio */ + printer_uri[1024]; /* Printer URI */ + ipp_t *request; /* Send-Document request */ + http_status_t status; /* HTTP status */ - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - "requesting-user-name", NULL, cupsUser()); - /* - * Add the original document filename... - */ + /* + * Create a Send-Document request... + */ - if ((base = strrchr(files[i], '/')) != NULL) - base ++; - else - base = files[i]; + if ((request = ippNewRequest(IPP_SEND_DOCUMENT)) == NULL) + { + _cupsSetError(IPP_INTERNAL_ERROR, NULL); + return (0); + } - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", - NULL, base); + httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp", + NULL, "localhost", ippPort(), "/printers/%s", name); + snprintf(resource, sizeof(resource), "/printers/%s", name); - /* - * Is this the last document? - */ + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, printer_uri); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + if (docname) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", + NULL, docname); + if (format) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, + "document-format", NULL, format); + ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", last_document); - if (i == (num_files - 1)) - ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); + /* + * Send and delete the request, then return the status... + */ - /* - * Send the file... - */ + status = cupsSendRequest(http, request, resource, CUPS_LENGTH_VARIABLE); - snprintf(uri, sizeof(uri), "/printers/%s", name); + ippDelete(request); - if ((response = cupsDoFileRequest(http, request, uri, - files[i])) != NULL) - ippDelete(response); - } - - return (jobid); + return (status); } /* - * 'cups_connect()' - Connect to the specified host... + * '_cupsConnect()' - Get the default server connection... */ -static char * /* I - Printer name or NULL */ -cups_connect(const char *name, /* I - Destination (printer[@host]) */ - char *printer, /* O - Printer name [HTTP_MAX_URI] */ - char *hostname) /* O - Hostname [HTTP_MAX_URI] */ +http_t * /* O - HTTP connection */ +_cupsConnect(void) { - char hostbuf[HTTP_MAX_URI], /* Name of host */ - http_hostname[HTTP_MAX_HOST]; /* Hostname associated with connection */ - _cups_globals_t *cg = _cupsGlobals();/* Pointer to library globals */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname)); + /* + * See if we are connected to the same server... + */ - if (name == NULL) + if (cg->http) { - _cupsSetError(IPP_BAD_REQUEST, NULL); + int port; /* Port for connection */ - return (NULL); - } - /* - * All jobs are now queued to cupsServer() to avoid hostname - * resolution problems and to ensure that the user sees all - * locally queued jobs locally. - */ + /* + * Get the port associated with the current connection... + */ - strlcpy(hostbuf, cupsServer(), sizeof(hostbuf)); +#ifdef AF_INET6 + if (cg->http->hostaddr->addr.sa_family == AF_INET6) + port = ntohs(cg->http->hostaddr->ipv6.sin6_port); + else +#endif /* AF_INET6 */ + if (cg->http->hostaddr->addr.sa_family == AF_INET) + port = ntohs(cg->http->hostaddr->ipv4.sin_port); + else + port = cg->ipp_port; - httpGetHostname(cg->http, http_hostname, sizeof(http_hostname)); + /* + * Compare the connection hostname, port, and encryption settings to + * the cached defaults; these were initialized the first time we + * connected... + */ - if (hostname != NULL) - strlcpy(hostname, hostbuf, HTTP_MAX_URI); - else - hostname = hostbuf; + if (strcmp(cg->http->hostname, cg->server) || cg->ipp_port != port || + (cg->http->encryption != cg->encryption && + cg->http->encryption == HTTP_ENCRYPT_NEVER)) + { + /* + * Need to close the current connection because something has changed... + */ - if (printer != NULL) - strlcpy(printer, name, HTTP_MAX_URI); - else - printer = (char *)name; - - if (cg->http != NULL) - { - if (!strcasecmp(http_hostname, hostname)) - return (printer); - - httpClose(cg->http); + httpClose(cg->http); + cg->http = NULL; + } } - DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort())); + /* + * (Re)connect as needed... + */ - if ((cg->http = httpConnectEncrypt(hostname, ippPort(), - cupsEncryption())) == NULL) + if (!cg->http) { - DEBUG_puts("Unable to connect to server!"); + if ((cg->http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + _cupsSetError(IPP_SERVICE_UNAVAILABLE, + errno ? strerror(errno) : "Unable to connect to host."); + } - _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno)); + /* + * Return the cached connection... + */ - return (NULL); - } - else - return (printer); + return (cg->http); } Index: cups/dest.c =================================================================== --- cups/dest.c (revision 7169) +++ cups/dest.c (working copy) @@ -265,20 +265,7 @@ int /* O - Number of destinations */ cupsGetDests(cups_dest_t **dests) /* O - Destinations */ { - int num_dests; /* Number of destinations */ - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - - - /* - * Connect to the CUPS server and get the destination list and options... - */ - - if (!cg->http) - cg->http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); - - num_dests = cupsGetDests2(cg->http, dests); - - return (num_dests); + return (cupsGetDests2(CUPS_HTTP_DEFAULT, dests)); } @@ -297,7 +284,7 @@ */ int /* O - Number of destinations */ -cupsGetDests2(http_t *http, /* I - HTTP connection */ +cupsGetDests2(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ cups_dest_t **dests) /* O - Destinations */ { int i; /* Looping var */ @@ -310,14 +297,14 @@ *instance; /* Pointer to instance name */ int num_reals; /* Number of real queues */ cups_dest_t *reals; /* Real queues */ - _cups_globals_t *cg = _cupsGlobals(); /* Global data */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * Range check the input... */ - if (!http || !dests) + if (!dests) return (0); /* @@ -461,7 +448,8 @@ * If NULL is returned, the destination does not exist or there is no default * destination. * - * If "http" is NULL, the connection to the default print server will be used. + * If "http" is CUPS_HTTP_DEFAULT, the connection to the default print server + * will be used. * * If "name" is NULL, the default printer for the current user will be returned. * @@ -472,7 +460,7 @@ */ cups_dest_t * /* O - Destination or NULL */ -cupsGetNamedDest(http_t *http, /* I - HTTP connection or NULL */ +cupsGetNamedDest(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ const char *name, /* I - Destination name or NULL */ const char *instance) /* I - Instance name or NULL */ { @@ -486,20 +474,6 @@ /* - * Connect to the server as needed... - */ - - if (!http) - { - if (!cg->http && - (cg->http = httpConnectEncrypt(cupsServer(), ippPort(), - cupsEncryption())) == NULL) - return (NULL); - - http = cg->http; - } - - /* * If "name" is NULL, find the default destination... */ @@ -634,7 +608,7 @@ /* - * 'cupsDestSetDefaultDest()' - Set the default destination. + * 'cupsSetDefaultDest()' - Set the default destination. * * @since CUPS 1.3@ */ @@ -681,17 +655,7 @@ cupsSetDests(int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - - - /* - * Connect to the CUPS server and save the destination list and options... - */ - - if (!cg->http) - cg->http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); - - cupsSetDests2(cg->http, num_dests, dests); + cupsSetDests2(CUPS_HTTP_DEFAULT, num_dests, dests); } @@ -705,7 +669,7 @@ */ int /* O - 0 on success, -1 on error */ -cupsSetDests2(http_t *http, /* I - HTTP connection */ +cupsSetDests2(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { @@ -723,14 +687,14 @@ cups_dest_t *temps, /* Temporary destinations */ *temp; /* Current temporary dest */ const char *val; /* Value of temporary option */ - _cups_globals_t *cg = _cupsGlobals(); /* Global data */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * Range check the input... */ - if (!http || !num_dests || !dests) + if (!num_dests || !dests) return (-1); /* @@ -1155,7 +1119,7 @@ */ static int /* O - Number of destinations */ -cups_get_sdests(http_t *http, /* I - HTTP connection */ +cups_get_sdests(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ ipp_op_t op, /* I - IPP operation */ const char *name, /* I - Name of destination */ int num_dests, /* I - Number of destinations */ Index: cups/cups.h =================================================================== --- cups/cups.h (revision 7169) +++ cups/cups.h (working copy) @@ -59,13 +59,21 @@ * Constants... */ -# define CUPS_VERSION 1.0400 +# define CUPS_VERSION 1.0399 # define CUPS_VERSION_MAJOR 1 # define CUPS_VERSION_MINOR 4 -# define CUPS_VERSION_PATCH 0 -# define CUPS_DATE_ANY -1 +# define CUPS_VERSION_PATCH -1 +# define CUPS_DATE_ANY (time_t)-1 +# define CUPS_FORMAT_AUTO "application/octet-stream" +# define CUPS_FORMAT_PDF "application/pdf" +# define CUPS_FORMAT_POSTSCRIPT "application/postscript" +# define CUPS_FORMAT_RAW "application/vnd.cups-raw" +# define CUPS_FORMAT_TEXT "text/plain" +# define CUPS_HTTP_DEFAULT (http_t *)0 +# define CUPS_LENGTH_VARIABLE (ssize_t)0 + /* * Types and structures... */ @@ -140,7 +148,7 @@ * Functions... */ -extern int cupsCancelJob(const char *printer, int job); +extern int cupsCancelJob(const char *name, int job_id); extern ipp_t *cupsDoFileRequest(http_t *http, ipp_t *request, const char *resource, const char *filename); @@ -152,13 +160,13 @@ extern const char *cupsGetDefault(void); extern int cupsGetJobs(cups_job_t **jobs, const char *dest, int myjobs, int completed); -extern const char *cupsGetPPD(const char *printer); +extern const char *cupsGetPPD(const char *name); extern int cupsGetPrinters(char ***printers) _CUPS_DEPRECATED; extern ipp_status_t cupsLastError(void); -extern int cupsPrintFile(const char *printer, const char *filename, +extern int cupsPrintFile(const char *name, const char *filename, const char *title, int num_options, cups_option_t *options); -extern int cupsPrintFiles(const char *printer, int num_files, +extern int cupsPrintFiles(const char *name, int num_files, const char **files, const char *title, int num_options, cups_option_t *options); extern char *cupsTempFile(char *filename, int len) _CUPS_DEPRECATED; @@ -206,14 +214,14 @@ extern const char *cupsGetDefault2(http_t *http) _CUPS_API_1_1_21; extern int cupsGetDests2(http_t *http, cups_dest_t **dests) _CUPS_API_1_1_21; extern int cupsGetJobs2(http_t *http, cups_job_t **jobs, - const char *dest, int myjobs, + const char *name, int myjobs, int completed) _CUPS_API_1_1_21; -extern const char *cupsGetPPD2(http_t *http, const char *printer) _CUPS_API_1_1_21; -extern int cupsPrintFile2(http_t *http, const char *printer, +extern const char *cupsGetPPD2(http_t *http, const char *name) _CUPS_API_1_1_21; +extern int cupsPrintFile2(http_t *http, const char *name, const char *filename, const char *title, int num_options, cups_option_t *options) _CUPS_API_1_1_21; -extern int cupsPrintFiles2(http_t *http, const char *printer, +extern int cupsPrintFiles2(http_t *http, const char *name, int num_files, const char **files, const char *title, int num_options, cups_option_t *options) _CUPS_API_1_1_21; @@ -249,11 +257,30 @@ cups_dest_t *dests) _CUPS_API_1_3; /**** New in CUPS 1.4 ****/ +extern ipp_status_t cupsCancelJob2(http_t *http, int job_id, int purge); +extern int cupsCreateJob(http_t *http, const char *name, + const char *title, int num_options, + cups_option_t *options) _CUPS_API_1_4; +extern ipp_status_t cupsFinishDocument(http_t *http, + const char *name) _CUPS_API_1_4; extern cups_dest_t *cupsGetNamedDest(http_t *http, const char *name, const char *instance) _CUPS_API_1_4; extern http_status_t cupsGetPPD3(http_t *http, const char *name, time_t *modtime, char *buffer, size_t bufsize) _CUPS_API_1_4; +extern ipp_t *cupsGetResponse(http_t *http, + const char *resource) _CUPS_API_1_4; +extern ssize_t cupsReadResponseData(http_t *http, char *buffer, + size_t length) _CUPS_API_1_4; +extern http_status_t cupsSendRequest(http_t *http, ipp_t *request, + const char *resource, + size_t length) _CUPS_API_1_4; +extern http_status_t cupsStartDocument(http_t *http, const char *name, + int job_id, const char *docname, + const char *format, + int last_document) _CUPS_API_1_4; +extern http_status_t cupsWriteRequestData(http_t *http, const char *buffer, + size_t length) _CUPS_API_1_4; # ifdef __cplusplus } Index: cups/request.c =================================================================== --- cups/request.c (revision 7169) +++ cups/request.c (working copy) @@ -3,7 +3,7 @@ * * IPP utilities for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -16,11 +16,15 @@ * * Contents: * - * cupsDoFileRequest() - Do an IPP request with a file. - * cupsDoIORequest() - Do an IPP request with file descriptors. - * cupsDoRequest() - Do an IPP request. - * _cupsSetError() - Set the last IPP status code and status-message. - * _cupsSetHTTPError() - Set the last error using the HTTP status. + * cupsDoFileRequest() - Do an IPP request with a file. + * cupsDoIORequest() - Do an IPP request with file descriptors. + * cupsDoRequest() - Do an IPP request. + * cupsGetResponse() - Get a response to an IPP request. + * cupsReadResponseData() - Read additional data after the IPP response. + * cupsSendRequest() - Send an IPP request. + * cupsWriteRequestData() - Write additional data after an IPP request. + * _cupsSetError() - Set the last IPP status code and status-message. + * _cupsSetHTTPError() - Set the last error using the HTTP status. */ /* @@ -52,7 +56,7 @@ */ ipp_t * /* O - Response data */ -cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ +cupsDoFileRequest(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ ipp_t *request, /* I - IPP request */ const char *resource, /* I - HTTP resource for POST */ const char *filename) /* I - File to send or NULL for none */ @@ -106,38 +110,45 @@ */ ipp_t * /* O - Response data */ -cupsDoIORequest(http_t *http, /* I - HTTP connection to server */ +cupsDoIORequest(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ ipp_t *request, /* I - IPP request */ const char *resource, /* I - HTTP resource for POST */ int infile, /* I - File to read from or -1 for none */ int outfile) /* I - File to write to or -1 for none */ { - ipp_t *response; /* IPP response data */ - size_t length; /* Content-Length value */ + ipp_t *response = NULL; /* IPP response data */ + size_t length = 0; /* Content-Length value */ http_status_t status; /* Status of HTTP request */ - int got_status; /* Did we get the status? */ - ipp_state_t state; /* State of IPP processing */ struct stat fileinfo; /* File information */ int bytes; /* Number of bytes read/written */ char buffer[32768]; /* Output buffer */ - http_status_t expect; /* Expect: header to use */ - DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n", - http, request, resource ? resource : "(null)", - filename ? filename : "(null)")); + DEBUG_printf(("cupsDoIORequest(http=%p, request=%p, resource=\"%s\"" + "infile=%d, outfile=%d)\n", http, request, + resource ? resource : "(null)", infile, outfile)); - if (http == NULL || request == NULL || resource == NULL) + /* + * Range check input... + */ + + if (!request || !resource) { - if (request != NULL) - ippDelete(request); + ippDelete(request); - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL)); return (NULL); } /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * See if we have a file to send... */ @@ -149,7 +160,7 @@ * Can't get file information! */ - _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, + _cupsSetError(errno == EBADF ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, strerror(errno)); ippDelete(request); @@ -173,10 +184,349 @@ return (NULL); } + +#ifndef WIN32 + if (!S_ISREG(fileinfo.st_mode)) + length = 0; /* Chunk when piping */ + else +#endif /* !WIN32 */ + length = ippLength(request) + fileinfo.st_size; } + else + length = ippLength(request); + /* + * Loop until we can send the request without authorization problems. + */ + + while (response == NULL) + { + DEBUG_puts("cupsDoFileRequest: setup..."); + + /* + * Send the request... + */ + + status = cupsSendRequest(http, request, resource, length); + + DEBUG_printf(("cupsDoFileRequest: status=%d\n", status)); + + if (status == HTTP_CONTINUE && request->state == IPP_DATA && infile >= 0) + { + DEBUG_puts("cupsDoFileRequest: file write..."); + + /* + * Send the file with the request... + */ + +#ifndef WIN32 + if (S_ISREG(fileinfo.st_mode)) +#endif /* WIN32 */ + lseek(infile, 0, SEEK_SET); + + while ((bytes = (int)read(infile, buffer, sizeof(buffer))) > 0) + { + if (httpCheck(http)) + { + if ((status = httpUpdate(http)) != HTTP_CONTINUE) + break; + } + + if (httpWrite2(http, buffer, bytes) < bytes) + break; + } + } + + /* + * Get the server's response... + */ + + if (status == HTTP_CONTINUE || status == HTTP_OK) + { + response = cupsGetResponse(http, resource); + status = http->status; + } + + if (response) + { + if (outfile >= 0) + { + /* + * Write trailing data to file... + */ + + while ((bytes = (int)httpRead2(http, buffer, sizeof(buffer))) > 0) + if (write(outfile, buffer, bytes) < bytes) + break; + } + else + { + /* + * Flush any remaining data... + */ + + httpFlush(http); + } + } + } + + /* + * Delete the original request and return the response... + */ + + ippDelete(request); + + return (response); +} + + +/* + * 'cupsDoRequest()' - Do an IPP request. + * + * This function sends the IPP request to the specified server, retrying + * and authenticating as necessary. The request is freed with ippDelete() + * after receiving a valid IPP response. + */ + +ipp_t * /* O - Response data */ +cupsDoRequest(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + ipp_t *request, /* I - IPP request */ + const char *resource) /* I - HTTP resource for POST */ +{ + return (cupsDoFileRequest(http, request, resource, NULL)); +} + + +/* + * 'cupsGetResponse()' - Get a response to an IPP request. + * + * Use this function to get the response for an IPP request sent using + * cupsSendDocument() or cupsSendRequest(). For requests that return + * additional data, use httpRead() after getting a successful response. + * + * @since CUPS 1.4@ + */ + +ipp_t * /* O - Response or NULL on HTTP error */ +cupsGetResponse(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + const char *resource) /* I - HTTP resource for POST */ +{ + http_status_t status; /* HTTP status */ + ipp_state_t state; /* IPP read state */ + ipp_t *response = NULL; /* IPP response */ + + + DEBUG_printf(("cupsGetReponse(http=%p)\n", http)); + + /* + * Connect to the default server as needed... + */ + + if (!http) + http = _cupsConnect(); + + if (!http || (http->state != HTTP_POST_RECV && http->state != HTTP_POST_SEND)) + return (NULL); + + /* + * Check for an unfinished chunked request... + */ + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + { + /* + * Send a 0-length chunk to finish off the request... + */ + + DEBUG_puts("cupsGetResponse: Finishing chunked POST..."); + + if (httpWrite2(http, "", 0) < 0) + return (NULL); + } + + /* + * Wait for a response from the server... + */ + + DEBUG_puts("cupsGetResponse: update..."); + + while ((status = httpUpdate(http)) == HTTP_CONTINUE) + /* Do nothing but update */; + + DEBUG_printf(("cupsGetResponse: status = %d\n", status)); + + if (status == HTTP_OK) + { + /* + * Get the IPP response... + */ + + response = ippNew(); + + while ((state = ippRead(http, response)) != IPP_DATA) + if (state == IPP_ERROR) + break; + + if (state == IPP_ERROR) + { + /* + * Delete the response... + */ + + DEBUG_puts("IPP read error!"); + + ippDelete(response); + response = NULL; + + _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno)); + } + } + else if (status != HTTP_ERROR) + { + /* + * Flush any error message... + */ + + httpFlush(http); + + /* + * Then handle encryption and authentication... + */ + + if (status == HTTP_UNAUTHORIZED) + { + /* + * See if we can do authentication... + */ + + DEBUG_puts("cupsGetResponse: Need authorization..."); + + if (!cupsDoAuthentication(http, "POST", resource)) + httpReconnect(http); + } + #ifdef HAVE_SSL + else if (status == HTTP_UPGRADE_REQUIRED) + { + /* + * Force a reconnect with encryption... + */ + + DEBUG_puts("cupsGetResponse: Need encryption..."); + + if (!httpReconnect(http)) + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); + } +#endif /* HAVE_SSL */ + } + + if (response) + { + ipp_attribute_t *attr; /* status-message attribute */ + + + attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); + + _cupsSetError(response->request.status.status_code, + attr ? attr->values[0].string.text : + ippErrorString(response->request.status.status_code)); + } + else if (status != HTTP_OK) + _cupsSetHTTPError(status); + + return (response); +} + + +/* + * 'cupsReadResponseData()' - Read additional data after the IPP response. + * + * This function is used after cupsGetResponse() to read the PPD or document + * files for CUPS_GET_PPD and CUPS_GET_DOCUMENT requests, respectively. + * + * @since CUPS 1.4@ + */ + +ssize_t /* O - Bytes read, 0 on EOF, -1 on error */ +cupsReadResponseData( + http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + char *buffer, /* I - Buffer to use */ + size_t length) /* I - Number of bytes to read */ +{ /* + * Get the default connection as needed... + */ + + if (!http) + { + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + if ((http = cg->http) == NULL) + { + _cupsSetError(IPP_INTERNAL_ERROR, "No active connection"); + return (-1); + } + } + + /* + * Then read from the HTTP connection... + */ + + return (httpRead2(http, buffer, length)); +} + + +/* + * 'cupsSendRequest()' - Send an IPP request. + * + * Use httpWrite() to write any additional data (document, PPD file, etc.) + * for the request, cupsGetResponse() to get the IPP response, and httpRead() + * to read any additional data following the response. Only one request can be + * sent/queued at a time. + * + * Unlike cupsDoFileRequest(), cupsDoIORequest(), and cupsDoRequest(), the + * request is not freed. + * + * @since CUPS 1.4@ + */ + +http_status_t /* O - Initial HTTP status */ +cupsSendRequest(http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + ipp_t *request, /* I - IPP request */ + const char *resource, /* I - Resource path */ + size_t length) /* I - Length of data to follow or CUPS_LENGTH_VARIABLE */ +{ + http_status_t status; /* Status of HTTP request */ + int got_status; /* Did we get the status? */ + ipp_state_t state; /* State of IPP processing */ + http_status_t expect; /* Expect: header to use */ + + + DEBUG_printf(("cupsSendRequest(http=%p, request=%p, resource=\"%s\", " + "length=" CUPS_LLFMT ")\n", http, request, + resource ? resource : "(null)", CUPS_LLCAST length)); + + /* + * Range check input... + */ + + if (!request || !resource) + { + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL)); + + return (HTTP_ERROR); + } + + /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + +#ifdef HAVE_SSL + /* * See if we have an auth-info attribute and are communicating over * a non-local link. If so, encrypt the link so that we can pass * the authentication information securely... @@ -185,57 +535,42 @@ if (ippFindAttribute(request, "auth-info", IPP_TAG_TEXT) && !httpAddrLocalhost(http->hostaddr) && !http->tls && httpEncryption(http, HTTP_ENCRYPT_REQUIRED)) - return (NULL); + return (HTTP_ERROR); #endif /* HAVE_SSL */ /* * Loop until we can send the request without authorization problems. */ - response = NULL; - status = HTTP_ERROR; - expect = HTTP_CONTINUE; + status = HTTP_ERROR; + expect = HTTP_CONTINUE; - while (response == NULL) + for (;;) { - DEBUG_puts("cupsDoFileRequest: setup..."); + DEBUG_puts("cupsSendRequest: setup..."); /* * Setup the HTTP variables needed... */ - length = ippLength(request); - if (infile >= 0) - { -#ifndef WIN32 - if (!S_ISREG(fileinfo.st_mode)) - length = 0; /* Chunk when piping */ - else -#endif /* !WIN32 */ - length += fileinfo.st_size; - } - httpClearFields(http); httpSetLength(http, length); httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetExpect(http, expect); - DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->authstring)); + DEBUG_printf(("cupsSendRequest: authstring=\"%s\"\n", http->authstring)); /* * Try the request... */ - DEBUG_puts("cupsDoFileRequest: post..."); + DEBUG_puts("cupsSendRequest: post..."); if (httpPost(http, resource)) { if (httpReconnect(http)) - { - status = HTTP_ERROR; - break; - } + return (HTTP_ERROR); else continue; } @@ -244,7 +579,7 @@ * Send the IPP data... */ - DEBUG_puts("cupsDoFileRequest: ipp write..."); + DEBUG_puts("cupsSendRequest: ipp write..."); request->state = IPP_IDLE; status = HTTP_CONTINUE; @@ -261,226 +596,119 @@ break; } - if (!got_status) + /* + * Wait up to 1 second to get the 100-continue response as needed... + */ + + if (!got_status && expect == HTTP_CONTINUE) { - /* - * Wait up to 1 second to get the 100-continue response... - */ - if (httpWait(http, 1000)) status = httpUpdate(http); } else if (httpCheck(http)) status = httpUpdate(http); - if (status == HTTP_CONTINUE && state == IPP_DATA && infile >= 0) - { - DEBUG_puts("cupsDoFileRequest: file write..."); - - /* - * Send the file... - */ - -#ifndef WIN32 - if (S_ISREG(fileinfo.st_mode)) -#endif /* WIN32 */ - lseek(infile, 0, SEEK_SET); - - while ((bytes = (int)read(infile, buffer, sizeof(buffer))) > 0) - { - if (httpCheck(http)) - { - if ((status = httpUpdate(http)) != HTTP_CONTINUE) - break; - } - - if (httpWrite2(http, buffer, bytes) < bytes) - break; - } - } - /* - * Get the server's return status... + * Process the current HTTP status... */ - DEBUG_puts("cupsDoFileRequest: update..."); - - while (status == HTTP_CONTINUE) - status = httpUpdate(http); - - DEBUG_printf(("cupsDoFileRequest: status = %d\n", status)); - - if (status == HTTP_UNAUTHORIZED) + switch (status) { - DEBUG_puts("cupsDoFileRequest: unauthorized..."); + case HTTP_ERROR : + case HTTP_CONTINUE : + case HTTP_OK : + return (status); - /* - * Flush any error message... - */ + case HTTP_UNAUTHORIZED : + if (!cupsDoAuthentication(http, "POST", resource)) + if (httpReconnect(http)) + return (HTTP_ERROR); - httpFlush(http); + return (status); - /* - * See if we can do authentication... - */ - - if (cupsDoAuthentication(http, "POST", resource)) - break; - - if (httpReconnect(http)) - { - status = HTTP_ERROR; - break; - } - - continue; - } - else if (status == HTTP_ERROR) - { - DEBUG_printf(("cupsDoFileRequest: http->error=%d (%s)\n", http->error, - strerror(http->error))); - -#ifdef WIN32 - if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH && - http->error != WSAETIMEDOUT) -#else - if (http->error != ENETDOWN && http->error != ENETUNREACH && - http->error != ETIMEDOUT) -#endif /* WIN32 */ - continue; - else - break; - } #ifdef HAVE_SSL - else if (status == HTTP_UPGRADE_REQUIRED) - { - /* Flush any error message... */ - httpFlush(http); + case HTTP_UPGRADE_REQUIRED : + /* + * Flush any error message, reconnect, and then upgrade with + * encryption... + */ - /* Reconnect... */ - if (httpReconnect(http)) - { - status = HTTP_ERROR; - break; - } + if (httpReconnect(http)) + return (HTTP_ERROR); - /* Upgrade with encryption... */ - httpEncryption(http, HTTP_ENCRYPT_REQUIRED); + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); - /* Try again, this time with encryption enabled... */ - continue; - } + return (status); #endif /* HAVE_SSL */ - else if (status == HTTP_EXPECTATION_FAILED) - { - /* - * Don't try using the Expect: header the next time around... - */ - expect = (http_status_t)0; - } - else if (status != HTTP_OK) - { - DEBUG_printf(("cupsDoFileRequest: error %d...\n", status)); + case HTTP_EXPECTATION_FAILED : + /* + * Don't try using the Expect: header the next time around... + */ - /* - * Flush any error message... - */ + expect = (http_status_t)0; - httpFlush(http); - break; + default : + /* + * Some other error... + */ + + return (status); } - else - { - /* - * Read the response... - */ + } +} - DEBUG_puts("cupsDoFileRequest: response..."); - response = ippNew(); +/* + * 'cupsWriteRequestData()' - Write additional data after an IPP request. + * + * This function is used after cupsSendRequest() or cupsStartDocument() + * to provide a PPD or document file as needed. + * + * @since CUPS 1.4@ + */ - while ((state = ippRead(http, response)) != IPP_DATA) - if (state == IPP_ERROR) - break; +http_status_t /* O - HTTP_CONTINUE if OK or HTTP status on error */ +cupsWriteRequestData( + http_t *http, /* I - HTTP connection or CUPS_HTTP_DEFAULT */ + const char *buffer, /* I - Bytes to write */ + size_t length) /* I - Number of bytes to write */ +{ + /* + * Get the default connection as needed... + */ - if (state == IPP_ERROR) - { - /* - * Delete the response... - */ + if (!http) + { + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ - DEBUG_puts("IPP read error!"); - ippDelete(response); - response = NULL; - - _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno)); - - break; - } - else if (outfile >= 0) - { - /* - * Write trailing data to file... - */ - - while ((bytes = (int)httpRead2(http, buffer, sizeof(buffer))) > 0) - if (write(outfile, buffer, bytes) < bytes) - break; - } - else - { - /* - * Flush any remaining data... - */ - - httpFlush(http); - } + if ((http = cg->http) == NULL) + { + _cupsSetError(IPP_INTERNAL_ERROR, "No active connection"); + return (HTTP_ERROR); } } /* - * Delete the original request and return the response... + * Then write to the HTTP connection... */ - - ippDelete(request); - if (response) - { - ipp_attribute_t *attr; /* status-message attribute */ + if (httpWrite2(http, buffer, length) < 0) + return (HTTP_ERROR); + /* + * Finally, check if we have any pending data from the server... + */ - attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); - - _cupsSetError(response->request.status.status_code, - attr ? attr->values[0].string.text : - ippErrorString(response->request.status.status_code)); - } - else if (status != HTTP_OK) - _cupsSetHTTPError(status); - - return (response); + if (httpCheck(http)) + return (httpUpdate(http)); + else + return (HTTP_CONTINUE); } /* - * 'cupsDoRequest()' - Do an IPP request. - * - * This function sends the IPP request to the specified server, retrying - * and authenticating as necessary. The request is freed with ippDelete() - * after receiving a valid IPP response. - */ - -ipp_t * /* O - Response data */ -cupsDoRequest(http_t *http, /* I - HTTP connection to server */ - ipp_t *request, /* I - IPP request */ - const char *resource) /* I - HTTP resource for POST */ -{ - return (cupsDoFileRequest(http, request, resource, NULL)); -} - - -/* * '_cupsSetError()' - Set the last IPP status code and status-message. */ Index: cups/libcups.exp =================================================================== --- cups/libcups.exp (revision 7169) +++ cups/libcups.exp (working copy) @@ -62,7 +62,9 @@ _cupsBackChannelWrite _cupsBackendDeviceURI _cupsCancelJob +_cupsCancelJob2 _cupsCharsetToUTF8 +_cupsCreateJob _cupsDirClose _cupsDirOpen _cupsDirRead @@ -100,6 +102,7 @@ _cupsFileTell _cupsFileUnlock _cupsFileWrite +_cupsFinishDocument _cupsFreeDests _cupsFreeJobs _cupsFreeOptions @@ -120,6 +123,7 @@ _cupsGetPPD2 _cupsGetPPD3 _cupsGetPrinters +_cupsGetResponse _cupsGetServerPPD _cupsLangDefault _cupsLangEncoding @@ -138,8 +142,10 @@ _cupsPrintFiles2 _cupsPutFd _cupsPutFile +_cupsReadResponseData _cupsRemoveDest _cupsRemoveOption +_cupsSendRequest _cupsServer _cupsSetDefaultDest _cupsSetDests @@ -151,6 +157,7 @@ _cupsSideChannelDoRequest _cupsSideChannelRead _cupsSideChannelWrite +_cupsStartDocument _cupsTempFd _cupsTempFile _cupsTempFile2 @@ -158,6 +165,7 @@ _cupsUTF32ToUTF8 _cupsUTF8ToCharset _cupsUTF8ToUTF32 +_cupsWriteRequestData _httpAddrAny _httpAddrConnect _httpAddrEqual Index: cups/globals.h =================================================================== --- cups/globals.h (revision 7169) +++ cups/globals.h (working copy) @@ -124,6 +124,7 @@ * Prototypes... */ +extern http_t *_cupsConnect(void); extern const char *_cupsGetPassword(const char *prompt); extern _cups_globals_t *_cupsGlobals(void); extern void _cupsSetError(ipp_status_t status, const char *message); Index: systemv/lp.c =================================================================== --- systemv/lp.c (revision 7169) +++ systemv/lp.c (working copy) @@ -17,7 +17,6 @@ * main() - Parse options and send files for printing. * restart_job() - Restart a job. * set_job_attrs() - Set job attributes. - * sighandler() - Signal catcher for when we print from stdin... */ /* @@ -32,30 +31,16 @@ #include -#ifndef WIN32 -# include -# include - - /* * Local functions. */ -void sighandler(int); -#endif /* !WIN32 */ int restart_job(const char *command, int job_id); int set_job_attrs(const char *command, int job_id, int num_options, cups_option_t *options); /* - * Globals... - */ - -char tempfile[1024]; /* Temporary file for printing from stdin */ - - -/* * 'main()' - Parse options and send files for printing. */ @@ -79,13 +64,6 @@ int end_options; /* No more options? */ int silent; /* Silent or verbose output? */ char buffer[8192]; /* Copy buffer */ - ssize_t bytes; /* Bytes copied */ - off_t filesize; /* Size of temp file */ - int temp; /* Temporary file descriptor */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Signal action */ - struct sigaction oldaction; /* Old signal action */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/ #ifdef __sun @@ -635,73 +613,38 @@ if (num_files > 0) job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options); - else + else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer, + title ? title : "(stdin)", + num_options, options)) > 0) { - num_files = 1; + http_status_t status; /* Write status */ + const char *format; /* Document format */ + ssize_t bytes; /* Bytes read */ -#ifndef WIN32 -# if defined(HAVE_SIGSET) - sigset(SIGHUP, sighandler); - if (sigset(SIGINT, sighandler) == SIG_IGN) - sigset(SIGINT, SIG_IGN); - sigset(SIGTERM, sighandler); -# elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - action.sa_handler = sighandler; - sigaction(SIGHUP, &action, NULL); - sigaction(SIGINT, NULL, &oldaction); - if (oldaction.sa_handler != SIG_IGN) - sigaction(SIGINT, &action, NULL); - sigaction(SIGTERM, &action, NULL); -# else - signal(SIGHUP, sighandler); - if (signal(SIGINT, sighandler) == SIG_IGN) - signal(SIGINT, SIG_IGN); - signal(SIGTERM, sighandler); -# endif -#endif /* !WIN32 */ + if (cupsGetOption("raw", num_options, options)) + format = CUPS_FORMAT_RAW; + else if ((format = cupsGetOption("document-format", num_options, + options)) == NULL) + format = CUPS_FORMAT_AUTO; - temp = cupsTempFd(tempfile, sizeof(tempfile)); + status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL, + format, 1); - if (temp < 0) - { - _cupsLangPrintf(stderr, - _("%s: Error - unable to create temporary file \"%s\" - %s\n"), - argv[0], tempfile, strerror(errno)); - return (1); - } + while (status == HTTP_CONTINUE && + (bytes = read(0, buffer, sizeof(buffer))) > 0) + status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes); - while ((bytes = read(0, buffer, sizeof(buffer))) > 0) - if (write(temp, buffer, bytes) < 0) - { - _cupsLangPrintf(stderr, - _("%s: Error - unable to write to temporary file " - "\"%s\" - %s\n"), - argv[0], tempfile, strerror(errno)); - close(temp); - unlink(tempfile); - return (1); - } - - filesize = lseek(temp, 0, SEEK_CUR); - close(temp); - - if (filesize <= 0) + if (status != HTTP_CONTINUE) { _cupsLangPrintf(stderr, - _("%s: Error - stdin is empty, so no job has been sent.\n"), - argv[0]); - unlink(tempfile); + _("%s: Error - unable to queue from stdin - %s\n"), + argv[0], httpStatus(status)); return (1); } - if (title) - job_id = cupsPrintFile(printer, tempfile, title, num_options, options); - else - job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options); - - unlink(tempfile); + if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK) + job_id = 0; } if (job_id < 1) @@ -725,13 +668,10 @@ restart_job(const char *command, /* I - Command name */ int job_id) /* I - Job ID */ { - http_t *http; /* HTTP connection to server */ ipp_t *request; /* IPP request */ char uri[HTTP_MAX_URI]; /* URI for job */ - http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); - request = ippNewRequest(IPP_RESTART_JOB); sprintf(uri, "ipp://localhost/jobs/%d", job_id); @@ -742,7 +682,7 @@ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); - ippDelete(cupsDoRequest(http, request, "/jobs")); + ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs")); if (cupsLastError() > IPP_OK_CONFLICT) { @@ -764,7 +704,6 @@ int num_options,/* I - Number of options */ cups_option_t *options) /* I - Options */ { - http_t *http; /* HTTP connection to server */ ipp_t *request; /* IPP request */ char uri[HTTP_MAX_URI]; /* URI for job */ @@ -772,8 +711,6 @@ if (num_options == 0) return (0); - http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); - request = ippNewRequest(IPP_SET_JOB_ATTRIBUTES); sprintf(uri, "ipp://localhost/jobs/%d", job_id); @@ -786,7 +723,7 @@ cupsEncodeOptions(request, num_options, options); - ippDelete(cupsDoRequest(http, request, "/jobs")); + ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs")); if (cupsLastError() > IPP_OK_CONFLICT) { @@ -798,29 +735,6 @@ } -#ifndef WIN32 /* - * 'sighandler()' - Signal catcher for when we print from stdin... - */ - -void -sighandler(int s) /* I - Signal number */ -{ - /* - * Remove the temporary file we're using to print from stdin... - */ - - unlink(tempfile); - - /* - * Exit... - */ - - exit(s); -} -#endif /* !WIN32 */ - - -/* * End of "$Id$". */