|
|
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.