]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/cups-lpd.c
Merge changes from CUPS 1.4svn-r7961.
[thirdparty/cups.git] / scheduler / cups-lpd.c
index eda350c52655784d409e0cd987e242f33eee82bb..756d8fedb2962c07a5e709f6a866f35a3ffd1968 100644 (file)
@@ -1,25 +1,16 @@
 /*
- * "$Id: cups-lpd.c 5196 2006-02-27 21:23:00Z mike $"
+ * "$Id: cups-lpd.c 7899 2008-09-03 12:57:17Z mike $"
  *
  *   Line Printer Daemon interface for the Common UNIX Printing System (CUPS).
  *
+ *   Copyright 2007-2008 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  * Contents:
  *
  */
 
 static int     create_job(http_t *http, const char *dest, const char *title,
-                          const char *user, int num_options,
-                          cups_option_t *options);
+                           const char *docname, const char *user,
+                          int num_options, cups_option_t *options);
 static int     get_printer(http_t *http, const char *name, char *dest,
                            int destsize, cups_option_t **options,
                            int *accepting, int *shared, ipp_pstate_t *state);
 static int     print_file(http_t *http, int id, const char *filename,
-                          const char *docname, const char *user, int last);
+                          const char *docname, const char *user,
+                          const char *format, int last);
 static int     recv_print_job(const char *name, int num_defaults,
                               cups_option_t *defaults);
 static int     remove_jobs(const char *name, const char *agent,
@@ -128,6 +120,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
   char         hostname[256],          /* Name of client */
                hostip[256],            /* IP address */
                *hostfamily;            /* Address family */
+  int          hostlookups;            /* Do hostname lookups? */
 
 
  /*
@@ -142,48 +135,32 @@ main(int  argc,                           /* I - Number of command-line arguments */
 
   openlog("cups-lpd", LOG_PID, LOG_LPR);
 
- /*
-  * Get the address of the client...
-  */
-
-  hostlen = sizeof(hostaddr);
-
-  if (getpeername(0, (struct sockaddr *)&hostaddr, &hostlen))
-  {
-    syslog(LOG_WARNING, "Unable to get client address - %s", strerror(errno));
-    strcpy(hostname, "unknown");
-  }
-  else
-  {
-    httpAddrLookup(&hostaddr, hostname, sizeof(hostname));
-    httpAddrString(&hostaddr, hostip, sizeof(hostip));
-
-#ifdef AF_INET6
-    if (hostaddr.addr.sa_family == AF_INET6)
-      hostfamily = "IPv6";
-    else
-#endif /* AF_INET6 */
-    hostfamily = "IPv4";
-
-    syslog(LOG_INFO, "Connection from %s (%s %s)", hostname, hostfamily,
-           hostip);
-  }
-
  /*
   * Scan the command-line for options...
   */
 
   num_defaults = 0;
   defaults     = NULL;
-
-  num_defaults = cupsAddOption("job-originating-host-name", hostname,
-                               num_defaults, &defaults);
+  hostlookups  = 1;
 
   for (i = 1; i < argc; i ++)
     if (argv[i][0] == '-')
     {
       switch (argv[i][1])
       {
+        case 'h' : /* -h hostname[:port] */
+            if (argv[i][2])
+             cupsSetServer(argv[i] + 2);
+           else
+           {
+             i ++;
+             if (i < argc)
+               cupsSetServer(argv[i]);
+             else
+               syslog(LOG_WARNING, "Expected hostname string after -h option!");
+           }
+           break;
+
        case 'o' : /* Option */
            if (argv[i][2])
              num_defaults = cupsParseOptions(argv[i] + 2, num_defaults,
@@ -198,6 +175,11 @@ main(int  argc,                            /* I - Number of command-line arguments */
                syslog(LOG_WARNING, "Expected option string after -o option!");
             }
            break;
+
+        case 'n' : /* Don't do hostname lookups */
+           hostlookups = 0;
+           break;
+
        default :
            syslog(LOG_WARNING, "Unknown option \"%c\" ignored!", argv[i][1]);
            break;
@@ -207,6 +189,40 @@ main(int  argc,                            /* I - Number of command-line arguments */
       syslog(LOG_WARNING, "Unknown command-line option \"%s\" ignored!",
              argv[i]);
 
+ /*
+  * Get the address of the client...
+  */
+
+  hostlen = sizeof(hostaddr);
+
+  if (getpeername(0, (struct sockaddr *)&hostaddr, &hostlen))
+  {
+    syslog(LOG_WARNING, "Unable to get client address - %s", strerror(errno));
+    strcpy(hostname, "unknown");
+  }
+  else
+  {
+    httpAddrString(&hostaddr, hostip, sizeof(hostip));
+
+    if (hostlookups)
+      httpAddrLookup(&hostaddr, hostname, sizeof(hostname));
+    else
+      strlcpy(hostname, hostip, sizeof(hostname));
+
+#ifdef AF_INET6
+    if (hostaddr.addr.sa_family == AF_INET6)
+      hostfamily = "IPv6";
+    else
+#endif /* AF_INET6 */
+    hostfamily = "IPv4";
+
+    syslog(LOG_INFO, "Connection from %s (%s %s)", hostname, hostfamily,
+           hostip);
+  }
+
+  num_defaults = cupsAddOption("job-originating-host-name", hostname,
+                               num_defaults, &defaults);
+
  /*
   * RFC1179 specifies that only 1 daemon command can be received for
   * every connection.
@@ -284,19 +300,24 @@ main(int  argc,                           /* I - Number of command-line arguments */
        break;
 
     case 0x05 : /* Remove jobs */
-       /*
-        * Grab the agent and skip to the list of users and/or jobs.
-       */
+        if (list)
+       {
+        /*
+         * Grab the agent and skip to the list of users and/or jobs.
+         */
 
-        agent = list;
+         agent = list;
 
-       for (; *list && !isspace(*list & 255); list ++);
-       while (isspace(*list & 255))
-         *list++ = '\0';
+         for (; *list && !isspace(*list & 255); list ++);
+         while (isspace(*list & 255))
+           *list++ = '\0';
 
-        syslog(LOG_INFO, "Remove jobs %s on %s by %s", list, dest, agent);
+         syslog(LOG_INFO, "Remove jobs %s on %s by %s", list, dest, agent);
 
-        status = remove_jobs(dest, agent, list);
+         status = remove_jobs(dest, agent, list);
+        }
+       else
+         status = 1;
 
        putchar(status);
        break;
@@ -317,6 +338,7 @@ static int                          /* O - Job ID or -1 on error */
 create_job(http_t        *http,                /* I - HTTP connection */
            const char    *dest,                /* I - Destination name */
           const char    *title,        /* I - job-name */
+          const char    *docname,      /* I - Name of job file */
            const char    *user,                /* I - requesting-user-name */
           int           num_options,   /* I - Number of options for job */
           cups_option_t *options)      /* I - Options for job */
@@ -343,10 +365,14 @@ create_job(http_t        *http,           /* I - HTTP connection */
   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
                "requesting-user-name", NULL, user);
 
-  if (title)
+  if (title[0])
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
                  NULL, title);
 
+  if (docname[0])
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", 
+                 NULL, docname);
+
   cupsEncodeOptions(request, num_options, options);
 
  /*
@@ -438,14 +464,41 @@ get_printer(http_t        *http,  /* I - HTTP connection */
     *options = NULL;
 
  /*
-  * If the queue name contains a space, lookup the printer-name using
-  * the printer-info value...
+  * See if the name is a queue name optionally with an instance name.
+  */
+
+  strlcpy(dest, name, destsize);
+  if ((value = strchr(dest, '/')) != NULL)
+    *value = '\0';
+
+ /*
+  * Setup the Get-Printer-Attributes request...
+  */
+
+  request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+                  "localhost", 0, "/printers/%s", dest);
+
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+              NULL, uri);
+
+  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+               "requested-attributes",
+               (int)(sizeof(requested) / sizeof(requested[0])),
+               NULL, requested);
+
+ /*
+  * Do the request...
   */
 
-  if (strchr(name, ' '))
+  response = cupsDoRequest(http, request, "/");
+
+  if (!response || cupsLastError() > IPP_OK_CONFLICT)
   {
    /*
-    * Lookup the printer-info...
+    * If we can't find the printer by name, look up the printer-name
+    * using the printer-info values...
     */
 
     ipp_attribute_t    *accepting_attr,/* printer-is-accepting-jobs */
@@ -455,13 +508,15 @@ get_printer(http_t        *http,  /* I - HTTP connection */
                        *state_attr;    /* printer-state */
 
 
+    ippDelete(response);
+
    /*
     * Setup the CUPS-Get-Printers request...
     */
 
     request = ippNewRequest(CUPS_GET_PRINTERS);
 
-    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                   "requested-attributes",
                  (int)(sizeof(requested) / sizeof(requested[0])),
                   NULL, requested);
@@ -567,47 +622,6 @@ get_printer(http_t        *http,   /* I - HTTP connection */
   }
   else
   {
-   /*
-    * Otherwise treat it as a queue name optionally with an instance name.
-    */
-
-    strlcpy(dest, name, destsize);
-    if ((value = strchr(dest, '/')) != NULL)
-      *value = '\0';
-
-   /*
-    * Setup the Get-Printer-Attributes request...
-    */
-
-    request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
-
-    httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
-                     "localhost", 0, "/printers/%s", dest);
-
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
-                NULL, uri);
-
-    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-                  "requested-attributes",
-                 (int)(sizeof(requested) / sizeof(requested[0])),
-                  NULL, requested);
-
-   /*
-    * Do the request...
-    */
-
-    response = cupsDoRequest(http, request, "/");
-
-    if (!response || cupsLastError() > IPP_OK_CONFLICT)
-    {
-      syslog(LOG_ERR, "Unable to check printer status - %s",
-             cupsLastErrorString());
-
-      ippDelete(response);
-
-      return (-1);
-    }
-
    /*
     * Get values from the response...
     */
@@ -615,9 +629,9 @@ get_printer(http_t        *http,    /* I - HTTP connection */
     if (accepting)
     {
       if ((attr = ippFindAttribute(response, "printer-is-accepting-jobs",
-                                  IPP_TAG_BOOLEAN)) == NULL)
+                                  IPP_TAG_BOOLEAN)) == NULL)
        syslog(LOG_ERR, "No printer-is-accepting-jobs attribute found in "
-                       "response from server!");
+                       "response from server!");
       else
        *accepting = attr->values[0].boolean;
     }
@@ -625,10 +639,10 @@ get_printer(http_t        *http,  /* I - HTTP connection */
     if (shared)
     {
       if ((attr = ippFindAttribute(response, "printer-is-shared",
-                                  IPP_TAG_BOOLEAN)) == NULL)
+                                  IPP_TAG_BOOLEAN)) == NULL)
       {
        syslog(LOG_ERR, "No printer-is-shared attribute found in "
-                       "response from server!");
+                       "response from server!");
        *shared = 1;
       }
       else
@@ -638,9 +652,9 @@ get_printer(http_t        *http,    /* I - HTTP connection */
     if (state)
     {
       if ((attr = ippFindAttribute(response, "printer-state",
-                                  IPP_TAG_INTEGER)) == NULL)
+                                  IPP_TAG_ENUM)) == NULL)
        syslog(LOG_ERR, "No printer-state attribute found in "
-                       "response from server!");
+                       "response from server!");
       else
        *state = (ipp_pstate_t)attr->values[0].integer;
     }
@@ -655,13 +669,12 @@ get_printer(http_t        *http,  /* I - HTTP connection */
 #ifdef HAVE_CFPRIV_H /* MacOS X */
   if (shared && *shared)
   {
-    CFURLRef           prefsurl;       /* */
-    CFDataRef          xmldata;        /* */
-    CFPropertyListRef  plist;          /* */
-    CFStringRef                queueid;        /* */
-    CFArrayRef         lprqarray;      /* */
-    CFBooleanRef       serverflag;     /* */
-    Boolean            prefsok;        /* */
+    CFURLRef           prefsurl;       /* URL for preferences file */
+    CFDataRef          xmldata;        /* XML data from preferences file */
+    CFPropertyListRef  plist;          /* Property list from XML data */
+    CFStringRef                queueid;        /* CFString of destination name */
+    CFArrayRef         lprqarray;      /* Array of shared "LPR" printers */
+    CFBooleanRef       serverflag;     /* State of the print service */
     static const char printerprefsfile[] =
         "/Library/Preferences/com.apple.printservice.plist";
                                        /* Preferences file */
@@ -690,22 +703,24 @@ get_printer(http_t        *http,  /* I - HTTP connection */
                     false);
       if (prefsurl)
       {
-        prefsok = CFURLCreateDataAndPropertiesFromResource(
-                     kCFAllocatorDefault, prefsurl, &xmldata, 
-                     NULL, NULL, NULL);
-        if (prefsok)
+        if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
+                                                    prefsurl, &xmldata, NULL,
+                                                    NULL, NULL))
        {
          plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, xmldata, 
-                                                 kCFPropertyListImmutable, NULL);
+                                                 kCFPropertyListImmutable,
+                                                 NULL);
          if (plist)
          {
            serverflag = (CFBooleanRef)CFDictionaryGetValue(
-                            (CFDictionaryRef)plist, CFSTR("serviceState"));
+                                          (CFDictionaryRef)plist,
+                                          CFSTR("serviceState"));
 
             if (serverflag && CFBooleanGetValue(serverflag))
            {
              lprqarray = (CFArrayRef)CFDictionaryGetValue(
-                             (CFDictionaryRef)plist, CFSTR("lprSharedQueues"));
+                                         (CFDictionaryRef)plist,
+                                         CFSTR("lprSharedQueues"));
 
              if (lprqarray)
              {
@@ -715,25 +730,20 @@ get_printer(http_t        *http,  /* I - HTTP connection */
 
                 if (queueid)
                {
-                 *shared = CFArrayContainsValue(
-                               lprqarray,
-                               CFRangeMake(0, CFArrayGetCount(lprqarray)),
-                               queueid);
+                 *shared = CFArrayContainsValue(lprqarray,
+                                                CFRangeMake(0,
+                                                    CFArrayGetCount(lprqarray)),
+                                                queueid);
 
                   CFRelease(queueid);
                }
-
-                CFRelease(lprqarray);
              }
            }
 
-            if (serverflag)
-             CFRelease(serverflag);
-
            CFRelease(plist);
          }
 
-         CFRelease(prefsok);
+         CFRelease(xmldata);
        }
 
        CFRelease(prefsurl);
@@ -744,7 +754,7 @@ get_printer(http_t        *http,    /* I - HTTP connection */
                        "on queue: %s", name);
     }
   }
-#endif /* HAVE_CFPRIV_H */
+#endif /* HAVE_CFPRIV_H */
 
  /*
   * Next look for the printer in the lpoptions file...
@@ -815,6 +825,7 @@ print_file(http_t     *http,                /* I - HTTP connection */
           const char *filename,        /* I - File to print */
            const char *docname,                /* I - document-name */
           const char *user,            /* I - requesting-user-name */
+          const char *format,          /* I - document-format */
           int        last)             /* I - 1 = last file in job */
 {
   ipp_t                *request;               /* IPP request */
@@ -837,6 +848,10 @@ print_file(http_t     *http,               /* I - HTTP connection */
     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);
+
   if (last)
     ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
 
@@ -1133,9 +1148,10 @@ recv_print_job(
       * Grab the job information...
       */
 
-      title[0] = '\0';
-      user[0]  = '\0';
-      doccount = 0;
+      title[0]   = '\0';
+      user[0]    = '\0';
+      docname[0] = '\0';
+      doccount   = 0;
 
       while (smart_gets(line, sizeof(line), fp) != NULL)
       {
@@ -1149,6 +1165,10 @@ recv_print_job(
              strlcpy(title, line + 1, sizeof(title));
              break;
 
+          case 'N' : /* Document name */
+              strlcpy(docname, line + 1, sizeof(docname));
+              break;
+
          case 'P' : /* User identification */
              strlcpy(user, line + 1, sizeof(user));
              break;
@@ -1212,7 +1232,8 @@ recv_print_job(
       * Create the job...
       */
 
-      if ((id = create_job(http, dest, title, user, num_options, options)) < 0)
+      if ((id = create_job(http, dest, title, docname, user, num_options,
+                           options)) < 0)
         status = 1;
       else
       {
@@ -1269,6 +1290,8 @@ recv_print_job(
                docnumber ++;
 
                if (print_file(http, id, temp[i], docname, user,
+                              cupsGetOption("document-format", num_options,
+                                            options),
                               docnumber == doccount))
                   status = 1;
                else
@@ -1280,9 +1303,9 @@ recv_print_job(
          if (status)
            break;
        }
-
-       fclose(fp);
       }
+
+      fclose(fp);
     }
   }
 
@@ -1379,7 +1402,7 @@ remove_jobs(const char *dest,             /* I - Destination */
       return (1);
     }
     else
-      syslog(LOG_INFO, "Job ID %d cancelled", id);
+      syslog(LOG_INFO, "Job ID %d canceled", id);
   }
 
   httpClose(http);
@@ -1708,5 +1731,5 @@ smart_gets(char *s,                       /* I - Pointer to line buffer */
 
 
 /*
- * End of "$Id: cups-lpd.c 5196 2006-02-27 21:23:00Z mike $".
+ * End of "$Id: cups-lpd.c 7899 2008-09-03 12:57:17Z mike $".
  */