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