home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / POPCLI.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  11KB  |  485 lines

  1. /*
  2.  *    POP2 Client routines.  Originally authored by Mike Stockett
  3.  *      (WA7DYX).
  4.  *    Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
  5.  *    facilities in NOS0423.  Fixed type mismatches spotted by C++.
  6.  *    Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  7.  *      with later releases (NOS0522).
  8.  *    Added into NOS by PA0GRI (and linted into "standard" C)
  9.  *
  10.  *    Some code culled from previous releases of SMTP.
  11.  *
  12.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  13.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  14.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  15.  *    Permission granted for non-commercial copying and use, provided
  16.  *      this notice is retained.
  17.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  18.  *      also rebuilt locking mechanism
  19.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  20.  *    Permission granted for non-commercial copying and use, provided
  21.  *    this notice is retained.
  22.  */
  23.  
  24. /****************************************************************************
  25. *    $Id: popcli.c 1.2 93/07/16 11:48:51 ROOT_DOS Exp $
  26. *    08 May 93    1.2        GT    Fix warnings.                                    *
  27. ****************************************************************************/
  28.  
  29. #include <stdio.h>
  30. #include <fcntl.h>
  31. #include <time.h>
  32. #include <setjmp.h>
  33. #ifdef UNIX
  34. #include <sys/types.h>
  35. #endif
  36. #ifdef    __TURBOC__
  37. #include <dir.h>
  38. #include <io.h>
  39. #endif
  40. #include "global.h"
  41. #ifdef    ANSIPROTO
  42. #include <stdarg.h>
  43. #endif
  44. #include "mbuf.h"
  45. #include "cmdparse.h"
  46. #include "proc.h"
  47. #include "socket.h"
  48. #include "timer.h"
  49. #include "netuser.h"
  50. #include "dirutil.h"
  51. #include "files.h"
  52.  
  53. extern char Badhost[];
  54.  
  55. #define BUF_LEN        257
  56.  
  57. /* POP client control block */
  58.  
  59. struct pop_ccb {
  60.     int    socket;        /* socket for this connection */
  61.     char    state;        /* client state */
  62. #define       CALL        0
  63. #define       NMBR        3
  64. #define       SIZE        5
  65. #define       XFER        8
  66. #define       EXIT        10
  67.     char    buf[BUF_LEN],    /* tcp input buffer */
  68.         count;        /* input buffer length */
  69.     int    folder_len;    /* number of msgs in current folder */
  70.     long    msg_len;    /* length of current msg */
  71.     int    msg_num;    /* current message number */
  72. } *ccb;
  73.  
  74. #define NULLCCB        (struct pop_ccb *)0
  75.  
  76. static int Popquiet = 0;
  77.  
  78. static struct timer  popcli_t;
  79. static int32 mailhost;
  80. static char    mailbox_name[10],
  81.         mailbox_pathname[BUF_LEN],
  82.         username[20],
  83.         password[20],
  84.         Workfile_name[] ="mbox.pop";
  85.  
  86. static int domailbox __ARGS((int argc,char *argv[],void *p));
  87. static int domailhost __ARGS((int argc,char *argv[],void *p));
  88. static int douserdata __ARGS((int argc,char *argv[],void *p));
  89. static int doquiet __ARGS((int argc,char *argv[],void *p));
  90. static int dotimer __ARGS((int argc,char *argv[],void *p));
  91. static struct pop_ccb     *new_ccb __ARGS((void));
  92. static void delete_ccb __ARGS((void));
  93. static void pop_send __ARGS((int unused,void *cb1,void *p));
  94. static int popkick __ARGS((int argc,char *argv[],void *p));
  95.  
  96. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  97. int poptick __ARGS((void));
  98.  
  99. static struct cmds Popcmds[] = {
  100.     { "mailbox",    domailbox,    0,    0,    NULLCHAR },
  101.     { "mailhost",    domailhost,    0,    0,    NULLCHAR },
  102.     { "kick",        popkick,    0,    0,    NULLCHAR },
  103.     { "quiet",    doquiet,    0,    0,    NULLCHAR },
  104.     { "timer",    dotimer,    0,    0,    NULLCHAR },
  105.     { "userdata",    douserdata,    0,    0,    NULLCHAR },
  106.     { NULLCHAR },
  107. };
  108.  
  109.  
  110. /* Command string specifications */
  111.  
  112. static char ackd_cmd[] = "ACKD\n",
  113. #ifdef POP_FOLDERS
  114.     fold_cmd[] = "FOLD %s\n",
  115. #endif
  116.     login_cmd[] = "HELO %s %s\n",
  117.     /* nack_cmd[]      = "NACK\n",     /* Not implemented */
  118.     quit_cmd[]      = "QUIT\n",
  119.     read_cur_cmd[]  = "READ\n",
  120.     retr_cmd[]      = "RETR\n";
  121.  
  122. /* Response string keys */
  123.  
  124. static char *greeting_rsp  = "+ POP2 ";
  125.  
  126. FILE    *fd;
  127. #define    NULLFILE    (FILE *)0
  128.  
  129. int
  130. dopop(argc,argv,p)
  131. int     argc;
  132. char     *argv[];
  133. void     *p;
  134. {
  135.     return subcmd(Popcmds,argc,argv,p);
  136. }
  137.  
  138. static int
  139. domailbox(argc,argv,p) 
  140. int argc;
  141. char *argv[];
  142. void *p;
  143. {
  144.     if(argc < 2) {
  145.         if(mailbox_name[0] == '\0')
  146.             tprintf("maibox name not set yet\n");
  147.         else
  148.             tprintf("%s\n",mailbox_name);
  149.     } else {
  150.         strncpy(mailbox_name,argv[1],10);
  151.     }
  152.  
  153.     return 0;
  154. }
  155.  
  156. static int
  157. domailhost(argc,argv,p)
  158. int argc;
  159. char *argv[];
  160. void *p;
  161. {
  162.     int32 n;
  163.  
  164.     if(argc < 2) {
  165.         tprintf("%s\n",inet_ntoa(mailhost));
  166.     } else
  167.         if((n = resolve(argv[1])) == 0) {
  168.             tprintf(Badhost,argv[1]);
  169.             return 1;
  170.         } else
  171.             mailhost = n;
  172.  
  173.     return 0;
  174. }
  175.  
  176. static int
  177. doquiet(argc,argv,p)
  178. int argc;
  179. char *argv[];
  180. void *p;
  181. {
  182.     return setbool(&Popquiet,"POP quiet",argc,argv);
  183. }
  184.  
  185. static int
  186. douserdata(argc,argv,p)
  187. int argc;
  188. char *argv[];
  189. void *p;
  190. {
  191.     if (argc < 2)
  192.         tprintf("%s\n",username);
  193.     else if (argc != 3) {
  194.         tprintf("Usage: pop userdata <username> <password>\n");
  195.         return 1;
  196.     } else {
  197.         sscanf(argv[1],"%18s",username);
  198.         sscanf(argv[2],"%18s",password);
  199.     }
  200.  
  201.     return 0;
  202. }
  203.  
  204. /* Set scan interval */
  205.  
  206. static int
  207. dotimer(argc,argv,p)
  208. int argc;
  209. char *argv[];
  210. void *p;
  211. {
  212.     if(argc < 2) {
  213.         tprintf("%lu/%lu\n",
  214.             read_timer(&popcli_t) /1000L,
  215.             dur_timer(&popcli_t)/ 1000L);
  216.         return 0;
  217.     }
  218.  
  219.     popcli_t.func  = (void (*)())poptick;          /* what to call on timeout */
  220.     popcli_t.arg   = NULL;                /* dummy value */
  221.     set_timer(&popcli_t, atol(argv[1])*1000L);     /* set timer duration */
  222.     start_timer(&popcli_t);                /* and fire it up */
  223.     return 0;
  224. }
  225.  
  226. static int
  227. popkick(argc,argv,p)
  228. int argc;
  229. char *argv[];
  230. void *p;
  231. {
  232.     poptick();
  233.     return 0;
  234. }
  235.  
  236. int
  237. poptick()
  238. {
  239.     if (ccb == NULLCCB) {
  240.  
  241.         /* Don't start if any of the required parameters have not been specified */
  242.  
  243.         if (mailhost == 0) {
  244.             tprintf("mailhost not defined yet.(pop mailhost <host>)\n");
  245.             return 0;
  246.         }
  247.  
  248.         if (mailbox_name[0] == '\0') {
  249.             tprintf("mailbox name not defined yet.(pop mailbox <name>)\n");
  250.             return 0;
  251.         }
  252.  
  253.         if (username[0] == '\0') {
  254.             tprintf("username not defined yet. (pop user <name> <pass>)\n");
  255.             return 0;
  256.         }
  257.  
  258.         if (password[0] == '\0') {
  259.             tprintf(" Unknown password\n");
  260.             return 0;
  261.         }
  262.  
  263.         if ((ccb = new_ccb()) == NULLCCB) {
  264.             fprintf(stderr,"*** Unable to allocate CCB");
  265.             return 0;
  266.         }
  267.  
  268.         newproc("Auto-POP Client",1024,pop_send,0,ccb,NULL,0);
  269.     }
  270.  
  271.     /* Restart timer */
  272.  
  273.     start_timer(&popcli_t);
  274.     return 0;
  275. }
  276.  
  277. /* this is the master state machine that handles a single SMTP transaction */
  278. /* it is called with a queue of jobs for a particular host. */
  279.  
  280. static void
  281. pop_send(unused,cb1,p) 
  282. int unused;
  283. void *cb1;
  284. void *p;
  285. {
  286.     char *cp;
  287.     struct sockaddr_in fsocket;
  288.     struct pop_ccb    *ccb;
  289.     void pop_csm(struct pop_ccb *);
  290.     void quit_session(struct pop_ccb *);
  291.  
  292.     ccb = (struct pop_ccb *)cb1;
  293.     fsocket.sin_family = AF_INET;
  294.     fsocket.sin_addr.s_addr = mailhost;
  295.     fsocket.sin_port = IPPORT_POP;
  296.  
  297.     ccb->socket = socket(AF_INET,SOCK_STREAM,0);
  298.  
  299.     ccb->state = CALL;
  300.  
  301.     if (connect(ccb->socket,(char *)&fsocket,SOCKSIZE) == 0) {
  302.         log(ccb->socket,"Connected to mailhost %s", inet_ntoa(mailhost));
  303.     } else {
  304.         cp = sockerr(ccb->socket);
  305.         log(ccb->socket,"Connect to mailhost %s failed: %s", inet_ntoa(mailhost),
  306.             (cp != NULLCHAR)? cp: "");
  307.     }
  308.  
  309.     while(1) {
  310.         if (recvline(ccb->socket,ccb->buf,BUF_LEN) == -1)
  311.             goto quit;
  312.  
  313.         rip(ccb->buf);
  314.         pop_csm(ccb);
  315.         if (ccb->state == EXIT)
  316.             goto quit;
  317.     }
  318. quit:
  319.     log(ccb->socket,"Connection closed to mailhost %s", inet_ntoa(mailhost));
  320.     (void) close_s(ccb->socket);
  321.     if (fd != NULLFILE)
  322.         fclose(fd);
  323.     delete_ccb();
  324. }
  325.  
  326. /* free the message struct and data */
  327.  
  328. static void
  329. delete_ccb()
  330. {
  331.     if (ccb == NULLCCB)
  332.         return;
  333.  
  334.     free((char *)ccb);
  335.     ccb = NULLCCB;
  336. }
  337.  
  338. /* create a new  pop control block */
  339.  
  340. static struct
  341. pop_ccb *new_ccb()
  342. {
  343.     register struct pop_ccb *ccb;
  344.  
  345.     if ((ccb = (struct pop_ccb *) callocw(1,sizeof(struct pop_ccb))) == NULLCCB)
  346.         return(NULLCCB);
  347.     return(ccb);
  348. }
  349.  
  350. /* ---------------------- pop client code starts here --------------------- */
  351.  
  352. void
  353. pop_csm(ccb)
  354. struct pop_ccb    *ccb;
  355. {
  356.     FILE *mf;
  357.  
  358.     int mlock (char *,char *);
  359.     int rmlock (char * ,char *);
  360.     void quit_session(struct pop_ccb *);
  361.     /* int mlock __ARGS((char *dir,char *id));   */
  362.     /* int rmlock __ARGS((char *dir,char *id));   */
  363.  
  364.  
  365.     switch(ccb->state) {
  366.     case CALL:
  367.         if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  368.              (void)usprintf(ccb->socket,login_cmd,username,password);
  369.             ccb->state = NMBR;
  370.         } else
  371.             (void) quit_session(ccb);
  372.         break;
  373.  
  374.     case NMBR:
  375.  
  376.         switch (ccb->buf[0]) {
  377.         case '#':
  378.             if ((fd = fopen(Workfile_name,"a+")) == NULLFILE) {
  379.                 perror("Unable to open work file");
  380.                 quit_session(ccb);
  381.                 return;
  382.             }
  383.  
  384.             fseek(fd,0,SEEK_SET);
  385.             ccb->folder_len = atoi(&(ccb->buf[1]));
  386.             (void)usprintf(ccb->socket,read_cur_cmd);
  387.             ccb->state = SIZE;
  388.             break;
  389.  
  390.         case '+':
  391.  
  392.             /* If there is no mail (the only time we get a "+"
  393.              * response back at this stage of the game),
  394.              * then just close out the connection, because
  395.              * there is nothing more to do!! */
  396.  
  397.         default:
  398.             quit_session(ccb);
  399.             break;
  400.         }
  401.     break;
  402.  
  403.     case SIZE:
  404.         if (ccb->buf[0] == '=') {
  405.             ccb->msg_len = atol(&(ccb->buf[1]));
  406.             if (ccb->msg_len > 0) {
  407.                 (void)usprintf(ccb->socket,retr_cmd);
  408.  
  409.                 ccb->state = XFER;
  410.             } else {
  411.                 log(ccb->socket,"POP client retrieved %d messages",
  412.                         ccb->folder_len);
  413.  
  414.                 /* All done, so do local cleanup */
  415.  
  416.                 if (mlock(Mailspool,mailbox_name)) {
  417.                     tprintf("\n*** Local mailbox locked, new mail in file %s\n",
  418.                          Workfile_name);
  419.                     quit_session(ccb);
  420.                     return;
  421.                 }
  422.  
  423.                 sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,
  424.                     mailbox_name);
  425.                 if ((mf = fopen(mailbox_pathname,"a+")) == NULL) {
  426.                     tprintf("\n*** Unable to open local mailbox, new mail in file %s\n",
  427.                            Workfile_name);
  428.                     quit_session(ccb);
  429.                     return;
  430.                 }
  431.  
  432.                 fseek(fd,0,SEEK_SET);
  433.  
  434.                 while (!feof(fd)) {
  435.                     if(fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  436.                         fputs(ccb->buf,mf);
  437.                     }
  438.                 }
  439.                 fclose(mf);
  440.                 fclose(fd);
  441.                 fd = NULL;
  442.                 tprintf("New mail arrived for %s from mailhost <%s>%c\n",
  443.                     mailbox_name, inet_ntoa(mailhost),
  444.                     Popquiet ? ' ' : '\007');
  445.                 rmlock(Mailspool,mailbox_name);
  446.                 unlink(Workfile_name);
  447.                 quit_session(ccb);
  448.             }
  449.         } else
  450.             quit_session(ccb);
  451.         break;
  452.  
  453.         case XFER:
  454.             fprintf(fd,"%s\n",ccb->buf);
  455.  
  456.             ccb->msg_len -= (long)(strlen(ccb->buf)+2);    /* Add CRLF */
  457.  
  458.             if (ccb->msg_len > 0)
  459.                 return;
  460.  
  461.             (void)usprintf(ccb->socket,ackd_cmd);
  462.  
  463.             ccb->msg_num++;
  464.             ccb->state = SIZE;
  465.             break;
  466.  
  467.         case EXIT:
  468.             if (fd != NULLFILE)
  469.                 fclose(fd);
  470.             break;
  471.  
  472.         default:
  473.             break;
  474.     }
  475. }
  476.  
  477. void
  478. quit_session(ccb)
  479. struct pop_ccb    *ccb;
  480. {
  481.     (void)usprintf(ccb->socket,quit_cmd);
  482.  
  483.     ccb->state  = EXIT;
  484. }
  485.