home *** CD-ROM | disk | FTP | other *** search
/ PDA Software Library / pdasoftwarelib.iso / PSION / COMMS / PSIONMAI / PMFULLSO / SUNMAIL / TALKTOPO.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-13  |  10.2 KB  |  461 lines

  1. /* this program talks to pop3 servers */
  2. /* (C) Tim Graves, Sun Microsystems 1995 */
  3. #include "talktopop.h"
  4. #include <netinet/in.h>
  5. #include <sys/uio.h>
  6. #include <netdb.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12.  
  13. /* info on the port we are dealing with etc */
  14. struct sockaddr_in sin ;
  15. int net ;
  16. FILE *netinfd, *netoutfd ;
  17.  
  18. /* various strings etc that are set or reset from the command line */
  19. char popserver[100] ;
  20. char popname [100] ;
  21. char protname [100] ;
  22. char uname[100] ;
  23. char passwd[100] ;
  24. int filestartno = 0 ;
  25. int dodel = FALSE ;
  26. int direction = TRUE ;
  27. int verbose = FALSE ;
  28. int maxsize = MAXSIZE ;
  29. int maxemail = MAXCOUNT ;
  30. int hnset, pwset, unset ;
  31.  
  32.  
  33. /* message information */
  34. int messcnt = 0 ;
  35.  
  36. /* debug information */
  37. int debug = FALSE ;
  38. /* pointer to the message size array */
  39. int * msglist ;
  40.  
  41. main(argc, argv, environ)
  42. int argc ;
  43. char * argv[] ;
  44. char * environ[] ;
  45. {
  46.     int ret ;
  47.     int startno ;
  48.     init() ;
  49.     /* handle the command line */
  50.     cmdline(argc, argv) ;
  51.     if (verbose == TRUE)
  52.         dogreet() ;
  53.     /* check that the arguments have worked out right and
  54.        get the password if required */
  55.     checkflags() ;
  56.     /* maxemail can viable be zero if there are more saved emails than
  57.        the default value of maxemail. in this case just crunch out */
  58.     if (maxemail == 0)
  59.         exit(0) ;
  60.     /* setup the network connection */
  61.     if (startnet() == NETERR)
  62.     {
  63.         printf("Network initialisation error\nExiting\n") ;
  64.         return ;
  65.     }
  66.     ret = doconnect() ;
  67.     if (ret == BADCMD)
  68.     {
  69.         printf("Pop server returns bad\n") ;
  70.         return ;
  71.     }
  72.     ret = dologin() ;
  73.     if (ret == GOODCMD)
  74.     {
  75.         dolist() ;
  76.         if (direction == FALSE)
  77.             startno = findfromlast() ;
  78.         else
  79.             startno = 1 ;
  80.         doget(startno) ;
  81.     }
  82.     doquit() ;
  83.     endnet() ;
  84. }
  85. checkflags() 
  86. {
  87.     char tmp[1024] ;
  88.     char * pass ;
  89.     /* ensure that we have a host name and user name */
  90.     if (hnset == FALSE)
  91.     {
  92.         printf("Error: talktopop cannot find your pop server name in the config file or the command list") ;
  93.         exit(1) ;
  94.     }
  95.     if (pwset == FALSE)
  96.     {
  97.         sprintf(tmp, "Please enter the password for user %s on machine %s:", uname, popserver) ;
  98.         pass = getpass(tmp) ;
  99.         strcpy(passwd, pass) ;
  100.     }
  101. }
  102. init()
  103. {
  104.     confinit() ;
  105.     getuname(uname) ;
  106.     unset = TRUE ;
  107.     readconf() ;
  108. }
  109. cmdline(argc, argv) 
  110. int argc ;
  111. char * argv[] ;
  112. {
  113.     int c ;
  114.     extern int optind ;
  115.     extern char * optarg ;
  116.     int cset = FALSE ;
  117.     while ((c = getopt(argc, argv, "h:u:p:c:s:flvdS:n:")) != EOF)
  118.     {
  119.         switch(c)
  120.         {
  121.             case 'h': /* hostname for pop server */
  122.                 strcpy(popserver, optarg) ;
  123.                 hnset = TRUE ;
  124.                 break ;
  125.             case 'u': /* username to use */
  126.                 strcpy(uname, optarg) ;
  127.                 unset = TRUE ;
  128.                 break ;
  129.             case 'p': /* password to use */
  130.                 strcpy(passwd, optarg) ;
  131.                 pwset = TRUE ;
  132.                 break ;
  133.             case 'c': /* max number of emails to retrieve */
  134.                 maxemail = atoi(optarg) ;
  135.                 cset = TRUE ;
  136.                 break ;
  137.             case 's': /* max size of email to retrieve */
  138.                 maxsize = atoi(optarg) ;
  139.                 break ;
  140.             case 'f': /* retrieve maxemails from the start of the email box */
  141.                 direction = TRUE ;
  142.                 break ;
  143.             case 'l': /* retrieve maxemails from the end of the email box */
  144.                 direction = FALSE ;
  145.                 break ;
  146.             case 'v': /* be verbose for debugging */
  147.                 verbose = TRUE ;
  148.                 break ;
  149.             case 'S': /* service name (defaults to pop-3) */
  150.                 strcpy(popname, optarg) ;
  151.                 break ;
  152.             case 'n': /* number to start the file count at */
  153.                 filestartno = atoi(optarg) ;
  154.                 break ;
  155.             case 'd': /* delete the messages once rtead */
  156.                 dodel = TRUE ;
  157.                 break ;
  158.         }
  159.     }
  160.     /* calculate the number of emails to actually retrieve. 
  161.        this is maxemail - the findnumber.
  162.        if the count has been specificaly set dont do this */
  163.     if (cset == FALSE)
  164.     {
  165.         maxemail = maxemail - filestartno ;
  166.         if (maxemail < 0)
  167.             maxemail = 0 ;
  168.     }
  169. }
  170. dogreet()
  171. {
  172.     printf("Talktopop, Version 1.9\n(C) Tim Graves, Sun Microsystems 1995\n") ;
  173. }
  174. doquit()
  175. {
  176.     char tmp[MAXLINE] ;
  177.     sprintf(tmp, "%s", QUITCMD) ;
  178.     tonet(tmp) ;
  179.     fromnet(tmp) ;
  180.     free(msglist) ;
  181. }
  182. dodelete(i)
  183. int i ;
  184. {
  185.     char tmp[MAXLINE] ;
  186.     if (verbose == TRUE)
  187.         printf("Deleting mail no %i\n", i) ;
  188.     sprintf(tmp, "%s %d", DELECMD, i) ;
  189.     tonet(tmp) ;
  190.     fromnet(tmp) ;
  191.     if (tmp[0] == BADCHAR)
  192.         return(BADCMD) ;
  193.     else
  194.         return(GOODCMD) ;
  195. }
  196.  
  197. doretrieve(i, fname)
  198. int i ;
  199. char * fname ;
  200. {
  201.     FILE *fd ;
  202.     char tmp[MAXLINE] ;
  203.     if (verbose == TRUE)
  204.         printf("Retrieving mail no %d to file %s\n", i, fname) ;
  205.     if ((fd = fopen(fname, "w")) == NULL)
  206.     {
  207.         return(BADFILE) ;
  208.     }
  209.     sprintf(tmp, "%s %d", RETRCMD, i) ;
  210.     tonet(tmp) ;
  211.     /* do the first line, if there is a - there its an error */
  212.     fromnet(tmp) ;
  213.     if (tmp[0] == BADCHAR)
  214.     {
  215.         fclose(fd) ;
  216.         return(BADCMD) ;
  217.     }
  218.     /* the line is OK, do the message */
  219.     while(fromnet(tmp) == TRUE)
  220.     {
  221.         /* NOTE fromnet removes andy \r o \n stuff, we need to 
  222.            reinsert this into the file */
  223.         fprintf(fd, "%s\n", tmp) ;
  224.     }
  225.     fclose(fd) ;
  226.     return(GOODCMD) ;
  227. }
  228. int findfromlast()
  229. {
  230.     /* counting backwards from the last entry in msglist count 
  231.        maxemails which are <= maxsize back and return the number of 
  232.        the last one */
  233.     int i, count ;
  234.     count = 0 ;
  235.     for ( i = messcnt ; ((i >= 0 ) && ( count < maxemail)) ; i--)
  236.         if (msglist[i] <= maxsize)
  237.             count ++ ;
  238.     return(i) ;
  239. }
  240. /* get maxcount emails from the pop server and save then away */
  241. doget(startno)
  242. int startno ;
  243. {
  244.     int i, count;
  245.     char tmp[100] ;
  246.     if (verbose == TRUE)
  247.         printf("Retrieving emails from %d\n", startno) ;
  248.     count = 0 ;
  249.     for (i = startno ; ((count < maxemail) && (i <= messcnt)) ; i ++)
  250.     {
  251.         /* is the email the right size ? */
  252.         if (msglist[i] > maxsize)
  253.             continue ;
  254.         /* OK we should be looking at this email */
  255.         /* create the filename */
  256.         sprintf(tmp, INSKELETON, count+filestartno) ;
  257.         /* get the file */
  258.         doretrieve(i, tmp) ;
  259.         /* are we deleting retrieved messages ? */
  260.         if (dodel == TRUE)
  261.             dodelete(i) ;
  262.         /* increment the count */
  263.         count ++ ;
  264.     }
  265. }
  266. dolist()
  267. {
  268.     char tmp [MAXLINE] ;
  269.     int i, mailno, mailsize ;
  270.     if (verbose == TRUE)
  271.         printf("Listing email size\n") ;
  272.     for (i = 1 ; i <= messcnt; i ++) 
  273.     {
  274.         sprintf(tmp, "%s %d", LISTCMD, i) ;
  275.         tonet(tmp) ;
  276.         fromnet(tmp) ;
  277.         if (tmp[0] == BADCHAR) /* this could get things out of sync but its usefull for debugging */
  278.         {
  279.             return(BADCMD) ;
  280.         }
  281.         /* skip over the "+OK " */
  282.         sscanf(&tmp[4],"%d %d", &mailno, &mailsize) ;
  283.         if (mailno > messcnt)
  284.             return(BADCMD) ;
  285.         if (mailno != i)
  286.             return(BADCMD) ;
  287.         msglist[i] = mailsize ;
  288.     }
  289.     return(GOODCMD) ;
  290. }
  291. doconnect()
  292. {
  293.     char tmp[MAXLINE] ;
  294.     if (verbose == TRUE)
  295.         printf("Connecting to pop server\n") ;
  296.     fromnet(tmp) ;
  297.     if (tmp[0] == BADCHAR)
  298.         return(BADCMD) ;
  299.     else
  300.         return(GOODCMD) ;
  301. }
  302. int dologin()
  303. {
  304.     char tmp[MAXLINE] ;
  305.     size_t i ;
  306.     if (verbose == TRUE)
  307.         printf("Logging in to pop server\n") ;
  308.     /* request the user name */
  309.     sprintf(tmp, "%s %s", USERCMD, uname) ;
  310.     tonet(tmp) ;
  311.     fromnet(tmp) ;
  312.     if (tmp[0] == BADCHAR)
  313.     {
  314.         return(BADCMD) ;
  315.     }
  316.     sprintf(tmp, "%s %s", PASSCMD, passwd) ;
  317.     tonet(tmp) ;
  318.     fromnet(tmp) ;
  319.     if (tmp[0] == BADCHAR)
  320.     {
  321.         return(BADCMD) ;
  322.     }
  323.     /* the format is something like 
  324.     +OK 360 messages ready for tim in /usr/spool/mail/tim
  325.     for a strict pop3 implementation but some are like
  326.     +OK tim has 77 message(s) (709547 octets).
  327.     find the first number and then extract it (assume the first
  328.     number is the message count  */
  329.     for (i = 0 ; i < strlen(tmp) ; i ++)
  330.         if (isdigit(tmp[i]))
  331.             break ;
  332.     messcnt = atoi(&tmp[i]) ;
  333.     msglist = calloc((size_t) messcnt + 1, (size_t) sizeof(int) );
  334.     return(GOODCMD) ;
  335. }
  336. endnet()
  337. {
  338.     fclose(netinfd) ;
  339.     fclose(netoutfd) ;
  340.     close(net) ;
  341. }
  342. int startnet()
  343. {
  344.     /* hard coded at the moment, connect, list and quit */
  345.     struct servent * sp ;
  346.     struct hostent *hp ;
  347.     int ret ;
  348.     
  349.     /* get the port information etc for pop */
  350.     if ((sp = getservbyname(popname, protname)) == NULL)
  351.     {
  352.         printf("%s/%s: unknown service\n", popname, protname) ;
  353.         return(NETERR) ;
  354.     }
  355.     if ((hp = gethostbyname(popserver)) == NULL)
  356.     {
  357.         printf("%s: unknown hostname\n", popserver) ;
  358.         return(NETERR) ;
  359.     }
  360.     /* build up the sin structure */
  361.     sin.sin_family = (short) AF_INET ;
  362.     memcpy((char *) &sin.sin_addr, (char *) hp->h_addr, hp->h_length) ;
  363.     sin.sin_port = htons((u_short) sp->s_port) ;
  364.     /* create the socket */
  365.     net = socket(AF_INET, SOCK_STREAM,0) ;
  366.     if (net < 0)
  367.     {
  368.         printf("socket error\n") ;
  369.         return(NETERR);
  370.     }
  371.     ret = connect(net, (struct sockaddr *) &sin, sizeof(sin)) ;
  372.     if (ret < 0)
  373.     {
  374.         printf("connect error\n") ;
  375.         return(NETERR) ;
  376.     }
  377.     netinfd = fdopen(net,"r") ;
  378.     netoutfd = fdopen(net, "w") ;
  379.     if ((netinfd == NULL) || (netoutfd == NULL))
  380.     {
  381.         printf("fdopen error\n") ;
  382.         if (netinfd != NULL)
  383.             fclose(netinfd) ;
  384.         if (netoutfd != NULL) 
  385.             fclose(netoutfd) ;
  386.         close(net) ;
  387.         return(NETERR) ;
  388.     }
  389.     return(NETOK) ;
  390. }
  391.  
  392. tonet(str)
  393. char * str ;
  394. {
  395.     int len ;
  396.     int ret ;
  397.     char tmp[MAXLINE] ;
  398.     sprintf(tmp, "%s\r\n", str) ;
  399.     len = strlen(tmp) ;
  400.     if (debug == TRUE)
  401.         printf("Sending :%slength %d\n", tmp, len) ;
  402.     ret = fprintf(netoutfd, "%s", tmp) ;
  403.     fflush(netoutfd) ;
  404.     if (ret == -1)
  405.     {
  406.         printf("error in send\n") ;
  407.     }
  408.     return ;
  409. }
  410. int fromnet(str)
  411. char * str ;
  412. {
  413.     char tmp[MAXLINE] ;
  414.     char ch ;
  415.     int i, ret ;
  416.     
  417.     ch = '\0' ;
  418.     i = 0 ;
  419.     while (ch != '\n')
  420.     {
  421.         ch = getc(netinfd) ;
  422.         if (ch == EOF)
  423.         {
  424.             printf("recv error") ;
  425.             tmp[i] = '\0' ;
  426.             return ;
  427.         }
  428.         tmp[i] = ch ;
  429.         if (debug == TRUE)
  430.             printf("%c", ch );
  431.         i ++ ;
  432.     }
  433.     /* to get here we must have  tmp[i-1] == '\n' so remove it */
  434.     tmp[i-1] = '\0' ;
  435.     /* if tmp[i-2] is '\r' remove it */
  436.     if (tmp[i-2] == '\r') 
  437.         tmp[i-2] = '\0' ;
  438.     /* if the first char is . and the length is greater than 1 remove the first .
  439.        (pop3 replaces .<text> with ..<text> and also uses . by itself to mean
  440.        end of the multi line message */
  441.     if (tmp[0] == '.') 
  442.     {
  443.         if (tmp[1] == '\0')
  444.         {
  445.             /* end of multi line stuff */
  446.             /* empty the return string */
  447.             str[0] = '\0' ;
  448.             return (FALSE) ;
  449.         }
  450.         else
  451.         {
  452.             /* the origional text started with a . remove the padding */
  453.             strcpy(str, &tmp[1]) ;
  454.             return(TRUE) ;
  455.         }
  456.     }
  457.     /* no special handling required */
  458.     strcpy(str, tmp) ;
  459.     return(TRUE) ;
  460. }
  461.