Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
ToDo: Iron Ox is unique in that it runs perfectly from
ToDo: tcsh but not at all from anywhere else, complaining
ToDo: about corrupt files. I've ruled out the possibilty
ToDo: of it being a terminal mode issue... no other ideas
ToDo: come to mind. */
FILE * doscmdrc;
sprintf(str,"%s.doscmdrc",cfg.node_dir);
if((doscmdrc=fopen(str,"w+"))==NULL) {
errormsg(WHERE,ERR_CREATE,str,0);
return(-1);
}
if(startup_dir!=NULL && startup_dir[0])
fprintf(doscmdrc,"assign C: %s\n",startup_dir);
else
fprintf(doscmdrc,"assign C: .\n");
fprintf(doscmdrc,"assign D: %s\n",cfg.node_dir);
SAFECOPY(str,cfg.exec_dir);
if((p=strrchr(str,'/'))!=NULL)
*p=0;
if((p=strrchr(str,'/'))!=NULL)
*p=0;
fprintf(doscmdrc,"assign E: %s\n",str);
/* setup doscmd env here */
/* ToDo Note, this assumes that the BBS uses standard dir names */
fprintf(doscmdrc,"DSZLOG=E:\\node%d\\PROTOCOL.LOG\n",cfg.node_num);
fprintf(doscmdrc,"SBBSNODE=D:\\\n");
fprintf(doscmdrc,"SBBSCTRL=E:\\ctrl\\\n");
fprintf(doscmdrc,"SBBSDATA=E:\\data\\\n");
fprintf(doscmdrc,"SBBSEXEC=E:\\exec\\\n");
fprintf(doscmdrc,"SBBSNNUM=%d\n",cfg.node_num);
fclose(doscmdrc);
SAFECOPY(str,cmdline);
sprintf(cmdline,"/usr/bin/doscmd -xFQ %s",str);
#endif

rswindell
committed
if(!(mode&EX_INR))
pthread_mutex_lock(&input_thread_mutex);
if((mode&EX_INR) && (mode&EX_OUTR)) {
struct winsize winsize;
winsize.ws_row=rows;
// #warning Currently cols are forced to 80 apparently TODO
winsize.ws_col=80;
if((pid=forkpty(&in_pipe[1],NULL,NULL,&winsize))==-1) {
pthread_mutex_unlock(&input_thread_mutex);
errormsg(WHERE,ERR_EXEC,cmdline,0);

rswindell
committed
return(-1);
}
out_pipe[0]=in_pipe[1];
}
else {
if(mode&EX_INR)
if(pipe(in_pipe)!=0) {
errormsg(WHERE,ERR_CREATE,"in_pipe",0);
return(-1);
}
if(mode&EX_OUTR)
if(pipe(out_pipe)!=0) {
errormsg(WHERE,ERR_CREATE,"out_pipe",0);
return(-1);
}
if((pid=fork())==-1) {
pthread_mutex_unlock(&input_thread_mutex);
errormsg(WHERE,ERR_EXEC,cmdline,0);

rswindell
committed
return(-1);
}
}
if(pid==0) { /* child process */
setup_term(0, startup->xtrn_term);
#ifdef __FreeBSD__
if(!native)
chdir(cfg.node_dir);
else
#endif
if(startup_dir!=NULL && startup_dir[0])
chdir(startup_dir);
if(mode&EX_SH || strcspn(cmdline,"<>|;")!=strlen(cmdline)) {
argv[0]=comspec;
argv[1]="-c";
argv[2]=cmdline;
argv[3]=NULL;
} else {
argv[0]=cmdline; /* point to the beginning of the string */
argc=1;
for(i=0;cmdline[i] && argc<MAX_ARGS;i++) /* Break up command line */
if(cmdline[i]==SP) {
cmdline[i]=0; /* insert nulls */
argv[argc++]=cmdline+i+1; /* point to the beginning of the next arg */
}
argv[argc]=NULL;
}
if(mode&EX_INR && !(mode&EX_OUTR)) {

rswindell
committed
close(in_pipe[1]); /* close write-end of pipe */
dup2(in_pipe[0],0); /* redirect stdin */
close(in_pipe[0]); /* close excess file descriptor */
}

rswindell
committed
if(mode&EX_OUTR && !(mode&EX_INR)) {

rswindell
committed
close(out_pipe[0]); /* close read-end of pipe */
dup2(out_pipe[1],1); /* stdout */
dup2(out_pipe[1],2); /* stderr */
close(out_pipe[1]); /* close excess file descriptor */

rswindell
committed
}
if(mode&EX_BG) /* background execution, detach child */
{
if(fork())
exit(0);
lprintf("Detaching external process pgid=%d",setsid());
}
sprintf(str,"!ERROR %d executing %s",errno,argv[0]);
errorlog(str);
exit(-1); /* should never get here */
lprintf("Node %d executing external: %s",cfg.node_num,cmdline);

rswindell
committed
if(mode&EX_OUTR) {
if(!(mode&EX_INR))
close(out_pipe[1]); /* close write-end of pipe */
while(!terminated) {

rswindell
committed
if(waitpid(pid, &i, WNOHANG)!=0) /* child exited */
break;
if(mode&EX_CHKTIME)
gettimeleft();

rswindell
committed
if(!online && !(mode&EX_OFFLINE)) {
sprintf(str,"%s hung-up in external program",useron.alias);
logline("X!",str);
break;
}

rswindell
committed
/* Input */
if(mode&EX_INR && RingBufFull(&inbuf)) {
if((wr=RingBufRead(&inbuf,buf,sizeof(buf)))!=0)
write(in_pipe[1],buf,wr);
}
/* Output */
#if 0

rswindell
committed
ioctl(out_pipe[0],FIONREAD,&rd); /* peek at input */
if(!rd) {
mswait(1);
continue;
}
#else
FD_ZERO(&ibits);
FD_SET(out_pipe[0],&ibits);
timeout.tv_sec=0;
timeout.tv_usec=0;
if(!select(out_pipe[0]+1,&ibits,NULL,NULL,&timeout)) {
mswait(1);
continue;
}
#endif
avail=RingBufFree(&outbuf);
if(avail==0) {
lprintf("Node %d !output buffer full (%u bytes)"
,cfg.node_num,RingBufFull(&outbuf));
mswait(1);
continue;
}
#if 0
if(rd>(int)avail)
#endif
rd=avail;
if(rd>(int)sizeof(buf))
rd=sizeof(buf);
if((rd=read(out_pipe[0],buf,rd))<1) {

rswindell
committed
mswait(1);
continue;
}

rswindell
committed
if(mode&EX_BIN) /* telnet IAC expansion */
bp=telnet_expand(buf, rd, output_buf, output_len);

rswindell
committed
else /* LF to CRLF expansion */
bp=lf_expand(buf, rd, output_buf, output_len);
/* Does expanded size fit? */
if(output_len>RingBufFree(&outbuf)) {
lprintf("Node %d !output buffer overflow (%u bytes)"
,cfg.node_num,output_len);
mswait(1);
continue;
}

rswindell
committed
RingBufWrite(&outbuf, bp, output_len);
sem_post(&output_sem);
}
if(waitpid(pid, &i, WNOHANG)==0) { // Child still running?
kill(pid, SIGHUP); // Tell child user has hung up
time_t start=time(NULL); // Wait up to 10 seconds
while(time(NULL)-start<10) { // for child to terminate
if(waitpid(pid, &i, WNOHANG)!=0)
break;
mswait(500);
}
if(waitpid(pid, &i, WNOHANG)==0) // Child still running?
kill(pid, SIGKILL); // terminate child process
}
/* close unneeded descriptors */
if(mode&EX_INR)
close(in_pipe[1]);
close(out_pipe[0]);

rswindell
committed
}

rswindell
committed
waitpid(pid, &i, 0); /* Wait for child to terminate */
pthread_mutex_unlock(&input_thread_mutex);
return(WEXITSTATUS(i));
}
#endif /* !WIN32 */
uint fakeriobp=0xffff;
/*****************************************************************************/
/* Returns command line generated from instr with %c replacments */
/*****************************************************************************/
char * sbbs_t::cmdstr(char *instr, char *fpath, char *fspec, char *outstr)
{
char str[256],*cmd;
int i,j,len;
if(outstr==NULL)
cmd=cmdstr_output;
else
cmd=outstr;
len=strlen(instr);
for(i=j=0;i<len && j<(int)sizeof(cmdstr_output);i++) {
if(instr[i]=='%') {
i++;
cmd[j]=0;
char ch=instr[i];
if(isalpha(ch))
ch=toupper(ch);
switch(ch) {
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
case 'A': /* User alias */
strcat(cmd,useron.alias);
break;
case 'B': /* Baud (DTE) Rate */
strcat(cmd,ultoa(dte_rate,str,10));
break;
case 'C': /* Connect Description */
strcat(cmd,connection);
break;
case 'D': /* Connect (DCE) Rate */
strcat(cmd,ultoa((ulong)cur_rate,str,10));
break;
case 'E': /* Estimated Rate */
strcat(cmd,ultoa((ulong)cur_cps*10,str,10));
break;
case 'F': /* File path */
strcat(cmd,fpath);
break;
case 'G': /* Temp directory */
strcat(cmd,cfg.temp_dir);
break;
case 'H': /* Port Handle or Hardware Flow Control */
#if defined(__unix__)
strcat(cmd,ultoa(client_socket,str,10));
#else
strcat(cmd,ultoa(client_socket_dup,str,10));
#endif
break;
case 'I': /* UART IRQ Line */
strcat(cmd,ultoa(cfg.com_irq,str,10));
break;
case 'J':
strcat(cmd,cfg.data_dir);
break;
case 'K':
strcat(cmd,cfg.ctrl_dir);
break;
case 'L': /* Lines per message */
strcat(cmd,ultoa(cfg.level_linespermsg[useron.level],str,10));
break;
case 'M': /* Minutes (credits) for user */
strcat(cmd,ultoa(useron.min,str,10));
break;
case 'N': /* Node Directory (same as SBBSNODE environment var) */
strcat(cmd,cfg.node_dir);
break;
case 'O': /* SysOp */
strcat(cmd,cfg.sys_op);
break;
case 'P': /* COM Port */
strcat(cmd,ultoa(online==ON_LOCAL ? 0:cfg.com_port,str,10));
break;
case 'Q': /* QWK ID */
strcat(cmd,cfg.sys_id);
break;
case 'R': /* Rows */
break;
case 'S': /* File Spec */
strcat(cmd,fspec);
break;
case 'T': /* Time left in seconds */
gettimeleft();
strcat(cmd,ultoa(timeleft,str,10));
break;
case 'U': /* UART I/O Address (in hex) */
strcat(cmd,ultoa(cfg.com_base,str,16));
break;
case 'V': /* Synchronet Version */
sprintf(str,"%s%c",VERSION,REVISION);
break;
case 'W': /* Time-slice API type (mswtype) */
#if 0 //ndef __FLAT__
#endif
break;
case 'X':
strcat(cmd,cfg.shell[useron.shell]->code);
break;
case '&': /* Address of msr */
sprintf(str,"%lu",(DWORD)&fakeriobp);
strcat(cmd,str);
break;
case 'Y':
strcat(cmd,comspec);
break;
case 'Z':
strcat(cmd,cfg.text_dir);
break;
case '~': /* DOS-compatible (8.3) filename */
#ifdef _WIN32
char sfpath[MAX_PATH+1];
SAFECOPY(sfpath,fpath);
GetShortPathName(fpath,sfpath,sizeof(sfpath));
strcat(cmd,sfpath);
#else
strcat(cmd,fpath);
#endif
break;
case '!': /* EXEC Directory */
strcat(cmd,cfg.exec_dir);
break;
case '#': /* Node number (same as SBBSNNUM environment var) */
sprintf(str,"%d",cfg.node_num);
strcat(cmd,str);
break;
case '*':
sprintf(str,"%03d",cfg.node_num);
strcat(cmd,str);
break;
case '$': /* Credits */
strcat(cmd,ultoa(useron.cdt+useron.freecdt,str,10));
break;
case '%': /* %% for percent sign */
strcat(cmd,"%");
break;
case '.': /* .exe for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
strcat(cmd,".exe");
#endif
break;
case '?': /* Platform */
#ifdef __OS2__
strcpy(str,"OS2");
#else
strcpy(str,PLATFORM_DESC);
#endif
strlwr(str);
strcat(cmd,str);
break;
default: /* unknown specification */
if(isdigit(instr[i])) {
sprintf(str,"%0*d",instr[i]&0xf,useron.number);
strcat(cmd,str); }
break; }
j=strlen(cmd); }
else
cmd[j++]=instr[i]; }
cmd[j]=0;
return(cmd);
}
#ifdef __unix__
void
setup_term(int fd, char* term)
{
struct termios tt;
// Shoud set speed here...
tcgetattr(fd, &tt);
tt.c_iflag = TTYDEF_IFLAG;
tt.c_oflag = TTYDEF_OFLAG;
tt.c_lflag = TTYDEF_LFLAG;
tcsetattr(fd, TCSAFLUSH, &tt);
setenv("TERM",term,1);
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
/* The following termcap entry is nice:
<---SNIP--->
# Handy for HyperTerminal and such
ansi-bbs|ANSI terminals (emulators):\
:co#80:li#24:am:\
:bs:mi:ms:pt:xn:xo:it#8:\
:RA=\E[?7l:SA=\E?7h:\
:bl=^G:cr=^M:ta=^I:\
:@7=\E[K:kh=\E[H::cm=\E[%i%d;%dH:\
:le=^H:up=\E[A:do=\E[B:nd=\E[C:\
:LE=\E[%dD:RI=\E[%dC:UP=\E[%dA:DO=\E[%dB:\
:ho=\E[H:cl=\E[H\E[2J:ce=\E[K:cb=\E[1K:cd=\E[J:sf=\ED:sr=\EM:\
:ct=\E[3g:st=\EH:\
:cs=\E[%i%d;%dr:sc=\E7:rc=\E8:\
:ic=\E[@:IC=\E[%d@:al=\E[L:AL=\E[%dL:\
:dc=\E[P:DC=\E[%dP:dl=\E[M:DL=\E[%dM:\
:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\
:mb=\E[5m:mh=\E[2m:md=\E[1m:mr=\E[7m:me=\E[m:\
:sc=\E7:rc=\E8:\
:ku=\E[A:kd=\E[B:kr=\E[C:kl=\E[D:\
:ZG#0:ZA=\E[0%?%p1%{0}%>%p1%{4}%<%&%t;1%;%?%p2%t;7%;%?%p3%t;5%;%?%p4%t;4%;m:\
:is=:rs=\Ec:kb=^H:\
:as=\E[m:ae=:eA=:\
:ac=0\333+\257,\256.\031-\030a\261f\370g\361j\331k\277l\332m\300n\305q\304t\264u\303v\301w\302x\263~\025:\
:kD=\177:kH=\E[Y:kN=\E[U:kP=\E[V:\
:kj=\177::kf=\E[U:kg=\E[V:\
:k0=\EOP:k1=\EOQ:k2=\EOR:k3=\EOS:k4=\EOT:\
:k5=\EOU:k6=\EOV:k7=\EOW:k8=\EOX:k9=\EOY:\
:gb=\332\300\277\331\304\263:\
:Co#8:pa#64:so=\E[7m:se=\E[27m:AF=\E[3%dm:AB=\E[4%dm:op=\E[39;49m:
<---SNIP--->
*/
}
#endif