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