1*a704a161Sapb /* Sample system-dependent communications i/o routines for embedded Kermit. */
2*a704a161Sapb
3*a704a161Sapb /*
4*a704a161Sapb Author: Frank da Cruz.
5*a704a161Sapb Copyright (C) 1995, 2011.
6*a704a161Sapb Trustees of Columbia University in the City of New York.
7*a704a161Sapb All rights reserved.
8*a704a161Sapb See kermit.c for license.
9*a704a161Sapb */
10*a704a161Sapb
11*a704a161Sapb /*
12*a704a161Sapb The sample i/o routines for UNIX that provide packet i/o
13*a704a161Sapb functions on the console (login) device.
14*a704a161Sapb Copy this file, rename it appropriately, and replace the contents
15*a704a161Sapb of each routine appropriately for your platform.
16*a704a161Sapb
17*a704a161Sapb Device i/o:
18*a704a161Sapb
19*a704a161Sapb int devopen() Communications device - open
20*a704a161Sapb int pktmode() Communications device - enter/exit packet mode
21*a704a161Sapb int readpkt() Communications device - read a packet
22*a704a161Sapb int tx_data() Communications device - send data
23*a704a161Sapb int devclose() Communications device - close
24*a704a161Sapb int inchk() Communications device - check if bytes are ready to read
25*a704a161Sapb
26*a704a161Sapb File i/o:
27*a704a161Sapb
28*a704a161Sapb int openfile() File - open for input or output
29*a704a161Sapb ULONG fileinfo() Get input file modtime and size
30*a704a161Sapb int readfile() Input file - read data
31*a704a161Sapb int writefile() Output file - write data
32*a704a161Sapb int closefile() Input or output file - close
33*a704a161Sapb
34*a704a161Sapb Full definitions below, prototypes in kermit.h.
35*a704a161Sapb
36*a704a161Sapb These routines must handle speed setting, parity, flow control, file i/o,
37*a704a161Sapb and similar items without the kermit() routine knowing anything about it.
38*a704a161Sapb If parity is in effect, these routines must add it to outbound characters
39*a704a161Sapb and strip it from inbound characters.
40*a704a161Sapb */
41*a704a161Sapb #include <stdio.h>
42*a704a161Sapb #include <sys/stat.h>
43*a704a161Sapb #include <time.h>
44*a704a161Sapb #include <errno.h>
45*a704a161Sapb #ifndef O_WRONLY
46*a704a161Sapb #include <sys/file.h>
47*a704a161Sapb #ifdef X_OK
48*a704a161Sapb #undef X_OK
49*a704a161Sapb #endif /* X_OK */
50*a704a161Sapb #endif /* O_WRONLY */
51*a704a161Sapb
52*a704a161Sapb #include "cdefs.h"
53*a704a161Sapb #include "debug.h"
54*a704a161Sapb #include "platform.h"
55*a704a161Sapb #include "kermit.h"
56*a704a161Sapb
57*a704a161Sapb UCHAR o_buf[OBUFLEN+8]; /* File output buffer */
58*a704a161Sapb UCHAR i_buf[IBUFLEN+8]; /* File output buffer */
59*a704a161Sapb
60*a704a161Sapb /*
61*a704a161Sapb In this example, the output file is unbuffered to ensure that every
62*a704a161Sapb output byte is commited. The input file, however, is buffered for speed.
63*a704a161Sapb This is just one of many possible implmentation choices, invisible to the
64*a704a161Sapb Kermit protocol module.
65*a704a161Sapb */
66*a704a161Sapb static int ttyfd, ofile = -1; /* File descriptors */
67*a704a161Sapb static FILE * ifile = (FILE *)0; /* and pointers */
68*a704a161Sapb
69*a704a161Sapb /* Debugging */
70*a704a161Sapb
71*a704a161Sapb #ifdef DEBUG
72*a704a161Sapb static FILE * dp = (FILE *)0; /* Debug log */
73*a704a161Sapb static int xdebug = 0; /* Debugging on/off */
74*a704a161Sapb
75*a704a161Sapb void
dodebug(int fc,UCHAR * label,UCHAR * sval,long nval)76*a704a161Sapb dodebug(int fc, UCHAR * label, UCHAR * sval, long nval) {
77*a704a161Sapb
78*a704a161Sapb if (fc != DB_OPN && !xdebug)
79*a704a161Sapb return;
80*a704a161Sapb if (!label)
81*a704a161Sapb label = "";
82*a704a161Sapb
83*a704a161Sapb switch (fc) { /* Function code */
84*a704a161Sapb case DB_OPN: /* Open debug log */
85*a704a161Sapb if (dp) fclose(dp);
86*a704a161Sapb if (!*label) label = "debug.log";
87*a704a161Sapb dp = fopen(label,"w");
88*a704a161Sapb if (!dp) {
89*a704a161Sapb dp = stderr;
90*a704a161Sapb } else {
91*a704a161Sapb setbuf(dp,(char *)0);
92*a704a161Sapb }
93*a704a161Sapb xdebug = 1;
94*a704a161Sapb fprintf(dp,"DEBUG LOG OPEN\n");
95*a704a161Sapb return;
96*a704a161Sapb case DB_MSG: /* Write a message */
97*a704a161Sapb if (dp) fprintf(dp,"%s\n",label);
98*a704a161Sapb return;
99*a704a161Sapb case DB_CHR: /* Write label and character */
100*a704a161Sapb if (dp) fprintf(dp,"%s=[%c]\n",label,(char)nval);
101*a704a161Sapb return;
102*a704a161Sapb case DB_PKT: /* Log a packet */
103*a704a161Sapb /* (fill in later, fall thru for now...) */
104*a704a161Sapb case DB_LOG: /* Write label and string or number */
105*a704a161Sapb if (sval && dp)
106*a704a161Sapb fprintf(dp,"%s[%s]\n",label,sval);
107*a704a161Sapb else
108*a704a161Sapb fprintf(dp,"%s=%ld\n",label,nval);
109*a704a161Sapb return;
110*a704a161Sapb case DB_CLS: /* Close debug log */
111*a704a161Sapb if (dp) {
112*a704a161Sapb fclose(dp);
113*a704a161Sapb dp = (FILE *)0;
114*a704a161Sapb }
115*a704a161Sapb xdebug = 0;
116*a704a161Sapb }
117*a704a161Sapb }
118*a704a161Sapb #endif /* DEBUG */
119*a704a161Sapb
120*a704a161Sapb /* D E V O P E N -- Open communications device */
121*a704a161Sapb /*
122*a704a161Sapb
123*a704a161Sapb Call with: string pointer to device name. This routine should get the
124*a704a161Sapb current device settings and save them so devclose() can restore them.
125*a704a161Sapb It should open the device. If the device is a serial port, devopen()
126*a704a161Sapb set the speed, stop bits, flow control, etc.
127*a704a161Sapb Returns: 0 on failure, 1 on success.
128*a704a161Sapb */
129*a704a161Sapb int
devopen(char * device)130*a704a161Sapb devopen(char *device) {
131*a704a161Sapb ttyfd = 0;
132*a704a161Sapb return(1);
133*a704a161Sapb }
134*a704a161Sapb
135*a704a161Sapb /* P K T M O D E -- Put communications device into or out of packet mode */
136*a704a161Sapb /*
137*a704a161Sapb Call with: 0 to put in normal (cooked) mode, 1 to put in packet (raw) mode.
138*a704a161Sapb For a "dumb i/o device" like an i/o port that does not have a login attached
139*a704a161Sapb to it, this routine can usually be a no-op.
140*a704a161Sapb Returns: 0 on failure, 1 on success.
141*a704a161Sapb */
142*a704a161Sapb int
pktmode(short on)143*a704a161Sapb pktmode(short on) {
144*a704a161Sapb if (ttyfd < 0) /* Device must be open */
145*a704a161Sapb return(0);
146*a704a161Sapb system(on ? "stty raw -echo" : "stty sane"); /* Crude but effective */
147*a704a161Sapb return(1);
148*a704a161Sapb }
149*a704a161Sapb
150*a704a161Sapb
151*a704a161Sapb /* D E V S E T T I N G S */
152*a704a161Sapb
153*a704a161Sapb int
devsettings(char * s)154*a704a161Sapb devsettings(char * s) {
155*a704a161Sapb /* Get current device settings, save them for devrestore() */
156*a704a161Sapb /* Parse string s, do whatever it says, e.g. "9600;8N1" */
157*a704a161Sapb if (!pktmode(ON)) /* And put device in packet mode */
158*a704a161Sapb return(0);
159*a704a161Sapb return(1);
160*a704a161Sapb }
161*a704a161Sapb
162*a704a161Sapb /* D E V R E S T O R E */
163*a704a161Sapb
164*a704a161Sapb int
devrestore(void)165*a704a161Sapb devrestore(void) {
166*a704a161Sapb /* Put device back as we found it */
167*a704a161Sapb pktmode(OFF);
168*a704a161Sapb return(1);
169*a704a161Sapb }
170*a704a161Sapb
171*a704a161Sapb
172*a704a161Sapb /* D E V C L O S E -- Closes the current open communications device */
173*a704a161Sapb /*
174*a704a161Sapb Call with: nothing
175*a704a161Sapb Closes the device and puts it back the way it was found by devopen().
176*a704a161Sapb Returns: 0 on failure, 1 on success.
177*a704a161Sapb */
178*a704a161Sapb int
devclose(void)179*a704a161Sapb devclose(void) {
180*a704a161Sapb ttyfd = -1;
181*a704a161Sapb return(1);
182*a704a161Sapb }
183*a704a161Sapb
184*a704a161Sapb /* I N C H K -- Check if input waiting */
185*a704a161Sapb
186*a704a161Sapb /*
187*a704a161Sapb Check if input is waiting to be read, needed for sliding windows. This
188*a704a161Sapb sample version simply looks in the stdin buffer (which is not portable
189*a704a161Sapb even among different Unixes). If your platform does not provide a way to
190*a704a161Sapb look at the device input buffer without blocking and without actually
191*a704a161Sapb reading from it, make this routine return -1. On success, returns the
192*a704a161Sapb numbers of characters waiting to be read, i.e. that can be safely read
193*a704a161Sapb without blocking.
194*a704a161Sapb */
195*a704a161Sapb int
inchk(struct k_data * k)196*a704a161Sapb inchk(struct k_data * k) {
197*a704a161Sapb #ifdef _IO_file_flags /* Linux */
198*a704a161Sapb if (ttyfd < 0) /* Device must be open */
199*a704a161Sapb return(0);
200*a704a161Sapb return((int) ((stdin->_IO_read_end) - (stdin->_IO_read_ptr)));
201*a704a161Sapb #else
202*a704a161Sapb #ifdef AIX /* AIX */
203*a704a161Sapb if (ttyfd < 0)
204*a704a161Sapb return(0);
205*a704a161Sapb return(stdin->_cnt);
206*a704a161Sapb #else
207*a704a161Sapb #ifdef SunOS /* Solaris and SunOS */
208*a704a161Sapb if (ttyfd < 0)
209*a704a161Sapb return(0);
210*a704a161Sapb return(stdin->_cnt);
211*a704a161Sapb #else
212*a704a161Sapb #ifdef HPUX /* HPUX */
213*a704a161Sapb if (ttyfd < 0)
214*a704a161Sapb return(0);
215*a704a161Sapb return(stdin->__cnt);
216*a704a161Sapb #else
217*a704a161Sapb return(-1);
218*a704a161Sapb #endif /* HPUX */
219*a704a161Sapb #endif /* SunOS */
220*a704a161Sapb #endif /* AIX */
221*a704a161Sapb #endif /* _IO_file_flags */
222*a704a161Sapb }
223*a704a161Sapb
224*a704a161Sapb /* R E A D P K T -- Read a Kermit packet from the communications device */
225*a704a161Sapb /*
226*a704a161Sapb Call with:
227*a704a161Sapb k - Kermit struct pointer
228*a704a161Sapb p - pointer to read buffer
229*a704a161Sapb len - length of read buffer
230*a704a161Sapb
231*a704a161Sapb When reading a packet, this function looks for start of Kermit packet
232*a704a161Sapb (k->r_soh), then reads everything between it and the end of the packet
233*a704a161Sapb (k->r_eom) into the indicated buffer. Returns the number of bytes read, or:
234*a704a161Sapb 0 - timeout or other possibly correctable error;
235*a704a161Sapb -1 - fatal error, such as loss of connection, or no buffer to read into.
236*a704a161Sapb */
237*a704a161Sapb
238*a704a161Sapb int
readpkt(struct k_data * k,UCHAR * p,int len,int fc)239*a704a161Sapb readpkt(struct k_data * k, UCHAR *p, int len, int fc) {
240*a704a161Sapb int x, n, max;
241*a704a161Sapb short flag;
242*a704a161Sapb UCHAR c;
243*a704a161Sapb /*
244*a704a161Sapb Timeout not implemented in this sample.
245*a704a161Sapb It should not be needed. All non-embedded Kermits that are capable of
246*a704a161Sapb making connections are also capable of timing out, and only one Kermit
247*a704a161Sapb needs to time out. NOTE: This simple example waits for SOH and then
248*a704a161Sapb reads everything up to the negotiated packet terminator. A more robust
249*a704a161Sapb version might be driven by the value of the packet-length field.
250*a704a161Sapb */
251*a704a161Sapb #ifdef DEBUG
252*a704a161Sapb char * p2;
253*a704a161Sapb #endif /* DEBUG */
254*a704a161Sapb
255*a704a161Sapb #ifdef F_CTRLC
256*a704a161Sapb short ccn;
257*a704a161Sapb ccn = 0;
258*a704a161Sapb #endif /* F_CTRLC */
259*a704a161Sapb
260*a704a161Sapb if (ttyfd < 0 || !p) { /* Device not open or no buffer */
261*a704a161Sapb debug(DB_MSG,"readpkt FAIL",0,0);
262*a704a161Sapb return(-1);
263*a704a161Sapb }
264*a704a161Sapb flag = n = 0; /* Init local variables */
265*a704a161Sapb
266*a704a161Sapb #ifdef DEBUG
267*a704a161Sapb p2 = p;
268*a704a161Sapb #endif /* DEBUG */
269*a704a161Sapb
270*a704a161Sapb while (1) {
271*a704a161Sapb x = getchar(); /* Replace this with real i/o */
272*a704a161Sapb c = (k->parity) ? x & 0x7f : x & 0xff; /* Strip parity */
273*a704a161Sapb
274*a704a161Sapb #ifdef F_CTRLC
275*a704a161Sapb /* In remote mode only: three consecutive ^C's to quit */
276*a704a161Sapb if (k->remote && c == (UCHAR) 3) {
277*a704a161Sapb if (++ccn > 2) {
278*a704a161Sapb debug(DB_MSG,"readpkt ^C^C^C",0,0);
279*a704a161Sapb return(-1);
280*a704a161Sapb }
281*a704a161Sapb } else {
282*a704a161Sapb ccn = 0;
283*a704a161Sapb }
284*a704a161Sapb #endif /* F_CTRLC */
285*a704a161Sapb
286*a704a161Sapb if (!flag && c != k->r_soh) /* No start of packet yet */
287*a704a161Sapb continue; /* so discard these bytes. */
288*a704a161Sapb if (c == k->r_soh) { /* Start of packet */
289*a704a161Sapb flag = 1; /* Remember */
290*a704a161Sapb continue; /* But discard. */
291*a704a161Sapb } else if (c == k->r_eom /* Packet terminator */
292*a704a161Sapb || c == '\012' /* 1.3: For HyperTerminal */
293*a704a161Sapb ) {
294*a704a161Sapb #ifdef DEBUG
295*a704a161Sapb *p = NUL; /* Terminate for printing */
296*a704a161Sapb debug(DB_PKT,"RPKT",p2,n);
297*a704a161Sapb #endif /* DEBUG */
298*a704a161Sapb return(n);
299*a704a161Sapb } else { /* Contents of packet */
300*a704a161Sapb if (n++ > k->r_maxlen) /* Check length */
301*a704a161Sapb return(0);
302*a704a161Sapb else
303*a704a161Sapb *p++ = x & 0xff;
304*a704a161Sapb }
305*a704a161Sapb }
306*a704a161Sapb debug(DB_MSG,"READPKT FAIL (end)",0,0);
307*a704a161Sapb return(-1);
308*a704a161Sapb }
309*a704a161Sapb
310*a704a161Sapb /* T X _ D A T A -- Writes n bytes of data to communication device. */
311*a704a161Sapb /*
312*a704a161Sapb Call with:
313*a704a161Sapb k = pointer to Kermit struct.
314*a704a161Sapb p = pointer to data to transmit.
315*a704a161Sapb n = length.
316*a704a161Sapb Returns:
317*a704a161Sapb X_OK on success.
318*a704a161Sapb X_ERROR on failure to write - i/o error.
319*a704a161Sapb */
320*a704a161Sapb int
tx_data(struct k_data * k,UCHAR * p,int n)321*a704a161Sapb tx_data(struct k_data * k, UCHAR *p, int n) {
322*a704a161Sapb int x;
323*a704a161Sapb int max;
324*a704a161Sapb
325*a704a161Sapb max = 10; /* Loop breaker */
326*a704a161Sapb
327*a704a161Sapb while (n > 0) { /* Keep trying till done */
328*a704a161Sapb x = write(ttyfd,p,n);
329*a704a161Sapb debug(DB_MSG,"tx_data write",0,x);
330*a704a161Sapb if (x < 0 || --max < 1) /* Errors are fatal */
331*a704a161Sapb return(X_ERROR);
332*a704a161Sapb n -= x;
333*a704a161Sapb p += x;
334*a704a161Sapb }
335*a704a161Sapb return(X_OK); /* Success */
336*a704a161Sapb }
337*a704a161Sapb
338*a704a161Sapb /* O P E N F I L E -- Open output file */
339*a704a161Sapb /*
340*a704a161Sapb Call with:
341*a704a161Sapb Pointer to filename.
342*a704a161Sapb Size in bytes.
343*a704a161Sapb Creation date in format yyyymmdd hh:mm:ss, e.g. 19950208 14:00:00
344*a704a161Sapb Mode: 1 = read, 2 = create, 3 = append.
345*a704a161Sapb Returns:
346*a704a161Sapb X_OK on success.
347*a704a161Sapb X_ERROR on failure, including rejection based on name, size, or date.
348*a704a161Sapb */
349*a704a161Sapb int
openfile(struct k_data * k,UCHAR * s,int mode)350*a704a161Sapb openfile(struct k_data * k, UCHAR * s, int mode) {
351*a704a161Sapb
352*a704a161Sapb switch (mode) {
353*a704a161Sapb case 1: /* Read */
354*a704a161Sapb if (!(ifile = fopen(s,"r"))) {
355*a704a161Sapb debug(DB_LOG,"openfile read error",s,0);
356*a704a161Sapb return(X_ERROR);
357*a704a161Sapb }
358*a704a161Sapb k->s_first = 1; /* Set up for getkpt */
359*a704a161Sapb k->zinbuf[0] = '\0'; /* Initialize buffer */
360*a704a161Sapb k->zinptr = k->zinbuf; /* Set up buffer pointer */
361*a704a161Sapb k->zincnt = 0; /* and count */
362*a704a161Sapb debug(DB_LOG,"openfile read ok",s,0);
363*a704a161Sapb return(X_OK);
364*a704a161Sapb
365*a704a161Sapb case 2: /* Write (create) */
366*a704a161Sapb ofile = creat(s,0644);
367*a704a161Sapb if (ofile < 0) {
368*a704a161Sapb debug(DB_LOG,"openfile write error",s,0);
369*a704a161Sapb return(X_ERROR);
370*a704a161Sapb }
371*a704a161Sapb debug(DB_LOG,"openfile write ok",s,0);
372*a704a161Sapb return(X_OK);
373*a704a161Sapb
374*a704a161Sapb #ifdef COMMENT
375*a704a161Sapb case 3: /* Append (not used) */
376*a704a161Sapb ofile = open(s,O_WRONLY|O_APPEND);
377*a704a161Sapb if (ofile < 0) {
378*a704a161Sapb debug(DB_LOG,"openfile append error",s,0);
379*a704a161Sapb return(X_ERROR);
380*a704a161Sapb }
381*a704a161Sapb debug(DB_LOG,"openfile append ok",s,0);
382*a704a161Sapb return(X_OK);
383*a704a161Sapb #endif /* COMMENT */
384*a704a161Sapb
385*a704a161Sapb default:
386*a704a161Sapb return(X_ERROR);
387*a704a161Sapb }
388*a704a161Sapb }
389*a704a161Sapb
390*a704a161Sapb /* F I L E I N F O -- Get info about existing file */
391*a704a161Sapb /*
392*a704a161Sapb Call with:
393*a704a161Sapb Pointer to filename
394*a704a161Sapb Pointer to buffer for date-time string
395*a704a161Sapb Length of date-time string buffer (must be at least 18 bytes)
396*a704a161Sapb Pointer to int file type:
397*a704a161Sapb 0: Prevailing type is text.
398*a704a161Sapb 1: Prevailing type is binary.
399*a704a161Sapb Transfer mode (0 = auto, 1 = manual):
400*a704a161Sapb 0: Figure out whether file is text or binary and return type.
401*a704a161Sapb 1: (nonzero) Don't try to figure out file type.
402*a704a161Sapb Returns:
403*a704a161Sapb X_ERROR on failure.
404*a704a161Sapb 0L or greater on success == file length.
405*a704a161Sapb Date-time string set to yyyymmdd hh:mm:ss modtime of file.
406*a704a161Sapb If date can't be determined, first byte of buffer is set to NUL.
407*a704a161Sapb Type set to 0 (text) or 1 (binary) if mode == 0.
408*a704a161Sapb */
409*a704a161Sapb #ifdef F_SCAN
410*a704a161Sapb #define SCANBUF 1024
411*a704a161Sapb #define SCANSIZ 49152
412*a704a161Sapb #endif /* F_SCAN */
413*a704a161Sapb
414*a704a161Sapb ULONG
fileinfo(struct k_data * k,UCHAR * filename,UCHAR * buf,int buflen,short * type,short mode)415*a704a161Sapb fileinfo(struct k_data * k,
416*a704a161Sapb UCHAR * filename, UCHAR * buf, int buflen, short * type, short mode) {
417*a704a161Sapb struct stat statbuf;
418*a704a161Sapb struct tm * timestamp, * localtime();
419*a704a161Sapb
420*a704a161Sapb #ifdef F_SCAN
421*a704a161Sapb FILE * fp; /* File scan pointer */
422*a704a161Sapb char inbuf[SCANBUF]; /* and buffer */
423*a704a161Sapb #endif /* F_SCAN */
424*a704a161Sapb
425*a704a161Sapb if (!buf)
426*a704a161Sapb return(X_ERROR);
427*a704a161Sapb buf[0] = '\0';
428*a704a161Sapb if (buflen < 18)
429*a704a161Sapb return(X_ERROR);
430*a704a161Sapb if (stat(filename,&statbuf) < 0)
431*a704a161Sapb return(X_ERROR);
432*a704a161Sapb timestamp = localtime(&(statbuf.st_mtime));
433*a704a161Sapb sprintf(buf,"%04d%02d%02d %02d:%02d:%02d",
434*a704a161Sapb timestamp->tm_year + 1900,
435*a704a161Sapb timestamp->tm_mon + 1,
436*a704a161Sapb timestamp->tm_mday,
437*a704a161Sapb timestamp->tm_hour,
438*a704a161Sapb timestamp->tm_min,
439*a704a161Sapb timestamp->tm_sec
440*a704a161Sapb );
441*a704a161Sapb #ifdef F_SCAN
442*a704a161Sapb /*
443*a704a161Sapb Here we determine if the file is text or binary if the transfer mode is
444*a704a161Sapb not forced. This is an extremely crude sample, which diagnoses any file
445*a704a161Sapb that contains a control character other than HT, LF, FF, or CR as binary.
446*a704a161Sapb A more thorough content analysis can be done that accounts for various
447*a704a161Sapb character sets as well as various forms of Unicode (UTF-8, UTF-16, etc).
448*a704a161Sapb Or the diagnosis could be based wholly or in part on the filename.
449*a704a161Sapb etc etc. Or the implementation could skip this entirely by not defining
450*a704a161Sapb F_SCAN and/or by always calling this routine with type set to -1.
451*a704a161Sapb */
452*a704a161Sapb if (!mode) { /* File type determination requested */
453*a704a161Sapb int isbinary = 1;
454*a704a161Sapb fp = fopen(filename,"r"); /* Open the file for scanning */
455*a704a161Sapb if (fp) {
456*a704a161Sapb int n = 0, count = 0;
457*a704a161Sapb char c, * p;
458*a704a161Sapb
459*a704a161Sapb debug(DB_LOG,"fileinfo scan ",filename,0);
460*a704a161Sapb
461*a704a161Sapb isbinary = 0;
462*a704a161Sapb while (count < SCANSIZ && !isbinary) { /* Scan this much */
463*a704a161Sapb n = fread(inbuf,1,SCANBUF,fp);
464*a704a161Sapb if (n == EOF || n == 0)
465*a704a161Sapb break;
466*a704a161Sapb count += n;
467*a704a161Sapb p = inbuf;
468*a704a161Sapb while (n--) {
469*a704a161Sapb c = *p++;
470*a704a161Sapb if (c < 32 || c == 127) {
471*a704a161Sapb if (c != 9 && /* Tab */
472*a704a161Sapb c != 10 && /* LF */
473*a704a161Sapb c != 12 && /* FF */
474*a704a161Sapb c != 13) { /* CR */
475*a704a161Sapb isbinary = 1;
476*a704a161Sapb debug(DB_MSG,"fileinfo BINARY",0,0);
477*a704a161Sapb break;
478*a704a161Sapb }
479*a704a161Sapb }
480*a704a161Sapb }
481*a704a161Sapb }
482*a704a161Sapb fclose(fp);
483*a704a161Sapb *type = isbinary;
484*a704a161Sapb }
485*a704a161Sapb }
486*a704a161Sapb #endif /* F_SCAN */
487*a704a161Sapb
488*a704a161Sapb return((ULONG)(statbuf.st_size));
489*a704a161Sapb }
490*a704a161Sapb
491*a704a161Sapb
492*a704a161Sapb /* R E A D F I L E -- Read data from a file */
493*a704a161Sapb
494*a704a161Sapb int
readfile(struct k_data * k)495*a704a161Sapb readfile(struct k_data * k) {
496*a704a161Sapb if (!k->zinptr) {
497*a704a161Sapb #ifdef DEBUG
498*a704a161Sapb fprintf(dp,"readfile ZINPTR NOT SET\n");
499*a704a161Sapb #endif /* DEBUG */
500*a704a161Sapb return(X_ERROR);
501*a704a161Sapb }
502*a704a161Sapb if (k->zincnt < 1) { /* Nothing in buffer - must refill */
503*a704a161Sapb if (k->binary) { /* Binary - just read raw buffers */
504*a704a161Sapb k->dummy = 0;
505*a704a161Sapb k->zincnt = fread(k->zinbuf, 1, k->zinlen, ifile);
506*a704a161Sapb debug(DB_LOG,"readfile binary ok zincnt",0,k->zincnt);
507*a704a161Sapb
508*a704a161Sapb } else { /* Text mode needs LF/CRLF handling */
509*a704a161Sapb int c; /* Current character */
510*a704a161Sapb for (k->zincnt = 0; (k->zincnt < (k->zinlen - 2)); (k->zincnt)++) {
511*a704a161Sapb if ((c = getc(ifile)) == EOF)
512*a704a161Sapb break;
513*a704a161Sapb if (c == '\n') /* Have newline? */
514*a704a161Sapb k->zinbuf[(k->zincnt)++] = '\r'; /* Insert CR */
515*a704a161Sapb k->zinbuf[k->zincnt] = c;
516*a704a161Sapb }
517*a704a161Sapb #ifdef DEBUG
518*a704a161Sapb k->zinbuf[k->zincnt] = '\0';
519*a704a161Sapb debug(DB_LOG,"readfile text ok zincnt",0,k->zincnt);
520*a704a161Sapb #endif /* DEBUG */
521*a704a161Sapb }
522*a704a161Sapb k->zinbuf[k->zincnt] = '\0'; /* Terminate. */
523*a704a161Sapb if (k->zincnt == 0) /* Check for EOF */
524*a704a161Sapb return(-1);
525*a704a161Sapb k->zinptr = k->zinbuf; /* Not EOF - reset pointer */
526*a704a161Sapb }
527*a704a161Sapb (k->zincnt)--; /* Return first byte. */
528*a704a161Sapb
529*a704a161Sapb debug(DB_LOG,"readfile exit zincnt",0,k->zincnt);
530*a704a161Sapb debug(DB_LOG,"readfile exit zinptr",0,k->zinptr);
531*a704a161Sapb return(*(k->zinptr)++ & 0xff);
532*a704a161Sapb }
533*a704a161Sapb
534*a704a161Sapb
535*a704a161Sapb /* W R I T E F I L E -- Write data to file */
536*a704a161Sapb /*
537*a704a161Sapb Call with:
538*a704a161Sapb Kermit struct
539*a704a161Sapb String pointer
540*a704a161Sapb Length
541*a704a161Sapb Returns:
542*a704a161Sapb X_OK on success
543*a704a161Sapb X_ERROR on failure, such as i/o error, space used up, etc
544*a704a161Sapb */
545*a704a161Sapb int
writefile(struct k_data * k,UCHAR * s,int n)546*a704a161Sapb writefile(struct k_data * k, UCHAR * s, int n) {
547*a704a161Sapb int rc;
548*a704a161Sapb rc = X_OK;
549*a704a161Sapb
550*a704a161Sapb debug(DB_LOG,"writefile binary",0,k->binary);
551*a704a161Sapb
552*a704a161Sapb if (k->binary) { /* Binary mode, just write it */
553*a704a161Sapb if (write(ofile,s,n) != n)
554*a704a161Sapb rc = X_ERROR;
555*a704a161Sapb } else { /* Text mode, skip CRs */
556*a704a161Sapb UCHAR * p, * q;
557*a704a161Sapb int i;
558*a704a161Sapb q = s;
559*a704a161Sapb
560*a704a161Sapb while (1) {
561*a704a161Sapb for (p = q, i = 0; ((*p) && (*p != (UCHAR)13)); p++, i++) ;
562*a704a161Sapb if (i > 0)
563*a704a161Sapb if (write(ofile,q,i) != i)
564*a704a161Sapb rc = X_ERROR;
565*a704a161Sapb if (!*p) break;
566*a704a161Sapb q = p+1;
567*a704a161Sapb }
568*a704a161Sapb }
569*a704a161Sapb return(rc);
570*a704a161Sapb }
571*a704a161Sapb
572*a704a161Sapb /* C L O S E F I L E -- Close output file */
573*a704a161Sapb /*
574*a704a161Sapb Mode = 1 for input file, mode = 2 or 3 for output file.
575*a704a161Sapb
576*a704a161Sapb For output files, the character c is the character (if any) from the Z
577*a704a161Sapb packet data field. If it is D, it means the file transfer was canceled
578*a704a161Sapb in midstream by the sender, and the file is therefore incomplete. This
579*a704a161Sapb routine should check for that and decide what to do. It should be
580*a704a161Sapb harmless to call this routine for a file that that is not open.
581*a704a161Sapb */
582*a704a161Sapb int
closefile(struct k_data * k,UCHAR c,int mode)583*a704a161Sapb closefile(struct k_data * k, UCHAR c, int mode) {
584*a704a161Sapb int rc = X_OK; /* Return code */
585*a704a161Sapb
586*a704a161Sapb switch (mode) {
587*a704a161Sapb case 1: /* Closing input file */
588*a704a161Sapb if (!ifile) /* If not not open */
589*a704a161Sapb break; /* do nothing but succeed */
590*a704a161Sapb debug(DB_LOG,"closefile (input)",k->filename,0);
591*a704a161Sapb if (fclose(ifile) < 0)
592*a704a161Sapb rc = X_ERROR;
593*a704a161Sapb break;
594*a704a161Sapb case 2: /* Closing output file */
595*a704a161Sapb case 3:
596*a704a161Sapb if (ofile < 0) /* If not open */
597*a704a161Sapb break; /* do nothing but succeed */
598*a704a161Sapb debug(DB_LOG,"closefile (output) name",k->filename,0);
599*a704a161Sapb debug(DB_LOG,"closefile (output) keep",0,k->ikeep);
600*a704a161Sapb if (close(ofile) < 0) { /* Try to close */
601*a704a161Sapb rc = X_ERROR;
602*a704a161Sapb } else if ((k->ikeep == 0) && /* Don't keep incomplete files */
603*a704a161Sapb (c == 'D')) { /* This file was incomplete */
604*a704a161Sapb if (k->filename) {
605*a704a161Sapb debug(DB_LOG,"deleting incomplete",k->filename,0);
606*a704a161Sapb unlink(k->filename); /* Delete it. */
607*a704a161Sapb }
608*a704a161Sapb }
609*a704a161Sapb break;
610*a704a161Sapb default:
611*a704a161Sapb rc = X_ERROR;
612*a704a161Sapb }
613*a704a161Sapb return(rc);
614*a704a161Sapb }
615*a704a161Sapb
616*a704a161Sapb #ifdef DEBUG
xerror()617*a704a161Sapb int xerror() {
618*a704a161Sapb unsigned int x;
619*a704a161Sapb extern int errorrate; /* Fix this - NO EXTERNS */
620*a704a161Sapb if (!errorrate)
621*a704a161Sapb return(0);
622*a704a161Sapb x = rand() % 100; /* Fix this - NO C LIBRARY */
623*a704a161Sapb debug(DB_LOG,"RANDOM",0,x);
624*a704a161Sapb debug(DB_LOG,"ERROR",0,(x < errorrate));
625*a704a161Sapb return(x < errorrate);
626*a704a161Sapb }
627*a704a161Sapb #endif /* DEBUG */
628