]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/log.c
Merge changes from CUPS 1.4svn-r7874.
[thirdparty/cups.git] / scheduler / log.c
index 1aa41a704a49613a168a0bdb8aad0daa37de53ea..dc2e23297afbea2bef98b934038ba6d8e1060390 100644 (file)
@@ -1,33 +1,28 @@
 /*
- * "$Id: log.c 4860 2005-12-01 22:07:26Z mike $"
+ * "$Id: log.c 7699 2008-06-27 20:44:23Z mike $"
  *
  *   Log file routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 1997-2007 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:
  *
- *   cupsdGetDateTime()    - Returns a pointer to a date/time string.
- *   cupsdLogMessage()     - Log a message to the error log file.
- *   cupsdLogPage()        - Log a page to the page log file.
- *   cupsdLogRequest()     - Log an HTTP request in Common Log Format.
- *   check_log_file() - Open/rotate a log file if it needs it.
+ *   cupsdGetDateTime()   - Returns a pointer to a date/time string.
+ *   cupsdLogGSSMessage() - Log a GSSAPI error...
+ *   cupsdLogJob()        - Log a job message.
+ *   cupsdLogMessage()    - Log a message to the error log file.
+ *   cupsdLogPage()       - Log a page to the page log file.
+ *   cupsdLogRequest()    - Log an HTTP request in Common Log Format.
+ *   cupsdWriteErrorLog() - Write a line to the ErrorLog.
+ *   check_log_file()     - Open/rotate a log file if it needs it.
+ *   format_log_line()    - Format a line for a log file.
  */
 
 /*
 
 #include "cupsd.h"
 #include <stdarg.h>
+#include <syslog.h>
 
-#ifdef HAVE_VSYSLOG
-#  include <syslog.h>
-#endif /* HAVE_VSYSLOG */
+
+/*
+ * Local globals...
+ */
+
+static int     log_linesize = 0;       /* Size of line for output file */
+static char    *log_line = NULL;       /* Line for output file */
 
 
 /*
  * Local functions...
  */
 
-static int     check_log_file(cups_file_t **, const char *);
+static int     check_log_file(cups_file_t **lf, const char *logname);
+static int     format_log_line(const char *message, va_list ap);
 
 
 /*
@@ -76,6 +77,13 @@ cupsdGetDateTime(time_t t)           /* I - Time value */
                };
 
 
+ /*
+  * Make sure we have a valid time...
+  */
+
+  if (!t)
+    t = time(NULL);
+
   if (t != last_time)
   {
     last_time = t;
@@ -110,167 +118,146 @@ cupsdGetDateTime(time_t t)              /* I - Time value */
 }
 
 
+#ifdef HAVE_GSSAPI
 /*
- * 'cupsdLogMessage()' - Log a message to the error log file.
+ * 'cupsdLogGSSMessage()' - Log a GSSAPI error...
  */
 
 int                                    /* O - 1 on success, 0 on error */
-cupsdLogMessage(int        level,      /* I - Log level */
-                const char *message,   /* I - printf-style message string */
-               ...)                    /* I - Additional args as needed */
+cupsdLogGSSMessage(
+    int        level,                  /* I - Log level */
+    int               major_status,            /* I - Major GSSAPI status */
+    int               minor_status,            /* I - Minor GSSAPI status */
+    const char *message,               /* I - printf-style message string */
+    ...)                               /* I - Additional args as needed */
+{
+  OM_uint32    err_major_status,       /* Major status code for display */
+               err_minor_status;       /* Minor status code for display */
+  OM_uint32    msg_ctx;                /* Message context */
+  gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER,
+                                       /* Major status message */
+               minor_status_string = GSS_C_EMPTY_BUFFER;
+                                       /* Minor status message */
+  int          ret;                    /* Return value */
+
+
+  msg_ctx             = 0;
+  err_major_status    = gss_display_status(&err_minor_status,
+                                          major_status,
+                                          GSS_C_GSS_CODE,
+                                          GSS_C_NO_OID,
+                                          &msg_ctx,
+                                          &major_status_string);
+
+  if (!GSS_ERROR(err_major_status))
+    gss_display_status(&err_minor_status, minor_status, GSS_C_MECH_CODE,
+                       GSS_C_NULL_OID, &msg_ctx, &minor_status_string);
+
+  ret = cupsdLogMessage(level, "%s: %s, %s", message,
+                       (char *)major_status_string.value,
+                       (char *)minor_status_string.value);
+  gss_release_buffer(&err_minor_status, &major_status_string);
+  gss_release_buffer(&err_minor_status, &minor_status_string);
+
+  return (ret);
+}
+#endif /* HAVE_GSSAPI */
+
+
+/*
+ * 'cupsdLogJob()' - Log a job message.
+ */
+
+int                                    /* O - 1 on success, 0 on error */
+cupsdLogJob(cupsd_job_t *job,          /* I - Job */
+            int         level,         /* I - Log level */
+           const char  *message,       /* I - Printf-style message string */
+           ...)                        /* I - Additional arguments as needed */
 {
-  int                  len;            /* Length of message */
   va_list              ap;             /* Argument pointer */
-  static const char    levels[] =      /* Log levels... */
-               {
-                 ' ',
-                 'X',
-                 'A',
-                 'C',
-                 'E',
-                 'W',
-                 'N',
-                 'I',
-                 'D',
-                 'd'
-               };
-#ifdef HAVE_VSYSLOG
-  static const int syslevels[] =       /* SYSLOG levels... */
-               {
-                 0,
-                 LOG_EMERG,
-                 LOG_ALERT,
-                 LOG_CRIT,
-                 LOG_ERR,
-                 LOG_WARNING,
-                 LOG_NOTICE,
-                 LOG_INFO,
-                 LOG_DEBUG,
-                 LOG_DEBUG
-               };
-#endif /* HAVE_VSYSLOG */
-  static int   linesize = 0;           /* Size of line for output file */
-  static char  *line = NULL;           /* Line for output file */
+  char                 jobmsg[1024];   /* Format string for job message */
+  int                  status;         /* Formatting status */
 
 
  /*
   * See if we want to log this message...
   */
 
-  if (level > LogLevel || !ErrorLog)
+  if (TestConfigFile || level > LogLevel || !ErrorLog)
     return (1);
 
-#ifdef HAVE_VSYSLOG
  /*
-  * See if we are logging errors via syslog...
+  * Format and write the log message...
   */
 
-  if (!strcmp(ErrorLog, "syslog"))
+  snprintf(jobmsg, sizeof(jobmsg), "[Job %d] %s", job->id, message);
+
+  do
   {
     va_start(ap, message);
-    vsyslog(syslevels[level], message, ap);
+    status = format_log_line(jobmsg, ap);
     va_end(ap);
-
-    return (1);
   }
-#endif /* HAVE_VSYSLOG */
+  while (status == 0);
 
- /*
-  * Not using syslog; check the log file...
-  */
+  if (status > 0)
+    return (cupsdWriteErrorLog(level, log_line));
+  else
+    return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
+                               "Unable to allocate memory for log line!"));
+}
 
-  if (!check_log_file(&ErrorFile, ErrorLog))
-    return (0);
 
- /*
-  * Print the log level and date/time...
-  */
+/*
+ * 'cupsdLogMessage()' - Log a message to the error log file.
+ */
+
+int                                    /* O - 1 on success, 0 on error */
+cupsdLogMessage(int        level,      /* I - Log level */
+                const char *message,   /* I - printf-style message string */
+               ...)                    /* I - Additional args as needed */
+{
+  va_list              ap;             /* Argument pointer */
+  int                  status;         /* Formatting status */
 
-  cupsFilePrintf(ErrorFile, "%c %s ", levels[level], cupsdGetDateTime(time(NULL)));
 
  /*
-  * Allocate the line buffer as needed...
+  * See if we want to log this message...
   */
 
-  if (!linesize)
+  if (TestConfigFile)
   {
-    linesize = 8192;
-    line     = malloc(linesize);
-
-    if (!line)
+    if (level <= CUPSD_LOG_WARN)
     {
-      cupsFilePrintf(ErrorFile,
-                     "ERROR: Unable to allocate memory for line - %s\n",
-                     strerror(errno));
-      cupsFileFlush(ErrorFile);
-
-      return (0);
+      va_start(ap, message);
+      vfprintf(stderr, message, ap);
+      putc('\n', stderr);
+      va_end(ap);
     }
-  }
 
- /*
-  * Format the log message...
-  */
+    return (1);
+  }
 
-  va_start(ap, message);
-  len = vsnprintf(line, linesize, message, ap);
-  va_end(ap);
+  if (level > LogLevel || !ErrorLog)
+    return (1);
 
  /*
-  * Resize the buffer as needed...
+  * Format and write the log message...
   */
 
-  if (len >= linesize)
+  do
   {
-    len ++;
-
-    if (len < 8192)
-      len = 8192;
-    else if (len > 65536)
-      len = 65536;
-
-    line = realloc(line, len);
-
-    if (line)
-      linesize = len;
-    else
-    {
-      cupsFilePrintf(ErrorFile,
-                     "ERROR: Unable to allocate memory for line - %s\n",
-                     strerror(errno));
-      cupsFileFlush(ErrorFile);
-
-      return (0);
-    }
-
     va_start(ap, message);
-    len = vsnprintf(line, linesize, message, ap);
+    status = format_log_line(message, ap);
     va_end(ap);
   }
+  while (status == 0);
 
-  if (len >= linesize)
-    len = linesize - 1;
-
- /*
-  * Then the log message...
-  */
-
-  cupsFilePuts(ErrorFile, line);
-
- /*
-  * Then a newline...
-  */
-
-  if (len > 0 && line[len - 1] != '\n')
-    cupsFilePutChar(ErrorFile, '\n');
-
- /*
-  * Flush the line to the file and return...
-  */
-
-  cupsFileFlush(ErrorFile);
-
-  return (1);
+  if (status > 0)
+    return (cupsdWriteErrorLog(level, log_line));
+  else
+    return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
+                               "Unable to allocate memory for log line!"));
 }
 
 
@@ -282,14 +269,160 @@ int                                      /* O - 1 on success, 0 on error */
 cupsdLogPage(cupsd_job_t *job,         /* I - Job being printed */
              const char  *page)                /* I - Page being printed */
 {
-  ipp_attribute_t *billing,            /* job-billing attribute */
-                  *hostname;           /* job-originating-host-name attribute */
+  int                  i;              /* Looping var */
+  char                 buffer[2048],   /* Buffer for page log */
+                       *bufptr,        /* Pointer into buffer */
+                       name[256];      /* Attribute name */
+  const char           *format,        /* Pointer into PageLogFormat */
+                       *nameend;       /* End of attribute name */
+  ipp_attribute_t      *attr;          /* Current attribute */
+  int                  number;         /* Page number */
+  char                 copies[256];    /* Number of copies */
 
 
-  billing  = ippFindAttribute(job->attrs, "job-billing", IPP_TAG_ZERO);
-  hostname = ippFindAttribute(job->attrs, "job-originating-host-name",
-                              IPP_TAG_ZERO);
+ /*
+  * Format the line going into the page log...
+  */
+
+  if (!PageLogFormat)
+    return (1);
+
+  number = 1;
+  strcpy(copies, "1");
+  sscanf(page, "%d%255s", &number, copies);
 
+  for (format = PageLogFormat, bufptr = buffer; *format; format ++)
+  {
+    if (*format == '%')
+    {
+      format ++;
+
+      switch (*format)
+      {
+        case '%' :                     /* Literal % */
+           if (bufptr < (buffer + sizeof(buffer) - 1))
+             *bufptr++ = '%';
+           break;
+
+        case 'p' :                     /* Printer name */
+           strlcpy(bufptr, job->printer->name,
+                   sizeof(buffer) - (bufptr - buffer));
+           bufptr += strlen(bufptr);
+           break;
+
+        case 'j' :                     /* Job ID */
+           snprintf(bufptr, sizeof(buffer) - (bufptr - buffer), "%d", job->id);
+           bufptr += strlen(bufptr);
+           break;
+
+        case 'u' :                     /* Username */
+           strlcpy(bufptr, job->username ? job->username : "-",
+                   sizeof(buffer) - (bufptr - buffer));
+           bufptr += strlen(bufptr);
+           break;
+
+        case 'T' :                     /* Date and time */
+           strlcpy(bufptr, cupsdGetDateTime(time(NULL)),
+                   sizeof(buffer) - (bufptr - buffer));
+           bufptr += strlen(bufptr);
+           break;
+
+        case 'P' :                     /* Page number */
+           snprintf(bufptr, sizeof(buffer) - (bufptr - buffer), "%d", number);
+           bufptr += strlen(bufptr);
+           break;
+
+        case 'C' :                     /* Number of copies */
+           strlcpy(bufptr, copies, sizeof(buffer) - (bufptr - buffer));
+           bufptr += strlen(bufptr);
+           break;
+
+        case '{' :                     /* {attribute} */
+           if ((nameend = strchr(format, '}')) != NULL &&
+               (nameend - format - 2) < (sizeof(name) - 1))
+           {
+            /*
+             * Pull the name from inside the brackets...
+             */
+
+             memcpy(name, format + 1, nameend - format - 1);
+             name[nameend - format - 1] = '\0';
+
+             format = nameend;
+
+             if ((attr = ippFindAttribute(job->attrs, name,
+                                          IPP_TAG_ZERO)) != NULL)
+             {
+              /*
+               * Add the attribute value...
+               */
+
+                for (i = 0;
+                    i < attr->num_values &&
+                        bufptr < (buffer + sizeof(buffer) - 1);
+                    i ++)
+               {
+                 if (i)
+                   *bufptr++ = ',';
+
+                 switch (attr->value_tag)
+                 {
+                   case IPP_TAG_INTEGER :
+                   case IPP_TAG_ENUM :
+                       snprintf(bufptr, sizeof(buffer) - (bufptr - buffer),
+                                "%d", attr->values[i].integer);
+                       bufptr += strlen(bufptr);
+                       break;
+
+                    case IPP_TAG_BOOLEAN :
+                       snprintf(bufptr, sizeof(buffer) - (bufptr - buffer),
+                                "%d", attr->values[i].boolean);
+                       bufptr += strlen(bufptr);
+                       break;
+
+                   case IPP_TAG_TEXTLANG :
+                   case IPP_TAG_NAMELANG :
+                   case IPP_TAG_TEXT :
+                   case IPP_TAG_NAME :
+                   case IPP_TAG_KEYWORD :
+                   case IPP_TAG_URI :
+                   case IPP_TAG_URISCHEME :
+                   case IPP_TAG_CHARSET :
+                   case IPP_TAG_LANGUAGE :
+                   case IPP_TAG_MIMETYPE :
+                       strlcpy(bufptr, attr->values[i].string.text,
+                               sizeof(buffer) - (bufptr - buffer));
+                       bufptr += strlen(bufptr);
+                       break;
+
+                   default :
+                       strlcpy(bufptr, "???",
+                               sizeof(buffer) - (bufptr - buffer));
+                       bufptr += strlen(bufptr);
+                       break;
+                 }
+               }
+             }
+             else if (bufptr < (buffer + sizeof(buffer) - 1))
+               *bufptr++ = '-';
+             break;
+           }
+
+        default :
+           if (bufptr < (buffer + sizeof(buffer) - 2))
+           {
+             *bufptr++ = '%';
+             *bufptr++ = *format;
+           }
+           break;
+      }
+    }
+    else if (bufptr < (buffer + sizeof(buffer) - 1))
+      *bufptr++ = *format;
+  }
+
+  *bufptr = '\0';
+      
 #ifdef HAVE_VSYSLOG
  /*
   * See if we are logging pages via syslog...
@@ -297,10 +430,7 @@ cupsdLogPage(cupsd_job_t *job,             /* I - Job being printed */
 
   if (!strcmp(PageLog, "syslog"))
   {
-    syslog(LOG_INFO, "PAGE %s %s %d %s %s %s", job->printer->name,
-           job->username ? job->username : "-",
-           job->id, page, billing ? billing->values[0].string.text : "-",
-           hostname->values[0].string.text);
+    syslog(LOG_INFO, "%s", buffer);
 
     return (1);
   }
@@ -316,15 +446,11 @@ cupsdLogPage(cupsd_job_t *job,            /* I - Job being printed */
  /*
   * Print a page log entry of the form:
   *
-  *    printer job-id user [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
+  *    printer user job-id [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
   *        billing hostname
   */
 
-  cupsFilePrintf(PageFile, "%s %s %d %s %s %s %s\n", job->printer->name,
-                job->username ? job->username : "-",
-                job->id, cupsdGetDateTime(time(NULL)), page,
-                billing ? billing->values[0].string.text : "-",
-                hostname->values[0].string.text);
+  cupsFilePrintf(PageFile, "%s\n", buffer);
   cupsFileFlush(PageFile);
 
   return (1);
@@ -339,6 +465,7 @@ int                                 /* O - 1 on success, 0 on error */
 cupsdLogRequest(cupsd_client_t *con,   /* I - Request to log */
                 http_status_t  code)   /* I - Response code */
 {
+  char temp[2048];                     /* Temporary string for URI */
   static const char * const states[] = /* HTTP client states... */
                {
                  "WAITING",
@@ -358,6 +485,112 @@ cupsdLogRequest(cupsd_client_t *con,      /* I - Request to log */
                };
 
 
+ /*
+  * Filter requests as needed...
+  */
+
+  if (AccessLogLevel < CUPSD_ACCESSLOG_ALL)
+  {
+   /*
+    * Eliminate simple GET requests...
+    */
+
+    if ((con->operation == HTTP_GET &&
+         strncmp(con->uri, "/admin/conf", 11) &&
+        strncmp(con->uri, "/admin/log", 10)) ||
+       (con->operation == HTTP_POST && !con->request &&
+        strncmp(con->uri, "/admin", 6)) ||
+       (con->operation != HTTP_POST && con->operation != HTTP_PUT))
+      return (1);
+
+    if (con->request && con->response &&
+        con->response->request.status.status_code < IPP_REDIRECTION_OTHER_SITE)
+    {
+     /*
+      * Check successful requests...
+      */
+
+      ipp_op_t op = con->request->request.op.operation_id;
+      static cupsd_accesslog_t standard_ops[] =
+      {
+        CUPSD_ACCESSLOG_ALL,   /* reserved */
+        CUPSD_ACCESSLOG_ALL,   /* reserved */
+        CUPSD_ACCESSLOG_ACTIONS,/* Print-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Print-URI */
+        CUPSD_ACCESSLOG_ACTIONS,/* Validate-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Create-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Send-Document */
+        CUPSD_ACCESSLOG_ACTIONS,/* Send-URI */
+        CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Job */
+        CUPSD_ACCESSLOG_ALL,   /* Get-Job-Attributes */
+        CUPSD_ACCESSLOG_ALL,   /* Get-Jobs */
+        CUPSD_ACCESSLOG_ALL,   /* Get-Printer-Attributes */
+        CUPSD_ACCESSLOG_ACTIONS,/* Hold-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Release-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Restart-Job */
+       CUPSD_ACCESSLOG_ALL,    /* reserved */
+        CUPSD_ACCESSLOG_CONFIG,        /* Pause-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Resume-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Purge-Jobs */
+        CUPSD_ACCESSLOG_CONFIG,        /* Set-Printer-Attributes */
+        CUPSD_ACCESSLOG_ACTIONS,/* Set-Job-Attributes */
+        CUPSD_ACCESSLOG_CONFIG,        /* Get-Printer-Supported-Values */
+        CUPSD_ACCESSLOG_ACTIONS,/* Create-Printer-Subscription */
+        CUPSD_ACCESSLOG_ACTIONS,/* Create-Job-Subscription */
+        CUPSD_ACCESSLOG_ALL,   /* Get-Subscription-Attributes */
+        CUPSD_ACCESSLOG_ALL,   /* Get-Subscriptions */
+        CUPSD_ACCESSLOG_ACTIONS,/* Renew-Subscription */
+        CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Subscription */
+        CUPSD_ACCESSLOG_ALL,   /* Get-Notifications */
+        CUPSD_ACCESSLOG_ACTIONS,/* Send-Notifications */
+        CUPSD_ACCESSLOG_ALL,   /* reserved */
+        CUPSD_ACCESSLOG_ALL,   /* reserved */
+        CUPSD_ACCESSLOG_ALL,   /* reserved */
+        CUPSD_ACCESSLOG_ALL,   /* Get-Print-Support-Files */
+        CUPSD_ACCESSLOG_CONFIG,        /* Enable-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Disable-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Pause-Printer-After-Current-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Hold-New-Jobs */
+        CUPSD_ACCESSLOG_ACTIONS,/* Release-Held-New-Jobs */
+        CUPSD_ACCESSLOG_CONFIG,        /* Deactivate-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Activate-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Restart-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Shutdown-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* Startup-Printer */
+        CUPSD_ACCESSLOG_ACTIONS,/* Reprocess-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Current-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Suspend-Current-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Resume-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* Promote-Job */
+        CUPSD_ACCESSLOG_ACTIONS        /* Schedule-Job-After */
+      };
+      static cupsd_accesslog_t cups_ops[] =
+      {
+        CUPSD_ACCESSLOG_ALL,   /* CUPS-Get-Default */
+        CUPSD_ACCESSLOG_ALL,   /* CUPS-Get-Printers */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Add-Modify-Printer */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Delete-Printer */
+        CUPSD_ACCESSLOG_ALL,   /* CUPS-Get-Classes */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Add-Modify-Class */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Delete-Class */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Accept-Jobs */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Reject-Jobs */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Set-Default */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Get-Devices */
+        CUPSD_ACCESSLOG_CONFIG,        /* CUPS-Get-PPDs */
+        CUPSD_ACCESSLOG_ACTIONS,/* CUPS-Move-Job */
+        CUPSD_ACCESSLOG_ACTIONS,/* CUPS-Authenticate-Job */
+        CUPSD_ACCESSLOG_ALL    /* CUPS-Get-PPD */
+      };
+      
+
+      if ((op <= IPP_SCHEDULE_JOB_AFTER && standard_ops[op] > AccessLogLevel) ||
+          (op >= CUPS_GET_DEFAULT && op <= CUPS_GET_PPD &&
+          cups_ops[op - CUPS_GET_DEFAULT] > AccessLogLevel))
+        return (1);
+    }
+  }
+
 #ifdef HAVE_VSYSLOG
  /*
   * See if we are logging accesses via syslog...
@@ -365,11 +598,16 @@ cupsdLogRequest(cupsd_client_t *con,      /* I - Request to log */
 
   if (!strcmp(AccessLog, "syslog"))
   {
-    syslog(LOG_INFO, "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT "\n",
+    syslog(LOG_INFO,
+           "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
            con->http.hostname, con->username[0] != '\0' ? con->username : "-",
-          states[con->operation], con->uri,
+          states[con->operation], _httpEncodeURI(temp, con->uri, sizeof(temp)),
           con->http.version / 100, con->http.version % 100,
-          code, CUPS_LLCAST con->bytes);
+          code, CUPS_LLCAST con->bytes,
+          con->request ?
+              ippOpString(con->request->request.op.operation_id) : "-",
+          con->response ?
+              ippErrorString(con->response->request.status.status_code) : "-");
 
     return (1);
   }
@@ -389,7 +627,8 @@ cupsdLogRequest(cupsd_client_t *con,        /* I - Request to log */
   cupsFilePrintf(AccessFile,
                  "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
                 con->http.hostname, con->username[0] != '\0' ? con->username : "-",
-                cupsdGetDateTime(con->start), states[con->operation], con->uri,
+                cupsdGetDateTime(con->start), states[con->operation],
+                _httpEncodeURI(temp, con->uri, sizeof(temp)),
                 con->http.version / 100, con->http.version % 100,
                 code, CUPS_LLCAST con->bytes,
                 con->request ?
@@ -404,6 +643,75 @@ cupsdLogRequest(cupsd_client_t *con,       /* I - Request to log */
 }
 
 
+/*
+ * 'cupsdWriteErrorLog()' - Write a line to the ErrorLog.
+ */
+
+int                                    /* O - 1 on success, 0 on failure */
+cupsdWriteErrorLog(int        level,   /* I - Log level */
+                   const char *message)        /* I - Message string */
+{
+  static const char    levels[] =      /* Log levels... */
+               {
+                 ' ',
+                 'X',
+                 'A',
+                 'C',
+                 'E',
+                 'W',
+                 'N',
+                 'I',
+                 'D',
+                 'd'
+               };
+#ifdef HAVE_VSYSLOG
+  static const int     syslevels[] =   /* SYSLOG levels... */
+               {
+                 0,
+                 LOG_EMERG,
+                 LOG_ALERT,
+                 LOG_CRIT,
+                 LOG_ERR,
+                 LOG_WARNING,
+                 LOG_NOTICE,
+                 LOG_INFO,
+                 LOG_DEBUG,
+                 LOG_DEBUG
+               };
+#endif /* HAVE_VSYSLOG */
+
+
+#ifdef HAVE_VSYSLOG
+ /*
+  * See if we are logging errors via syslog...
+  */
+
+  if (!strcmp(ErrorLog, "syslog"))
+  {
+    syslog(syslevels[level], "%s", message);
+    return (1);
+  }
+#endif /* HAVE_VSYSLOG */
+
+ /*
+  * Not using syslog; check the log file...
+  */
+
+  if (!check_log_file(&ErrorFile, ErrorLog))
+    return (0);
+
+ /*
+  * Write the log message...
+  */
+
+  cupsFilePrintf(ErrorFile, "%c %s %s\n", levels[level],
+                 cupsdGetDateTime(time(NULL)), message);
+  cupsFileFlush(ErrorFile);
+
+  return (1);
+}
+
+
 /*
  * 'check_log_file()' - Open/rotate a log file if it needs it.
  */
@@ -412,9 +720,10 @@ static int                         /* O  - 1 if log file open */
 check_log_file(cups_file_t **lf,       /* IO - Log file */
               const char  *logname)    /* I  - Log filename */
 {
-  char backname[1024],                 /* Backup log filename */
-       filename[1024],                 /* Formatted log filename */
-       *ptr;                           /* Pointer into filename */
+  char         backname[1024],         /* Backup log filename */
+               filename[1024],         /* Formatted log filename */
+               *ptr;                   /* Pointer into filename */
+  const char   *logptr;                /* Pointer into log filename */
 
 
  /*
@@ -428,7 +737,9 @@ check_log_file(cups_file_t **lf,    /* IO - Log file */
   * Format the filename as needed...
   */
 
-  if (!*lf || (cupsFileTell(*lf) > MaxLogSize && MaxLogSize > 0))
+  if (!*lf ||
+      (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
+       MaxLogSize > 0))
   {
    /*
     * Handle format strings...
@@ -444,17 +755,17 @@ check_log_file(cups_file_t **lf,  /* IO - Log file */
     else
       filename[0] = '\0';
 
-    for (ptr = filename + strlen(filename);
-         *logname && ptr < (filename + sizeof(filename) - 1);
-        logname ++)
-      if (*logname == '%')
+    for (logptr = logname, ptr = filename + strlen(filename);
+         *logptr && ptr < (filename + sizeof(filename) - 1);
+        logptr ++)
+      if (*logptr == '%')
       {
        /*
         * Format spec...
        */
 
-        logname ++;
-       if (*logname == 's')
+        logptr ++;
+       if (*logptr == 's')
        {
         /*
          * Insert the server name...
@@ -469,11 +780,11 @@ check_log_file(cups_file_t **lf,  /* IO - Log file */
          * Otherwise just insert the character...
          */
 
-         *ptr++ = *logname;
+         *ptr++ = *logptr;
        }
       }
       else
-       *ptr++ = *logname;
+       *ptr++ = *logptr;
 
     *ptr = '\0';
   }
@@ -490,10 +801,23 @@ check_log_file(cups_file_t **lf,  /* IO - Log file */
 
     if ((*lf = cupsFileOpen(filename, "a")) == NULL)
     {
-      syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
-             strerror(errno));
+     /*
+      * If the file is in CUPS_LOGDIR then try to create a missing directory...
+      */
 
-      return (0);
+      if (!strncmp(filename, CUPS_LOGDIR, strlen(CUPS_LOGDIR)))
+      {
+        cupsdCheckPermissions(CUPS_LOGDIR, NULL, 0755, RunUser, Group, 1, -1);
+
+        *lf = cupsFileOpen(filename, "a");
+      }
+
+      if (*lf == NULL)
+      {
+       syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
+              strerror(errno));
+       return (0);
+      }
     }
 
     if (strncmp(filename, "/dev/", 5))
@@ -511,7 +835,8 @@ check_log_file(cups_file_t **lf,    /* IO - Log file */
   * Do we need to rotate the log?
   */
 
-  if (cupsFileTell(*lf) > MaxLogSize && MaxLogSize > 0)
+  if (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
+      MaxLogSize > 0)
   {
    /*
     * Rotate log file...
@@ -533,14 +858,76 @@ check_log_file(cups_file_t **lf,  /* IO - Log file */
       return (0);
     }
 
-    if (strncmp(filename, "/dev/", 5))
+   /*
+    * Change ownership and permissions of non-device logs...
+    */
+
+    fchown(cupsFileNumber(*lf), RunUser, Group);
+    fchmod(cupsFileNumber(*lf), LogFilePerm);
+  }
+
+  return (1);
+}
+
+
+/*
+ * 'format_log_line()' - Format a line for a log file.
+ *
+ * This function resizes a global string buffer as needed.  Each call returns
+ * a pointer to this buffer, so the contents are only good until the next call
+ * to format_log_line()...
+ */
+
+static int                             /* O - -1 for fatal, 0 for retry, 1 for success */
+format_log_line(const char *message,   /* I - Printf-style format string */
+                va_list    ap)         /* I - Argument list */
+{
+  int          len;                    /* Length of formatted line */
+
+
+ /*
+  * Allocate the line buffer as needed...
+  */
+
+  if (!log_linesize)
+  {
+    log_linesize = 8192;
+    log_line     = malloc(log_linesize);
+
+    if (!log_line)
+      return (-1);
+  }
+
+ /*
+  * Format the log message...
+  */
+
+  len = vsnprintf(log_line, log_linesize, message, ap);
+
+ /*
+  * Resize the buffer as needed...
+  */
+
+  if (len >= log_linesize)
+  {
+    char       *temp;                  /* Temporary string pointer */
+
+
+    len ++;
+
+    if (len < 8192)
+      len = 8192;
+    else if (len > 65536)
+      len = 65536;
+
+    temp = realloc(log_line, len);
+
+    if (temp)
     {
-     /*
-      * Change ownership and permissions of non-device logs...
-      */
+      log_line     = temp;
+      log_linesize = len;
 
-      fchown(cupsFileNumber(*lf), RunUser, Group);
-      fchmod(cupsFileNumber(*lf), LogFilePerm);
+      return (0);
     }
   }
 
@@ -549,5 +936,5 @@ check_log_file(cups_file_t **lf,    /* IO - Log file */
 
 
 /*
- * End of "$Id: log.c 4860 2005-12-01 22:07:26Z mike $".
+ * End of "$Id: log.c 7699 2008-06-27 20:44:23Z mike $".
  */