From 282312abba459f6e3e9c819aca3a792780369c90 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Wed, 25 Sep 1996 04:04:59 +0000 Subject: Eliminate an #ifdef. svn path=/trunk/; revision=135 --- driver.c | 714 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 355 insertions(+), 359 deletions(-) diff --git a/driver.c b/driver.c index 53b41e5a..d79624c3 100644 --- a/driver.c +++ b/driver.c @@ -29,388 +29,106 @@ char tag[TAGLEN]; static int tagnum; #define GENSYM (sprintf(tag, "a%04d", ++tagnum), tag) -#ifdef HAVE_PROTOTYPES -static int gen_readmsg (int socket, int mboxfd, long len, int delimited, - char *user, char *host, int topipe, int rewrite); -#endif /* HAVE_PROTOTYPES */ - /********************************************************************* - function: do_protocol - description: retrieve messages from the specified mail server - using a given set of methods + function: + description: hack message headers so replies will work properly - arguments: - queryctl fully-specified options (i.e. parsed, defaults invoked, - etc). - proto protocol method pointer + arguments: + after where to put the hacked header + before header to hack + host name of the pop header - return value: exit code from the set of PS_.* constants defined in - fetchmail.h - calls: - globals: reads outlevel. + return value: none. + calls: none. *********************************************************************/ -int do_protocol(queryctl, proto) -struct hostrec *queryctl; -struct method *proto; +static void reply_hack(buf, host) +/* hack local mail IDs -- code by Eric S. Raymond 20 Jun 1996 */ +char *buf; +const char *host; { - int ok, len; - int mboxfd; - char buf [POPBUFSIZE+1], host[HOSTLEN+1]; - int socket; - int first,number,count; - - tagnum = 0; - protocol = proto; - - /* open the output sink, locking it if it is a folder */ - if (queryctl->output == TO_FOLDER || queryctl->output == TO_STDOUT) { - if ((mboxfd = openuserfolder(queryctl)) < 0) - return(PS_IOERR); - } else if (queryctl->output == TO_SMTP) { - if ((mboxfd = Socket(queryctl->smtphost, SMTP_PORT)) < 0) - return(PS_SOCKET); + const char *from; + int state = 0; + char mycopy[POPBUFSIZE+1]; - /* eat the greeting message */ - if (SMTP_ok(mboxfd, NULL) != SM_OK) { - close(mboxfd); - mboxfd = 0; - return(PS_SMTP); - } - - /* make it look like mail is coming from the server */ - if (SMTP_helo(mboxfd,queryctl->servername) != SM_OK) { - close(mboxfd); - mboxfd = 0; - return(PS_SMTP); - } + if (strncmp("From: ", buf, 6) + && strncmp("To: ", buf, 4) + && strncmp("Reply-", buf, 6) + && strncmp("Cc: ", buf, 4) + && strncmp("Bcc: ", buf, 5)) { + return; } - /* open a socket to the mail server */ - if ((socket = Socket(queryctl->servername, - queryctl->port ? queryctl->port : protocol->port))<0) + strcpy(mycopy, buf); + for (from = mycopy; *from; from++) { - perror("do_protocol: socket"); - ok = PS_SOCKET; - goto closeUp; - } - - /* accept greeting message from mail server */ - ok = (protocol->parse_response)(buf, socket); - if (ok != 0) { - if (ok != PS_SOCKET) - gen_transact(socket, protocol->exit_cmd); - close(socket); - goto closeUp; - } + switch (state) + { + case 0: /* before header colon */ + if (*from == ':') + state = 1; + break; - /* try to get authorized to fetch mail */ - ok = (protocol->getauth)(socket, queryctl, buf); - if (ok == PS_ERROR) - ok = PS_AUTHFAIL; - if (ok != 0) - goto cleanUp; + case 1: /* we've seen the colon, we're looking for addresses */ + if (*from == '"') + state = 2; + else if (*from == '(') + state = 3; + else if (*from == '<' || isalnum(*from)) + state = 4; + break; - /* compute count and first */ - if ((*protocol->getrange)(socket, queryctl, &count, &first) != 0) - goto cleanUp; + case 2: /* we're in a quoted human name, copy and ignore */ + if (*from == '"') + state = 1; + break; - /* show them how many messages we'll be downloading */ - if (outlevel > O_SILENT && outlevel < O_VERBOSE) - if (count == 0) - fprintf(stderr, "No mail from %s\n", queryctl->servername); - else if (first > 1) - fprintf(stderr, - "%d message%s from %s, %d new messages.\n", - count, count > 1 ? "s" : "", - queryctl->servername, count - first + 1); - else - fprintf(stderr, - "%d %smessage%s from %s.\n", - count, ok ? "" : "new ", - count > 1 ? "s" : "", - queryctl->servername); + case 3: /* we're in a parenthesized human name, copy and ignore */ + if (*from == ')') + state = 1; + break; - if (count > 0) { - for (number = queryctl->flush ? 1 : first; number<=count; number++) { + case 4: /* the real work gets done here */ + /* + * We're in something that might be an address part, + * either a bare unquoted/unparenthesized text or text + * enclosed in <> as per RFC822. + */ + /* if the address part contains an @, don't mess with it */ + if (*from == '@') + state = 5; - char *cp; + /* If the address token is not properly terminated, ignore it. */ + else if (*from == ' ' || *from == '\t') + state = 1; - /* open the mail pipe if we're using an MDA */ - if (queryctl->output == TO_MDA - && (queryctl->fetchall || number >= first)) { - ok = (mboxfd = openmailpipe(queryctl)) < 0 ? -1 : 0; - if (ok != 0) - goto cleanUp; - } - - if (queryctl->flush && number < first && !queryctl->fetchall) - ok = 0; /* no command to send here, will delete message below */ - else + /* + * On proper termination with no @, insert hostname. + * Case '>' catches <>-enclosed mail IDs. Case ',' catches + * comma-separated bare IDs. Cases \r and \n catch the case + * of a single ID alone on the line. + */ + else if (strchr(">,\r\n", *from)) { - (*protocol->fetch)(socket, number, linelimit, &len); - if (outlevel == O_VERBOSE) - if (protocol->delimited) - fprintf(stderr,"fetching message %d (delimited)\n",number); - else - fprintf(stderr,"fetching message %d (%d bytes)\n",number,len); - ok = gen_readmsg(socket,mboxfd,len,protocol->delimited, - queryctl->localname, - queryctl->servername, - queryctl->output, - !queryctl->norewrite); - if (protocol->trail) - (*protocol->trail)(socket, queryctl, number); - if (ok != 0) - goto cleanUp; + strcpy(buf, "@"); + strcat(buf, host); + buf += strlen(buf); + state = 1; } - /* maybe we delete this message now? */ - if (protocol->delete_cmd) - { - if ((number < first && queryctl->flush) || !queryctl->keep) { - if (outlevel > O_SILENT && outlevel < O_VERBOSE) - fprintf(stderr,"flushing message %d\n", number); - else - ; - ok = gen_transact(socket, protocol->delete_cmd, number); - if (ok != 0) - goto cleanUp; - } - } + /* everything else, including alphanumerics, just passes through */ + break; - /* close the mail pipe, we'll reopen before next message */ - if (queryctl->output == TO_MDA - && (queryctl->fetchall || number >= first)) { - ok = closemailpipe(mboxfd); - if (ok != 0) - goto cleanUp; - } + case 5: /* we're in a remote mail ID, no need to append hostname */ + if (*from == '>' || *from == ',' || isspace(*from)) + state = 1; + break; } - /* remove all messages flagged for deletion */ - if (!queryctl->keep && protocol->expunge_cmd) - { - ok = gen_transact(socket, protocol->expunge_cmd); - if (ok != 0) - goto cleanUp; - } - - ok = gen_transact(socket, protocol->exit_cmd); - if (ok == 0) - ok = PS_SUCCESS; - close(socket); - goto closeUp; - } - else { - ok = gen_transact(socket, protocol->exit_cmd); - if (ok == 0) - ok = PS_NOMAIL; - close(socket); - goto closeUp; - } - -cleanUp: - if (ok != 0 && ok != PS_SOCKET) - gen_transact(socket, protocol->exit_cmd); - -closeUp: - if (queryctl->output == TO_FOLDER) - { - if (closeuserfolder(mboxfd) < 0 && ok == 0) - ok = PS_IOERR; - } - else if (queryctl->output == TO_SMTP && mboxfd > 0) { - SMTP_quit(mboxfd); - close(mboxfd); + /* all characters from the old buffer get copied to the new one */ + *buf++ = *from; } - - if (ok == PS_IOERR || ok == PS_SOCKET) - perror("do_protocol: cleanUp"); - - return(ok); -} - -/********************************************************************* - function: gen_send - description: Assemble command in print style and send to the server - - arguments: - socket socket to which the server is connected. - fmt printf-style format - - return value: none. - calls: SockPuts. - globals: reads outlevel. - *********************************************************************/ - -void gen_send(socket, fmt, va_alist) -int socket; -const char *fmt; -va_dcl { - - char buf [POPBUFSIZE+1]; - va_list ap; - - if (protocol->tagged) - (void) sprintf(buf, "%s ", GENSYM); - else - buf[0] = '\0'; - - va_start(ap); - vsprintf(buf + strlen(buf), fmt, ap); - va_end(ap); - - SockPuts(socket, buf); - - if (outlevel == O_VERBOSE) - fprintf(stderr,"> %s\n", buf); -} - -/********************************************************************* - function: gen_transact - description: Assemble command in print style and send to the server. - then accept a protocol-dependent response. - - arguments: - socket socket to which the server is connected. - fmt printf-style format - - return value: none. - calls: SockPuts, imap_ok. - globals: reads outlevel. - *********************************************************************/ - -int gen_transact(socket, fmt, va_alist) -int socket; -const char *fmt; -va_dcl { - - int ok; - char buf [POPBUFSIZE+1]; - va_list ap; - - if (protocol->tagged) - (void) sprintf(buf, "%s ", GENSYM); - else - buf[0] = '\0'; - - va_start(ap); - vsprintf(buf + strlen(buf), fmt, ap); - va_end(ap); - - SockPuts(socket, buf); - - if (outlevel == O_VERBOSE) - fprintf(stderr,"> %s\n", buf); - - ok = (protocol->parse_response)(buf,socket); - if (ok != 0 && outlevel > O_SILENT && outlevel <= O_VERBOSE) - fprintf(stderr,"%s\n",buf); - - return(ok); -} - -/********************************************************************* - function: - description: hack message headers so replies will work properly - - arguments: - after where to put the hacked header - before header to hack - host name of the pop header - - return value: none. - calls: none. - *********************************************************************/ - -static void reply_hack(buf, host) -/* hack local mail IDs -- code by Eric S. Raymond 20 Jun 1996 */ -char *buf; -const char *host; -{ - const char *from; - int state = 0; - char mycopy[POPBUFSIZE+1]; - - if (strncmp("From: ", buf, 6) - && strncmp("To: ", buf, 4) - && strncmp("Reply-", buf, 6) - && strncmp("Cc: ", buf, 4) - && strncmp("Bcc: ", buf, 5)) { - return; - } - - strcpy(mycopy, buf); - for (from = mycopy; *from; from++) - { - switch (state) - { - case 0: /* before header colon */ - if (*from == ':') - state = 1; - break; - - case 1: /* we've seen the colon, we're looking for addresses */ - if (*from == '"') - state = 2; - else if (*from == '(') - state = 3; - else if (*from == '<' || isalnum(*from)) - state = 4; - break; - - case 2: /* we're in a quoted human name, copy and ignore */ - if (*from == '"') - state = 1; - break; - - case 3: /* we're in a parenthesized human name, copy and ignore */ - if (*from == ')') - state = 1; - break; - - case 4: /* the real work gets done here */ - /* - * We're in something that might be an address part, - * either a bare unquoted/unparenthesized text or text - * enclosed in <> as per RFC822. - */ - /* if the address part contains an @, don't mess with it */ - if (*from == '@') - state = 5; - - /* If the address token is not properly terminated, ignore it. */ - else if (*from == ' ' || *from == '\t') - state = 1; - - /* - * On proper termination with no @, insert hostname. - * Case '>' catches <>-enclosed mail IDs. Case ',' catches - * comma-separated bare IDs. Cases \r and \n catch the case - * of a single ID alone on the line. - */ - else if (strchr(">,\r\n", *from)) - { - strcpy(buf, "@"); - strcat(buf, host); - buf += strlen(buf); - state = 1; - } - - /* everything else, including alphanumerics, just passes through */ - break; - - case 5: /* we're in a remote mail ID, no need to append hostname */ - if (*from == '>' || *from == ',' || isspace(*from)) - state = 1; - break; - } - - /* all characters from the old buffer get copied to the new one */ - *buf++ = *from; - } - *buf++ = '\0'; + *buf++ = '\0'; } /********************************************************************* @@ -800,3 +518,281 @@ int rewrite; ; return(0); } + +/********************************************************************* + function: do_protocol + description: retrieve messages from the specified mail server + using a given set of methods + + arguments: + queryctl fully-specified options (i.e. parsed, defaults invoked, + etc). + proto protocol method pointer + + return value: exit code from the set of PS_.* constants defined in + fetchmail.h + calls: + globals: reads outlevel. + *********************************************************************/ + +int do_protocol(queryctl, proto) +struct hostrec *queryctl; +struct method *proto; +{ + int ok, len; + int mboxfd; + char buf [POPBUFSIZE+1], host[HOSTLEN+1]; + int socket; + int first,number,count; + + tagnum = 0; + protocol = proto; + + /* open the output sink, locking it if it is a folder */ + if (queryctl->output == TO_FOLDER || queryctl->output == TO_STDOUT) { + if ((mboxfd = openuserfolder(queryctl)) < 0) + return(PS_IOERR); + } else if (queryctl->output == TO_SMTP) { + if ((mboxfd = Socket(queryctl->smtphost, SMTP_PORT)) < 0) + return(PS_SOCKET); + + /* eat the greeting message */ + if (SMTP_ok(mboxfd, NULL) != SM_OK) { + close(mboxfd); + mboxfd = 0; + return(PS_SMTP); + } + + /* make it look like mail is coming from the server */ + if (SMTP_helo(mboxfd,queryctl->servername) != SM_OK) { + close(mboxfd); + mboxfd = 0; + return(PS_SMTP); + } + } + + /* open a socket to the mail server */ + if ((socket = Socket(queryctl->servername, + queryctl->port ? queryctl->port : protocol->port))<0) + { + perror("do_protocol: socket"); + ok = PS_SOCKET; + goto closeUp; + } + + /* accept greeting message from mail server */ + ok = (protocol->parse_response)(buf, socket); + if (ok != 0) { + if (ok != PS_SOCKET) + gen_transact(socket, protocol->exit_cmd); + close(socket); + goto closeUp; + } + + /* try to get authorized to fetch mail */ + ok = (protocol->getauth)(socket, queryctl, buf); + if (ok == PS_ERROR) + ok = PS_AUTHFAIL; + if (ok != 0) + goto cleanUp; + + /* compute count and first */ + if ((*protocol->getrange)(socket, queryctl, &count, &first) != 0) + goto cleanUp; + + /* show them how many messages we'll be downloading */ + if (outlevel > O_SILENT && outlevel < O_VERBOSE) + if (count == 0) + fprintf(stderr, "No mail from %s\n", queryctl->servername); + else if (first > 1) + fprintf(stderr, + "%d message%s from %s, %d new messages.\n", + count, count > 1 ? "s" : "", + queryctl->servername, count - first + 1); + else + fprintf(stderr, + "%d %smessage%s from %s.\n", + count, ok ? "" : "new ", + count > 1 ? "s" : "", + queryctl->servername); + + if (count > 0) { + for (number = queryctl->flush ? 1 : first; number<=count; number++) { + + char *cp; + + /* open the mail pipe if we're using an MDA */ + if (queryctl->output == TO_MDA + && (queryctl->fetchall || number >= first)) { + ok = (mboxfd = openmailpipe(queryctl)) < 0 ? -1 : 0; + if (ok != 0) + goto cleanUp; + } + + if (queryctl->flush && number < first && !queryctl->fetchall) + ok = 0; /* no command to send here, will delete message below */ + else + { + (*protocol->fetch)(socket, number, linelimit, &len); + if (outlevel == O_VERBOSE) + if (protocol->delimited) + fprintf(stderr,"fetching message %d (delimited)\n",number); + else + fprintf(stderr,"fetching message %d (%d bytes)\n",number,len); + ok = gen_readmsg(socket,mboxfd,len,protocol->delimited, + queryctl->localname, + queryctl->servername, + queryctl->output, + !queryctl->norewrite); + if (protocol->trail) + (*protocol->trail)(socket, queryctl, number); + if (ok != 0) + goto cleanUp; + } + + /* maybe we delete this message now? */ + if (protocol->delete_cmd) + { + if ((number < first && queryctl->flush) || !queryctl->keep) { + if (outlevel > O_SILENT && outlevel < O_VERBOSE) + fprintf(stderr,"flushing message %d\n", number); + else + ; + ok = gen_transact(socket, protocol->delete_cmd, number); + if (ok != 0) + goto cleanUp; + } + } + + /* close the mail pipe, we'll reopen before next message */ + if (queryctl->output == TO_MDA + && (queryctl->fetchall || number >= first)) { + ok = closemailpipe(mboxfd); + if (ok != 0) + goto cleanUp; + } + } + + /* remove all messages flagged for deletion */ + if (!queryctl->keep && protocol->expunge_cmd) + { + ok = gen_transact(socket, protocol->expunge_cmd); + if (ok != 0) + goto cleanUp; + } + + ok = gen_transact(socket, protocol->exit_cmd); + if (ok == 0) + ok = PS_SUCCESS; + close(socket); + goto closeUp; + } + else { + ok = gen_transact(socket, protocol->exit_cmd); + if (ok == 0) + ok = PS_NOMAIL; + close(socket); + goto closeUp; + } + +cleanUp: + if (ok != 0 && ok != PS_SOCKET) + gen_transact(socket, protocol->exit_cmd); + +closeUp: + if (queryctl->output == TO_FOLDER) + { + if (closeuserfolder(mboxfd) < 0 && ok == 0) + ok = PS_IOERR; + } + else if (queryctl->output == TO_SMTP && mboxfd > 0) { + SMTP_quit(mboxfd); + close(mboxfd); + } + + if (ok == PS_IOERR || ok == PS_SOCKET) + perror("do_protocol: cleanUp"); + + return(ok); +} + +/********************************************************************* + function: gen_send + description: Assemble command in print style and send to the server + + arguments: + socket socket to which the server is connected. + fmt printf-style format + + return value: none. + calls: SockPuts. + globals: reads outlevel. + *********************************************************************/ + +void gen_send(socket, fmt, va_alist) +int socket; +const char *fmt; +va_dcl { + + char buf [POPBUFSIZE+1]; + va_list ap; + + if (protocol->tagged) + (void) sprintf(buf, "%s ", GENSYM); + else + buf[0] = '\0'; + + va_start(ap); + vsprintf(buf + strlen(buf), fmt, ap); + va_end(ap); + + SockPuts(socket, buf); + + if (outlevel == O_VERBOSE) + fprintf(stderr,"> %s\n", buf); +} + +/********************************************************************* + function: gen_transact + description: Assemble command in print style and send to the server. + then accept a protocol-dependent response. + + arguments: + socket socket to which the server is connected. + fmt printf-style format + + return value: none. + calls: SockPuts, imap_ok. + globals: reads outlevel. + *********************************************************************/ + +int gen_transact(socket, fmt, va_alist) +int socket; +const char *fmt; +va_dcl { + + int ok; + char buf [POPBUFSIZE+1]; + va_list ap; + + if (protocol->tagged) + (void) sprintf(buf, "%s ", GENSYM); + else + buf[0] = '\0'; + + va_start(ap); + vsprintf(buf + strlen(buf), fmt, ap); + va_end(ap); + + SockPuts(socket, buf); + + if (outlevel == O_VERBOSE) + fprintf(stderr,"> %s\n", buf); + + ok = (protocol->parse_response)(buf,socket); + if (ok != 0 && outlevel > O_SILENT && outlevel <= O_VERBOSE) + fprintf(stderr,"%s\n",buf); + + return(ok); +} + -- cgit v1.2.3