Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* ftpsrvr.c */
/* Synchronet FTP server */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
/* Platform-specific headers */
#ifdef _WIN32
#include <share.h> /* SH_DENYNO */
#include <direct.h> /* _mkdir/_rmdir() */
#include <process.h> /* _beginthread */
#include <windows.h> /* required for mmsystem.h */
#include <mmsystem.h> /* SND_ASYNC */
#elif defined(__unix__)
#include <signal.h> /* signal/SIGPIPE */
#include <stdlib.h> /* ltoa in GNU C lib */
#include <stdarg.h> /* va_list, varargs */
#include <string.h> /* strrchr */
#include <fcntl.h> /* O_WRONLY, O_RDONLY, etc. */
#include <errno.h> /* EACCES */
#include <ctype.h> /* toupper */
#include <sys/stat.h> /* S_IWRITE */
#include "sbbs.h"
#include "telnet.h"
/* Constants */
#define FTP_SERVER "Synchronet FTP Server"
#else
#define FTP_VERSION "1.05"
#endif
#define STATUS_WFC "Listening"
#define ANONYMOUS "anonymous"
#define BBS_VIRTUAL_PATH "bbs:/""/" /* this is actually bbs:<slash><slash> */
#define LOCAL_FSYS_DIR "local:"
#define BBS_FSYS_DIR "bbs:"
#define TIMEOUT_THREAD_WAIT 15 /* Seconds */
#define TIMEOUT_SOCKET_LISTEN 30 /* Seconds */
#define XFER_REPORT_INTERVAL 60 /* Seconds */
#define INDEX_FNAME_LEN 15
#define NAME_LEN 15 /* User name length for listings */
static ftp_startup_t* startup=NULL;
static scfg_t scfg;
static SOCKET server_socket=INVALID_SOCKET;
static DWORD active_clients=0;
static DWORD sockets=0;
static HANDLE socket_mutex=NULL;
static time_t uptime=0;
static BOOL recycle_server=FALSE;
static BYTE socket_debug[0x10000]={0};
#define SOCKET_DEBUG_CTRL (1<<0) // 0x01
#define SOCKET_DEBUG_SEND (1<<1) // 0x02
#define SOCKET_DEBUG_READLINE (1<<2) // 0x04
#define SOCKET_DEBUG_ACCEPT (1<<3) // 0x08
#define SOCKET_DEBUG_TERMINATE (1<<5) // 0x20
#define SOCKET_DEBUG_RECV_CHAR (1<<6) // 0x40
typedef struct {
SOCKET socket;
SOCKADDR_IN client_addr;
} ftp_t;
static const char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
,"Jul","Aug","Sep","Oct","Nov","Dec"};
BOOL direxist(char *dir)
{
if(access(dir,0)==0)
return(TRUE);
else
return(FALSE);
}
BOOL dir_op(scfg_t* cfg, user_t* user, uint dirnum)
{
return(user->level>=SYSOP_LEVEL || user->exempt&FLAG('R')
|| (cfg->dir[dirnum]->op_ar[0] && chk_ar(cfg,cfg->dir[dirnum]->op_ar,user)));
}
static int lprintf(char *fmt, ...)
{
int result;
va_list argptr;
char sbuf[1024];
if(startup==NULL || startup->lputs==NULL)
#if defined(_WIN32) && defined(_DEBUG)
if(IsBadCodePtr((FARPROC)startup->lputs)) {
DebugBreak();

rswindell
committed
return(0);

rswindell
committed
#endif
va_start(argptr,fmt);
vsprintf(sbuf,fmt,argptr);
va_end(argptr);
result=startup->lputs(sbuf);
return(result);
}
#ifdef _WINSOCKAPI_
static WSADATA WSAData;
static BOOL WSAInitialized=FALSE;
static BOOL winsock_startup(void)
{
int status; /* Status Code */
if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
lprintf("%s %s",WSAData.szDescription, WSAData.szSystemStatus);
WSAInitialized=TRUE;
return (TRUE);
}
lprintf("!WinSock startup ERROR %d", status);
return (FALSE);
}
#else /* No WINSOCK */
#define winsock_startup() (TRUE)
#endif
static void status(char* str)
{
if(startup!=NULL && startup->status!=NULL)
startup->status(str);
}
static void update_clients(void)
{
if(startup!=NULL && startup->clients!=NULL)
startup->clients(active_clients);
}
static void client_on(SOCKET sock, client_t* client, BOOL update)
{
if(startup!=NULL && startup->client_on!=NULL)
startup->client_on(TRUE,sock,client,update);
}
static void client_off(SOCKET sock)
{
if(startup!=NULL && startup->client_on!=NULL)
startup->client_on(FALSE,sock,NULL,FALSE);
static void thread_up(BOOL setuid)
if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(TRUE);
if(setuid && startup!=NULL && startup->setuid!=NULL)
startup->setuid();
}
static void thread_down(void)
{
if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(FALSE);
}

rswindell
committed
static SOCKET ftp_open_socket(int type)
sock=socket(AF_INET, type, IPPROTO_IP);
if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(TRUE);
if(sock!=INVALID_SOCKET) {
sockets++;
#ifdef _DEBUG
lprintf("%04d Socket opened (%u sockets in use)",sock,sockets);
#endif
}
return(sock);
}
#ifdef __BORLANDC__
#pragma argsused
#endif

rswindell
committed
static int ftp_close_socket(SOCKET* sock, int line)
if((result=WaitForSingleObject(socket_mutex,5000))!=WAIT_OBJECT_0)
lprintf("%04d !ERROR %d getting socket mutex from line %u"
,*sock,ERROR_VALUE,line);
if(IsBadWritePtr(sock,sizeof(SOCKET))) {
ReleaseMutex(socket_mutex);
lprintf("0000 !BAD socket pointer in close_socket from line %u",line);
if((*sock)==INVALID_SOCKET) {
ReleaseMutex(socket_mutex);
lprintf("0000 !INVALID_SOCKET in close_socket from line %u",line);
shutdown(*sock,SHUT_RDWR); /* required on Unix */
if(result==0 && startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(FALSE);
sockets--;

rswindell
committed
if(result!=0) {
if(ERROR_VALUE!=ENOTSOCK)
lprintf("%04d !ERROR %d closing socket from line %u",*sock,ERROR_VALUE,line);

rswindell
committed
}

rswindell
committed
else
lprintf("%04d Socket closed (%u sockets in use) from line %u",*sock,sockets,line);
#endif
*sock=INVALID_SOCKET;
ReleaseMutex(socket_mutex);
return(result);
}
static int sockprintf(SOCKET sock, char *fmt, ...)
{
int len;
int result;
va_list argptr;
char sbuf[1024];
fd_set socket_set;
struct timeval tv;
va_start(argptr,fmt);
len=vsprintf(sbuf,fmt,argptr);
if(startup!=NULL && startup->options&FTP_OPT_DEBUG_TX)
lprintf("%04d TX: %s", sock, sbuf);
strcat(sbuf,"\r\n");
len+=2;
va_end(argptr);
/* Check socket for writability (using select) */
tv.tv_sec=60;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(sock,&socket_set);
if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) {
lprintf("%04d !ERROR %d (%d) selecting socket for send"
,sock, result, ERROR_VALUE, sock);
return(0);
}
while((result=sendsocket(sock,sbuf,len))!=len) {
lprintf("%04d Connection reset by peer on send",sock);
else if(ERROR_VALUE==ECONNABORTED)
lprintf("%04d Connection aborted by peer on send",sock);
else
lprintf("%04d !ERROR %d sending",sock,ERROR_VALUE);
return(0);
}
lprintf("%04d !ERROR: short send: %u instead of %u",sock,result,len);
}
return(len);
}
/************************************************/
/* Truncates white-space chars off end of 'str' */
/************************************************/

rswindell
committed
static void truncsp(char *str)
{
uint c;
c=strlen(str);
while(c && (uchar)str[c-1]<=' ') c--;
str[c]=0;
}
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/* Returns the directory index of a virtual lib/dir path (e.g. main/games/filename) */
int getdir(char* p, user_t* user)
{
char* tp;
char path[MAX_PATH+1];
int dir;
int lib;
sprintf(path,"%.*s",(int)sizeof(path)-1,p);
p=path;
if(*p=='/')
p++;
else if(!strncmp(p,"./",2))
p+=2;
tp=strchr(p,'/');
if(tp) *tp=0;
for(lib=0;lib<scfg.total_libs;lib++) {
if(!chk_ar(&scfg,scfg.lib[lib]->ar,user))
continue;
if(!stricmp(scfg.lib[lib]->sname,p))
break;
}
if(lib>=scfg.total_libs)
return(-1);
if(tp!=NULL)
p=tp+1;
tp=strchr(p,'/');
if(tp) *tp=0;
for(dir=0;dir<scfg.total_dirs;dir++) {
if(scfg.dir[dir]->lib!=lib)
continue;
if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir
&& !chk_ar(&scfg,scfg.dir[dir]->ar,user))
continue;
if(!stricmp(scfg.dir[dir]->code,p))
break;
}
if(dir>=scfg.total_dirs)
return(-1);
return(dir);
}
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
/*********************************/
/* JavaScript Data and Functions */
/*********************************/
#ifdef JAVASCRIPT
static JSBool
js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
uintN i;
JSString * str;
FILE* fp;
if((fp=(FILE*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
for (i = 0; i < argc; i++) {
str = JS_ValueToString(cx, argv[i]);
if (!str)
return JS_FALSE;
fprintf(fp,"%s",JS_GetStringBytes(str));
}
return(JS_TRUE);
}
static JSFunctionSpec js_global_functions[] = {
{"write", js_write, 1}, /* write to HTML file */
{0}
};
static void
js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{
char line[64];
char file[MAX_PATH+1];
char* warning;
FILE* fp;
fp=(FILE*)JS_GetContextPrivate(cx);
if(report==NULL) {
lprintf("!JavaScript: %s", message);
if(fp!=NULL)
fprintf(fp,"!JavaScript: %s", message);
return;
}
if(report->filename)
sprintf(file," %s",report->filename);
else
file[0]=0;
if(report->lineno)
sprintf(line," line %u",report->lineno);
else
line[0]=0;
if(JSREPORT_IS_WARNING(report->flags)) {
if(JSREPORT_IS_STRICT(report->flags))
warning="strict warning";
else
warning="warning";
} else
warning="";
lprintf("!JavaScript %s%s%s: %s",warning,file,line,message);
if(fp!=NULL)
fprintf(fp,"!JavaScript %s%s%s: %s",warning,file,line,message);
static JSClass js_server_class = {
"FtpServer",0,
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub
};
static JSClass js_ftp_class = {
"Ftp",0,
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub
};

rswindell
committed
js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp)
{
char ver[256];
JSContext* js_cx;
JSObject* js_glob;
JSObject* server;

rswindell
committed
lprintf("%04d JavaScript: Initializing context (stack: %lu bytes)"
,sock,JAVASCRIPT_CONTEXT_STACK);

rswindell
committed
if((js_cx = JS_NewContext(runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
lprintf("%04d JavaScript: Context created",sock);
JS_SetErrorReporter(js_cx, js_ErrorReporter);
lprintf("%04d JavaScript: Initializing Global object",sock);
if((js_glob=js_CreateGlobalObject(js_cx, &scfg))==NULL)
if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
break;
lprintf("%04d JavaScript: Initializing System object",sock);
if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime)==NULL)
break;
if((*ftp=JS_DefineObject(js_cx, js_glob, "ftp", &js_ftp_class
,NULL,0))==NULL)
break;
if((server=JS_DefineObject(js_cx, js_glob, "server", &js_server_class
,NULL,0))==NULL)
sprintf(ver,"%s v%s",FTP_SERVER,FTP_VERSION);
val = STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, ver));
if(!JS_SetProperty(js_cx, server, "version", &val))
break;
val = STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, ftp_ver()));
if(!JS_SetProperty(js_cx, server, "version_detail", &val))
break;
if(glob!=NULL)
*glob=js_glob;
success=TRUE;
} while(0);
if(!success) {
JS_DestroyContext(js_cx);
return(NULL);
}
return(js_cx);
}
static JSClass js_file_class = {

rswindell
committed
"FtpFile",0,
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub
};
BOOL js_add_file(JSContext* js_cx, JSObject* array,
char* name, char* desc, char* ext_desc,
ulong size, ulong credits,
time_t time, time_t uploaded, time_t last_downloaded,
ulong times_downloaded, ulong misc,
char* uploader, char* link)

rswindell
committed
jsuint index;
if((file=JS_NewObject(js_cx, &js_file_class, NULL, NULL))==NULL)
return(FALSE);
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, name));
if(!JS_SetProperty(js_cx, file, "name", &val))
return(FALSE);
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, desc));
if(!JS_SetProperty(js_cx, file, "description", &val))
return(FALSE);
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, ext_desc));
if(!JS_SetProperty(js_cx, file, "extended_description", &val))
return(FALSE);
val=INT_TO_JSVAL(size);
if(!JS_SetProperty(js_cx, file, "size", &val))
return(FALSE);
val=INT_TO_JSVAL(credits);
if(!JS_SetProperty(js_cx, file, "credits", &val))
return(FALSE);
val=INT_TO_JSVAL(time);
if(!JS_SetProperty(js_cx, file, "time", &val))
return(FALSE);
val=INT_TO_JSVAL(uploaded);
if(!JS_SetProperty(js_cx, file, "uploaded", &val))
return(FALSE);
val=INT_TO_JSVAL(last_downloaded);
if(!JS_SetProperty(js_cx, file, "last_downloaded", &val))
return(FALSE);
val=INT_TO_JSVAL(times_downloaded);
if(!JS_SetProperty(js_cx, file, "times_downloaded", &val))
return(FALSE);
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, uploader));
if(!JS_SetProperty(js_cx, file, "uploader", &val))
return(FALSE);
val=INT_TO_JSVAL(misc);
if(!JS_SetProperty(js_cx, file, "settings", &val))
return(FALSE);
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, link));
if(!JS_SetProperty(js_cx, file, "link", &val))
return(FALSE);
if(!JS_GetArrayLength(js_cx, array, &index))
return(FALSE);
val=OBJECT_TO_JSVAL(file);
return(JS_SetElement(js_cx, array, index, &val));
}
BOOL js_generate_index(JSContext* js_cx, JSObject* parent,
SOCKET sock, FILE* fp, int lib, int dir, user_t* user)
{
char str[256];
char path[MAX_PATH+1];
char spath[MAX_PATH+1]; /* script path */
char vpath[MAX_PATH+1]; /* virtual path */
char aliasfile[MAX_PATH+1];
char extdesc[513];
BOOL alias_dir;
BOOL success=FALSE;
FILE* alias_fp;
uint i;
file_t f;
glob_t g;
jsval val;
jsval rval;
JSObject* lib_obj=NULL;
JSObject* dir_obj=NULL;
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
JSObject* file_array=NULL;
JSObject* dir_array=NULL;
JSScript* js_script=NULL;
JS_SetContextPrivate(js_cx, fp);
do { /* pseudo try/catch */
if((file_array=JS_NewArrayObject(js_cx, 0, NULL))==NULL) {
lprintf("%04d !JavaScript FAILED to create file_array",sock);
break;
}
if((dir_array=JS_NewArrayObject(js_cx, 0, NULL))==NULL) {
lprintf("%04d !JavaScript FAILED to create dir_array",sock);
break;
}
/* Add extension if not specified */
if(!strchr(startup->html_index_script,BACKSLASH))
sprintf(spath,"%s%s",scfg.exec_dir,startup->html_index_script);
else
sprintf(spath,"%.*s",sizeof(spath)-4,startup->html_index_script);
if(!strchr(spath,'.'))
strcat(spath,".js");
if(!fexist(spath)) {
lprintf("%04d !HTML JavaScript (%s) doesn't exist",sock,spath);
break;
}
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, startup->html_index_file));
if(!JS_SetProperty(js_cx, parent, "html_index_file", &val)) {
lprintf("%04d !JavaScript FAILED to set html_index_file property",sock);
break;
}
/* file[] */
if(!JS_SetProperty(js_cx, parent, "file_list", &val)) {
lprintf("%04d !JavaScript FAILED to set file property",sock);
break;
}
/* dir[] */
if(!JS_SetProperty(js_cx, parent, "dir_list", &val)) {
lprintf("%04d !JavaScript FAILED to set dir property",sock);
break;
}
/* curlib */

rswindell
committed
if((lib_obj=JS_NewObject(js_cx, &js_file_class, 0, NULL))==NULL) {
lprintf("%04d !JavaScript FAILED to create lib_obj",sock);
break;
}
val=OBJECT_TO_JSVAL(lib_obj);
if(!JS_SetProperty(js_cx, parent, "curlib", &val)) {
lprintf("%04d !JavaScript FAILED to set curlib property",sock);
break;
/* curdir */

rswindell
committed
if((dir_obj=JS_NewObject(js_cx, &js_file_class, 0, NULL))==NULL) {
lprintf("%04d !JavaScript FAILED to create dir_obj",sock);
val=OBJECT_TO_JSVAL(dir_obj);
if(!JS_SetProperty(js_cx, parent, "curdir", &val)) {
lprintf("%04d !JavaScript FAILED to set curdir property",sock);
strcpy(vpath,"/");
if(lib>=0) { /* root */
strcat(vpath,scfg.lib[lib]->sname);
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, scfg.lib[lib]->sname));
if(!JS_SetProperty(js_cx, lib_obj, "name", &val)) {
lprintf("%04d !JavaScript FAILED to set curlib.name property",sock);
break;
}
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, scfg.lib[lib]->lname));
if(!JS_SetProperty(js_cx, lib_obj, "description", &val)) {
lprintf("%04d !JavaScript FAILED to set curlib.desc property",sock);
break;
}
if(dir>=0) { /* 1st level */
strcat(vpath,scfg.dir[dir]->code);
strcat(vpath,"/");
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, scfg.dir[dir]->code));
if(!JS_SetProperty(js_cx, dir_obj, "code", &val)) {
lprintf("%04d !JavaScript FAILED to set curdir.code property",sock);
break;
}
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, scfg.dir[dir]->sname));
if(!JS_SetProperty(js_cx, dir_obj, "name", &val)) {
lprintf("%04d !JavaScript FAILED to set curdir.name property",sock);
break;
}
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, scfg.dir[dir]->lname));
if(!JS_SetProperty(js_cx, dir_obj, "description", &val)) {
lprintf("%04d !JavaScript FAILED to set curdir.desc property",sock);
break;
}
val=INT_TO_JSVAL(scfg.dir[dir]->misc);
if(!JS_SetProperty(js_cx, dir_obj, "settings", &val)) {
lprintf("%04d !JavaScript FAILED to set curdir.misc property",sock);
break;
}
}
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, vpath));
if(!JS_SetProperty(js_cx, parent, "path", &val)) {
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
lprintf("%04d !JavaScript FAILED to set curdir property",sock);
break;
}
if(lib<0) { /* root dir */
/* File Aliases */
sprintf(path,"%sftpalias.cfg",scfg.ctrl_dir);
if((alias_fp=fopen(path,"r"))!=NULL) {
while(!feof(alias_fp)) {
if(!fgets(aliasline,sizeof(aliasline)-1,alias_fp))
break;
p=aliasline; /* alias pointer */
while(*p && *p<=' ') p++;
if(*p==';') /* comment */
continue;
tp=p; /* terminator pointer */
while(*tp && *tp>' ') tp++;
if(*tp) *tp=0;
np=tp+1; /* filename pointer */
while(*np && *np<=' ') np++;
tp=np; /* terminator pointer */
while(*tp && *tp>' ') tp++;
if(*tp) *tp=0;
dp=tp+1; /* description pointer */
while(*dp && *dp<=' ') dp++;
truncsp(dp);
alias_dir=FALSE;
/* Virtual Path? */
if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),user))<0)
continue; /* No access or invalid virtual path */
tp=strrchr(np,'/');
if(tp==NULL)
continue;
tp++;
if(*tp) {
sprintf(aliasfile,"%s%s",scfg.dir[dir]->path,tp);
np=aliasfile;
}
else
alias_dir=TRUE;
}
if(!alias_dir && !fexist(np))
continue;
if(alias_dir) {
if(!chk_ar(&scfg,scfg.dir[dir]->ar,user))
continue;
sprintf(vpath,"/%s/%s",p,startup->html_index_file);
strcpy(vpath,p);
,alias_dir ? dir_array : file_array
,dp /* description */
,NULL /* extdesc */
,flength(np) /* size */
,fdate(np) /* time */
,fdate(np) /* uploaded */
,0 /* last downloaded */
,0 /* times downloaded */
,0 /* misc */
,vpath /* link */
);
}
fclose(alias_fp);
}
/* QWK Packet */
if(startup->options&FTP_OPT_ALLOW_QWK /* && fexist(qwkfile) */) {
sprintf(str,"%s.qwk",scfg.sys_id);
sprintf(vpath,"/%s",str);
js_add_file(js_cx
,file_array
,str /* filename */
,"QWK Message Packet" /* description */
,NULL /* extdesc */
,time(NULL) /* time */
,0 /* uploaded */
,0 /* last downloaded */
,0 /* times downloaded */
,0 /* misc */
,str /* link */
);
}
/* Library Folders */
for(i=0;i<scfg.total_libs;i++) {
if(!chk_ar(&scfg,scfg.lib[i]->ar,user))
continue;
sprintf(vpath,"/%s/%s",scfg.lib[i]->sname,startup->html_index_file);
js_add_file(js_cx
,dir_array
,scfg.lib[i]->sname /* filename */
,scfg.lib[i]->lname /* description */
,NULL /* extdesc */
,0,0,0,0,0,0,0 /* unused */
,vpath /* link */
for(i=0;i<scfg.total_dirs;i++) {
if(scfg.dir[i]->lib!=lib)
continue;
if(/* i!=scfg.sysop_dir && i!=scfg.upload_dir && */
!chk_ar(&scfg,scfg.dir[i]->ar,user))
continue;
sprintf(vpath,"/%s/%s/%s"
,scfg.lib[scfg.dir[i]->lib]->sname
,scfg.dir[i]->code
,startup->html_index_file);
js_add_file(js_cx
,dir_array
,scfg.dir[i]->sname /* filename */
,NULL /* extdesc */
,getfiles(&scfg,i) /* size */
,0,0,0,0,0 /* unused */
,scfg.dir[i]->misc /* misc */
,vpath /* link */
);
}
} else if(chk_ar(&scfg,scfg.dir[dir]->ar,user)){
sprintf(path,"%s*",scfg.dir[dir]->path);
glob(path,0,NULL,&g);
for(i=0;i<(int)g.gl_pathc;i++) {
if(isdir(g.gl_pathv[i]))
continue;
#ifdef _WIN32
GetShortPathName(g.gl_pathv[i], str, sizeof(str));
#else
strcpy(str,g.gl_pathv[i]);
#endif
padfname(getfname(str),f.name);
strupr(f.name);
f.dir=dir;
if(getfileixb(&scfg,&f)) {
f.size=0; /* flength(g.gl_pathv[i]); */
getfiledat(&scfg,&f);
getextdesc(&scfg, dir, f.datoffset, extdesc);
/* Remove Ctrl-A Codes and Ex-ASCII code */
remove_ctrl_a(extdesc,NULL);
}
sprintf(vpath,"/%s/%s/%s"
,scfg.lib[scfg.dir[dir]->lib]->sname
,scfg.dir[dir]->code
,getfname(g.gl_pathv[i]));
js_add_file(js_cx
,file_array
,getfname(g.gl_pathv[i]) /* filename */
,f.desc /* description */
,f.misc&FM_EXTDESC ? extdesc : NULL
,f.size /* size */
,f.cdt /* credits */
,f.date /* time */
,f.dateuled /* uploaded */
,f.datedled /* last downloaded */
,f.timesdled /* times downloaded */
,f.misc /* misc */
,getfname(g.gl_pathv[i]) /* link */
);
}
}
globfree(&g);
}
/* RUN SCRIPT */
if((js_script=JS_CompileFile(js_cx, parent, spath))==NULL) {
lprintf("%04d !JavaScript FAILED to compile script (%s)",sock,spath);
break;
}
if((success=JS_ExecuteScript(js_cx, parent, js_script, &rval))!=TRUE) {
lprintf("%04d !JavaScript FAILED to execute script (%s)",sock,spath);
break;
}
} while(0);
JS_DeleteProperty(js_cx, parent, "path");
JS_DeleteProperty(js_cx, parent, "sort");
JS_DeleteProperty(js_cx, parent, "reverse");
JS_DeleteProperty(js_cx, parent, "file_list");
JS_DeleteProperty(js_cx, parent, "dir_list");
JS_DeleteProperty(js_cx, parent, "curlib");
JS_DeleteProperty(js_cx, parent, "curdir");
JS_DeleteProperty(js_cx, parent, "html_index_file");
return(success);
}
#endif
static int nopen(char *str, int access)