/* * etrn.c -- ETRN protocol methods * * For license terms, see the file COPYING in this directory. */ #include "config.h" #include #include #include #include #include #include "fetchmail.h" #include "smtp.h" #include "socket.h" static int etrn_ok (int sock, char *argbuf) /* parse command response */ { int ok; ok = SMTP_ok(sock); if (ok == SM_UNRECOVERABLE) return(PS_PROTOCOL); else return(ok); } static int etrn_getrange(int sock, struct query *ctl, char *id, int *countp, int *newp) /* send ETRN and interpret the response */ { int ok, opts, qdone = 0; char buf [POPBUFSIZE+1], hname[256]; const char *qname; struct idlist *qnp; /* pointer to Q names */ struct hostent *hp; if ((ok = SMTP_ehlo(sock, ctl->server.truename, &opts))) { error(0, 0, "%s's SMTP listener does not support ESMTP", ctl->server.pollname); return(ok); } else if (!(opts & ESMTP_ETRN)) { error(0, 0, "%s's SMTP listener does not support ETRN", ctl->server.pollname); return(PS_PROTOCOL); } *countp = *newp = -1; /* make sure we don't enter the fetch loop */ /*** This is a sort of horrible HACK because the ETRN protocol *** does not fit very well into the mailbox concept used in *** this program (IMHO). The last element of ctl->smtphunt *** turned out to be the host being queried (i.e., the smtp server). *** for that reason the rather "funny" condition in the for loop. *** Isn't it sort of unreasonable to add the server to the ETRN *** hunt list? (Concerning ETRN I'm sure! In case I want a Q-run of *** my SMTP-server I can always specify -Smyserver, and this is only *** resonable if I start sendmail without -qtime and in Q-only mode.) *** *** -- 1997-06-22 Guenther Leber ***/ /* do it for all queues in the smtphunt list except the last one which is the SMTP-server itself */ for (qnp = ctl->smtphunt; ( (qnp != (struct idlist *) NULL) && (qnp->next != (struct idlist *) NULL) ) || (qdone == 0); qnp = qnp->next, qdone++) { /* extract name of Q */ if ( (qnp != (struct idlist *) NULL) && (qnp->next != (struct idlist *) NULL) ) { /* take Q-name given in smtp hunt list */ qname = qnp->id; } else { assert(qdone == 0); /*** use fully qualified host name as Q name ***/ /* get hostname */ if (gethostname(hname, sizeof hname) != 0) { /* exit with error message */ error(0, errno, "gethostname failed: "); return PS_UNDEFINED; } /* in case we got a host basename (as we do in Linux), make a FQDN of it */ hp = gethostbyname(hname); if (hp == (struct hostent *) NULL) { /* exit with error message */ error(0, 0, "gethostbyname failed for %s", hname); return PS_TRANSIENT; } /* here it is */ qname = hp->h_name; } /* ship the actual poll and get the response */ gen_send(sock, "ETRN %s", qname); if ((ok = gen_recv(sock, buf, sizeof(buf)))) return(ok); /* this switch includes all the response codes described in RFC1985 */ switch(atoi(buf)) { case 250: /* OK, queuing for node started */ error(0, 0, "Queuing for %s started", qname); break; case 251: /* OK, no messages waiting for node */ error(0, 0, "No messages waiting for %s", qname); return(PS_NOMAIL); case 252: /* OK, pending messages for node started */ case 253: /* OK, pending messages for node started */ error(0, 0, "Pending messages for %s started", qname); break; case 458: /* Unable to queue messages for node */ error(0, -1, "Unable to queue messages for node %s", qname); return(PS_PROTOCOL); case 459: /* Node not allowed: */ error(0, -1, "Node %s not allowed: %s", qname, buf); return(PS_AUTHFAIL); case 500: /* Syntax Error */ error(0, -1, "ETRN syntax error"); return(PS_PROTOCOL); case 501: /* Syntax Error in Parameters */ error(0, -1, "ETRN syntax error in parameters"); return(PS_PROTOCOL); default: error(0, -1, "Unknown ETRN error %d", atoi(buf)); return(PS_PROTOCOL); } } return(0); } const static struct method etrn = { "ETRN", /* ESMTP ETRN extension */ 25, /* standard SMTP port */ FALSE, /* this is not a tagged protocol */ FALSE, /* this does not use a message delimiter */ etrn_ok, /* parse command response */ NULL, /* no need to get authentication */ etrn_getrange, /* initialize message sending */ NULL, /* we cannot get a list of sizes */ NULL, /* how do we tell a message is old? */ NULL, /* no way to fetch headers */ NULL, /* no way to fetch body */ NULL, /* no message trailer */ NULL, /* how to delete a message */ NULL, /* no retained-header check */ "QUIT", /* the ETRN exit command */ }; int doETRN (struct query *ctl) /* retrieve messages using ETRN */ { int status; if (ctl->keep) { fprintf(stderr, "Option --keep is not supported with ETRN\n"); return(PS_SYNTAX); } if (ctl->flush) { fprintf(stderr, "Option --flush is not supported with ETRN\n"); return(PS_SYNTAX); } if (ctl->mailboxes->id) { fprintf(stderr, "Option --remote is not supported with ETRN\n"); return(PS_SYNTAX); } if (check_only) { fprintf(stderr, "Option --check is not supported with ETRN\n"); return(PS_SYNTAX); } peek_capable = FALSE; status = do_protocol(ctl, &etrn); if (status == PS_NOMAIL) status = PS_SUCCESS; return(status); } /* etrn.c ends here */