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

1.1     ! root        1: /* ftpsrvr.c */
        !             2: 
        !             3: /* Synchronet FTP server */
        !             4: 
        !             5: /* $Id: ftpsrvr.c,v 1.313 2006/12/29 08:42:56 rswindell Exp $ */
        !             6: 
        !             7: /****************************************************************************
        !             8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
        !             9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
        !            10:  *                                                                                                                                                     *
        !            11:  * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html         *
        !            12:  *                                                                                                                                                     *
        !            13:  * This program is free software; you can redistribute it and/or                       *
        !            14:  * modify it under the terms of the GNU General Public License                         *
        !            15:  * as published by the Free Software Foundation; either version 2                      *
        !            16:  * of the License, or (at your option) any later version.                                      *
        !            17:  * See the GNU General Public License for more details: gpl.txt or                     *
        !            18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
        !            19:  *                                                                                                                                                     *
        !            20:  * Anonymous FTP access to the most recent released source is available at     *
        !            21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
        !            22:  *                                                                                                                                                     *
        !            23:  * Anonymous CVS access to the development source and modification history     *
        !            24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
        !            25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
        !            26:  *     (just hit return, no password is necessary)                                                     *
        !            27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
        !            28:  *                                                                                                                                                     *
        !            29:  * For Synchronet coding style and modification guidelines, see                                *
        !            30:  * http://www.synchro.net/source.html                                                                          *
        !            31:  *                                                                                                                                                     *
        !            32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
        !            33:  * format) via e-mail to [email protected]                                                                      *
        !            34:  *                                                                                                                                                     *
        !            35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
        !            36:  ****************************************************************************/
        !            37: 
        !            38: /* ANSI C Library headers */
        !            39: #include <stdio.h>
        !            40: #include <stdlib.h>                    /* ltoa in GNU C lib */
        !            41: #include <stdarg.h>                    /* va_list, varargs */
        !            42: #include <string.h>                    /* strrchr */
        !            43: #include <fcntl.h>                     /* O_WRONLY, O_RDONLY, etc. */
        !            44: #include <errno.h>                     /* EACCES */
        !            45: #include <ctype.h>                     /* toupper */
        !            46: #include <sys/stat.h>          /* S_IWRITE */
        !            47: 
        !            48: /* Synchronet-specific headers */
        !            49: #undef SBBS    /* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
        !            50: #include "sbbs.h"
        !            51: #include "text.h"                      /* TOTAL_TEXT */
        !            52: #include "ftpsrvr.h"
        !            53: #include "telnet.h"
        !            54: 
        !            55: /* Constants */
        !            56: 
        !            57: #define FTP_SERVER                             "Synchronet FTP Server"
        !            58: 
        !            59: #define STATUS_WFC                             "Listening"
        !            60: #define ANONYMOUS                              "anonymous"
        !            61: 
        !            62: #define BBS_VIRTUAL_PATH               "bbs:/""/"      /* this is actually bbs:<slash><slash> */
        !            63: #define LOCAL_FSYS_DIR                 "local:"
        !            64: #define BBS_FSYS_DIR                   "bbs:"
        !            65: #define BBS_HIDDEN_ALIAS               "hidden"
        !            66: 
        !            67: #define TIMEOUT_THREAD_WAIT            60              /* Seconds */
        !            68: 
        !            69: #define TIMEOUT_SOCKET_LISTEN  30              /* Seconds */
        !            70: 
        !            71: #define XFER_REPORT_INTERVAL   60              /* Seconds */
        !            72: 
        !            73: #define INDEX_FNAME_LEN                        15
        !            74: 
        !            75: #define        NAME_LEN                                15              /* User name length for listings */
        !            76: 
        !            77: static ftp_startup_t*  startup=NULL;
        !            78: static scfg_t  scfg;
        !            79: static SOCKET  server_socket=INVALID_SOCKET;
        !            80: static DWORD   active_clients=0;
        !            81: static DWORD   sockets=0;
        !            82: static DWORD   thread_count=0;
        !            83: static time_t  uptime=0;
        !            84: static DWORD   served=0;
        !            85: static BOOL            terminate_server=FALSE;
        !            86: static char            revision[16];
        !            87: static char    *text[TOTAL_TEXT];
        !            88: static str_list_t recycle_semfiles;
        !            89: static str_list_t shutdown_semfiles;
        !            90: 
        !            91: #ifdef _DEBUG
        !            92:        static BYTE     socket_debug[0x10000]={0};
        !            93: 
        !            94:        #define SOCKET_DEBUG_CTRL               (1<<0)  /* 0x01 */
        !            95:        #define SOCKET_DEBUG_SEND               (1<<1)  /* 0x02 */
        !            96:        #define SOCKET_DEBUG_READLINE   (1<<2)  /* 0x04 */
        !            97:        #define SOCKET_DEBUG_ACCEPT             (1<<3)  /* 0x08 */
        !            98:        #define SOCKET_DEBUG_SENDTHREAD (1<<4)  /* 0x10 */
        !            99:        #define SOCKET_DEBUG_TERMINATE  (1<<5)  /* 0x20 */
        !           100:        #define SOCKET_DEBUG_RECV_CHAR  (1<<6)  /* 0x40 */
        !           101:        #define SOCKET_DEBUG_FILEXFER   (1<<7)  /* 0x80 */
        !           102: #endif
        !           103: 
        !           104: 
        !           105: typedef struct {
        !           106:        SOCKET                  socket;
        !           107:        SOCKADDR_IN             client_addr;
        !           108: } ftp_t;
        !           109: 
        !           110: 
        !           111: static const char *ftp_mon[]={"Jan","Feb","Mar","Apr","May","Jun"
        !           112:             ,"Jul","Aug","Sep","Oct","Nov","Dec"};
        !           113: 
        !           114: BOOL direxist(char *dir)
        !           115: {
        !           116:        if(access(dir,0)==0)
        !           117:                return(TRUE);
        !           118:        else
        !           119:                return(FALSE);
        !           120: }
        !           121: 
        !           122: BOOL dir_op(scfg_t* cfg, user_t* user, uint dirnum)
        !           123: {
        !           124:        return(user->level>=SYSOP_LEVEL || user->exempt&FLAG('R')
        !           125:                || (cfg->dir[dirnum]->op_ar[0] && chk_ar(cfg,cfg->dir[dirnum]->op_ar,user)));
        !           126: }
        !           127: 
        !           128: static int lprintf(int level, char *fmt, ...)
        !           129: {
        !           130:        int             result;
        !           131:        va_list argptr;
        !           132:        char sbuf[1024];
        !           133: 
        !           134:     if(startup==NULL || startup->lputs==NULL)
        !           135:         return(0);
        !           136: 
        !           137:     va_start(argptr,fmt);
        !           138:     vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
        !           139:        sbuf[sizeof(sbuf)-1]=0;
        !           140:     va_end(argptr);
        !           141:     result=startup->lputs(startup->cbdata,level,sbuf);
        !           142: 
        !           143:        return(result);
        !           144: }
        !           145: 
        !           146: #ifdef _WINSOCKAPI_
        !           147: 
        !           148: static WSADATA WSAData;
        !           149: #define SOCKLIB_DESC WSAData.szDescription
        !           150: 
        !           151: static BOOL WSAInitialized=FALSE;
        !           152: 
        !           153: static BOOL winsock_startup(void)
        !           154: {
        !           155:        int             status;             /* Status Code */
        !           156: 
        !           157:     if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
        !           158:                lprintf(LOG_INFO,"%s %s",WSAData.szDescription, WSAData.szSystemStatus);
        !           159:                WSAInitialized=TRUE;
        !           160:                return (TRUE);
        !           161:        }
        !           162: 
        !           163:     lprintf(LOG_ERR,"!WinSock startup ERROR %d", status);
        !           164:        return (FALSE);
        !           165: }
        !           166: 
        !           167: #else /* No WINSOCK */
        !           168: 
        !           169: #define winsock_startup()      (TRUE)
        !           170: #define SOCKLIB_DESC           NULL
        !           171: 
        !           172: #endif
        !           173: 
        !           174: static void status(char* str)
        !           175: {
        !           176:        if(startup!=NULL && startup->status!=NULL)
        !           177:            startup->status(startup->cbdata,str);
        !           178: }
        !           179: 
        !           180: static void update_clients(void)
        !           181: {
        !           182:        if(startup!=NULL && startup->clients!=NULL)
        !           183:                startup->clients(startup->cbdata,active_clients);
        !           184: }
        !           185: 
        !           186: static void client_on(SOCKET sock, client_t* client, BOOL update)
        !           187: {
        !           188:        if(startup!=NULL && startup->client_on!=NULL)
        !           189:                startup->client_on(startup->cbdata,TRUE,sock,client,update);
        !           190: }
        !           191: 
        !           192: static void client_off(SOCKET sock)
        !           193: {
        !           194:        if(startup!=NULL && startup->client_on!=NULL)
        !           195:                startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE);
        !           196: }
        !           197: 
        !           198: static void thread_up(BOOL setuid)
        !           199: {
        !           200:        thread_count++;
        !           201:        if(startup!=NULL && startup->thread_up!=NULL)
        !           202:                startup->thread_up(startup->cbdata,TRUE, setuid);
        !           203: }
        !           204: 
        !           205: static void thread_down(void)
        !           206: {
        !           207:        if(thread_count>0)
        !           208:                thread_count--;
        !           209:        if(startup!=NULL && startup->thread_up!=NULL)
        !           210:                startup->thread_up(startup->cbdata,FALSE, FALSE);
        !           211: }
        !           212: 
        !           213: static SOCKET ftp_open_socket(int type)
        !           214: {
        !           215:        SOCKET  sock;
        !           216:        char    error[256];
        !           217: 
        !           218:        sock=socket(AF_INET, type, IPPROTO_IP);
        !           219:        if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) 
        !           220:                startup->socket_open(startup->cbdata,TRUE);
        !           221:        if(sock!=INVALID_SOCKET) {
        !           222:                if(set_socket_options(&scfg, sock, "FTP", error, sizeof(error)))
        !           223:                        lprintf(LOG_ERR,"%04d !ERROR %s",sock, error);
        !           224:                sockets++;
        !           225: #ifdef _DEBUG
        !           226:                lprintf(LOG_DEBUG,"%04d Socket opened (%u sockets in use)",sock,sockets);
        !           227: #endif
        !           228:        }
        !           229:        return(sock);
        !           230: }
        !           231: 
        !           232: #ifdef __BORLANDC__
        !           233: #pragma argsused
        !           234: #endif
        !           235: static int ftp_close_socket(SOCKET* sock, int line)
        !           236: {
        !           237:        int             result;
        !           238: 
        !           239:        if((*sock)==INVALID_SOCKET) {
        !           240:                lprintf(LOG_WARNING,"0000 !INVALID_SOCKET in close_socket from line %u",line);
        !           241:                return(-1);
        !           242:        }
        !           243: 
        !           244:        shutdown(*sock,SHUT_RDWR);      /* required on Unix */
        !           245: 
        !           246:        result=closesocket(*sock);
        !           247:        if(startup!=NULL && startup->socket_open!=NULL) 
        !           248:                startup->socket_open(startup->cbdata,FALSE);
        !           249: 
        !           250:        sockets--;
        !           251: 
        !           252:        if(result!=0) {
        !           253:                if(ERROR_VALUE!=ENOTSOCK)
        !           254:                        lprintf(LOG_WARNING,"%04d !ERROR %d closing socket from line %u",*sock,ERROR_VALUE,line);
        !           255:        } else if(sock==&server_socket || *sock==server_socket)
        !           256:                lprintf(LOG_DEBUG,"%04d Server socket closed (%u sockets in use) from line %u",*sock,sockets,line);
        !           257: #ifdef _DEBUG
        !           258:        else 
        !           259:                lprintf(LOG_DEBUG,"%04d Socket closed (%u sockets in use) from line %u",*sock,sockets,line);
        !           260: #endif
        !           261:        *sock=INVALID_SOCKET;
        !           262: 
        !           263:        return(result);
        !           264: }
        !           265: 
        !           266: static int sockprintf(SOCKET sock, char *fmt, ...)
        !           267: {
        !           268:        int             len;
        !           269:        int             maxlen;
        !           270:        int             result;
        !           271:        va_list argptr;
        !           272:        char    sbuf[1024];
        !           273:        fd_set  socket_set;
        !           274:        struct timeval tv;
        !           275: 
        !           276:     va_start(argptr,fmt);
        !           277:     len=vsnprintf(sbuf,maxlen=sizeof(sbuf)-2,fmt,argptr);
        !           278:     va_end(argptr);
        !           279: 
        !           280:        if(len<0 || len>maxlen) /* format error or output truncated */
        !           281:                len=maxlen;
        !           282:        if(startup!=NULL && startup->options&FTP_OPT_DEBUG_TX)
        !           283:                lprintf(LOG_DEBUG,"%04d TX: %.*s", sock, len, sbuf);
        !           284:        memcpy(sbuf+len,"\r\n",2);
        !           285:        len+=2;
        !           286: 
        !           287:        if(sock==INVALID_SOCKET) {
        !           288:                lprintf(LOG_WARNING,"!INVALID SOCKET in call to sockprintf");
        !           289:                return(0);
        !           290:        }
        !           291: 
        !           292:        /* Check socket for writability (using select) */
        !           293:        tv.tv_sec=300;
        !           294:        tv.tv_usec=0;
        !           295: 
        !           296:        FD_ZERO(&socket_set);
        !           297:        FD_SET(sock,&socket_set);
        !           298: 
        !           299:        if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) {
        !           300:                if(result==0)
        !           301:                        lprintf(LOG_WARNING,"%04d !TIMEOUT selecting socket for send"
        !           302:                                ,sock);
        !           303:                else
        !           304:                        lprintf(LOG_WARNING,"%04d !ERROR %d selecting socket for send"
        !           305:                                ,sock, ERROR_VALUE);
        !           306:                return(0);
        !           307:        }
        !           308:        while((result=sendsocket(sock,sbuf,len))!=len) {
        !           309:                if(result==SOCKET_ERROR) {
        !           310:                        if(ERROR_VALUE==EWOULDBLOCK) {
        !           311:                                YIELD();
        !           312:                                continue;
        !           313:                        }
        !           314:                        if(ERROR_VALUE==ECONNRESET) 
        !           315:                                lprintf(LOG_WARNING,"%04d Connection reset by peer on send",sock);
        !           316:                        else if(ERROR_VALUE==ECONNABORTED)
        !           317:                                lprintf(LOG_WARNING,"%04d Connection aborted by peer on send",sock);
        !           318:                        else
        !           319:                                lprintf(LOG_WARNING,"%04d !ERROR %d sending",sock,ERROR_VALUE);
        !           320:                        return(0);
        !           321:                }
        !           322:                lprintf(LOG_WARNING,"%04d !ERROR: short send: %u instead of %u",sock,result,len);
        !           323:        }
        !           324:        return(len);
        !           325: }
        !           326: 
        !           327: 
        !           328: /* Returns the directory index of a virtual lib/dir path (e.g. main/games/filename) */
        !           329: int getdir(char* p, user_t* user)
        !           330: {
        !           331:        char*   tp;
        !           332:        char    path[MAX_PATH+1];
        !           333:        int             dir;
        !           334:        int             lib;
        !           335: 
        !           336:        SAFECOPY(path,p);
        !           337:        p=path;
        !           338: 
        !           339:        if(*p=='/') 
        !           340:                p++;
        !           341:        else if(!strncmp(p,"./",2))
        !           342:                p+=2;
        !           343: 
        !           344:        tp=strchr(p,'/');
        !           345:        if(tp) *tp=0;
        !           346:        for(lib=0;lib<scfg.total_libs;lib++) {
        !           347:                if(!chk_ar(&scfg,scfg.lib[lib]->ar,user))
        !           348:                        continue;
        !           349:                if(!stricmp(scfg.lib[lib]->sname,p))
        !           350:                        break;
        !           351:        }
        !           352:        if(lib>=scfg.total_libs) 
        !           353:                return(-1);
        !           354: 
        !           355:        if(tp!=NULL)
        !           356:                p=tp+1;
        !           357: 
        !           358:        tp=strchr(p,'/');
        !           359:        if(tp) *tp=0;
        !           360:        for(dir=0;dir<scfg.total_dirs;dir++) {
        !           361:                if(scfg.dir[dir]->lib!=lib)
        !           362:                        continue;
        !           363:                if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir 
        !           364:                        && !chk_ar(&scfg,scfg.dir[dir]->ar,user))
        !           365:                        continue;
        !           366:                if(!stricmp(scfg.dir[dir]->code_suffix,p))
        !           367:                        break;
        !           368:        }
        !           369:        if(dir>=scfg.total_dirs) 
        !           370:                return(-1);
        !           371: 
        !           372:        return(dir);
        !           373: }
        !           374: 
        !           375: /*********************************/
        !           376: /* JavaScript Data and Functions */
        !           377: /*********************************/
        !           378: #ifdef JAVASCRIPT
        !           379: 
        !           380: js_server_props_t js_server_props;
        !           381: 
        !           382: static JSBool
        !           383: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           384: {
        !           385:     uintN              i;
        !           386:     JSString*  str=NULL;
        !           387:        FILE*   fp;
        !           388: 
        !           389:        if((fp=(FILE*)JS_GetContextPrivate(cx))==NULL)
        !           390:                return(JS_FALSE);
        !           391: 
        !           392:     for (i = 0; i < argc; i++) {
        !           393:                str = JS_ValueToString(cx, argv[i]);
        !           394:                if (!str)
        !           395:                    return JS_FALSE;
        !           396:                fprintf(fp,"%s",JS_GetStringBytes(str));
        !           397:        }
        !           398: 
        !           399:        if(str==NULL)
        !           400:                *rval = JSVAL_VOID;
        !           401:        else
        !           402:                *rval = STRING_TO_JSVAL(str);
        !           403:        return(JS_TRUE);
        !           404: }
        !           405: 
        !           406: static JSBool
        !           407: js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           408: {
        !           409:        FILE*   fp;
        !           410: 
        !           411:        if((fp=(FILE*)JS_GetContextPrivate(cx))==NULL)
        !           412:                return(JS_FALSE);
        !           413: 
        !           414:        js_write(cx,obj,argc,argv,rval);
        !           415:        fprintf(fp,"\r\n");
        !           416:        return(JS_TRUE);
        !           417: }
        !           418: 
        !           419: static JSFunctionSpec js_global_functions[] = {
        !           420:        {"write",           js_write,           1},             /* write to HTML file */
        !           421:        {"writeln",         js_writeln,         1},             /* write to HTML file */
        !           422:        {"print",                       js_writeln,         1},         /* alias for writeln */
        !           423:        {0}
        !           424: };
        !           425: 
        !           426: static void
        !           427: js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
        !           428: {
        !           429:        char    line[64];
        !           430:        char    file[MAX_PATH+1];
        !           431:        char*   warning;
        !           432:        FILE*   fp;
        !           433: 
        !           434:        fp=(FILE*)JS_GetContextPrivate(cx);
        !           435:        
        !           436:        if(report==NULL) {
        !           437:                lprintf(LOG_ERR,"!JavaScript: %s", message);
        !           438:                if(fp!=NULL)
        !           439:                        fprintf(fp,"!JavaScript: %s", message);
        !           440:                return;
        !           441:     }
        !           442: 
        !           443:        if(report->filename)
        !           444:                sprintf(file," %s",report->filename);
        !           445:        else
        !           446:                file[0]=0;
        !           447: 
        !           448:        if(report->lineno)
        !           449:                sprintf(line," line %u",report->lineno);
        !           450:        else
        !           451:                line[0]=0;
        !           452: 
        !           453:        if(JSREPORT_IS_WARNING(report->flags)) {
        !           454:                if(JSREPORT_IS_STRICT(report->flags))
        !           455:                        warning="strict warning";
        !           456:                else
        !           457:                        warning="warning";
        !           458:        } else
        !           459:                warning="";
        !           460: 
        !           461:        lprintf(LOG_ERR,"!JavaScript %s%s%s: %s",warning,file,line,message);
        !           462:        if(fp!=NULL)
        !           463:                fprintf(fp,"!JavaScript %s%s%s: %s",warning,file,line,message);
        !           464: }
        !           465: 
        !           466: static JSContext* 
        !           467: js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp)
        !           468: {
        !           469:        JSContext*      js_cx;
        !           470:        JSObject*       js_glob;
        !           471:        BOOL            success=FALSE;
        !           472: 
        !           473:        lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)"
        !           474:                ,sock,startup->js.cx_stack);
        !           475: 
        !           476:     if((js_cx = JS_NewContext(runtime, startup->js.cx_stack))==NULL)
        !           477:                return(NULL);
        !           478: 
        !           479:        lprintf(LOG_DEBUG,"%04d JavaScript: Context created",sock);
        !           480: 
        !           481:     JS_SetErrorReporter(js_cx, js_ErrorReporter);
        !           482: 
        !           483:        do {
        !           484: 
        !           485:                lprintf(LOG_DEBUG,"%04d JavaScript: Initializing Global object",sock);
        !           486:                if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL))==NULL) 
        !           487:                        break;
        !           488: 
        !           489:                if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions)) 
        !           490:                        break;
        !           491: 
        !           492:                lprintf(LOG_DEBUG,"%04d JavaScript: Initializing System object",sock);
        !           493:                if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL) 
        !           494:                        break;
        !           495: 
        !           496:                if((*ftp=JS_DefineObject(js_cx, js_glob, "ftp", NULL
        !           497:                        ,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
        !           498:                        break;
        !           499: 
        !           500:                if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL)
        !           501:                        break;
        !           502: 
        !           503:                if(glob!=NULL)
        !           504:                        *glob=js_glob;
        !           505: 
        !           506:                success=TRUE;
        !           507: 
        !           508:        } while(0);
        !           509: 
        !           510:        if(!success) {
        !           511:                JS_DestroyContext(js_cx);
        !           512:                return(NULL);
        !           513:        }
        !           514: 
        !           515:        return(js_cx);
        !           516: }
        !           517: 
        !           518: BOOL js_add_file(JSContext* js_cx, JSObject* array, 
        !           519:                                 char* name, char* desc, char* ext_desc,
        !           520:                                 ulong size, ulong credits, 
        !           521:                                 time_t time, time_t uploaded, time_t last_downloaded, 
        !           522:                                 ulong times_downloaded, ulong misc, 
        !           523:                                 char* uploader, char* link)
        !           524: {
        !           525:        JSObject*       file;
        !           526:        JSString*       js_str;
        !           527:        jsval           val;
        !           528:        jsuint          index;
        !           529: 
        !           530:        if((file=JS_NewObject(js_cx, NULL, NULL, NULL))==NULL)
        !           531:                return(FALSE);
        !           532: 
        !           533:        if((js_str=JS_NewStringCopyZ(js_cx, name))==NULL)
        !           534:                return(FALSE);
        !           535:        val=STRING_TO_JSVAL(js_str);
        !           536:        if(!JS_SetProperty(js_cx, file, "name", &val))
        !           537:                return(FALSE);
        !           538: 
        !           539:        if((js_str=JS_NewStringCopyZ(js_cx, desc))==NULL)
        !           540:                return(FALSE);
        !           541:        val=STRING_TO_JSVAL(js_str);
        !           542:        if(!JS_SetProperty(js_cx, file, "description", &val))
        !           543:                return(FALSE);
        !           544: 
        !           545:        if((js_str=JS_NewStringCopyZ(js_cx, ext_desc))==NULL)
        !           546:                return(FALSE);
        !           547:        val=STRING_TO_JSVAL(js_str);
        !           548:        if(!JS_SetProperty(js_cx, file, "extended_description", &val))
        !           549:                return(FALSE);
        !           550: 
        !           551:        val=INT_TO_JSVAL(size);
        !           552:        if(!JS_SetProperty(js_cx, file, "size", &val))
        !           553:                return(FALSE);
        !           554: 
        !           555:        val=INT_TO_JSVAL(credits);
        !           556:        if(!JS_SetProperty(js_cx, file, "credits", &val))
        !           557:                return(FALSE);
        !           558: 
        !           559:        JS_NewNumberValue(js_cx,time,&val);
        !           560:        if(!JS_SetProperty(js_cx, file, "time", &val))
        !           561:                return(FALSE);
        !           562: 
        !           563:        val=INT_TO_JSVAL(uploaded);
        !           564:        if(!JS_SetProperty(js_cx, file, "uploaded", &val))
        !           565:                return(FALSE);
        !           566: 
        !           567:        val=INT_TO_JSVAL(last_downloaded);
        !           568:        if(!JS_SetProperty(js_cx, file, "last_downloaded", &val))
        !           569:                return(FALSE);
        !           570: 
        !           571:        val=INT_TO_JSVAL(times_downloaded);
        !           572:        if(!JS_SetProperty(js_cx, file, "times_downloaded", &val))
        !           573:                return(FALSE);
        !           574: 
        !           575:        if((js_str=JS_NewStringCopyZ(js_cx, uploader))==NULL)
        !           576:                return(FALSE);
        !           577:        val=STRING_TO_JSVAL(js_str);
        !           578:        if(!JS_SetProperty(js_cx, file, "uploader", &val))
        !           579:                return(FALSE);
        !           580: 
        !           581:        val=INT_TO_JSVAL(misc);
        !           582:        if(!JS_SetProperty(js_cx, file, "settings", &val))
        !           583:                return(FALSE);
        !           584: 
        !           585:        if((js_str=JS_NewStringCopyZ(js_cx, link))==NULL)
        !           586:                return(FALSE);
        !           587:        val=STRING_TO_JSVAL(js_str);
        !           588:        if(!JS_SetProperty(js_cx, file, "link", &val))
        !           589:                return(FALSE);
        !           590: 
        !           591:        if(!JS_GetArrayLength(js_cx, array, &index))
        !           592:                return(FALSE);
        !           593: 
        !           594:        val=OBJECT_TO_JSVAL(file);
        !           595:        return(JS_SetElement(js_cx, array, index, &val));
        !           596: }
        !           597: 
        !           598: BOOL js_generate_index(JSContext* js_cx, JSObject* parent, 
        !           599:                                           SOCKET sock, FILE* fp, int lib, int dir, user_t* user)
        !           600: {
        !           601:        char            str[256];
        !           602:        char            path[MAX_PATH+1];
        !           603:        char            spath[MAX_PATH+1];      /* script path */
        !           604:        char            vpath[MAX_PATH+1];      /* virtual path */
        !           605:        char            aliasfile[MAX_PATH+1];
        !           606:        char            extdesc[513];
        !           607:        char*           p;
        !           608:        char*           tp;
        !           609:        char*           np;
        !           610:        char*           dp;
        !           611:        char            aliasline[512];
        !           612:        BOOL            alias_dir;
        !           613:        BOOL            success=FALSE;
        !           614:        FILE*           alias_fp;
        !           615:        uint            i;
        !           616:        file_t          f;
        !           617:        glob_t          g;
        !           618:        jsval           val;
        !           619:        jsval           rval;
        !           620:        JSObject*       lib_obj=NULL;
        !           621:        JSObject*       dir_obj=NULL;
        !           622:        JSObject*       file_array=NULL;
        !           623:        JSObject*       dir_array=NULL;
        !           624:        JSScript*       js_script=NULL;
        !           625:        JSString*       js_str;
        !           626: 
        !           627:        JS_SetContextPrivate(js_cx, fp);
        !           628: 
        !           629:        do {    /* pseudo try/catch */
        !           630: 
        !           631:                if((file_array=JS_NewArrayObject(js_cx, 0, NULL))==NULL) {
        !           632:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to create file_array",sock);
        !           633:                        break;
        !           634:                }
        !           635: 
        !           636:                /* file[] */
        !           637:                val=OBJECT_TO_JSVAL(file_array);
        !           638:                if(!JS_SetProperty(js_cx, parent, "file_list", &val)) {
        !           639:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to set file property",sock);
        !           640:                        break;
        !           641:                }
        !           642: 
        !           643:                if((dir_array=JS_NewArrayObject(js_cx, 0, NULL))==NULL) {
        !           644:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to create dir_array",sock);
        !           645:                        break;
        !           646:                }
        !           647: 
        !           648:                /* dir[] */
        !           649:                val=OBJECT_TO_JSVAL(dir_array);
        !           650:                if(!JS_SetProperty(js_cx, parent, "dir_list", &val)) {
        !           651:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to set dir property",sock);
        !           652:                        break;
        !           653:                }
        !           654: 
        !           655:                if(strcspn(startup->html_index_script,"/\\")==strlen(startup->html_index_script)) {
        !           656:                        sprintf(spath,"%s%s",scfg.mods_dir,startup->html_index_script);
        !           657:                        if(scfg.mods_dir[0]==0 || !fexist(spath))
        !           658:                                sprintf(spath,"%s%s",scfg.exec_dir,startup->html_index_script);
        !           659:                } else
        !           660:                        sprintf(spath,"%.*s",(int)sizeof(spath)-4,startup->html_index_script);
        !           661:                /* Add extension if not specified */
        !           662:                if(!strchr(spath,'.'))
        !           663:                        strcat(spath,".js");
        !           664: 
        !           665:                if(!fexist(spath)) {
        !           666:                        lprintf(LOG_ERR,"%04d !HTML JavaScript (%s) doesn't exist",sock,spath);
        !           667:                        break;
        !           668:                }
        !           669: 
        !           670:                if((js_str=JS_NewStringCopyZ(js_cx, startup->html_index_file))==NULL)
        !           671:                        break;
        !           672:                val=STRING_TO_JSVAL(js_str);
        !           673:                if(!JS_SetProperty(js_cx, parent, "html_index_file", &val)) {
        !           674:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to set html_index_file property",sock);
        !           675:                        break;
        !           676:                }
        !           677: 
        !           678:                /* curlib */
        !           679:                if((lib_obj=JS_NewObject(js_cx, NULL, 0, NULL))==NULL) {
        !           680:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to create lib_obj",sock);
        !           681:                        break;
        !           682:                }
        !           683: 
        !           684:                val=OBJECT_TO_JSVAL(lib_obj);
        !           685:                if(!JS_SetProperty(js_cx, parent, "curlib", &val)) {
        !           686:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curlib property",sock);
        !           687:                        break;
        !           688:                }
        !           689: 
        !           690:                /* curdir */
        !           691:                if((dir_obj=JS_NewObject(js_cx, NULL, 0, NULL))==NULL) {
        !           692:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to create dir_obj",sock);
        !           693:                        break;
        !           694:                }
        !           695: 
        !           696:                val=OBJECT_TO_JSVAL(dir_obj);
        !           697:                if(!JS_SetProperty(js_cx, parent, "curdir", &val)) {
        !           698:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir property",sock);
        !           699:                        break;
        !           700:                }
        !           701: 
        !           702:                SAFECOPY(vpath,"/");
        !           703: 
        !           704:                if(lib>=0) { /* root */
        !           705: 
        !           706:                        strcat(vpath,scfg.lib[lib]->sname);
        !           707:                        strcat(vpath,"/");
        !           708: 
        !           709:                        if((js_str=JS_NewStringCopyZ(js_cx, scfg.lib[lib]->sname))==NULL)
        !           710:                                break;
        !           711:                        val=STRING_TO_JSVAL(js_str);
        !           712:                        if(!JS_SetProperty(js_cx, lib_obj, "name", &val)) {
        !           713:                                lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curlib.name property",sock);
        !           714:                                break;
        !           715:                        }
        !           716: 
        !           717:                        if((js_str=JS_NewStringCopyZ(js_cx, scfg.lib[lib]->lname))==NULL)
        !           718:                                break;
        !           719:                        val=STRING_TO_JSVAL(js_str);
        !           720:                        if(!JS_SetProperty(js_cx, lib_obj, "description", &val)) {
        !           721:                                lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curlib.desc property",sock);
        !           722:                                break;
        !           723:                        }
        !           724:                }
        !           725: 
        !           726:                if(dir>=0) { /* 1st level */
        !           727:                        strcat(vpath,scfg.dir[dir]->code_suffix);
        !           728:                        strcat(vpath,"/");
        !           729: 
        !           730:                        if((js_str=JS_NewStringCopyZ(js_cx, scfg.dir[dir]->code))==NULL)
        !           731:                                break;
        !           732:                        val=STRING_TO_JSVAL(js_str);
        !           733:                        if(!JS_SetProperty(js_cx, dir_obj, "code", &val)) {
        !           734:                                lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.code property",sock);
        !           735:                                break;
        !           736:                        }
        !           737: 
        !           738:                        if((js_str=JS_NewStringCopyZ(js_cx, scfg.dir[dir]->sname))==NULL)
        !           739:                                break;
        !           740:                        val=STRING_TO_JSVAL(js_str);
        !           741:                        if(!JS_SetProperty(js_cx, dir_obj, "name", &val)) {
        !           742:                                lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.name property",sock);
        !           743:                                break;
        !           744:                        }
        !           745: 
        !           746:                        if((js_str=JS_NewStringCopyZ(js_cx, scfg.dir[dir]->lname))==NULL)
        !           747:                                break;
        !           748:                        val=STRING_TO_JSVAL(js_str);
        !           749:                        if(!JS_SetProperty(js_cx, dir_obj, "description", &val)) {
        !           750:                                lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.desc property",sock);
        !           751:                                break;
        !           752:                        }
        !           753: 
        !           754:                        val=INT_TO_JSVAL(scfg.dir[dir]->misc);
        !           755:                        if(!JS_SetProperty(js_cx, dir_obj, "settings", &val)) {
        !           756:                                lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.misc property",sock);
        !           757:                                break;
        !           758:                        }
        !           759:                }
        !           760: 
        !           761:                if((js_str=JS_NewStringCopyZ(js_cx, vpath))==NULL)
        !           762:                        break;
        !           763:                val=STRING_TO_JSVAL(js_str);
        !           764:                if(!JS_SetProperty(js_cx, parent, "path", &val)) {
        !           765:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir property",sock);
        !           766:                        break;
        !           767:                }
        !           768: 
        !           769:                if(lib<0) {     /* root dir */
        !           770: 
        !           771:                        /* File Aliases */
        !           772:                        sprintf(path,"%sftpalias.cfg",scfg.ctrl_dir);
        !           773:                        if((alias_fp=fopen(path,"r"))!=NULL) {
        !           774: 
        !           775:                                while(!feof(alias_fp)) {
        !           776:                                        if(!fgets(aliasline,sizeof(aliasline),alias_fp))
        !           777:                                                break;
        !           778: 
        !           779:                                        p=aliasline;    /* alias pointer */
        !           780:                                        while(*p && *p<=' ') p++;
        !           781: 
        !           782:                                        if(*p==';')     /* comment */
        !           783:                                                continue;
        !           784: 
        !           785:                                        tp=p;           /* terminator pointer */
        !           786:                                        while(*tp && *tp>' ') tp++;
        !           787:                                        if(*tp) *tp=0;
        !           788: 
        !           789:                                        np=tp+1;        /* filename pointer */
        !           790:                                        while(*np && *np<=' ') np++;
        !           791: 
        !           792:                                        tp=np;          /* terminator pointer */
        !           793:                                        while(*tp && *tp>' ') tp++;
        !           794:                                        if(*tp) *tp=0;
        !           795: 
        !           796:                                        dp=tp+1;        /* description pointer */
        !           797:                                        while(*dp && *dp<=' ') dp++;
        !           798:                                        truncsp(dp);
        !           799: 
        !           800:                                        if(stricmp(dp,BBS_HIDDEN_ALIAS)==0)
        !           801:                                                continue;
        !           802: 
        !           803:                                        alias_dir=FALSE;
        !           804: 
        !           805:                                        /* Virtual Path? */
        !           806:                                        if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
        !           807:                                                if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),user))<0)
        !           808:                                                        continue; /* No access or invalid virtual path */
        !           809:                                                tp=strrchr(np,'/');
        !           810:                                                if(tp==NULL) 
        !           811:                                                        continue;
        !           812:                                                tp++;
        !           813:                                                if(*tp) {
        !           814:                                                        SAFEPRINTF2(aliasfile,"%s%s",scfg.dir[dir]->path,tp);
        !           815:                                                        np=aliasfile;
        !           816:                                                }
        !           817:                                                else 
        !           818:                                                        alias_dir=TRUE;
        !           819:                                        }
        !           820: 
        !           821:                                        if(!alias_dir && !fexist(np))
        !           822:                                                continue;
        !           823: 
        !           824:                                        if(alias_dir) {
        !           825:                                                if(!chk_ar(&scfg,scfg.dir[dir]->ar,user))
        !           826:                                                        continue;
        !           827:                                                SAFEPRINTF2(vpath,"/%s/%s",p,startup->html_index_file);
        !           828:                                        } else
        !           829:                                                SAFECOPY(vpath,p);
        !           830:                                        js_add_file(js_cx
        !           831:                                                ,alias_dir ? dir_array : file_array
        !           832:                                                ,p                              /* filename */
        !           833:                                                ,dp                             /* description */
        !           834:                                                ,NULL                   /* extdesc */
        !           835:                                                ,flength(np)    /* size */
        !           836:                                                ,0                              /* credits */
        !           837:                                                ,fdate(np)              /* time */
        !           838:                                                ,fdate(np)              /* uploaded */
        !           839:                                                ,0                              /* last downloaded */
        !           840:                                                ,0                              /* times downloaded */
        !           841:                                                ,0                              /* misc */
        !           842:                                                ,scfg.sys_id    /* uploader */
        !           843:                                                ,vpath                  /* link */
        !           844:                                                );
        !           845:                                }
        !           846: 
        !           847:                                fclose(alias_fp);
        !           848:                        }
        !           849: 
        !           850:                        /* QWK Packet */
        !           851:                        if(startup->options&FTP_OPT_ALLOW_QWK /* && fexist(qwkfile) */) {
        !           852:                                sprintf(str,"%s.qwk",scfg.sys_id);
        !           853:                                SAFEPRINTF(vpath,"/%s",str);
        !           854:                                js_add_file(js_cx
        !           855:                                        ,file_array 
        !           856:                                        ,str                                            /* filename */
        !           857:                                        ,"QWK Message Packet"           /* description */
        !           858:                                        ,NULL                                           /* extdesc */
        !           859:                                        ,10240                                          /* size */
        !           860:                                        ,0                                                      /* credits */
        !           861:                                        ,time(NULL)                                     /* time */
        !           862:                                        ,0                                                      /* uploaded */
        !           863:                                        ,0                                                      /* last downloaded */
        !           864:                                        ,0                                                      /* times downloaded */
        !           865:                                        ,0                                                      /* misc */
        !           866:                                        ,scfg.sys_id                            /* uploader */
        !           867:                                        ,str                                            /* link */
        !           868:                                        );
        !           869:                        }
        !           870: 
        !           871:                        /* Library Folders */
        !           872:                        for(i=0;i<scfg.total_libs;i++) {
        !           873:                                if(!chk_ar(&scfg,scfg.lib[i]->ar,user))
        !           874:                                        continue;
        !           875:                                SAFEPRINTF2(vpath,"/%s/%s",scfg.lib[i]->sname,startup->html_index_file);
        !           876:                                js_add_file(js_cx
        !           877:                                        ,dir_array 
        !           878:                                        ,scfg.lib[i]->sname                     /* filename */
        !           879:                                        ,scfg.lib[i]->lname                     /* description */
        !           880:                                        ,NULL                                           /* extdesc */
        !           881:                                        ,0,0,0,0,0,0,0                          /* unused */
        !           882:                                        ,scfg.sys_id                            /* uploader */
        !           883:                                        ,vpath                                          /* link */
        !           884:                                        );
        !           885:                        }
        !           886:                } else if(dir<0) {
        !           887:                        /* Directories */
        !           888:                        for(i=0;i<scfg.total_dirs;i++) {
        !           889:                                if(scfg.dir[i]->lib!=lib)
        !           890:                                        continue;
        !           891:                                if(/* i!=scfg.sysop_dir && i!=scfg.upload_dir && */
        !           892:                                        !chk_ar(&scfg,scfg.dir[i]->ar,user))
        !           893:                                        continue;
        !           894:                                SAFEPRINTF3(vpath,"/%s/%s/%s"
        !           895:                                        ,scfg.lib[scfg.dir[i]->lib]->sname
        !           896:                                        ,scfg.dir[i]->code_suffix
        !           897:                                        ,startup->html_index_file);
        !           898:                                js_add_file(js_cx
        !           899:                                        ,dir_array 
        !           900:                                        ,scfg.dir[i]->sname                     /* filename */
        !           901:                                        ,scfg.dir[i]->lname                     /* description */
        !           902:                                        ,NULL                                           /* extdesc */
        !           903:                                        ,getfiles(&scfg,i)                      /* size */
        !           904:                                        ,0,0,0,0,0                                      /* unused */
        !           905:                                        ,scfg.dir[i]->misc                      /* misc */
        !           906:                                        ,scfg.sys_id                            /* uploader */
        !           907:                                        ,vpath                                          /* link */
        !           908:                                        );
        !           909: 
        !           910:                        }
        !           911:                } else if(chk_ar(&scfg,scfg.dir[dir]->ar,user)){
        !           912:                        SAFEPRINTF(path,"%s*",scfg.dir[dir]->path);
        !           913:                        glob(path,0,NULL,&g);
        !           914:                        for(i=0;i<(int)g.gl_pathc;i++) {
        !           915:                                if(isdir(g.gl_pathv[i]))
        !           916:                                        continue;
        !           917:        #ifdef _WIN32
        !           918:                                GetShortPathName(g.gl_pathv[i], str, sizeof(str));
        !           919:        #else
        !           920:                                SAFECOPY(str,g.gl_pathv[i]);
        !           921:        #endif
        !           922:                                padfname(getfname(str),f.name);
        !           923:                                f.dir=dir;
        !           924:                                if(getfileixb(&scfg,&f)) {
        !           925:                                        f.size=0; /* flength(g.gl_pathv[i]); */
        !           926:                                        getfiledat(&scfg,&f);
        !           927:                                        if(f.misc&FM_EXTDESC) {
        !           928:                                                extdesc[0]=0;
        !           929:                                                getextdesc(&scfg, dir, f.datoffset, extdesc);
        !           930:                                                /* Remove Ctrl-A Codes and Ex-ASCII code */
        !           931:                                                remove_ctrl_a(extdesc,NULL);
        !           932:                                        }
        !           933:                                        SAFEPRINTF3(vpath,"/%s/%s/%s"
        !           934:                                                ,scfg.lib[scfg.dir[dir]->lib]->sname
        !           935:                                                ,scfg.dir[dir]->code_suffix
        !           936:                                                ,getfname(g.gl_pathv[i]));
        !           937:                                        js_add_file(js_cx
        !           938:                                                ,file_array 
        !           939:                                                ,getfname(g.gl_pathv[i])        /* filename */
        !           940:                                                ,f.desc                                         /* description */
        !           941:                                                ,f.misc&FM_EXTDESC ? extdesc : NULL
        !           942:                                                ,f.size                                         /* size */
        !           943:                                                ,f.cdt                                          /* credits */
        !           944:                                                ,f.date                                         /* time */
        !           945:                                                ,f.dateuled                                     /* uploaded */
        !           946:                                                ,f.datedled                                     /* last downloaded */
        !           947:                                                ,f.timesdled                            /* times downloaded */
        !           948:                                                ,f.misc                                         /* misc */
        !           949:                                                ,f.uler                                         /* uploader */
        !           950:                                                ,getfname(g.gl_pathv[i])        /* link */
        !           951:                                                );
        !           952:                                }
        !           953:                        }
        !           954:                        globfree(&g);
        !           955:                }
        !           956: 
        !           957: 
        !           958:                /* RUN SCRIPT */
        !           959:                JS_ClearPendingException(js_cx);
        !           960: 
        !           961:                if((js_script=JS_CompileFile(js_cx, parent, spath))==NULL) {
        !           962:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)",sock,spath);
        !           963:                        break;
        !           964:                }
        !           965: 
        !           966:                if((success=JS_ExecuteScript(js_cx, parent, js_script, &rval))!=TRUE) {
        !           967:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to execute script (%s)",sock,spath);
        !           968:                        break;
        !           969:                }
        !           970: 
        !           971:        } while(0);
        !           972: 
        !           973: 
        !           974:        if(js_script!=NULL) 
        !           975:                JS_DestroyScript(js_cx, js_script);
        !           976: 
        !           977:        JS_DeleteProperty(js_cx, parent, "path");
        !           978:        JS_DeleteProperty(js_cx, parent, "sort");
        !           979:        JS_DeleteProperty(js_cx, parent, "reverse");
        !           980:        JS_DeleteProperty(js_cx, parent, "file_list");
        !           981:        JS_DeleteProperty(js_cx, parent, "dir_list");
        !           982:        JS_DeleteProperty(js_cx, parent, "curlib");
        !           983:        JS_DeleteProperty(js_cx, parent, "curdir");
        !           984:        JS_DeleteProperty(js_cx, parent, "html_index_file");
        !           985: 
        !           986:        return(success);
        !           987: }
        !           988: 
        !           989: 
        !           990: #endif /* ifdef JAVASCRIPT */
        !           991: 
        !           992: 
        !           993: time_t gettimeleft(scfg_t* cfg, user_t* user, time_t starttime)
        !           994: {
        !           995:        time_t  now;
        !           996:     long    tleft;
        !           997:        time_t  timeleft;
        !           998: 
        !           999:        now=time(NULL);
        !          1000: 
        !          1001:        if(user->exempt&FLAG('T')) {   /* Time online exemption */
        !          1002:                timeleft=cfg->level_timepercall[user->level]*60;
        !          1003:                if(timeleft<10)             /* never get below 10 for exempt users */
        !          1004:                        timeleft=10; }
        !          1005:        else {
        !          1006:                tleft=(((long)cfg->level_timeperday[user->level]-user->ttoday)
        !          1007:                        +user->textra)*60L;
        !          1008:                if(tleft<0) tleft=0;
        !          1009:                if(tleft>cfg->level_timepercall[user->level]*60)
        !          1010:                        tleft=cfg->level_timepercall[user->level]*60;
        !          1011:                tleft+=user->min*60L;
        !          1012:                tleft-=now-starttime;
        !          1013:                if(tleft>0x7fffL)
        !          1014:                        timeleft=0x7fff;
        !          1015:                else
        !          1016:                        timeleft=tleft; }
        !          1017: 
        !          1018:        return(timeleft);
        !          1019: }
        !          1020: 
        !          1021: static time_t checktime(void)
        !          1022: {
        !          1023:        struct tm tm;
        !          1024: 
        !          1025:     memset(&tm,0,sizeof(tm));
        !          1026:     tm.tm_year=94;
        !          1027:     tm.tm_mday=1;
        !          1028:     return(mktime(&tm)-0x2D24BD00L);
        !          1029: }
        !          1030: 
        !          1031: BOOL upload_stats(ulong bytes)
        !          1032: {
        !          1033:        char    str[MAX_PATH+1];
        !          1034:        int             file;
        !          1035:        ulong   val;
        !          1036: 
        !          1037:        sprintf(str,"%sdsts.dab",scfg.ctrl_dir);
        !          1038:        if((file=nopen(str,O_RDWR))==-1) 
        !          1039:                return(FALSE);
        !          1040: 
        !          1041:        lseek(file,20L,SEEK_SET);   /* Skip timestamp, logons and logons today */
        !          1042:        read(file,&val,4);        /* Uploads today         */
        !          1043:        val++;
        !          1044:        lseek(file,-4L,SEEK_CUR);
        !          1045:        write(file,&val,4);
        !          1046:        read(file,&val,4);        /* Upload bytes today    */
        !          1047:        val+=bytes;
        !          1048:        lseek(file,-4L,SEEK_CUR);
        !          1049:        write(file,&val,4);
        !          1050:        close(file);
        !          1051:        return(TRUE);
        !          1052: }
        !          1053: 
        !          1054: BOOL download_stats(ulong bytes)
        !          1055: {
        !          1056:        char    str[MAX_PATH+1];
        !          1057:        int             file;
        !          1058:        ulong   val;
        !          1059: 
        !          1060:        sprintf(str,"%sdsts.dab",scfg.ctrl_dir);
        !          1061:        if((file=nopen(str,O_RDWR))==-1) 
        !          1062:                return(FALSE);
        !          1063: 
        !          1064:        lseek(file,28L,SEEK_SET);   /* Skip timestamp, logons and logons today */
        !          1065:        read(file,&val,4);        /* Downloads today         */
        !          1066:        val++;
        !          1067:        lseek(file,-4L,SEEK_CUR);
        !          1068:        write(file,&val,4);
        !          1069:        read(file,&val,4);        /* Download bytes today    */
        !          1070:        val+=bytes;
        !          1071:        lseek(file,-4L,SEEK_CUR);
        !          1072:        write(file,&val,4);
        !          1073:        close(file);
        !          1074:        return(TRUE);
        !          1075: }
        !          1076: 
        !          1077: void recverror(SOCKET socket, int rd, int line)
        !          1078: {
        !          1079:        if(rd==0) 
        !          1080:                lprintf(LOG_NOTICE,"%04d Socket closed by peer on receive (line %u)"
        !          1081:                        ,socket, line);
        !          1082:        else if(rd==SOCKET_ERROR) {
        !          1083:                if(ERROR_VALUE==ECONNRESET) 
        !          1084:                        lprintf(LOG_NOTICE,"%04d Connection reset by peer on receive (line %u)"
        !          1085:                                ,socket, line);
        !          1086:                else if(ERROR_VALUE==ECONNABORTED) 
        !          1087:                        lprintf(LOG_NOTICE,"%04d Connection aborted by peer on receive (line %u)"
        !          1088:                                ,socket, line);
        !          1089:                else
        !          1090:                        lprintf(LOG_NOTICE,"%04d !ERROR %d receiving on socket (line %u)"
        !          1091:                                ,socket, ERROR_VALUE, line);
        !          1092:        } else
        !          1093:                lprintf(LOG_WARNING,"%04d !ERROR: recv on socket returned unexpected value: %d (line %u)"
        !          1094:                        ,socket, rd, line);
        !          1095: }
        !          1096: 
        !          1097: int sockreadline(SOCKET socket, char* buf, int len, time_t* lastactive)
        !          1098: {
        !          1099:        char    ch;
        !          1100:        int             i,rd=0;
        !          1101:        fd_set  socket_set;
        !          1102:        struct timeval  tv;
        !          1103: 
        !          1104:        buf[0]=0;
        !          1105: 
        !          1106:        if(socket==INVALID_SOCKET) {
        !          1107:                lprintf(LOG_WARNING,"INVALID SOCKET in call to sockreadline");
        !          1108:                return(0);
        !          1109:        }
        !          1110:        
        !          1111:        while(rd<len-1) {
        !          1112: 
        !          1113:                tv.tv_sec=startup->max_inactivity;
        !          1114:                tv.tv_usec=0;
        !          1115: 
        !          1116:                FD_ZERO(&socket_set);
        !          1117:                FD_SET(socket,&socket_set);
        !          1118: 
        !          1119:                i=select(socket+1,&socket_set,NULL,NULL,&tv);
        !          1120: 
        !          1121:                if(server_socket==INVALID_SOCKET || terminate_server) {
        !          1122:                        sockprintf(socket,"421 Server downed, aborting.");
        !          1123:                        lprintf(LOG_WARNING,"%04d Server downed, aborting",socket);
        !          1124:                        return(0);
        !          1125:                }
        !          1126:                if(i<1) {
        !          1127:                        if(i==0) {
        !          1128:                                if((time(NULL)-(*lastactive))>startup->max_inactivity) {
        !          1129:                                        lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",socket);
        !          1130:                                        sockprintf(socket,"421 Disconnecting due to inactivity (%u seconds)."
        !          1131:                                                ,startup->max_inactivity);
        !          1132:                                        return(0);
        !          1133:                                }
        !          1134:                                continue;
        !          1135:                        }
        !          1136:                        recverror(socket,i,__LINE__);
        !          1137:                        return(i);
        !          1138:                }
        !          1139: #ifdef SOCKET_DEBUG_RECV_CHAR
        !          1140:                socket_debug[socket]|=SOCKET_DEBUG_RECV_CHAR;
        !          1141: #endif
        !          1142:                i=recv(socket, &ch, 1, 0);
        !          1143: #ifdef SOCKET_DEBUG_RECV_CHAR
        !          1144:                socket_debug[socket]&=~SOCKET_DEBUG_RECV_CHAR;
        !          1145: #endif
        !          1146:                if(i<1) {
        !          1147:                        recverror(socket,i,__LINE__);
        !          1148:                        return(i);
        !          1149:                }
        !          1150:                if(ch=='\n' /* && rd>=1 */) { /* Mar-9-2003: terminate on sole LF */
        !          1151:                        break;
        !          1152:                }       
        !          1153:                buf[rd++]=ch;
        !          1154:        }
        !          1155:        if(rd>0 && buf[rd-1]=='\r')
        !          1156:                buf[rd-1]=0;
        !          1157:        else
        !          1158:                buf[rd]=0;
        !          1159:        
        !          1160:        return(rd);
        !          1161: }
        !          1162: 
        !          1163: #if 0  /* now exported from in xtrn.cpp */
        !          1164: /*****************************************************************************/
        !          1165: /* Returns command line generated from instr with %c replacments             */
        !          1166: /*****************************************************************************/
        !          1167: static char* cmdstr(user_t* user, char *instr, char *fpath, char *fspec, char *cmd)
        !          1168: {
        !          1169:        char    str[256];
        !          1170:     int                i,j,len;
        !          1171: #ifdef _WIN32
        !          1172:        char sfpath[MAX_PATH+1];
        !          1173: #endif
        !          1174: 
        !          1175:     len=strlen(instr);
        !          1176:     for(i=j=0;i<len;i++) {
        !          1177:         if(instr[i]=='%') {
        !          1178:             i++;
        !          1179:             cmd[j]=0;
        !          1180:             switch(toupper(instr[i])) {
        !          1181:                 case 'A':   /* User alias */
        !          1182:                     strcat(cmd,user->alias);
        !          1183:                     break;
        !          1184:                 case 'B':   /* Baud (DTE) Rate */
        !          1185:                 case 'C':   /* Connect Description */
        !          1186:                 case 'D':   /* Connect (DCE) Rate */
        !          1187:                 case 'E':   /* Estimated Rate */
        !          1188:                 case 'H':   /* Port Handle or Hardware Flow Control */
        !          1189:                 case 'P':   /* COM Port */
        !          1190:                 case 'R':   /* Rows */
        !          1191:                 case 'T':   /* Time left in seconds */
        !          1192:                 case '&':   /* Address of msr */
        !          1193:                 case 'Y':      /* COMSPEC */
        !          1194:                                        /* UNSUPPORTED */
        !          1195:                                        break;
        !          1196:                 case 'F':   /* File path */
        !          1197:                     strcat(cmd,fpath);
        !          1198:                     break;
        !          1199:                 case 'G':   /* Temp directory */
        !          1200:                     strcat(cmd,scfg.temp_dir);
        !          1201:                     break;
        !          1202:                 case 'I':   /* UART IRQ Line */
        !          1203:                     strcat(cmd,ultoa(scfg.com_irq,str,10));
        !          1204:                     break;
        !          1205:                 case 'J':
        !          1206:                     strcat(cmd,scfg.data_dir);
        !          1207:                     break;
        !          1208:                 case 'K':
        !          1209:                     strcat(cmd,scfg.ctrl_dir);
        !          1210:                     break;
        !          1211:                 case 'L':   /* Lines per message */
        !          1212:                     strcat(cmd,ultoa(scfg.level_linespermsg[user->level],str,10));
        !          1213:                     break;
        !          1214:                 case 'M':   /* Minutes (credits) for user */
        !          1215:                     strcat(cmd,ultoa(user->min,str,10));
        !          1216:                     break;
        !          1217:                 case 'N':   /* Node Directory (same as SBBSNODE environment var) */
        !          1218:                     strcat(cmd,scfg.node_dir);
        !          1219:                     break;
        !          1220:                 case 'O':   /* SysOp */
        !          1221:                     strcat(cmd,scfg.sys_op);
        !          1222:                     break;
        !          1223:                 case 'Q':   /* QWK ID */
        !          1224:                     strcat(cmd,scfg.sys_id);
        !          1225:                     break;
        !          1226:                 case 'S':   /* File Spec */
        !          1227:                     strcat(cmd,fspec);
        !          1228:                     break;
        !          1229:                 case 'U':   /* UART I/O Address (in hex) */
        !          1230:                     strcat(cmd,ultoa(scfg.com_base,str,16));
        !          1231:                     break;
        !          1232:                 case 'V':   /* Synchronet Version */
        !          1233:                     sprintf(str,"%s%c",VERSION,REVISION);
        !          1234:                     break;
        !          1235:                 case 'W':   /* Time-slice API type (mswtype) */
        !          1236:                     break;
        !          1237:                 case 'X':
        !          1238:                     strcat(cmd,scfg.shell[user->shell]->code);
        !          1239:                     break;
        !          1240:                 case 'Z':
        !          1241:                     strcat(cmd,scfg.text_dir);
        !          1242:                     break;
        !          1243:                                case '~':       /* DOS-compatible (8.3) filename */
        !          1244: #ifdef _WIN32
        !          1245:                                        SAFECOPY(sfpath,fpath);
        !          1246:                                        GetShortPathName(fpath,sfpath,sizeof(sfpath));
        !          1247:                                        strcat(cmd,sfpath);
        !          1248: #else
        !          1249:                     strcat(cmd,fpath);
        !          1250: #endif                 
        !          1251:                                        break;
        !          1252:                 case '!':   /* EXEC Directory */
        !          1253:                     strcat(cmd,scfg.exec_dir);
        !          1254:                     break;
        !          1255:                 case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
        !          1256: #ifndef __unix__
        !          1257:                     strcat(cmd,scfg.exec_dir);
        !          1258: #endif
        !          1259:                     break;
        !          1260:                 case '#':   /* Node number (same as SBBSNNUM environment var) */
        !          1261:                     sprintf(str,"%u",scfg.node_num);
        !          1262:                     strcat(cmd,str);
        !          1263:                     break;
        !          1264:                 case '*':
        !          1265:                     sprintf(str,"%03u",scfg.node_num);
        !          1266:                     strcat(cmd,str);
        !          1267:                     break;
        !          1268:                 case '$':   /* Credits */
        !          1269:                     strcat(cmd,ultoa(user->cdt+user->freecdt,str,10));
        !          1270:                     break;
        !          1271:                 case '%':   /* %% for percent sign */
        !          1272:                     strcat(cmd,"%");
        !          1273:                     break;
        !          1274:                                case '?':       /* Platform */
        !          1275: #ifdef __OS2__
        !          1276:                                        SAFECOPY(str,"OS2");
        !          1277: #else
        !          1278:                                        SAFECOPY(str,PLATFORM_DESC);
        !          1279: #endif
        !          1280:                                        strlwr(str);
        !          1281:                                        strcat(cmd,str);
        !          1282:                                        break;
        !          1283:                 default:    /* unknown specification */
        !          1284:                     if(isdigit(instr[i])) {
        !          1285:                         sprintf(str,"%0*d",instr[i]&0xf,user->number);
        !          1286:                         strcat(cmd,str); }
        !          1287:                     break; }
        !          1288:             j=strlen(cmd); }
        !          1289:         else
        !          1290:             cmd[j++]=instr[i]; }
        !          1291:     cmd[j]=0;
        !          1292: 
        !          1293:     return(cmd);
        !          1294: }
        !          1295: #endif
        !          1296: 
        !          1297: void DLLCALL ftp_terminate(void)
        !          1298: {
        !          1299:        lprintf(LOG_DEBUG,"%04d FTP Server terminate",server_socket);
        !          1300:        terminate_server=TRUE;
        !          1301: }
        !          1302: 
        !          1303: 
        !          1304: typedef struct {
        !          1305:        SOCKET  ctrl_sock;
        !          1306:        SOCKET* data_sock;
        !          1307:        BOOL*   inprogress;
        !          1308:        BOOL*   aborted;
        !          1309:        BOOL    delfile;
        !          1310:        BOOL    tmpfile;
        !          1311:        BOOL    credits;
        !          1312:        BOOL    append;
        !          1313:        long    filepos;
        !          1314:        char    filename[MAX_PATH+1];
        !          1315:        time_t* lastactive;
        !          1316:        user_t* user;
        !          1317:        int             dir;
        !          1318:        char*   desc;
        !          1319: } xfer_t;
        !          1320: 
        !          1321: static void send_thread(void* arg)
        !          1322: {
        !          1323:        char            buf[8192];
        !          1324:        char            fname[MAX_PATH+1];
        !          1325:        char            str[128];
        !          1326:        char            tmp[128];
        !          1327:        char            username[128];
        !          1328:        int                     i;
        !          1329:        int                     rd;
        !          1330:        int                     wr;
        !          1331:        long            mod;
        !          1332:        ulong           l;
        !          1333:        ulong           total=0;
        !          1334:        ulong           last_total=0;
        !          1335:        ulong           dur;
        !          1336:        ulong           cps;
        !          1337:        ulong           length;
        !          1338:        BOOL            error=FALSE;
        !          1339:        FILE*           fp;
        !          1340:        file_t          f;
        !          1341:        xfer_t          xfer;
        !          1342:        time_t          now;
        !          1343:        time_t          start;
        !          1344:        time_t          last_report;
        !          1345:        user_t          uploader;
        !          1346:        SOCKADDR_IN     addr;
        !          1347:        socklen_t       addr_len;
        !          1348:        fd_set          socket_set;
        !          1349:        struct timeval tv;
        !          1350: 
        !          1351:        xfer=*(xfer_t*)arg;
        !          1352:        free(arg);
        !          1353: 
        !          1354:        thread_up(TRUE /* setuid */);
        !          1355: 
        !          1356:        length=flength(xfer.filename);
        !          1357: 
        !          1358:        if((fp=fnopen(NULL,xfer.filename,O_RDONLY|O_BINARY))==NULL      /* non-shareable open failed */
        !          1359:                && (fp=fopen(xfer.filename,"rb"))==NULL) {                              /* shareable open failed */
        !          1360:                lprintf(LOG_ERR,"%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,errno,xfer.filename);
        !          1361:                sockprintf(xfer.ctrl_sock,"450 ERROR %d opening %s.",errno,xfer.filename);
        !          1362:                if(xfer.tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
        !          1363:                        remove(xfer.filename);
        !          1364:                ftp_close_socket(xfer.data_sock,__LINE__);
        !          1365:                *xfer.inprogress=FALSE;
        !          1366:                thread_down();
        !          1367:                return;
        !          1368:        }
        !          1369: 
        !          1370: #ifdef SOCKET_DEBUG_SENDTHREAD
        !          1371:                        socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_SENDTHREAD;
        !          1372: #endif
        !          1373: 
        !          1374:        *xfer.aborted=FALSE;
        !          1375:        if(startup->options&FTP_OPT_DEBUG_DATA || xfer.filepos)
        !          1376:                lprintf(LOG_DEBUG,"%04d DATA socket %d sending %s from offset %lu"
        !          1377:                        ,xfer.ctrl_sock,*xfer.data_sock,xfer.filename,xfer.filepos);
        !          1378: 
        !          1379:        fseek(fp,xfer.filepos,SEEK_SET);
        !          1380:        last_report=start=time(NULL);
        !          1381:        while((xfer.filepos+total)<length) {
        !          1382: 
        !          1383:                now=time(NULL);
        !          1384: 
        !          1385:                /* Periodic progress report */
        !          1386:                if(total && now>=last_report+XFER_REPORT_INTERVAL) {
        !          1387:                        if(xfer.filepos)
        !          1388:                                sprintf(str," from offset %lu",xfer.filepos);
        !          1389:                        else
        !          1390:                                str[0]=0;
        !          1391:                        lprintf(LOG_INFO,"%04d Sent %lu bytes (%lu total) of %s (%lu cps)%s"
        !          1392:                                ,xfer.ctrl_sock,total,length,xfer.filename
        !          1393:                                ,(total-last_total)/(now-last_report)
        !          1394:                                ,str);
        !          1395:                        last_total=total;
        !          1396:                        last_report=now;
        !          1397:                }
        !          1398: 
        !          1399:                if(*xfer.aborted==TRUE) {
        !          1400:                        lprintf(LOG_WARNING,"%04d !DATA Transfer aborted",xfer.ctrl_sock);
        !          1401:                        sockprintf(xfer.ctrl_sock,"426 Transfer aborted.");
        !          1402:                        error=TRUE;
        !          1403:                        break;
        !          1404:                }
        !          1405:                if(server_socket==INVALID_SOCKET || terminate_server) {
        !          1406:                        lprintf(LOG_WARNING,"%04d !DATA Transfer locally aborted",xfer.ctrl_sock);
        !          1407:                        sockprintf(xfer.ctrl_sock,"426 Transfer locally aborted.");
        !          1408:                        error=TRUE;
        !          1409:                        break;
        !          1410:                }
        !          1411: 
        !          1412:                /* Check socket for writability (using select) */
        !          1413:                tv.tv_sec=1;
        !          1414:                tv.tv_usec=0;
        !          1415: 
        !          1416:                FD_ZERO(&socket_set);
        !          1417:                FD_SET(*xfer.data_sock,&socket_set);
        !          1418: 
        !          1419:                i=select((*xfer.data_sock)+1,NULL,&socket_set,NULL,&tv);
        !          1420:                if(i==SOCKET_ERROR) {
        !          1421:                        lprintf(LOG_WARNING,"%04d !DATA ERROR %d selecting socket %d for send"
        !          1422:                                ,xfer.ctrl_sock, ERROR_VALUE, *xfer.data_sock);
        !          1423:                        sockprintf(xfer.ctrl_sock,"426 Transfer error.");
        !          1424:                        error=TRUE;
        !          1425:                        break;
        !          1426:                }
        !          1427:                if(i<1)
        !          1428:                        continue;
        !          1429: 
        !          1430:                fseek(fp,xfer.filepos+total,SEEK_SET);
        !          1431:                rd=fread(buf,sizeof(char),sizeof(buf),fp);
        !          1432:                if(rd<1) /* EOF or READ error */
        !          1433:                        break;
        !          1434: 
        !          1435: #ifdef SOCKET_DEBUG_SEND
        !          1436:                socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_SEND;
        !          1437: #endif
        !          1438:                wr=sendsocket(*xfer.data_sock,buf,rd);
        !          1439: #ifdef SOCKET_DEBUG_SEND
        !          1440:                socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_SEND;
        !          1441: #endif
        !          1442:                if(wr<1) {
        !          1443:                        if(wr==SOCKET_ERROR) {
        !          1444:                                if(ERROR_VALUE==EWOULDBLOCK) {
        !          1445:                                        /*lprintf(LOG_WARNING,"%04d DATA send would block, retrying",xfer.ctrl_sock);*/
        !          1446:                                        YIELD();
        !          1447:                                        continue;
        !          1448:                                }
        !          1449:                                else if(ERROR_VALUE==ECONNRESET) 
        !          1450:                                        lprintf(LOG_WARNING,"%04d DATA Connection reset by peer, sending on socket %d"
        !          1451:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !          1452:                                else if(ERROR_VALUE==ECONNABORTED) 
        !          1453:                                        lprintf(LOG_WARNING,"%04d DATA Connection aborted by peer, sending on socket %d"
        !          1454:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !          1455:                                else
        !          1456:                                        lprintf(LOG_WARNING,"%04d !DATA ERROR %d sending on data socket %d"
        !          1457:                                                ,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock);
        !          1458:                                /* Send NAK */
        !          1459:                                sockprintf(xfer.ctrl_sock,"426 Error %d sending on DATA channel"
        !          1460:                                        ,ERROR_VALUE);
        !          1461:                                error=TRUE;
        !          1462:                                break;
        !          1463:                        }
        !          1464:                        if(wr==0) {
        !          1465:                                lprintf(LOG_WARNING,"%04d !DATA socket %d disconnected",xfer.ctrl_sock, *xfer.data_sock);
        !          1466:                                sockprintf(xfer.ctrl_sock,"426 DATA channel disconnected");
        !          1467:                                error=TRUE;
        !          1468:                                break;
        !          1469:                        }
        !          1470:                        lprintf(LOG_ERR,"%04d !DATA SEND ERROR %d (%d) on socket %d"
        !          1471:                                ,xfer.ctrl_sock, wr, ERROR_VALUE, *xfer.data_sock);
        !          1472:                        sockprintf(xfer.ctrl_sock,"451 DATA send error");
        !          1473:                        error=TRUE;
        !          1474:                        break;
        !          1475:                }
        !          1476:                total+=wr;
        !          1477:                *xfer.lastactive=time(NULL);
        !          1478:                YIELD();
        !          1479:        }
        !          1480: 
        !          1481:        if((i=ferror(fp))!=0) 
        !          1482:                lprintf(LOG_ERR,"%04d !FILE ERROR %d (%d)",xfer.ctrl_sock,i,errno);
        !          1483: 
        !          1484:        ftp_close_socket(xfer.data_sock,__LINE__);      /* Signal end of file */
        !          1485:        if(startup->options&FTP_OPT_DEBUG_DATA)
        !          1486:                lprintf(LOG_DEBUG,"%04d DATA socket closed",xfer.ctrl_sock);
        !          1487:        
        !          1488:        if(!error) {
        !          1489:                dur=time(NULL)-start;
        !          1490:                cps=dur ? total/dur : total*2;
        !          1491:                lprintf(LOG_INFO,"%04d Transfer successful: %lu bytes sent in %lu seconds (%lu cps)"
        !          1492:                        ,xfer.ctrl_sock
        !          1493:                        ,total,dur,cps);
        !          1494:                sockprintf(xfer.ctrl_sock,"226 Download complete (%lu cps).",cps);
        !          1495: 
        !          1496:                if(xfer.dir>=0) {
        !          1497:                        memset(&f,0,sizeof(f));
        !          1498: #ifdef _WIN32
        !          1499:                        GetShortPathName(xfer.filename,fname,sizeof(fname));
        !          1500: #else
        !          1501:                        SAFECOPY(fname,xfer.filename);
        !          1502: #endif
        !          1503:                        padfname(getfname(fname),f.name);
        !          1504:                        f.dir=xfer.dir;
        !          1505:                        f.size=total;
        !          1506:                        if(getfileixb(&scfg,&f)==TRUE && getfiledat(&scfg,&f)==TRUE) {
        !          1507:                                f.timesdled++;
        !          1508:                                putfiledat(&scfg,&f);
        !          1509:                                f.datedled=time(NULL);
        !          1510:                                putfileixb(&scfg,&f);
        !          1511: 
        !          1512:                                lprintf(LOG_INFO,"%04d %s downloaded: %s (%lu times total)"
        !          1513:                                        ,xfer.ctrl_sock
        !          1514:                                        ,xfer.user->alias
        !          1515:                                        ,xfer.filename
        !          1516:                                        ,f.timesdled);
        !          1517:                                /**************************/
        !          1518:                                /* Update Uploader's Info */
        !          1519:                                /**************************/
        !          1520:                                uploader.number=matchuser(&scfg,f.uler,TRUE /*sysop_alias*/);
        !          1521:                                if(uploader.number
        !          1522:                                        && uploader.number!=xfer.user->number 
        !          1523:                                        && getuserdat(&scfg,&uploader)==0
        !          1524:                                        && uploader.firston<f.dateuled) {
        !          1525:                                        l=f.cdt;
        !          1526:                                        if(!(scfg.dir[f.dir]->misc&DIR_CDTDL))  /* Don't give credits on d/l */
        !          1527:                                                l=0;
        !          1528:                                        if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps) { /* Give min instead of cdt */
        !          1529:                                                mod=((ulong)(l*(scfg.dir[f.dir]->dn_pct/100.0))/cps)/60;
        !          1530:                                                adjustuserrec(&scfg,uploader.number,U_MIN,10,mod);
        !          1531:                                                sprintf(tmp,"%lu minute",mod);
        !          1532:                                        } else {
        !          1533:                                                mod=(ulong)(l*(scfg.dir[f.dir]->dn_pct/100.0));
        !          1534:                                                adjustuserrec(&scfg,uploader.number,U_CDT,10,mod);
        !          1535:                                                ultoac(mod,tmp);
        !          1536:                                        }
        !          1537:                                        if(!(scfg.dir[f.dir]->misc&DIR_QUIET)) {
        !          1538:                                                addr_len = sizeof(addr);
        !          1539:                                                if(uploader.level>=SYSOP_LEVEL
        !          1540:                                                        && getpeername(xfer.ctrl_sock,(struct sockaddr *)&addr,&addr_len)==0)
        !          1541:                                                        SAFEPRINTF2(username,"%s [%s]",xfer.user->alias,inet_ntoa(addr.sin_addr));
        !          1542:                                                else
        !          1543:                                                        SAFECOPY(username,xfer.user->alias);
        !          1544:                                                /* Inform uploader of downloaded file */
        !          1545:                                                safe_snprintf(str,sizeof(str),text[DownloadUserMsg]
        !          1546:                                                        ,getfname(xfer.filename)
        !          1547:                                                        ,xfer.filepos ? "partially FTP-" : "FTP-"
        !          1548:                                                        ,username,tmp); 
        !          1549:                                                putsmsg(&scfg,uploader.number,str); 
        !          1550:                                        }
        !          1551:                                }
        !          1552:                        }
        !          1553:                        if(!xfer.tmpfile && !xfer.delfile && !(scfg.dir[f.dir]->misc&DIR_NOSTAT))
        !          1554:                                download_stats(total);
        !          1555:                }       
        !          1556: 
        !          1557:                if(xfer.credits) {
        !          1558:                        user_downloaded(&scfg, xfer.user, 1, total);
        !          1559:                        if(xfer.dir>=0 && !is_download_free(&scfg,xfer.dir,xfer.user))
        !          1560:                                subtract_cdt(&scfg, xfer.user, xfer.credits);
        !          1561:                }
        !          1562:        }
        !          1563: 
        !          1564:        fclose(fp);
        !          1565:        if(server_socket!=INVALID_SOCKET && !terminate_server)
        !          1566:                *xfer.inprogress=FALSE;
        !          1567:        if(xfer.tmpfile) {
        !          1568:                if(!(startup->options&FTP_OPT_KEEP_TEMP_FILES))
        !          1569:                        remove(xfer.filename);
        !          1570:        } 
        !          1571:        else if(xfer.delfile && !error)
        !          1572:                remove(xfer.filename);
        !          1573: 
        !          1574: #if defined(SOCKET_DEBUG_SENDTHREAD)
        !          1575:                        socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_SENDTHREAD;
        !          1576: #endif
        !          1577: 
        !          1578:        thread_down();
        !          1579: }
        !          1580: 
        !          1581: static void receive_thread(void* arg)
        !          1582: {
        !          1583:        char*           p;
        !          1584:        char            str[128];
        !          1585:        char            buf[8192];
        !          1586:        char            ext[F_EXBSIZE+1];
        !          1587:        char            desc[F_EXBSIZE+1];
        !          1588:        char            cmd[MAX_PATH*2];
        !          1589:        char            tmp[MAX_PATH+1];
        !          1590:        char            fname[MAX_PATH+1];
        !          1591:        int                     i;
        !          1592:        int                     rd;
        !          1593:        int                     file;
        !          1594:        ulong           total=0;
        !          1595:        ulong           last_total=0;
        !          1596:        ulong           dur;
        !          1597:        ulong           cps;
        !          1598:        BOOL            error=FALSE;
        !          1599:        BOOL            filedat;
        !          1600:        FILE*           fp;
        !          1601:        file_t          f;
        !          1602:        xfer_t          xfer;
        !          1603:        time_t          now;
        !          1604:        time_t          start;
        !          1605:        time_t          last_report;
        !          1606:        fd_set          socket_set;
        !          1607:        struct timeval tv;
        !          1608: 
        !          1609:        xfer=*(xfer_t*)arg;
        !          1610:        free(arg);
        !          1611: 
        !          1612:        thread_up(TRUE /* setuid */);
        !          1613: 
        !          1614:        if((fp=fopen(xfer.filename,xfer.append ? "ab" : "wb"))==NULL) {
        !          1615:                lprintf(LOG_ERR,"%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,errno,xfer.filename);
        !          1616:                sockprintf(xfer.ctrl_sock,"450 ERROR %d opening %s.",errno,xfer.filename);
        !          1617:                ftp_close_socket(xfer.data_sock,__LINE__);
        !          1618:                *xfer.inprogress=FALSE;
        !          1619:                thread_down();
        !          1620:                return;
        !          1621:        }
        !          1622: 
        !          1623:        if(xfer.append)
        !          1624:                xfer.filepos=filelength(fileno(fp));
        !          1625: 
        !          1626:        *xfer.aborted=FALSE;
        !          1627:        if(xfer.filepos || startup->options&FTP_OPT_DEBUG_DATA)
        !          1628:                lprintf(LOG_DEBUG,"%04d DATA socket %d receiving %s from offset %lu"
        !          1629:                        ,xfer.ctrl_sock,*xfer.data_sock,xfer.filename,xfer.filepos);
        !          1630: 
        !          1631:        fseek(fp,xfer.filepos,SEEK_SET);
        !          1632:        last_report=start=time(NULL);
        !          1633:        while(1) {
        !          1634: 
        !          1635:                now=time(NULL);
        !          1636: 
        !          1637:                /* Periodic progress report */
        !          1638:                if(total && now>=last_report+XFER_REPORT_INTERVAL) {
        !          1639:                        if(xfer.filepos)
        !          1640:                                sprintf(str," from offset %lu",xfer.filepos);
        !          1641:                        else
        !          1642:                                str[0]=0;
        !          1643:                        lprintf(LOG_INFO,"%04d Received %lu bytes of %s (%lu cps)%s"
        !          1644:                                ,xfer.ctrl_sock,total,xfer.filename
        !          1645:                                ,(total-last_total)/(now-last_report)
        !          1646:                                ,str);
        !          1647:                        last_total=total;
        !          1648:                        last_report=now;
        !          1649:                }
        !          1650:                if(*xfer.aborted==TRUE) {
        !          1651:                        lprintf(LOG_WARNING,"%04d !DATA Transfer aborted",xfer.ctrl_sock);
        !          1652:                        /* Send NAK */
        !          1653:                        sockprintf(xfer.ctrl_sock,"426 Transfer aborted.");
        !          1654:                        error=TRUE;
        !          1655:                        break;
        !          1656:                }
        !          1657:                if(server_socket==INVALID_SOCKET || terminate_server) {
        !          1658:                        lprintf(LOG_WARNING,"%04d !DATA Transfer locally aborted",xfer.ctrl_sock);
        !          1659:                        /* Send NAK */
        !          1660:                        sockprintf(xfer.ctrl_sock,"426 Transfer locally aborted.");
        !          1661:                        error=TRUE;
        !          1662:                        break;
        !          1663:                }
        !          1664: 
        !          1665:                /* Check socket for readability (using select) */
        !          1666:                tv.tv_sec=1;
        !          1667:                tv.tv_usec=0;
        !          1668: 
        !          1669:                FD_ZERO(&socket_set);
        !          1670:                FD_SET(*xfer.data_sock,&socket_set);
        !          1671: 
        !          1672:                i=select((*xfer.data_sock)+1,&socket_set,NULL,NULL,&tv);
        !          1673:                if(i==SOCKET_ERROR) {
        !          1674:                        lprintf(LOG_WARNING,"%04d !DATA ERROR %d selecting socket %d for receive"
        !          1675:                                ,xfer.ctrl_sock, ERROR_VALUE, *xfer.data_sock);
        !          1676:                        sockprintf(xfer.ctrl_sock,"426 Transfer error.");
        !          1677:                        error=TRUE;
        !          1678:                        break;
        !          1679:                }
        !          1680:                if(i<1)
        !          1681:                        continue;
        !          1682: 
        !          1683: #if defined(SOCKET_DEBUG_RECV_BUF)
        !          1684:                socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_RECV_BUF;
        !          1685: #endif
        !          1686:                rd=recv(*xfer.data_sock,buf,sizeof(buf),0);
        !          1687: #if defined(SOCKET_DEBUG_RECV_BUF)
        !          1688:                socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_RECV_BUF;
        !          1689: #endif
        !          1690:                if(rd<1) {
        !          1691:                        if(rd==0) { /* Socket closed */
        !          1692:                                if(startup->options&FTP_OPT_DEBUG_DATA)
        !          1693:                                        lprintf(LOG_DEBUG,"%04d DATA socket %d closed by client"
        !          1694:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !          1695:                                break;
        !          1696:                        }
        !          1697:                        if(rd==SOCKET_ERROR) {
        !          1698:                                if(ERROR_VALUE==EWOULDBLOCK) {
        !          1699:                                        /*lprintf(LOG_WARNING,"%04d DATA recv would block, retrying",xfer.ctrl_sock);*/
        !          1700:                                        YIELD();
        !          1701:                                        continue;
        !          1702:                                }
        !          1703:                                else if(ERROR_VALUE==ECONNRESET) 
        !          1704:                                        lprintf(LOG_WARNING,"%04d DATA Connection reset by peer, receiving on socket %d"
        !          1705:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !          1706:                                else if(ERROR_VALUE==ECONNABORTED) 
        !          1707:                                        lprintf(LOG_WARNING,"%04d DATA Connection aborted by peer, receiving on socket %d"
        !          1708:                                                ,xfer.ctrl_sock,*xfer.data_sock);
        !          1709:                                else
        !          1710:                                        lprintf(LOG_WARNING,"%04d !DATA ERROR %d receiving on data socket %d"
        !          1711:                                                ,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock);
        !          1712:                                /* Send NAK */
        !          1713:                                sockprintf(xfer.ctrl_sock,"426 Error %d receiving on DATA channel"
        !          1714:                                        ,ERROR_VALUE);
        !          1715:                                error=TRUE;
        !          1716:                                break;
        !          1717:                        }
        !          1718:                        lprintf(LOG_ERR,"%04d !DATA ERROR recv returned %d on socket %d"
        !          1719:                                ,xfer.ctrl_sock,rd,*xfer.data_sock);
        !          1720:                        /* Send NAK */
        !          1721:                        sockprintf(xfer.ctrl_sock,"451 Unexpected socket error: %d",rd);
        !          1722:                        error=TRUE;
        !          1723:                        break;
        !          1724:                }
        !          1725:                fwrite(buf,1,rd,fp);
        !          1726:                total+=rd;
        !          1727:                *xfer.lastactive=time(NULL);
        !          1728:                YIELD();
        !          1729:        }
        !          1730: 
        !          1731:        if(server_socket!=INVALID_SOCKET && !terminate_server)
        !          1732:                *xfer.inprogress=FALSE;
        !          1733:        fclose(fp);
        !          1734: 
        !          1735:        ftp_close_socket(xfer.data_sock,__LINE__);
        !          1736:        if(error && startup->options&FTP_OPT_DEBUG_DATA)
        !          1737:                lprintf(LOG_DEBUG,"%04d DATA socket %d closed",xfer.ctrl_sock,*xfer.data_sock);
        !          1738:        
        !          1739:        if(!error) {
        !          1740:                dur=time(NULL)-start;
        !          1741:                cps=dur ? total/dur : total*2;
        !          1742:                lprintf(LOG_INFO,"%04d Transfer successful: %lu bytes received in %lu seconds (%lu cps)"
        !          1743:                        ,xfer.ctrl_sock
        !          1744:                        ,total,dur,cps);
        !          1745: 
        !          1746:                if(xfer.dir>=0) {
        !          1747:                        memset(&f,0,sizeof(f));
        !          1748: #ifdef _WIN32
        !          1749:                        GetShortPathName(xfer.filename,fname,sizeof(fname));
        !          1750: #else
        !          1751:                        SAFECOPY(fname,xfer.filename);
        !          1752: #endif
        !          1753:                        padfname(getfname(fname),f.name);
        !          1754:                        f.dir=xfer.dir;
        !          1755:                        filedat=getfileixb(&scfg,&f);
        !          1756:                        if(scfg.dir[f.dir]->misc&DIR_AONLY)  /* Forced anonymous */
        !          1757:                                f.misc|=FM_ANON;
        !          1758:                        f.cdt=flength(xfer.filename);
        !          1759:                        f.dateuled=time(NULL);
        !          1760: 
        !          1761:                        /* Desciption specified with DESC command? */
        !          1762:                        if(xfer.desc!=NULL && *xfer.desc!=0)    
        !          1763:                                SAFECOPY(f.desc,xfer.desc);
        !          1764: 
        !          1765:                        /* Necessary for DIR and LIB ARS keyword support in subsequent chk_ar()'s */
        !          1766:                        SAFECOPY(xfer.user->curdir, scfg.dir[f.dir]->code);
        !          1767: 
        !          1768:                        /* FILE_ID.DIZ support */
        !          1769:                        p=strrchr(f.name,'.');
        !          1770:                        if(p!=NULL && scfg.dir[f.dir]->misc&DIR_DIZ) {
        !          1771:                                for(i=0;i<scfg.total_fextrs;i++)
        !          1772:                                        if(!stricmp(scfg.fextr[i]->ext,p+1) 
        !          1773:                                                && chk_ar(&scfg,scfg.fextr[i]->ar,xfer.user))
        !          1774:                                                break;
        !          1775:                                if(i<scfg.total_fextrs) {
        !          1776:                                        sprintf(tmp,"%sFILE_ID.DIZ",scfg.temp_dir);
        !          1777:                                        if(fexistcase(tmp))
        !          1778:                                                remove(tmp);
        !          1779:                                        system(cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"FILE_ID.DIZ",cmd));
        !          1780:                                        if(!fexistcase(tmp)) {
        !          1781:                                                sprintf(tmp,"%sDESC.SDI",scfg.temp_dir);
        !          1782:                                                if(fexistcase(tmp))
        !          1783:                                                        remove(tmp);
        !          1784:                                                system(cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"DESC.SDI",cmd)); 
        !          1785:                                                fexistcase(tmp);        /* fixes filename case */
        !          1786:                                        }
        !          1787:                                        if((file=nopen(tmp,O_RDONLY))!=-1) {
        !          1788:                                                memset(ext,0,sizeof(ext));
        !          1789:                                                read(file,ext,sizeof(ext)-1);
        !          1790:                                                for(i=sizeof(ext)-1;i;i--)      /* trim trailing spaces */
        !          1791:                                                        if(ext[i-1]>' ')
        !          1792:                                                                break;
        !          1793:                                                ext[i]=0;
        !          1794:                                                if(!f.desc[0]) {                        /* use for normal description */
        !          1795:                                                        SAFECOPY(desc,ext);
        !          1796:                                                        strip_exascii(desc);    /* strip extended ASCII chars */
        !          1797:                                                        prep_file_desc(desc);   /* strip control chars and dupe chars */
        !          1798:                                                        for(i=0;desc[i];i++)    /* find approprate first char */
        !          1799:                                                                if(isalnum(desc[i]))
        !          1800:                                                                        break;
        !          1801:                                                        SAFECOPY(f.desc,desc+i); 
        !          1802:                                                }
        !          1803:                                                close(file);
        !          1804:                                                remove(tmp);
        !          1805:                                                f.misc|=FM_EXTDESC; 
        !          1806:                                        } 
        !          1807:                                } 
        !          1808:                        } /* FILE_ID.DIZ support */
        !          1809: 
        !          1810:                        if(f.desc[0]==0)        /* no description given, use (long) filename */
        !          1811:                                SAFECOPY(f.desc,getfname(xfer.filename));
        !          1812: 
        !          1813:                        SAFECOPY(f.uler,xfer.user->alias);      /* exception here, Aug-27-2002 */
        !          1814:                        if(filedat) {
        !          1815:                                if(!putfiledat(&scfg,&f))
        !          1816:                                        lprintf(LOG_ERR,"%04d !ERROR updating file (%s) in database",xfer.ctrl_sock,f.name);
        !          1817:                                /* need to update the index here */
        !          1818:                        } else {
        !          1819:                                if(!addfiledat(&scfg,&f))
        !          1820:                                        lprintf(LOG_ERR,"%04d !ERROR adding file (%s) to database",xfer.ctrl_sock,f.name);
        !          1821:                        }
        !          1822: 
        !          1823:                        if(f.misc&FM_EXTDESC)
        !          1824:                                putextdesc(&scfg,f.dir,f.datoffset,ext);
        !          1825: 
        !          1826:                        if(scfg.dir[f.dir]->upload_sem[0])
        !          1827:                                ftouch(scfg.dir[f.dir]->upload_sem);
        !          1828:                        /**************************/
        !          1829:                        /* Update Uploader's Info */
        !          1830:                        /**************************/
        !          1831:                        user_uploaded(&scfg, xfer.user, (!xfer.append && xfer.filepos==0) ? 1:0, total);
        !          1832:                        if(scfg.dir[f.dir]->up_pct && scfg.dir[f.dir]->misc&DIR_CDTUL) { /* credit for upload */
        !          1833:                                if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps)    /* Give min instead of cdt */
        !          1834:                                        xfer.user->min=adjustuserrec(&scfg,xfer.user->number,U_MIN,10
        !          1835:                                                ,((ulong)(total*(scfg.dir[f.dir]->up_pct/100.0))/cps)/60);
        !          1836:                                else
        !          1837:                                        xfer.user->cdt=adjustuserrec(&scfg,xfer.user->number,U_CDT,10
        !          1838:                                                ,(ulong)(f.cdt*(scfg.dir[f.dir]->up_pct/100.0))); 
        !          1839:                        }
        !          1840:                        if(!(scfg.dir[f.dir]->misc&DIR_NOSTAT))
        !          1841:                                upload_stats(total);
        !          1842:                }
        !          1843:                /* Send ACK */
        !          1844:                sockprintf(xfer.ctrl_sock,"226 Upload complete (%lu cps).",cps);
        !          1845:        }
        !          1846: 
        !          1847:        thread_down();
        !          1848: }
        !          1849: 
        !          1850: 
        !          1851: 
        !          1852: static void filexfer(SOCKADDR_IN* addr, SOCKET ctrl_sock, SOCKET pasv_sock, SOCKET* data_sock
        !          1853:                                        ,char* filename, long filepos, BOOL* inprogress, BOOL* aborted
        !          1854:                                        ,BOOL delfile, BOOL tmpfile
        !          1855:                                        ,time_t* lastactive
        !          1856:                                        ,user_t* user
        !          1857:                                        ,int dir
        !          1858:                                        ,BOOL receiving
        !          1859:                                        ,BOOL credits
        !          1860:                                        ,BOOL append
        !          1861:                                        ,char* desc)
        !          1862: {
        !          1863:        int                     result;
        !          1864:        ulong           l;
        !          1865:        socklen_t       addr_len;
        !          1866:        SOCKADDR_IN     server_addr;
        !          1867:        BOOL            reuseaddr;
        !          1868:        xfer_t*         xfer;
        !          1869:        struct timeval  tv;
        !          1870:        fd_set                  socket_set;
        !          1871: 
        !          1872:        if((*inprogress)==TRUE) {
        !          1873:                lprintf(LOG_WARNING,"%04d !TRANSFER already in progress",ctrl_sock);
        !          1874:                sockprintf(ctrl_sock,"425 Transfer already in progress.");
        !          1875:                return;
        !          1876:        }
        !          1877:        *inprogress=TRUE;
        !          1878: 
        !          1879:        if(*data_sock!=INVALID_SOCKET)
        !          1880:                ftp_close_socket(data_sock,__LINE__);
        !          1881: 
        !          1882:        if(pasv_sock==INVALID_SOCKET) { /* !PASV */
        !          1883: 
        !          1884:                if((*data_sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) {
        !          1885:                        lprintf(LOG_ERR,"%04d !DATA ERROR %d opening socket", ctrl_sock, ERROR_VALUE);
        !          1886:                        sockprintf(ctrl_sock,"425 Error %d opening socket",ERROR_VALUE);
        !          1887:                        if(tmpfile)
        !          1888:                                remove(filename);
        !          1889:                        *inprogress=FALSE;
        !          1890:                        return;
        !          1891:                }
        !          1892:                if(startup->socket_open!=NULL)
        !          1893:                        startup->socket_open(startup->cbdata,TRUE);
        !          1894:                sockets++;
        !          1895:                if(startup->options&FTP_OPT_DEBUG_DATA)
        !          1896:                        lprintf(LOG_DEBUG,"%04d DATA socket %d opened",ctrl_sock,*data_sock);
        !          1897: 
        !          1898:                /* Use port-1 for all data connections */
        !          1899:                reuseaddr=TRUE;
        !          1900:                setsockopt(*data_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseaddr,sizeof(reuseaddr));
        !          1901: 
        !          1902:                memset(&server_addr, 0, sizeof(server_addr));
        !          1903: 
        !          1904:                server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
        !          1905:                server_addr.sin_family = AF_INET;
        !          1906:                server_addr.sin_port   = htons((WORD)(startup->port-1));        /* 20? */
        !          1907: 
        !          1908:                result=bind(*data_sock, (struct sockaddr *) &server_addr,sizeof(server_addr));
        !          1909:                if(result!=0) {
        !          1910:                        server_addr.sin_port = 0;       /* any user port */
        !          1911:                        result=bind(*data_sock, (struct sockaddr *) &server_addr,sizeof(server_addr));
        !          1912:                }
        !          1913:                if(result!=0) {
        !          1914:                        lprintf(LOG_ERR,"%04d !DATA ERROR %d (%d) binding socket %d"
        !          1915:                                ,ctrl_sock, result, ERROR_VALUE, *data_sock);
        !          1916:                        sockprintf(ctrl_sock,"425 Error %d binding socket",ERROR_VALUE);
        !          1917:                        if(tmpfile)
        !          1918:                                remove(filename);
        !          1919:                        *inprogress=FALSE;
        !          1920:                        ftp_close_socket(data_sock,__LINE__);
        !          1921:                        return;
        !          1922:                }
        !          1923: 
        !          1924:                result=connect(*data_sock, (struct sockaddr *)addr,sizeof(struct sockaddr));
        !          1925:                if(result!=0) {
        !          1926:                        lprintf(LOG_WARNING,"%04d !DATA ERROR %d (%d) connecting to client %s port %u on socket %d"
        !          1927:                                        ,ctrl_sock,result,ERROR_VALUE
        !          1928:                                        ,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),*data_sock);
        !          1929:                        sockprintf(ctrl_sock,"425 Error %d connecting to socket",ERROR_VALUE);
        !          1930:                        if(tmpfile)
        !          1931:                                remove(filename);
        !          1932:                        *inprogress=FALSE;
        !          1933:                        ftp_close_socket(data_sock,__LINE__);
        !          1934:                        return;
        !          1935:                }
        !          1936:                if(startup->options&FTP_OPT_DEBUG_DATA)
        !          1937:                        lprintf(LOG_DEBUG,"%04d DATA socket %d connected to %s port %u"
        !          1938:                                ,ctrl_sock,*data_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port));
        !          1939: 
        !          1940:        } else {        /* PASV */
        !          1941: 
        !          1942:                if(startup->options&FTP_OPT_DEBUG_DATA) {
        !          1943:                        addr_len=sizeof(SOCKADDR_IN);
        !          1944:                        if((result=getsockname(pasv_sock, (struct sockaddr *)addr,&addr_len))!=0)
        !          1945:                                lprintf(LOG_ERR,"%04d !ERROR %d (%d) getting address/port of passive socket (%u)"
        !          1946:                                        ,ctrl_sock,result,ERROR_VALUE,pasv_sock);
        !          1947:                        else
        !          1948:                                lprintf(LOG_DEBUG,"%04d PASV DATA socket %d listening on %s port %u"
        !          1949:                                        ,ctrl_sock,pasv_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port));
        !          1950:                }
        !          1951: 
        !          1952:                /* Setup for select() */
        !          1953:                tv.tv_sec=TIMEOUT_SOCKET_LISTEN;
        !          1954:                tv.tv_usec=0;
        !          1955: 
        !          1956:                FD_ZERO(&socket_set);
        !          1957:                FD_SET(pasv_sock,&socket_set);
        !          1958: 
        !          1959: #if defined(SOCKET_DEBUG_SELECT)
        !          1960:                socket_debug[ctrl_sock]|=SOCKET_DEBUG_SELECT;
        !          1961: #endif
        !          1962:                result=select(pasv_sock+1,&socket_set,NULL,NULL,&tv);
        !          1963: #if defined(SOCKET_DEBUG_SELECT)
        !          1964:                socket_debug[ctrl_sock]&=~SOCKET_DEBUG_SELECT;
        !          1965: #endif
        !          1966:                if(result<1) {
        !          1967:                        lprintf(LOG_WARNING,"%04d !PASV select returned %d (error: %d)",ctrl_sock,result,ERROR_VALUE);
        !          1968:                        sockprintf(ctrl_sock,"425 Error %d selecting socket for connection",ERROR_VALUE);
        !          1969:                        if(tmpfile)
        !          1970:                                remove(filename);
        !          1971:                        *inprogress=FALSE;
        !          1972:                        return;
        !          1973:                }
        !          1974:                        
        !          1975:                addr_len=sizeof(SOCKADDR_IN);
        !          1976: #ifdef SOCKET_DEBUG_ACCEPT
        !          1977:                socket_debug[ctrl_sock]|=SOCKET_DEBUG_ACCEPT;
        !          1978: #endif
        !          1979:                *data_sock=accept(pasv_sock,(struct sockaddr*)addr,&addr_len);
        !          1980: #ifdef SOCKET_DEBUG_ACCEPT
        !          1981:                socket_debug[ctrl_sock]&=~SOCKET_DEBUG_ACCEPT;
        !          1982: #endif
        !          1983:                if(*data_sock==INVALID_SOCKET) {
        !          1984:                        lprintf(LOG_WARNING,"%04d !PASV DATA ERROR %d accepting connection on socket %d"
        !          1985:                                ,ctrl_sock,ERROR_VALUE,pasv_sock);
        !          1986:                        sockprintf(ctrl_sock,"425 Error %d accepting connection",ERROR_VALUE);
        !          1987:                        if(tmpfile)
        !          1988:                                remove(filename);
        !          1989:                        *inprogress=FALSE;
        !          1990:                        return;
        !          1991:                }
        !          1992:                if(startup->socket_open!=NULL)
        !          1993:                        startup->socket_open(startup->cbdata,TRUE);
        !          1994:                sockets++;
        !          1995:                if(startup->options&FTP_OPT_DEBUG_DATA)
        !          1996:                        lprintf(LOG_DEBUG,"%04d PASV DATA socket %d connected to %s port %u"
        !          1997:                                ,ctrl_sock,*data_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port));
        !          1998:        }
        !          1999: 
        !          2000:        do {
        !          2001: 
        !          2002:                l=1;
        !          2003: 
        !          2004:                if(ioctlsocket(*data_sock, FIONBIO, &l)!=0) {
        !          2005:                        lprintf(LOG_ERR,"%04d !DATA ERROR %d disabling socket blocking"
        !          2006:                                ,ctrl_sock, ERROR_VALUE);
        !          2007:                        sockprintf(ctrl_sock,"425 Error %d disabling socket blocking"
        !          2008:                                ,ERROR_VALUE);
        !          2009:                        break;
        !          2010:                }
        !          2011: 
        !          2012:                if((xfer=malloc(sizeof(xfer_t)))==NULL) {
        !          2013:                        lprintf(LOG_CRIT,"%04d !MALLOC FAILURE LINE %d",ctrl_sock,__LINE__);
        !          2014:                        sockprintf(ctrl_sock,"425 MALLOC FAILURE");
        !          2015:                        break;
        !          2016:                }
        !          2017:                memset(xfer,0,sizeof(xfer_t));
        !          2018:                xfer->ctrl_sock=ctrl_sock;
        !          2019:                xfer->data_sock=data_sock;
        !          2020:                xfer->inprogress=inprogress;
        !          2021:                xfer->aborted=aborted;
        !          2022:                xfer->delfile=delfile;
        !          2023:                xfer->tmpfile=tmpfile;
        !          2024:                xfer->append=append;
        !          2025:                xfer->filepos=filepos;
        !          2026:                xfer->credits=credits;
        !          2027:                xfer->lastactive=lastactive;
        !          2028:                xfer->user=user;
        !          2029:                xfer->dir=dir;
        !          2030:                xfer->desc=desc;
        !          2031:                SAFECOPY(xfer->filename,filename);
        !          2032:                if(receiving)
        !          2033:                        result=_beginthread(receive_thread,0,(void*)xfer);
        !          2034:                else
        !          2035:                        result=_beginthread(send_thread,0,(void*)xfer);
        !          2036: 
        !          2037:                if(result!=-1)
        !          2038:                        return; /* success */
        !          2039: 
        !          2040:        } while(0);
        !          2041: 
        !          2042:        /* failure */
        !          2043:        if(tmpfile)
        !          2044:                remove(filename);
        !          2045:        *inprogress=FALSE;
        !          2046: }
        !          2047: 
        !          2048: /* convert "user name" to "user.name" or "mr. user" to "mr._user" */
        !          2049: char* dotname(char* in, char* out)
        !          2050: {
        !          2051:        char    ch;
        !          2052:        int             i;
        !          2053: 
        !          2054:        if(strchr(in,'.')==NULL)
        !          2055:                ch='.';
        !          2056:        else
        !          2057:                ch='_';
        !          2058:        for(i=0;in[i];i++)
        !          2059:                if(in[i]<=' ')
        !          2060:                        out[i]=ch;
        !          2061:                else
        !          2062:                        out[i]=in[i];
        !          2063:        out[i]=0;
        !          2064:        return(out);
        !          2065: }
        !          2066: 
        !          2067: void parsepath(char** pp, user_t* user, int* curlib, int* curdir)
        !          2068: {
        !          2069:        char*   p;
        !          2070:        char*   tp;
        !          2071:        char    path[MAX_PATH+1];
        !          2072:        int             dir=*curdir;
        !          2073:        int             lib=*curlib;
        !          2074: 
        !          2075:        SAFECOPY(path,*pp);
        !          2076:        p=path;
        !          2077: 
        !          2078:        if(*p=='/') {
        !          2079:                p++;
        !          2080:                lib=-1;
        !          2081:        }
        !          2082:        else if(!strncmp(p,"./",2))
        !          2083:                p+=2;
        !          2084: 
        !          2085:        if(!strncmp(p,"..",2)) {
        !          2086:                p+=2;
        !          2087:                if(dir>=0)
        !          2088:                        dir=-1;
        !          2089:                else if(lib>=0)
        !          2090:                        lib=-1;
        !          2091:                if(*p=='/')
        !          2092:                        p++;
        !          2093:        }
        !          2094: 
        !          2095:        if(*p==0) {
        !          2096:                *curlib=lib;
        !          2097:                *curdir=dir;
        !          2098:                return;
        !          2099:        }
        !          2100: 
        !          2101:        if(lib<0) { /* root */
        !          2102:                tp=strchr(p,'/');
        !          2103:                if(tp) *tp=0;
        !          2104:                for(lib=0;lib<scfg.total_libs;lib++) {
        !          2105:                        if(!chk_ar(&scfg,scfg.lib[lib]->ar,user))
        !          2106:                                continue;
        !          2107:                        if(!stricmp(scfg.lib[lib]->sname,p))
        !          2108:                                break;
        !          2109:                }
        !          2110:                if(lib>=scfg.total_libs) { /* not found */
        !          2111:                        *curlib=-1;
        !          2112:                        return;
        !          2113:                }
        !          2114:                *curlib=lib;
        !          2115: 
        !          2116:                if(tp==NULL) {
        !          2117:                        *curdir=-1;
        !          2118:                        return;
        !          2119:                }
        !          2120: 
        !          2121:                p=tp+1;
        !          2122:        }
        !          2123: 
        !          2124:        tp=strchr(p,'/');
        !          2125:        if(tp!=NULL) {
        !          2126:                *tp=0;
        !          2127:                tp++;
        !          2128:        } else 
        !          2129:                tp=p+strlen(p);
        !          2130: 
        !          2131:        for(dir=0;dir<scfg.total_dirs;dir++) {
        !          2132:                if(scfg.dir[dir]->lib!=lib)
        !          2133:                        continue;
        !          2134:                if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir 
        !          2135:                        && !chk_ar(&scfg,scfg.dir[dir]->ar,user))
        !          2136:                        continue;
        !          2137:                if(!stricmp(scfg.dir[dir]->code_suffix,p))
        !          2138:                        break;
        !          2139:        }
        !          2140: 
        !          2141:        if(dir>=scfg.total_dirs)  /* not found */
        !          2142:                return;
        !          2143: 
        !          2144:        *curdir=dir;
        !          2145: 
        !          2146:        *pp+=tp-path;   /* skip "lib/dir/" */
        !          2147: }
        !          2148: 
        !          2149: static BOOL ftpalias(char* fullalias, char* filename, user_t* user, int* curdir)
        !          2150: {
        !          2151:        char*   p;
        !          2152:        char*   tp;
        !          2153:        char*   fname="";
        !          2154:        char    line[512];
        !          2155:        char    alias[512];
        !          2156:        char    aliasfile[MAX_PATH+1];
        !          2157:        int             dir=-1;
        !          2158:        FILE*   fp;
        !          2159:        BOOL    result=FALSE;
        !          2160: 
        !          2161:        sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
        !          2162:        if((fp=fopen(aliasfile,"r"))==NULL) 
        !          2163:                return(FALSE);
        !          2164: 
        !          2165:        SAFECOPY(alias,fullalias);
        !          2166:        p=strrchr(alias+1,'/');
        !          2167:        if(p) {
        !          2168:                *p=0;
        !          2169:                fname=p+1;
        !          2170:        }
        !          2171: 
        !          2172:        if(filename==NULL /* directory */ && *fname /* filename specified */) {
        !          2173:                fclose(fp);
        !          2174:                return(FALSE);
        !          2175:        }
        !          2176: 
        !          2177:        while(!feof(fp)) {
        !          2178:                if(!fgets(line,sizeof(line),fp))
        !          2179:                        break;
        !          2180: 
        !          2181:                p=line; /* alias */
        !          2182:                while(*p && *p<=' ') p++;
        !          2183:                if(*p==';')     /* comment */
        !          2184:                        continue;
        !          2185: 
        !          2186:                tp=p;           /* terminator */
        !          2187:                while(*tp && *tp>' ') tp++;
        !          2188:                if(*tp) *tp=0;
        !          2189: 
        !          2190:                if(stricmp(p,alias))    /* Not a match */
        !          2191:                        continue;
        !          2192: 
        !          2193:                p=tp+1;         /* filename */
        !          2194:                while(*p && *p<=' ') p++;
        !          2195: 
        !          2196:                tp=p;           /* terminator */
        !          2197:                while(*tp && *tp>' ') tp++;
        !          2198:                if(*tp) *tp=0;
        !          2199: 
        !          2200:                if(!strnicmp(p,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
        !          2201:                        if((dir=getdir(p+strlen(BBS_VIRTUAL_PATH),user))<0)     {
        !          2202:                                lprintf(LOG_WARNING,"0000 !Invalid virtual path (%s) for %s",p,user->alias);
        !          2203:                                /* invalid or no access */
        !          2204:                                continue;
        !          2205:                        }
        !          2206:                        p=strrchr(p,'/');
        !          2207:                        if(p!=NULL) p++;
        !          2208:                        if(p!=NULL && filename!=NULL) {
        !          2209:                                if(*p)
        !          2210:                                        sprintf(filename,"%s%s",scfg.dir[dir]->path,p);
        !          2211:                                else
        !          2212:                                        sprintf(filename,"%s%s",scfg.dir[dir]->path,fname);
        !          2213:                        }
        !          2214:                } else if(filename!=NULL)
        !          2215:                        strcpy(filename,p);
        !          2216: 
        !          2217:                result=TRUE;    /* success */
        !          2218:                break;
        !          2219:        }
        !          2220:        fclose(fp);
        !          2221:        if(curdir!=NULL)
        !          2222:                *curdir=dir;
        !          2223:        return(result);
        !          2224: }
        !          2225: 
        !          2226: char* root_dir(char* path)
        !          2227: {
        !          2228:        char*   p;
        !          2229:        static char     root[MAX_PATH+1];
        !          2230: 
        !          2231:        SAFECOPY(root,path);
        !          2232: 
        !          2233:        if(!strncmp(root,"\\\\",2)) {   /* network path */
        !          2234:                p=strchr(root+2,'\\');
        !          2235:                if(p) p=strchr(p+1,'\\');
        !          2236:                if(p) *(p+1)=0;                         /* truncate at \\computer\sharename\ */
        !          2237:        } 
        !          2238:        else if(!strncmp(root+1,":/",2) || !strncmp(root+1,":\\",2))
        !          2239:                root[3]=0;
        !          2240:        else if(*root=='/' || *root=='\\')
        !          2241:                root[1]=0;
        !          2242: 
        !          2243:        return(root);
        !          2244: }
        !          2245: 
        !          2246: char* vpath(int lib, int dir, char* str)
        !          2247: {
        !          2248:        strcpy(str,"/");
        !          2249:        if(lib<0)
        !          2250:                return(str);
        !          2251:        strcat(str,scfg.lib[lib]->sname);
        !          2252:        strcat(str,"/");
        !          2253:        if(dir<0)
        !          2254:                return(str);
        !          2255:        strcat(str,scfg.dir[dir]->code_suffix);
        !          2256:        strcat(str,"/");
        !          2257:        return(str);
        !          2258: }
        !          2259: 
        !          2260: void ftp_printfile(SOCKET sock, const char* name, unsigned code)
        !          2261: {
        !          2262:        char    path[MAX_PATH+1];
        !          2263:        char    buf[512];
        !          2264:        FILE*   fp;
        !          2265:        unsigned i;
        !          2266: 
        !          2267:        SAFEPRINTF2(path,"%sftp%s.txt",scfg.text_dir,name);
        !          2268:        if((fp=fopen(path,"rb"))!=NULL) {
        !          2269:                i=0;
        !          2270:                while(!feof(fp)) {
        !          2271:                        if(!fgets(buf,sizeof(buf),fp))
        !          2272:                                break;
        !          2273:                        truncsp(buf);
        !          2274:                        if(!i)
        !          2275:                                sockprintf(sock,"%u-%s",code,buf);
        !          2276:                        else
        !          2277:                                sockprintf(sock," %s",buf);
        !          2278:                        i++;
        !          2279:                }
        !          2280:                fclose(fp);
        !          2281:        }
        !          2282: }
        !          2283: 
        !          2284: static BOOL badlogin(SOCKET sock, ulong* login_attempts)
        !          2285: {
        !          2286:        mswait(5000);   /* As recommended by RFC2577 */
        !          2287:        if(++(*login_attempts)>=3) {
        !          2288:                sockprintf(sock,"421 Too many failed login attempts.");
        !          2289:                return(TRUE);
        !          2290:        }
        !          2291:        ftp_printfile(sock,"badlogin",530);
        !          2292:        sockprintf(sock,"530 Invalid login.");
        !          2293:        return(FALSE);
        !          2294: }
        !          2295: 
        !          2296: static char* ftp_tmpfname(char* str, SOCKET sock)
        !          2297: {
        !          2298:        safe_snprintf(str,MAX_PATH,"%sSBBS_FTP.%u.%u.tx",scfg.temp_dir,getpid(),sock);
        !          2299:        return(str);
        !          2300: }
        !          2301: 
        !          2302: static void ctrl_thread(void* arg)
        !          2303: {
        !          2304:        char            buf[512];
        !          2305:        char            str[128];
        !          2306:        char*           cmd;
        !          2307:        char*           p;
        !          2308:        char*           np;
        !          2309:        char*           tp;
        !          2310:        char*           dp;
        !          2311:        char*           mode="active";
        !          2312:        char            password[64];
        !          2313:        char            fname[MAX_PATH+1];
        !          2314:        char            qwkfile[MAX_PATH+1];
        !          2315:        char            aliasfile[MAX_PATH+1];
        !          2316:        char            aliasline[512];
        !          2317:        char            desc[501]="";
        !          2318:        char            sys_pass[128];
        !          2319:        char*           host_name;
        !          2320:        char            host_ip[64];
        !          2321:        char            path[MAX_PATH+1];
        !          2322:        char            local_dir[MAX_PATH+1];
        !          2323:        char            ren_from[MAX_PATH+1]="";
        !          2324:        char            html_index_ext[MAX_PATH+1];
        !          2325:        WORD            port;
        !          2326:        ulong           ip_addr;
        !          2327:        socklen_t       addr_len;
        !          2328:        DWORD           h1,h2,h3,h4;
        !          2329:        u_short         p1,p2;  /* For PORT command */
        !          2330:        int                     i;
        !          2331:        int                     rd;
        !          2332:        int                     result;
        !          2333:        int                     lib;
        !          2334:        int                     dir;
        !          2335:        int                     curlib=-1;
        !          2336:        int                     curdir=-1;
        !          2337:        int                     orglib;
        !          2338:        int                     orgdir;
        !          2339:        long            filepos=0L;
        !          2340:        long            timeleft;
        !          2341:        ulong           l;
        !          2342:        ulong           login_attempts=0;
        !          2343:        ulong           avail;  /* disk space */
        !          2344:        ulong           count;
        !          2345:        BOOL            detail;
        !          2346:        BOOL            success;
        !          2347:        BOOL            getdate;
        !          2348:        BOOL            getsize;
        !          2349:        BOOL            delecmd;
        !          2350:        BOOL            delfile;
        !          2351:        BOOL            tmpfile;
        !          2352:        BOOL            credits;
        !          2353:        BOOL            filedat=FALSE;
        !          2354:        BOOL            transfer_inprogress;
        !          2355:        BOOL            transfer_aborted;
        !          2356:        BOOL            sysop=FALSE;
        !          2357:        BOOL            local_fsys=FALSE;
        !          2358:        BOOL            alias_dir;
        !          2359:        BOOL            append;
        !          2360:        BOOL            reuseaddr;
        !          2361:        FILE*           fp;
        !          2362:        FILE*           alias_fp;
        !          2363:        SOCKET          sock;
        !          2364:        SOCKET          tmp_sock;
        !          2365:        SOCKET          pasv_sock=INVALID_SOCKET;
        !          2366:        SOCKET          data_sock=INVALID_SOCKET;
        !          2367:        HOSTENT*        host;
        !          2368:        SOCKADDR_IN     addr;
        !          2369:        SOCKADDR_IN     data_addr;
        !          2370:        SOCKADDR_IN     pasv_addr;
        !          2371:        ftp_t           ftp=*(ftp_t*)arg;
        !          2372:        user_t          user;
        !          2373:        time_t          t;
        !          2374:        time_t          now;
        !          2375:        time_t          logintime=0;
        !          2376:        time_t          lastactive;
        !          2377:        file_t          f;
        !          2378:        glob_t          g;
        !          2379:        node_t          node;
        !          2380:        client_t        client;
        !          2381:        struct tm       tm;
        !          2382:        struct tm       cur_tm;
        !          2383: #ifdef JAVASCRIPT
        !          2384:        jsval           js_val;
        !          2385:        JSRuntime*      js_runtime=NULL;
        !          2386:        JSContext*      js_cx=NULL;
        !          2387:        JSObject*       js_glob;
        !          2388:        JSObject*       js_ftp;
        !          2389:        JSString*       js_str;
        !          2390: #endif
        !          2391: 
        !          2392:        thread_up(TRUE /* setuid */);
        !          2393: 
        !          2394:        lastactive=time(NULL);
        !          2395: 
        !          2396:        sock=ftp.socket;
        !          2397:        data_addr=ftp.client_addr;
        !          2398:        /* Default data port is ctrl port-1 */
        !          2399:        data_addr.sin_port=ntohs(data_addr.sin_port)-1;
        !          2400:        data_addr.sin_port=htons(data_addr.sin_port);
        !          2401:        
        !          2402:        lprintf(LOG_DEBUG,"%04d CTRL thread started", sock);
        !          2403: 
        !          2404:        free(arg);      /* unexplicable assertion here on July 26, 2001 */
        !          2405: 
        !          2406: #ifdef _WIN32
        !          2407:        if(startup->answer_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          2408:                PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          2409: #endif
        !          2410: 
        !          2411:        transfer_inprogress = FALSE;
        !          2412:        transfer_aborted = FALSE;
        !          2413: 
        !          2414:        l=1;
        !          2415: 
        !          2416:        if((i=ioctlsocket(sock, FIONBIO, &l))!=0) {
        !          2417:                lprintf(LOG_ERR,"%04d !ERROR %d (%d) disabling socket blocking"
        !          2418:                        ,sock, i, ERROR_VALUE);
        !          2419:                sockprintf(sock,"425 Error %d disabling socket blocking"
        !          2420:                        ,ERROR_VALUE);
        !          2421:                ftp_close_socket(&sock,__LINE__);
        !          2422:                thread_down();
        !          2423:                return;
        !          2424:        }
        !          2425: 
        !          2426:        memset(&user,0,sizeof(user));
        !          2427: 
        !          2428:        SAFECOPY(host_ip,inet_ntoa(ftp.client_addr.sin_addr));
        !          2429: 
        !          2430:        lprintf(LOG_DEBUG,"%04d CTRL connection accepted from: %s port %u"
        !          2431:                ,sock, host_ip, ntohs(ftp.client_addr.sin_port));
        !          2432: 
        !          2433:        if(startup->options&FTP_OPT_NO_HOST_LOOKUP)
        !          2434:                host=NULL;
        !          2435:        else
        !          2436:                host=gethostbyaddr ((char *)&ftp.client_addr.sin_addr
        !          2437:                        ,sizeof(ftp.client_addr.sin_addr),AF_INET);
        !          2438: 
        !          2439:        if(host!=NULL && host->h_name!=NULL)
        !          2440:                host_name=host->h_name;
        !          2441:        else
        !          2442:                host_name="<no name>";
        !          2443: 
        !          2444:        if(!(startup->options&FTP_OPT_NO_HOST_LOOKUP)) {
        !          2445:                lprintf(LOG_INFO,"%04d Hostname: %s", sock, host_name);
        !          2446:                for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
        !          2447:                        lprintf(LOG_INFO,"%04d HostAlias: %s", sock, host->h_aliases[i]);
        !          2448:        }
        !          2449: 
        !          2450:        if(trashcan(&scfg,host_ip,"ip")) {
        !          2451:                lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", sock, host_ip);
        !          2452:                sockprintf(sock,"550 Access denied.");
        !          2453:                ftp_close_socket(&sock,__LINE__);
        !          2454:                thread_down();
        !          2455:                return;
        !          2456:        }
        !          2457: 
        !          2458:        if(trashcan(&scfg,host_name,"host")) {
        !          2459:                lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in host.can: %s", sock, host_name);
        !          2460:                sockprintf(sock,"550 Access denied.");
        !          2461:                ftp_close_socket(&sock,__LINE__);
        !          2462:                thread_down();
        !          2463:                return;
        !          2464:        }
        !          2465: 
        !          2466:        /* For PASV mode */
        !          2467:        addr_len=sizeof(pasv_addr);
        !          2468:        if((result=getsockname(sock, (struct sockaddr *)&pasv_addr,&addr_len))!=0) {
        !          2469:                lprintf(LOG_ERR,"%04d !ERROR %d (%d) getting address/port", sock, result, ERROR_VALUE);
        !          2470:                sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE);
        !          2471:                ftp_close_socket(&sock,__LINE__);
        !          2472:                thread_down();
        !          2473:                return;
        !          2474:        } 
        !          2475: 
        !          2476:        active_clients++, update_clients();
        !          2477: 
        !          2478:        /* Initialize client display */
        !          2479:        client.size=sizeof(client);
        !          2480:        client.time=time(NULL);
        !          2481:        SAFECOPY(client.addr,host_ip);
        !          2482:        SAFECOPY(client.host,host_name);
        !          2483:        client.port=ntohs(ftp.client_addr.sin_port);
        !          2484:        client.protocol="FTP";
        !          2485:        client.user="<unknown>";
        !          2486:        client_on(sock,&client,FALSE /* update */);
        !          2487: 
        !          2488:        sockprintf(sock,"220-%s (%s)",scfg.sys_name, startup->host_name);
        !          2489:        sockprintf(sock," Synchronet FTP Server %s-%s Ready"
        !          2490:                ,revision,PLATFORM_DESC);
        !          2491:        sprintf(str,"%sftplogin.txt",scfg.text_dir);
        !          2492:        if((fp=fopen(str,"rb"))!=NULL) {
        !          2493:                while(!feof(fp)) {
        !          2494:                        if(!fgets(buf,sizeof(buf),fp))
        !          2495:                                break;
        !          2496:                        truncsp(buf);
        !          2497:                        sockprintf(sock," %s",buf);
        !          2498:                }
        !          2499:                fclose(fp);
        !          2500:        }
        !          2501:        sockprintf(sock,"220 Please enter your user name.");
        !          2502: 
        !          2503: #ifdef SOCKET_DEBUG_CTRL
        !          2504:        socket_debug[sock]|=SOCKET_DEBUG_CTRL;
        !          2505: #endif
        !          2506:        while(1) {
        !          2507: 
        !          2508: #ifdef SOCKET_DEBUG_READLINE
        !          2509:                socket_debug[sock]|=SOCKET_DEBUG_READLINE;
        !          2510: #endif
        !          2511:                rd = sockreadline(sock, buf, sizeof(buf), &lastactive);
        !          2512: #ifdef SOCKET_DEBUG_READLINE
        !          2513:                socket_debug[sock]&=~SOCKET_DEBUG_READLINE;
        !          2514: #endif
        !          2515:                if(rd<1) {
        !          2516:                        if(transfer_inprogress==TRUE) {
        !          2517:                                lprintf(LOG_WARNING,"%04d Aborting transfer due to receive error",sock);
        !          2518:                                transfer_aborted=TRUE;
        !          2519:                        }
        !          2520:                        break;
        !          2521:                }
        !          2522:                truncsp(buf);
        !          2523:                lastactive=time(NULL);
        !          2524:                cmd=buf;
        !          2525:                while(((BYTE)*cmd)==TELNET_IAC) {
        !          2526:                        cmd++;
        !          2527:                        lprintf(LOG_DEBUG,"%04d RX: Telnet cmd: %s",sock,telnet_cmd_desc(*cmd));
        !          2528:                        cmd++;
        !          2529:                }
        !          2530:                while(*cmd && *cmd<' ') {
        !          2531:                        lprintf(LOG_DEBUG,"%04d RX: %d (0x%02X)",sock,(BYTE)*cmd,(BYTE)*cmd);
        !          2532:                        cmd++;
        !          2533:                }
        !          2534:                if(!(*cmd))
        !          2535:                        continue;
        !          2536:                if(startup->options&FTP_OPT_DEBUG_RX)
        !          2537:                        lprintf(LOG_DEBUG,"%04d RX: %s", sock, cmd);
        !          2538:                if(!stricmp(cmd, "NOOP")) {
        !          2539:                        sockprintf(sock,"200 NOOP command successful.");
        !          2540:                        continue;
        !          2541:                }
        !          2542:                if(!stricmp(cmd, "HELP SITE") || !stricmp(cmd, "SITE HELP")) {
        !          2543:                        sockprintf(sock,"214-The following SITE commands are recognized (* => unimplemented):");
        !          2544:                        sockprintf(sock," HELP    VER     WHO     UPTIME");
        !          2545:                        if(user.level>=SYSOP_LEVEL)
        !          2546:                                sockprintf(sock,
        !          2547:                                                        " RECYCLE [ALL]");
        !          2548:                        if(sysop)
        !          2549:                                sockprintf(sock,
        !          2550:                                                        " EXEC <cmd>");
        !          2551:                        sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr);
        !          2552:                        continue;
        !          2553:                }
        !          2554:                if(!strnicmp(cmd, "HELP",4)) {
        !          2555:                        sockprintf(sock,"214-The following commands are recognized (* => unimplemented, # => extension):");
        !          2556:                        sockprintf(sock," USER    PASS    CWD     XCWD    CDUP    XCUP    PWD     XPWD");
        !          2557:                        sockprintf(sock," QUIT    REIN    PORT    PASV    LIST    NLST    NOOP    HELP");
        !          2558:                        sockprintf(sock," SIZE    MDTM    RETR    STOR    REST    ALLO    ABOR    SYST");
        !          2559:                        sockprintf(sock," TYPE    STRU    MODE    SITE    RNFR*   RNTO*   DELE*   DESC#");
        !          2560:                        sockprintf(sock," FEAT#   OPTS#");
        !          2561:                        sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr);
        !          2562:                        continue;
        !          2563:                }
        !          2564:                if(!stricmp(cmd, "FEAT")) {
        !          2565:                        sockprintf(sock,"211-The following additional (post-RFC949) features are supported:");
        !          2566:                        sockprintf(sock," DESC");
        !          2567:                        sockprintf(sock," MDTM");
        !          2568:                        sockprintf(sock," SIZE");
        !          2569:                        sockprintf(sock," REST STREAM");
        !          2570:                        sockprintf(sock,"211 End");
        !          2571:                        continue;
        !          2572:                }
        !          2573:                if(!strnicmp(cmd, "OPTS",4)) {
        !          2574:                        sockprintf(sock,"501 No options supported.");
        !          2575:                        continue;
        !          2576:                }
        !          2577:                if(!stricmp(cmd, "QUIT")) {
        !          2578:                        ftp_printfile(sock,"bye",221);
        !          2579:                        sockprintf(sock,"221 Goodbye. Closing control connection.");
        !          2580:                        break;
        !          2581:                }
        !          2582:                if(!strnicmp(cmd, "USER ",5)) {
        !          2583:                        sysop=FALSE;
        !          2584:                        user.number=0;
        !          2585:                        p=cmd+5;
        !          2586:                        while(*p && *p<=' ') p++;
        !          2587:                        truncsp(p);
        !          2588:                        SAFECOPY(user.alias,p);
        !          2589:                        user.number=matchuser(&scfg,user.alias,FALSE /*sysop_alias*/);
        !          2590:                        if(!user.number && !stricmp(user.alias,"anonymous"))    
        !          2591:                                user.number=matchuser(&scfg,"guest",FALSE);
        !          2592:                        if(user.number && getuserdat(&scfg, &user)==0 && user.pass[0]==0) 
        !          2593:                                sockprintf(sock,"331 User name okay, give your full e-mail address as password.");
        !          2594:                        else
        !          2595:                                sockprintf(sock,"331 User name okay, need password.");
        !          2596:                        user.number=0;
        !          2597:                        continue;
        !          2598:                }
        !          2599:                if(!strnicmp(cmd, "PASS ",5) && user.alias[0]) {
        !          2600:                        user.number=0;
        !          2601:                        p=cmd+5;
        !          2602:                        while(*p && *p<=' ') p++;
        !          2603: 
        !          2604:                        SAFECOPY(password,p);
        !          2605:                        user.number=matchuser(&scfg,user.alias,FALSE /*sysop_alias*/);
        !          2606:                        if(!user.number) {
        !          2607:                                if(scfg.sys_misc&SM_ECHO_PW)
        !          2608:                                        lprintf(LOG_WARNING,"%04d !UNKNOWN USER: %s, Password: %s",sock,user.alias,p);
        !          2609:                                else
        !          2610:                                        lprintf(LOG_WARNING,"%04d !UNKNOWN USER: %s",sock,user.alias);
        !          2611:                                if(badlogin(sock,&login_attempts))
        !          2612:                                        break;
        !          2613:                                continue;
        !          2614:                        }
        !          2615:                        if((i=getuserdat(&scfg, &user))!=0) {
        !          2616:                                lprintf(LOG_ERR,"%04d !ERROR %d getting data for user #%d (%s)"
        !          2617:                                        ,sock,i,user.number,user.alias);
        !          2618:                                sockprintf(sock,"530 Database error %d",i);
        !          2619:                                user.number=0;
        !          2620:                                continue;
        !          2621:                        }
        !          2622:                        if(user.misc&(DELETED|INACTIVE)) {
        !          2623:                                lprintf(LOG_WARNING,"%04d !DELETED or INACTIVE user #%d (%s)"
        !          2624:                                        ,sock,user.number,user.alias);
        !          2625:                                user.number=0;
        !          2626:                                if(badlogin(sock,&login_attempts))
        !          2627:                                        break;
        !          2628:                                continue;
        !          2629:                        }
        !          2630:                        if(user.rest&FLAG('T')) {
        !          2631:                                lprintf(LOG_WARNING,"%04d !T RESTRICTED user #%d (%s)"
        !          2632:                                        ,sock,user.number,user.alias);
        !          2633:                                user.number=0;
        !          2634:                                if(badlogin(sock,&login_attempts))
        !          2635:                                        break;
        !          2636:                                continue;
        !          2637:                        }
        !          2638:                        if(user.ltoday>scfg.level_callsperday[user.level]
        !          2639:                                && !(user.exempt&FLAG('L'))) {
        !          2640:                                lprintf(LOG_WARNING,"%04d !MAXIMUM LOGONS (%d) reached for %s"
        !          2641:                                        ,sock,scfg.level_callsperday[user.level],user.alias);
        !          2642:                                sockprintf(sock,"530 Maximum logons reached.");
        !          2643:                                user.number=0;
        !          2644:                                continue;
        !          2645:                        }
        !          2646:                        if(user.rest&FLAG('L') && user.ltoday>1) {
        !          2647:                                lprintf(LOG_WARNING,"%04d !L RESTRICTED user #%d (%s) already on today"
        !          2648:                                        ,sock,user.number,user.alias);
        !          2649:                                sockprintf(sock,"530 Maximum logons reached.");
        !          2650:                                user.number=0;
        !          2651:                                continue;
        !          2652:                        }
        !          2653: 
        !          2654:                        SAFEPRINTF2(sys_pass,"%s:%s",user.pass,scfg.sys_pass);
        !          2655:                        if(!user.pass[0]) {     /* Guest/Anonymous */
        !          2656:                                if(trashcan(&scfg,password,"email")) {
        !          2657:                                        lprintf(LOG_NOTICE,"%04d !BLOCKED e-mail address: %s",sock,password);
        !          2658:                                        user.number=0;
        !          2659:                                        if(badlogin(sock,&login_attempts))
        !          2660:                                                break;
        !          2661:                                        continue;
        !          2662:                                }
        !          2663:                                lprintf(LOG_INFO,"%04d %s: <%s>",sock,user.alias,password);
        !          2664:                                putuserrec(&scfg,user.number,U_NETMAIL,LEN_NETMAIL,password);
        !          2665:                        }
        !          2666:                        else if(user.level>=SYSOP_LEVEL && !stricmp(password,sys_pass)) {
        !          2667:                                lprintf(LOG_INFO,"%04d Sysop access granted to %s", sock, user.alias);
        !          2668:                                sysop=TRUE;
        !          2669:                        }
        !          2670:                        else if(stricmp(password,user.pass)) {
        !          2671:                                if(scfg.sys_misc&SM_ECHO_PW)
        !          2672:                                        lprintf(LOG_WARNING,"%04d !FAILED Password attempt for user %s: '%s' expected '%s'"
        !          2673:                                                ,sock, user.alias, password, user.pass);
        !          2674:                                else
        !          2675:                                        lprintf(LOG_WARNING,"%04d !FAILED Password attempt for user %s"
        !          2676:                                                ,sock, user.alias);
        !          2677:                                user.number=0;
        !          2678:                                if(badlogin(sock,&login_attempts))
        !          2679:                                        break;
        !          2680:                                continue;
        !          2681:                        }
        !          2682: 
        !          2683:                        /* Update client display */
        !          2684:                        if(user.pass[0])
        !          2685:                                client.user=user.alias;
        !          2686:                        else {  /* anonymous */
        !          2687:                                sprintf(str,"%s <%.32s>",user.alias,password);
        !          2688:                                client.user=str;
        !          2689:                        }
        !          2690:                        client_on(sock,&client,TRUE /* update */);
        !          2691: 
        !          2692: 
        !          2693:                        lprintf(LOG_INFO,"%04d %s logged in",sock,user.alias);
        !          2694:                        logintime=time(NULL);
        !          2695:                        timeleft=gettimeleft(&scfg,&user,logintime);
        !          2696:                        ftp_printfile(sock,"hello",230);
        !          2697: 
        !          2698: #ifdef JAVASCRIPT
        !          2699: #ifdef JS_CX_PER_SESSION
        !          2700:                        if(js_cx!=NULL) {
        !          2701: 
        !          2702:                                if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL) 
        !          2703:                                        lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user class",sock);
        !          2704: 
        !          2705:                                if(js_CreateUserObject(js_cx, js_glob, &scfg, "user", user.number)==NULL) 
        !          2706:                                        lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user object",sock);
        !          2707: 
        !          2708:                                if(js_CreateClientObject(js_cx, js_glob, "client", &client, sock)==NULL) 
        !          2709:                                        lprintf(LOG_ERR,"%04d !JavaScript ERROR creating client object",sock);
        !          2710: 
        !          2711:                                if(js_CreateFileAreaObject(js_cx, js_glob, &scfg, &user
        !          2712:                                        ,startup->html_index_file)==NULL) 
        !          2713:                                        lprintf(LOG_ERR,"%04d !JavaScript ERROR creating file area object",sock);
        !          2714: 
        !          2715:                        }
        !          2716: #endif
        !          2717: #endif
        !          2718: 
        !          2719:                        if(sysop)
        !          2720:                                sockprintf(sock,"230-Sysop access granted.");
        !          2721:                        sockprintf(sock,"230-%s logged in.",user.alias);
        !          2722:                        if(!(user.exempt&FLAG('D')) && (user.cdt+user.freecdt)>0)
        !          2723:                                sockprintf(sock,"230-You have %lu download credits."
        !          2724:                                        ,user.cdt+user.freecdt);
        !          2725:                        sockprintf(sock,"230 You are allowed %lu minutes of use for this session."
        !          2726:                                ,timeleft/60);
        !          2727:                        sprintf(qwkfile,"%sfile/%04d.qwk",scfg.data_dir,user.number);
        !          2728: 
        !          2729:                        /* Adjust User Total Logons/Logons Today */
        !          2730:                        adjustuserrec(&scfg,user.number,U_LOGONS,5,1);
        !          2731:                        putuserrec(&scfg,user.number,U_LTODAY,5,ultoa(user.ltoday+1,str,10));
        !          2732:                        putuserrec(&scfg,user.number,U_MODEM,LEN_MODEM,"FTP");
        !          2733:                        putuserrec(&scfg,user.number,U_COMP,LEN_COMP,host_name);
        !          2734:                        putuserrec(&scfg,user.number,U_NOTE,LEN_NOTE,host_ip);
        !          2735:                        putuserrec(&scfg,user.number,U_LOGONTIME,0,ultoa(logintime,str,16));
        !          2736:                        getuserdat(&scfg, &user);       /* make user current */
        !          2737: 
        !          2738:                        continue;
        !          2739:                }
        !          2740: 
        !          2741:                if(!user.number) {
        !          2742:                        sockprintf(sock,"530 Please login with USER and PASS.");
        !          2743:                        continue;
        !          2744:                }
        !          2745: 
        !          2746:                if(!(user.rest&FLAG('G')))
        !          2747:                        getuserdat(&scfg, &user);       /* get current user data */
        !          2748: 
        !          2749:                if((timeleft=gettimeleft(&scfg,&user,logintime))<1L) {
        !          2750:                        sockprintf(sock,"421 Sorry, you've run out of time.");
        !          2751:                        lprintf(LOG_WARNING,"%04d Out of time, disconnecting",sock);
        !          2752:                        break;
        !          2753:                }
        !          2754: 
        !          2755:                /********************************/
        !          2756:                /* These commands require login */
        !          2757:                /********************************/
        !          2758: 
        !          2759:                if(!stricmp(cmd, "REIN")) {
        !          2760:                        lprintf(LOG_INFO,"%04d %s reinitialized control session",sock,user.alias);
        !          2761:                        user.number=0;
        !          2762:                        sysop=FALSE;
        !          2763:                        filepos=0;
        !          2764:                        sockprintf(sock,"220 Control session re-initialized. Ready for re-login.");
        !          2765:                        continue;
        !          2766:                }
        !          2767: 
        !          2768:                if(!stricmp(cmd, "SITE WHO")) {
        !          2769:                        sockprintf(sock,"211-Active Telnet Nodes:");
        !          2770:                        for(i=0;i<scfg.sys_nodes && i<scfg.sys_lastnode;i++) {
        !          2771:                                if((result=getnodedat(&scfg, i+1, &node, 0))!=0) {
        !          2772:                                        sockprintf(sock," Error %d getting data for Telnet Node %d",result,i+1);
        !          2773:                                        continue;
        !          2774:                                }
        !          2775:                                if(node.status==NODE_INUSE)
        !          2776:                                        sockprintf(sock," Node %3d: %s",i+1, username(&scfg,node.useron,str));
        !          2777:                        }
        !          2778:                        sockprintf(sock,"211 End (%d active FTP clients)", active_clients);
        !          2779:                        continue;
        !          2780:                }
        !          2781:                if(!stricmp(cmd, "SITE VER")) {
        !          2782:                        sockprintf(sock,"211 %s",ftp_ver());
        !          2783:                        continue;
        !          2784:                }
        !          2785:                if(!stricmp(cmd, "SITE UPTIME")) {
        !          2786:                        sockprintf(sock,"211 %s (%lu served)",sectostr(time(NULL)-uptime,str),served);
        !          2787:                        continue;
        !          2788:                }
        !          2789:                if(!stricmp(cmd, "SITE RECYCLE") && user.level>=SYSOP_LEVEL) {
        !          2790:                        startup->recycle_now=TRUE;
        !          2791:                        sockprintf(sock,"211 server will recycle when not in-use");
        !          2792:                        continue;
        !          2793:                }
        !          2794:                if(!stricmp(cmd, "SITE RECYCLE ALL") && user.level>=SYSOP_LEVEL) {
        !          2795:                        refresh_cfg(&scfg);
        !          2796:                        sockprintf(sock,"211 ALL servers/nodes will recycle when not in-use");
        !          2797:                        continue;
        !          2798:                }
        !          2799:                if(!strnicmp(cmd,"SITE EXEC ",10) && sysop) {
        !          2800:                        p=cmd+10;
        !          2801:                        while(*p && *p<=' ') p++;
        !          2802: #ifdef __unix__
        !          2803:                        fp=popen(p,"r");
        !          2804:                        if(fp==NULL)
        !          2805:                                sockprintf(sock,"500 Error %d opening pipe to: %s",errno,p);
        !          2806:                        else {
        !          2807:                                while(!feof(fp)) {
        !          2808:                                        if(fgets(str,sizeof(str),fp)==NULL)
        !          2809:                                                break;
        !          2810:                                        sockprintf(sock,"200-%s",str);
        !          2811:                                }
        !          2812:                                sockprintf(sock,"200 %s returned %d",p,pclose(fp));
        !          2813:                        }
        !          2814: #else
        !          2815:                        sockprintf(sock,"200 system(%s) returned %d",p,system(p));
        !          2816: #endif
        !          2817:                        continue;
        !          2818:                }
        !          2819: 
        !          2820: 
        !          2821: #ifdef SOCKET_DEBUG_CTRL
        !          2822:                if(!stricmp(cmd, "SITE DEBUG")) {
        !          2823:                        sockprintf(sock,"211-Debug");
        !          2824:                        for(i=0;i<sizeof(socket_debug);i++) 
        !          2825:                                if(socket_debug[i]!=0)
        !          2826:                                        sockprintf(sock,"211-socket %d = 0x%X",i,socket_debug[i]);
        !          2827:                        sockprintf(sock,"211 End");
        !          2828:                        continue;
        !          2829:                }
        !          2830: #endif
        !          2831: 
        !          2832:                if(!strnicmp(cmd, "PORT ",5)) {
        !          2833: 
        !          2834:                        if(pasv_sock!=INVALID_SOCKET) 
        !          2835:                                ftp_close_socket(&pasv_sock,__LINE__);
        !          2836: 
        !          2837:                        p=cmd+5;
        !          2838:                        while(*p && *p<=' ') p++;
        !          2839:                        sscanf(p,"%ld,%ld,%ld,%ld,%hd,%hd",&h1,&h2,&h3,&h4,&p1,&p2);
        !          2840:                        data_addr.sin_addr.s_addr=htonl((h1<<24)|(h2<<16)|(h3<<8)|h4);
        !          2841:                        data_addr.sin_port=(u_short)((p1<<8)|p2);
        !          2842:                        if(data_addr.sin_port< IPPORT_RESERVED) {       
        !          2843:                                lprintf(LOG_WARNING,"%04d !SUSPECTED BOUNCE ATTACK ATTEMPT by %s to %s port %u"
        !          2844:                                        ,sock,user.alias
        !          2845:                                        ,inet_ntoa(data_addr.sin_addr),data_addr.sin_port);
        !          2846:                                hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
        !          2847:                                sockprintf(sock,"504 Bad port number.");        
        !          2848: #ifdef _WIN32
        !          2849:                                if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          2850:                                        PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          2851: #endif
        !          2852:                                continue; /* As recommended by RFC2577 */
        !          2853:                        }
        !          2854:                        data_addr.sin_port=htons(data_addr.sin_port);
        !          2855:                        sockprintf(sock,"200 PORT Command successful.");
        !          2856:                        mode="active";
        !          2857:                        continue;
        !          2858:                }
        !          2859: 
        !          2860:                if(!stricmp(cmd, "PASV") 
        !          2861:                        || !stricmp(cmd, "P@SW")) {     /* Kludge required for SMC Barricade V1.2 */
        !          2862: 
        !          2863:                        if(pasv_sock!=INVALID_SOCKET) 
        !          2864:                                ftp_close_socket(&pasv_sock,__LINE__);
        !          2865: 
        !          2866:                        if((pasv_sock=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) {
        !          2867:                                lprintf(LOG_WARNING,"%04d !PASV ERROR %d opening socket", sock,ERROR_VALUE);
        !          2868:                                sockprintf(sock,"425 Error %d opening PASV data socket", ERROR_VALUE);
        !          2869:                                continue;
        !          2870:                        }
        !          2871: 
        !          2872:                        reuseaddr=FALSE;
        !          2873:                        if((result=setsockopt(pasv_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseaddr,sizeof(reuseaddr)))!=0) {
        !          2874:                                lprintf(LOG_WARNING,"%04d !PASV ERROR %d disabling REUSEADDR socket option"
        !          2875:                                        ,sock,ERROR_VALUE);
        !          2876:                                sockprintf(sock,"425 Error %d disabling REUSEADDR socket option", ERROR_VALUE);
        !          2877:                                continue;
        !          2878:                        }
        !          2879: 
        !          2880:                        if(startup->options&FTP_OPT_DEBUG_DATA)
        !          2881:                                lprintf(LOG_DEBUG,"%04d PASV DATA socket %d opened",sock,pasv_sock);
        !          2882: 
        !          2883:                        for(port=startup->pasv_port_low; port<=startup->pasv_port_high; port++) {
        !          2884: 
        !          2885:                                if(startup->options&FTP_OPT_DEBUG_DATA)
        !          2886:                                        lprintf(LOG_DEBUG,"%04d PASV DATA trying to bind socket to port %u"
        !          2887:                                                ,sock,port);
        !          2888: 
        !          2889:                                pasv_addr.sin_port = htons(port);
        !          2890: 
        !          2891:                                if((result=bind(pasv_sock, (struct sockaddr *) &pasv_addr,sizeof(pasv_addr)))==0)
        !          2892:                                        break;
        !          2893:                        }
        !          2894:                        if(result!= 0) {
        !          2895:                                lprintf(LOG_ERR,"%04d !PASV ERROR %d (%d) binding socket to port %u"
        !          2896:                                        ,sock, result, ERROR_VALUE, port);
        !          2897:                                sockprintf(sock,"425 Error %d binding data socket",ERROR_VALUE);
        !          2898:                                ftp_close_socket(&pasv_sock,__LINE__);
        !          2899:                                continue;
        !          2900:                        }
        !          2901:                        if(startup->options&FTP_OPT_DEBUG_DATA)
        !          2902:                                lprintf(LOG_DEBUG,"%04d PASV DATA socket %d bound to port %u",sock,pasv_sock,port);
        !          2903: 
        !          2904:                        addr_len=sizeof(addr);
        !          2905:                        if((result=getsockname(pasv_sock, (struct sockaddr *)&addr,&addr_len))!=0) {
        !          2906:                                lprintf(LOG_ERR,"%04d !PASV ERROR %d (%d) getting address/port"
        !          2907:                                        ,sock, result, ERROR_VALUE);
        !          2908:                                sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE);
        !          2909:                                ftp_close_socket(&pasv_sock,__LINE__);
        !          2910:                                continue;
        !          2911:                        } 
        !          2912: 
        !          2913:                        if((result=listen(pasv_sock, 1))!= 0) {
        !          2914:                                lprintf(LOG_ERR,"%04d !PASV ERROR %d (%d) listening on port %u"
        !          2915:                                        ,sock, result, ERROR_VALUE,port);
        !          2916:                                sockprintf(sock,"425 Error %d listening on data socket",ERROR_VALUE);
        !          2917:                                ftp_close_socket(&pasv_sock,__LINE__);
        !          2918:                                continue;
        !          2919:                        }
        !          2920: 
        !          2921:                        /* Choose IP address to use in passive response */
        !          2922:                        ip_addr=0;
        !          2923:                        if(startup->options&FTP_OPT_LOOKUP_PASV_IP
        !          2924:                                && (host=gethostbyname(startup->host_name))!=NULL) 
        !          2925:                                ip_addr=ntohl(*((ulong*)host->h_addr_list[0]));
        !          2926:                        if(ip_addr==0 && (ip_addr=startup->pasv_ip_addr)==0)
        !          2927:                                ip_addr=ntohl(pasv_addr.sin_addr.s_addr);
        !          2928: 
        !          2929:                        if(startup->options&FTP_OPT_DEBUG_DATA)
        !          2930:                                lprintf(LOG_INFO,"%04d PASV DATA IP address in response: %u.%u.%u.%u (subject to NAT)"
        !          2931:                                        ,sock
        !          2932:                                        ,(ip_addr>>24)&0xff
        !          2933:                                        ,(ip_addr>>16)&0xff
        !          2934:                                        ,(ip_addr>>8)&0xff
        !          2935:                                        ,ip_addr&0xff
        !          2936:                                        );
        !          2937:                        port=ntohs(addr.sin_port);
        !          2938:                        sockprintf(sock,"227 Entering Passive Mode (%u,%u,%u,%u,%hu,%hu)"
        !          2939:                                ,(ip_addr>>24)&0xff
        !          2940:                                ,(ip_addr>>16)&0xff
        !          2941:                                ,(ip_addr>>8)&0xff
        !          2942:                                ,ip_addr&0xff
        !          2943:                                ,(port>>8)&0xff
        !          2944:                                ,port&0xff
        !          2945:                                );
        !          2946:                        mode="passive";
        !          2947:                        continue;
        !          2948:                }
        !          2949: 
        !          2950:                if(!strnicmp(cmd, "TYPE ",5)) {
        !          2951:                        sockprintf(sock,"200 All files sent in BINARY mode.");
        !          2952:                        continue;
        !          2953:                }
        !          2954: 
        !          2955:                if(!strnicmp(cmd, "ALLO",4)) {
        !          2956:                        p=cmd+5;
        !          2957:                        while(*p && *p<=' ') p++;
        !          2958:                        if(*p)
        !          2959:                                l=atol(p);      
        !          2960:                        else
        !          2961:                                l=0;
        !          2962:                        if(local_fsys)
        !          2963:                                avail=getfreediskspace(local_dir,0);
        !          2964:                        else
        !          2965:                                avail=getfreediskspace(scfg.data_dir,0);        /* Change to temp_dir? */
        !          2966:                        if(l && l>avail)
        !          2967:                                sockprintf(sock,"504 Only %lu bytes available.",avail);
        !          2968:                        else
        !          2969:                                sockprintf(sock,"200 %lu bytes available.",avail);
        !          2970:                        continue;
        !          2971:                }
        !          2972: 
        !          2973:                if(!strnicmp(cmd, "REST",4)) {
        !          2974:                        p=cmd+4;
        !          2975:                        while(*p && *p<=' ') p++;
        !          2976:                        if(*p)
        !          2977:                                filepos=atol(p);
        !          2978:                        else
        !          2979:                                filepos=0;
        !          2980:                        sockprintf(sock,"350 Restarting at %lu. Send STORE or RETRIEVE to initiate transfer."
        !          2981:                                ,filepos);
        !          2982:                        continue;
        !          2983:                }
        !          2984: 
        !          2985:                if(!strnicmp(cmd, "MODE ",5)) {
        !          2986:                        p=cmd+5;
        !          2987:                        while(*p && *p<=' ') p++;
        !          2988:                        if(toupper(*p)!='S')
        !          2989:                                sockprintf(sock,"504 Only STREAM mode supported.");
        !          2990:                        else
        !          2991:                                sockprintf(sock,"200 STREAM mode.");
        !          2992:                        continue;
        !          2993:                }
        !          2994: 
        !          2995:                if(!strnicmp(cmd, "STRU ",5)) {
        !          2996:                        p=cmd+5;
        !          2997:                        while(*p && *p<=' ') p++;
        !          2998:                        if(toupper(*p)!='F')
        !          2999:                                sockprintf(sock,"504 Only FILE structure supported.");
        !          3000:                        else
        !          3001:                                sockprintf(sock,"200 FILE structure.");
        !          3002:                        continue;
        !          3003:                }
        !          3004: 
        !          3005:                if(!stricmp(cmd, "SYST")) {
        !          3006:                        sockprintf(sock,"215 UNIX Type: L8");
        !          3007:                        continue;
        !          3008:                }
        !          3009: 
        !          3010:                if(!stricmp(cmd, "ABOR")) {
        !          3011:                        if(!transfer_inprogress)
        !          3012:                                sockprintf(sock,"226 No tranfer in progress.");
        !          3013:                        else {
        !          3014:                                lprintf(LOG_WARNING,"%04d %s aborting transfer"
        !          3015:                                        ,sock,user.alias);
        !          3016:                                transfer_aborted=TRUE;
        !          3017:                                YIELD(); /* give send thread time to abort */
        !          3018:                                sockprintf(sock,"226 Transfer aborted.");
        !          3019:                        }
        !          3020:                        continue;
        !          3021:                }
        !          3022: 
        !          3023:                if(!strnicmp(cmd,"SMNT ",5) && sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) {
        !          3024:                        p=cmd+5;
        !          3025:                        while(*p && *p<=' ') p++;
        !          3026:                        if(!stricmp(p,BBS_FSYS_DIR)) 
        !          3027:                                local_fsys=FALSE;
        !          3028:                        else {
        !          3029:                                if(!direxist(p)) {
        !          3030:                                        sockprintf(sock,"550 Directory does not exist.");
        !          3031:                                        lprintf(LOG_WARNING,"%04d !%s attempted to mount invalid directory: %s"
        !          3032:                                                ,sock, user.alias, p);
        !          3033:                                        continue;
        !          3034:                                }
        !          3035:                                local_fsys=TRUE;
        !          3036:                                SAFECOPY(local_dir,p);
        !          3037:                        }
        !          3038:                        sockprintf(sock,"250 %s file system mounted."
        !          3039:                                ,local_fsys ? "Local" : "BBS");
        !          3040:                        lprintf(LOG_INFO,"%04d %s mounted %s file system"
        !          3041:                                ,sock, user.alias, local_fsys ? "local" : "BBS");
        !          3042:                        continue;
        !          3043:                }
        !          3044: 
        !          3045:                /****************************/
        !          3046:                /* Local File System Access */
        !          3047:                /****************************/
        !          3048:                if(sysop && local_fsys && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) {
        !          3049:                        if(local_dir[0] 
        !          3050:                                && local_dir[strlen(local_dir)-1]!='\\'
        !          3051:                                && local_dir[strlen(local_dir)-1]!='/')
        !          3052:                                strcat(local_dir,"/");
        !          3053: 
        !          3054:                        if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) {    
        !          3055:                                if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) {
        !          3056:                                        lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname);
        !          3057:                                        sockprintf(sock, "451 Insufficient system storage");
        !          3058:                                        continue;
        !          3059:                                }
        !          3060:                                if(!strnicmp(cmd, "LIST", 4))
        !          3061:                                        detail=TRUE;
        !          3062:                                else
        !          3063:                                        detail=FALSE;
        !          3064: 
        !          3065:                                p=cmd+4;
        !          3066:                                while(*p && *p<=' ') p++;
        !          3067: 
        !          3068:                                if(*p=='-') {   /* -Letc */
        !          3069:                                        while(*p && *p>' ') p++;
        !          3070:                                        while(*p && *p<=' ') p++;
        !          3071:                                }
        !          3072: 
        !          3073:                                SAFEPRINTF2(path,"%s%s",local_dir, *p ? p : "*");
        !          3074:                                lprintf(LOG_INFO,"%04d %s listing: %s in %s mode", sock, user.alias, path, mode);
        !          3075:                                sockprintf(sock, "150 Directory of %s%s", local_dir, p);
        !          3076: 
        !          3077:                                now=time(NULL);
        !          3078:                                if(localtime_r(&now,&cur_tm)==NULL) 
        !          3079:                                        memset(&cur_tm,0,sizeof(cur_tm));
        !          3080:                        
        !          3081:                                glob(path,0,NULL,&g);
        !          3082:                                for(i=0;i<(int)g.gl_pathc;i++) {
        !          3083:                                        if(detail) {
        !          3084:                                                f.size=flength(g.gl_pathv[i]);
        !          3085:                                                t=fdate(g.gl_pathv[i]);
        !          3086:                                                if(localtime_r(&t,&tm)==NULL)
        !          3087:                                                        memset(&tm,0,sizeof(tm));
        !          3088:                                                fprintf(fp,"%crw-r--r--   1 %-8s local %9ld %s %2d "
        !          3089:                                                        ,isdir(g.gl_pathv[i]) ? 'd':'-'
        !          3090:                                                        ,scfg.sys_id
        !          3091:                                                        ,f.size
        !          3092:                                                        ,ftp_mon[tm.tm_mon],tm.tm_mday);
        !          3093:                                                if(tm.tm_year==cur_tm.tm_year)
        !          3094:                                                        fprintf(fp,"%02d:%02d %s\r\n"
        !          3095:                                                                ,tm.tm_hour,tm.tm_min
        !          3096:                                                                ,getfname(g.gl_pathv[i]));
        !          3097:                                                else
        !          3098:                                                        fprintf(fp,"%5d %s\r\n"
        !          3099:                                                                ,1900+tm.tm_year
        !          3100:                                                                ,getfname(g.gl_pathv[i]));
        !          3101:                                        } else
        !          3102:                                                fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i]));
        !          3103:                                }
        !          3104:                                globfree(&g);
        !          3105:                                fclose(fp);
        !          3106:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,0L
        !          3107:                                        ,&transfer_inprogress,&transfer_aborted
        !          3108:                                        ,TRUE   /* delfile */
        !          3109:                                        ,TRUE   /* tmpfile */
        !          3110:                                        ,&lastactive,&user,-1,FALSE,FALSE,FALSE,NULL);
        !          3111:                                continue;
        !          3112:                        } /* Local LIST/NLST */
        !          3113:                                
        !          3114:                        if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) {
        !          3115:                            if(!strnicmp(cmd,"CWD ",4))
        !          3116:                                        p=cmd+4;
        !          3117:                                else
        !          3118:                                        p=cmd+5;
        !          3119:                                while(*p && *p<=' ') p++;
        !          3120:                                tp=p;
        !          3121:                                if(*tp=='/' || *tp=='\\') /* /local: and /bbs: are valid */
        !          3122:                                        tp++;
        !          3123:                                if(!strnicmp(tp,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) {
        !          3124:                                        local_fsys=FALSE;
        !          3125:                                        sockprintf(sock,"250 CWD command successful (BBS file system mounted).");
        !          3126:                                        lprintf(LOG_INFO,"%04d %s mounted BBS file system", sock, user.alias);
        !          3127:                                        continue;
        !          3128:                                }
        !          3129:                                if(!strnicmp(tp,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) {
        !          3130:                                        tp+=strlen(LOCAL_FSYS_DIR);     /* already mounted */
        !          3131:                                        p=tp;
        !          3132:                                }
        !          3133: 
        !          3134:                                if(p[1]==':' || !strncmp(p,"\\\\",2))
        !          3135:                                        SAFECOPY(path,p);
        !          3136:                                else if(*p=='/' || *p=='\\')
        !          3137:                                        SAFEPRINTF2(path,"%s%s",root_dir(local_dir),p);
        !          3138:                                else {
        !          3139:                                        SAFEPRINTF2(fname,"%s%s",local_dir,p);
        !          3140:                                        FULLPATH(path,fname,sizeof(path));
        !          3141:                                }
        !          3142: 
        !          3143:                                if(!direxist(path)) {
        !          3144:                                        sockprintf(sock,"550 Directory does not exist (%s).",path);
        !          3145:                                        lprintf(LOG_WARNING,"%04d !%s attempted to change to an invalid directory: %s"
        !          3146:                                                ,sock, user.alias, path);
        !          3147:                                } else {
        !          3148:                                        SAFECOPY(local_dir,path);
        !          3149:                                        sockprintf(sock,"250 CWD command successful (%s).", local_dir);
        !          3150:                                }
        !          3151:                                continue;
        !          3152:                        } /* Local CWD */
        !          3153: 
        !          3154:                        if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) {
        !          3155:                                SAFEPRINTF(path,"%s..",local_dir);
        !          3156:                                if(FULLPATH(local_dir,path,sizeof(local_dir))==NULL)
        !          3157:                                        sockprintf(sock,"550 Directory does not exist.");
        !          3158:                                else
        !          3159:                                        sockprintf(sock,"200 CDUP command successful.");
        !          3160:                                continue;
        !          3161:                        }
        !          3162: 
        !          3163:                        if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) {
        !          3164:                                if(strlen(local_dir)>3)
        !          3165:                                        local_dir[strlen(local_dir)-1]=0;       /* truncate '/' */
        !          3166: 
        !          3167:                                sockprintf(sock,"257 \"%s\" is current directory."
        !          3168:                                        ,local_dir);
        !          3169:                                continue;
        !          3170:                        } /* Local PWD */
        !          3171: 
        !          3172:                        if(!strnicmp(cmd, "MKD ", 4) || !strnicmp(cmd,"XMKD",4)) {
        !          3173:                                p=cmd+4;
        !          3174:                                while(*p && *p<=' ') p++;
        !          3175:                                if(*p=='/')     /* absolute */
        !          3176:                                        SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1);
        !          3177:                                else            /* relative */
        !          3178:                                        SAFEPRINTF2(fname,"%s%s",local_dir,p);
        !          3179: 
        !          3180:                                if((i=MKDIR(fname))==0) {
        !          3181:                                        sockprintf(sock,"257 \"%s\" directory created",fname);
        !          3182:                                        lprintf(LOG_NOTICE,"%04d %s created directory: %s",sock,user.alias,fname);
        !          3183:                                } else {
        !          3184:                                        sockprintf(sock,"521 Error %d creating directory: %s",i,fname);
        !          3185:                                        lprintf(LOG_WARNING,"%04d !%s attempted to create directory: %s (Error %d)"
        !          3186:                                                ,sock,user.alias,fname,i);
        !          3187:                                }
        !          3188:                                continue;
        !          3189:                        }
        !          3190: 
        !          3191:                        if(!strnicmp(cmd, "RMD ", 4) || !strnicmp(cmd,"XRMD",4)) {
        !          3192:                                p=cmd+4;
        !          3193:                                while(*p && *p<=' ') p++;
        !          3194:                                if(*p=='/')     /* absolute */
        !          3195:                                        SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1);
        !          3196:                                else            /* relative */
        !          3197:                                        SAFEPRINTF2(fname,"%s%s",local_dir,p);
        !          3198: 
        !          3199:                                if((i=rmdir(fname))==0) {
        !          3200:                                        sockprintf(sock,"250 \"%s\" directory removed",fname);
        !          3201:                                        lprintf(LOG_NOTICE,"%04d %s removed directory: %s",sock,user.alias,fname);
        !          3202:                                } else {
        !          3203:                                        sockprintf(sock,"450 Error %d removing directory: %s",i,fname);
        !          3204:                                        lprintf(LOG_WARNING,"%04d !%s attempted to remove directory: %s (Error %d)"
        !          3205:                                                ,sock,user.alias,fname,i);
        !          3206:                                }
        !          3207:                                continue;
        !          3208:                        }
        !          3209: 
        !          3210:                        if(!strnicmp(cmd, "RNFR ",5)) {
        !          3211:                                p=cmd+5;
        !          3212:                                while(*p && *p<=' ') p++;
        !          3213:                                if(*p=='/')     /* absolute */
        !          3214:                                        SAFEPRINTF2(ren_from,"%s%s",root_dir(local_dir),p+1);
        !          3215:                                else            /* relative */
        !          3216:                                        SAFEPRINTF2(ren_from,"%s%s",local_dir,p);
        !          3217:                                if(!fexist(ren_from)) {
        !          3218:                                        sockprintf(sock,"550 File not found: %s",ren_from);
        !          3219:                                        lprintf(LOG_WARNING,"%04d !%s attempted to rename %s (not found)"
        !          3220:                                                ,sock,user.alias,ren_from);
        !          3221:                                } else
        !          3222:                                        sockprintf(sock,"350 File exists, ready for destination name");
        !          3223:                                continue;
        !          3224:                        }
        !          3225: 
        !          3226:                        if(!strnicmp(cmd, "RNTO ",5)) {
        !          3227:                                p=cmd+5;
        !          3228:                                while(*p && *p<=' ') p++;
        !          3229:                                if(*p=='/')     /* absolute */
        !          3230:                                        SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1);
        !          3231:                                else            /* relative */
        !          3232:                                        SAFEPRINTF2(fname,"%s%s",local_dir,p);
        !          3233: 
        !          3234:                                if((i=rename(ren_from, fname))==0) {
        !          3235:                                        sockprintf(sock,"250 \"%s\" renamed to \"%s\"",ren_from,fname);
        !          3236:                                        lprintf(LOG_NOTICE,"%04d %s renamed %s to %s",sock,user.alias,ren_from,fname);
        !          3237:                                } else {
        !          3238:                                        sockprintf(sock,"450 Error %d renaming file: %s",i,ren_from);
        !          3239:                                        lprintf(LOG_WARNING,"%04d !%s attempted to rename file: %s (Error %d)"
        !          3240:                                                ,sock,user.alias,ren_from,i);
        !          3241:                                }
        !          3242:                                continue;
        !          3243:                        }
        !          3244: 
        !          3245: 
        !          3246:                        if(!strnicmp(cmd, "RETR ", 5) || !strnicmp(cmd,"SIZE ",5) 
        !          3247:                                || !strnicmp(cmd, "MDTM ",5) || !strnicmp(cmd, "DELE ",5)) {
        !          3248:                                p=cmd+5;
        !          3249:                                while(*p && *p<=' ') p++;
        !          3250: 
        !          3251:                                if(!strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) 
        !          3252:                                        p+=strlen(LOCAL_FSYS_DIR);      /* already mounted */
        !          3253: 
        !          3254:                                if(p[1]==':')           /* drive specified */
        !          3255:                                        SAFECOPY(fname,p);
        !          3256:                                else if(*p=='/')        /* absolute, current drive */
        !          3257:                                        SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1);
        !          3258:                                else            /* relative */
        !          3259:                                        SAFEPRINTF2(fname,"%s%s",local_dir,p);
        !          3260:                                if(!fexist(fname)) {
        !          3261:                                        lprintf(LOG_WARNING,"%04d !%s file not found: %s",sock,user.alias,fname);
        !          3262:                                        sockprintf(sock,"550 File not found: %s",fname);
        !          3263:                                        continue;
        !          3264:                                }
        !          3265:                                if(!strnicmp(cmd,"SIZE ",5)) {
        !          3266:                                        sockprintf(sock,"213 %lu",flength(fname));
        !          3267:                                        continue;
        !          3268:                                }
        !          3269:                                if(!strnicmp(cmd,"MDTM ",5)) {
        !          3270:                                        t=fdate(fname);
        !          3271:                                        if(gmtime_r(&t,&tm)==NULL) /* specifically use GMT/UTC representation */
        !          3272:                                                memset(&tm,0,sizeof(tm));
        !          3273:                                        sockprintf(sock,"213 %u%02u%02u%02u%02u%02u"
        !          3274:                                                ,1900+tm.tm_year,tm.tm_mon+1,tm.tm_mday
        !          3275:                                                ,tm.tm_hour,tm.tm_min,tm.tm_sec);                                       
        !          3276:                                        continue;
        !          3277:                                }
        !          3278:                                if(!strnicmp(cmd,"DELE ",5)) {
        !          3279:                                        if((i=remove(fname))==0) {
        !          3280:                                                sockprintf(sock,"250 \"%s\" removed successfully.",fname);
        !          3281:                                                lprintf(LOG_NOTICE,"%04d %s deleted file: %s",sock,user.alias,fname);
        !          3282:                                        } else {
        !          3283:                                                sockprintf(sock,"450 Error %d removing file: %s",i,fname);
        !          3284:                                                lprintf(LOG_WARNING,"%04d !%s attempted to delete file: %s (Error %d)"
        !          3285:                                                        ,sock,user.alias,fname,i);
        !          3286:                                        }
        !          3287:                                        continue;
        !          3288:                                }
        !          3289:                                /* RETR */
        !          3290:                                lprintf(LOG_INFO,"%04d %s downloading: %s (%lu bytes) in %s mode"
        !          3291:                                        ,sock,user.alias,fname,flength(fname)
        !          3292:                                        ,mode);
        !          3293:                                sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          3294:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          3295:                                        ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
        !          3296:                                        ,&lastactive,&user,-1,FALSE,FALSE,FALSE,NULL);
        !          3297:                                continue;
        !          3298:                        } /* Local RETR/SIZE/MDTM */
        !          3299: 
        !          3300:                        if(!strnicmp(cmd, "STOR ", 5) || !strnicmp(cmd, "APPE ", 5)) {
        !          3301:                                p=cmd+5;
        !          3302:                                while(*p && *p<=' ') p++;
        !          3303: 
        !          3304:                                if(!strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) 
        !          3305:                                        p+=strlen(LOCAL_FSYS_DIR);      /* already mounted */
        !          3306: 
        !          3307:                                if(p[1]==':')           /* drive specified */
        !          3308:                                        SAFECOPY(fname,p);
        !          3309:                                else if(*p=='/')        /* absolute, current drive */
        !          3310:                                        SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1);
        !          3311:                                else                            /* relative */
        !          3312:                                        SAFEPRINTF2(fname,"%s%s",local_dir,p);
        !          3313: 
        !          3314:                                lprintf(LOG_INFO,"%04d %s uploading: %s in %s mode", sock,user.alias,fname
        !          3315:                                        ,mode);
        !          3316:                                sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          3317:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          3318:                                        ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
        !          3319:                                        ,&lastactive
        !          3320:                                        ,&user
        !          3321:                                        ,-1             /* dir */
        !          3322:                                        ,TRUE   /* uploading */
        !          3323:                                        ,FALSE  /* credits */
        !          3324:                                        ,!strnicmp(cmd,"APPE",4) ? TRUE : FALSE /* append */
        !          3325:                                        ,NULL   /* desc */
        !          3326:                                        );
        !          3327:                                filepos=0;
        !          3328:                                continue;
        !          3329:                        } /* Local STOR */
        !          3330:                }
        !          3331: 
        !          3332:                if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) {    
        !          3333:                        dir=curdir;
        !          3334:                        lib=curlib;
        !          3335: 
        !          3336:                        if(cmd[4]!=0) 
        !          3337:                                lprintf(LOG_DEBUG,"%04d LIST/NLST: %s",sock,cmd);
        !          3338: 
        !          3339:                        /* path specified? */
        !          3340:                        p=cmd+4;
        !          3341:                        while(*p && *p<=' ') p++;
        !          3342: 
        !          3343:                        if(*p=='-') {   /* -Letc */
        !          3344:                                while(*p && *p>' ') p++;
        !          3345:                                while(*p && *p<=' ') p++;
        !          3346:                        }
        !          3347: 
        !          3348:                        parsepath(&p,&user,&lib,&dir);
        !          3349: 
        !          3350:                        if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) {
        !          3351:                                lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname);
        !          3352:                                sockprintf(sock, "451 Insufficient system storage");
        !          3353:                                continue;
        !          3354:                        }
        !          3355:                        if(!strnicmp(cmd, "LIST", 4))
        !          3356:                                detail=TRUE;
        !          3357:                        else
        !          3358:                                detail=FALSE;
        !          3359:                        sockprintf(sock,"150 Opening ASCII mode data connection for /bin/ls.");
        !          3360:                        now=time(NULL);
        !          3361:                        if(localtime_r(&now,&cur_tm)==NULL) 
        !          3362:                                memset(&cur_tm,0,sizeof(cur_tm));
        !          3363: 
        !          3364:                        /* ASCII Index File */
        !          3365:                        if(startup->options&FTP_OPT_INDEX_FILE && startup->index_file_name[0]
        !          3366:                                && (!stricmp(p,startup->index_file_name) || *p==0 || *p=='*')) {
        !          3367:                                if(detail)
        !          3368:                                        fprintf(fp,"-r--r--r--   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          3369:                                                ,NAME_LEN
        !          3370:                                                ,scfg.sys_id
        !          3371:                                                ,lib<0 ? scfg.sys_id : dir<0 
        !          3372:                                                        ? scfg.lib[lib]->sname : scfg.dir[dir]->code_suffix
        !          3373:                                                ,512L
        !          3374:                                                ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          3375:                                                ,startup->index_file_name);
        !          3376:                                else
        !          3377:                                        fprintf(fp,"%s\r\n",startup->index_file_name);
        !          3378:                        } 
        !          3379:                        /* HTML Index File */
        !          3380:                        if(startup->options&FTP_OPT_HTML_INDEX_FILE && startup->html_index_file[0]
        !          3381:                                && (!stricmp(p,startup->html_index_file) || *p==0 || *p=='*')) {
        !          3382:                                if(detail)
        !          3383:                                        fprintf(fp,"-r--r--r--   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          3384:                                                ,NAME_LEN
        !          3385:                                                ,scfg.sys_id
        !          3386:                                                ,lib<0 ? scfg.sys_id : dir<0 
        !          3387:                                                        ? scfg.lib[lib]->sname : scfg.dir[dir]->code_suffix
        !          3388:                                                ,512L
        !          3389:                                                ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          3390:                                                ,startup->html_index_file);
        !          3391:                                else
        !          3392:                                        fprintf(fp,"%s\r\n",startup->html_index_file);
        !          3393:                        } 
        !          3394: 
        !          3395:                        if(lib<0) { /* Root dir */
        !          3396:                                lprintf(LOG_INFO,"%04d %s listing: root in %s mode",sock,user.alias, mode);
        !          3397: 
        !          3398:                                /* QWK Packet */
        !          3399:                                if(startup->options&FTP_OPT_ALLOW_QWK/* && fexist(qwkfile)*/) {
        !          3400:                                        if(detail) {
        !          3401:                                                if(fexistcase(qwkfile)) {
        !          3402:                                                        t=fdate(qwkfile);
        !          3403:                                                        l=flength(qwkfile);
        !          3404:                                                } else {
        !          3405:                                                        t=time(NULL);
        !          3406:                                                        l=10240;
        !          3407:                                                };
        !          3408:                                                if(localtime_r(&t,&tm)==NULL) 
        !          3409:                                                        memset(&tm,0,sizeof(tm));
        !          3410:                                                fprintf(fp,"-r--r--r--   1 %-*s %-8s %9ld %s %2d %02d:%02d %s.qwk\r\n"
        !          3411:                                                        ,NAME_LEN
        !          3412:                                                        ,scfg.sys_id
        !          3413:                                                        ,scfg.sys_id
        !          3414:                                                        ,l
        !          3415:                                                        ,ftp_mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min
        !          3416:                                                        ,scfg.sys_id);
        !          3417:                                        } else
        !          3418:                                                fprintf(fp,"%s.qwk\r\n",scfg.sys_id);
        !          3419:                                } 
        !          3420: 
        !          3421:                                /* File Aliases */
        !          3422:                                sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
        !          3423:                                if((alias_fp=fopen(aliasfile,"r"))!=NULL) {
        !          3424: 
        !          3425:                                        while(!feof(alias_fp)) {
        !          3426:                                                if(!fgets(aliasline,sizeof(aliasline),alias_fp))
        !          3427:                                                        break;
        !          3428: 
        !          3429:                                                alias_dir=FALSE;
        !          3430: 
        !          3431:                                                p=aliasline;            /* alias pointer */
        !          3432:                                                while(*p && *p<=' ') p++;
        !          3433: 
        !          3434:                                                if(*p==';')     /* comment */
        !          3435:                                                        continue;
        !          3436: 
        !          3437:                                                tp=p;           /* terminator pointer */
        !          3438:                                                while(*tp && *tp>' ') tp++;
        !          3439:                                                if(*tp) *tp=0;
        !          3440: 
        !          3441:                                                np=tp+1;        /* filename pointer */
        !          3442:                                                while(*np && *np<=' ') np++;
        !          3443: 
        !          3444:                                                tp=np;          /* terminator pointer */
        !          3445:                                                while(*tp && *tp>' ') tp++;
        !          3446:                                                if(*tp) *tp=0;
        !          3447: 
        !          3448:                                                dp=tp+1;        /* description pointer */
        !          3449:                                                while(*dp && *dp<=' ') dp++;
        !          3450:                                                truncsp(dp);
        !          3451: 
        !          3452:                                                if(stricmp(dp,BBS_HIDDEN_ALIAS)==0)
        !          3453:                                                        continue;
        !          3454: 
        !          3455:                                                /* Virtual Path? */
        !          3456:                                                if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
        !          3457:                                                        if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),&user))<0)
        !          3458:                                                                continue; /* No access or invalid virtual path */
        !          3459:                                                        tp=strrchr(np,'/');
        !          3460:                                                        if(tp==NULL) 
        !          3461:                                                                continue;
        !          3462:                                                        tp++;
        !          3463:                                                        if(*tp) {
        !          3464:                                                                SAFEPRINTF2(aliasfile,"%s%s",scfg.dir[dir]->path,tp);
        !          3465:                                                                np=aliasfile;
        !          3466:                                                        }
        !          3467:                                                        else 
        !          3468:                                                                alias_dir=TRUE;
        !          3469:                                                }
        !          3470: 
        !          3471:                                                if(!alias_dir && !fexist(np))
        !          3472:                                                        continue;
        !          3473: 
        !          3474:                                                if(detail) {
        !          3475: 
        !          3476:                                                        if(alias_dir==TRUE) {
        !          3477:                                                                fprintf(fp,"drwxrwxrwx   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          3478:                                                                        ,NAME_LEN
        !          3479:                                                                        ,scfg.sys_id
        !          3480:                                                                        ,scfg.lib[scfg.dir[dir]->lib]->sname
        !          3481:                                                                        ,512L
        !          3482:                                                                        ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          3483:                                                                        ,p);
        !          3484:                                                        }
        !          3485:                                                        else {
        !          3486:                                                                t=fdate(np);
        !          3487:                                                                if(localtime_r(&t,&tm)==NULL)
        !          3488:                                                                        memset(&tm,0,sizeof(tm));
        !          3489:                                                                fprintf(fp,"-r--r--r--   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          3490:                                                                        ,NAME_LEN
        !          3491:                                                                        ,scfg.sys_id
        !          3492:                                                                        ,scfg.sys_id
        !          3493:                                                                        ,flength(np)
        !          3494:                                                                        ,ftp_mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min
        !          3495:                                                                        ,p);
        !          3496:                                                        }
        !          3497:                                                } else
        !          3498:                                                        fprintf(fp,"%s\r\n",p);
        !          3499: 
        !          3500:                                        }
        !          3501: 
        !          3502:                                        fclose(alias_fp);
        !          3503:                                }
        !          3504: 
        !          3505:                                /* Library folders */
        !          3506:                                for(i=0;i<scfg.total_libs;i++) {
        !          3507:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          3508:                                                continue;
        !          3509:                                        if(detail)
        !          3510:                                                fprintf(fp,"dr-xr-xr-x   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          3511:                                                        ,NAME_LEN
        !          3512:                                                        ,scfg.sys_id
        !          3513:                                                        ,scfg.sys_id
        !          3514:                                                        ,512L
        !          3515:                                                        ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          3516:                                                        ,scfg.lib[i]->sname);
        !          3517:                                        else
        !          3518:                                                fprintf(fp,"%s\r\n",scfg.lib[i]->sname);
        !          3519:                                }
        !          3520:                        } else if(dir<0) {
        !          3521:                                lprintf(LOG_INFO,"%04d %s listing: %s library in %s mode"
        !          3522:                                        ,sock,user.alias,scfg.lib[lib]->sname,mode);
        !          3523:                                for(i=0;i<scfg.total_dirs;i++) {
        !          3524:                                        if(scfg.dir[i]->lib!=lib)
        !          3525:                                                continue;
        !          3526:                                        if(i!=scfg.sysop_dir && i!=scfg.upload_dir 
        !          3527:                                                && !chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          3528:                                                continue;
        !          3529:                                        if(detail)
        !          3530:                                                fprintf(fp,"drwxrwxrwx   1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
        !          3531:                                                        ,NAME_LEN
        !          3532:                                                        ,scfg.sys_id
        !          3533:                                                        ,scfg.lib[lib]->sname
        !          3534:                                                        ,512L
        !          3535:                                                        ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
        !          3536:                                                        ,scfg.dir[i]->code_suffix);
        !          3537:                                        else
        !          3538:                                                fprintf(fp,"%s\r\n",scfg.dir[i]->code_suffix);
        !          3539:                                }
        !          3540:                        } else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user)) {
        !          3541:                                lprintf(LOG_INFO,"%04d %s listing: %s/%s directory in %s mode"
        !          3542:                                        ,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code_suffix,mode);
        !          3543: 
        !          3544:                                SAFEPRINTF2(path,"%s%s",scfg.dir[dir]->path,*p ? p : "*");
        !          3545:                                glob(path,0,NULL,&g);
        !          3546:                                for(i=0;i<(int)g.gl_pathc;i++) {
        !          3547:                                        if(isdir(g.gl_pathv[i]))
        !          3548:                                                continue;
        !          3549: #ifdef _WIN32
        !          3550:                                        GetShortPathName(g.gl_pathv[i], str, sizeof(str));
        !          3551: #else
        !          3552:                                        SAFECOPY(str,g.gl_pathv[i]);
        !          3553: #endif
        !          3554:                                        padfname(getfname(str),f.name);
        !          3555:                                        f.dir=dir;
        !          3556:                                        if((filedat=getfileixb(&scfg,&f))==FALSE
        !          3557:                                                && !(startup->options&FTP_OPT_DIR_FILES))
        !          3558:                                                continue;
        !          3559:                                        if(detail) {
        !          3560:                                                f.size=flength(g.gl_pathv[i]);
        !          3561:                                                getfiledat(&scfg,&f);
        !          3562:                                                t=fdate(g.gl_pathv[i]);
        !          3563:                                                if(localtime_r(&t,&tm)==NULL)
        !          3564:                                                        memset(&tm,0,sizeof(tm));
        !          3565:                                                if(filedat) {
        !          3566:                                                        if(f.misc&FM_ANON)
        !          3567:                                                                SAFECOPY(str,ANONYMOUS);
        !          3568:                                                        else
        !          3569:                                                                dotname(f.uler,str);
        !          3570:                                                } else
        !          3571:                                                        SAFECOPY(str,scfg.sys_id);
        !          3572:                                                fprintf(fp,"-r--r--r--   1 %-*s %-8s %9ld %s %2d "
        !          3573:                                                        ,NAME_LEN
        !          3574:                                                        ,str
        !          3575:                                                        ,scfg.dir[dir]->code_suffix
        !          3576:                                                        ,f.size
        !          3577:                                                        ,ftp_mon[tm.tm_mon],tm.tm_mday);
        !          3578:                                                if(tm.tm_year==cur_tm.tm_year)
        !          3579:                                                        fprintf(fp,"%02d:%02d %s\r\n"
        !          3580:                                                                ,tm.tm_hour,tm.tm_min
        !          3581:                                                                ,getfname(g.gl_pathv[i]));
        !          3582:                                                else
        !          3583:                                                        fprintf(fp,"%5d %s\r\n"
        !          3584:                                                                ,1900+tm.tm_year
        !          3585:                                                                ,getfname(g.gl_pathv[i]));
        !          3586:                                        } else
        !          3587:                                                fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i]));
        !          3588:                                }
        !          3589:                                globfree(&g);
        !          3590:                        } else 
        !          3591:                                lprintf(LOG_INFO,"%04d %s listing: %s/%s directory in %s mode (empty - no access)"
        !          3592:                                        ,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code_suffix,mode);
        !          3593: 
        !          3594:                        fclose(fp);
        !          3595:                        filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,0L
        !          3596:                                ,&transfer_inprogress,&transfer_aborted
        !          3597:                                ,TRUE /* delfile */
        !          3598:                                ,TRUE /* tmpfile */
        !          3599:                                ,&lastactive,&user,dir,FALSE,FALSE,FALSE,NULL);
        !          3600:                        continue;
        !          3601:                }
        !          3602: 
        !          3603:                if(!strnicmp(cmd, "RETR ", 5) 
        !          3604:                        || !strnicmp(cmd, "SIZE ",5) 
        !          3605:                        || !strnicmp(cmd, "MDTM ",5)
        !          3606:                        || !strnicmp(cmd, "DELE ",5)) {
        !          3607:                        getdate=FALSE;
        !          3608:                        getsize=FALSE;
        !          3609:                        delecmd=FALSE;
        !          3610:                        if(!strnicmp(cmd,"SIZE ",5))
        !          3611:                                getsize=TRUE;
        !          3612:                        else if(!strnicmp(cmd,"MDTM ",5))
        !          3613:                                getdate=TRUE;
        !          3614:                        else if(!strnicmp(cmd,"DELE ",5))
        !          3615:                                delecmd=TRUE;
        !          3616: 
        !          3617:                        if(!getsize && !getdate && user.rest&FLAG('D')) {
        !          3618:                                sockprintf(sock,"550 Insufficient access.");
        !          3619:                                filepos=0;
        !          3620:                                continue;
        !          3621:                        }
        !          3622:                        credits=TRUE;
        !          3623:                        success=FALSE;
        !          3624:                        delfile=FALSE;
        !          3625:                        tmpfile=FALSE;
        !          3626:                        lib=curlib;
        !          3627:                        dir=curdir;
        !          3628: 
        !          3629:                        p=cmd+5;
        !          3630:                        while(*p && *p<=' ') p++;
        !          3631: 
        !          3632:                        if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) 
        !          3633:                                p+=strlen(BBS_FSYS_DIR);        /* already mounted */
        !          3634: 
        !          3635:                        if(*p=='/') {
        !          3636:                                lib=-1;
        !          3637:                                p++;
        !          3638:                        }
        !          3639:                        else if(!strncmp(p,"./",2))
        !          3640:                                p+=2;
        !          3641: 
        !          3642:                        if(lib<0 && ftpalias(p, fname, &user, &dir)==TRUE) {
        !          3643:                                success=TRUE;
        !          3644:                                credits=TRUE;   /* include in d/l stats */
        !          3645:                                tmpfile=FALSE;
        !          3646:                                delfile=FALSE;
        !          3647:                                lprintf(LOG_INFO,"%04d %s %.4s by alias: %s"
        !          3648:                                        ,sock,user.alias,cmd,p);
        !          3649:                                p=getfname(fname);
        !          3650:                                if(dir>=0)
        !          3651:                                        lib=scfg.dir[dir]->lib;
        !          3652:                        }
        !          3653:                        if(!success && lib<0 && (tp=strchr(p,'/'))!=NULL) {
        !          3654:                                dir=-1;
        !          3655:                                *tp=0;
        !          3656:                                for(i=0;i<scfg.total_libs;i++) {
        !          3657:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          3658:                                                continue;
        !          3659:                                        if(!stricmp(scfg.lib[i]->sname,p))
        !          3660:                                                break;
        !          3661:                                }
        !          3662:                                if(i<scfg.total_libs) 
        !          3663:                                        lib=i;
        !          3664:                                p=tp+1;
        !          3665:                        }
        !          3666:                        if(!success && dir<0 && (tp=strchr(p,'/'))!=NULL) {
        !          3667:                                *tp=0;
        !          3668:                                for(i=0;i<scfg.total_dirs;i++) {
        !          3669:                                        if(scfg.dir[i]->lib!=lib)
        !          3670:                                                continue;
        !          3671:                                        if(!chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          3672:                                                continue;
        !          3673:                                        if(!stricmp(scfg.dir[i]->code_suffix,p))
        !          3674:                                                break;
        !          3675:                                }
        !          3676:                                if(i<scfg.total_dirs) 
        !          3677:                                        dir=i;
        !          3678:                                p=tp+1;
        !          3679:                        }
        !          3680: 
        !          3681:                        sprintf(html_index_ext,"%s?",startup->html_index_file);
        !          3682: 
        !          3683:                        sprintf(str,"%s.qwk",scfg.sys_id);
        !          3684:                        if(lib<0 && startup->options&FTP_OPT_ALLOW_QWK 
        !          3685:                                && !stricmp(p,str) && !delecmd) {
        !          3686:                                if(!fexistcase(qwkfile)) {
        !          3687:                                        lprintf(LOG_INFO,"%04d %s creating QWK packet...",sock,user.alias);
        !          3688:                                        sprintf(str,"%spack%04u.now",scfg.data_dir,user.number);
        !          3689:                                        if(!ftouch(str))
        !          3690:                                                lprintf(LOG_ERR,"%04d !ERROR creating semaphore file: %s"
        !          3691:                                                        ,sock, str);
        !          3692:                                        t=time(NULL);
        !          3693:                                        while(fexist(str)) {
        !          3694:                                                if(time(NULL)-t>startup->qwk_timeout)
        !          3695:                                                        break;
        !          3696:                                                mswait(1000);
        !          3697:                                        }
        !          3698:                                        if(fexist(str)) {
        !          3699:                                                lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for QWK packet creation",sock);
        !          3700:                                                sockprintf(sock,"451 Time-out waiting for packet creation.");
        !          3701:                                                remove(str);
        !          3702:                                                filepos=0;
        !          3703:                                                continue;
        !          3704:                                        }
        !          3705:                                        if(!fexistcase(qwkfile)) {
        !          3706:                                                lprintf(LOG_INFO,"%04d No QWK Packet created (no new messages)",sock);
        !          3707:                                                sockprintf(sock,"550 No QWK packet created (no new messages)");
        !          3708:                                                filepos=0;
        !          3709:                                                continue;
        !          3710:                                        }
        !          3711:                                }
        !          3712:                                SAFECOPY(fname,qwkfile);
        !          3713:                                success=TRUE;
        !          3714:                                delfile=TRUE;
        !          3715:                                credits=FALSE;
        !          3716:                                if(!getsize && !getdate)
        !          3717:                                        lprintf(LOG_INFO,"%04d %s downloading QWK packet (%lu bytes) in %s mode"
        !          3718:                                                ,sock,user.alias,flength(fname)
        !          3719:                                                ,mode);
        !          3720:                        /* ASCII Index File */
        !          3721:                        } else if(startup->options&FTP_OPT_INDEX_FILE 
        !          3722:                                && !stricmp(p,startup->index_file_name)
        !          3723:                                && !delecmd) {
        !          3724:                                if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) {
        !          3725:                                        lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname);
        !          3726:                                        sockprintf(sock, "451 Insufficient system storage");
        !          3727:                                        filepos=0;
        !          3728:                                        continue;
        !          3729:                                }
        !          3730:                                if(!getsize && !getdate)
        !          3731:                                        lprintf(LOG_INFO,"%04d %s downloading index for %s in %s mode"
        !          3732:                                                ,sock,user.alias,vpath(lib,dir,str)
        !          3733:                                                ,mode);
        !          3734:                                success=TRUE;
        !          3735:                                credits=FALSE;
        !          3736:                                tmpfile=TRUE;
        !          3737:                                delfile=TRUE;
        !          3738:                                fprintf(fp,"%-*s File/Folder Descriptions\r\n"
        !          3739:                                        ,INDEX_FNAME_LEN,startup->index_file_name);
        !          3740:                                if(startup->options&FTP_OPT_HTML_INDEX_FILE)
        !          3741:                                        fprintf(fp,"%-*s File/Folder Descriptions (HTML)\r\n"
        !          3742:                                                ,INDEX_FNAME_LEN,startup->html_index_file);
        !          3743:                                if(lib<0) {
        !          3744: 
        !          3745:                                        /* File Aliases */
        !          3746:                                        sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
        !          3747:                                        if((alias_fp=fopen(aliasfile,"r"))!=NULL) {
        !          3748: 
        !          3749:                                                while(!feof(alias_fp)) {
        !          3750:                                                        if(!fgets(aliasline,sizeof(aliasline),alias_fp))
        !          3751:                                                                break;
        !          3752: 
        !          3753:                                                        p=aliasline;    /* alias pointer */
        !          3754:                                                        while(*p && *p<=' ') p++;
        !          3755: 
        !          3756:                                                        if(*p==';')     /* comment */
        !          3757:                                                                continue;
        !          3758: 
        !          3759:                                                        tp=p;           /* terminator pointer */
        !          3760:                                                        while(*tp && *tp>' ') tp++;
        !          3761:                                                        if(*tp) *tp=0;
        !          3762: 
        !          3763:                                                        np=tp+1;        /* filename pointer */
        !          3764:                                                        while(*np && *np<=' ') np++;
        !          3765: 
        !          3766:                                                        np++;           /* description pointer */
        !          3767:                                                        while(*np && *np>' ') np++;
        !          3768: 
        !          3769:                                                        while(*np && *np<' ') np++;
        !          3770: 
        !          3771:                                                        truncsp(np);
        !          3772: 
        !          3773:                                                        fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN,p,np);
        !          3774:                                                }
        !          3775: 
        !          3776:                                                fclose(alias_fp);
        !          3777:                                        }
        !          3778: 
        !          3779:                                        /* QWK Packet */
        !          3780:                                        if(startup->options&FTP_OPT_ALLOW_QWK /* && fexist(qwkfile) */) {
        !          3781:                                                sprintf(str,"%s.qwk",scfg.sys_id);
        !          3782:                                                fprintf(fp,"%-*s QWK Message Packet\r\n"
        !          3783:                                                        ,INDEX_FNAME_LEN,str);
        !          3784:                                        }
        !          3785: 
        !          3786:                                        /* Library Folders */
        !          3787:                                        for(i=0;i<scfg.total_libs;i++) {
        !          3788:                                                if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          3789:                                                        continue;
        !          3790:                                                fprintf(fp,"%-*s %s\r\n"
        !          3791:                                                        ,INDEX_FNAME_LEN,scfg.lib[i]->sname,scfg.lib[i]->lname);
        !          3792:                                        }
        !          3793:                                } else if(dir<0) {
        !          3794:                                        for(i=0;i<scfg.total_dirs;i++) {
        !          3795:                                                if(scfg.dir[i]->lib!=lib)
        !          3796:                                                        continue;
        !          3797:                                                if(i!=scfg.sysop_dir && i!=scfg.upload_dir
        !          3798:                                                        && !chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          3799:                                                        continue;
        !          3800:                                                fprintf(fp,"%-*s %s\r\n"
        !          3801:                                                        ,INDEX_FNAME_LEN,scfg.dir[i]->code_suffix,scfg.dir[i]->lname);
        !          3802:                                        }
        !          3803:                                } else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user)){
        !          3804:                                        sprintf(cmd,"%s*",scfg.dir[dir]->path);
        !          3805:                                        glob(cmd,0,NULL,&g);
        !          3806:                                        for(i=0;i<(int)g.gl_pathc;i++) {
        !          3807:                                                if(isdir(g.gl_pathv[i]))
        !          3808:                                                        continue;
        !          3809: #ifdef _WIN32
        !          3810:                                                GetShortPathName(g.gl_pathv[i], str, sizeof(str));
        !          3811: #else
        !          3812:                                                SAFECOPY(str,g.gl_pathv[i]);
        !          3813: #endif
        !          3814:                                                padfname(getfname(str),f.name);
        !          3815:                                                f.dir=dir;
        !          3816:                                                if(getfileixb(&scfg,&f)) {
        !          3817:                                                        f.size=flength(g.gl_pathv[i]);
        !          3818:                                                        getfiledat(&scfg,&f);
        !          3819:                                                        fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN
        !          3820:                                                                ,getfname(g.gl_pathv[i]),f.desc);
        !          3821:                                                }
        !          3822:                                        }
        !          3823:                                        globfree(&g);
        !          3824:                                }
        !          3825:                                fclose(fp);
        !          3826:                        /* HTML Index File */
        !          3827:                        } else if(startup->options&FTP_OPT_HTML_INDEX_FILE 
        !          3828:                                && (!stricmp(p,startup->html_index_file) 
        !          3829:                                || !strnicmp(p,html_index_ext,strlen(html_index_ext)))
        !          3830:                                && !delecmd) {
        !          3831: #ifdef JAVASCRIPT
        !          3832:                                if(startup->options&FTP_OPT_NO_JAVASCRIPT) {
        !          3833:                                        lprintf(LOG_ERR,"%04d !JavaScript disabled, cannot generate %s",sock,fname);
        !          3834:                                        sockprintf(sock, "451 JavaScript disabled");
        !          3835:                                        filepos=0;
        !          3836:                                        continue;
        !          3837:                                }
        !          3838:                                if(js_runtime == NULL) {
        !          3839:                                        lprintf(LOG_DEBUG,"%04d JavaScript: Creating runtime: %lu bytes"
        !          3840:                                                ,sock,startup->js.max_bytes);
        !          3841: 
        !          3842:                                        if((js_runtime = JS_NewRuntime(startup->js.max_bytes))==NULL) {
        !          3843:                                                lprintf(LOG_ERR,"%04d !ERROR creating JavaScript runtime",sock);
        !          3844:                                                sockprintf(sock,"451 Error creating JavaScript runtime");
        !          3845:                                                filepos=0;
        !          3846:                                                continue;
        !          3847:                                        }
        !          3848:                                }
        !          3849: 
        !          3850:                                if(js_cx==NULL) {       /* Context not yet created, create it now */
        !          3851:                                        if(((js_cx=js_initcx(js_runtime, sock,&js_glob,&js_ftp))==NULL)) {
        !          3852:                                                lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript context",sock);
        !          3853:                                                sockprintf(sock,"451 Error initializing JavaScript context");
        !          3854:                                                filepos=0;
        !          3855:                                                continue;
        !          3856:                                        }
        !          3857:                                        if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL) 
        !          3858:                                                lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user class",sock);
        !          3859: 
        !          3860:                                        if(js_CreateFileClass(js_cx, js_glob)==NULL) 
        !          3861:                                                lprintf(LOG_ERR,"%04d !JavaScript ERROR creating file class",sock);
        !          3862: 
        !          3863:                                        if(js_CreateUserObject(js_cx, js_glob, &scfg, "user", user.number)==NULL) 
        !          3864:                                                lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user object",sock);
        !          3865: 
        !          3866:                                        if(js_CreateClientObject(js_cx, js_glob, "client", &client, sock)==NULL) 
        !          3867:                                                lprintf(LOG_ERR,"%04d !JavaScript ERROR creating client object",sock);
        !          3868: 
        !          3869:                                        if(js_CreateFileAreaObject(js_cx, js_glob, &scfg, &user
        !          3870:                                                ,startup->html_index_file)==NULL) 
        !          3871:                                                lprintf(LOG_ERR,"%04d !JavaScript ERROR creating file area object",sock);
        !          3872:                                }
        !          3873: 
        !          3874:                                if((js_str=JS_NewStringCopyZ(js_cx, "name"))!=NULL) {
        !          3875:                                        js_val=STRING_TO_JSVAL(js_str);
        !          3876:                                        JS_SetProperty(js_cx, js_ftp, "sort", &js_val);
        !          3877:                                }
        !          3878:                                js_val=BOOLEAN_TO_JSVAL(FALSE);
        !          3879:                                JS_SetProperty(js_cx, js_ftp, "reverse", &js_val);
        !          3880: 
        !          3881:                                if(!strnicmp(p,html_index_ext,strlen(html_index_ext))) {
        !          3882:                                        p+=strlen(html_index_ext);
        !          3883:                                        tp=strrchr(p,'$');
        !          3884:                                        if(tp!=NULL)
        !          3885:                                                *tp=0;
        !          3886:                                        if(!strnicmp(p,"ext=",4)) {
        !          3887:                                                p+=4;
        !          3888:                                                if(!strcmp(p,"on"))
        !          3889:                                                        user.misc|=EXTDESC;
        !          3890:                                                else
        !          3891:                                                        user.misc&=~EXTDESC;
        !          3892:                                                if(!(user.rest&FLAG('G')))
        !          3893:                                                        putuserrec(&scfg,user.number,U_MISC,8,ultoa(user.misc,str,16));
        !          3894:                                        } 
        !          3895:                                        else if(!strnicmp(p,"sort=",5)) {
        !          3896:                                                p+=5;
        !          3897:                                                tp=strchr(p,'&');
        !          3898:                                                if(tp!=NULL) {
        !          3899:                                                        *tp=0;
        !          3900:                                                        tp++;
        !          3901:                                                        if(!stricmp(tp,"reverse")) {
        !          3902:                                                                js_val=BOOLEAN_TO_JSVAL(TRUE);
        !          3903:                                                                JS_SetProperty(js_cx, js_ftp, "reverse", &js_val);
        !          3904:                                                        }
        !          3905:                                                }
        !          3906:                                                if((js_str=JS_NewStringCopyZ(js_cx, p))!=NULL) {
        !          3907:                                                        js_val=STRING_TO_JSVAL(js_str);
        !          3908:                                                        JS_SetProperty(js_cx, js_ftp, "sort", &js_val);
        !          3909:                                                }
        !          3910:                                        }
        !          3911:                                }
        !          3912: 
        !          3913:                                js_val=BOOLEAN_TO_JSVAL(INT_TO_BOOL(user.misc&EXTDESC));
        !          3914:                                JS_SetProperty(js_cx, js_ftp, "extended_descriptions", &js_val);
        !          3915: 
        !          3916: #endif
        !          3917:                                if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) {
        !          3918:                                        lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname);
        !          3919:                                        sockprintf(sock, "451 Insufficient system storage");
        !          3920:                                        filepos=0;
        !          3921:                                        continue;
        !          3922:                                }
        !          3923:                                if(!getsize && !getdate)
        !          3924:                                        lprintf(LOG_INFO,"%04d %s downloading HTML index for %s in %s mode"
        !          3925:                                                ,sock,user.alias,vpath(lib,dir,str)
        !          3926:                                                ,mode);
        !          3927:                                success=TRUE;
        !          3928:                                credits=FALSE;
        !          3929:                                tmpfile=TRUE;
        !          3930:                                delfile=TRUE;
        !          3931: #ifdef JAVASCRIPT
        !          3932:                                js_val=INT_TO_JSVAL(timeleft);
        !          3933:                                if(!JS_SetProperty(js_cx, js_ftp, "time_left", &js_val))
        !          3934:                                        lprintf(LOG_ERR,"%04d !JavaScript ERROR setting user.time_left",sock);
        !          3935:                                js_generate_index(js_cx, js_ftp, sock, fp, lib, dir, &user);
        !          3936: #endif
        !          3937:                                fclose(fp);
        !          3938:                        } else if(dir>=0) {
        !          3939: 
        !          3940:                                if(!chk_ar(&scfg,scfg.dir[dir]->ar,&user)) {
        !          3941:                                        lprintf(LOG_WARNING,"%04d !%s has insufficient access to /%s/%s"
        !          3942:                                                ,sock,user.alias
        !          3943:                                                ,scfg.lib[scfg.dir[dir]->lib]->sname
        !          3944:                                                ,scfg.dir[dir]->code_suffix);
        !          3945:                                        sockprintf(sock,"550 Insufficient access.");
        !          3946:                                        filepos=0;
        !          3947:                                        continue;
        !          3948:                                }
        !          3949: 
        !          3950:                                if(!getsize && !getdate && !delecmd
        !          3951:                                        && !chk_ar(&scfg,scfg.dir[dir]->dl_ar,&user)) {
        !          3952:                                        lprintf(LOG_WARNING,"%04d !%s has insufficient access to download from /%s/%s"
        !          3953:                                                ,sock,user.alias
        !          3954:                                                ,scfg.lib[scfg.dir[dir]->lib]->sname
        !          3955:                                                ,scfg.dir[dir]->code_suffix);
        !          3956:                                        sockprintf(sock,"550 Insufficient access.");
        !          3957:                                        filepos=0;
        !          3958:                                        continue;
        !          3959:                                }
        !          3960: 
        !          3961:                                if(delecmd && !dir_op(&scfg,&user,dir)) {
        !          3962:                                        lprintf(LOG_WARNING,"%04d !%s has insufficient access to delete files in /%s/%s"
        !          3963:                                                ,sock,user.alias
        !          3964:                                                ,scfg.lib[scfg.dir[dir]->lib]->sname
        !          3965:                                                ,scfg.dir[dir]->code_suffix);
        !          3966:                                        sockprintf(sock,"550 Insufficient access.");
        !          3967:                                        filepos=0;
        !          3968:                                        continue;
        !          3969:                                }
        !          3970:                                SAFEPRINTF2(fname,"%s%s",scfg.dir[dir]->path,p);
        !          3971: #ifdef _WIN32
        !          3972:                                GetShortPathName(fname, str, sizeof(str));
        !          3973: #else
        !          3974:                                SAFECOPY(str,fname);
        !          3975: #endif
        !          3976:                                padfname(getfname(str),f.name);
        !          3977:                                f.dir=dir;
        !          3978:                                f.cdt=0;
        !          3979:                                f.size=-1;
        !          3980:                                filedat=getfileixb(&scfg,&f);
        !          3981:                                if(!filedat && !(startup->options&FTP_OPT_DIR_FILES)) {
        !          3982:                                        sockprintf(sock,"550 File not found: %s",p);
        !          3983:                                        lprintf(LOG_WARNING,"%04d !%s file (%s%s) not in database for %.4s command"
        !          3984:                                                ,sock,user.alias,vpath(lib,dir,str),p,cmd);
        !          3985:                                        filepos=0;
        !          3986:                                        continue;
        !          3987:                                }
        !          3988: 
        !          3989:                                /* Verify credits */
        !          3990:                                if(!getsize && !getdate && !delecmd
        !          3991:                                        && !is_download_free(&scfg,dir,&user)) {
        !          3992:                                        if(filedat)
        !          3993:                                                getfiledat(&scfg,&f);
        !          3994:                                        else
        !          3995:                                                f.cdt=flength(fname);
        !          3996:                                        if(f.cdt>(user.cdt+user.freecdt)) {
        !          3997:                                                lprintf(LOG_WARNING,"%04d !%s has insufficient credit to download /%s/%s/%s (%lu credits)"
        !          3998:                                                        ,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname
        !          3999:                                                        ,scfg.dir[dir]->code_suffix
        !          4000:                                                        ,p
        !          4001:                                                        ,f.cdt);
        !          4002:                                                sockprintf(sock,"550 Insufficient credit (%lu required).",f.cdt);
        !          4003:                                                filepos=0;
        !          4004:                                                continue;
        !          4005:                                        }
        !          4006:                                }
        !          4007: 
        !          4008:                                if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)) {
        !          4009:                                        success=FALSE;
        !          4010:                                        lprintf(LOG_WARNING,"%04d !ILLEGAL FILENAME ATTEMPT by %s: %s"
        !          4011:                                                ,sock,user.alias,p);
        !          4012:                                        hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
        !          4013: #ifdef _WIN32
        !          4014:                                        if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          4015:                                                PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          4016: #endif
        !          4017:                                } else {
        !          4018:                                        if(fexist(fname)) {
        !          4019:                                                success=TRUE;
        !          4020:                                                if(!getsize && !getdate && !delecmd)
        !          4021:                                                        lprintf(LOG_INFO,"%04d %s downloading: %s (%lu bytes) in %s mode"
        !          4022:                                                                ,sock,user.alias,fname,flength(fname)
        !          4023:                                                                ,mode);
        !          4024:                                        } 
        !          4025:                                }
        !          4026:                        }
        !          4027: #if defined(SOCKET_DEBUG_DOWNLOAD)
        !          4028:                        socket_debug[sock]|=SOCKET_DEBUG_DOWNLOAD;
        !          4029: #endif
        !          4030: 
        !          4031:                        if(getsize && success) 
        !          4032:                                sockprintf(sock,"213 %lu",flength(fname));
        !          4033:                        else if(getdate && success) {
        !          4034:                                t=fdate(fname);
        !          4035:                                if(gmtime_r(&t,&tm)==NULL)      /* specifically use GMT/UTC representation */
        !          4036:                                        memset(&tm,0,sizeof(tm));
        !          4037:                                sockprintf(sock,"213 %u%02u%02u%02u%02u%02u"
        !          4038:                                        ,1900+tm.tm_year,tm.tm_mon+1,tm.tm_mday
        !          4039:                                        ,tm.tm_hour,tm.tm_min,tm.tm_sec);
        !          4040:                        } else if(delecmd && success) {
        !          4041:                                if(remove(fname)!=0) {
        !          4042:                                        lprintf(LOG_ERR,"%04d !ERROR %d deleting %s",sock,errno,fname);
        !          4043:                                        sockprintf(sock,"450 %s could not be deleted (error: %d)"
        !          4044:                                                ,fname,errno);
        !          4045:                                } else {
        !          4046:                                        lprintf(LOG_NOTICE,"%04d %s deleted %s",sock,user.alias,fname);
        !          4047:                                        if(filedat) 
        !          4048:                                                removefiledat(&scfg,&f);
        !          4049:                                        sockprintf(sock,"250 %s deleted.",fname);
        !          4050:                                }
        !          4051:                        } else if(success) {
        !          4052:                                sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          4053:                                filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          4054:                                        ,&transfer_inprogress,&transfer_aborted,delfile,tmpfile
        !          4055:                                        ,&lastactive,&user,dir,FALSE,credits,FALSE,NULL);
        !          4056:                        }
        !          4057:                        else {
        !          4058:                                sockprintf(sock,"550 File not found: %s",p);
        !          4059:                                lprintf(LOG_WARNING,"%04d !%s file (%s%s) not found for %.4s command"
        !          4060:                                        ,sock,user.alias,vpath(lib,dir,str),p,cmd);
        !          4061:                        }
        !          4062:                        filepos=0;
        !          4063: #if defined(SOCKET_DEBUG_DOWNLOAD)
        !          4064:                        socket_debug[sock]&=~SOCKET_DEBUG_DOWNLOAD;
        !          4065: #endif
        !          4066:                        continue;
        !          4067:                }
        !          4068: 
        !          4069:                if(!strnicmp(cmd, "DESC", 4)) {
        !          4070: 
        !          4071:                        if(user.rest&FLAG('U')) {
        !          4072:                                sockprintf(sock,"553 Insufficient access.");
        !          4073:                                continue;
        !          4074:                        }
        !          4075: 
        !          4076:                        p=cmd+4;
        !          4077:                        while(*p && *p<=' ') p++;
        !          4078: 
        !          4079:                        if(*p==0) 
        !          4080:                                sockprintf(sock,"501 No file description given.");
        !          4081:                        else {
        !          4082:                                SAFECOPY(desc,p);
        !          4083:                                sockprintf(sock,"200 File description set. Ready to STOR file.");
        !          4084:                        }
        !          4085:                        continue;
        !          4086:                }
        !          4087: 
        !          4088:                if(!strnicmp(cmd, "STOR ", 5) || !strnicmp(cmd, "APPE ", 5)) {
        !          4089: 
        !          4090:                        if(user.rest&FLAG('U')) {
        !          4091:                                sockprintf(sock,"553 Insufficient access.");
        !          4092:                                continue;
        !          4093:                        }
        !          4094: 
        !          4095:                        if(transfer_inprogress==TRUE) {
        !          4096:                                lprintf(LOG_WARNING,"%04d !TRANSFER already in progress (%s)",sock,cmd);
        !          4097:                                sockprintf(sock,"425 Transfer already in progress.");
        !          4098:                                continue;
        !          4099:                        }
        !          4100: 
        !          4101:                        append=FALSE;
        !          4102:                        lib=curlib;
        !          4103:                        dir=curdir;
        !          4104:                        p=cmd+5;
        !          4105: 
        !          4106:                        while(*p && *p<=' ') p++;
        !          4107: 
        !          4108:                        if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) 
        !          4109:                                p+=strlen(BBS_FSYS_DIR);        /* already mounted */
        !          4110: 
        !          4111:                        if(*p=='/') {
        !          4112:                                lib=-1;
        !          4113:                                p++;
        !          4114:                        }
        !          4115:                        else if(!strncmp(p,"./",2))
        !          4116:                                p+=2;
        !          4117:                        /* Need to add support for uploading to aliased directories */
        !          4118:                        if(lib<0 && (tp=strchr(p,'/'))!=NULL) {
        !          4119:                                dir=-1;
        !          4120:                                *tp=0;
        !          4121:                                for(i=0;i<scfg.total_libs;i++) {
        !          4122:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          4123:                                                continue;
        !          4124:                                        if(!stricmp(scfg.lib[i]->sname,p))
        !          4125:                                                break;
        !          4126:                                }
        !          4127:                                if(i<scfg.total_libs) 
        !          4128:                                        lib=i;
        !          4129:                                p=tp+1;
        !          4130:                        }
        !          4131:                        if(dir<0 && (tp=strchr(p,'/'))!=NULL) {
        !          4132:                                *tp=0;
        !          4133:                                for(i=0;i<scfg.total_dirs;i++) {
        !          4134:                                        if(scfg.dir[i]->lib!=lib)
        !          4135:                                                continue;
        !          4136:                                        if(i!=scfg.sysop_dir && i!=scfg.upload_dir 
        !          4137:                                                && !chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          4138:                                                continue;
        !          4139:                                        if(!stricmp(scfg.dir[i]->code_suffix,p))
        !          4140:                                                break;
        !          4141:                                }
        !          4142:                                if(i<scfg.total_dirs) 
        !          4143:                                        dir=i;
        !          4144:                                p=tp+1;
        !          4145:                        }
        !          4146:                        if(dir<0) {
        !          4147:                                sprintf(str,"%s.rep",scfg.sys_id);
        !          4148:                                if(!(startup->options&FTP_OPT_ALLOW_QWK)
        !          4149:                                        || stricmp(p,str)) {
        !          4150:                                        lprintf(LOG_WARNING,"%04d !%s attempted to upload to invalid directory"
        !          4151:                                                ,sock,user.alias);
        !          4152:                                        sockprintf(sock,"553 Invalid directory.");
        !          4153:                                        continue;
        !          4154:                                }
        !          4155:                                sprintf(fname,"%sfile/%04d.rep",scfg.data_dir,user.number);
        !          4156:                                lprintf(LOG_INFO,"%04d %s uploading: %s in %s mode"
        !          4157:                                        ,sock,user.alias,fname
        !          4158:                                        ,mode);
        !          4159:                        } else {
        !          4160: 
        !          4161:                                append=(strnicmp(cmd,"APPE",4)==0);
        !          4162:                        
        !          4163:                                if(!chk_ar(&scfg,scfg.dir[dir]->ul_ar,&user)) {
        !          4164:                                        lprintf(LOG_WARNING,"%04d !%s has insufficient access to upload to /%s/%s"
        !          4165:                                                ,sock,user.alias
        !          4166:                                                ,scfg.lib[scfg.dir[dir]->lib]->sname
        !          4167:                                                ,scfg.dir[dir]->code_suffix);
        !          4168:                                        sockprintf(sock,"553 Insufficient access.");
        !          4169:                                        continue;
        !          4170:                                }
        !          4171:                                if(*p=='-'
        !          4172:                                        || strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)
        !          4173:                                        || trashcan(&scfg,p,"file")) {
        !          4174:                                        lprintf(LOG_WARNING,"%04d !ILLEGAL FILENAME ATTEMPT by %s: %s"
        !          4175:                                                ,sock,user.alias,p);
        !          4176:                                        sockprintf(sock,"553 Illegal filename attempt");
        !          4177:                                        hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
        !          4178: #ifdef _WIN32
        !          4179:                                        if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          4180:                                                PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          4181: #endif
        !          4182:                                        continue;
        !          4183:                                }
        !          4184:                                SAFEPRINTF2(fname,"%s%s",scfg.dir[dir]->path,p);
        !          4185:                                if((!append && filepos==0 && fexist(fname))
        !          4186:                                        || (startup->options&FTP_OPT_INDEX_FILE 
        !          4187:                                                && !stricmp(p,startup->index_file_name))
        !          4188:                                        || (startup->options&FTP_OPT_HTML_INDEX_FILE 
        !          4189:                                                && !stricmp(p,startup->html_index_file))
        !          4190:                                        ) {
        !          4191:                                        lprintf(LOG_WARNING,"%04d !%s attempted to overwrite existing file: %s"
        !          4192:                                                ,sock,user.alias,fname);
        !          4193:                                        sockprintf(sock,"553 File already exists.");
        !          4194:                                        continue;
        !          4195:                                }
        !          4196:                                if(append || filepos) { /* RESUME */
        !          4197: #ifdef _WIN32
        !          4198:                                        GetShortPathName(fname, str, sizeof(str));
        !          4199: #else
        !          4200:                                        SAFECOPY(str,fname);
        !          4201: #endif
        !          4202:                                        padfname(getfname(str),f.name);
        !          4203:                                        f.dir=dir;
        !          4204:                                        f.cdt=0;
        !          4205:                                        f.size=-1;
        !          4206:                                        if(!getfileixb(&scfg,&f) || !getfiledat(&scfg,&f)) {
        !          4207:                                                if(filepos) {
        !          4208:                                                        lprintf(LOG_WARNING,"%04d !%s file (%s) not in database for %.4s command"
        !          4209:                                                                ,sock,user.alias,fname,cmd);
        !          4210:                                                        sockprintf(sock,"550 File not found: %s",p);
        !          4211:                                                        continue;
        !          4212:                                                }
        !          4213:                                                append=FALSE;
        !          4214:                                        }
        !          4215:                                        /* Verify user is original uploader */
        !          4216:                                        if((append || filepos) && stricmp(f.uler,user.alias)) {
        !          4217:                                                lprintf(LOG_WARNING,"%04d !%s cannot resume upload of %s, uploaded by %s"
        !          4218:                                                        ,sock,user.alias,fname,f.uler);
        !          4219:                                                sockprintf(sock,"553 Insufficient access (can't resume upload from different user).");
        !          4220:                                                continue;
        !          4221:                                        }
        !          4222:                                }
        !          4223:                                lprintf(LOG_INFO,"%04d %s uploading: %s to %s (%s) in %s mode"
        !          4224:                                        ,sock,user.alias
        !          4225:                                        ,p                                              /* filename */
        !          4226:                                        ,vpath(lib,dir,str)             /* virtual path */
        !          4227:                                        ,scfg.dir[dir]->path    /* actual path */
        !          4228:                                        ,mode);
        !          4229:                        }
        !          4230:                        sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
        !          4231:                        filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
        !          4232:                                ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
        !          4233:                                ,&lastactive
        !          4234:                                ,&user
        !          4235:                                ,dir
        !          4236:                                ,TRUE   /* uploading */
        !          4237:                                ,TRUE   /* credits */
        !          4238:                                ,append
        !          4239:                                ,desc
        !          4240:                                );
        !          4241:                        filepos=0;
        !          4242:                        continue;
        !          4243:                }
        !          4244: 
        !          4245:                if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) {
        !          4246:                        if(curdir<0)
        !          4247:                                curlib=-1;
        !          4248:                        else
        !          4249:                                curdir=-1;
        !          4250:                        sockprintf(sock,"200 CDUP command successful.");
        !          4251:                        continue;
        !          4252:                }
        !          4253: 
        !          4254:                if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) {
        !          4255:                        p=cmd+4;
        !          4256:                        while(*p && *p<=' ') p++;
        !          4257: 
        !          4258:                        if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) 
        !          4259:                                p+=strlen(BBS_FSYS_DIR);        /* already mounted */
        !          4260: 
        !          4261:                        if(*p=='/') {
        !          4262:                                curlib=-1;
        !          4263:                                curdir=-1;
        !          4264:                                p++;
        !          4265:                        }
        !          4266:                        /* Local File System? */
        !          4267:                        if(sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS) 
        !          4268:                                && !strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) {        
        !          4269:                                p+=strlen(LOCAL_FSYS_DIR);
        !          4270:                                if(!direxist(p)) {
        !          4271:                                        sockprintf(sock,"550 Directory does not exist.");
        !          4272:                                        lprintf(LOG_WARNING,"%04d !%s attempted to mount invalid directory: %s"
        !          4273:                                                ,sock, user.alias, p);
        !          4274:                                        continue;
        !          4275:                                }
        !          4276:                                SAFECOPY(local_dir,p);
        !          4277:                                local_fsys=TRUE;
        !          4278:                                sockprintf(sock,"250 CWD command successful (local file system mounted).");
        !          4279:                                lprintf(LOG_INFO,"%04d %s mounted local file system", sock, user.alias);
        !          4280:                                continue;
        !          4281:                        }
        !          4282:                        success=FALSE;
        !          4283: 
        !          4284:                        /* Directory Alias? */
        !          4285:                        if(curlib<0 && ftpalias(p,NULL,&user,&curdir)==TRUE) {
        !          4286:                                if(curdir>=0)
        !          4287:                                        curlib=scfg.dir[curdir]->lib;
        !          4288:                                success=TRUE;
        !          4289:                        }
        !          4290: 
        !          4291:                        orglib=curlib;
        !          4292:                        orgdir=curdir;
        !          4293:                        tp=0;
        !          4294:                        if(!strncmp(p,"...",3)) {
        !          4295:                                curlib=-1;
        !          4296:                                curdir=-1;
        !          4297:                                p+=3;
        !          4298:                        }
        !          4299:                        if(!strncmp(p,"./",2))
        !          4300:                                p+=2;
        !          4301:                        else if(!strncmp(p,"..",2)) {
        !          4302:                                if(curdir<0)
        !          4303:                                        curlib=-1;
        !          4304:                                else
        !          4305:                                        curdir=-1;
        !          4306:                                p+=2;
        !          4307:                        }
        !          4308:                        if(*p==0)
        !          4309:                                success=TRUE;
        !          4310:                        else if(!strcmp(p,".")) 
        !          4311:                                success=TRUE;
        !          4312:                        if(!success  && (curlib<0 || *p=='/')) { /* Root dir */
        !          4313:                                if(*p=='/') p++;
        !          4314:                                tp=strchr(p,'/');
        !          4315:                                if(tp) *tp=0;
        !          4316:                                for(i=0;i<scfg.total_libs;i++) {
        !          4317:                                        if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
        !          4318:                                                continue;
        !          4319:                                        if(!stricmp(scfg.lib[i]->sname,p))
        !          4320:                                                break;
        !          4321:                                }
        !          4322:                                if(i<scfg.total_libs) {
        !          4323:                                        curlib=i;
        !          4324:                                        success=TRUE;
        !          4325:                                }
        !          4326:                        }
        !          4327:                        if((!success && curdir<0) || (success && tp && *(tp+1))) {
        !          4328:                                if(tp)
        !          4329:                                        p=tp+1;
        !          4330:                                tp=lastchar(p);
        !          4331:                                if(tp && *tp=='/') *tp=0;
        !          4332:                                for(i=0;i<scfg.total_dirs;i++) {
        !          4333:                                        if(scfg.dir[i]->lib!=curlib)
        !          4334:                                                continue;
        !          4335:                                        if(i!=scfg.sysop_dir && i!=scfg.upload_dir
        !          4336:                                                && !chk_ar(&scfg,scfg.dir[i]->ar,&user))
        !          4337:                                                continue;
        !          4338:                                        if(!stricmp(scfg.dir[i]->code_suffix,p))
        !          4339:                                                break;
        !          4340:                                }
        !          4341:                                if(i<scfg.total_dirs) {
        !          4342:                                        curdir=i;
        !          4343:                                        success=TRUE;
        !          4344:                                } else
        !          4345:                                        success=FALSE;
        !          4346:                        }
        !          4347: 
        !          4348:                        if(success)
        !          4349:                                sockprintf(sock,"250 CWD command successful.");
        !          4350:                        else {
        !          4351:                                sockprintf(sock,"550 %s: No such file or directory.",p);
        !          4352:                                curlib=orglib;
        !          4353:                                curdir=orgdir;
        !          4354:                        }
        !          4355:                        continue;
        !          4356:                }
        !          4357: 
        !          4358:                if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) {
        !          4359:                        if(curlib<0)
        !          4360:                                sockprintf(sock,"257 \"/\" is current directory.");
        !          4361:                        else if(curdir<0)
        !          4362:                                sockprintf(sock,"257 \"/%s\" is current directory."
        !          4363:                                        ,scfg.lib[curlib]->sname);
        !          4364:                        else
        !          4365:                                sockprintf(sock,"257 \"/%s/%s\" is current directory."
        !          4366:                                        ,scfg.lib[curlib]->sname
        !          4367:                                        ,scfg.dir[curdir]->code_suffix);
        !          4368:                        continue;
        !          4369:                }
        !          4370: 
        !          4371:                if(!strnicmp(cmd, "MKD", 3) || 
        !          4372:                        !strnicmp(cmd,"XMKD",4) || 
        !          4373:                        !strnicmp(cmd,"SITE EXEC",9)) {
        !          4374:                        lprintf(LOG_WARNING,"%04d !SUSPECTED HACK ATTEMPT by %s: '%s'"
        !          4375:                                ,sock,user.alias,cmd);
        !          4376:                        hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
        !          4377: #ifdef _WIN32
        !          4378:                        if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          4379:                                PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          4380: #endif
        !          4381:                }               
        !          4382:                sockprintf(sock,"500 Syntax error: '%s'",cmd);
        !          4383:                lprintf(LOG_WARNING,"%04d !UNSUPPORTED COMMAND from %s: '%s'"
        !          4384:                        ,sock,user.alias,cmd);
        !          4385:        } /* while(1) */
        !          4386: 
        !          4387: #if defined(SOCKET_DEBUG_TERMINATE)
        !          4388:        socket_debug[sock]|=SOCKET_DEBUG_TERMINATE;
        !          4389: #endif
        !          4390: 
        !          4391:        if(transfer_inprogress==TRUE) {
        !          4392:                lprintf(LOG_DEBUG,"%04d Waiting for transfer to complete...",sock);
        !          4393:                count=0;
        !          4394:                while(transfer_inprogress==TRUE) {
        !          4395:                        if(server_socket==INVALID_SOCKET || terminate_server) {
        !          4396:                                mswait(2000);   /* allow xfer threads to terminate */
        !          4397:                                break;
        !          4398:                        }
        !          4399:                        if(!transfer_aborted) {
        !          4400:                                if(gettimeleft(&scfg,&user,logintime)<1) {
        !          4401:                                        lprintf(LOG_WARNING,"%04d Out of time, disconnecting",sock);
        !          4402:                                        sockprintf(sock,"421 Sorry, you've run out of time.");
        !          4403:                                        ftp_close_socket(&data_sock,__LINE__);
        !          4404:                                        transfer_aborted=TRUE;
        !          4405:                                }
        !          4406:                                if((time(NULL)-lastactive)>startup->max_inactivity) {
        !          4407:                                        lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",sock);
        !          4408:                                        sockprintf(sock,"421 Disconnecting due to inactivity (%u seconds)."
        !          4409:                                                ,startup->max_inactivity);
        !          4410:                                        ftp_close_socket(&data_sock,__LINE__);
        !          4411:                                        transfer_aborted=TRUE;
        !          4412:                                }
        !          4413:                        }
        !          4414:                        if(count && (count%60)==0)
        !          4415:                                lprintf(LOG_WARNING,"%04d Still waiting for transfer to complete "
        !          4416:                                        "(count=%lu, aborted=%d, lastactive=%lX) ..."
        !          4417:                                        ,sock,count,transfer_aborted,lastactive);
        !          4418:                        count++;
        !          4419:                        mswait(1000);
        !          4420:                }
        !          4421:                lprintf(LOG_DEBUG,"%04d Done waiting for transfer to complete",sock);
        !          4422:        }
        !          4423: 
        !          4424:        if(user.number) {
        !          4425:                /* Update User Statistics */
        !          4426:                logoutuserdat(&scfg, &user, time(NULL), logintime);
        !          4427:                /* Remove QWK-pack semaphore file (if left behind) */
        !          4428:                sprintf(str,"%spack%04u.now",scfg.data_dir,user.number);
        !          4429:                remove(str);
        !          4430:                lprintf(LOG_INFO,"%04d %s logged off",sock,user.alias);
        !          4431:        }
        !          4432: 
        !          4433: #ifdef _WIN32
        !          4434:        if(startup->hangup_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
        !          4435:                PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          4436: #endif
        !          4437: 
        !          4438: #ifdef JAVASCRIPT
        !          4439:        if(js_cx!=NULL) {
        !          4440:                lprintf(LOG_DEBUG,"%04d JavaScript: Destroying context",sock);
        !          4441:                JS_DestroyContext(js_cx);       /* Free Context */
        !          4442:        }
        !          4443: 
        !          4444:        if(js_runtime!=NULL) {
        !          4445:                lprintf(LOG_DEBUG,"%04d JavaScript: Destroying runtime",sock);
        !          4446:                JS_DestroyRuntime(js_runtime);
        !          4447:        }
        !          4448: 
        !          4449: #endif
        !          4450: 
        !          4451: /*     status(STATUS_WFC); server thread should control status display */
        !          4452: 
        !          4453:        if(pasv_sock!=INVALID_SOCKET)
        !          4454:                ftp_close_socket(&pasv_sock,__LINE__);
        !          4455:        if(data_sock!=INVALID_SOCKET)
        !          4456:                ftp_close_socket(&data_sock,__LINE__);
        !          4457: 
        !          4458:        client_off(sock);
        !          4459: 
        !          4460: #ifdef SOCKET_DEBUG_CTRL
        !          4461:        socket_debug[sock]&=~SOCKET_DEBUG_CTRL;
        !          4462: #endif
        !          4463: 
        !          4464: #if defined(SOCKET_DEBUG_TERMINATE)
        !          4465:        socket_debug[sock]&=~SOCKET_DEBUG_TERMINATE;
        !          4466: #endif
        !          4467: 
        !          4468:        tmp_sock=sock;
        !          4469:        ftp_close_socket(&tmp_sock,__LINE__);
        !          4470: 
        !          4471:        if(active_clients)
        !          4472:                active_clients--, update_clients();
        !          4473: 
        !          4474:        thread_down();
        !          4475:        lprintf(LOG_DEBUG,"%04d CTRL thread terminated (%d clients, %u threads remain, %lu served)"
        !          4476:                ,sock, active_clients, thread_count, served);
        !          4477: }
        !          4478: 
        !          4479: static void cleanup(int code, int line)
        !          4480: {
        !          4481: #ifdef _DEBUG
        !          4482:        lprintf(LOG_INFO,"0000 cleanup called from line %d",line);
        !          4483: #endif
        !          4484:        free_cfg(&scfg);
        !          4485:        free_text(text);
        !          4486: 
        !          4487:        semfile_list_free(&recycle_semfiles);
        !          4488:        semfile_list_free(&shutdown_semfiles);
        !          4489: 
        !          4490:        if(server_socket!=INVALID_SOCKET)
        !          4491:                ftp_close_socket(&server_socket,__LINE__);
        !          4492: 
        !          4493:        update_clients();
        !          4494: 
        !          4495: #ifdef _WINSOCKAPI_
        !          4496:        if(WSAInitialized && WSACleanup()!=0) 
        !          4497:                lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
        !          4498: #endif
        !          4499: 
        !          4500:        thread_down();
        !          4501:        status("Down");
        !          4502:        if(terminate_server || code)
        !          4503:                lprintf(LOG_INFO,"#### FTP Server thread terminated (%u threads remain, %lu clients served)"
        !          4504:                        ,thread_count, served);
        !          4505:        if(startup!=NULL && startup->terminated!=NULL)
        !          4506:                startup->terminated(startup->cbdata,code);
        !          4507: }
        !          4508: 
        !          4509: const char* DLLCALL ftp_ver(void)
        !          4510: {
        !          4511:        static char ver[256];
        !          4512:        char compiler[32];
        !          4513: 
        !          4514:        DESCRIBE_COMPILER(compiler);
        !          4515: 
        !          4516:        sscanf("$Revision: 1.313 $", "%*s %s", revision);
        !          4517: 
        !          4518:        sprintf(ver,"%s %s%s  "
        !          4519:                "Compiled %s %s with %s"
        !          4520:                ,FTP_SERVER
        !          4521:                ,revision
        !          4522: #ifdef _DEBUG
        !          4523:                ," Debug"
        !          4524: #else
        !          4525:                ,""
        !          4526: #endif
        !          4527:                ,__DATE__, __TIME__, compiler);
        !          4528: 
        !          4529:        return(ver);
        !          4530: }
        !          4531: 
        !          4532: void DLLCALL ftp_server(void* arg)
        !          4533: {
        !          4534:        char*                   p;
        !          4535:        char                    path[MAX_PATH+1];
        !          4536:        char                    error[256];
        !          4537:        char                    compiler[32];
        !          4538:        char                    str[256];
        !          4539:        SOCKADDR_IN             server_addr;
        !          4540:        SOCKADDR_IN             client_addr;
        !          4541:        socklen_t               client_addr_len;
        !          4542:        SOCKET                  client_socket;
        !          4543:        int                             i;
        !          4544:        int                             result;
        !          4545:        time_t                  t;
        !          4546:        time_t                  start;
        !          4547:        time_t                  initialized=0;
        !          4548:        fd_set                  socket_set;
        !          4549:        ftp_t*                  ftp;
        !          4550:        struct timeval  tv;
        !          4551: 
        !          4552:        ftp_ver();
        !          4553: 
        !          4554:        startup=(ftp_startup_t*)arg;
        !          4555: 
        !          4556: #ifdef _THREAD_SUID_BROKEN
        !          4557:        if(thread_suid_broken)
        !          4558:                startup->seteuid(TRUE);
        !          4559: #endif
        !          4560: 
        !          4561:     if(startup==NULL) {
        !          4562:        sbbs_beep(100,500);
        !          4563:        fprintf(stderr, "No startup structure passed!\n");
        !          4564:        return;
        !          4565:     }
        !          4566: 
        !          4567:        if(startup->size!=sizeof(ftp_startup_t)) {      /* verify size */
        !          4568:                sbbs_beep(100,500);
        !          4569:                sbbs_beep(300,500);
        !          4570:                sbbs_beep(100,500);
        !          4571:                fprintf(stderr, "Invalid startup structure!\n");
        !          4572:                return;
        !          4573:        }
        !          4574: 
        !          4575:        /* Setup intelligent defaults */
        !          4576:        if(startup->port==0)                                    startup->port=IPPORT_FTP;
        !          4577:        if(startup->qwk_timeout==0)                             startup->qwk_timeout=600;               /* seconds */
        !          4578:        if(startup->max_inactivity==0)                  startup->max_inactivity=300;    /* seconds */
        !          4579:        if(startup->sem_chk_freq==0)                    startup->sem_chk_freq=2;                /* seconds */
        !          4580:        if(startup->index_file_name[0]==0)              SAFECOPY(startup->index_file_name,"00index");
        !          4581:        if(startup->html_index_file[0]==0)              SAFECOPY(startup->html_index_file,"00index.html");
        !          4582:        if(startup->html_index_script[0]==0) {  SAFECOPY(startup->html_index_script,"ftp-html.js");
        !          4583:                                                                                        startup->options|=FTP_OPT_HTML_INDEX_FILE;
        !          4584:        }
        !          4585:        if(startup->options&FTP_OPT_HTML_INDEX_FILE)
        !          4586:                startup->options&=~FTP_OPT_NO_JAVASCRIPT;
        !          4587:        else
        !          4588:                startup->options|=FTP_OPT_NO_JAVASCRIPT;
        !          4589: #ifdef JAVASCRIPT
        !          4590:        if(startup->js.max_bytes==0)                    startup->js.max_bytes=JAVASCRIPT_MAX_BYTES;
        !          4591:        if(startup->js.cx_stack==0)                             startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK;
        !          4592: 
        !          4593:        ZERO_VAR(js_server_props);
        !          4594:        SAFEPRINTF2(js_server_props.version,"%s %s",FTP_SERVER,revision);
        !          4595:        js_server_props.version_detail=ftp_ver();
        !          4596:        js_server_props.clients=&active_clients;
        !          4597:        js_server_props.options=&startup->options;
        !          4598:        js_server_props.interface_addr=&startup->interface_addr;
        !          4599: #endif
        !          4600: 
        !          4601: 
        !          4602:        uptime=0;
        !          4603:        served=0;
        !          4604:        startup->recycle_now=FALSE;
        !          4605:        startup->shutdown_now=FALSE;
        !          4606:        terminate_server=FALSE;
        !          4607: 
        !          4608:        do {
        !          4609: 
        !          4610:                thread_up(FALSE /* setuid */);
        !          4611: 
        !          4612:                status("Initializing");
        !          4613: 
        !          4614:                memset(&scfg, 0, sizeof(scfg));
        !          4615: 
        !          4616:                lprintf(LOG_INFO,"Synchronet FTP Server Revision %s%s"
        !          4617:                        ,revision
        !          4618: #ifdef _DEBUG
        !          4619:                        ," Debug"
        !          4620: #else
        !          4621:                        ,""
        !          4622: #endif
        !          4623:                        );
        !          4624: 
        !          4625:                DESCRIBE_COMPILER(compiler);
        !          4626: 
        !          4627:                lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler);
        !          4628: 
        !          4629:                sbbs_srand();   /* Seed random number generator */
        !          4630: 
        !          4631:                if(!winsock_startup()) {
        !          4632:                        cleanup(1,__LINE__);
        !          4633:                        return;
        !          4634:                }
        !          4635: 
        !          4636:                t=time(NULL);
        !          4637:                lprintf(LOG_INFO,"Initializing on %.24s with options: %lx"
        !          4638:                        ,CTIME_R(&t,str),startup->options);
        !          4639: 
        !          4640:                /* Initial configuration and load from CNF files */
        !          4641:                SAFECOPY(scfg.ctrl_dir, startup->ctrl_dir);
        !          4642:                lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
        !          4643:                scfg.size=sizeof(scfg);
        !          4644:                SAFECOPY(error,UNKNOWN_LOAD_ERROR);
        !          4645:                if(!load_cfg(&scfg, text, TRUE, error)) {
        !          4646:                        lprintf(LOG_ERR,"!ERROR %s",error);
        !          4647:                        lprintf(LOG_ERR,"!Failed to load configuration files");
        !          4648:                        cleanup(1,__LINE__);
        !          4649:                        return;
        !          4650:                }
        !          4651: 
        !          4652:                if(startup->host_name[0]==0)
        !          4653:                        SAFECOPY(startup->host_name,scfg.sys_inetaddr);
        !          4654: 
        !          4655:                if(!(scfg.sys_misc&SM_LOCAL_TZ) && !(startup->options&FTP_OPT_LOCAL_TIMEZONE)) { 
        !          4656:                        if(putenv("TZ=UTC0"))
        !          4657:                                lprintf(LOG_ERR,"!putenv() FAILED");
        !          4658:                        tzset();
        !          4659: 
        !          4660:                        if((t=checktime())!=0) {   /* Check binary time */
        !          4661:                                lprintf(LOG_ERR,"!TIME PROBLEM (%ld)",t);
        !          4662:                                cleanup(1,__LINE__);
        !          4663:                                return;
        !          4664:                        }
        !          4665:                }
        !          4666: 
        !          4667:                if(uptime==0)
        !          4668:                        uptime=time(NULL);      /* this must be done *after* setting the timezone */
        !          4669: 
        !          4670:                if(startup->temp_dir[0])
        !          4671:                        SAFECOPY(scfg.temp_dir,startup->temp_dir);
        !          4672:                else
        !          4673:                        SAFECOPY(scfg.temp_dir,"../temp");
        !          4674:                prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
        !          4675:                MKDIR(scfg.temp_dir);
        !          4676:                lprintf(LOG_DEBUG,"Temporary file directory: %s", scfg.temp_dir);
        !          4677:                if(!isdir(scfg.temp_dir)) {
        !          4678:                        lprintf(LOG_ERR,"!Invalid temp directory: %s", scfg.temp_dir);
        !          4679:                        cleanup(1,__LINE__);
        !          4680:                        return;
        !          4681:                }
        !          4682: 
        !          4683:                if(!startup->max_clients) {
        !          4684:                        startup->max_clients=scfg.sys_nodes;
        !          4685:                        if(startup->max_clients<10)
        !          4686:                                startup->max_clients=10;
        !          4687:                }
        !          4688:                lprintf(LOG_DEBUG,"Maximum clients: %d",startup->max_clients);
        !          4689: 
        !          4690:                /* Sanity-check the passive port range */
        !          4691:                if(startup->pasv_port_low || startup->pasv_port_high) {
        !          4692:                        if(startup->pasv_port_low > startup->pasv_port_high
        !          4693:                                || startup->pasv_port_high-startup->pasv_port_low < (startup->max_clients-1)) {
        !          4694:                                lprintf(LOG_WARNING,"!Correcting Passive Port Range (Low: %u, High: %u)"
        !          4695:                                        ,startup->pasv_port_low,startup->pasv_port_high);
        !          4696:                                if(startup->pasv_port_low)
        !          4697:                                        startup->pasv_port_high = startup->pasv_port_low+(startup->max_clients-1);
        !          4698:                                else
        !          4699:                                        startup->pasv_port_low = startup->pasv_port_high-(startup->max_clients-1);
        !          4700:                        }
        !          4701:                        lprintf(LOG_DEBUG,"Passive Port Low: %u",startup->pasv_port_low);
        !          4702:                        lprintf(LOG_DEBUG,"Passive Port High: %u",startup->pasv_port_high);
        !          4703:                }
        !          4704: 
        !          4705:                lprintf(LOG_DEBUG,"Maximum inactivity: %d seconds",startup->max_inactivity);
        !          4706: 
        !          4707:                active_clients=0, update_clients();
        !          4708: 
        !          4709:                strlwr(scfg.sys_id); /* Use lower-case unix-looking System ID for group name */
        !          4710: 
        !          4711:                for(i=0;i<scfg.total_libs;i++) {
        !          4712:                        strlwr(scfg.lib[i]->sname);
        !          4713:                        dotname(scfg.lib[i]->sname,scfg.lib[i]->sname);
        !          4714:                }
        !          4715: #if 0  /* this is now handled by load_cfg()->prep_cfg() */
        !          4716:                for(i=0;i<scfg.total_dirs;i++) 
        !          4717:                        strlwr(scfg.dir[i]->code_suffix);
        !          4718: #endif
        !          4719:                /* open a socket and wait for a client */
        !          4720: 
        !          4721:                if((server_socket=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) {
        !          4722:                        lprintf(LOG_ERR,"!ERROR %d opening socket", ERROR_VALUE);
        !          4723:                        cleanup(1,__LINE__);
        !          4724:                        return;
        !          4725:                }
        !          4726: 
        !          4727:                lprintf(LOG_DEBUG,"%04d FTP Server socket opened",server_socket);
        !          4728: 
        !          4729:                /*****************************/
        !          4730:                /* Listen for incoming calls */
        !          4731:                /*****************************/
        !          4732:                memset(&server_addr, 0, sizeof(server_addr));
        !          4733: 
        !          4734:                server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
        !          4735:                server_addr.sin_family = AF_INET;
        !          4736:                server_addr.sin_port   = htons(startup->port);
        !          4737: 
        !          4738:                if(startup->seteuid!=NULL)
        !          4739:                        startup->seteuid(FALSE);
        !          4740:                result=retry_bind(server_socket, (struct sockaddr *) &server_addr,sizeof(server_addr)
        !          4741:                        ,startup->bind_retry_count,startup->bind_retry_delay,"FTP Server",lprintf);
        !          4742:                if(startup->seteuid!=NULL)
        !          4743:                        startup->seteuid(TRUE);
        !          4744:                if(result!=0) {
        !          4745:                        lprintf(LOG_ERR,"%04d %s", server_socket, BIND_FAILURE_HELP);
        !          4746:                        cleanup(1,__LINE__);
        !          4747:                        return;
        !          4748:                }
        !          4749: 
        !          4750:                if((result=listen(server_socket, 1))!= 0) {
        !          4751:                        lprintf(LOG_ERR,"%04d !ERROR %d (%d) listening on socket"
        !          4752:                                ,server_socket, result, ERROR_VALUE);
        !          4753:                        cleanup(1,__LINE__);
        !          4754:                        return;
        !          4755:                }
        !          4756: 
        !          4757:                lprintf(LOG_NOTICE,"%04d FTP Server thread started on port %d",server_socket,startup->port);
        !          4758:                status(STATUS_WFC);
        !          4759: 
        !          4760:                /* Setup recycle/shutdown semaphore file lists */
        !          4761:                shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","ftp");
        !          4762:                recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","ftp");
        !          4763:                SAFEPRINTF(path,"%sftpsrvr.rec",scfg.ctrl_dir); /* legacy */
        !          4764:                semfile_list_add(&recycle_semfiles,path);
        !          4765:                if(!initialized) {
        !          4766:                        initialized=time(NULL);
        !          4767:                        semfile_list_check(&initialized,recycle_semfiles);
        !          4768:                        semfile_list_check(&initialized,shutdown_semfiles);
        !          4769:                }
        !          4770: 
        !          4771: 
        !          4772:                /* signal caller that we've started up successfully */
        !          4773:                if(startup->started!=NULL)
        !          4774:                startup->started(startup->cbdata);
        !          4775: 
        !          4776:                while(server_socket!=INVALID_SOCKET && !terminate_server) {
        !          4777: 
        !          4778:                        if(active_clients==0) {
        !          4779:                                if(!(startup->options&FTP_OPT_NO_RECYCLE)) {
        !          4780:                                        if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
        !          4781:                                                lprintf(LOG_INFO,"0000 Recycle semaphore file (%s) detected",p);
        !          4782:                                                break;
        !          4783:                                        }
        !          4784: #if 0  /* unused */
        !          4785:                                        if(startup->recycle_sem!=NULL && sem_trywait(&startup->recycle_sem)==0)
        !          4786:                                                startup->recycle_now=TRUE;
        !          4787: #endif
        !          4788:                                        if(startup->recycle_now==TRUE) {
        !          4789:                                                lprintf(LOG_NOTICE,"0000 Recycle semaphore signaled");
        !          4790:                                                startup->recycle_now=FALSE;
        !          4791:                                                break;
        !          4792:                                        }
        !          4793:                                }
        !          4794:                                if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL
        !          4795:                                                && lprintf(LOG_INFO,"0000 Shutdown semaphore file (%s) detected",p))
        !          4796:                                        || (startup->shutdown_now==TRUE
        !          4797:                                                && lprintf(LOG_INFO,"0000 Shutdown semaphore signaled"))) {
        !          4798:                                        startup->shutdown_now=FALSE;
        !          4799:                                        terminate_server=TRUE;
        !          4800:                                        break;
        !          4801:                                }
        !          4802:                        }
        !          4803:                        /* now wait for connection */
        !          4804: 
        !          4805:                        tv.tv_sec=startup->sem_chk_freq;
        !          4806:                        tv.tv_usec=0;
        !          4807: 
        !          4808:                        FD_ZERO(&socket_set);
        !          4809:                        FD_SET(server_socket,&socket_set);
        !          4810: 
        !          4811:                        if((i=select(server_socket+1,&socket_set,NULL,NULL,&tv))<1) {
        !          4812:                                if(i==0)
        !          4813:                                        continue;
        !          4814:                                if(ERROR_VALUE==EINTR)
        !          4815:                                        lprintf(LOG_DEBUG,"%04d FTP Server listening interrupted", server_socket);
        !          4816:                                else if(ERROR_VALUE == ENOTSOCK)
        !          4817:                        lprintf(LOG_NOTICE,"%04d FTP Server socket closed", server_socket);
        !          4818:                                else
        !          4819:                                        lprintf(LOG_WARNING,"%04d !ERROR %d selecting socket",server_socket, ERROR_VALUE);
        !          4820:                                continue;
        !          4821:                        }
        !          4822: 
        !          4823:                        if(server_socket==INVALID_SOCKET || terminate_server)   /* terminated */
        !          4824:                                break;
        !          4825: 
        !          4826:                        client_addr_len = sizeof(client_addr);
        !          4827:                        client_socket = accept(server_socket, (struct sockaddr *)&client_addr
        !          4828:                        ,&client_addr_len);
        !          4829: 
        !          4830:                        if(client_socket == INVALID_SOCKET)
        !          4831:                        {
        !          4832: #if 0  /* is this necessary still? */
        !          4833:                                if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINTR || ERROR_VALUE == EINVAL) {
        !          4834:                        lprintf(LOG_NOTICE,"0000 FTP socket closed while listening");
        !          4835:                                        break;
        !          4836:                                }
        !          4837: #endif
        !          4838:                                lprintf(LOG_WARNING,"%04d !ERROR %d accepting connection"
        !          4839:                                        ,server_socket, ERROR_VALUE);
        !          4840: #ifdef _WIN32
        !          4841:                                if(WSAGetLastError()==WSAENOBUFS)       /* recycle (re-init WinSock) on this error */
        !          4842:                                        break;
        !          4843: #endif
        !          4844:                                continue;
        !          4845:                        }
        !          4846:                        if(startup->socket_open!=NULL)
        !          4847:                                startup->socket_open(startup->cbdata,TRUE);
        !          4848:                        sockets++;
        !          4849: 
        !          4850:                        if(trashcan(&scfg,inet_ntoa(client_addr.sin_addr),"ip-silent")) {
        !          4851:                                ftp_close_socket(&client_socket,__LINE__);
        !          4852:                                continue;
        !          4853:                        }
        !          4854: 
        !          4855:                        if(active_clients>=startup->max_clients) {
        !          4856:                                lprintf(LOG_WARNING,"%04d !MAXIMUM CLIENTS (%d) reached, access denied"
        !          4857:                                        ,client_socket, startup->max_clients);
        !          4858:                                sockprintf(client_socket,"421 Maximum active clients reached, please try again later.");
        !          4859:                                mswait(3000);
        !          4860:                                ftp_close_socket(&client_socket,__LINE__);
        !          4861:                                continue;
        !          4862:                        }
        !          4863: 
        !          4864:                        if((ftp=malloc(sizeof(ftp_t)))==NULL) {
        !          4865:                                lprintf(LOG_CRIT,"%04d !ERROR allocating %d bytes of memory for ftp_t"
        !          4866:                                        ,client_socket,sizeof(ftp_t));
        !          4867:                                sockprintf(client_socket,"421 System error, please try again later.");
        !          4868:                                mswait(3000);
        !          4869:                                ftp_close_socket(&client_socket,__LINE__);
        !          4870:                                continue;
        !          4871:                        }
        !          4872: 
        !          4873:                        ftp->socket=client_socket;
        !          4874:                        ftp->client_addr=client_addr;
        !          4875: 
        !          4876:                        _beginthread (ctrl_thread, 0, ftp);
        !          4877:                        served++;
        !          4878:                }
        !          4879: 
        !          4880: #ifdef _DEBUG
        !          4881:                lprintf(LOG_DEBUG,"0000 server_socket: %d",server_socket);
        !          4882:                lprintf(LOG_DEBUG,"0000 terminate_server: %d",terminate_server);
        !          4883: #endif
        !          4884:                if(active_clients) {
        !          4885:                        lprintf(LOG_DEBUG,"%04d Waiting for %d active clients to disconnect..."
        !          4886:                                ,server_socket, active_clients);
        !          4887:                        start=time(NULL);
        !          4888:                        while(active_clients) {
        !          4889:                                if(time(NULL)-start>startup->max_inactivity) {
        !          4890:                                        lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d active clients"
        !          4891:                                                ,server_socket, active_clients);
        !          4892:                                        break;
        !          4893:                                }
        !          4894:                                mswait(100);
        !          4895:                        }
        !          4896:                }
        !          4897: 
        !          4898:                if(thread_count>1) {
        !          4899:                        lprintf(LOG_DEBUG,"%04d Waiting for %d threads to terminate..."
        !          4900:                                ,server_socket, thread_count-1);
        !          4901:                        start=time(NULL);
        !          4902:                        while(thread_count>1) {
        !          4903:                                if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
        !          4904:                                        lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d threads"
        !          4905:                                                ,server_socket, thread_count-1);
        !          4906:                                        break;
        !          4907:                                }
        !          4908:                                mswait(100);
        !          4909:                        }
        !          4910:                }
        !          4911: 
        !          4912:                cleanup(0,__LINE__);
        !          4913: 
        !          4914:                if(!terminate_server) {
        !          4915:                        lprintf(LOG_INFO,"Recycling server...");
        !          4916:                        mswait(2000);
        !          4917:                        if(startup->recycle!=NULL)
        !          4918:                                startup->recycle(startup->cbdata);
        !          4919:                }
        !          4920: 
        !          4921:        } while(!terminate_server);
        !          4922: }

unix.superglobalmegacorp.com

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