home *** CD-ROM | disk | FTP | other *** search
/ PDA Software Library / pdasoftwarelib.iso / PSION / COMMS / PSIONMAI / PMFULLSO / SUNMAIL / SCCS / S.C < prev    next >
Encoding:
Text File  |  1995-07-13  |  13.4 KB  |  708 lines

  1. h30450
  2. s 00009/00002/00451
  3. d D 1.9 95/07/13 12:40:09 tim 9 8
  4. c added code to support differing versions of the pop-3 implementation which seem to have different greeting formats with the message count in differing places
  5. e
  6. s 00004/00002/00449
  7. d D 1.8 95/07/06 19:55:20 tim 8 7
  8. c user the getpass command to get the users password as it is secure
  9. e
  10. s 00040/00011/00411
  11. d D 1.7 95/07/06 14:53:45 tim 7 6
  12. c modified talk to pop to operate on the config files
  13. e
  14. s 00001/00034/00421
  15. d D 1.6 95/07/06 13:42:18 tim 6 5
  16. c the #defines ar now in a seperate file
  17. e
  18. s 00001/00001/00454
  19. d D 1.5 95/07/05 20:10:50 tim 5 4
  20. c now deletes outgoing email files as well
  21. e
  22. s 00001/00001/00454
  23. d D 1.4 95/07/05 11:43:15 tim 4 3
  24. c added a newline print in one command
  25. e
  26. s 00235/00011/00220
  27. d D 1.3 95/07/04 19:40:36 tim 3 2
  28. c it seems to work now
  29. e
  30. s 00231/00000/00000
  31. d D 1.2 95/07/03 13:04:08 tim 2 1
  32. c the thing works in principle. it can connect, authenticate list and quit. 
  33. c it will need defaults handling installing
  34. e
  35. s 00000/00000/00000
  36. d D 1.1 95/07/01 16:19:59 tim 1 0
  37. c 
  38. e
  39. u
  40. U
  41. f e 0
  42. t
  43. T
  44. I 2
  45. /* this program talks to pop3 servers */
  46. /* (C) Tim Graves, Sun Microsystems 1995 */
  47. I 6
  48. #include "talktopop.h"
  49. E 6
  50. #include <netinet/in.h>
  51. #include <sys/uio.h>
  52. #include <netdb.h>
  53. #include <sys/types.h>
  54. #include <sys/socket.h>
  55. #include <string.h>
  56. #include <stdio.h>
  57. I 3
  58. #include <stdlib.h>
  59. E 3
  60. D 6
  61. #define POPNAME "pop-3"
  62. #define PROTNAME "tcp"
  63. #define POPSERVER "astir"
  64.  
  65. #define USERCMD "USER"
  66. #define PASSCMD "PASS"
  67. #define LISTCMD "LIST"
  68. I 3
  69. #define RETRCMD "RETR"
  70. #define DELECMD "DELE"
  71. E 3
  72. #define QUITCMD "QUIT"
  73. #define READY "."
  74. #define BADCHAR '-'
  75. #define OKCHAR '+'
  76.  
  77. /* standard defines */
  78. #define TRUE 1
  79. #define FALSE 0
  80.  
  81. /* error codes */
  82. #define NETERR -1
  83. #define NETOK -2
  84. #define GOODCMD 1
  85. #define BADCMD 0
  86. I 3
  87. #define BADFILE BADCMD
  88. E 3
  89.  
  90. /* sizes and stuff */
  91. #define MAXLINE 1024
  92. I 3
  93. #define MAXSIZE 2048 /* max size of an email to get */
  94. #define MAXCOUNT 10 /* get 10 emails */
  95. #define FIRST 1 
  96. #define LAST  -1
  97. E 3
  98.  
  99. I 3
  100. /* skeleton for generating file names */
  101. D 5
  102. #define INSKELETON "in%d.msg"
  103. E 5
  104. I 5
  105. #define INSKELETON "in%03d.msg"
  106. E 6
  107. E 5
  108.  
  109. E 3
  110. /* info on the port we are dealing with etc */
  111. struct sockaddr_in sin ;
  112. int net ;
  113. FILE *netinfd, *netoutfd ;
  114.  
  115. I 3
  116. /* various strings etc that are set or reset from the command line */
  117. char popserver[100] ;
  118. char popname [100] ;
  119. char protname [100] ;
  120. char uname[100] ;
  121. char passwd[100] ;
  122. int filestartno = 0 ;
  123. int dodel = FALSE ;
  124. D 7
  125. int direction = FIRST ;
  126. E 7
  127. I 7
  128. int direction = TRUE ;
  129. E 7
  130. int verbose = FALSE ;
  131. int maxsize = MAXSIZE ;
  132. int maxemail = MAXCOUNT ;
  133. I 7
  134. int hnset, pwset, unset ;
  135. E 7
  136.  
  137.  
  138. E 3
  139. /* message information */
  140. int messcnt = 0 ;
  141.  
  142. /* debug information */
  143. D 3
  144. int debug = TRUE ;
  145. E 3
  146. I 3
  147. int debug = FALSE ;
  148. /* pointer to the message size array */
  149. int * msglist ;
  150. E 3
  151.  
  152. main(argc, argv, environ)
  153. int argc ;
  154. char * argv[] ;
  155. char * environ[] ;
  156. {
  157.     int ret ;
  158. I 3
  159.     int startno ;
  160.     init() ;
  161.     /* handle the command line */
  162.     cmdline(argc, argv) ;
  163.     if (verbose == TRUE)
  164.         dogreet() ;
  165. I 7
  166.     /* check that the arguments have worked out right and
  167.        get the password if required */
  168.     checkflags() ;
  169.     /* maxemail can viable be zero if there are more saved emails than
  170.        the default value of maxemail. in this case just crunch out */
  171.     if (maxemail == 0)
  172.         exit(0) ;
  173. E 7
  174. E 3
  175.     /* setup the network connection */
  176.     if (startnet() == NETERR)
  177.     {
  178.         printf("Network initialisation error\nExiting\n") ;
  179.         return ;
  180.     }
  181.     ret = doconnect() ;
  182.     if (ret == BADCMD)
  183.     {
  184.         printf("Pop server returns bad\n") ;
  185.         return ;
  186.     }
  187.     ret = dologin() ;
  188.     if (ret == GOODCMD)
  189.     {
  190.         dolist() ;
  191. I 3
  192. D 7
  193.         if (direction == LAST)
  194. E 7
  195. I 7
  196.         if (direction == FALSE)
  197. E 7
  198.             startno = findfromlast() ;
  199.         else
  200.             startno = 1 ;
  201.         doget(startno) ;
  202. E 3
  203.     }
  204.     doquit() ;
  205.     endnet() ;
  206. }
  207. I 7
  208. checkflags() 
  209. {
  210.     char tmp[1024] ;
  211. I 8
  212.     char * pass ;
  213. E 8
  214.     /* ensure that we have a host name and user name */
  215.     if (hnset == FALSE)
  216.     {
  217.         printf("Error: talktopop cannot find your pop server name in the config file or the command list") ;
  218.         exit(1) ;
  219.     }
  220.     if (pwset == FALSE)
  221.     {
  222. D 8
  223.         sprintf(tmp, "the password for user %s on machine %s", uname, popserver) ;
  224.         getstr(passwd, tmp, TRUE) ;
  225. E 8
  226. I 8
  227.         sprintf(tmp, "Please enter the password for user %s on machine %s:", uname, popserver) ;
  228.         pass = getpass(tmp) ;
  229.         strcpy(passwd, pass) ;
  230. E 8
  231.     }
  232. }
  233. E 7
  234. I 3
  235. init()
  236. {
  237. D 7
  238.     strcpy(popname, POPNAME) ;
  239.     strcpy(protname, PROTNAME) ;
  240.     strcpy(popserver, POPSERVER) ;
  241. E 7
  242. I 7
  243.     confinit() ;
  244.     getuname(uname) ;
  245.     unset = TRUE ;
  246.     readconf() ;
  247. E 7
  248. }
  249. cmdline(argc, argv) 
  250. int argc ;
  251. char * argv[] ;
  252. {
  253.     int c ;
  254.     extern int optind ;
  255.     extern char * optarg ;
  256. D 7
  257.     int hnset = FALSE, unset = FALSE, pwset = FALSE ;
  258. E 7
  259. I 7
  260.     int cset = FALSE ;
  261. E 7
  262.     while ((c = getopt(argc, argv, "h:u:p:c:s:flvdS:n:")) != EOF)
  263.     {
  264.         switch(c)
  265.         {
  266.             case 'h': /* hostname for pop server */
  267.                 strcpy(popserver, optarg) ;
  268.                 hnset = TRUE ;
  269.                 break ;
  270.             case 'u': /* username to use */
  271.                 strcpy(uname, optarg) ;
  272.                 unset = TRUE ;
  273.                 break ;
  274.             case 'p': /* password to use */
  275.                 strcpy(passwd, optarg) ;
  276.                 pwset = TRUE ;
  277.                 break ;
  278.             case 'c': /* max number of emails to retrieve */
  279.                 maxemail = atoi(optarg) ;
  280. I 7
  281.                 cset = TRUE ;
  282. E 7
  283.                 break ;
  284.             case 's': /* max size of email to retrieve */
  285.                 maxsize = atoi(optarg) ;
  286.                 break ;
  287.             case 'f': /* retrieve maxemails from the start of the email box */
  288. D 7
  289.                 direction = FIRST ;
  290. E 7
  291. I 7
  292.                 direction = TRUE ;
  293. E 7
  294.                 break ;
  295.             case 'l': /* retrieve maxemails from the end of the email box */
  296. D 7
  297.                 direction = LAST ;
  298. E 7
  299. I 7
  300.                 direction = FALSE ;
  301. E 7
  302.                 break ;
  303.             case 'v': /* be verbose for debugging */
  304.                 verbose = TRUE ;
  305.                 break ;
  306.             case 'S': /* service name (defaults to pop-3) */
  307.                 strcpy(popname, optarg) ;
  308.                 break ;
  309.             case 'n': /* number to start the file count at */
  310.                 filestartno = atoi(optarg) ;
  311.                 break ;
  312.             case 'd': /* delete the messages once rtead */
  313.                 dodel = TRUE ;
  314.                 break ;
  315.         }
  316.     }
  317. D 7
  318.     if ((hnset == FALSE) || (unset == FALSE) || (pwset == FALSE))
  319. E 7
  320. I 7
  321.     /* calculate the number of emails to actually retrieve. 
  322.        this is maxemail - the findnumber.
  323.        if the count has been specificaly set dont do this */
  324.     if (cset == FALSE)
  325. E 7
  326.     {
  327. D 7
  328.         fprintf(stderr, "Usage:  talktopop -h <popserver name> -u <your username> -p <your password> [-c <max number of emails to retrieve>] [-s <max size of email to retrieve in bytes>] [-f] [-l] [-v] [-S <pop name in services file, defaults to pop-3>] [-n <start number>]") ;
  329.         exit(1) ;
  330. E 7
  331. I 7
  332.         maxemail = maxemail - filestartno ;
  333.         if (maxemail < 0)
  334.             maxemail = 0 ;
  335. E 7
  336.     }
  337. }
  338. dogreet()
  339. {
  340.     printf("Talktopop, Version %I%\n(C) Tim Graves, Sun Microsystems 1995\n") ;
  341. }
  342. E 3
  343. doquit()
  344. {
  345.     char tmp[MAXLINE] ;
  346.     sprintf(tmp, "%s", QUITCMD) ;
  347.     tonet(tmp) ;
  348.     fromnet(tmp) ;
  349. I 3
  350.     free(msglist) ;
  351. E 3
  352. }
  353. I 3
  354. dodelete(i)
  355. int i ;
  356. {
  357.     char tmp[MAXLINE] ;
  358.     if (verbose == TRUE)
  359.         printf("Deleting mail no %i\n", i) ;
  360.     sprintf(tmp, "%s %d", DELECMD, i) ;
  361.     tonet(tmp) ;
  362.     fromnet(tmp) ;
  363.     if (tmp[0] == BADCHAR)
  364.         return(BADCMD) ;
  365.     else
  366.         return(GOODCMD) ;
  367. }
  368.  
  369. doretrieve(i, fname)
  370. int i ;
  371. char * fname ;
  372. {
  373.     FILE *fd ;
  374.     char tmp[MAXLINE] ;
  375.     if (verbose == TRUE)
  376. D 4
  377.         printf("Retrieving mail no %d to file %s", i, fname) ;
  378. E 4
  379. I 4
  380.         printf("Retrieving mail no %d to file %s\n", i, fname) ;
  381. E 4
  382.     if ((fd = fopen(fname, "w")) == NULL)
  383.     {
  384.         return(BADFILE) ;
  385.     }
  386.     sprintf(tmp, "%s %d", RETRCMD, i) ;
  387.     tonet(tmp) ;
  388.     /* do the first line, if there is a - there its an error */
  389.     fromnet(tmp) ;
  390.     if (tmp[0] == BADCHAR)
  391.     {
  392.         fclose(fd) ;
  393.         return(BADCMD) ;
  394.     }
  395.     /* the line is OK, do the message */
  396.     while(fromnet(tmp) == TRUE)
  397.     {
  398.         /* NOTE fromnet removes andy \r o \n stuff, we need to 
  399.            reinsert this into the file */
  400.         fprintf(fd, "%s\n", tmp) ;
  401.     }
  402.     fclose(fd) ;
  403.     return(GOODCMD) ;
  404. }
  405. int findfromlast()
  406. {
  407.     /* counting backwards from the last entry in msglist count 
  408.        maxemails which are <= maxsize back and return the number of 
  409.        the last one */
  410.     int i, count ;
  411.     count = 0 ;
  412.     for ( i = messcnt ; ((i >= 0 ) && ( count < maxemail)) ; i--)
  413.         if (msglist[i] <= maxsize)
  414.             count ++ ;
  415.     return(i) ;
  416. }
  417. /* get maxcount emails from the pop server and save then away */
  418. doget(startno)
  419. int startno ;
  420. {
  421.     int i, count;
  422.     char tmp[100] ;
  423.     if (verbose == TRUE)
  424.         printf("Retrieving emails from %d\n", startno) ;
  425.     count = 0 ;
  426.     for (i = startno ; ((count < maxemail) && (i <= messcnt)) ; i ++)
  427.     {
  428.         /* is the email the right size ? */
  429.         if (msglist[i] > maxsize)
  430.             continue ;
  431.         /* OK we should be looking at this email */
  432.         /* create the filename */
  433.         sprintf(tmp, INSKELETON, count+filestartno) ;
  434.         /* get the file */
  435.         doretrieve(i, tmp) ;
  436.         /* are we deleting retrieved messages ? */
  437.         if (dodel == TRUE)
  438.             dodelete(i) ;
  439.         /* increment the count */
  440.         count ++ ;
  441.     }
  442. }
  443. E 3
  444. dolist()
  445. {
  446.     char tmp [MAXLINE] ;
  447. D 3
  448.     int i ;
  449.     for (i = 1 ; i <= messcnt ; i ++)
  450. E 3
  451. I 3
  452.     int i, mailno, mailsize ;
  453.     if (verbose == TRUE)
  454.         printf("Listing email size\n") ;
  455.     for (i = 1 ; i <= messcnt; i ++) 
  456. E 3
  457.     {
  458.         sprintf(tmp, "%s %d", LISTCMD, i) ;
  459.         tonet(tmp) ;
  460.         fromnet(tmp) ;
  461. D 3
  462.         if (tmp[0] == BADCMD)
  463. E 3
  464. I 3
  465.         if (tmp[0] == BADCHAR) /* this could get things out of sync but its usefull for debugging */
  466. E 3
  467.         {
  468.             return(BADCMD) ;
  469.         }
  470. I 3
  471.         /* skip over the "+OK " */
  472.         sscanf(&tmp[4],"%d %d", &mailno, &mailsize) ;
  473.         if (mailno > messcnt)
  474.             return(BADCMD) ;
  475.         if (mailno != i)
  476.             return(BADCMD) ;
  477.         msglist[i] = mailsize ;
  478. E 3
  479.     }
  480.     return(GOODCMD) ;
  481. }
  482. doconnect()
  483. {
  484.     char tmp[MAXLINE] ;
  485. I 3
  486.     if (verbose == TRUE)
  487.         printf("Connecting to pop server\n") ;
  488. E 3
  489.     fromnet(tmp) ;
  490.     if (tmp[0] == BADCHAR)
  491.         return(BADCMD) ;
  492.     else
  493.         return(GOODCMD) ;
  494. }
  495. int dologin()
  496. {
  497.     char tmp[MAXLINE] ;
  498. I 9
  499.     size_t i ;
  500. E 9
  501. I 3
  502.     if (verbose == TRUE)
  503.         printf("Logging in to pop server\n") ;
  504. E 3
  505.     /* request the user name */
  506. D 3
  507.     sprintf(tmp, "%s %s", USERCMD, UNAME) ;
  508. E 3
  509. I 3
  510.     sprintf(tmp, "%s %s", USERCMD, uname) ;
  511. E 3
  512.     tonet(tmp) ;
  513.     fromnet(tmp) ;
  514.     if (tmp[0] == BADCHAR)
  515.     {
  516.         return(BADCMD) ;
  517.     }
  518. D 3
  519.     sprintf(tmp, "%s %s", PASSCMD, PASSWORD) ;
  520. E 3
  521. I 3
  522.     sprintf(tmp, "%s %s", PASSCMD, passwd) ;
  523. E 3
  524.     tonet(tmp) ;
  525.     fromnet(tmp) ;
  526.     if (tmp[0] == BADCHAR)
  527.     {
  528.         return(BADCMD) ;
  529.     }
  530.     /* the format is something like 
  531.     +OK 360 messages ready for tim in /usr/spool/mail/tim
  532. D 9
  533.     extract the number */
  534.     messcnt = atoi(&tmp[4]) ;
  535. E 9
  536. I 9
  537.     for a strict pop3 implementation but some are like
  538.     +OK tim has 77 message(s) (709547 octets).
  539.     find the first number and then extract it (assume the first
  540.     number is the message count  */
  541.     for (i = 0 ; i < strlen(tmp) ; i ++)
  542.         if (isdigit(tmp[i]))
  543.             break ;
  544.     messcnt = atoi(&tmp[i]) ;
  545. E 9
  546. I 3
  547.     msglist = calloc((size_t) messcnt + 1, (size_t) sizeof(int) );
  548. E 3
  549.     return(GOODCMD) ;
  550. }
  551. endnet()
  552. {
  553.     fclose(netinfd) ;
  554.     fclose(netoutfd) ;
  555.     close(net) ;
  556. }
  557. int startnet()
  558. {
  559.     /* hard coded at the moment, connect, list and quit */
  560.     struct servent * sp ;
  561.     struct hostent *hp ;
  562.     int ret ;
  563.     
  564.     /* get the port information etc for pop */
  565. D 3
  566.     if ((sp = getservbyname(POPNAME, PROTNAME)) == NULL)
  567. E 3
  568. I 3
  569.     if ((sp = getservbyname(popname, protname)) == NULL)
  570. E 3
  571.     {
  572. D 3
  573.         printf("%s/%s: unknown service\n", POPNAME, PROTNAME) ;
  574. E 3
  575. I 3
  576.         printf("%s/%s: unknown service\n", popname, protname) ;
  577. E 3
  578.         return(NETERR) ;
  579.     }
  580. D 3
  581.     if ((hp = gethostbyname(POPSERVER)) == NULL)
  582. E 3
  583. I 3
  584.     if ((hp = gethostbyname(popserver)) == NULL)
  585. E 3
  586.     {
  587. D 3
  588.         printf("%s: unknown hostname\n", POPSERVER) ;
  589. E 3
  590. I 3
  591.         printf("%s: unknown hostname\n", popserver) ;
  592. E 3
  593.         return(NETERR) ;
  594.     }
  595.     /* build up the sin structure */
  596.     sin.sin_family = (short) AF_INET ;
  597.     memcpy((char *) &sin.sin_addr, (char *) hp->h_addr, hp->h_length) ;
  598.     sin.sin_port = htons((u_short) sp->s_port) ;
  599.     /* create the socket */
  600.     net = socket(AF_INET, SOCK_STREAM,0) ;
  601.     if (net < 0)
  602.     {
  603.         printf("socket error\n") ;
  604.         return(NETERR);
  605.     }
  606.     ret = connect(net, (struct sockaddr *) &sin, sizeof(sin)) ;
  607.     if (ret < 0)
  608.     {
  609.         printf("connect error\n") ;
  610.         return(NETERR) ;
  611.     }
  612.     netinfd = fdopen(net,"r") ;
  613.     netoutfd = fdopen(net, "w") ;
  614.     if ((netinfd == NULL) || (netoutfd == NULL))
  615.     {
  616.         printf("fdopen error\n") ;
  617.         if (netinfd != NULL)
  618.             fclose(netinfd) ;
  619.         if (netoutfd != NULL) 
  620.             fclose(netoutfd) ;
  621.         close(net) ;
  622.         return(NETERR) ;
  623.     }
  624.     return(NETOK) ;
  625. }
  626.  
  627. tonet(str)
  628. char * str ;
  629. {
  630.     int len ;
  631.     int ret ;
  632.     char tmp[MAXLINE] ;
  633.     sprintf(tmp, "%s\r\n", str) ;
  634.     len = strlen(tmp) ;
  635.     if (debug == TRUE)
  636.         printf("Sending :%slength %d\n", tmp, len) ;
  637.     ret = fprintf(netoutfd, "%s", tmp) ;
  638.     fflush(netoutfd) ;
  639.     if (ret == -1)
  640.     {
  641.         printf("error in send\n") ;
  642.     }
  643.     return ;
  644. }
  645. D 3
  646. fromnet(str)
  647. E 3
  648. I 3
  649. int fromnet(str)
  650. E 3
  651. char * str ;
  652. {
  653.     char tmp[MAXLINE] ;
  654.     char ch ;
  655.     int i, ret ;
  656.     
  657.     ch = '\0' ;
  658.     i = 0 ;
  659.     while (ch != '\n')
  660.     {
  661.         ch = getc(netinfd) ;
  662.         if (ch == EOF)
  663.         {
  664.             printf("recv error") ;
  665.             tmp[i] = '\0' ;
  666.             return ;
  667.         }
  668.         tmp[i] = ch ;
  669.         if (debug == TRUE)
  670.             printf("%c", ch );
  671.         i ++ ;
  672.     }
  673.     /* to get here we must have  tmp[i-1] == '\n' so remove it */
  674.     tmp[i-1] = '\0' ;
  675.     /* if tmp[i-2] is '\r' remove it */
  676.     if (tmp[i-2] == '\r') 
  677.         tmp[i-2] = '\0' ;
  678. I 3
  679.     /* if the first char is . and the length is greater than 1 remove the first .
  680.        (pop3 replaces .<text> with ..<text> and also uses . by itself to mean
  681.        end of the multi line message */
  682.     if (tmp[0] == '.') 
  683.     {
  684.         if (tmp[1] == '\0')
  685.         {
  686.             /* end of multi line stuff */
  687.             /* empty the return string */
  688.             str[0] = '\0' ;
  689.             return (FALSE) ;
  690.         }
  691.         else
  692.         {
  693.             /* the origional text started with a . remove the padding */
  694.             strcpy(str, &tmp[1]) ;
  695.             return(TRUE) ;
  696.         }
  697.     }
  698.     /* no special handling required */
  699. E 3
  700.     strcpy(str, tmp) ;
  701. I 3
  702.     return(TRUE) ;
  703. E 3
  704. }
  705. E 2
  706. I 1
  707. E 1
  708.