]> Pileus Git - ~andy/fetchmail/blob - odmr.c
e97a755e1d8167db8d493d06137751bcd1937f1a
[~andy/fetchmail] / odmr.c
1 /*
2  * odmr.c -- ODMR protocol methods (see RFC 2645)
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6
7 #include  "config.h"
8 #ifdef ODMR_ENABLE
9 #include  <stdio.h>
10 #include  <stdlib.h>
11 #include  <assert.h>
12 #ifdef HAVE_STRING_H /* strcat() */
13 #include <string.h>
14 #endif
15 #ifdef HAVE_NET_SOCKET_H /* BeOS needs this */
16 #include <net/socket.h>
17 #endif
18 #include  <sys/types.h>
19 #include  <sys/time.h>
20 #ifdef HAVE_NET_SELECT_H /* AIX needs this */
21 #include <net/select.h>
22 #endif
23 #include  <netdb.h>
24 #include  <errno.h>
25 #include  <unistd.h>
26 #include  "i18n.h"
27 #include  "fetchmail.h"
28 #include  "smtp.h"
29 #include  "socket.h"
30
31 static int odmr_ok (int sock, char *argbuf)
32 /* parse command response */
33 {
34     int ok;
35
36     ok = SMTP_ok(sock);
37     if (ok == SM_UNRECOVERABLE)
38         return(PS_PROTOCOL);
39     else
40         return(ok);
41 }
42
43 static int odmr_getrange(int sock, struct query *ctl, const char *id, 
44                          int *countp, int *newp, int *bytes)
45 /* send ODMR and then run a reverse SMTP session */
46 {
47     int ok, opts, smtp_sock;
48     char buf [MSGBUFSIZE+1];
49     struct idlist *qnp;         /* pointer to Q names */
50
51     if ((ok = SMTP_ehlo(sock, fetchmailhost, &opts)))
52     {
53         report(stderr, _("%s's SMTP listener does not support ESMTP\n"),
54               ctl->server.pollname);
55         return(ok);
56     }
57     else if (!(opts & ESMTP_ATRN))
58     {
59         report(stderr, _("%s's SMTP listener does not support ATRN\n"),
60               ctl->server.pollname);
61         return(PS_PROTOCOL);
62     }
63
64     /* make sure we don't enter the fetch loop */
65     *bytes = *countp = *newp = -1;
66
67     /* authenticate via CRAM-MD5 */
68     ok = do_cram_md5(sock, "AUTH", ctl, "334 ");
69     if (ok)
70         return(ok);
71
72     /*
73      * By default, the hostlist has a single entry, the fetchmail host's
74      * canonical DNS name.
75      */
76     buf[0] = '\0';
77     for (qnp = ctl->smtphunt; qnp; qnp = qnp->next)
78         if (strlen(buf) + strlen(qnp->id) + 1 >= sizeof(buf))
79             break;
80         else
81         {
82             strcat(buf, qnp->id);
83             strcat(buf, ",");
84         }
85     buf[strlen(buf) - 1] = '\0';        /* nuke final comma */
86
87     /* ship the domain list and get turnaround */
88     gen_send(sock, "ATRN %s", buf);
89     if ((ok = gen_recv(sock, buf, sizeof(buf))))
90         return(ok);
91
92     /* this switch includes all response codes described in RFC2645 */
93     switch(atoi(buf))
94     {
95     case 250:   /* OK, turnaround is about to happe */
96         if (outlevel >= O_SILENT)
97             report(stdout, _("Turnaround now...\n"));
98         break;
99
100     case 450:   /* ATRN request refused */
101         if (outlevel >= O_SILENT)
102             report(stdout, _("ATRN request refused.\n"));
103         return(PS_PROTOCOL);
104
105     case 451:   /* Unable to process ATRN request now */
106         report(stderr, _("Unable to process ATRN request now\n"));
107         return(PS_EXCLUDE);
108
109     case 453:   /* You have no mail */
110         report(stderr, _("You have no mail.\n"));
111         return(PS_NOMAIL);
112
113     case 502:   /* Command not implemented */
114         report(stderr, _("Command not implemented\n"));
115         return(PS_PROTOCOL);
116
117     case 530:   /* Authentication required */
118         report(stderr, _("Authentication required.\n"));
119         return(PS_AUTHFAIL);
120
121     default:
122         report(stderr, _("Unknown ODMR error %d\n"), atoi(buf));
123         return(PS_PROTOCOL);
124     }
125
126     /*
127      * OK, if we got here it's time to become a pipe between the ODMR
128      * remote server (sending) and the local SMTP daemon (receiving).
129      * We're npt going to try to be a protocol machine; instead, we'll
130      * use select(2) to watch the read sides of both sockets and just
131      * throw their data at each other.
132      */
133     /*
134      * FIXME: we hardcode "localhost" here because ODMR is fighting
135      * over the ETRN meaning of smtphost and the POP/IMAP meaning.
136      * ODMR needs both meanings, but there is only one config var.  So
137      * for now ODMR always uses the "localhost" SMTP server to connect
138      * with locally.
139      */
140     smtp_sock = SockOpen("localhost", SMTP_PORT, NULL, NULL);
141     if (smtp_sock == -1)
142         return(PS_SOCKET);
143     else
144     {
145         int     maxfd = (sock > smtp_sock) ? sock : smtp_sock;
146
147         for (;;)
148         {
149             fd_set      readfds;
150             struct timeval timeout;
151             char        buf[MSGBUFSIZE];
152
153             FD_ZERO(&readfds);
154             FD_SET(sock, &readfds);
155             FD_SET(smtp_sock, &readfds);
156
157             timeout.tv_sec  = ctl->server.timeout;
158             timeout.tv_usec = 0;
159
160             if (select(maxfd+1, &readfds, NULL, NULL, &timeout) == -1)
161                 return(PS_PROTOCOL);            /* timeout */
162
163             if (FD_ISSET(sock, &readfds))
164             {
165                 int n = SockRead(sock, buf, sizeof(buf));
166                 if (n <= 0)
167                     break;
168
169                 SockWrite(smtp_sock, buf, n);
170                 if (outlevel >= O_MONITOR)
171                     report(stdout, "ODMR< %s\n", buf);
172             }
173             if (FD_ISSET(smtp_sock, &readfds))
174             {
175                 int n = SockRead(smtp_sock, buf, sizeof(buf));
176                 if (n <= 0)
177                     break;
178
179                 SockWrite(sock, buf, n);
180                 if (outlevel >= O_MONITOR)
181                     report(stdout, "ODMR> %s\n", buf);
182             }
183         }
184         SockClose(smtp_sock);
185     }
186
187     return(0);
188 }
189
190 static int odmr_logout(int sock, struct query *ctl)
191 /* send logout command */
192 {
193     return(gen_transact(sock, "QUIT"));
194 }
195
196 const static struct method odmr =
197 {
198     "ODMR",             /* ODMR protocol */
199 #if INET6_ENABLE
200     "odmr",             /* standard SMTP port */
201     "odmrs",            /* ssl SMTP port */
202 #else /* INET6_ENABLE */
203     366,                /* standard SMTP port */
204     2366,               /* ssl SMTP port (BOGUS! RANDOM VALUE) */
205 #endif /* INET6_ENABLE */
206     FALSE,              /* this is not a tagged protocol */
207     FALSE,              /* this does not use a message delimiter */
208     odmr_ok,            /* parse command response */
209     NULL,               /* no need to get authentication */
210     odmr_getrange,      /* initialize message sending */
211     NULL,               /* we cannot get a list of sizes */
212     NULL,               /* how do we tell a message is old? */
213     NULL,               /* no way to fetch headers */
214     NULL,               /* no way to fetch body */
215     NULL,               /* no message trailer */
216     NULL,               /* how to delete a message */
217     odmr_logout,        /* log out, we're done */
218     FALSE,              /* no, we can't re-poll */
219 };
220
221 int doODMR (struct query *ctl)
222 /* retrieve messages using ODMR */
223 {
224     int status;
225
226     if (ctl->keep) {
227         fprintf(stderr, _("Option --keep is not supported with ODMR\n"));
228         return(PS_SYNTAX);
229     }
230     if (ctl->flush) {
231         fprintf(stderr, _("Option --flush is not supported with ODMR\n"));
232         return(PS_SYNTAX);
233     }
234     if (ctl->mailboxes->id) {
235         fprintf(stderr, _("Option --remote is not supported with ODMR\n"));
236         return(PS_SYNTAX);
237     }
238     if (check_only) {
239         fprintf(stderr, _("Option --check is not supported with ODMR\n"));
240         return(PS_SYNTAX);
241     }
242     peek_capable = FALSE;
243
244     status = do_protocol(ctl, &odmr);
245     if (status == PS_NOMAIL)
246         status = PS_SUCCESS;
247     return(status);
248 }
249 #endif /* ODMR_ENABLE */
250
251 /* odmr.c ends here */