home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / POP3SERV.C < prev    next >
C/C++ Source or Header  |  1994-09-03  |  26KB  |  1,016 lines

  1. /* POP3 Server state machine - see RFC 1225
  2.  *
  3.  *      Jan 92  Erik Olson olson@phys.washington.edu
  4.  *              Taken from POP2 server code in NOS 910618
  5.  *              Rewritten/converted to POP3
  6.  *      Feb 92  William Allen Simpson
  7.  *              integrated with current work
  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.  *              corrected confusion of sockmode()
  12.  *
  13.  *  "Need-to" list: XTND XMIT (to get WinQVTnet to work)
  14.  *
  15.  *  Support for Mail Index Files, June/July 1993, Johan. K. Reinalda, WG7J
  16.  *  LZW support by Dave Brown, N2RJT.
  17.  */
  18.   
  19. #include <fcntl.h>
  20. #include <time.h>
  21. #include <sys/stat.h>
  22. #ifdef UNIX
  23. #include <sys/types.h>
  24. #endif
  25. #if     defined(__STDC__) || defined(__TURBOC__)
  26. #include <stdarg.h>
  27. #endif
  28. #include <ctype.h>
  29. #include <setjmp.h>
  30. #include "global.h"
  31. #ifdef POP3SERVER
  32. #include "mbuf.h"
  33. #include "cmdparse.h"
  34. #include "socket.h"
  35. #include "proc.h"
  36. #include "files.h"
  37. #include "smtp.h"
  38. #include "dirutil.h"
  39. #include "mailutil.h"
  40. #include "bm.h"
  41. #include "index.h"
  42. #if defined(LZW)
  43. #include "lzw.h"
  44. #ifdef MAILCLIENT
  45. extern int poplzw;
  46. #else
  47. static int poplzw = TRUE;   /* no way yet to reset this */
  48. #endif
  49. #endif
  50.   
  51. /* ---------------- common server data structures ---------------- */
  52. /* POP message pointer element */
  53.   
  54. struct pop_msg {
  55.     long len;
  56.     long pos;
  57.     int deleted;
  58.     struct pop_msg *next;
  59. };
  60.   
  61. /* POP server control block */
  62.   
  63. struct pop_scb {
  64.     int socket;             /* socket number for this connection */
  65.     char state;             /* server state */
  66. #define      LSTN       0
  67. #define      AUTH       1
  68. #define      TRANS      2
  69. #define      UPDATE     3
  70. #define      DONE       5
  71.   
  72.     char    buf[TLINELEN];   /* input line buffer */
  73.     char    count;          /* line buffer length */
  74.     char    username[64];   /* user/folder name */
  75.     FILE    *wf;            /* work folder file pointer */
  76.     int     folder_len;     /* number of msgs in current folder */
  77.     int     high_num;       /* highest message number accessed */
  78.     long    folder_file_size; /* length of the current folder file, in bytes */
  79.     char    folder_modified; /* mail folder contents modified flag */
  80.     struct pop_msg *msg;    /* message database link-list */
  81. };
  82.   
  83. #define NULLSCB  (struct pop_scb *)0
  84.   
  85. /* Response messages -- '\n' is converted to '\r\n' by the socket code */
  86.   
  87. static char     count_rsp[]     = "+OK you have %d messages\n",
  88. error_rsp[]     = "-ERR %s\n",
  89. greeting_msg[]  = "+OK %s POP3 ready\n",
  90. #if defined(LZW)
  91. xlzw_rsp[]      = "+OK lzw %d %d\n",
  92. #endif
  93. user_rsp[]      = "+OK user\n",
  94. stat_rsp[]      = "+OK %d %ld\n",
  95. list_single_rsp[]       = "+OK %d %ld\n",
  96. list_multi_rsp[]        = "+OK %d messages (%ld octets)\n",
  97. retr_rsp[]      = "+OK %ld octets\n",
  98. multi_end_rsp[] = ".\n",
  99. dele_rsp[]      = "+OK message %d deleted\n",
  100. noop_rsp[]      = "+OK\n",
  101. last_rsp[]      = "+OK %d\n",
  102. signoff_msg[]   = "+OK Bye, bye-bye, bye now, goodbye\n";
  103.   
  104. static void rrip __ARGS((char *s));
  105. static struct pop_scb *create_scb __ARGS((void));
  106. static void delete_scb __ARGS((struct pop_scb *scb));
  107. static void popserv __ARGS((int s,void *unused,void *p));
  108. static int poplogin __ARGS((char *pass,char *username));
  109.   
  110. static void pop_sm __ARGS((struct pop_scb *scb));
  111.   
  112. static int Spop = -1; /* prototype socket for service */
  113.   
  114.   
  115. /* Start up POP receiver service */
  116. int
  117. pop3start(argc,argv,p)
  118. int argc;
  119. char *argv[];
  120. void *p;
  121. {
  122.     int16 port;
  123.   
  124.     if(argc < 2)
  125.         port = IPPORT_POP3;
  126.     else
  127.         port = atoi(argv[1]);
  128.   
  129.     return start_tcp(port,"POP3 Server",popserv,1536);
  130. }
  131.   
  132. /* Shutdown POP3 service (existing connections are allowed to finish) */
  133.   
  134. int
  135. pop3stop(argc,argv,p)
  136. int argc;
  137. char *argv[];
  138. void *p;
  139. {
  140.     int16 port;
  141.   
  142.     if(argc < 2)
  143.         port = IPPORT_POP3;
  144.     else
  145.         port = atoi(argv[1]);
  146.     return stop_tcp(port);
  147. }
  148.   
  149. static void
  150. popserv(s,unused,p)
  151. int s;
  152. void *unused;
  153. void *p;
  154. {
  155.     struct pop_scb *scb;
  156.     char *cp;
  157.   
  158.     sockowner(s,Curproc);           /* We own it now */
  159.     log(s,"open POP3");
  160.   
  161.     if((scb = create_scb()) == NULLSCB) {
  162.         tputs(Nospace);
  163.         log(s,"close POP3 - no space");
  164.         close_s(s);
  165.         return;
  166.     }
  167.   
  168.     scb->socket = s;
  169.     scb->state  = AUTH;
  170.   
  171.     sockmode(s,SOCK_ASCII);         /* N1BEE */
  172.     (void) usprintf(s,greeting_msg,Hostname);
  173.   
  174.     loop:   if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  175.         /* He closed on us */
  176.   
  177.         goto quit;
  178.     }
  179.   
  180.     rip(scb->buf);
  181.     if (strlen(scb->buf) == 0)      /* Ignore blank cmd lines */
  182.         goto loop;
  183.   
  184.     /* Convert lower, and mixed case commands to UPPER case - Ashok */
  185.     for(cp = scb->buf;*cp != ' ' && *cp != '\0';cp++)
  186.         *cp = toupper(*cp);
  187.   
  188.     pop_sm(scb);
  189.     if (scb->state == DONE)
  190.         goto quit;
  191.   
  192.     goto loop;
  193.   
  194.     quit:
  195.     log(scb->socket,"close POP3");
  196.     close_s(scb->socket);
  197.     delete_scb(scb);
  198. }
  199.   
  200.   
  201. /* Create control block, initialize */
  202.   
  203. static struct
  204. pop_scb *create_scb()
  205. {
  206.     register struct pop_scb *scb;
  207.   
  208.     if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  209.         return NULLSCB;
  210.   
  211.     scb->username[0] = '\0';
  212.     scb->msg = NULL;
  213.     scb->wf = NULL;
  214.   
  215.     scb->count = scb->folder_file_size = 0;
  216.   
  217.     scb->folder_modified = FALSE;
  218.     return scb;
  219. }
  220.   
  221.   
  222. /* Free msg link-list */
  223. static void
  224. delete_msglist(struct pop_msg *b_msg)
  225. {
  226.     struct pop_msg *msg,*msg2;
  227.     msg=b_msg;
  228.     while(msg!=NULL) {msg2=msg->next; free(msg); msg=msg2;}
  229. }
  230.   
  231. /* Free resources, delete control block */
  232.   
  233. static void
  234. delete_scb(scb)
  235. register struct pop_scb *scb;
  236. {
  237.     if (scb == NULLSCB)
  238.         return;
  239.     if (scb->wf != NULL)
  240.         fclose(scb->wf);
  241.     if (scb->msg  != NULL)
  242.         delete_msglist(scb->msg);
  243.   
  244.     free((char *)scb);
  245. }
  246.   
  247. /* replace terminating end of line marker(s) (\r and \n) with null,
  248.             and change . to .. */
  249. static void
  250. rrip(s)
  251. register char *s;
  252. {
  253.     register char *cp;
  254.   
  255.     if((cp = strchr(s,'\r')) != NULLCHAR)
  256.         *cp = '\0';
  257.     if((cp = strchr(s,'\n')) != NULLCHAR)
  258.         *cp = '\0';
  259. }
  260.   
  261. /* --------------------- start of POP server code ------------------------ */
  262.   
  263. #define BITS_PER_WORD   16
  264.   
  265. #define isSOM(x)        ((strncmp(x,"From ",5) == 0))
  266.   
  267. /* Command string specifications */
  268.   
  269. static char
  270. user_cmd[] = "USER ",
  271. pass_cmd[] = "PASS ",
  272. quit_cmd[] = "QUIT",
  273. stat_cmd[] = "STAT",
  274. list_cmd[] = "LIST",
  275. #if defined(LZW)
  276. xlzw_cmd[] = "XLZW ",
  277. #endif
  278. retr_cmd[] = "RETR",
  279. dele_cmd[] = "DELE",
  280. noop_cmd[] = "NOOP",
  281. rset_cmd[] = "RSET",
  282. top_cmd[]  = "TOP",
  283. last_cmd[] = "LAST";
  284.   
  285. static void
  286. pop_sm(scb)
  287. struct pop_scb *scb;
  288. {
  289.     char password[40];
  290. #if defined(LZW)
  291.     int lzwmode, lzwbits;
  292.     extern int16 Lzwbits;
  293.     extern int Lzwmode;
  294. #endif
  295.   
  296. #ifndef __TURBOC__
  297.     static
  298. #endif
  299.     void state_error(struct pop_scb *,char *);
  300. #ifndef __TURBOC__
  301.     static
  302. #endif
  303.     void fatal_error(struct pop_scb *,char *);
  304. #ifndef __TURBOC__
  305.     static
  306. #endif
  307.     void open_folder(struct pop_scb *);
  308. #ifndef __TURBOC__
  309.     static
  310. #endif
  311.     void do_cleanup(struct pop_scb *);
  312. #ifndef __TURBOC__
  313.     static
  314. #endif
  315.     void stat_message(struct pop_scb *);
  316. #ifndef __TURBOC__
  317.     static
  318. #endif
  319.     void list_message(struct pop_scb *);
  320. #ifndef __TURBOC__
  321.     static
  322. #endif
  323.     void retr_message(struct pop_scb *);
  324. #ifndef __TURBOC__
  325.     static
  326. #endif
  327.     void dele_message(struct pop_scb *);
  328. #ifndef __TURBOC__
  329.     static
  330. #endif
  331.     void noop_message(struct pop_scb *);
  332. #ifndef __TURBOC__
  333.     static
  334. #endif
  335.     void last_message(struct pop_scb *);
  336. #ifndef __TURBOC__
  337.     static
  338. #endif
  339.     void rset_message(struct pop_scb *);
  340. #ifndef __TURBOC__
  341.     static
  342. #endif
  343.     void top_message(struct pop_scb *);
  344. #ifndef __TURBOC__
  345.     static
  346. #endif
  347.     void close_folder(struct pop_scb *);
  348.   
  349.     if (scb == NULLSCB) /* be certain it is good -- wa6smn */
  350.         return;
  351.   
  352. #if defined(LZW)
  353.     if (strncmp(scb->buf,xlzw_cmd,strlen(xlzw_cmd)) == 0){
  354.         sscanf(scb->buf,"XLZW %d %d", &lzwbits,&lzwmode);
  355.         if((lzwmode == 0 || lzwmode == 1)
  356.            && (lzwbits > 8 && lzwbits < 17) && poplzw) {
  357.                (void) usprintf(scb->socket,xlzw_rsp,lzwbits,lzwmode);
  358.                lzwinit(scb->socket,lzwbits,lzwmode);
  359.         } else if (!poplzw)
  360.             state_error(scb,"(AUTH) LZW compression disabled");
  361.         else
  362.             state_error(scb,"LZW bits or mode invalid");
  363.         return;
  364.     }
  365. #endif
  366.  
  367.     switch(scb->state) {
  368.   
  369.         case AUTH:
  370.             if (strncmp(scb->buf,user_cmd,strlen(user_cmd)) == 0){
  371.                 sscanf(scb->buf,"USER %s",scb->username);
  372.                 (void) usputs(scb->socket,user_rsp);
  373.   
  374.             } else if (strncmp(scb->buf,pass_cmd,strlen(pass_cmd)) == 0){
  375.                 sscanf(scb->buf,"PASS %s",password);
  376.   
  377.                 if (!poplogin(scb->username,password)) {
  378.                     log(scb->socket,"POP3 access DENIED to %s",
  379.                     scb->username);
  380.                     state_error(scb,"Access DENIED!!");
  381.                     return;
  382.                 }
  383.   
  384.                 log(scb->socket,"POP3 access granted to %s",
  385.                 scb->username);
  386.                 open_folder(scb);
  387.             } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  388.                 do_cleanup(scb);
  389.             } else
  390.                 state_error(scb,"(AUTH) expected USER, PASS or QUIT");
  391.             break;
  392.   
  393.         case TRANS:
  394.             if (strncmp(scb->buf,stat_cmd,strlen(stat_cmd)) == 0)
  395.                 stat_message(scb);
  396.   
  397.             else if (strncmp(scb->buf,list_cmd,strlen(list_cmd)) == 0)
  398.                 list_message(scb);
  399.   
  400.             else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  401.                 retr_message(scb);
  402.   
  403.             else if (strncmp(scb->buf,dele_cmd,strlen(dele_cmd)) == 0)
  404.                 dele_message(scb);
  405.   
  406.             else if (strncmp(scb->buf,last_cmd,strlen(noop_cmd)) == 0)
  407.                 noop_message(scb);
  408.   
  409.             else if (strncmp(scb->buf,last_cmd,strlen(last_cmd)) == 0)
  410.                 last_message(scb);
  411.   
  412.             else if (strncmp(scb->buf,top_cmd,strlen(top_cmd)) == 0)
  413.                 top_message(scb);
  414.   
  415.             else if (strncmp(scb->buf,rset_cmd,strlen(rset_cmd)) == 0)
  416.                 rset_message(scb);
  417.   
  418.             else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  419.                 do_cleanup(scb);
  420.   
  421.             else
  422.                 state_error(scb,
  423.                 "(TRANS) unsupported/unrecognized command");
  424.             break;
  425.   
  426.         case DONE:
  427.             break;
  428.   
  429.         default:
  430.             fatal_error(scb,"(TOP) State Error!!");
  431.             break;
  432.     }
  433. }
  434.   
  435. static void
  436. do_cleanup(scb)
  437. struct pop_scb *scb;
  438. {
  439. #ifndef __TURBOC__
  440.     static
  441. #endif
  442.     void close_folder(struct pop_scb *);
  443.   
  444.     close_folder(scb);
  445.     (void) usputs(scb->socket,signoff_msg);
  446.     scb->state = DONE;
  447. }
  448.   
  449. static void
  450. state_error(scb,msg)
  451. struct pop_scb *scb;
  452. char *msg;
  453. {
  454.     (void) usprintf(scb->socket,error_rsp,msg);
  455.     /* scb->state = DONE; */  /* Don't automatically hang up */
  456. }
  457.   
  458. static void
  459. fatal_error(scb,msg)
  460. struct pop_scb *scb;
  461. char *msg;
  462. {
  463.     (void) usprintf(scb->socket,error_rsp,msg);
  464.     scb->state = DONE;
  465. }
  466.   
  467. static void
  468. close_folder(scb)
  469. struct pop_scb *scb;
  470. {
  471.     char folder_pathname[64];
  472.     char line[TLINELEN];
  473.     FILE *fd;
  474.     int deleted = FALSE;
  475.     int msg_no = 0;
  476.     struct pop_msg *msg;
  477.   
  478.     int prev;
  479.     long start = 0L;
  480.     char *cp;
  481.     struct mailindex ind;
  482.   
  483. #ifndef __TURBOC__
  484.     static
  485. #endif
  486.     int newmail(struct pop_scb *);
  487. #ifndef __TURBOC__
  488.     static
  489. #endif
  490.     void state_error(struct pop_scb *,char *);
  491. #ifndef __TURBOC__
  492.     static
  493. #endif
  494.     void fatal_error(struct pop_scb *,char *);
  495.   
  496.   
  497.     if (scb->wf == NULL)
  498.         return;
  499.   
  500.     if (!scb->folder_modified) {
  501.         /* no need to re-write the folder if we have not modified it */
  502.   
  503.         fclose(scb->wf);
  504.         scb->wf = NULL;
  505.   
  506.         delete_msglist(scb->msg);
  507.         scb->msg=NULL;
  508.         return;
  509.     }
  510.   
  511.   
  512.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  513.   
  514.     if (newmail(scb)) {
  515.         /* copy new mail into the work file and save the
  516.                     message count for later */
  517.   
  518.         if ((fd = fopen(folder_pathname,"r")) == NULL) {
  519.             fatal_error(scb,"Unable to add new mail to folder");
  520.             return;
  521.         }
  522.   
  523.         fseek(scb->wf,0,SEEK_END);
  524.         fseek(fd,scb->folder_file_size,SEEK_SET);
  525.         while (!feof(fd)) {
  526.             fgets(line,TLINELEN,fd);
  527.             fputs(line,scb->wf);
  528.         }
  529.   
  530.         fclose(fd);
  531.     }
  532.   
  533.     /* now create the updated mail folder */
  534.   
  535.     if ((fd = fopen(folder_pathname,"w")) == NULL){
  536.         fatal_error(scb,"Unable to update mail folder");
  537.         return;
  538.     }
  539.   
  540.     /* This simply rewrites the whole mail folder,
  541.      * so also simply recreate the index file - WG7J
  542.      */
  543.     delete_index(scb->username);
  544.     memset(&ind,0,sizeof(struct mailindex));
  545.   
  546.     rewind(scb->wf);
  547.     msg=scb->msg;
  548.     prev = 0;
  549.     while(fgets(line,TLINELEN,scb->wf) != NULLCHAR) {
  550.   
  551.         if (isSOM(line)){
  552.             if(prev && !deleted) {
  553.                 /* write the index for the previous message */
  554.                 ind.size = ftell(fd) - start;
  555.                 write_index(scb->username,&ind);
  556.             } else
  557.                 prev = 1;
  558.             if (msg!=NULL)
  559.                 msg=msg->next;
  560.             msg_no++;
  561.             if (msg!=NULL)
  562.                 deleted = msg->deleted;
  563.             else
  564.                 deleted = FALSE;
  565.             if(!deleted) {
  566.                 /* read the smtp header first to create the index */
  567.                 start = ftell(fd);  /* Starting offset of this message */
  568.                 fputs(line,fd);     /* put the from line back */
  569.                 default_index(scb->username,&ind);
  570.   
  571.                 /* read the 'Received...' and 'ID... lines'
  572.                  * to get the msgid
  573.                  */
  574.                 fgets(line,TLINELEN,scb->wf);
  575.                 fputs(line,fd);
  576.                 fgets(line,TLINELEN,scb->wf);
  577.                 fputs(line,fd);
  578.                 if((cp=strstr(line,"AA")) != NULLCHAR)
  579.                     /*what follows is the message-number*/
  580.                     ind.msgid = atol(cp+2);
  581.   
  582.                 /* now scan rest of headers */
  583.                 while(fgets(line,TLINELEN,scb->wf) != NULLCHAR) {
  584.                     fputs(line,fd);
  585.                     if(*line == '\n')
  586.                         break; /* end of headers */
  587.                     set_index(line,&ind);
  588.                 }
  589.             }
  590.         } else if(!deleted) {
  591.   
  592.             fputs(line,fd);
  593.         }
  594.     }
  595.   
  596.     /* Update the last message handled */
  597.     if(prev && !deleted) {
  598.         ind.size = ftell(fd) - start;
  599.         write_index(scb->username,&ind);
  600.     }
  601.   
  602.     fclose(fd);
  603.     if(fsize(folder_pathname) == 0L)                /* N1BEE */
  604.         unlink(folder_pathname);
  605.     fclose(scb->wf);
  606.     scb->wf = NULL;
  607.     delete_msglist(scb->msg);
  608.     scb->msg=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];
  617.     long pos;
  618.     FILE *fd;
  619.     FILE *tmpfile __ARGS((void));
  620.     struct stat folder_stat;
  621.     struct pop_msg *msg;
  622.   
  623.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  624.     scb->folder_len       = 0;
  625.     scb->folder_file_size = 0;
  626.     /* if (stat(folder_pathname,&folder_stat)){ */
  627.     if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
  628.         (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  629.         scb->state  = TRANS;
  630.         return;         /* no file = OK */
  631.     }
  632.   
  633.     scb->folder_file_size = folder_stat.st_size;
  634.     if ((fd = fopen(folder_pathname,"r")) == NULL){
  635.         state_error(scb,"Unable to open mail folder");
  636.         return;
  637.     }
  638.   
  639.     if ((scb->wf = tmpfile()) == NULL) {
  640.         state_error(scb,"Unable to create work folder");
  641.         return;
  642.     }
  643.   
  644.     scb->msg=calloc(sizeof(struct pop_msg),1); /* create first element */
  645.     if (scb->msg==NULL)
  646.     {
  647.         fatal_error(scb,"Unable to create pointer list");
  648.         return;
  649.     }
  650.     scb->msg->next=NULL;
  651.     msg=scb->msg;
  652.     msg->len=0;
  653.     msg->deleted=0;
  654.   
  655.     while(!feof(fd)) {
  656.         pos=ftell(scb->wf);
  657.         fgets(line,TLINELEN,fd);
  658.   
  659.         /* scan for begining of a message */
  660.   
  661.         if (isSOM(line))
  662.         {
  663.             scb->folder_len++;
  664.             msg->next=calloc(sizeof(struct pop_msg),1);
  665.             if (msg->next==NULL)
  666.             {
  667.                 fatal_error(scb,
  668.                 "Unable to create pointer list");
  669.                 return;
  670.             }
  671.             msg=msg->next;
  672.             msg->pos=pos;
  673.             msg->next=NULL;
  674.             msg->len=0;
  675.             msg->deleted=0;
  676.   
  677.         /* now put  the line in the work file */
  678.         }
  679.         fputs(line,scb->wf);
  680.         rrip(line);
  681.         if ( *line == '.' ) msg->len++;
  682.         msg->len +=strlen(line)+2; /* Add msg len count */
  683.     }
  684.   
  685.     fclose(fd);
  686.     scb->high_num=0;  /* reset high read */
  687.   
  688.     (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  689.   
  690.     scb->state  = TRANS;
  691. }
  692.   
  693. static void
  694. stat_message(scb)
  695. struct pop_scb *scb;
  696. {
  697.     long total=0;
  698.     int count=0;
  699.     struct pop_msg *msg;
  700.   
  701.     if (scb == NULLSCB) /* check for null -- wa6smn */
  702.         return;
  703.   
  704.     if (scb->folder_len)    /* add everything up */
  705.         for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  706.             if (!msg->deleted)
  707.                 {       total += msg->len; ++count;}
  708.   
  709.     (void) usprintf(scb->socket,stat_rsp,count,total);
  710. }
  711.   
  712. static void
  713. list_message(scb)
  714. struct pop_scb *scb;
  715. {
  716.     struct pop_msg *msg;
  717.     int msg_no=0;
  718.     long total=0;
  719. #ifndef __TURBOC__
  720.     static
  721. #endif
  722.     struct pop_msg *goto_msg(struct pop_scb *,int );
  723.   
  724.     if (scb == NULLSCB) /* check for null -- wa6smn */
  725.         return;
  726.     if (scb->buf[sizeof(list_cmd) - 1] == ' ')
  727.     {
  728.         msg_no = atoi(&(scb->buf[sizeof(list_cmd) - 1]));
  729.         msg=goto_msg(scb,msg_no);
  730.         if (msg==NULL || msg->deleted)
  731.             state_error(scb,"non existent or deleted message");
  732.         else
  733.             (void) usprintf(scb->socket,list_single_rsp,
  734.             msg_no,msg->len);
  735.     } else  /* multiline */
  736.     {
  737.         if (scb->folder_len)            /* add everything */
  738.             for (msg=scb->msg->next; msg!=NULL;msg=msg->next)
  739.                 if (!msg->deleted)
  740.                     total += msg->len,++msg_no;
  741.   
  742.         (void) usprintf(scb->socket,list_multi_rsp,
  743.         msg_no,total);
  744.   
  745.         if (scb->folder_len)
  746.             for (msg=scb->msg->next,msg_no=1; msg!=NULL;
  747.                 msg=msg->next,msg_no++)
  748.                 if (!msg->deleted) {
  749.                     (void) usprintf(scb->socket,"%d %ld\n",
  750.                     msg_no,msg->len);
  751.                 }
  752.         (void) usputs(scb->socket,multi_end_rsp);
  753.     }
  754. }
  755.   
  756. static void
  757. retr_message(scb)
  758. struct pop_scb *scb;
  759. {
  760.     char line[TLINELEN];
  761.     long cnt;
  762.     int msg_no;
  763.     struct pop_msg *msg;
  764. #ifndef __TURBOC__
  765.     static
  766. #endif
  767.     struct pop_msg *goto_msg(struct pop_scb *,int );
  768.   
  769.     if (scb == NULLSCB) /* check for null -- wa6smn */
  770.         return;
  771.     if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  772.     {
  773.         state_error(scb,"no such message");
  774.         return;
  775.     }
  776.     msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  777.     msg=goto_msg(scb,msg_no);
  778.     if (msg==NULL || msg->deleted) {
  779.         state_error(scb,"no such message");
  780.         return;
  781.     }
  782.   
  783.     cnt  = msg->len;
  784.     (void) usprintf(scb->socket,retr_rsp,cnt);
  785.     fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  786.     setflush(scb->socket, -1);
  787.     while(!feof(scb->wf) && (cnt > 0)) {
  788.         fgets(line,TLINELEN,scb->wf);
  789.         rrip(line);
  790.         if ( *line == '.' ) {
  791.             (void) usputc(scb->socket,'.');
  792.             cnt--;
  793.         }
  794.         (void) usputs(scb->socket,line);
  795.         (void) usputc(scb->socket,'\n');
  796.         cnt -= (strlen(line)+2); /* Compensate for CRLF */
  797.     }
  798.     setflush(scb->socket,'\n');
  799.     (void) usputs(scb->socket,".\n");
  800.     if (msg_no >= scb->high_num)
  801.         scb->high_num=msg_no;     /* bump high water mark */
  802. }
  803.   
  804. static void
  805. noop_message(scb)
  806. struct pop_scb *scb;
  807. {
  808.     (void) usputs(scb->socket,noop_rsp);
  809. }
  810.   
  811. static void
  812. last_message(scb)
  813. struct pop_scb *scb;
  814. {
  815.     (void) usprintf(scb->socket,last_rsp,scb->high_num);
  816. }
  817.   
  818. static void
  819. rset_message(scb)
  820. struct pop_scb *scb;
  821. {
  822.     struct pop_msg *msg;
  823.     long total=0;
  824.   
  825.     if (scb->folder_len)
  826.         for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  827.             msg->deleted=FALSE,total+=msg->len;
  828.   
  829.     scb->high_num=0;  /* reset last */
  830.     scb->folder_modified=FALSE;
  831.     (void) usprintf(scb->socket,list_multi_rsp,scb->folder_len,total);
  832. }
  833.   
  834. static void
  835. top_message(scb)
  836. struct pop_scb *scb;
  837. {
  838.     char *ptr;
  839.     char line[TLINELEN];
  840.     struct pop_msg *msg;
  841.     int msg_no=0,lines=0;
  842.     long total=0;
  843.   
  844. #ifndef __TURBOC__
  845.     static
  846. #endif
  847.     struct pop_msg *goto_msg(struct pop_scb *,int );
  848.   
  849.     if (scb == NULLSCB) /* check for null -- wa6smn */
  850.         return;
  851.     if (scb->buf[sizeof(top_cmd) - 1] != ' ')
  852.     {
  853.         state_error(scb,"No message specified");
  854.         return;
  855.     }
  856.     for (ptr=scb->buf+sizeof(top_cmd); *ptr==' ' ; ++ptr);
  857.         /* Space drop */
  858.     for ( ; *ptr!=' ' && *ptr !='\0'; ++ptr);
  859.         /* token drop */
  860.     msg_no = atoi(&(scb->buf[sizeof(top_cmd) - 1]));
  861.     lines = atoi(++ptr);  /* Get # lines to top */
  862.     if (lines < 0) lines=0;
  863.   
  864.     msg=goto_msg(scb,msg_no);
  865.     if (msg==NULL || msg->deleted)
  866.     {
  867.         state_error(scb,"non existent or deleted message");
  868.         return;
  869.     }
  870.     fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  871.     total=msg->len;  /* Length of current message */
  872.     (void) usputs(scb->socket,noop_rsp);  /* Give OK */
  873.     do {
  874.         fgets(line,TLINELEN,scb->wf);
  875.         rrip(line);
  876.         if ( *line == '.' ) {
  877.             (void) usputc(scb->socket,'.');
  878.             total--;
  879.         }
  880.         total -= strlen(line)+2;
  881.         (void) usputs(scb->socket,line);
  882.         (void) usputc(scb->socket,'\n');
  883.     } while (*line!='\0' && total>0);
  884.     for ( ; total > 0 && lines; --lines) {
  885.         fgets(line,TLINELEN,scb->wf);
  886.         rrip(line);
  887.         if ( *line == '.' ) {
  888.             (void) usputc(scb->socket,'.');
  889.             total--;
  890.         }
  891.         total -= strlen(line)+2;
  892.         (void) usputs(scb->socket,line);
  893.         (void) usputc(scb->socket,'\n');
  894.     }
  895.     (void) usputs(scb->socket,multi_end_rsp);
  896. }
  897.   
  898. static int
  899. poplogin(username,pass)
  900. char *pass;
  901. char *username;
  902. {
  903.     char buf[80];
  904.     char *cp;
  905.     char *cp1;
  906.     FILE *fp;
  907.   
  908.     if((fp = fopen(Popusers,"r")) == NULLFILE) {
  909.         /* User file doesn't exist */
  910.         tprintf("POP users file %s not found\n",Popusers);
  911.         return(FALSE);
  912.     }
  913.   
  914.     while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  915.         if(buf[0] == '#')
  916.             continue; /* Comment */
  917.   
  918.         if((cp = strchr(buf,':')) == NULLCHAR)
  919.             /* Bogus entry */
  920.             continue;
  921.   
  922.         *cp++ = '\0';  /* Now points to password */
  923.         if(strcmp(username,buf) == 0)
  924.             break;  /* Found user name */
  925.     }
  926.   
  927.     if(feof(fp)) {
  928.         /* User name not found in file */
  929.   
  930.         fclose(fp);
  931.         return(FALSE);
  932.     }
  933.     fclose(fp);
  934.   
  935.     if ((cp1 = strchr(cp,':')) == NULLCHAR)
  936.         return(FALSE);
  937.   
  938.     *cp1 = '\0';
  939.     if(strcmp(cp,pass) != 0) {
  940.         /* Password required, but wrong one given */
  941.   
  942.         return(FALSE);
  943.     }
  944.   
  945.     /* whew! finally made it!! */
  946.   
  947.     return(TRUE);
  948. }
  949.   
  950. static void
  951. dele_message(scb)
  952. struct pop_scb *scb;
  953. {
  954.     struct pop_msg *msg;
  955.     int msg_no;
  956. #ifndef __TURBOC__
  957.     static
  958. #endif
  959.     struct pop_msg *goto_msg(struct pop_scb *,int );
  960.   
  961.     if (scb == NULLSCB) /* check for null -- wa6smn */
  962.         return;
  963.     if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  964.     {
  965.         state_error(scb,"no such message");
  966.         return;
  967.     }
  968.     msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  969.     msg=goto_msg(scb,msg_no);
  970.     if (msg==NULL || msg->deleted) {
  971.         state_error(scb,"attempt to access deleted message");
  972.         return;
  973.     }
  974.     if (msg->deleted) /* Don't bother if already dead */
  975.     {
  976.         state_error(scb,"message already deleted");
  977.         return;
  978.     }
  979.     msg->deleted=TRUE;
  980.     scb->folder_modified = TRUE;
  981.     (void) usprintf(scb->socket,dele_rsp,msg_no);
  982. }
  983.   
  984. static int
  985. newmail(scb)
  986. struct pop_scb *scb;
  987. {
  988.     char folder_pathname[64];
  989.     struct stat folder_stat;
  990.   
  991.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  992.   
  993.     /* if (stat(folder_pathname,&folder_stat)) { */
  994.     if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
  995.         state_error(scb,"Unable to get old mail folder's status");
  996.         return(FALSE);
  997.     } else
  998.         return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  999. }
  1000.   
  1001. static struct pop_msg *
  1002. goto_msg(struct pop_scb *scb,int msg_no)
  1003. {
  1004.     int msg_num;
  1005.     struct pop_msg *msg;
  1006.   
  1007.     msg_num=msg_no-1;
  1008.     if (scb->folder_len==0 || msg_num < 0)
  1009.         return NULL;
  1010.     for (msg=scb->msg->next; msg_num && msg!=NULL; --msg_num) msg=msg->next;
  1011.     return msg;
  1012. }
  1013.   
  1014. #endif
  1015.   
  1016.