home *** CD-ROM | disk | FTP | other *** search
- /* this program talks to pop3 servers */
- /* (C) Tim Graves, Sun Microsystems 1995 */
- #include "talktopop.h"
- #include <netinet/in.h>
- #include <sys/uio.h>
- #include <netdb.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- /* info on the port we are dealing with etc */
- struct sockaddr_in sin ;
- int net ;
- FILE *netinfd, *netoutfd ;
-
- /* various strings etc that are set or reset from the command line */
- char popserver[100] ;
- char popname [100] ;
- char protname [100] ;
- char uname[100] ;
- char passwd[100] ;
- int filestartno = 0 ;
- int dodel = FALSE ;
- int direction = TRUE ;
- int verbose = FALSE ;
- int maxsize = MAXSIZE ;
- int maxemail = MAXCOUNT ;
- int hnset, pwset, unset ;
-
-
- /* message information */
- int messcnt = 0 ;
-
- /* debug information */
- int debug = FALSE ;
- /* pointer to the message size array */
- int * msglist ;
-
- main(argc, argv, environ)
- int argc ;
- char * argv[] ;
- char * environ[] ;
- {
- int ret ;
- int startno ;
- init() ;
- /* handle the command line */
- cmdline(argc, argv) ;
- if (verbose == TRUE)
- dogreet() ;
- /* check that the arguments have worked out right and
- get the password if required */
- checkflags() ;
- /* maxemail can viable be zero if there are more saved emails than
- the default value of maxemail. in this case just crunch out */
- if (maxemail == 0)
- exit(0) ;
- /* setup the network connection */
- if (startnet() == NETERR)
- {
- printf("Network initialisation error\nExiting\n") ;
- return ;
- }
- ret = doconnect() ;
- if (ret == BADCMD)
- {
- printf("Pop server returns bad\n") ;
- return ;
- }
- ret = dologin() ;
- if (ret == GOODCMD)
- {
- dolist() ;
- if (direction == FALSE)
- startno = findfromlast() ;
- else
- startno = 1 ;
- doget(startno) ;
- }
- doquit() ;
- endnet() ;
- }
- checkflags()
- {
- char tmp[1024] ;
- char * pass ;
- /* ensure that we have a host name and user name */
- if (hnset == FALSE)
- {
- printf("Error: talktopop cannot find your pop server name in the config file or the command list") ;
- exit(1) ;
- }
- if (pwset == FALSE)
- {
- sprintf(tmp, "Please enter the password for user %s on machine %s:", uname, popserver) ;
- pass = getpass(tmp) ;
- strcpy(passwd, pass) ;
- }
- }
- init()
- {
- confinit() ;
- getuname(uname) ;
- unset = TRUE ;
- readconf() ;
- }
- cmdline(argc, argv)
- int argc ;
- char * argv[] ;
- {
- int c ;
- extern int optind ;
- extern char * optarg ;
- int cset = FALSE ;
- while ((c = getopt(argc, argv, "h:u:p:c:s:flvdS:n:")) != EOF)
- {
- switch(c)
- {
- case 'h': /* hostname for pop server */
- strcpy(popserver, optarg) ;
- hnset = TRUE ;
- break ;
- case 'u': /* username to use */
- strcpy(uname, optarg) ;
- unset = TRUE ;
- break ;
- case 'p': /* password to use */
- strcpy(passwd, optarg) ;
- pwset = TRUE ;
- break ;
- case 'c': /* max number of emails to retrieve */
- maxemail = atoi(optarg) ;
- cset = TRUE ;
- break ;
- case 's': /* max size of email to retrieve */
- maxsize = atoi(optarg) ;
- break ;
- case 'f': /* retrieve maxemails from the start of the email box */
- direction = TRUE ;
- break ;
- case 'l': /* retrieve maxemails from the end of the email box */
- direction = FALSE ;
- break ;
- case 'v': /* be verbose for debugging */
- verbose = TRUE ;
- break ;
- case 'S': /* service name (defaults to pop-3) */
- strcpy(popname, optarg) ;
- break ;
- case 'n': /* number to start the file count at */
- filestartno = atoi(optarg) ;
- break ;
- case 'd': /* delete the messages once rtead */
- dodel = TRUE ;
- break ;
- }
- }
- /* calculate the number of emails to actually retrieve.
- this is maxemail - the findnumber.
- if the count has been specificaly set dont do this */
- if (cset == FALSE)
- {
- maxemail = maxemail - filestartno ;
- if (maxemail < 0)
- maxemail = 0 ;
- }
- }
- dogreet()
- {
- printf("Talktopop, Version 1.9\n(C) Tim Graves, Sun Microsystems 1995\n") ;
- }
- doquit()
- {
- char tmp[MAXLINE] ;
- sprintf(tmp, "%s", QUITCMD) ;
- tonet(tmp) ;
- fromnet(tmp) ;
- free(msglist) ;
- }
- dodelete(i)
- int i ;
- {
- char tmp[MAXLINE] ;
- if (verbose == TRUE)
- printf("Deleting mail no %i\n", i) ;
- sprintf(tmp, "%s %d", DELECMD, i) ;
- tonet(tmp) ;
- fromnet(tmp) ;
- if (tmp[0] == BADCHAR)
- return(BADCMD) ;
- else
- return(GOODCMD) ;
- }
-
- doretrieve(i, fname)
- int i ;
- char * fname ;
- {
- FILE *fd ;
- char tmp[MAXLINE] ;
- if (verbose == TRUE)
- printf("Retrieving mail no %d to file %s\n", i, fname) ;
- if ((fd = fopen(fname, "w")) == NULL)
- {
- return(BADFILE) ;
- }
- sprintf(tmp, "%s %d", RETRCMD, i) ;
- tonet(tmp) ;
- /* do the first line, if there is a - there its an error */
- fromnet(tmp) ;
- if (tmp[0] == BADCHAR)
- {
- fclose(fd) ;
- return(BADCMD) ;
- }
- /* the line is OK, do the message */
- while(fromnet(tmp) == TRUE)
- {
- /* NOTE fromnet removes andy \r o \n stuff, we need to
- reinsert this into the file */
- fprintf(fd, "%s\n", tmp) ;
- }
- fclose(fd) ;
- return(GOODCMD) ;
- }
- int findfromlast()
- {
- /* counting backwards from the last entry in msglist count
- maxemails which are <= maxsize back and return the number of
- the last one */
- int i, count ;
- count = 0 ;
- for ( i = messcnt ; ((i >= 0 ) && ( count < maxemail)) ; i--)
- if (msglist[i] <= maxsize)
- count ++ ;
- return(i) ;
- }
- /* get maxcount emails from the pop server and save then away */
- doget(startno)
- int startno ;
- {
- int i, count;
- char tmp[100] ;
- if (verbose == TRUE)
- printf("Retrieving emails from %d\n", startno) ;
- count = 0 ;
- for (i = startno ; ((count < maxemail) && (i <= messcnt)) ; i ++)
- {
- /* is the email the right size ? */
- if (msglist[i] > maxsize)
- continue ;
- /* OK we should be looking at this email */
- /* create the filename */
- sprintf(tmp, INSKELETON, count+filestartno) ;
- /* get the file */
- doretrieve(i, tmp) ;
- /* are we deleting retrieved messages ? */
- if (dodel == TRUE)
- dodelete(i) ;
- /* increment the count */
- count ++ ;
- }
- }
- dolist()
- {
- char tmp [MAXLINE] ;
- int i, mailno, mailsize ;
- if (verbose == TRUE)
- printf("Listing email size\n") ;
- for (i = 1 ; i <= messcnt; i ++)
- {
- sprintf(tmp, "%s %d", LISTCMD, i) ;
- tonet(tmp) ;
- fromnet(tmp) ;
- if (tmp[0] == BADCHAR) /* this could get things out of sync but its usefull for debugging */
- {
- return(BADCMD) ;
- }
- /* skip over the "+OK " */
- sscanf(&tmp[4],"%d %d", &mailno, &mailsize) ;
- if (mailno > messcnt)
- return(BADCMD) ;
- if (mailno != i)
- return(BADCMD) ;
- msglist[i] = mailsize ;
- }
- return(GOODCMD) ;
- }
- doconnect()
- {
- char tmp[MAXLINE] ;
- if (verbose == TRUE)
- printf("Connecting to pop server\n") ;
- fromnet(tmp) ;
- if (tmp[0] == BADCHAR)
- return(BADCMD) ;
- else
- return(GOODCMD) ;
- }
- int dologin()
- {
- char tmp[MAXLINE] ;
- size_t i ;
- if (verbose == TRUE)
- printf("Logging in to pop server\n") ;
- /* request the user name */
- sprintf(tmp, "%s %s", USERCMD, uname) ;
- tonet(tmp) ;
- fromnet(tmp) ;
- if (tmp[0] == BADCHAR)
- {
- return(BADCMD) ;
- }
- sprintf(tmp, "%s %s", PASSCMD, passwd) ;
- tonet(tmp) ;
- fromnet(tmp) ;
- if (tmp[0] == BADCHAR)
- {
- return(BADCMD) ;
- }
- /* the format is something like
- +OK 360 messages ready for tim in /usr/spool/mail/tim
- for a strict pop3 implementation but some are like
- +OK tim has 77 message(s) (709547 octets).
- find the first number and then extract it (assume the first
- number is the message count */
- for (i = 0 ; i < strlen(tmp) ; i ++)
- if (isdigit(tmp[i]))
- break ;
- messcnt = atoi(&tmp[i]) ;
- msglist = calloc((size_t) messcnt + 1, (size_t) sizeof(int) );
- return(GOODCMD) ;
- }
- endnet()
- {
- fclose(netinfd) ;
- fclose(netoutfd) ;
- close(net) ;
- }
- int startnet()
- {
- /* hard coded at the moment, connect, list and quit */
- struct servent * sp ;
- struct hostent *hp ;
- int ret ;
-
- /* get the port information etc for pop */
- if ((sp = getservbyname(popname, protname)) == NULL)
- {
- printf("%s/%s: unknown service\n", popname, protname) ;
- return(NETERR) ;
- }
- if ((hp = gethostbyname(popserver)) == NULL)
- {
- printf("%s: unknown hostname\n", popserver) ;
- return(NETERR) ;
- }
- /* build up the sin structure */
- sin.sin_family = (short) AF_INET ;
- memcpy((char *) &sin.sin_addr, (char *) hp->h_addr, hp->h_length) ;
- sin.sin_port = htons((u_short) sp->s_port) ;
- /* create the socket */
- net = socket(AF_INET, SOCK_STREAM,0) ;
- if (net < 0)
- {
- printf("socket error\n") ;
- return(NETERR);
- }
- ret = connect(net, (struct sockaddr *) &sin, sizeof(sin)) ;
- if (ret < 0)
- {
- printf("connect error\n") ;
- return(NETERR) ;
- }
- netinfd = fdopen(net,"r") ;
- netoutfd = fdopen(net, "w") ;
- if ((netinfd == NULL) || (netoutfd == NULL))
- {
- printf("fdopen error\n") ;
- if (netinfd != NULL)
- fclose(netinfd) ;
- if (netoutfd != NULL)
- fclose(netoutfd) ;
- close(net) ;
- return(NETERR) ;
- }
- return(NETOK) ;
- }
-
- tonet(str)
- char * str ;
- {
- int len ;
- int ret ;
- char tmp[MAXLINE] ;
- sprintf(tmp, "%s\r\n", str) ;
- len = strlen(tmp) ;
- if (debug == TRUE)
- printf("Sending :%slength %d\n", tmp, len) ;
- ret = fprintf(netoutfd, "%s", tmp) ;
- fflush(netoutfd) ;
- if (ret == -1)
- {
- printf("error in send\n") ;
- }
- return ;
- }
- int fromnet(str)
- char * str ;
- {
- char tmp[MAXLINE] ;
- char ch ;
- int i, ret ;
-
- ch = '\0' ;
- i = 0 ;
- while (ch != '\n')
- {
- ch = getc(netinfd) ;
- if (ch == EOF)
- {
- printf("recv error") ;
- tmp[i] = '\0' ;
- return ;
- }
- tmp[i] = ch ;
- if (debug == TRUE)
- printf("%c", ch );
- i ++ ;
- }
- /* to get here we must have tmp[i-1] == '\n' so remove it */
- tmp[i-1] = '\0' ;
- /* if tmp[i-2] is '\r' remove it */
- if (tmp[i-2] == '\r')
- tmp[i-2] = '\0' ;
- /* if the first char is . and the length is greater than 1 remove the first .
- (pop3 replaces .<text> with ..<text> and also uses . by itself to mean
- end of the multi line message */
- if (tmp[0] == '.')
- {
- if (tmp[1] == '\0')
- {
- /* end of multi line stuff */
- /* empty the return string */
- str[0] = '\0' ;
- return (FALSE) ;
- }
- else
- {
- /* the origional text started with a . remove the padding */
- strcpy(str, &tmp[1]) ;
- return(TRUE) ;
- }
- }
- /* no special handling required */
- strcpy(str, tmp) ;
- return(TRUE) ;
- }
-