/* $Id: pop3.c 1.2 1995/01/08 21:26:16 cthuang Exp $ * * This module has been modified for souper. */ /* Copyright 1993,1994 by Carl Harris, Jr. * All rights reserved * * Distribute freely, except: don't remove my name from the source or * documentation (don't take credit for my work), mark your changes (don't * get me blamed for your possible bugs), don't alter or remove this * notice. May be sold if buildable source is provided to buyer. No * warrantee of any kind, express or implied, is included with this * software; use at your own risk, responsibility for damages (if any) to * anyone resulting from the use of this software rests entirely with the * user. * * Send bug reports, bug fixes, enhancements, requests, flames, etc., and * I'll try to keep a version up to date. I can be reached as follows: * Carl Harris */ /*********************************************************************** module: pop3.c program: popclient SCCS ID: @(#)pop3.c 2.4 3/31/94 programmer: Carl Harris, ceharris@vt.edu date: 29 December 1993 compiler: DEC RISC C compiler (Ultrix 4.1) environment: DEC Ultrix 4.3 description: POP2 client code. ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include "socket.h" #include "souper.h" /* requisite, venerable SCCS ID string */ static char sccs_id [] = "@(#)pop3.c 2.4\t3/31/94"; /* TCP port number for POP2 as defined by RFC 937 */ #define POP3_PORT 110 /* exit code values */ #define PS_SUCCESS 0 /* successful receipt of messages */ #define PS_NOMAIL 1 /* no mail available */ #define PS_SOCKET 2 /* socket I/O woes */ #define PS_AUTHFAIL 3 /* user authorization failed */ #define PS_PROTOCOL 4 /* protocol violation */ #define PS_SYNTAX 5 /* command-line syntax error */ #define PS_FOLDER 6 /* local folder I/O woes */ #define PS_ERROR 7 /* some kind of POP3 error condition */ #define PS_UNDEFINED 9 /* something I hadn't thought of */ /********************************************************************* function: POP3_OK description: get the server's response to a command, and return the extra arguments sent with the response. arguments: argbuf buffer to receive the argument string. socket socket to which the server is connected. return value: zero if okay, else return code. calls: SockGets *********************************************************************/ static int POP3_OK (char *argbuf, int socket) { int ok; char buf[BUFSIZ]; char *bufp; if (SockGets(socket, buf, sizeof(buf)) == 0) { bufp = buf; if (*bufp == '+' || *bufp == '-') bufp++; else return(PS_PROTOCOL); while (isalpha(*bufp)) bufp++; *(bufp++) = '\0'; if (strcmp(buf,"+OK") == 0) ok = 0; else if (strcmp(buf,"-ERR") == 0) ok = PS_ERROR; else ok = PS_PROTOCOL; if (argbuf != NULL) strcpy(argbuf,bufp); } else ok = PS_SOCKET; return(ok); } /********************************************************************* function: POP3_auth description: send the USER and PASS commands to the server, and get the server's response. arguments: userid user's mailserver id. password user's mailserver password. socket socket to which the server is connected. return value: non-zero if success, else zero. calls: SockPrintf, POP3_OK. *********************************************************************/ static int POP3_auth (const char *userid, const char *password, int socket) { int ok; char buf[BUFSIZ]; SockPrintf(socket,"USER %s\r\n",userid); if ((ok = POP3_OK(buf,socket)) == 0) { SockPrintf(socket,"PASS %s\r\n",password); if ((ok = POP3_OK(buf,socket)) == 0) ; /* okay, we're approved.. */ else fprintf(stderr,"%s\n",buf); } else fprintf(stderr,"%s\n",buf); return(ok); } /********************************************************************* function: POP3_sendQUIT description: send the QUIT command to the server and close the socket. arguments: socket socket to which the server is connected. return value: none. calls: SockPuts, POP3_OK. *********************************************************************/ static int POP3_sendQUIT (int socket) { int ok; char buf[BUFSIZ]; SockPuts(socket,"QUIT"); ok = POP3_OK(buf,socket); if (ok != 0) fprintf(stderr,"%s\n",buf); return(ok); } /********************************************************************* function: POP3_sendSTAT description: send the STAT command to the POP3 server to find out how many messages are waiting. arguments: count pointer to an integer to receive the message count. socket socket to which the POP3 server is connected. return value: return code from POP3_OK. calls: POP3_OK, SockPrintf *********************************************************************/ static int POP3_sendSTAT (int *msgcount, int socket) { int ok; char buf[BUFSIZ]; int totalsize; SockPrintf(socket,"STAT\r\n"); ok = POP3_OK(buf,socket); if (ok == 0) sscanf(buf,"%d %d",msgcount,&totalsize); else fprintf(stderr,"%s\n",buf); return(ok); } /********************************************************************* function: POP3_sendRETR description: send the RETR command to the POP3 server. arguments: msgnum message ID number socket socket to which the POP3 server is connected. return value: return code from POP3_OK. calls: POP3_OK, SockPrintf *********************************************************************/ static int POP3_sendRETR (int msgnum, int socket) { int ok; char buf[BUFSIZ]; SockPrintf(socket,"RETR %d\r\n",msgnum); ok = POP3_OK(buf,socket); if (ok != 0) fprintf(stderr,"%s\n",buf); return(ok); } /********************************************************************* function: POP3_sendDELE description: send the DELE command to the POP3 server. arguments: msgnum message ID number socket socket to which the POP3 server is connected. return value: return code from POP3_OK. calls: POP3_OK, SockPrintF. *********************************************************************/ static int POP3_sendDELE (int msgnum, int socket) { int ok; char buf[BUFSIZ]; SockPrintf(socket,"DELE %d\r\n",msgnum); ok = POP3_OK(buf,socket); if (ok != 0) fprintf(stderr,"%s\n",buf); return(ok); } /********************************************************************* function: POP3_readmsg description: Read the message content as described in RFC 1225. arguments: socket ... to which the server is connected. mboxfd open file descriptor to which the retrieved message will be written. topipe true if we're writing to the system mailbox pipe. return value: zero if success else PS_* return code. calls: SockGets. *********************************************************************/ static int POP3_readmsg (int socket, FILE *outf) { char buf[BUFSIZ]; char *bufp; time_t now; /* This keeps the retrieved message count for display purposes */ static int msgnum = 0; /* Unix mail folder format requires the Unix-syntax 'From' header. POP3 doesn't send it, so we fake it here. */ now = time(NULL); fprintf(outf, "From POPmail %s", ctime(&now)); /* read the message content from the server */ while (1) { if (SockGets(socket,buf,sizeof(buf)) < 0) return(PS_SOCKET); bufp = buf; if (*bufp == '.') { bufp++; if (*bufp == 0) break; /* end of message */ } if (strncmp(bufp, "From ", 5) == 0) fputc('>', outf); fputs(bufp, outf); fputc('\n', outf); } return(0); } /********************************************************************* function: getMail description: retrieve messages from the specified mail server using Post Office Protocol 3. arguments: options fully-specified options (i.e. parsed, defaults invoked, etc). return value: exit code from the set of PS_.* constants defined in popclient.h calls: *********************************************************************/ int getMail (const char *host, const char *userid, const char *password) { struct servent *sp; int ok; char buf[BUFSIZ]; int socket; int number,count; int percent, lastPercent; if ((sp = getservbyname("pop", "tcp")) == NULL) { fprintf(stderr, "pop/tcp: Unknown service.\n"); return PS_SOCKET; } /* open the socket and get the greeting */ if ((socket = Socket(host, ntohs(sp->s_port))) < 0) { perror("doPOP3: socket"); return PS_SOCKET; } ok = POP3_OK(buf, socket); if (ok != 0) { if (ok != PS_SOCKET) POP3_sendQUIT(socket); close(socket); return(ok); } /* try to get authorized */ ok = POP3_auth(userid, password, socket); if (ok == PS_ERROR) ok = PS_AUTHFAIL; if (ok != 0) goto cleanUp; /* find out how many messages are waiting */ ok = POP3_sendSTAT(&count, socket); if (ok != 0) { goto cleanUp; } /* show them how many messages we'll be downloading */ printf("%s: you have %d mail message%s\n", progname, count, (count == 1) ? "" : "s"); if (count > 0) { /* Open the mailbox file. */ FILE *outf; if ((outf = openMsgFile(0, "Email", "mn")) == NULL) goto cleanUp; lastPercent = 0; for (number = 1; number <= count; number++) { percent = (number * 100) / count; if (percent != lastPercent) { printf("%d%%\r", percent); lastPercent = percent; } ok = POP3_sendRETR(number,socket); if (ok != 0) goto cleanUp; ok = POP3_readmsg(socket, outf); if (ok != 0) goto cleanUp; if (!readOnly) { ok = POP3_sendDELE(number,socket); if (ok != 0) goto cleanUp; } } closeMsgFile(); ok = POP3_sendQUIT(socket); if (ok == 0) ok = PS_SUCCESS; close(socket); return(ok); } else { ok = POP3_sendQUIT(socket); if (ok == 0) ok = PS_NOMAIL; close(socket); return(ok); } cleanUp: if (ok != 0 && ok != PS_SOCKET) POP3_sendQUIT(socket); if (ok == PS_FOLDER || ok == PS_SOCKET) perror("doPOP3: cleanUp"); return(ok); }