extend API to add streaming print function cupsPrintStream #2261

Closed
michaelrsweet opened this Issue Feb 23, 2007 · 6 comments

Comments

Projects
None yet
1 participant
Collaborator

michaelrsweet commented Feb 23, 2007

Version: 1.4-feature
CUPS.org User: pulse

currently, cupsPrintFile() is the only method of submitting a print job via the convenience functions provided by the API. cupsPrintFile() expects to be given the name of the file, then cupsPrintFile() opens and reads the file.

a streaming version of this function utilizing chunked transfer encoding would be a universally welcome addition to the API.

attached is a patch against cups-1.2 svn as of 2006-02-23 implementing cupsPrintStream(), just such a streaming print function.

the changes have been tested with linux-2.6.19.1/libc-2.3.6/gcc-4.0.3. cupsPrintFile() is modified in the patch to use cupsPrintStream() to reduce code duplication. lpr is also modified to use cupsPrintStream() for printing from stdin.

Collaborator

michaelrsweet commented Dec 21, 2007

CUPS.org User: mike

I've created a branch to track the development of this feature; we will not be using your example code, but have come up with a more general-purpose set of APIs for job and request submission.

Collaborator

michaelrsweet commented Dec 21, 2007

CUPS.org User: mike

The branch is:

http://svn.easysw.com/public/cups/branches/stream
Collaborator

michaelrsweet commented Jan 4, 2008

CUPS.org User: mike

The new API is now merged to trunk and consists of several new functions along with general support for the new CUPS_HTTP_DEFAULT constant for http_t * arguments to CUPS functions.

Collaborator

michaelrsweet commented Jan 4, 2008

"cups-stream.patch":

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 <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
@@ -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 <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <fcntl.h>
    @@ -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
Collaborator

michaelrsweet commented Jan 4, 2008

"str2261.patch":

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 <cups/cups.h>
    #include <cups/i18n.h>

-#ifndef WIN32
-# include <unistd.h>
-# include <signal.h>

/*

  • * 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));
Collaborator

michaelrsweet commented Jan 4, 2008

  • 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 <cups/i18n.h>

-#ifndef WIN32
-# include <unistd.h>

-# include <signal.h>

/*

  • 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$".
    */

michaelrsweet added this to the Stable milestone Mar 17, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment