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