#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <libintl.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include "netpr.h"
#define TIMEOUT 1
static int netpr_send_message(int, char *, ...);
static int xfer_cfAfile(int, char *, char *, uint);
int
bsd_print(int sockfd, caddr_t pa, np_bsdjob_t * bsdjob)
{
int filesize;
int xfer;
int net;
syslog(LOG_DEBUG, "bsd_print");
filesize = bsdjob->np_data->np_data_size;
syslog(LOG_DEBUG, "filesize is %d", filesize);
if (netpr_send_message(sockfd, "%c%s\n", XFER_REQUEST,
bsdjob->np_printer) != 0) {
return (NETWORK_ERROR_SEND_RESPONSE);
}
if (bsdjob->np_print_order == CONTROL_FIRST) {
if ((xfer_cfAfile(sockfd, bsdjob->np_cfAfile,
bsdjob->np_cfAfilename,
bsdjob->np_cfAfilesize)) != 0) {
(void) fprintf(stderr,
gettext("Netpr: Error sending control file\n"));
syslog(LOG_DEBUG, "Error sending control file");
return (NETWORK_ERROR_UNKNOWN);
}
}
if ((netpr_send_message(sockfd, "%c%d %s\n", XFER_DATA, filesize,
bsdjob->np_data->np_dfAfilename)) != 0) {
return (NETWORK_ERROR_SEND_RESPONSE);
}
if ((xfer = xfer_file(sockfd, pa, filesize, bsdjob->np_timeout)) != 0) {
return (xfer);
}
if ((net = netpr_send_message(sockfd, "", NULL)) != 0) {
(void) fprintf(stderr,
gettext("Netpr: network error transfering %s returns: %d\n"),
bsdjob->np_filename, net);
syslog(LOG_DEBUG,
"network error transfering %s returns: %d",
bsdjob->np_filename, net);
return (NETWORK_ERROR_WRITE_FAILED);
}
if (bsdjob->np_print_order == DATA_FIRST) {
if ((xfer_cfAfile(sockfd, bsdjob->np_cfAfile,
bsdjob->np_cfAfilename,
bsdjob->np_cfAfilesize)) != 0) {
(void) fprintf(stderr,
gettext("Netpr: Error sending control file\n"));
syslog(LOG_DEBUG, "Error sending control file");
return (NETWORK_ERROR_UNKNOWN);
}
}
return (0);
}
int
xfer_file(int sockfd, caddr_t pa, int filesize, int seed)
{
int ctr;
int timeout;
int nw;
int error_msg = 0;
int pause = 0;
syslog(LOG_DEBUG, "xfer_file");
ctr = filesize;
timeout = seed = seed ? seed : 10;
while (ctr > 0) {
syslog(LOG_DEBUG, "xfer_file: write while loop => ctr = %d", ctr);
syslog(LOG_DEBUG, "xfer_file: timeout = %d", timeout);
(void) signal(SIGALRM, null_sighandler);
(void) alarm(10);
nw = write(sockfd, pa, ctr);
syslog(LOG_DEBUG, "xfer_file: write while loop => nw = %d", nw);
(void) alarm(0);
if ((nw == 0) || (nw < 0)) {
if (timeout < (seed * 4)) {
(void) sleep(timeout);
timeout *= 2;
} else if (timeout == (seed * 4)) {
(void) sleep(timeout);
timeout *= 2;
if (error_msg == 0) {
error_msg++;
tell_lptell(ERRORMSG,
gettext("Printer not accepting input;"
"possibly offline or out of paper."));
}
} else if (timeout > (seed * 4)) {
(void) sleep(timeout);
if (pause++ > 3)
timeout = (seed * 10);
}
} else {
ctr -= nw;
pa += nw;
if (error_msg) {
tell_lptell(OKMSG, "Current");
error_msg = 0;
pause = 0;
}
timeout = seed;
}
}
return (E_SUCCESS);
}
static int
xfer_cfAfile(int sockfd, char * cfAfile, char * cfAname, uint size)
{
int ctr;
caddr_t pa;
int nw = 0;
int timeout;
int printererr;
syslog(LOG_DEBUG, "xfer_cfAfile");
if ((netpr_send_message(sockfd, "%c%d %s\n", XFER_CONTROL,
size, cfAname)) != 0) {
return (NETWORK_ERROR_MSG_FAILED);
}
pa = cfAfile;
ctr = size;
syslog(LOG_DEBUG, "xfer_cfAfile : cfAfile %s", pa);
syslog(LOG_DEBUG, "xfer_cfAfile : size %d", size);
timeout = TIMEOUT;
printererr = 0;
while (ctr > 0) {
(void) signal(SIGALRM, null_sighandler);
(void) alarm(2);
nw = write(sockfd, pa, size);
(void) alarm(0);
if (nw <= 0) {
if (timeout < 16) {
(void) sleep(timeout);
timeout *= 2;
} else if (timeout == 16) {
(void) sleep(timeout);
timeout *= 2;
printererr = 1;
tell_lptell(ERRORMSG,
gettext("Printer not accepting input;"
"possibly offline or out of paper."));
} else if (timeout > 16) {
(void) sleep(timeout);
}
}
ctr -= nw;
pa += nw;
}
if (printererr == 1) {
(void) fprintf(stderr, gettext("Printer status ok\n"));
tell_lptell(OKMSG, "Current");
}
if (netpr_send_message(sockfd, "", NULL) != 0) {
return (NETWORK_ERROR_MSG_FAILED);
}
return (0);
}
static int
netpr_response(int nd)
{
char c;
int msg_given = 0;
int firstloop = 0;
syslog(LOG_DEBUG, "netpr_response");
(void) signal(SIGALRM, null_sighandler);
(void) alarm(2);
while (1) {
errno = 0;
if ((read(nd, &c, 1) != 1)) {
if (firstloop == 0) {
(void) alarm(0);
firstloop++;
}
if (errno == EINTR) {
if (msg_given == 0) {
tell_lptell(ERRORMSG,
gettext("Printer not responding;"
"Either warming up or needs attention"));
msg_given++;
syslog(LOG_DEBUG,
"read hanging in netpr_response: %m");
}
} else {
syslog(LOG_DEBUG,
"read in netpr_response failed: %m");
return (NETWORK_READ_RESPONSE_FAILED);
}
} else {
if (c) {
syslog(LOG_DEBUG,
"Printer returned error: %m");
return (NETWORK_PRINTER_REFUSED_CONN);
} else {
if (msg_given)
tell_lptell(OKMSG, "Current");
return (0);
}
}
}
}
static int
netpr_send_message(int nd, char *fmt, ...)
{
char buf[BUFSIZ];
int ctr;
char * pa;
va_list ap;
int timeout = 1;
int nw;
int err_msg = 0;
syslog(LOG_DEBUG, "netpr_send_message");
va_start(ap, fmt);
(void) vsnprintf(buf, sizeof (buf), fmt, ap);
va_end(ap);
pa = buf;
ctr = (strlen(buf) != 0) ? strlen(buf) : 1;
syslog(LOG_DEBUG, "netpr_send_message : ctr = %d", ctr);
while (ctr > 0) {
(void) signal(SIGALRM, null_sighandler);
(void) alarm(2);
nw = write(nd, pa, ctr);
syslog(LOG_DEBUG, "netpr_send_message : nw = %d", nw);
(void) alarm(0);
if (nw <= 0) {
if (timeout < 16) {
(void) sleep(timeout);
timeout *= 2;
} else if (timeout == 16) {
(void) sleep(timeout);
timeout *= 2;
if (err_msg == 0) {
err_msg++;
tell_lptell(ERRORMSG,
gettext("Printer not accepting input;"
"possibly offline or out of paper."));
}
} else
(void) sleep(timeout);
} else {
ctr -= nw;
pa += nw;
if (err_msg)
tell_lptell(OKMSG, "Current");
}
}
return (netpr_response(nd));
}
void
null_sighandler(int i)
{
}