Index: cups/request.c =================================================================== --- cups/request.c (revision 6305) +++ cups/request.c (working copy) @@ -36,6 +36,7 @@ #include "globals.h" #include "debug.h" +#include #include #include #include @@ -48,34 +49,33 @@ /* - * 'cupsDoFileRequest()' - Do an IPP request with a file. + * 'cupsDoStreamRequest()' - Do a stream request with a file. * * 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 */ -cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ - 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 */ +ipp_t * /* O - Response data */ +cupsDoStreamRequest(http_t *http, /* I - HTTP connection to server */ + ipp_t *request, /* I - IPP request */ + const char *resource, /* I - HTTP resource for POST */ + cups_stream_cb_t fpread, /* I - function pointer for read */ + void *arg) /* I - arbitrary arg to pass to fp */ { ipp_t *response; /* IPP response data */ size_t length; /* 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 */ - FILE *file; /* File to send */ - 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", + DEBUG_printf(("cupsDoStreamRequest(%p, %p, \'%s\', %p, %p)\n", http, request, resource ? resource : "(null)", - filename ? filename : "(null)")); + fpread ? fpread : "(null)", + arg ? arg : "(null)")); if (http == NULL || request == NULL || resource == NULL) { @@ -88,60 +88,6 @@ } /* - * See if we have a file to send... - */ - - if (filename != NULL) - { - if (stat(filename, &fileinfo)) - { - /* - * Can't get file information! - */ - - _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, - strerror(errno)); - - ippDelete(request); - - return (NULL); - } - -#ifdef WIN32 - if (fileinfo.st_mode & _S_IFDIR) -#else - if (S_ISDIR(fileinfo.st_mode)) -#endif /* WIN32 */ - { - /* - * Can't send a directory... - */ - - ippDelete(request); - - _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR)); - - return (NULL); - } - - if ((file = fopen(filename, "rb")) == NULL) - { - /* - * Can't open file! - */ - - _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, - strerror(errno)); - - ippDelete(request); - - return (NULL); - } - } - else - file = NULL; - - /* * Loop until we can send the request without authorization problems. */ @@ -151,29 +97,30 @@ while (response == NULL) { - DEBUG_puts("cupsDoFileRequest: setup..."); + DEBUG_puts("cupsDoStreamRequest: setup..."); /* * Setup the HTTP variables needed... */ length = ippLength(request); - if (filename) - length += fileinfo.st_size; httpClearFields(http); - httpSetLength(http, length); + if (fpread) + httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); + else + 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(("cupsDoStreamRequest: authstring=\"%s\"\n", http->authstring)); /* * Try the request... */ - DEBUG_puts("cupsDoFileRequest: post..."); + DEBUG_puts("cupsDoStreamRequest: post..."); if (httpPost(http, resource)) { @@ -190,7 +137,7 @@ * Send the IPP data... */ - DEBUG_puts("cupsDoFileRequest: ipp write..."); + DEBUG_puts("cupsDoStreamRequest: ipp write..."); request->state = IPP_IDLE; status = HTTP_CONTINUE; @@ -219,18 +166,19 @@ else if (httpCheck(http)) status = httpUpdate(http); - if (status == HTTP_CONTINUE && state == IPP_DATA && filename) + DEBUG_printf(("cupsDoStreamRequest: fpread=%p\n", fpread)); + + if (status == HTTP_CONTINUE && state == IPP_DATA && fpread) { - DEBUG_puts("cupsDoFileRequest: file write..."); + DEBUG_puts("cupsDoStreamRequest: file write..."); /* * Send the file... */ - rewind(file); - - while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0) + while ((bytes = (int)fpread(buffer, 1, sizeof(buffer), arg)) > 0) { + DEBUG_printf(("cupsDoStreamRequest: read %d bytes from stream\n", bytes)); if (httpCheck(http)) { if ((status = httpUpdate(http)) != HTTP_CONTINUE) @@ -239,23 +187,28 @@ if (httpWrite2(http, buffer, bytes) < bytes) break; + + httpFlushWrite(http); } + + httpWrite2(http, "", 0); + httpFlushWrite(http); } /* * Get the server's return status... */ - DEBUG_puts("cupsDoFileRequest: update..."); + DEBUG_puts("cupsDoStreamRequest: update..."); while (status == HTTP_CONTINUE) status = httpUpdate(http); - DEBUG_printf(("cupsDoFileRequest: status = %d\n", status)); + DEBUG_printf(("cupsDoStreamRequest: status = %d\n", status)); if (status == HTTP_UNAUTHORIZED) { - DEBUG_puts("cupsDoFileRequest: unauthorized..."); + DEBUG_puts("cupsDoStreamRequest: unauthorized..."); /* * Flush any error message... @@ -280,7 +233,7 @@ } else if (status == HTTP_ERROR) { - DEBUG_printf(("cupsDoFileRequest: http->error=%d (%s)\n", http->error, + DEBUG_printf(("cupsDoStreamRequest: http->error=%d (%s)\n", http->error, strerror(http->error))); #ifdef WIN32 @@ -324,7 +277,7 @@ } else if (status != HTTP_OK) { - DEBUG_printf(("cupsDoFileRequest: error %d...\n", status)); + DEBUG_printf(("cupsDoStreamRequest: error %d...\n", status)); /* * Flush any error message... @@ -339,7 +292,7 @@ * Read the response... */ - DEBUG_puts("cupsDoFileRequest: response..."); + DEBUG_puts("cupsDoStreamRequest: response..."); response = ippNew(); @@ -362,13 +315,6 @@ } /* - * Close the file if needed... - */ - - if (filename != NULL) - fclose(file); - - /* * Flush any remaining data... */ @@ -436,6 +382,87 @@ /* + * 'cupsDoFileRequest()' - Do an IPP request with a file. + * + * 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 */ +cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ + 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 */ +{ + FILE *file; /* File to send */ + struct stat fileinfo; /* File information */ + ipp_t *response; /* IPP response data */ + + DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n", + http, request, resource ? resource : "(null)", + filename ? filename : "(null)")); + + if (filename != NULL) + { + if (stat(filename, &fileinfo)) + { + /* + * Can't get file information! + */ + + _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, + strerror(errno)); + + ippDelete(request); + + return (NULL); + } + +#ifdef WIN32 + if (fileinfo.st_mode & _S_IFDIR) +#else + if (S_ISDIR(fileinfo.st_mode)) +#endif /* WIN32 */ + { + /* + * Can't send a directory... + */ + + ippDelete(request); + + _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR)); + + return (NULL); + } + + if ((file = fopen(filename, "rb")) == NULL) + { + /* + * Can't open file! + */ + + _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, + strerror(errno)); + + ippDelete(request); + + return (NULL); + } + } + else + file = NULL; + + response = cupsDoStreamRequest(http, request, resource, file ? (cups_stream_cb_t) fread : NULL, file); + + if (file) + fclose(file); + + return (response); +} + + +/* * 'cupsDoRequest()' - Do an IPP request. * * This function sends the IPP request to the specified server, retrying Index: berkeley/lpr.c =================================================================== --- berkeley/lpr.c (revision 6305) +++ berkeley/lpr.c (working copy) @@ -429,70 +429,7 @@ } else { - num_files = 1; - -#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 ((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); - } - - 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) - { - _cupsLangPrintf(stderr, - _("%s: Error - stdin is empty, so no job has been sent.\n"), - argv[0]); - unlink(tempfile); - 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); + job_id = cupsPrintStream(NULL, printer, (cups_stream_cb_t) fread, stdin, title, num_options, options); } if (job_id < 1) @@ -504,30 +441,6 @@ return (0); } - -#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/cups.h =================================================================== --- cups/cups.h (revision 6305) +++ cups/cups.h (working copy) @@ -110,6 +110,8 @@ CUPS_PRINTER_OPTIONS = 0xe6fffc /* ~(CLASS | REMOTE | IMPLICIT) */ }; +typedef size_t (*cups_stream_cb_t)(void *, size_t, size_t, void *); + /**** Streaming callback ****/ typedef const char *(*cups_password_cb_t)(const char *); /**** Password callback ****/ @@ -243,6 +245,15 @@ cups_option_t **options); extern cups_file_t *cupsTempFile2(char *filename, int len); +/**** New in CUPS 1.2.? ****/ +extern int cupsPrintStream(http_t *http, const char *printer, + cups_stream_cb_t fpread, void *arg, + const char *title, int num_options, + cups_option_t *options); +extern ipp_t *cupsDoStreamRequest(http_t *http, ipp_t *request, + const char *resource, + cups_stream_cb_t fpread, + void *arg); # ifdef __cplusplus } Index: cups/request.c =================================================================== --- cups/request.c (revision 6305) +++ cups/request.c (working copy) @@ -36,6 +36,7 @@ #include "globals.h" #include "debug.h" +#include #include #include #include @@ -48,34 +49,33 @@ /* - * 'cupsDoFileRequest()' - Do an IPP request with a file. + * 'cupsDoStreamRequest()' - Do a stream request with a file. * * 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 */ -cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ - 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 */ +ipp_t * /* O - Response data */ +cupsDoStreamRequest(http_t *http, /* I - HTTP connection to server */ + ipp_t *request, /* I - IPP request */ + const char *resource, /* I - HTTP resource for POST */ + cups_stream_cb_t fpread, /* I - function pointer for read */ + void *arg) /* I - arbitrary arg to pass to fp */ { ipp_t *response; /* IPP response data */ size_t length; /* 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 */ - FILE *file; /* File to send */ - 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", + DEBUG_printf(("cupsDoStreamRequest(%p, %p, \'%s\', %p, %p)\n", http, request, resource ? resource : "(null)", - filename ? filename : "(null)")); + fpread ? fpread : "(null)", + arg ? arg : "(null)")); if (http == NULL || request == NULL || resource == NULL) { @@ -88,60 +88,6 @@ } /* - * See if we have a file to send... - */ - - if (filename != NULL) - { - if (stat(filename, &fileinfo)) - { - /* - * Can't get file information! - */ - - _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, - strerror(errno)); - - ippDelete(request); - - return (NULL); - } - -#ifdef WIN32 - if (fileinfo.st_mode & _S_IFDIR) -#else - if (S_ISDIR(fileinfo.st_mode)) -#endif /* WIN32 */ - { - /* - * Can't send a directory... - */ - - ippDelete(request); - - _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR)); - - return (NULL); - } - - if ((file = fopen(filename, "rb")) == NULL) - { - /* - * Can't open file! - */ - - _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, - strerror(errno)); - - ippDelete(request); - - return (NULL); - } - } - else - file = NULL; - - /* * Loop until we can send the request without authorization problems. */ @@ -151,29 +97,30 @@ while (response == NULL) { - DEBUG_puts("cupsDoFileRequest: setup..."); + DEBUG_puts("cupsDoStreamRequest: setup..."); /* * Setup the HTTP variables needed... */ length = ippLength(request); - if (filename) - length += fileinfo.st_size; httpClearFields(http); - httpSetLength(http, length); + if (fpread) + httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); + else + 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(("cupsDoStreamRequest: authstring=\"%s\"\n", http->authstring)); /* * Try the request... */ - DEBUG_puts("cupsDoFileRequest: post..."); + DEBUG_puts("cupsDoStreamRequest: post..."); if (httpPost(http, resource)) { @@ -190,7 +137,7 @@ * Send the IPP data... */ - DEBUG_puts("cupsDoFileRequest: ipp write..."); + DEBUG_puts("cupsDoStreamRequest: ipp write..."); request->state = IPP_IDLE; status = HTTP_CONTINUE; @@ -219,18 +166,19 @@ else if (httpCheck(http)) status = httpUpdate(http); - if (status == HTTP_CONTINUE && state == IPP_DATA && filename) + DEBUG_printf(("cupsDoStreamRequest: fpread=%p\n", fpread)); + + if (status == HTTP_CONTINUE && state == IPP_DATA && fpread) { - DEBUG_puts("cupsDoFileRequest: file write..."); + DEBUG_puts("cupsDoStreamRequest: file write..."); /* * Send the file... */ - rewind(file); - - while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0) + while ((bytes = (int)fpread(buffer, 1, sizeof(buffer), arg)) > 0) { + DEBUG_printf(("cupsDoStreamRequest: read %d bytes from stream\n", bytes)); if (httpCheck(http)) { if ((status = httpUpdate(http)) != HTTP_CONTINUE) @@ -239,23 +187,28 @@ if (httpWrite2(http, buffer, bytes) < bytes) break; + + httpFlushWrite(http); } + + httpWrite2(http, "", 0); + httpFlushWrite(http); } /* * Get the server's return status... */ - DEBUG_puts("cupsDoFileRequest: update..."); + DEBUG_puts("cupsDoStreamRequest: update..."); while (status == HTTP_CONTINUE) status = httpUpdate(http); - DEBUG_printf(("cupsDoFileRequest: status = %d\n", status)); + DEBUG_printf(("cupsDoStreamRequest: status = %d\n", status)); if (status == HTTP_UNAUTHORIZED) { - DEBUG_puts("cupsDoFileRequest: unauthorized..."); + DEBUG_puts("cupsDoStreamRequest: unauthorized..."); /* * Flush any error message... @@ -280,7 +233,7 @@ } else if (status == HTTP_ERROR) { - DEBUG_printf(("cupsDoFileRequest: http->error=%d (%s)\n", http->error, + DEBUG_printf(("cupsDoStreamRequest: http->error=%d (%s)\n", http->error, strerror(http->error))); #ifdef WIN32 @@ -324,7 +277,7 @@ } else if (status != HTTP_OK) { - DEBUG_printf(("cupsDoFileRequest: error %d...\n", status)); + DEBUG_printf(("cupsDoStreamRequest: error %d...\n", status)); /* * Flush any error message... @@ -339,7 +292,7 @@ * Read the response... */ - DEBUG_puts("cupsDoFileRequest: response..."); + DEBUG_puts("cupsDoStreamRequest: response..."); response = ippNew(); @@ -362,13 +315,6 @@ } /* - * Close the file if needed... - */ - - if (filename != NULL) - fclose(file); - - /* * Flush any remaining data... */ @@ -436,6 +382,87 @@ /* + * 'cupsDoFileRequest()' - Do an IPP request with a file. + * + * 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 */ +cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ + 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 */ +{ + FILE *file; /* File to send */ + struct stat fileinfo; /* File information */ + ipp_t *response; /* IPP response data */ + + DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n", + http, request, resource ? resource : "(null)", + filename ? filename : "(null)")); + + if (filename != NULL) + { + if (stat(filename, &fileinfo)) + { + /* + * Can't get file information! + */ + + _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, + strerror(errno)); + + ippDelete(request); + + return (NULL); + } + +#ifdef WIN32 + if (fileinfo.st_mode & _S_IFDIR) +#else + if (S_ISDIR(fileinfo.st_mode)) +#endif /* WIN32 */ + { + /* + * Can't send a directory... + */ + + ippDelete(request); + + _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR)); + + return (NULL); + } + + if ((file = fopen(filename, "rb")) == NULL) + { + /* + * Can't open file! + */ + + _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, + strerror(errno)); + + ippDelete(request); + + return (NULL); + } + } + else + file = NULL; + + response = cupsDoStreamRequest(http, request, resource, file ? (cups_stream_cb_t) fread : NULL, file); + + if (file) + fclose(file); + + return (response); +} + + +/* * 'cupsDoRequest()' - Do an IPP request. * * This function sends the IPP request to the specified server, retrying