r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
[tprouty/samba.git] / source / printing / print_cups.c
index 5c5d1e60d2c7b12215258c10e28479570de686d0..5cc36d6e170284a575efc1a2de9637dfae28edca 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Support code for the Common UNIX Printing System ("CUPS")
  *
- * Copyright 1999-2001 by Michael R Sweet
+ * Copyright 1999-2003 by Michael R Sweet.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "includes.h"
 #include "printing.h"
-#include "smb.h"
 
 #ifdef HAVE_CUPS
 #include <cups/cups.h>
 #include <cups/language.h>
 
 
-/*
- * CUPS printing interface definitions...
- */
-
-static int cups_job_delete(int snum, struct printjob *pjob);
-static int cups_job_pause(int snum, struct printjob *pjob);
-static int cups_job_resume(int snum, struct printjob *pjob);
-static int cups_job_submit(int snum, struct printjob *pjob);
-static int cups_queue_get(int snum, print_queue_struct **q,
-                          print_status_struct *status);
-static int cups_queue_pause(int snum);
-static int cups_queue_resume(int snum);
-
-
-struct printif cups_printif =
-               {
-                 cups_queue_get,
-                 cups_queue_pause,
-                 cups_queue_resume,
-                 cups_job_delete,
-                 cups_job_pause,
-                 cups_job_resume,
-                 cups_job_submit,
-               };
-
-extern int DEBUGLEVEL;
-
-
 /*
  * 'cups_passwd_cb()' - The CUPS password callback...
  */
 
-const char *                           /* O - Password or NULL */
+static const char *                            /* O - Password or NULL */
 cups_passwd_cb(const char *prompt)     /* I - Prompt */
 {
  /*
   * Always return NULL to indicate that no password is available...
   */
 
-  (void)prompt;
-
   return (NULL);
 }
 
+static const char *cups_server(void)
+{
+       if ((lp_cups_server() != NULL) && (strlen(lp_cups_server()) > 0)) {
+               DEBUG(10, ("cups server explicitly set to %s\n",
+                          lp_cups_server()));
+               return lp_cups_server();
+       }
+
+       DEBUG(10, ("cups server left to default %s\n", cupsServer()));
+       return cupsServer();
+}
 
 /*
  * 'cups_printer_fn()' - Call a function for every printer known to the
  *                       system.
  */
 
-void
-cups_printer_fn(void (*fn)(char *, char *))    /* I - Function to call */
+void cups_printer_fn(void (*fn)(char *, char *))
 {
+       /* I - Function to call */
        http_t          *http;          /* HTTP connection to server */
        ipp_t           *request,       /* IPP Request */
                        *response;      /* IPP Response */
        ipp_attribute_t *attr;          /* Current attribute */
        cups_lang_t     *language;      /* Default language */
        char            *name,          /* printer-name attribute */
-                       *make_model,    /* printer-make-and-model attribute */
                        *info;          /* printer-info attribute */
        static const char *requested[] =/* Requested attributes */
                        {
                          "printer-name",
-                         "printer-make-and-model",
                          "printer-info"
                        };       
 
@@ -107,10 +86,10 @@ cups_printer_fn(void (*fn)(char *, char *))        /* I - Function to call */
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return;
        }
 
@@ -170,7 +149,6 @@ cups_printer_fn(void (*fn)(char *, char *)) /* I - Function to call */
                */
 
                name       = NULL;
-               make_model = NULL;
                info       = NULL;
 
                while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
@@ -179,9 +157,89 @@ cups_printer_fn(void (*fn)(char *, char *))        /* I - Function to call */
                            attr->value_tag == IPP_TAG_NAME)
                                name = attr->values[0].string.text;
 
-                       if (strcmp(attr->name, "printer-make-and-model") == 0 &&
+                       if (strcmp(attr->name, "printer-info") == 0 &&
                            attr->value_tag == IPP_TAG_TEXT)
-                               make_model = attr->values[0].string.text;
+                               info = attr->values[0].string.text;
+
+                       attr = attr->next;
+               }
+
+              /*
+               * See if we have everything needed...
+               */
+
+               if (name == NULL)
+                       break;
+
+               (*fn)(name, info);
+       }
+
+       ippDelete(response);
+
+
+       /*
+       * Build a CUPS_GET_CLASSES request, which requires the following
+       * attributes:
+       *
+       *    attributes-charset
+       *    attributes-natural-language
+       *    requested-attributes
+       */
+
+       request = ippNew();
+
+       request->request.op.operation_id = CUPS_GET_CLASSES;
+       request->request.op.request_id   = 1;
+
+       language = cupsLangDefault();
+
+       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                     "attributes-charset", NULL, cupsLangEncoding(language));
+
+       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                     "attributes-natural-language", NULL, language->language);
+
+        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                     "requested-attributes",
+                     (sizeof(requested) / sizeof(requested[0])),
+                     NULL, requested);
+
+       /*
+       * Do the request and get back a response...
+       */
+
+       if ((response = cupsDoRequest(http, request, "/")) == NULL)
+       {
+               DEBUG(0,("Unable to get printer list - %s\n",
+                        ippErrorString(cupsLastError())));
+               httpClose(http);
+               return;
+       }
+
+       for (attr = response->attrs; attr != NULL;)
+       {
+              /*
+               * Skip leading attributes until we hit a printer...
+               */
+
+               while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+                       attr = attr->next;
+
+               if (attr == NULL)
+                       break;
+
+              /*
+               * Pull the needed attributes from this printer...
+               */
+
+               name       = NULL;
+               info       = NULL;
+
+               while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+               {
+                       if (strcmp(attr->name, "printer-name") == 0 &&
+                           attr->value_tag == IPP_TAG_NAME)
+                               name = attr->values[0].string.text;
 
                        if (strcmp(attr->name, "printer-info") == 0 &&
                            attr->value_tag == IPP_TAG_TEXT)
@@ -197,15 +255,15 @@ cups_printer_fn(void (*fn)(char *, char *))       /* I - Function to call */
                if (name == NULL)
                        break;
 
-               if (info == NULL || !info[0])
-                       (*fn)(name, make_model);
-               else
-                       (*fn)(name,info);
-               
-
+               (*fn)(name, info);
        }
 
        ippDelete(response);
+
+       /*
+        * Close the connection to the server...
+       */
+
        httpClose(http);
 }
 
@@ -213,10 +271,10 @@ cups_printer_fn(void (*fn)(char *, char *))       /* I - Function to call */
 /*
  * 'cups_printername_ok()' - Provide the equivalent of pcap_printername_ok()
  *                           for CUPS.
+ * O - 1 if printer name OK
+ * I - Name of printer 
  */
-
-int                                    /* O - 1 if printer name OK */
-cups_printername_ok(char *name)                /* I - Name of printer */
+int cups_printername_ok(const char *name)
 {
        http_t          *http;          /* HTTP connection to server */
        ipp_t           *request,       /* IPP Request */
@@ -237,10 +295,10 @@ cups_printername_ok(char *name)           /* I - Name of printer */
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
-               DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+               DEBUG(3,("Unable to connect to CUPS server %s - %s\n", 
+                        cups_server(), strerror(errno)));
                return (0);
        }
 
@@ -281,7 +339,7 @@ cups_printername_ok(char *name)             /* I - Name of printer */
 
        if ((response = cupsDoRequest(http, request, "/")) == NULL)
        {
-               DEBUG(0,("Unable to get printer status for %s - %s\n", name,
+               DEBUG(3,("Unable to get printer status for %s - %s\n", name,
                         ippErrorString(cupsLastError())));
                httpClose(http);
                return (0);
@@ -291,7 +349,7 @@ cups_printername_ok(char *name)             /* I - Name of printer */
 
        if (response->request.status.status_code >= IPP_OK_CONFLICT)
        {
-               DEBUG(0,("Unable to get printer status for %s - %s\n", name,
+               DEBUG(3,("Unable to get printer status for %s - %s\n", name,
                         ippErrorString(response->request.status.status_code)));
                ippDelete(response);
                return (0);
@@ -331,10 +389,10 @@ cups_job_delete(int snum, struct printjob *pjob)
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return (1);
        }
 
@@ -421,10 +479,10 @@ cups_job_pause(int snum, struct printjob *pjob)
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return (1);
        }
 
@@ -511,10 +569,10 @@ cups_job_resume(int snum, struct printjob *pjob)
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return (1);
        }
 
@@ -587,7 +645,10 @@ cups_job_submit(int snum, struct printjob *pjob)
                        *response;      /* IPP Response */
        cups_lang_t     *language;      /* Default language */
        char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
-
+       char            *clientname;    /* hostname of client for job-originating-host attribute */
+       pstring         new_jobname;
+       int             num_options = 0; 
+       cups_option_t   *options;
 
        DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
 
@@ -601,10 +662,10 @@ cups_job_submit(int snum, struct printjob *pjob)
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return (1);
        }
 
@@ -641,8 +702,31 @@ cups_job_submit(int snum, struct printjob *pjob)
        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
                     NULL, pjob->user);
 
+       clientname = client_name();
+       if (strcmp(clientname, "UNKNOWN") == 0) {
+               clientname = client_addr();
+       }
+
+       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                    "job-originating-host-name", NULL,
+                     clientname);
+
+        pstr_sprintf(new_jobname,"%s%.8u %s", PRINT_SPOOL_PREFIX, 
+               (unsigned int)pjob->smbjob, pjob->jobname);
+
        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
-                    pjob->jobname);
+                    new_jobname);
+
+       /* 
+        * add any options defined in smb.conf 
+        */
+
+       num_options = 0;
+       options     = NULL;
+       num_options = cupsParseOptions(lp_cups_options(snum), num_options, &options);
+
+       if ( num_options )
+               cupsEncodeOptions(request, num_options, options); 
 
        /*
        * Do the request and get back a response...
@@ -668,16 +752,23 @@ cups_job_submit(int snum, struct printjob *pjob)
 
        httpClose(http);
 
+       if ( ret == 0 )
+               unlink(pjob->filename);
+       /* else print_job_end will do it for us */
+
        return (ret);
 }
 
-
 /*
  * 'cups_queue_get()' - Get all the jobs in the print queue.
  */
 
 static int
-cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
+cups_queue_get(const char *printer_name,
+               enum printing_types printing_type,
+               char *lpq_command,
+               print_queue_struct **q, 
+               print_status_struct *status)
 {
        http_t          *http;          /* HTTP connection to server */
        ipp_t           *request,       /* IPP Request */
@@ -713,7 +804,7 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
                        };
 
 
-       DEBUG(5,("cups_queue_get(%d, %p, %p)\n", snum, q, status));
+       DEBUG(5,("cups_queue_get(%s, %p, %p)\n", printer_name, q, status));
 
        /*
         * Make sure we don't ask for passwords...
@@ -725,10 +816,10 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return (0);
        }
 
@@ -736,8 +827,7 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
         * Generate the printer URI...
        */
 
-       slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
-                PRINTERNAME(snum));
+       slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printer_name);
 
        /*
        * Build an IPP_GET_JOBS request, which requires the following
@@ -819,7 +909,7 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
                {
                        qalloc += 16;
 
-                       temp = Realloc(queue, sizeof(print_queue_struct) * qalloc);
+                       temp = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
 
                        if (temp == NULL)
                        {
@@ -827,7 +917,7 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
                                ippDelete(response);
                                httpClose(http);
 
-                               free (queue);
+                               SAFE_FREE(queue);
                                return (0);
                        }
 
@@ -908,8 +998,8 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
                                 LPQ_PRINTING;
                temp->priority = job_priority;
                temp->time     = job_time;
-               strncpy(temp->user, user_name, sizeof(temp->user) - 1);
-               strncpy(temp->file, job_name, sizeof(temp->file) - 1);
+               strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
+               strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
 
                qcount ++;
 
@@ -956,7 +1046,7 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
 
        if ((response = cupsDoRequest(http, request, "/")) == NULL)
        {
-               DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum),
+               DEBUG(0,("Unable to get printer status for %s - %s\n", printer_name,
                         ippErrorString(cupsLastError())));
                httpClose(http);
                *q = queue;
@@ -965,7 +1055,7 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
 
        if (response->request.status.status_code >= IPP_OK_CONFLICT)
        {
-               DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum),
+               DEBUG(0,("Unable to get printer status for %s - %s\n", printer_name,
                         ippErrorString(response->request.status.status_code)));
                ippDelete(response);
                httpClose(http);
@@ -1030,10 +1120,10 @@ cups_queue_pause(int snum)
         * Try to connect to the server...
         */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return (1);
        }
 
@@ -1122,10 +1212,10 @@ cups_queue_resume(int snum)
        * Try to connect to the server...
        */
 
-       if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+       if ((http = httpConnect(cups_server(), ippPort())) == NULL)
        {
                DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
-                        cupsServer(), strerror(errno)));
+                        cups_server(), strerror(errno)));
                return (1);
        }
 
@@ -1185,6 +1275,21 @@ cups_queue_resume(int snum)
        return (ret);
 }
 
+/*******************************************************************
+ * CUPS printing interface definitions...
+ ******************************************************************/
+
+struct printif cups_printif =
+{
+       PRINT_CUPS,
+       cups_queue_get,
+       cups_queue_pause,
+       cups_queue_resume,
+       cups_job_delete,
+       cups_job_pause,
+       cups_job_resume,
+       cups_job_submit,
+};
 
 #else
  /* this keeps fussy compilers happy */