aboutsummaryrefslogtreecommitdiffstats
path: root/odmr.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2001-02-07 08:01:54 +0000
committerEric S. Raymond <esr@thyrsus.com>2001-02-07 08:01:54 +0000
commit8a111f01e0f0b650a48529f743b67cc9c84e1bbc (patch)
tree482c54f9ee0993e492bd28d455c1de1dc25a3c12 /odmr.c
parent19580930369179181789233ab2f311530d65edf1 (diff)
downloadfetchmail-8a111f01e0f0b650a48529f743b67cc9c84e1bbc.tar.gz
fetchmail-8a111f01e0f0b650a48529f743b67cc9c84e1bbc.tar.bz2
fetchmail-8a111f01e0f0b650a48529f743b67cc9c84e1bbc.zip
Initial revision
svn path=/trunk/; revision=3029
Diffstat (limited to 'odmr.c')
-rw-r--r--odmr.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/odmr.c b/odmr.c
new file mode 100644
index 00000000..d0623c0f
--- /dev/null
+++ b/odmr.c
@@ -0,0 +1,222 @@
+/*
+ * odmr.c -- ODMR protocol methods (see RFC 2645)
+ *
+ * For license terms, see the file COPYING in this directory.
+ */
+
+#include "config.h"
+#ifdef ODMR_ENABLE
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#ifdef HAVE_NET_SOCKET_H /* BeOS needs this */
+#include <net/socket.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <errno.h>
+#include <unistd.h>
+#include "i18n.h"
+#include "fetchmail.h"
+#include "smtp.h"
+#include "socket.h"
+
+static int odmr_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 odmr_getrange(int sock, struct query *ctl, const char *id,
+ int *countp, int *newp, int *bytes)
+/* send ODMR and then run a reverse SMTP session */
+{
+ int ok, opts, smtp_sock;
+ char buf [MSGBUFSIZE+1];
+ struct idlist *qnp; /* pointer to Q names */
+
+ if ((ok = SMTP_ehlo(sock, fetchmailhost, &opts)))
+ {
+ report(stderr, _("%s's SMTP listener does not support ESMTP\n"),
+ ctl->server.pollname);
+ return(ok);
+ }
+ else if (!(opts & ESMTP_ATRN))
+ {
+ report(stderr, _("%s's SMTP listener does not support ATRN\n"),
+ ctl->server.pollname);
+ return(PS_PROTOCOL);
+ }
+
+ /* make sure we don't enter the fetch loop */
+ *bytes = *countp = *newp = -1;
+
+ /* authenticate via CRAM-MD5 */
+ ok = do_cram_md5(sock, ctl);
+ if (ok)
+ return(ok);
+
+ /*
+ * By default, the hostlist has a single entry, the fetchmail host's
+ * canonical DNS name.
+ */
+ buf[0] = '\0';
+ for (qnp = ctl->smtphunt; qnp; qnp = qnp->next)
+ if (strlen(buf) + strlen(qnp->id) + 1 >= sizeof(buf))
+ break;
+ else
+ {
+ strcat(buf, qnp->id);
+ strcat(buf, ",");
+ }
+ buf[strlen(buf) - 1] = '\0'; /* nuke final comma */
+
+ /* ship the domain list and get turnaround */
+ gen_send(sock, "ATRN %s", buf);
+ if ((ok = gen_recv(sock, buf, sizeof(buf))))
+ return(ok);
+
+ /* this switch includes all response codes described in RFC2645 */
+ switch(atoi(buf))
+ {
+ case 250: /* OK, turnaround is about to happe */
+ if (outlevel >= O_SILENT)
+ report(stdout, _("Turnaround now...\n"));
+ break;
+
+ case 450: /* ATRN request refused */
+ if (outlevel >= O_SILENT)
+ report(stdout, _("ATRN request refused.\n"));
+ return(PS_PROTOCOL);
+
+ case 451: /* Unable to process ATRN request now */
+ report(stderr, _("Unable to process ATRN request now\n"));
+ return(PS_EXCLUDE);
+
+ case 453: /* You have no mail */
+ report(stderr, _("You have no mail.\n"));
+ return(PS_NOMAIL);
+
+ case 502: /* Command not implemented */
+ report(stderr, _("Command not implemented\n"));
+ return(PS_PROTOCOL);
+
+ case 530: /* Authentication required */
+ report(stderr, _("Authentication required.\n"));
+ return(PS_AUTHFAIL);
+
+ default:
+ report(stderr, _("Unknown ODMR error %d\n"), atoi(buf));
+ return(PS_PROTOCOL);
+ }
+
+ /*
+ * OK, if we got here it's time to become a pipe between the ODMR
+ * remote server (sending) and the local SMTP daemon (receiving).
+ * We're npt going to try to be a protocol machine; instead, we'll
+ * use select(2) to watch the read sides of both sockets and just
+ * throw their data at each other.
+ */
+ smtp_sock = SockOpen(ctl->smtphost, SMTP_PORT, NULL, NULL);
+ if (smtp_sock)
+ return(PS_SOCKET);
+ else
+ {
+ int maxfd = (sock > smtp_sock) ? sock : smtp_sock;
+
+ for (;;)
+ {
+ fd_set readfds;
+ struct timeval timeout;
+ char buf[MSGBUFSIZE];
+
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+ FD_SET(smtp_sock, &readfds);
+
+ timeout.tv_sec = ctl->server.timeout;
+ timeout.tv_usec = 0;
+
+ if (select(maxfd+1, &readfds, NULL, NULL, &timeout) == -1)
+ return(PS_PROTOCOL); /* timeout */
+
+ if (FD_ISSET(sock, &readfds))
+ {
+ int n = SockRead(sock, buf, sizeof(buf));
+ SockWrite(smtp_sock, buf, n);
+ }
+ if (FD_ISSET(smtp_sock, &readfds))
+ {
+ int n = SockRead(smtp_sock, buf, sizeof(buf));
+ SockWrite(sock, buf, n);
+ }
+ }
+ }
+
+ return(0);
+}
+
+const static struct method odmr =
+{
+ "ODMR", /* ODMR protocol */
+#if INET6_ENABLE
+ "odmr", /* standard SMTP port */
+ "odmrs", /* ssl SMTP port */
+#else /* INET6_ENABLE */
+ 366, /* standard SMTP port */
+ 2366, /* ssl SMTP port (BOGUS! RANDOM VALUE) */
+#endif /* INET6_ENABLE */
+ FALSE, /* this is not a tagged protocol */
+ FALSE, /* this does not use a message delimiter */
+ odmr_ok, /* parse command response */
+ NULL, /* no password canonicalization */
+ NULL, /* no need to get authentication */
+ odmr_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, /* log out, we're done */
+ FALSE, /* no, we can't re-poll */
+};
+
+int doODMR (struct query *ctl)
+/* retrieve messages using ODMR */
+{
+ int status;
+
+ if (ctl->keep) {
+ fprintf(stderr, _("Option --keep is not supported with ODMR\n"));
+ return(PS_SYNTAX);
+ }
+ if (ctl->flush) {
+ fprintf(stderr, _("Option --flush is not supported with ODMR\n"));
+ return(PS_SYNTAX);
+ }
+ if (ctl->mailboxes->id) {
+ fprintf(stderr, _("Option --remote is not supported with ODMR\n"));
+ return(PS_SYNTAX);
+ }
+ if (check_only) {
+ fprintf(stderr, _("Option --check is not supported with ODMR\n"));
+ return(PS_SYNTAX);
+ }
+ peek_capable = FALSE;
+
+ status = do_protocol(ctl, &odmr);
+ if (status == PS_NOMAIL)
+ status = PS_SUCCESS;
+ return(status);
+}
+#endif /* ODMR_ENABLE */
+
+/* odmr.c ends here */