rev |
line source |
yuuji@0
|
1 /* ========================================================================
|
yuuji@0
|
2 * Copyright 1988-2008 University of Washington
|
yuuji@0
|
3 *
|
yuuji@0
|
4 * Licensed under the Apache License, Version 2.0 (the "License");
|
yuuji@0
|
5 * you may not use this file except in compliance with the License.
|
yuuji@0
|
6 * You may obtain a copy of the License at
|
yuuji@0
|
7 *
|
yuuji@0
|
8 * http://www.apache.org/licenses/LICENSE-2.0
|
yuuji@0
|
9 *
|
yuuji@0
|
10 *
|
yuuji@0
|
11 * ========================================================================
|
yuuji@0
|
12 */
|
yuuji@0
|
13
|
yuuji@0
|
14 /*
|
yuuji@0
|
15 * Program: IPOP3D - IMAP to POP3 conversion server
|
yuuji@0
|
16 *
|
yuuji@0
|
17 * Author: Mark Crispin
|
yuuji@0
|
18 * UW Technology
|
yuuji@0
|
19 * University of Washington
|
yuuji@0
|
20 * Seattle, WA 98195
|
yuuji@0
|
21 * Internet: MRC@Washington.EDU
|
yuuji@0
|
22 *
|
yuuji@0
|
23 * Date: 1 November 1990
|
yuuji@0
|
24 * Last Edited: 19 February 2008
|
yuuji@0
|
25 */
|
yuuji@0
|
26
|
yuuji@0
|
27 /* Parameter files */
|
yuuji@0
|
28
|
yuuji@0
|
29 #include <stdio.h>
|
yuuji@0
|
30 #include <ctype.h>
|
yuuji@0
|
31 #include <errno.h>
|
yuuji@0
|
32 extern int errno; /* just in case */
|
yuuji@0
|
33 #include <signal.h>
|
yuuji@0
|
34 #include <time.h>
|
yuuji@0
|
35 #include "c-client.h"
|
yuuji@0
|
36
|
yuuji@0
|
37
|
yuuji@0
|
38 #define CRLF PSOUT ("\015\012") /* primary output terpri */
|
yuuji@0
|
39
|
yuuji@0
|
40
|
yuuji@0
|
41 /* Autologout timer */
|
yuuji@0
|
42 #define KODTIMEOUT 60*5
|
yuuji@0
|
43 #define LOGINTIMEOUT 60*3
|
yuuji@0
|
44 #define TIMEOUT 60*10
|
yuuji@0
|
45
|
yuuji@0
|
46
|
yuuji@0
|
47 /* Server states */
|
yuuji@0
|
48
|
yuuji@0
|
49 #define AUTHORIZATION 0
|
yuuji@0
|
50 #define TRANSACTION 1
|
yuuji@0
|
51 #define UPDATE 2
|
yuuji@0
|
52 #define LOGOUT 3
|
yuuji@0
|
53
|
yuuji@0
|
54 /* Eudora food */
|
yuuji@0
|
55
|
yuuji@0
|
56 #define STATUS "Status: %s%s\015\012"
|
yuuji@0
|
57 #define SLEN (sizeof (STATUS)-3)
|
yuuji@0
|
58
|
yuuji@0
|
59
|
yuuji@0
|
60 /* Global storage */
|
yuuji@0
|
61
|
yuuji@0
|
62 char *version = "104"; /* edit number of this server */
|
yuuji@0
|
63 short state = AUTHORIZATION; /* server state */
|
yuuji@0
|
64 short critical = NIL; /* non-zero if in critical code */
|
yuuji@0
|
65 MAILSTREAM *stream = NIL; /* mailbox stream */
|
yuuji@0
|
66 time_t idletime = 0; /* time we went idle */
|
yuuji@0
|
67 unsigned long nmsgs = 0; /* current number of messages */
|
yuuji@0
|
68 unsigned long ndele = 0; /* number of deletes */
|
yuuji@0
|
69 unsigned long nseen = 0; /* number of mark-seens */
|
yuuji@0
|
70 unsigned long last = 0; /* highest message accessed */
|
yuuji@0
|
71 unsigned long il = 0; /* initial last message */
|
yuuji@0
|
72 char challenge[128]; /* challenge */
|
yuuji@0
|
73 char *host = NIL; /* remote host name */
|
yuuji@0
|
74 char *user = NIL; /* user name */
|
yuuji@0
|
75 char *pass = NIL; /* password */
|
yuuji@0
|
76 char *initial = NIL; /* initial response */
|
yuuji@0
|
77 long *msg = NIL; /* message translation vector */
|
yuuji@0
|
78 short *flags = NIL; /* flags */
|
yuuji@0
|
79 char *logout = "Logout";
|
yuuji@0
|
80 char *goodbye = "+OK Sayonara\015\012";
|
yuuji@0
|
81
|
yuuji@0
|
82
|
yuuji@0
|
83 /* POP3 flags */
|
yuuji@0
|
84
|
yuuji@0
|
85 #define DELE 0x1
|
yuuji@0
|
86 #define SEEN 0x2
|
yuuji@0
|
87
|
yuuji@0
|
88
|
yuuji@0
|
89 /* Function prototypes */
|
yuuji@0
|
90
|
yuuji@0
|
91 int main (int argc,char *argv[]);
|
yuuji@0
|
92 void sayonara (int status);
|
yuuji@0
|
93 void clkint ();
|
yuuji@0
|
94 void kodint ();
|
yuuji@0
|
95 void hupint ();
|
yuuji@0
|
96 void trmint ();
|
yuuji@0
|
97 int pass_login (char *t,int argc,char *argv[]);
|
yuuji@0
|
98 char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
|
yuuji@0
|
99 char *responder (void *challenge,unsigned long clen,unsigned long *rlen);
|
yuuji@0
|
100 int mbxopen (char *mailbox);
|
yuuji@0
|
101 long blat (char *text,long lines,unsigned long size,STRING *st);
|
yuuji@0
|
102 void rset ();
|
yuuji@0
|
103
|
yuuji@0
|
104 /* Main program */
|
yuuji@0
|
105
|
yuuji@0
|
106 int main (int argc,char *argv[])
|
yuuji@0
|
107 {
|
yuuji@0
|
108 unsigned long i,j,k;
|
yuuji@0
|
109 char *s,*t;
|
yuuji@0
|
110 char tmp[MAILTMPLEN];
|
yuuji@0
|
111 time_t autologouttime;
|
yuuji@0
|
112 char *pgmname = (argc && argv[0]) ?
|
yuuji@0
|
113 (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
|
yuuji@0
|
114 s+1 : argv[0]) : "ipop3d";
|
yuuji@0
|
115 /* set service name before linkage */
|
yuuji@0
|
116 mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
|
yuuji@0
|
117 #include "linkage.c"
|
yuuji@0
|
118 /* initialize server */
|
yuuji@0
|
119 server_init (pgmname,"pop3","pop3s",clkint,kodint,hupint,trmint,NIL);
|
yuuji@0
|
120 mail_parameters (NIL,SET_BLOCKENVINIT,VOIDT);
|
yuuji@0
|
121 s = myusername_full (&i); /* get user name and flags */
|
yuuji@0
|
122 mail_parameters (NIL,SET_BLOCKENVINIT,NIL);
|
yuuji@0
|
123 if (i == MU_LOGGEDIN) { /* allow EXTERNAL if logged in already */
|
yuuji@0
|
124 mail_parameters (NIL,UNHIDE_AUTHENTICATOR,(void *) "EXTERNAL");
|
yuuji@0
|
125 mail_parameters (NIL,SET_EXTERNALAUTHID,(void *) s);
|
yuuji@0
|
126 }
|
yuuji@0
|
127 { /* set up MD5 challenge */
|
yuuji@0
|
128 AUTHENTICATOR *auth = mail_lookup_auth (1);
|
yuuji@0
|
129 while (auth && compare_cstring (auth->name,"CRAM-MD5")) auth = auth->next;
|
yuuji@0
|
130 /* build challenge -- less than 128 chars */
|
yuuji@0
|
131 if (auth && auth->server && !(auth->flags & AU_DISABLE))
|
yuuji@0
|
132 sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (),
|
yuuji@0
|
133 (unsigned long) time (0),tcp_serverhost ());
|
yuuji@0
|
134 else challenge[0] = '\0'; /* no MD5 authentication */
|
yuuji@0
|
135 }
|
yuuji@0
|
136 /* There are reports of POP3 clients which get upset if anything appears
|
yuuji@0
|
137 * between the "+OK" and the "POP3" in the greeting.
|
yuuji@0
|
138 */
|
yuuji@0
|
139 PSOUT ("+OK POP3 ");
|
yuuji@0
|
140 if (!challenge[0]) { /* if no MD5 enable, output host name */
|
yuuji@0
|
141 PSOUT (tcp_serverhost ());
|
yuuji@0
|
142 PBOUT (' ');
|
yuuji@0
|
143 }
|
yuuji@0
|
144 PSOUT (CCLIENTVERSION);
|
yuuji@0
|
145 PBOUT ('.');
|
yuuji@0
|
146 PSOUT (version);
|
yuuji@0
|
147 PSOUT (" server ready");
|
yuuji@0
|
148 if (challenge[0]) { /* if MD5 enable, output challenge here */
|
yuuji@0
|
149 PBOUT (' ');
|
yuuji@0
|
150 PSOUT (challenge);
|
yuuji@0
|
151 }
|
yuuji@0
|
152 CRLF;
|
yuuji@0
|
153 PFLUSH (); /* dump output buffer */
|
yuuji@0
|
154 autologouttime = time (0) + LOGINTIMEOUT;
|
yuuji@0
|
155 /* command processing loop */
|
yuuji@0
|
156 while ((state != UPDATE) && (state != LOGOUT)) {
|
yuuji@0
|
157 idletime = time (0); /* get a command under timeout */
|
yuuji@0
|
158 alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT);
|
yuuji@0
|
159 clearerr (stdin); /* clear stdin errors */
|
yuuji@0
|
160 /* read command line */
|
yuuji@0
|
161 while (!PSIN (tmp,MAILTMPLEN)) {
|
yuuji@0
|
162 /* ignore if some interrupt */
|
yuuji@0
|
163 if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
|
yuuji@0
|
164 else {
|
yuuji@0
|
165 char *e = ferror (stdin) ?
|
yuuji@0
|
166 strerror (errno) : "Unexpected client disconnect";
|
yuuji@0
|
167 alarm (0); /* disable all interrupts */
|
yuuji@0
|
168 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
169 sprintf (logout = tmp,"%.80s, while reading line",e);
|
yuuji@0
|
170 goodbye = NIL;
|
yuuji@0
|
171 rset (); /* try to gracefully close the stream */
|
yuuji@0
|
172 if (state == TRANSACTION) mail_close (stream);
|
yuuji@0
|
173 stream = NIL;
|
yuuji@0
|
174 state = LOGOUT;
|
yuuji@0
|
175 sayonara (1);
|
yuuji@0
|
176 }
|
yuuji@0
|
177 }
|
yuuji@0
|
178 alarm (0); /* make sure timeout disabled */
|
yuuji@0
|
179 idletime = 0; /* no longer idle */
|
yuuji@0
|
180
|
yuuji@0
|
181 if (!strchr (tmp,'\012')) /* find end of line */
|
yuuji@0
|
182 PSOUT ("-ERR Command line too long\015\012");
|
yuuji@0
|
183 else if (!(s = strtok (tmp," \015\012")))
|
yuuji@0
|
184 PSOUT ("-ERR Null command\015\012");
|
yuuji@0
|
185 else { /* dispatch based on command */
|
yuuji@0
|
186 ucase (s); /* canonicalize case */
|
yuuji@0
|
187 /* snarf argument */
|
yuuji@0
|
188 t = strtok (NIL,"\015\012");
|
yuuji@0
|
189 /* QUIT command always valid */
|
yuuji@0
|
190 if (!strcmp (s,"QUIT")) state = UPDATE;
|
yuuji@0
|
191 else if (!strcmp (s,"CAPA")) {
|
yuuji@0
|
192 AUTHENTICATOR *auth;
|
yuuji@0
|
193 PSOUT ("+OK Capability list follows:\015\012");
|
yuuji@0
|
194 PSOUT ("TOP\015\012LOGIN-DELAY 180\015\012UIDL\015\012");
|
yuuji@0
|
195 if (s = ssl_start_tls (NIL)) fs_give ((void **) &s);
|
yuuji@0
|
196 else PSOUT ("STLS\015\012");
|
yuuji@0
|
197 if (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))
|
yuuji@0
|
198 PSOUT ("USER\015\012");
|
yuuji@0
|
199 /* display secure server authenticators */
|
yuuji@0
|
200 for (auth = mail_lookup_auth (1), s = "SASL"; auth; auth = auth->next)
|
yuuji@0
|
201 if (auth->server && !(auth->flags & AU_DISABLE) &&
|
yuuji@0
|
202 !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
|
yuuji@0
|
203 if (s) {
|
yuuji@0
|
204 PSOUT (s);
|
yuuji@0
|
205 s = NIL;
|
yuuji@0
|
206 }
|
yuuji@0
|
207 PBOUT (' ');
|
yuuji@0
|
208 PSOUT (auth->name);
|
yuuji@0
|
209 }
|
yuuji@0
|
210 PSOUT (s ? ".\015\012" : "\015\012.\015\012");
|
yuuji@0
|
211 }
|
yuuji@0
|
212
|
yuuji@0
|
213 else switch (state) { /* else dispatch based on state */
|
yuuji@0
|
214 case AUTHORIZATION: /* waiting to get logged in */
|
yuuji@0
|
215 if (!strcmp (s,"AUTH")) {
|
yuuji@0
|
216 if (t && *t) { /* mechanism given? */
|
yuuji@0
|
217 if (host) fs_give ((void **) &host);
|
yuuji@0
|
218 if (user) fs_give ((void **) &user);
|
yuuji@0
|
219 if (pass) fs_give ((void **) &pass);
|
yuuji@0
|
220 s = strtok (t," "); /* get mechanism name */
|
yuuji@0
|
221 /* get initial response */
|
yuuji@0
|
222 if (initial = strtok (NIL,"\015\012")) {
|
yuuji@0
|
223 if ((*initial == '=') && !initial[1]) ++initial;
|
yuuji@0
|
224 else if (!*initial) initial = NIL;
|
yuuji@0
|
225 }
|
yuuji@0
|
226 if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) {
|
yuuji@0
|
227 PSOUT ("-ERR Bad authentication\015\012");
|
yuuji@0
|
228 syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s,
|
yuuji@0
|
229 tcp_clienthost ());
|
yuuji@0
|
230 }
|
yuuji@0
|
231 else if ((state = mbxopen ("INBOX")) == TRANSACTION)
|
yuuji@0
|
232 syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%lu/%lu",
|
yuuji@0
|
233 user,tcp_clienthost (),nmsgs,stream->nmsgs);
|
yuuji@0
|
234 else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox",
|
yuuji@0
|
235 user,tcp_clienthost ());
|
yuuji@0
|
236 }
|
yuuji@0
|
237 else {
|
yuuji@0
|
238 AUTHENTICATOR *auth;
|
yuuji@0
|
239 PSOUT ("+OK Supported authentication mechanisms:\015\012");
|
yuuji@0
|
240 i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL);
|
yuuji@0
|
241 for (auth = mail_lookup_auth (1); auth; auth = auth->next)
|
yuuji@0
|
242 if (auth->server && !(auth->flags & AU_DISABLE) &&
|
yuuji@0
|
243 !(auth->flags & AU_HIDE) &&
|
yuuji@0
|
244 (i || (auth->flags & AU_SECURE))) {
|
yuuji@0
|
245 PSOUT (auth->name);
|
yuuji@0
|
246 CRLF;
|
yuuji@0
|
247 }
|
yuuji@0
|
248 PBOUT ('.');
|
yuuji@0
|
249 CRLF;
|
yuuji@0
|
250 }
|
yuuji@0
|
251 }
|
yuuji@0
|
252
|
yuuji@0
|
253 else if (!strcmp (s,"APOP")) {
|
yuuji@0
|
254 if (challenge[0]) { /* can do it if have an MD5 challenge */
|
yuuji@0
|
255 if (host) fs_give ((void **) &host);
|
yuuji@0
|
256 if (user) fs_give ((void **) &user);
|
yuuji@0
|
257 if (pass) fs_give ((void **) &pass);
|
yuuji@0
|
258 /* get user name */
|
yuuji@0
|
259 if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"\012"))))
|
yuuji@0
|
260 PSOUT ("-ERR Missing APOP argument\015\012");
|
yuuji@0
|
261 else if (!(user = apop_login (challenge,s,t,argc,argv)))
|
yuuji@0
|
262 PSOUT ("-ERR Bad APOP\015\012");
|
yuuji@0
|
263 else if ((state = mbxopen ("INBOX")) == TRANSACTION)
|
yuuji@0
|
264 syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%lu/%lu",
|
yuuji@0
|
265 user,tcp_clienthost (),nmsgs,stream->nmsgs);
|
yuuji@0
|
266 else syslog (LOG_INFO,"APOP user=%.80s host=%.80s no mailbox",
|
yuuji@0
|
267 user,tcp_clienthost ());
|
yuuji@0
|
268 }
|
yuuji@0
|
269 else PSOUT ("-ERR Not supported\015\012");
|
yuuji@0
|
270 }
|
yuuji@0
|
271 /* (chuckle) */
|
yuuji@0
|
272 else if (!strcmp (s,"RPOP"))
|
yuuji@0
|
273 PSOUT ("-ERR Nice try, bunkie\015\012");
|
yuuji@0
|
274 else if (!strcmp (s,"STLS")) {
|
yuuji@0
|
275 if (t = ssl_start_tls (pgmname)) {
|
yuuji@0
|
276 PSOUT ("-ERR STLS failed: ");
|
yuuji@0
|
277 PSOUT (t);
|
yuuji@0
|
278 CRLF;
|
yuuji@0
|
279 }
|
yuuji@0
|
280 else PSOUT ("+OK STLS completed\015\012");
|
yuuji@0
|
281 }
|
yuuji@0
|
282 else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
|
yuuji@0
|
283 !strcmp (s,"USER")) {
|
yuuji@0
|
284 if (host) fs_give ((void **) &host);
|
yuuji@0
|
285 if (user) fs_give ((void **) &user);
|
yuuji@0
|
286 if (pass) fs_give ((void **) &pass);
|
yuuji@0
|
287 if (t && *t) { /* if user name given */
|
yuuji@0
|
288 /* skip leading whitespace (bogus clients!) */
|
yuuji@0
|
289 while (*t == ' ') ++t;
|
yuuji@0
|
290 /* remote user name? */
|
yuuji@0
|
291 if (s = strchr (t,':')) {
|
yuuji@0
|
292 *s++ = '\0'; /* tie off host name */
|
yuuji@0
|
293 host = cpystr (t);/* copy host name */
|
yuuji@0
|
294 user = cpystr (s);/* copy user name */
|
yuuji@0
|
295 }
|
yuuji@0
|
296 /* local user name */
|
yuuji@0
|
297 else user = cpystr (t);
|
yuuji@0
|
298 PSOUT ("+OK User name accepted, password please\015\012");
|
yuuji@0
|
299 }
|
yuuji@0
|
300 else PSOUT ("-ERR Missing username argument\015\012");
|
yuuji@0
|
301 }
|
yuuji@0
|
302 else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
|
yuuji@0
|
303 user && *user && !strcmp (s,"PASS"))
|
yuuji@0
|
304 state = pass_login (t,argc,argv);
|
yuuji@0
|
305 else PSOUT ("-ERR Unknown AUTHORIZATION state command\015\012");
|
yuuji@0
|
306 break;
|
yuuji@0
|
307
|
yuuji@0
|
308 case TRANSACTION: /* logged in */
|
yuuji@0
|
309 if (!strcmp (s,"STAT")) {
|
yuuji@0
|
310 for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
|
yuuji@0
|
311 /* message still exists? */
|
yuuji@0
|
312 if (msg[i] && !(flags[i] & DELE)) {
|
yuuji@0
|
313 j++; /* count one more undeleted message */
|
yuuji@0
|
314 k += mail_elt (stream,msg[i])->rfc822_size + SLEN;
|
yuuji@0
|
315 }
|
yuuji@0
|
316 sprintf (tmp,"+OK %lu %lu\015\012",j,k);
|
yuuji@0
|
317 PSOUT (tmp);
|
yuuji@0
|
318 }
|
yuuji@0
|
319 else if (!strcmp (s,"LIST")) {
|
yuuji@0
|
320 if (t && *t) { /* argument do single message */
|
yuuji@0
|
321 if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
|
yuuji@0
|
322 !(flags[i] & DELE)) {
|
yuuji@0
|
323 sprintf (tmp,"+OK %lu %lu\015\012",i,
|
yuuji@0
|
324 mail_elt(stream,msg[i])->rfc822_size + SLEN);
|
yuuji@0
|
325 PSOUT (tmp);
|
yuuji@0
|
326 }
|
yuuji@0
|
327 else PSOUT ("-ERR No such message\015\012");
|
yuuji@0
|
328 }
|
yuuji@0
|
329 else { /* entire mailbox */
|
yuuji@0
|
330 PSOUT ("+OK Mailbox scan listing follows\015\012");
|
yuuji@0
|
331 for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
|
yuuji@0
|
332 if (msg[i] && !(flags[i] & DELE)) {
|
yuuji@0
|
333 sprintf (tmp,"%lu %lu\015\012",i,
|
yuuji@0
|
334 mail_elt (stream,msg[i])->rfc822_size + SLEN);
|
yuuji@0
|
335 PSOUT (tmp);
|
yuuji@0
|
336 }
|
yuuji@0
|
337 PBOUT ('.'); /* end of list */
|
yuuji@0
|
338 CRLF;
|
yuuji@0
|
339 }
|
yuuji@0
|
340 }
|
yuuji@0
|
341 else if (!strcmp (s,"UIDL")) {
|
yuuji@0
|
342 if (t && *t) { /* argument do single message */
|
yuuji@0
|
343 if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
|
yuuji@0
|
344 !(flags[i] & DELE)) {
|
yuuji@0
|
345 sprintf (tmp,"+OK %lu %08lx%08lx\015\012",i,stream->uid_validity,
|
yuuji@0
|
346 mail_uid (stream,msg[i]));
|
yuuji@0
|
347 PSOUT (tmp);
|
yuuji@0
|
348 }
|
yuuji@0
|
349 else PSOUT ("-ERR No such message\015\012");
|
yuuji@0
|
350 }
|
yuuji@0
|
351 else { /* entire mailbox */
|
yuuji@0
|
352 PSOUT ("+OK Unique-ID listing follows\015\012");
|
yuuji@0
|
353 for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
|
yuuji@0
|
354 if (msg[i] && !(flags[i] & DELE)) {
|
yuuji@0
|
355 sprintf (tmp,"%lu %08lx%08lx\015\012",i,stream->uid_validity,
|
yuuji@0
|
356 mail_uid (stream,msg[i]));
|
yuuji@0
|
357 PSOUT (tmp);
|
yuuji@0
|
358 }
|
yuuji@0
|
359 PBOUT ('.'); /* end of list */
|
yuuji@0
|
360 CRLF;
|
yuuji@0
|
361 }
|
yuuji@0
|
362 }
|
yuuji@0
|
363
|
yuuji@0
|
364 else if (!strcmp (s,"RETR")) {
|
yuuji@0
|
365 if (t && *t) { /* must have an argument */
|
yuuji@0
|
366 if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
|
yuuji@0
|
367 !(flags[i] & DELE)) {
|
yuuji@0
|
368 MESSAGECACHE *elt;
|
yuuji@0
|
369 /* update highest message accessed */
|
yuuji@0
|
370 if (i > last) last = i;
|
yuuji@0
|
371 sprintf (tmp,"+OK %lu octets\015\012",
|
yuuji@0
|
372 (elt = mail_elt (stream,msg[i]))->rfc822_size + SLEN);
|
yuuji@0
|
373 PSOUT (tmp);
|
yuuji@0
|
374 /* if not marked seen or noted to be marked */
|
yuuji@0
|
375 if (!(elt->seen || (flags[i] & SEEN))) {
|
yuuji@0
|
376 ++nseen; /* note that we need to mark it seen */
|
yuuji@0
|
377 flags[i] |= SEEN;
|
yuuji@0
|
378 }
|
yuuji@0
|
379 /* get header */
|
yuuji@0
|
380 t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
|
yuuji@0
|
381 blat (t,-1,k,NIL);/* write up to trailing CRLF */
|
yuuji@0
|
382 /* build status */
|
yuuji@0
|
383 sprintf (tmp,STATUS,elt->seen ? "R" : " ",
|
yuuji@0
|
384 elt->recent ? " " : "O");
|
yuuji@0
|
385 if (k < 4) CRLF; /* don't write Status: if no header */
|
yuuji@0
|
386 /* normal header ending with CRLF CRLF? */
|
yuuji@0
|
387 else if (t[k-3] == '\012') {
|
yuuji@0
|
388 PSOUT (tmp); /* write status */
|
yuuji@0
|
389 CRLF; /* then write second CRLF */
|
yuuji@0
|
390 }
|
yuuji@0
|
391 else { /* abnormal - no blank line at end of header */
|
yuuji@0
|
392 CRLF; /* write CRLF first then */
|
yuuji@0
|
393 PSOUT (tmp);
|
yuuji@0
|
394 }
|
yuuji@0
|
395 /* output text */
|
yuuji@0
|
396 t = mail_fetch_text (stream,msg[i],NIL,&k,
|
yuuji@0
|
397 FT_RETURNSTRINGSTRUCT | FT_PEEK);
|
yuuji@0
|
398 if (k) { /* only if there is a text body */
|
yuuji@0
|
399 blat (t,-1,k,&stream->private.string);
|
yuuji@0
|
400 CRLF; /* end of list */
|
yuuji@0
|
401 }
|
yuuji@0
|
402 PBOUT ('.');
|
yuuji@0
|
403 CRLF;
|
yuuji@0
|
404 }
|
yuuji@0
|
405 else PSOUT ("-ERR No such message\015\012");
|
yuuji@0
|
406 }
|
yuuji@0
|
407 else PSOUT ("-ERR Missing message number argument\015\012");
|
yuuji@0
|
408 }
|
yuuji@0
|
409
|
yuuji@0
|
410 else if (!strcmp (s,"DELE")) {
|
yuuji@0
|
411 if (t && *t) { /* must have an argument */
|
yuuji@0
|
412 if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
|
yuuji@0
|
413 !(flags[i] & DELE)) {
|
yuuji@0
|
414 /* update highest message accessed */
|
yuuji@0
|
415 if (i > last) last = i;
|
yuuji@0
|
416 flags[i] |= DELE; /* note that deletion is requested */
|
yuuji@0
|
417 PSOUT ("+OK Message deleted\015\012");
|
yuuji@0
|
418 ++ndele; /* one more message deleted */
|
yuuji@0
|
419 }
|
yuuji@0
|
420 else PSOUT ("-ERR No such message\015\012");
|
yuuji@0
|
421 }
|
yuuji@0
|
422 else PSOUT ("-ERR Missing message number argument\015\012");
|
yuuji@0
|
423 }
|
yuuji@0
|
424 else if (!strcmp (s,"NOOP"))
|
yuuji@0
|
425 PSOUT ("+OK No-op to you too!\015\012");
|
yuuji@0
|
426 else if (!strcmp (s,"LAST")) {
|
yuuji@0
|
427 sprintf (tmp,"+OK %lu\015\012",last);
|
yuuji@0
|
428 PSOUT (tmp);
|
yuuji@0
|
429 }
|
yuuji@0
|
430 else if (!strcmp (s,"RSET")) {
|
yuuji@0
|
431 rset (); /* reset the mailbox */
|
yuuji@0
|
432 PSOUT ("+OK Reset state\015\012");
|
yuuji@0
|
433 }
|
yuuji@0
|
434
|
yuuji@0
|
435 else if (!strcmp (s,"TOP")) {
|
yuuji@0
|
436 if (t && *t && (i =strtoul (t,&s,10)) && (i <= nmsgs) && msg[i] &&
|
yuuji@0
|
437 !(flags[i] & DELE)) {
|
yuuji@0
|
438 /* skip whitespace */
|
yuuji@0
|
439 while (*s == ' ') s++;
|
yuuji@0
|
440 /* make sure line count argument good */
|
yuuji@0
|
441 if ((*s >= '0') && (*s <= '9')) {
|
yuuji@0
|
442 MESSAGECACHE *elt = mail_elt (stream,msg[i]);
|
yuuji@0
|
443 j = strtoul (s,NIL,10);
|
yuuji@0
|
444 /* update highest message accessed */
|
yuuji@0
|
445 if (i > last) last = i;
|
yuuji@0
|
446 PSOUT ("+OK Top of message follows\015\012");
|
yuuji@0
|
447 /* get header */
|
yuuji@0
|
448 t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
|
yuuji@0
|
449 blat (t,-1,k,NIL);/* write up to trailing CRLF */
|
yuuji@0
|
450 /* build status */
|
yuuji@0
|
451 sprintf (tmp,STATUS,elt->seen ? "R" : " ",
|
yuuji@0
|
452 elt->recent ? " " : "O");
|
yuuji@0
|
453 if (k < 4) CRLF; /* don't write Status: if no header */
|
yuuji@0
|
454 /* normal header ending with CRLF CRLF? */
|
yuuji@0
|
455 else if (t[k-3] == '\012') {
|
yuuji@0
|
456 PSOUT (tmp); /* write status */
|
yuuji@0
|
457 CRLF; /* then write second CRLF */
|
yuuji@0
|
458 }
|
yuuji@0
|
459 else { /* abnormal - no blank line at end of header */
|
yuuji@0
|
460 CRLF; /* write CRLF first then */
|
yuuji@0
|
461 PSOUT (tmp);
|
yuuji@0
|
462 }
|
yuuji@0
|
463 if (j) { /* want any text lines? */
|
yuuji@0
|
464 /* output text */
|
yuuji@0
|
465 t = mail_fetch_text (stream,msg[i],NIL,&k,
|
yuuji@0
|
466 FT_PEEK | FT_RETURNSTRINGSTRUCT);
|
yuuji@0
|
467 /* tie off final line if full text output */
|
yuuji@0
|
468 if (k && (j -= blat (t,j,k,&stream->private.string))) CRLF;
|
yuuji@0
|
469 }
|
yuuji@0
|
470 PBOUT ('.'); /* end of list */
|
yuuji@0
|
471 CRLF;
|
yuuji@0
|
472 }
|
yuuji@0
|
473 else PSOUT ("-ERR Bad line count argument\015\012");
|
yuuji@0
|
474 }
|
yuuji@0
|
475 else PSOUT ("-ERR Bad message number argument\015\012");
|
yuuji@0
|
476 }
|
yuuji@0
|
477
|
yuuji@0
|
478 else if (!strcmp (s,"XTND"))
|
yuuji@0
|
479 PSOUT ("-ERR Sorry I can't do that\015\012");
|
yuuji@0
|
480 else PSOUT ("-ERR Unknown TRANSACTION state command\015\012");
|
yuuji@0
|
481 break;
|
yuuji@0
|
482 default:
|
yuuji@0
|
483 PSOUT ("-ERR Server in unknown state\015\012");
|
yuuji@0
|
484 break;
|
yuuji@0
|
485 }
|
yuuji@0
|
486 }
|
yuuji@0
|
487 PFLUSH (); /* make sure output finished */
|
yuuji@0
|
488 if (autologouttime) { /* have an autologout in effect? */
|
yuuji@0
|
489 /* cancel if no longer waiting for login */
|
yuuji@0
|
490 if (state != AUTHORIZATION) autologouttime = 0;
|
yuuji@0
|
491 /* took too long to login */
|
yuuji@0
|
492 else if (autologouttime < time (0)) {
|
yuuji@0
|
493 goodbye = "-ERR Autologout\015\012";
|
yuuji@0
|
494 logout = "Autologout";
|
yuuji@0
|
495 state = LOGOUT; /* sayonara */
|
yuuji@0
|
496 }
|
yuuji@0
|
497 }
|
yuuji@0
|
498 }
|
yuuji@0
|
499
|
yuuji@0
|
500 /* open and need to update? */
|
yuuji@0
|
501 if (stream && (state == UPDATE)) {
|
yuuji@0
|
502 if (nseen) { /* only bother if messages need marking seen */
|
yuuji@0
|
503 *(s = tmp) = '\0'; /* clear sequence */
|
yuuji@0
|
504 for (i = 1; i <= nmsgs; ++i) if (flags[i] & SEEN) {
|
yuuji@0
|
505 for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & SEEN); ++j) k = j;
|
yuuji@0
|
506 if (k) sprintf (s,",%lu:%lu",i,k);
|
yuuji@0
|
507 else sprintf (s,",%lu",i);
|
yuuji@0
|
508 s += strlen (s); /* point to end of string */
|
yuuji@0
|
509 if ((s - tmp) > (MAILTMPLEN - 30)) {
|
yuuji@0
|
510 mail_setflag (stream,tmp + 1,"\\Seen");
|
yuuji@0
|
511 *(s = tmp) = '\0'; /* restart sequence */
|
yuuji@0
|
512 }
|
yuuji@0
|
513 i = j; /* continue after the range */
|
yuuji@0
|
514 }
|
yuuji@0
|
515 if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Seen");
|
yuuji@0
|
516 }
|
yuuji@0
|
517 if (ndele) { /* any messages to delete? */
|
yuuji@0
|
518 *(s = tmp) = '\0'; /* clear sequence */
|
yuuji@0
|
519 for (i = 1; i <= nmsgs; ++i) if (flags[i] & DELE) {
|
yuuji@0
|
520 for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & DELE); ++j) k = j;
|
yuuji@0
|
521 if (k) sprintf (s,",%lu:%lu",i,k);
|
yuuji@0
|
522 else sprintf (s,",%lu",i);
|
yuuji@0
|
523 s += strlen (s); /* point to end of string */
|
yuuji@0
|
524 if ((s - tmp) > (MAILTMPLEN - 30)) {
|
yuuji@0
|
525 mail_setflag (stream,tmp + 1,"\\Deleted");
|
yuuji@0
|
526 *(s = tmp) = '\0'; /* restart sequence */
|
yuuji@0
|
527 }
|
yuuji@0
|
528 i = j; /* continue after the range */
|
yuuji@0
|
529 }
|
yuuji@0
|
530 if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Deleted");
|
yuuji@0
|
531 mail_expunge (stream);
|
yuuji@0
|
532 }
|
yuuji@0
|
533 syslog (LOG_INFO,"Update user=%.80s host=%.80s nmsgs=%lu ndele=%lu nseen=%lu",
|
yuuji@0
|
534 user,tcp_clienthost (),stream->nmsgs,ndele,nseen);
|
yuuji@0
|
535 mail_close (stream);
|
yuuji@0
|
536 }
|
yuuji@0
|
537 sayonara (0);
|
yuuji@0
|
538 return 0; /* stupid compilers */
|
yuuji@0
|
539 }
|
yuuji@0
|
540
|
yuuji@0
|
541
|
yuuji@0
|
542 /* Say goodbye
|
yuuji@0
|
543 * Accepts: exit status
|
yuuji@0
|
544 *
|
yuuji@0
|
545 * Does not return
|
yuuji@0
|
546 */
|
yuuji@0
|
547
|
yuuji@0
|
548 void sayonara (int status)
|
yuuji@0
|
549 {
|
yuuji@0
|
550 logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
|
yuuji@0
|
551 if (goodbye) { /* have a goodbye message? */
|
yuuji@0
|
552 PSOUT (goodbye);
|
yuuji@0
|
553 PFLUSH (); /* make sure blatted */
|
yuuji@0
|
554 }
|
yuuji@0
|
555 syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
|
yuuji@0
|
556 user ? (char *) user : "???",tcp_clienthost ());
|
yuuji@0
|
557 /* do logout hook if needed */
|
yuuji@0
|
558 if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
|
yuuji@0
|
559 _exit (status); /* all done */
|
yuuji@0
|
560 }
|
yuuji@0
|
561
|
yuuji@0
|
562 /* Clock interrupt
|
yuuji@0
|
563 */
|
yuuji@0
|
564
|
yuuji@0
|
565 void clkint ()
|
yuuji@0
|
566 {
|
yuuji@0
|
567 alarm (0); /* disable all interrupts */
|
yuuji@0
|
568 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
569 goodbye = "-ERR Autologout; idle for too long\015\012";
|
yuuji@0
|
570 logout = "Autologout";
|
yuuji@0
|
571 if (critical) state = LOGOUT; /* badly hosed if in critical code */
|
yuuji@0
|
572 else { /* try to gracefully close the stream */
|
yuuji@0
|
573 if ((state == TRANSACTION) && !stream->lock) {
|
yuuji@0
|
574 rset ();
|
yuuji@0
|
575 mail_close (stream);
|
yuuji@0
|
576 }
|
yuuji@0
|
577 state = LOGOUT;
|
yuuji@0
|
578 stream = NIL;
|
yuuji@0
|
579 sayonara (1);
|
yuuji@0
|
580 }
|
yuuji@0
|
581 }
|
yuuji@0
|
582
|
yuuji@0
|
583
|
yuuji@0
|
584 /* Kiss Of Death interrupt
|
yuuji@0
|
585 */
|
yuuji@0
|
586
|
yuuji@0
|
587 void kodint ()
|
yuuji@0
|
588 {
|
yuuji@0
|
589 /* only if idle */
|
yuuji@0
|
590 if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
|
yuuji@0
|
591 alarm (0); /* disable all interrupts */
|
yuuji@0
|
592 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
593 goodbye = "-ERR Received Kiss of Death\015\012";
|
yuuji@0
|
594 logout = "Killed (lost mailbox lock)";
|
yuuji@0
|
595 if (critical) state =LOGOUT;/* must defer if in critical code */
|
yuuji@0
|
596 else { /* try to gracefully close the stream */
|
yuuji@0
|
597 if ((state == TRANSACTION) && !stream->lock) {
|
yuuji@0
|
598 rset ();
|
yuuji@0
|
599 mail_close (stream);
|
yuuji@0
|
600 }
|
yuuji@0
|
601 state = LOGOUT;
|
yuuji@0
|
602 stream = NIL;
|
yuuji@0
|
603 sayonara (1); /* die die die */
|
yuuji@0
|
604 }
|
yuuji@0
|
605 }
|
yuuji@0
|
606 }
|
yuuji@0
|
607
|
yuuji@0
|
608
|
yuuji@0
|
609 /* Hangup interrupt
|
yuuji@0
|
610 */
|
yuuji@0
|
611
|
yuuji@0
|
612 void hupint ()
|
yuuji@0
|
613 {
|
yuuji@0
|
614 alarm (0); /* disable all interrupts */
|
yuuji@0
|
615 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
616 goodbye = NIL; /* nobody left to talk to */
|
yuuji@0
|
617 logout = "Hangup";
|
yuuji@0
|
618 if (critical) state = LOGOUT; /* must defer if in critical code */
|
yuuji@0
|
619 else { /* try to gracefully close the stream */
|
yuuji@0
|
620 if ((state == TRANSACTION) && !stream->lock) {
|
yuuji@0
|
621 rset ();
|
yuuji@0
|
622 mail_close (stream);
|
yuuji@0
|
623 }
|
yuuji@0
|
624 state = LOGOUT;
|
yuuji@0
|
625 stream = NIL;
|
yuuji@0
|
626 sayonara (1); /* die die die */
|
yuuji@0
|
627 }
|
yuuji@0
|
628 }
|
yuuji@0
|
629
|
yuuji@0
|
630
|
yuuji@0
|
631 /* Termination interrupt
|
yuuji@0
|
632 */
|
yuuji@0
|
633
|
yuuji@0
|
634 void trmint ()
|
yuuji@0
|
635 {
|
yuuji@0
|
636 alarm (0); /* disable all interrupts */
|
yuuji@0
|
637 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
638 goodbye = "-ERR Killed\015\012";
|
yuuji@0
|
639 logout = "Killed";
|
yuuji@0
|
640 if (critical) state = LOGOUT; /* must defer if in critical code */
|
yuuji@0
|
641 /* Make no attempt at graceful closure since a shutdown may be in
|
yuuji@0
|
642 * progress, and we won't have any time to do mail_close() actions.
|
yuuji@0
|
643 */
|
yuuji@0
|
644 else sayonara (1); /* die die die */
|
yuuji@0
|
645 }
|
yuuji@0
|
646
|
yuuji@0
|
647 /* Parse PASS command
|
yuuji@0
|
648 * Accepts: pointer to command argument
|
yuuji@0
|
649 * Returns: new state
|
yuuji@0
|
650 */
|
yuuji@0
|
651
|
yuuji@0
|
652 int pass_login (char *t,int argc,char *argv[])
|
yuuji@0
|
653 {
|
yuuji@0
|
654 char tmp[MAILTMPLEN];
|
yuuji@0
|
655 /* flush old passowrd */
|
yuuji@0
|
656 if (pass) fs_give ((void **) &pass);
|
yuuji@0
|
657 if (!(t && *t)) { /* if no password given */
|
yuuji@0
|
658 PSOUT ("-ERR Missing password argument\015\012");
|
yuuji@0
|
659 return AUTHORIZATION;
|
yuuji@0
|
660 }
|
yuuji@0
|
661 pass = cpystr (t); /* copy password argument */
|
yuuji@0
|
662 if (!host) { /* want remote mailbox? */
|
yuuji@0
|
663 /* no, delimit user from possible admin */
|
yuuji@0
|
664 if (t = strchr (user,'*')) *t++ ='\0';
|
yuuji@0
|
665 /* attempt the login */
|
yuuji@0
|
666 if (server_login (user,pass,t,argc,argv)) {
|
yuuji@0
|
667 int ret = mbxopen ("INBOX");
|
yuuji@0
|
668 if (ret == TRANSACTION) /* mailbox opened OK? */
|
yuuji@0
|
669 syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s nmsgs=%lu/%lu",
|
yuuji@0
|
670 t ? "Admin " : "",user,tcp_clienthost (),nmsgs,stream->nmsgs);
|
yuuji@0
|
671 else syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s no mailbox",
|
yuuji@0
|
672 t ? "Admin " : "",user,tcp_clienthost ());
|
yuuji@0
|
673 return ret;
|
yuuji@0
|
674 }
|
yuuji@0
|
675 }
|
yuuji@0
|
676 #ifndef DISABLE_POP_PROXY
|
yuuji@0
|
677 /* remote; build remote INBOX */
|
yuuji@0
|
678 else if (anonymous_login (argc,argv)) {
|
yuuji@0
|
679 syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",host,
|
yuuji@0
|
680 user,tcp_clienthost ());
|
yuuji@0
|
681 sprintf (tmp,"{%.128s/user=%.128s}INBOX",host,user);
|
yuuji@0
|
682 /* disable rimap just in case */
|
yuuji@0
|
683 mail_parameters (NIL,SET_RSHTIMEOUT,0);
|
yuuji@0
|
684 return mbxopen (tmp);
|
yuuji@0
|
685 }
|
yuuji@0
|
686 #endif
|
yuuji@0
|
687 /* vague error message to confuse crackers */
|
yuuji@0
|
688 PSOUT ("-ERR Bad login\015\012");
|
yuuji@0
|
689 return AUTHORIZATION;
|
yuuji@0
|
690 }
|
yuuji@0
|
691
|
yuuji@0
|
692 /* Authentication responder
|
yuuji@0
|
693 * Accepts: challenge
|
yuuji@0
|
694 * length of challenge
|
yuuji@0
|
695 * pointer to response length return location if non-NIL
|
yuuji@0
|
696 * Returns: response
|
yuuji@0
|
697 */
|
yuuji@0
|
698
|
yuuji@0
|
699 #define RESPBUFLEN 8*MAILTMPLEN
|
yuuji@0
|
700
|
yuuji@0
|
701 char *responder (void *challenge,unsigned long clen,unsigned long *rlen)
|
yuuji@0
|
702 {
|
yuuji@0
|
703 unsigned long i,j;
|
yuuji@0
|
704 unsigned char *t,resp[RESPBUFLEN];
|
yuuji@0
|
705 char tmp[MAILTMPLEN];
|
yuuji@0
|
706 if (initial) { /* initial response given? */
|
yuuji@0
|
707 if (clen) return NIL; /* not permitted */
|
yuuji@0
|
708 /* set up response */
|
yuuji@0
|
709 t = (unsigned char *) initial;
|
yuuji@0
|
710 initial = NIL; /* no more initial response */
|
yuuji@0
|
711 return (char *) rfc822_base64 (t,strlen ((char *) t),rlen ? rlen : &i);
|
yuuji@0
|
712 }
|
yuuji@0
|
713 PSOUT ("+ ");
|
yuuji@0
|
714 for (t = rfc822_binary (challenge,clen,&i),j = 0; j < i; j++)
|
yuuji@0
|
715 if (t[j] > ' ') PBOUT (t[j]);
|
yuuji@0
|
716 fs_give ((void **) &t);
|
yuuji@0
|
717 CRLF;
|
yuuji@0
|
718 PFLUSH (); /* dump output buffer */
|
yuuji@0
|
719 resp[RESPBUFLEN-1] = '\0'; /* last buffer character is guaranteed NUL */
|
yuuji@0
|
720 alarm (LOGINTIMEOUT); /* get a response under timeout */
|
yuuji@0
|
721 clearerr (stdin); /* clear stdin errors */
|
yuuji@0
|
722 /* read buffer */
|
yuuji@0
|
723 while (!PSIN ((char *) resp,RESPBUFLEN)) {
|
yuuji@0
|
724 /* ignore if some interrupt */
|
yuuji@0
|
725 if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
|
yuuji@0
|
726 else {
|
yuuji@0
|
727 char *e = ferror (stdin) ?
|
yuuji@0
|
728 strerror (errno) : "Command stream end of file";
|
yuuji@0
|
729 alarm (0); /* disable all interrupts */
|
yuuji@0
|
730 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
731 sprintf (logout = tmp,"%.80s, while reading authentication",e);
|
yuuji@0
|
732 goodbye = NIL;
|
yuuji@0
|
733 state = LOGOUT;
|
yuuji@0
|
734 sayonara (1);
|
yuuji@0
|
735 }
|
yuuji@0
|
736 }
|
yuuji@0
|
737 if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) {
|
yuuji@0
|
738 int c;
|
yuuji@0
|
739 while ((c = PBIN ()) != '\012') if (c == EOF) {
|
yuuji@0
|
740 /* ignore if some interrupt */
|
yuuji@0
|
741 if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
|
yuuji@0
|
742 else {
|
yuuji@0
|
743 char *e = ferror (stdin) ?
|
yuuji@0
|
744 strerror (errno) : "Command stream end of file";
|
yuuji@0
|
745 alarm (0); /* disable all interrupts */
|
yuuji@0
|
746 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
747 sprintf (logout = tmp,"%.80s, while reading auth char",e);
|
yuuji@0
|
748 goodbye = NIL;
|
yuuji@0
|
749 state = LOGOUT;
|
yuuji@0
|
750 sayonara (1);
|
yuuji@0
|
751 }
|
yuuji@0
|
752 }
|
yuuji@0
|
753 return NIL;
|
yuuji@0
|
754 }
|
yuuji@0
|
755 alarm (0); /* make sure timeout disabled */
|
yuuji@0
|
756 if (t[-1] == '\015') --t; /* remove CR */
|
yuuji@0
|
757 *t = '\0'; /* tie off buffer */
|
yuuji@0
|
758 return (resp[0] != '*') ?
|
yuuji@0
|
759 (char *) rfc822_base64 (resp,t-resp,rlen ? rlen : &i) : NIL;
|
yuuji@0
|
760 }
|
yuuji@0
|
761
|
yuuji@0
|
762 /* Select mailbox
|
yuuji@0
|
763 * Accepts: mailbox name
|
yuuji@0
|
764 * Returns: new state
|
yuuji@0
|
765 */
|
yuuji@0
|
766
|
yuuji@0
|
767 int mbxopen (char *mailbox)
|
yuuji@0
|
768 {
|
yuuji@0
|
769 unsigned long i,j;
|
yuuji@0
|
770 char tmp[MAILTMPLEN];
|
yuuji@0
|
771 MESSAGECACHE *elt;
|
yuuji@0
|
772 if (msg) fs_give ((void **) &msg);
|
yuuji@0
|
773 /* open mailbox */
|
yuuji@0
|
774 if (!(stream = mail_open (stream,mailbox,NIL)))
|
yuuji@0
|
775 goodbye = "-ERR Unable to open user's INBOX\015\012";
|
yuuji@0
|
776 else if (stream->rdonly) /* make sure not readonly */
|
yuuji@0
|
777 goodbye = "-ERR Can't get lock. Mailbox in use\015\012";
|
yuuji@0
|
778 else {
|
yuuji@0
|
779 nmsgs = 0; /* no messages yet */
|
yuuji@0
|
780 if (j = stream->nmsgs) { /* if mailbox non-empty */
|
yuuji@0
|
781 sprintf (tmp,"1:%lu",j); /* fetch fast information for all messages */
|
yuuji@0
|
782 mail_fetch_fast (stream,tmp,NIL);
|
yuuji@0
|
783 }
|
yuuji@0
|
784 /* create 1-origin tables */
|
yuuji@0
|
785 msg = (long *) fs_get (++j * sizeof (long));
|
yuuji@0
|
786 flags = (short *) fs_get (j * sizeof (short));
|
yuuji@0
|
787 /* build map */
|
yuuji@0
|
788 for (i = 1; i < j; ++i) if (!(elt = mail_elt (stream,i))->deleted) {
|
yuuji@0
|
789 msg[++nmsgs] = i; /* note the presence of this message */
|
yuuji@0
|
790 if (elt->seen) il = nmsgs;/* and set up initial LAST */
|
yuuji@0
|
791 }
|
yuuji@0
|
792 /* make sure unused map entries are zero */
|
yuuji@0
|
793 for (i = nmsgs + 1; i < j; ++i) msg[i] = 0;
|
yuuji@0
|
794 rset (); /* do implicit RSET */
|
yuuji@0
|
795 sprintf (tmp,"+OK Mailbox open, %lu messages\015\012",nmsgs);
|
yuuji@0
|
796 PSOUT (tmp);
|
yuuji@0
|
797 return TRANSACTION;
|
yuuji@0
|
798 }
|
yuuji@0
|
799 syslog (LOG_INFO,"Error opening or locking INBOX user=%.80s host=%.80s",
|
yuuji@0
|
800 user,tcp_clienthost ());
|
yuuji@0
|
801 return UPDATE;
|
yuuji@0
|
802 }
|
yuuji@0
|
803
|
yuuji@0
|
804 /* Blat a string with dot checking
|
yuuji@0
|
805 * Accepts: string
|
yuuji@0
|
806 * maximum number of lines if greater than zero
|
yuuji@0
|
807 * maximum number of bytes to output
|
yuuji@0
|
808 * alternative stringstruct
|
yuuji@0
|
809 * Returns: number of lines output
|
yuuji@0
|
810 *
|
yuuji@0
|
811 * This routine is uglier and kludgier than it should be, just to be robust
|
yuuji@0
|
812 * in the case of a message which doesn't end in a newline. Yes, this routine
|
yuuji@0
|
813 * does truncate the last two bytes from the text. Since it is normally a
|
yuuji@0
|
814 * newline and the main routine adds it back, it usually does not make a
|
yuuji@0
|
815 * difference. But if it isn't, since the newline is required and the octet
|
yuuji@0
|
816 * counts have to match, there's no choice but to truncate.
|
yuuji@0
|
817 */
|
yuuji@0
|
818
|
yuuji@0
|
819 long blat (char *text,long lines,unsigned long size,STRING *st)
|
yuuji@0
|
820 {
|
yuuji@0
|
821 char c,d,e;
|
yuuji@0
|
822 long ret = 0;
|
yuuji@0
|
823 /* no-op if zero lines or empty string */
|
yuuji@0
|
824 if (!(lines && (size-- > 2))) return 0;
|
yuuji@0
|
825 if (text) {
|
yuuji@0
|
826 c = *text++; d = *text++; /* collect first two bytes */
|
yuuji@0
|
827 if (c == '.') PBOUT ('.'); /* double string-leading dot if necessary */
|
yuuji@0
|
828 while (lines && --size) { /* copy loop */
|
yuuji@0
|
829 e = *text++; /* get next byte */
|
yuuji@0
|
830 PBOUT (c); /* output character */
|
yuuji@0
|
831 if (c == '\012') { /* end of line? */
|
yuuji@0
|
832 ret++; --lines; /* count another line */
|
yuuji@0
|
833 /* double leading dot as necessary */
|
yuuji@0
|
834 if (lines && size && (d == '.')) PBOUT ('.');
|
yuuji@0
|
835 }
|
yuuji@0
|
836 c = d; d = e; /* move to next character */
|
yuuji@0
|
837 }
|
yuuji@0
|
838 }
|
yuuji@0
|
839 else {
|
yuuji@0
|
840 c = SNX (st); d = SNX (st); /* collect first two bytes */
|
yuuji@0
|
841 if (c == '.') PBOUT ('.'); /* double string-leading dot if necessary */
|
yuuji@0
|
842 while (lines && --size) { /* copy loop */
|
yuuji@0
|
843 e = SNX (st); /* get next byte */
|
yuuji@0
|
844 PBOUT (c); /* output character */
|
yuuji@0
|
845 if (c == '\012') { /* end of line? */
|
yuuji@0
|
846 ret++; --lines; /* count another line */
|
yuuji@0
|
847 /* double leading dot as necessary */
|
yuuji@0
|
848 if (lines && size && (d == '.')) PBOUT ('.');
|
yuuji@0
|
849 }
|
yuuji@0
|
850 c = d; d = e; /* move to next character */
|
yuuji@0
|
851 }
|
yuuji@0
|
852 }
|
yuuji@0
|
853 return ret;
|
yuuji@0
|
854 }
|
yuuji@0
|
855
|
yuuji@0
|
856 /* Reset mailbox
|
yuuji@0
|
857 */
|
yuuji@0
|
858
|
yuuji@0
|
859 void rset ()
|
yuuji@0
|
860 {
|
yuuji@0
|
861 /* clear all flags */
|
yuuji@0
|
862 if (flags) memset ((void *) flags,0,(nmsgs + 1) * sizeof (short));
|
yuuji@0
|
863 ndele = nseen = 0; /* no more deleted or seen messages */
|
yuuji@0
|
864 last = il; /* restore previous LAST value */
|
yuuji@0
|
865 }
|
yuuji@0
|
866
|
yuuji@0
|
867 /* Co-routines from MAIL library */
|
yuuji@0
|
868
|
yuuji@0
|
869
|
yuuji@0
|
870 /* Message matches a search
|
yuuji@0
|
871 * Accepts: MAIL stream
|
yuuji@0
|
872 * message number
|
yuuji@0
|
873 */
|
yuuji@0
|
874
|
yuuji@0
|
875 void mm_searched (MAILSTREAM *stream,unsigned long msgno)
|
yuuji@0
|
876 {
|
yuuji@0
|
877 /* Never called */
|
yuuji@0
|
878 }
|
yuuji@0
|
879
|
yuuji@0
|
880
|
yuuji@0
|
881 /* Message exists (i.e. there are that many messages in the mailbox)
|
yuuji@0
|
882 * Accepts: MAIL stream
|
yuuji@0
|
883 * message number
|
yuuji@0
|
884 */
|
yuuji@0
|
885
|
yuuji@0
|
886 void mm_exists (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
887 {
|
yuuji@0
|
888 /* Can't use this mechanism. POP has no means of notifying the client of
|
yuuji@0
|
889 new mail during the session. */
|
yuuji@0
|
890 }
|
yuuji@0
|
891
|
yuuji@0
|
892
|
yuuji@0
|
893 /* Message expunged
|
yuuji@0
|
894 * Accepts: MAIL stream
|
yuuji@0
|
895 * message number
|
yuuji@0
|
896 */
|
yuuji@0
|
897
|
yuuji@0
|
898 void mm_expunged (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
899 {
|
yuuji@0
|
900 unsigned long i = number + 1;
|
yuuji@0
|
901 msg[number] = 0; /* I bet that this will annoy someone */
|
yuuji@0
|
902 while (i <= nmsgs) --msg[i++];
|
yuuji@0
|
903 }
|
yuuji@0
|
904
|
yuuji@0
|
905
|
yuuji@0
|
906 /* Message flag status change
|
yuuji@0
|
907 * Accepts: MAIL stream
|
yuuji@0
|
908 * message number
|
yuuji@0
|
909 */
|
yuuji@0
|
910
|
yuuji@0
|
911 void mm_flags (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
912 {
|
yuuji@0
|
913 /* This isn't used */
|
yuuji@0
|
914 }
|
yuuji@0
|
915
|
yuuji@0
|
916
|
yuuji@0
|
917 /* Mailbox found
|
yuuji@0
|
918 * Accepts: MAIL stream
|
yuuji@0
|
919 * hierarchy delimiter
|
yuuji@0
|
920 * mailbox name
|
yuuji@0
|
921 * mailbox attributes
|
yuuji@0
|
922 */
|
yuuji@0
|
923
|
yuuji@0
|
924 void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
yuuji@0
|
925 {
|
yuuji@0
|
926 /* This isn't used */
|
yuuji@0
|
927 }
|
yuuji@0
|
928
|
yuuji@0
|
929
|
yuuji@0
|
930 /* Subscribe mailbox found
|
yuuji@0
|
931 * Accepts: MAIL stream
|
yuuji@0
|
932 * hierarchy delimiter
|
yuuji@0
|
933 * mailbox name
|
yuuji@0
|
934 * mailbox attributes
|
yuuji@0
|
935 */
|
yuuji@0
|
936
|
yuuji@0
|
937 void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
yuuji@0
|
938 {
|
yuuji@0
|
939 /* This isn't used */
|
yuuji@0
|
940 }
|
yuuji@0
|
941
|
yuuji@0
|
942
|
yuuji@0
|
943 /* Mailbox status
|
yuuji@0
|
944 * Accepts: MAIL stream
|
yuuji@0
|
945 * mailbox name
|
yuuji@0
|
946 * mailbox status
|
yuuji@0
|
947 */
|
yuuji@0
|
948
|
yuuji@0
|
949 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
|
yuuji@0
|
950 {
|
yuuji@0
|
951 /* This isn't used */
|
yuuji@0
|
952 }
|
yuuji@0
|
953
|
yuuji@0
|
954 /* Notification event
|
yuuji@0
|
955 * Accepts: MAIL stream
|
yuuji@0
|
956 * string to log
|
yuuji@0
|
957 * error flag
|
yuuji@0
|
958 */
|
yuuji@0
|
959
|
yuuji@0
|
960 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
|
yuuji@0
|
961 {
|
yuuji@0
|
962 mm_log (string,errflg); /* just do mm_log action */
|
yuuji@0
|
963 }
|
yuuji@0
|
964
|
yuuji@0
|
965
|
yuuji@0
|
966 /* Log an event for the user to see
|
yuuji@0
|
967 * Accepts: string to log
|
yuuji@0
|
968 * error flag
|
yuuji@0
|
969 */
|
yuuji@0
|
970
|
yuuji@0
|
971 void mm_log (char *string,long errflg)
|
yuuji@0
|
972 {
|
yuuji@0
|
973 switch (errflg) {
|
yuuji@0
|
974 case NIL: /* information message */
|
yuuji@0
|
975 case PARSE: /* parse glitch */
|
yuuji@0
|
976 break; /* too many of these to log */
|
yuuji@0
|
977 case WARN: /* warning */
|
yuuji@0
|
978 syslog (LOG_DEBUG,"%s",string);
|
yuuji@0
|
979 break;
|
yuuji@0
|
980 case BYE: /* driver broke connection */
|
yuuji@0
|
981 if (state != UPDATE) {
|
yuuji@0
|
982 char tmp[MAILTMPLEN];
|
yuuji@0
|
983 alarm (0); /* disable all interrupts */
|
yuuji@0
|
984 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
985 sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
|
yuuji@0
|
986 goodbye = NIL;
|
yuuji@0
|
987 state = LOGOUT;
|
yuuji@0
|
988 sayonara (1);
|
yuuji@0
|
989 }
|
yuuji@0
|
990 break;
|
yuuji@0
|
991 case ERROR: /* error that broke command */
|
yuuji@0
|
992 default: /* default should never happen */
|
yuuji@0
|
993 syslog (LOG_NOTICE,"%s",string);
|
yuuji@0
|
994 break;
|
yuuji@0
|
995 }
|
yuuji@0
|
996 }
|
yuuji@0
|
997
|
yuuji@0
|
998
|
yuuji@0
|
999 /* Log an event to debugging telemetry
|
yuuji@0
|
1000 * Accepts: string to log
|
yuuji@0
|
1001 */
|
yuuji@0
|
1002
|
yuuji@0
|
1003 void mm_dlog (char *string)
|
yuuji@0
|
1004 {
|
yuuji@0
|
1005 /* Not doing anything here for now */
|
yuuji@0
|
1006 }
|
yuuji@0
|
1007
|
yuuji@0
|
1008
|
yuuji@0
|
1009 /* Get user name and password for this host
|
yuuji@0
|
1010 * Accepts: parse of network mailbox name
|
yuuji@0
|
1011 * where to return user name
|
yuuji@0
|
1012 * where to return password
|
yuuji@0
|
1013 * trial count
|
yuuji@0
|
1014 */
|
yuuji@0
|
1015
|
yuuji@0
|
1016 void mm_login (NETMBX *mb,char *username,char *password,long trial)
|
yuuji@0
|
1017 {
|
yuuji@0
|
1018 /* set user name */
|
yuuji@0
|
1019 strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
|
yuuji@0
|
1020 if (pass) {
|
yuuji@0
|
1021 strncpy (password,pass,255);/* and password */
|
yuuji@0
|
1022 fs_give ((void **) &pass);
|
yuuji@0
|
1023 }
|
yuuji@0
|
1024 else memset (password,0,256); /* no password to send, abort login */
|
yuuji@0
|
1025 username[NETMAXUSER] = password[255] = '\0';
|
yuuji@0
|
1026 }
|
yuuji@0
|
1027
|
yuuji@0
|
1028 /* About to enter critical code
|
yuuji@0
|
1029 * Accepts: stream
|
yuuji@0
|
1030 */
|
yuuji@0
|
1031
|
yuuji@0
|
1032 void mm_critical (MAILSTREAM *stream)
|
yuuji@0
|
1033 {
|
yuuji@0
|
1034 ++critical;
|
yuuji@0
|
1035 }
|
yuuji@0
|
1036
|
yuuji@0
|
1037
|
yuuji@0
|
1038 /* About to exit critical code
|
yuuji@0
|
1039 * Accepts: stream
|
yuuji@0
|
1040 */
|
yuuji@0
|
1041
|
yuuji@0
|
1042 void mm_nocritical (MAILSTREAM *stream)
|
yuuji@0
|
1043 {
|
yuuji@0
|
1044 --critical;
|
yuuji@0
|
1045 }
|
yuuji@0
|
1046
|
yuuji@0
|
1047
|
yuuji@0
|
1048 /* Disk error found
|
yuuji@0
|
1049 * Accepts: stream
|
yuuji@0
|
1050 * system error code
|
yuuji@0
|
1051 * flag indicating that mailbox may be clobbered
|
yuuji@0
|
1052 * Returns: abort flag
|
yuuji@0
|
1053 */
|
yuuji@0
|
1054
|
yuuji@0
|
1055 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
|
yuuji@0
|
1056 {
|
yuuji@0
|
1057 if (serious) { /* try your damnest if clobberage likely */
|
yuuji@0
|
1058 syslog (LOG_ALERT,
|
yuuji@0
|
1059 "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
|
yuuji@0
|
1060 user,tcp_clienthost (),
|
yuuji@0
|
1061 (stream && stream->mailbox) ? stream->mailbox : "???",
|
yuuji@0
|
1062 strerror (errcode));
|
yuuji@0
|
1063 alarm (0); /* make damn sure timeout disabled */
|
yuuji@0
|
1064 sleep (60); /* give it some time to clear up */
|
yuuji@0
|
1065 return NIL;
|
yuuji@0
|
1066 }
|
yuuji@0
|
1067 syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
|
yuuji@0
|
1068 user,tcp_clienthost (),
|
yuuji@0
|
1069 (stream && stream->mailbox) ? stream->mailbox : "???",
|
yuuji@0
|
1070 strerror (errcode));
|
yuuji@0
|
1071 return T;
|
yuuji@0
|
1072 }
|
yuuji@0
|
1073
|
yuuji@0
|
1074
|
yuuji@0
|
1075 /* Log a fatal error event
|
yuuji@0
|
1076 * Accepts: string to log
|
yuuji@0
|
1077 */
|
yuuji@0
|
1078
|
yuuji@0
|
1079 void mm_fatal (char *string)
|
yuuji@0
|
1080 {
|
yuuji@0
|
1081 mm_log (string,ERROR); /* shouldn't happen normally */
|
yuuji@0
|
1082 }
|