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