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

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

unix.superglobalmegacorp.com

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