home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / h / if / POP / c / pop
Encoding:
Text File  |  1994-09-24  |  14.3 KB  |  630 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4. #include <time.h>
  5. #include <ctype.h>
  6. #include <string.h>
  7. #include "global.h"
  8. #include "timer.h"
  9. #include "cmdparse.h"
  10. #include "netuser.h"
  11. #include "pop.h"
  12. #include "smtp.h"
  13. #include "domain.h"
  14. #include "misc.h"
  15. #include "tcp.h"
  16. #include "mbuf.h"
  17. #include "Terminal.h"
  18. #include "vterm.h"
  19.  
  20. #include "os.h"
  21. #include "swis.h"
  22.  
  23. typedef enum {
  24.   state_IDLE,
  25.   state_RECM,
  26.   state_USER,
  27.   state_PASS,
  28.   state_QUIT,
  29.   state_LIST,
  30.   state_LISTANS,
  31.   state_LISTREC,
  32.   state_RETR,
  33.   state_RETRANS,
  34.   state_RETRREC,
  35.   state_DELETE
  36. };
  37.  
  38.  
  39. struct messages {
  40.   struct messages *next;
  41.   int msg_id;
  42.   int msg_size;
  43. };
  44.  
  45. static struct popservers {
  46.   struct timer pop_t;
  47.   char *name;
  48.   char *abbr;
  49.   char *user;
  50.   char *pwd;
  51.   int lowtime, hightime;  /* for connect window */
  52.   struct popservers *next;
  53.   struct tcb *tcb;        /* tcp task control buffer */
  54.   int32   ipdest;         /* address of forwarding system */
  55.   char    state;          /* state machine placeholder */
  56.   char    stage;          /* another state machine placeholder */
  57.   char    buf[LINELEN];   /* Input buffer */
  58.   int     cnt;            /* Length of input buffer */
  59.   char    locked;
  60.   long    msgstart;       /* Place holder for writing mail separator */
  61.   FILE    *mail;
  62.   char    ismulti;
  63.   char    quit;
  64.   struct messages *msgs;
  65.   Terminal *window;
  66. };
  67.  
  68. extern int16 lport;                     /* local port placeholder */
  69.  
  70. struct popservers *POPservers = NULL;
  71. int trace = 0;
  72.  
  73. static char *seps[] = {"From", "Ctrl-A", "#! rnews", "#! rmail"};
  74. static int pop_sep = sep_UNIX;
  75.  
  76. static void poptick( void * );
  77. static void pop_rec(struct tcb *, int16);
  78. static void pop_cts(struct tcb *, int16);
  79. static void pop_state(struct tcb *, char, char);
  80. static void pop_transaction( struct popservers * );
  81. static int lock_spoolfile( struct popservers * );
  82. static int dosep(int argc, char *argv[]);
  83.  
  84.  
  85. static void pop_cts(struct tcb *tcb, int16 cnt)
  86. {
  87.   tcb = tcb;
  88.   cnt = cnt;
  89.   /* we actually don't use it */
  90. }
  91.  
  92.  
  93. static void pop_state(register struct tcb *tcb, char old, char new)
  94. {
  95.   register struct popservers *cb;
  96.   extern char *tcpstates[];
  97.  
  98.   old = old;
  99.  
  100.   cb = (struct popservers *)tcb->user;
  101.   if (trace > 4)
  102.     cwprintf(cb->window, "pop_state called: %s\n",tcpstates[new]);
  103.  
  104.   switch(new)
  105.   {
  106.   case ESTABLISHED:
  107.     cb->state = state_USER;     /* shouldn't be needed */
  108.     cb->cnt = 0;
  109.     cb->ismulti = 0;
  110.     cb->quit = 1;
  111.     cb->msgs = NULL;
  112.     if (lock_spoolfile(cb))
  113.       close_tcp(tcb);
  114.     break;
  115.   case CLOSE_WAIT:
  116.     close_tcp(tcb);                 /* shut things down */
  117.     break;
  118.   case CLOSED:
  119.     if (cb->locked )
  120.       rmlock( mailspool, cb->user );
  121.     if (cb->mail )
  122.     {
  123.       long len;
  124.       char mailbox[200];
  125.       fseek( cb->mail, 0, SEEK_END); /* check for 0 length file */
  126.       len = ftell(cb->mail);
  127.       fclose( cb->mail );
  128.       if (!len) /* dispose of 0 length file */
  129.       {
  130.         sprintf(mailbox,"%s.text.%s",mailspool,cb->user);
  131.         remove(mailbox);
  132.       }
  133.     }
  134.  
  135.     /* if this close was not done by us ie. a RST */
  136.     del_tcp(tcb);
  137.     if (cb->window)
  138.     {
  139.       cb->window->Attr = ATTR_REVERSE;
  140.       cb->window->Flags.flags.dont_destroy = FALSE;
  141.       Window_Close(cb->window);
  142.       cb->window = NULL;
  143.     }
  144.     start_timer(&cb->pop_t);
  145.     break;
  146.   }
  147. }
  148.  
  149. static void pop_rec(struct tcb *tcb, int16 cnt)
  150. {
  151.   register struct popservers *cb;
  152.   char c;
  153.   struct mbuf *bp;
  154.  
  155.   if (trace > 4)
  156.   {
  157.     cwprintf(cb->window, "pop_rec called\n");
  158.   }
  159.  
  160.   if((cb = (struct popservers *)tcb->user) == NULL) /* point to our struct */
  161.   {
  162.     close_tcp(tcb);
  163.     return;
  164.   }
  165.   recv_tcp(tcb,&bp,cnt);  /* suck up chars from low level routine */
  166.  
  167.   /* Assemble input line in buffer, return if incomplete */
  168.   while(pullone(&bp,&c) == 1)
  169.   {
  170.     switch(c)
  171.     {
  172.     case '\r':      /* strip cr's */
  173.       continue;
  174.     case '\n':      /* line is finished, go do it! */
  175.       cb->buf[cb->cnt] = '\0';
  176.       pop_transaction(cb);
  177.       cb->cnt = 0;
  178.       break;
  179.     default:        /* other chars get added to buffer */
  180.       cb->buf[cb->cnt++] = c;
  181.       if(cb->cnt > LINELEN - 2)
  182.       {
  183.         cb->buf[cb->cnt] = '\0';
  184.         pop_transaction(cb);
  185.         cb->cnt = 0;
  186.       }
  187.       break;
  188.     }
  189.   }
  190. }
  191.  
  192.  
  193. /* Send message back to server */
  194. static void sendit(struct popservers *cb, char *fmt, ...)
  195. {
  196.   va_list argptr;
  197.   struct mbuf *bp;
  198.   char tmpstring[256];
  199.  
  200.   va_start(argptr,fmt);
  201.   vsprintf(tmpstring,fmt,argptr);
  202.   va_end(argptr);
  203.  
  204.   if (trace > 3)
  205.   {
  206.     cwprintf(cb->window, ">>> %s\n", tmpstring);
  207.   }
  208.   bp = qdata(tmpstring,(int16)strlen(tmpstring));
  209.   send_tcp(cb->tcb,bp);
  210. }
  211.  
  212.  
  213. static void clear_msglist( struct popservers *cb )
  214. {
  215.   struct messages *msg;
  216.   struct messages *msgnext;
  217.  
  218.   for (msg = cb->msgs; msg; msg = msgnext)
  219.   {
  220.     msgnext = msg->next;
  221.     free(msg);
  222.   }
  223. }
  224.  
  225.  
  226. static int eof( struct popservers *cb )
  227. {
  228.   return(!strcmp( cb->buf, "." ));
  229. }
  230.  
  231.  
  232. static void pop_transaction( struct popservers *cb )
  233. {
  234.   char error = 0;
  235.   int cont   = 1;
  236.   time_t t;
  237.   int fail   = 0;
  238.  
  239.   if (trace > 5 || (trace > 3 && !cb->ismulti))
  240.     cwprintf(cb->window, "<<< %s\n", cb->buf );
  241.   if (!cb->ismulti)
  242.     error = cb->buf[0] == '-';
  243.   if (error)
  244.   {
  245.     cwprintf(cb->window, "POP error: %s\n", cb->buf);
  246.     if (cb->quit)
  247.       cb->state = state_QUIT;
  248.   }
  249.  
  250.   while( cont )
  251.   {
  252.     cont = 0;
  253.     switch( cb->state )
  254.     {
  255.  
  256.     case state_QUIT:
  257.       clear_msglist( cb );
  258.       if (!cb->quit)
  259.         break;
  260.       sendit( cb, "QUIT\r\n" );
  261.       if (! --(cb->quit))
  262.         cb->state = state_IDLE;
  263.       break;
  264.  
  265.     case state_USER:
  266.       sendit( cb, "USER %s\r\n", cb->user );
  267.       cb->state = state_PASS;
  268.       break;
  269.  
  270.     case state_PASS:
  271.       sendit( cb, "PASS %s\r\n", cb->pwd );
  272.       cb->state = state_LIST;
  273.       break;
  274.  
  275.     case state_LIST:
  276.       cb->quit = 2;              /* we need double quit to quit here */
  277.       sendit( cb, "LIST\r\n" );
  278.       cb->state = state_LISTANS;
  279.       break;
  280.  
  281.     case state_LISTANS:
  282.       cb->state = state_LISTREC;
  283.       cb->ismulti = 1;
  284.       break;
  285.  
  286.     case state_LISTREC:
  287.       if (eof(cb))
  288.       {
  289.         if (trace>4 )
  290.           cwprintf(cb->window, "end of list\n" );
  291.         cb->ismulti = 0, cb->state = state_RETR;
  292.         cont = 1;
  293.       }
  294.       else
  295.       {
  296.         struct messages *msg;
  297.  
  298.         if (trace > 4)
  299.           cwprintf(cb->window, "adding to list: %s\n", cb->buf );
  300.         msg = malloc( sizeof(*msg) );
  301.         if (!msg)
  302.           cwprintf(cb->window, "POP: fatal error: memory overflow\n" );
  303.         msg->next = cb->msgs;
  304.         cb->msgs = msg;
  305.         sscanf( cb->buf, "%d %d", &msg->msg_id, &msg->msg_size );
  306.       }
  307.       break;
  308.  
  309.     case state_RETR:
  310.       if ( !cb->msgs )
  311.       {
  312.         cb->state = state_QUIT;
  313.         cont = 1;
  314.       }
  315.       else
  316.       {
  317.         if (trace )
  318.           cwprintf(cb->window, "retrieving message %d\n", cb->msgs->msg_id );
  319.         sendit( cb, "RETR %d\r\n", cb->msgs->msg_id );
  320.         cb->state = state_RETRANS;
  321.       }
  322.       break;
  323.  
  324.     case state_RETRANS:
  325.       cb->state = state_RETRREC;
  326.       cb->ismulti = 1;
  327.       time(&t);
  328.       if (pop_sep==sep_UNIX)
  329.         fprintf(cb->mail,"From %s",ctime(&t));
  330.       else if (pop_sep==sep_RMAIL)
  331.         fprintf(cb->mail,"#! rmail         \n");
  332.       else if (pop_sep==sep_RNEWS)
  333.         fprintf(cb->mail,"#! rnews         \n");
  334.       else if (pop_sep==sep_CTLA)
  335.         fprintf(cb->mail, "%c\n", 0x01);
  336.       if (ferror( cb->mail ) )
  337.         fail = 1;
  338.       cb->msgstart = ftell(cb->mail);
  339.       break;
  340.  
  341.     case state_RETRREC:
  342.       if (eof(cb) )
  343.       {
  344.         fprintf( cb->mail, "\n" );
  345.         if (ferror( cb->mail ) )
  346.           fail=1;
  347.         else
  348.         {
  349.           if (pop_sep==sep_RMAIL || pop_sep==sep_RNEWS)
  350.           {
  351.             long p = ftell(cb->mail);
  352.             fseek(cb->mail, cb->msgstart+9, SEEK_SET);
  353.             fprintf(cb->mail,"%.8ld",p-cb->msgstart);
  354.             fseek(cb->mail, p, SEEK_SET);
  355.           }
  356.         }
  357.         cb->ismulti = 0, cb->state = state_DELETE;
  358.         cont=1;
  359.       }
  360.       else
  361.       {
  362.         /* '.' unescaping and "From " escaping */
  363.         if (*cb->buf=='.')
  364.           fprintf( cb->mail, "%s\n", cb->buf+1 );
  365.         else if (pop_sep==sep_UNIX && !strncmp(cb->buf, "From ", 5))
  366.           fprintf( cb->mail, ">%s\n", cb->buf );
  367.         else
  368.           fprintf( cb->mail, "%s\n", cb->buf );
  369.         if (ferror( cb->mail ) )
  370.           fail=1;
  371.       }
  372.       break;
  373.  
  374.     case state_DELETE:
  375.       if (fail )
  376.       {
  377.         cwprintf(cb->window, "POP: fatal error - mail left on pop server\n" );
  378.         cb->state = state_QUIT;
  379.         cont = 1;
  380.         break;
  381.       }
  382.       sendit( cb, "DELE %d\r\n", cb->msgs->msg_id );
  383.       cb->state = state_RETR;
  384.       {
  385.         struct messages *msg;
  386.         msg = cb->msgs;
  387.         cb->msgs = cb->msgs->next;
  388.         free(msg);
  389.       }
  390.       break;
  391.     }
  392.   }
  393. }
  394.  
  395. static int lock_spoolfile( struct popservers * cb )
  396. {
  397.   char mailbox[200];
  398.  
  399.   if (mlock(mailspool,cb->user))
  400.   {
  401.     cwprintf(cb->window, "POP: error: spool file locked - try later\n" );
  402.     return 1;
  403.   }
  404.   else
  405.   {
  406.     sprintf(mailbox,"%s.text.%s",mailspool,cb->user);
  407.     if((cb->mail = fopen(mailbox,"a+")) != NULLFILE)
  408.     {
  409.       cb->locked = 1;
  410.       return 0;
  411.     }
  412.     else rmlock(mailspool,cb->user);
  413.   }
  414.   return 1;
  415. }
  416.  
  417.  
  418. static int doadds(int argc, char *argv[])
  419. {
  420.   struct popservers *pop;
  421.   int i;
  422.  
  423.   for(pop = POPservers; pop != NULL; pop = pop->next)
  424.     if(stricmp(pop->abbr,argv[5]) == 0)              /* ought to be stricmp */
  425.       break;
  426.   if (pop == NULL)
  427.   {
  428.     pop = (struct popservers *) calloc(1,sizeof(struct popservers));
  429.     pop->name = strdup(argv[1]);
  430.     pop->abbr = strdup(argv[5]);
  431.     pop->ipdest = resolve(argv[1]);
  432.     pop->user = strdup(argv[3]);
  433.     pop->pwd = strdup(argv[4]);
  434.     pop->next = POPservers;
  435.     POPservers = pop;
  436.     pop->lowtime = pop->hightime = -1;
  437.     pop->pop_t.func = poptick;  /* what to call on timeout */
  438.     pop->pop_t.arg = (void *)pop;
  439.     pop->state = state_IDLE;
  440.   }
  441.   for (i = 5; i < argc; ++i)
  442.   {
  443.     if (isdigit(*argv[i]))
  444.     {
  445.       int lh, ll, hh, hl;
  446.       sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
  447.       pop->lowtime = lh * 100 + ll;
  448.       pop->hightime = hh * 100 + hl;
  449.     }
  450.   }
  451.   /* set timer duration */
  452.   set_timer(&pop->pop_t,atol(argv[2])*1000L);
  453.   start_timer(&pop->pop_t);            /* and fire it up */
  454.  
  455.   return 0;
  456. }
  457.  
  458. static int dodrops(int argc, char *argv[])
  459. {
  460.   struct popservers *pop, *popprev = NULL;
  461.  
  462.   for(pop = POPservers; pop != NULL; popprev = pop, pop = pop->next)
  463.   {
  464.     if (stricmp(pop->name, argv[1]) == 0 || stricmp(pop->abbr, argv[1]) == 0)
  465.       if (pop->state == state_IDLE )
  466.       {
  467.         stop_timer(&pop->pop_t);
  468.         free(pop->name);
  469.         free(pop->abbr);
  470.         free(pop->user);
  471.         free(pop->pwd);
  472.         if(popprev != NULL)
  473.           popprev->next = pop->next;
  474.         else
  475.           POPservers = pop->next;
  476.         free((char *)pop);
  477.         return 0;
  478.       }
  479.   }
  480.   cwprintf(NULL, "POP - No such server enabled.\n");
  481.   return 0;
  482. }
  483.  
  484. static int dokicks(int argc, char *argv[])
  485. {
  486.   struct popservers *pop;
  487.  
  488.   for (pop = POPservers; pop != NULL; pop = pop->next)
  489.   {
  490.     if (stricmp(pop->name, argv[1]) == 0 || stricmp(pop->abbr, argv[1]) == 0)
  491.     {
  492.       /* If the timer is not running, the timeout function has
  493.              * already been called and we don't want to call it again.
  494.                                           */
  495.       if(run_timer(&pop->pop_t))
  496.       {
  497.         stop_timer(&pop->pop_t);
  498.         poptick((void *)pop);
  499.       }
  500.       else
  501.       {
  502.         cwprintf(NULL, "POP - Can't restart\n");
  503.       }
  504.       return 0;
  505.     }
  506.   }
  507.   cwprintf(NULL, "POP - No such server enabled.\n");
  508.   return 0;
  509. }
  510.  
  511.  
  512.  
  513. static int dolists(int argc, char *argv[])
  514. {
  515.   struct popservers *pop;
  516.  
  517.   for (pop = POPservers; pop != NULL; pop = pop->next)
  518.   {
  519.     char tbuf[80];
  520.  
  521.     if (pop->lowtime != -1 && pop->hightime != -1)
  522.       sprintf(tbuf, " -- %02d:%02d-%02d:%02d", pop->lowtime/100, pop->lowtime%100, pop->hightime/100, pop->hightime%100);
  523.     else
  524.       tbuf[0] = '\0';
  525.     cwprintf(NULL, "%-32s (%lu/%lu%s)\n", pop->name,
  526.              read_timer(&pop->pop_t) /1000L,
  527.              dur_timer(&pop->pop_t) /1000L,
  528.              tbuf);
  529.   }
  530.   return 0;
  531. }
  532.  
  533.  
  534.  
  535. static int dopoptrace(int argc, char **argv)
  536. {
  537.   if (argc < 2)
  538.     cwprintf(NULL, "%d\n",trace);
  539.   else
  540.     trace = atoi(argv[1]);
  541.   return 0;
  542. }
  543.  
  544.  
  545. static void poptick(void *tp)
  546. {
  547.   char title[80];
  548.   struct socket lsocket, fsocket;
  549.   register struct popservers *cb;
  550.  
  551.   cb = (struct popservers *) tp;
  552.   if (cb == NULL)
  553.     return;
  554.   if(cb->state != state_IDLE)
  555.     return;
  556.  
  557.   sprintf(title, "POP - %s", cb->name);
  558.   cb->window = Window_Open(NULL, title, term_NO_INPUT);
  559.   vterm_visible(cb->window->vt, 40, 8);
  560.   vterm_setflags(cb->window->vt, VTSW_WRAP, VTSW_WRAP);
  561.   /* setup the socket */
  562.   fsocket.address = cb->ipdest;
  563.   fsocket.port    = POP_PORT;
  564.   lsocket.address = ip_addr;      /* our ip address */
  565.   lsocket.port    = lport++;      /* next unused port */
  566.  
  567.   if (trace)
  568.   {
  569.     cwprintf(cb->window, "POP daemon entered\n",inet_ntoa(fsocket.address));
  570.   }
  571.  
  572.   if (trace > 1)
  573.   {
  574.     cwprintf(cb->window, "POP trying Connection to %s\n",inet_ntoa(fsocket.address));
  575.   }
  576.   stop_timer(&cb->pop_t);
  577.  
  578.   /* open pop connection */
  579.   cb->state = state_USER;      /* init state placeholder */
  580.   cb->tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, tcp_window,
  581.   (void(*)())pop_rec, (void(*)())pop_cts, (void(*)())pop_state, 0, (char *)cb);
  582.   cb->tcb->user = (char *)cb;     /* Upward pointer */
  583. }
  584.  
  585.  
  586.  
  587. struct cmds popcmds[] = {
  588.   "addserver",    doadds,        4,   "pop addserver <name> <time> <user> <password> <abbr>", NULLCHAR,
  589.   "dropserver",   dodrops,       2,   "pop dropserver <name|abbr>",          NULLCHAR,
  590.   "kick",         dokicks,       2,   "pop kick <name|abbr>",                NULLCHAR,
  591.   "listserver",   dolists,       0,   NULLCHAR,                              NULLCHAR,
  592.   "separator",    dosep,         1,   "pop separator A|U|RN|RM",             NULLCHAR,
  593.   "trace",        dopoptrace,    0,   NULLCHAR,                              NULLCHAR,
  594.   NULLCHAR
  595. };
  596.  
  597. int dopop(int argc, char **argv)
  598. {
  599.   return subcmd(popcmds,argc,argv);
  600. }
  601.  
  602. static int dosep(int argc, char *argv[])
  603. {
  604.   if (argc < 2)
  605.   {
  606.     cwprintf(NULL, "pop separator: %s\r\n", seps[pop_sep]);
  607.   }
  608.   else
  609.   {
  610.     switch(tolower(*argv[1]))
  611.     {
  612.     case 'a':
  613.     case '^':
  614.       pop_sep = sep_CTLA;
  615.       break;
  616.     case 'r':
  617.       if (tolower(*(argv[1]+1))=='m')
  618.         pop_sep = sep_RMAIL;
  619.       else
  620.         pop_sep = sep_RNEWS;
  621.       break;
  622.     default:
  623.       pop_sep = sep_UNIX;
  624.       break;
  625.     }
  626.   }
  627.   return 0;
  628. }
  629.  
  630.