]> Pileus Git - ~andy/fetchmail/blob - etrn.c
c0f6fea1d56d86bc449d4d33d9083f9c8798246c
[~andy/fetchmail] / etrn.c
1 /*
2  * etrn.c -- ETRN protocol methods
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6
7 #include  "config.h"
8 #include  <stdio.h>
9 #include  <stdlib.h>
10 #include  <assert.h>
11 #include  <netdb.h>
12 #include  <errno.h>
13 #include  "fetchmail.h"
14 #include  "smtp.h"
15 #include  "socket.h"
16
17 static int etrn_ok (int sock, char *argbuf)
18 /* parse command response */
19 {
20     int ok;
21
22     ok = SMTP_ok(sock);
23     if (ok == SM_UNRECOVERABLE)
24         return(PS_PROTOCOL);
25     else
26         return(ok);
27 }
28
29 static int etrn_getrange(int sock, struct query *ctl, char *id, int *countp,
30                                                                     int *newp)
31 /* send ETRN and interpret the response */
32 {
33     int ok, opts, qdone = 0;
34     char buf [POPBUFSIZE+1],
35          hname[256];
36     const char *qname;
37     struct idlist *qnp;         /* pointer to Q names */
38     struct hostent *hp;
39
40     if ((ok = SMTP_ehlo(sock, ctl->server.truename, &opts)))
41     {
42         error(0, 0, "%s's SMTP listener does not support ESMTP",
43               ctl->server.pollname);
44         return(ok);
45     }
46     else if (!(opts & ESMTP_ETRN))
47     {
48         error(0, 0, "%s's SMTP listener does not support ETRN",
49               ctl->server.pollname);
50         return(PS_PROTOCOL);
51     }
52
53     *countp = *newp = -1;       /* make sure we don't enter the fetch loop */
54
55     /*** This is a sort of horrible HACK because the ETRN protocol
56      *** does not fit very well into the mailbox concept used in
57      *** this program (IMHO).  The last element of ctl->smtphunt
58      *** turned out to be the host being queried (i.e., the smtp server).
59      *** for that reason the rather "funny" condition in the for loop.
60      *** Isn't it sort of unreasonable to add the server to the ETRN
61      *** hunt list? (Concerning ETRN I'm sure! In case I want a Q-run of
62      *** my SMTP-server I can always specify -Smyserver, and this is only
63      *** resonable if I start sendmail without -qtime and in Q-only mode.)
64      *** 
65      *** -- 1997-06-22 Guenther Leber
66      ***/
67     /* do it for all queues in the smtphunt list except the last one
68        which is the SMTP-server itself */
69     for (qnp = ctl->smtphunt; ( (qnp != (struct idlist *) NULL) && 
70                 (qnp->next != (struct idlist *) NULL) ) || (qdone == 0);
71                 qnp = qnp->next, qdone++)
72     {
73
74         /* extract name of Q */
75         if ( (qnp != (struct idlist *) NULL) &&
76                                 (qnp->next != (struct idlist *) NULL) )
77         {
78             /* take Q-name given in smtp hunt list */
79             qname = qnp->id;
80         } else {
81             assert(qdone == 0);
82             /*** use fully qualified host name as Q name ***/
83             /* get hostname */
84             if (gethostname(hname, sizeof hname) != 0)
85             {
86                 /* exit with error message */
87                 error(0, errno, "gethostname failed: ");
88                 return PS_UNDEFINED;
89             }
90             /* in case we got a host basename (as we do in Linux),
91                make a FQDN of it                                */
92             hp = gethostbyname(hname);
93             if (hp == (struct hostent *) NULL)
94             {
95                 /* exit with error message */
96                 error(0, 0, "gethostbyname failed for %s", hname);
97                 return PS_TRANSIENT;
98             }
99             /* here it is */
100             qname = hp->h_name;
101         }
102
103
104         /* ship the actual poll and get the response */
105         gen_send(sock, "ETRN %s", qname);
106         if ((ok = gen_recv(sock, buf, sizeof(buf))))
107             return(ok);
108
109         /* this switch includes all the response codes described in RFC1985 */
110         switch(atoi(buf))
111         {
112         case 250:       /* OK, queuing for node <x> started */
113             error(0, 0, "Queuing for %s started", qname);
114             break;
115
116         case 251:       /* OK, no messages waiting for node <x> */
117             error(0, 0, "No messages waiting for %s", qname);
118             return(PS_NOMAIL);
119
120         case 252:       /* OK, pending messages for node <x> started */
121         case 253:       /* OK, <n> pending messages for node <x> started */
122             error(0, 0, "Pending messages for %s started", qname);
123             break;
124
125         case 458:       /* Unable to queue messages for node <x> */
126             error(0, -1, "Unable to queue messages for node %s", qname);
127             return(PS_PROTOCOL);
128
129         case 459:       /* Node <x> not allowed: <reason> */
130             error(0, -1, "Node %s not allowed: %s", qname, buf);
131             return(PS_AUTHFAIL);
132
133         case 500:       /* Syntax Error */
134             error(0, -1, "ETRN syntax error");
135             return(PS_PROTOCOL);
136
137         case 501:       /* Syntax Error in Parameters */
138             error(0, -1, "ETRN syntax error in parameters");
139             return(PS_PROTOCOL);
140
141         default:
142             error(0, -1, "Unknown ETRN error %d", atoi(buf));
143             return(PS_PROTOCOL);
144         }
145     }
146
147     return(0);
148 }
149
150 const static struct method etrn =
151 {
152     "ETRN",             /* ESMTP ETRN extension */
153     25,                 /* standard SMTP port */
154     FALSE,              /* this is not a tagged protocol */
155     FALSE,              /* this does not use a message delimiter */
156     FALSE,              /* no getsizes method */
157     etrn_ok,            /* parse command response */
158     NULL,               /* no need to get authentication */
159     etrn_getrange,      /* initialize message sending */
160     NULL,               /* we cannot get a list of sizes */
161     NULL,               /* how do we tell a message is old? */
162     NULL,               /* no way to fetch headers */
163     NULL,               /* no way to fetch body */
164     NULL,               /* no message trailer */
165     NULL,               /* how to delete a message */
166     "QUIT",             /* the ETRN exit command */
167 };
168
169 int doETRN (struct query *ctl)
170 /* retrieve messages using ETRN */
171 {
172     if (ctl->keep) {
173         fprintf(stderr, "Option --keep is not supported with ETRN\n");
174         return(PS_SYNTAX);
175     }
176     if (ctl->flush) {
177         fprintf(stderr, "Option --flush is not supported with ETRN\n");
178         return(PS_SYNTAX);
179     }
180     if (ctl->mailboxes->id) {
181         fprintf(stderr, "Option --remote is not supported with ETRN\n");
182         return(PS_SYNTAX);
183     }
184     if (check_only) {
185         fprintf(stderr, "Option --check is not supported with ETRN\n");
186         return(PS_SYNTAX);
187     }
188     peek_capable = FALSE;
189     return(do_protocol(ctl, &etrn));
190 }
191
192 /* etrn.c ends here */