xref: /netbsd-src/external/bsd/ekermit/dist/unixio.c (revision a704a1616e7ddaeafbe5387b074cf5a12f1e6545)
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