]> Pileus Git - ~andy/fetchmail/blob - etrn.c
5ccc0f86412964b4a809269488c71c7404e5210c
[~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.names->id, &opts)))
41     {
42         error(0, 0, "%s's SMTP listener does not support ESMTP",
43               ctl->server.names->id);
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.names->id);
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(5, errno, "gethostname");
88             }
89             /* in case we got a host basename (as we do in Linux),
90                make a FQDN of it                                */
91             hp = gethostbyname(hname);
92             if (hp == (struct hostent *) NULL)
93             {
94                 /* exit with error message */
95                 error(5, h_errno, "gethostbyname");
96             }
97             /* here it is */
98             qname = hp->h_name;
99         }
100
101
102         /* ship the actual poll and get the response */
103         gen_send(sock, "ETRN %s", qname);
104         if ((ok = gen_recv(sock, buf, sizeof(buf))))
105             return(ok);
106
107         /* this switch includes all the response codes described in RFC1985 */
108         switch(atoi(buf))
109         {
110         case 250:       /* OK, queuing for node <x> started */
111             error(0, 0, "Queuing for %s started", qname);
112             break;
113
114         case 251:       /* OK, no messages waiting for node <x> */
115             error(0, 0, "No messages waiting for %s", qname);
116             return(PS_NOMAIL);
117
118         case 252:       /* OK, pending messages for node <x> started */
119         case 253:       /* OK, <n> pending messages for node <x> started */
120             error(0, 0, "Pending messages for %s started", qname);
121             break;
122
123         case 458:       /* Unable to queue messages for node <x> */
124             error(0, -1, "Unable to queue messages for node %s", qname);
125             return(PS_PROTOCOL);
126
127         case 459:       /* Node <x> not allowed: <reason> */
128             error(0, -1, "Node %s not allowed: %s", qname, buf);
129             return(PS_AUTHFAIL);
130
131         case 500:       /* Syntax Error */
132             error(0, -1, "ETRN syntax error");
133             return(PS_PROTOCOL);
134
135         case 501:       /* Syntax Error in Parameters */
136             error(0, -1, "ETRN syntax error in parameters");
137             return(PS_PROTOCOL);
138
139         default:
140             error(0, -1, "Unknown ETRN error %d", atoi(buf));
141             return(PS_PROTOCOL);
142         }
143     }
144
145     return(0);
146 }
147
148 const static struct method etrn =
149 {
150     "ETRN",             /* ESMTP ETRN extension */
151     25,                 /* standard SMTP port */
152     FALSE,              /* this is not a tagged protocol */
153     FALSE,              /* this does not use a message delimiter */
154     FALSE,              /* no getsizes method */
155     etrn_ok,            /* parse command response */
156     NULL,               /* no need to get authentication */
157     etrn_getrange,      /* initialize message sending */
158     NULL,               /* we cannot get a list of sizes */
159     NULL,               /* how do we tell a message is old? */
160     NULL,               /* no way to fetch headers */
161     NULL,               /* no way to fetch body */
162     NULL,               /* no message trailer */
163     NULL,               /* how to delete a message */
164     "QUIT",             /* the ETRN exit command */
165 };
166
167 int doETRN (struct query *ctl)
168 /* retrieve messages using ETRN */
169 {
170     if (ctl->keep) {
171         fprintf(stderr, "Option --keep is not supported with ETRN\n");
172         return(PS_SYNTAX);
173     }
174     if (ctl->flush) {
175         fprintf(stderr, "Option --flush is not supported with ETRN\n");
176         return(PS_SYNTAX);
177     }
178     if (ctl->mailboxes->id) {
179         fprintf(stderr, "Option --remote is not supported with ETRN\n");
180         return(PS_SYNTAX);
181     }
182     if (check_only) {
183         fprintf(stderr, "Option --check is not supported with ETRN\n");
184         return(PS_SYNTAX);
185     }
186     peek_capable = FALSE;
187     return(do_protocol(ctl, &etrn));
188 }
189
190 /* etrn.c ends here */