diff --git a/src/sbbs3/baja.c b/src/sbbs3/baja.c index c902ea7f0e9e1636f7d64a8496f6f7caa5f02af6..b95dfac0a9db34cdccc208ff37438da8bfca9562 100644 --- a/src/sbbs3/baja.c +++ b/src/sbbs3/baja.c @@ -440,7 +440,7 @@ void expdefs(uchar *line) void compile(char *src) { - uchar *str,*save,*p,*sp,*tp,*arg,*arg2,*arg3,*ar,ch; + uchar *str,*save,*p,*sp,*tp,*arg,*arg2,*arg3,*arg4,*ar,ch; ushort i,j; long l,savline; FILE *in; @@ -478,7 +478,7 @@ void compile(char *src) if(display) printf("%s\n",p); sp=strchr(p,SP); - arg=arg2=arg3=""; + arg=arg2=arg3=arg4=""; if(sp) { *sp=0; arg=sp+1; @@ -490,7 +490,11 @@ void compile(char *src) sp=strchr(arg2,SP); if(sp) { arg3=sp+1; - while(*arg3 && *arg3<=SP) arg3++; } } } + while(*arg3 && *arg3<=SP) arg3++; + sp=strchr(arg3,SP); + if(sp) { + arg4=sp+1; + while(*arg4 && *arg4<=SP) arg4++; } } } } if(!stricmp(p,"!INCLUDE")) { savline=line; @@ -622,6 +626,19 @@ void compile(char *src) fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_EXIT); continue; } + if(!stricmp(p,"LOOP") || !stricmp(p,"LOOP_BEGIN")) { + fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_LOOP_BEGIN); + continue; } + if(!stricmp(p,"CONTINUE") || !stricmp(p,"CONTINUE_LOOP")) { + fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_CONTINUE_LOOP); + continue; } + if(!stricmp(p,"BREAK") || !stricmp(p,"BREAK_LOOP")) { + fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_BREAK_LOOP); + continue; } + if(!stricmp(p,"END_LOOP")) { + fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_END_LOOP); + continue; } + if(!stricmp(p,"USER_EVENT")) { if(!(*arg)) break; @@ -646,8 +663,8 @@ void compile(char *src) if(!stricmp(p,"ASYNC")) { fprintf(out,"%c",CS_ASYNC); continue; } - if(!stricmp(p,"RIOSYNC")) { - fprintf(out,"%c",CS_RIOSYNC); + if(!stricmp(p,"RIOSYNC")) { /* deprecated */ + fprintf(out,"%c",CS_SYNC); continue; } if(!stricmp(p,"GETTIMELEFT")) { fprintf(out,"%c",CS_GETTIMELEFT); @@ -942,13 +959,20 @@ void compile(char *src) writecrc(src,arg); writecrc(src,arg2); continue; } + if(!stricmp(p,"COPY_CHAR") || !stricmp(p,"COPY_KEY")) { + if(!(*arg)) break; + fprintf(out,"%c%c",CS_VAR_INSTRUCTION,COPY_CHAR); + writecrc(src,arg); + continue; } if(!stricmp(p,"COPY_FIRST_CHAR")) { + if(!(*arg) || !(*arg2)) break; fputc(CS_VAR_INSTRUCTION,out); fputc(COPY_FIRST_CHAR,out); writecrc(src,arg); writecrc(src,arg2); continue; } if(!stricmp(p,"COMPARE_FIRST_CHAR")) { + if(!(*arg) || !(*arg2)) break; fputc(CS_VAR_INSTRUCTION,out); fputc(COMPARE_FIRST_CHAR,out); writecrc(src,arg); @@ -1407,6 +1431,24 @@ void compile(char *src) writecrc(src,arg2); continue; } + if(!stricmp(p,"COMPARE_ANY_BITS") || !stricmp(p,"COMPARE_ALL_BITS")) { + if(!(*arg) || !(*arg2)) + break; + if((l=isvar(arg2))!=0) { + fputc(CS_USE_INT_VAR,out); + fwrite(&l,4,1,out); // variable + fputc(6,out); // int offset + fputc(4,out); // int length + l=0; } // place holder + else + l=val(src,arg2); + fprintf(out,"%c%c",CS_VAR_INSTRUCTION + ,!stricmp(p,"COMPARE_ANY_BITS") ? COMPARE_ANY_BITS : COMPARE_ALL_BITS); + writecrc(src,arg); + fwrite(&l,sizeof(l),1,out); + continue; + } + if(!stricmp(p,"OR_INT_VAR") || (!stricmp(p,"OR") && (isdigit(*arg2) || atol(arg2) || *arg2=='\'' || *arg2=='.'))) { @@ -1972,6 +2014,175 @@ void compile(char *src) writecrc(src,arg); /* int var */ continue; } + /* NET_FUNCTIONS */ + + if(!stricmp(p,"SOCKET_OPEN")) { + if(!(*arg)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_OPEN); + writecrc(src,arg); /* int var (socket) */ + continue; + } + if(!stricmp(p,"SOCKET_CLOSE")) { + if(!(*arg)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_CLOSE); + writecrc(src,arg); /* int var (socket) */ + continue; + } + if(!stricmp(p,"SOCKET_CHECK")) { + if(!(*arg)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_CHECK); + writecrc(src,arg); /* int var (socket) */ + continue; + } + if(!stricmp(p,"SOCKET_CONNECT")) { + if(!(*arg) || !(*arg2) || !(*arg3)) break; + + /* TCP port */ + if((l=isvar(arg3))!=0) { + fputc(CS_USE_INT_VAR,out); + fwrite(&l,4,1,out); // variable + fputc(10,out); // int offset + fputc(2,out); // int length + i=0; } // place holder + else + i=val(src,arg3); + + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_CONNECT); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (address) */ + fwrite(&i,2,1,out); + continue; + } + if(!stricmp(p,"SOCKET_ACCEPT")) { + if(!(*arg)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_ACCEPT); + writecrc(src,arg); /* int var (socket) */ + continue; + } + if(!stricmp(p,"SOCKET_NREAD")) { + if(!(*arg) || !(*arg2)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_NREAD); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* int var (nbytes) */ + continue; + } + if(!stricmp(p,"SOCKET_PEEK")) { + if(!(*arg) || !(*arg2)) break; + + /* length */ + if(!(*arg3)) + i=0; + else if((l=isvar(arg3))!=0) { + fputc(CS_USE_INT_VAR,out); + fwrite(&l,4,1,out); // variable + fputc(10,out); // int offset + fputc(2,out); // int length + i=0; } // place holder + else + i=val(src,arg3); + + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_PEEK); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (buffer) */ + fwrite(&i,sizeof(i),1,out); /* word (length) */ + continue; + } + if(!stricmp(p,"SOCKET_READ")) { + if(!(*arg) || !(*arg2)) break; + + /* length */ + if(!(*arg3)) + i=0; + else if((l=isvar(arg3))!=0) { + fputc(CS_USE_INT_VAR,out); + fwrite(&l,4,1,out); // variable + fputc(10,out); // int offset + fputc(2,out); // int length + i=0; } // place holder + else + i=val(src,arg3); + + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_READ); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (buffer) */ + fwrite(&i,sizeof(i),1,out); /* word (length) */ + continue; + } + if(!stricmp(p,"SOCKET_WRITE")) { + if(!(*arg) || !(*arg2)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_SOCKET_WRITE); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (buffer) */ + continue; + } + + /* FTP functions */ + if(!stricmp(p,"FTP_LOGIN")) { + if(!(*arg) || !(*arg2) || !(*arg3)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_LOGIN); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* int var (user) */ + writecrc(src,arg3); /* int var (password) */ + continue; + } + if(!stricmp(p,"FTP_LOGOUT")) { + if(!(*arg)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_LOGOUT); + writecrc(src,arg); /* int var (socket) */ + continue; + } + if(!stricmp(p,"FTP_PWD")) { + if(!(*arg)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_PWD); + writecrc(src,arg); /* int var (socket) */ + continue; + } + if(!stricmp(p,"FTP_CWD")) { + if(!(*arg) || !(*arg2)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_CWD); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (path) */ + continue; + } + if(!stricmp(p,"FTP_DIR")) { + if(!(*arg) || !(*arg2)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_DIR); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (path) */ + continue; + } + if(!stricmp(p,"FTP_GET")) { + if(!(*arg) || !(*arg2) || !(*arg3)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_GET); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (src path) */ + writecrc(src,arg3); /* str var (dest path) */ + continue; + } + if(!stricmp(p,"FTP_PUT")) { + if(!(*arg) || !(*arg2) || !(*arg3)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_PUT); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (src path) */ + writecrc(src,arg3); /* str var (dest path) */ + continue; + } + if(!stricmp(p,"FTP_DELETE")) { + if(!(*arg) || !(*arg2)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_DELETE); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (path) */ + continue; + } + if(!stricmp(p,"FTP_RENAME")) { + if(!(*arg) || !(*arg2) || !(*arg3)) break; + fprintf(out,"%c%c",CS_NET_FUNCTION,CS_FTP_RENAME); + writecrc(src,arg); /* int var (socket) */ + writecrc(src,arg2); /* str var (org name) */ + writecrc(src,arg3); /* str var (new name) */ + continue; + } + if(!stricmp(p,"NODE_ACTION")) { if(!(*arg)) break; if((l=isvar(arg))!=0) { @@ -2438,7 +2649,7 @@ void compile(char *src) if(!(*arg)) break; p=strchr(arg,SP); if(p) *p=0; - if(!(*arg) || isdigit(*arg)) + if(isdigit(*arg)) fprintf(out,"%c%c",CS_SHIFT_STR,atoi(arg)); else { if((l=isvar(arg2))!=0) { @@ -2455,6 +2666,23 @@ void compile(char *src) if(!i) i=128; fwrite(&i,1,1,out); } continue; } + if(!stricmp(p,"SHIFT_TO_FIRST_CHAR") || !stricmp(p,"SHIFT_TO_LAST_CHAR")) { + if(!(*arg) || !(*arg2)) break; + if((l=isvar(arg2))!=0) { + fputc(CS_USE_INT_VAR,out); + fwrite(&l,4,1,out); // variable + fputc(6,out); // int offset + fputc(1,out); // int length + ch=0; } // place holder + else + ch=val(src,arg2); + + fprintf(out,"%c%c",CS_VAR_INSTRUCTION + ,!stricmp(p,"SHIFT_TO_FIRST_CHAR") ? SHIFT_TO_FIRST_CHAR : SHIFT_TO_LAST_CHAR); + writecrc(src,arg); + fwrite(&ch,sizeof(ch),1,out); + continue; + } if(!stricmp(p,"TRUNCSP")) { fprintf(out,"%c%c",CS_VAR_INSTRUCTION,TRUNCSP_STR_VAR); writecrc(src,arg); @@ -2746,6 +2974,9 @@ void compile(char *src) if(!stricmp(p,"INKEY")) { fprintf(out,"%c",CS_INKEY); continue; } + if(!stricmp(p,"INCHAR")) { + fprintf(out,"%c",CS_INCHAR); + continue; } if(!stricmp(p,"GETKEY")) { fprintf(out,"%c",CS_GETKEY); continue; } @@ -3119,8 +3350,8 @@ void compile(char *src) } char *banner= "\n" - "BAJA v2.20 - Synchronet Shell/Module Compiler - " - "Copyright 2000 Rob Swindell\n"; + "BAJA v2.30 - Synchronet Shell/Module Compiler - " + "Copyright 2001 Rob Swindell\n"; char *usage= "\n" "usage: baja [/opts] file[.src]\n" diff --git a/src/sbbs3/cmdshell.h b/src/sbbs3/cmdshell.h index 8f6090171e56020aef8ee68043a19dc3016c6552..3a1988d1ae3ca88a1596ee63ffbc1ed84dbdb823 100644 --- a/src/sbbs3/cmdshell.h +++ b/src/sbbs3/cmdshell.h @@ -81,7 +81,7 @@ enum { ,CS_SELECT_EDITOR ,CS_SET_EDITOR // 0x20 ,CS_INKEY - ,CS_RIOSYNC + ,CS_INCHAR // Was RIOSYNC (now deprecated) 02/18/01 ,CS_GETTIMELEFT ,CS_SAVELINE ,CS_RESTORELINE @@ -175,6 +175,10 @@ enum { ,CS_CASE ,CS_USE_INT_VAR // 0x7a +/* Network (TCP/IP) Functions */ + + ,CS_NET_FUNCTION=0x7d + /* File I/O Functions */ ,CS_FIO_FUNCTION=0x7e @@ -403,8 +407,8 @@ enum { ,VAR_RESERVED_L1 ,AND_INT_VAR // Bit-wise AND int variable (static) ,AND_INT_VARS // 0x50 // Bit-wise AND int variable (dynamic) - ,VAR_RESERVED_M4 - ,VAR_RESERVED_M3 + ,COMPARE_ANY_BITS + ,COMPARE_ALL_BITS ,VAR_RESERVED_M2 ,VAR_RESERVED_M1 ,OR_INT_VAR // Bit-wise OR int variable (static) @@ -450,11 +454,14 @@ enum { ,SEND_FILE_VIA_VAR // Send file (dynamic) via protocol ,FTIME_TO_INT // Put time of str var file into int ,RECEIVE_FILE_VIA // Receive file (static) via protocol - ,RECEIVE_FILE_VIA_VAR // Receive file (dynamic) via protocol + ,RECEIVE_FILE_VIA_VAR // 0x80 // Receive file (dynamic) via protocol ,TELNET_GATE_STR // Run telnet gateway to static address with mode ,TELNET_GATE_VAR // Run telnet gateway to variable address with mode ,COPY_FIRST_CHAR // Copy first char of str var to int var ,COMPARE_FIRST_CHAR // Compare first char of str var to static char + ,COPY_CHAR // Copy cmdkey to int var or str var + ,SHIFT_TO_FIRST_CHAR // Shift str var to first occurance of static char + ,SHIFT_TO_LAST_CHAR // Shift str var to last occurance of static char }; /* Preceeded by CS_STR_FUNCTION */ @@ -472,6 +479,10 @@ enum { // More single byte instructions ,CS_LOGON // Logon procedure ,CS_LOGOUT // Logout procedure ,CS_EXIT // Exit current module immediately + ,CS_LOOP_BEGIN // Looping anchor + ,CS_CONTINUE_LOOP // "next" loop + ,CS_BREAK_LOOP // Stop executing loop + ,CS_END_LOOP // End of looping code block }; /* Preceeded by CS_TWO_MORE_BYTES */ @@ -479,6 +490,30 @@ enum { // More two byte instructions CS_USER_EVENT // External user event }; +/* Preceeded by CS_NET_FUNCTION */ + +enum { + CS_SOCKET_OPEN // Open a socket + ,CS_SOCKET_CLOSE // Close a socket + ,CS_SOCKET_CONNECT // Outbound connection + ,CS_SOCKET_ACCEPT // Accept an incomming connection + ,CS_SOCKET_NREAD // Get number of bytes in input buffer + ,CS_SOCKET_PEEK // Peek at input buffer + ,CS_SOCKET_READ // Read input buffer + ,CS_SOCKET_WRITE // Write to socket + ,CS_SOCKET_CHECK // Check connection + + ,CS_FTP_LOGIN // socket, username, password + ,CS_FTP_LOGOUT + ,CS_FTP_PWD // print working dir + ,CS_FTP_CWD // change working dir + ,CS_FTP_DIR // path + ,CS_FTP_PUT // path + ,CS_FTP_GET // path, offset + ,CS_FTP_RENAME + ,CS_FTP_DELETE + }; + /* Preceeded by CS_FIO_FUNCTION */ enum { FIO_OPEN // Open file (static filename) @@ -562,12 +597,21 @@ enum { #define CS_IN_SWITCH (1L<<0) /* Inside active switch statement */ #define CS_OFFLINE_EXEC (1L<<1) /* Offline execution */ + /* Bits for csi_t.ftp_mode */ +#define CS_FTP_ECHO_CMD (1L<<0) /* Echo command lines to user (for debug) */ +#define CS_FTP_ECHO_RSP (1L<<1) /* Echo response lines to user */ +#define CS_FTP_PASV (1L<<2) /* Use PASV mode transfers */ +#define CS_FTP_ASCII (1L<<3) /* Use ASCII file transfers */ +#define CS_FTP_HASH (1L<<4) /* Hash marks printing during xfers */ + #define MAX_RETS 50 /* maximum nested call depth */ #define MAX_CMDRETS 50 /* maximum nested cmd depth */ +#define MAX_LOOPDEPTH 50 /* maximum nested loop depth */ #define MAX_STRVARS 26 #define MAX_INTVARS 26 #define MAX_STRLEN 81 #define MAX_FOPENS 10 /* maximum open files */ +#define MAX_SOCKETS 10 /* maximum open sockets */ #define MAX_SYSVARS 16 /* maximum system variable saves */ #define LOGIC_LESS -1 @@ -586,20 +630,26 @@ typedef struct { /* Command shell image */ cmd, /* Current command key */ etx, /* End-of-text character */ *ret[MAX_RETS], /* Return address stack */ - rets, /* Returns on stack */ *cmdret[MAX_CMDRETS], /* Command return address stack */ - cmdrets; /* Command returns on stack */ + *loop_home[MAX_LOOPDEPTH]; /* Loop home address stack */ int logic; /* Current logic */ FILE *file[MAX_FOPENS]; /* Each file ptr */ + int socket[MAX_SOCKETS]; /* Open socket descriptors */ + long socket_error; /* Last socket error */ uint str_vars, /* Total number of string variables */ int_vars, /* Total number of integer variables */ - files; /* Open files */ + files, /* Open files */ + sockets, /* Open sockets */ + rets, /* Returns on stack */ + loops, /* Nested loop depth (loops on stack) */ + cmdrets; /* Command returns on stack */ long retval, /* Return value */ misc, /* Misc bits */ + ftp_mode, /* FTP operation mode */ switch_val, /* Current switch value */ *int_var, /* Integer variables */ *str_var_name, /* String variable names (CRC-32) */ diff --git a/src/sbbs3/exec.cpp b/src/sbbs3/exec.cpp index 497dba81d34af2ca5fc24dd3d08673f4fb92d7a0..ca5bac4402f54c5ec87cdc8c3abc25d620f6a532 100644 --- a/src/sbbs3/exec.cpp +++ b/src/sbbs3/exec.cpp @@ -427,6 +427,19 @@ long * sbbs_t::getintvar(csi_t *bin, long name) case 0x430178ec: return((long *)&cfg.uq); + case 0x455CB929: + return(&bin->ftp_mode); + + case 0x2105D2B9: + return(&bin->socket_error); + + case 0xA0023A2E: + return((long *)&cfg.startup->options); + + case 0x16E2585F: + sysvar_l[sysvar_li]=client_socket; + break; + default: if(bin->int_var && bin->int_var_name) for(i=0;i<bin->int_vars;i++) @@ -450,6 +463,8 @@ void sbbs_t::clearvars(csi_t *bin) bin->int_var=NULL; bin->int_var_name=NULL; bin->files=0; + bin->loops=0; + bin->sockets=0; bin->retval=0; } @@ -475,6 +490,12 @@ void sbbs_t::freevars(csi_t *bin) bin->file[i]=0; } } + for(i=0;i<bin->sockets;i++) { + if(bin->socket[i]) { + close_socket((SOCKET)bin->socket[i]); + bin->socket[i]=0; + } + } } /****************************************************************************/ @@ -616,6 +637,7 @@ void sbbs_t::skipto(csi_t *csi, uchar inst) case STRLWR_VAR: case TRUNCSP_STR_VAR: case CHKFILE_VAR: + case COPY_CHAR: case STRIP_CTRL_STR_VAR: csi->ip+=4; /* Skip variable name */ continue; @@ -627,6 +649,8 @@ void sbbs_t::skipto(csi_t *csi, uchar inst) case SEND_FILE_VIA_VAR: case RECEIVE_FILE_VIA_VAR: case COMPARE_FIRST_CHAR: + case SHIFT_TO_FIRST_CHAR: + case SHIFT_TO_LAST_CHAR: csi->ip+=4; /* Skip variable name */ csi->ip++; /* Skip char */ continue; @@ -721,6 +745,48 @@ void sbbs_t::skipto(csi_t *csi, uchar inst) csi->ip+=4; /* Variable */ continue; } + case CS_NET_FUNCTION: + csi->ip++; + switch(*(csi->ip++)) { + case CS_SOCKET_CONNECT: + csi->ip+=4; /* socket */ + csi->ip+=4; /* address */ + csi->ip+=2; /* port */ + continue; + case CS_SOCKET_NREAD: + csi->ip+=4; /* socket */ + csi->ip+=4; /* intvar */ + continue; + case CS_SOCKET_READ: + case CS_SOCKET_PEEK: + csi->ip+=4; /* socket */ + csi->ip+=4; /* buffer */ + csi->ip+=2; /* length */ + continue; + case CS_SOCKET_WRITE: + csi->ip+=4; /* socket */ + csi->ip+=4; /* strvar */ + continue; + + case CS_FTP_LOGIN: + case CS_FTP_GET: + case CS_FTP_PUT: + case CS_FTP_RENAME: + csi->ip+=4; /* socket */ + csi->ip+=4; /* username/path */ + csi->ip+=4; /* password/path */ + continue; + case CS_FTP_DIR: + case CS_FTP_CWD: + case CS_FTP_DELETE: + csi->ip+=4; /* socket */ + csi->ip+=4; /* path */ + continue; + + default: + csi->ip+=4; /* socket */ + continue; } + case CS_COMPARE_ARS: csi->ip++; csi->ip+=(*csi->ip); @@ -746,8 +812,17 @@ void sbbs_t::skipto(csi_t *csi, uchar inst) continue; } if(*csi->ip==CS_ONE_MORE_BYTE) { + if(inst==CS_END_LOOP && *(csi->ip+1)==CS_END_LOOP) + break; + csi->ip++; /* skip extension */ csi->ip++; /* skip instruction */ + + if(*(csi->ip-1)==CS_LOOP_BEGIN) { /* nested loop */ + skipto(csi,CS_END_LOOP); + csi->ip+=2; + } + continue; } if(*csi->ip==CS_TWO_MORE_BYTES) { @@ -1000,8 +1075,10 @@ int sbbs_t::exec(csi_t *csi) csi->ip=csi->cs+*((ushort *)(csi->ip)); return(0); case CS_CALL: - csi->ret[csi->rets++]=csi->ip+2; - csi->ip=csi->cs+*((ushort *)(csi->ip)); + if(csi->rets<MAX_RETS) { + csi->ret[csi->rets++]=csi->ip+2; + csi->ip=csi->cs+*((ushort *)(csi->ip)); + } return(0); case CS_MSWAIT: mswait(*(ushort *)csi->ip); @@ -1179,10 +1256,12 @@ int sbbs_t::exec(csi_t *csi) csi->str[0]=0; return(0); case CS_SHIFT_STR: - if(strlen(csi->str)>=*csi->ip) - memmove(csi->str,csi->str+(*csi->ip) - ,strlen(csi->str)+1); - csi->ip++; + i=*(csi->ip++); + j=strlen(csi->str); + if(i>j) + i=j; + if(i) + memmove(csi->str,csi->str+i,j+1); return(0); case CS_COMPARE_KEY: if( ((*csi->ip)==CS_DIGIT && isdigit(csi->cmd)) @@ -1353,6 +1432,22 @@ int sbbs_t::exec(csi_t *csi) return(0); case CS_EXIT: return(1); + case CS_LOOP_BEGIN: + if(csi->loops<MAX_LOOPDEPTH) + csi->loop_home[csi->loops++]=(csi->ip-1); + return(0); + case CS_BREAK_LOOP: + if(csi->loops) { + skipto(csi,CS_END_LOOP); + csi->ip+=2; + csi->loops--; + } + return(0); + case CS_END_LOOP: + case CS_CONTINUE_LOOP: + if(csi->loops) + csi->ip=csi->loop_home[csi->loops-1]; + return(0); default: errormsg(WHERE,ERR_CHK,"one byte extended function" ,*(csi->ip-1)); @@ -1397,9 +1492,11 @@ int sbbs_t::exec(csi_t *csi) case CS_ASYNC: ASYNC; return(0); +#if 0 /* Removed 02/18/01 - never used, officially deprecated for INCHAR */ case CS_RIOSYNC: RIOSYNC(0); return(0); +#endif case CS_GETTIMELEFT: gettimeleft(); return(0); @@ -1412,7 +1509,7 @@ int sbbs_t::exec(csi_t *csi) csi->cmd=getkey(K_UPPER); return(0); case CS_GETCHAR: - csi->cmd=csi->str[0]=getkey(0); + csi->cmd=getkey(0); return(0); case CS_INKEY: csi->cmd=toupper(inkey(K_GETSTR)); @@ -1421,6 +1518,13 @@ int sbbs_t::exec(csi_t *csi) else csi->logic=LOGIC_FALSE; return(0); + case CS_INCHAR: + csi->cmd=inkey(K_GETSTR); + if(csi->cmd) + csi->logic=LOGIC_TRUE; + else + csi->logic=LOGIC_FALSE; + return(0); case CS_GETKEYE: csi->cmd=getkey(K_UPPER); if(csi->cmd=='/') { @@ -1514,15 +1618,12 @@ int sbbs_t::exec(csi_t *csi) putmsg(csi->str,P_SAVEATR|P_NOABORT); return(0); case CS_CMD_HOME: - csi->cmdret[csi->cmdrets++]=(csi->ip-1); + if(csi->cmdrets<MAX_CMDRETS) + csi->cmdret[csi->cmdrets++]=(csi->ip-1); return(0); case CS_END_CMD: if(csi->cmdrets) csi->ip=csi->cmdret[--csi->cmdrets]; - /* Removed 06/07/95 - else - errormsg(WHERE,ERR_CHK,"misplaced end_cmd",(csi->ip-csi->cs)-1); - */ return(0); case CS_CMD_POP: if(csi->cmdrets) diff --git a/src/sbbs3/execmisc.cpp b/src/sbbs3/execmisc.cpp index 9def1b031f0657575f5a02322b7620b351dcf5ef..79a954607b373b3ac279b89fe8048108702c03ae 100644 --- a/src/sbbs3/execmisc.cpp +++ b/src/sbbs3/execmisc.cpp @@ -38,9 +38,33 @@ #include "sbbs.h" #include "cmdshell.h" -int sbbs_t::exec_misc(csi_t *csi, char *path) +/* Return true if connected */ +bool socket_check(SOCKET sock) { - char str[512],tmp[512],buf[1025],ch,*p,**pp,**pp1,**pp2; + char ch; + int i; + fd_set socket_set; + struct timeval tv; + + FD_ZERO(&socket_set); + FD_SET(sock,&socket_set); + + tv.tv_sec=0; + tv.tv_usec=0; + + i=select(sock+1,&socket_set,NULL,NULL,&tv); + if(i==SOCKET_ERROR) + return(false); + + if(i==0 || recv(sock,&ch,1,MSG_PEEK)==1) + return(true); + + return(false); +} + +int sbbs_t::exec_misc(csi_t* csi, char *path) +{ + char str[512],tmp[512],rsp[512],buf[1025],ch,*p,**pp,**pp1,**pp2; ushort w; uint i,j; long l,*lp,*lp1,*lp2; @@ -609,6 +633,25 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) *lp^=l; break; } return(0); + case COMPARE_ANY_BITS: + case COMPARE_ALL_BITS: + i=*(csi->ip-1); + lp=getintvar(csi,*(long *)csi->ip); + csi->ip+=4; + l=*(long *)csi->ip; + csi->ip+=4; + csi->logic=LOGIC_FALSE; + if(!lp) + return(0); + + if(i==COMPARE_ANY_BITS) { + if(((*lp)&l)!=0) + csi->logic=LOGIC_TRUE; + } else { + if(((*lp)&l)==l) + csi->logic=LOGIC_TRUE; + } + return(0); case ADD_INT_VARS: case SUB_INT_VARS: case MUL_INT_VARS: @@ -832,6 +875,27 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) memmove(*pp,*pp+i,strlen(*pp)+1); return(0); + case SHIFT_TO_FIRST_CHAR: + case SHIFT_TO_LAST_CHAR: + i=*(csi->ip-1); + pp=getstrvar(csi,*(long *)csi->ip); + csi->ip+=4; + ch=*(csi->ip++); + csi->logic=LOGIC_FALSE; + if(!pp || !*pp) + return(0); + if(i==SHIFT_TO_FIRST_CHAR) + p=strchr(*pp,ch); + else /* _TO_LAST_CHAR */ + p=strrchr(*pp,ch); + if(p==NULL) + return(0); + csi->logic=LOGIC_TRUE; + i=p-*pp; + if(i>0) + memmove(*pp,*pp+i,strlen(p)+1); + return(0); + case CHKFILE_VAR: pp=getstrvar(csi,*(long *)csi->ip); csi->ip+=4; @@ -873,6 +937,19 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) while(*(csi->ip++)); /* Find NULL */ telnet_gate(str,l); return(0); + case COPY_CHAR: + pp=getstrvar(csi,*(long *)csi->ip); + if(pp==NULL) + lp=getintvar(csi,*(long *)csi->ip); + csi->ip+=4; + + if(pp==NULL && lp!=NULL) + *lp=csi->cmd; + else if(pp!=NULL) { + sprintf(tmp,"%c",csi->cmd); + *pp=copystrvar(csi,*pp,tmp); + } + return(0); case COPY_FIRST_CHAR: lp=getintvar(csi,*(long *)csi->ip); csi->ip+=4; @@ -984,7 +1061,9 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) csi->logic=fclose((FILE *)*lp); for(i=0;i<csi->files;i++) if(csi->file[i]==(FILE *)*lp) - csi->file[i]=0; } + csi->file[i]=0; + *lp=0; + } else csi->logic=LOGIC_FALSE; return(0); @@ -1014,8 +1093,8 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) if(!vp) return(0); i=*(short *)vp; } - if(i>1024) - i=1024; + if(i>sizeof(buf)-1) + i=sizeof(buf)-1; if(!lp1 || !(*lp1) || (!pp && !lp2)) return(0); if(pp) { @@ -1048,7 +1127,7 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) if(!lp1 || !(*lp1) || feof((FILE *)*lp1) || (!pp && !lp2)) return(0); csi->logic=LOGIC_TRUE; - for(i=0;i<1024 /* && !eof(*lp1) removed 1/23/96 */;i++) { + for(i=0;i<sizeof(buf)-1;i++) { if(!fread(buf+i,1,1,(FILE *)*lp1)) break; if(*(buf+i)==LF) { @@ -1081,8 +1160,8 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) if(!vp) return(0); i=*(short *)vp; } - if(i>1024) - i=1024; + if(i>sizeof(buf)-1) + i=sizeof(buf)-1; if(!lp1 || !(*lp1) || (!pp && !lp2) || (pp && !*pp)) return(0); if(pp) { @@ -1315,7 +1394,7 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) else csi->logic=LOGIC_FALSE; return(0); - #if 1 /* posix dirent */ + case OPEN_DIR: lp=getintvar(csi,*(long *)csi->ip); csi->ip+=4; @@ -1356,11 +1435,308 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) else csi->logic=LOGIC_FALSE; return(0); - #endif + default: errormsg(WHERE,ERR_CHK,"fio sub-instruction",*(csi->ip-1)); return(0); } + case CS_NET_FUNCTION: + switch(*(csi->ip++)) { /* sub-op-code stored as next byte */ + case CS_SOCKET_OPEN: + lp=getintvar(csi,*(long *)csi->ip); + csi->ip+=4; + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + if(csi->sockets>=MAX_SOCKETS) + return(0); + if(lp!=NULL) { + + SOCKET sock=open_socket(SOCK_STREAM); + if(sock!=INVALID_SOCKET) { + + SOCKADDR_IN addr; + + memset(&addr,0,sizeof(addr)); + addr.sin_addr.s_addr = htonl(cfg.startup->telnet_interface); + addr.sin_family = AF_INET; + + if((i=bind(sock, (struct sockaddr *) &addr, sizeof (addr)))!=0) { + csi->socket_error=ERROR_VALUE; + close_socket(sock); + return(0); + } + + *lp=sock; + + for(i=0;i<csi->sockets;i++) + if(!csi->socket[i]) + break; + csi->socket[i]=*lp; + if(i==csi->sockets) + csi->sockets++; + csi->logic=LOGIC_TRUE; + } + } + return(0); + case CS_SOCKET_CLOSE: + lp=getintvar(csi,*(long *)csi->ip); + csi->ip+=4; + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + if(lp && *lp) { + csi->logic=close_socket((SOCKET)*lp); + csi->socket_error=ERROR_VALUE; + for(i=0;i<csi->sockets;i++) + if(csi->socket[i]==*lp) + csi->socket[i]=0; + *lp=0; + } + return(0); + case CS_SOCKET_CHECK: + lp=getintvar(csi,*(long *)csi->ip); + csi->ip+=4; + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(lp==NULL || *lp==INVALID_SOCKET) + return(0); + + if(socket_check(*lp)==true) + csi->logic=LOGIC_TRUE; + else + csi->socket_error=ERROR_VALUE; + + return(0); + case CS_SOCKET_CONNECT: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + + pp=getstrvar(csi,*(long *)csi->ip); /* address */ + csi->ip+=4; + + w=*(ushort *)csi->ip; /* port */ + csi->ip+=2; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp || !*lp || !pp || !*pp || !w) + return(0); + + ulong ip_addr; + + if((ip_addr=resolve_ip(*pp))==0) + return(0); + + SOCKADDR_IN addr; + + memset(&addr,0,sizeof(addr)); + addr.sin_addr.s_addr = ip_addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(w); + + if((i=connect(*lp, (struct sockaddr *)&addr, sizeof(addr)))!=0) { + csi->socket_error=ERROR_VALUE; + return(0); + } + csi->logic=LOGIC_TRUE; + return(0); + case CS_SOCKET_ACCEPT: + lp1=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + csi->socket_error=0; + /* TODO */ + return(0); + case CS_SOCKET_NREAD: + lp1=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + lp2=getintvar(csi,*(long *)csi->ip); /* var */ + csi->ip+=4; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp1 || !lp2) + return(0); + + if(ioctlsocket(*lp1, FIONREAD, (ulong*)lp2)==0) + csi->logic=LOGIC_TRUE; + else + csi->socket_error=ERROR_VALUE; + return(0); + case CS_SOCKET_PEEK: + case CS_SOCKET_READ: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + pp=getstrvar(csi,*(long *)csi->ip); /* buffer */ + csi->ip+=4; + w=*(ushort *)csi->ip; /* length */ + csi->ip+=2; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp || !pp) + return(0); + + if(w<1 || w>sizeof(buf)-1) + w=sizeof(buf)-1; + + if((i=recv(*lp,buf,w + ,*(csi->ip-13)==CS_SOCKET_PEEK ? MSG_PEEK : 0))>0) { + csi->logic=LOGIC_TRUE; + buf[i]=0; + if(csi->etx) { + p=strchr(buf,csi->etx); + if(p) *p=0; + } + *pp=copystrvar(csi,*pp,buf); + } else + csi->socket_error=ERROR_VALUE; + return(0); + case CS_SOCKET_WRITE: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + pp=getstrvar(csi,*(long *)csi->ip); /* buffer */ + csi->ip+=4; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp || !pp || !(*pp)) + return(0); + + if(send(*lp,*pp,strlen(*pp),0)>0) + csi->logic=LOGIC_TRUE; + else + csi->socket_error=ERROR_VALUE; + return(0); + + case CS_FTP_LOGIN: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + pp1=getstrvar(csi,*(long *)csi->ip); /* username */ + csi->ip+=4; + pp2=getstrvar(csi,*(long *)csi->ip); /* password */ + csi->ip+=4; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp || !pp1 || !pp2) + return(0); + + if(!ftp_cmd(csi,*lp,NULL,rsp)) + return(0); + + if(atoi(rsp)!=220) + return(0); + + sprintf(str,"USER %s",*pp1); + + if(!ftp_cmd(csi,*lp,str,rsp)) + return(0); + + if(atoi(rsp)==331) { /* Password needed */ + sprintf(str,"PASS %s\r\n",*pp2); + if(!ftp_cmd(csi,*lp,str,rsp)) + return(0); + } + + if(atoi(rsp)==230) /* Login successful */ + csi->logic=LOGIC_TRUE; + return(0); + + case CS_FTP_LOGOUT: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp) + return(0); + + if(!ftp_cmd(csi,*lp,"QUIT",rsp)) + return(0); + + if(atoi(rsp)==221) /* Logout successful */ + csi->logic=LOGIC_TRUE; + return(0); + + case CS_FTP_PWD: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + if(!lp) + return(0); + + if(!ftp_cmd(csi,*lp,"PWD",rsp)) + return(0); + + if(atoi(rsp)==257) /* pathname */ + csi->logic=LOGIC_TRUE; + return(0); + + case CS_FTP_CWD: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + pp=getstrvar(csi,*(long *)csi->ip); /* path */ + csi->ip+=4; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + if(!lp || !pp) + return(0); + + sprintf(str,"CWD %s",*pp); + if(!ftp_cmd(csi,*lp,str,rsp)) + return(0); + + if(atoi(rsp)==250) + csi->logic=LOGIC_TRUE; + + return(0); + + case CS_FTP_DIR: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + pp=getstrvar(csi,*(long *)csi->ip); /* path */ + csi->ip+=4; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp || !pp) + return(0); + + if(ftp_get(csi,*lp,*pp,NULL /* unused */, true /* DIR */)==true) + csi->logic=LOGIC_TRUE; + + return(0); + + case CS_FTP_GET: + lp=getintvar(csi,*(long *)csi->ip); /* socket */ + csi->ip+=4; + pp1=getstrvar(csi,*(long *)csi->ip); /* src path */ + csi->ip+=4; + pp2=getstrvar(csi,*(long *)csi->ip); /* dest path */ + csi->ip+=4; + + csi->logic=LOGIC_FALSE; + csi->socket_error=0; + + if(!lp || !pp1 || !pp2) + return(0); + + if(ftp_get(csi,*lp,*pp1,*pp2)==true) + csi->logic=LOGIC_TRUE; + + return(0); + + default: + errormsg(WHERE,ERR_CHK,"net sub-instruction",*(csi->ip-1)); + return(0); } case CS_SWITCH: lp=getintvar(csi,*(long *)csi->ip); @@ -1479,3 +1855,259 @@ int sbbs_t::exec_misc(csi_t *csi, char *path) errormsg(WHERE,ERR_CHK,"shell instruction",*(csi->ip-1)); return(0); } } + +/* FTP Command/Response function */ +bool sbbs_t::ftp_cmd(csi_t* csi, SOCKET sock, char* cmdsrc, char* rsp) +{ + char cmd[512]; + int len; + + if(cmdsrc!=NULL) { + sprintf(cmd,"%s\r\n",cmdsrc); + + if(csi->ftp_mode&CS_FTP_ECHO_CMD) + bputs(cmd); + + len=strlen(cmd); + if(send(sock,cmd,len,0)!=len) { + csi->socket_error=ERROR_VALUE; + return(FALSE); + } + } + + if(rsp!=NULL) { + + int rd; + char ch; + + while(1) { + rd=0; + + while(rd<500) { + + if(!online) + return(FALSE); + + if(recv(sock, &ch, 1, 0)!=1) { + csi->socket_error=ERROR_VALUE; + return(FALSE); + } + + if(ch=='\n' && rd>=1) + break; + + rsp[rd++]=ch; + } + rsp[rd-1]=0; + if(csi->ftp_mode&CS_FTP_ECHO_RSP) + bprintf("%s\r\n",rsp); + if(rsp[0]!=' ' && rsp[3]!='-') + break; + } + } + + return(TRUE); +} + +SOCKET sbbs_t::ftp_data_sock(csi_t* csi, SOCKET ctrl_sock, SOCKADDR_IN* addr) +{ + char cmd[512]; + char rsp[512]; + char* p; + int addr_len; + SOCKET data_sock; + int ip_b[4]; + int port_b[2]; + union { + DWORD dw; + BYTE b[sizeof(DWORD)]; + } ip_addr; + union { + WORD w; + BYTE b[sizeof(WORD)]; + } port; + + if((data_sock=open_socket(SOCK_STREAM))==INVALID_SOCKET) { + csi->socket_error=ERROR_VALUE; + return(INVALID_SOCKET); + } + + memset(addr,0,sizeof(addr)); + addr->sin_addr.s_addr = htonl(cfg.startup->telnet_interface); + addr->sin_family = AF_INET; + + if(bind(data_sock, (struct sockaddr *)addr,sizeof(SOCKADDR_IN))!= 0) { + csi->socket_error=ERROR_VALUE; + close_socket(data_sock); + return(INVALID_SOCKET); + } + + if(csi->ftp_mode&CS_FTP_PASV) { + + if(!ftp_cmd(csi,ctrl_sock,"PASV",rsp) + || atoi(rsp)!=227 /* PASV response */) { + close_socket(data_sock); + return(INVALID_SOCKET); + } + + p=strchr(rsp,'('); + if(p==NULL) { + close_socket(data_sock); + return(INVALID_SOCKET); + } + p++; + if(sscanf(p,"%u,%u,%u,%u,%u,%u" + ,&ip_b[0],&ip_b[1],&ip_b[2],&ip_b[3] + ,&port_b[0],&port_b[1])!=6) { + close_socket(data_sock); + return(INVALID_SOCKET); + } + + ip_addr.b[0]=ip_b[0]; ip_addr.b[1]=ip_b[1]; + ip_addr.b[2]=ip_b[2]; ip_addr.b[3]=ip_b[3]; + port.b[0]=port_b[0]; port.b[1]=port_b[1]; + + addr->sin_addr.s_addr=ip_addr.dw; + addr->sin_port=port.w; + + } else { /* Normal (Active) FTP */ + + addr_len=sizeof(SOCKADDR_IN); + if(getsockname(data_sock, (struct sockaddr *)addr,&addr_len)!=0) { + csi->socket_error=ERROR_VALUE; + close_socket(data_sock); + return(INVALID_SOCKET); + } + + if(listen(data_sock, 1)!= 0) { + csi->socket_error=ERROR_VALUE; + close_socket(data_sock); + return(INVALID_SOCKET); + } + + ip_addr.dw=ntohl(addr->sin_addr.s_addr); + port.w=ntohs(addr->sin_port); + sprintf(cmd,"PORT %u,%u,%u,%u,%hu,%hu" + ,ip_addr.b[3] + ,ip_addr.b[2] + ,ip_addr.b[1] + ,ip_addr.b[0] + ,port.b[1] + ,port.b[0] + ); + + if(!ftp_cmd(csi,ctrl_sock,cmd,rsp) + || atoi(rsp)!=200 /* PORT response */) { + close_socket(data_sock); + return(INVALID_SOCKET); + } + + } + + return(data_sock); +} + +/* FTP Command/Response function */ +bool sbbs_t::ftp_get(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest, bool dir) +{ + char cmd[512]; + char rsp[512]; + char buf[4097]; + int rd; + int addr_len; + ulong total=0; + SOCKET data_sock; + SOCKADDR_IN addr; + FILE* fp=NULL; + + if((data_sock=ftp_data_sock(csi, ctrl_sock, &addr))==INVALID_SOCKET) + return(false); + + if(dir) + sprintf(cmd,"LIST %s",src); + else + sprintf(cmd,"RETR %s",src); + + if(!ftp_cmd(csi,ctrl_sock,cmd,rsp) + || atoi(rsp)!=150 /* Open data connection */) { + close_socket(data_sock); + return(false); + } + + if(csi->ftp_mode&CS_FTP_PASV) { + +#if 0 // Debug + bprintf("Connecting to %s:%hd\r\n" + ,inet_ntoa(addr.sin_addr) + ,ntohs(addr.sin_port)); +#endif + + if(connect(data_sock,(struct sockaddr *)&addr,sizeof(addr))!=0) { + csi->socket_error=ERROR_VALUE; + close_socket(data_sock); + return(false); + } + + } else { /* Normal (Active) FTP */ + + SOCKET accept_sock; + + addr_len=sizeof(addr); + if((accept_sock=accept(data_sock,(struct sockaddr*)&addr,&addr_len)) + ==INVALID_SOCKET) { + csi->socket_error=ERROR_VALUE; + closesocket(data_sock); + return(false); + } + + if(cfg.startup->socket_open!=NULL) + cfg.startup->socket_open(TRUE); + + close_socket(data_sock); + data_sock=accept_sock; + } + + + if(!dir) + if((fp=fopen(dest,"wb"))==NULL) { + close_socket(data_sock); + return(false); + } + + while(online) { + + if(!socket_check(ctrl_sock)) + break; /* Control connection lost */ + + if((rd=recv(data_sock, buf, sizeof(buf)-1, 0))<1) + break; + + if(dir) { + buf[rd]=0; + bputs(buf); + } else + fwrite(buf,1,rd,fp); + + total+=rd; + + if(!dir && csi->ftp_mode&CS_FTP_HASH) + outchar('#'); + } + + if(!dir && csi->ftp_mode&CS_FTP_HASH) { + CRLF; + } + + if(fp!=NULL) + fclose(fp); + + close_socket(data_sock); + + if(!ftp_cmd(csi,ctrl_sock,NULL,rsp) + || atoi(rsp)!=226 /* Download complete */) + return(false); + + bprintf("ftp: %lu bytes received.\r\n", total); + + return(true); +}