]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - backend/pap.c
Merge changes from CUPS 1.4svn-r7961.
[thirdparty/cups.git] / backend / pap.c
index f5eadae33efda5cd06f7e2623ef078ce9e2317cd..12dbb9e89c4c382bcf777867c21fe7cfc01dc087 100644 (file)
@@ -1,7 +1,7 @@
 /*
-* "$Id: pap.c 5480 2006-05-02 15:17:04Z mike $"
+* "$Id: pap.c 7720 2008-07-11 22:46:21Z mike $"
 *
-* © Copyright 2004 Apple Computer, Inc. All rights reserved.
+* Copyright 2004-2008 Apple Inc. All rights reserved.
 * 
 * IMPORTANT:  This Apple software is supplied to you by Apple Computer,
 * Inc. ("Apple") in consideration of your agreement to the following
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
-* This program implements the Printer Access Protocol (PAP) on top of AppleTalk Transaction
-* Protocol (ATP). If it were to use the blocking pap functions of the AppleTalk library it 
-* would need seperate threads for reading, writing and status.
+* This program implements the Printer Access Protocol (PAP) on top of AppleTalk 
+* Transaction Protocol (ATP). If it were to use the blocking pap functions of 
+* the AppleTalk library it would need seperate threads for reading, writing
+* and status.
 *
 * Contents:
 *
-*  main()              - Send a file to the specified Appletalk printer.
-*  listDevices()       - List all LaserWriter printers in the local zone.
-*  printFile()         - Print from a file descriptor to an NBP specified printer.
-*  papOpen()           - Open a pap session to a printer.
-*  papClose()          - Close a pap session after cleaning up pending transactions.
-*  papWrite()          - Write bytes to a printer.
-*  papCloseResp()      - Send a pap close response in the rare case we receive a close connection request.
-*  papSendRequest()    - Fomrat and send a pap packet.
-*  papCancelRequest()  - Cancel a pending pap request.
-*  statusUpdate()      - Print printer status to stderr.
-*  parseUri()          - Extract the print name and zone from a uri.
-*  addPercentEscapes() - Encode a string with percent escapes.
-*  removePercentEscapes        - Returns a string with any percent escape sequences replaced with their equivalent.
-*  nbptuple_compare()  - Compare routine for qsort.
-*  okayToUseAppleTalk() - Returns true if AppleTalk is available and enabled.
-*  connectTimeout()    - Returns the connect timeout preference value.
-*  signalHandler()     - handle SIGINT to close the session before quiting.
+*  main()               - Send a file to the specified Appletalk printer.
+*  listDevices()        - List all LaserWriter printers in the local zone.
+*  printFile()          - Print file.
+*  papOpen()            - Open a pap session to a printer.
+*  papClose()           - Close a pap session.
+*  papWrite()           - Write bytes to a printer.
+*  papCloseResp()       - Send a pap close response.
+*  papSendRequest()     - Fomrat and send a pap packet.
+*  papCancelRequest()   - Cancel a pending pap request.
+*  sidechannel_request() - Handle side-channel requests.
+*  statusUpdate()       - Print printer status to stderr.
+*  parseUri()           - Extract the print name and zone from a uri.
+*  addPercentEscapes()  - Encode a string with percent escapes.
+*  removePercentEscapes         - Remove percent escape sequences from a string.
+*  nbptuple_compare()   - Compare routine for qsort.
+*  okayToUseAppleTalk()  - Returns true if AppleTalk is available and enabled.
+*  packet_name()        - Returns packet name string.
+*  connectTimeout()     - Returns the connect timeout preference value.
+*  signalHandler()      - handle SIGINT to close the session before quiting.
 */
 
+/*
+ * This backend uses deprecated APIs for AppleTalk; we know this, so
+ * silence any warnings about it...
+ */
+
+#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
+#  undef MAC_OS_X_VERSION_MIN_REQUIRED
+#endif /* MAX_OS_X_VERSION_MIN_REQUIRED */
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_0
+
+#include <config.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <sys/time.h>
 #include <sys/errno.h>
 
+#include <cups/cups.h>
+#include <cups/backend.h>
+#include <cups/sidechannel.h>
+#include <cups/i18n.h>
+
 #include <netat/appletalk.h>
 #include <netat/atp.h>
 #include <netat/ddp.h>
 #include <netat/nbp.h>
 #include <netat/pap.h>
 
-#include <cups/http.h>
-
 #include <libkern/OSByteOrder.h>
 
 #ifdef HAVE_APPLETALK_AT_PROTO_H
 #else
 /* These definitions come from at_proto.h... */
 #  define ZIP_DEF_INTERFACE NULL
-enum { RUNNING, NOTLOADED, LOADED, OTHERERROR };       /* Appletalk Stack status Function. */
+enum { RUNNING, NOTLOADED, LOADED, OTHERERROR };
 
 extern int atp_abort(int fd, at_inet_t *dest, u_short tid);
 extern int atp_close(int fd);
-extern int atp_getreq(int fd, at_inet_t *src, char *buf, int *len, int *userdata, int *xo, u_short *tid, u_char *bitmap, int nowait);
+extern int atp_getreq(int fd, at_inet_t *src, char *buf, int *len, int *userdata, 
+                     int *xo, u_short *tid, u_char *bitmap, int nowait);
 extern int atp_getresp(int fd, u_short *tid, at_resp_t *resp);
 extern int atp_look(int fd);
 extern int atp_open(at_socket *sock);
-extern int atp_sendreq(int fd, at_inet_t *dest, char *buf, int len, int userdata, int xo, int xo_relt, u_short *tid, at_resp_t *resp, at_retry_t *retry, int nowait);
-extern int atp_sendrsp(int fd, at_inet_t *dest, int xo, u_short tid, at_resp_t *resp);
+extern int atp_sendreq(int fd, at_inet_t *dest, char *buf, int len, 
+                      int userdata, int xo, int xo_relt, u_short *tid, 
+                      at_resp_t *resp, at_retry_t *retry, int nowait);
+extern int atp_sendrsp(int fd, at_inet_t *dest, int xo, u_short tid, 
+                      at_resp_t *resp);
 extern int checkATStack();
-extern int nbp_lookup(at_entity_t *entity, at_nbptuple_t *buf, int max, at_retry_t *retry);
-extern int nbp_make_entity(at_entity_t *entity, char *obj, char *type, char *zone);
+extern int nbp_lookup(at_entity_t *entity, at_nbptuple_t *buf, int max, 
+                     at_retry_t *retry);
+extern int nbp_make_entity(at_entity_t *entity, char *obj, char *type, 
+                          char *zone);
 extern int zip_getmyzone(char *ifName, at_nvestr_t *zone);
 #endif /* HAVE_APPLETALK_AT_PROTO_H */
 
@@ -116,7 +140,7 @@ extern int zip_getmyzone(char *ifName,      at_nvestr_t *zone);
 #include <CoreFoundation/CFPreferences.h>
 
 /* Defines */
-#define MAX_PRINTERS   500        /* Max number of printers we can lookup in listDevices */
+#define MAX_PRINTERS   500        /* Max number of printers we can lookup */
 #define PAP_CONNID     0
 #define PAP_TYPE       1
 #define PAP_EOF                2
@@ -126,50 +150,44 @@ extern int zip_getmyzone(char *ifName,    at_nvestr_t *zone);
 #define SEQUENCE_NUM(p)        (((u_char *)&p)[2])
 #define IS_PAP_EOF(p)  (((u_char *)&p)[2])
 
-#define  PAPPacketStr(x) \
-  ((x) == AT_PAP_TYPE_OPEN_CONN)       ? "PAP_OPEN_CONN"        : \
-  ((x) == AT_PAP_TYPE_OPEN_CONN_REPLY) ? "PAP_OPEN_CONN_REPLY"  : \
-  ((x) == AT_PAP_TYPE_SEND_DATA)       ? "PAP_SEND_DATA"        : \
-  ((x) == AT_PAP_TYPE_DATA)            ? "PAP_DATA"             : \
-  ((x) == AT_PAP_TYPE_TICKLE)          ? "PAP_TICKLE"           : \
-  ((x) == AT_PAP_TYPE_CLOSE_CONN)      ? "PAP_CLOSE_CONN"       : \
-  ((x) == AT_PAP_TYPE_CLOSE_CONN_REPLY)        ? "PAP_CLOSE_CONN_REPLY" : \
-  ((x) == AT_PAP_TYPE_SEND_STATUS)     ? "PAP_SEND_STATUS"      : \
-  ((x) == AT_PAP_TYPE_SEND_STS_REPLY)  ? "PAP_SEND_STS_REPLY"   : \
-  ((x) == AT_PAP_TYPE_READ_LW)         ? "PAP_READ_LW"          : \
-  "<Unknown>"
-
 #ifndef true
 #define true   1
 #define false  0
 #endif
 
 /* Globals */
-int       gSockfd      = 0;            /* Socket descriptor                */
-at_inet_t gSessionAddr = { 0 };        /* Address of the session responding socket    */
-u_char    gConnID      = 0;            /* PAP session connection id            */
-u_short   gSendDataID  = 0;            /* Transaction id of our pending send-data request  */
-u_short   gTickleID    = 0;            /* Transaction id of our outstanding tickle request*/
-int       gWaitEOF     = false;        /* Option: causes us to wait for a remote's EOF  */
+int       gSockfd      = 0;            /* Socket descriptor */
+at_inet_t gSessionAddr = { 0 };        /* Address of the session responding socket */
+u_char    gConnID      = 0;            /* PAP session connection id */
+u_short   gSendDataID  = 0;            /* Transaction id of pending send-data request  */
+u_short   gTickleID    = 0;            /* Transaction id of outstanding tickle request*/
+int       gWaitEOF     = false;        /* Option: wait for a remote's EOF  */
 int       gStatusInterval= 5;          /* Option: 0=off else seconds between status requests*/
 int       gErrorlogged  = false;       /* If an error was logged don't send any more INFO messages */
-int       gDebug       = 0;            /* Option: causes us to emit debugging info    */
+int       gDebug       = 0;            /* Option: emit debugging info    */
 
 /* Local functions */
 static int listDevices(void);
-static int printFile(char* name, char* type, char* zone, int fdin, int fdout, int fderr, int copies, int argc);
-static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, at_inet_t* pap_to, u_char* flowQuantum);
-static int papClose(int abortflag);
-static int papWrite(int sockfd, at_inet_t* dest, u_short tid, u_char connID, u_char flowQuantum, char* data, int len, int eof);
-static int papCloseResp(int sockfd, at_inet_t* dest, int xo, u_short tid, u_char connID);
-static int papSendRequest(int sockfd, at_inet_t* dest, u_char connID, int function, u_char bitmap, int xo, int seqno);
+static int printFile(char* name, char* type, char* zone, int fdin, int fdout, 
+                    int fderr, int copies, int argc);
+static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, 
+                  at_inet_t* pap_to, u_char* flowQuantum);
+static int papClose();
+static int papWrite(int sockfd, at_inet_t* dest, u_short tid, u_char connID, 
+                   u_char flowQuantum, char* data, int len, int eof);
+static int papCloseResp(int sockfd, at_inet_t* dest, int xo, u_short tid, 
+                       u_char connID);
+static int papSendRequest(int sockfd, at_inet_t* dest, u_char connID, 
+                         int function, u_char bitmap, int xo, int seqno);
 static int papCancelRequest(int sockfd, u_short tid);
+static void sidechannel_request();
 static void statusUpdate(char* status, u_char statusLen);
 static int parseUri(const char* argv0, char* name, char* type, char* zone);
 static int addPercentEscapes(const char* src, char* dst, int dstMax);
 static int removePercentEscapes(const char* src, char* dst, int dstMax);
 static int nbptuple_compare(const void *p1, const void *p2);
 static int okayToUseAppleTalk(void);
+static const char *packet_name(u_char x);
 static int connectTimeout(void);
 static void signalHandler(int sigraised);
 
@@ -199,21 +217,17 @@ int main (int argc, const char * argv[])
 
   if (argc == 1 || (argc == 2 && strcmp(argv[1], "-discover") == 0))
   {
-    /* Ignore errors returned by listDevices - they may be transitory 
-    *  and we don't want cupsd to think that pap is forever unusable.
-    */
     listDevices();
+
     return 0;
   }
 
   if (argc < 6 || argc > 7)
   {
-    fprintf(stderr, "argc = %d\n", argc);
-    for (err = 0; err < argc; err++) {
-      fprintf(stderr, "%02d:%s\n", err, argv[err]);
-    }
-    fprintf(stderr, "Usage: pap job-id user title copies options [file]\n");
-    exit(EINVAL);
+    _cupsLangPrintf(stderr,
+                    _("Usage: %s job-id user title copies options [file]\n"),
+                    argv[0]);
+    return (CUPS_BACKEND_FAILED);
   }
 
   /* If we have 7 arguments, print the file named on the command-line.
@@ -231,17 +245,19 @@ int main (int argc, const char * argv[])
     /* Try to open the print file... */
     if ((fp = fopen(argv[6], "rb")) == NULL)
     {
-      fprintf(stderr, "ERROR: unable to open print file \"%s\": %s\n", argv[6], strerror(errno));
-      return (1);
+      _cupsLangPrintf(stderr,
+                      _("ERROR: Unable to open print file \"%s\": %s\n"),
+                     argv[6], strerror(errno));
+      return (CUPS_BACKEND_FAILED);
     }
 
     copies = atoi(argv[4]);
   }
 
   /* Extract the device name and options from the URI... */
-  parseUri(argv[0], name, type, zone);
+  parseUri(cupsBackendDeviceURI((char **)argv), name, type, zone);
 
-  err = printFile(name, type, zone, fileno(fp), 3, STDERR_FILENO, copies, argc);
+  err = printFile(name, type, zone, fileno(fp), STDOUT_FILENO, STDERR_FILENO, copies, argc);
 
   if (fp != stdin)
     fclose(fp);
@@ -262,8 +278,7 @@ int main (int argc, const char * argv[])
  */
 static int listDevices(void)
 {
-  int  err = noErr;
-  int  ind;
+  int  i;
   int  numberFound;
 
   at_nvestr_t   at_zone;
@@ -278,19 +293,23 @@ static int listDevices(void)
   /* Make sure it's okay to use appletalk */
   if (!okayToUseAppleTalk())
   {
-    fprintf(stderr, "ERROR: AppleTalk disabled in System Preferences\n");
+    _cupsLangPuts(stderr, _("INFO: AppleTalk disabled in System Preferences\n"));
     return -1;  /* Network is down */
   }
 
-  if ((err = zip_getmyzone(ZIP_DEF_INTERFACE, &at_zone)) != 0)
+  if (zip_getmyzone(ZIP_DEF_INTERFACE, &at_zone))
   {
-    perror("ERROR: Unable to get default AppleTalk zone");
+    _cupsLangPrintError(_("ERROR: Unable to get default AppleTalk zone"));
     return -2;
   }
+
   memcpy(zone, at_zone.str, MIN(at_zone.len, sizeof(zone)-1));
   zone[MIN(at_zone.len, sizeof(zone)-1)] = '\0';
 
-  err = addPercentEscapes(zone, encodedZone, sizeof(encodedZone));
+  _cupsLangPrintf(stderr, _("INFO: Using default AppleTalk zone \"%s\"\n"),
+                  zone);
+
+  addPercentEscapes(zone, encodedZone, sizeof(encodedZone));
 
   /* Look up all the printers in our zone */
   nbp_make_entity(&entity, "=", "LaserWriter", zone);
@@ -300,20 +319,22 @@ static int listDevices(void)
 
   if ((numberFound = nbp_lookup(&entity, buf, MAX_PRINTERS, &retry)) < 0)
   {
-    perror("ERROR: Unable to lookup AppleTalk printers");
+    _cupsLangPrintError(_("ERROR: Unable to lookup AppleTalk printers"));
     return numberFound;
   }
 
   if (numberFound >= MAX_PRINTERS)
-    fprintf(stderr, "WARNING: Adding only the first %d printers found", MAX_PRINTERS);
+    _cupsLangPrintf(stderr,
+                    _("WARNING: Adding only the first %d printers found"),
+                   MAX_PRINTERS);
 
   /* Not required but sort them so they look nice */
   qsort(buf, numberFound, sizeof(at_nbptuple_t), nbptuple_compare);
 
-  for (ind = 0; ind < numberFound; ind++) 
+  for (i = 0; i < numberFound; i++) 
   {
-    memcpy(name, buf[ind].enu_entity.object.str, MIN(buf[ind].enu_entity.object.len, sizeof(name)-1));
-    name[MIN(buf[ind].enu_entity.object.len, sizeof(name)-1)] = '\0';
+    memcpy(name, buf[i].enu_entity.object.str, MIN(buf[i].enu_entity.object.len, sizeof(name)-1));
+    name[MIN(buf[i].enu_entity.object.len, sizeof(name)-1)] = '\0';
 
     if (addPercentEscapes(name, encodedName, sizeof(encodedName)) == 0)
     {
@@ -371,7 +392,7 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
   int  err;
   int  rc;
   int  val;
-  int  len, ind;
+  int  len, i;
 
   char fileBuffer[4096];    /* File buffer */
   int  fileBufferNbytes;
@@ -382,37 +403,52 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
   char sockBuffer[4096 + 1];    /* Socket buffer with room for nul */
   char atpReqBuf[AT_PAP_DATA_SIZE];
   fd_set readSet;
+  int  use_sidechannel;        /* Use side channel? */
 
   at_nbptuple_t        tuple;
   at_inet_t    sendDataAddr;
   at_inet_t    src;
   at_resp_t    resp;
-  int          userdata, xo, reqlen;
+  int          userdata, xo = 0, reqlen;
   u_short      tid;
   u_char       bitmap;
-  int          maxfdp1;
+  int          maxfdp1,
+               nbp_failures = 0;
   struct timeval timeout, *timeoutPtr;
   u_char       flowQuantum = 1;
-  u_short      recvSequence = 0;
   time_t       now,
-               connect_time,
+               start_time,
                elasped_time, 
                sleep_time,
                connect_timeout = -1,
                nextStatusTime = 0;
   at_entity_t  entity;
   at_retry_t   retry;
-  Boolean      recoverableErrShown = false;
-
 
 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
   struct sigaction action;  /* Actions for POSIX signals */
 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
 
+ /*
+  * Test the side channel descriptor before calling papOpen() since it may open
+  * an unused fd 4 (a.k.a. CUPS_SC_FD)...
+  */
+
+  FD_ZERO(&readSet);
+  FD_SET(CUPS_SC_FD, &readSet);
+
+  timeout.tv_sec  = 0;
+  timeout.tv_usec = 0;
+
+  if ((select(CUPS_SC_FD+1, &readSet, NULL, NULL, &timeout)) >= 0)
+    use_sidechannel = 1;
+  else
+    use_sidechannel = 0;
+
   /* try to find our printer */
   if ((err = nbp_make_entity(&entity, name, type, zone)) != noErr)
   {
-    fprintf(stderr, "ERROR: Unable to make AppleTalk address: %s\n", strerror(errno));
+    _cupsLangPrintError(_("ERROR: Unable to make AppleTalk address"));
     goto Exit;
   }
 
@@ -420,64 +456,75 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
   * Remember when we started looking for the printer.
   */
 
-  connect_time = time(NULL);
+  start_time = time(NULL);
 
   retry.interval = 1;
   retry.retries  = 5;
   retry.backoff  = 0;
 
+  fprintf(stderr, "STATE: +connecting-to-device\n");
+
   /* Loop forever trying to get an open session with the printer.  */
   for (;;)
   {
     /* Make sure it's okay to use appletalk */
     if (okayToUseAppleTalk())
     {
+      /* Clear this printer-state-reason in case we've set it */
+      fprintf(stderr, "STATE: -apple-appletalk-disabled-warning\n");
+
       /* Resolve the name into an address. Returns the number found or an error */
       if ((err = nbp_lookup(&entity, &tuple, 1, &retry)) > 0)
       {
         if (err > 1)
           fprintf(stderr, "DEBUG: Found more than one printer with the name \"%s\"\n", name);
 
-       if (recoverableErrShown)
-       {
-         fprintf(stderr, "INFO: recovered: \n");
-         sleep(5);
-         recoverableErrShown = false;
+        if (nbp_failures)
+        {
+         fprintf(stderr, "STATE: -apple-nbp-lookup-warning\n");
+         nbp_failures = 0;
        }
 
         /* Open a connection to the device */
         if ((err = papOpen(&tuple, &gConnID, &gSockfd, &gSessionAddr, &flowQuantum)) == 0)
           break;
 
-        fprintf(stderr, "WARNING: Unable to open \"%s:%s\": %s\n", name, zone, strerror(errno));
+        _cupsLangPrintf(stderr, _("WARNING: Unable to open \"%s:%s\": %s\n"),
+                       name, zone, strerror(err));
       }
       else
       {
-       fprintf(stderr, "WARNING: recoverable: Printer not responding\n");
-       recoverableErrShown = true;
+       /* It's not unusual to have to call nbp_lookup() twice before it's sucessful... */
+        if (++nbp_failures > 2)
+        {
+         retry.interval = 2;
+         retry.retries = 3;
+         fprintf(stderr, "STATE: +apple-nbp-lookup-warning\n");
+         _cupsLangPuts(stderr, _("WARNING: Printer not responding\n"));
+       }
       }
     }
     else
     {
-      fprintf(stderr, "WARNING: recoverable: AppleTalk disabled in System Preferences.\n");
-      recoverableErrShown = true;
+      fprintf(stderr, "STATE: +apple-appletalk-disabled-warning\n");
+      _cupsLangPuts(stderr,
+                    _("INFO: AppleTalk disabled in System Preferences.\n"));
     }
 
-    retry.retries = 3;
-    elasped_time = time(NULL) - connect_time;
+    elasped_time = time(NULL) - start_time;
 
     if (connect_timeout == -1)
       connect_timeout = connectTimeout();
 
     if (connect_timeout && elasped_time > connect_timeout)
     {
-      fprintf(stderr, "ERROR: Printer not responding\n");
+      _cupsLangPuts(stderr, _("ERROR: Printer not responding\n"));
       err = ETIMEDOUT;
       goto Exit;                                               /* Waiting too long... */
     }
-    else if (elasped_time < 30 /*(30 * 60)*/)
+    else if (elasped_time < (30 * 60))
       sleep_time = 10;                                 /* Waiting < 30 minutes */
-    else if (elasped_time < 60 /*(24 * 60 * 60)*/)
+    else if (elasped_time < (24 * 60 * 60))
       sleep_time = 30;                                 /* Waiting < 24 hours */
     else
       sleep_time = 60;                                 /* Waiting > 24 hours */
@@ -486,6 +533,8 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
     sleep(sleep_time);
   }
 
+  fprintf(stderr, "STATE: -connecting-to-device\n");
+
   /*
   * Now that we are connected to the printer ignore SIGTERM so that we
   * can finish out any page data the driver sends (e.g. to eject the
@@ -512,14 +561,14 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
 
 #endif /* HAVE_SIGSET */
 
-  fprintf(stderr, "INFO: Sending data\n");
+  _cupsLangPuts(stderr, _("INFO: Sending data\n"));
 
   sendDataAddr = tuple.enu_addr;
 
   /* Start the tickle packets and set a timeout alarm  */
   if ((err = papSendRequest(gSockfd, &gSessionAddr, gConnID, AT_PAP_TYPE_TICKLE, 0, false, false)) < 0)
   {
-    perror("ERROR: Unable to send PAP tickle request");
+    _cupsLangPrintError(_("ERROR: Unable to send PAP tickle request"));
     goto Exit;
   }
   signal(SIGALRM, signalHandler);
@@ -528,7 +577,7 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
   /* Prime the pump with an initial send-data packet */
   if ((err = papSendRequest(gSockfd, &gSessionAddr, gConnID, AT_PAP_TYPE_SEND_DATA, 0xFF, true, true)) < 0)
   {
-    perror("ERROR: Unable to send initial PAP send data request");
+    _cupsLangPrintError(_("ERROR: Unable to send initial PAP send data request"));
     goto Exit;
   }
 
@@ -536,26 +585,15 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
   val = fcntl(fdin, F_GETFL, 0);
   fcntl(fdin, F_SETFL, val | O_NONBLOCK);
 
-  /* Set non-blocking mode on our data destination descriptor */
-  val = fcntl(fdout, F_GETFL, 0);
-  if (val < 0)
-  {
-   /*
-    * Map output to stdout if we don't have the backchannel pipe
-    * available on file descriptor 3...
-    */
-
-    if (fdout == 3 && errno == EBADF)
-      fdout = 1;
-  }
-  else
-    fcntl(fdout, F_SETFL, val | O_NONBLOCK);
-
   fileBufferNbytes = 0;
   fileTbytes = 0;
   fileEOFRead = fileEOFSent = false;
+
   maxfdp1 = MAX(fdin, gSockfd) + 1;
 
+  if (use_sidechannel && CUPS_SC_FD >= maxfdp1)
+    maxfdp1 = CUPS_SC_FD + 1;
+
   if (gStatusInterval != 0)
   {
     timeout.tv_usec  = 0;
@@ -575,6 +613,9 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
     if (fileBufferNbytes == 0 && fileEOFRead == false)
       FD_SET(fdin, &readSet);
 
+    if (use_sidechannel)
+      FD_SET(CUPS_SC_FD, &readSet);
+
     /* Set the select timeout value based on the next status interval */
     if (gStatusInterval != 0)
     {
@@ -585,7 +626,7 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
     /* Wait here for something interesting to happen */
     if ((err = select(maxfdp1, &readSet, 0, 0, timeoutPtr)) < 0)
     {
-      perror("ERROR: select");
+      _cupsLangPrintError(_("ERROR: select() failed"));
       break;
     }
 
@@ -593,12 +634,19 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
     {
       /* Time to send a status request */
       if ((err = papSendRequest(gSockfd, &tuple.enu_addr, 0, AT_PAP_TYPE_SEND_STATUS, 0x01, false, false)) < 0)
-        perror("WARNING: Unable to send PAP status request");
+        _cupsLangPrintError(_("WARNING: Unable to send PAP status request"));
 
       if (gStatusInterval)
         nextStatusTime = time(NULL) + gStatusInterval;
     }
 
+   /*
+    * Check if we have a side-channel request ready...
+    */
+
+    if (use_sidechannel && FD_ISSET(CUPS_SC_FD, &readSet))
+      sidechannel_request();
+
     /* Was there an event on the input stream? */
     if (FD_ISSET(fdin, &readSet))
     {
@@ -637,7 +685,7 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
     {
       if ((rc = atp_look(gSockfd)) < 0)
       {
-        perror("ERROR: Unable to look for PAP response");
+        _cupsLangPrintError(_("ERROR: Unable to look for PAP response"));
         break;
       }
   
@@ -650,7 +698,7 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
   
         if ((err = atp_getresp(gSockfd, &tid, &resp)) < 0)
         {
-          perror("ERROR: Unable to get PAP response");
+          _cupsLangPrintError(_("ERROR: Unable to get PAP response"));
           break;
         }
         userdata = resp.userdata[0];
@@ -661,12 +709,12 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
         reqlen = sizeof(atpReqBuf);
         if ((err = atp_getreq(gSockfd, &src, atpReqBuf, &reqlen, &userdata, &xo, &tid, &bitmap, 0)) < 0)
         {
-          perror("ERROR: Unable to get PAP request");
+          _cupsLangPrintError(_("ERROR: Unable to get PAP request"));
           break;
         }
       }
 
-      fprintf(stderr, "DEBUG: <- %s\n", PAPPacketStr(TYPE_OF(userdata)));
+      fprintf(stderr, "DEBUG: <- %s\n", packet_name(TYPE_OF(userdata)));
 
       switch (TYPE_OF(userdata))
       {
@@ -681,7 +729,7 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
       case AT_PAP_TYPE_SEND_DATA:            /* Send-Data packet */
         sendDataAddr.socket  = src.socket;
         gSendDataID     = tid;
-        recvSequence    = OSReadBigInt16(&SEQUENCE_NUM(userdata), 0);
+        OSReadBigInt16(&SEQUENCE_NUM(userdata), 0);
 
         if ((fileBufferNbytes > 0 || fileEOFRead) && fileEOFSent == false)
         {
@@ -707,10 +755,10 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
         break;
     
       case AT_PAP_TYPE_DATA:              /* Data packet */
-        for (len=0, ind=0; ind < ATP_TRESP_MAX; ind++)
+        for (len=0, i=0; i < ATP_TRESP_MAX; i++)
         {
-          if (resp.bitmap & (1 << ind))
-            len += resp.resp[ind].iov_len;
+          if (resp.bitmap & (1 << i))
+            len += resp.resp[i].iov_len;
         }
 
         fprintf(stderr, "DEBUG: <- PAP_DATA %d bytes %s\n", len, IS_PAP_EOF(userdata) ? "with EOF" : "");
@@ -722,7 +770,7 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
           char logstr[512];
           int  logstrlen;
           
-         write(fdout, sockBuffer, len);
+         cupsBackChannelWrite(sockBuffer, len, 1.0);
           
           sockBuffer[len] = '\0';     /* We always reserve room for the nul so we can use strstr() below*/
           pLineBegin = sockBuffer;
@@ -780,13 +828,15 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
             goto Exit;
           else
           {
-            fprintf(stderr, "WARNING: Printer sent unexpected EOF\n");
+            _cupsLangPuts(stderr, _("WARNING: Printer sent unexpected EOF\n"));
           }
         }
 
         if ((err = papSendRequest(gSockfd, &gSessionAddr, gConnID, AT_PAP_TYPE_SEND_DATA, 0xFF, true, true)) < 0)
         {
-          fprintf(stderr, "ERROR: Error %d sending PAPSendData resuest: %s\n", err, strerror(errno));
+          _cupsLangPrintf(stderr,
+                         _("ERROR: Error %d sending PAPSendData request: %s\n"),
+                         err, strerror(errno));
           goto Exit;
         }
         break;
@@ -801,11 +851,11 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
         /* If this is EOF then were we expecting it? */
         if (fileEOFSent == true)
         {
-          fprintf(stderr, "WARNING: Printer sent unexpected EOF\n");
+          _cupsLangPuts(stderr, _("WARNING: Printer sent unexpected EOF\n"));
         }
         else
         {
-          fprintf(stderr, "ERROR: Printer sent unexpected EOF\n");
+          _cupsLangPuts(stderr, _("ERROR: Printer sent unexpected EOF\n"));
         }
         goto Exit;
         break;
@@ -814,11 +864,13 @@ static int printFile(char* name, char* type, char* zone, int fdin, int fdout, in
       case AT_PAP_TYPE_OPEN_CONN_REPLY:        /* Open-Connection-Reply packet */
       case AT_PAP_TYPE_SEND_STATUS:          /* Send-Status packet */
       case AT_PAP_TYPE_CLOSE_CONN_REPLY:        /* Close-Connection-Reply packet */
-        fprintf(stderr, "WARNING: Unexpected PAP packet of type %d\n", TYPE_OF(userdata));
+        _cupsLangPrintf(stderr, _("WARNING: Unexpected PAP packet of type %d\n"),
+                       TYPE_OF(userdata));
         break;
       
       default:
-        fprintf(stderr, "WARNING: Unknown PAP packet of type %d\n", TYPE_OF(userdata));
+        _cupsLangPrintf(stderr, _("WARNING: Unknown PAP packet of type %d\n"),
+                       TYPE_OF(userdata));
         break;
       }
     
@@ -835,7 +887,7 @@ Exit:
   /*
   * Close the socket and return...
   */
-  papClose(false);
+  papClose();
 
   return err;
 }
@@ -854,37 +906,34 @@ Exit:
  *
  * @result    A non-zero return value for errors
  */
-static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, at_inet_t* sessionAddr, u_char* flowQuantum)
+static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, 
+                  at_inet_t* sessionAddr, u_char* flowQuantum)
 {
   int          result,
-               openResult;
-  long         tm;
-  char         data[10], rdata[ATP_DATA_SIZE];
-  int          userdata;
-  u_char       *puserdata = (u_char *)&userdata;
-  at_socket    sock = 0;
-  u_short      waitTime;
-  int          status;
+               open_result,
+               userdata;
+  time_t       tm,
+               waitTime;
+  char         data[10], 
+               rdata[ATP_DATA_SIZE];
+  u_char       *puserdata;
+  at_socket    socketfd;
   at_resp_t    resp;
   at_retry_t   retry;
 
-  if (tuple == NULL)
-  {
-    errno = EINVAL;
-    return -1;
-  }
-
-  fprintf(stderr, "INFO: Opening connection\n");
+  result    = 0;
+  socketfd  = 0;
+  puserdata = (u_char *)&userdata;
 
-  errno  = 0;
-  result  = 0;
+  _cupsLangPuts(stderr, _("INFO: Opening connection\n"));
 
-  *fd = atp_open(&sock);
-  if (*fd < 0)
+  if ((*fd = atp_open(&socketfd)) < 0)
     return -1;
 
-  /* Build the open connection request packet.
+ /* 
+  * Build the open connection request packet.
   */
+
   tm = time(NULL);
   srand(tm);
 
@@ -901,64 +950,67 @@ static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, at_inet_t* ses
   resp.resp[0].iov_base = rdata;
   resp.resp[0].iov_len = sizeof(rdata);
 
-  data[0] = sock;
+  data[0] = socketfd;
   data[1] = 8;
 
   for (;;)
   {
-    waitTime = (u_short)(time(NULL) - tm);
-    OSWriteBigInt16(&data[2], 0, waitTime);
+    waitTime = time(NULL) - tm;
+    OSWriteBigInt16(&data[2], 0, (u_short)waitTime);
 
-    fprintf(stderr, "DEBUG: -> %s\n", PAPPacketStr(AT_PAP_TYPE_OPEN_CONN));
+    fprintf(stderr, "DEBUG: -> %s\n", packet_name(AT_PAP_TYPE_OPEN_CONN));
 
-    status = atp_sendreq(*fd, &tuple->enu_addr, data, 4, userdata, 1, 0, 0, &resp, &retry, 0);
-
-    if (status < 0)
+    if (atp_sendreq(*fd, &tuple->enu_addr, data, 4, userdata, 1, 0, 
+                   0, &resp, &retry, 0) < 0)
     {
       statusUpdate("Destination unreachable", 23);
       result = EHOSTUNREACH;
-      errno = EHOSTUNREACH;
-      sleep(1);
-      goto Exit;
+      break;
     }
-    else
-    {
-      puserdata = (u_char *)&resp.userdata[0];
-      openResult = OSReadBigInt16(&rdata[2], 0);
 
-      fprintf(stderr, "DEBUG: <- %s, status %d\n", PAPPacketStr(puserdata[1]), openResult);
+    puserdata = (u_char *)&resp.userdata[0];
+    open_result = OSReadBigInt16(&rdata[2], 0);
 
-      /* Just for the sake of our sanity check the other fields in the packet
-      */
-      if (puserdata[1] != AT_PAP_TYPE_OPEN_CONN_REPLY ||
-        (openResult == 0 && (puserdata[0] & 0xff) != *connID))
-      {
-       result = EINVAL;
-       errno = EINVAL;
-       goto Exit;
-      }
-  
-      statusUpdate(&rdata[5], rdata[4] & 0xff);
+    fprintf(stderr, "DEBUG: <- %s, status %d\n", packet_name(puserdata[1]), 
+           open_result);
 
-      if (openResult == 0)
-       break;        /* Connection established okay, exit from the loop */
+   /*
+    * Just for the sake of our sanity check the other fields in the packet
+    */
+
+    if (puserdata[1] != AT_PAP_TYPE_OPEN_CONN_REPLY ||
+       (open_result == 0 && (puserdata[0] & 0xff) != *connID))
+    {
+      result = EINVAL;
+      break;
     }
 
+    statusUpdate(&rdata[5], rdata[4] & 0xff);
+
+   /*
+    * if the connection established okay exit from the loop
+    */
+
+    if (open_result == 0)
+      break;
+
     sleep(1);
   }
 
-  /* Update the session address
-  */
-  sessionAddr->net  = tuple->enu_addr.net;
-  sessionAddr->node  = tuple->enu_addr.node;
-  sessionAddr->socket  = rdata[0];
-  *flowQuantum    = rdata[1];
-
-Exit:
-  if (result != 0)
+  if (result == 0)
+  {
+    /* Update the session address
+    */
+    sessionAddr->net  = tuple->enu_addr.net;
+    sessionAddr->node  = tuple->enu_addr.node;
+    sessionAddr->socket  = rdata[0];
+    *flowQuantum    = rdata[1];
+  }
+  else
   {
     atp_close(*fd);
     *fd = 0;
+    sleep(1);
   }
 
   return result;
@@ -970,16 +1022,12 @@ Exit:
  * @abstract  End a PAP session by canceling outstanding send-data & tickle 
  *            transactions and sending a PAP close request.
  *
- * @param  abort  If we're aborting then send the close request 
- *               with 0 retries (not yet implemented)
- *
  * @result  A non-zero return value for errors
  */
-static int papClose(int abortflag)
+static int papClose()
 {
   int          fd;
   u_short      tmpID;
-  int          result;
   unsigned char        rdata[ATP_DATA_SIZE];
   int          userdata;
   u_char       *puserdata = (u_char *)&userdata;
@@ -1018,7 +1066,7 @@ static int papClose(int abortflag)
     if (gWaitEOF == false)
       sleep(2);
 
-    fprintf(stderr, "DEBUG: -> %s\n", PAPPacketStr(AT_PAP_TYPE_CLOSE_CONN));
+    fprintf(stderr, "DEBUG: -> %s\n", packet_name(AT_PAP_TYPE_CLOSE_CONN));
   
     puserdata[0] = gConnID;
     puserdata[1] = AT_PAP_TYPE_CLOSE_CONN;
@@ -1032,9 +1080,9 @@ static int papClose(int abortflag)
     resp.resp[0].iov_base = rdata;
     resp.resp[0].iov_len = sizeof(rdata);
   
-    result = atp_sendreq(fd, &gSessionAddr, 0, 0, userdata, 1, 0, 0, &resp, &retry, 0);
+    atp_sendreq(fd, &gSessionAddr, 0, 0, userdata, 1, 0, 0, &resp, &retry, 0);
   
-    result = close(fd);
+    close(fd);
   }
   return noErr;
 }
@@ -1058,7 +1106,7 @@ static int papClose(int abortflag)
 static int papWrite(int sockfd, at_inet_t* dest, u_short tid, u_char connID, u_char flowQuantum, char* data, int len, int eof)
 {
   int          result;
-  int          ind;
+  int          i;
   u_char*      puserdata;
   at_resp_t    resp;
 
@@ -1076,26 +1124,26 @@ static int papWrite(int sockfd, at_inet_t* dest, u_short tid, u_char connID, u_c
   * response packets to reply to an incoming
   * PAP 'SENDDATA' request
   */
-  for (ind = 0; ind < flowQuantum; ind++)
+  for (i = 0; i < flowQuantum; i++)
   {
-    resp.userdata[ind] = 0;
-    puserdata = (u_char *)&resp.userdata[ind];
+    resp.userdata[i] = 0;
+    puserdata = (u_char *)&resp.userdata[i];
 
     puserdata[PAP_CONNID]  = connID;
     puserdata[PAP_TYPE]    = AT_PAP_TYPE_DATA;
     puserdata[PAP_EOF]    = eof ? 1 : 0;
 
-    resp.resp[ind].iov_base = (caddr_t)data;
+    resp.resp[i].iov_base = (caddr_t)data;
 
     if (data)
       data += AT_PAP_DATA_SIZE;
 
-    resp.resp[ind].iov_len = MIN((int)len, (int)AT_PAP_DATA_SIZE);
-    len -= resp.resp[ind].iov_len;
+    resp.resp[i].iov_len = MIN((int)len, (int)AT_PAP_DATA_SIZE);
+    len -= resp.resp[i].iov_len;
     if (len == 0)
       break;
   }
-  resp.bitmap = (1 << (ind + 1)) - 1;
+  resp.bitmap = (1 << (i + 1)) - 1;
 
   /*
   *  Write out the data as a PAP 'DATA' response
@@ -1168,7 +1216,7 @@ static int papSendRequest(int sockfd, at_inet_t* dest, u_char connID, int functi
   at_resp_t    resp;
   static u_short pap_send_count = 0;
 
-  fprintf(stderr, "DEBUG: -> %s\n", PAPPacketStr(function));
+  fprintf(stderr, "DEBUG: -> %s\n", packet_name(function));
 
   puserdata[0] = connID;
   puserdata[1] = function;
@@ -1226,6 +1274,50 @@ int papCancelRequest(int sockfd, u_short tid)
 }
 
 
+/*
+ * 'sidechannel_request()' - Handle side-channel requests.
+ */
+
+static void
+sidechannel_request()
+{
+  cups_sc_command_t    command;        /* Request command */
+  cups_sc_status_t     status;         /* Request/response status */
+  char                 data[2048];     /* Request/response data */
+  int                  datalen;        /* Request/response data size */
+
+  datalen = sizeof(data);
+
+  if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+  {
+    fputs(_("WARNING: Failed to read side-channel request!\n"), stderr);
+    return;
+  }
+
+  switch (command)
+  {
+    case CUPS_SC_CMD_GET_BIDI:         /* Is the connection bidirectional? */
+       data[0] = 1;
+       cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
+       break;
+
+    case CUPS_SC_CMD_GET_STATE:                /* Return device state */
+       data[0] = CUPS_SC_STATE_ONLINE;
+       cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
+       break;
+
+    case CUPS_SC_CMD_DRAIN_OUTPUT:     /* Drain all pending output */
+    case CUPS_SC_CMD_SOFT_RESET:       /* Do a soft reset */
+    case CUPS_SC_CMD_GET_DEVICE_ID:    /* Return IEEE-1284 device ID */
+    default:
+       cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED, 
+                            NULL, 0, 1.0);
+       break;
+  }
+  return;
+}
+
+
 #pragma mark -
 /*!
  * @function  statusUpdate
@@ -1274,24 +1366,26 @@ void statusUpdate(char* status, u_char statusLen)
  */
 static int parseUri(const char* argv0, char* name, char* type, char* zone)
 {
-  char  scheme[255],           /* Scheme in URI */
+  char  method[255],           /* Method in URI */
         hostname[1024],                /* Hostname */
         username[255],         /* Username info (not used) */
         resource[1024],                /* Resource info (device and options) */
         *resourcePtr,
         *typePtr,
         *options,              /* Pointer to options */
-        optionName[255],       /* Name of option */
-        value[255],            /* Value of option */
-        *ptr;                  /* Pointer into name or value */
+        *optionName,           /* Name of option */
+        *value,                        /* Value of option */
+        sep;                   /* Separator character */
   int   port;                  /* Port number (not used) */
   int   statusInterval;                /* */
 
   /*
   * Extract the device name and options from the URI...
   */
+  method[0] = username[0] = hostname[0] = resource[0] = '\0';
+  port = 0;
 
-  httpSeparateURI(HTTP_URI_CODING_NONE, argv0, scheme, sizeof(scheme), 
+  httpSeparateURI(HTTP_URI_CODING_NONE, argv0, method, sizeof(method), 
                  username, sizeof(username),
                  hostname, sizeof(hostname), &port,
                  resource, sizeof(resource));
@@ -1309,68 +1403,76 @@ static int parseUri(const char* argv0, char* name, char* type, char* zone)
 
     while (*options != '\0')
     {
-      /*
+     /*
       * Get the name...
       */
-      for (ptr = optionName; *options && *options != '=' && *options != '+'; )
-        *ptr++ = *options++;
 
-      *ptr = '\0';
-      value[0] = '\0';
+      optionName = options;
 
-      if (*options == '=')
-      {
-        /*
-        * Get the value...
-        */
-        
+      while (*options && *options != '=' && *options != '+' && *options != '&')
         options ++;
-        
-        for (ptr = value; *options && *options != '+';)
-          *ptr++ = *options++;
-
-        *ptr = '\0';
-        
-        if (*options == '+')
-          options ++;
-      }
-      else if (*options == '+')
+
+      if ((sep = *options) != '\0')
+        *options++ = '\0';
+
+      if (sep == '=')
       {
-        options ++;
+       /*
+        * Get the value...
+       */
+
+        value = options;
+
+       while (*options && *options != '+' && *options != '&')
+         options ++;
+
+        if (*options)
+         *options++ = '\0';
       }
+      else
+        value = (char *)"";
 
-      /*
+     /*
       * Process the option...
       */
-      if (strcasecmp(optionName, "waiteof") == 0)
+
+      if (!strcasecmp(optionName, "waiteof"))
       {
-        /*
-        * Set the banner...
+       /*
+        * Wait for the end of the print file?
         */
-        if (strcasecmp(value, "on") == 0 ||
-          strcasecmp(value, "yes") == 0 ||
-          strcasecmp(value, "true") == 0)
+
+        if (!strcasecmp(value, "on") ||
+            !strcasecmp(value, "yes") ||
+            !strcasecmp(value, "true"))
         {
           gWaitEOF = true;
         }
-        else if (strcasecmp(value, "off") == 0 ||
-            strcasecmp(value, "no") == 0 ||
-            strcasecmp(value, "false") == 0)
+        else if (!strcasecmp(value, "off") ||
+                 !strcasecmp(value, "no") ||
+                 !strcasecmp(value, "false"))
         {
           gWaitEOF = false;
         }
         else
         {
-          fprintf(stderr, "WARNING: Boolean expected for waiteof option \"%s\"\n", value);
+          _cupsLangPrintf(stderr,
+                         _("WARNING: Boolean expected for waiteof option \"%s\"\n"),
+                         value);
         }
       }
-      else if (strcasecmp(optionName, "status") == 0)
+      else if (!strcasecmp(optionName, "status"))
       {
+       /*
+        * Set status reporting interval...
+       */
+
         statusInterval = atoi(value);
-        if (value[0] < '0' || value[0] > '9' || 
-          statusInterval < 0)
+        if (value[0] < '0' || value[0] > '9' || statusInterval < 0)
         {
-          fprintf(stderr, "WARNING: number expected for status option \"%s\"\n", value);
+          _cupsLangPrintf(stderr,
+                         _("WARNING: number expected for status option \"%s\"\n"),
+                         value);
         }
         else
         {
@@ -1385,20 +1487,24 @@ static int parseUri(const char* argv0, char* name, char* type, char* zone)
   if (*resourcePtr == '/')
     resourcePtr++;
 
-        /* If the resource has a slash we assume the slash seperates the AppleTalk object
-         * name from the AppleTalk type. If the slash is not present we assume the AppleTalk
-         * type is LaserWriter.
-         */
-        typePtr = strchr(resourcePtr, '/');
-        if (typePtr != NULL) {
-            *typePtr++ = '\0';
-        } else {
-            typePtr = "LaserWriter";
-        }
+ /* If the resource has a slash we assume the slash seperates the AppleTalk object
+  * name from the AppleTalk type. If the slash is not present we assume the AppleTalk
+  * type is LaserWriter.
+  */
+
+  typePtr = strchr(resourcePtr, '/');
+  if (typePtr != NULL)
+  {
+    *typePtr++ = '\0';
+  }
+  else
+  {
+    typePtr = "LaserWriter";
+  }
 
-  removePercentEscapes(hostname,    zone, NBP_NVE_STR_SIZE + 1);
-  removePercentEscapes(resourcePtr,  name, NBP_NVE_STR_SIZE + 1);
-  removePercentEscapes(typePtr,     type, NBP_NVE_STR_SIZE + 1);
+  removePercentEscapes(hostname, zone, NBP_NVE_STR_SIZE + 1);
+  removePercentEscapes(resourcePtr, name, NBP_NVE_STR_SIZE + 1);
+  removePercentEscapes(typePtr, type, NBP_NVE_STR_SIZE + 1);
 
   return 0;
 }
@@ -1527,6 +1633,31 @@ static int okayToUseAppleTalk()
 }
 
 
+/*!
+ * @function  packet_name
+ * @abstract  Returns packet name string.
+ *
+ * @result    A string
+ */
+static const char *packet_name(u_char x)
+{
+  switch (x)
+  {
+  case AT_PAP_TYPE_OPEN_CONN:          return "PAP_OPEN_CONN";
+  case AT_PAP_TYPE_OPEN_CONN_REPLY:    return "PAP_OPEN_CONN_REPLY";
+  case AT_PAP_TYPE_SEND_DATA:          return "PAP_SEND_DATA";
+  case AT_PAP_TYPE_DATA:               return "PAP_DATA";
+  case AT_PAP_TYPE_TICKLE:             return "PAP_TICKLE";
+  case AT_PAP_TYPE_CLOSE_CONN:         return "PAP_CLOSE_CONN";
+  case AT_PAP_TYPE_CLOSE_CONN_REPLY:   return "PAP_CLOSE_CONN_REPLY";
+  case AT_PAP_TYPE_SEND_STATUS:                return "PAP_SEND_STATUS";
+  case AT_PAP_TYPE_SEND_STS_REPLY:     return "PAP_SEND_STS_REPLY";
+  case AT_PAP_TYPE_READ_LW:            return "PAP_READ_LW";
+  }
+  return "<Unknown>";
+}
+
+
 /*!
  * @function  connectTimeout
  * @abstract  Returns the connect timeout preference value.
@@ -1560,9 +1691,9 @@ static int connectTimeout()
  */
 static void signalHandler(int sigraised)
 {
-  fprintf(stderr, "ERROR: There was a timeout error while sending data to the printer\n");
+  _cupsLangPuts(stderr, _("ERROR: There was a timeout error while sending data to the printer\n"));
 
-  papClose(true);
+  papClose();
 
   _exit(1);
 }