mailbox.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:41k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* There are only two functions in this mailbox code that depend on the
  2.  * underlying protocol, namely mbx_getname() and dochat(). All the other
  3.  * functions can hopefully be used without modification on other stream
  4.  * oriented protocols than AX.25 or NET/ROM.
  5.  *
  6.  * SM0RGV 890506, most work done previously by W9NK
  7.  *
  8.  *** Changed 900114 by KA9Q to use newline mapping features in stream socket
  9.  * interface code; everything here uses C eol convention (n)
  10.  *
  11.  * Numerous new commands and other changes by SM0RGV, 900120
  12.  */
  13. #include <stdio.h>
  14. #include <time.h>
  15. #include <ctype.h>
  16. #ifdef UNIX
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #endif
  20. #include "global.h"
  21. #include "config.h"
  22. #include "timer.h"
  23. #include "proc.h"
  24. #include "socket.h"
  25. #include "usock.h"
  26. #include "session.h"
  27. #include "smtp.h"
  28. #include "dirutil.h"
  29. #include "telnet.h"
  30. #include "ftp.h"
  31. #include "ftpserv.h"
  32. #include "commands.h"
  33. #include "netuser.h"
  34. #include "files.h"
  35. #include "bm.h"
  36. #include "mailbox.h"
  37. #include "ax25mail.h"
  38. #include "nr4mail.h"
  39. #include "cmdparse.h"
  40. /*
  41. #define MBDEBUG
  42. */
  43. struct mbx *Mbox[NUMMBX];
  44. static char *Motd = NULL;
  45. static int Attended = TRUE; /* default to attended mode */
  46. unsigned Maxlet = BM_NLET;
  47. char Noperm[] = "Permission denied.n";
  48. char Nosock[] = "Can't create socketn";
  49. static char Mbbanner[] = "[NET-H$]nWelcome %s to the %s TCP/IP Mailbox (%s)n%s";
  50. static char Mbmenu[] = "Current msg# %d : A,B,C,D,E,F,G,H,I,J,K,L,N,R,S,T,U,V,W,Z,? >n";
  51. static char Longmenu1[] = "(?)help    (A)rea     (B)ye      (C)hat     (D)ownload (E)scape   (F)ingern";
  52. static char Longmenu2[] = "(G)ateway  (H)elp     (I)nfo     (J)heard   (K)ill     (L)ist     (N)etromn";
  53. static char Longmenu3[] = "(R)ead     (S)end     (T)elnet   (U)pload   (V)erbose  (W)hat     (Z)apn";
  54. static char Loginbanner[] = "nKA9Q NOS (%s)nn";
  55. static char Howtoend[] = "Terminate with /EX or ^Z in first column (^A aborts):n";
  56. static int doarea(int argc,char *argv[],void *p);
  57. static int mbx_getname(struct mbx *m);
  58. /************************************************************************/
  59. /* C O M M A N D S */
  60. /************************************************************************/
  61. static int doattend(int argc,char *argv[],void *p);
  62. static int domaxmsg(int argc,char *argv[],void *p);
  63. static int domotd(int argc,char *argv[],void *p);
  64. static int dotimeout(int argc,char *argv[],void *p);
  65. /* mbox subcommand table */
  66. static struct cmds Mbtab[] = {
  67. "attend", doattend, 0, 0, NULL,
  68. #ifdef AX25
  69. "kick", dombkick, 0, 0, NULL,
  70. #endif
  71. "maxmsg", domaxmsg, 0, 0, NULL,
  72. "motd", domotd, 0, 0, NULL,
  73. "status", domboxdisplay, 0, 0, NULL,
  74. #ifdef AX25
  75. "timer", dombtimer, 0, 0, NULL,
  76. #endif
  77. "tiptimeout", dotimeout, 0, 0, NULL,
  78. NULL,
  79. };
  80. int
  81. dombox(argc,argv,p)
  82. int argc;
  83. char *argv[];
  84. void *p;
  85. {
  86. if(argc == 1)
  87. return domboxdisplay(argc,argv,p);
  88. return subcmd(Mbtab,argc,argv,p);
  89. }
  90. /* if unattended mode is set, ax25, telnet and maybe other sessions will
  91.  * be restricted.
  92.  */
  93. static int
  94. doattend(argc,argv,p)
  95. int argc;
  96. char *argv[];
  97. void *p;
  98. {
  99. return setbool(&Attended,"Attended flag",argc,argv);
  100. }
  101. static int
  102. domaxmsg(argc,argv,p)
  103. int argc;
  104. char *argv[];
  105. void *p;
  106. {
  107. return setuns(&Maxlet,"Maximum messages per area",argc,argv);
  108. }
  109. static int
  110. domotd(argc,argv,p)
  111. int argc;
  112. char *argv[];
  113. void *p;
  114. {
  115. if(argc > 2) {
  116. printf("Usage: mbox motd "<your message>"n");
  117. return 0;
  118. }
  119. if(argc < 2) {
  120. if(Motd != NULL)
  121. puts(Motd);
  122. }
  123. else {
  124. if(Motd != NULL){
  125. free(Motd);
  126. Motd = NULL; /* reset the pointer */
  127. }
  128. if(!strlen(argv[1]))
  129. return 0; /* clearing the buffer */
  130. Motd = mallocw(strlen(argv[1])+5);/* allow for the EOL char */
  131. strcpy(Motd, argv[1]);
  132. strcat(Motd, "n"); /* add the EOL char */
  133. }
  134. return 0;
  135. }
  136. int
  137. domboxdisplay(argc,argv,p)
  138. int argc;
  139. char *argv[];
  140. void *p;
  141. {
  142. int i, j, len;
  143. struct mbx *m;
  144. struct sockaddr fsocket;
  145. static char *states[] = {"LOGIN","CMD","SUBJ","DATA","REVFWD",
  146. "TRYING","FORWARD"};
  147. printf("User       State    S#  Wheren");
  148. for (i = 0; i < NUMMBX; i++){
  149. if((m = Mbox[i]) != NULL){
  150. len = MAXSOCKSIZE;
  151. j = getpeername(fileno(m->user),&fsocket,&len);
  152. printf("%-11s%-9s%-4u%sn",m->name,
  153.  states[m->state],fileno(m->user),
  154.  j != -1 ? psocket(&fsocket): "");
  155. }
  156. }
  157. return 0;
  158. }
  159. static int
  160. dotimeout(argc,argv,p)
  161. int argc;
  162. char *argv[];
  163. void *p;
  164. {
  165. return setuns(&Tiptimeout,"Tip connection timeout",argc,argv);
  166. }
  167. /**********************************************************************/
  168. void
  169. listusers(network)
  170. FILE *network;
  171. {
  172. FILE *outsave;
  173. fprintf(network,"nCurrent remote users:n");
  174. outsave = stdout;
  175. stdout = network;
  176. domboxdisplay(0,NULL,NULL);
  177. stdout = outsave;
  178. }
  179. struct mbx *
  180. newmbx()
  181. {
  182. int i;
  183. struct mbx *m;
  184. for(i = 0; i < NUMMBX; i++){
  185. if(Mbox[i] == NULL){
  186. m = Mbox[i] = (struct mbx *)callocw(1,sizeof(struct mbx));
  187. m->mbnum = i;
  188. return m;
  189. }
  190. }
  191. /* If we get here, there are no free mailbox sessions */
  192. return NULL;
  193. }
  194. static int
  195. mbx_getname(m)
  196. struct mbx *m;
  197. {
  198. #ifdef AX25
  199. char *cp;
  200. #endif
  201. union sp sp;
  202. struct sockaddr tmp;
  203. char buf[MBXLINE];
  204. int len = MAXSOCKSIZE;
  205. int anony = 0;
  206. int oldmode;
  207. sp.sa = &tmp;
  208. sp.sa->sa_family = AF_LOCAL; /* default to AF_LOCAL */
  209. getpeername(fileno(m->user),&tmp,&len);
  210. m->path = mallocw(MBXLINE);
  211. /* This is one of the two parts of the mbox code that depends on the
  212.  * underlying protocol. We have to figure out the name of the
  213.  * calling station. This is only practical when AX.25 or NET/ROM is
  214.  * used. Telnet users have to identify themselves by a login procedure.
  215.  */
  216. switch(sp.sa->sa_family){
  217. #ifdef AX25
  218. case AF_NETROM:
  219. case AF_AX25:
  220. /* NETROM and AX25 socket address structures are "compatible" */
  221. pax25(m->name,sp.ax->ax25_addr);
  222. cp = strchr(m->name,'-');
  223. if(cp != NULL) /* get rid of SSID */
  224. *cp = '';
  225. /* SMTP wants the name to be in lower case */
  226. cp = m->name;
  227. while(*cp){
  228. if(isupper(*cp))
  229. *cp = tolower(*cp);
  230. ++cp;
  231. }
  232. anony = 1;
  233. /* Try to find the privileges of this user from the userfile */
  234. if((m->privs = userlogin(m->name,buf,&m->path,MBXLINE,&anony)) == -1)
  235. if((m->privs = userlogin("bbs",buf,&m->path,MBXLINE,&anony)) == -1)
  236. if((m->privs = userlogin("anonymous",buf,&m->path,MBXLINE,
  237.  &anony)) == -1){
  238. m->privs = 0;
  239. free(m->path);
  240. m->path = NULL;
  241. }
  242. if(m->privs & EXCLUDED_CMD)
  243. return -1;
  244. return 0;
  245. #endif
  246. case AF_LOCAL:
  247. case AF_INET:
  248. m->state = MBX_LOGIN;
  249. printf(Loginbanner,Hostname);
  250. for(;;){
  251. fputs("login: ",stdout);
  252. if(mbxrecvline(m->user,m->name,sizeof(m->name),-1) == EOF)
  253. return -1;
  254. if(*m->name == '')
  255. continue;
  256. printf("Password: %c%c%c",IAC,WILL,TN_ECHO);
  257. oldmode = fmode(m->user,STREAM_BINARY);
  258. if(mbxrecvline(m->user,buf,MBXLINE,-1) == EOF)
  259. return -1;
  260. printf("%c%c%c",IAC,WONT,TN_ECHO);
  261. fmode(m->user,oldmode);
  262. putchar('n');
  263. #ifdef notdef
  264. /* This is needed if the password was send before the
  265.  * telnet no-echo options were received. We neeed to
  266.  * flush the eold sequence from the input buffers, sigh
  267.  */
  268. if(socklen(fileno(m->user),0))/* discard any remaining input */
  269. recv_mbuf(fileno(m->user),NULL,0,NULL,0);
  270. #endif
  271. if((m->privs = userlogin(m->name,buf,&m->path,MBXLINE,&anony))
  272.  != -1){
  273. if(anony)
  274. logmsg(fileno(m->user),"MBOX login: %s Password: %s",m->name,buf);
  275. else
  276. logmsg(fileno(m->user),"MBOX login: %s",m->name);
  277. if(m->privs & EXCLUDED_CMD)
  278. return -1;
  279. return 0;
  280. }
  281. printf("Login incorrectn");
  282. *m->name = ''; /* wipe any garbage */
  283. }
  284. }
  285. return 0;
  286. }
  287. /* Incoming mailbox session */
  288. void
  289. mbx_incom(s,t,p)
  290. int s;
  291. void *t;
  292. void *p;
  293. {
  294. struct mbx *m;
  295. struct usock *up;
  296. char *buf[3];
  297. int rval;
  298. FILE *network;
  299. sockowner(s,Curproc); /* We own it now */
  300. if(p == NULL)
  301. network = fdopen(s,"r+t");
  302. else
  303. network = (FILE *)p;
  304. /* Secede from the parent's sockets, and use the network socket that
  305.  * was passed to us for both input and output. The reference
  306.  * count on this socket will still be 1; this allows the domboxbye()
  307.  * command to work by closing that socket with a single call.
  308.  * If we return, the socket will be closed automatically.
  309.  */
  310. fclose(stdin);
  311. stdin = fdup(network);
  312. fclose(stdout);
  313. stdout = fdup(network);
  314. logmsg(fileno(network),"open MBOX");
  315. if((m = newmbx()) == NULL){
  316. printf("Too many mailbox sessionsn");
  317. return;
  318. }
  319. m->user = network;
  320. m->escape = 24; /* default escape character is Ctrl-X */
  321. m->type = (int) t;
  322. /* get the name of the remote station */
  323. if(mbx_getname(m) == -1) {
  324. exitbbs(m);
  325. return;
  326. }
  327. m->state = MBX_CMD; /* start in command state */
  328. /* Now say hi */
  329. printf(Mbbanner,m->name,Hostname,Version,
  330. Motd != NULL ? Motd : "");
  331. /* Enable our local message area */
  332. buf[1] = m->name;
  333. doarea(2,buf,m);
  334. printf(Mbmenu,m->current);
  335. while(mbxrecvline(network,m->line,MBXLINE,-1) != EOF){
  336. if((rval = mbx_parse(m)) == -2)
  337. break;
  338. if(rval == 1)
  339. printf("Bad syntax.n");
  340. if(!(m->sid & MBX_SID) && isnewprivmail(m) > 0L)
  341. printf("You have new mail.n");
  342. scanmail(m);
  343. printf((m->sid & MBX_SID) ? ">n" : Mbmenu, m->current);
  344. m->state = MBX_CMD;
  345. }
  346. exitbbs(m);
  347. /* nasty hack! we may have screwed up reference count */
  348. /* by invoking newproc("smtp_send",....); Fudge it!   */
  349. if((up = itop(fileno(stdout))) != NULL)
  350. up->refcnt = 1;
  351. fclose(stdout);
  352. }
  353. void
  354. exitbbs(m)
  355. struct mbx *m;
  356. {
  357. closenotes(m);
  358. free(m->to);
  359. free(m->tofrom);
  360. free(m->origto);
  361. free(m->tomsgid);
  362. free(m->path);
  363. free(m->mbox);
  364. Mbox[m->mbnum] = NULL;
  365. free(m);
  366. }
  367. /**********************************************************************/
  368. static int dochat(int argc,char *argv[],void *p);
  369. static int dodownload(int argc,char *argv[],void *p);
  370. static int dombupload(int argc,char *argv[],void *p);
  371. static int dowhat(int argc,char *argv[],void *p);
  372. static int dozap(int argc,char *argv[],void *p);
  373. static int dosend(int argc,char *argv[],void *p);
  374. static int dosid(int argc,char *argv[],void *p);
  375. static int dosysop(int argc,char *argv[],void *p);
  376. static int dostars(int argc,char *argv[],void *p);
  377. static int dombhelp(int argc,char *argv[],void *p);
  378. static int dombtelnet(int argc,char *argv[],void *p);
  379. static int dombfinger(int argc,char *argv[],void *p);
  380. static void gw_alarm(void *p);
  381. static void gw_input(int s,void *notused,void *p);
  382. static void gw_superv(int null,void *proc,void *p);
  383. static int mbx_to(int argc,char *argv[],void *p);
  384. static int mbx_data(struct mbx *m,struct list *cclist,char *extra);
  385. static int msgidcheck(char *string);
  386. static int uuencode(FILE *infile,FILE *outfile,char *infilename);
  387. static struct cmds Mbcmds[] = {
  388. "", doreadnext, 0, 0, NULL,
  389. "area", doarea, 0, 0, NULL,
  390. "send", dosend, 0, 0, NULL,
  391. "read", doreadmsg, 0, 2, "R numbers",
  392. "verbose", doreadmsg, 0, 2, "V numbers",
  393. #ifdef AX25
  394. "jheard", doaxheard, 0, 0, NULL,
  395. #endif
  396. "kill", dodelmsg, 0, 2, "K numbers",
  397. "list", dolistnotes, 0, 0, NULL,
  398. "escape", dombescape, 0, 0, NULL,
  399. "download", dodownload, 0, 2, "D[U] filename",
  400. "upload", dombupload, 0, 2, "U filename",
  401. "what", dowhat, 0, 0, NULL,
  402. "zap", dozap, 0, 2, "Z filename",
  403. #ifdef AX25
  404. "gateway", dogateway, 0, 3, "G interface callsigns",
  405. #endif
  406. "telnet", dombtelnet, 0, 2, "T hostname",
  407. "finger", dombfinger, 0, 0, NULL,
  408. #ifdef NETROM
  409. "netrom", dombnetrom, 0, 0, NULL,
  410. #endif
  411. "chat", dochat, 0, 0, NULL,
  412. "bye", domboxbye, 0, 0, NULL,
  413. "help", dombhelp, 0, 0, NULL,
  414. "info", dombhelp, 0, 0, NULL,
  415. "?", dombhelp, 0, 0, NULL,
  416. "[", dosid, 0, 0, NULL,
  417. #ifdef AX25
  418. "f>", dorevfwd, 0, 0, NULL,
  419. #endif
  420. "@", dosysop, 0, 0, NULL,
  421. "***", dostars, 0, 0, NULL,
  422. NULL, NULL, 0, 0, "Huh?",
  423. };
  424. /* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
  425.  * They have to be treated specially since cmdparse() wants a space between
  426.  * the actual command and its arguments.
  427.  * "SP FOO" is converted to "s  foo" and the second command letter is saved
  428.  * in m->stype. Longer commands like "SEND" are unaffected, except for
  429.  * commands starting with "[", i.e. the SID, since we don't know what it will
  430.  * look like.
  431.  */
  432. static char twocmds[] = "slrd["; /* S,L,R,D are two-letter commands */
  433. int
  434. mbx_parse(m)
  435. struct mbx *m;
  436. {
  437. char *cp;
  438. int i;
  439. char *newargv[2];
  440. /* Translate entire buffer to lower case */
  441. for (cp = m->line; *cp != ''; ++cp)
  442. if(isupper(*cp))
  443. *cp = tolower(*cp);
  444. /* Skip any spaces at the begining */
  445. for(cp = m->line;isspace(*cp);++cp)
  446. ;
  447. m->stype = ' ';
  448. if(*cp != '' && *(cp+1) != '')
  449. for(i=0; i<strlen(twocmds); ++i){
  450. if(*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == ''
  451.  || *cp == '[')){
  452. if(islower(*(++cp)))
  453. m->stype = toupper(*cp); /* Save the second character */
  454. else
  455. m->stype = *cp;
  456. *cp = ' ';
  457. break;
  458. }
  459. }
  460. /* See if the input line consists solely of digits */
  461. cp = m->line;
  462. for(cp = m->line;isspace(*cp);++cp)
  463. ;
  464. newargv[1] = cp;
  465. for(;*cp != '' && isdigit(*cp);++cp)
  466. ;
  467. if(*cp == '' && strlen(newargv[1]) > 0) {
  468. newargv[0] = "read";
  469. return doreadmsg(2,newargv,(void *)m);
  470. }
  471. else
  472. return cmdparse(Mbcmds,m->line,(void *)m);
  473. }
  474. /* This works like recvline(), but telnet options are answered and the
  475.  * terminating newline character is not put into the buffer. If the
  476.  * incoming character equals the value of escape, any queued input is
  477.  * flushed and -2 returned.
  478.  */
  479. int
  480. mbxrecvline(network,buf,len,escape)
  481. FILE *network;
  482. char *buf;
  483. int len;
  484. int escape;
  485. {
  486. int c, cnt = 0, opt;
  487. if(buf == NULL)
  488. return 0;
  489. fflush(stdout);
  490. while((c = getc(network)) != EOF){
  491. if(c == IAC){ /* Telnet command escape */
  492. if((c = getc(network)) == EOF)
  493. break;
  494. if(c > 250 && c < 255 && (opt = getc(network)) != EOF){
  495. #ifdef foo
  496. switch(c){
  497. case WILL:
  498. printf("%c%c%c",IAC,DONT,opt);
  499. break;
  500. case WONT:
  501. printf("%c%c%c",IAC,DONT,opt);
  502. break;
  503. case DO:
  504. printf("%c%c%c",IAC,WONT,opt);
  505. break;
  506. case DONT:
  507. printf("%c%c%c",IAC,WONT,opt);
  508. }
  509. #endif
  510. /* to be fixed  fflush(stdout);*/
  511. continue;
  512. }
  513. if(c != IAC && (c = fgetc(network)) == EOF)
  514. break;
  515. }
  516. /* ordinary character */
  517. if(c == 'r' || c == 'n')
  518. break;
  519. if(c == escape){
  520. if(socklen(fileno(network),0)) /* discard any remaining input */
  521. recv_mbuf(fileno(network),NULL,0,NULL,0);
  522. cnt = -2;
  523. break;
  524. }
  525. *buf++ = c;
  526. ++cnt;
  527. if(cnt == len - 1)
  528. break;
  529. }
  530. if(c == EOF && cnt == 0)
  531. return -1;
  532. *buf = '';
  533. return cnt;
  534. }
  535. int
  536. domboxbye(argc,argv,p)
  537. int argc;
  538. char *argv[];
  539. void *p;
  540. {
  541. struct mbx *m;
  542. m = (struct mbx *)p;
  543. /* Now say goodbye */
  544. printf("Thank you %s, for calling the %s Tcp/Ip Mailbox.n",m->name,
  545. Hostname);
  546. if(m->type == TIP)
  547. printf("Please hang up now.n");
  548. return -2; /* signal that exitbbs() should be called */
  549. }
  550. static int
  551. dombhelp(argc,argv,p)
  552. int argc;
  553. char *argv[];
  554. void *p;
  555. {
  556. char buf[255];
  557. int i;
  558. FILE *fp;
  559. if(*argv[0] == '?') {
  560. fputs(Longmenu1,stdout);
  561. fputs(Longmenu2,stdout);
  562. fputs(Longmenu3,stdout);
  563. return 0;
  564. }
  565. buf[0] = '';
  566. if(argc > 1)
  567. for(i=0; Mbcmds[i].name != NULL; ++i)
  568. if(!strncmp(Mbcmds[i].name,argv[1],strlen(argv[1]))) {
  569. sprintf(buf,"%s/%s.hlp",Helpdir,Mbcmds[i].name);
  570. break;
  571. }
  572. if(buf[0] == '')
  573. if(*argv[0] == 'i') /* INFO command */
  574. sprintf(buf,"%s/info.hlp",Helpdir);
  575. else
  576. sprintf(buf,"%s/help.hlp",Helpdir);
  577. if((fp = fopen(buf,READ_TEXT)) != NULL) {
  578. sendfile(fp,Curproc->output,ASCII_TYPE,0);
  579. fclose(fp);
  580. }
  581. else
  582. printf("No help available. (%s not found)n",buf);
  583. return 0;
  584. }
  585. static int
  586. dochat(argc,argv,p)
  587. int argc;
  588. char *argv[];
  589. void *p;
  590. {
  591. char buf[8], *newargv[3];
  592. if(Attended){
  593. newargv[0] = "telnet";
  594. newargv[1] = Hostname;
  595. sprintf(buf,"%d",IPPORT_TTYLINK);
  596. newargv[2] = buf;
  597. return dombtelnet(3,newargv,p);
  598. }
  599. else {
  600. printf("Sorry - the system is unattended.07n");
  601. }
  602. /* It returns only after a disconnect or refusal */
  603. return 0;
  604. }
  605. static int
  606. dosend(argc,argv,p)
  607. int argc;
  608. char *argv[];
  609. void *p;
  610. {
  611. int cccnt = 0, fail = 0;
  612. char *host, *cp, fullfrom[MBXLINE], sigwork[LINELEN], *rhdr = NULL;
  613. struct list *ap, *cclist = NULL;
  614. struct mbx *m;
  615. FILE *fp;
  616. m = (struct mbx *)p;
  617. if((m->stype != 'R' || (m->sid & MBX_SID)) && mbx_to(argc,argv,m)
  618.    == -1){
  619. if(m->sid & MBX_SID)
  620. printf("NO - syntax errorn");
  621. else {
  622. printf("S command syntax error - format is:n");
  623. printf("  S[F] name [@ host] [< from_addr] [$bulletin_id]n");
  624. printf("  SR [number]n");
  625. }
  626. return 0;
  627. }
  628. if(m->stype != 'R' && msgidcheck(m->tomsgid)) {
  629. if(m->sid & MBX_SID)
  630. fputs("NO - ",stdout);
  631. printf("Already have %sn",m->tomsgid);
  632. return 0;
  633. }
  634. if(m->stype == 'R' && !(m->sid & MBX_SID) &&
  635.    mbx_reply(argc,argv,m,&cclist,&rhdr) == -1)
  636. return 0;
  637. if((cp = rewrite_address(m->to)) != NULL)
  638.      if(strcmp(m->to,cp) != 0){
  639.   m->origto = m->to;
  640.   m->to = cp;
  641.      }
  642.      else
  643.   free(cp);
  644. if((m->origto != NULL || m->stype == 'R') && !(m->sid & MBX_SID))
  645. printf("To: %sn", m->to);
  646. if(validate_address(m->to) == 0){
  647. if(m->sid & MBX_SID)
  648. printf("NO - bad addressn");
  649. else
  650. printf("Bad user or host namen");
  651. free(rhdr);
  652. del_list(cclist);
  653. /* We don't free any more buffers here. They are freed upon
  654.  * the next call to mbx_to() or to domboxbye()
  655.  */
  656. return 0;
  657. }
  658. /* Display the Cc: line (during SR command) */
  659. for(ap = cclist; ap != NULL; ap = ap->next) {
  660. if(cccnt == 0){
  661. printf("%s",Hdrs[CC]);
  662. cccnt = 4;
  663. }
  664. else {
  665. fputs(", ",stdout);
  666. cccnt += 2;
  667. }
  668. if(cccnt + strlen(ap->val) > 80 - 3) {
  669. fputs("n    ",stdout);
  670. cccnt = 4;
  671. }
  672. fputs(ap->val,stdout);
  673. cccnt += strlen(ap->val);
  674. }
  675. if(cccnt)
  676. putchar('n');
  677. m->state = MBX_SUBJ;
  678. if(m->stype != 'R' || (m->sid & MBX_SID) != 0) {
  679. printf((m->sid & MBX_SID) ? "OKn" : "Subject: ");
  680. if(mbxrecvline(m->user,m->line,MBXLINE,-1) == -1)
  681. return 0;
  682. }
  683. else /* Replying to a message */
  684. printf("Subject: %sn",m->line);
  685. if(mbx_data(m,cclist,rhdr) == -1){
  686. free(rhdr);
  687. del_list(cclist);
  688. puts("Can't create temp file for mail");
  689. return 0;
  690. }
  691. free(rhdr);
  692. m->state = MBX_DATA;
  693. if((m->sid & MBX_SID) == 0 && m->stype != 'F')
  694. printf("Enter message.  %s",Howtoend);
  695. if(m->stype != 'F' || (m->sid & MBX_SID) != 0)
  696. while(mbxrecvline(m->user,m->line,MBXLINE,-1) != -1){
  697. if(m->line[0] == 0x01){  /* CTRL-A */
  698. fclose(m->tfile);
  699. puts("Aborted.");
  700. del_list(cclist);
  701. return 0;
  702. }
  703. if(m->line[0] != CTLZ && stricmp(m->line, "/ex"))
  704. fprintf(m->tfile,"%sn",m->line);
  705. else
  706. break; /* all done */
  707. }
  708. else {
  709. fprintf(m->tfile,"----- Forwarded message -----nn");
  710. msgtofile(m,m->current,m->tfile,0);
  711. fprintf(m->tfile,"----- End of forwarded message -----n");
  712. }
  713. /* Insert customised signature if one is found */
  714. if(!(m->sid & MBX_SID)) { /* not a forwarding BBS */
  715.      sprintf(sigwork,"%s/%s.sig",Signature,
  716.      m->tofrom ? m->tofrom : m->name);
  717.      if((fp = fopen(sigwork,READ_TEXT)) != NULL){
  718.   while(fgets(sigwork,LINELEN,fp) != NULL)
  719. fputs(sigwork,m->tfile);
  720.   fclose(fp);
  721.      }
  722. }
  723. if((host = strrchr(m->to,'@')) == NULL) {
  724. host = Hostname; /* use our hostname */
  725. if(m->origto != NULL) {
  726. /* rewrite_address() will be called again by our
  727.  * SMTP server, so revert to the original address.
  728.  */
  729.   free(m->to);
  730. m->to = m->origto;
  731. m->origto = NULL;
  732. }
  733. }
  734. else
  735. host++; /* use the host part of address */
  736. /* make up full from name for work file */
  737. if(m->tofrom != NULL)
  738. sprintf(fullfrom,"%s%%%s.bbs@%s",m->tofrom, m->name, Hostname);
  739. else
  740. sprintf(fullfrom,"%s@%s",m->name,Hostname);
  741. if(cclist != NULL && stricmp(host,Hostname) != 0) {
  742. fseek(m->tfile,0L,0); /* reset to beginning */
  743. fail = queuejob(m->tfile,Hostname,cclist,fullfrom);
  744. del_list(cclist);
  745. cclist = NULL;
  746. }
  747. addlist(&cclist,m->to,0);
  748. fseek(m->tfile,0L,0);
  749. fail += queuejob(m->tfile,host,cclist,fullfrom);
  750. del_list(cclist);
  751. fclose(m->tfile);
  752. if(fail)
  753.      puts("Couldn't queue message for delivery");
  754. else
  755.      if(m->tomsgid != NULL &&
  756. (fp = fopen(Historyfile,APPEND_TEXT)) != NULL) {
  757.   fprintf(fp,"%sn",m->tomsgid); /* Save BID in history file */
  758.   fclose(fp);
  759.      }
  760. smtptick(0L); /* wake SMTP to send that mail */
  761. return 0;
  762. }
  763. static int
  764. dosid(argc,argv,p)
  765. int argc;
  766. char *argv[];
  767. void *p;
  768. {
  769. struct mbx *m;
  770. char *cp;
  771. m = (struct mbx *)p;
  772. if(argc == 1)
  773. return 1;
  774. if(argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
  775. return 1;
  776. m->sid = MBX_SID;
  777. /* Now check to see if this is an RLI board.
  778.  * As usual, Hank does it a bit differently from
  779.  * the rest of the world.
  780.  */
  781. if(m->stype == 'R' && strncmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
  782. m->sid |= MBX_RLI_SID;
  783. /* Check to see if the BBS supports a kludge called "hierarchical
  784.  * routing designators."
  785.  *
  786.  * No need to check for ']' -- it must be there or this is not
  787.  * a valid mbox id -- it is checked earlier (fix de OH3LKU)
  788.  */
  789. if((cp = strchr(argv[1],'-')) != NULL
  790.  && (cp=strchr(cp+1,'h')) != NULL
  791.  && strchr(cp+1,'$'))
  792. m->sid |= MBX_HIER_SID;
  793. return 0;
  794. }
  795. int
  796. dombescape(argc,argv,p)
  797. int argc;
  798. char *argv[];
  799. void *p;
  800. {
  801. struct mbx *m;
  802. m = (struct mbx *)p;
  803. if(argc < 2){
  804. printf("The escape character is: ");
  805. if(m->escape < 32)
  806. printf("CTRL-%cn",m->escape+'A'-1);
  807. else
  808. printf("'%c'n",m->escape);
  809. return 0;
  810. }
  811. if(strlen(argv[1]) > 1)
  812. if(isdigit(*argv[1]))
  813. m->escape = (char) atoi(argv[1]);
  814. else
  815. return 1;
  816. else
  817. m->escape = *argv[1];
  818. return 0;
  819. }
  820. static int
  821. dodownload(argc,argv,p)
  822. int argc;
  823. char *argv[];
  824. void *p;
  825. {
  826. struct mbx *m;
  827. FILE *fp;
  828. char *file;
  829. m = (struct mbx *)p;
  830. file = pathname(m->path,argv[1]);
  831. if(!permcheck(m->path,m->privs,RETR_CMD,file)){
  832. printf(Noperm);
  833. return 0;
  834. }
  835. if((fp = fopen(file,READ_TEXT)) == NULL)
  836. printf("Can't open "%s": %sn",file,sys_errlist[errno]);
  837. else
  838. if(m->stype == 'U'){ /* uuencode ? */
  839. fclose(fp);
  840. fp = fopen(file,READ_BINARY); /* assume non-ascii */
  841. uuencode(fp,m->user,file);
  842. } else
  843. sendfile(fp,m->user,ASCII_TYPE,0);
  844. free(file);
  845. fclose(fp);
  846. return 0;
  847. }
  848. static int
  849. dombupload(argc,argv,p)
  850. int argc;
  851. char *argv[];
  852. void *p;
  853. {
  854. struct mbx *m;
  855. FILE *fp;
  856. char *file, buf[LINELEN];
  857. m = (struct mbx *)p;
  858. file = pathname(m->path,argv[1]);
  859. if(!permcheck(m->path,m->privs,STOR_CMD,file)){
  860. printf(Noperm);
  861. return 0;
  862. }
  863. if((fp = fopen(file,WRITE_TEXT)) == NULL){
  864. printf("Can't create "%s": %sn",file,sys_errlist[errno]);
  865. free(file);
  866. return 0;
  867. }
  868. logmsg(fileno(m->user),"MBOX upload: %s",file);
  869. printf("Send file,  %s",Howtoend);
  870. for(;;){
  871. if(mbxrecvline(m->user,buf,LINELEN,-1) == -1){
  872. unlink(file);
  873. break;
  874. }
  875. if(buf[0] == 0x01){  /* CTRL-A */
  876. unlink(file);
  877. printf("Aborted.n");
  878. break;
  879. }
  880. if(buf[0] == CTLZ || !stricmp("/ex",buf))
  881. break;
  882. fputs(buf,fp);
  883. #if !defined(UNIX) && !defined(__TURBOC__) && !defined(AMIGA)
  884. /* Needed only if the OS uses a CR/LF
  885.  * convention and putc doesn't do
  886.  * an automatic translation
  887.  */
  888. if(putc('r',fp) == EOF)
  889. break;
  890. #endif
  891. if(putc('n',fp) == EOF)
  892. break;
  893. }
  894. free(file);
  895. fclose(fp);
  896. return 0;
  897. }
  898. static int
  899. dowhat(argc,argv,p)
  900. int argc;
  901. char *argv[];
  902. void *p;
  903. {
  904. struct mbx *m;
  905. FILE *fp;
  906. char *file;
  907. m = (struct mbx *)p;
  908. if(argc < 2)
  909. file = strdup(m->path);
  910. else
  911. file = pathname(m->path,argv[1]);
  912. if(!permcheck(m->path,m->privs,RETR_CMD,file)){
  913. printf(Noperm);
  914. return 0;
  915. }
  916. if((fp = dir(file,1)) == NULL)
  917. printf("Can't read directory: "%s": %sn",file,sys_errlist[errno]);
  918. else
  919. sendfile(fp,m->user,ASCII_TYPE,0);
  920. free(file);
  921. fclose(fp);
  922. return 0;
  923. }
  924. static int
  925. dozap(argc,argv,p)
  926. int argc;
  927. char *argv[];
  928. void *p;
  929. {
  930. struct mbx *m;
  931. char *file;
  932. m = (struct mbx *)p;
  933. file = pathname(m->path,argv[1]);
  934. if(!permcheck(m->path,m->privs,DELE_CMD,file)){
  935. printf(Noperm);
  936. return 0;
  937. }
  938. if(unlink(file))
  939. printf("Zap failed: %sn",sys_errlist[errno]);
  940. logmsg(fileno(m->user),"MBOX Zap: %s",file);
  941. free(file);
  942. return 0;
  943. }
  944. static int
  945. dosysop(argc,argv,p)
  946. int argc;
  947. char *argv[];
  948. void *p;
  949. {
  950. struct mbx *m;
  951. int c;
  952. extern struct cmds Cmds[];
  953. m = (struct mbx *) p;
  954. if(!(m->privs & SYSOP_CMD)){
  955. printf(Noperm);
  956. return 0;
  957. }
  958. dombescape(1,NULL,p);
  959. for(;;){
  960. printf("Net> ");
  961. fflush(stdout);
  962. c = mbxrecvline(stdin,m->line,MBXLINE,m->escape);
  963. if(c == EOF || c == -2)
  964. break;
  965. logmsg(fileno(m->user),"MBOX sysop: %s",m->line);
  966. cmdparse(Cmds,m->line,NULL);
  967. }
  968. return 0;
  969. }
  970. /* Handle the "*** Done" command when reverse forwarding ends or the
  971.  * "*** LINKED to" command.
  972.  */
  973. static int
  974. dostars(argc,argv,p)
  975. int argc;
  976. char *argv[];
  977. void *p;
  978. {
  979. struct mbx *m;
  980. int anony = 1;
  981. m = (struct mbx *)p;
  982. /* The "*** LINKED to" command is only allowed to stations with
  983.  * SYSOP privileges to prevent others from obtaining the same.
  984.  */
  985. if((m->privs & SYSOP_CMD) && argc == 4 && !strcmp(argv[1],"linked")) {
  986. strcpy(m->name,argv[3]);
  987. /* Try to find the privileges of this user from the userfile */
  988. if((m->privs = userlogin(m->name,NULL,&m->path,MBXLINE,
  989.  &anony)) == -1)
  990.      if((m->privs = userlogin("bbs",NULL,&m->path,
  991.       MBXLINE,&anony)) == -1)
  992.   if((m->privs = userlogin("anonymous",NULL,
  993.    &m->path,MBXLINE,&anony)) == -1){
  994. m->privs = 0;
  995. free(m->path);
  996. m->path = NULL;
  997.   }
  998. printf("Oh, hello %s.n",m->name);
  999. if(m->privs & EXCLUDED_CMD)
  1000. return domboxbye(0,NULL,p);
  1001. changearea(m,m->name);
  1002. return 0;
  1003. }
  1004. if(argc > 1 && (m->sid & MBX_SID)) /* "*** Done" or similar */
  1005. return 2;
  1006. return -1;
  1007. }
  1008. static int
  1009. doarea(argc,argv,p)
  1010. int argc;
  1011. char *argv[];
  1012. void *p;
  1013. {
  1014. struct mbx *m;
  1015. FILE *fp;
  1016. m = (struct mbx *) p;
  1017. if(argc < 2){
  1018. printf("Current message area is: %sn",m->area);
  1019. printf("Available areas are:n%-15s  Your private mail arean",
  1020.   m->name);
  1021. if((fp = fopen(Arealist,READ_TEXT)) == NULL)
  1022. return 0;
  1023. sendfile(fp,m->user,ASCII_TYPE,0);
  1024. fclose(fp);
  1025. return 0;
  1026. }
  1027. if((m->privs & SYSOP_CMD) || strcmp(m->name,argv[1]) == 0){
  1028. changearea(m,argv[1]);
  1029. if(m->nmsgs){
  1030. if(!strcmp(m->name,m->area))
  1031. printf("You have ");
  1032. else
  1033. printf("%s: ",m->area);
  1034. printf("%d message%s -  %d new.n", m->nmsgs,
  1035.   m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  1036. }
  1037. return 0;
  1038. }
  1039. if(isarea(argv[1])) {
  1040. changearea(m,argv[1]);
  1041. printf("%s: %d message%s.n", m->area, m->nmsgs,
  1042.   m->nmsgs == 1 ? "" : "s");
  1043. }
  1044. else
  1045. printf("No such message area: %sn",argv[1]);
  1046. return 0;
  1047. }
  1048. /* subroutine to do the actual switch from one area to another */
  1049. void
  1050. changearea(m,area)
  1051. struct mbx *m;
  1052. char *area;
  1053. {
  1054. closenotes(m);
  1055. m->nmsgs = m->newmsgs = m->current = 0;
  1056. strcpy(m->area,area);
  1057. scanmail(m);
  1058. }
  1059. static int
  1060. dombtelnet(argc,argv,p)
  1061. int argc;
  1062. char *argv[];
  1063. void *p;
  1064. {
  1065. struct mbx *m;
  1066. int s, len, i;
  1067. struct sockaddr dsocket;
  1068. struct sockaddr_in fsocket;
  1069. m = (struct mbx *) p;
  1070. fsocket.sin_family = AF_INET;
  1071. if(argc < 3)
  1072. fsocket.sin_port = IPPORT_TELNET;
  1073. else
  1074. fsocket.sin_port = atoi(argv[2]);
  1075. if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
  1076. printf(Badhost,argv[1]);
  1077. return 0;
  1078. }
  1079. /* Only local telnets are are allowed to the unprivileged user */
  1080. if(!(m->privs & TELNET_CMD) && !ismyaddr(fsocket.sin_addr.s_addr)){
  1081. printf(Noperm);
  1082. return 0;
  1083. }
  1084. if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  1085. printf(Nosock);
  1086. return 0;
  1087. }
  1088. if(fsocket.sin_port == IPPORT_TTYLINK) {
  1089. m->startmsg = mallocw(80);
  1090. len = MAXSOCKSIZE;
  1091. i = getpeername(fileno(m->user),&dsocket,&len);
  1092. sprintf(m->startmsg,"*** Incoming call from %s@%s ***n",
  1093. m->name,i != -1 ? psocket(&dsocket): Hostname);
  1094. }
  1095. return gw_connect(m,s,(struct sockaddr *)&fsocket,SOCKSIZE);
  1096. }
  1097. static int
  1098. dombfinger(argc,argv,p)
  1099. int argc;
  1100. char *argv[];
  1101. void *p;
  1102. {
  1103. struct mbx *m;
  1104. char *host, *user = NULL, buf[8], *newargv[3];
  1105. if(argc > 2){
  1106. printf("Usage: F user@host  or  F @host  or  F user.n");
  1107. return 0;
  1108. }
  1109. host = Hostname;
  1110. if(argc == 2){
  1111. if((host = strchr(argv[1], '@')) != NULL){
  1112. *host = '';
  1113. host++;
  1114. } else
  1115. host = Hostname;
  1116. user = argv[1];
  1117. }
  1118. m = (struct mbx *) p;
  1119. m->startmsg = mallocw(80);
  1120. if(user != NULL)
  1121. sprintf(m->startmsg,"%sn",user);
  1122. else
  1123. strcpy(m->startmsg,"n");
  1124. newargv[0] = "telnet";
  1125. newargv[1] = host;
  1126. sprintf(buf,"%d",IPPORT_FINGER);
  1127. newargv[2] = buf;
  1128. return dombtelnet(3,newargv,p);
  1129. }
  1130. /* Generic mbox gateway code. It sends and frees the contents of m->startmsg
  1131.  * when the connection has been established unless it a null pointer.
  1132.  */
  1133. int
  1134. gw_connect(m,s,fsocket,len)
  1135. struct mbx *m;
  1136. int s;
  1137. struct sockaddr *fsocket;
  1138. int len;
  1139. {
  1140. int c;
  1141. char *cp;
  1142. struct proc *child;
  1143. struct gwalarm *gwa;
  1144. FILE *network;
  1145. child = newproc("gateway supervisor",256,gw_superv,0,Curproc,m,0);
  1146. printf("Trying %s...  ",psocket(fsocket));
  1147. dombescape(0,NULL,(void *)m);
  1148. fflush(stdout);
  1149. if(connect(s,fsocket,len) == -1){
  1150. cp = sockerr(s);
  1151. printf("Connection failed: ");
  1152. if(cp != NULL)
  1153. printf("%s errno %dn",cp,errno);
  1154. else
  1155. printf("Escape character sent.n");
  1156. free(m->startmsg);
  1157. m->startmsg = NULL;
  1158. killproc(child);
  1159. close_s(s);
  1160. return 0;
  1161. }
  1162. network = fdopen(s,"r+t");
  1163. /* The user did not type the escape character */
  1164. killproc(child);
  1165. puts("Connected.");
  1166. if(m->startmsg != NULL){
  1167. fputs(m->startmsg,network);
  1168. free(m->startmsg);
  1169. m->startmsg = NULL;
  1170. }
  1171. /* Since NOS does not flush the output socket after a certain
  1172.  * period of time, we have to arrange that ourselves.
  1173.  */
  1174. gwa = (struct gwalarm *) mallocw(sizeof(struct gwalarm));
  1175. gwa->s1 = stdout;
  1176. gwa->s2 = network;
  1177. set_timer(&gwa->t,240L);
  1178. gwa->t.func = gw_alarm;
  1179. gwa->t.arg = (void *) gwa;
  1180. start_timer(&gwa->t);
  1181. /* Fork off the receive process */
  1182. child = newproc("gateway in",1024,gw_input,s,(void *)network,Curproc,0);
  1183. for(;;){
  1184. if((c = getchar()) == EOF)
  1185. break;
  1186. if(c == m->escape){
  1187. puts("Disconnecting.");
  1188. if(socklen(fileno(stdin),0))
  1189. recv_mbuf(fileno(stdin),NULL,0,NULL,0);
  1190. break;
  1191. }
  1192. if(putc(c,network) == EOF)
  1193. break;
  1194. }
  1195. stop_timer(&gwa->t);
  1196. free(gwa);
  1197. fclose(network);
  1198. killproc(child); /* get rid of the receive process */
  1199. printf("%c%c%cn",IAC,WONT,TN_ECHO);
  1200. return 0;
  1201. }
  1202. static void
  1203. gw_input(s,n,p)
  1204. int s;
  1205. void *n;
  1206. void *p;
  1207. {
  1208. int c;
  1209. char *cp;
  1210. struct proc *parent;
  1211. FILE *network;
  1212. network = (FILE *)n;
  1213. parent = (struct proc *) p;
  1214. while((c = getc(network)) != EOF)
  1215. putchar((char)c);
  1216. printf("Disconnected ");
  1217. cp = sockerr(fileno(network));
  1218. if(cp != NULL)
  1219. puts(cp);
  1220. /* Tell the parent that we are no longer connected */
  1221. alert(parent,ENOTCONN);
  1222. kwait(Curproc); /* Now wait to be killed */
  1223. }
  1224. /* Check if the escape character is typed while the parent process is busy
  1225.  * doing other things. 
  1226.  */
  1227. static void
  1228. gw_superv(null,proc,p)
  1229. int null;
  1230. void *proc;
  1231. void *p;
  1232. {
  1233. struct proc *parent;
  1234. struct mbx *m;
  1235. int c;
  1236. parent = (struct proc *) proc;
  1237. m = (struct mbx *) p;
  1238. while((c = getchar()) != EOF)
  1239. if(c == m->escape){
  1240. /* flush anything in the input queue */
  1241. if(socklen(fileno(stdin),0))
  1242. recv_mbuf(fileno(stdin),NULL,0,NULL,0);
  1243. break;
  1244. }
  1245. alert(parent,EINTR);  /* Tell the parent to quit */
  1246. kwait(Curproc);  /* Please kill me */
  1247. }
  1248. static void
  1249. gw_alarm(p)
  1250. void *p;
  1251. {
  1252. struct gwalarm *gwa = (struct gwalarm *)p;
  1253. char oldbl;
  1254. struct usock *up;
  1255. /* Flush sockets s1 and s2, but first make sure that the socket
  1256.  * is set to non-blocking mode, to prevent the flush from blocking
  1257.  * if the high water mark has been reached.
  1258.  */
  1259. if((up = itop(fileno(gwa->s1))) != NULL) {
  1260. oldbl = up->noblock;
  1261. up->noblock = 1;
  1262. fflush(gwa->s1);
  1263. up->noblock = oldbl;
  1264. }
  1265. if((up = itop(fileno(gwa->s2))) != NULL) {
  1266. oldbl = up->noblock;
  1267. up->noblock = 1;
  1268. fflush(gwa->s2);
  1269. up->noblock = oldbl;
  1270. }
  1271. start_timer(&gwa->t);
  1272. }
  1273. /* States for send line parser state machine */
  1274. #define LOOK_FOR_USER 2
  1275. #define IN_USER 3
  1276. #define AFTER_USER 4
  1277. #define LOOK_FOR_HOST 5
  1278. #define IN_HOST 6
  1279. #define AFTER_HOST 7
  1280. #define LOOK_FOR_FROM 8
  1281. #define IN_FROM 9
  1282. #define AFTER_FROM 10
  1283. #define LOOK_FOR_MSGID 11
  1284. #define IN_MSGID 12
  1285. #define FINAL_STATE 13
  1286. #define ERROR_STATE 14
  1287. /* Prepare the addressee.  If the address is bad, return -1, otherwise
  1288.  * return 0
  1289.  */
  1290. static int
  1291. mbx_to(argc,argv,p)
  1292. int argc;
  1293. char *argv[];
  1294. void *p;
  1295. {
  1296. register char *cp;
  1297. int state, i;
  1298. char *user, *host, *from, *msgid;
  1299. int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0;
  1300. struct mbx *m;
  1301. m = (struct mbx *)p;
  1302. /* Free anything that might be allocated
  1303.  * since the last call to mbx_to() or mbx_reply()
  1304.  */
  1305. free(m->to);
  1306. m->to = NULL;
  1307. free(m->tofrom);
  1308. m->tofrom = NULL;
  1309. free(m->tomsgid);
  1310. m->tomsgid = NULL;
  1311. free(m->origto);
  1312. m->origto = NULL;
  1313. if(argc == 1)
  1314. return -1;
  1315. i = 1;
  1316. cp = argv[i];
  1317. state = LOOK_FOR_USER;
  1318. while(state < FINAL_STATE){
  1319. #ifdef MBDEBUG
  1320. printf("State is %d, char is %cn", state, *cp);
  1321. #endif
  1322. switch(state){
  1323. case LOOK_FOR_USER:
  1324. if(*cp == '@' || *cp == '<' || *cp == '$'){
  1325. state = ERROR_STATE; /* no user */
  1326. } else {
  1327. user = cp; /* point at start */
  1328. userlen++; /* start counting */
  1329. state = IN_USER;
  1330. }
  1331. break;
  1332. case IN_USER:
  1333. switch(*cp){
  1334. case '':
  1335. state = AFTER_USER; /* done with username */
  1336. break;
  1337. case '@':
  1338. state = LOOK_FOR_HOST; /* hostname should follow */
  1339. break;
  1340. case '<':
  1341. state = LOOK_FOR_FROM; /* from name should follow */
  1342. break;
  1343. case '$':
  1344. state = LOOK_FOR_MSGID; /* message id should follow */
  1345. break;
  1346. default:
  1347. userlen++; /* part of username */
  1348. }
  1349. break;
  1350. case AFTER_USER:
  1351. switch(*cp){
  1352. case '@':
  1353. state = LOOK_FOR_HOST; /* hostname follows */
  1354. break;
  1355. case '<':
  1356. state = LOOK_FOR_FROM; /* fromname follows */
  1357. break;
  1358. case '$':
  1359. state = LOOK_FOR_MSGID; /* message id follows */
  1360. break;
  1361. default:
  1362. state = ERROR_STATE;
  1363. }
  1364. break;
  1365. case LOOK_FOR_HOST:
  1366. if(*cp == '@' || *cp == '<' || *cp == '$'){
  1367. state = ERROR_STATE;
  1368. break;
  1369. }
  1370. if(*cp == '')
  1371. break;
  1372. host = cp;
  1373. hostlen++;
  1374. state = IN_HOST;
  1375. break;
  1376. case IN_HOST:
  1377. switch(*cp){
  1378. case '':
  1379. state = AFTER_HOST; /* found user@host */
  1380. break;
  1381. case '@':
  1382. state = ERROR_STATE; /* user@host@? */
  1383. break;
  1384. case '<':
  1385. state = LOOK_FOR_FROM; /* fromname follows */
  1386. break;
  1387. case '$':
  1388. state = LOOK_FOR_MSGID; /* message id follows */
  1389. break;
  1390. default:
  1391. hostlen++;
  1392. }
  1393. break;
  1394. case AFTER_HOST:
  1395. switch(*cp){
  1396. case '@':
  1397. state = ERROR_STATE; /* user@host @ */
  1398. break;
  1399. case '<':
  1400. state = LOOK_FOR_FROM; /* user@host < */
  1401. break;
  1402. case '$':
  1403. state = LOOK_FOR_MSGID; /* user@host $ */
  1404. break;
  1405. default:
  1406. state = ERROR_STATE; /* user@host foo */
  1407. }
  1408. break;
  1409. case LOOK_FOR_FROM:
  1410. if(*cp == '@' || *cp == '<' || *cp == '$'){
  1411. state = ERROR_STATE;
  1412. break;
  1413. }
  1414. if(*cp == '')
  1415. break;
  1416. from = cp;
  1417. fromlen++;
  1418. state = IN_FROM;
  1419. break;
  1420. case IN_FROM:
  1421. switch(*cp){
  1422. case '':
  1423. state = AFTER_FROM; /* user@host <foo */
  1424. break;
  1425. case '<':
  1426. state = ERROR_STATE; /* user@host <foo< */
  1427. break;
  1428. case '$':
  1429. state = LOOK_FOR_MSGID; /* message id follows */
  1430. break;
  1431. default:
  1432. fromlen++;
  1433. }
  1434. break;
  1435. case AFTER_FROM:
  1436. switch(*cp){
  1437. case '@': /* user@host <foo @ */
  1438. case '<': /* user@host <foo < */
  1439. state = ERROR_STATE;
  1440. break;
  1441. case '$':
  1442. state = LOOK_FOR_MSGID; /* user@host <foo $ */
  1443. break;
  1444. default:
  1445. state = ERROR_STATE; /* user@host foo */
  1446. }
  1447. break;
  1448. case LOOK_FOR_MSGID:
  1449. if(*cp == '')
  1450. break;
  1451. msgid = cp;
  1452. msgidlen++;
  1453. state = IN_MSGID;
  1454. break;
  1455. case IN_MSGID:
  1456. if(*cp == '')
  1457. state = FINAL_STATE;
  1458. else
  1459. msgidlen++;
  1460. break;
  1461. default:
  1462. /* what are we doing in this state? */
  1463. state = ERROR_STATE;
  1464. }
  1465. if(*(cp) == ''){
  1466. ++i;
  1467. if(i < argc)
  1468. cp = argv[i];
  1469. else break;
  1470. } else
  1471. ++cp;
  1472. }
  1473. if(state == ERROR_STATE || state == LOOK_FOR_HOST
  1474.  || state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
  1475. return -1; /* syntax error */
  1476. m->to = mallocw(userlen + hostlen + 2);
  1477. strncpy(m->to, user, userlen);
  1478. m->to[userlen] = '';
  1479. if(hostlen){
  1480. m->to[userlen] = '@';
  1481. strncpy(m->to + userlen + 1, host, hostlen);
  1482. m->to[userlen + hostlen + 1] = '';
  1483. }
  1484. if(fromlen){
  1485. m->tofrom = mallocw(fromlen + 1);
  1486. strncpy(m->tofrom, from, fromlen);
  1487. m->tofrom[fromlen] = '';
  1488. }
  1489. if(msgidlen){
  1490. m->tomsgid = mallocw(msgidlen + 1);
  1491. strncpy(m->tomsgid, msgid, msgidlen);
  1492. m->tomsgid[msgidlen] = '';
  1493. }
  1494. return 0;
  1495. }
  1496. /* This opens the data file and writes the mail header into it.
  1497.  * Returns 0 if OK, and -1 if not.
  1498.  */
  1499. static int
  1500. mbx_data(m,cclist,extra)
  1501. struct mbx *m;
  1502. struct list *cclist; /* list of carbon copy recipients */
  1503. char *extra; /* optional extra header lines */
  1504. {
  1505. time_t t;
  1506. struct list *ap;
  1507. int cccnt = 0;
  1508. if((m->tfile = tmpfile()) == NULL)
  1509. return -1;
  1510. time(&t);
  1511. fprintf(m->tfile,Hdrs[RECEIVED]);
  1512. if(m->tofrom != NULL)
  1513. fprintf(m->tfile,"from %s.bbs ",m->name);
  1514. fprintf(m->tfile,"by %s (%s)ntid AA%ld ; %s",
  1515. Hostname, Version, get_msgid(), ptime(&t));
  1516. fprintf(m->tfile,"%s%s",Hdrs[DATE],ptime(&t));
  1517. fprintf(m->tfile,Hdrs[MSGID]);
  1518. if(m->tomsgid)
  1519. fprintf(m->tfile,"<%s@%s.bbs>n", m->tomsgid, m->name);
  1520. else
  1521. fprintf(m->tfile,"<%ld@%s>n",get_msgid(), Hostname);
  1522. fprintf(m->tfile,Hdrs[FROM]);
  1523. if(m->tofrom)
  1524. fprintf(m->tfile,"%s%%%s.bbs@%sn",
  1525. m->tofrom, m->name, Hostname);
  1526. else
  1527. fprintf(m->tfile,"%s@%sn", m->name, Hostname);
  1528. fprintf(m->tfile,"%s%sn",Hdrs[TO],m->origto != NULL ? m->origto : m->to);
  1529. /* Write Cc: line */
  1530. for(ap = cclist; ap != NULL; ap = ap->next) {
  1531. if(cccnt == 0){
  1532. fprintf(m->tfile,"%s",Hdrs[CC]);
  1533. cccnt = 4;
  1534. }
  1535. else {
  1536.        fprintf(m->tfile,", ");
  1537.        cccnt += 2;
  1538. }
  1539. if(cccnt + strlen(ap->val) > 80 - 3) {
  1540.        fprintf(m->tfile,"n    ");
  1541.        cccnt = 4;
  1542. }
  1543. fputs(ap->val,m->tfile);
  1544. cccnt += strlen(ap->val);
  1545. }
  1546. if(cccnt)
  1547. fputc('n',m->tfile);
  1548. fprintf(m->tfile,"%s%sn",Hdrs[SUBJECT],m->line);
  1549. if(!isspace(m->stype) && ((m->stype != 'R' && m->stype != 'F') ||
  1550.   (m->sid & MBX_SID) !=0))
  1551.   fprintf(m->tfile,"%s%cn", Hdrs[BBSTYPE],m->stype);
  1552. if(extra != NULL)
  1553. fprintf(m->tfile,extra);
  1554. fprintf(m->tfile,"n");
  1555. return 0;
  1556. }
  1557. /* Returns true if string is in history file or if string appears to be a
  1558.  * message id generated by our system.
  1559.  */
  1560. static int
  1561. msgidcheck(string)
  1562. char *string;
  1563. {
  1564.      FILE *fp;
  1565.      char buf[LINELEN], *cp;
  1566.      if(string == NULL)
  1567.   return 0;
  1568.      /* BID's that we have generated ourselves are not kept in the history
  1569.       * file. Such BID's are in the nnnn_hhhh form, where hhhh is a part of
  1570.       * our hostname, truncated so that the BID is no longer than 11
  1571.       * characters.
  1572.       */
  1573.      if((cp = strchr(string,'_')) != NULL && *(cp+1) != '' && 
  1574. strnicmp(cp+1,Hostname,strlen(cp+1)) == 0)
  1575.   return 1;
  1576.      if((fp = fopen(Historyfile,READ_TEXT)) == NULL)
  1577.   return 0;
  1578.      while(fgets(buf,LINELEN,fp) != NULL) {
  1579.   rip(buf);
  1580.   if(stricmp(string,buf) == 0) { /* found */
  1581.        fclose(fp);
  1582.        return 1;
  1583.   }
  1584.      }
  1585.      fclose(fp);
  1586.      return 0;
  1587. }
  1588.      
  1589. /* uuencode a file -- translated from C++; both versions copyright 1990
  1590.    by David R. Evans, G4AMJ/NQ0I
  1591. */
  1592. static int
  1593. uuencode(infile,outfile,infilename)
  1594. FILE *infile;
  1595. FILE *outfile;
  1596. char *infilename;
  1597. {
  1598.   int n_read_so_far = 0, n_written_so_far = 0, in_chars, n, mode = 0755;
  1599.   int32 cnt = 0;
  1600.   unsigned char in[3], out[4], line[100];
  1601. #ifdef UNIX
  1602.   struct stat stb;
  1603.   
  1604.   if(stat(infilename,&stb) != -1)
  1605.        mode = stb.st_mode & 0777; /* get real file protection mode */
  1606. #endif
  1607.   fprintf(outfile, "begin %03o %sn", mode, infilename);
  1608.   /* do the encode */
  1609.   for(;;) {
  1610.     in_chars = fread(in, 1, 3, infile);
  1611.     out[0] = in[0] >> 2;
  1612.     out[1] = in[0] << 6;
  1613.     out[1] = out[1] >> 2;
  1614.     out[1] = out[1] | (in[1] >> 4);
  1615.     out[2] = in[1] << 4;
  1616.     out[2] = out[2] >> 2;
  1617.     out[2] = out[2] | (in[2] >> 6);
  1618.     out[3] = in[2] << 2;
  1619.     out[3] = out[3] >> 2;
  1620.     for (n = 0; n < 4; n++)
  1621.       out[n] += ' ';
  1622.     n_read_so_far += in_chars;
  1623.     for (n = 0; n < 4; n++)
  1624.       line[n_written_so_far++] = out[n];
  1625.     if (((in_chars != 3) || (n_written_so_far == 60)) && n_read_so_far > 0) {
  1626.       line[(n_read_so_far + 2) / 3 * 4] = '';
  1627.       
  1628.       fprintf(outfile,"%c%sn",n_read_so_far + ' ', line);
  1629.       cnt += n_read_so_far;
  1630.       n_read_so_far = 0;
  1631.       n_written_so_far = 0;
  1632.     }
  1633.     if (in_chars == 0)
  1634.       break;
  1635.   }
  1636.   if (fprintf(outfile," nendnsize %lun", cnt) == EOF)
  1637.     return 1;
  1638.   return 0;
  1639. }