Home | History | Annotate | Download | only in cups
      1 /*
      2  * Destination job support for CUPS.
      3  *
      4  * Copyright 2012-2017 by Apple Inc.
      5  *
      6  * These coded instructions, statements, and computer programs are the
      7  * property of Apple Inc. and are protected by Federal copyright
      8  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
      9  * which should have been included with this file.  If this file is
     10  * missing or damaged, see the license at "http://www.cups.org/".
     11  *
     12  * This file is subject to the Apple OS-Developed Software exception.
     13  */
     14 
     15 /*
     16  * Include necessary headers...
     17  */
     18 
     19 #include "cups-private.h"
     20 
     21 
     22 /*
     23  * 'cupsCancelDestJob()' - Cancel a job on a destination.
     24  *
     25  * The "job_id" is the number returned by cupsCreateDestJob.
     26  *
     27  * Returns @code IPP_STATUS_OK@ on success and
     28  * @code IPP_STATUS_ERROR_NOT_AUTHORIZED@ or
     29  * @code IPP_STATUS_ERROR_FORBIDDEN@ on failure.
     30  *
     31  * @since CUPS 1.6/macOS 10.8@
     32  */
     33 
     34 ipp_status_t                            /* O - Status of cancel operation */
     35 cupsCancelDestJob(http_t      *http,	/* I - Connection to destination */
     36                   cups_dest_t *dest,	/* I - Destination */
     37                   int         job_id)	/* I - Job ID */
     38 {
     39   cups_dinfo_t	*info;			/* Destination information */
     40 
     41 
     42   if ((info = cupsCopyDestInfo(http, dest)) != NULL)
     43   {
     44     ipp_t	*request;		/* Cancel-Job request */
     45 
     46     request = ippNewRequest(IPP_OP_CANCEL_JOB);
     47 
     48     ippSetVersion(request, info->version / 10, info->version % 10);
     49 
     50     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri);
     51     ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id);
     52     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
     53 
     54     ippDelete(cupsDoRequest(http, request, info->resource));
     55     cupsFreeDestInfo(info);
     56   }
     57 
     58   return (cupsLastError());
     59 }
     60 
     61 
     62 /*
     63  * 'cupsCloseDestJob()' - Close a job and start printing.
     64  *
     65  * Use when the last call to cupsStartDocument passed 0 for "last_document".
     66  * "job_id" is the job ID returned by cupsCreateDestJob. Returns @code IPP_STATUS_OK@
     67  * on success.
     68  *
     69  * @since CUPS 1.6/macOS 10.8@
     70  */
     71 
     72 ipp_status_t				/* O - IPP status code */
     73 cupsCloseDestJob(
     74     http_t       *http,			/* I - Connection to destination */
     75     cups_dest_t  *dest,			/* I - Destination */
     76     cups_dinfo_t *info, 		/* I - Destination information */
     77     int          job_id)		/* I - Job ID */
     78 {
     79   int			i;		/* Looping var */
     80   ipp_t			*request = NULL;/* Close-Job/Send-Document request */
     81   ipp_attribute_t	*attr;		/* operations-supported attribute */
     82 
     83 
     84   DEBUG_printf(("cupsCloseDestJob(http=%p, dest=%p(%s/%s), info=%p, job_id=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id));
     85 
     86  /*
     87   * Get the default connection as needed...
     88   */
     89 
     90   if (!http)
     91     http = _cupsConnect();
     92 
     93  /*
     94   * Range check input...
     95   */
     96 
     97   if (!http || !dest || !info || job_id <= 0)
     98   {
     99     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    100     DEBUG_puts("1cupsCloseDestJob: Bad arguments.");
    101     return (IPP_STATUS_ERROR_INTERNAL);
    102   }
    103 
    104  /*
    105   * Build a Close-Job or empty Send-Document request...
    106   */
    107 
    108   if ((attr = ippFindAttribute(info->attrs, "operations-supported",
    109                                IPP_TAG_ENUM)) != NULL)
    110   {
    111     for (i = 0; i < attr->num_values; i ++)
    112       if (attr->values[i].integer == IPP_OP_CLOSE_JOB)
    113       {
    114         request = ippNewRequest(IPP_OP_CLOSE_JOB);
    115         break;
    116       }
    117   }
    118 
    119   if (!request)
    120     request = ippNewRequest(IPP_OP_SEND_DOCUMENT);
    121 
    122   if (!request)
    123   {
    124     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
    125     DEBUG_puts("1cupsCloseDestJob: Unable to create Close-Job/Send-Document "
    126                "request.");
    127     return (IPP_STATUS_ERROR_INTERNAL);
    128   }
    129 
    130   ippSetVersion(request, info->version / 10, info->version % 10);
    131 
    132   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    133                NULL, info->uri);
    134   ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
    135                 job_id);
    136   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    137                NULL, cupsUser());
    138   if (ippGetOperation(request) == IPP_OP_SEND_DOCUMENT)
    139     ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
    140 
    141  /*
    142   * Send the request and return the status...
    143   */
    144 
    145   ippDelete(cupsDoRequest(http, request, info->resource));
    146 
    147   DEBUG_printf(("1cupsCloseDestJob: %s (%s)", ippErrorString(cupsLastError()),
    148                 cupsLastErrorString()));
    149 
    150   return (cupsLastError());
    151 }
    152 
    153 
    154 /*
    155  * 'cupsCreateDestJob()' - Create a job on a destination.
    156  *
    157  * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success, saving the job ID
    158  * in the variable pointed to by "job_id".
    159  *
    160  * @since CUPS 1.6/macOS 10.8@
    161  */
    162 
    163 ipp_status_t				/* O - IPP status code */
    164 cupsCreateDestJob(
    165     http_t        *http,		/* I - Connection to destination */
    166     cups_dest_t   *dest,		/* I - Destination */
    167     cups_dinfo_t  *info, 		/* I - Destination information */
    168     int           *job_id,		/* O - Job ID or 0 on error */
    169     const char    *title,		/* I - Job name */
    170     int           num_options,		/* I - Number of job options */
    171     cups_option_t *options)		/* I - Job options */
    172 {
    173   ipp_t			*request,	/* Create-Job request */
    174 			*response;	/* Create-Job response */
    175   ipp_attribute_t	*attr;		/* job-id attribute */
    176 
    177 
    178   DEBUG_printf(("cupsCreateDestJob(http=%p, dest=%p(%s/%s), info=%p, "
    179                 "job_id=%p, title=\"%s\", num_options=%d, options=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, (void *)job_id, title, num_options, (void *)options));
    180 
    181  /*
    182   * Get the default connection as needed...
    183   */
    184 
    185   if (!http)
    186     http = _cupsConnect();
    187 
    188  /*
    189   * Range check input...
    190   */
    191 
    192   if (job_id)
    193     *job_id = 0;
    194 
    195   if (!http || !dest || !info || !job_id)
    196   {
    197     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    198     DEBUG_puts("1cupsCreateDestJob: Bad arguments.");
    199     return (IPP_STATUS_ERROR_INTERNAL);
    200   }
    201 
    202  /*
    203   * Build a Create-Job request...
    204   */
    205 
    206   if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL)
    207   {
    208     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
    209     DEBUG_puts("1cupsCreateDestJob: Unable to create Create-Job request.");
    210     return (IPP_STATUS_ERROR_INTERNAL);
    211   }
    212 
    213   ippSetVersion(request, info->version / 10, info->version % 10);
    214 
    215   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    216                NULL, info->uri);
    217   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    218                NULL, cupsUser());
    219   if (title)
    220     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
    221                  title);
    222 
    223   cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
    224   cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
    225   cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION);
    226 
    227  /*
    228   * Send the request and get the job-id...
    229   */
    230 
    231   response = cupsDoRequest(http, request, info->resource);
    232 
    233   if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
    234   {
    235     *job_id = attr->values[0].integer;
    236     DEBUG_printf(("1cupsCreateDestJob: job-id=%d", *job_id));
    237   }
    238 
    239   ippDelete(response);
    240 
    241  /*
    242   * Return the status code from the Create-Job request...
    243   */
    244 
    245   DEBUG_printf(("1cupsCreateDestJob: %s (%s)", ippErrorString(cupsLastError()),
    246                 cupsLastErrorString()));
    247 
    248   return (cupsLastError());
    249 }
    250 
    251 
    252 /*
    253  * 'cupsFinishDestDocument()' - Finish the current document.
    254  *
    255  * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success.
    256  *
    257  * @since CUPS 1.6/macOS 10.8@
    258  */
    259 
    260 ipp_status_t				/* O - Status of document submission */
    261 cupsFinishDestDocument(
    262     http_t       *http,			/* I - Connection to destination */
    263     cups_dest_t  *dest,			/* I - Destination */
    264     cups_dinfo_t *info) 		/* I - Destination information */
    265 {
    266   DEBUG_printf(("cupsFinishDestDocument(http=%p, dest=%p(%s/%s), info=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info));
    267 
    268  /*
    269   * Get the default connection as needed...
    270   */
    271 
    272   if (!http)
    273     http = _cupsConnect();
    274 
    275  /*
    276   * Range check input...
    277   */
    278 
    279   if (!http || !dest || !info)
    280   {
    281     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    282     DEBUG_puts("1cupsFinishDestDocument: Bad arguments.");
    283     return (IPP_STATUS_ERROR_INTERNAL);
    284   }
    285 
    286  /*
    287   * Get the response at the end of the document and return it...
    288   */
    289 
    290   ippDelete(cupsGetResponse(http, info->resource));
    291 
    292   DEBUG_printf(("1cupsFinishDestDocument: %s (%s)",
    293                 ippErrorString(cupsLastError()), cupsLastErrorString()));
    294 
    295   return (cupsLastError());
    296 }
    297 
    298 
    299 /*
    300  * 'cupsStartDestDocument()' - Start a new document.
    301  *
    302  * "job_id" is the job ID returned by cupsCreateDestJob.  "docname" is the name
    303  * of the document/file being printed, "format" is the MIME media type for the
    304  * document (see CUPS_FORMAT_xxx constants), and "num_options" and "options"
    305  * are the options do be applied to the document. "last_document" should be 1
    306  * if this is the last document to be submitted in the job.  Returns
    307  * @code HTTP_CONTINUE@ on success.
    308  *
    309  * @since CUPS 1.6/macOS 10.8@
    310  */
    311 
    312 http_status_t				/* O - Status of document creation */
    313 cupsStartDestDocument(
    314     http_t        *http,		/* I - Connection to destination */
    315     cups_dest_t   *dest,		/* I - Destination */
    316     cups_dinfo_t  *info, 		/* I - Destination information */
    317     int           job_id,		/* I - Job ID */
    318     const char    *docname,		/* I - Document name */
    319     const char    *format,		/* I - Document format */
    320     int           num_options,		/* I - Number of document options */
    321     cups_option_t *options,		/* I - Document options */
    322     int           last_document)	/* I - 1 if this is the last document */
    323 {
    324   ipp_t		*request;		/* Send-Document request */
    325   http_status_t	status;			/* HTTP status */
    326 
    327 
    328   DEBUG_printf(("cupsStartDestDocument(http=%p, dest=%p(%s/%s), info=%p, job_id=%d, docname=\"%s\", format=\"%s\", num_options=%d, options=%p, last_document=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id, docname, format, num_options, (void *)options, last_document));
    329 
    330  /*
    331   * Get the default connection as needed...
    332   */
    333 
    334   if (!http)
    335     http = _cupsConnect();
    336 
    337  /*
    338   * Range check input...
    339   */
    340 
    341   if (!http || !dest || !info || job_id <= 0)
    342   {
    343     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    344     DEBUG_puts("1cupsStartDestDocument: Bad arguments.");
    345     return (HTTP_STATUS_ERROR);
    346   }
    347 
    348  /*
    349   * Create a Send-Document request...
    350   */
    351 
    352   if ((request = ippNewRequest(IPP_OP_SEND_DOCUMENT)) == NULL)
    353   {
    354     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
    355     DEBUG_puts("1cupsStartDestDocument: Unable to create Send-Document "
    356                "request.");
    357     return (HTTP_STATUS_ERROR);
    358   }
    359 
    360   ippSetVersion(request, info->version / 10, info->version % 10);
    361 
    362   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    363                NULL, info->uri);
    364   ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id);
    365   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    366                NULL, cupsUser());
    367   if (docname)
    368     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
    369                  NULL, docname);
    370   if (format)
    371     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
    372                  "document-format", NULL, format);
    373   ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", (char)last_document);
    374 
    375   cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
    376   cupsEncodeOptions2(request, num_options, options, IPP_TAG_DOCUMENT);
    377 
    378  /*
    379   * Send and delete the request, then return the status...
    380   */
    381 
    382   status = cupsSendRequest(http, request, info->resource, CUPS_LENGTH_VARIABLE);
    383 
    384   ippDelete(request);
    385 
    386   return (status);
    387 }
    388