home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / POPCLIEN.000 / POPCLIEN / pop / pop3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  13.5 KB  |  534 lines

  1. /* Copyright 1993,1994 by Carl Harris, Jr.
  2.  * All rights reserved
  3.  *
  4.  * Distribute freely, except: don't remove my name from the source or
  5.  * documentation (don't take credit for my work), mark your changes (don't
  6.  * get me blamed for your possible bugs), don't alter or remove this
  7.  * notice.  May be sold if buildable source is provided to buyer.  No
  8.  * warrantee of any kind, express or implied, is included with this
  9.  * software; use at your own risk, responsibility for damages (if any) to
  10.  * anyone resulting from the use of this software rests entirely with the
  11.  * user.
  12.  *
  13.  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  14.  * I'll try to keep a version up to date.  I can be reached as follows:
  15.  * Carl Harris <ceharris@vt.edu>
  16.  */
  17.  
  18.  
  19. /***********************************************************************
  20.   module:       pop3.c
  21.   program:      popclient
  22.   SCCS ID:      @(#)pop3.c    2.4  3/31/94
  23.   programmer:   Carl Harris, ceharris@vt.edu
  24.   date:         29 December 1993
  25.   compiler:     DEC RISC C compiler (Ultrix 4.1)
  26.   environment:  DEC Ultrix 4.3 
  27.   description:  POP2 client code.
  28.  ***********************************************************************/
  29.  
  30. #include  <stdio.h>
  31. #include  <sys/time.h>
  32. #include  <unistd.h>
  33. #include  <ctype.h>
  34. #include  <errno.h>
  35.  
  36. #include  "socket.h"
  37. #include  "config.h"
  38. #include  "popclient.h"
  39.  
  40.  
  41. /* requisite, venerable SCCS ID string */
  42. static char sccs_id [] = "@(#)pop3.c    2.4\t3/31/94";
  43.  
  44. /* TCP port number for POP2 as defined by RFC 937 */
  45. #define      POP3_PORT    110
  46.  
  47. #ifndef NO_PROTO
  48. /* prototypes for internal functions */
  49. int POP3_OK (char *buf, int socket);
  50. int POP3_auth (char *userid, char *password, int socket);
  51. int POP3_sendQUIT (int socket);
  52. int POP3_sendSTAT (int *msgcount, int socket);
  53. int POP3_sendRETR (int msgnum, int socket);
  54. int POP3_sendDELE (int msgnum, int socket);
  55. int POP3_readmsg (int socket, int mboxfd, int topipe);
  56. #endif
  57.  
  58.  
  59. /*********************************************************************
  60.   function:      doPOP3
  61.   description:   retrieve messages from the specified mail server
  62.                  using Post Office Protocol 3.
  63.  
  64.   arguments:     
  65.     options      fully-specified options (i.e. parsed, defaults invoked,
  66.                  etc).
  67.  
  68.   return value:  exit code from the set of PS_.* constants defined in 
  69.                  popclient.h
  70.   calls:
  71.   globals:       reads outlevel.
  72.  *********************************************************************/
  73.  
  74. int doPOP3 (options)
  75. struct optrec *options;
  76. {
  77.   int ok;
  78.   int mboxfd;
  79.   char buf [POPBUFSIZE];
  80.   int socket;
  81.   int number,count;
  82.  
  83.  
  84.   /* open the folder if we're not using the system mailbox */
  85.   if (options->foldertype != OF_SYSMBOX) 
  86.     if ((mboxfd = openuserfolder(options)) < 0) 
  87.       return(PS_FOLDER);
  88.     
  89.   /* open the socket and get the greeting */
  90.   if ((socket = Socket(options->host,POP3_PORT)) < 0) {
  91.     perror("doPOP3: socket");
  92.     return(PS_SOCKET);
  93.   }
  94.  
  95.   ok = POP3_OK(buf,socket);
  96.   if (ok != 0) {
  97.     if (ok != PS_SOCKET)
  98.       POP3_sendQUIT(socket);
  99.     close(socket);
  100.     return(ok);
  101.   }
  102.  
  103.   /* print the greeting */
  104.   if (outlevel > O_SILENT && outlevel < O_VERBOSE) 
  105.     fprintf(stderr,"%s\n",buf);
  106.   else 
  107.     ;
  108.  
  109.   /* try to get authorized */
  110.   ok = POP3_auth(options->userid,options->password,socket);
  111.   if (ok == PS_ERROR)
  112.     ok = PS_AUTHFAIL;
  113.   if (ok != 0)
  114.     goto cleanUp;
  115.  
  116.   /* find out how many messages are waiting */
  117.   ok = POP3_sendSTAT(&count,socket);
  118.   if (ok != 0) {
  119.     goto cleanUp;
  120.   }
  121.  
  122.   /* show them how many messages we'll be downloading */
  123.   if (outlevel > O_SILENT && outlevel < O_VERBOSE)
  124.     fprintf(stderr,"%d messages in folder\n",count);
  125.   else
  126.     ;
  127.  
  128.   if (count > 0) { 
  129.     for (number = 1;  number <= count;  number++) {
  130.  
  131.       /* open the mail pipe if we're using the system mailbox */
  132.       if (options->foldertype == OF_SYSMBOX) {
  133.         ok = (mboxfd = openmailpipe(options)) < 0 ? -1 : 0;
  134.         if (ok != 0)
  135.           goto cleanUp;
  136.       }
  137.            
  138.       ok = POP3_sendRETR(number,socket);
  139.       if (ok != 0)
  140.         goto cleanUp;
  141.         
  142.       ok = POP3_readmsg(socket,mboxfd,options->foldertype == OF_SYSMBOX);
  143.       if (ok != 0)
  144.         goto cleanUp;
  145.  
  146.       if (!options->keep) {
  147.         ok = POP3_sendDELE(number,socket);
  148.         if (ok != 0)
  149.           goto cleanUp;
  150.       }
  151.       else
  152.         ; /* message is kept */
  153.  
  154.       /* close the mail pipe if we're using the system mailbox */
  155.       if (options->foldertype == OF_SYSMBOX) {
  156.         ok = closemailpipe(mboxfd);
  157.         if (ok != 0)
  158.           goto cleanUp;
  159.       }
  160.  
  161.     }
  162.     ok = POP3_sendQUIT(socket);
  163.     if (ok == 0)
  164.       ok = PS_SUCCESS;
  165.     close(socket);
  166.     return(ok);
  167.   }
  168.   else {
  169.     ok = POP3_sendQUIT(socket);
  170.     if (ok == 0)
  171.       ok = PS_NOMAIL;
  172.     close(socket);
  173.     return(ok);
  174.   }
  175.  
  176. cleanUp:
  177.   if (ok != 0 && ok != PS_SOCKET)
  178.     POP3_sendQUIT(socket);
  179.  
  180.   if (options->foldertype != OF_SYSMBOX)
  181.     if (closeuserfolder(mboxfd) < 0 && ok == 0)
  182.       ok = PS_FOLDER;
  183.     
  184.   if (ok == PS_FOLDER || ok == PS_SOCKET) 
  185.     perror("doPOP3: cleanUp");
  186.  
  187.   return(ok);
  188. }
  189.  
  190.  
  191.  
  192. /*********************************************************************
  193.   function:      POP3_OK
  194.   description:   get the server's response to a command, and return
  195.                  the extra arguments sent with the response.
  196.   arguments:     
  197.     argbuf       buffer to receive the argument string.
  198.     socket       socket to which the server is connected.
  199.  
  200.   return value:  zero if okay, else return code.
  201.   calls:         SockGets
  202.   globals:       reads outlevel.
  203.  *********************************************************************/
  204.  
  205. int POP3_OK (argbuf,socket)
  206. char *argbuf;
  207. int socket;
  208. {
  209.   int ok;
  210.   char buf [POPBUFSIZE];
  211.   char *bufp;
  212.  
  213.   if (SockGets(socket, buf, sizeof(buf)) == 0) {
  214.     if (outlevel == O_VERBOSE)
  215.       fprintf(stderr,"%s\n",buf);
  216.  
  217.     bufp = buf;
  218.     if (*bufp == '+' || *bufp == '-')
  219.       bufp++;
  220.     else
  221.       return(PS_PROTOCOL);
  222.  
  223.     while (isalpha(*bufp))
  224.       bufp++;
  225.     *(bufp++) = '\0';
  226.  
  227.     if (strcmp(buf,"+OK") == 0)
  228.       ok = 0;
  229.     else if (strcmp(buf,"-ERR") == 0)
  230.       ok = PS_ERROR;
  231.     else
  232.       ok = PS_PROTOCOL;
  233.  
  234.     if (argbuf != NULL)
  235.       strcpy(argbuf,bufp);
  236.   }
  237.   else 
  238.     ok = PS_SOCKET;
  239.  
  240.   return(ok);
  241. }
  242.  
  243.  
  244.  
  245. /*********************************************************************
  246.   function:      POP3_auth
  247.   description:   send the USER and PASS commands to the server, and
  248.                  get the server's response.
  249.   arguments:     
  250.     userid       user's mailserver id.
  251.     password     user's mailserver password.
  252.     socket       socket to which the server is connected.
  253.  
  254.   return value:  non-zero if success, else zero.
  255.   calls:         SockPrintf, POP3_OK.
  256.   globals:       read outlevel.
  257.  *********************************************************************/
  258.  
  259. int POP3_auth (userid,password,socket) 
  260. char *userid, *password;
  261. int socket;
  262. {
  263.   int ok;
  264.   char buf [POPBUFSIZE];
  265.  
  266.   SockPrintf(socket,"USER %s\r\n",userid);
  267.   if (outlevel == O_VERBOSE)
  268.     fprintf(stderr,"> USER %s\n",userid);
  269.  
  270.   if ((ok = POP3_OK(buf,socket)) == 0) {
  271.     SockPrintf(socket,"PASS %s\r\n",password);
  272.     if (outlevel == O_VERBOSE)
  273.       fprintf(stderr,"> PASS password\n");
  274.  
  275.     if ((ok = POP3_OK(buf,socket)) == 0) 
  276.       ;  /* okay, we're approved.. */
  277.     else if (outlevel > O_SILENT && outlevel < O_VERBOSE)
  278.       fprintf(stderr,"%s\n",buf);
  279.     else
  280.       ; /* say nothing */
  281.   }
  282.   else if (outlevel > O_SILENT && outlevel < O_VERBOSE)
  283.     fprintf(stderr,"%s\n",buf);
  284.   else
  285.     ; /* say nothing */
  286.   
  287.   return(ok);
  288. }
  289.  
  290.  
  291.  
  292.  
  293. /*********************************************************************
  294.   function:      POP3_sendQUIT
  295.   description:   send the QUIT command to the server and close 
  296.                  the socket.
  297.  
  298.   arguments:     
  299.     socket       socket to which the server is connected.
  300.  
  301.   return value:  none.
  302.   calls:         SockPuts, POP3_OK.
  303.   globals:       reads outlevel.
  304.  *********************************************************************/
  305.  
  306. int POP3_sendQUIT (socket)
  307. int socket;
  308. {
  309.   int ok;
  310.   char buf [POPBUFSIZE];
  311.  
  312.   SockPuts(socket,"QUIT");
  313.  
  314.   if (outlevel == O_VERBOSE)
  315.     fprintf(stderr,"> QUIT\n");
  316.   else
  317.     ;
  318.  
  319.   ok = POP3_OK(buf,socket);
  320.   if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
  321.     fprintf(stderr,"%s\n",buf);
  322.  
  323.   return(ok);
  324. }
  325.  
  326.  
  327.  
  328. /*********************************************************************
  329.   function:      POP3_sendSTAT
  330.   description:   send the STAT command to the POP3 server to find
  331.                  out how many messages are waiting.
  332.   arguments:     
  333.     count        pointer to an integer to receive the message count.
  334.     socket       socket to which the POP3 server is connected.
  335.  
  336.   return value:  return code from POP3_OK.
  337.   calls:         POP3_OK, SockPrintf
  338.   globals:       reads outlevel.
  339.  *********************************************************************/
  340.  
  341. int POP3_sendSTAT (msgcount,socket)
  342. int *msgcount;
  343. int socket;
  344. {
  345.   int ok;
  346.   char buf [POPBUFSIZE];
  347.   int totalsize;
  348.  
  349.   SockPrintf(socket,"STAT\r\n");
  350.   if (outlevel == O_VERBOSE)
  351.     fprintf(stderr,"> STAT\n");
  352.   
  353.   ok = POP3_OK(buf,socket);
  354.   if (ok == 0)
  355.     sscanf(buf,"%d %d",msgcount,&totalsize);
  356.   else if (outlevel > O_SILENT && outlevel < O_VERBOSE)
  357.     fprintf(stderr,"%s\n",buf);
  358.  
  359.   return(ok);
  360. }
  361.  
  362.  
  363.  
  364.  
  365. /*********************************************************************
  366.   function:      POP3_sendRETR
  367.   description:   send the RETR command to the POP3 server.
  368.   arguments:     
  369.     msgnum       message ID number
  370.     socket       socket to which the POP3 server is connected.
  371.  
  372.   return value:  return code from POP3_OK.
  373.   calls:         POP3_OK, SockPrintf
  374.   globals:       reads outlevel.
  375.  *********************************************************************/
  376.  
  377. int POP3_sendRETR (msgnum,socket)
  378. int msgnum;
  379. int socket;
  380. {
  381.   int ok;
  382.   char buf [POPBUFSIZE];
  383.  
  384.   SockPrintf(socket,"RETR %d\r\n",msgnum);
  385.   if (outlevel == O_VERBOSE)
  386.     fprintf(stderr,"> RETR %d\n",msgnum);
  387.   
  388.   ok = POP3_OK(buf,socket);
  389.   if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
  390.     fprintf(stderr,"%s\n",buf);
  391.  
  392.   return(ok);
  393. }
  394.  
  395.  
  396.  
  397. /*********************************************************************
  398.   function:      POP3_sendDELE
  399.   description:   send the DELE command to the POP3 server.
  400.   arguments:     
  401.     msgnum       message ID number
  402.     socket       socket to which the POP3 server is connected.
  403.  
  404.   return value:  return code from POP3_OK.
  405.   calls:         POP3_OK, SockPrintF.
  406.   globals:       reads outlevel.
  407.  *********************************************************************/
  408.  
  409. int POP3_sendDELE (msgnum,socket)
  410. int msgnum;
  411. int socket;
  412. {
  413.   int ok;
  414.   char buf [POPBUFSIZE];
  415.  
  416.   SockPrintf(socket,"DELE %d\r\n",msgnum);
  417.   if (outlevel == O_VERBOSE)
  418.     fprintf(stderr,"> DELE %d\n",msgnum);
  419.   
  420.   ok = POP3_OK(buf,socket);
  421.   if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
  422.     fprintf(stderr,"%s\n",buf);
  423.  
  424.   return(ok);
  425. }
  426.  
  427.  
  428.  
  429. /*********************************************************************
  430.   function:      POP3_readmsg
  431.   description:   Read the message content as described in RFC 1225.
  432.   arguments:     
  433.     socket       ... to which the server is connected.
  434.     mboxfd       open file descriptor to which the retrieved message will
  435.                  be written.  
  436.     topipe       true if we're writing to the system mailbox pipe.
  437.  
  438.   return value:  zero if success else PS_* return code.
  439.   calls:         SockGets.
  440.   globals:       reads outlevel. 
  441.  *********************************************************************/
  442.  
  443. int POP3_readmsg (socket,mboxfd,topipe)
  444. int socket;
  445. int mboxfd;
  446. int topipe;
  447. {
  448.   char buf [MSGBUFSIZE];
  449.   char *bufp;
  450.   int lines,sizeticker;
  451.   time_t now;
  452.   /* This keeps the retrieved message count for display purposes */
  453.   static int msgnum = 0;  
  454.  
  455.   /* set up for status message if outlevel allows it */
  456.   if (outlevel > O_SILENT && outlevel < O_VERBOSE) {
  457.     fprintf(stderr,"reading message %d",++msgnum);
  458.     /* won't do the '...' if retrieved messages are being sent to stdout */
  459.     if (mboxfd == 1)
  460.       fputs(".\n",stderr);
  461.     else
  462.       ;
  463.   }
  464.   else
  465.     ;
  466.  
  467.   /* Unix mail folder format requires the Unix-syntax 'From' header.
  468.      POP3 doesn't send it, so we fake it here. */
  469.   if (!topipe) {  
  470.     now = time(NULL);
  471.     sprintf(buf,"From POPmail %s",ctime(&now));
  472.     if (write(mboxfd,buf,strlen(buf)) < 0) {
  473.       perror("POP3_readmsg: write");
  474.       return(PS_FOLDER);
  475.     }
  476.   }
  477.  
  478.  
  479.   /* read the message content from the server */
  480.   lines = 0;
  481.   sizeticker = MSGBUFSIZE;
  482.   while (1) {
  483.     if (SockGets(socket,buf,sizeof(buf)) < 0)
  484.       return(PS_SOCKET);
  485.     bufp = buf;
  486.     if (*bufp == '.') {
  487.       bufp++;
  488.       if (*bufp == 0)
  489.         break;  /* end of message */
  490.     }
  491.     strcat(bufp,"\n");
  492.     if (write(mboxfd,bufp,strlen(bufp)) < 0) {
  493.       perror("POP3_readmsg: write");
  494.       return(PS_FOLDER);
  495.     }
  496.  
  497.     sizeticker -= strlen(bufp);
  498.     if (sizeticker <= 0) {
  499.       if (outlevel > O_SILENT && outlevel < O_VERBOSE)
  500.         fputc('.',stderr);
  501.       sizeticker = MSGBUFSIZE;
  502.     }
  503.     lines++;
  504.   }
  505.  
  506.   if (!topipe) {
  507.     /* The server may not write the extra newline required by the Unix
  508.        mail folder format, so we write one here just in case */
  509.     if (write(mboxfd,"\n",1) < 0) {
  510.       perror("POP3_readmsg: write");
  511.       return(PS_FOLDER);
  512.     }
  513.   }
  514.   else {
  515.     /* The mail delivery agent may require a terminator.  Write it if
  516.        it has been defined */
  517. #ifdef BINMAIL_TERM
  518.     if (write(mboxfd,BINMAIL_TERM,strlen(BINMAIL_TERM)) < 0) {
  519.       perror("POP3_readmsg: write");
  520.       return(PS_FOLDER);
  521.     }
  522. #endif
  523.     }
  524.  
  525.   /* finish up display output */
  526.   if (outlevel == O_VERBOSE)
  527.     fprintf(stderr,"(%d lines of message content)\n",lines);
  528.   else if (outlevel > O_SILENT && mboxfd != 1) 
  529.     fputs(".\n",stderr);
  530.   else
  531.     ;
  532.   return(0);
  533. }
  534.