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