Home | History | Annotate | Download | only in cups
      1 /*
      2  * Destination job support for CUPS.
      3  *
      4  * Copyright 2012-2016 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_ERRPR_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
     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   * Range check input...
     88   */
     89 
     90   if (!http || !dest || !info || job_id <= 0)
     91   {
     92     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
     93     DEBUG_puts("1cupsCloseDestJob: Bad arguments.");
     94     return (IPP_STATUS_ERROR_INTERNAL);
     95   }
     96 
     97  /*
     98   * Build a Close-Job or empty Send-Document request...
     99   */
    100 
    101   if ((attr = ippFindAttribute(info->attrs, "operations-supported",
    102                                IPP_TAG_ENUM)) != NULL)
    103   {
    104     for (i = 0; i < attr->num_values; i ++)
    105       if (attr->values[i].integer == IPP_OP_CLOSE_JOB)
    106       {
    107         request = ippNewRequest(IPP_OP_CLOSE_JOB);
    108         break;
    109       }
    110   }
    111 
    112   if (!request)
    113     request = ippNewRequest(IPP_OP_SEND_DOCUMENT);
    114 
    115   if (!request)
    116   {
    117     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
    118     DEBUG_puts("1cupsCloseDestJob: Unable to create Close-Job/Send-Document "
    119                "request.");
    120     return (IPP_STATUS_ERROR_INTERNAL);
    121   }
    122 
    123   ippSetVersion(request, info->version / 10, info->version % 10);
    124 
    125   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    126                NULL, info->uri);
    127   ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
    128                 job_id);
    129   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    130                NULL, cupsUser());
    131   if (ippGetOperation(request) == IPP_OP_SEND_DOCUMENT)
    132     ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
    133 
    134  /*
    135   * Send the request and return the status...
    136   */
    137 
    138   ippDelete(cupsDoRequest(http, request, info->resource));
    139 
    140   DEBUG_printf(("1cupsCloseDestJob: %s (%s)", ippErrorString(cupsLastError()),
    141                 cupsLastErrorString()));
    142 
    143   return (cupsLastError());
    144 }
    145 
    146 
    147 /*
    148  * 'cupsCreateDestJob()' - Create a job on a destination.
    149  *
    150  * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success, saving the job ID
    151  * in the variable pointed to by "job_id".
    152  *
    153  * @since CUPS 1.6/macOS 10.8@
    154  */
    155 
    156 ipp_status_t				/* O - IPP status code */
    157 cupsCreateDestJob(
    158     http_t        *http,		/* I - Connection to destination */
    159     cups_dest_t   *dest,		/* I - Destination */
    160     cups_dinfo_t  *info, 		/* I - Destination information */
    161     int           *job_id,		/* O - Job ID or 0 on error */
    162     const char    *title,		/* I - Job name */
    163     int           num_options,		/* I - Number of job options */
    164     cups_option_t *options)		/* I - Job options */
    165 {
    166   ipp_t			*request,	/* Create-Job request */
    167 			*response;	/* Create-Job response */
    168   ipp_attribute_t	*attr;		/* job-id attribute */
    169 
    170 
    171   DEBUG_printf(("cupsCreateDestJob(http=%p, dest=%p(%s/%s), info=%p, "
    172                 "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));
    173 
    174  /*
    175   * Range check input...
    176   */
    177 
    178   if (job_id)
    179     *job_id = 0;
    180 
    181   if (!http || !dest || !info || !job_id)
    182   {
    183     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    184     DEBUG_puts("1cupsCreateDestJob: Bad arguments.");
    185     return (IPP_STATUS_ERROR_INTERNAL);
    186   }
    187 
    188  /*
    189   * Build a Create-Job request...
    190   */
    191 
    192   if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL)
    193   {
    194     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
    195     DEBUG_puts("1cupsCreateDestJob: Unable to create Create-Job request.");
    196     return (IPP_STATUS_ERROR_INTERNAL);
    197   }
    198 
    199   ippSetVersion(request, info->version / 10, info->version % 10);
    200 
    201   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    202                NULL, info->uri);
    203   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    204                NULL, cupsUser());
    205   if (title)
    206     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
    207                  title);
    208 
    209   cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
    210   cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
    211   cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION);
    212 
    213  /*
    214   * Send the request and get the job-id...
    215   */
    216 
    217   response = cupsDoRequest(http, request, info->resource);
    218 
    219   if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
    220   {
    221     *job_id = attr->values[0].integer;
    222     DEBUG_printf(("1cupsCreateDestJob: job-id=%d", *job_id));
    223   }
    224 
    225   ippDelete(response);
    226 
    227  /*
    228   * Return the status code from the Create-Job request...
    229   */
    230 
    231   DEBUG_printf(("1cupsCreateDestJob: %s (%s)", ippErrorString(cupsLastError()),
    232                 cupsLastErrorString()));
    233 
    234   return (cupsLastError());
    235 }
    236 
    237 
    238 /*
    239  * 'cupsFinishDestDocument()' - Finish the current document.
    240  *
    241  * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success.
    242  *
    243  * @since CUPS 1.6/macOS 10.8@
    244  */
    245 
    246 ipp_status_t				/* O - Status of document submission */
    247 cupsFinishDestDocument(
    248     http_t       *http,			/* I - Connection to destination */
    249     cups_dest_t  *dest,			/* I - Destination */
    250     cups_dinfo_t *info) 		/* I - Destination information */
    251 {
    252   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));
    253 
    254  /*
    255   * Range check input...
    256   */
    257 
    258   if (!http || !dest || !info)
    259   {
    260     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    261     DEBUG_puts("1cupsFinishDestDocument: Bad arguments.");
    262     return (IPP_STATUS_ERROR_INTERNAL);
    263   }
    264 
    265  /*
    266   * Get the response at the end of the document and return it...
    267   */
    268 
    269   ippDelete(cupsGetResponse(http, info->resource));
    270 
    271   DEBUG_printf(("1cupsFinishDestDocument: %s (%s)",
    272                 ippErrorString(cupsLastError()), cupsLastErrorString()));
    273 
    274   return (cupsLastError());
    275 }
    276 
    277 
    278 /*
    279  * 'cupsStartDestDocument()' - Start a new document.
    280  *
    281  * "job_id" is the job ID returned by cupsCreateDestJob.  "docname" is the name
    282  * of the document/file being printed, "format" is the MIME media type for the
    283  * document (see CUPS_FORMAT_xxx constants), and "num_options" and "options"
    284  * are the options do be applied to the document. "last_document" should be 1
    285  * if this is the last document to be submitted in the job.  Returns
    286  * @code HTTP_CONTINUE@ on success.
    287  *
    288  * @since CUPS 1.6/macOS 10.8@
    289  */
    290 
    291 http_status_t				/* O - Status of document creation */
    292 cupsStartDestDocument(
    293     http_t        *http,		/* I - Connection to destination */
    294     cups_dest_t   *dest,		/* I - Destination */
    295     cups_dinfo_t  *info, 		/* I - Destination information */
    296     int           job_id,		/* I - Job ID */
    297     const char    *docname,		/* I - Document name */
    298     const char    *format,		/* I - Document format */
    299     int           num_options,		/* I - Number of document options */
    300     cups_option_t *options,		/* I - Document options */
    301     int           last_document)	/* I - 1 if this is the last document */
    302 {
    303   ipp_t		*request;		/* Send-Document request */
    304   http_status_t	status;			/* HTTP status */
    305 
    306 
    307   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));
    308 
    309  /*
    310   * Range check input...
    311   */
    312 
    313   if (!http || !dest || !info || job_id <= 0)
    314   {
    315     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    316     DEBUG_puts("1cupsStartDestDocument: Bad arguments.");
    317     return (HTTP_STATUS_ERROR);
    318   }
    319 
    320  /*
    321   * Create a Send-Document request...
    322   */
    323 
    324   if ((request = ippNewRequest(IPP_OP_SEND_DOCUMENT)) == NULL)
    325   {
    326     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
    327     DEBUG_puts("1cupsStartDestDocument: Unable to create Send-Document "
    328                "request.");
    329     return (HTTP_STATUS_ERROR);
    330   }
    331 
    332   ippSetVersion(request, info->version / 10, info->version % 10);
    333 
    334   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    335                NULL, info->uri);
    336   ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id);
    337   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    338                NULL, cupsUser());
    339   if (docname)
    340     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
    341                  NULL, docname);
    342   if (format)
    343     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
    344                  "document-format", NULL, format);
    345   ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", (char)last_document);
    346 
    347   cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
    348   cupsEncodeOptions2(request, num_options, options, IPP_TAG_DOCUMENT);
    349 
    350  /*
    351   * Send and delete the request, then return the status...
    352   */
    353 
    354   status = cupsSendRequest(http, request, info->resource, CUPS_LENGTH_VARIABLE);
    355 
    356   ippDelete(request);
    357 
    358   return (status);
    359 }
    360