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