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

TCP/IP协议栈

开发平台:

Visual C++

  1. /* POP Server state machine - see RFC 937
  2.  *
  3.  *  also see other credits in popcli.c
  4.  *  10/89 Mike Stockett wa7dyx
  5.  *  Modified 5/27/90 by Allen Gwinn, N5CKP, for later NOS releases.
  6.  *  Added to NOS by PA0GRI 2/6/90 (and linted into "standard" C)
  7.  */
  8. #include <stdio.h>
  9. #include <time.h>
  10. #include <sys/stat.h>
  11. #ifdef UNIX
  12. #include <sys/types.h>
  13. #endif
  14. #if defined(__STDC__) || defined(__TURBOC__)
  15. #include <stdarg.h>
  16. #endif
  17. #include <ctype.h>
  18. #include <setjmp.h>
  19. #include "global.h"
  20. #include "mbuf.h"
  21. #include "cmdparse.h"
  22. #include "socket.h"
  23. #include "proc.h"
  24. #include "files.h"
  25. #include "pop.h"
  26. extern char Nospace[];
  27. static struct pop_scb *create_scb(void);
  28. static void delete_scb(struct pop_scb *scb);
  29. static void popserv(int s,void *unused,void *p);
  30. static int poplogin(char *pass,char *username);
  31. static void rrip(register char *s);
  32. int newmail(struct pop_scb *);
  33. int isdeleted(struct pop_scb *,int);
  34. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  35. void pop_sm(struct pop_scb *scb);
  36. static int Spop = -1; /* prototype socket for service */
  37. /* Start up POP receiver service */
  38. int
  39. pop1(argc,argv,p)
  40. int argc;
  41. char *argv[];
  42. void *p;
  43. {
  44. struct sockaddr_in lsocket;
  45. int s;
  46. if (Spop != -1) {
  47. return 0;
  48. }
  49. ksignal(Curproc,0); /* Don't keep the parser waiting */
  50. chname(Curproc,"POP listener");
  51. lsocket.sin_family = AF_INET;
  52. lsocket.sin_addr.s_addr = INADDR_ANY;
  53. if(argc < 2)
  54. lsocket.sin_port = IPPORT_POP;
  55. else
  56. lsocket.sin_port = atoi(argv[1]);
  57. Spop = socket(AF_INET,SOCK_STREAM,0);
  58. bind(Spop,(struct sockaddr *)&lsocket,sizeof(lsocket));
  59. listen(Spop,1);
  60. for (;;) {
  61. if((s = accept(Spop,NULL,(int *)NULL)) == -1)
  62. break; /* Service is shutting down */
  63. /* Spawn a server */
  64. newproc("POP server",2048,popserv,s,NULL,NULL,0);
  65. }
  66. return 0;
  67. }
  68. /* Shutdown POP service (existing connections are allowed to finish) */
  69. int
  70. pop0(argc,argv,p)
  71. int argc;
  72. char *argv[];
  73. void *p;
  74. {
  75. close_s(Spop);
  76. Spop = -1;
  77. return 0;
  78. }
  79. static void
  80. popserv(s,unused,p)
  81. int s;
  82. void *unused;
  83. void *p;
  84. {
  85. struct pop_scb *scb;
  86. FILE *network;
  87. sockowner(s,Curproc); /* We own it now */
  88. logmsg(s,"open POP");
  89. network = fdopen(s,"r+t");
  90. if((scb = create_scb()) == NULL) {
  91. printf(Nospace);
  92. logmsg(s,"close POP - no space");
  93. fclose(network);
  94. return;
  95. }
  96. scb->network = network;
  97. scb->state  = AUTH;
  98. (void) fprintf(network,greeting_msg,Hostname);
  99. loop: if (fgets(scb->buf,BUF_LEN,network) == NULL){
  100. /* He closed on us */
  101. goto quit;
  102. }
  103. scb->count = strlen(scb->buf);
  104. rip(scb->buf);
  105. if (strlen(scb->buf) == 0) /* Ignore blank cmd lines */
  106. goto loop;
  107. pop_sm(scb);
  108. if (scb->state == DONE)
  109. goto quit;
  110. goto loop;
  111. quit:
  112. logmsg(fileno(scb->network),"close POP");
  113. fclose(scb->network);
  114. delete_scb(scb);
  115. }
  116. /* Create control block, initialize */
  117. static struct
  118. pop_scb *create_scb()
  119. {
  120. register struct pop_scb *scb;
  121. if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULL)
  122. return NULL;
  123. scb->username[0] = '';
  124. scb->msg_status = NULL;
  125. scb->wf = NULL;
  126. scb->count = scb->folder_file_size = scb->msg_num = 0;
  127. scb->folder_modified = FALSE;
  128. return scb;
  129. }
  130. /* Free resources, delete control block */
  131. static void
  132. delete_scb(scb)
  133. register struct pop_scb *scb;
  134. {
  135. if (scb == NULL)
  136. return;
  137. if (scb->wf != NULL)
  138. fclose(scb->wf);
  139. if (scb->msg_status  != NULL)
  140. free(scb->msg_status);
  141. free(scb);
  142. }
  143. /* replace terminating end of line marker(s) (r and n) with null */
  144. static void
  145. rrip(s)
  146. register char *s;
  147. {
  148. register char *cp;
  149. if((cp = strchr(s,'r')) != NULL)
  150. *cp = '';
  151. if((cp = strchr(s,'n')) != NULL)
  152. *cp = '';
  153. }
  154. /* --------------------- start of POP server code ------------------------ */
  155. #define BITS_PER_WORD 16
  156. #define isSOM(x) ((strncmp(x,"From ",5) == 0))
  157. /* Command string specifications */
  158. static char ackd_cmd[] = "ACKD",
  159. acks_cmd[] = "ACKS",
  160. #ifdef POP_FOLDERS
  161. fold_cmd[] = "FOLD ",
  162. #endif
  163. login_cmd[] = "HELO ",
  164. nack_cmd[] = "NACK",
  165. quit_cmd[] = "QUIT",
  166. read_cmd[] = "READ",
  167. retr_cmd[] = "RETR";
  168. void
  169. pop_sm(scb)
  170. struct pop_scb *scb;
  171. {
  172. char password[40];
  173. void state_error(struct pop_scb *,char *);
  174. void open_folder(struct pop_scb *);
  175. void do_cleanup(struct pop_scb *);
  176. void read_message(struct pop_scb *);
  177. void retrieve_message(struct pop_scb *);
  178. void deletemsg(struct pop_scb *,int);
  179. void get_message(struct pop_scb *,int);
  180. void print_message_length(struct pop_scb *);
  181. void close_folder(struct pop_scb *);
  182. #ifdef POP_FOLDERS
  183. void select_folder(struct pop_scb *);
  184. #endif
  185. if (scb == NULL) /* be certain it is good -- wa6smn */
  186. return;
  187. switch(scb->state) {
  188. case AUTH:
  189. if (strncmp(scb->buf,login_cmd,strlen(login_cmd)) == 0){
  190. sscanf(scb->buf,"HELO %s%s",scb->username,password);
  191. if (!poplogin(scb->username,password)) {
  192. logmsg(fileno(scb->network),"POP access DENIED to %s",
  193.     scb->username);
  194. state_error(scb,"Access DENIED!!");
  195. return;
  196. }
  197. logmsg(fileno(scb->network),"POP access granted to %s",
  198.     scb->username);
  199. open_folder(scb);
  200. } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  201. do_cleanup(scb);
  202. } else
  203. state_error(scb,"(AUTH) Expected HELO or QUIT command");
  204. break;
  205. case MBOX:
  206. if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  207. read_message(scb);
  208. #ifdef POP_FOLDERS
  209. else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  210. select_folder(scb);
  211. #endif
  212. else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0) {
  213. do_cleanup(scb);
  214. } else
  215. state_error(scb,
  216. #ifdef POP_FOLDERS
  217.     "(MBOX) Expected FOLD, READ, or QUIT command");
  218. #else
  219.     "(MBOX) Expected READ or QUIT command");
  220. #endif
  221. break;
  222. case ITEM:
  223. if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  224. read_message(scb);
  225. #ifdef POP_FOLDERS
  226. else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  227. select_folder(scb);
  228. #endif
  229. else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  230. retrieve_message(scb);
  231. else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  232. do_cleanup(scb);
  233. else
  234. state_error(scb,
  235. #ifdef POP_FOLDERS
  236.    "(ITEM) Expected FOLD, READ, RETR, or QUIT command");
  237. #else
  238.    "(ITEM) Expected READ, RETR, or QUIT command");
  239. #endif
  240. break;
  241. case NEXT:
  242. if (strncmp(scb->buf,ackd_cmd,strlen(ackd_cmd)) == 0){
  243. /* ACKD processing */
  244. deletemsg(scb,scb->msg_num);
  245. scb->msg_num++;
  246. get_message(scb,scb->msg_num);
  247. } else if (strncmp(scb->buf,acks_cmd,strlen(acks_cmd)) == 0){
  248. /* ACKS processing */
  249. scb->msg_num++;
  250. get_message(scb,scb->msg_num);
  251. } else if (strncmp(scb->buf,nack_cmd,strlen(nack_cmd)) == 0){
  252. /* NACK processing */
  253. fseek(scb->wf,scb->curpos,SEEK_SET);
  254. } else {
  255. state_error(scb,"(NEXT) Expected ACKD, ACKS, or NACK command");
  256. return;
  257. }
  258. print_message_length(scb);
  259. scb->state  = ITEM;
  260. break;
  261. case DONE:
  262. do_cleanup(scb);
  263. break;
  264. default:
  265. state_error(scb,"(TOP) State Error!!");
  266. break;
  267. }
  268. }
  269. void
  270. do_cleanup(scb)
  271. struct pop_scb *scb;
  272. {
  273. void close_folder(struct pop_scb *);
  274. close_folder(scb);
  275. (void) fprintf(scb->network,signoff_msg);
  276. scb->state = DONE;
  277. }
  278. void
  279. state_error(scb,msg)
  280. struct pop_scb *scb;
  281. char *msg;
  282. {
  283. (void) fprintf(scb->network,error_rsp,msg);
  284. scb->state = DONE;
  285. }
  286. #ifdef POP_FOLDERS
  287. select_folder(scb)
  288. struct pop_scb *scb;
  289. {
  290. sscanf(scb->buf,"FOLD %s",scb->username);
  291. if (scb->wf != NULL)
  292. close_folder(scb);
  293. open_folder(scb);
  294. }
  295. #endif
  296. void
  297. close_folder(scb)
  298. struct pop_scb *scb;
  299. {
  300. char folder_pathname[64];
  301. char line[BUF_LEN];
  302. FILE *fd;
  303. int deleted = FALSE;
  304. int msg_no = 0;
  305. struct stat folder_stat;
  306. if (scb->wf == NULL)
  307. return;
  308. if (!scb->folder_modified) {
  309. /* no need to re-write the folder if we have not modified it */
  310. fclose(scb->wf);
  311. scb->wf = NULL;
  312. free(scb->msg_status);
  313. scb->msg_status = NULL;
  314. return;
  315. }
  316. sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  317. if (newmail(scb)) {
  318. /* copy new mail into the work file and save the
  319.    message count for later */
  320. if ((fd = fopen(folder_pathname,"r")) == NULL) {
  321. state_error(scb,"Unable to add new mail to folder");
  322. return;
  323. }
  324. fseek(scb->wf,0,SEEK_END);
  325. fseek(fd,scb->folder_file_size,SEEK_SET);
  326. while (!feof(fd)) {
  327. fgets(line,BUF_LEN,fd);
  328. fputs(line,scb->wf);
  329. }
  330. fclose(fd);
  331. }
  332. /* now create the updated mail folder */
  333. if ((fd = fopen(folder_pathname,"w")) == NULL){
  334. state_error(scb,"Unable to update mail folder");
  335. return;
  336. }
  337. rewind(scb->wf);
  338. while (!feof(scb->wf)){
  339. fgets(line,BUF_LEN,scb->wf);
  340. if (isSOM(line)){
  341. msg_no++;
  342. if (msg_no <= scb->folder_len)
  343. deleted = isdeleted(scb,msg_no);
  344. else
  345. deleted = FALSE;
  346. }
  347. if (deleted)
  348. continue;
  349. fputs(line,fd);
  350. }
  351. fclose(fd);
  352. /* trash the updated mail folder if it is empty */
  353. if ((stat(folder_pathname,&folder_stat) == 0) && (folder_stat.st_size == 0))
  354. unlink(folder_pathname);
  355. fclose(scb->wf);
  356. scb->wf = NULL;
  357. free(scb->msg_status);
  358. scb->msg_status = NULL;
  359. }
  360. void
  361. open_folder(scb)
  362. struct pop_scb *scb;
  363. {
  364. char folder_pathname[64];
  365. char line[BUF_LEN];
  366. FILE *fd;
  367. FILE *tmpfile();
  368. struct stat folder_stat;
  369. sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  370. scb->folder_len       = 0;
  371. scb->folder_file_size = 0;
  372. if (stat(folder_pathname,&folder_stat)){
  373.  (void) fprintf(scb->network,no_mail_rsp);
  374.  return;
  375. }
  376. scb->folder_file_size = folder_stat.st_size;
  377. if ((fd = fopen(folder_pathname,"r")) == NULL){
  378. state_error(scb,"Unable to open mail folder");
  379. return;
  380. }
  381. if ((scb->wf = tmpfile()) == NULL) {
  382. state_error(scb,"Unable to create work folder");
  383. return;
  384. }
  385. while(!feof(fd)) {
  386. fgets(line,BUF_LEN,fd);
  387. /* scan for begining of a message */
  388. if (isSOM(line))
  389. scb->folder_len++;
  390. /* now put  the line in the work file */
  391. fputs(line,scb->wf);
  392. }
  393. fclose(fd);
  394. scb->msg_status_size = (scb->folder_len) / BITS_PER_WORD;
  395. if ((((scb->folder_len) % BITS_PER_WORD) != 0) ||
  396.     (scb->msg_status_size == 0))
  397. scb->msg_status_size++;
  398. if ((scb->msg_status = (unsigned int *) callocw(scb->msg_status_size,
  399. sizeof(unsigned int))) == NULL) {
  400. state_error(scb,"Unable to create message status array");
  401. return;
  402. }
  403. (void) fprintf(scb->network,count_rsp,scb->folder_len);
  404. scb->state  = MBOX;
  405. }
  406. void
  407. read_message(scb)
  408. struct pop_scb *scb;
  409. {
  410. void get_message(struct pop_scb *,int);
  411. void print_message_length(struct pop_scb *);
  412. if (scb == NULL) /* check for null -- wa6smn */
  413. return;
  414. if (scb->buf[sizeof(read_cmd) - 1] == ' ')
  415. scb->msg_num = atoi(&(scb->buf[sizeof(read_cmd) - 1]));
  416. else
  417. scb->msg_num++;
  418. get_message(scb,scb->msg_num);
  419. print_message_length(scb);
  420. scb->state  = ITEM;
  421. }
  422. void
  423. retrieve_message(scb)
  424. struct pop_scb *scb;
  425. {
  426. char line[BUF_LEN];
  427. long cnt;
  428. if (scb == NULL) /* check for null -- wa6smn */
  429. return;
  430. if (scb->msg_len == 0) {
  431. state_error(scb,"Attempt to access a DELETED message!");
  432. return;
  433. }
  434. cnt  = scb->msg_len;
  435. while(!feof(scb->wf) && (cnt > 0)) {
  436. fgets(line,BUF_LEN,scb->wf);
  437. rrip(line);
  438. (void) fprintf(scb->network,msg_line,line);
  439. cnt -= (strlen(line)+2); /* Compensate for CRLF */
  440. }
  441. scb->state = NEXT;
  442. }
  443. void
  444. get_message(scb,msg_no)
  445. struct pop_scb *scb;
  446. int msg_no;
  447. {
  448. char line[BUF_LEN];
  449. if (scb == NULL) /* check for null -- wa6smn */
  450. return;
  451. scb->msg_len = 0;
  452. if (msg_no > scb->folder_len) {
  453. scb->curpos  = 0;
  454. scb->nextpos = 0;
  455. return;
  456. } else {
  457. /* find the message and its length */
  458. rewind(scb->wf);
  459. while (!feof(scb->wf) && (msg_no > -1)) {
  460. if (msg_no > 0)
  461. scb->curpos = ftell(scb->wf);
  462. fgets(line,BUF_LEN,scb->wf);
  463. rrip(line);
  464. if (isSOM(line))
  465. msg_no--;
  466. if (msg_no != 0)
  467. continue;
  468. scb->nextpos  = ftell(scb->wf);
  469. scb->msg_len += (strlen(line)+2); /* Add CRLF */
  470. }
  471. }
  472. if (scb->msg_len > 0)
  473. fseek(scb->wf,scb->curpos,SEEK_SET);
  474. /* we need the pointers even if the message was deleted */
  475. if  (isdeleted(scb,scb->msg_num))
  476. scb->msg_len = 0;
  477. }
  478. static int
  479. poplogin(username,pass)
  480. char *pass;
  481. char *username;
  482. {
  483. char buf[80];
  484. char *cp;
  485. char *cp1;
  486. FILE *fp;
  487. if((fp = fopen(Popusers,"r")) == NULL) {
  488. /* User file doesn't exist */
  489. printf("POP users file %s not foundn",Popusers);
  490. return(FALSE);
  491. }
  492. while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  493. if(buf[0] == '#')
  494. continue; /* Comment */
  495. if((cp = strchr(buf,':')) == NULL)
  496. /* Bogus entry */
  497. continue;
  498. *cp++ = ''; /* Now points to password */
  499. if(strcmp(username,buf) == 0)
  500. break; /* Found user name */
  501. }
  502. if(feof(fp)) {
  503. /* User name not found in file */
  504. fclose(fp);
  505. return(FALSE);
  506. }
  507. fclose(fp);
  508. if ((cp1 = strchr(cp,':')) == NULL)
  509. return(FALSE);
  510. *cp1 = '';
  511. if(strcmp(cp,pass) != 0) {
  512. /* Password required, but wrong one given */
  513. return(FALSE);
  514. }
  515. /* whew! finally made it!! */
  516. return(TRUE);
  517. }
  518. int
  519. isdeleted(scb,msg_no)
  520. struct pop_scb *scb;
  521. int msg_no;
  522. {
  523. unsigned int mask = 1,offset;
  524. msg_no--;
  525. offset = msg_no / BITS_PER_WORD;
  526. mask <<= msg_no % BITS_PER_WORD;
  527. return (((scb->msg_status[offset]) & mask)? TRUE:FALSE);
  528. }
  529. void
  530. deletemsg(scb,msg_no)
  531. struct pop_scb *scb;
  532. int msg_no;
  533. {
  534. unsigned int mask = 1,offset;
  535. if (scb == NULL) /* check for null -- wa6smn */
  536. return;
  537. msg_no--;
  538. offset = msg_no / BITS_PER_WORD;
  539. mask <<= msg_no % BITS_PER_WORD;
  540. scb->msg_status[offset] |= mask;
  541. scb->folder_modified = TRUE;
  542. }
  543. int
  544. newmail(scb)
  545. struct pop_scb *scb;
  546. {
  547. char folder_pathname[64];
  548. struct stat folder_stat;
  549. sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  550. if (stat(folder_pathname,&folder_stat)) {
  551. state_error(scb,"Unable to get old mail folder's status");
  552. return(FALSE);
  553. } else
  554. return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  555. }
  556. void
  557. print_message_length(scb)
  558. struct pop_scb *scb;
  559. {
  560. char *print_control_string;
  561. if (scb == NULL) /* check for null -- wa6smn */
  562. return;
  563. if (scb->msg_len > 0)
  564. print_control_string = length_rsp;
  565. else if (scb->msg_num <= scb->folder_len)
  566. print_control_string = length_rsp;
  567. else
  568. print_control_string = no_more_rsp;
  569. (void)fprintf(scb->network,print_control_string,scb->msg_len,scb->msg_num);
  570. }