Annotation of sbbs/src/sbbs3/sexyz.c, revision 1.1.1.2

1.1       root        1: /* sexyz.c */
                      2: 
                      3: /* Synchronet External X/Y/ZMODEM Transfer Protocols */
                      4: 
1.1.1.2 ! root        5: /* $Id: sexyz.c,v 1.132 2011/07/14 08:30:52 rswindell Exp $ */
1.1       root        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:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       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)
1.1.1.2 ! root       80: #define INBUF_SIZE                     (64*1024)
        !            81: #define        MAX_FILE_SIZE           0                       /* Default value for max recv file size, 0 = unlimited*/
1.1       root       82: 
                     83: /***************/
                     84: /* Global Vars */
                     85: /***************/
                     86: long   mode=0;                                                 /* Program mode                                         */
                     87: long   zmode=0L;                                               /* Zmodem mode                                          */
1.1.1.2 ! root       88: uchar  block[XMODEM_MAX_BLOCK_SIZE];   /* Block buffer                                         */
1.1       root       89: ulong  block_num;                                              /* Block number                                         */
                     90: char*  dszlog;
                     91: BOOL   dszlog_path=TRUE;                               /* Log complete path to filename        */
                     92: BOOL   dszlog_short=FALSE;                             /* Log Micros~1 short filename          */
                     93: BOOL   dszlog_quotes=FALSE;                    /* Quote filenames in DSZLOG            */
                     94: int            log_level=LOG_INFO;
1.1.1.2 ! root       95: BOOL   use_syslog=FALSE;
        !            96: int64_t        max_file_size=MAX_FILE_SIZE;
1.1       root       97: 
                     98: xmodem_t xm;
                     99: zmodem_t zm;
                    100: 
                    101: FILE*  errfp;
                    102: FILE*  statfp;
                    103: FILE*  logfp=NULL;
                    104: 
                    105: char   revision[16];
                    106: 
                    107: SOCKET sock=INVALID_SOCKET;
                    108: 
                    109: BOOL   telnet=TRUE;
                    110: #ifdef __unix__
                    111: BOOL   stdio=FALSE;
                    112: #endif
                    113: BOOL   terminate=FALSE;
                    114: BOOL   debug_tx=FALSE;
                    115: BOOL   debug_rx=FALSE;
                    116: BOOL   debug_telnet=FALSE;
                    117: BOOL   pause_on_exit=FALSE;
                    118: BOOL   pause_on_abend=FALSE;
                    119: BOOL   newline=TRUE;
1.1.1.2 ! root      120: BOOL   connected=TRUE;
1.1       root      121: 
                    122: time_t         progress_interval;
                    123: 
                    124: RingBuf                outbuf;
                    125: #if defined(RINGBUF_EVENT)
                    126:        #define         outbuf_empty outbuf.empty_event
                    127: #else
                    128:        xpevent_t       outbuf_empty;
                    129: #endif
                    130: unsigned       outbuf_drain_timeout;
                    131: long           outbuf_size;
                    132: 
1.1.1.2 ! root      133: uchar          inbuf[INBUF_SIZE];
        !           134: unsigned       inbuf_pos=0;
        !           135: unsigned       inbuf_len=0;
        !           136: 
1.1       root      137: unsigned       flows=0;
                    138: unsigned       select_errors=0;
                    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;
1.1.1.2 ! root      167:        int             ret;
1.1       root      168: 
                    169: #if defined(_WIN32) && defined(_DEBUG)
                    170:        if(log_level==LOG_DEBUG)
                    171:                OutputDebugString(str);
                    172: #endif
                    173: 
                    174:        if(level>log_level)
                    175:                return 0;
                    176: 
                    177:     if(level<LOG_NOTICE)
                    178:                fp=errfp;
                    179: 
                    180:        if(!newline) {
                    181:                fprintf(fp,"\n");
                    182:                newline=TRUE;
                    183:        }
                    184:        if(level<LOG_NOTICE)
1.1.1.2 ! root      185:                ret=fprintf(fp,"!%s\n",str);
1.1       root      186:        else
1.1.1.2 ! root      187:                ret=fprintf(fp,"%s\n",str);
        !           188: 
        !           189: #if defined(__unix__)
        !           190:        if(use_syslog) {
        !           191:                char*   msg;
        !           192:                char*   p;
        !           193:                if((msg=strdup(str))!=NULL) {
        !           194:                        REPLACE_CHARS(msg,'\r',' ',p);
        !           195:                        REPLACE_CHARS(msg,'\n',' ',p);
        !           196:                        syslog(level,"%s",msg);
        !           197:                        free(msg);
        !           198:                }
        !           199:        }
        !           200: #endif
        !           201: 
        !           202:        return ret;
1.1       root      203: }
                    204: 
                    205: static int lprintf(int level, const char *fmt, ...)
                    206: {
                    207:        char sbuf[1024];
                    208:        va_list argptr;
                    209: 
1.1.1.2 ! root      210:        if(level>log_level)
        !           211:                return 0;
        !           212: 
1.1       root      213:     va_start(argptr,fmt);
                    214:     vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
                    215:        sbuf[sizeof(sbuf)-1]=0;
                    216:     va_end(argptr);
                    217:     return(lputs(NULL,level,sbuf));
                    218: }
                    219: 
                    220: void break_handler(int type)
                    221: {
                    222:        lprintf(LOG_NOTICE,"-> Aborted Locally (signal: %d)",type);
                    223: 
                    224:        /* Flag to indicate local (as opposed to remote) abort */
1.1.1.2 ! root      225:        zm.local_abort=TRUE;
1.1       root      226: 
                    227:        /* Stop any transfers in progress immediately */
                    228:        xm.cancelled=TRUE;      
                    229:        zm.cancelled=TRUE;
                    230: }
                    231: 
                    232: #if defined(_WIN32)
1.1.1.2 ! root      233: BOOL WINAPI ControlHandler(unsigned long CtrlType)
1.1       root      234: {
                    235:        break_handler((int)CtrlType);
                    236:        return TRUE;
                    237: }
                    238: #endif
                    239: 
                    240: char* dszlog_filename(char* str)
                    241: {
                    242:        char*           p=str;
                    243:        static char     path[MAX_PATH+1];
                    244: 
                    245: #ifdef _WIN32
                    246:        char sfpath[MAX_PATH+1];
                    247:        if(dszlog_short) {
                    248:                SAFECOPY(sfpath,str);
                    249:                GetShortPathName(str,sfpath,sizeof(sfpath));
                    250:                p=sfpath;
                    251:        }
                    252: #endif
                    253: 
                    254:        if(!dszlog_path)
                    255:                p=getfname(p);
                    256: 
                    257:        if(!dszlog_quotes)
                    258:                return(p);
                    259: 
                    260:        SAFEPRINTF(path,"\"%s\"",p);
                    261:        return(path);
                    262: }
                    263: 
                    264: static char *chr(uchar ch)
                    265: {
                    266:        static char str[25];
                    267: 
                    268:        if(mode&ZMODEM) {
                    269:                switch(ch) {
                    270:                        case ZRQINIT:   return("ZRQINIT");
                    271:                        case ZRINIT:    return("ZRINIT");
                    272:                        case ZSINIT:    return("ZSINIT");
                    273:                        case ZACK:              return("ZACK");
                    274:                        case ZFILE:             return("ZFILE");
                    275:                        case ZSKIP:             return("ZSKIP");
                    276:                        case ZNAK:              return("ZNAK");
                    277:                        case ZABORT:    return("ZABORT");
                    278:                        case ZFIN:              return("ZFIN");
                    279:                        case ZRPOS:             return("ZRPOS");
                    280:                        case ZDATA:             return("ZDATA");
                    281:                        case ZEOF:              return("ZEOF");
                    282:                        case ZPAD:              return("ZPAD");
                    283:                        case ZDLE:              return("ZDLE");
                    284:                        case ZDLEE:             return("ZDLEE");
                    285:                        case ZBIN:              return("ZBIN");
                    286:                        case ZHEX:              return("ZHEX");
                    287:                        case ZBIN32:    return("ZBIN32");
                    288:                        case ZRESC:             return("ZRESC");
                    289:                        case ZCRCE:             return("ZCRCE");
                    290:                        case ZCRCG:             return("ZCRCG");
                    291:                        case ZCRCQ:             return("ZCRCQ");
                    292:                        case ZCRCW:             return("ZCRCW");
                    293:                }
                    294:        } else {
                    295:                switch(ch) {
                    296:                        case SOH:       return("SOH");
                    297:                        case STX:       return("STX");
                    298:                        case ETX:       return("ETX");
                    299:                        case EOT:       return("EOT");
                    300:                        case ACK:       return("ACK");
                    301:                        case NAK:       return("NAK");
                    302:                        case CAN:       return("CAN");
                    303:                }
                    304:        }
                    305:        if(ch>=' ' && ch<='~')
                    306:                sprintf(str,"'%c' (%02Xh)",ch,ch);
                    307:        else
                    308:                sprintf(str,"%u (%02Xh)",ch,ch);
                    309:        return(str); 
                    310: }
                    311: 
                    312: void dump(BYTE* buf, int len)
                    313: {
                    314:        char str[128];
                    315:        int i,j;
                    316:        size_t slen=0;
                    317: 
                    318:        slen=sprintf(str,"TX: ");
                    319:        for(i=0;i<len;i+=j) {
                    320:                for(j=0;i+j<len && j<32;j++)
                    321:                        slen+=sprintf(str+slen,"%02X ",buf[i+j]);
                    322:                lprintf(LOG_DEBUG,"%s",str);
                    323:                slen=sprintf(str,"TX: ");
                    324:        }
                    325: }
                    326: 
1.1.1.2 ! root      327: int sendbuf(SOCKET s, void *buf, size_t buflen)
        !           328: {
        !           329:        size_t          sent=0;
        !           330:        int                     ret;
        !           331:        fd_set          socket_set;
        !           332: 
        !           333:        for(;;) {
        !           334: #ifdef __unix__
        !           335:                if(stdio)
        !           336:                        ret=write(STDOUT_FILENO, (char *)buf+sent,buflen-sent);
        !           337:                else
        !           338: #endif
        !           339:                        ret=sendsocket(s,(char *)buf+sent,buflen-sent);
        !           340:                if(ret==SOCKET_ERROR) {
        !           341:                        switch(ERROR_VALUE) {
        !           342:                                case EAGAIN:
        !           343:                                case ENOBUFS:
        !           344: #if (EAGAIN != EWOULDBLOCK)
        !           345:                                case EWOULDBLOCK:
        !           346: #endif
        !           347:                                        /* Block until we can send */
        !           348:                                        FD_ZERO(&socket_set);
        !           349: #ifdef __unix__
        !           350:                                        if(stdio)
        !           351:                                                FD_SET(STDIN_FILENO,&socket_set);
        !           352:                                        else
        !           353: #endif
        !           354:                                                FD_SET(sock,&socket_set);
        !           355: 
        !           356:                                        if((ret=select(sock+1,NULL,&socket_set,NULL,NULL))<1) {
        !           357:                                                if(ret==SOCKET_ERROR && ERROR_VALUE != EINTR) {
        !           358:                                                        lprintf(LOG_ERR,"ERROR %d selecting socket", ERROR_VALUE);
        !           359:                                                        goto disconnect;
        !           360:                                                }
        !           361:                                        }
        !           362:                                        break;
        !           363:                                default:
        !           364:                                        goto disconnect;
        !           365:                        }
        !           366:                }
        !           367:                else {
        !           368:                        sent += ret;
        !           369:                        if(sent >= buflen)
        !           370:                                return(sent);
        !           371:                }
        !           372:        }
        !           373: 
        !           374: disconnect:
        !           375:        lprintf(LOG_DEBUG,"DISCONNECTED line %u", __LINE__);
        !           376:        connected=FALSE;
        !           377:        if(sent)
        !           378:                return sent;
        !           379:        return SOCKET_ERROR;
        !           380: }
        !           381: 
1.1       root      382: void send_telnet_cmd(SOCKET sock, uchar cmd, uchar opt)
                    383: {
                    384:        uchar   buf[3];
                    385:        
                    386:        buf[0]=TELNET_IAC;
                    387:        buf[1]=cmd;
                    388:        buf[2]=opt;
                    389: 
                    390:        if(debug_telnet)
                    391:                lprintf(LOG_DEBUG,"Sending telnet command: %s %s"
                    392:                        ,telnet_cmd_desc(buf[1]),telnet_opt_desc(buf[2]));
                    393: 
1.1.1.2 ! root      394:        if(sendbuf(sock,buf,sizeof(buf))!=sizeof(buf) && debug_telnet)
1.1       root      395:                lprintf(LOG_ERR,"FAILED");
                    396: }
                    397: 
                    398: #define DEBUG_TELNET FALSE
                    399: 
1.1.1.2 ! root      400: /*
        !           401:  * Returns -1 on disconnect or the number of bytes read.
        !           402:  * Does not muck around with ERROR_VALUE (hopefully)
        !           403:  */
        !           404: static int recv_buffer(int timeout /* seconds */)
        !           405: {
        !           406:        int i;
        !           407:        fd_set          socket_set;
        !           408:        struct timeval  tv;
        !           409:        int                     magic_errno;
        !           410: 
        !           411:        for(;;) {
        !           412:                if(inbuf_len > inbuf_pos)
        !           413:                        return(inbuf_len-inbuf_pos);
        !           414: #ifdef __unix__
        !           415:                if(stdio) {
        !           416:                        i=read(STDIN_FILENO,inbuf,sizeof(inbuf));
        !           417:                        /* Look like a socket using MAGIC! */
        !           418:                        switch(i) {
        !           419:                                case 0:
        !           420:                                        i=-1;
        !           421:                                        magic_errno=EAGAIN;
        !           422:                                        break;
        !           423:                                case -1:
        !           424:                                        magic_errno=errno;
        !           425:                                        break;
        !           426:                        }
        !           427:                }
        !           428:                else
        !           429: #endif
        !           430:                {
        !           431:                        i=recv(sock,inbuf,sizeof(inbuf),0);
        !           432:                        if(i==SOCKET_ERROR)
        !           433:                                magic_errno=ERROR_VALUE;
        !           434:                }
        !           435:                if(i==SOCKET_ERROR) {
        !           436:                        switch(magic_errno) {
        !           437:                                case EAGAIN:
        !           438:                                case EINTR:
        !           439: #if (EAGAIN != EWOULDBLOCK)
        !           440:                                case EWOULDBLOCK:
        !           441: #endif
        !           442:                                        // Call select()
        !           443:                                        if(timeout) {
        !           444:                                                FD_ZERO(&socket_set);
        !           445: #ifdef __unix__
        !           446:                                                if(stdio)
        !           447:                                                        FD_SET(STDIN_FILENO,&socket_set);
        !           448:                                                else
        !           449: #endif
        !           450:                                                        FD_SET(sock,&socket_set);
        !           451:                                                tv.tv_sec=timeout;
        !           452:                                                timeout=0;
        !           453:                                                tv.tv_usec=0;
        !           454:                                                if((i=select(sock+1,&socket_set,NULL,NULL,&tv))<1) {
        !           455:                                                        if(i==SOCKET_ERROR) {
        !           456:                                                                lprintf(LOG_ERR,"ERROR %d selecting socket", magic_errno);
        !           457:                                                                connected=FALSE;
        !           458:                                                        }
        !           459:                                                        else
        !           460:                                                                lprintf(LOG_WARNING,"Receive timeout (%u seconds)", timeout);
        !           461:                                                }
        !           462:                                                else
        !           463:                                                        continue;
        !           464:                                        }
        !           465:                                        return 0;
        !           466:                                default:
        !           467:                                        lprintf(LOG_DEBUG,"DISCONNECTED line %u, error=%u", __LINE__,magic_errno);
        !           468:                                        connected=FALSE;
        !           469:                                        return -1;
        !           470:                        }
        !           471:                        return -1; // Impossible.
        !           472:                }
        !           473:                else if(i==0) {
        !           474:                        lprintf(LOG_DEBUG,"DISCONNECTED line %u", __LINE__);
        !           475:                        connected=FALSE;
        !           476:                        return -1;
        !           477:                }
        !           478:                else {
        !           479:                        inbuf_len=i;
        !           480:                        return i;
        !           481:                }
        !           482:        };
        !           483: }
        !           484: 
1.1       root      485: /****************************************************************************/
                    486: /* Receive a byte from remote (single-threaded version)                                                */
                    487: /****************************************************************************/
1.1.1.2 ! root      488: int recv_byte(void* unused, unsigned timeout /* seconds */)
1.1       root      489: {
                    490:        int                     i;
                    491:        uchar           ch;
                    492:        static uchar    telnet_cmd;
                    493:        static int              telnet_cmdlen;
                    494: 
1.1.1.2 ! root      495:        while((inbuf_len || connected) && !terminate) {
        !           496:                if(inbuf_len) {
        !           497:                        ch=inbuf[inbuf_pos++];
        !           498:                        i=1;
        !           499:                        if(inbuf_pos >= inbuf_len)
        !           500:                                inbuf_pos=inbuf_len=0;
        !           501:                }
        !           502:                else {
        !           503:                        i=recv_buffer(timeout);
        !           504:                        switch(i) {
        !           505:                                case -1:
        !           506:                                        i=0;
        !           507:                                        break;
        !           508:                                case 0:
        !           509:                                        return NOINP;
        !           510:                                default:
        !           511:                                        i=1;
        !           512:                                        continue;
        !           513:                        }
1.1       root      514:                }
                    515: 
                    516:                if(i!=sizeof(ch)) {
                    517:                        if(i==0) {
                    518:                                lprintf(LOG_WARNING,"Socket Disconnected");
                    519:                        } else
                    520:                                lprintf(LOG_ERR,"recv error %d (%d)",i,ERROR_VALUE);
                    521:                        return(NOINP); 
                    522:                }
                    523: 
                    524:                if(telnet) {
                    525:                        if(ch==TELNET_IAC) {
                    526: #if DEBUG_TELNET
                    527:                                lprintf(LOG_DEBUG,"T<%s> ",telnet_cmd_desc(ch));
                    528: #endif
                    529:                                if(telnet_cmdlen==0) {
                    530:                                        telnet_cmdlen=1;
                    531:                                        continue;
                    532:                                }
                    533:                                if(telnet_cmdlen==1) {
                    534:                                        telnet_cmdlen=0;
                    535:                                        if(debug_rx)
                    536:                                                lprintf(LOG_DEBUG,"RX: %s",chr(TELNET_IAC));
                    537:                                        return(TELNET_IAC);
                    538:                                }
                    539:                        }
                    540:                        if(telnet_cmdlen) {
                    541:                                telnet_cmdlen++;
                    542: #if DEBUG_TELNET
                    543:                                if(telnet_cmdlen==2)
                    544:                                        lprintf(LOG_DEBUG,"T<%s> ",telnet_cmd_desc(ch));
                    545:                                else
                    546:                                        lprintf(LOG_DEBUG,"T<%s> ",telnet_opt_desc(ch));
                    547: #endif
                    548:                                if(debug_telnet && telnet_cmdlen==3)
                    549:                                        lprintf(LOG_DEBUG,"Received telnet command: %s %s"
                    550:                                                ,telnet_cmd_desc(telnet_cmd),telnet_opt_desc(ch));
                    551:                                if(telnet_cmdlen==3 && telnet_cmd==TELNET_DO)
                    552:                                        send_telnet_cmd(sock, TELNET_WILL,ch);
                    553:        /*
                    554:                                else if(telnet_cmdlen==3 && telnet_cmd==TELNET_WILL)
                    555:                                        send_telnet_cmd(sock, TELNET_DO,ch);
                    556:        */
                    557:                                telnet_cmd=ch;
                    558:                                if((telnet_cmdlen==2 && ch<TELNET_WILL) || telnet_cmdlen>2) {
                    559:                                        telnet_cmdlen=0;
                    560:                                        /* Code disabled.  Why?  ToDo */
                    561:                                        /* break; */
                    562:                                }
                    563:                                continue;
                    564:                        }
                    565:                }
                    566:                if(debug_rx)
                    567:                        lprintf(LOG_DEBUG,"RX: %s",chr(ch));
                    568:                return(ch);
                    569:        }
                    570: 
                    571:        return(NOINP);
                    572: }
                    573: 
                    574: #if !SINGLE_THREADED
                    575: /*************************/
                    576: /* Send a byte to remote */
                    577: /*************************/
                    578: int send_byte(void* unused, uchar ch, unsigned timeout)
                    579: {
                    580:        uchar           buf[2] = { TELNET_IAC, TELNET_IAC };
                    581:        unsigned        len=1;
                    582:        DWORD           result;
                    583: 
                    584:        if(telnet && ch==TELNET_IAC)    /* escape IAC char */
                    585:                len=2;
                    586:        else
                    587:                buf[0]=ch;
                    588: 
                    589:        if(RingBufFree(&outbuf)<len) {
1.1.1.2 ! root      590: #if !defined(RINGBUF_EVENT)
        !           591:                ResetEvent(outbuf_empty);
        !           592: #endif
1.1       root      593:                fprintf(statfp,"FLOW");
                    594:                flows++;
                    595:                result=WaitForEvent(outbuf_empty,timeout*1000);
                    596:                fprintf(statfp,"\b\b\b\b    \b\b\b\b");
                    597:                if(result!=WAIT_OBJECT_0) {
1.1.1.2 ! root      598:                        lprintf(LOG_WARNING
        !           599:                                ,"!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n"
        !           600:                                ,result, timeout, RingBufFull(&outbuf));
1.1       root      601:                        fprintf(statfp
                    602:                                ,"\n!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n"
                    603:                                ,result, timeout, RingBufFull(&outbuf));
                    604:                        newline=TRUE;
1.1.1.2 ! root      605:                        if((result=RingBufFree(&outbuf))<len) {
        !           606:                                lprintf(LOG_ERR,"Still not enough space in ring buffer (need %d, avail=%d)",len,result);
1.1       root      607:                                return(-1);
1.1.1.2 ! root      608:                        }
        !           609:                }
        !           610:                if((result=RingBufFree(&outbuf))<len) {
        !           611:                        lprintf(LOG_ERR,"Not enough space in ring buffer (need %d, avail=%d) although empty event is set!",len,result);
        !           612:                        return(-1);
1.1       root      613:                }
                    614:        }
                    615: 
1.1.1.2 ! root      616:        if((result=RingBufWrite(&outbuf,buf,len))!=len) {
        !           617:                lprintf(LOG_ERR,"RingBufWrite() returned %d, expected %d",result,len);
        !           618:        }
1.1       root      619: 
                    620: #if 0
                    621:        if(debug_tx)
                    622:                lprintf(LOG_DEBUG,"TX: %s",chr(ch));
                    623: #endif
                    624:        return(0);
                    625: }
                    626: 
                    627: #else
                    628: 
                    629: /*************************/
                    630: /* Send a byte to remote */
                    631: /*************************/
                    632: int send_byte(void* unused, uchar ch, unsigned timeout)
                    633: {
                    634:        uchar           buf[2] = { TELNET_IAC, TELNET_IAC };
                    635:        int                     len=1;
                    636:        int                     i;
                    637: 
                    638:        if(telnet && ch==TELNET_IAC)    /* escape IAC char */
                    639:                len=2;
                    640:        else
                    641:                buf[0]=ch;
                    642: 
1.1.1.2 ! root      643:        i=sendbuf(sock,buf,len);
1.1       root      644:        
                    645:        if(i==len) {
                    646:                if(debug_tx)
                    647:                        lprintf(LOG_DEBUG,"TX: %s",chr(ch));
                    648:                return(0);
                    649:        }
                    650: 
                    651:        return(-1);
                    652: }
                    653: #endif
                    654: 
                    655: static void output_thread(void* arg)
                    656: {
                    657:        char            stats[128];
                    658:     BYTE               buf[MAX_OUTBUF_SIZE];
                    659:        int                     i;
                    660:     ulong              avail;
1.1.1.2 ! root      661:        uint64_t        total_sent=0;
        !           662:        uint64_t        total_pkts=0;
1.1       root      663:        ulong           short_sends=0;
                    664:     ulong              bufbot=0;
                    665:     ulong              buftop=0;
                    666: 
                    667: #if 0 /* def _DEBUG */
                    668:        fprintf(statfp,"output thread started\n");
                    669: #endif
                    670: 
                    671:        while(sock!=INVALID_SOCKET && !terminate) {
                    672: 
                    673:                if(bufbot==buftop)
                    674:                avail=RingBufFull(&outbuf);
                    675:                else
                    676:                avail=buftop-bufbot;
                    677: 
                    678:                if(!avail) {
                    679: #if !defined(RINGBUF_EVENT)
                    680:                        SetEvent(outbuf_empty);
                    681: #endif
                    682:                        sem_wait(&outbuf.sem);
                    683:                        if(outbuf.highwater_mark)
                    684:                                sem_trywait_block(&outbuf.highwater_sem,outbuf_drain_timeout);
                    685:                        continue; 
                    686:                }
                    687: 
                    688:         if(bufbot==buftop) { /* linear buf empty, read from ring buf */
                    689:             if(avail>sizeof(buf)) {
                    690:                 lprintf(LOG_ERR,"Insufficient linear output buffer (%lu > %lu)"
                    691:                                        ,avail, sizeof(buf));
                    692:                 avail=sizeof(buf);
                    693:             }
                    694:             buftop=RingBufRead(&outbuf, buf, avail);
                    695:             bufbot=0;
                    696:         }
1.1.1.2 ! root      697:                i=sendbuf(sock, (char*)buf+bufbot, buftop-bufbot);
1.1       root      698:                if(i==SOCKET_ERROR) {
                    699:                if(ERROR_VALUE == ENOTSOCK)
                    700:                 lprintf(LOG_ERR,"client socket closed on send");
                    701:             else if(ERROR_VALUE==ECONNRESET) 
                    702:                                lprintf(LOG_ERR,"connection reset by peer on send");
                    703:             else if(ERROR_VALUE==ECONNABORTED) 
                    704:                                lprintf(LOG_ERR,"connection aborted by peer on send");
                    705:                        else
                    706:                                lprintf(LOG_ERR,"ERROR %d sending on socket %d"
                    707:                        ,ERROR_VALUE, sock);
                    708:                        break;
                    709:                }
                    710: 
                    711:                if(debug_tx)
                    712:                        dump(buf+bufbot,i);
                    713: 
                    714:                if(i!=(int)(buftop-bufbot)) {
                    715:                        lprintf(LOG_ERR,"Short socket send (%u instead of %u)"
                    716:                                ,i ,buftop-bufbot);
                    717:                        short_sends++;
                    718:                }
                    719:                bufbot+=i;
                    720:                total_sent+=i;
                    721:                total_pkts++;
                    722:     }
                    723: 
                    724:        if(total_sent)
1.1.1.2 ! root      725:                sprintf(stats,"(sent %"PRIu64" bytes in %"PRIu64" blocks, %"PRIu64" average, %lu short, %lu errors)"
1.1       root      726:                        ,total_sent, total_pkts, total_sent/total_pkts, short_sends, select_errors);
                    727:        else
                    728:                stats[0]=0;
                    729: 
                    730:        lprintf(LOG_DEBUG,"output thread terminated\n%s", stats);
                    731: }
                    732: 
1.1.1.2 ! root      733: /* Flush output buffer */
        !           734: void flush(void* unused)
1.1       root      735: {
1.1.1.2 ! root      736: #ifdef __unix__
        !           737:        if(stdio)
        !           738:                fflush(stdout);
        !           739: #endif
1.1       root      740: }
                    741: 
1.1.1.2 ! root      742: BOOL is_connected(void* unused)
1.1       root      743: {
1.1.1.2 ! root      744:        if(inbuf_len > inbuf_pos)
        !           745:                return TRUE;
        !           746:        return connected;
        !           747: }
1.1       root      748: 
1.1.1.2 ! root      749: BOOL data_waiting(void* unused, unsigned timeout /* seconds */)
        !           750: {
        !           751:        if(recv_buffer(timeout) > 0)
        !           752:                return TRUE;
        !           753:        return FALSE;
1.1       root      754: }
                    755: 
                    756: /****************************************************************************/
1.1.1.2 ! root      757: /* Returns the total number of blocks required to send the file                                */
1.1       root      758: /****************************************************************************/
1.1.1.2 ! root      759: uint64_t num_blocks(unsigned block_num, uint64_t offset, uint64_t len, unsigned block_size)
1.1       root      760: {
1.1.1.2 ! root      761:        uint64_t blocks;
        !           762:        uint64_t remain = len - offset;
1.1       root      763: 
1.1.1.2 ! root      764:        blocks=block_num + (remain/block_size);
        !           765:        if(remain%block_size)
1.1       root      766:                blocks++;
                    767:        return(blocks);
                    768: }
                    769: 
                    770: /************************************************/
                    771: /* Dump the current block contents - for debug  */
                    772: /************************************************/
                    773: void dump_block(long block_size)
                    774: {
                    775:        long l;
                    776: 
                    777:        for(l=0;l<block_size;l++)
                    778:                fprintf(statfp,"%02X  ",block[l]);
                    779:        fprintf(statfp,"\n");
                    780: }
                    781: 
1.1.1.2 ! root      782: void xmodem_progress(void* unused, unsigned block_num, int64_t offset, int64_t fsize, time_t start)
1.1       root      783: {
                    784:        unsigned        cps;
1.1.1.2 ! root      785:        uint64_t        total_blocks;
1.1       root      786:        long            l;
                    787:        long            t;
                    788:        time_t          now;
                    789:        static time_t last_progress;
                    790: 
                    791:        now=time(NULL);
                    792:        if(now-last_progress>=progress_interval || offset >= fsize || newline) {
                    793:                t=now-start;
                    794:                if(t<=0)
                    795:                        t=1;
1.1.1.2 ! root      796:                if((cps=(unsigned)(offset/t))==0)
        !           797:                        cps=1;                          /* cps so far */
        !           798:                l=(long)(fsize/cps);    /* total transfer est time */
        !           799:                l-=t;                                   /* now, it's est time left */
1.1       root      800:                if(l<0) l=0;
                    801:                if(mode&SEND) {
1.1.1.2 ! root      802:                        total_blocks=num_blocks(block_num,offset,fsize,xm.block_size);
        !           803:                        fprintf(statfp,"\rBlock (%lu%s): %lu/%"PRId64"  Byte: %"PRId64"  "
1.1       root      804:                                "Time: %lu:%02lu/%lu:%02lu  %u cps  %lu%% "
                    805:                                ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
                    806:                                ,xm.block_size%1024L ? "" : "K"
                    807:                                ,block_num
                    808:                                ,total_blocks
                    809:                                ,offset
                    810:                                ,t/60L
                    811:                                ,t%60L
                    812:                                ,l/60L
                    813:                                ,l%60L
                    814:                                ,cps
1.1.1.2 ! root      815:                                ,fsize?(long)(((float)offset/(float)fsize)*100.0):100
1.1       root      816:                                );
                    817:                } else if(mode&YMODEM) {
1.1.1.2 ! root      818:                        fprintf(statfp,"\rBlock (%lu%s): %lu  Byte: %"PRId64"  "
1.1       root      819:                                "Time: %lu:%02lu/%lu:%02lu  %u cps  %lu%% "
                    820:                                ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
                    821:                                ,xm.block_size%1024L ? "" : "K"
                    822:                                ,block_num
                    823:                                ,offset
                    824:                                ,t/60L
                    825:                                ,t%60L
                    826:                                ,l/60L
                    827:                                ,l%60L
                    828:                                ,cps
1.1.1.2 ! root      829:                                ,fsize?(long)(((float)offset/(float)fsize)*100.0):100
1.1       root      830:                                );
                    831:                } else { /* XModem receive */
1.1.1.2 ! root      832:                        fprintf(statfp,"\rBlock (%lu%s): %lu  Byte: %"PRId64"  "
1.1       root      833:                                "Time: %lu:%02lu  %u cps "
                    834:                                ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
                    835:                                ,xm.block_size%1024L ? "" : "K"
                    836:                                ,block_num
                    837:                                ,offset
                    838:                                ,t/60L
                    839:                                ,t%60L
                    840:                                ,cps
                    841:                                );
                    842:                }
                    843:                newline=FALSE;
                    844:                last_progress=now;
                    845:        }
                    846: }
                    847: 
                    848: /* 
                    849:  * show the progress of the transfer like this:
                    850:  * zmtx: sending file "garbage" 4096 bytes ( 20%)
                    851:  */
1.1.1.2 ! root      852: void zmodem_progress(void* cbdata, int64_t current_pos)
1.1       root      853: {
                    854:        unsigned        cps;
                    855:        long            l;
                    856:        long            t;
                    857:        time_t          now;
                    858:        static time_t last_progress;
                    859: 
                    860:        now=time(NULL);
                    861:        if(now-last_progress>=progress_interval || current_pos >= zm.current_file_size || newline) {
                    862:                t=now-zm.transfer_start_time;
                    863:                if(t<=0)
                    864:                        t=1;
                    865:                if(zm.transfer_start_pos>current_pos)
                    866:                        zm.transfer_start_pos=0;
1.1.1.2 ! root      867:                if((cps=(unsigned)((current_pos-zm.transfer_start_pos)/t))==0)
        !           868:                        cps=1;                                                  /* cps so far */
        !           869:                l=(long)(zm.current_file_size/cps);     /* total transfer est time */
        !           870:                l-=t;                                                           /* now, it's est time left */
1.1       root      871:                if(l<0) l=0;
1.1.1.2 ! root      872:                fprintf(statfp,"\rKByte: %"PRId64"/%"PRId64"  %u/CRC-%u  "
1.1       root      873:                        "Time: %lu:%02lu/%lu:%02lu  %u cps  %lu%% "
                    874:                        ,current_pos/1024
                    875:                        ,zm.current_file_size/1024
                    876:                        ,zm.block_size
                    877:                        ,mode&RECV ? (zm.receive_32bit_data ? 32:16) : 
                    878:                                (zm.can_fcs_32 && !zm.want_fcs_16) ? 32:16
                    879:                        ,t/60L
                    880:                        ,t%60L
                    881:                        ,l/60L
                    882:                        ,l%60L
                    883:                        ,cps
1.1.1.2 ! root      884:                        ,zm.current_file_size?(long)(((float)current_pos/(float)zm.current_file_size)*100.0):100
1.1       root      885:                        );
                    886:                newline=FALSE;
                    887:                last_progress=now;
                    888:        }
                    889: }
                    890: 
                    891: static int send_files(char** fname, uint fnames)
                    892: {
1.1.1.2 ! root      893:        char            path[MAX_PATH+1];
        !           894:        int                     i;
        !           895:        uint            errors;
        !           896:        uint            fnum;
        !           897:        uint            cps;
        !           898:        glob_t          g;
        !           899:        int                     gi;
        !           900:        BOOL            success=TRUE;
        !           901:        uint64_t        fsize;
        !           902:        uint64_t        sent_bytes;
        !           903:        uint64_t        total_bytes=0;
        !           904:        time_t          t,startfile;
        !           905:        time_t          startall;
        !           906:        FILE*           fp;
1.1       root      907: 
                    908:        startall=time(NULL);
                    909: 
                    910:        /****************************************************/
                    911:        /* Search through all to find total files and bytes */
                    912:        /****************************************************/
                    913:        for(fnum=0;fnum<fnames;fnum++) {
                    914:                if(glob(fname[fnum],0,NULL,&g)) {
                    915:                        lprintf(LOG_WARNING,"%s not found",fname[fnum]);
                    916:                        continue;
                    917:                }
                    918:                for(i=0;i<(int)g.gl_pathc;i++) {
                    919:                        if(isdir(g.gl_pathv[i]))
                    920:                                continue;
                    921:                        xm.total_files++;
                    922:                        xm.total_bytes+=flength(g.gl_pathv[i]);
                    923:                } 
                    924:                globfree(&g);
                    925:        }
                    926: 
                    927:        if(xm.total_files<1) {
                    928:                lprintf(LOG_ERR,"No files to send");
                    929:                return(-1);
                    930:        }
                    931:        if(xm.total_files>1)
1.1.1.2 ! root      932:                lprintf(LOG_INFO,"Sending %u files (%"PRId64" KB total)"
1.1       root      933:                        ,xm.total_files,xm.total_bytes/1024);
                    934: 
                    935:        zm.files_remaining = xm.total_files;
                    936:        zm.bytes_remaining = xm.total_bytes;
                    937: 
                    938:        /***********************************************/
                    939:        /* Send every file matching names or filespecs */
                    940:        /***********************************************/
                    941:        for(fnum=0;fnum<fnames;fnum++) {
                    942:                if(glob(fname[fnum],0,NULL,&g)) {
                    943:                        lprintf(LOG_WARNING,"%s not found",fname[fnum]);
                    944:                        continue;
                    945:                }
                    946:                for(gi=0;gi<(int)g.gl_pathc;gi++) {
                    947:                        SAFECOPY(path,g.gl_pathv[gi]);
                    948:                        if(isdir(path))
                    949:                                continue;
                    950: 
                    951:                        if((fp=fnopen(NULL,path,O_RDONLY|O_BINARY))==NULL
                    952:                                && (fp=fopen(path,"rb"))==NULL) {
                    953:                                lprintf(LOG_ERR,"Error %d opening %s for read",errno,path);
                    954:                                continue;
                    955:                        }
                    956:                        setvbuf(fp,NULL,_IOFBF,0x10000);
                    957: 
                    958:                        fsize=filelength(fileno(fp));
                    959: 
                    960:                        errors=0;
                    961:                        startfile=time(NULL);
                    962: 
1.1.1.2 ! root      963:                        lprintf(LOG_INFO,"Sending %s (%"PRId64" KB) via %cMODEM"
1.1       root      964:                                ,path,fsize/1024
1.1.1.2 ! root      965:                                ,mode&XMODEM ? 'X' : mode&YMODEM ? 'Y' : 'Z');
1.1       root      966: 
                    967:                        if(mode&ZMODEM)
1.1.1.2 ! root      968:                                success=zmodem_send_file(&zm, path, fp, /* ZRQINIT? */fnum==0, &startfile, &sent_bytes);
1.1       root      969:                        else    /* X/Ymodem */
1.1.1.2 ! root      970:                                success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes);
1.1       root      971: 
                    972:                        fclose(fp);
                    973: 
                    974:                        if((t=time(NULL)-startfile)<=0) 
                    975:                                t=1;
1.1.1.2 ! root      976:                        if((cps=(unsigned)(sent_bytes/t))==0)
1.1       root      977:                                cps=1;
                    978:                        if(success) {
                    979:                                xm.sent_files++;
                    980:                                xm.sent_bytes+=fsize;
1.1.1.2 ! root      981:                                if(zm.file_skipped)
        !           982:                                        lprintf(LOG_WARNING,"File Skipped");
        !           983:                                else
        !           984:                                        lprintf(LOG_INFO,"Successful - Time: %lu:%02lu  CPS: %lu"
1.1       root      985:                                                ,t/60,t%60,cps);
                    986: 
                    987:                                if(xm.total_files-xm.sent_files)
1.1.1.2 ! root      988:                                        lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu  Files: %u  KBytes: %"PRId64
1.1       root      989:                                                ,((xm.total_bytes-xm.sent_bytes)/cps)/60
                    990:                                                ,((xm.total_bytes-xm.sent_bytes)/cps)%60
                    991:                                                ,xm.total_files-xm.sent_files
                    992:                                                ,(xm.total_bytes-xm.sent_bytes)/1024
                    993:                                                );
                    994:                        } else
1.1.1.2 ! root      995:                                lprintf(LOG_WARNING,"File Transfer %s", zm.local_abort ? "Aborted" : "Failure");
1.1       root      996: 
                    997:                        /* DSZLOG entry */
                    998:                        if(logfp) {
                    999:                                lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog);
1.1.1.2 ! root     1000:                                fprintf(logfp,"%c %7"PRId64" %5u bps %6lu cps %3u errors %5u %4u "
1.1       root     1001:                                        "%s -1\n"
1.1.1.2 ! root     1002:                                        ,(mode&ZMODEM && zm.file_skipped) ? 's' 
        !          1003:                                                : success ? (mode&ZMODEM ? 'z':'S') 
1.1       root     1004:                                                : 'E'
                   1005:                                        ,sent_bytes
                   1006:                                        ,115200 /* baud */
                   1007:                                        ,cps
                   1008:                                        ,mode&ZMODEM ? zm.errors : xm.errors
                   1009:                                        ,flows
                   1010:                                        ,mode&ZMODEM ? zm.block_size : xm.block_size
                   1011:                                        ,dszlog_filename(path)); 
                   1012:                                fflush(logfp);
                   1013:                        }
                   1014:                        total_bytes += sent_bytes;
                   1015: 
1.1.1.2 ! root     1016:                        if(zm.local_abort) {
1.1       root     1017:                                xm.cancelled=FALSE;
                   1018:                                xmodem_cancel(&xm);
                   1019:                                break;
                   1020:                        }
                   1021: 
1.1.1.2 ! root     1022:                        if(xm.cancelled || zm.cancelled || !success)
1.1       root     1023:                                break;
                   1024: 
                   1025:                } /* while(gi<(int)g.gl_pathc) */
                   1026: 
                   1027:                if(gi<(int)g.gl_pathc)/* error occurred */
                   1028:                        break;
                   1029:        }
                   1030: 
1.1.1.2 ! root     1031:        if(mode&ZMODEM && !zm.cancelled && is_connected(NULL) && (success || total_bytes))
1.1       root     1032:                zmodem_get_zfin(&zm);
                   1033: 
                   1034:        if(fnum<fnames) /* error occurred */
                   1035:                return(-1);
                   1036: 
                   1037:        if(!success)
                   1038:                return(-1);
                   1039: 
                   1040:        if(mode&XMODEM)
                   1041:                return(0);
                   1042:        if(mode&YMODEM) {
                   1043: 
                   1044:                if(xmodem_get_mode(&xm)) {
                   1045: 
1.1.1.2 ! root     1046:                        lprintf(LOG_INFO,"Sending YMODEM termination block");
1.1       root     1047: 
1.1.1.2 ! root     1048:                        memset(block,0,XMODEM_MIN_BLOCK_SIZE);  /* send short block for terminator */
        !          1049:                        xmodem_put_block(&xm, block, XMODEM_MIN_BLOCK_SIZE /* block_size */, 0 /* block_num */);
        !          1050:                        if(xmodem_get_ack(&xm, /* tries: */6, /* block_num: */0) != ACK) {
1.1       root     1051:                                lprintf(LOG_WARNING,"Failed to receive ACK after terminating block"); 
                   1052:                        } 
                   1053:                }
                   1054:        }
                   1055:        if(xm.total_files>1) {
                   1056:                t=time(NULL)-startall;
                   1057:                if(!t) t=1;
1.1.1.2 ! root     1058:                lprintf(LOG_INFO,"Overall - Time %02lu:%02lu  KBytes: %"PRId64"  CPS: %lu"
1.1       root     1059:                        ,t/60,t%60,total_bytes/1024,total_bytes/t); 
                   1060:        }
                   1061:        return(0);      /* success */
                   1062: }
                   1063: 
                   1064: static int receive_files(char** fname_list, int fnames)
                   1065: {
                   1066:        char    str[MAX_PATH+1];
                   1067:        char    fname[MAX_PATH+1];
                   1068:        int             i;
                   1069:        int             fnum=0;
                   1070:        uint    errors;
                   1071:        uint    total_files=0;
                   1072:        uint    cps;
                   1073:        uint    wr;
                   1074:        BOOL    success=FALSE;
                   1075:        long    fmode;
                   1076:        long    serial_num=-1;
1.1.1.2 ! root     1077:        int64_t file_bytes=0,file_bytes_left=0;
        !          1078:        int64_t total_bytes=0;
1.1       root     1079:        FILE*   fp;
                   1080:        time_t  t,startfile,ftime;
                   1081: 
                   1082:        if(fnames>1)
                   1083:                lprintf(LOG_INFO,"Receiving %u files",fnames);
                   1084: 
                   1085:        outbuf.highwater_mark=0;        /* don't delay ACK/NAK transmits */
                   1086: 
                   1087:        /* Purge input buffer */
                   1088:        while(is_connected(NULL) && (i=recv_byte(NULL,0))!=NOINP)
                   1089:                lprintf(LOG_WARNING,"Throwing out received: %s",chr((uchar)i));
                   1090: 
                   1091:        while(is_connected(NULL)) {
1.1.1.2 ! root     1092:                file_bytes=0x7fffffff;
1.1       root     1093:                if(mode&XMODEM) {
                   1094:                        SAFECOPY(str,fname_list[0]);    /* we'll have at least one fname */
1.1.1.2 ! root     1095:                        file_bytes_left=file_bytes;
1.1       root     1096:                }
                   1097:                else {
                   1098:                        if(mode&YMODEM) {
1.1.1.2 ! root     1099:                                lprintf(LOG_INFO,"Fetching YMODEM header block");
1.1       root     1100:                                for(errors=0;errors<=xm.max_errors && !xm.cancelled;errors++) {
                   1101:                                        xmodem_put_nak(&xm, /* expected_block: */ 0);
1.1.1.2 ! root     1102:                                        if(xmodem_get_block(&xm, block, /* expected_block: */ 0) == SUCCESS) {
1.1       root     1103:                                                send_byte(NULL,ACK,10);
                   1104:                                                break; 
                   1105:                                        } 
1.1.1.2 ! root     1106:                                        if(errors+1>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) {
        !          1107:                                                lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode");
        !          1108:                                                mode&=~CRC;
        !          1109:                                        }
1.1       root     1110:                                }
1.1.1.2 ! root     1111:                                if(errors>xm.max_errors || xm.cancelled) {
        !          1112:                                        lprintf(LOG_ERR,"Error fetching YMODEM header block");
1.1       root     1113:                                        xmodem_cancel(&xm);
                   1114:                                        return(1); 
                   1115:                                }
                   1116:                                if(!block[0]) {
1.1.1.2 ! root     1117:                                        lprintf(LOG_INFO,"Received YMODEM termination block");
1.1       root     1118:                                        return(0); 
                   1119:                                }
1.1.1.2 ! root     1120:                                ftime=total_files=0;
        !          1121:                                total_bytes=0;
        !          1122:                                i=sscanf(block+strlen(block)+1,"%"PRId64" %lo %lo %lo %u %"PRId64
1.1       root     1123:                                        ,&file_bytes                    /* file size (decimal) */
                   1124:                                        ,&ftime                                 /* file time (octal unix format) */
                   1125:                                        ,&fmode                                 /* file mode (not used) */
                   1126:                                        ,&serial_num                    /* program serial number */
                   1127:                                        ,&total_files                   /* remaining files to be sent */
                   1128:                                        ,&total_bytes                   /* remaining bytes to be sent */
                   1129:                                        );
1.1.1.2 ! root     1130:                                lprintf(LOG_DEBUG,"YMODEM header (%u fields): %s", i, block+strlen(block)+1);
1.1       root     1131:                                SAFECOPY(fname,block);
                   1132: 
                   1133:                        } else {        /* Zmodem */
1.1.1.2 ! root     1134:                                lprintf(LOG_INFO,"Waiting for ZMODEM sender...");
1.1       root     1135: 
                   1136:                                i=zmodem_recv_init(&zm);
                   1137: 
                   1138:                                if(zm.cancelled)
                   1139:                                        return(1);
                   1140:                                if(i<0)
                   1141:                                        return(-1);
                   1142:                                switch(i) {
                   1143:                                        case ZFILE:
                   1144:                                                SAFECOPY(fname,zm.current_file_name);
                   1145:                                                file_bytes = zm.current_file_size;
                   1146:                                                ftime = zm.current_file_time;
                   1147:                                                total_files = zm.files_remaining;
                   1148:                                                total_bytes = zm.bytes_remaining;
                   1149:                                                break;
                   1150:                                        case ZFIN:
                   1151:                                        case ZCOMPL:
                   1152:                                                return(!success);
                   1153:                                        default:
                   1154:                                                return(-1);
                   1155:                                }
                   1156:                        }
                   1157:                        file_bytes_left=file_bytes;
                   1158:                        if(!total_files)
                   1159:                                total_files=fnames-fnum;
                   1160:                        if(!total_files)
                   1161:                                total_files=1;
                   1162:                        if(total_bytes<file_bytes)
                   1163:                                total_bytes=file_bytes;
                   1164: 
                   1165:                        lprintf(LOG_DEBUG,"Incoming filename: %.64s ",fname);
                   1166: 
                   1167:                        if(mode&RECVDIR)
                   1168:                                sprintf(str,"%s%s",fname_list[0],getfname(fname));
                   1169:                        else {
                   1170:                                SAFECOPY(str,getfname(fname));
                   1171:                                for(i=0;i<fnames;i++) {
                   1172:                                        if(!fname_list[i][0])   /* name blank or already used */
                   1173:                                                continue;
                   1174:                                        if(!stricmp(getfname(fname_list[i]),str)) {
                   1175:                                                SAFECOPY(str,fname_list[i]);
                   1176:                                                fname_list[i][0]=0;
                   1177:                                                break; 
                   1178:                                        } 
                   1179:                                }
                   1180:                                if(i==fnames) {                                 /* Not found in list */
                   1181:                                        if(fnames)
                   1182:                                                fprintf(statfp," - Not in receive list!");
                   1183:                                        if(!fnames || fnum>=fnames || !fname_list[fnum][0])
                   1184:                                                SAFECOPY(str,getfname(fname));  /* worst case */
                   1185:                                        else {
                   1186:                                                SAFECOPY(str,fname_list[fnum]);
                   1187:                                                fname_list[fnum][0]=0; 
                   1188:                                        } 
                   1189:                                } 
                   1190:                        }
1.1.1.2 ! root     1191:                        fprintf(statfp,"File size: %"PRId64" bytes\n", file_bytes);
1.1       root     1192:                        if(total_files>1)
1.1.1.2 ! root     1193:                                fprintf(statfp,"Remaining: %"PRId64" bytes in %u files\n", total_bytes, total_files);
1.1       root     1194:                }
                   1195: 
                   1196:                lprintf(LOG_DEBUG,"Receiving: %.64s ",str);
                   1197: 
                   1198:                fnum++;
                   1199: 
                   1200:                if(!(mode&RECVDIR) && fnames && fnum>fnames) {
                   1201:                        lprintf(LOG_WARNING,"Attempt to send more files than specified");
                   1202:                        xmodem_cancel(&xm);
                   1203:                        break; 
                   1204:                }
                   1205: 
                   1206:                if(fexistcase(str) && !(mode&OVERWRITE)) {
                   1207:                        lprintf(LOG_WARNING,"%s already exists",str);
                   1208:                        if(mode&ZMODEM) {
                   1209:                                zmodem_send_zskip(&zm);
                   1210:                                continue;
                   1211:                        }
                   1212:                        xmodem_cancel(&xm);
                   1213:                        return(1); 
                   1214:                }
1.1.1.2 ! root     1215: 
        !          1216:                if(!(mode&XMODEM) && max_file_size!=0 && file_bytes > max_file_size) {
        !          1217:                        lprintf(LOG_WARNING,"%s file size (%"PRId64") exceeds specified maximum: %"PRId64" bytes", str, file_bytes, max_file_size);
        !          1218:                        if(mode&ZMODEM) {
        !          1219:                                zmodem_send_zskip(&zm);
        !          1220:                                continue;
        !          1221:                        }
        !          1222:                        xmodem_cancel(&xm);
        !          1223:                        return(1)        !          1224:                }
        !          1225: 
1.1       root     1226:                if((fp=fnopen(NULL,str,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY))==NULL
                   1227:                        && (fp=fopen(str,"wb"))==NULL) {
                   1228:                        lprintf(LOG_ERR,"Error %d creating %s",errno,str);
                   1229:                        if(mode&ZMODEM) {
                   1230:                                zmodem_send_zskip(&zm);
                   1231:                                continue;
                   1232:                        }
                   1233:                        xmodem_cancel(&xm);
                   1234:                        return(1); 
                   1235:                }
                   1236: 
                   1237:                if(mode&XMODEM)
1.1.1.2 ! root     1238:                        lprintf(LOG_INFO,"Receiving %s via XMODEM%s %s"
1.1       root     1239:                                ,str
1.1.1.2 ! root     1240:                                ,mode&GMODE ? "-G" : ""
1.1       root     1241:                                ,mode&CRC ? "CRC-16":"Checksum");
                   1242:                else
1.1.1.2 ! root     1243:                        lprintf(LOG_INFO,"Receiving %s (%"PRId64" KB) via %s %s"
1.1       root     1244:                                ,str
                   1245:                                ,file_bytes/1024
1.1.1.2 ! root     1246:                                ,mode&YMODEM ? mode&GMODE ? "YMODEM-G" : "YMODEM" :"ZMODEM"
1.1       root     1247:                                ,mode&ZMODEM ? "" : (mode&CRC ? "CRC-16" : "Checksum"));
                   1248: 
                   1249:                startfile=time(NULL);
                   1250:                success=FALSE;
                   1251:                if(mode&ZMODEM) {
                   1252: 
                   1253:                        errors=zmodem_recv_file_data(&zm,fp,0);
                   1254: 
1.1.1.2 ! root     1255:                        if(errors<=zm.max_errors && !zm.cancelled)
        !          1256:                                success=TRUE;
1.1       root     1257: 
                   1258:                } else {
                   1259:                        errors=0;
                   1260:                        block_num=1;
                   1261:                        xmodem_put_nak(&xm, block_num);
                   1262:                        while(is_connected(NULL)) {
1.1.1.2 ! root     1263:                                off_t pos=ftello(fp);
        !          1264:                                if(max_file_size!=0 && pos>=max_file_size) {
        !          1265:                                        lprintf(LOG_WARNING,"Specified maximum file size (%"PRId64" bytes) reached at offset %"PRId64
        !          1266:                                                ,max_file_size, pos);
        !          1267:                                        break;
        !          1268:                                }
        !          1269:                                xmodem_progress(NULL,block_num,pos,file_bytes,startfile);
1.1       root     1270:                                i=xmodem_get_block(&xm, block, block_num);      
                   1271: 
1.1.1.2 ! root     1272:                                if(i!=SUCCESS) {
1.1       root     1273:                                        if(i==EOT)      {               /* end of transfer */
                   1274:                                                success=TRUE;
                   1275:                                                xmodem_put_ack(&xm);
                   1276:                                                break;
                   1277:                                        }
                   1278:                                        if(i==CAN) {            /* Cancel */
                   1279:                                                xm.cancelled=TRUE;
                   1280:                                                break;
                   1281:                                        }
                   1282: 
1.1.1.2 ! root     1283:                                        if(++errors>xm.max_errors || (mode&GMODE)) {
1.1       root     1284:                                                lprintf(LOG_ERR,"Too many errors (%u)",errors);
                   1285:                                                xmodem_cancel(&xm);
                   1286:                                                break;
                   1287:                                        }
1.1.1.2 ! root     1288:                                        if(i!=NOT_XMODEM 
        !          1289:                                                && block_num==1 && errors>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) {
        !          1290:                                                lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode (error=%d)", i);
1.1       root     1291:                                                mode&=~CRC;
1.1.1.2 ! root     1292:                                        }
1.1       root     1293:                                        xmodem_put_nak(&xm, block_num);
                   1294:                                        continue;
                   1295:                                }
                   1296:                                if(!(mode&GMODE))
                   1297:                                        send_byte(NULL,ACK,10);
1.1.1.2 ! root     1298:                                if(file_bytes_left<=0L)  { /* No more bytes to receive */
        !          1299:                                        lprintf(LOG_WARNING,"Sender attempted to send more bytes than were specified in header");
1.1       root     1300:                                        break; 
                   1301:                                }
                   1302:                                wr=xm.block_size;
1.1.1.2 ! root     1303:                                if(wr>(uint)file_bytes_left)
        !          1304:                                        wr=(uint)file_bytes_left;
1.1       root     1305:                                if(fwrite(block,1,wr,fp)!=wr) {
1.1.1.2 ! root     1306:                                        lprintf(LOG_ERR,"ERROR %d writing %u bytes at file offset %"PRIu64
        !          1307:                                                ,errno, wr, (uint64_t)ftello(fp));
1.1       root     1308:                                        xmodem_cancel(&xm);
                   1309:                                        return(1); 
                   1310:                                }
                   1311:                                file_bytes_left-=wr; 
                   1312:                                block_num++;
                   1313:                        }
                   1314:                }
                   1315: 
                   1316:                /* Use correct file size */
1.1.1.2 ! root     1317:                if(mode&ZMODEM)
        !          1318:                        file_bytes = zm.current_file_size;      /* file can grow in transit */
        !          1319:                else {
        !          1320:                        fflush(fp);
        !          1321:                        if(file_bytes < filelength(fileno(fp))) {
        !          1322:                                lprintf(LOG_INFO,"Truncating file to %"PRIu64" bytes", file_bytes);
        !          1323:                                chsize(fileno(fp),(ulong)file_bytes);   /* <--- 4GB limit */
        !          1324:                        } else
        !          1325:                                file_bytes = filelength(fileno(fp));
        !          1326:                }
1.1       root     1327:                fclose(fp);
1.1.1.2 ! root     1328: 
1.1       root     1329:                t=time(NULL)-startfile;
                   1330:                if(!t) t=1;
1.1.1.2 ! root     1331:                if(zm.file_skipped)
        !          1332:                        lprintf(LOG_WARNING,"File Skipped");
        !          1333:                else if(success)
1.1       root     1334:                        lprintf(LOG_INFO,"Successful - Time: %lu:%02lu  CPS: %lu"
1.1.1.2 ! root     1335:                                ,t/60,t%60,(ulong)(file_bytes/t));
1.1       root     1336:                else
1.1.1.2 ! root     1337:                        lprintf(LOG_ERR,"File Transfer %s"
        !          1338:                                ,zm.local_abort ? "Aborted": zm.cancelled ? "Cancelled":"Failure");
1.1       root     1339: 
                   1340:                if(!(mode&XMODEM) && ftime)
                   1341:                        setfdate(str,ftime); 
                   1342: 
                   1343:                if(logfp) {
                   1344:                        lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog);
                   1345:                        fprintf(logfp,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u "
                   1346:                                "%s %d\n"
                   1347:                                ,success ? (mode&ZMODEM ? 'Z' : 'R') : 'E'
                   1348:                                ,file_bytes
                   1349:                                ,115200 /* baud */
                   1350:                                ,file_bytes/t
                   1351:                                ,errors
                   1352:                                ,flows
                   1353:                                ,mode&ZMODEM ? zm.block_size : xm.block_size
                   1354:                                ,dszlog_filename(str)
                   1355:                                ,serial_num); 
                   1356:                        fflush(logfp);
                   1357:                }
                   1358: 
1.1.1.2 ! root     1359:                if(zm.local_abort) {
1.1       root     1360:                        lprintf(LOG_DEBUG,"Locally aborted, sending cancel to remote");
                   1361:                        if(mode&ZMODEM)
1.1.1.2 ! root     1362:                                zmodem_send_zabort(&zm);
1.1       root     1363:                        xm.cancelled=FALSE;
                   1364:                        xmodem_cancel(&xm);
                   1365:                        break;
                   1366:                }
                   1367: 
                   1368:                if(mode&XMODEM) /* maximum of one file */
                   1369:                        break;
1.1.1.2 ! root     1370:                if((cps=(unsigned)(file_bytes/t))==0)
1.1       root     1371:                        cps=1;
                   1372:                total_files--;
                   1373:                total_bytes-=file_bytes;
                   1374:                if(total_files>1 && total_bytes)
1.1.1.2 ! root     1375:                        lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu  Files: %u  KBytes: %"PRIu64
1.1       root     1376:                                ,(total_bytes/cps)/60
                   1377:                                ,(total_bytes/cps)%60
                   1378:                                ,total_files
                   1379:                                ,total_bytes/1024
                   1380:                                );
                   1381:        }
                   1382:        return(!success);       /* 0=success */
                   1383: }
                   1384: 
                   1385: void bail(int code)
                   1386: {
                   1387:        if(logfp!=NULL)
                   1388:                fclose(logfp);
                   1389:        if(pause_on_exit || (pause_on_abend && code!=0)) {
                   1390:                printf("Hit enter to continue...");
                   1391:                getchar();
                   1392:        }
                   1393:        exit(code);
                   1394: }
                   1395: 
                   1396: static const char* usage=
                   1397:        "usage: sexyz <socket> [-opts] <cmd> [file | path | @list]\n"
                   1398:        "\n"
                   1399: #ifdef __unix__
                   1400:        "socket = TCP socket descriptor (leave blank for stdio mode)\n"
                   1401: #else
                   1402:        "socket = TCP socket descriptor\n"
                   1403: #endif
                   1404:        "\n"
1.1.1.2 ! root     1405:        "opts   = -y  allow overwriting of existing files when receiving\n"
1.1       root     1406:        "         -o  disable Zmodem CRC-32 mode (use CRC-16)\n"
                   1407:        "         -s  disable Zmodem streaming (Slow Zmodem)\n"
1.1.1.2 ! root     1408:        "         -k  enable X/Ymodem-1K send mode\n"
        !          1409:     "         -c  enable Xmodem-CRC receive mode\n"
        !          1410:        "         -g  enable X/Ymodem-G receive mode (no error recovery)\n"
1.1       root     1411:        "         -2  set maximum Zmodem block size to 2K\n"
                   1412:        "         -4  set maximum Zmodem block size to 4K\n"
                   1413:        "         -8  set maximum Zmodem block size to 8K (ZedZap)\n"
1.1.1.2 ! root     1414:        "         -m# set maximum receive file size to # bytes (0=unlimited, default=%u)\n"
1.1       root     1415:        "         -!  to pause after abnormal exit (error)\n"
1.1.1.2 ! root     1416: #ifdef __unix__
        !          1417:        "         -telnet to enable Telnet mode (the default except in stdio mode)\n"
        !          1418: #else
1.1       root     1419:        "         -telnet to enable Telnet mode (the default)\n"
1.1.1.2 ! root     1420: #endif
1.1       root     1421:        "         -rlogin or -ssh or -raw to disable Telnet mode\n"
                   1422:        "\n"
                   1423:        "cmd    = v  to display detailed version information\n"
1.1.1.2 ! root     1424:        "         sx to send Xmodem     rx to receive Xmodem\n"
        !          1425:        "         sX to send Xmodem-1K  rc to receive Xmodem-CRC\n"
        !          1426:        "         sy to send Ymodem     ry to receive Ymodem\n"
        !          1427:        "         sY to send Ymodem-1K  rg to receive Ymodem-G\n"
        !          1428:        "         sz to send Zmodem     rz to receive Zmodem\n"
1.1       root     1429:        "\n"
                   1430:        "file   = filename to send or receive\n"
                   1431:        "path   = directory to receive files into\n"
                   1432:        "list   = name of text file with list of filenames to send or receive\n";
                   1433: 
1.1.1.2 ! root     1434: #ifdef __unix__
        !          1435: 
        !          1436: struct termios tio_default;                            /* Initial term settings */
        !          1437: 
        !          1438: #ifdef NEEDS_CFMAKERAW
        !          1439: static void
        !          1440: cfmakeraw(struct termios *t)
        !          1441: {
        !          1442:        t->c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
        !          1443:        t->c_oflag &= ~OPOST;
        !          1444:        t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
        !          1445:        t->c_cflag &= ~(CSIZE|PARENB);
        !          1446:        t->c_cflag |= CS8;
        !          1447: }
        !          1448: #endif
        !          1449: 
        !          1450: static void fixterm(void)
        !          1451: {
        !          1452:        tcsetattr(STDIN_FILENO,TCSANOW,&tio_default);
        !          1453: }
        !          1454: 
        !          1455: static void init_stdio(void)
        !          1456: {
        !          1457:        struct termios tio_raw;
        !          1458: 
        !          1459:        if(isatty(STDERR_FILENO))
        !          1460:                fclose(stderr);
        !          1461: 
        !          1462:        if (isatty(STDIN_FILENO))  {
        !          1463:                tcgetattr(STDIN_FILENO,&tio_default);
        !          1464:                tio_raw = tio_default;
        !          1465:                /* cfmakeraw(&tio_raw); */
        !          1466:                tio_raw.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
        !          1467:                tio_raw.c_oflag &= ~OPOST;
        !          1468:                tio_raw.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
        !          1469:                tio_raw.c_cflag &= ~(CSIZE|PARENB);
        !          1470:                tio_raw.c_cflag |= CS8;
        !          1471:                tcsetattr(STDIN_FILENO,TCSANOW,&tio_raw);
        !          1472:                setvbuf(stdout, NULL, _IOFBF, 0);
        !          1473:                atexit(fixterm);
        !          1474:        }
        !          1475: }
        !          1476: 
        !          1477: BOOL   RingBufIsEmpty(void *buf)
        !          1478: {
        !          1479:        return(RingBufFull(buf)==0);
        !          1480: }
        !          1481: 
        !          1482: #endif
        !          1483: 
1.1       root     1484: /***************/
                   1485: /* Entry Point */
                   1486: /***************/
                   1487: int main(int argc, char **argv)
                   1488: {
                   1489:        char    str[MAX_PATH+1];
                   1490:        char    fname[MAX_PATH+1];
                   1491:        char    ini_fname[MAX_PATH+1];
                   1492:        char*   p;
                   1493:        char*   arg;
                   1494:        int     i;
                   1495:        int             retval;
                   1496:        uint    fnames=0;
                   1497:        FILE*   fp;
                   1498:        BOOL    tcp_nodelay;
                   1499:        char    compiler[32];
1.1.1.2 ! root     1500:        BOOL    telnet_requested=FALSE;
1.1       root     1501:        str_list_t fname_list;
                   1502: 
                   1503:        fname_list=strListInit();
                   1504: 
                   1505:        DESCRIBE_COMPILER(compiler);
                   1506: 
                   1507:        errfp=stderr;
                   1508: #ifdef __unix__
                   1509:        statfp=stderr;
                   1510: #else
                   1511:        statfp=stdout;
                   1512: #endif
                   1513: 
1.1.1.2 ! root     1514:        sscanf("$Revision: 1.132 $", "%*s %s", revision);
1.1       root     1515: 
1.1.1.2 ! root     1516:        fprintf(statfp,"\nSynchronet External X/Y/ZMODEM  v%s-%s"
1.1       root     1517:                "  Copyright %s Rob Swindell\n\n"
                   1518:                ,revision
                   1519:                ,PLATFORM_DESC
                   1520:                ,__DATE__+7
                   1521:                );
                   1522: 
1.1.1.2 ! root     1523:        xmodem_init(&xm,NULL,&mode,lputs,xmodem_progress,send_byte,recv_byte,is_connected,NULL,flush);
        !          1524:        zmodem_init(&zm,NULL,lputs,zmodem_progress,send_byte,recv_byte,is_connected,NULL,data_waiting,flush);
        !          1525:        xm.log_level=&log_level;
        !          1526:        zm.log_level=&log_level;
1.1       root     1527: 
                   1528:        /* Generate path/sexyz[.host].ini from path/sexyz[.exe] */
                   1529:        SAFECOPY(str,argv[0]);
                   1530:        p=getfname(str);
                   1531:        SAFECOPY(fname,p);
                   1532:        *p=0;
                   1533:        if((p=getfext(fname))!=NULL) 
                   1534:                *p=0;
                   1535:        strcat(fname,".ini");
                   1536:        
                   1537:        iniFileName(ini_fname,sizeof(ini_fname),str,fname);
                   1538:        if((fp=fopen(ini_fname,"r"))!=NULL)
                   1539:                fprintf(statfp,"Reading %s\n",ini_fname);
                   1540: 
                   1541:        tcp_nodelay                             =iniReadBool(fp,ROOT_SECTION,"TCP_NODELAY",TRUE);
                   1542: 
                   1543:        telnet                                  =iniReadBool(fp,ROOT_SECTION,"Telnet",TRUE);
                   1544:        debug_tx                                =iniReadBool(fp,ROOT_SECTION,"DebugTx",FALSE);
                   1545:        debug_rx                                =iniReadBool(fp,ROOT_SECTION,"DebugRx",FALSE);
                   1546:        debug_telnet                    =iniReadBool(fp,ROOT_SECTION,"DebugTelnet",FALSE);
                   1547: 
                   1548:        pause_on_exit                   =iniReadBool(fp,ROOT_SECTION,"PauseOnExit",FALSE);
                   1549:        pause_on_abend                  =iniReadBool(fp,ROOT_SECTION,"PauseOnAbend",FALSE);
                   1550: 
                   1551:        log_level                               =iniReadLogLevel(fp,ROOT_SECTION,"LogLevel",log_level);
1.1.1.2 ! root     1552:        use_syslog                              =iniReadBool(fp,ROOT_SECTION,"SysLog",use_syslog);
1.1       root     1553: 
1.1.1.2 ! root     1554:        outbuf.highwater_mark   =(ulong)iniReadBytes(fp,ROOT_SECTION,"OutbufHighwaterMark",1,1100);
1.1       root     1555:        outbuf_drain_timeout    =iniReadInteger(fp,ROOT_SECTION,"OutbufDrainTimeout",10);
1.1.1.2 ! root     1556:        outbuf_size                             =(ulong)iniReadBytes(fp,ROOT_SECTION,"OutbufSize",1,16*1024);
1.1       root     1557: 
                   1558:        progress_interval               =iniReadInteger(fp,ROOT_SECTION,"ProgressInterval",1);
1.1.1.2 ! root     1559:        max_file_size                   =iniReadBytes(fp,ROOT_SECTION,"MaxFileSize",/* unit: */1,MAX_FILE_SIZE);
1.1       root     1560: 
                   1561:        if(iniReadBool(fp,ROOT_SECTION,"Debug",FALSE))
                   1562:                log_level=LOG_DEBUG;
                   1563: 
                   1564:        xm.send_timeout                 =iniReadInteger(fp,"Xmodem","SendTimeout",xm.send_timeout);     /* seconds */
                   1565:        xm.recv_timeout                 =iniReadInteger(fp,"Xmodem","RecvTimeout",xm.recv_timeout);     /* seconds */
                   1566:        xm.byte_timeout                 =iniReadInteger(fp,"Xmodem","ByteTimeout",xm.byte_timeout);     /* seconds */
                   1567:        xm.ack_timeout                  =iniReadInteger(fp,"Xmodem","AckTimeout",xm.ack_timeout);       /* seconds */
1.1.1.2 ! root     1568:        xm.block_size                   =(ulong)iniReadBytes(fp,"Xmodem","BlockSize",1,xm.block_size);                  /* 128 or 1024 */
        !          1569:        xm.max_block_size               =(ulong)iniReadBytes(fp,"Xmodem","MaxBlockSize",1,xm.max_block_size);   /* 128 or 1024 */
1.1       root     1570:        xm.max_errors                   =iniReadInteger(fp,"Xmodem","MaxErrors",xm.max_errors);
                   1571:        xm.g_delay                              =iniReadInteger(fp,"Xmodem","G_Delay",xm.g_delay);
1.1.1.2 ! root     1572:        xm.crc_mode_supported   =iniReadBool(fp,"Xmodem","SendCRC",xm.crc_mode_supported);
        !          1573:        xm.g_mode_supported             =iniReadBool(fp,"Xmodem","SendG",xm.g_mode_supported);
        !          1574: 
        !          1575:        xm.fallback_to_xmodem   =iniReadInteger(fp,"Ymodem","FallbackToXmodem", xm.fallback_to_xmodem);
1.1       root     1576: 
                   1577:        zm.init_timeout                 =iniReadInteger(fp,"Zmodem","InitTimeout",zm.init_timeout);     /* seconds */
                   1578:        zm.send_timeout                 =iniReadInteger(fp,"Zmodem","SendTimeout",zm.send_timeout);     /* seconds */
                   1579:        zm.recv_timeout                 =iniReadInteger(fp,"Zmodem","RecvTimeout",zm.recv_timeout);     /* seconds */
                   1580:        zm.crc_timeout                  =iniReadInteger(fp,"Zmodem","CrcTimeout",zm.crc_timeout);       /* seconds */
1.1.1.2 ! root     1581:        zm.block_size                   =(ulong)iniReadBytes(fp,"Zmodem","BlockSize",1,zm.block_size);  /* 1024  */
        !          1582:        zm.max_block_size               =(ulong)iniReadBytes(fp,"Zmodem","MaxBlockSize",1,zm.max_block_size); /* 1024 or 8192 */
1.1       root     1583:        zm.max_errors                   =iniReadInteger(fp,"Zmodem","MaxErrors",zm.max_errors);
1.1.1.2 ! root     1584:        zm.recv_bufsize                 =(ulong)iniReadBytes(fp,"Zmodem","RecvBufSize",1,0);
1.1       root     1585:        zm.no_streaming                 =!iniReadBool(fp,"Zmodem","Streaming",TRUE);
                   1586:        zm.want_fcs_16                  =!iniReadBool(fp,"Zmodem","CRC32",TRUE);
                   1587:        zm.escape_telnet_iac    =iniReadBool(fp,"Zmodem","EscapeTelnetIAC",TRUE);
                   1588:        zm.escape_8th_bit               =iniReadBool(fp,"Zmodem","Escape8thBit",FALSE);
                   1589:        zm.escape_ctrl_chars    =iniReadBool(fp,"Zmodem","EscapeCtrlChars",FALSE);
                   1590: 
                   1591:        dszlog_path                             =iniReadBool(fp,"DSZLOG","Path",TRUE);
                   1592:        dszlog_short                    =iniReadBool(fp,"DSZLOG","Short",FALSE);
                   1593:        dszlog_quotes                   =iniReadBool(fp,"DSZLOG","Quotes",FALSE);
                   1594: 
                   1595:        if(fp!=NULL)
                   1596:                fclose(fp);
                   1597: 
                   1598:        if(zm.recv_bufsize > 0xffff)
                   1599:                zm.recv_bufsize = 0xffff;
                   1600: 
                   1601:        if(outbuf_size < MIN_OUTBUF_SIZE)
                   1602:                outbuf_size = MIN_OUTBUF_SIZE;
                   1603:        else if(outbuf_size > MAX_OUTBUF_SIZE)
                   1604:                outbuf_size = MAX_OUTBUF_SIZE;
                   1605:        
                   1606:        fprintf(statfp,"Output buffer size: %u\n", outbuf_size);
                   1607:        RingBufInit(&outbuf, outbuf_size);
                   1608: 
                   1609: #if !defined(RINGBUF_EVENT)
                   1610:        outbuf_empty=CreateEvent(NULL,/* ManualReset */TRUE, /*InitialState */TRUE,NULL);
1.1.1.2 ! root     1611: #ifdef __unix__
        !          1612:        outbuf_empty->cbdata=&outbuf;
        !          1613:        outbuf_empty->verify=RingBufIsEmpty;
        !          1614: #endif
1.1       root     1615: #endif
                   1616: 
                   1617: #if 0
                   1618:        if(argc>1) {
                   1619:                fprintf(statfp,"Command line: ");
                   1620:                for(i=1;i<argc;i++)
                   1621:                        fprintf(statfp,"%s ",argv[i]);
                   1622:                fprintf(statfp,"\n",statfp);
                   1623:        }
                   1624: #endif
                   1625: 
                   1626: 
                   1627:        for(i=1;i<argc;i++) {
                   1628: 
                   1629:                if(sock==INVALID_SOCKET && isdigit(argv[i][0])) {
                   1630:                        sock=atoi(argv[i]);
                   1631:                        continue;
                   1632:                }
                   1633: 
                   1634:                if(!(mode&(SEND|RECV))) {
                   1635:                        if(toupper(argv[i][0])=='S' || toupper(argv[i][0])=='R') { /* cmd */
                   1636:                                if(toupper(argv[i][0])=='R')
                   1637:                                        mode|=RECV;
                   1638:                                else
                   1639:                                        mode|=SEND;
                   1640: 
                   1641:                                switch(argv[i][1]) {
                   1642:                                        case 'c':
                   1643:                                        case 'C':
                   1644:                                                mode|=XMODEM|CRC;
                   1645:                                                break;
                   1646:                                        case 'x':
1.1.1.2 ! root     1647:                                                xm.block_size=XMODEM_MIN_BLOCK_SIZE;
1.1       root     1648:                                        case 'X':
                   1649:                                                mode|=XMODEM;
                   1650:                                                break;
                   1651:                                        case 'b':       /* sz/rz compatible */
                   1652:                                        case 'B':
                   1653:                                        case 'y':
1.1.1.2 ! root     1654:                                                xm.block_size=XMODEM_MIN_BLOCK_SIZE;
1.1       root     1655:                                        case 'Y':
                   1656:                                                mode|=(YMODEM|CRC);
                   1657:                                                break;
1.1.1.2 ! root     1658:                                        case 'k':       /* Ymodem-Checksum for debug/test purposes only */
        !          1659:                                                mode|=YMODEM;
        !          1660:                                                break;
1.1       root     1661:                                        case 'g':
                   1662:                                        case 'G':
                   1663:                                                mode|=(YMODEM|CRC|GMODE);
                   1664:                                                break;
                   1665:                                        case 'z':
                   1666:                                        case 'Z':
                   1667:                                                mode|=(ZMODEM|CRC);
                   1668:                                                break;
                   1669:                                        default:
                   1670:                                                fprintf(statfp,"Unrecognized command '%s'\n\n",argv[i]);
1.1.1.2 ! root     1671:                                                fprintf(statfp,usage,MAX_FILE_SIZE);
1.1       root     1672:                                                bail(1)1.1.1.2 ! root     1673:                                                return -1;
1.1       root     1674:                                } 
                   1675:                                continue;
                   1676:                        }
                   1677: 
                   1678:                        if(toupper(argv[i][0])=='V') {
                   1679: 
                   1680:                                fprintf(statfp,"%-8s %s\n",getfname(__FILE__)           ,revision);
                   1681:                                fprintf(statfp,"%-8s %s\n",getfname(xmodem_source()),xmodem_ver(str));
                   1682:                                fprintf(statfp,"%-8s %s\n",getfname(zmodem_source()),zmodem_ver(str));
                   1683: #ifdef _DEBUG
                   1684:                                fprintf(statfp,"Debug\n");
                   1685: #endif
                   1686:                                fprintf(statfp,"Compiled %s %.5s with %s\n",__DATE__,__TIME__,compiler);
                   1687:                                fprintf(statfp,"%s\n",os_version(str));
                   1688:                                bail(0);
1.1.1.2 ! root     1689:                                return 0;
1.1       root     1690:                        }
                   1691: 
                   1692:                        arg=argv[i];
                   1693:                        if(*arg=='-') {
                   1694:                                while(*arg=='-')
                   1695:                                        arg++;
                   1696:                                if(stricmp(arg,"telnet")==0) {
1.1.1.2 ! root     1697:                                        telnet_requested=TRUE;
1.1       root     1698:                                        telnet=TRUE;
                   1699:                                        continue;
                   1700:                                }
                   1701:                                if(stricmp(arg,"rlogin")==0 || stricmp(arg,"ssh")==0 || stricmp(arg,"raw")==0) {
1.1.1.2 ! root     1702:                                        telnet_requested=FALSE;
1.1       root     1703:                                        telnet=FALSE;
                   1704:                                        continue;
                   1705:                                }
                   1706:                                if(stricmp(arg,"debug")==0) {
                   1707:                                        log_level=LOG_DEBUG;
                   1708:                                        continue;
                   1709:                                }
1.1.1.2 ! root     1710:                                if(stricmp(arg,"syslog")==0) {
        !          1711:                                        use_syslog=TRUE;
        !          1712:                                        continue;
        !          1713:                                }
1.1       root     1714:                                if(stricmp(arg,"quotes")==0) {
                   1715:                                        dszlog_quotes=TRUE;
                   1716:                                        continue;
                   1717:                                }
                   1718:                                switch(toupper(*arg)) {
                   1719:                                        case 'K':       /* sz/rz compatible */
1.1.1.2 ! root     1720:                                                xm.block_size=XMODEM_MAX_BLOCK_SIZE;
1.1       root     1721:                                                break;
                   1722:                                        case 'C':       /* sz/rz compatible */
                   1723:                                                mode|=CRC;
                   1724:                                                break;
                   1725:                                        case '2':
                   1726:                                                zm.max_block_size=2048;
                   1727:                                                break;
                   1728:                                        case '4':
                   1729:                                                zm.max_block_size=4096;
                   1730:                                                break;
                   1731:                                        case '8':       /* ZedZap */
                   1732:                                                zm.max_block_size=8192;
                   1733:                                                break;
                   1734:                                        case 'O':       /* disable Zmodem CRC-32 */
                   1735:                                                zm.want_fcs_16=TRUE;
                   1736:                                                break;
                   1737:                                        case 'S':       /* disable Zmodem streaming */
                   1738:                                                zm.no_streaming=TRUE;
                   1739:                                                break;
1.1.1.2 ! root     1740:                                        case 'G':       /* Ymodem-G or Xmodem-G (a.k.a. Qmodem-G) */
        !          1741:                                                mode|=(GMODE|CRC);
1.1       root     1742:                                                break;
                   1743:                                        case 'Y':
                   1744:                                                mode|=OVERWRITE;
                   1745:                                                break;
                   1746:                                        case '!':
                   1747:                                                pause_on_abend=TRUE;
                   1748:                                                break;
1.1.1.2 ! root     1749:                                        case 'M':       /* MaxFileSize */
        !          1750:                                                max_file_size=strtoul(arg++,NULL,0);    /* TODO: use strtoull() ? */
        !          1751:                                                break;
1.1       root     1752:                                }
                   1753:                        }
                   1754:                }
                   1755: 
                   1756:                else if((argv[i][0]=='+' || argv[i][0]=='@') && fexist(argv[i]+1)) {
                   1757:                        if(mode&RECVDIR) {
                   1758:                                fprintf(statfp,"!Cannot specify both directory and filename\n");
                   1759:                                bail(1)1.1.1.2 ! root     1760:                                return -1;
1.1       root     1761:                        }
                   1762:                        sprintf(str,"%s",argv[i]+1);
                   1763:                        if((fp=fopen(str,"r"))==NULL) {
                   1764:                                fprintf(statfp,"!Error %d opening filelist: %s\n",errno,str);
                   1765:                                bail(1)1.1.1.2 ! root     1766:                                return -1;
1.1       root     1767:                        }
                   1768:                        while(!feof(fp) && !ferror(fp)) {
                   1769:                                if(!fgets(str,sizeof(str),fp))
                   1770:                                        break;
                   1771:                                truncsp(str);
                   1772:                                strListAppend(&fname_list,strdup(str),fnames++);
                   1773:                        }
                   1774:                        fclose(fp); 
                   1775:                }
                   1776: 
                   1777:                else if(mode&(SEND|RECV)){
                   1778:                        if(isdir(argv[i])) { /* is a directory */
                   1779:                                if(mode&RECVDIR) {
                   1780:                                        fprintf(statfp,"!Only one directory can be specified\n");
                   1781:                                        bail(1)1.1.1.2 ! root     1782:                                        return -1;
1.1       root     1783:                                }
                   1784:                                if(fnames) {
                   1785:                                        fprintf(statfp,"!Cannot specify both directory and filename\n");
                   1786:                                        bail(1)1.1.1.2 ! root     1787:                                        return -1;
1.1       root     1788:                                }
                   1789:                                if(mode&SEND) {
                   1790:                                        fprintf(statfp,"!Cannot send directory '%s'\n",argv[i]);
                   1791:                                        bail(1);
1.1.1.2 ! root     1792:                                        return -1;
1.1       root     1793:                                }
                   1794:                                mode|=RECVDIR; 
                   1795:                        }
                   1796:                        strListAppend(&fname_list,argv[i],fnames++);
                   1797:                } 
                   1798:        }
                   1799: 
1.1.1.2 ! root     1800:        if(max_file_size)
        !          1801:                fprintf(statfp,"Maximum receive file size: %"PRIi64"\n", max_file_size);
        !          1802: 
        !          1803:        if(!(mode&(SEND|RECV))) {
        !          1804:                fprintf(statfp,"!No command specified\n\n");
        !          1805:                fprintf(statfp,usage,MAX_FILE_SIZE);
        !          1806:                bail(1)        !          1807:                return -1;
        !          1808:        }
        !          1809: 
        !          1810:        if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */
        !          1811:                fprintf(statfp,"!Must specify filename or filelist\n\n");
        !          1812:                fprintf(statfp,usage,MAX_FILE_SIZE);
        !          1813:                bail(1)        !          1814:                return -1;
        !          1815:        }
1.1       root     1816: 
                   1817:        if(sock==INVALID_SOCKET || sock<1) {
                   1818: #ifdef __unix__
                   1819:                if(STDOUT_FILENO > STDIN_FILENO)
                   1820:                        sock=STDOUT_FILENO;
                   1821:                else
                   1822:                        sock=STDIN_FILENO;
                   1823:                stdio=TRUE;
1.1.1.2 ! root     1824: 
1.1       root     1825:                fprintf(statfp,"No socket descriptor specified, using STDIO\n");
1.1.1.2 ! root     1826:                if(!telnet_requested)
        !          1827:                        telnet=FALSE;
        !          1828:                init_stdio();
1.1       root     1829: #else
                   1830:                fprintf(statfp,"!No socket descriptor specified\n\n");
1.1.1.2 ! root     1831:                fprintf(errfp,usage,MAX_FILE_SIZE);
1.1       root     1832:                bail(1);
1.1.1.2 ! root     1833:                return -1;
1.1       root     1834: #endif
                   1835:        }
                   1836: #ifdef __unix__
                   1837:        else
                   1838:                statfp=stdout;
                   1839: #endif
                   1840: 
1.1.1.2 ! root     1841:        if(!telnet)
        !          1842:                zm.escape_telnet_iac = FALSE;
1.1       root     1843: 
1.1.1.2 ! root     1844:        zm.max_file_size = max_file_size;
1.1       root     1845: 
                   1846:        /* Code disabled.  Why?  ToDo */
                   1847: /*     if(mode&RECVDIR)
                   1848:                backslash(fname[0]); */
                   1849: 
                   1850:        if(!winsock_startup())
                   1851:                bail(-1);
                   1852: 
                   1853:        /* Enable the Nagle Algorithm */
                   1854: #ifdef __unix__
                   1855:        if(!stdio) {
                   1856: #endif
                   1857:                lprintf(LOG_DEBUG,"Setting TCP_NODELAY to %d",tcp_nodelay);
                   1858:                setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char*)&tcp_nodelay,sizeof(tcp_nodelay));
                   1859: #ifdef __unix__
                   1860:        }
                   1861: #endif
                   1862: 
1.1.1.2 ! root     1863:        /* Set non-blocking mode */
        !          1864: #ifdef __unix__
        !          1865:        if(stdio) {
        !          1866:                fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
        !          1867:        }
        !          1868:        else
        !          1869: #endif
        !          1870:        {
        !          1871:                i=1;
        !          1872:                ioctlsocket(sock, FIONBIO, &i);
        !          1873:        }
        !          1874: 
1.1       root     1875:        if(!socket_check(sock, NULL, NULL, 0)) {
                   1876:                lprintf(LOG_WARNING,"No socket connection");
                   1877:                bail(-1); 
1.1.1.2 ! root     1878:                return -1;
1.1       root     1879:        }
                   1880: 
                   1881:        if((dszlog=getenv("DSZLOG"))!=NULL) {
                   1882:                if((logfp=fopen(dszlog,"w"))==NULL) {
                   1883:                        lprintf(LOG_WARNING,"Error %d opening DSZLOG file: %s",errno,dszlog);
                   1884:                        bail(-1); 
1.1.1.2 ! root     1885:                        return -1;
1.1       root     1886:                }
                   1887:        }
                   1888: 
                   1889:        /* Install Ctrl-C/Break signal handler here */
                   1890: #if defined(_WIN32)
                   1891:        SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */);
                   1892: #elif defined(__unix__)
                   1893:        signal(SIGQUIT,break_handler);
                   1894:        signal(SIGINT,break_handler);
                   1895:        signal(SIGTERM,break_handler);
                   1896: 
                   1897:        signal(SIGHUP,SIG_IGN);
                   1898: 
                   1899:        /* Don't die on SIGPIPE  */
                   1900:        signal(SIGPIPE,SIG_IGN);
                   1901: #endif
                   1902: 
                   1903: #if !SINGLE_THREADED
                   1904:        _beginthread(output_thread,0,NULL);
                   1905: #endif
                   1906: 
                   1907:        if(mode&RECV)
                   1908:                retval=receive_files(fname_list, fnames);
                   1909:        else
                   1910:                retval=send_files(fname_list, fnames);
                   1911: 
                   1912: #if !SINGLE_THREADED
                   1913:        lprintf(LOG_DEBUG,"Waiting for output buffer to empty... ");
1.1.1.2 ! root     1914:        if(RingBufFull(&outbuf)) {
        !          1915: #if !defined(RINGBUF_EVENT)
        !          1916:                ResetEvent(outbuf_empty);
        !          1917: #endif
        !          1918:                if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0)
        !          1919:                        lprintf(LOG_DEBUG,"FAILURE");
        !          1920:        }
1.1       root     1921: #endif
                   1922: 
                   1923:        terminate=TRUE; /* stop output thread */
                   1924:        /* Code disabled.  Why?  ToDo */
                   1925: /*     sem_post(outbuf.sem);
                   1926:        sem_post(outbuf.highwater_sem); */
                   1927: 
                   1928:        fprintf(statfp,"Exiting - Error level: %d, flows: %u, select_errors=%u"
                   1929:                ,retval, flows, select_errors);
                   1930:        fprintf(statfp,"\n");
                   1931: 
                   1932:        bail(retval);
1.1.1.2 ! root     1933:        return retval;
1.1       root     1934: }
                   1935: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.