]> Pileus Git - ~andy/fetchmail/commitdiff
Initial revision
authorEric S. Raymond <esr@thyrsus.com>
Wed, 7 Feb 2001 08:01:54 +0000 (08:01 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Wed, 7 Feb 2001 08:01:54 +0000 (08:01 -0000)
svn path=/trunk/; revision=3029

odmr.c [new file with mode: 0644]

diff --git a/odmr.c b/odmr.c
new file mode 100644 (file)
index 0000000..d0623c0
--- /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 */