Annotation of sbbs/sbbs3/ftpsrvr.c, revision 1.1

1.1     ! root        1: /* ftpsrvr.c */
        !             2: 
        !             3: /* Synchronet FTP server */
        !             4: 
        !             5: /* $Id: ftpsrvr.c,v 1.52 2000/12/14 12:40:07 rswindell Exp $ */
        !             6: 
        !             7: /****************************************************************************
        !             8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
        !             9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
        !            10:  *                                                                                                                                                     *
        !            11:  * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html         *
        !            12:  *                                                                                                                                                     *
        !            13:  * This program is free software; you can redistribute it and/or                       *
        !            14:  * modify it under the terms of the GNU General Public License                         *
        !            15:  * as published by the Free Software Foundation; either version 2                      *
        !            16:  * of the License, or (at your option) any later version.                                      *
        !            17:  * See the GNU General Public License for more details: gpl.txt or                     *
        !            18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
        !            19:  *                                                                                                                                                     *
        !            20:  * Anonymous FTP access to the most recent released source is available at     *
        !            21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
        !            22:  *                                                                                                                                                     *
        !            23:  * Anonymous CVS access to the development source and modification history     *
        !            24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
        !            25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
        !            26:  *     (just hit return, no password is necessary)                                                     *
        !            27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
        !            28:  *                                                                                                                                                     *
        !            29:  * For Synchronet coding style and modification guidelines, see                                *
        !            30:  * http://www.synchro.net/source.html                                                                          *
        !            31:  *                                                                                                                                                     *
        !            32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
        !            33:  * format) via e-mail to [email protected]                                                                      *
        !            34:  *                                                                                                                                                     *
        !            35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
        !            36:  ****************************************************************************/
        !            37: 
        !            38: /* Platform-specific headers */
        !            39: #ifdef _WIN32
        !            40: 
        !            41:        #include <share.h>              /* SH_DENYNO */
        !            42:        #include <direct.h>             /* _mkdir/_rmdir() */
        !            43:        #include <process.h>    /* _beginthread */
        !            44:        #include <windows.h>    /* required for mmsystem.h */
        !            45:        #include <mmsystem.h>   /* SND_ASYNC */
        !            46: 
        !            47: #elif defined(__unix__)
        !            48: 
        !            49:        #include <signal.h>             /* signal/SIGPIPE */
        !            50: 
        !            51: #endif
        !            52: 
        !            53: 
        !            54: /* ANSI C Library headers */
        !            55: #include <stdio.h>
        !            56: #include <stdlib.h>                    /* ltoa in GNU C lib */
        !            57: #include <stdarg.h>                    /* va_list, varargs */
        !            58: #include <string.h>                    /* strrchr */
        !            59: #include <fcntl.h>                     /* O_WRONLY, O_RDONLY, etc. */
        !            60: #include <errno.h>                     /* EACCES */
        !            61: #include <ctype.h>                     /* toupper */
        !            62: #include <sys/stat.h>          /* S_IWRITE */
        !            63: 
        !            64: /* Synchronet-specific headers */
        !            65: #include "sbbs.h"
        !            66: #include "ftpsrvr.h"
        !            67: #include "telnet.h"
        !            68: 
        !            69: /* Constants */
        !            70: 
        !            71: #define FTP_VERSION                            "1.02"
        !            72: 
        !            73: #define ILLEGAL_FILENAME_CHARS "\\/|<>+[]:=\";,%"
        !            74: 
        !            75: #define STATUS_WFC                             "Listening"
        !            76: 
        !            77: #define BBS_VIRTUAL_PATH               "bbs:/""/"      /* this is actually bbs:<slash><slash> */
        !            78: #define LOCAL_FSYS_DIR                 "local:"
        !            79: #define BBS_FSYS_DIR                   "bbs:"
        !            80: 
        !            81: #define TIMEOUT_THREAD_WAIT            60              /* Seconds */
        !            82: 
        !            83: #define XFER_REPORT_INTERVAL   60              /* Seconds */
        !            84: 
        !            85: #define INDEX_FNAME_LEN                        15
        !            86: 
        !            87: #define        NAME_LEN                                15              /* User name length for listings */
        !            88: 
        !            89: static const char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
        !            90:             ,"Jul","Aug","Sep","Oct","Nov","Dec"};
        !            91: 
        !            92: BOOL direxist(char *dir)
        !            93: {
        !            94:        if(access(dir,0)==0)
        !            95:                return(TRUE);
        !            96:        else
        !            97:                return(FALSE);
        !            98: }
        !            99: 
        !           100: BOOL dir_op(scfg_t* cfg, user_t* user, uint dirnum)
        !           101: {
        !           102:        return(user->level>=SYSOP_LEVEL || user->exempt&FLAG('R')
        !           103:                || (cfg->dir[dirnum]->op_ar[0] && chk_ar(cfg,cfg->dir[dirnum]->op_ar,user)));
        !           104: }
        !           105: 
        !           106: static ftp_startup_t* startup=NULL;
        !           107: static scfg_t  scfg;
        !           108: static SOCKET  server_socket=INVALID_SOCKET;
        !           109: static DWORD   active_clients=0;
        !           110: static DWORD   sockets=0;
        !           111: static HANDLE  socket_mutex=NULL;
        !           112: 
        !           113: typedef struct {
        !           114:        SOCKET                  socket;
        !           115:        SOCKADDR_IN             client_addr;
        !           116: } ftp_t;
        !           117: 
        !           118: static int lprintf(char *fmt, ...)
        !           119: {
        !           120:        int             result;
        !           121:        va_list argptr;
        !           122:        char sbuf[1024];
        !           123: 
        !           124:     if(startup!=NULL && startup->lputs==NULL)
        !           125:         return(0);
        !           126:     va_start(argptr,fmt);
        !           127:     vsprintf(sbuf,fmt,argptr);
        !           128:     va_end(argptr);
        !           129:     result=startup->lputs(sbuf);
        !           130: 
        !           131:        return(result);
        !           132: }
        !           133: 
        !           134: #ifdef _WINSOCKAPI_
        !           135: 
        !           136: static WSADATA WSAData;
        !           137: static BOOL WSAInitialized=FALSE;
        !           138: 
        !           139: static BOOL winsock_startup(void)
        !           140: {
        !           141:        int             status;             /* Status Code */
        !           142: 
        !           143:     if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
        !           144:                lprintf("%s %s",WSAData.szDescription, WSAData.szSystemStatus);
        !           145:                WSAInitialized=TRUE;
        !           146:                return (TRUE);
        !           147:        }
        !           148: 
        !           149:     lprintf("!WinSock startup ERROR %d", status);
        !           150:        return (FALSE);
        !           151: }
        !           152: 
        !           153: #else /* No WINSOCK */
        !           154: 
        !           155: #define winsock_startup()      (TRUE)
        !           156: 
        !           157: #endif
        !           158: 
        !           159: static void status(char* str)
        !           160: {
        !           161:        if(startup!=NULL && startup->status!=NULL)
        !           162:            startup->status(str);
        !           163: }
        !           164: 
        !           165: static void update_clients(void)
        !           166: {
        !           167:        if(startup!=NULL && startup->clients!=NULL)
        !           168:                startup->clients(active_clients);
        !           169: }
        !           170: 
        !           171: static void client_on(SOCKET sock, client_t* client)
        !           172: {
        !           173:        if(startup!=NULL && startup->client_on!=NULL)
        !           174:                startup->client_on(TRUE,sock,client);
        !           175: }
        !           176: 
        !           177: static void client_off(SOCKET sock)
        !           178: {
        !           179:        if(startup!=NULL && startup->client_on!=NULL)
        !           180:                startup->client_on(FALSE,sock,NULL);
        !           181: }
        !           182: 
        !           183: static void thread_up(void)
        !           184: {
        !           185:        if(startup!=NULL && startup->thread_up!=NULL)
        !           186:                startup->thread_up(TRUE);
        !           187: }
        !           188: 
        !           189: static void thread_down(void)
        !           190: {
        !           191:        if(startup!=NULL && startup->thread_up!=NULL)
        !           192:                startup->thread_up(FALSE);
        !           193: }
        !           194: 
        !           195: static SOCKET open_socket(int type)
        !           196: {
        !           197:        SOCKET sock;
        !           198: 
        !           199:        sock=socket(AF_INET, type, IPPROTO_IP);
        !           200:        if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) 
        !           201:                startup->socket_open(TRUE);
        !           202:        if(sock!=INVALID_SOCKET) {
        !           203:                sockets++;
        !           204: #ifdef _DEBUG
        !           205:                lprintf("%04d Socket opened (%d sockets in use)",sock,sockets);
        !           206: #endif
        !           207:        }
        !           208:        return(sock);
        !           209: }
        !           210: 
        !           211: #ifdef __BORLANDC__
        !           212: #pragma argsused
        !           213: #endif
        !           214: static int close_socket(SOCKET* sock, int line)
        !           215: {
        !           216:        int             result;
        !           217: 
        !           218: #ifndef _WIN32
        !           219: #define ReleaseMutex(x)
        !           220: #else
        !           221:        if((result=WaitForSingleObject(socket_mutex,5000))!=WAIT_OBJECT_0) 
        !           222:                lprintf("%04d !ERROR %d getting socket mutex from line %d"
        !           223:                        ,*sock,ERROR_VALUE,line);
        !           224: 
        !           225:        if(IsBadWritePtr(sock,sizeof(SOCKET))) {
        !           226:                ReleaseMutex(socket_mutex);
        !           227:                lprintf("0000 !BAD socket pointer in close_socket from line %d",line);
        !           228:                return(-1);
        !           229:        }
        !           230: #endif
        !           231:        if((*sock)==INVALID_SOCKET) {
        !           232:                ReleaseMutex(socket_mutex);
        !           233:                lprintf("0000 !INVALID_SOCKET in close_socket from line %d",line);
        !           234:                return(-1);
        !           235:        }
        !           236: 
        !           237:        shutdown(*sock,SHUT_RDWR);      /* required on Unix */
        !           238: 
        !           239:        result=closesocket(*sock);
        !           240:        if(/* result==0 && */ startup!=NULL && startup->socket_open!=NULL) 
        !           241:                startup->socket_open(FALSE);
        !           242: 
        !           243:        sockets--;
        !           244: 
        !           245:        if(result!=0)
        !           246:                lprintf("%04d !ERROR %d closing socket from line %d",*sock,ERROR_VALUE,line);
        !           247:        else {
        !           248: #ifdef _DEBUG
        !           249:                lprintf("%04d Socket closed (%d sockets in use) from line %d",*sock,sockets,line);
        !           250: #endif
        !           251:        }
        !           252:        *sock=INVALID_SOCKET;
        !           253:        ReleaseMutex(socket_mutex);
        !           254: 
        !           255:        return(result);
        !           256: }
        !           257: 
        !           258: static int sockprintf(SOCKET sock, char *fmt, ...)
        !           259: {
        !           260:        int             len;
        !           261:        int             result;
        !           262:        va_list argptr;
        !           263:        char    sbuf[1024];
        !           264: 
        !           265:     va_start(argptr,fmt);
        !           266:     len=vsprintf(sbuf,fmt,argptr);
        !           267:        if(startup->options&FTP_OPT_DEBUG_TX)
        !           268:                lprintf("%04d TX: %s", sock, sbuf);
        !           269:        strcat(sbuf,"\r\n");
        !           270:        len+=2;
        !           271:     va_end(argptr);
        !           272:        while((result=send(sock,sbuf,len,0))!=len) {
        !           273:                if(result==SOCKET_ERROR) {
        !           274:                        if(ERROR_VALUE==EWOULDBLOCK) {
        !           275:                                mswait(1);
        !           276:                                continue;
        !           277:                        }
        !           278:                        if(ERROR_VALUE==ECONNRESET) 
        !           279:                                lprintf("%04d Connection reset by peer on send",sock);
        !           280:                        else if(ERROR_VALUE==ECONNABORTED)
        !           281:                                lprintf("%04d Connection aborted by peer on send",sock);
        !           282:                        else
        !           283:                                lprintf("%04d !ERROR %d sending",sock,ERROR_VALUE);
        !           284:                        return(0);
        !           285:                }
        !           286:                lprintf("%04d !ERROR: short send: %d instead of %d",sock,result,len);
        !           287:        }
        !           288:        return(len);
        !           289: }
        !           290: 
        !           291: /************************************************/
        !           292: /* Truncates white-space chars off end of 'str' */
        !           293: /************************************************/
        !           294: static void truncsp(char *str)
        !           295: {
        !           296:        uint c;
        !           297: 
        !           298: c=strlen(str);
        !           299: while(c && (uchar)str[c-1]<=' ') c--;
        !           300: str[c]=0;
        !           301: }
        !           302: 
        !           303: 
        !           304: static int nopen(char *str, int access)
        !           305: {
        !           306:        int file,share,count=0;
        !           307: 
        !           308:     if(access&O_DENYNONE) {
        !           309:         share=SH_DENYNO;
        !           310:         access&=~O_DENYNONE; }
        !           311:     else if(access==O_RDONLY) share=SH_DENYWR;
        !           312:     else share=SH_DENYRW;
        !           313:     while(((file=sopen(str,O_BINARY|access,share))==-1)
        !           314:         && errno==EACCES && count++<LOOP_NOPEN)
        !           315:         if(count>10)
        !           316:             mswait(55);
        !           317:     return(file);
        !           318: }
        !           319: 
        !           320: time_t gettimeleft(scfg_t* cfg, user_t* user, time_t starttime)
        !           321: {
        !           322:        time_t  now;
        !           323:     long    tleft;
        !           324:        time_t  timeleft;
        !           325: 
        !           326:        now=time(NULL);
        !           327: 
        !           328:        if(user->exempt&FLAG('T')) {   /* Time online exemption */
        !           329:                timeleft=cfg->level_timepercall[user->level]*60;
        !           330:                if(timeleft<10)             /* never get below 10 for exempt users */
        !           331:                        timeleft=10; }
        !           332:        else {
        !           333:                tleft=(((long)cfg->level_timeperday[user->level]-user->ttoday)
        !           334:                        +user->textra)*60L;
        !           335:                if(tleft<0) tleft=0;
        !           336:                if(tleft>cfg->level_timepercall[user->level]*60)
        !           337:                        tleft=cfg->level_timepercall[user->level]*60;
        !           338:                tleft+=user->min*60L;
        !           339:                tleft-=now-starttime;
        !           340:                if(tleft>0x7fffL)
        !           341:                        timeleft=0x7fff;
        !           342:                else
        !           343:                        timeleft=tleft; }
        !           344: 
        !           345:        return(timeleft);
        !           346: }
        !           347: 
        !           348: static time_t checktime(void)
        !           349: {
        !           350:        struct tm tm;
        !           351: 
        !           352:     memset(&tm,0,sizeof(tm));
        !           353:     tm.tm_year=94;
        !           354:     tm.tm_mday=1;
        !           355:     return(mktime(&tm)-0x2D24BD00L);
        !           356: }
        !           357: 
        !           358: BOOL upload_stats(ulong bytes)
        !           359: {
        !           360:        char    str[MAX_PATH];
        !           361:        int             file;
        !           362:        ulong   val;
        !           363: 
        !           364:        sprintf(str,"%sdsts.dab",scfg.ctrl_dir);
        !           365:        if((file=nopen(str,O_RDWR))==-1) 
        !           366:                return(FALSE);
        !           367: 
        !           368:        lseek(file,20L,SEEK_SET);   /* Skip timestamp, logons and logons today */
        !           369:        read(file,&val,4);        /* Uploads today         */
        !           370:        val++;
        !           371:        lseek(file,-4L,SEEK_CUR);
        !           372:        write(file,&val,4);
        !           373:        read(file,&val,4);        /* Upload bytes today    */
        !           374:        val+=bytes;
        !           375:        lseek(file,-4L,SEEK_CUR);
        !           376:        write(file,&val,4);
        !           377:        close(file);
        !           378:        return(TRUE);
        !           379: }
        !           380: 
        !           381: BOOL download_stats(ulong bytes)
        !           382: {
        !           383:        char    str[MAX_PATH];
        !           384:        int             file;
        !           385:        ulong   val;
        !           386: 
        !           387:        sprintf(str,"%sdsts.dab",scfg.ctrl_dir);
        !           388:        if((file=nopen(str,O_RDWR))==-1) 
        !           389:                return(FALSE);
        !           390: 
        !           391:        lseek(file,28L,SEEK_SET);   /* Skip timestamp, logons and logons today */
        !           392:        read(file,&val,4);        /* Downloads today         */
        !           393:        val++;
        !           394:        lseek(file,-4L,SEEK_CUR);
        !           395:        write(file,&val,4);
        !           396:        read(file,&val,4);        /* Download bytes today    */
        !           397:        val+=bytes;
        !           398:        lseek(file,-4L,SEEK_CUR);
        !           399:        write(file,&val,4);
        !           400:        close(file);
        !           401:        return(TRUE);
        !           402: }
        !           403: 
        !           404: void recverror(SOCKET socket, int rd)
        !           405: {
        !           406:        if(rd==0) 
        !           407:                lprintf("%04d Socket closed by peer on receive",socket);
        !           408:        else if(rd==SOCKET_ERROR) {
        !           409:                if(ERROR_VALUE==ECONNRESET) 
        !           410:                        lprintf("%04d Connection reset by peer on receive",socket);
        !           411:                else if(ERROR_VALUE==ECONNABORTED) 
        !           412:                        lprintf("%04d Connection aborted by peer on receive",socket);
        !           413:                else
        !           414:                        lprintf("%04d !ERROR %d receiving on socket", socket, ERROR_VALUE);
        !           415:        } else
        !           416:                lprintf("%04d !ERROR: recv on socket returned unexpected value: %d",socket,rd);
        !           417: }
        !           418: 
        !           419: int sockreadline(SOCKET socket, char* buf, int len, time_t* lastactive)
        !           420: {
        !           421:        char    ch;
        !           422:        int             i,rd=0;
        !           423:        fd_set  socket_set;
        !           424:        struct timeval  tv;
        !           425:        
        !           426:        while(rd<len-1) {
        !           427: 
        !           428:                tv.tv_sec=1;
        !           429:                tv.tv_usec=0;
        !           430: 
        !           431:                FD_ZERO(&socket_set);
        !           432:                FD_SET(socket,&socket_set);
        !           433: 
        !           434:                i=select(socket+1,&socket_set,NULL,NULL,&tv);
        !           435: 
        !           436:                if(server_socket==INVALID_SOCKET) {
        !           437:                        sockprintf(socket,"421 Server downed, aborting.");
        !           438:                        lprintf("%04d Server downed, aborting.",socket);
        !           439:                        return(0);
        !           440:                }
        !           441:                if(i<1) {
        !           442:                        if(i==0) {
        !           443:                                if((time(NULL)-(*lastactive))>startup->max_inactivity) {
        !           444:                                        lprintf("%04d Disconnecting due to to inactivity.",socket);
        !           445:                                        sockprintf(socket,"421 Disconnecting due to inactivity (%u seconds)."
        !           446:                                                ,startup->max_inactivity);
        !           447:                                        return(0);
        !           448:                                }
        !           449:                                mswait(1);
        !           450:                                continue;
        !           451:                        }
        !           452:                        recverror(socket,i);
        !           453:                        return(i);
        !           454:                }
        !           455:                i=recv(socket, &ch, 1, 0);
        !           456:                if(i<1) {
        !           457: #if 0
        !           458:                        if(ERROR_VALUE==EWOULDBLOCK) {
        !           459:                                mswait(1);
        !           460:                                continue;
        !           461:                        }
        !           462: #endif
        !           463:                        recverror(socket,i);
        !           464:                        return(i);
        !           465:                }
        !           466:                if(ch=='\n' && rd>=1) {
        !           467:                        break;
        !           468:                }       
        !           469:                buf[rd++]=ch;
        !           470:        }
        !           471:        buf[rd-1]=0;
        !           472:        
        !           473:        return(rd);
        !           474: }
        !           475: 
        !           476: void DLLCALL ftp_terminate(void)
        !           477: {
        !           478:        if(server_socket!=INVALID_SOCKET) {
        !           479:        lprintf("%04d FTP Terminate: closing socket",server_socket);
        !           480:                close_socket(&server_socket,__LINE__);
        !           481:            server_socket=INVALID_SOCKET;
        !           482:     }
        !           483: }
        !           484: 
        !           485: 
        !           486: typedef struct {
        !           487:        SOCKET  ctrl_sock;
        !           488:        SOCKET* data_sock;
        !           489:        BOOL*   inprogress;
        !           490:        BOOL*   aborted;
        !           491:        BOOL    delfile;
        !           492:        BOOL    tmpfile;
        !           493:        BOOL    credits;
        !           494:        BOOL    append;
        !           495:        long    filepos;
        !           496:        char    filename[MAX_PATH];
        !           497:        time_t* lastactive;
        !           498:        user_t* user;
        !           499:        int             dir;
        !           500:        char*   desc;
        !           501: } xfer_t;
        !           502: 
        !           503: static void send_thread(void* arg)
        !           504: {
        !           505:        char            buf[8192];
        !           506:        char            fname[MAX_PATH];
        !           507:        int                     i;
        !           508:        int                     rd;
        !           509:        int                     wr;
        !           510:        ulong           total=0;
        !           511:        ulong           dur;
        !           512:        ulong           cps;
        !           513:        ulong           length;
        !           514:        BOOL            error=FALSE;
        !           515:        FILE*           fp;
        !           516:        file_t          f;
        !           517:        xfer_t          xfer;
        !           518:        time_t          now;
        !           519:        time_t          start;
        !           520:        time_t          last_report;
        !           521: 
        !           522:        xfer=*(xfer_t*)arg;
        !           523: 
        !           524:        length=flength(xfer.filename);
        !           525: 
        !           526:        if((fp=fopen(xfer.filename,"rb"))==NULL) {
        !           527:                lprintf("%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,errno,xfer.filename);
        !           528:                sockprintf(xfer.ctrl_sock,"450 ERROR %d opening %s.",errno,xfer.filename);
        !           529:                if(xfer.tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
        !           530:                        remove(xfer.filename);
        !           531:                close_socket(xfer.data_sock,__LINE__);
        !           532:                *xfer.inprogress=FALSE;
        !           533:                return;
        !           534:        }
        !           535:        thread_up();
        !           536: 
        !           537:        *xfer.inprogress=TRUE;
        !           538:        *xfer.aborted=FALSE;
        !           539:        if(startup->options&FTP_OPT_DEBUG_DATA || xfer.filepos)
        !           540:                lprintf("%04d DATA socket %d sending %s from offset %ld"
        !           541:                        ,xfer.ctrl_sock,*xfer.data_sock,xfer.filename,xfer.filepos);
        !           542: 
        !           543:        fseek(fp,xfer.filepos,SEEK_SET);
        !           544:        last_report=start=time(NULL);
        !           545:        while(!feof(fp)) {
        !           546:                now=time(NULL);
        !           547:                if(total && now>=last_report+XFER_REPORT_INTERVAL) {
        !           548:                        lprintf("%04d Sent %ld bytes (%ld total) of %s (%lu cps)"
        !           549:                                ,xfer.ctrl_sock,total,length,xfer.filename
        !           550:                                ,now-start ? total/(now-start) : total*2);
        !           551:                        last_report=now;
        !           552:                }
        !           553: 
        !           554:                if(*xfer.aborted==TRUE) {
        !           555:                        lprintf("%04d !DATA Transfer aborted",xfer.ctrl_sock);
        !           556:                        sockprintf(xfer.ctrl_sock,"426 Transfer aborted.");
        !           557:                        error=TRUE;
        !           558:                        break;
        !           559:                }
        !           560:                if(server_socket==INVALID_SOCKET) {
        !           561:                        lprintf("%04d !DATA Transfer locally aborted",xfer.ctrl_sock);
        !           562:                        sockprintf(xfer.ctrl_sock,"426 Transfer locally aborted.");
        !           563:                        error=TRUE;
        !           564:                        break;
        !           565:                }
        !           566:                rd=fread(buf,sizeof(char),sizeof(buf),fp);
        !           567:                if(rd<1) {
        !           568:                        lprintf("%04d !READ ERROR (%d) on %s",xfer.ctrl_sock,errno,xfer.filename);
        !           569:                        error=TRUE;
        !           570:                        break;
        !           571:                }
        !           572:                wr=send(*xfer.data_sock,buf,rd,0);
        !           573:                if(wr!=rd) {
        !           574:                        if(wr==SOCKET_ERROR) {
        !           575:                                if(ERROR_VALUE==ECONNRESET) 
        !           576:                                        lprintf("%04d DATA Connection reset by peer, sending on socket %d"
        !           577:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !           578:                                else if(ERROR_VALUE==ECONNABORTED) 
        !           579:                                        lprintf("%04d DATA Connection aborted by peer, sending on socket %d"
        !           580:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !           581:                                else
        !           582:                                        lprintf("%04d !DATA ERROR %d sending on data socket %d"
        !           583:                                                ,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock);
        !           584:                                sockprintf(xfer.ctrl_sock,"426 Error %d sending on DATA channel",ERROR_VALUE);
        !           585:                                error=TRUE;
        !           586:                                break;
        !           587:                        }
        !           588:                        if(wr==0) {
        !           589:                                lprintf("%04d !DATA socket %d disconnected",xfer.ctrl_sock, *xfer.data_sock);
        !           590:                                sockprintf(xfer.ctrl_sock,"426 DATA channel disconnected");
        !           591:                                error=TRUE;
        !           592:                                break;
        !           593:                        }
        !           594:                        lprintf("%04d !DATA ERROR sent %d instead of %d on socket %d"
        !           595:                                ,xfer.ctrl_sock,wr,rd,*xfer.data_sock);
        !           596:                        sockprintf(xfer.ctrl_sock,"451 Short DATA transfer");
        !           597:                        error=TRUE;
        !           598:                        break;
        !           599:                }
        !           600:                total+=wr;
        !           601:                *xfer.lastactive=time(NULL);
        !           602:                mswait(1);
        !           603:        }
        !           604: 
        !           605:        if((i=ferror(fp))!=0) 
        !           606:                lprintf("%04d !FILE ERROR %d (%d)",xfer.ctrl_sock,i,errno);
        !           607: 
        !           608:        close_socket(xfer.data_sock,__LINE__);  /* Signal end of file */
        !           609:        if(startup->options&FTP_OPT_DEBUG_DATA)
        !           610:                lprintf("%04d DATA socket closed",xfer.ctrl_sock);
        !           611:        
        !           612:        if(!error) {
        !           613:                dur=time(NULL)-start;
        !           614:                cps=dur ? total/dur : total*2;
        !           615:                lprintf("%04d Transfer successful: %lu bytes sent in %lu seconds (%lu cps)"
        !           616:                        ,xfer.ctrl_sock
        !           617:                        ,total,dur,cps);
        !           618:                sockprintf(xfer.ctrl_sock,"226 Download complete (%lu cps).",cps);
        !           619: 
        !           620:                if(xfer.dir>=0) {
        !           621:                        memset(&f,0,sizeof(f));
        !           622: #ifdef _WIN32
        !           623:                        GetShortPathName(xfer.filename,fname,sizeof(fname));
        !           624: #else
        !           625:                        strcpy(xfer.filename,fname);
        !           626: #endif
        !           627:                        padfname(getfname(fname),f.name);
        !           628:                        strupr(f.name);
        !           629:                        f.dir=xfer.dir;
        !           630:                        f.size=total;
        !           631:                        if(getfileixb(&scfg,&f)==TRUE && getfiledat(&scfg,&f)==TRUE) {
        !           632:                                f.timesdled++;
        !           633:                                putfiledat(&scfg,&f);
        !           634:                        lprintf("%04d %s downloaded: %s (%lu times total)"
        !           635:                                ,xfer.ctrl_sock
        !           636:                                ,xfer.user->alias
        !           637:                                ,xfer.filename
        !           638:                                ,f.timesdled);
        !           639:                        }
        !           640:                        /* Need to update datedled in index */
        !           641:                }       
        !           642: 
        !           643:                if(xfer.credits) {
        !           644:                        xfer.user->dls=(ushort)adjustuserrec(&scfg, xfer.user->number,U_DLS,5,1);
        !           645:                        xfer.user->dlb=adjustuserrec(&scfg, xfer.user->number,U_DLB,10,total);
        !           646:                        if(xfer.dir>=0 && !(scfg.dir[xfer.dir]->misc&DIR_FREE) 
        !           647:                                && !(xfer.user->exempt&FLAG('D')))
        !           648:                                subtract_cdt(&scfg, xfer.user, xfer.credits);
        !           649:                }
        !           650:                if(!xfer.tmpfile && !xfer.delfile)
        !           651:                        download_stats(total);
        !           652:        }
        !           653: 
        !           654:        fclose(fp);
        !           655:        *xfer.inprogress=FALSE;
        !           656:        if(xfer.tmpfile) {
        !           657:                if(!(startup->options&FTP_OPT_KEEP_TEMP_FILES))
        !           658:                        remove(xfer.filename);
        !           659:        } 
        !           660:        else if(xfer.delfile && !error)
        !           661:                remove(xfer.filename);
        !           662: 
        !           663:        thread_down();
        !           664: }
        !           665: 
        !           666: static void receive_thread(void* arg)
        !           667: {
        !           668:        char            buf[8192];
        !           669:        char            fname[MAX_PATH];
        !           670:        int                     rd;
        !           671:        int                     file;
        !           672:        ulong           total=0;
        !           673:        ulong           dur;
        !           674:        ulong           cps;
        !           675:        BOOL            error=FALSE;
        !           676:        FILE*           fp;
        !           677:        file_t          f;
        !           678:        xfer_t          xfer;
        !           679:        time_t          now;
        !           680:        time_t          start;
        !           681:        time_t          last_report;
        !           682: 
        !           683:        xfer=*(xfer_t*)arg;
        !           684: 
        !           685:        if((fp=fopen(xfer.filename,xfer.append ? "ab" : "wb"))==NULL) {
        !           686:                lprintf("%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,xfer.filename,errno);
        !           687:                close_socket(xfer.data_sock,__LINE__);
        !           688:                return;
        !           689:        }
        !           690: 
        !           691:        thread_up();
        !           692: 
        !           693:        *xfer.inprogress=TRUE;
        !           694:        *xfer.aborted=FALSE;
        !           695:        if(xfer.filepos || startup->options&FTP_OPT_DEBUG_DATA)
        !           696:                lprintf("%04d DATA socket %d receiving from offset %ld"
        !           697:                        ,xfer.ctrl_sock,*xfer.data_sock,xfer.filepos);
        !           698: 
        !           699:        fseek(fp,xfer.filepos,SEEK_SET);
        !           700:        last_report=start=time(NULL);
        !           701:        while(1) {
        !           702: 
        !           703:                now=time(NULL);
        !           704:                if(total && now>=last_report+XFER_REPORT_INTERVAL) {
        !           705:                        lprintf("%04d Received %ld bytes of %s (%lu cps)"
        !           706:                                ,xfer.ctrl_sock,total,xfer.filename
        !           707:                                ,now-start? total/(now-start) : total*2);
        !           708:                        last_report=now;
        !           709:                }
        !           710:                if(*xfer.aborted==TRUE) {
        !           711:                        lprintf("%04d !DATA Transfer aborted",xfer.ctrl_sock);
        !           712:                        /* Send NAK */
        !           713:                        sockprintf(xfer.ctrl_sock,"426 Transfer aborted.");
        !           714:                        error=TRUE;
        !           715:                        break;
        !           716:                }
        !           717:                if(server_socket==INVALID_SOCKET) {
        !           718:                        lprintf("%04d !DATA Transfer locally aborted",xfer.ctrl_sock);
        !           719:                        /* Send NAK */
        !           720:                        sockprintf(xfer.ctrl_sock,"426 Transfer locally aborted.");
        !           721:                        error=TRUE;
        !           722:                        break;
        !           723:                }
        !           724:                rd=recv(*xfer.data_sock,buf,sizeof(buf),0);
        !           725:                if(rd<1) {
        !           726:                        if(rd==0) { /* Socket closed */
        !           727:                                if(startup->options&FTP_OPT_DEBUG_DATA)
        !           728:                                        lprintf("%04d DATA socket %d closed by client"
        !           729:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !           730:                                break;
        !           731:                        }
        !           732:                        if(rd==SOCKET_ERROR) {
        !           733:                                if(ERROR_VALUE==ECONNRESET) 
        !           734:                                        lprintf("%04d Connection reset by peer, receiving on socket %d"
        !           735:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !           736:                                else if(ERROR_VALUE==ECONNABORTED) 
        !           737:                                        lprintf("%04d Connection aborted by peer, receiving on socket %d"
        !           738:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !           739:                                else
        !           740:                                        lprintf("%04d !DATA ERROR %d receiving on data socket %d"
        !           741:                                                ,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock);
        !           742:                                /* Send NAK */
        !           743:                                sockprintf(xfer.ctrl_sock,"426 Error %d receiving on DATA channel"
        !           744:                                        ,ERROR_VALUE);
        !           745:                                error=TRUE;
        !           746:                                break;
        !           747:                        }
        !           748:                        lprintf("%04d !DATA ERROR recv returned %d on socket %d"
        !           749:                                ,xfer.ctrl_sock,rd,*xfer.data_sock);
        !           750:                        /* Send NAK */
        !           751:                        sockprintf(xfer.ctrl_sock,"451 Unexpected socket error: %d",rd);
        !           752:                        error=TRUE;
        !           753:                        break;
        !           754:                }
        !           755:                fwrite(buf,1,rd,fp);
        !           756:                total+=rd;
        !           757:                *xfer.lastactive=time(NULL);
        !           758:                mswait(1);
        !           759:        }
        !           760: 
        !           761:        *xfer.inprogress=FALSE;
        !           762:        fclose(fp);
        !           763: 
        !           764:        close_socket(xfer.data_sock,__LINE__);
        !           765:        if(error && startup->options&FTP_OPT_DEBUG_DATA)
        !           766:                lprintf("%04d DATA socket %d closed",xfer.ctrl_sock,*xfer.data_sock);
        !           767:        
        !           768:        if(!error) {
        !           769:                dur=time(NULL)-start;
        !           770:                cps=dur ? total/dur : total*2;
        !           771:                lprintf("%04d Transfer successful: %lu bytes received in %lu seconds (%lu cps)"
        !           772:                        ,xfer.ctrl_sock
        !           773:                        ,total,dur,cps);
        !           774: 
        !           775:                if(xfer.dir>=0) {
        !           776:                        memset(&f,0,sizeof(f));
        !           777: #ifdef _WIN32
        !           778:                        GetShortPathName(xfer.filename,fname,sizeof(fname));
        !           779: #else
        !           780:                        strcpy(fname,xfer.filename);
        !           781: #endif
        !           782:                        padfname(getfname(fname),f.name);
        !           783:                        strupr(f.name);
        !           784:                        f.dir=xfer.dir;
        !           785:                        if(scfg.dir[f.dir]->misc&DIR_AONLY)  /* Forced anonymous */
        !           786:                                f.misc|=FM_ANON;
        !           787:                        f.cdt=total;
        !           788:                        f.dateuled=time(NULL);
        !           789:                        f.timesdled=0;
        !           790:                        f.datedled=0L;
        !           791:                        f.opencount=0;
        !           792:                        if(xfer.desc==NULL || *xfer.desc==0) {
        !           793:                                sprintf(f.desc,"%.*s",(int)sizeof(f.desc)-1,getfname(xfer.filename));
        !           794: /* old way             strcpy(f.desc,"Received via FTP: No description given"); */
        !           795:                        } else
        !           796:                                sprintf(f.desc,"%.*s",(int)sizeof(f.desc)-1,xfer.desc);
        !           797:                        strcpy(f.uler,xfer.user->alias);
        !           798:                        if(!addfiledat(&scfg,&f))
        !           799:                                lprintf("%04d !ERROR adding file (%s) to database",xfer.ctrl_sock,f.name);
        !           800:                        if(scfg.dir[f.dir]->upload_sem[0])
        !           801:                                if((file=sopen(scfg.dir[f.dir]->upload_sem,O_WRONLY|O_CREAT|O_TRUNC,SH_DENYNO))!=-1)
        !           802:                                        close(file);
        !           803:                        /**************************/
        !           804:                        /* Update Uploader's Info */
        !           805:                        /**************************/
        !           806:                        xfer.user->uls=(short)adjustuserrec(&scfg, xfer.user->number,U_ULS,5,1);
        !           807:                        xfer.user->ulb=adjustuserrec(&scfg, xfer.user->number,U_ULB,10,total);
        !           808:                        if(scfg.dir[f.dir]->up_pct && scfg.dir[f.dir]->misc&DIR_CDTUL) { /* credit for upload */
        !           809:                                if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps)    /* Give min instead of cdt */
        !           810:                                        xfer.user->min=adjustuserrec(&scfg,xfer.user->number,U_MIN,10
        !           811:                                                ,((ulong)(total*(scfg.dir[f.dir]->up_pct/100.0))/cps)/60);
        !           812:                                else
        !           813:                                        xfer.user->cdt=adjustuserrec(&scfg,xfer.user->number,U_CDT,10
        !           814:                                                ,(ulong)(f.cdt*(scfg.dir[f.dir]->up_pct/100.0))); 
        !           815:                        }
        !           816:                        upload_stats(total);
        !           817:                }
        !           818:                /* Send ACK */
        !           819:                sockprintf(xfer.ctrl_sock,"226 Upload complete (%lu cps).",cps);
        !           820:        }
        !           821: 
        !           822:        thread_down();
        !           823: }
        !           824: 
        !           825: 
        !           826: 
        !           827: static void filexfer(SOCKADDR_IN* addr, SOCKET ctrl_sock, SOCKET pasv_sock, SOCKET* data_sock
        !           828:                                        ,char* filename, long filepos, BOOL* inprogress, BOOL* aborted
        !           829:                                        ,BOOL delfile, BOOL tmpfile
        !           830:                                        ,time_t* lastactive
        !           831:                                        ,user_t* user
        !           832:                                        ,int dir
        !           833:                                        ,BOOL receiving
        !           834:                                        ,BOOL credits
        !           835:                                        ,BOOL append
        !           836:                                        ,char* desc)
        !           837: {
        !           838:        int                     result;
        !           839:        int                     addr_len;
        !           840:        SOCKADDR_IN     server_addr;
        !           841:        static xfer_t xfer;
        !           842: 
        !           843:        if((*inprogress)==TRUE) {
        !           844:                lprintf("%04d !TRANSFER already in progress",ctrl_sock);
        !           845:                sockprintf(ctrl_sock,"425 Transfer already in progress.");
        !           846:                return;
        !           847:        }
        !           848:        *inprogress=TRUE;
        !           849: 
        !           850:        if(*data_sock!=INVALID_SOCKET)
        !           851:                close_socket(data_sock,__LINE__);
        !           852: 
        !           853:        if(pasv_sock==INVALID_SOCKET) { /* !PASV */
        !           854: 
        !           855:                if((*data_sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) {
        !           856:                        lprintf("%04d !DATA ERROR %d opening socket", ctrl_sock, ERROR_VALUE);
        !           857:                        sockprintf(ctrl_sock,"425 Error %d opening socket",ERROR_VALUE);
        !           858:                        if(tmpfile)
        !           859:                                remove(filename);
        !           860:                        *inprogress=FALSE;
        !           861:                        return;
        !           862:                }
        !           863:                if(startup->socket_open!=NULL)
        !           864:                        startup->socket_open(TRUE);
        !           865:                sockets++;
        !           866:                if(startup->options&FTP_OPT_DEBUG_DATA)
        !           867:                        lprintf("%04d DATA socket %d opened",ctrl_sock,*data_sock);
        !           868: 
        !           869:                memset(&server_addr, 0, sizeof(server_addr));
        !           870: 
        !           871:                server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
        !           872:                server_addr.sin_family = AF_INET;
        !           873:                server_addr.sin_port   = htons(0);
        !           874: 
        !           875:                if((result=bind(*data_sock, (struct sockaddr *) &server_addr
        !           876:                        ,sizeof(server_addr)))!=0) {
        !           877:                        lprintf ("%04d !DATA ERROR %d (%d) binding socket %d"
        !           878:                                ,ctrl_sock, result, ERROR_VALUE, *data_sock);
        !           879:                        sockprintf(ctrl_sock,"425 Error %d binding socket",ERROR_VALUE);
        !           880:                        if(tmpfile)
        !           881:                                remove(filename);
        !           882:                        *inprogress=FALSE;
        !           883:                        close_socket(data_sock,__LINE__);
        !           884:                        return;
        !           885:                }
        !           886: 
        !           887:                if((result=connect(*data_sock, (struct sockaddr *)addr
        !           888:                        ,sizeof(struct sockaddr)))!=0) {
        !           889:                        lprintf("%04d !DATA ERROR %d (%d) connecting to client %s port %d on socket %d"
        !           890:                                        ,ctrl_sock,result,ERROR_VALUE
        !           891:                                        ,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),*data_sock);
        !           892:                        sockprintf(ctrl_sock,"425 Error %d connecting to socket",ERROR_VALUE);
        !           893:                        if(tmpfile)
        !           894:                                remove(filename);
        !           895:                        *inprogress=FALSE;
        !           896:                        close_socket(data_sock,__LINE__);
        !           897:                        return;
        !           898:                }
        !           899:                if(startup->options&FTP_OPT_DEBUG_DATA)
        !           900:                        lprintf("%04d DATA socket %d connected to %s port %d"
        !           901:                                ,ctrl_sock,*data_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port));
        !           902: 
        !           903:        } else {        /* PASV */
        !           904:                addr_len=sizeof(SOCKADDR_IN);
        !           905:                if((*data_sock=accept(pasv_sock,(struct sockaddr*)addr,&addr_len))==INVALID_SOCKET) {
        !           906:                        lprintf("%04d !PASV DATA ERROR %d accepting connection on socket %d"
        !           907:                                ,ctrl_sock,ERROR_VALUE,pasv_sock);
        !           908:                        sockprintf(ctrl_sock,"425 Error %d accepting connection",ERROR_VALUE);
        !           909:                        if(tmpfile)
        !           910:                                remove(filename);
        !           911:                        *inprogress=FALSE;
        !           912:                        return;
        !           913:                }
        !           914:                if(startup->socket_open!=NULL)
        !           915:                        startup->socket_open(TRUE);
        !           916:                sockets++;
        !           917:                if(startup->options&FTP_OPT_DEBUG_DATA)
        !           918:                        lprintf("%04d PASV DATA socket %d connected to %s port %d"
        !           919:                                ,ctrl_sock,*data_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port));
        !           920:        }
        !           921: 
        !           922: 
        !           923:        /* Get Mutex here? */
        !           924:        memset(&xfer,0,sizeof(xfer));
        !           925:        xfer.ctrl_sock=ctrl_sock;
        !           926:        xfer.data_sock=data_sock;
        !           927:        xfer.inprogress=inprogress;
        !           928:        xfer.aborted=aborted;
        !           929:        xfer.delfile=delfile;
        !           930:        xfer.tmpfile=tmpfile;
        !           931:        xfer.append=append;
        !           932:        xfer.filepos=filepos;
        !           933:        xfer.credits=credits;
        !           934:        xfer.lastactive=lastactive;
        !           935:        xfer.user=user;
        !           936:        xfer.dir=dir;
        !           937:        xfer.desc=desc;
        !           938:        sprintf(xfer.filename,"%.*s",(int)sizeof(xfer.filename)-1,filename);
        !           939:        if(receiving)
        !           940:                _beginthread(receive_thread,0,(void*)&xfer);
        !           941:        else
        !           942:                _beginthread(send_thread,0,(void*)&xfer);
        !           943: }
        !           944: 
        !           945: /* convert "user name" to "user.name" or "mr. user" to "mr._user" */
        !           946: char* dotname(char* in, char* out)
        !           947: {
        !           948:        char    ch;
        !           949:        int             i;
        !           950: 
        !           951:        if(strchr(in,'.')==NULL)
        !           952:                ch='.';
        !           953:        else
        !           954:                ch='_';
        !           955:        for(i=0;in[i];i++)
        !           956:                if(in[i]<=' ')
        !           957:                        out[i]=ch;
        !           958:                else
        !           959:                        out[i]=in[i];
        !           960:        out[i]=0;
        !           961:        return(out);
        !           962: }
        !           963: 
        !           964: /* Returns the directory index of a virtual lib/dir path (e.g. main/games/filename) */
        !           965: int getdir(char* p, user_t* user)
        !           966: {
        !           967:        char*   tp;
        !           968:        char    path[MAX_PATH];
        !           969:        int             dir;
        !           970:        int             lib;
        !           971: 
        !           972:        sprintf(path,"%.*s",(int)sizeof(path)-1,p);
        !           973:        p=path;
        !           974: 
        !           975:        if(*p=='/') 
        !           976:                p++;
        !           977:        else if(!strncmp(p,"./",2))
        !           978:                p+=2;
        !           979: 
        !           980:        tp=strchr(p,'/');
        !           981:        if(tp) *tp=0;
        !           982:        for(lib=0;lib<scfg.total_libs;lib++) {
        !           983:                if(!chk_ar(&scfg,scfg.lib[lib]->ar,user))
        !           984:                        continue;
        !           985:                if(!stricmp(scfg.lib[lib]->sname,p))
        !           986:                        break;
        !           987:        }
        !           988:        if(lib>=scfg.total_libs) 
        !           989:                return(-1);
        !           990: 
        !           991:        if(tp!=NULL)
        !           992:                p=tp+1;
        !           993: 
        !           994:        tp=strchr(p,'/');
        !           995:        if(tp) *tp=0;
        !           996:        for(dir=0;dir<scfg.total_dirs;dir++) {
        !           997:                if(scfg.dir[dir]->lib!=lib)
        !           998:                        continue;
        !           999:                if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir 
        !          1000:                        && !chk_ar(&scfg,scfg.dir[dir]->ar,user))
        !          1001:                        continue;
        !          1002:                if(!stricmp(scfg.dir[dir]->code,p))
        !          1003:                        break;
        !          1004:        }
        !          1005:        if(dir>=scfg.total_dirs) 
        !          1006:                return(-1);
        !          1007: 
        !          1008:        return(dir);
        !          1009: }
        !          1010: 
        !          1011: void parsepath(char** pp, user_t* user, int* curlib, int* curdir)
        !          1012: {
        !          1013:        char*   p;
        !          1014:        char*   tp;
        !          1015:        char    path[MAX_PATH];
        !          1016:        int             dir=*curdir;
        !          1017:        int             lib=*curlib;
        !          1018: 
        !          1019:        sprintf(path,"%.*s",(int)sizeof(path)-1,*pp);
        !          1020:        p=path;
        !          1021: 
        !          1022:        if(*p=='/') {
        !          1023:                p++;
        !          1024:                lib=-1;
        !          1025:        }
        !          1026:        else if(!strncmp(p,"./",2))
        !          1027:                p+=2;
        !          1028: 
        !          1029:        if(!strncmp(p,"..",2)) {
        !          1030:                p+=2;
        !          1031:                if(dir>=0)
        !          1032:                        dir=-1;
        !          1033:                else if(lib>=0)
        !          1034:                        lib=-1;
        !          1035:                if(*p=='/')
        !          1036:                        p++;
        !          1037:        }
        !          1038: 
        !          1039:        if(*p==0) {
        !          1040:                *curlib=lib;
        !          1041:                *curdir=dir;
        !          1042:                return;
        !          1043:        }
        !          1044: 
        !          1045:        if(lib<0) {
        !          1046:                tp=strchr(p,'/');
        !          1047:                if(tp) *tp=0;
        !          1048:                for(lib=0;lib<scfg.total_libs;lib++) {
        !          1049:                        if(!chk_ar(&scfg,scfg.lib[lib]->ar,user))
        !          1050:                                continue;
        !          1051:                        if(!stricmp(scfg.lib[lib]->sname,p))
        !          1052:                                break;
        !          1053:                }
        !          1054:                if(lib>=scfg.total_libs) { /* not found */
        !          1055:                        *curlib=-1;
        !          1056:                        return;
        !          1057:                }
        !          1058:                *curlib=lib;
        !          1059: 
        !          1060:                if(tp==NULL) {
        !          1061:                        *curdir=-1;
        !          1062:                        return;
        !          1063:                }
        !          1064: 
        !          1065:                p=tp+1;
        !          1066:        }
        !          1067: 
        !          1068:        tp=strchr(p,'/');
        !          1069:        if(tp!=NULL) {
        !          1070:                *tp=0;
        !          1071:                tp++;
        !          1072:        } else 
        !          1073:                tp=p+strlen(p);
        !          1074: 
        !          1075:        for(dir=0;dir<scfg.total_dirs;dir++) {
        !          1076:                if(scfg.dir[dir]->lib!=lib)
        !          1077:                        continue;
        !          1078:                if(!chk_ar(&scfg,scfg.dir[dir]->ar,user))
        !          1079:                        continue;
        !          1080:                if(!stricmp(scfg.dir[dir]->code,p))
        !          1081:                        break;
        !          1082:        }
        !          1083: 
        !          1084:        if(dir>=scfg.total_dirs)  /* not found */
        !          1085:                return;
        !          1086: 
        !          1087:        *curdir=dir;
        !          1088: 
        !          1089:        *pp+=tp-path;   /* skip "lib/dir/" */
        !          1090: }
        !          1091: 
        !          1092: BOOL alias(char* fullalias, char* filename, user_t* user, int* curdir)
        !          1093: {
        !          1094:        char*   p;
        !          1095:        char*   tp;
        !          1096:        char*   fname="";
        !          1097:        char    line[512];
        !          1098:        char    alias[512];
        !          1099:        char    aliasfile[MAX_PATH];
        !          1100:        int             dir=-1;
        !          1101:        FILE*   fp;
        !          1102:        BOOL    result=FALSE;
        !          1103: 
        !          1104:        sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
        !          1105:        if((fp=fopen(aliasfile,"r"))==NULL) 
        !          1106:                return(result);
        !          1107: 
        !          1108:        sprintf(alias,"%.*s",(int)sizeof(alias)-1,fullalias);
        !          1109:        p=strrchr(alias+1,'/');
        !          1110:        if(p) {
        !          1111:                *p=0;
        !          1112:                fname=p+1;
        !          1113:        }
        !          1114: 
        !          1115:        while(!feof(fp)) {
        !          1116:                if(!fgets(line,sizeof(line)-1,fp))
        !          1117:                        break;
        !          1118: 
        !          1119:                p=line; /* alias */
        !          1120:                while(*p && *p<=' ') p++;
        !          1121:                if(*p==';')     /* comment */
        !          1122:                        continue;
        !          1123: 
        !          1124:                tp=p;           /* terminator */
        !          1125:                while(*tp && *tp>' ') tp++;
        !          1126:                if(*tp) *tp=0;
        !          1127: 
        !          1128:                if(stricmp(p,alias))    /* Not a match */
        !          1129:                        continue;
        !          1130: 
        !          1131:                p=tp+1;         /* filename */
        !          1132:                while(*p && *p<=' ') p++;
        !          1133: 
        !          1134:                tp=p;           /* terminator */
        !          1135:                while(*tp && *tp>' ') tp++;
        !          1136:                if(*tp) *tp=0;
        !          1137: 
        !          1138:                if(!strnicmp(p,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
        !          1139:                        if((dir=getdir(p+strlen(BBS_VIRTUAL_PATH),user))<0)     {
        !          1140:                                lprintf("0000 !Invalid virtual path (%s) for %s",p,user->alias);
        !          1141:                                /* invalid or no access */
        !          1142:                                continue;
        !          1143:                        }
        !          1144:                        p=strrchr(p,'/');
        !          1145:                        if(p!=NULL) p++;
        !          1146:                        if(p!=NULL && filename!=NULL) {
        !          1147:                                if(*p)
        !          1148:                                        sprintf(filename,"%s%s",scfg.dir[dir]->path,p);
        !          1149:                                else
        !          1150:                                        sprintf(filename,"%s%s",scfg.dir[dir]->path,fname);
        !          1151:                        }
        !          1152:                } else if(filename!=NULL)
        !          1153:                        strcpy(filename,p);
        !          1154: 
        !          1155:                result=TRUE;    /* success */
        !          1156:                break;
        !          1157:        }
        !          1158:        fclose(fp);
        !          1159:        if(curdir!=NULL)
        !          1160:                *curdir=dir;
        !          1161:        return(result);
        !          1162: }
        !          1163: 
        !          1164: char* root_dir(char* path)
        !          1165: {
        !          1166:        char*   p;
        !          1167:        static char     root[MAX_PATH];
        !          1168: 
        !          1169:        sprintf(root,"%.*s",(int)sizeof(root)-1,path);
        !          1170: 
        !          1171:        if(!strncmp(root,"\\\\",2)) {   /* network path */
        !          1172:                p=strchr(root+2,'\\');
        !          1173:                if(p) p=strchr(p+1,'\\');
        !          1174:                if(p) *(p+1)=0;                         /* truncate at \\computer\sharename\ */
        !          1175:        } 
        !          1176:        else if(!strncmp(root+1,":/",2) || !strncmp(root+1,":\\",2))
        !          1177:                root[3]=0;
        !          1178:        else if(*root=='/' || *root=='\\')
        !          1179:                root[1]=0;
        !          1180: 
        !          1181:        return(root);
        !          1182: }
        !          1183: 
        !          1184: static void ctrl_thread(void* arg)
        !          1185: {
        !          1186:        char            buf[512];
        !          1187:        char            str[128];
        !          1188:        char*           cmd;
        !          1189:        char*           p;
        !          1190:        char*           np;
        !          1191:        char*           tp;
        !          1192:        char            password[64];
        !          1193:        char            fname[MAX_PATH];
        !          1194:        char            qwkfile[MAX_PATH];
        !          1195:        char            aliasfile[MAX_PATH];
        !          1196:        char            aliasline[512];
        !          1197:        char            desc[501]="";
        !          1198:        char            sys_pass[128];
        !          1199:        char*           host_name;
        !          1200:        char            host_ip[64];
        !          1201:        char            path[MAX_PATH];
        !          1202:        char            local_dir[MAX_PATH];
        !          1203:        char            ren_from[MAX_PATH]="";
        !          1204:        WORD            port;
        !          1205:        ulong           ip_addr;
        !          1206:        int                     addr_len;
        !          1207:        DWORD           h1,h2,h3,h4;
        !          1208:        u_short         p1,p2;  /* For PORT command */
        !          1209:        int                     i;
        !          1210:        int                     rd;
        !          1211:        int                     file;
        !          1212:        int                     result;
        !          1213:        int                     lib;
        !          1214:        int                     dir;
        !          1215:        int                     curlib=-1;
        !          1216:        int                     curdir=-1;
        !          1217:        int                     orglib;
        !          1218:        int                     orgdir;
        !          1219:        long            filepos=0L;
        !          1220:        long            timeleft;
        !          1221:        ulong           l;
        !          1222:        ulong           avail;
        !          1223:        BOOL            detail;
        !          1224:        BOOL            success;
        !          1225:        BOOL            getdate;
        !          1226:        BOOL            getsize;
        !          1227:        BOOL            delecmd;
        !          1228:        BOOL            delfile;
        !          1229:        BOOL            tmpfile;
        !          1230:        BOOL            credits;
        !          1231:        BOOL            filedat;
        !          1232:        BOOL            transfer_inprogress;
        !          1233:        BOOL            transfer_aborted;
        !          1234:        BOOL            sysop=FALSE;
        !          1235:        BOOL            local_fsys=FALSE;
        !          1236:        BOOL            alias_dir;
        !          1237:        FILE*           fp;
        !          1238:        FILE*           alias_fp;
        !          1239:        SOCKET          sock;
        !          1240:        SOCKET          pasv_sock=INVALID_SOCKET;
        !          1241:        SOCKET          data_sock=INVALID_SOCKET;
        !          1242:        HOSTENT*        host;
        !          1243:        SOCKADDR_IN     addr;
        !          1244:        SOCKADDR_IN     data_addr;
        !          1245:        SOCKADDR_IN     pasv_addr;
        !          1246:        ftp_t           ftp=*(ftp_t*)arg;
        !          1247:        user_t          user;
        !          1248:        time_t          t;
        !          1249:        time_t          now;
        !          1250:        time_t          logintime;
        !          1251:        time_t          lastactive;
        !          1252:        file_t          f;
        !          1253:        glob_t          g;
        !          1254:        node_t          node;
        !          1255:        client_t        client;
        !          1256:        struct tm       tm;
        !          1257:        struct tm *     tm_p;
        !          1258:        struct tm       cur_tm;
        !          1259: 
        !          1260:        thread_up();
        !          1261: 
        !          1262:        lastactive=time(NULL);
        !          1263: 
        !          1264:        sock=ftp.socket;
        !          1265:        data_addr=ftp.client_addr;
        !          1266:        /* Default data port is ctrl port-1 */
        !          1267:        data_addr.sin_port=ntohs(data_addr.sin_port)-1;
        !          1268:        data_addr.sin_port=htons(data_addr.sin_port);
        !          1269:        
        !          1270:        lprintf("%04d CTRL thread started", sock);
        !          1271: 
        !          1272:        free(arg);
        !          1273: 
        !          1274: #ifdef _WIN32
        !          1275:        if(startup->answer_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          1276:                PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          1277: #endif
        !          1278: 
        !          1279:        transfer_inprogress = FALSE;
        !          1280:        transfer_aborted = FALSE;
        !          1281: 
        !          1282:        l=1;
        !          1283: 
        !          1284:        if((i=ioctlsocket(sock, FIONBIO, &l))!=0) {
        !          1285:                lprintf("%04d !ERROR %d (%d) disabling socket blocking"
        !          1286:                        ,sock, i, ERROR_VALUE);
        !          1287:                sockprintf(sock,"425 Error %d disabling socket blocking"
        !          1288:                        ,ERROR_VALUE);
        !          1289:                close_socket(&sock,__LINE__);
        !          1290:                thread_down();
        !          1291:                return;
        !          1292:        }
        !          1293: 
        !          1294:        memset(&user,0,sizeof(user));
        !          1295: 
        !          1296:        strcpy(host_ip,inet_ntoa(ftp.client_addr.sin_addr));
        !          1297: 
        !          1298:        lprintf ("%04d CTRL connection accepted from: %s", sock, host_ip);
        !          1299: 
        !          1300:        if(startup->options&FTP_OPT_NO_HOST_LOOKUP)
        !          1301:                host=NULL;
        !          1302:        else
        !          1303:                host=gethostbyaddr ((char *)&ftp.client_addr.sin_addr
        !          1304:                        ,sizeof(ftp.client_addr.sin_addr),AF_INET);
        !          1305: 
        !          1306:        if(host!=NULL && host->h_name!=NULL)
        !          1307:                host_name=host->h_name;
        !          1308:        else
        !          1309:                host_name="<no name>";
        !          1310: 
        !          1311:        lprintf("%04d Host name: %s", sock, host_name);
        !          1312: 
        !          1313:        if(trashcan(&scfg,host_ip,"ip")) {
        !          1314:                lprintf("%04d !Client blocked in ip.can: %s", sock, host_ip);
        !          1315:                sockprintf(sock,"550 Access denied.");
        !          1316:                close_socket(&sock,__LINE__);
        !          1317:                thread_down();
        !          1318:                return;
        !          1319:        }
        !          1320: 
        !          1321:        if(trashcan(&scfg,host_name,"host")) {
        !          1322:                lprintf("%04d !Client blocked in host.can: %s", sock, host_name);
        !          1323:                sockprintf(sock,"550 Access denied.");
        !          1324:                close_socket(&sock,__LINE__);
        !          1325:                thread_down();
        !          1326:                return;
        !          1327:        }
        !          1328: 
        !          1329:        /* For PASV mode */
        !          1330:        addr_len=sizeof(pasv_addr);
        !          1331:        if((result=getsockname(sock, (struct sockaddr *)&pasv_addr,&addr_len))!=0) {
        !          1332:                lprintf("%04d !ERROR %d (%d) getting address/port", sock, result, ERROR_VALUE);
        !          1333:                sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE);
        !          1334:                close_socket(&sock,__LINE__);
        !          1335:                thread_down();
        !          1336:                return;
        !          1337:        } 
        !          1338: 
        !          1339:        active_clients++;
        !          1340:        update_clients();
        !          1341: 
        !          1342:        /* Initialize client display */
        !          1343:        client.size=sizeof(client);
        !          1344:        client.time=time(NULL);
        !          1345:        sprintf(client.addr,"%.*s",(int)sizeof(client.addr)-1,host_ip);
        !          1346:        sprintf(client.host,"%.*s",(int)sizeof(client.host)-1,host_name);
        !          1347:        client.port=ntohs(ftp.client_addr.sin_port);
        !          1348:        client.protocol="FTP";
        !          1349:        client.user="<unknown>";
        !          1350:        client_on(sock,&client);
        !          1351: 
        !          1352:        sockprintf(sock,"220-%s (%s)",scfg.sys_name, scfg.sys_inetaddr);
        !          1353:        sockprintf(sock," Synchronet FTP Server for %s v%s Ready"
        !          1354:                ,PLATFORM_DESC,FTP_VERSION);
        !          1355:        sprintf(str,"%sftplogin.txt",scfg.text_dir);
        !          1356:        if((fp=fopen(str,"rb"))!=NULL) {
        !          1357:                while(!feof(fp)) {
        !          1358:                        if(!fgets(buf,sizeof(buf),fp))
        !          1359:                                break;
        !          1360:                        truncsp(buf);
        !          1361:                        sockprintf(sock," %s",buf);
        !          1362:                }
        !          1363:                fclose(fp);
        !          1364:        }
        !          1365:        sockprintf(sock,"220 Please enter your user name.");
        !          1366: 
        !          1367:        while(1) {
        !          1368: 
        !          1369:                rd = sockreadline(sock, buf, sizeof(buf), &lastactive);
        !          1370:                if(rd<1) {
        !          1371:                        if(transfer_inprogress==TRUE)
        !          1372:                                transfer_aborted=TRUE;
        !          1373:                        break;
        !          1374:                }
        !          1375:                lastactive=time(NULL);
        !          1376:                cmd=buf;
        !          1377:                while(((BYTE)*cmd)==TELNET_IAC) {
        !          1378:                        cmd++;
        !          1379:                        lprintf("%04d RX: Telnet cmd %d",sock,(BYTE)*cmd);
        !          1380:                        cmd++;
        !          1381:                }
        !          1382:                while(*cmd && *cmd<' ') {
        !          1383:                        lprintf("%04d RX: %d (0x%02X)",sock,(BYTE)*cmd,(BYTE)*cmd);
        !          1384:                        cmd++;
        !          1385:                }
        !          1386:                if(!(*cmd))
        !          1387:                        continue;
        !          1388:                if(startup->options&FTP_OPT_DEBUG_RX)
        !          1389:                        lprintf("%04d RX: %s", sock, cmd);
        !          1390:                if(!stricmp(cmd, "NOOP")) {
        !          1391:                        sockprintf(sock,"200 NOOP command successful.");
        !          1392:                        continue;
        !          1393:                }
        !          1394:                if(!stricmp(cmd, "HELP SITE") || !stricmp(cmd, "SITE HELP")) {
        !          1395:                        sockprintf(sock,"214-The following SITE commands are recognized (* => unimplemented):");
        !          1396:                        sockprintf(sock," HELP    WHO");
        !          1397:                        sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr);
        !          1398:                        continue;
        !          1399:                }
        !          1400:                if(!strnicmp(cmd, "HELP",4)) {
        !          1401:                        sockprintf(sock,"214-The following commands are recognized (* => unimplemented, # => extension):");
        !          1402:                        sockprintf(sock," USER    PASS    CWD     XCWD    CDUP    XCUP    PWD     XPWD");
        !          1403:                        sockprintf(sock," QUIT    REIN    PORT    PASV    LIST    NLST    NOOP    HELP");
        !          1404:                        sockprintf(sock," SIZE    MDTM    RETR    STOR    REST    ALLO    ABOR    SYST");
        !          1405:                        sockprintf(sock," TYPE    STRU    MODE    SITE    RNFR*   RNTO*   DELE*   DESC#");
        !          1406:                        sockprintf(sock," FEAT#   OPTS#");
        !          1407:                        sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr);
        !          1408:                        continue;
        !          1409:                }
        !          1410:                if(!stricmp(cmd, "FEAT")) {
        !          1411:                        sockprintf(sock,"211-The following additional (post-RFC949) features are supported:");
        !          1412:                        sockprintf(sock," DESC");
        !          1413:                        sockprintf(sock," MDTM");
        !          1414:                        sockprintf(sock," SIZE");
        !          1415:                        sockprintf(sock," REST STREAM");
        !          1416:                        sockprintf(sock,"211 End");
        !          1417:                        continue;
        !          1418:                }
        !          1419:                if(!strnicmp(cmd, "OPTS",4)) {
        !          1420:                        sockprintf(sock,"501 No options supported.");
        !          1421:                        continue;
        !          1422:                }
        !          1423:                if(!stricmp(cmd, "QUIT")) {
        !          1424:                        sprintf(str,"%sftpbye.txt",scfg.text_dir);
        !          1425:                        if((fp=fopen(str,"rb"))!=NULL) {
        !          1426:                                i=0;
        !          1427:                                while(!feof(fp)) {
        !          1428:                                        if(!fgets(buf,sizeof(buf),fp))
        !          1429:                                                break;
        !          1430:                                        truncsp(buf);
        !          1431:                                        if(!i)
        !          1432:                                                sockprintf(sock,"221-%s",buf);
        !          1433:                                        else
        !          1434:                                                sockprintf(sock," %s",buf);
        !          1435:                                        i++;
        !          1436:                                }
        !          1437:                                fclose(fp);
        !          1438:                        }
        !          1439:                        sockprintf(sock,"221 Goodbye. Closing control connection.");
        !          1440:                        break;
        !          1441:                }
        !          1442:                if(!strnicmp(cmd, "USER ",5)) {
        !          1443:                        sysop=FALSE;
        !          1444:                        user.number=0;
        !          1445:                        p=cmd+5;
        !          1446:                        while(*p && *p<=' ') p++;
        !          1447:                        truncsp(p);
        !          1448:                        sprintf(user.alias,"%.*s",(int)sizeof(user.alias)-1,p);
        !          1449:                        if(!stricmp(user.alias,"anonymous"))
        !          1450:                                strcpy(user.alias,"guest");
        !          1451:                        user.number=matchuser(&scfg,user.alias);
        !          1452:                        if(user.number && getuserdat(&scfg, &user)==0 && user.pass[0]==0) 
        !          1453:                                sockprintf(sock,"331 User name okay, give your full e-mail address as password.");
        !          1454:                        else
        !          1455:                                sockprintf(sock,"331 User name okay, need password.");
        !          1456:                        continue;
        !          1457:                }
        !          1458:                if(!strnicmp(cmd, "PASS ",5) && user.alias[0]) {
        !          1459:                        user.number=0;
        !          1460:                        p=cmd+5;
        !          1461:                        while(*p && *p<=' ') p++;
        !          1462: 
        !          1463:                        sprintf(password,"%.*s",(int)sizeof(password)-1,p);
        !          1464:                        user.number=matchuser(&scfg,user.alias);
        !          1465:                        if(!user.number) {
        !          1466:                                lprintf("%04d !FTP: UNKNOWN USER: %s",sock,user.alias);
        !          1467:                                sockprintf(sock,"530 Password not accepted.");
        !          1468:                                continue;
        !          1469:                        }
        !          1470:                        if((i=getuserdat(&scfg, &user))!=0) {
        !          1471:                                lprintf("%04d !FTP: ERROR %d getting data on user #%d (%s)"
        !          1472:                                        ,sock,i,user.number,user.alias);
        !          1473:                                sockprintf(sock,"530 Database error %d",i);
        !          1474:                                user.number=0;
        !          1475:                                continue;
        !          1476:                        }
        !          1477:                        if(user.misc&(DELETED|INACTIVE)) {
        !          1478:                                lprintf("%04d !FTP: DELETED or INACTIVE user #%d (%s)"
        !          1479:                                        ,sock,user.number,user.alias);
        !          1480:                                sockprintf(sock,"530 Password not accepted.");
        !          1481:                                user.number=0;
        !          1482:                                continue;
        !          1483:                        }
        !          1484:                        if(user.rest&FLAG('T')) {
        !          1485:                                lprintf("%04d !FTP: 'T' RESTRICTED user #%d (%s)"
        !          1486:                                        ,sock,user.number,user.alias);
        !          1487:                                sockprintf(sock,"530 Password not accepted.");
        !          1488:                                user.number=0;
        !          1489:                                continue;
        !          1490:                        }
        !          1491:                        if(user.ltoday>scfg.level_callsperday[user.level]
        !          1492:                                && !(user.exempt&FLAG('L'))) {
        !          1493:                                lprintf("%04d !FTP: Max logons (%d) reached"
        !          1494:                                        ,sock,scfg.level_callsperday[user.level]);
        !          1495:                                sockprintf(sock,"530 Maximum logons reached.");
        !          1496:                                user.number=0;
        !          1497:                                continue;
        !          1498:                        }
        !          1499:                        if(user.rest&FLAG('L') && user.ltoday>1) {
        !          1500:                                lprintf("%04d !FTP: L Restricted user already on today"
        !          1501:                                        ,sock);
        !          1502:                                sockprintf(sock,"530 Maximum logons reached.");
        !          1503:                                user.number=0;
        !          1504:                                continue;
        !          1505:                        }
        !          1506: 
        !          1507:                        sprintf(sys_pass,"%s:%s",user.pass,scfg.sys_pass);
        !          1508:                        if(!user.pass[0]) {     /* Guest/Anonymous */
        !          1509:                                lprintf("%04d Guest: %s",sock,password);
        !          1510:                                putuserrec(&scfg,user.number,U_NETMAIL,LEN_NETMAIL,password);
        !          1511:                        }
        !          1512:                        else if(user.level>=SYSOP_LEVEL && !stricmp(password,sys_pass)) {
        !          1513:                                lprintf("%04d Sysop access granted to %s", sock, user.alias);
        !          1514:                                sysop=TRUE;
        !          1515:                        }
        !          1516:                        else if(stricmp(password,user.pass)) {
        !          1517:                                lprintf("%04d !FTP: WRONG PASSWORD for user %s: '%s' expected '%s'"
        !          1518:                                        ,sock,user.alias,password,user.pass);
        !          1519:                                sockprintf(sock,"530 Password not accepted.");
        !          1520:                                user.number=0;
        !          1521:                                continue;
        !          1522:                        }
        !          1523: 
        !          1524:                        /* Update client display */
        !          1525:                        client.user=user.alias;
        !          1526:                        client_on(sock,&client);
        !          1527: 
        !          1528: 
        !          1529:                        lprintf("%04d %s logged in.",sock,user.alias);
        !          1530:                        logintime=time(NULL);
        !          1531:                        timeleft=gettimeleft(&scfg,&user,logintime);
        !          1532:                        sprintf(str,"%sftphello.txt",scfg.text_dir);
        !          1533:                        if((fp=fopen(str,"rb"))!=NULL) {
        !          1534:                                i=0;
        !          1535:                                while(!feof(fp)) {
        !          1536:                                        if(!fgets(buf,sizeof(buf),fp))
        !          1537:                                                break;
        !          1538:                                        truncsp(buf);
        !          1539:                                        if(!i)
        !          1540:                                                sockprintf(sock,"230-%s",buf);
        !          1541:                                        else
        !          1542:                                                sockprintf(sock," %s",buf);
        !          1543:                                        i++;
        !          1544:                                }
        !          1545:                                fclose(fp);
        !          1546:                        }
        !          1547:                        if(sysop)
        !          1548:                                sockprintf(sock,"230-Sysop access granted.");
        !          1549:                        sockprintf(sock,"230-%s logged in.",user.alias);
        !          1550:                        if(!(user.exempt&FLAG('D')) && (user.cdt+user.freecdt)>0)
        !          1551:                                sockprintf(sock,"230-You have %lu download credits."
        !          1552:                                        ,user.cdt+user.freecdt);
        !          1553:                        sockprintf(sock,"230 You are allowed %ld minutes of use for this session."
        !          1554:                                ,timeleft/60);
        !          1555:                        sprintf(qwkfile,"%sfile/%04d.qwk",scfg.data_dir,user.number);
        !          1556: 
        !          1557:                        /* Adjust User Total Logons/Logons Today */
        !          1558:                        adjustuserrec(&scfg,user.number,U_LOGONS,5,1);
        !          1559:                        putuserrec(&scfg,user.number,U_LTODAY,5,ultoa(user.ltoday+1,str,10));
        !          1560:                        putuserrec(&scfg,user.number,U_MODEM,LEN_MODEM,"FTP");
        !          1561:                        putuserrec(&scfg,user.number,U_COMP,LEN_COMP,host_name);
        !          1562:                        putuserrec(&scfg,user.number,U_NOTE,LEN_NOTE,host_ip);
        !          1563: 
        !          1564:                        continue;
        !          1565:                }
        !          1566: 
        !          1567:                if(!user.number) {
        !          1568:                        sockprintf(sock,"530 Please login with USER and PASS.");
        !          1569:                        continue;
        !          1570:                }
        !          1571: 
        !          1572:                if((timeleft=gettimeleft(&scfg,&user,logintime))<1L) {
        !          1573:                        sockprintf(sock,"421 Sorry, you've run out of time.");
        !          1574:                        lprintf("%04d Out of time, disconnecting",sock);
        !          1575:                        break;
        !          1576:                }
        !          1577: 
        !          1578:                /********************************/
        !          1579:                /* These commands require login */
        !          1580:                /********************************/
        !          1581: 
        !          1582:                if(!stricmp(cmd, "REIN")) {
        !          1583:                        lprintf("%04d %s reinitialized control session",sock,user.alias);
        !          1584:                        user.number=0;
        !          1585:                        sysop=FALSE;
        !          1586:                        filepos=0;
        !          1587:                        sockprintf(sock,"220 Control session re-initialized. Ready for re-login.");
        !          1588:                        continue;
        !          1589:                }
        !          1590: 
        !          1591:                if(!stricmp(cmd, "SITE WHO")) {
        !          1592:                        sockprintf(sock,"211-Active users");
        !          1593:                        for(i=0;i<scfg.sys_nodes && i<scfg.sys_lastnode;i++) {
        !          1594:                                if((result=getnodedat(&scfg, i+1, &node, 0))!=0) {
        !          1595:                                        sockprintf(sock," Error %d getting data for Telnet Node %d",result,i+1);
        !          1596:                                        continue;
        !          1597:                                }
        !          1598:                                if(node.status==NODE_INUSE)
        !          1599:                                        sockprintf(sock," Telnet Node %3d: %s",i+1, username(&scfg,node.useron,str));
        !          1600:                        }
        !          1601:                        sockprintf(sock,"211 End");
        !          1602:                        continue;
        !          1603:                }
        !          1604: 
        !          1605:                if(!strnicmp(cmd, "PORT ",5)) {
        !          1606:                        p=cmd+5;
        !          1607:                        while(*p && *p<=' ') p++;
        !          1608:                        sscanf(p,"%ld,%ld,%ld,%ld,%hd,%hd",&h1,&h2,&h3,&h4,&p1,&p2);
        !          1609:                        data_addr.sin_addr.s_addr=htonl((h1<<24)|(h2<<16)|(h3<<8)|h4);
        !          1610:                        data_addr.sin_port=htons((u_short)((p1<<8)|p2));
        !          1611:                        sockprintf(sock,"200 PORT Command successful.");
        !          1612:                        continue;
        !          1613:                }
        !          1614: 
        !          1615:                if(!strcmp(cmd, "PASV")) {
        !          1616: 
        !          1617:                        if(pasv_sock!=INVALID_SOCKET) 
        !          1618:                                close_socket(&pasv_sock,__LINE__);
        !          1619: 
        !          1620:                        if((pasv_sock=open_socket(SOCK_STREAM))==INVALID_SOCKET) {
        !          1621:                                lprintf("%04d !PASV ERROR %d opening socket", sock,ERROR_VALUE);
        !          1622:                                sockprintf(sock,"425 Error %d opening PASV data socket", ERROR_VALUE);
        !          1623:                                continue;
        !          1624:                        }
        !          1625: 
        !          1626:                        if(startup->options&FTP_OPT_DEBUG_DATA)
        !          1627:                                lprintf("%04d PASV DATA socket %d opened",sock,pasv_sock);
        !          1628: 
        !          1629:                        pasv_addr.sin_port = 0;
        !          1630: 
        !          1631:                        if((result=bind(pasv_sock, (struct sockaddr *) &pasv_addr,sizeof(pasv_addr)))!= 0) {
        !          1632:                                lprintf("%04d !PASV ERROR %d (%d) binding socket", sock, result, ERROR_VALUE);
        !          1633:                                sockprintf(sock,"425 Error %d binding data socket",ERROR_VALUE);
        !          1634:                                close_socket(&pasv_sock,__LINE__);
        !          1635:                                continue;
        !          1636:                        }
        !          1637: 
        !          1638:                        addr_len=sizeof(addr);
        !          1639:                        if((result=getsockname(pasv_sock, (struct sockaddr *)&addr,&addr_len))!=0) {
        !          1640:                                lprintf("%04d !PASV ERROR %d (%d) getting address/port", sock, result, ERROR_VALUE);
        !          1641:                                sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE);
        !          1642:                                close_socket(&pasv_sock,__LINE__);
        !          1643:                                continue;
        !          1644:                        } 
        !          1645: 
        !          1646:                        if((result=listen(pasv_sock, 1))!= 0) {
        !          1647:                                lprintf("%04d !PASV ERROR %d (%d) listening on socket", sock, result, ERROR_VALUE);
        !          1648:                                sockprintf(sock,"425 Error %d listening on data socket",ERROR_VALUE);
        !          1649:                                close_socket(&pasv_sock,__LINE__);
        !          1650:                                continue;
        !          1651:                        }
        !          1652: 
        !          1653:                        ip_addr=ntohl(pasv_addr.sin_addr.s_addr);
        !          1654:                        port=ntohs(addr.sin_port);
        !          1655:                        sockprintf(sock,"227 Entering Passive Mode (%d,%d,%d,%d,%hd,%hd)"
        !          1656:                                ,(ip_addr>>24)&0xff
        !          1657:                                ,(ip_addr>>16)&0xff
        !          1658:                                ,(ip_addr>>8)&0xff
        !          1659:                                ,ip_addr&0xff
        !          1660:                                ,(port>>8)&0xff
        !          1661:                                ,port&0xff
        !          1662:                                );
        !          1663:                        continue;
        !          1664:                }
        !          1665: 
        !          1666:                if(!strnicmp(cmd, "TYPE ",5)) {
        !          1667:                        sockprintf(sock,"200 All files sent in BINARY mode.");
        !          1668:                        continue;
        !          1669:                }
        !          1670: 
        !          1671:                if(!strnicmp(cmd, "ALLO",4)) {
        !          1672:                        p=cmd+5;
        !          1673:                        while(*p && *p<=' ') p++;
        !          1674:                        if(*p)
        !          1675:                                l=atol(p);      
        !          1676:                        else
        !          1677:                                l=0;
        !          1678:                        if(local_fsys)
        !          1679:                                avail=getfreediskspace(local_dir);
        !          1680:                        else
        !          1681:                                avail=getfreediskspace(scfg.data_dir);  /* Change to temp_dir? */
        !          1682:                        if(l && l>avail)
        !          1683:                                sockprintf(sock,"504 Only %ld bytes available.",avail);
        !          1684:                        else
        !          1685:                                sockprintf(sock,"200 %ld bytes available.",avail);
        !          1686:                        continue;
        !          1687:                }
        !          1688: 
        !          1689:                if(!strnicmp(cmd, "REST",4)) {
        !          1690:                        p=cmd+4;
        !          1691:                        while(*p && *p<=' ') p++;
        !          1692:                        if(*p)
        !          1693:                                filepos=atol(p);
        !          1694:                        else
        !          1695:                                filepos=0;
        !          1696:                        sockprintf(sock,"200 File marker set to %ld",filepos);
        !          1697:                        continue;
        !          1698:                }
        !          1699: 
        !          1700:                if(!strnicmp(cmd, "MODE ",5)) {
        !          1701:                        p=cmd+5;
        !          1702:                        while(*p && *p<=' ') p++;
        !          1703:                        if(toupper(*p)!='S')
        !          1704:                                sockprintf(sock,"504 Only STREAM mode supported.");
        !          1705:                        else
        !          1706:                                sockprintf(sock,"200 STREAM mode.");
        !          1707:                        continue;
        !          1708:                }
        !          1709: 
        !          1710:                if(!strnicmp(cmd, "STRU ",5)) {
        !          1711:                        p=cmd+5;
        !          1712:                        while(*p && *p<=' ') p++;
        !          1713:                        if(toupper(*p)!='F')
        !          1714:                                sockprintf(sock,"504 Only FILE structure supported.");
        !          1715:                        else
        !          1716:                                sockprintf(sock,"200 FILE structure.");
        !          1717:                        continue;
        !          1718:                }
        !          1719: 
        !          1720:                if(!stricmp(cmd, "SYST")) {
        !          1721:                        sockprintf(sock,"215 UNIX Type: L8");
        !          1722:                        continue;
        !          1723:                }
        !          1724: 
        !          1725:                if(!stricmp(cmd, "ABOR")) {
        !          1726:                        if(!transfer_inprogress)
        !          1727:                                sockprintf(sock,"226 No tranfer in progress.");
        !          1728:                        else {
        !          1729:                                transfer_aborted=TRUE;
        !          1730:                                mswait(1); /* give send thread time to abort */
        !          1731:                                sockprintf(sock,"226 Transfer aborted.");
        !          1732:                        }
        !          1733:                        continue;
        !          1734:                }
        !          1735: 
        !          1736:                if(!strnicmp(cmd,"SMNT ",5) && sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) {
        !          1737:                        p=cmd+5;
        !          1738:                        while(*p && *p<=' ') p++;
        !          1739:                        if(!stricmp(p,BBS_FSYS_DIR)) 
        !          1740:                                local_fsys=FALSE;
        !          1741:                        else {
        !          1742:                                if(!direxist(p)) {
        !          1743:                                        sockprintf(sock,"550 Directory does not exist.");
        !          1744:                                        lprintf("%04d !%s attempted to mount invalid directory: %s"
        !          1745:                                                ,sock, user.alias, p);
        !          1746:                                        continue;
        !          1747:                                }
        !          1748:                                local_fsys=TRUE;
        !          1749:                                sprintf(local_dir,"%.*s",(int)sizeof(local_dir)-1,p);
        !          1750:                        }
        !          1751:                        sockprintf(sock,"250 %s file system mounted."
        !          1752:                                ,local_fsys ? "Local" : "BBS");
        !          1753:                        lprintf("%04d %s mounted %s file system"
        !          1754:                                ,sock, user.alias, local_fsys ? "local" : "BBS");
        !          1755:                        continue;
        !          1756:                }
        !          1757: 
        !          1758:                /****************************/
        !          1759:                /* Local File System Access */
        !          1760:                /****************************/
        !          1761:                if(sysop && local_fsys && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) {
        !          1762:                        if(local_dir[0] 
        !          1763:                                && local_dir[strlen(local_dir)-1]!='\\'
        !          1764:                                && local_dir[strlen(local_dir)-1]!='/')
        !          1765:                                strcat(local_dir,"/");
        !          1766: 
        !          1767:                        if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) {    
        !          1768:                                sprintf(fname,"%sftp%d.tx", scfg.data_dir, sock);
        !          1769:                                if((fp=fopen(fname,"w+b"))==NULL) {
        !          1770:                                        lprintf("%04d !ERROR %d opening %s",sock,errno,fname);
        !          1771:                                        sockprintf(sock, "451 Insufficient system storage");
        !          1772:                                        continue;
        !          1773:                                }
        !          1774:                                if(!strnicmp(cmd, "LIST", 4))
        !          1775:                                        detail=TRUE;
        !          1776:                                else
        !          1777:                                        detail=FALSE;
        !          1778: 
        !          1779:                                p=cmd+4;
        !          1780:                                while(*p && *p<=' ') p++;
        !          1781:                                sprintf(path,"%s%s",local_dir, *p ? p : "*");
        !          1782:                                lprintf("%04d %s listing: %s", sock, user.alias, path);
        !          1783:                                sockprintf(sock, "150 Directory of %s%s", local_dir, p);
        !          1784:                        
        !          1785:                                glob(path,0,NULL,&g);
        !          1786:                                for(i=0;i<(int)g.gl_pathc;i++) {
        !          1787:                                        if(detail) {
        !          1788:                                                f.size=flength(g.gl_pathv[i]);
        !          1789:                                                t=fdate(g.gl_pathv[i]);
        !          1790:                                                tm_p=localtime(&t);
        !          1791:                                                if(tm_p==NULL)
        !          1792:                                                        memset(&tm,0,sizeof(tm));
        !          1793:                                                else
        !          1794:                                                        tm=*tm_p;
        !          1795:                                                fprintf(fp,"%crw-r--r--   1 %-8s local %9ld %s %2d "
        !          1796:                                                        ,isdir(g.gl_pathv[i]) ? 'd':'-'
        !          1797:                                                        ,scfg.sys_id
        !          1798:                                                        ,f.size
        !          1799:                                                        ,mon[tm.tm_mon],tm.tm_mday);
        !          1800:                                                if(tm.tm_year==cur_tm.tm_year)
        !          1801:                                                        fprintf(fp,"%02d:%02d %s\r\n"
        !          1802:                                                                ,tm.tm_hour,tm.tm_min
        !          1803:                                                                ,getfname(g.gl_pathv[i]));
        !          1804:                                                else
        !          1805:                                                        fprintf(fp,"%5d %s\r\n"
        !          1806:                                                                ,1900+tm.tm_year
        !          1807:                                                                ,getfname(g.gl_pathv[i]));
        !          1808:                                        } else
        !          1809:                                                fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i]));
        !          1810:                                }
        !          1811:                                globfree(&g);
        !          1812:                                fclose(fp);
        !          1813:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,0L
        !          1814:                                        ,&transfer_inprogress,&transfer_aborted
        !          1815:                                        ,TRUE   /* delfile */
        !          1816:                                        ,TRUE   /* tmpfile */
        !          1817:                                        ,&lastactive,&user,-1,FALSE,FALSE,FALSE,NULL);
        !          1818:                                continue;
        !          1819:                        } /* Local LIST/NLST */
        !          1820:                                
        !          1821:                        if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) {
        !          1822:                            if(!strnicmp(cmd,"CWD ",4))
        !          1823:                                        p=cmd+4;
        !          1824:                                else
        !          1825:                                        p=cmd+5;
        !          1826:                                while(*p && *p<=' ') p++;
        !          1827:                                tp=p;
        !          1828:                                if(*tp=='/' || *tp=='\\') /* /local: and /bbs: are valid */
        !          1829:                                        tp++;
        !          1830:                                if(!strnicmp(tp,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) {
        !          1831:                                        local_fsys=FALSE;
        !          1832:                                        sockprintf(sock,"250 CWD command successful (BBS file system mounted).");
        !          1833:                                        lprintf("%04d %s mounted BBS file system", sock, user.alias);
        !          1834:                                        continue;
        !          1835:                                }
        !          1836:                                if(!strnicmp(tp,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) {
        !          1837:                                        tp+=strlen(LOCAL_FSYS_DIR);     /* already mounted */
        !          1838:                                        p=tp;
        !          1839:                                }
        !          1840: 
        !          1841:                                if(p[1]==':' || !strncmp(p,"\\\\",2))
        !          1842:                                        strcpy(path,p);
        !          1843:                                else if(*p=='/' || *p=='\\')
        !          1844:                                        sprintf(path,"%s%s",root_dir(local_dir),p);
        !          1845:                                else {
        !          1846:                                        sprintf(fname,"%s%s",local_dir,p);
        !          1847:                                        _fullpath(path,fname,sizeof(path));
        !          1848:                                }
        !          1849: 
        !          1850:                                if(!direxist(path)) {
        !          1851:                                        sockprintf(sock,"550 Directory does not exist (%s).",path);
        !          1852:                                        lprintf("%04d !%s attempted to change to an invalid directory: %s"
        !          1853:                                                ,sock, user.alias, path);
        !          1854:                                } else {
        !          1855:                                        strcpy(local_dir,path);
        !          1856:                                        sockprintf(sock,"250 CWD command successful (%s).", local_dir);
        !          1857:                                }
        !          1858:                                continue;
        !          1859:                        } /* Local CWD */
        !          1860: 
        !          1861:                        if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) {
        !          1862:                                sprintf(path,"%s..",local_dir);
        !          1863:                                if(_fullpath(local_dir,path,sizeof(local_dir))==NULL)
        !          1864:                                        sockprintf(sock,"550 Directory does not exist.");
        !          1865:                                else
        !          1866:                                        sockprintf(sock,"200 CDUP command successful.");
        !          1867:                                continue;
        !          1868:                        }
        !          1869: 
        !          1870:                        if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) {
        !          1871:                                if(strlen(local_dir)>3)
        !          1872:                                        local_dir[strlen(local_dir)-1]=0;       /* truncate '/' */
        !          1873: 
        !          1874:                                sockprintf(sock,"257 \"%s\" is current directory."
        !          1875:                                        ,local_dir);
        !          1876:                                continue;
        !          1877:                        } /* Local PWD */
        !          1878: 
        !          1879:                        if(!strnicmp(cmd, "MKD ", 4) || !strnicmp(cmd,"XMKD",4)) {
        !          1880:                                p=cmd+4;
        !          1881:                                while(*p && *p<=' ') p++;
        !          1882:                                if(*p=='/')     /* absolute */
        !          1883:                                        sprintf(fname,"%s%s",root_dir(local_dir),p+1);
        !          1884:                                else            /* relative */
        !          1885:                                        sprintf(fname,"%s%s",local_dir,p);
        !          1886: 
        !          1887:                                if((i=_mkdir(fname))==0) {
        !          1888:                                        sockprintf(sock,"257 \"%s\" directory created",fname);
        !          1889:                                        lprintf("%04d %s created directory: %s",sock,user.alias,fname);
        !          1890:                                } else {
        !          1891:                                        sockprintf(sock,"521 Error %d creating directory: %s",i,fname);
        !          1892:                                        lprintf("%04d !%s attempted to create directory: %s (Error %d)"
        !          1893:                                                ,sock,user.alias,fname,i);
        !          1894:                                }
        !          1895:                                continue;
        !          1896:                        }
        !          1897: 
        !          1898:                        if(!strnicmp(cmd, "RMD ", 4) || !strnicmp(cmd,"XRMD",4)) {
        !          1899:                                p=cmd+4;
        !          1900:                                while(*p && *p<=' ') p++;
        !          1901:                                if(*p=='/')     /* absolute */
        !          1902:                                        sprintf(fname,"%s%s",root_dir(local_dir),p+1);
        !          1903:                                else            /* relative */
        !          1904:                                        sprintf(fname,"%s%s",local_dir,p);
        !          1905: 
        !          1906:                                if((i=_rmdir(fname))==0) {
        !          1907:                                        sockprintf(sock,"250 \"%s\" directory removed",fname);
        !          1908:                                        lprintf("%04d %s removed directory: %s",sock,user.alias,fname);
        !          1909:                                } else {
        !          1910:                                        sockprintf(sock,"450 Error %d removing directory: %s",i,fname);
        !          1911:                                        lprintf("%04d !%s attempted to remove directory: %s (Error %d)"
        !          1912:                                                ,sock,user.alias,fname,i);
        !          1913:                                }
        !          1914:                                continue;
        !          1915:                        }
        !          1916: 
        !          1917:                        if(!strnicmp(cmd, "RNFR ",5)) {
        !          1918:                                p=cmd+5;
        !          1919:                                while(*p && *p<=' ') p++;
        !          1920:                                if(*p=='/')     /* absolute */
        !          1921:                                        sprintf(ren_from,"%s%s",root_dir(local_dir),p+1);
        !          1922:                                else            /* relative */
        !          1923:                                        sprintf(ren_from,"%s%s",local_dir,p);
        !          1924:                                if(!fexist(ren_from)) {
        !          1925:                                        sockprintf(sock,"550 File not found: %s",ren_from);
        !          1926:                                        lprintf("%04d !%s attempted to rename %s (not found)"
        !          1927:                                                ,sock,user.alias,ren_from);
        !          1928:                                } else
        !          1929:                                        sockprintf(sock,"350 File exists, ready for destination name");
        !          1930:                                continue;
        !          1931:                        }
        !          1932: 
        !          1933:                        if(!strnicmp(cmd, "RNTO ",5)) {
        !          1934:                                p=cmd+5;
        !          1935:                                while(*p && *p<=' ') p++;
        !          1936:                                if(*p=='/')     /* absolute */
        !          1937:                                        sprintf(fname,"%s%s",root_dir(local_dir),p+1);
        !          1938:                                else            /* relative */
        !          1939:                                        sprintf(fname,"%s%s",local_dir,p);
        !          1940: 
        !          1941:                                if((i=rename(ren_from, fname))==0) {
        !          1942:                                        sockprintf(sock,"250 \"%s\" renamed to \"%s\"",ren_from,fname);
        !          1943:                                        lprintf("%04d %s renamed %s to %s",sock,user.alias,ren_from,fname);
        !          1944:                                } else {
        !          1945:                                        sockprintf(sock,"450 Error %d renaming file: %s",i,ren_from);
        !          1946:                                        lprintf("%04d !%s attempted to rename file: %s (Error %d)"
        !          1947:                                                ,sock,user.alias,ren_from,i);
        !          1948:                                }
        !          1949:                                continue;
        !          1950:                        }
        !          1951: 
        !          1952: 
        !          1953:                        if(!strnicmp(cmd, "RETR ", 5) || !strnicmp(cmd,"SIZE ",5) 
        !          1954:                                || !strnicmp(cmd, "MDTM ",5) || !strnicmp(cmd, "DELE ",5)) {
        !          1955:                                p=cmd+5;
        !          1956:                                while(*p && *p<=' ') p++;
        !          1957: 
        !          1958:                                if(!strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) 
        !          1959:                                        p+=strlen(LOCAL_FSYS_DIR);      /* already mounted */
        !          1960: 
        !          1961:                                if(p[1]==':')           /* drive specified */
        !          1962:                                        strcpy(fname,p);
        !          1963:                                else if(*p=='/')        /* absolute, current drive */
        !          1964:                                        sprintf(fname,"%s%s",root_dir(local_dir),p+1);
        !          1965:                                else            /* relative */
        !          1966:                                        sprintf(fname,"%s%s",local_dir,p);
        !          1967:                                if(!fexist(fname)) {
        !          1968:                                        lprintf("%04d !%s file not found: %s",sock,user.alias,fname);
        !          1969:                                        sockprintf(sock,"550 File not found: %s",fname);
        !          1970:                                        continue;
        !          1971:                                }
        !          1972:                                if(!strnicmp(cmd,"SIZE ",5)) {
        !          1973:                                        sockprintf(sock,"213 %lu",flength(fname));
        !          1974:                                        continue;
        !          1975:                                }
        !          1976:                                if(!strnicmp(cmd,"MDTM ",5)) {
        !          1977:                                        t=fdate(fname);
        !          1978:                                        tm_p=gmtime(&t);
        !          1979:                                        if(tm_p==NULL)
        !          1980:                                                memset(&tm,0,sizeof(tm));
        !          1981:                                        else
        !          1982:                                                tm=*tm_p;
        !          1983:                                        sockprintf(sock,"213 %u%02u%02u%02u%02u%02u"
        !          1984:                                                ,1900+tm.tm_year,tm.tm_mon+1,tm.tm_mday
        !          1985:                                                ,tm.tm_hour,tm.tm_min,tm.tm_sec);                                       
        !          1986:                                        continue;
        !          1987:                                }
        !          1988:                                if(!strnicmp(cmd,"DELE ",5)) {
        !          1989:                                        if((i=remove(fname))==0) {
        !          1990:                                                sockprintf(sock,"250 \"%s\" removed successfully.",fname);
        !          1991:                                                lprintf("%04d %s deleted file: %s",sock,user.alias,fname);
        !          1992:                                        } else {
        !          1993:                                                sockprintf(sock,"450 Error %d removing file: %s",i,fname);
        !          1994:                                                lprintf("%04d !%s attempted to delete file: %s (Error %d)"
        !          1995:                                                        ,sock,user.alias,fname,i);
        !          1996:                                        }
        !          1997:                                        continue;
        !          1998:                                }
        !          1999:                                /* RETR */
        !          2000:                                lprintf("%04d %s downloading: %s (%ld bytes)"
        !          2001:                                        ,sock,user.alias,fname,flength(fname));
        !          2002:                                sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          2003:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          2004:                                        ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
        !          2005:                                        ,&lastactive,&user,-1,FALSE,FALSE,FALSE,NULL);
        !          2006:                                continue;
        !          2007:                        } /* Local RETR/SIZE/MDTM */
        !          2008: 
        !          2009:                        if(!strnicmp(cmd, "STOR ", 5) || !strnicmp(cmd, "APPE ", 5)) {
        !          2010:                                p=cmd+5;
        !          2011:                                while(*p && *p<=' ') p++;
        !          2012: 
        !          2013:                                if(!strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) 
        !          2014:                                        p+=strlen(LOCAL_FSYS_DIR);      /* already mounted */
        !          2015: 
        !          2016:                                if(p[1]==':')           /* drive specified */
        !          2017:                                        strcpy(fname,p);
        !          2018:                                else if(*p=='/')        /* absolute, current drive */
        !          2019:                                        sprintf(fname,"%s%s",root_dir(local_dir),p+1);
        !          2020:                                else                            /* relative */
        !          2021:                                        sprintf(fname,"%s%s",local_dir,p);
        !          2022: 
        !          2023:                                lprintf("%04d %s uploading %s", sock,user.alias,fname);
        !          2024:                                sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          2025:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          2026:                                        ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
        !          2027:                                        ,&lastactive
        !          2028:                                        ,&user
        !          2029:                                        ,-1             /* dir */
        !          2030:                                        ,TRUE   /* uploading */
        !          2031:                                        ,FALSE  /* credits */
        !          2032:                                        ,!strnicmp(cmd,"APPE",4) ? TRUE : FALSE /* append */
        !          2033:                                        ,NULL   /* desc */
        !          2034:                                        );
        !          2035:                                filepos=0;
        !          2036:                                continue;
        !          2037:                        } /* Local STOR */
        !          2038:                }
        !          2039: 
        !          2040:                if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) {    
        !          2041:                        dir=curdir;
        !          2042:                        lib=curlib;
        !          2043: 
        !          2044:                        if(cmd[4]!=0) 
        !          2045:                                lprintf("%04d LIST/NLST: %s",sock,cmd);
        !          2046: 
        !          2047:                        /* path specified? */
        !          2048:                        p=cmd+4;
        !          2049:                        while(*p && *p<=' ') p++;
        !          2050: 
        !          2051:                        if(*p=='-') {   /* -Letc */
        !          2052:                                while(*p && *p>' ') p++;
        !          2053:                                while(*p && *p<=' ') p++;
        !          2054:                        }
        !          2055: 
        !          2056:                        parsepath(&p,&user,&lib,&dir);
        !          2057: 
        !          2058:                        sprintf(fname,"%sftp%d.tx", scfg.data_dir, sock);
        !          2059:                        if((fp=fopen(fname,"w+b"))==NULL) {
        !          2060:                                lprintf("%04d !ERROR %d opening %s",sock,errno,fname);
        !          2061:                                sockprintf(sock, "451 Insufficient system storage");
        !          2062:                                continue;
        !          2063:                        }
        !          2064:                        if(!strnicmp(cmd, "LIST", 4))
        !          2065:                                detail=TRUE;
        !          2066:                        else
        !          2067:                                detail=FALSE;
        !          2068:                        sockprintf(sock,"150 Opening ASCII mode data connection for /bin/ls.");
        !          2069:                        now=time(NULL);
        !          2070:                        tm_p=localtime(&now);
        !          2071:                        if(tm_p==NULL) 
        !          2072:                                memset(&cur_tm,0,sizeof(cur_tm));
        !          2073:                        else
        !          2074:                                cur_tm=*tm_p;
        !          2075: 
        !          2076:                        if(startup->options&FTP_OPT_INDEX_FILE && startup->index_file_name[0]
        !          2077:                                && (!stricmp(p,startup->index_file_name) || *p==0 || *p=='*')) {
        !          2078:                                if(detail)
        !          2079:                                        fprintf(fp,"-rw-r--r--   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          2080:                                                ,NAME_LEN
        !          2081:                                                ,scfg.sys_id
        !          2082:                                                ,lib<0 ? scfg.sys_id : dir<0 
        !          2083:                                                        ? scfg.lib[lib]->sname : scfg.dir[dir]->code
        !          2084:                                                ,512L
        !          2085:                                                ,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          2086:                                                ,startup->index_file_name);
        !          2087:                                else
        !          2088:                                        fprintf(fp,"%s\r\n",startup->index_file_name);
        !          2089:                        } 
        !          2090:                        if(lib<0) { /* Root dir */
        !          2091:                                lprintf("%04d %s listing: root",sock,user.alias);
        !          2092: 
        !          2093:                                /* QWK Packet */
        !          2094:                                if(startup->options&FTP_OPT_ALLOW_QWK/* && fexist(qwkfile)*/) {
        !          2095:                                        if(detail) {
        !          2096:                                                if(fexist(qwkfile)) {
        !          2097:                                                        t=fdate(qwkfile);
        !          2098:                                                        l=flength(qwkfile);
        !          2099:                                                } else {
        !          2100:                                                        t=time(NULL);
        !          2101:                                                        l=10240;
        !          2102:                                                };
        !          2103:                                                tm_p=localtime(&t);
        !          2104:                                                if(tm_p==NULL) 
        !          2105:                                                        memset(&tm,0,sizeof(tm));
        !          2106:                                                else
        !          2107:                                                        tm=*tm_p;
        !          2108:                                                fprintf(fp,"-rw-r--r--   1 %-*s %-8s %9ld %s %2d %02d:%02d %s.qwk\r\n"
        !          2109:                                                        ,NAME_LEN
        !          2110:                                                        ,scfg.sys_id
        !          2111:                                                        ,scfg.sys_id
        !          2112:                                                        ,l
        !          2113:                                                        ,mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min
        !          2114:                                                        ,scfg.sys_id);
        !          2115:                                        } else
        !          2116:                                                fprintf(fp,"%s.qwk\r\n",scfg.sys_id);
        !          2117:                                } 
        !          2118: 
        !          2119:                                /* File Aliases */
        !          2120:                                sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
        !          2121:                                if((alias_fp=fopen(aliasfile,"r"))!=NULL) {
        !          2122: 
        !          2123:                                        while(!feof(alias_fp)) {
        !          2124:                                                if(!fgets(aliasline,sizeof(aliasline)-1,alias_fp))
        !          2125:                                                        break;
        !          2126: 
        !          2127:                                                alias_dir=FALSE;
        !          2128: 
        !          2129:                                                p=aliasline;            /* alias pointer */
        !          2130:                                                while(*p && *p<=' ') p++;
        !          2131: 
        !          2132:                                                if(*p==';')     /* comment */
        !          2133:                                                        continue;
        !          2134: 
        !          2135:                                                tp=p;           /* terminator pointer */
        !          2136:                                                while(*tp && *tp>' ') tp++;
        !          2137:                                                if(*tp) *tp=0;
        !          2138: 
        !          2139:                                                np=tp+1;        /* filename pointer */
        !          2140:                                                while(*np && *np<=' ') np++;
        !          2141: 
        !          2142:                                                tp=np;          /* terminator pointer */
        !          2143:                                                while(*tp && *tp>' ') tp++;
        !          2144:                                                if(*tp) *tp=0;
        !          2145: 
        !          2146:                                                /* Virtual Path? */
        !          2147:                                                if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
        !          2148:                                                        if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),&user))<0)
        !          2149:                                                                continue; /* No access or invalid virtual path */
        !          2150:                                                        tp=strrchr(np,'/');
        !          2151:                                                        if(tp==NULL) 
        !          2152:                                                                continue;
        !          2153:                                                        tp++;
        !          2154:                                                        if(*tp) {
        !          2155:                                                                sprintf(aliasfile,"%s%s",scfg.dir[dir]->path,tp);
        !          2156:                                                                np=aliasfile;
        !          2157:                                                        }
        !          2158:                                                        else 
        !          2159:                                                                alias_dir=TRUE;
        !          2160:                                                }
        !          2161: 
        !          2162:                                                if(!alias_dir && !fexist(np))
        !          2163:                                                        continue;
        !          2164: 
        !          2165:                                                if(detail) {
        !          2166: 
        !          2167:                                                        if(alias_dir==TRUE) {
        !          2168:                                                                fprintf(fp,"drwxr-xr-x   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          2169:                                                                        ,NAME_LEN
        !          2170:                                                                        ,scfg.sys_id
        !          2171:                                                                        ,scfg.lib[scfg.dir[dir]->lib]->sname
        !          2172:                                                                        ,512L
        !          2173:                                                                        ,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          2174:                                                                        ,p);
        !          2175:                                                        }
        !          2176:                                                        else {
        !          2177:                                                                t=fdate(np);
        !          2178:                                                                tm_p=localtime(&t);
        !          2179:                                                                if(tm_p==NULL)
        !          2180:                                                                        memset(&tm,0,sizeof(tm));
        !          2181:                                                                else
        !          2182:                                                                        tm=*tm_p;
        !          2183:                                                                fprintf(fp,"-rw-r--r--   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          2184:                                                                        ,NAME_LEN
        !          2185:                                                                        ,scfg.sys_id
        !          2186:                                                                        ,scfg.sys_id
        !          2187:                                                                        ,flength(np)
        !          2188:                                                                        ,mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min
        !          2189:                                                                        ,p);
        !          2190:                                                        }
        !          2191:                                                } else
        !          2192:                                                        fprintf(fp,"%s\r\n",p);
        !          2193: 
        !          2194:                                        }
        !          2195: 
        !          2196:                                        fclose(alias_fp);
        !          2197:                                }
        !          2198: 
        !          2199:                                /* Library folders */
        !          2200:                                for(i=0;i<scfg.total_libs;i++) {
        !          2201:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          2202:                                                continue;
        !          2203:                                        if(detail)
        !          2204:                                                fprintf(fp,"drwxr-xr-x   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          2205:                                                        ,NAME_LEN
        !          2206:                                                        ,scfg.sys_id
        !          2207:                                                        ,scfg.sys_id
        !          2208:                                                        ,512L
        !          2209:                                                        ,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          2210:                                                        ,scfg.lib[i]->sname);
        !          2211:                                        else
        !          2212:                                                fprintf(fp,"%s\r\n",scfg.lib[i]->sname);
        !          2213:                                }
        !          2214:                        } else if(dir<0) {
        !          2215:                                lprintf("%04d %s listing: %s library",sock,user.alias,scfg.lib[lib]->sname);
        !          2216:                                for(i=0;i<scfg.total_dirs;i++) {
        !          2217:                                        if(scfg.dir[i]->lib!=lib)
        !          2218:                                                continue;
        !          2219:                                        if(i!=scfg.sysop_dir && i!=scfg.upload_dir 
        !          2220:                                                && !chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          2221:                                                continue;
        !          2222:                                        if(detail)
        !          2223:                                                fprintf(fp,"drwxr-xr-x   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          2224:                                                        ,NAME_LEN
        !          2225:                                                        ,scfg.sys_id
        !          2226:                                                        ,scfg.lib[lib]->sname
        !          2227:                                                        ,512L
        !          2228:                                                        ,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          2229:                                                        ,scfg.dir[i]->code);
        !          2230:                                        else
        !          2231:                                                fprintf(fp,"%s\r\n",scfg.dir[i]->code);
        !          2232:                                }
        !          2233:                        } else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user)) {
        !          2234:                                lprintf("%04d %s listing: %s/%s directory"
        !          2235:                                        ,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code);
        !          2236: 
        !          2237:                                sprintf(path,"%s%s",scfg.dir[dir]->path,*p ? p : "*");
        !          2238:                                glob(path,0,NULL,&g);
        !          2239:                                for(i=0;i<(int)g.gl_pathc;i++) {
        !          2240:                                        if(isdir(g.gl_pathv[i]))
        !          2241:                                                continue;
        !          2242: #ifdef _WIN32
        !          2243:                                        GetShortPathName(g.gl_pathv[i], str, sizeof(str));
        !          2244: #else
        !          2245:                                        strcpy(str,g.gl_pathv[i]);
        !          2246: #endif
        !          2247:                                        padfname(getfname(str),f.name);
        !          2248:                                        strupr(f.name);
        !          2249:                                        f.dir=dir;
        !          2250:                                        if((filedat=getfileixb(&scfg,&f))==FALSE
        !          2251:                                                && !(startup->options&FTP_OPT_DIR_FILES))
        !          2252:                                                continue;
        !          2253:                                        if(detail) {
        !          2254:                                                f.size=flength(g.gl_pathv[i]);
        !          2255:                                                getfiledat(&scfg,&f);
        !          2256:                                                t=fdate(g.gl_pathv[i]);
        !          2257:                                                tm_p=localtime(&t);
        !          2258:                                                if(tm_p==NULL)
        !          2259:                                                        memset(&tm,0,sizeof(tm));
        !          2260:                                                else
        !          2261:                                                        tm=*tm_p;
        !          2262:                                                fprintf(fp,"-rw-r--r--   1 %-*s %-8s %9ld %s %2d "
        !          2263:                                                        ,NAME_LEN
        !          2264:                                                        ,filedat ? dotname(f.uler,str) : scfg.sys_id
        !          2265:                                                        ,scfg.dir[dir]->code
        !          2266:                                                        ,f.size
        !          2267:                                                        ,mon[tm.tm_mon],tm.tm_mday);
        !          2268:                                                if(tm.tm_year==cur_tm.tm_year)
        !          2269:                                                        fprintf(fp,"%02d:%02d %s\r\n"
        !          2270:                                                                ,tm.tm_hour,tm.tm_min
        !          2271:                                                                ,getfname(g.gl_pathv[i]));
        !          2272:                                                else
        !          2273:                                                        fprintf(fp,"%5d %s\r\n"
        !          2274:                                                                ,1900+tm.tm_year
        !          2275:                                                                ,getfname(g.gl_pathv[i]));
        !          2276:                                        } else
        !          2277:                                                fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i]));
        !          2278:                                }
        !          2279:                                globfree(&g);
        !          2280:                        } else 
        !          2281:                                lprintf("%04d %s listing: %s/%s directory (empty - no access)"
        !          2282:                                        ,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code);
        !          2283: 
        !          2284:                        fclose(fp);
        !          2285:                        filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,0L
        !          2286:                                ,&transfer_inprogress,&transfer_aborted
        !          2287:                                ,TRUE /* delfile */
        !          2288:                                ,TRUE /* tmpfile */
        !          2289:                                ,&lastactive,&user,dir,FALSE,FALSE,FALSE,NULL);
        !          2290:                        continue;
        !          2291:                }
        !          2292: 
        !          2293:                if(!strnicmp(cmd, "RETR ", 5) 
        !          2294:                        || !strnicmp(cmd, "SIZE ",5) 
        !          2295:                        || !strnicmp(cmd, "MDTM ",5)
        !          2296:                        || !strnicmp(cmd, "DELE ",5)) {
        !          2297:                        getdate=FALSE;
        !          2298:                        getsize=FALSE;
        !          2299:                        delecmd=FALSE;
        !          2300:                        if(!strnicmp(cmd,"SIZE ",5))
        !          2301:                                getsize=TRUE;
        !          2302:                        else if(!strnicmp(cmd,"MDTM ",5))
        !          2303:                                getdate=TRUE;
        !          2304:                        else if(!strnicmp(cmd,"DELE ",5))
        !          2305:                                delecmd=TRUE;
        !          2306: 
        !          2307:                        if(!getsize && !getdate && user.rest&FLAG('D')) {
        !          2308:                                sockprintf(sock,"550 Insufficient access.");
        !          2309:                                filepos=0;
        !          2310:                                continue;
        !          2311:                        }
        !          2312:                        credits=TRUE;
        !          2313:                        success=FALSE;
        !          2314:                        delfile=FALSE;
        !          2315:                        tmpfile=FALSE;
        !          2316:                        lib=curlib;
        !          2317:                        dir=curdir;
        !          2318: 
        !          2319:                        p=cmd+5;
        !          2320:                        while(*p && *p<=' ') p++;
        !          2321: 
        !          2322:                        if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) 
        !          2323:                                p+=strlen(BBS_FSYS_DIR);        /* already mounted */
        !          2324: 
        !          2325:                        if(*p=='/') {
        !          2326:                                lib=-1;
        !          2327:                                p++;
        !          2328:                        }
        !          2329:                        else if(!strncmp(p,"./",2))
        !          2330:                                p+=2;
        !          2331: 
        !          2332:                        if(lib<0 && alias(p, fname, &user, &dir)==TRUE) {
        !          2333:                                success=TRUE;
        !          2334:                                credits=TRUE;   /* include in d/l stats */
        !          2335:                                tmpfile=FALSE;
        !          2336:                                delfile=FALSE;
        !          2337:                                lprintf("%04d %s %.4s by alias: %s"
        !          2338:                                        ,sock,user.alias,cmd,p);
        !          2339:                                p=getfname(fname);
        !          2340:                                if(dir>=0)
        !          2341:                                        lib=scfg.dir[dir]->lib;
        !          2342:                        }
        !          2343:                        if(!success && lib<0 && (tp=strchr(p,'/'))!=NULL) {
        !          2344:                                dir=-1;
        !          2345:                                *tp=0;
        !          2346:                                for(i=0;i<scfg.total_libs;i++) {
        !          2347:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          2348:                                                continue;
        !          2349:                                        if(!stricmp(scfg.lib[i]->sname,p))
        !          2350:                                                break;
        !          2351:                                }
        !          2352:                                if(i<scfg.total_libs) 
        !          2353:                                        lib=i;
        !          2354:                                p=tp+1;
        !          2355:                        }
        !          2356:                        if(!success && dir<0 && (tp=strchr(p,'/'))!=NULL) {
        !          2357:                                *tp=0;
        !          2358:                                for(i=0;i<scfg.total_dirs;i++) {
        !          2359:                                        if(scfg.dir[i]->lib!=lib)
        !          2360:                                                continue;
        !          2361:                                        if(!chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          2362:                                                continue;
        !          2363:                                        if(!stricmp(scfg.dir[i]->code,p))
        !          2364:                                                break;
        !          2365:                                }
        !          2366:                                if(i<scfg.total_dirs) 
        !          2367:                                        dir=i;
        !          2368:                                p=tp+1;
        !          2369:                        }
        !          2370: 
        !          2371:                        sprintf(str,"%s.qwk",scfg.sys_id);
        !          2372:                        if(lib<0 && startup->options&FTP_OPT_ALLOW_QWK 
        !          2373:                                && !stricmp(p,str) && !delecmd) {
        !          2374:                                lprintf("%04d %s creating/updating QWK packet...",sock,user.alias);
        !          2375:                                sprintf(str,"%spack%04u.now",scfg.data_dir,user.number);
        !          2376:                                if((file=open(str,O_WRONLY|O_CREAT,S_IWRITE))==-1) {
        !          2377:                                        lprintf("%04d !ERROR %d opening %s",sock, errno, str);
        !          2378:                                        sockprintf(sock, "451 !ERROR %d creating semaphore file",errno);
        !          2379:                                        filepos=0;
        !          2380:                                        continue;
        !          2381:                                }
        !          2382:                                close(file);
        !          2383:                                t=time(NULL);
        !          2384:                                while(fexist(str)) {
        !          2385:                                        if(time(NULL)-t>300)
        !          2386:                                                break;
        !          2387:                                        mswait(500);
        !          2388:                                }
        !          2389:                                if(fexist(str)) {
        !          2390:                                        lprintf("%04d !TIMEOUT waiting for QWK packet creation",sock);
        !          2391:                                        sockprintf(sock,"451 Time-out waiting for packet creation.");
        !          2392:                                        remove(str);
        !          2393:                                        filepos=0;
        !          2394:                                        continue;
        !          2395:                                }
        !          2396:                                if(!fexist(qwkfile)) {
        !          2397:                                        lprintf("%04d No QWK Packet created (no new messages)",sock);
        !          2398:                                        sockprintf(sock,"550 No QWK packet created (no new messages)");
        !          2399:                                        filepos=0;
        !          2400:                                        continue;
        !          2401:                                }
        !          2402:                                strcpy(fname,qwkfile);
        !          2403:                                success=TRUE;
        !          2404:                                delfile=TRUE;
        !          2405:                                credits=FALSE;
        !          2406:                                lprintf("%04d %s downloading QWK packet (%ld bytes)"
        !          2407:                                        ,sock,user.alias,flength(fname));
        !          2408:                        } else if(startup->options&FTP_OPT_INDEX_FILE 
        !          2409:                                && !stricmp(p,startup->index_file_name)
        !          2410:                                && !delecmd) {
        !          2411:                                sprintf(fname,"%sftp%d.tx", scfg.data_dir, sock);
        !          2412:                                if((fp=fopen(fname,"w+b"))==NULL) {
        !          2413:                                        lprintf("%04d !ERROR %d opening %s",sock,errno,fname);
        !          2414:                                        sockprintf(sock, "451 Insufficient system storage");
        !          2415:                                        filepos=0;
        !          2416:                                        continue;
        !          2417:                                }
        !          2418:                                if(!getsize && !getdate)
        !          2419:                                        lprintf("%04d %s downloading index",sock,user.alias);
        !          2420:                                success=TRUE;
        !          2421:                                credits=FALSE;
        !          2422:                                tmpfile=TRUE;
        !          2423:                                delfile=TRUE;
        !          2424:                                fprintf(fp,"%-*s File/Folder Descriptions\r\n"
        !          2425:                                        ,INDEX_FNAME_LEN,startup->index_file_name);
        !          2426:                                if(lib<0) {
        !          2427: 
        !          2428:                                        /* File Aliases */
        !          2429:                                        sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
        !          2430:                                        if((alias_fp=fopen(aliasfile,"r"))!=NULL) {
        !          2431: 
        !          2432:                                                while(!feof(alias_fp)) {
        !          2433:                                                        if(!fgets(aliasline,sizeof(aliasline)-1,alias_fp))
        !          2434:                                                                break;
        !          2435: 
        !          2436:                                                        p=aliasline;    /* alias pointer */
        !          2437:                                                        while(*p && *p<=' ') p++;
        !          2438: 
        !          2439:                                                        if(*p==';')     /* comment */
        !          2440:                                                                continue;
        !          2441: 
        !          2442:                                                        tp=p;           /* terminator pointer */
        !          2443:                                                        while(*tp && *tp>' ') tp++;
        !          2444:                                                        if(*tp) *tp=0;
        !          2445: 
        !          2446:                                                        np=tp+1;        /* filename pointer */
        !          2447:                                                        while(*np && *np<=' ') np++;
        !          2448: 
        !          2449:                                                        np++;           /* description pointer */
        !          2450:                                                        while(*np && *np>' ') np++;
        !          2451: 
        !          2452:                                                        while(*np && *np<' ') np++;
        !          2453: 
        !          2454:                                                        truncsp(np);
        !          2455: 
        !          2456:                                                        fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN,p,np);
        !          2457:                                                }
        !          2458: 
        !          2459:                                                fclose(alias_fp);
        !          2460:                                        }
        !          2461: 
        !          2462:                                        /* QWK Packet */
        !          2463:                                        if(startup->options&FTP_OPT_ALLOW_QWK /* && fexist(qwkfile) */) {
        !          2464:                                                sprintf(str,"%s.qwk",scfg.sys_id);
        !          2465:                                                fprintf(fp,"%-*s QWK Message Packet\r\n"
        !          2466:                                                        ,INDEX_FNAME_LEN,str);
        !          2467:                                        }
        !          2468: 
        !          2469:                                        /* Library Folders */
        !          2470:                                        for(i=0;i<scfg.total_libs;i++) {
        !          2471:                                                if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          2472:                                                        continue;
        !          2473:                                                fprintf(fp,"%-*s %s\r\n"
        !          2474:                                                        ,INDEX_FNAME_LEN,scfg.lib[i]->sname,scfg.lib[i]->lname);
        !          2475:                                        }
        !          2476:                                } else if(dir<0) {
        !          2477:                                        for(i=0;i<scfg.total_dirs;i++) {
        !          2478:                                                if(scfg.dir[i]->lib!=lib)
        !          2479:                                                        continue;
        !          2480:                                                if(i!=scfg.sysop_dir && i!=scfg.upload_dir
        !          2481:                                                        && !chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          2482:                                                        continue;
        !          2483:                                                fprintf(fp,"%-*s %s\r\n"
        !          2484:                                                        ,INDEX_FNAME_LEN,scfg.dir[i]->code,scfg.dir[i]->lname);
        !          2485:                                        }
        !          2486:                                } else {
        !          2487:                                        sprintf(cmd,"%s*",scfg.dir[dir]->path);
        !          2488:                                        glob(cmd,0,NULL,&g);
        !          2489:                                        for(i=0;i<(int)g.gl_pathc;i++) {
        !          2490:                                                if(isdir(g.gl_pathv[i]))
        !          2491:                                                        continue;
        !          2492: #ifdef _WIN32
        !          2493:                                                GetShortPathName(g.gl_pathv[i], str, sizeof(str));
        !          2494: #else
        !          2495:                                                strcpy(str,g.gl_pathv[i]);
        !          2496: #endif
        !          2497:                                                padfname(getfname(str),f.name);
        !          2498:                                                strupr(f.name);
        !          2499:                                                f.dir=dir;
        !          2500:                                                if(getfileixb(&scfg,&f)) {
        !          2501:                                                        f.size=flength(g.gl_pathv[i]);
        !          2502:                                                        getfiledat(&scfg,&f);
        !          2503:                                                        fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN
        !          2504:                                                                ,getfname(g.gl_pathv[i]),f.desc);
        !          2505:                                                }
        !          2506:                                        }
        !          2507:                                        globfree(&g);
        !          2508:                                }
        !          2509:                                fclose(fp);
        !          2510:                        } else if(dir>=0) {
        !          2511: 
        !          2512:                                if(!chk_ar(&scfg,scfg.dir[dir]->ar,&user)) {
        !          2513:                                        lprintf("%04d !%s has insufficient access to /%s/%s"
        !          2514:                                                ,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname,scfg.dir[dir]->code);
        !          2515:                                        sockprintf(sock,"550 Insufficient access.");
        !          2516:                                        filepos=0;
        !          2517:                                        continue;
        !          2518:                                }
        !          2519: 
        !          2520:                                if(!getsize && !getdate && !delecmd
        !          2521:                                        && !chk_ar(&scfg,scfg.dir[dir]->dl_ar,&user)) {
        !          2522:                                        lprintf("%04d !%s has insufficient access to download from /%s/%s"
        !          2523:                                                ,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname,scfg.dir[dir]->code);
        !          2524:                                        sockprintf(sock,"550 Insufficient access.");
        !          2525:                                        filepos=0;
        !          2526:                                        continue;
        !          2527:                                }
        !          2528: 
        !          2529:                                if(delecmd && !dir_op(&scfg,&user,dir)) {
        !          2530:                                        lprintf("%04d !%s has insufficient access to delete files in /%s/%s"
        !          2531:                                                ,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname,scfg.dir[dir]->code);
        !          2532:                                        sockprintf(sock,"550 Insufficient access.");
        !          2533:                                        filepos=0;
        !          2534:                                        continue;
        !          2535:                                }
        !          2536:                                sprintf(fname,"%s%s",scfg.dir[dir]->path,p);
        !          2537: #ifdef _WIN32
        !          2538:                                GetShortPathName(fname, str, sizeof(str));
        !          2539: #else
        !          2540:                                strcpy(str,fname);
        !          2541: #endif
        !          2542:                                padfname(getfname(str),f.name);
        !          2543:                                strupr(f.name);
        !          2544:                                f.dir=dir;
        !          2545:                                f.cdt=0;
        !          2546:                                f.size=-1;
        !          2547:                                filedat=getfileixb(&scfg,&f);
        !          2548:                                if(!filedat && !(startup->options&FTP_OPT_DIR_FILES)) {
        !          2549:                                        sockprintf(sock,"550 File not found: %s",p);
        !          2550:                                        lprintf("%04d !%s file not in database (%s) for %.4s command"
        !          2551:                                                ,sock,user.alias,fname,cmd);
        !          2552:                                        filepos=0;
        !          2553:                                        continue;
        !          2554:                                }
        !          2555: 
        !          2556:                                /* Verify credits */
        !          2557:                                if(!getsize && !getdate && !delecmd
        !          2558:                                        && !(scfg.dir[dir]->misc&DIR_FREE) && !(user.exempt&FLAG('D'))) {
        !          2559:                                        if(filedat)
        !          2560:                                                getfiledat(&scfg,&f);
        !          2561:                                        else
        !          2562:                                                f.cdt=flength(fname);
        !          2563:                                        if(f.cdt>(user.cdt+user.freecdt)) {
        !          2564:                                                lprintf("%04d !%s has insufficient credit to download /%s/%s/%s (%lu credits)"
        !          2565:                                                        ,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname
        !          2566:                                                        ,scfg.dir[dir]->code
        !          2567:                                                        ,p
        !          2568:                                                        ,f.cdt);
        !          2569:                                                sockprintf(sock,"550 Insufficient credit (%lu required).",f.cdt);
        !          2570:                                                filepos=0;
        !          2571:                                                continue;
        !          2572:                                        }
        !          2573:                                }
        !          2574: 
        !          2575:                                if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)) {
        !          2576:                                        success=FALSE;
        !          2577:                                        lprintf("%04d !%s illegal filename attempt: %s"
        !          2578:                                                ,sock,user.alias,p);
        !          2579:                                } else {
        !          2580:                                        if(fexist(fname)) {
        !          2581:                                                success=TRUE;
        !          2582:                                                if(!getsize && !getdate && !delecmd)
        !          2583:                                                        lprintf("%04d %s downloading: %s (%ld bytes)"
        !          2584:                                                                ,sock,user.alias,fname,flength(fname));
        !          2585:                                        } 
        !          2586:                                }
        !          2587:                        }
        !          2588:                        if(getsize && success) 
        !          2589:                                sockprintf(sock,"213 %lu",flength(fname));
        !          2590:                        else if(getdate && success) {
        !          2591:                                t=fdate(fname);
        !          2592:                                tm_p=gmtime(&t);
        !          2593:                                if(tm_p==NULL)
        !          2594:                                        memset(&tm,0,sizeof(tm));
        !          2595:                                else
        !          2596:                                        tm=*tm_p;
        !          2597:                                sockprintf(sock,"213 %u%02u%02u%02u%02u%02u"
        !          2598:                                        ,1900+tm.tm_year,tm.tm_mon+1,tm.tm_mday
        !          2599:                                        ,tm.tm_hour,tm.tm_min,tm.tm_sec);
        !          2600:                        } else if(delecmd && success) {
        !          2601:                                if(remove(fname)!=0) {
        !          2602:                                        lprintf("%04d !ERROR %d deleting %s",sock,errno,fname);
        !          2603:                                        sockprintf(sock,"450 %s could not be deleted (error: %d)"
        !          2604:                                                ,fname,errno);
        !          2605:                                } else {
        !          2606:                                        lprintf("%04d %s deleted %s",sock,user.alias,fname);
        !          2607:                                        if(filedat) 
        !          2608:                                                removefiledat(&scfg,&f);
        !          2609:                                        sockprintf(sock,"250 %s deleted.",fname);
        !          2610:                                }
        !          2611:                        } else if(success) {
        !          2612:                                sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          2613:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          2614:                                        ,&transfer_inprogress,&transfer_aborted,delfile,tmpfile
        !          2615:                                        ,&lastactive,&user,dir,FALSE,credits,FALSE,NULL);
        !          2616:                        }
        !          2617:                        else {
        !          2618:                                sockprintf(sock,"550 File not found: %s",p);
        !          2619:                                lprintf("%04d !%s file not found (%s) for %.4s command"
        !          2620:                                        ,sock,user.alias,p,cmd);
        !          2621:                        }
        !          2622:                        filepos=0;
        !          2623:                        continue;
        !          2624:                }
        !          2625: 
        !          2626:                if(!strnicmp(cmd, "DESC", 4)) {
        !          2627: 
        !          2628:                        if(user.rest&FLAG('U')) {
        !          2629:                                sockprintf(sock,"553 Insufficient access.");
        !          2630:                                continue;
        !          2631:                        }
        !          2632: 
        !          2633:                        p=cmd+4;
        !          2634:                        while(*p && *p<=' ') p++;
        !          2635: 
        !          2636:                        if(*p==0) 
        !          2637:                                sockprintf(sock,"501 No file description given.");
        !          2638:                        else {
        !          2639:                                sprintf(desc,"%.*s",(int)sizeof(desc)-1,p);
        !          2640:                                sockprintf(sock,"200 File description set. Ready to STOR file.");
        !          2641:                        }
        !          2642:                        continue;
        !          2643:                }
        !          2644: 
        !          2645:                if(!strnicmp(cmd, "STOR ", 5)) {
        !          2646: 
        !          2647:                        if(user.rest&FLAG('U')) {
        !          2648:                                sockprintf(sock,"553 Insufficient access.");
        !          2649:                                continue;
        !          2650:                        }
        !          2651: 
        !          2652:                        if(transfer_inprogress==TRUE) {
        !          2653:                                lprintf("%04d !TRANSFER already in progress (%s)",sock,cmd);
        !          2654:                                sockprintf(sock,"425 Transfer already in progress.");
        !          2655:                                continue;
        !          2656:                        }
        !          2657: 
        !          2658:                        lib=curlib;
        !          2659:                        dir=curdir;
        !          2660:                        p=cmd+5;
        !          2661: 
        !          2662:                        while(*p && *p<=' ') p++;
        !          2663: 
        !          2664:                        if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) 
        !          2665:                                p+=strlen(BBS_FSYS_DIR);        /* already mounted */
        !          2666: 
        !          2667:                        if(*p=='/') {
        !          2668:                                lib=-1;
        !          2669:                                p++;
        !          2670:                        }
        !          2671:                        else if(!strncmp(p,"./",2))
        !          2672:                                p+=2;
        !          2673:                        if(lib<0 && (tp=strchr(p,'/'))!=NULL) {
        !          2674:                                dir=-1;
        !          2675:                                *tp=0;
        !          2676:                                for(i=0;i<scfg.total_libs;i++) {
        !          2677:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          2678:                                                continue;
        !          2679:                                        if(!stricmp(scfg.lib[i]->sname,p))
        !          2680:                                                break;
        !          2681:                                }
        !          2682:                                if(i<scfg.total_libs) 
        !          2683:                                        lib=i;
        !          2684:                                p=tp+1;
        !          2685:                        }
        !          2686:                        if(dir<0 && (tp=strchr(p,'/'))!=NULL) {
        !          2687:                                *tp=0;
        !          2688:                                for(i=0;i<scfg.total_dirs;i++) {
        !          2689:                                        if(scfg.dir[i]->lib!=lib)
        !          2690:                                                continue;
        !          2691:                                        if(!chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          2692:                                                continue;
        !          2693:                                        if(!stricmp(scfg.dir[i]->code,p))
        !          2694:                                                break;
        !          2695:                                }
        !          2696:                                if(i<scfg.total_dirs) 
        !          2697:                                        dir=i;
        !          2698:                                p=tp+1;
        !          2699:                        }
        !          2700:                        if(dir<0) {
        !          2701:                                sprintf(str,"%s.rep",scfg.sys_id);
        !          2702:                                if(!(startup->options&FTP_OPT_ALLOW_QWK)
        !          2703:                                        || stricmp(p,str)) {
        !          2704:                                        lprintf("%04d !%s attempted to upload to invalid directory"
        !          2705:                                                ,sock,user.alias);
        !          2706:                                        sockprintf(sock,"553 Invalid directory.");
        !          2707:                                        continue;
        !          2708:                                }
        !          2709:                                sprintf(fname,"%sfile/%04d.rep",scfg.data_dir,user.number);
        !          2710:                                lprintf("%04d %s uploading %s"
        !          2711:                                        ,sock,user.alias,fname);
        !          2712:                        } else {
        !          2713:                                if(!chk_ar(&scfg,scfg.dir[dir]->ul_ar,&user)) {
        !          2714:                                        lprintf("%04d !%s has insufficient access to upload to /%s/%s"
        !          2715:                                                ,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname,scfg.dir[dir]->code);
        !          2716:                                        sockprintf(sock,"553 Insufficient access.");
        !          2717:                                        continue;
        !          2718:                                }
        !          2719:                                if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)
        !          2720:                                        || trashcan(&scfg,p,"file")) {
        !          2721:                                        lprintf("%04d !%s illegal filename attempt: %s"
        !          2722:                                                ,sock,user.alias,p);
        !          2723:                                        sockprintf(sock,"553 Illegal filename attempt");
        !          2724:                                        continue;
        !          2725:                                }
        !          2726:                                sprintf(fname,"%s%s",scfg.dir[dir]->path,p);
        !          2727:                                if(fexist(fname)) {
        !          2728:                                        lprintf("%04d !%s attempted to overwrite existing file: %s"
        !          2729:                                                ,sock,user.alias,fname);
        !          2730:                                        sockprintf(sock,"553 File already exists.");
        !          2731:                                        continue;
        !          2732:                                }
        !          2733:                                lprintf("%04d %s uploading %s to /%s/%s"
        !          2734:                                        ,sock,user.alias,fname
        !          2735:                                        ,scfg.lib[scfg.dir[dir]->lib]->sname,scfg.dir[dir]->code);
        !          2736:                        }
        !          2737:                        sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          2738:                        filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          2739:                                ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
        !          2740:                                ,&lastactive
        !          2741:                                ,&user
        !          2742:                                ,dir
        !          2743:                                ,TRUE   /* uploading */
        !          2744:                                ,TRUE   /* credits */
        !          2745:                                ,FALSE  /* append */
        !          2746:                                ,desc
        !          2747:                                );
        !          2748:                        filepos=0;
        !          2749:                        continue;
        !          2750:                }
        !          2751: 
        !          2752:                if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) {
        !          2753:                        if(curdir<0)
        !          2754:                                curlib=-1;
        !          2755:                        else
        !          2756:                                curdir=-1;
        !          2757:                        sockprintf(sock,"200 CDUP command successful.");
        !          2758:                        continue;
        !          2759:                }
        !          2760: 
        !          2761:                if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) {
        !          2762:                        p=cmd+4;
        !          2763:                        while(*p && *p<=' ') p++;
        !          2764: 
        !          2765:                        if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) 
        !          2766:                                p+=strlen(BBS_FSYS_DIR);        /* already mounted */
        !          2767: 
        !          2768:                        if(*p=='/') {
        !          2769:                                curlib=-1;
        !          2770:                                curdir=-1;
        !          2771:                                p++;
        !          2772:                        }
        !          2773:                        /* Local File System? */
        !          2774:                        if(sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS) 
        !          2775:                                && !strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) {        
        !          2776:                                p+=strlen(LOCAL_FSYS_DIR);
        !          2777:                                if(!direxist(p)) {
        !          2778:                                        sockprintf(sock,"550 Directory does not exist.");
        !          2779:                                        lprintf("%04d !%s attempted to mount invalid directory: %s"
        !          2780:                                                ,sock, user.alias, p);
        !          2781:                                        continue;
        !          2782:                                }
        !          2783:                                sprintf(local_dir,"%.*s",(int)sizeof(local_dir)-1,p);
        !          2784:                                local_fsys=TRUE;
        !          2785:                                sockprintf(sock,"250 CWD command successful (local file system mounted).");
        !          2786:                                lprintf("%04d %s mounted local file system", sock, user.alias);
        !          2787:                                continue;
        !          2788:                        }
        !          2789:                        success=FALSE;
        !          2790: 
        !          2791:                        /* Directory Alias? */
        !          2792:                        if(curlib<0 && alias(p,NULL,&user,&curdir)==TRUE) {
        !          2793:                                if(curdir>=0)
        !          2794:                                        curlib=scfg.dir[curdir]->lib;
        !          2795:                                success=TRUE;
        !          2796:                        }
        !          2797: 
        !          2798:                        orglib=curlib;
        !          2799:                        orgdir=curdir;
        !          2800:                        tp=0;
        !          2801:                        if(!strncmp(p,"...",3)) {
        !          2802:                                curlib=-1;
        !          2803:                                curdir=-1;
        !          2804:                                p+=3;
        !          2805:                        }
        !          2806:                        if(!strncmp(p,"./",2))
        !          2807:                                p+=2;
        !          2808:                        else if(!strncmp(p,"..",2)) {
        !          2809:                                if(curdir<0)
        !          2810:                                        curlib=-1;
        !          2811:                                else
        !          2812:                                        curdir=-1;
        !          2813:                                p+=2;
        !          2814:                        }
        !          2815:                        if(*p==0)
        !          2816:                                success=TRUE;
        !          2817:                        else if(!strcmp(p,".")) 
        !          2818:                                success=TRUE;
        !          2819:                        if(!success  && (curlib<0 || *p=='/')) { /* Root dir */
        !          2820:                                if(*p=='/') p++;
        !          2821:                                tp=strchr(p,'/');
        !          2822:                                if(tp) *tp=0;
        !          2823:                                for(i=0;i<scfg.total_libs;i++) {
        !          2824:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          2825:                                                continue;
        !          2826:                                        if(!stricmp(scfg.lib[i]->sname,p))
        !          2827:                                                break;
        !          2828:                                }
        !          2829:                                if(i<scfg.total_libs) {
        !          2830:                                        curlib=i;
        !          2831:                                        success=TRUE;
        !          2832:                                }
        !          2833:                        }
        !          2834:                        if((!success && curdir<0) || (success && tp && *(tp+1))) {
        !          2835:                                if(tp)
        !          2836:                                        p=tp+1;
        !          2837:                                tp=strchr(p,'/');
        !          2838:                                if(tp) *tp=0;
        !          2839:                                for(i=0;i<scfg.total_dirs;i++) {
        !          2840:                                        if(scfg.dir[i]->lib!=curlib)
        !          2841:                                                continue;
        !          2842:                                        if(i!=scfg.sysop_dir && i!=scfg.upload_dir
        !          2843:                                                && !chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          2844:                                                continue;
        !          2845:                                        if(!stricmp(scfg.dir[i]->code,p))
        !          2846:                                                break;
        !          2847:                                }
        !          2848:                                if(i<scfg.total_dirs) {
        !          2849:                                        curdir=i;
        !          2850:                                        success=TRUE;
        !          2851:                                } else
        !          2852:                                        success=FALSE;
        !          2853:                        }
        !          2854: 
        !          2855:                        if(success)
        !          2856:                                sockprintf(sock,"250 CWD command successful.");
        !          2857:                        else {
        !          2858:                                sockprintf(sock,"550 %s: No such file or directory.",p);
        !          2859:                                curlib=orglib;
        !          2860:                                curdir=orgdir;
        !          2861:                        }
        !          2862:                        continue;
        !          2863:                }
        !          2864: 
        !          2865:                if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) {
        !          2866:                        if(curlib<0)
        !          2867:                                sockprintf(sock,"257 \"/\" is current directory.");
        !          2868:                        else if(curdir<0)
        !          2869:                                sockprintf(sock,"257 \"/%s\" is current directory."
        !          2870:                                        ,scfg.lib[curlib]->sname);
        !          2871:                        else
        !          2872:                                sockprintf(sock,"257 \"/%s/%s\" is current directory."
        !          2873:                                        ,scfg.lib[curlib]->sname,scfg.dir[curdir]->code);
        !          2874:                        continue;
        !          2875:                }
        !          2876:                
        !          2877:                sockprintf(sock,"500 Syntax error: '%s'",cmd);
        !          2878:                lprintf("%04d !FTP: UNSUPPORTED COMMAND: '%s'",sock,cmd);
        !          2879:        }
        !          2880: 
        !          2881:        if(transfer_inprogress==TRUE) {
        !          2882:                lprintf("%04d Waiting for transfer to complete...",sock);
        !          2883:                while(data_sock!=INVALID_SOCKET && transfer_inprogress==TRUE) {
        !          2884:                        mswait(500);
        !          2885:                        if(gettimeleft(&scfg,&user,logintime)<1) {
        !          2886:                                lprintf("%04d Out of time, disconnecting",sock);
        !          2887:                                sockprintf(sock,"421 Sorry, you've run out of time.");
        !          2888:                                close_socket(&data_sock,__LINE__);
        !          2889:                                transfer_aborted=TRUE;
        !          2890:                        }
        !          2891:                        if((time(NULL)-lastactive)>startup->max_inactivity) {
        !          2892:                                lprintf("%04d Disconnecting due to to inactivity.",sock);
        !          2893:                                sockprintf(sock,"421 Disconnecting due to inactivity (%u seconds)."
        !          2894:                                        ,startup->max_inactivity);
        !          2895:                                close_socket(&data_sock,__LINE__);
        !          2896:                                transfer_aborted=TRUE;
        !          2897:                        }
        !          2898:                }
        !          2899:                lprintf("%04d Done waiting for transfer to complete",sock);
        !          2900:        }
        !          2901: 
        !          2902:        /* Update User Statistics */
        !          2903:        if(user.number) {
        !          2904:                user.tlast=(ushort)(time(NULL)-logintime);
        !          2905:                putuserrec(&scfg,user.number,U_LASTON,8,ultoa(time(NULL),str,16));
        !          2906:                putuserrec(&scfg,user.number,U_TLAST,5,ultoa(user.tlast,str,10));
        !          2907:                adjustuserrec(&scfg,user.number,U_TIMEON,5,user.tlast);
        !          2908:        }
        !          2909: 
        !          2910:        if(user.number)
        !          2911:                lprintf("%04d %s logged off.",sock,user.alias);
        !          2912: 
        !          2913: #ifdef _WIN32
        !          2914:        if(startup->hangup_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          2915:                PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          2916: #endif
        !          2917: 
        !          2918:        status(STATUS_WFC);
        !          2919: 
        !          2920:        lprintf("%04d CTRL thread terminated", sock);
        !          2921:        active_clients--;
        !          2922:        update_clients();
        !          2923:        client_off(sock);
        !          2924: 
        !          2925:        /* Free up resources here */
        !          2926:        close_socket(&sock,__LINE__);
        !          2927:        if(pasv_sock!=INVALID_SOCKET)
        !          2928:                close_socket(&pasv_sock,__LINE__);
        !          2929:        if(data_sock!=INVALID_SOCKET)
        !          2930:                close_socket(&data_sock,__LINE__);
        !          2931: 
        !          2932:        thread_down();
        !          2933: }
        !          2934: 
        !          2935: static void cleanup(int code)
        !          2936: {
        !          2937:        if(server_socket!=INVALID_SOCKET)
        !          2938:                close_socket(&server_socket,__LINE__);
        !          2939:        server_socket=INVALID_SOCKET;
        !          2940: 
        !          2941:        update_clients();
        !          2942: 
        !          2943: #ifdef _WINSOCKAPI_
        !          2944:        if(WSAInitialized && WSACleanup()!=0) 
        !          2945:                lprintf("0000 !WSACleanup ERROR %d",ERROR_VALUE);
        !          2946: #endif
        !          2947: 
        !          2948:     lprintf("#### FTP Server thread terminated");
        !          2949:        status("Down");
        !          2950:        if(startup!=NULL && startup->terminated!=NULL)
        !          2951:                startup->terminated(code);
        !          2952:        thread_down();
        !          2953: }
        !          2954: 
        !          2955: char* DLLCALL ftp_ver(void)
        !          2956: {
        !          2957:        static char ver[256];
        !          2958:        char compiler[32];
        !          2959: 
        !          2960:        COMPILER_DESC(compiler);
        !          2961: 
        !          2962:        sprintf(ver,"Synchronet FTP Server v%s%s  "
        !          2963:                "Compiled %s %s with %s"
        !          2964:                ,FTP_VERSION
        !          2965: #ifdef _DEBUG
        !          2966:                ," Debug"
        !          2967: #else
        !          2968:                ,""
        !          2969: #endif
        !          2970:                ,__DATE__, __TIME__, compiler);
        !          2971: 
        !          2972:        return(ver);
        !          2973: }
        !          2974: 
        !          2975: void DLLCALL ftp_server(void* arg)
        !          2976: {
        !          2977:        char                    compiler[32];
        !          2978:        SOCKADDR_IN             server_addr;
        !          2979:        SOCKADDR_IN             client_addr;
        !          2980:        int                             client_addr_len;
        !          2981:        SOCKET                  client_socket;
        !          2982:        int                             i;
        !          2983:        int                             result;
        !          2984:        time_t                  t;
        !          2985:        time_t                  start;
        !          2986:        LINGER                  linger;
        !          2987:        fd_set                  socket_set;
        !          2988:        SOCKET                  high_socket_set;
        !          2989:        ftp_t*                  ftp;
        !          2990:        struct timeval  tv;
        !          2991: 
        !          2992:        startup=(ftp_startup_t*)arg;
        !          2993: 
        !          2994:     if(startup==NULL) {
        !          2995:        sbbs_beep(100,500);
        !          2996:        fprintf(stderr, "No startup structure passed!\n");
        !          2997:        return;
        !          2998:     }
        !          2999: 
        !          3000:        if(startup->size!=sizeof(ftp_startup_t)) {      /* verify size */
        !          3001:                sbbs_beep(100,500);
        !          3002:                sbbs_beep(300,500);
        !          3003:                sbbs_beep(100,500);
        !          3004:                fprintf(stderr, "Invalid startup structure!\n");
        !          3005:                return;
        !          3006:        }
        !          3007: 
        !          3008:        thread_up();
        !          3009: 
        !          3010:        status("Initializing");
        !          3011: 
        !          3012: #ifdef __unix__                /* Ignore "Broken Pipe" signal */
        !          3013:        signal(SIGPIPE,SIG_IGN);
        !          3014: #endif
        !          3015: 
        !          3016:        lprintf("Synchronet FTP Server Version %s%s"
        !          3017:                ,FTP_VERSION
        !          3018: #ifdef _DEBUG
        !          3019:                ," Debug"
        !          3020: #else
        !          3021:                ,""
        !          3022: #endif
        !          3023:                );
        !          3024: 
        !          3025:        COMPILER_DESC(compiler);
        !          3026: 
        !          3027:        lprintf("Compiled %s %s with %s", __DATE__, __TIME__, compiler);
        !          3028: 
        !          3029:        srand(time(NULL));
        !          3030: 
        !          3031:        if(!(startup->options&FTP_OPT_LOCAL_TIMEZONE)) { 
        !          3032:                if(PUTENV("TZ=UCT0"))
        !          3033:                        lprintf("!putenv() FAILED");
        !          3034:                tzset();
        !          3035: 
        !          3036:                if((t=checktime())!=0) {   /* Check binary time */
        !          3037:                        lprintf("!TIME PROBLEM (%ld)",t);
        !          3038:                        cleanup(1);
        !          3039:                        return;
        !          3040:                }
        !          3041:        }
        !          3042: 
        !          3043:        if(!winsock_startup()) {
        !          3044:                cleanup(1);
        !          3045:                return;
        !          3046:        }
        !          3047: 
        !          3048:        t=time(NULL);
        !          3049:        lprintf("Initializing on %.24s with options: %lx"
        !          3050:                ,ctime(&t),startup->options);
        !          3051: 
        !          3052: #ifdef _WIN32
        !          3053:     if((socket_mutex=CreateMutex(NULL,FALSE,NULL))==NULL) {
        !          3054:        lprintf("!ERROR %d creating socket_mutex", GetLastError());
        !          3055:                cleanup(1);
        !          3056:         return;
        !          3057:     }
        !          3058: #endif
        !          3059: 
        !          3060:        /* Initial configuration and load from CNF files */
        !          3061:     memset(&scfg, 0, sizeof(scfg));
        !          3062:     sprintf(scfg.ctrl_dir, "%.*s",(int)sizeof(scfg.ctrl_dir)-1
        !          3063:        ,startup->ctrl_dir);
        !          3064:     lprintf("Loading configuration files from %s", scfg.ctrl_dir);
        !          3065:        if(!load_cfg(&scfg, NULL)) {
        !          3066:                lprintf("!Failed to load configuration files");
        !          3067:                cleanup(1);
        !          3068:                return;
        !          3069:        }
        !          3070: 
        !          3071:        if(!startup->max_clients) {
        !          3072:                startup->max_clients=scfg.sys_nodes;
        !          3073:                if(startup->max_clients<10)
        !          3074:                        startup->max_clients=10;
        !          3075:        }
        !          3076:        lprintf("Maximum clients: %d",startup->max_clients);
        !          3077: 
        !          3078:        if(!startup->max_inactivity) 
        !          3079:                startup->max_inactivity=300; /* seconds */
        !          3080: 
        !          3081:        lprintf("Maximum inactivity: %d seconds",startup->max_inactivity);
        !          3082: 
        !          3083:        active_clients=0;
        !          3084:        update_clients();
        !          3085: 
        !          3086:        strlwr(scfg.sys_id); /* Use lower-case unix-looking System ID for group name */
        !          3087: 
        !          3088:        for(i=0;i<scfg.total_libs;i++) {
        !          3089:                strlwr(scfg.lib[i]->sname);
        !          3090:                dotname(scfg.lib[i]->sname,scfg.lib[i]->sname);
        !          3091:        }
        !          3092: 
        !          3093:        for(i=0;i<scfg.total_dirs;i++) 
        !          3094:                strlwr(scfg.dir[i]->code);
        !          3095: 
        !          3096: 
        !          3097:     /* open a socket and wait for a client */
        !          3098: 
        !          3099:     if((server_socket=open_socket(SOCK_STREAM))==INVALID_SOCKET) {
        !          3100:                lprintf("!ERROR %d opening socket", ERROR_VALUE);
        !          3101:                cleanup(1);
        !          3102:                return;
        !          3103:        }
        !          3104: 
        !          3105:     lprintf("%04d FTP socket opened",server_socket);
        !          3106: 
        !          3107: #if 1
        !          3108:        linger.l_onoff=TRUE;
        !          3109:     linger.l_linger=5; /* seconds */
        !          3110: 
        !          3111:        if((result=setsockopt(server_socket, SOL_SOCKET, SO_LINGER
        !          3112:        ,(char *)&linger, sizeof(linger)))!=0) {
        !          3113:                lprintf ("%04d !ERROR %d (%d) setting socket options."
        !          3114:                        ,server_socket, result, ERROR_VALUE);
        !          3115:                cleanup(1);
        !          3116:                return;
        !          3117:        }
        !          3118: #endif
        !          3119: 
        !          3120:        /*****************************/
        !          3121:        /* Listen for incoming calls */
        !          3122:        /*****************************/
        !          3123:     memset(&server_addr, 0, sizeof(server_addr));
        !          3124: 
        !          3125:        server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
        !          3126:     server_addr.sin_family = AF_INET;
        !          3127:     server_addr.sin_port   = htons(startup->port);
        !          3128: 
        !          3129:     if((result=bind(server_socket, (struct sockaddr *) &server_addr
        !          3130:        ,sizeof(server_addr)))!=0) {
        !          3131:                lprintf("%04d !ERROR %d (%d) binding socket to port %d"
        !          3132:                        ,server_socket, result, ERROR_VALUE,startup->port);
        !          3133:                cleanup(1);
        !          3134:                return;
        !          3135:        }
        !          3136: 
        !          3137:     if((result=listen(server_socket, 1))!= 0) {
        !          3138:                lprintf("%04d !ERROR %d (%d) listening on socket"
        !          3139:                        ,server_socket, result, ERROR_VALUE);
        !          3140:                cleanup(1);
        !          3141:                return;
        !          3142:        }
        !          3143: 
        !          3144:        /* signal caller that we've started up successfully */
        !          3145:     if(startup->started!=NULL)
        !          3146:        startup->started();
        !          3147: 
        !          3148:        lprintf("%04d FTP Server thread started on port %d",server_socket,startup->port);
        !          3149:        status(STATUS_WFC);
        !          3150: 
        !          3151:        while(server_socket!=INVALID_SOCKET) {
        !          3152: 
        !          3153:                /* now wait for connection */
        !          3154: 
        !          3155:                tv.tv_sec=2;
        !          3156:                tv.tv_usec=0;
        !          3157: 
        !          3158:                FD_ZERO(&socket_set);
        !          3159:                FD_SET(server_socket,&socket_set);
        !          3160:                high_socket_set=server_socket+1;
        !          3161: 
        !          3162:                if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) {
        !          3163:                        if(i==0) {
        !          3164:                                mswait(1);
        !          3165:                                continue;
        !          3166:                        }
        !          3167:                        if(ERROR_VALUE==EINTR)
        !          3168:                                lprintf("0000 FTP Server listening interrupted");
        !          3169:                        else if(ERROR_VALUE == ENOTSOCK)
        !          3170:                lprintf("0000 FTP Server sockets closed");
        !          3171:                        else
        !          3172:                                lprintf("0000 !ERROR %d selecting sockets",ERROR_VALUE);
        !          3173:                        break;
        !          3174:                }
        !          3175: 
        !          3176:                client_addr_len = sizeof(client_addr);
        !          3177:                client_socket = accept(server_socket, (struct sockaddr *)&client_addr
        !          3178:                ,&client_addr_len);
        !          3179: 
        !          3180:                if(client_socket == INVALID_SOCKET)
        !          3181:                {
        !          3182:                        if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINTR)
        !          3183:                lprintf("0000 FTP socket closed while listening");
        !          3184:             else
        !          3185:                                lprintf("0000 !accept failed (ERROR %d)", ERROR_VALUE);
        !          3186:                        break;
        !          3187:                }
        !          3188:                if(startup->socket_open!=NULL)
        !          3189:                        startup->socket_open(TRUE);
        !          3190:                sockets++;
        !          3191: 
        !          3192:                if(active_clients>=startup->max_clients) {
        !          3193:                        lprintf("%04d !MAXMIMUM CLIENTS (%d) reached, access denied"
        !          3194:                                ,client_socket, startup->max_clients);
        !          3195:                        sockprintf(client_socket,"421 Maximum active clients reached, please try again later.");
        !          3196:                        mswait(3000);
        !          3197:                        close_socket(&client_socket,__LINE__);
        !          3198:                        continue;
        !          3199:                }
        !          3200: 
        !          3201:                if((ftp=malloc(sizeof(ftp_t)))==NULL) {
        !          3202:                        lprintf("%04d !ERROR allocating %d bytes of memory for ftp_t"
        !          3203:                                ,client_socket,sizeof(ftp_t));
        !          3204:                        sockprintf(client_socket,"421 System error, please try again later.");
        !          3205:                        mswait(3000);
        !          3206:                        close_socket(&client_socket,__LINE__);
        !          3207:                        continue;
        !          3208:                }
        !          3209: 
        !          3210:                ftp->socket=client_socket;
        !          3211:                ftp->client_addr=client_addr;
        !          3212: 
        !          3213:                _beginthread (ctrl_thread, 0, ftp);
        !          3214:        }
        !          3215: 
        !          3216:        if(active_clients) {
        !          3217:                lprintf("0000 Waiting for %d active clients to disconnect...", active_clients);
        !          3218:                start=time(NULL);
        !          3219:                while(active_clients) {
        !          3220:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
        !          3221:                                lprintf("0000 !TIMEOUT waiting for %d active clients ",active_clients);
        !          3222:                                break;
        !          3223:                        }
        !          3224:                        mswait(100);
        !          3225:                }
        !          3226:        }
        !          3227: 
        !          3228:        cleanup(0);
        !          3229: }

unix.superglobalmegacorp.com

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