home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / POPCLIEN.000 / POPCLIEN / pop / pop2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  14.3 KB  |  536 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:       pop2.c
  21.   program:      popclient
  22.   SCCS ID:    @(#)pop2.c    1.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  <errno.h>
  34.  
  35. #include  "socket.h"
  36. #include  "config.h"
  37. #include  "popclient.h"
  38.  
  39. /* requisite, venerable SCCS ID */
  40. static char sccs_id [] = "@(#)pop2.c    1.4\t3/31/94";
  41.  
  42. /* TCP port number for POP2 as defined by RFC 937 */
  43. #define      POP2_PORT    109
  44.  
  45. #ifndef NO_PROTO
  46. /* prototypes for internal functions */
  47. int POP2_sendcmd (char *cmd, int socket);
  48. int POP2_sendHELO (char *userid, char *password, int socket);
  49. int POP2_sendFOLD (char *folder, int socket);
  50. int POP2_quit (int socket);
  51. int POP2_stateGREET (int socket);
  52. int POP2_stateNMBR (int socket);
  53. int POP2_stateSIZE (int socket);
  54. int POP2_stateXFER (int msgsize, int socket, int mboxfd, int topipe);
  55. #endif
  56.  
  57.  
  58. /*********************************************************************
  59.   function:      doPOP2
  60.   description:   retrieve messages from the specified mail server
  61.                  using Post Office Protocol 2.
  62.  
  63.   arguments:     
  64.     options      fully-specified options (i.e. parsed, defaults invoked,
  65.                  etc).
  66.  
  67.   return value:  exit code from the set of PS_.* constants defined in 
  68.                  popclient.h
  69.   calls:         POP2_stateGREET, POP2_stateNMBR, POP2_stateSIZE,
  70.                  POP2_stateXFER, POP2_sendcmd, POP2_sendHELO,
  71.                  POP2_sendFOLD, POP2_quit, Socket, openuserfolder,
  72.                  closeuserfolder, openmailpipe, closemailpipe.
  73.   globals:       reads outlevel.
  74.  *********************************************************************/
  75.  
  76. int doPOP2 (options)
  77. struct optrec *options;
  78. {
  79.   int mboxfd;
  80.   int socket;
  81.   int number,msgsize,actsize;
  82.   int status = PS_UNDEFINED;
  83.  
  84.   /* open the socket to the POP server */
  85.   if ((socket = Socket(options->host,POP2_PORT)) < 0) {
  86.     perror("doPOP2: socket");
  87.     return(PS_SOCKET);
  88.   }
  89.     
  90.   /* open/lock the folder if it is a user folder or stdout */
  91.   if (options->foldertype != OF_SYSMBOX)
  92.     if ((mboxfd = openuserfolder(options)) < 0) 
  93.       return(PS_FOLDER);
  94.  
  95.   /* wait for the POP2 greeting */
  96.   if (POP2_stateGREET(socket) != 0) {
  97.     POP2_quit(socket);
  98.     return(PS_PROTOCOL);
  99.   }
  100.  
  101.   /* log the user onto the server */
  102.   POP2_sendHELO(options->userid,options->password,socket);
  103.   if ((number = POP2_stateNMBR(socket)) < 0) {
  104.     POP2_quit(socket);
  105.     return(PS_AUTHFAIL);
  106.   }
  107.  
  108.   /* set the remote folder if selected */
  109.   if (*options->remotefolder != 0) {
  110.     POP2_sendFOLD(options->remotefolder,socket);
  111.     if ((number = POP2_stateNMBR(socket)) < 0) {
  112.       POP2_quit(socket);
  113.       return(PS_PROTOCOL);
  114.     }
  115.   }
  116.  
  117.   /* tell 'em how many messages are waiting */
  118.   if (outlevel > O_SILENT && outlevel < O_VERBOSE)
  119.     fprintf(stderr,"%d messages in folder %s\n",number,options->remotefolder);
  120.   else
  121.     ;
  122.  
  123.   /* fall into a retrieve/acknowledge loop */
  124.   if (number > 0) { 
  125.  
  126.     POP2_sendcmd("READ",socket);
  127.     msgsize = POP2_stateSIZE(socket);
  128.     while (msgsize > 0) {
  129.  
  130.       /* open the pipe */
  131.       if (options->foldertype == OF_SYSMBOX)
  132.         if ((mboxfd = openmailpipe(options)) < 0) {   
  133.           POP2_quit(socket);
  134.           return(PS_FOLDER);
  135.         }
  136.  
  137.       POP2_sendcmd("RETR",socket);
  138.       actsize = POP2_stateXFER(msgsize,socket,mboxfd,
  139.                                options->foldertype == OF_SYSMBOX);
  140.       if (actsize == msgsize) 
  141.         if (options->keep)
  142.           POP2_sendcmd("ACKS",socket);
  143.         else
  144.           POP2_sendcmd("ACKD",socket);
  145.       else if (actsize >= 0) 
  146.         POP2_sendcmd("NACK",socket);
  147.       else {
  148.         POP2_quit(socket);
  149.         return(PS_SOCKET);
  150.       }
  151.  
  152.       /* close the pipe */
  153.       if (options->foldertype == OF_SYSMBOX)
  154.         if (closemailpipe(mboxfd) < 0) {
  155.           POP2_quit(socket);
  156.           return(PS_FOLDER);
  157.         }
  158.     
  159.       msgsize = POP2_stateSIZE(socket);
  160.     }
  161.     POP2_quit(socket);
  162.     status = msgsize == 0 ? PS_SUCCESS : PS_PROTOCOL;
  163.   }
  164.   else {
  165.     POP2_quit(socket);
  166.     status = PS_NOMAIL;
  167.   }
  168.  
  169.   if (options->foldertype != OF_SYSMBOX)
  170.     closeuserfolder(mboxfd);
  171.  
  172.   return(status);
  173. }
  174.  
  175.  
  176.  
  177. /*********************************************************************
  178.   function:      POP2_sendcmd
  179.   description:   send a command string (with no arguments) a server.
  180.   arguments:     
  181.     cmd          command string to send.
  182.     socket       socket to which the server is connected.
  183.  
  184.   return value:  none.
  185.   calls:         SockPuts.
  186.   globals:       reads outlevel.
  187.  *********************************************************************/
  188.  
  189. int POP2_sendcmd (cmd,socket) 
  190. char *cmd;
  191. int socket;
  192. {
  193.   SockPuts(socket,cmd);
  194.  
  195.   if (outlevel == O_VERBOSE)
  196.     fprintf(stderr,"> %s\n",cmd);
  197.   else
  198.     ;
  199. }
  200.  
  201.  
  202. /*********************************************************************
  203.   function:      POP2_sendHELO
  204.   description:   send the HELO command to the server.
  205.   arguments:     
  206.     userid       user's mailserver id.
  207.     password     user's mailserver password.
  208.     socket       socket to which the server is connected.
  209.  
  210.   return value:  none.
  211.   calls:         SockPrintf.
  212.   globals:       read outlevel.
  213.  *********************************************************************/
  214.  
  215. int POP2_sendHELO (userid,password,socket) 
  216. char *userid, *password;
  217. int socket;
  218. {
  219.   SockPrintf(socket,"HELO %s %s\r\n",userid,password);
  220.     
  221.  
  222.   if (outlevel == O_VERBOSE)
  223.     fprintf(stderr,"> HELO %s password\n",userid);
  224.   else
  225.     ;
  226. }
  227.  
  228.  
  229. /*********************************************************************
  230.   function:      POP2_sendFOLD
  231.   description:   send the FOLD command to the server.
  232.   arguments:     
  233.     folder       name of the folder to open on the server.
  234.     socket       socket to which the server is connected.  
  235.  
  236.   return value:  none.
  237.   calls:         SockPrintf.
  238.   globals:       reads outlevel.
  239.  *********************************************************************/
  240.  
  241. int POP2_sendFOLD (folder,socket)
  242. char *folder;
  243. int socket;
  244. {
  245.   SockPrintf(socket,"FOLD %s\r\n",folder);
  246.  
  247.   if (outlevel == O_VERBOSE)
  248.     fprintf(stderr,"> FOLD %s\n",folder);
  249.   else
  250.     ;
  251. }
  252.  
  253.  
  254. /*********************************************************************
  255.   function:      POP2_quit
  256.   description:   send the QUIT command to the server and close 
  257.                  the socket.
  258.  
  259.   arguments:     
  260.     socket       socket to which the server is connected.
  261.  
  262.   return value:  none.
  263.   calls:         SockPuts.
  264.   globals:       reads outlevel.
  265.  *********************************************************************/
  266.  
  267. int POP2_quit (socket)
  268. int socket;
  269. {
  270.   SockPuts(socket,"QUIT");
  271.   close(socket);
  272.  
  273.   if (outlevel == O_VERBOSE)
  274.     fprintf(stderr,"> QUIT\n");
  275.   else
  276.     ;
  277. }
  278.  
  279.  
  280. /*********************************************************************
  281.   function:      POP2_stateGREET
  282.   description:   process the GREET state as described in RFC 937.
  283.   arguments:     
  284.     socket       ...to which server is connected.
  285.  
  286.   return value:  zero if server's handling of the GREET state was 
  287.                  correct, else non-zero (may indicate difficulty
  288.                  at the socket).
  289.   calls:         SockGets.
  290.   globals:       reads outlevel.
  291.  *********************************************************************/
  292.  
  293. int POP2_stateGREET (socket)
  294. int socket;
  295. {
  296.   char buf [POPBUFSIZE];
  297.  
  298.   /* read the greeting from the server */
  299.   if (SockGets(socket, buf, sizeof(buf)) == 0) {
  300.  
  301.     /* echo the server's greeting to the user */
  302.     if (outlevel > O_SILENT)
  303.       fprintf(stderr,"%s\n",buf);
  304.     else
  305.       ;
  306.     /* is the greeting in the correct format? */
  307.     if (*buf == '+')
  308.       return(0);
  309.     else
  310.       return(-1);
  311.   }
  312.   else {
  313.     /* an error at the socket */ 
  314.     if (outlevel > O_SILENT)
  315.       perror("error reading socket\n");
  316.     else
  317.       ;
  318.     return(-1);
  319.   }
  320. }
  321.  
  322.  
  323. /*********************************************************************
  324.   function:      POP2_stateNMBR
  325.   description:   process the NMBR state as described in RFC 937.
  326.   arguments:     
  327.     socket       ...to which the server is connected.
  328.  
  329.   return value:  zero if the expected NMBR state action occured, else
  330.                  non-zero.  Following HELO, a non-zero return value 
  331.                  usually here means the user authorization at the server
  332.                  failed.
  333.   calls:         SockGets.
  334.   globals:       reads outlevel.
  335.  *********************************************************************/
  336.  
  337. int POP2_stateNMBR (socket)
  338. int socket;
  339. {
  340.   int number;
  341.   char buf [POPBUFSIZE];
  342.  
  343.   /* read the NMBR (#ccc) message from the server */
  344.   if (SockGets(socket, buf, sizeof(buf)) == 0) {
  345.  
  346.     /* is the message in the proper format? */
  347.     if (*buf == '#') {
  348.       number = atoi(buf + 1);
  349.       if (outlevel == O_VERBOSE)
  350.         fprintf(stderr,"%s\n",buf);
  351.       else
  352.         ;
  353.     }
  354.     else {
  355.       number = -1;
  356.       if (outlevel > O_SILENT) 
  357.         fprintf(stderr,"%s\n",buf);
  358.       else
  359.         ;
  360.     }
  361.   }
  362.   else {
  363.     /* socket problem */
  364.     number = -1;
  365.     if (outlevel == O_VERBOSE) 
  366.       perror("socket read error\n");
  367.     else
  368.       ;
  369.   }
  370.   return(number);
  371. }
  372.  
  373.  
  374. /*********************************************************************
  375.   function:      POP2_stateSIZE
  376.   description:   process the SIZE state as described in RFC 937.
  377.   arguments:     
  378.     socket       ...to which the server is connected.
  379.  
  380.   return value:  zero if the expected SIZE state action occured, else
  381.                  non-zero (usually indicates a protocol violation).
  382.   calls:         SockGets.
  383.   globals:       reads outlevel.
  384.  *********************************************************************/
  385.  
  386. int POP2_stateSIZE (socket)
  387. int socket;
  388. {
  389.   int msgsize;
  390.   char buf [POPBUFSIZE];
  391.  
  392.   /* read the SIZE message (=ccc) from the server */
  393.   if (SockGets(socket, buf, sizeof(buf)) == 0) 
  394.     /* is the message in the correct format? */
  395.     if (*buf == '=') {
  396.       msgsize = atoi(buf + 1);
  397.       if (outlevel == O_VERBOSE)
  398.         fprintf(stderr,"%s\n",buf);
  399.       else
  400.         ;
  401.     }
  402.     else {
  403.       msgsize = -1;
  404.       if (outlevel > O_SILENT) 
  405.         fprintf(stderr,"%s\n",buf);
  406.       else
  407.         ;
  408.     }
  409.   else {
  410.     /* socket problem */
  411.     msgsize = -1;
  412.     if (outlevel == O_VERBOSE) 
  413.       perror("socket read error\n");
  414.     else
  415.       ;
  416.   }
  417.  
  418.   return(msgsize);
  419. }
  420.  
  421.  
  422. /*********************************************************************
  423.   function:      POP2_stateXFER
  424.   description:   process the XFER state as described in RFC 937.
  425.   arguments:     
  426.     msgsize      content length of the message as reported in the 
  427.                  SIZE state.
  428.     socket       ... to which the server is connected.
  429.     mboxfd       open file descriptor to which the retrieved message will
  430.                  be written.  
  431.     topipe       true if we're writing to a the /bin/mail pipe.
  432.  
  433.   return value:  
  434.     >= 0         actual length of the message received. 
  435.     < 0          socket I/O problem.
  436.  
  437.   calls:         SockRead.
  438.   globals:       reads outlevel. 
  439.  *********************************************************************/
  440.  
  441. int POP2_stateXFER (msgsize,socket,mboxfd,topipe)
  442. int msgsize;
  443. int socket;
  444. int mboxfd;
  445. int topipe;
  446. {
  447.   int i,buflen,actsize;
  448.   char buf [MSGBUFSIZE]; 
  449.   time_t now;
  450.  
  451.   /* This keeps the retrieved message count for display purposes */
  452.   static int msgnum = 0;  
  453.  
  454.   /* set up for status message if outlevel allows it */
  455.   if (outlevel > O_SILENT && outlevel < O_VERBOSE) {
  456.     fprintf(stderr,"reading message %d",++msgnum);
  457.     /* won't do the '...' if retrieved messages are being sent to stdout */
  458.     if (mboxfd == 1)  /* we're writing to stdout */
  459.       fputs(".\n",stderr);
  460.     else
  461.       ;
  462.   }
  463.   else
  464.     ;
  465.  
  466.   /* Unix mail folder format requires the Unix-syntax 'From' header.
  467.      POP doesn't send it, so we fake it here. */
  468.   if (!topipe) {
  469.     now = time(NULL);
  470.     sprintf(buf,"From POPmail %s",ctime(&now));
  471.     if (write(mboxfd,buf,strlen(buf)) < 0) {
  472.       perror("POP2_stateXFER: write");
  473.       return(-1);
  474.     }
  475.   }
  476.  
  477.   /* read the specified message content length from the server */
  478.   actsize = 0;
  479.   while (msgsize > 0) {
  480.     buflen = msgsize <= MSGBUFSIZE ? msgsize : MSGBUFSIZE;
  481.     /* read a bufferful */ 
  482.     if (SockRead(socket, buf, buflen) == 0) {
  483.       /* write to folder, stripping CR chars in the process */
  484.       for (i = 0;  i < buflen;  i++)
  485.         if (*(buf + i) != '\r')
  486.           if (write(mboxfd,buf + i,1) < 0) {
  487.             perror("POP2_stateXFER: write");
  488.             return(-1);
  489.           }
  490.           else
  491.             ;  /* it was written */
  492.         else
  493.           ;  /* ignore CR character */
  494.     }
  495.     else
  496.       return(-1);   /* socket problem */
  497.  
  498.     /* write another . for every bufferful received */
  499.     if (outlevel > O_SILENT && outlevel < O_VERBOSE && mboxfd != 1) 
  500.       fputc('.',stderr);
  501.     else
  502.       ;
  503.     msgsize -= buflen;
  504.     actsize += buflen;
  505.   }
  506.  
  507.   if (!topipe) {
  508.     /* The server may not write the extra newline required by the Unix
  509.        mail folder format, so we write one here just in case */
  510.     if (write(mboxfd,"\n",1) < 1) {
  511.       perror("POP2_stateXFER: write");
  512.       return(-1);
  513.     }
  514.   }
  515.   else {
  516.      /* the mailer might require some sort of termination string, send
  517.         it if it is defined */
  518. #ifdef BINMAIL_TERM
  519.     if (write(mboxfd,BINMAIL_TERM,strlen(BINMAIL_TERM)) < 0) {
  520.       perror("POP2_stateXFER: write");
  521.       return(-1);
  522.     }
  523. #endif
  524.   }
  525.  
  526.   /* finish up display output */
  527.   if (outlevel == O_VERBOSE)
  528.     fprintf(stderr,"(%d characters of message content)\n",actsize);
  529.   else if (outlevel > O_SILENT && mboxfd != 0)
  530.     fputc('\n',stderr);
  531.   else
  532.     ;
  533.  
  534.   return(actsize);
  535. }
  536.