/*
-* "$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 */
#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
#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);
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.
/* 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);
*/
static int listDevices(void)
{
- int err = noErr;
- int ind;
+ int i;
int numberFound;
at_nvestr_t at_zone;
/* 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);
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)
{
int err;
int rc;
int val;
- int len, ind;
+ int len, i;
char fileBuffer[4096]; /* File buffer */
int fileBufferNbytes;
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;
}
* 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 */
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
#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);
/* 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;
}
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;
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)
{
/* Wait here for something interesting to happen */
if ((err = select(maxfdp1, &readSet, 0, 0, timeoutPtr)) < 0)
{
- perror("ERROR: select");
+ _cupsLangPrintError(_("ERROR: select() failed"));
break;
}
{
/* 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))
{
{
if ((rc = atp_look(gSockfd)) < 0)
{
- perror("ERROR: Unable to look for PAP response");
+ _cupsLangPrintError(_("ERROR: Unable to look for PAP response"));
break;
}
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];
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))
{
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)
{
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" : "");
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;
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;
/* 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;
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;
}
/*
* Close the socket and return...
*/
- papClose(false);
+ papClose();
return err;
}
*
* @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);
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;
* @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;
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;
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;
}
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;
* 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
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;
}
+/*
+ * '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
*/
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));
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
{
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;
}
}
+/*!
+ * @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.
*/
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);
}