bbspop3d.c
上传用户:minyiyu
上传日期:2018-12-24
资源大小:864k
文件大小:22k
源码类别:

Telnet服务器

开发平台:

Unix_Linux

  1. /*
  2.     POP3D server for Firebird BBS.
  3.     Revision [29 Oct 1997] By Peng-Piaw Foong, ppfoong@csie.ncu.edu.tw
  4.     
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13. */
  14. /* $Id: bbspop3d.c,v 1.2 2000/02/11 01:47:52 skyo Exp $ */
  15. #include <sys/ioctl.h>
  16. #include "bbs.h" 
  17. #include <sys/wait.h>
  18. #include <netinet/in.h>
  19. #include <sys/socket.h>
  20. #include <netdb.h>
  21. /* Edit these lines to fit the configuration of your server */
  22. #define POP3D_PORT  110
  23. #define BUFSIZE     1024
  24. #define BBSPASSWDS  BBSHOME"/.PASSWDS"
  25. /*  You needn't modify any lines below unless you know what you're doing */
  26. struct fileheader currentmail;
  27. struct userec currentuser;
  28. char LowUserid[20];
  29. char genbuf[BUFSIZE];
  30. char hostname[80];
  31. #define QLEN            5
  32. #define S_CONNECT       1
  33. #define S_LOGIN         2
  34. #define STRN_CPY(d,s,l) { strncpy((d),(s),(l)); (d)[(l)-1] = 0; }
  35. #define ANY_PORT        0
  36. #define RFC931_PORT     113
  37. #define RFC931_TIMEOUT  5
  38. #define POP3_TIMEOUT    60
  39. static jmp_buf timebuf;
  40. int     State;
  41. int     msock,sock;    /* master server socket */
  42. static int reaper();
  43. char    fromhost[ STRLEN ];
  44. char    inbuf[ BUFSIZE ];
  45. char    remote_userid[ STRLEN ];
  46. FILE    *cfp;
  47. char    *msg,*cmd;
  48. int     fd;
  49. struct  fileheader *fcache;
  50. int     totalnum, totalbyte, markdel, idletime;
  51. int     *postlen;
  52. void    log_usies();
  53. int     Quit(), User(), Pass(), Noop(), Stat(), List(), Retr(), Rset();
  54. int     Last(), Dele(), Uidl();
  55. struct commandlist {
  56.     char        *name;
  57.     int         (*fptr)();
  58. } cmdlists[] = {
  59.         "retr",       Retr,
  60.         "dele",       Dele,
  61.         "user",       User,
  62.         "pass",       Pass,
  63.         "stat",       Stat,
  64.         "list",       List,
  65.         "uidl",       Uidl,
  66.         "quit",       Quit,
  67.         "rset",       Rset,
  68.         "last",       Last,
  69.         "noop",       Noop,
  70.         NULL,         NULL
  71. };
  72. char *crypt();
  73. int
  74. checkpasswd(passwd, test)
  75. char *passwd, *test;
  76. {
  77.     static char pwbuf[14];
  78.     char *pw;
  79.         
  80.     strncpy(pwbuf, test, 14);
  81.     pw = crypt(pwbuf, passwd);  
  82.     return (!strcmp(pw, passwd));
  83. }
  84. static int
  85. abort_server()
  86. {
  87.     log_usies("ABORT SERVER");
  88.     close(msock);
  89.     close(sock);
  90.     exit(1);
  91. }
  92. int dokill()
  93. {
  94.    return kill(0,SIGKILL);
  95. }
  96. static FILE *fsocket(domain, type, protocol)
  97. int     domain;
  98. int     type;  
  99. int     protocol;
  100. {
  101.     int     s;
  102.     FILE   *fp;
  103.         
  104.     if ((s = socket(domain, type, protocol)) < 0) {
  105.       return (0);
  106.     } else {
  107.       if ((fp = fdopen(s, "r+")) == 0) {
  108.         close(s);
  109.       }
  110.       return (fp);
  111.     }
  112. }
  113. void
  114. outs(str)
  115. char *str;
  116. {
  117.   char sendbuf[BUFSIZE];
  118.   (void)bzero(sendbuf, sizeof(sendbuf));
  119.   (void)sprintf(sendbuf, "%srn", str);
  120.   (void)write(sock, sendbuf, strlen(sendbuf));
  121. }
  122. void
  123. outfile(filename, linenum)
  124. char *filename;
  125. int linenum;
  126. {
  127.      FILE *fp;
  128.      char linebuf[ 256 ];
  129.      
  130.      if (linenum && (fp = fopen(filename,"r")) != NULL) {
  131.        while ( fgets( linebuf, 256, fp )!=NULL && linenum > 0) {
  132.          linebuf[ strlen(linebuf)-1 ] = '';
  133.          if (strcmp( linebuf, ".")==0) outs("..");
  134.          else outs(linebuf);
  135.          linenum--;
  136.        }
  137.        fclose(fp);
  138.      }
  139.      outs(".");
  140. }
  141. /* timeout - handle timeouts */
  142. static void timeout(sig)
  143. int     sig;
  144. {
  145.     longjmp(timebuf, sig);
  146. }
  147. void    rfc931(rmt_sin, our_sin, dest)
  148. struct sockaddr_in *rmt_sin;
  149. struct sockaddr_in *our_sin;
  150. char   *dest;
  151. {
  152.     unsigned rmt_port;
  153.     unsigned our_port;
  154.     struct sockaddr_in rmt_query_sin;
  155.     struct sockaddr_in our_query_sin;
  156.     char    user[256];
  157.     char    buffer[512];
  158.     char   *cp;
  159.     FILE   *fp;
  160.     char   *result = "unknown";
  161.     struct hostent *hp;
  162.     /*
  163.      * Use one unbuffered stdio stream for writing to and for reading from
  164.      * the RFC931 etc. server. This is done because of a bug in the SunOS 
  165.      * 4.1.x stdio library. The bug may live in other stdio implementations,
  166.      * too. When we use a single, buffered, bidirectional stdio stream ("r+"
  167.      * or "w+" mode) we read our own output. Such behaviour would make sense
  168.      * with resources that support random-access operations, but not with   
  169.      * sockets.
  170.      */
  171.     if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
  172.         setbuf(fp, (char *) 0);
  173.         
  174.         /*
  175.          * Set up a timer so we won't get stuck while waiting for the server.
  176.          */
  177.         if (setjmp(timebuf) == 0) {
  178.             signal(SIGALRM, (void *)timeout);
  179.             alarm(RFC931_TIMEOUT);
  180.             /*
  181.              * Bind the local and remote ends of the query socket to the same
  182.              * IP addresses as the connection under investigation. We go
  183.              * through all this trouble because the local or remote system
  184.              * might have more than one network address. The RFC931 etc.  
  185.              * client sends only port numbers; the server takes the IP    
  186.              * addresses from the query socket.
  187.              */
  188.                                                                                                        
  189.             our_query_sin = *our_sin;
  190.             our_query_sin.sin_port = htons(ANY_PORT);
  191.             rmt_query_sin = *rmt_sin;
  192.             rmt_query_sin.sin_port = htons(RFC931_PORT);
  193.             if (bind(fileno(fp), (struct sockaddr *) & our_query_sin,
  194.                      sizeof(our_query_sin)) >= 0 &&
  195.                 connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
  196.                         sizeof(rmt_query_sin)) >= 0) {
  197.                 /*
  198.                  * Send query to server. Neglect the risk that a 13-byte
  199.                  * write would have to be fragmented by the local system and
  200.                  * cause trouble with buggy System V stdio libraries.
  201.                  */
  202.                 fprintf(fp, "%u,%urn",
  203.                         ntohs(rmt_sin->sin_port),
  204.                         ntohs(our_sin->sin_port));
  205.                 fflush(fp);
  206.                 /*
  207.                  * Read response from server. Use fgets()/sscanf() so we can
  208.                  * work around System V stdio libraries that incorrectly
  209.                  * assume EOF when a read from a socket returns less than
  210.                  * requested.
  211.                  */
  212.                 if (fgets(buffer, sizeof(buffer), fp) != 0
  213.                     && ferror(fp) == 0 && feof(fp) == 0
  214.                     && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
  215.                               &rmt_port, &our_port, user) == 3
  216.                     && ntohs(rmt_sin->sin_port) == rmt_port   
  217.                     && ntohs(our_sin->sin_port) == our_port) {
  218.                     /*
  219.                      * Strip trailing carriage return. It is part of the
  220.                      * protocol, not part of the data.
  221.                      */
  222.                     if (cp = strchr(user, 'r'))
  223.                         *cp = 0;  
  224.                     result = user;
  225.                 }
  226.             }
  227.             alarm(0);
  228.         }
  229.         fclose(fp);
  230.     }
  231.     STRN_CPY(dest, result, 60);
  232.     if (strcmp(dest,"unknown")==0) strcpy(dest,"");
  233.     else strcat( dest, "@" );
  234.     hp = gethostbyaddr((char *) &rmt_sin->sin_addr, sizeof (struct in_addr),
  235.             rmt_sin->sin_family);
  236.     if (hp)
  237.             strcat(dest, hp->h_name);
  238.     else
  239.             strcat(dest, (char *)inet_ntoa(rmt_sin->sin_addr));
  240.                                                                         
  241. }
  242. int
  243. Isspace(ch)
  244. char ch;   
  245. {
  246.     return (ch == ' ' || ch =='t' || ch == 10 || ch == 13);
  247. }
  248.     
  249. char *
  250. nextwordlower(str)
  251. char **str;
  252. {
  253.     char *p;
  254.     while (Isspace(**str))
  255.       (*str)++;
  256.     p = (*str);
  257.     while (**str && !Isspace(**str)) {
  258.       **str = tolower(**str);
  259.       (*str)++;
  260.     }
  261.     if (**str) {
  262.       **str = '';
  263.       (*str)++;
  264.     }
  265.     return p;
  266. }
  267. char *
  268. nextword(str)
  269. char **str;
  270. {
  271.     char *p;
  272.     while (Isspace(**str))
  273.       (*str)++;
  274.     p = (*str);
  275.     while (**str && !Isspace(**str))
  276.       (*str)++;
  277.     if (**str) {
  278.       **str = '';
  279.       (*str)++;
  280.     }
  281.     return p;
  282. }
  283. void
  284. Init()
  285. {
  286.      State = S_CONNECT;
  287.      LowUserid[0] = '';
  288.      markdel = 0;
  289.      idletime = 0;
  290.      (void)gethostname(hostname, 80);
  291. }
  292. void
  293. Login_init()
  294. {
  295.      int fd, i;
  296.      char *ptr;
  297.      struct stat st;
  298.           
  299.      totalnum = totalbyte = 0;
  300. /*     sprintf(genbuf, "mail/%s/.DIR", LowUserid); */
  301.      sprintf(genbuf, "mail/%c/%s/.DIR", toupper(*LowUserid), LowUserid);
  302.      if (stat(genbuf, &st) == -1 || st.st_size == 0) {
  303.        return;
  304.      }
  305.      totalnum = st.st_size / sizeof(struct fileheader);
  306.      fcache = (struct fileheader *)malloc(st.st_size);
  307.      postlen = (int *)malloc(sizeof(int) * totalnum);
  308.      fd = open(genbuf, O_RDONLY);
  309.      read(fd, fcache, st.st_size);
  310.      close(fd);
  311.      for (i = 0; i < totalnum; i++) {
  312.        if (index(fcache[i].owner, '@') == NULL) {
  313.          if (ptr = strchr(fcache[i].owner, ' '))
  314.            *ptr = '';
  315.          strcat(fcache[i].owner, ".bbs@MSIA.pine.ncu.edu.tw");
  316.        }
  317.        sprintf(genbuf, "mail/%c/%s/%s", toupper(*LowUserid), LowUserid, fcache[i].filename);
  318.        if (stat(genbuf, &st) == -1)
  319.          st.st_size = 0;
  320.        postlen[i] = st.st_size + strlen(fcache[i].owner) + 10 + strlen(fcache[i].title)
  321.                       + 10 + 40;
  322.        totalbyte += postlen[i];
  323.        fcache[i].accessed[0] = ' ';
  324.      }
  325. }
  326. void
  327. pop3_timeout()
  328. {
  329.     idletime++;
  330.     if (idletime > 5) {
  331.       log_usies("ABORT - TIMEOUT");
  332.       fclose(cfp);
  333.       close(sock);
  334.       exit(1);
  335.     }
  336.     alarm(POP3_TIMEOUT);
  337. }
  338. main(argc,argv)
  339. int argc;
  340. char **argv;
  341. {
  342.         struct sockaddr_in fsin,our;
  343.         int on,alen,len,i, n;
  344.         char *str;
  345.         int portnum = POP3D_PORT;
  346.         int childpid;
  347.         if(fork()) 
  348.           exit(0);
  349.         for (n = 0; n<10; n++)
  350.           close(n);
  351.         open("/dev/null", O_RDONLY);
  352.         dup2(0,1);
  353.         dup2(0,2);
  354.         if((n=open("/dev/tty",O_RDWR)) > 0) {
  355.           ioctl(n, TIOCNOTTY, 0) ; 
  356.           close(n);
  357.         }
  358.         
  359.         if ((msock = socket(AF_INET,SOCK_STREAM,0)) < 0) {
  360.           exit(1);
  361.         }
  362.         setsockopt(msock,SOL_SOCKET,SO_REUSEADDR, (char *) &on, sizeof(on));
  363.         bzero((char *)&fsin,sizeof(fsin));
  364.         fsin.sin_family = AF_INET;
  365.         fsin.sin_addr.s_addr = htonl(INADDR_ANY);
  366.         fsin.sin_port = htons(portnum);
  367.                                                         
  368.         if (bind(msock,(struct sockaddr *)&fsin,sizeof(fsin))<0) {
  369.           exit(1);
  370.         }
  371.         signal(SIGHUP, (void *)abort_server) ;
  372.         signal(SIGCHLD,(void *)reaper);
  373.         signal(SIGINT, (void *)dokill);
  374.         signal(SIGTERM,(void *)dokill);
  375.         listen(msock,QLEN);
  376.        
  377.         while (1) {
  378.           alen=sizeof(fsin);
  379.           sock = accept(msock,(struct sockaddr *)&fsin,&alen);
  380.           if ((sock < 0) && (errno == EINTR)) 
  381.             continue;
  382.           if ((childpid = fork()) < 0) {
  383.             exit(1);
  384.           }  
  385.           switch (childpid) {
  386.           case 0:  /* child process */
  387.             close(msock);
  388.             setgid(BBSGID);
  389.             setuid(BBSUID);
  390.             strcpy(fromhost, (char *)inet_ntoa(fsin.sin_addr));
  391.             len = sizeof our;
  392.             getsockname(sock, (struct sockaddr *) &our,&len);
  393.             Init();
  394.             rfc931( &fsin, &our, remote_userid );
  395.     
  396.             cfp = fdopen(sock, "r+");
  397.             setbuf(cfp, (char *) 0);
  398.             
  399.             sprintf(genbuf, "+OK InternetBBS Pop server at %s starting.", hostname);
  400.             outs(genbuf);
  401.             chdir(BBSHOME);
  402.             log_usies("CONNECT");
  403.             alarm(0);
  404.             signal(SIGALRM, (void *)pop3_timeout);
  405.             alarm(POP3_TIMEOUT);
  406.             
  407.             while (fgets(inbuf, sizeof(inbuf), cfp)!=0) {
  408.             
  409.                idletime = 0;
  410.                
  411.                msg = inbuf;
  412.        
  413.                inbuf[ strlen(inbuf)-1 ] = '';
  414.                if (inbuf[strlen(inbuf)-1] == 'r') inbuf[strlen(inbuf)-1] = '';
  415.                cmd = nextwordlower(&msg);
  416.                if (*cmd==0) continue;
  417.                
  418.                i = 0;
  419.                while ( (str = cmdlists[i].name) != NULL ) {
  420.                  if ( strcmp( cmd, str ) == 0 ) break;
  421.                  i++;
  422.                }
  423.                if (str==NULL)
  424.                {
  425.                   sprintf(genbuf, "-ERR Unknown command: "%s".", cmd);
  426.                   outs(genbuf);
  427.                }
  428.                else (*cmdlists[i].fptr)();
  429.             }
  430.             if (State == S_LOGIN) {
  431.               free(fcache);
  432.               free(postlen);
  433.             }
  434.             log_usies("ABORT");
  435.             fclose(cfp);
  436.             close(sock);
  437.             exit(0);
  438.             break;
  439.           default:   /* parent process */
  440.             close(sock);
  441.             break;
  442.           }        
  443.         }
  444. }
  445. static int
  446. reaper()
  447. {
  448.      int state, pid;
  449.      signal(SIGCHLD,(void *)reaper);
  450.      signal(SIGINT, (void *)dokill);
  451.      signal(SIGTERM,(void *)dokill);
  452.      while (( pid = waitpid(-1, &state, WNOHANG|WUNTRACED)) > 0);
  453.      return 0;
  454. }
  455. int
  456. Noop()
  457. {
  458.     outs("+OK");
  459.     return 0;
  460. }
  461. int
  462. get_userdata(user)
  463. char *user;
  464. {
  465.         FILE *rec;
  466.         int found=0;
  467.         if((rec=fopen(BBSPASSWDS,"rb"))==NULL)
  468.                 return -1;
  469.         while(1)
  470.         {
  471.                 if(fread(&currentuser,sizeof(currentuser),1,rec)<=0) break;
  472.                 if(currentuser.numlogins<=0)
  473.                         continue;
  474.                 if(strcasecmp(user,currentuser.userid))
  475.                         continue;
  476.                 else
  477.                 {
  478.                         found=1;
  479.                         strcpy(user,currentuser.userid);
  480.                         break;
  481.                 }
  482.         }
  483.         fclose(rec);
  484.         if(!found)
  485.                 return -1;
  486.         else
  487.                 return 1;
  488. }
  489. int
  490. User()
  491. {
  492.      char *ptr;
  493.      
  494.      if (State == S_LOGIN) {
  495.        outs("-ERR Unknown command: "user".");
  496.        return -1;
  497.      }
  498.      cmd = nextwordlower(&msg);
  499.      if (*cmd == 0) {
  500.        outs("-ERR Too few arguments for the user command.");
  501.        return -1;
  502.      }
  503.      if (strstr(cmd, ".bbs") == NULL) {
  504.        sprintf(genbuf, "-ERR Unknown user: "%s".", cmd);
  505.        outs(genbuf);
  506.        return -1;
  507.      }
  508.      ptr = strchr(cmd, '.');
  509.      *ptr = '';
  510.      if(get_userdata(cmd)==1)
  511.      {
  512.              strcpy(LowUserid, cmd);
  513.              sprintf(genbuf, "+OK Password required for %s.bbs.", cmd);
  514.              outs(genbuf);
  515.              return 0;
  516.      }else
  517.      {
  518.        sprintf(genbuf, "-ERR Unknown user: "%s".", cmd);
  519.        outs(genbuf);
  520.        return -1;
  521.      }
  522. }
  523. void
  524. log_usies(buf)
  525. char *buf;
  526. {
  527.      FILE *fp;
  528.      if ((fp = fopen("log/pop3d.log","a")) != NULL) {
  529.        time_t now;
  530.        struct tm *p;
  531.        
  532.        time(&now);
  533.        p = localtime(&now);
  534.        fprintf(fp, "%02d/%02d/%02d %02d:%02d:%02d [%s](%s) %sn",
  535.                  p->tm_year, p->tm_mon+1, p->tm_mday, p->tm_hour, p->tm_min,
  536.                  p->tm_sec, currentuser.userid ? currentuser.userid : "",
  537.                       remote_userid ? remote_userid : "", buf);
  538.        fflush(fp);
  539.        fclose(fp);
  540.      }
  541. }
  542. int
  543. Retr()
  544. {
  545.      int num;
  546.      
  547.      if (State != S_LOGIN) {
  548.        outs("-ERR Unknown command: "retr".");
  549.        return -1;
  550.      }
  551.      cmd = nextword(&msg);
  552.      
  553.      if (*cmd==0) {
  554.        outs("-ERR Too few arguments for the retr command.");
  555.        return -1;
  556.      }
  557.      
  558.      num = atoi(cmd);
  559.      if (num <= 0 || totalnum < num) {
  560.        sprintf(genbuf, "-ERR Message %d does not exist.", num);
  561.        outs(genbuf);
  562.        return -1;
  563.      } else if (fcache[num-1].accessed[0] == 'X') {
  564.        sprintf(genbuf, "-ERR Message %d has been deleted.", num);
  565.        outs(genbuf);
  566.        return -1;
  567.      }
  568.      num--;
  569.      sprintf(genbuf, "+OK %d octets", postlen[num]);
  570.      outs(genbuf);
  571.      sprintf(genbuf, "From: %s", fcache[num].owner);
  572.      outs(genbuf);
  573.      sprintf(genbuf, "To: %s.bbs@MSIA.pine.ncu.edu.tw", currentuser.userid);
  574.      outs(genbuf);
  575.      sprintf(genbuf, "Subject: %s", fcache[num].title);
  576.      outs(genbuf);
  577.      outs("");
  578.      sprintf(genbuf, "mail/%c/%s/%s", toupper(*LowUserid), LowUserid, fcache[num].filename);
  579.      outfile(genbuf,99999);
  580.      return 0;
  581. }
  582. int
  583. Stat()
  584. {
  585.      if (State != S_LOGIN) {
  586.        outs("-ERR Unknown command: "stat".");
  587.        return -1;
  588.      }
  589.      sprintf(genbuf, "+OK %d %d", totalnum, totalbyte);
  590.      outs(genbuf);
  591.      return 0;
  592. }
  593. int
  594. Rset()
  595. {
  596.      int i;
  597.      
  598.      if (State != S_LOGIN) {
  599.        outs("-ERR Unknown command: "rset".");
  600.        return -1;
  601.      }
  602.      for (i = 0; i < totalnum; i++) {
  603.        fcache[i].accessed[0] = ' ';
  604.      }
  605.      markdel = 0;
  606.      sprintf(genbuf, "+OK Maildrop has %d messages (%d octets)", totalnum, totalbyte);
  607.      outs(genbuf);
  608.      return 0;
  609. }
  610. int
  611. List()
  612. {
  613.      int i;
  614.      
  615.      if (State != S_LOGIN) {
  616.        outs("-ERR Unknown command: "list".");
  617.        return -1;
  618.      }
  619.      cmd = nextword(&msg);
  620.      
  621.      if (*cmd == 0) {
  622.        sprintf(genbuf, "+OK %d messages (%d octets)", totalnum, totalbyte);
  623.        outs(genbuf);
  624.        for (i = 0; i < totalnum; i++) {
  625.          if (fcache[i].accessed[0] == ' ') {
  626.            sprintf(genbuf, "%d %d", i+1, postlen[i]);
  627.            outs(genbuf);
  628.          }
  629.        }
  630.        outs(".");
  631.      } else {
  632.        i = atoi(cmd);
  633.        if (i <= 0 || totalnum < i) {
  634.          sprintf(genbuf, "-ERR Message %d does not exist.", i);
  635.          outs(genbuf);
  636.          return -1;
  637.        } else if (fcache[i-1].accessed[0] == 'X') {
  638.          sprintf(genbuf, "-ERR Message %d has been deleted.", i);
  639.          outs(genbuf);
  640.          return -1;
  641.        }
  642.        sprintf(genbuf, "+OK %d %d", i, postlen[i-1]);
  643.        outs(genbuf);
  644.      }
  645.      return 0;
  646. }
  647. int
  648. Uidl()
  649. {
  650.      int i;
  651.      
  652.      if (State != S_LOGIN) {
  653.        outs("-ERR Unknown command: "uidl".");
  654.        return -1;
  655.      }
  656.      cmd = nextword(&msg);
  657.      
  658.      if (*cmd == 0) {
  659.        outs("+OK");
  660.        for (i = 0; i < totalnum; i++) {
  661.          if (fcache[i].accessed[0] == ' ') {
  662.            sprintf(genbuf, "%d %s", i+1, fcache[i].filename);
  663.            outs(genbuf);
  664.          }
  665.        }
  666.        outs(".");
  667.      } else {
  668.        i = atoi(cmd);
  669.        if (i <= 0 || totalnum < i) {
  670.          sprintf(genbuf, "-ERR Message %d does not exist.", i);
  671.          outs(genbuf);
  672.          return -1;
  673.        } else if (fcache[i-1].accessed[0] == 'X') {
  674.          sprintf(genbuf, "-ERR Message %d has been deleted.", i);
  675.          outs(genbuf);
  676.          return -1;
  677.        }
  678.        sprintf(genbuf, "+OK %d %s", i, fcache[i-1].filename);
  679.        outs(genbuf);
  680.      }
  681.      return 0;
  682. }
  683. int
  684. Pass()
  685. {
  686.      if (State == S_LOGIN) {
  687.        outs("-ERR Unknown command: "pass".");
  688.        return -1;
  689.      }
  690.      cmd = nextword(&msg);
  691.      
  692.      if (*cmd==0) {
  693.        outs("-ERR Too few arguments for the pass command.");
  694.        return -1;
  695.      }
  696.      if (LowUserid[0]=='') {
  697.        outs("-ERR need a USER");
  698.        return -1;
  699.      }
  700.      if (!checkpasswd(currentuser.passwd, cmd)) {
  701.        sprintf(genbuf, "-ERR Password supplied for "%s.bbs" is incorrect.", LowUserid);
  702.        outs(genbuf);
  703.        LowUserid[0] = '';
  704.        log_usies("ERROR PASSWD");
  705.        return -1;
  706.      }
  707.      if (State==S_CONNECT) {
  708.        log_usies("ENTER");
  709.        State = S_LOGIN;
  710.      }
  711.      Login_init();
  712.      sprintf(genbuf, "+OK %s has %d message(s) (%d octets).", LowUserid, totalnum, totalbyte);
  713.      outs(genbuf);
  714.      return 0;
  715. }
  716. int
  717. Last()
  718. {
  719.      if (State != S_LOGIN) {
  720.        outs("-ERR Unknown command: "last".");
  721.        return -1;
  722.      }
  723.      sprintf(genbuf, "+OK %d is the last message seen.", totalnum);
  724.      outs(genbuf);
  725.      return 0;
  726. }
  727. int
  728. Dele()
  729. {
  730.      int num;
  731.      
  732.      if (State != S_LOGIN) {
  733.        outs("-ERR Unknown command: "dele".");
  734.        return -1;
  735.      }
  736.      cmd = nextword(&msg);
  737.      
  738.      if (*cmd==0) {
  739.        outs("-ERR Too few arguments for the dele command.");
  740.        return -1;
  741.      }
  742.      
  743.      num = atoi(cmd);
  744.      if (num <= 0 || totalnum < num) {
  745.        sprintf(genbuf, "-ERR Message %d does not exist.", num);
  746.        outs(genbuf);
  747.        return -1;
  748.      } else if (fcache[num-1].accessed[0] == 'X') {
  749.        sprintf(genbuf, "-ERR Message %d has already been deleted.", num);
  750.        outs(genbuf);
  751.        return -1;
  752.      }
  753.      num--;
  754.      fcache[num].accessed[0] = 'X';
  755.      markdel++;
  756.      sprintf(genbuf, "+OK Message %d has been deleted.", num);
  757.      outs(genbuf);
  758.      return 0;
  759. }
  760. int
  761. do_delete()
  762. {
  763.     int i, fdr, fdw, count;
  764.     char fpath[80], fnew[80];
  765.     
  766.     sprintf(fpath, "mail/%c/%s/.DIR", toupper(*LowUserid), LowUserid);
  767.     sprintf(fnew, "mail/%c/%s/pop3.DIR", toupper(*LowUserid), LowUserid);
  768.     if ((fdr = open(fpath, O_RDONLY)) == -1) return -1;
  769.     if ((fdw = open(fnew, O_RDWR|O_CREAT, 0644)) == -1) return -1;
  770.     i = count = 0;
  771.     while (read(fdr, &currentmail, sizeof(currentmail))) {
  772.       if (i >= totalnum || fcache[i].accessed[0] == ' ') {
  773.         write(fdw, &currentmail, sizeof(currentmail));
  774.         count++;
  775.       } else {
  776.         sprintf(genbuf, "mail/%c/%s/%s", toupper(*LowUserid), LowUserid,
  777.                            currentmail.filename);
  778.         unlink(genbuf);
  779.       }
  780.       i++;
  781.     }
  782.     close(fdr);
  783.     close(fdw);
  784.     unlink(fpath);
  785.     if (count) 
  786.     {
  787.         rename(fnew, fpath);
  788.     }
  789.     else 
  790.         unlink(fnew);
  791.     return 0;
  792. }
  793. int
  794. Quit()
  795. {
  796.      if (State == S_LOGIN) {
  797.        if (markdel) do_delete();
  798.        free(fcache);
  799.        free(postlen);
  800.      }
  801.      log_usies("EXIT");
  802.      sprintf(genbuf, "+OK InternetBBS Pop server at %s signing off.", hostname);
  803.      outs(genbuf);
  804.      fclose(cfp);
  805.      close(sock);
  806.      exit(0);
  807. }