|
|
1.1 root 1: /* sexyz.c */
2:
3: /* Synchronet External X/Y/ZMODEM Transfer Protocols */
4:
5: /* $Id: sexyz.c,v 1.7 2004/09/11 09:36:19 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 2004 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 <sys/stat.h>
50:
51: #include "conwrap.h"
52: #include "genwrap.h"
53: #include "dirwrap.h"
54: #include "filewrap.h"
55: #include "sockwrap.h"
56:
57: #include "telnet.h"
58:
59: #include "sexyz.h"
60:
61: #define LOOP_NOPEN 50
62:
63: #define MAX_FNAMES 100 /* Up to 100 filenames */
64:
65: /************************/
66: /* Remote I/O Constants */
67: /************************/
68:
69: /* i/o mode and state flags */
70:
71: void cancel(void);
72:
73: /***************/
74: /* Global Vars */
75: /***************/
76: long mode=TELNET; /* Program mode */
77: long zmode=0L; /* Zmodem mode */
78: uchar block[1024]; /* Block buffer */
79: int block_size; /* Block size (128 or 1024) */
80: ulong block_num; /* Block number */
81: ulong last_block_num; /* Last block number sent */
82: uint flows=0; /* Number of flow controls */
83: time_t startall;
84:
85: FILE* errfp;
86: FILE* statfp;
87:
88: char revision[16];
89:
90: SOCKET sock=INVALID_SOCKET;
91: #define DCDHIGH socket_check(sock, NULL, NULL, 0)
92:
93: #define getcom(t) recv_byte(sock,t,mode)
94: #define putcom(ch) send_byte(sock,ch,10,mode)
95:
96:
97: #ifdef _WINSOCKAPI_
98:
99: WSADATA WSAData;
100: static BOOL WSAInitialized=FALSE;
101:
102: static BOOL winsock_startup(void)
103: {
104: int status; /* Status Code */
105:
106: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
107: fprintf(statfp,"%s %s\n",WSAData.szDescription, WSAData.szSystemStatus);
108: WSAInitialized=TRUE;
109: return(TRUE);
110: }
111:
112: fprintf(errfp,"!WinSock startup ERROR %d\n", status);
113: return(FALSE);
114: }
115:
116: #else /* No WINSOCK */
117:
118: #define winsock_startup() (TRUE)
119:
120: #endif
121:
122: /********/
123: /* Code */
124: /********/
125:
126: void newline(void)
127: {
128: fprintf(statfp,"\n");
129: }
130:
131: /**************/
132: /* Exit Point */
133: /**************/
134: void bail(int code)
135: {
136:
137: if(mode&ALARM) {
138: BEEP(2000,500);
139: BEEP(1000,500);
140: }
141: newline();
142: fprintf(statfp,"Exiting - Error level: %d",code);
143: if(flows)
144: fprintf(statfp," Flow restraint count: %u",flows);
145: fprintf(statfp,"\n");
146:
147: if(/* code && */ mode&PAUSE_ABEND) {
148: printf("Hit enter to continue...");
149: getchar();
150: }
151:
152: exit(code);
153: }
154:
155: char *chr(uchar ch)
156: {
157: static char str[25];
158:
159: switch(ch) {
160: case SOH:
161: return("SOH");
162: case STX:
163: return("STX");
164: case ETX:
165: return("ETX");
166: case EOT:
167: return("EOT");
168: case ACK:
169: return("ACK");
170: case NAK:
171: return("NAK");
172: case CAN:
173: return("CAN");
174: default:
175: if(ch>=' ' && ch<='~')
176: sprintf(str,"'%c' (%02Xh)",ch,ch);
177: else
178: sprintf(str,"%u (%02Xh)",ch,ch);
179: return(str);
180: }
181: }
182:
183: void send_telnet_cmd(SOCKET sock, uchar cmd, uchar opt)
184: {
185: uchar buf[3];
186:
187: buf[0]=TELNET_IAC;
188: buf[1]=cmd;
189: buf[2]=opt;
190:
191: fprintf(statfp,"\nSending telnet command: %s %s"
192: ,telnet_cmd_desc(buf[1]),telnet_opt_desc(buf[2]));
193: if(send(sock,buf,sizeof(buf),0)==sizeof(buf))
194: fprintf(statfp,"\n");
195: else
196: fprintf(statfp," FAILED!\n");
197: }
198:
199: #define DEBUG_TELNET FALSE
200:
201: /****************************************************************************/
202: /* Receive a byte from remote */
203: /****************************************************************************/
204: uint recv_byte(SOCKET sock, int timeout, long mode)
205: {
206: int i;
207: uchar ch;
208: fd_set socket_set;
209: struct timeval tv;
210: static uchar telnet_cmd;
211: static int telnet_cmdlen;
212:
213: while(1) {
214:
215: FD_ZERO(&socket_set);
216: FD_SET(sock,&socket_set);
217: tv.tv_sec=timeout;
218: tv.tv_usec=0;
219:
220: if(select(sock+1,&socket_set,NULL,NULL,&tv)<1) {
221: if(timeout) {
222: newline();
223: fprintf(statfp,"Input timeout\n");
224: }
225: return(NOINP);
226: }
227:
228: i=recv(sock,&ch,sizeof(ch),0);
229:
230: if(i!=sizeof(ch)) {
231: newline();
232: if(i==0)
233: fprintf(statfp,"No carrier\n");
234: else
235: fprintf(statfp,"!recv error %d (%d)\n",i,ERROR_VALUE);
236: bail(1);
237: }
238:
239: if(mode&TELNET) {
240: if(ch==TELNET_IAC) {
241: #if DEBUG_TELNET
242: fprintf(statfp,"T<%s> ",telnet_cmd_desc(ch));
243: #endif
244: if(telnet_cmdlen==0) {
245: telnet_cmdlen=1;
246: continue;
247: }
248: if(telnet_cmdlen==1) {
249: telnet_cmdlen=0;
250: return(TELNET_IAC);
251: }
252: }
253: if(telnet_cmdlen) {
254: telnet_cmdlen++;
255: #if DEBUG_TELNET
256: if(telnet_cmdlen==2)
257: fprintf(statfp,"T<%s> ",telnet_cmd_desc(ch));
258: else
259: fprintf(statfp,"T<%s> ",telnet_opt_desc(ch));
260: #endif
261: if(telnet_cmdlen==3 && telnet_cmd==TELNET_DO)
262: send_telnet_cmd(sock, TELNET_WILL,ch);
263: /*
264: else if(telnet_cmdlen==3 && telnet_cmd==TELNET_WILL)
265: send_telnet_cmd(sock, TELNET_DO,ch);
266: */
267: telnet_cmd=ch;
268: if((telnet_cmdlen==2 && ch<TELNET_WILL) || telnet_cmdlen>2)
269: telnet_cmdlen=0;
270: continue;
271: }
272: }
273: return(ch);
274: }
275:
276: return(NOINP);
277: }
278:
279: /*************************/
280: /* Send a byte to remote */
281: /*************************/
282: int send_byte(SOCKET sock, uchar ch, int timeout, long mode)
283: {
284: uchar buf[2] = { TELNET_IAC, TELNET_IAC };
285: int len=1;
286: int i;
287: fd_set socket_set;
288: struct timeval tv;
289:
290: FD_ZERO(&socket_set);
291: FD_SET(sock,&socket_set);
292: tv.tv_sec=timeout;
293: tv.tv_usec=0;
294:
295: if(select(sock+1,NULL,&socket_set,NULL,&tv)<1)
296: return(ERROR_VALUE);
297:
298: if(mode&TELNET && ch==TELNET_IAC) /* escape IAC char */
299: len=2;
300: else
301: buf[0]=ch;
302:
303: i=send(sock,buf,len,0);
304:
305: if(i==len)
306: return(0);
307:
308: return(-1);
309: }
310:
311: int send_str(SOCKET sock, char* str, int timeout, long mode)
312: {
313: char* p;
314: int i;
315:
316: for(p=str;*p;p++) {
317: if((i=send_byte(sock,*p,timeout,mode))!=0)
318: return(i);
319: }
320: return(0);
321: }
322:
323:
324: /****************************************************************************/
325: /* Returns the number of blocks required to send len bytes */
326: /****************************************************************************/
327: long num_blocks(long len, long block_size)
328: {
329: long blocks;
330:
331: blocks=len/block_size;
332: if(len%block_size)
333: blocks++;
334: return(blocks);
335: }
336:
337: /************************************************/
338: /* Dump the current block contents - for debug */
339: /************************************************/
340: void dump_block()
341: {
342: int l;
343:
344: for(l=0;l<block_size;l++)
345: fprintf(statfp,"%02X ",block[l]);
346: fprintf(statfp,"\n");
347: }
348:
349: void send_files(char** fname, uint fnames, FILE* log)
350: {
351: char path[MAX_PATH+1];
352: int ch;
353: int i;
354: uint errors;
355: uint fnum;
356: uint cps;
357: glob_t g;
358: int gi;
359: BOOL can;
360: BOOL success;
361: long b,l;
362: long fsize;
363: uint total_files=0,sent_files=0;
364: ulong total_bytes=0,sent_bytes=0;
365: time_t t,startfile;
366: FILE* fp;
367: xmodem_t xm;
368: zmodem_t zm;
369:
370: /****************************************************/
371: /* Search through all to find total files and bytes */
372: /****************************************************/
373: for(fnum=0;fnum<fnames;fnum++) {
374: if(glob(fname[fnum],0,NULL,&g)) {
375: fprintf(statfp,"%s not found\n",fname[fnum]);
376: continue;
377: }
378: for(i=0;i<(int)g.gl_pathc;i++) {
379: if(isdir(g.gl_pathv[i]))
380: continue;
381: total_files++;
382: total_bytes+=flength(g.gl_pathv[i]);
383: }
384: globfree(&g);
385: }
386:
387: if(fnames>1)
388: fprintf(statfp,"Sending %u files (%lu bytes total)\n"
389: ,total_files,total_bytes);
390:
391: memset(&xm,0,sizeof(xm));
392: xm.sock=sock;
393: xm.mode=mode;
394: xm.errfp=errfp;
395: xm.statfp=statfp;
396:
397: memset(&zm,0,sizeof(zm));
398: zm.sock=sock;
399: zm.mode=mode;
400: zm.errfp=errfp;
401: zm.statfp=statfp;
402: zm.n_files_remaining = total_files;
403: zm.n_bytes_remaining = total_bytes;
404:
405: /***********************************************/
406: /* Send every file matching names or filespecs */
407: /***********************************************/
408: for(fnum=0;fnum<fnames;fnum++) {
409: if(glob(fname[fnum],0,NULL,&g)) {
410: fprintf(statfp,"%s not found\n",fname[fnum]);
411: continue;
412: }
413: for(gi=0;gi<(int)g.gl_pathc;gi++) {
414: SAFECOPY(path,g.gl_pathv[gi]);
415: if(isdir(path))
416: continue;
417:
418: if((fp=fopen(path,"rb"))==NULL) {
419: fprintf(statfp,"!Error %d opening %s for read\n",errno,path);
420: continue;
421: }
422:
423: if(mode&ZMODEM) {
424:
425: for(errors=0;errors<MAXERRORS;errors++) {
426: fprintf(statfp,"\nSending ZRQINIT\n");
427: i = zmodem_get_zrinit(&zm);
428: if(i == ZRINIT) {
429: zmodem_parse_zrinit(&zm);
430: break;
431: }
432: fprintf(statfp,"\n!RX header: %d 0x%02X\n", i, i);
433: }
434:
435: } else { /* X/Ymodem */
436:
437: mode&=~GMODE;
438: flows=0;
439: for(errors=can=0;errors<MAXERRORS;errors++) {
440: i=getcom(10);
441: if(can && i!=CAN)
442: can=0;
443: if(i==NAK) { /* csum */
444: mode&=~CRC;
445: break;
446: }
447: if(i=='C') {
448: mode|=CRC;
449: break;
450: }
451: if(i=='G') {
452: mode|=(GMODE|CRC);
453: break;
454: }
455: if(i==CAN) {
456: if(can) {
457: newline();
458: fprintf(statfp,"Cancelled remotely\n");
459: bail(1);
460: }
461: can=1;
462: }
463: #if 0
464: rioctl(IOFB); /* flush buffers cause we have crap-o-la */
465: #endif
466: if(i!=NOINP) {
467: newline();
468: fprintf(statfp,"Received %s Expected NAK, C, or G\n"
469: ,chr((uchar)i));
470: }
471: }
472: }
473:
474: if(errors==MAXERRORS) {
475: fprintf(statfp,"\n!Timeout waiting for receiver to start/accept file transfer\n");
476: xmodem_cancel(&xm);
477: bail(1);
478: }
479:
480: fsize=filelength(fileno(fp));
481:
482: fprintf(statfp,"\nSending %s (%lu bytes) via %s %s\n"
483: ,path,fsize
484: ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? mode&GMODE ? "Ymodem-G"
485: : "Ymodem" : "Zmodem"
486: ,mode&ZMODEM ? (zm.can_fcs_32 ? "CRC-32" : "CRC-16")
487: : mode&CRC ? "CRC-16":"Checksum");
488:
489: errors=0;
490: success=0;
491: startfile=time(NULL);
492:
493: if(mode&ZMODEM) {
494: if(zmodem_send_file(&zm,getfname(path),fp)==0) {
495: sent_files++;
496: sent_bytes+=fsize;
497:
498: t=time(NULL)-startfile;
499: if(!t) t=1;
500: fprintf(statfp,"\rSuccesssful - Time: %lu:%02lu CPS: %lu\n"
501: ,t/60,t%60,fsize/t);
502: success=1;
503: }
504: else {
505: newline();
506: fprintf(statfp,"Unsuccessful!\n");
507: t=time(NULL)-startfile;
508: if(!t) t=1;
509: }
510:
511: } else { /* X/Ymodem */
512:
513: if(!(mode&XMODEM)) {
514: t=fdate(path);
515: memset(block,0,sizeof(block));
516: SAFECOPY(block,getfname(path));
517: sprintf(block+strlen(block)+1,"%lu %lo 0 0 %d %ld"
518: ,fsize,t,total_files-sent_files,total_bytes-sent_bytes);
519: /*
520: fprintf(statfp,"Sending Ymodem block '%s'\n",block+strlen(block)+1);
521: */
522: for(errors=0;errors<MAXERRORS;errors++) {
523: xmodem_put_block(&xm, block, 128 /* block_size */, 0 /* block_num */);
524: if(xmodem_get_ack(&xm,1))
525: break;
526: }
527: if(errors==MAXERRORS) {
528: newline();
529: fprintf(statfp,"Failed to send header block\n");
530: xmodem_cancel(&xm);
531: bail(1);
532: }
533: mode&=~GMODE;
534: for(errors=can=0;errors<MAXERRORS;errors++) {
535: i=getcom(10);
536: if(can && i!=CAN)
537: can=0;
538: if(i==NAK) { /* csum */
539: mode&=~CRC;
540: break;
541: }
542: if(i=='C') {
543: mode|=CRC;
544: break;
545: }
546: if(i=='G') {
547: mode|=(GMODE|CRC);
548: break;
549: }
550: if(i==CAN) {
551: if(can) {
552: newline();
553: fprintf(statfp,"Cancelled remotely\n");
554: bail(1);
555: }
556: can=1;
557: }
558: #if 0
559: rioctl(IOFB);
560: #endif
561: if(i!=NOINP) {
562: newline();
563: fprintf(statfp,"Received %s Expected NAK, C, or G\n"
564: ,chr((uchar)i));
565: }
566: }
567: if(errors==MAXERRORS) {
568: newline();
569: fprintf(statfp,"Too many errors waiting for receiver\n");
570: xmodem_cancel(&xm);
571: bail(1);
572: }
573: }
574: last_block_num=block_num=1;
575: errors=0;
576: while((block_num-1)*block_size<(ulong)fsize && errors<MAXERRORS) {
577: if(last_block_num==block_num) { /* block_num didn't increment */
578: fseek(fp,(block_num-1)*(long)block_size,SEEK_SET);
579: i=fread(block,1,block_size,fp);
580: while(i<block_size)
581: block[i++]=CPMEOF;
582: }
583: last_block_num=block_num;
584: xmodem_put_block(&xm, block, block_size, block_num);
585: i=fread(block,1,block_size,fp); /* read next block from disk */
586: while(i<(int)block_size)
587: block[i++]=CPMEOF;
588: t=time(NULL)-startfile;
589: if(!t) t=1; /* t is time so far */
590: cps=(uint)((block_num*(long)block_size)/t); /* cps so far */
591: if(!cps) cps=1;
592: l=fsize/cps; /* total transfer est time */
593: l-=t; /* now, it's est time left */
594: if(l<0) l=0;
595: b=num_blocks(fsize,block_size);
596: fprintf(statfp,"\rBlock (%lu%s): %lu/%lu Byte: %lu "
597: "Time: %lu:%02lu/%lu:%02lu CPS: %u %lu%% "
598: ,block_size%1024L ? block_size: block_size/1024L
599: ,block_size%1024L ? "" : "k"
600: ,block_num
601: ,b
602: ,block_num*(long)block_size
603: ,t/60L
604: ,t%60L
605: ,l/60L
606: ,l%60L
607: ,cps
608: ,(long)(((float)block_num/(float)b)*100.0)
609: );
610: if(!xmodem_get_ack(&xm,5))
611: errors++;
612: else
613: block_num++;
614: }
615: fclose(fp);
616: if((long)(block_num-1)*(long)block_size>=fsize) {
617: sent_files++;
618: sent_bytes+=fsize;
619: fprintf(statfp,"\n");
620:
621: for(i=0;i<10;i++) {
622: fprintf(statfp,"\rSending EOT (%d)",i+1);
623: #if 0
624: rioctl(IOFI);
625: #endif
626: putcom(EOT);
627: ch=getcom(10);
628: if(ch==ACK)
629: break;
630: if(ch==NAK && i==0 && (mode&(YMODEM|GMODE))==YMODEM)
631: continue; /* chuck's double EOT trick so don't complain */
632: if(ch!=NOINP) {
633: newline();
634: fprintf(statfp,"Received %s Expected ACK\n"
635: ,chr((uchar)ch));
636: }
637: }
638: if(i==3)
639: fprintf(statfp,"\rNo ACK on EOT \n");
640: t=time(NULL)-startfile;
641: if(!t) t=1;
642: fprintf(statfp,"\rSuccesssful - Time: %lu:%02lu CPS: %lu\n"
643: ,t/60,t%60,fsize/t);
644: success=1;
645: }
646: else {
647: newline();
648: fprintf(statfp,"Unsuccessful!\n");
649: t=time(NULL)-startfile;
650: if(!t) t=1;
651: }
652: }
653:
654: if(total_files>1 && total_files-sent_files>1)
655: fprintf(statfp,"Remaining - Time: %lu:%02lu Files: %u Bytes: %lu\n"
656: ,((total_bytes-sent_bytes)/cps)/60
657: ,((total_bytes-sent_bytes)/cps)%60
658: ,total_files-sent_files
659: ,total_bytes-sent_bytes
660: );
661:
662: /* DSZLOG entry */
663: if(log) {
664: if(mode&ZMODEM)
665: l=fsize;
666: else {
667: l=(block_num-1)*(long)block_size;
668: if(l>fsize)
669: l=fsize;
670: }
671: fprintf(log,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u "
672: "%s -1\n"
673: ,success ? (mode&ZMODEM ? 'z':'S') : 'E'
674: ,l
675: ,30000 /* baud */
676: ,l/t
677: ,errors
678: ,flows
679: ,block_size
680: ,path);
681: }
682: }
683: }
684: if(mode&XMODEM)
685: bail(0);
686: if(mode&ZMODEM)
687: zmodem_send_zfin(&zm);
688: else { /* YMODEM */
689: mode&=~GMODE;
690: i=getcom(10);
691: if(i==NAK)
692: mode&=~CRC;
693: else if(i=='C')
694: mode|=CRC;
695: else if(i=='G')
696: mode|=(GMODE|CRC);
697: if(i!=NOINP && i!=NAK && i!='C' && i!='G') {
698: newline();
699: fprintf(statfp,"Received %s Expected NAK, C, or G\n",chr((uchar)i));
700: }
701: else if(i!=NOINP) {
702: block[0]=0;
703: xmodem_put_block(&xm, block, 128 /* block_size */, 0 /* block_num */);
704: if(!xmodem_get_ack(&xm,6)) {
705: newline();
706: fprintf(statfp,"Failed to receive ACK after terminating block\n");
707: }
708: }
709: }
710: if(total_files>1) {
711: t=time(NULL)-startall;
712: if(!t) t=1;
713: newline();
714: fprintf(statfp,"Overall - Time %02lu:%02lu Bytes: %lu CPS: %lu\n"
715: ,t/60,t%60,sent_bytes,sent_bytes/t);
716: }
717: }
718:
719: void receive_files(char** fname, int fnames, FILE* log)
720: {
721: char str[MAX_PATH+1];
722: int i;
723: int fnum=0;
724: uint errors;
725: uint total_files;
726: uint cps;
727: uint hdr_block_num;
728: long b,l,m;
729: long serial_num;
730: ulong file_bytes=0,file_bytes_left=0;
731: ulong total_bytes=0;
732: FILE* fp;
733: time_t t,startfile,ftime;
734: xmodem_t xm;
735: zmodem_t zm;
736:
737: if(fnames>1)
738: fprintf(statfp,"Receiving %u files\n",fnames);
739:
740: memset(&xm,0,sizeof(xm));
741: xm.sock=sock;
742: xm.mode=mode;
743:
744: memset(&zm,0,sizeof(zm));
745: zm.sock=sock;
746: zm.mode=mode;
747:
748: while(1) {
749: if(mode&XMODEM) {
750: SAFECOPY(str,fname[0]);
751: file_bytes=file_bytes_left=0x7fffffff;
752: serial_num=-1;
753: }
754:
755: else if(mode&YMODEM) {
756: fprintf(statfp,"Fetching Ymodem header block\n");
757: for(errors=0;errors<MAXERRORS;errors++) {
758: if(errors>3 && mode&CRC && !(mode&GMODE))
759: mode&=~CRC;
760: if(mode&GMODE) /* G for Ymodem-G */
761: putcom('G');
762: else if(mode&CRC) /* C for CRC */
763: putcom('C');
764: else /* NAK for checksum */
765: putcom(NAK);
766: #if 0
767: for(i=60;i;i--) {
768: if(rioctl(RXBC)) /* no chars in-bound */
769: break;
770: SLEEP(100); /* so wait */
771: }
772: if(!i) { /* none after 6 secs */
773: if(errors)
774: fprintf(statfp,"Ymodem header timeout (%d)\n",errors);
775: continue;
776: }
777: #endif
778: if(xmodem_get_block(&xm, block,block_size,TRUE)==0) { /* block received successfully */
779: putcom(ACK);
780: break;
781: }
782: }
783: if(errors==MAXERRORS) {
784: fprintf(statfp,"Error fetching Ymodem header block\n");
785: xmodem_cancel(&xm);
786: bail(1);
787: }
788: if(!block[0]) {
789: fprintf(statfp,"Received Ymodem termination block\n");
790: bail(0);
791: }
792: sscanf(block+strlen(block)+1,"%ld %lo %lo %lo %d %ld"
793: ,&file_bytes /* file size (decimal) */
794: ,&ftime /* file time (octal unix format) */
795: ,&m /* file mode (not used) */
796: ,&serial_num /* program serial number */
797: ,&total_files /* remaining files to be sent */
798: ,&total_bytes /* remaining bytes to be sent */
799: );
800: if(!file_bytes)
801: file_bytes=0x7fffffff;
802: file_bytes_left=file_bytes;
803: if(!total_files)
804: total_files=fnames-fnum;
805: if(!total_files)
806: total_files=1;
807: if(total_bytes<file_bytes)
808: total_bytes=file_bytes;
809: if(!serial_num)
810: serial_num=-1;
811: fprintf(statfp,"Incoming filename: %.64s ",block);
812: if(mode&DIR)
813: sprintf(str,"%s%s",fname[0],getfname(block));
814: else {
815: SAFECOPY(str,getfname(block));
816: for(i=0;i<fnames;i++) {
817: if(!fname[i][0]) /* name blank or already used */
818: continue;
819: if(!stricmp(getfname(fname[i]),str)) {
820: SAFECOPY(str,fname[i]);
821: fname[i][0]=0;
822: break;
823: }
824: }
825: if(i==fnames) { /* Not found in list */
826: if(fnames)
827: fprintf(statfp," - Not in receive list!");
828: if(!fnames || fnum>=fnames || !fname[fnum][0])
829: SAFECOPY(str,getfname(block)); /* worst case */
830: else {
831: SAFECOPY(str,fname[fnum]);
832: fname[fnum][0]=0;
833: }
834: }
835: }
836: fprintf(statfp,"\n");
837: }
838:
839: else { /* Zmodem */
840: #if 0
841: tryzhdrtype=ZRINIT;
842: while(1) {
843: Txhdr[ZF0]=(CANFC32|CANFDX|CANOVIO|CANRLE);
844: /* add CANBRK if we can send break signal */
845: if(zmode&CTRL_ESC)
846: Txhdr[ZF0]|=TESCCTL;
847: Txhdr[ZF1]=CANVHDR;
848: Txhdr[ZP0]=0;
849: Txhdr[ZP1]=0;
850: putzhhdr(tryzhdrtype);
851: done=0;
852: while(!done) {
853: done=1;
854: switch(getzhdr()) {
855: case ZRQINIT:
856: if(Rxhdr[ZF3]&0x80)
857: zmode|=VAR_HDRS; /* we can var header */
858: break;
859: case ZFILE:
860: zconv=Rxhdr[ZF0];
861: zmanag=Rxhdr[ZF1];
862: ztrans=Rxhdr[ZF2];
863: if(Rxhdr[ZF3]&ZCANVHDR)
864: zmode|=VAR_HDRS;
865: tryzhdrtype=ZRINIT;
866: if(getzdata(block, 1024)==GOTCRCW) {
867: /* something */
868: done=1;
869: }
870: putzhhdr(ZNAK);
871: done=0;
872: break;
873: case ZSINIT:
874: if(Rxhdr[ZF0]&TESCCTL)
875: zmode|=CTRL_ESC;
876: if (getzdata(attn,ZATTNLEN)==GOTCRCW) {
877: ltohdr(1L);
878: putzhhdr(ZACK);
879: }
880: else
881: putzhhdr(ZNAK);
882: done=0;
883: break;
884: case ZFREECNT:
885: ltohdr(0); /* should be free disk space */
886: putzhhdr(ZACK);
887: done=0;
888: break;
889: case ZCOMMAND:
890: /***
891: cmdzack1flg = Rxhdr[ZF0];
892: if(getzdata(block,1024)==GOTCRCW) {
893: if (cmdzack1flg & ZCACK1)
894: ltohdr(0L);
895: else
896: ltohdr((long)sys2(block));
897: purgeline(); /* dump impatient questions */
898: do {
899: zshhdr(4,ZCOMPL, Txhdr);
900: }
901: while (++errors<20 && zgethdr(Rxhdr,1)!=ZFIN);
902: ackbibi();
903: if (cmdzack1flg & ZCACK1)
904: exec2(block);
905: return ZCOMPL;
906: }
907: ***/
908: putzhhdr(ZNAK);
909: done=0;
910: break;
911: case ZCOMPL:
912: done=0;
913: break;
914: case ZFIN:
915: ackbibi();
916: return ZCOMPL;
917: case ZCAN:
918: return ERROR;
919: }
920: }
921: #endif
922: }
923:
924: fnum++;
925:
926: if(!(mode&DIR) && fnames && fnum>fnames) {
927: newline();
928: fprintf(statfp,"Attempt to send more files than specified\n");
929: xmodem_cancel(&xm);
930: break;
931: }
932:
933: if(fexist(str) && !(mode&OVERWRITE)) {
934: fprintf(statfp,"%s already exists\n",str);
935: xmodem_cancel(&xm);
936: bail(1);
937: }
938: if((fp=fopen(str,"wb"))==NULL) {
939: fprintf(statfp,"Error creating %s\n",str);
940: xmodem_cancel(&xm);
941: bail(1);
942: }
943: setvbuf(fp,NULL,_IOFBF,8*1024);
944: startfile=time(NULL);
945: fprintf(statfp,"Receiving %s (%lu bytes) via %s %s\n"
946: ,str
947: ,mode&XMODEM ? 0 : file_bytes
948: ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? mode&GMODE ? "Ymodem-G"
949: : "Ymodem" :"Zmodem"
950: ,mode&CRC ? "CRC-16":"Checksum");
951:
952: errors=0;
953: block_num=0;
954: if(mode&GMODE) /* G for Ymodem-G */
955: putcom('G');
956: else if(mode&CRC) /* C for CRC */
957: putcom('C');
958: else /* NAK for checksum */
959: putcom(NAK);
960: while(errors<MAXERRORS) {
961: if(block_num && !(mode&GMODE))
962: putcom(ACK);
963: i=xmodem_get_block(&xm, block,block_size,FALSE); /* returns block num */
964: if(i<0) {
965: if(i==-EOT) /* end of transfer */
966: break;
967: /* other error */
968: xmodem_cancel(&xm);
969: bail(1);
970: }
971: hdr_block_num=i;
972: if(file_bytes_left<=0L) { /* No more bytes to send */
973: newline();
974: fprintf(statfp,"Attempt to send more than header specified\n");
975: break;
976: }
977: if(hdr_block_num==(uchar)((block_num+1)&0xff)) { /* correct block */
978: block_num++;
979: if(file_bytes_left<(ulong)block_size) {
980: if(fwrite(block,1,file_bytes_left,fp)
981: !=file_bytes_left) {
982: newline();
983: fprintf(statfp,"Error writing to file\n");
984: xmodem_cancel(&xm);
985: bail(1);
986: }
987: }
988: else {
989: if(fwrite(block,1,block_size,fp)
990: !=(uint)block_size) {
991: newline();
992: fprintf(statfp,"Error writing to file\n");
993: xmodem_cancel(&xm);
994: bail(1);
995: }
996: }
997: file_bytes_left-=block_size;
998: }
999: else {
1000: newline();
1001: fprintf(statfp,"Block number %u instead of %u\n"
1002: ,hdr_block_num,(block_num+1)&0xff);
1003: // dump_block();
1004: errors++;
1005: }
1006: t=time(NULL)-startfile;
1007: if(!t) t=1;
1008: cps=(uint)((block_num*(long)block_size)/t); /* cps so far */
1009: if(!cps) cps=1;
1010: l=file_bytes/cps; /* total transfer est time */
1011: l-=t; /* now, it's est time left */
1012: if(l<0) l=0;
1013: b=num_blocks(file_bytes, block_size);
1014: if(mode&YMODEM)
1015: fprintf(statfp,"\rBlock (%lu%s): %lu/%lu Byte: %lu Time: %lu:%02lu/"
1016: "%lu:%02lu CPS: %u %lu%% "
1017: ,block_size%1024L ? block_size: block_size/1024L
1018: ,block_size%1024L ? "" : "k"
1019: ,block_num
1020: ,b
1021: ,block_num*(long)block_size
1022: ,t/60L
1023: ,t%60L
1024: ,l/60L
1025: ,l%60L
1026: ,cps
1027: ,(long)(((float)block_num/(float)b)*100.0)
1028: );
1029: else /* Xmodem */
1030: fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %lu Time: %lu:%02lu "
1031: "CPS: %u "
1032: ,block_size%1024L ? block_size: block_size/1024L
1033: ,block_size%1024L ? "" : "k"
1034: ,block_num
1035: ,block_num*(long)block_size
1036: ,t/60L
1037: ,t%60L
1038: ,cps
1039: );
1040: }
1041:
1042: putcom(ACK);
1043: if(!(mode&XMODEM) && ftime)
1044: setfdate(str,ftime);
1045: /* Use correct file size */
1046: fflush(fp);
1047: if(file_bytes < (ulong)filelength(fileno(fp)));
1048: chsize(fileno(fp),file_bytes);
1049: fclose(fp);
1050: t=time(NULL)-startfile;
1051: if(!t) t=1;
1052: l=(block_num-1)*block_size;
1053: if(l>(long)file_bytes)
1054: l=file_bytes;
1055: newline();
1056: fprintf(statfp,"Successsful - Time: %lu:%02lu CPS: %lu\n"
1057: ,t/60,t%60,l/t);
1058: if(log) {
1059: fprintf(log,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u "
1060: "%s %d\n"
1061: ,mode&ZMODEM ? 'Z' : 'R'
1062: ,l
1063: ,30000 /* baud */
1064: ,l/t
1065: ,errors
1066: ,flows
1067: ,block_size
1068: ,str
1069: ,serial_num);
1070: }
1071: if(mode&XMODEM)
1072: break;
1073: total_files--;
1074: total_bytes-=file_bytes;
1075: if(total_files>1 && total_bytes)
1076: fprintf(statfp,"Remaining - Time: %lu:%02lu Files: %u Bytes: %lu\n"
1077: ,(total_bytes/cps)/60
1078: ,(total_bytes/cps)%60
1079: ,total_files
1080: ,total_bytes
1081: );
1082: }
1083: }
1084:
1085: static const char* usage=
1086: "usage: sexyz <socket> [opts] <cmd> [file | path | +list]\n\n"
1087: "socket = TCP socket descriptor\n"
1088: "opts = o to overwrite files when receiving\n"
1089: " d to disable dropped carrier detection\n"
1090: " a to sound alarm at start and stop of transfer\n"
1091: " p to pause after abnormal exit (error)\n"
1092: "cmd = v to display detailed version information\n"
1093: " sx to send Xmodem rx to recv Xmodem\n"
1094: " sX to send Xmodem-1k rc to recv Xmodem-CRC\n"
1095: " sy to send Ymodem ry to recv Ymodem\n"
1096: " sY to send Ymodem-1k rg to recv Ymodem-G\n"
1097: " sz to send Zmodem rz to recv Zmodem\n"
1098: "file = filename to send or receive\n"
1099: "path = path to receive files into\n"
1100: "list = name of text file with list of filenames to send or receive\n";
1101:
1102: /***************/
1103: /* Entry Point */
1104: /***************/
1105: int main(int argc, char **argv)
1106: {
1107: char str[256],*p
1108: ,*fname[MAX_FNAMES];
1109: int i;
1110: uint fnames=0;
1111: FILE* fp;
1112: FILE* log=NULL;
1113: BOOL b;
1114: char compiler[32];
1115:
1116: DESCRIBE_COMPILER(compiler);
1117:
1118: errfp=stderr;
1119: statfp=stdout;
1120:
1121: sscanf("$Revision: 1.7 $", "%*s %s", revision);
1122:
1123: fprintf(statfp,"\nSynchronet External X/Y/Zmodem v%s-%s"
1124: " Copyright 2003 Rob Swindell\n\n"
1125: ,revision
1126: ,PLATFORM_DESC
1127: );
1128:
1129: #if 0
1130: if(argc>1) {
1131: fprintf(statfp,"Command line: ");
1132: for(i=1;i<argc;i++)
1133: fprintf(statfp,"%s ",argv[i]);
1134: fprintf(statfp,"\n",statfp);
1135: }
1136: #endif
1137:
1138: for(i=1;i<argc;i++) {
1139:
1140: if(sock==INVALID_SOCKET && isdigit(argv[i][0])) {
1141: sock=atoi(argv[i]);
1142: continue;
1143: }
1144:
1145: if(!(mode&(SEND|RECV))) {
1146: if(toupper(argv[i][0])=='S' || toupper(argv[i][0])=='R') { /* cmd */
1147: if(toupper(argv[i][0])=='R')
1148: mode|=RECV;
1149: else
1150: mode|=SEND;
1151:
1152: block_size=1024;
1153:
1154: switch(argv[i][1]) {
1155: case 'c':
1156: case 'C':
1157: mode|=CRC;
1158: case 'x':
1159: block_size=128;
1160: case 'X':
1161: mode|=XMODEM;
1162: break;
1163: case 'y':
1164: block_size=128;
1165: case 'Y':
1166: mode|=(YMODEM|CRC);
1167: break;
1168: case 'g':
1169: case 'G':
1170: mode|=(YMODEM|CRC|GMODE);
1171: break;
1172: case 'z':
1173: case 'Z':
1174: mode|=(ZMODEM|CRC);
1175: break;
1176: default:
1177: fprintf(statfp,"Unrecognized command '%s'\n\n",argv[i]);
1178: fprintf(statfp,usage);
1179: exit(1);
1180: }
1181: }
1182:
1183: else if(toupper(argv[i][0])=='V') {
1184:
1185: fprintf(statfp,"%-8s %s\n",getfname(__FILE__) ,revision);
1186: fprintf(statfp,"%-8s %s\n",getfname(xmodem_source()),xmodem_ver(str));
1187: fprintf(statfp,"%-8s %s\n",getfname(zmodem_source()),zmodem_ver(str));
1188: #ifdef _DEBUG
1189: fprintf(statfp,"Debug\n");
1190: #endif
1191: fprintf(statfp,"Compiled %s %.5s with %s\n",__DATE__,__TIME__,compiler);
1192: fprintf(statfp,"%s\n",os_version(str));
1193: exit(1);
1194: }
1195:
1196:
1197: else if(toupper(argv[i][0])=='O')
1198: mode|=OVERWRITE;
1199:
1200: else if(toupper(argv[i][0])=='D')
1201: mode|=IGNORE_DCD;
1202:
1203: else if(toupper(argv[i][0])=='A')
1204: mode|=ALARM;
1205:
1206: else if(toupper(argv[i][0])=='P')
1207: mode|=PAUSE_ABEND;
1208:
1209: else if(argv[i][0]=='*')
1210: mode|=DEBUG;
1211: }
1212:
1213: else if(argv[i][0]=='+') {
1214: if(mode&DIR) {
1215: fprintf(statfp,"Cannot specify both directory and filename\n");
1216: exit(1);
1217: }
1218: sprintf(str,"%s",argv[i]+1);
1219: if((fp=fopen(str,"r"))==NULL) {
1220: fprintf(statfp,"Error %d opening filelist: %s\n",errno,str);
1221: exit(1);
1222: }
1223: while(!feof(fp) && !ferror(fp) && fnames<MAX_FNAMES) {
1224: if(!fgets(str,sizeof(str),fp))
1225: break;
1226: truncsp(str);
1227: if((fname[fnames]=(char *)malloc(strlen(str)+1))==NULL) {
1228: fprintf(statfp,"Error allocating memory for filename\n");
1229: exit(1);
1230: }
1231: strcpy(fname[fnames++],str);
1232: }
1233: fclose(fp);
1234: }
1235:
1236: else if(mode&(SEND|RECV)){
1237: if((fname[fnames]=(char *)malloc(strlen(argv[i])+1))==NULL) {
1238: fprintf(statfp,"Error allocating memory for filename\n");
1239: exit(1);
1240: }
1241: strcpy(fname[fnames],argv[i]);
1242: if(isdir(fname[fnames])) { /* is a directory */
1243: if(mode&DIR) {
1244: fprintf(statfp,"Only one directory can be specified\n");
1245: exit(1);
1246: }
1247: if(fnames) {
1248: fprintf(statfp,"Cannot specify both directory and filename\n");
1249: exit(1);
1250: }
1251: if(mode&SEND) {
1252: fprintf(statfp,"Cannot send directory '%s'\n",fname[fnames]);
1253: exit(1);
1254: }
1255: mode|=DIR;
1256: }
1257: fnames++;
1258: }
1259: }
1260:
1261: if(sock==INVALID_SOCKET || sock<1) {
1262: fprintf(statfp,"!No socket descriptor specified\n\n");
1263: fprintf(errfp,usage);
1264: exit(1);
1265: }
1266:
1267: if(!(mode&(SEND|RECV))) {
1268: fprintf(statfp,"!No command specified\n\n");
1269: fprintf(statfp,usage);
1270: exit(1);
1271: }
1272:
1273: if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */
1274: fprintf(statfp,"!Must specify filename or filelist\n\n");
1275: fprintf(statfp,usage);
1276: exit(1);
1277: }
1278:
1279:
1280: if(mode&DIR)
1281: backslash(fname[0]);
1282:
1283: if(mode&ALARM) {
1284: BEEP(1000,500);
1285: BEEP(2000,500);
1286: }
1287:
1288: if(!winsock_startup())
1289: bail(2);
1290: #if 0
1291: /* Non-blocking socket I/O */
1292: val=1;
1293: ioctlsocket(sock,FIONBIO,&val);
1294: #endif
1295:
1296: /* Enable the Nagle Algorithm */
1297: b=0;
1298: setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char*)&b,sizeof(b));
1299:
1300: if(!DCDHIGH) {
1301: newline();
1302: fprintf(statfp,"No carrier\n");
1303: bail(1);
1304: }
1305:
1306: p=getenv("DSZLOG");
1307: if(p) {
1308: if((log=fopen(p,"w"))==NULL) {
1309: fprintf(statfp,"Error opening DSZLOG file: %s\n",p);
1310: bail(1);
1311: }
1312: }
1313:
1314: startall=time(NULL);
1315:
1316: if(mode&RECV)
1317: receive_files(fname, fnames, log);
1318: else
1319: send_files(fname, fnames, log);
1320:
1321: bail(0);
1322: return(0);
1323: }
1324:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.