|
|
1.1 root 1: /* sexyz.c */
2:
3: /* Synchronet External X/Y/ZMODEM Transfer Protocols */
4:
5: /* $Id: sexyz.c,v 1.77 2006/12/28 22:25:36 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /*
39: * ZMODEM code based on zmtx/zmrx v1.02 (C) Mattheij Computer Service 1994
40: * by Jacques Mattheij <[email protected]>
41: */
42:
43: #include <time.h>
44: #include <stdio.h>
45: #include <errno.h>
46: #include <string.h>
47: #include <stdlib.h>
48: #include <stdarg.h>
49: #include <ctype.h> /* isdigit */
50: #include <sys/stat.h>
51:
52: #ifdef __unix__
53: #include <termios.h>
54: #include <signal.h>
55: #endif
56:
57: /* xpdev */
58: #include "conwrap.h"
59: #include "genwrap.h"
60: #include "semwrap.h"
61: #include "dirwrap.h"
62: #include "filewrap.h"
63: #include "sockwrap.h"
64: #include "str_list.h"
65: #include "ini_file.h"
66: #include "eventwrap.h"
67: #include "threadwrap.h"
68:
69: /* sbbs */
70: #include "ringbuf.h"
71: #include "telnet.h"
72: #include "nopen.h"
73:
74: /* sexyz */
75: #include "sexyz.h"
76:
77: #define SINGLE_THREADED FALSE
78: #define MIN_OUTBUF_SIZE 1024
79: #define MAX_OUTBUF_SIZE (64*1024)
80:
81: /***************/
82: /* Global Vars */
83: /***************/
84: long mode=0; /* Program mode */
85: long zmode=0L; /* Zmodem mode */
86: uchar block[1024]; /* Block buffer */
87: ulong block_num; /* Block number */
88: char* dszlog;
89: BOOL dszlog_path=TRUE; /* Log complete path to filename */
90: BOOL dszlog_short=FALSE; /* Log Micros~1 short filename */
91: BOOL dszlog_quotes=FALSE; /* Quote filenames in DSZLOG */
92: int log_level=LOG_INFO;
93:
94: xmodem_t xm;
95: zmodem_t zm;
96:
97: FILE* errfp;
98: FILE* statfp;
99: FILE* logfp=NULL;
100:
101: char revision[16];
102:
103: SOCKET sock=INVALID_SOCKET;
104:
105: BOOL telnet=TRUE;
106: #ifdef __unix__
107: BOOL stdio=FALSE;
108: struct termios origterm;
109: #endif
110: BOOL aborted=FALSE;
111: BOOL terminate=FALSE;
112: BOOL debug_tx=FALSE;
113: BOOL debug_rx=FALSE;
114: BOOL debug_telnet=FALSE;
115: BOOL pause_on_exit=FALSE;
116: BOOL pause_on_abend=FALSE;
117: BOOL newline=TRUE;
118:
119: time_t progress_interval;
120:
121: RingBuf outbuf;
122: #if defined(RINGBUF_EVENT)
123: #define outbuf_empty outbuf.empty_event
124: #else
125: xpevent_t outbuf_empty;
126: #endif
127: unsigned outbuf_drain_timeout;
128: long outbuf_size;
129:
130: unsigned flows=0;
131: unsigned select_errors=0;
132:
133: #ifdef __unix__
134: void resetterm(void)
135: {
136: tcsetattr(STDOUT_FILENO, TCSADRAIN, &origterm);
137: }
138: #endif
139:
140: #ifdef _WINSOCKAPI_
141:
142: /* Note: Don't call WSACleanup() or TCP session will close! */
143: WSADATA WSAData;
144:
145: static BOOL winsock_startup(void)
146: {
147: int status; /* Status Code */
148:
149: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
150: fprintf(statfp,"%s %s\n",WSAData.szDescription, WSAData.szSystemStatus);
151: return(TRUE);
152: }
153:
154: fprintf(errfp,"!WinSock startup ERROR %d\n", status);
155: return(FALSE);
156: }
157:
158: #else /* No WINSOCK */
159:
160: #define winsock_startup() (TRUE)
161:
162: #endif
163:
164: static int lputs(void* unused, int level, const char* str)
165: {
166: FILE* fp=statfp;
167:
168: #if defined(_WIN32) && defined(_DEBUG)
169: if(log_level==LOG_DEBUG)
170: OutputDebugString(str);
171: #endif
172:
173: if(level>log_level)
174: return 0;
175:
176: if(level<LOG_NOTICE)
177: fp=errfp;
178:
179: if(!newline) {
180: fprintf(fp,"\n");
181: newline=TRUE;
182: }
183: if(level<LOG_NOTICE)
184: return fprintf(fp,"!%s\n",str);
185: else
186: return fprintf(fp,"%s\n",str);
187: }
188:
189: static int lprintf(int level, const char *fmt, ...)
190: {
191: char sbuf[1024];
192: va_list argptr;
193:
194: va_start(argptr,fmt);
195: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
196: sbuf[sizeof(sbuf)-1]=0;
197: va_end(argptr);
198: return(lputs(NULL,level,sbuf));
199: }
200:
201: void break_handler(int type)
202: {
203: lprintf(LOG_NOTICE,"-> Aborted Locally (signal: %d)",type);
204:
205: /* Flag to indicate local (as opposed to remote) abort */
206: aborted=TRUE;
207:
208: /* Stop any transfers in progress immediately */
209: xm.cancelled=TRUE;
210: zm.cancelled=TRUE;
211: }
212:
213: #if defined(_WIN32)
214: BOOL WINAPI ControlHandler(DWORD CtrlType)
215: {
216: break_handler((int)CtrlType);
217: return TRUE;
218: }
219: #endif
220:
221: char* dszlog_filename(char* str)
222: {
223: char* p=str;
224: static char path[MAX_PATH+1];
225:
226: #ifdef _WIN32
227: char sfpath[MAX_PATH+1];
228: if(dszlog_short) {
229: SAFECOPY(sfpath,str);
230: GetShortPathName(str,sfpath,sizeof(sfpath));
231: p=sfpath;
232: }
233: #endif
234:
235: if(!dszlog_path)
236: p=getfname(p);
237:
238: if(!dszlog_quotes)
239: return(p);
240:
241: SAFEPRINTF(path,"\"%s\"",p);
242: return(path);
243: }
244:
245: static char *chr(uchar ch)
246: {
247: static char str[25];
248:
249: if(mode&ZMODEM) {
250: switch(ch) {
251: case ZRQINIT: return("ZRQINIT");
252: case ZRINIT: return("ZRINIT");
253: case ZSINIT: return("ZSINIT");
254: case ZACK: return("ZACK");
255: case ZFILE: return("ZFILE");
256: case ZSKIP: return("ZSKIP");
257: case ZNAK: return("ZNAK");
258: case ZABORT: return("ZABORT");
259: case ZFIN: return("ZFIN");
260: case ZRPOS: return("ZRPOS");
261: case ZDATA: return("ZDATA");
262: case ZEOF: return("ZEOF");
263: case ZPAD: return("ZPAD");
264: case ZDLE: return("ZDLE");
265: case ZDLEE: return("ZDLEE");
266: case ZBIN: return("ZBIN");
267: case ZHEX: return("ZHEX");
268: case ZBIN32: return("ZBIN32");
269: case ZRESC: return("ZRESC");
270: case ZCRCE: return("ZCRCE");
271: case ZCRCG: return("ZCRCG");
272: case ZCRCQ: return("ZCRCQ");
273: case ZCRCW: return("ZCRCW");
274: }
275: } else {
276: switch(ch) {
277: case SOH: return("SOH");
278: case STX: return("STX");
279: case ETX: return("ETX");
280: case EOT: return("EOT");
281: case ACK: return("ACK");
282: case NAK: return("NAK");
283: case CAN: return("CAN");
284: }
285: }
286: if(ch>=' ' && ch<='~')
287: sprintf(str,"'%c' (%02Xh)",ch,ch);
288: else
289: sprintf(str,"%u (%02Xh)",ch,ch);
290: return(str);
291: }
292:
293: void dump(BYTE* buf, int len)
294: {
295: char str[128];
296: int i,j;
297: size_t slen=0;
298:
299: slen=sprintf(str,"TX: ");
300: for(i=0;i<len;i+=j) {
301: for(j=0;i+j<len && j<32;j++)
302: slen+=sprintf(str+slen,"%02X ",buf[i+j]);
303: lprintf(LOG_DEBUG,"%s",str);
304: slen=sprintf(str,"TX: ");
305: }
306: }
307:
308: void send_telnet_cmd(SOCKET sock, uchar cmd, uchar opt)
309: {
310: uchar buf[3];
311:
312: buf[0]=TELNET_IAC;
313: buf[1]=cmd;
314: buf[2]=opt;
315:
316: if(debug_telnet)
317: lprintf(LOG_DEBUG,"Sending telnet command: %s %s"
318: ,telnet_cmd_desc(buf[1]),telnet_opt_desc(buf[2]));
319:
320: if(sendsocket(sock,buf,sizeof(buf))!=sizeof(buf) && debug_telnet)
321: lprintf(LOG_ERR,"FAILED");
322: }
323:
324: #define DEBUG_TELNET FALSE
325:
326: /****************************************************************************/
327: /* Receive a byte from remote (single-threaded version) */
328: /****************************************************************************/
329: int recv_byte(void* unused, unsigned timeout)
330: {
331: int i;
332: long t;
333: uchar ch;
334: fd_set socket_set;
335: time_t end;
336: struct timeval tv;
337: static uchar telnet_cmd;
338: static int telnet_cmdlen;
339:
340: end=msclock()+(timeout*MSCLOCKS_PER_SEC);
341: while(!terminate) {
342:
343: FD_ZERO(&socket_set);
344: #ifdef __unix__
345: if(stdio)
346: FD_SET(STDIN_FILENO,&socket_set);
347: else
348: #endif
349: FD_SET(sock,&socket_set);
350: if((t=end-msclock())<0) t=0;
351: tv.tv_sec=t/MSCLOCKS_PER_SEC;
352: tv.tv_usec=0;
353:
354: if((i=select(sock+1,&socket_set,NULL,NULL,&tv))<1) {
355: if(i==SOCKET_ERROR) {
356: lprintf(LOG_ERR,"ERROR %d selecting socket", ERROR_VALUE);
357: }
358: if(timeout)
359: lprintf(LOG_WARNING,"Receive timeout (%u seconds)", timeout);
360: return(NOINP);
361: }
362:
363: #ifdef __unix__
364: if(stdio)
365: i=read(STDIN_FILENO,&ch,sizeof(ch));
366: else
367: #endif
368: i=recv(sock,&ch,sizeof(ch),0);
369:
370: if(i!=sizeof(ch)) {
371: if(i==0) {
372: lprintf(LOG_WARNING,"Socket Disconnected");
373: } else
374: lprintf(LOG_ERR,"recv error %d (%d)",i,ERROR_VALUE);
375: return(NOINP);
376: }
377:
378: if(telnet) {
379: if(ch==TELNET_IAC) {
380: #if DEBUG_TELNET
381: lprintf(LOG_DEBUG,"T<%s> ",telnet_cmd_desc(ch));
382: #endif
383: if(telnet_cmdlen==0) {
384: telnet_cmdlen=1;
385: continue;
386: }
387: if(telnet_cmdlen==1) {
388: telnet_cmdlen=0;
389: if(debug_rx)
390: lprintf(LOG_DEBUG,"RX: %s",chr(TELNET_IAC));
391: return(TELNET_IAC);
392: }
393: }
394: if(telnet_cmdlen) {
395: telnet_cmdlen++;
396: #if DEBUG_TELNET
397: if(telnet_cmdlen==2)
398: lprintf(LOG_DEBUG,"T<%s> ",telnet_cmd_desc(ch));
399: else
400: lprintf(LOG_DEBUG,"T<%s> ",telnet_opt_desc(ch));
401: #endif
402: if(debug_telnet && telnet_cmdlen==3)
403: lprintf(LOG_DEBUG,"Received telnet command: %s %s"
404: ,telnet_cmd_desc(telnet_cmd),telnet_opt_desc(ch));
405: if(telnet_cmdlen==3 && telnet_cmd==TELNET_DO)
406: send_telnet_cmd(sock, TELNET_WILL,ch);
407: /*
408: else if(telnet_cmdlen==3 && telnet_cmd==TELNET_WILL)
409: send_telnet_cmd(sock, TELNET_DO,ch);
410: */
411: telnet_cmd=ch;
412: if((telnet_cmdlen==2 && ch<TELNET_WILL) || telnet_cmdlen>2) {
413: telnet_cmdlen=0;
414: /* Code disabled. Why? ToDo */
415: /* break; */
416: }
417: continue;
418: }
419: }
420: if(debug_rx)
421: lprintf(LOG_DEBUG,"RX: %s",chr(ch));
422: return(ch);
423: }
424:
425: return(NOINP);
426: }
427:
428: #if !SINGLE_THREADED
429: /*************************/
430: /* Send a byte to remote */
431: /*************************/
432: int send_byte(void* unused, uchar ch, unsigned timeout)
433: {
434: uchar buf[2] = { TELNET_IAC, TELNET_IAC };
435: unsigned len=1;
436: DWORD result;
437:
438: if(telnet && ch==TELNET_IAC) /* escape IAC char */
439: len=2;
440: else
441: buf[0]=ch;
442:
443: if(RingBufFree(&outbuf)<len) {
444: fprintf(statfp,"FLOW");
445: flows++;
446: result=WaitForEvent(outbuf_empty,timeout*1000);
447: fprintf(statfp,"\b\b\b\b \b\b\b\b");
448: if(result!=WAIT_OBJECT_0) {
449: fprintf(statfp
450: ,"\n!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n"
451: ,result, timeout, RingBufFull(&outbuf));
452: newline=TRUE;
453: if(RingBufFree(&outbuf)<len)
454: return(-1);
455: }
456: }
457:
458: RingBufWrite(&outbuf,buf,len);
459: #if !defined(RINGBUF_EVENT)
460: ResetEvent(outbuf_empty);
461: #endif
462:
463: #if 0
464: if(debug_tx)
465: lprintf(LOG_DEBUG,"TX: %s",chr(ch));
466: #endif
467: return(0);
468: }
469:
470: #else
471:
472: /*************************/
473: /* Send a byte to remote */
474: /*************************/
475: int send_byte(void* unused, uchar ch, unsigned timeout)
476: {
477: uchar buf[2] = { TELNET_IAC, TELNET_IAC };
478: int len=1;
479: int i;
480: fd_set socket_set;
481: struct timeval tv;
482:
483: FD_ZERO(&socket_set);
484: #ifdef __unix__
485: if(stdio)
486: FD_SET(STDOUT_FILENO,&socket_set);
487: else
488: #endif
489: FD_SET(sock,&socket_set);
490: tv.tv_sec=timeout;
491: tv.tv_usec=0;
492:
493: if(select(sock+1,NULL,&socket_set,NULL,&tv)<1)
494: return(ERROR_VALUE);
495:
496: if(telnet && ch==TELNET_IAC) /* escape IAC char */
497: len=2;
498: else
499: buf[0]=ch;
500:
501: #ifdef __unix__
502: if(stdio)
503: i=write(STDOUT_FILENO,buf,len);
504: else
505: #endif
506: i=sendsocket(sock,buf,len);
507:
508: if(i==len) {
509: if(debug_tx)
510: lprintf(LOG_DEBUG,"TX: %s",chr(ch));
511: return(0);
512: }
513:
514: return(-1);
515: }
516: #endif
517:
518: static void output_thread(void* arg)
519: {
520: char stats[128];
521: BYTE buf[MAX_OUTBUF_SIZE];
522: int i;
523: ulong avail;
524: ulong total_sent=0;
525: ulong total_pkts=0;
526: ulong short_sends=0;
527: ulong bufbot=0;
528: ulong buftop=0;
529: fd_set socket_set;
530: struct timeval tv;
531:
532: #if 0 /* def _DEBUG */
533: fprintf(statfp,"output thread started\n");
534: #endif
535:
536: while(sock!=INVALID_SOCKET && !terminate) {
537:
538: if(bufbot==buftop)
539: avail=RingBufFull(&outbuf);
540: else
541: avail=buftop-bufbot;
542:
543: if(!avail) {
544: #if !defined(RINGBUF_EVENT)
545: SetEvent(outbuf_empty);
546: #endif
547: sem_wait(&outbuf.sem);
548: if(outbuf.highwater_mark)
549: sem_trywait_block(&outbuf.highwater_sem,outbuf_drain_timeout);
550: continue;
551: }
552:
553: /* Check socket for writability (using select) */
554: tv.tv_sec=0;
555: tv.tv_usec=1000;
556:
557: FD_ZERO(&socket_set);
558: #ifdef __unix__
559: if(stdio)
560: FD_SET(STDOUT_FILENO,&socket_set);
561: else
562: #endif
563: FD_SET(sock,&socket_set);
564:
565: i=select(sock+1,NULL,&socket_set,NULL,&tv);
566: if(i==SOCKET_ERROR) {
567: lprintf(LOG_ERR,"ERROR %d selecting socket %u for send"
568: ,ERROR_VALUE,sock);
569: break;
570: }
571: if(i<1) {
572: select_errors++;
573: continue;
574: }
575:
576: if(bufbot==buftop) { /* linear buf empty, read from ring buf */
577: if(avail>sizeof(buf)) {
578: lprintf(LOG_ERR,"Insufficient linear output buffer (%lu > %lu)"
579: ,avail, sizeof(buf));
580: avail=sizeof(buf);
581: }
582: buftop=RingBufRead(&outbuf, buf, avail);
583: bufbot=0;
584: }
585: #ifdef __unix__
586: if(stdio)
587: i=write(STDOUT_FILENO, (char*)buf+bufbot, buftop-bufbot);
588: else
589: #endif
590: i=sendsocket(sock, (char*)buf+bufbot, buftop-bufbot);
591: if(i==SOCKET_ERROR) {
592: if(ERROR_VALUE == ENOTSOCK)
593: lprintf(LOG_ERR,"client socket closed on send");
594: else if(ERROR_VALUE==ECONNRESET)
595: lprintf(LOG_ERR,"connection reset by peer on send");
596: else if(ERROR_VALUE==ECONNABORTED)
597: lprintf(LOG_ERR,"connection aborted by peer on send");
598: else
599: lprintf(LOG_ERR,"ERROR %d sending on socket %d"
600: ,ERROR_VALUE, sock);
601: break;
602: }
603:
604: if(debug_tx)
605: dump(buf+bufbot,i);
606:
607: if(i!=(int)(buftop-bufbot)) {
608: lprintf(LOG_ERR,"Short socket send (%u instead of %u)"
609: ,i ,buftop-bufbot);
610: short_sends++;
611: }
612: bufbot+=i;
613: total_sent+=i;
614: total_pkts++;
615: }
616:
617: if(total_sent)
618: sprintf(stats,"(sent %lu bytes in %lu blocks, %lu average, %lu short, %lu errors)"
619: ,total_sent, total_pkts, total_sent/total_pkts, short_sends, select_errors);
620: else
621: stats[0]=0;
622:
623: lprintf(LOG_DEBUG,"output thread terminated\n%s", stats);
624: }
625:
626: BOOL is_connected(void* unused)
627: {
628: return socket_check(sock,NULL,NULL,0);
629: }
630:
631: BOOL data_waiting(void* unused, unsigned timeout)
632: {
633: BOOL rd;
634:
635: if(!socket_check(sock,&rd,NULL,timeout))
636: return(FALSE);
637: return(rd);
638: }
639:
640: /****************************************************************************/
641: /* Returns the number of blocks required to send len bytes */
642: /****************************************************************************/
643: unsigned num_blocks(ulong len, unsigned block_size)
644: {
645: ulong blocks;
646:
647: blocks=len/block_size;
648: if(len%block_size)
649: blocks++;
650: return(blocks);
651: }
652:
653: /************************************************/
654: /* Dump the current block contents - for debug */
655: /************************************************/
656: void dump_block(long block_size)
657: {
658: long l;
659:
660: for(l=0;l<block_size;l++)
661: fprintf(statfp,"%02X ",block[l]);
662: fprintf(statfp,"\n");
663: }
664:
665: void xmodem_progress(void* unused, unsigned block_num, ulong offset, ulong fsize, time_t start)
666: {
667: unsigned cps;
668: unsigned total_blocks;
669: long l;
670: long t;
671: time_t now;
672: static time_t last_progress;
673:
674: now=time(NULL);
675: if(now-last_progress>=progress_interval || offset >= fsize || newline) {
676: t=now-start;
677: if(t<=0)
678: t=1;
679: if((cps=offset/t)==0)
680: cps=1; /* cps so far */
681: l=fsize/cps; /* total transfer est time */
682: l-=t; /* now, it's est time left */
683: if(l<0) l=0;
684: if(mode&SEND) {
685: total_blocks=num_blocks(fsize,xm.block_size);
686: fprintf(statfp,"\rBlock (%lu%s): %lu/%lu Byte: %lu "
687: "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% "
688: ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
689: ,xm.block_size%1024L ? "" : "K"
690: ,block_num
691: ,total_blocks
692: ,offset
693: ,t/60L
694: ,t%60L
695: ,l/60L
696: ,l%60L
697: ,cps
698: ,(long)(((float)offset/(float)fsize)*100.0)
699: );
700: } else if(mode&YMODEM) {
701: fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %lu "
702: "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% "
703: ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
704: ,xm.block_size%1024L ? "" : "K"
705: ,block_num
706: ,offset
707: ,t/60L
708: ,t%60L
709: ,l/60L
710: ,l%60L
711: ,cps
712: ,(long)(((float)offset/(float)fsize)*100.0)
713: );
714: } else { /* XModem receive */
715: fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %lu "
716: "Time: %lu:%02lu %u cps "
717: ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
718: ,xm.block_size%1024L ? "" : "K"
719: ,block_num
720: ,offset
721: ,t/60L
722: ,t%60L
723: ,cps
724: );
725: }
726: newline=FALSE;
727: last_progress=now;
728: }
729: }
730:
731: /*
732: * show the progress of the transfer like this:
733: * zmtx: sending file "garbage" 4096 bytes ( 20%)
734: */
735: void zmodem_progress(void* cbdata, ulong current_pos)
736: {
737: unsigned cps;
738: long l;
739: long t;
740: time_t now;
741: static time_t last_progress;
742:
743: now=time(NULL);
744: if(now-last_progress>=progress_interval || current_pos >= zm.current_file_size || newline) {
745: t=now-zm.transfer_start_time;
746: if(t<=0)
747: t=1;
748: if(zm.transfer_start_pos>current_pos)
749: zm.transfer_start_pos=0;
750: if((cps=(current_pos-zm.transfer_start_pos)/t)==0)
751: cps=1; /* cps so far */
752: l=zm.current_file_size/cps; /* total transfer est time */
753: l-=t; /* now, it's est time left */
754: if(l<0) l=0;
755: fprintf(statfp,"\rKByte: %lu/%lu %u/CRC-%u "
756: "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% "
757: ,current_pos/1024
758: ,zm.current_file_size/1024
759: ,zm.block_size
760: ,mode&RECV ? (zm.receive_32bit_data ? 32:16) :
761: (zm.can_fcs_32 && !zm.want_fcs_16) ? 32:16
762: ,t/60L
763: ,t%60L
764: ,l/60L
765: ,l%60L
766: ,cps
767: ,(long)(((float)current_pos/(float)zm.current_file_size)*100.0)
768: );
769: newline=FALSE;
770: last_progress=now;
771: }
772: }
773:
774: static int send_files(char** fname, uint fnames)
775: {
776: char path[MAX_PATH+1];
777: int i;
778: uint errors;
779: uint fnum;
780: uint cps;
781: glob_t g;
782: int gi;
783: BOOL success=TRUE;
784: long fsize;
785: ulong sent_bytes;
786: ulong total_bytes=0;
787: time_t t,startfile;
788: time_t startall;
789: FILE* fp;
790:
791: startall=time(NULL);
792:
793: /****************************************************/
794: /* Search through all to find total files and bytes */
795: /****************************************************/
796: for(fnum=0;fnum<fnames;fnum++) {
797: if(glob(fname[fnum],0,NULL,&g)) {
798: lprintf(LOG_WARNING,"%s not found",fname[fnum]);
799: continue;
800: }
801: for(i=0;i<(int)g.gl_pathc;i++) {
802: if(isdir(g.gl_pathv[i]))
803: continue;
804: xm.total_files++;
805: xm.total_bytes+=flength(g.gl_pathv[i]);
806: }
807: globfree(&g);
808: }
809:
810: if(xm.total_files<1) {
811: lprintf(LOG_ERR,"No files to send");
812: return(-1);
813: }
814: if(xm.total_files>1)
815: lprintf(LOG_INFO,"Sending %u files (%lu KB total)"
816: ,xm.total_files,xm.total_bytes/1024);
817:
818: zm.files_remaining = xm.total_files;
819: zm.bytes_remaining = xm.total_bytes;
820:
821: /***********************************************/
822: /* Send every file matching names or filespecs */
823: /***********************************************/
824: for(fnum=0;fnum<fnames;fnum++) {
825: if(glob(fname[fnum],0,NULL,&g)) {
826: lprintf(LOG_WARNING,"%s not found",fname[fnum]);
827: continue;
828: }
829: for(gi=0;gi<(int)g.gl_pathc;gi++) {
830: SAFECOPY(path,g.gl_pathv[gi]);
831: if(isdir(path))
832: continue;
833:
834: if((fp=fnopen(NULL,path,O_RDONLY|O_BINARY))==NULL
835: && (fp=fopen(path,"rb"))==NULL) {
836: lprintf(LOG_ERR,"Error %d opening %s for read",errno,path);
837: continue;
838: }
839: setvbuf(fp,NULL,_IOFBF,0x10000);
840:
841: fsize=filelength(fileno(fp));
842:
843: errors=0;
844: success=FALSE;
845: startfile=time(NULL);
846:
847: lprintf(LOG_INFO,"Sending %s (%lu KB) via %s"
848: ,path,fsize/1024
849: ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? "Ymodem" : "Zmodem");
850:
851: if(mode&ZMODEM)
852: success=zmodem_send_file(&zm, path, fp, /* ZRQINIT? */fnum==0, &startfile, &sent_bytes);
853: else /* X/Ymodem */
854: success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes);
855:
856: fclose(fp);
857:
858: if((t=time(NULL)-startfile)<=0)
859: t=1;
860: if((cps=sent_bytes/t)==0)
861: cps=1;
862: if(success) {
863: xm.sent_files++;
864: xm.sent_bytes+=fsize;
865: lprintf(LOG_INFO,"Successful - Time: %lu:%02lu CPS: %lu"
866: ,t/60,t%60,cps);
867:
868: if(xm.total_files-xm.sent_files)
869: lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %lu"
870: ,((xm.total_bytes-xm.sent_bytes)/cps)/60
871: ,((xm.total_bytes-xm.sent_bytes)/cps)%60
872: ,xm.total_files-xm.sent_files
873: ,(xm.total_bytes-xm.sent_bytes)/1024
874: );
875: } else
876: lprintf(LOG_WARNING,"File Transfer %s", aborted ? "Aborted" : "Failure");
877:
878: /* DSZLOG entry */
879: if(logfp) {
880: lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog);
881: fprintf(logfp,"%c %7lu %5u bps %6lu cps %3u errors %5u %4u "
882: "%s -1\n"
883: ,success ? (mode&ZMODEM ? 'z':'S')
884: : (mode&ZMODEM && zm.file_skipped) ? 's'
885: : 'E'
886: ,sent_bytes
887: ,115200 /* baud */
888: ,cps
889: ,mode&ZMODEM ? zm.errors : xm.errors
890: ,flows
891: ,mode&ZMODEM ? zm.block_size : xm.block_size
892: ,dszlog_filename(path));
893: fflush(logfp);
894: }
895: total_bytes += sent_bytes;
896:
897: if(aborted) {
898: xm.cancelled=FALSE;
899: xmodem_cancel(&xm);
900: break;
901: }
902:
903: if(xm.cancelled || zm.cancelled)
904: break;
905:
906: } /* while(gi<(int)g.gl_pathc) */
907:
908: if(gi<(int)g.gl_pathc)/* error occurred */
909: break;
910: }
911:
912: if(mode&ZMODEM && !zm.cancelled && is_connected(NULL))
913: zmodem_get_zfin(&zm);
914:
915: if(fnum<fnames) /* error occurred */
916: return(-1);
917:
918: if(!success)
919: return(-1);
920:
921: if(mode&XMODEM)
922: return(0);
923: if(mode&YMODEM) {
924:
925: if(xmodem_get_mode(&xm)) {
926:
927: lprintf(LOG_INFO,"Sending Ymodem termination block");
928:
929: memset(block,0,128); /* send short block for terminator */
930: xmodem_put_block(&xm, block, 128 /* block_size */, 0 /* block_num */);
931: if(!xmodem_get_ack(&xm,6,0)) {
932: lprintf(LOG_WARNING,"Failed to receive ACK after terminating block");
933: }
934: }
935: }
936: if(xm.total_files>1) {
937: t=time(NULL)-startall;
938: if(!t) t=1;
939: lprintf(LOG_INFO,"Overall - Time %02lu:%02lu KBytes: %lu CPS: %lu"
940: ,t/60,t%60,total_bytes/1024,total_bytes/t);
941: }
942: return(0); /* success */
943: }
944:
945: static int receive_files(char** fname_list, int fnames)
946: {
947: char str[MAX_PATH+1];
948: char fname[MAX_PATH+1];
949: int i;
950: int fnum=0;
951: uint errors;
952: uint total_files=0;
953: uint cps;
954: uint wr;
955: BOOL success=FALSE;
956: long fmode;
957: long serial_num=-1;
958: ulong file_bytes=0,file_bytes_left=0;
959: ulong total_bytes=0;
960: FILE* fp;
961: time_t t,startfile,ftime;
962:
963: if(fnames>1)
964: lprintf(LOG_INFO,"Receiving %u files",fnames);
965:
966: outbuf.highwater_mark=0; /* don't delay ACK/NAK transmits */
967:
968: /* Purge input buffer */
969: while(is_connected(NULL) && (i=recv_byte(NULL,0))!=NOINP)
970: lprintf(LOG_WARNING,"Throwing out received: %s",chr((uchar)i));
971:
972: while(is_connected(NULL)) {
973: if(mode&XMODEM) {
974: SAFECOPY(str,fname_list[0]); /* we'll have at least one fname */
975: file_bytes=file_bytes_left=0x7fffffff;
976: }
977:
978: else {
979: if(mode&YMODEM) {
980: lprintf(LOG_INFO,"Fetching Ymodem header block");
981: for(errors=0;errors<=xm.max_errors && !xm.cancelled;errors++) {
982: if(errors>(xm.max_errors/2) && mode&CRC && !(mode&GMODE))
983: mode&=~CRC;
984: xmodem_put_nak(&xm, /* expected_block: */ 0);
985: if(xmodem_get_block(&xm, block, /* expected_block: */ 0) == 0) {
986: send_byte(NULL,ACK,10);
987: break;
988: }
989: }
990: if(errors>=xm.max_errors || xm.cancelled) {
991: lprintf(LOG_ERR,"Error fetching Ymodem header block");
992: xmodem_cancel(&xm);
993: return(1);
994: }
995: if(!block[0]) {
996: lprintf(LOG_INFO,"Received Ymodem termination block");
997: return(0);
998: }
999: file_bytes=ftime=total_files=total_bytes=0;
1000: i=sscanf(block+strlen(block)+1,"%ld %lo %lo %lo %d %ld"
1001: ,&file_bytes /* file size (decimal) */
1002: ,&ftime /* file time (octal unix format) */
1003: ,&fmode /* file mode (not used) */
1004: ,&serial_num /* program serial number */
1005: ,&total_files /* remaining files to be sent */
1006: ,&total_bytes /* remaining bytes to be sent */
1007: );
1008: lprintf(LOG_DEBUG,"Ymodem header (%u fields): %s", i, block+strlen(block)+1);
1009: SAFECOPY(fname,block);
1010:
1011: } else { /* Zmodem */
1012: lprintf(LOG_INFO,"Waiting for Zmodem sender...");
1013:
1014: i=zmodem_recv_init(&zm);
1015:
1016: if(zm.cancelled)
1017: return(1);
1018: if(i<0)
1019: return(-1);
1020: switch(i) {
1021: case ZFILE:
1022: SAFECOPY(fname,zm.current_file_name);
1023: file_bytes = zm.current_file_size;
1024: ftime = zm.current_file_time;
1025: total_files = zm.files_remaining;
1026: total_bytes = zm.bytes_remaining;
1027: break;
1028: case ZFIN:
1029: case ZCOMPL:
1030: return(!success);
1031: default:
1032: return(-1);
1033: }
1034: }
1035:
1036: if(!file_bytes)
1037: file_bytes=0x7fffffff;
1038: file_bytes_left=file_bytes;
1039: if(!total_files)
1040: total_files=fnames-fnum;
1041: if(!total_files)
1042: total_files=1;
1043: if(total_bytes<file_bytes)
1044: total_bytes=file_bytes;
1045:
1046: lprintf(LOG_DEBUG,"Incoming filename: %.64s ",fname);
1047:
1048: if(mode&RECVDIR)
1049: sprintf(str,"%s%s",fname_list[0],getfname(fname));
1050: else {
1051: SAFECOPY(str,getfname(fname));
1052: for(i=0;i<fnames;i++) {
1053: if(!fname_list[i][0]) /* name blank or already used */
1054: continue;
1055: if(!stricmp(getfname(fname_list[i]),str)) {
1056: SAFECOPY(str,fname_list[i]);
1057: fname_list[i][0]=0;
1058: break;
1059: }
1060: }
1061: if(i==fnames) { /* Not found in list */
1062: if(fnames)
1063: fprintf(statfp," - Not in receive list!");
1064: if(!fnames || fnum>=fnames || !fname_list[fnum][0])
1065: SAFECOPY(str,getfname(fname)); /* worst case */
1066: else {
1067: SAFECOPY(str,fname_list[fnum]);
1068: fname_list[fnum][0]=0;
1069: }
1070: }
1071: }
1072: fprintf(statfp,"File size: %lu bytes\n", file_bytes);
1073: if(total_files>1)
1074: fprintf(statfp,"Remaining: %lu bytes in %u files\n", total_bytes, total_files);
1075: }
1076:
1077: lprintf(LOG_DEBUG,"Receiving: %.64s ",str);
1078:
1079: fnum++;
1080:
1081: if(!(mode&RECVDIR) && fnames && fnum>fnames) {
1082: lprintf(LOG_WARNING,"Attempt to send more files than specified");
1083: xmodem_cancel(&xm);
1084: break;
1085: }
1086:
1087: if(fexistcase(str) && !(mode&OVERWRITE)) {
1088: lprintf(LOG_WARNING,"%s already exists",str);
1089: if(mode&ZMODEM) {
1090: zmodem_send_zskip(&zm);
1091: continue;
1092: }
1093: xmodem_cancel(&xm);
1094: return(1);
1095: }
1096: if((fp=fnopen(NULL,str,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY))==NULL
1097: && (fp=fopen(str,"wb"))==NULL) {
1098: lprintf(LOG_ERR,"Error %d creating %s",errno,str);
1099: if(mode&ZMODEM) {
1100: zmodem_send_zskip(&zm);
1101: continue;
1102: }
1103: xmodem_cancel(&xm);
1104: return(1);
1105: }
1106:
1107: if(mode&XMODEM)
1108: lprintf(LOG_INFO,"Receiving %s via Xmodem %s"
1109: ,str
1110: ,mode&CRC ? "CRC-16":"Checksum");
1111: else
1112: lprintf(LOG_INFO,"Receiving %s (%lu KB) via %s %s"
1113: ,str
1114: ,file_bytes/1024
1115: ,mode&YMODEM ? mode&GMODE ? "Ymodem-G" : "Ymodem" :"Zmodem"
1116: ,mode&ZMODEM ? "" : (mode&CRC ? "CRC-16" : "Checksum"));
1117:
1118: startfile=time(NULL);
1119: success=FALSE;
1120: if(mode&ZMODEM) {
1121:
1122: errors=zmodem_recv_file_data(&zm,fp,0);
1123:
1124: /*
1125: * wait for the eof header
1126: */
1127:
1128: for(;errors<=zm.max_errors && !success && !zm.cancelled; errors++) {
1129: if(zmodem_recv_header_and_check(&zm))
1130: success=TRUE;
1131: }
1132:
1133: } else {
1134: errors=0;
1135: block_num=1;
1136: xmodem_put_nak(&xm, block_num);
1137: while(is_connected(NULL)) {
1138: xmodem_progress(NULL,block_num,ftell(fp),file_bytes,startfile);
1139: i=xmodem_get_block(&xm, block, block_num);
1140:
1141: if(i!=0) {
1142: if(i==EOT) { /* end of transfer */
1143: success=TRUE;
1144: xmodem_put_ack(&xm);
1145: break;
1146: }
1147: if(i==CAN) { /* Cancel */
1148: xm.cancelled=TRUE;
1149: break;
1150: }
1151:
1152: if(mode&GMODE)
1153: return(-1);
1154:
1155: if(++errors>=xm.max_errors) {
1156: lprintf(LOG_ERR,"Too many errors (%u)",errors);
1157: xmodem_cancel(&xm);
1158: break;
1159: }
1160: if(block_num==1 && errors>(xm.max_errors/2) && mode&CRC && !(mode&GMODE))
1161: mode&=~CRC;
1162: xmodem_put_nak(&xm, block_num);
1163: continue;
1164: }
1165: if(!(mode&GMODE))
1166: send_byte(NULL,ACK,10);
1167: if(file_bytes_left<=0L) { /* No more bytes to send */
1168: lprintf(LOG_WARNING,"Attempt to send more byte specified in header");
1169: break;
1170: }
1171: wr=xm.block_size;
1172: if(wr>file_bytes_left)
1173: wr=file_bytes_left;
1174: if(fwrite(block,1,wr,fp)!=wr) {
1175: lprintf(LOG_ERR,"Error writing %u bytes to file at offset %lu"
1176: ,wr,ftell(fp));
1177: xmodem_cancel(&xm);
1178: return(1);
1179: }
1180: file_bytes_left-=wr;
1181: block_num++;
1182: }
1183: }
1184:
1185: /* Use correct file size */
1186: fflush(fp);
1187: if(file_bytes < (ulong)filelength(fileno(fp))) {
1188: lprintf(LOG_INFO,"Truncating file to %lu bytes", file_bytes);
1189: chsize(fileno(fp),file_bytes);
1190: } else
1191: file_bytes = filelength(fileno(fp));
1192: fclose(fp);
1193:
1194: t=time(NULL)-startfile;
1195: if(!t) t=1;
1196: if(success)
1197: lprintf(LOG_INFO,"Successful - Time: %lu:%02lu CPS: %lu"
1198: ,t/60,t%60,file_bytes/t);
1199: else
1200: lprintf(LOG_ERR,"File Transfer %s", aborted ? "Aborted":"Failure");
1201:
1202: if(!(mode&XMODEM) && ftime)
1203: setfdate(str,ftime);
1204:
1205: if(logfp) {
1206: lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog);
1207: fprintf(logfp,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u "
1208: "%s %d\n"
1209: ,success ? (mode&ZMODEM ? 'Z' : 'R') : 'E'
1210: ,file_bytes
1211: ,115200 /* baud */
1212: ,file_bytes/t
1213: ,errors
1214: ,flows
1215: ,mode&ZMODEM ? zm.block_size : xm.block_size
1216: ,dszlog_filename(str)
1217: ,serial_num);
1218: fflush(logfp);
1219: }
1220:
1221: if(aborted) {
1222: lprintf(LOG_DEBUG,"Locally aborted, sending cancel to remote");
1223: if(mode&ZMODEM)
1224: zmodem_abort_receive(&zm);
1225: xm.cancelled=FALSE;
1226: xmodem_cancel(&xm);
1227: break;
1228: }
1229:
1230: if(mode&XMODEM) /* maximum of one file */
1231: break;
1232: if((cps=file_bytes/t)==0)
1233: cps=1;
1234: total_files--;
1235: total_bytes-=file_bytes;
1236: if(total_files>1 && total_bytes)
1237: lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %lu"
1238: ,(total_bytes/cps)/60
1239: ,(total_bytes/cps)%60
1240: ,total_files
1241: ,total_bytes/1024
1242: );
1243: }
1244: return(!success); /* 0=success */
1245: }
1246:
1247: void bail(int code)
1248: {
1249: if(logfp!=NULL)
1250: fclose(logfp);
1251: if(pause_on_exit || (pause_on_abend && code!=0)) {
1252: printf("Hit enter to continue...");
1253: getchar();
1254: }
1255: exit(code);
1256: }
1257:
1258: static const char* usage=
1259: "usage: sexyz <socket> [-opts] <cmd> [file | path | @list]\n"
1260: "\n"
1261: #ifdef __unix__
1262: "socket = TCP socket descriptor (leave blank for stdio mode)\n"
1263: #else
1264: "socket = TCP socket descriptor\n"
1265: #endif
1266: "\n"
1267: "opts = -y to overwrite files when receiving\n"
1268: " -o disable Zmodem CRC-32 mode (use CRC-16)\n"
1269: " -s disable Zmodem streaming (Slow Zmodem)\n"
1270: " -2 set maximum Zmodem block size to 2K\n"
1271: " -4 set maximum Zmodem block size to 4K\n"
1272: " -8 set maximum Zmodem block size to 8K (ZedZap)\n"
1273: " -! to pause after abnormal exit (error)\n"
1274: " -telnet to enable Telnet mode (the default)\n"
1275: " -rlogin or -ssh or -raw to disable Telnet mode\n"
1276: "\n"
1277: "cmd = v to display detailed version information\n"
1278: " sx to send Xmodem rx to recv Xmodem\n"
1279: " sX to send Xmodem-1K rc to recv Xmodem-CRC\n"
1280: " sy to send Ymodem ry to recv Ymodem\n"
1281: " sY to send Ymodem-1K rg to recv Ymodem-G\n"
1282: " sz to send Zmodem rz to recv Zmodem\n"
1283: "\n"
1284: "file = filename to send or receive\n"
1285: "path = directory to receive files into\n"
1286: "list = name of text file with list of filenames to send or receive\n";
1287:
1288: /***************/
1289: /* Entry Point */
1290: /***************/
1291: int main(int argc, char **argv)
1292: {
1293: char str[MAX_PATH+1];
1294: char fname[MAX_PATH+1];
1295: char ini_fname[MAX_PATH+1];
1296: char* p;
1297: char* arg;
1298: int i;
1299: int retval;
1300: uint fnames=0;
1301: FILE* fp;
1302: BOOL tcp_nodelay;
1303: char compiler[32];
1304: str_list_t fname_list;
1305:
1306: fname_list=strListInit();
1307:
1308: DESCRIBE_COMPILER(compiler);
1309:
1310: errfp=stderr;
1311: #ifdef __unix__
1312: statfp=stderr;
1313: #else
1314: statfp=stdout;
1315: #endif
1316:
1317: sscanf("$Revision: 1.77 $", "%*s %s", revision);
1318:
1319: fprintf(statfp,"\nSynchronet External X/Y/Zmodem v%s-%s"
1320: " Copyright %s Rob Swindell\n\n"
1321: ,revision
1322: ,PLATFORM_DESC
1323: ,__DATE__+7
1324: );
1325:
1326: xmodem_init(&xm,NULL,&mode,lputs,xmodem_progress,send_byte,recv_byte,is_connected,NULL);
1327: zmodem_init(&zm,NULL,lputs,zmodem_progress,send_byte,recv_byte,is_connected,NULL,data_waiting);
1328:
1329: /* Generate path/sexyz[.host].ini from path/sexyz[.exe] */
1330: SAFECOPY(str,argv[0]);
1331: p=getfname(str);
1332: SAFECOPY(fname,p);
1333: *p=0;
1334: if((p=getfext(fname))!=NULL)
1335: *p=0;
1336: strcat(fname,".ini");
1337:
1338: iniFileName(ini_fname,sizeof(ini_fname),str,fname);
1339: if((fp=fopen(ini_fname,"r"))!=NULL)
1340: fprintf(statfp,"Reading %s\n",ini_fname);
1341:
1342: tcp_nodelay =iniReadBool(fp,ROOT_SECTION,"TCP_NODELAY",TRUE);
1343:
1344: telnet =iniReadBool(fp,ROOT_SECTION,"Telnet",TRUE);
1345: debug_tx =iniReadBool(fp,ROOT_SECTION,"DebugTx",FALSE);
1346: debug_rx =iniReadBool(fp,ROOT_SECTION,"DebugRx",FALSE);
1347: debug_telnet =iniReadBool(fp,ROOT_SECTION,"DebugTelnet",FALSE);
1348:
1349: pause_on_exit =iniReadBool(fp,ROOT_SECTION,"PauseOnExit",FALSE);
1350: pause_on_abend =iniReadBool(fp,ROOT_SECTION,"PauseOnAbend",FALSE);
1351:
1352: log_level =iniReadLogLevel(fp,ROOT_SECTION,"LogLevel",log_level);
1353:
1354: outbuf.highwater_mark =iniReadInteger(fp,ROOT_SECTION,"OutbufHighwaterMark",1100);
1355: outbuf_drain_timeout =iniReadInteger(fp,ROOT_SECTION,"OutbufDrainTimeout",10);
1356: outbuf_size =iniReadInteger(fp,ROOT_SECTION,"OutbufSize",16*1024);
1357:
1358: progress_interval =iniReadInteger(fp,ROOT_SECTION,"ProgressInterval",1);
1359:
1360: if(iniReadBool(fp,ROOT_SECTION,"Debug",FALSE))
1361: log_level=LOG_DEBUG;
1362:
1363: xm.send_timeout =iniReadInteger(fp,"Xmodem","SendTimeout",xm.send_timeout); /* seconds */
1364: xm.recv_timeout =iniReadInteger(fp,"Xmodem","RecvTimeout",xm.recv_timeout); /* seconds */
1365: xm.byte_timeout =iniReadInteger(fp,"Xmodem","ByteTimeout",xm.byte_timeout); /* seconds */
1366: xm.ack_timeout =iniReadInteger(fp,"Xmodem","AckTimeout",xm.ack_timeout); /* seconds */
1367: xm.block_size =iniReadInteger(fp,"Xmodem","BlockSize",xm.block_size); /* 128 or 1024 */
1368: xm.max_errors =iniReadInteger(fp,"Xmodem","MaxErrors",xm.max_errors);
1369: xm.g_delay =iniReadInteger(fp,"Xmodem","G_Delay",xm.g_delay);
1370:
1371: zm.init_timeout =iniReadInteger(fp,"Zmodem","InitTimeout",zm.init_timeout); /* seconds */
1372: zm.send_timeout =iniReadInteger(fp,"Zmodem","SendTimeout",zm.send_timeout); /* seconds */
1373: zm.recv_timeout =iniReadInteger(fp,"Zmodem","RecvTimeout",zm.recv_timeout); /* seconds */
1374: zm.crc_timeout =iniReadInteger(fp,"Zmodem","CrcTimeout",zm.crc_timeout); /* seconds */
1375: zm.block_size =iniReadInteger(fp,"Zmodem","BlockSize",zm.block_size); /* 1024 */
1376: zm.max_block_size =iniReadInteger(fp,"Zmodem","MaxBlockSize",zm.max_block_size); /* 1024 or 8192 */
1377: zm.max_errors =iniReadInteger(fp,"Zmodem","MaxErrors",zm.max_errors);
1378: zm.recv_bufsize =iniReadInteger(fp,"Zmodem","RecvBufSize",0);
1379: zm.no_streaming =!iniReadBool(fp,"Zmodem","Streaming",TRUE);
1380: zm.want_fcs_16 =!iniReadBool(fp,"Zmodem","CRC32",TRUE);
1381: zm.escape_telnet_iac =iniReadBool(fp,"Zmodem","EscapeTelnetIAC",TRUE);
1382: zm.escape_8th_bit =iniReadBool(fp,"Zmodem","Escape8thBit",FALSE);
1383: zm.escape_ctrl_chars =iniReadBool(fp,"Zmodem","EscapeCtrlChars",FALSE);
1384:
1385: dszlog_path =iniReadBool(fp,"DSZLOG","Path",TRUE);
1386: dszlog_short =iniReadBool(fp,"DSZLOG","Short",FALSE);
1387: dszlog_quotes =iniReadBool(fp,"DSZLOG","Quotes",FALSE);
1388:
1389: if(fp!=NULL)
1390: fclose(fp);
1391:
1392: if(zm.recv_bufsize > 0xffff)
1393: zm.recv_bufsize = 0xffff;
1394:
1395: if(outbuf_size < MIN_OUTBUF_SIZE)
1396: outbuf_size = MIN_OUTBUF_SIZE;
1397: else if(outbuf_size > MAX_OUTBUF_SIZE)
1398: outbuf_size = MAX_OUTBUF_SIZE;
1399:
1400: fprintf(statfp,"Output buffer size: %u\n", outbuf_size);
1401: RingBufInit(&outbuf, outbuf_size);
1402:
1403: #if !defined(RINGBUF_EVENT)
1404: outbuf_empty=CreateEvent(NULL,/* ManualReset */TRUE, /*InitialState */TRUE,NULL);
1405: #endif
1406:
1407: #if 0
1408: if(argc>1) {
1409: fprintf(statfp,"Command line: ");
1410: for(i=1;i<argc;i++)
1411: fprintf(statfp,"%s ",argv[i]);
1412: fprintf(statfp,"\n",statfp);
1413: }
1414: #endif
1415:
1416:
1417: for(i=1;i<argc;i++) {
1418:
1419: if(sock==INVALID_SOCKET && isdigit(argv[i][0])) {
1420: sock=atoi(argv[i]);
1421: continue;
1422: }
1423:
1424: if(!(mode&(SEND|RECV))) {
1425: if(toupper(argv[i][0])=='S' || toupper(argv[i][0])=='R') { /* cmd */
1426: if(toupper(argv[i][0])=='R')
1427: mode|=RECV;
1428: else
1429: mode|=SEND;
1430:
1431: switch(argv[i][1]) {
1432: case 'c':
1433: case 'C':
1434: mode|=XMODEM|CRC;
1435: break;
1436: case 'x':
1437: xm.block_size=128;
1438: case 'X':
1439: mode|=XMODEM;
1440: break;
1441: case 'b': /* sz/rz compatible */
1442: case 'B':
1443: case 'y':
1444: xm.block_size=128;
1445: case 'Y':
1446: mode|=(YMODEM|CRC);
1447: break;
1448: case 'g':
1449: case 'G':
1450: mode|=(YMODEM|CRC|GMODE);
1451: break;
1452: case 'z':
1453: case 'Z':
1454: mode|=(ZMODEM|CRC);
1455: break;
1456: default:
1457: fprintf(statfp,"Unrecognized command '%s'\n\n",argv[i]);
1458: fprintf(statfp,usage);
1459: bail(1);
1460: }
1461: continue;
1462: }
1463:
1464: if(toupper(argv[i][0])=='V') {
1465:
1466: fprintf(statfp,"%-8s %s\n",getfname(__FILE__) ,revision);
1467: fprintf(statfp,"%-8s %s\n",getfname(xmodem_source()),xmodem_ver(str));
1468: fprintf(statfp,"%-8s %s\n",getfname(zmodem_source()),zmodem_ver(str));
1469: #ifdef _DEBUG
1470: fprintf(statfp,"Debug\n");
1471: #endif
1472: fprintf(statfp,"Compiled %s %.5s with %s\n",__DATE__,__TIME__,compiler);
1473: fprintf(statfp,"%s\n",os_version(str));
1474: bail(0);
1475: }
1476:
1477: arg=argv[i];
1478: if(*arg=='-') {
1479: while(*arg=='-')
1480: arg++;
1481: if(stricmp(arg,"telnet")==0) {
1482: telnet=TRUE;
1483: continue;
1484: }
1485: if(stricmp(arg,"rlogin")==0 || stricmp(arg,"ssh")==0 || stricmp(arg,"raw")==0) {
1486: telnet=FALSE;
1487: continue;
1488: }
1489: if(stricmp(arg,"debug")==0) {
1490: log_level=LOG_DEBUG;
1491: continue;
1492: }
1493: if(stricmp(arg,"quotes")==0) {
1494: dszlog_quotes=TRUE;
1495: continue;
1496: }
1497: switch(toupper(*arg)) {
1498: case 'K': /* sz/rz compatible */
1499: xm.block_size=1024;
1500: break;
1501: case 'C': /* sz/rz compatible */
1502: mode|=CRC;
1503: break;
1504: case '2':
1505: zm.max_block_size=2048;
1506: break;
1507: case '4':
1508: zm.max_block_size=4096;
1509: break;
1510: case '8': /* ZedZap */
1511: zm.max_block_size=8192;
1512: break;
1513: case 'O': /* disable Zmodem CRC-32 */
1514: zm.want_fcs_16=TRUE;
1515: break;
1516: case 'S': /* disable Zmodem streaming */
1517: zm.no_streaming=TRUE;
1518: break;
1519: case 'G': /* Ymodem-G */
1520: mode|=GMODE;
1521: break;
1522: case 'Y':
1523: mode|=OVERWRITE;
1524: break;
1525: case '!':
1526: pause_on_abend=TRUE;
1527: break;
1528: }
1529: }
1530: }
1531:
1532: else if((argv[i][0]=='+' || argv[i][0]=='@') && fexist(argv[i]+1)) {
1533: if(mode&RECVDIR) {
1534: fprintf(statfp,"!Cannot specify both directory and filename\n");
1535: bail(1);
1536: }
1537: sprintf(str,"%s",argv[i]+1);
1538: if((fp=fopen(str,"r"))==NULL) {
1539: fprintf(statfp,"!Error %d opening filelist: %s\n",errno,str);
1540: bail(1);
1541: }
1542: while(!feof(fp) && !ferror(fp)) {
1543: if(!fgets(str,sizeof(str),fp))
1544: break;
1545: truncsp(str);
1546: strListAppend(&fname_list,strdup(str),fnames++);
1547: }
1548: fclose(fp);
1549: }
1550:
1551: else if(mode&(SEND|RECV)){
1552: if(isdir(argv[i])) { /* is a directory */
1553: if(mode&RECVDIR) {
1554: fprintf(statfp,"!Only one directory can be specified\n");
1555: bail(1);
1556: }
1557: if(fnames) {
1558: fprintf(statfp,"!Cannot specify both directory and filename\n");
1559: bail(1);
1560: }
1561: if(mode&SEND) {
1562: fprintf(statfp,"!Cannot send directory '%s'\n",argv[i]);
1563: bail(1);
1564: }
1565: mode|=RECVDIR;
1566: }
1567: strListAppend(&fname_list,argv[i],fnames++);
1568: }
1569: }
1570:
1571: if(!telnet)
1572: zm.escape_telnet_iac = FALSE;
1573:
1574: if(sock==INVALID_SOCKET || sock<1) {
1575: #ifdef __unix__
1576: if(STDOUT_FILENO > STDIN_FILENO)
1577: sock=STDOUT_FILENO;
1578: else
1579: sock=STDIN_FILENO;
1580: stdio=TRUE;
1581:
1582: fprintf(statfp,"No socket descriptor specified, using STDIO\n");
1583: telnet=FALSE;
1584: #else
1585: fprintf(statfp,"!No socket descriptor specified\n\n");
1586: fprintf(errfp,usage);
1587: bail(1);
1588: #endif
1589: }
1590: #ifdef __unix__
1591: else
1592: statfp=stdout;
1593: #endif
1594:
1595: if(!(mode&(SEND|RECV))) {
1596: fprintf(statfp,"!No command specified\n\n");
1597: fprintf(statfp,usage);
1598: bail(1);
1599: }
1600:
1601: if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */
1602: fprintf(statfp,"!Must specify filename or filelist\n\n");
1603: fprintf(statfp,usage);
1604: bail(1);
1605: }
1606:
1607: #ifdef __unix__
1608: if(stdio) {
1609: struct termios term;
1610: memset(&term,0,sizeof(term));
1611: cfsetispeed(&term,B19200);
1612: cfsetospeed(&term,B19200);
1613: term.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
1614: term.c_oflag &= ~OPOST;
1615: term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1616: term.c_cflag &= ~(CSIZE|PARENB);
1617: term.c_cflag |= CS8;
1618: atexit(resetterm);
1619: tcgetattr(STDOUT_FILENO, &origterm);
1620: tcsetattr(STDOUT_FILENO, TCSADRAIN, &term);
1621: }
1622: #endif
1623:
1624: /* Code disabled. Why? ToDo */
1625: /* if(mode&RECVDIR)
1626: backslash(fname[0]); */
1627:
1628: if(!winsock_startup())
1629: bail(-1);
1630:
1631: /* Enable the Nagle Algorithm */
1632: #ifdef __unix__
1633: if(!stdio) {
1634: #endif
1635: lprintf(LOG_DEBUG,"Setting TCP_NODELAY to %d",tcp_nodelay);
1636: setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char*)&tcp_nodelay,sizeof(tcp_nodelay));
1637: #ifdef __unix__
1638: }
1639: #endif
1640:
1641: if(!socket_check(sock, NULL, NULL, 0)) {
1642: lprintf(LOG_WARNING,"No socket connection");
1643: bail(-1);
1644: }
1645:
1646: if((dszlog=getenv("DSZLOG"))!=NULL) {
1647: if((logfp=fopen(dszlog,"w"))==NULL) {
1648: lprintf(LOG_WARNING,"Error %d opening DSZLOG file: %s",errno,dszlog);
1649: bail(-1);
1650: }
1651: }
1652:
1653: /* Install Ctrl-C/Break signal handler here */
1654: #if defined(_WIN32)
1655: SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */);
1656: #elif defined(__unix__)
1657: signal(SIGQUIT,break_handler);
1658: signal(SIGINT,break_handler);
1659: signal(SIGTERM,break_handler);
1660:
1661: signal(SIGHUP,SIG_IGN);
1662:
1663: /* Don't die on SIGPIPE */
1664: signal(SIGPIPE,SIG_IGN);
1665: #endif
1666:
1667: #if !SINGLE_THREADED
1668: _beginthread(output_thread,0,NULL);
1669: #endif
1670:
1671: if(mode&RECV)
1672: retval=receive_files(fname_list, fnames);
1673: else
1674: retval=send_files(fname_list, fnames);
1675:
1676: #if !SINGLE_THREADED
1677: lprintf(LOG_DEBUG,"Waiting for output buffer to empty... ");
1678: if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0)
1679: lprintf(LOG_DEBUG,"FAILURE");
1680: #endif
1681:
1682: terminate=TRUE; /* stop output thread */
1683: /* Code disabled. Why? ToDo */
1684: /* sem_post(outbuf.sem);
1685: sem_post(outbuf.highwater_sem); */
1686:
1687: fprintf(statfp,"Exiting - Error level: %d, flows: %u, select_errors=%u"
1688: ,retval, flows, select_errors);
1689: fprintf(statfp,"\n");
1690:
1691: bail(retval);
1692: }
1693:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.