home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / POP2SERV.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  25KB  |  938 lines

  1. /* POP2 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.  *      Aug-Oct 92      Mike Bilow, N1BEE, mikebw@ids.net
  9.  *              Extensive bug fixes, changed uses of Borland stat()
  10.  *              to fsize() in order to fix intermittent crashes
  11.  *
  12.  *  Support for Mail Index Files, June/July 1993, Johan. K. Reinalda, WG7J
  13.  */
  14.   
  15. #include <fcntl.h>
  16. #include <time.h>
  17. #include <sys/stat.h>
  18. #ifdef UNIX
  19. #include <sys/types.h>
  20. #endif
  21. #if     defined(__STDC__) || defined(__TURBOC__)
  22. #include <stdarg.h>
  23. #endif
  24. #include <ctype.h>
  25. #include <setjmp.h>
  26. #include "global.h"
  27. #ifdef POP2SERVER
  28. #include "mbuf.h"
  29. #include "cmdparse.h"
  30. #include "socket.h"
  31. #include "proc.h"
  32. #include "files.h"
  33. #include "smtp.h"
  34. #include "mailcli.h"                    /* N1BEE */
  35. #include "dirutil.h"
  36. #include "index.h"
  37. #include "bm.h"
  38.   
  39. #ifdef LINUX
  40. extern int unlink __ARGS((char *));
  41. #endif
  42.   
  43. #undef DEBUG                            /* N1BEE */
  44.   
  45.   
  46. /* ---------------- common server data structures ---------------- */
  47.   
  48. /* POP server control block */
  49.   
  50. struct pop_scb {
  51.     int     socket;         /* socket number for this connection */
  52.     char    state;          /* server state */
  53. #define         LSTN    0
  54. #define         AUTH    1
  55. #define         MBOX    2
  56. #define         ITEM    3
  57. #define         NEXT    4
  58. #define         DONE    5
  59.     char    buf[TLINELEN+1];        /* input line buffer */
  60.     char    count;          /* line buffer length */
  61.     char    username[32];   /* user/folder name */
  62.     FILE    *wf;            /* work folder file pointer */
  63.     int     folder_len;     /* number of msgs in current folder */
  64.     int     msg_num;        /* current msg number */
  65.     long    msg_len;        /* length of current msg */
  66.     int     msg_status_size; /* size of the message status array */
  67.     long    curpos;         /* current msg's position in file */
  68.     long    folder_file_size; /* length of the current folder file, in bytes */
  69.     long    nextpos;        /* next msg's position in file */
  70.     char    folder_modified; /* mail folder contents modified flag */
  71.     int16   *msg_status;    /* message status array pointer */
  72. };
  73.   
  74. #define NULLSCB         (struct pop_scb *)0
  75.   
  76. /* Response messages */
  77.   
  78. static char     count_rsp[]    = "#%d messages in this folder\n",
  79. error_rsp[]    = "- ERROR: %s\n",
  80. greeting_msg[] = "+ POP2 %s\n",
  81. /*              length_rsp[]   = "=%ld bytes in this message\n", */
  82. length_rsp[]   = "=%ld characters in Message #%d\n",
  83. msg_line[]     = "%s\n",
  84. no_mail_rsp[]  = "+ No mail, sorry\n",
  85. no_more_rsp[]  = "=%d No more messages in this folder\n",
  86. signoff_msg[]  = "+ Bye, thanks for calling\n";
  87.   
  88. static void rrip __ARGS((char *s));
  89. static struct pop_scb *create_scb __ARGS((void));
  90. static void delete_scb __ARGS((struct pop_scb *scb));
  91. static void popserv __ARGS((int s,void *unused,void *p));
  92. static int poplogin __ARGS((char *pass,char *username));
  93.   
  94. static void pop_sm __ARGS((struct pop_scb *scb));
  95.   
  96. /* Start up POP receiver service */
  97. int
  98. pop2start(argc,argv,p)
  99. int argc;
  100. char *argv[];
  101. void *p;
  102. {
  103.     int16 port;
  104.   
  105.     if(argc < 2)
  106.         port = IPPORT_POP2;
  107.     else
  108.         port = atoi(argv[1]);
  109.   
  110.     return start_tcp(port,"POP2 Server",popserv,1536);
  111. }
  112.   
  113. /* Shutdown POP2 service (existing connections are allowed to finish) */
  114. int
  115. pop2stop(argc,argv,p)
  116. int argc;
  117. char *argv[];
  118. void *p;
  119. {
  120.     int16 port;
  121.   
  122.     if(argc < 2)
  123.         port = IPPORT_POP2;
  124.     else
  125.         port = atoi(argv[1]);
  126.     return stop_tcp(port);
  127. }
  128.   
  129. static void
  130. popserv(s,unused,p)
  131. int s;
  132. void *unused;
  133. void *p;
  134. {
  135.     struct pop_scb *scb;
  136.     char *cp;
  137.   
  138.     sockowner(s,Curproc);           /* We own it now */
  139.     log(s,"open POP2");
  140.   
  141.     if((scb = create_scb()) == NULLSCB) {
  142.         tputs(Nospace);
  143.         log(s,"close POP2 - no space");
  144.         close_s(s);
  145.         return;
  146.     }
  147.   
  148.     scb->socket = s;
  149.     scb->state  = AUTH;
  150.   
  151.     (void) usprintf(s,greeting_msg,Hostname);
  152.   
  153.     loop:   if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  154.         /* He closed on us */
  155.   
  156.         goto quit;
  157.     }
  158.   
  159.     rrip(scb->buf);         /* Was "rip()" not "rrip()" -- N1BEE */
  160.     if (strlen(scb->buf) == 0)      /* Ignore blank cmd lines */
  161.         goto loop;
  162.   
  163. #ifdef DEBUG
  164.     if(Mailtrace >= 3) {
  165.         tprintf("POP2SERV(popserv): Processing line <%s>\n",scb->buf);
  166.         /* getch(); */
  167.     }
  168. #endif /* DEBUG */
  169.   
  170.     /* Convert lower, and mixed case commands to UPPER case - Ashok */
  171.     for(cp = scb->buf;*cp != ' ' && *cp != '\0';cp++)
  172.         *cp = toupper(*cp);
  173.   
  174.     pop_sm(scb);
  175.     if (scb->state == DONE)
  176.         goto quit;
  177.   
  178.     goto loop;
  179.   
  180.     quit:
  181.     log(scb->socket,"close POP2");
  182.     close_s(scb->socket);
  183.     delete_scb(scb);
  184. }
  185.   
  186.   
  187. /* Create control block, initialize */
  188.   
  189. static struct
  190. pop_scb *create_scb()
  191. {
  192.     register struct pop_scb *scb;
  193.   
  194.     if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  195.         return NULLSCB;
  196.   
  197.     scb->username[0] = '\0';
  198.     scb->msg_status = NULL;
  199.     scb->wf = NULL;
  200.   
  201.     scb->count = scb->folder_file_size = scb->msg_num = 0;
  202.   
  203.     scb->folder_modified = FALSE;
  204.     return scb;
  205. }
  206.   
  207.   
  208. /* Free resources, delete control block */
  209.   
  210. static void
  211. delete_scb(scb)
  212. register struct pop_scb *scb;
  213. {
  214.   
  215.     if (scb == NULLSCB)
  216.         return;
  217.     if (scb->wf != NULL)
  218.         fclose(scb->wf);
  219.     if (scb->msg_status  != NULL)
  220.         free((char *)scb->msg_status);
  221.   
  222.     free((char *)scb);
  223. }
  224.   
  225. /* replace terminating end of line marker(s) (\r and \n) with null */
  226. static void
  227. rrip(s)
  228. register char *s;
  229. {
  230.     register char *cp;
  231.   
  232.     if((cp = strchr(s,'\r')) != NULLCHAR)
  233.         *cp = '\0';
  234.     if((cp = strchr(s,'\n')) != NULLCHAR)
  235.         *cp = '\0';
  236. }
  237.   
  238. /* --------------------- start of POP server code ------------------------ */
  239.   
  240. #define BITS_PER_WORD   16
  241.   
  242. #define isSOM(x)        ((strncmp(x,"From ",5) == 0))   /* Start Of Message */
  243.   
  244. /* Command string specifications */
  245.   
  246. static char     ackd_cmd[] = "ACKD",
  247. acks_cmd[] = "ACKS",
  248. #ifdef POP_FOLDERS
  249. fold_cmd[] = "FOLD ",
  250. #endif
  251. login_cmd[] = "HELO ",
  252. nack_cmd[] = "NACK",
  253. quit_cmd[] = "QUIT",
  254. read_cmd[] = "READ",
  255. retr_cmd[] = "RETR";
  256.   
  257. static void
  258. pop_sm(scb)
  259. struct pop_scb *scb;
  260. {
  261.     char password[30];
  262. #ifndef __TURBOC__
  263.     static
  264. #endif
  265.     void state_error(struct pop_scb *,char *);
  266. #ifndef __TURBOC__
  267.     static
  268. #endif
  269.     void open_folder(struct pop_scb *);
  270. #ifndef __TURBOC__
  271.     static
  272. #endif
  273.     void do_cleanup(struct pop_scb *);
  274. #ifndef __TURBOC__
  275.     static
  276. #endif
  277.     void read_message(struct pop_scb *);
  278. #ifndef __TURBOC__
  279.     static
  280. #endif
  281.     void retrieve_message(struct pop_scb *);
  282. #ifndef __TURBOC__
  283.     static
  284. #endif
  285.     void deletemsg(struct pop_scb *,int);
  286. #ifndef __TURBOC__
  287.     static
  288. #endif
  289.     void get_message(struct pop_scb *,int);
  290. #ifndef __TURBOC__
  291.     static
  292. #endif
  293.     void print_message_length(struct pop_scb *);
  294. #ifndef __TURBOC__
  295.     static
  296. #endif
  297.     void close_folder(struct pop_scb *);
  298. #ifdef POP_FOLDERS
  299. #ifndef __TURBOC__
  300.     static
  301. #endif
  302.     void select_folder(struct pop_scb *);
  303. #endif
  304.   
  305.     if (scb == NULLSCB)     /* be certain it is good -- wa6smn */
  306.         return;
  307.   
  308.     switch(scb->state) {
  309.         case AUTH:
  310. #ifdef DEBUG
  311.             if(Mailtrace >= 3)
  312.                 tputs("POP2SERV(pop_sm): Entering case AUTH\n");
  313. #endif /* DEBUG */
  314.             if (strncmp(scb->buf,login_cmd,strlen(login_cmd)) == 0){
  315.                 sscanf(scb->buf,"HELO %31s %29s",scb->username,password);
  316. #ifdef DEBUG
  317.                 if(Mailtrace >= 3) {
  318.                     tprintf("POP2SERV(pop_sm): Processing USER %s PASS %s\n",scb->username,password);
  319.                     tprintf("POP2SERV(pop_sm): Calling poplogin() for %s:%s:\n",scb->username,password);
  320.                 }
  321. #endif /* DEBUG */
  322.   
  323.                 if (!poplogin(scb->username,password)) {
  324.                     log(scb->socket,"POP2 access DENIED to %s",
  325.                     scb->username);
  326.                     state_error(scb,"Access DENIED!!");
  327.                     return;
  328.                 }
  329.   
  330.                 log(scb->socket,"POP2 access granted to %s",
  331.                 scb->username);
  332.                 open_folder(scb);
  333.             } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  334.                 do_cleanup(scb);
  335.             } else
  336.                 state_error(scb,"(AUTH) Expected HELO or QUIT command");
  337. #ifdef DEBUG
  338.             if(Mailtrace >= 3)
  339.                 tputs("POP2SERV(pop_sm): Leaving case AUTH\n");
  340. #endif /* DEBUG */
  341.             break;
  342.   
  343.         case MBOX:
  344.             if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  345.                 read_message(scb);
  346.   
  347. #ifdef POP_FOLDERS
  348.             else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  349.                 select_folder(scb);
  350.   
  351. #endif
  352.   
  353.             else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0) {
  354.                 do_cleanup(scb);
  355.             } else
  356.                 state_error(scb,
  357. #ifdef POP_FOLDERS
  358.                 "(MBOX) Expected FOLD, READ, or QUIT command");
  359. #else
  360.             "(MBOX) Expected READ or QUIT command");
  361. #endif
  362.             break;
  363.   
  364.         case ITEM:
  365.             if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  366.                 read_message(scb);
  367.   
  368. #ifdef POP_FOLDERS
  369.   
  370.             else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  371.                 select_folder(scb);
  372. #endif
  373.   
  374.             else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  375.                 retrieve_message(scb);
  376.             else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  377.                 do_cleanup(scb);
  378.             else
  379.                 state_error(scb,
  380. #ifdef POP_FOLDERS
  381.                 "(ITEM) Expected FOLD, READ, RETR, or QUIT command");
  382. #else
  383.             "(ITEM) Expected READ, RETR, or QUIT command");
  384. #endif
  385.             break;
  386.   
  387.         case NEXT:
  388.             if (strncmp(scb->buf,ackd_cmd,strlen(ackd_cmd)) == 0){
  389.                 /* ACKD processing */
  390.                 deletemsg(scb,scb->msg_num);
  391.                 scb->msg_num++;
  392.                 get_message(scb,scb->msg_num);
  393.             } else if (strncmp(scb->buf,acks_cmd,strlen(acks_cmd)) == 0){
  394.                 /* ACKS processing */
  395.                 scb->msg_num++;
  396.                 get_message(scb,scb->msg_num);
  397.             } else if (strncmp(scb->buf,nack_cmd,strlen(nack_cmd)) == 0){
  398.                 /* NACK processing */
  399.                 fseek(scb->wf,scb->curpos,SEEK_SET);
  400.             } else {
  401.                 state_error(scb,"(NEXT) Expected ACKD, ACKS, or NACK command");
  402.                 return;
  403.             }
  404.   
  405.             print_message_length(scb);
  406.             scb->state  = ITEM;
  407.             break;
  408.   
  409.         case DONE:
  410.             do_cleanup(scb);
  411.             break;
  412.   
  413.         default:
  414.             state_error(scb,"(TOP) State Error!!");
  415.             break;
  416.     }
  417.   
  418. #ifdef DEBUG
  419.     if(Mailtrace >= 3)
  420.         tprintf("POP2SERV(pop_sm): Leaving state machine; state %u\n",scb->state);
  421. #endif /* DEBUG */
  422. }
  423.   
  424. static void
  425. do_cleanup(scb)
  426. struct pop_scb *scb;
  427. {
  428. #ifndef __TURBOC__
  429.     static
  430. #endif
  431.     void close_folder(struct pop_scb *);
  432.   
  433.     close_folder(scb);
  434.     (void) usputs(scb->socket,signoff_msg);
  435.     scb->state = DONE;
  436. }
  437.   
  438. static void
  439. state_error(scb,msg)
  440. struct pop_scb *scb;
  441. char *msg;
  442. {
  443.     if(Mailtrace >= 2)
  444.         tprintf(error_rsp,msg);
  445.     (void) usprintf(scb->socket,error_rsp,msg);
  446.     scb->state = DONE;
  447. }
  448.   
  449. #ifdef POP_FOLDERS
  450.   
  451. static void
  452. select_folder(scb)
  453. struct pop_scb  *scb;
  454. {
  455.     sscanf(scb->buf,"FOLD %s",scb->username);
  456.   
  457.     if (scb->wf != NULL)
  458.         close_folder(scb);
  459.   
  460.     open_folder(scb);
  461. }
  462.   
  463. #endif
  464.   
  465.   
  466. static void
  467. close_folder(scb)
  468. struct pop_scb *scb;
  469. {
  470.     char folder_pathname[64];
  471.     char line[TLINELEN+1];
  472.     FILE *fd;
  473.     int deleted = FALSE;
  474.     int msg_no = 0;
  475.   
  476.     int prev;
  477.     long start;
  478.     char *cp;
  479.     struct mailindex ind;
  480.   
  481. #ifndef __TURBOC__
  482.     static
  483. #endif
  484.     int newmail(struct pop_scb *);
  485. #ifndef __TURBOC__
  486.     static
  487. #endif
  488. #ifndef __TURBOC__
  489.     static
  490. #endif
  491.     int isdeleted(struct pop_scb *,int);
  492.   
  493.     if (scb->wf == NULL)
  494.         return;
  495.   
  496.     if (!scb->folder_modified) {
  497.         /* no need to re-write the folder if we have not modified it */
  498.   
  499.         fclose(scb->wf);
  500.         scb->wf = NULL;
  501.   
  502.         free((char *)scb->msg_status);
  503.         scb->msg_status = NULL;
  504.         return;
  505.     }
  506.   
  507.   
  508.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  509.   
  510.     if (newmail(scb)) {
  511.         /* copy new mail into the work file and save the
  512.            message count for later */
  513.   
  514.         if ((fd = fopen(folder_pathname,"r")) == NULL) {
  515.             state_error(scb,"Unable to add new mail to folder");
  516.             return;
  517.         }
  518.   
  519.         fseek(scb->wf,0,SEEK_END);
  520.         fseek(fd,scb->folder_file_size,SEEK_SET);
  521.         while (!feof(fd)) {
  522.             fgets(line,TLINELEN,fd);
  523.             fputs(line,scb->wf);
  524.         }
  525.   
  526.         fclose(fd);
  527.     }
  528.   
  529.     /* now create the updated mail folder */
  530.   
  531.     if ((fd = fopen(folder_pathname,"w")) == NULL){
  532.         state_error(scb,"Unable to update mail folder");
  533.         return;
  534.     }
  535.   
  536.     /* This simply rewrites the whole mail folder,
  537.      * so also simply recreate the index file - WG7J
  538.      */
  539.     delete_index(scb->username);
  540.     memset(&ind,0,sizeof(struct mailindex));
  541.   
  542.     rewind(scb->wf);
  543.     prev = 0;
  544.     start = 0;
  545.     while(fgets(line,TLINELEN,scb->wf) != NULLCHAR) {
  546.   
  547.         if (isSOM(line)){
  548.             if(prev && !deleted) {
  549.                 /* write the index for the previous message */
  550.                 ind.size = ftell(fd) - start;
  551.                 write_index(scb->username,&ind);
  552.             } else
  553.                 prev = 1;
  554.             msg_no++;
  555.             if (msg_no <= scb->folder_len)
  556.                 deleted = isdeleted(scb,msg_no);
  557.             else
  558.                 deleted = FALSE;
  559.             if(!deleted) {
  560.                 /* read the smtp header first to create the index */
  561.                 start = ftell(fd);  /* Starting offset of this message */
  562.                 fputs(line,fd);     /* put the from line back */
  563.   
  564.                 default_index(scb->username,&ind);
  565.   
  566.                 /* read the 'Received...' and 'ID... lines'
  567.                  * to get the msgid
  568.                  */
  569.                 fgets(line,TLINELEN,scb->wf);
  570.                 fputs(line,fd);
  571.                 fgets(line,TLINELEN,scb->wf);
  572.                 fputs(line,fd);
  573.                 if((cp=strstr(line,"AA")) != NULLCHAR)
  574.                     /*what follows is the message-number*/
  575.                     ind.msgid = atol(cp+2);
  576.   
  577.                 /* now scan rest of headers */
  578.                 while(fgets(line,TLINELEN,scb->wf) != NULLCHAR) {
  579.                     fputs(line,fd);
  580.                     if(*line == '\n')
  581.                         break; /* end of headers */
  582.                     set_index(line,&ind);
  583.                 }
  584.             }
  585.         } else if (!deleted) {
  586.   
  587.             fputs(line,fd);
  588.         }
  589.     }
  590.   
  591.     /* Update the last message handled */
  592.     if(prev && !deleted) {
  593.         ind.size = ftell(fd) - start;
  594.         write_index(scb->username,&ind);
  595.     }
  596.   
  597.     fclose(fd);
  598.   
  599.     /* trash the updated mail folder if it is empty */
  600.   
  601.     if(fsize(folder_pathname) == 0L)                /* N1BEE */
  602.         unlink(folder_pathname);
  603.   
  604.     fclose(scb->wf);
  605.     scb->wf = NULL;
  606.   
  607.     free((char *)scb->msg_status);
  608.     scb->msg_status = NULL;
  609. }
  610.   
  611. static void
  612. open_folder(scb)
  613. struct pop_scb  *scb;
  614. {
  615.     char folder_pathname[64];
  616.     char line[TLINELEN+1];
  617.     FILE *fd;
  618. /*      FILE *tmpfile();                should not declare here -- N1BEE */
  619.     struct stat folder_stat;
  620.   
  621.   
  622.     sprintf(folder_pathname,"%.45s/%.8s.txt",Mailspool,scb->username);
  623. #ifdef DEBUG
  624.     if(Mailtrace >= 3) {
  625.         tprintf("POP2SERV(open_folder): will open %s\n",folder_pathname);
  626.     }
  627. #endif /* DEBUG */
  628.     scb->folder_len       = 0;
  629.     scb->folder_file_size = 0;
  630.   
  631.     /* Ordinarily, we would call stat() to find out if the file exists
  632.        and get its size at the same time.  However, there is a bug in
  633.        Borland's stat() code which crashes DesqView and OS/2 (!) if
  634.        stat() is called on a file which does not exist.  -- N1BEE
  635.     */
  636.   
  637.     /* if (stat(folder_pathname,&folder_stat)){ */
  638.     if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  639. #ifdef DEBUG
  640.         if(Mailtrace >= 3) {
  641.             tputs("POP2SERV(open_folder): folder not found (empty)\n");
  642.         }
  643. #endif /* DEBUG */
  644.         (void) usputs(scb->socket,no_mail_rsp);
  645.   
  646.         /* state remains AUTH, expecting HELO or QUIT */
  647.         return;
  648.     }
  649.   
  650.     scb->folder_file_size = folder_stat.st_size;
  651.     if ((fd = fopen(folder_pathname,"r")) == NULL){
  652.         state_error(scb,"POP2SERV(open_folder): Unable to open mail folder");
  653.         return;
  654.     }
  655.   
  656.     if ((scb->wf = tmpfile()) == NULL) {
  657.         state_error(scb,"POP2SERV(open_folder): Unable to create work folder");
  658.         return;
  659.     }
  660.   
  661.     while(!feof(fd)) {
  662.         fgets(line,TLINELEN,fd);
  663.   
  664.         /* scan for begining of a message */
  665.   
  666.         if (isSOM(line))
  667.             scb->folder_len++;
  668.   
  669.         /* now put  the line in the work file */
  670.   
  671.         fputs(line,scb->wf);
  672.     }
  673.   
  674.     fclose(fd);
  675.   
  676.     scb->msg_status_size = (scb->folder_len) / BITS_PER_WORD;
  677.   
  678.     if ((((scb->folder_len) % BITS_PER_WORD) != 0) ||
  679.         (scb->msg_status_size == 0))
  680.         scb->msg_status_size++;
  681.   
  682.     if ((scb->msg_status = (int16 *) callocw(scb->msg_status_size,
  683.     sizeof(int16))) == NULL) {
  684.         state_error(scb,"Unable to create message status array");
  685.         return;
  686.     }
  687.   
  688.     (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  689.   
  690.     scb->state  = MBOX;
  691.   
  692. #ifdef DEBUG
  693.     if(Mailtrace >= 3)
  694.         tputs("POP2SERV: open_folder() completed successfully.\n");
  695. #endif /* DEBUG */
  696. }
  697.   
  698. static void
  699. read_message(scb)
  700. struct pop_scb  *scb;
  701. {
  702. #ifndef __TURBOC__
  703.     static
  704. #endif
  705.     void get_message(struct pop_scb *,int);
  706. #ifndef __TURBOC__
  707.     static
  708. #endif
  709.     void print_message_length(struct pop_scb *);
  710.   
  711.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  712.         return;
  713.     if (scb->buf[sizeof(read_cmd) - 1] == ' ')
  714.         scb->msg_num = atoi(&(scb->buf[sizeof(read_cmd) - 1]));
  715.     else
  716.         scb->msg_num++;
  717.   
  718.     get_message(scb,scb->msg_num);
  719.     print_message_length(scb);
  720.     scb->state  = ITEM;
  721. }
  722.   
  723. static void
  724. retrieve_message(scb)
  725. struct pop_scb  *scb;
  726. {
  727.     char line[TLINELEN+1];
  728.     long cnt;
  729.   
  730.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  731.         return;
  732.     if (scb->msg_len == 0) {
  733.         state_error(scb,"Attempt to access a DELETED message!");
  734.         return;
  735.     }
  736.   
  737.     cnt  = scb->msg_len;
  738.     while(!feof(scb->wf) && (cnt > 0)) {
  739.         fgets(line,TLINELEN,scb->wf);
  740.         rrip(line);
  741.   
  742.         (void) usprintf(scb->socket,msg_line,line);
  743.         cnt -= (strlen(line)+2);        /* Compensate for CRLF */
  744.     }
  745.   
  746.     scb->state = NEXT;
  747. }
  748.   
  749. static void
  750. get_message(scb,msg_no)
  751. struct pop_scb  *scb;
  752. int msg_no;
  753. {
  754.     char line[TLINELEN+1];
  755.     long ftell();
  756.   
  757.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  758.         return;
  759.     scb->msg_len = 0;
  760.     if (msg_no > scb->folder_len) {
  761.         scb->curpos  = 0;
  762.         scb->nextpos = 0;
  763.         return;
  764.     } else {
  765.         /* find the message and its length */
  766.   
  767.         rewind(scb->wf);
  768.         while (!feof(scb->wf) && (msg_no > -1)) {
  769.             if (msg_no > 0)
  770.                 scb->curpos = ftell(scb->wf);
  771.   
  772.             fgets(line,TLINELEN,scb->wf);
  773.             rrip(line);
  774.   
  775.             if (isSOM(line))
  776.                 msg_no--;
  777.   
  778.             if (msg_no != 0)
  779.                 continue;
  780.   
  781.             scb->nextpos  = ftell(scb->wf);
  782.             scb->msg_len += (strlen(line)+2);       /* Add CRLF */
  783.         }
  784.     }
  785.   
  786.     if (scb->msg_len > 0)
  787.         fseek(scb->wf,scb->curpos,SEEK_SET);
  788.   
  789.     /* we need the pointers even if the message was deleted */
  790.   
  791.     if  (isdeleted(scb,scb->msg_num))
  792.         scb->msg_len = 0;
  793. }
  794.   
  795. static int
  796. poplogin(username,pass)
  797. char *pass;
  798. char *username;
  799. {
  800.     char buf[80];
  801.     char *cp;
  802.     char *cp1;
  803.     FILE *fp;
  804.   
  805. #ifdef DEBUG
  806.     if(Mailtrace >= 3)
  807.         tprintf("POP2SERV(poplogin): Opening POP users file %s\n",Popusers);
  808. #endif /* DEBUG */
  809.   
  810.     if((fp = fopen(Popusers,"r")) == NULLFILE) {
  811.         /* User file doesn't exist */
  812.         tprintf("POP2 users file %s not found\n",Popusers);
  813.         return(FALSE);
  814.     }
  815.   
  816. #ifdef DEBUG
  817.     if(Mailtrace >= 3)
  818.         tprintf("POP2SERV(poplogin): Login request from %s:%s:\n",username,pass);
  819. #endif /* DEBUG */
  820.   
  821.     while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  822.         if(buf[0] == '#')
  823.             continue;       /* Comment */
  824.   
  825.         if((cp = strchr(buf,':')) == NULLCHAR)
  826.             /* Bogus entry */
  827.             continue;
  828.   
  829.         *cp++ = '\0';           /* Now points to password */
  830.         if(strcmp(username,buf) == 0)
  831.             break;          /* Found user name */
  832.     }
  833.   
  834.     if(feof(fp)) {
  835. #ifdef DEBUG
  836.         if(Mailtrace >= 3)
  837.             tputs("POP2SERV(poplogin): username not found in POPUSERS\n");
  838. #endif /* DEBUG */
  839.         /* User name not found in file */
  840.   
  841.         fclose(fp);
  842.         return(FALSE);
  843.     }
  844.     fclose(fp);
  845.   
  846.     if ((cp1 = strchr(cp,':')) == NULLCHAR) {
  847. #ifdef DEBUG
  848.         if(Mailtrace >= 3)
  849.             tputs("POP2SERV(poplogin): No second ':' in POPUSERS entry\n");
  850. #endif /* DEBUG */
  851.         return(FALSE);
  852.     }
  853.   
  854.     *cp1 = '\0';
  855.     if(strcmp(cp,pass) != 0) {
  856. #ifdef DEBUG
  857.         if(Mailtrace >= 3)
  858.             tprintf("POP2SERV(poplogin): Wrong password (%s) from user %s, expecting %s\n",pass,username,cp);
  859. #endif /* DEBUG */
  860.         /* Password required, but wrong one given */
  861.         return(FALSE);
  862.     }
  863.   
  864.     /* whew! finally made it!! */
  865. #ifdef DEBUG
  866.     if(Mailtrace >= 3)
  867.         tprintf("POP2SERV(poplogin): %s authenticated\n",username);
  868. #endif /* DEBUG */
  869.   
  870.     return(TRUE);
  871. }
  872.   
  873. static int
  874. isdeleted(scb,msg_no)
  875. struct pop_scb *scb;
  876. int msg_no;
  877. {
  878.     int16 mask = 1,offset;
  879.   
  880.     msg_no--;
  881.     offset = msg_no / BITS_PER_WORD;
  882.     mask <<= msg_no % BITS_PER_WORD;
  883.     return (((scb->msg_status[offset]) & mask)? TRUE:FALSE);
  884. }
  885.   
  886. static void
  887. deletemsg(scb,msg_no)
  888. struct pop_scb *scb;
  889. int msg_no;
  890. {
  891.     int16 mask = 1,offset;
  892.   
  893.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  894.         return;
  895.     msg_no--;
  896.     offset = msg_no / BITS_PER_WORD;
  897.     mask <<= msg_no % BITS_PER_WORD;
  898.     scb->msg_status[offset] |= mask;
  899.     scb->folder_modified = TRUE;
  900. }
  901.   
  902. static int
  903. newmail(scb)
  904. struct pop_scb *scb;
  905. {
  906.     char folder_pathname[64];
  907.     struct stat folder_stat;
  908.   
  909.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  910.   
  911.     /* if (stat(folder_pathname,&folder_stat)) { */
  912.     if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  913.         state_error(scb,"Unable to get old mail folder's status");
  914.         return(FALSE);
  915.     } else
  916.         return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  917. }
  918.   
  919. static void
  920. print_message_length(scb)
  921. struct pop_scb *scb;
  922. {
  923.     char *print_control_string;
  924.   
  925.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  926.         return;
  927.     if (scb->msg_len > 0)
  928.         print_control_string = length_rsp;
  929.     else if (scb->msg_num <= scb->folder_len)
  930.         print_control_string = length_rsp;
  931.     else
  932.         print_control_string = no_more_rsp;
  933.   
  934.     (void)usprintf(scb->socket,print_control_string,scb->msg_len,scb->msg_num);
  935. }
  936.   
  937. #endif
  938.