]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/ipp.c
Refactor common on-demand socket setup code
[thirdparty/cups.git] / scheduler / ipp.c
index 9f076098d188df202e34695f0ec7800aed3b6f7e..c0c2222f003a57ba32b918edb69102ba08bbb983 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * "$Id$"
- *
  * IPP routines for the CUPS scheduler.
  *
  * Copyright 2007-2016 by Apple Inc.
@@ -1696,7 +1694,24 @@ add_job(cupsd_client_t  *con,            /* I - Client connection */
     attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
                         "job-hold-until", NULL, val);
   }
-  if (attr && strcmp(attr->values[0].string.text, "no-hold"))
+
+  if (printer->holding_new_jobs)
+  {
+   /*
+    * Hold all new jobs on this printer...
+    */
+
+    if (attr && strcmp(attr->values[0].string.text, "no-hold"))
+      cupsdSetJobHoldUntil(job, ippGetString(attr, 0, NULL), 0);
+    else
+      cupsdSetJobHoldUntil(job, "indefinite", 0);
+
+    job->state->values[0].integer = IPP_JOB_HELD;
+    job->state_value              = IPP_JOB_HELD;
+
+    ippSetString(job->attrs, &job->reasons, 0, "job-held-on-create");
+  }
+  else if (attr && strcmp(attr->values[0].string.text, "no-hold"))
   {
    /*
     * Hold job until specified time...
@@ -5200,6 +5215,123 @@ create_job(cupsd_client_t  *con,        /* I - Client connection */
 }
 
 
+/*
+ * 'create_local_bg_thread()' - Background thread for creating a local print queue.
+ */
+
+static void *                          /* O - Exit status */
+create_local_bg_thread(
+    cupsd_printer_t *printer)          /* I - Printer */
+{
+  cups_file_t  *from,                  /* Source file */
+               *to;                    /* Destination file */
+  char         fromppd[1024],          /* Source PPD */
+               toppd[1024],            /* Destination PPD */
+               scheme[32],             /* URI scheme */
+               userpass[256],          /* User:pass */
+               host[256],              /* Hostname */
+               resource[1024],         /* Resource path */
+               line[1024];             /* Line from PPD */
+  int          port;                   /* Port number */
+  http_encryption_t encryption;                /* Type of encryption to use */
+  http_t       *http;                  /* Connection to printer */
+  ipp_t                *request,               /* Request to printer */
+               *response;              /* Response from printer */
+  ipp_attribute_t *attr;               /* Attribute in response */
+
+
+ /*
+  * Try connecting to the printer...
+  */
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri);
+
+  if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri);
+    return (NULL);
+  }
+
+  if (!strcmp(scheme, "ipps") || port == 443)
+    encryption = HTTP_ENCRYPTION_ALWAYS;
+  else
+    encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+  if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsLastErrorString());
+    return (NULL);
+  }
+
+ /*
+  * Query the printer for its capabilities...
+  */
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Connected to %s:%d, sending Get-Printer-Attributes request...", printer->name, host, port);
+
+  request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri);
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all");
+
+  response = cupsDoRequest(http, request, resource);
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s", printer->name, ippErrorString(cupsLastError()));
+
+  // TODO: Grab printer icon file...
+  httpClose(http);
+
+ /*
+  * Write the PPD for the queue...
+  */
+
+  if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response))
+  {
+    if ((!printer->info || !*(printer->info)) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL)
+      cupsdSetString(&printer->info, ippGetString(attr, 0, NULL));
+
+    if ((!printer->location || !*(printer->location)) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL)
+      cupsdSetString(&printer->location, ippGetString(attr, 0, NULL));
+
+    if ((!printer->geo_location || !*(printer->geo_location)) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL)
+      cupsdSetString(&printer->geo_location, ippGetString(attr, 0, NULL));
+
+    if ((from = cupsFileOpen(fromppd, "r")) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno));
+      return (NULL);
+    }
+
+    snprintf(toppd, sizeof(toppd), "%s/ppd/%s.ppd", ServerRoot, printer->name);
+    if ((to = cupsdCreateConfFile(toppd, ConfigFilePerm)) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to create PPD for printer: %s", printer->name, strerror(errno));
+      cupsFileClose(from);
+      return (NULL);
+    }
+
+    while (cupsFileGets(from, line, sizeof(line)))
+      cupsFilePrintf(to, "%s\n", line);
+
+    cupsFileClose(from);
+    if (!cupsdCloseCreatedConfFile(to, toppd))
+    {
+      printer->config_time = time(NULL);
+      printer->state       = IPP_PSTATE_IDLE;
+      printer->accepting   = 1;
+
+      cupsdSetPrinterAttrs(printer);
+
+      cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name);
+      cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" is now available.", printer->name);
+    }
+  }
+  else
+    cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed.", printer->name);
+
+  return (NULL);
+}
+
+
 /*
  * 'create_local_printer()' - Create a local (temporary) print queue.
  */
@@ -5208,8 +5340,136 @@ static void
 create_local_printer(
     cupsd_client_t *con)               /* I - Client connection */
 {
-  // TODO: Finish me
-  (void)con;
+  ipp_attribute_t *device_uri,         /* device-uri attribute */
+               *printer_geo_location,  /* printer-geo-location attribute */
+               *printer_info,          /* printer-info attribute */
+               *printer_location,      /* printer-location attribute */
+               *printer_name;          /* printer-name attribute */
+  cupsd_printer_t *printer;            /* New printer */
+  http_status_t        status;                 /* Policy status */
+  char         name[128],              /* Sanitized printer name */
+               *nameptr,               /* Pointer into name */
+               uri[1024];              /* printer-uri-supported value */
+  const char   *ptr;                   /* Pointer into attribute value */
+
+
+ /*
+  * Require local access to create a local printer...
+  */
+
+  if (!httpAddrLocalhost(httpGetAddress(con->http)))
+  {
+    send_ipp_status(con, IPP_STATUS_ERROR_FORBIDDEN, _("Only local users can create a local printer."));
+    return;
+  }
+
+ /*
+  * Check any other policy limits...
+  */
+
+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+  {
+    send_http_error(con, status, NULL);
+    return;
+  }
+
+ /*
+  * Grab needed attributes...
+  */
+
+  if ((printer_name = ippFindAttribute(con->request, "printer-name", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(printer_name) != IPP_TAG_PRINTER || ippGetValueTag(printer_name) != IPP_TAG_NAME)
+  {
+    if (!printer_name)
+      send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "printer-name");
+    else if (ippGetGroupTag(printer_name) != IPP_TAG_PRINTER)
+      send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "printer-name");
+    else
+      send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "printer-name");
+
+    return;
+  }
+
+  for (nameptr = name, ptr = ippGetString(printer_name, 0, NULL); *ptr && nameptr < (name + sizeof(name) - 1); ptr ++)
+  {
+   /*
+    * Sanitize the printer name...
+    */
+
+    if (_cups_isalnum(*ptr))
+      *nameptr++ = *ptr;
+    else if (nameptr == name || nameptr[-1] != '_')
+      *nameptr++ = '_';
+  }
+
+  *nameptr = '\0';
+
+  if ((device_uri = ippFindAttribute(con->request, "device-uri", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(device_uri) != IPP_TAG_PRINTER || ippGetValueTag(device_uri) != IPP_TAG_URI)
+  {
+    if (!device_uri)
+      send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "device-uri");
+    else if (ippGetGroupTag(device_uri) != IPP_TAG_PRINTER)
+      send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "device-uri");
+    else
+      send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "device-uri");
+
+    return;
+  }
+
+  printer_geo_location = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI);
+  printer_info         = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT);
+  printer_location     = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT);
+
+ /*
+  * See if the printer already exists...
+  */
+
+  if ((printer = cupsdFindDest(name)) != NULL)
+  {
+    send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name);
+    goto add_printer_attributes;
+  }
+
+ /*
+  * Create the printer...
+  */
+
+  if ((printer = cupsdAddPrinter(name)) == NULL)
+  {
+    send_ipp_status(con, IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer."));
+    return;
+  }
+
+  cupsdSetDeviceURI(printer, ippGetString(device_uri, 0, NULL));
+
+  if (printer_geo_location)
+    cupsdSetString(&printer->geo_location, ippGetString(printer_geo_location, 0, NULL));
+  if (printer_info)
+    cupsdSetString(&printer->info, ippGetString(printer_info, 0, NULL));
+  if (printer_location)
+    cupsdSetString(&printer->location, ippGetString(printer_location, 0, NULL));
+
+  cupsdSetPrinterAttrs(printer);
+
+ /*
+  * Run a background thread to create the PPD...
+  */
+
+  _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer);
+
+ /*
+  * Return printer attributes...
+  */
+
+  send_ipp_status(con, IPP_STATUS_OK, _("Local printer created."));
+
+  add_printer_attributes:
+
+  ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
+  ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state);
+  add_printer_state_reasons(con, printer);
+
+  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name);
+  ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
 }
 
 
@@ -8645,6 +8905,8 @@ release_held_new_jobs(
                     "Printer \"%s\" now printing pending/new jobs (\"%s\").",
                     printer->name, get_username(con));
 
+  cupsdCheckJobs();
+
  /*
   * Everything was ok, so return OK status...
   */
@@ -11155,8 +11417,3 @@ validate_user(cupsd_job_t    *job,      /* I - Job */
   return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr,
                            con, owner) == HTTP_OK);
 }
-
-
-/*
- * End of "$Id$".
- */