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: IPOP2D - IMAP to POP2 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: 28 October 1990
|
yuuji@0
|
24 * Last Edited: 13 February 2008
|
yuuji@0
|
25 */
|
yuuji@0
|
26
|
yuuji@0
|
27
|
yuuji@0
|
28 /* Parameter files */
|
yuuji@0
|
29
|
yuuji@0
|
30 #include <stdio.h>
|
yuuji@0
|
31 #include <ctype.h>
|
yuuji@0
|
32 #include <errno.h>
|
yuuji@0
|
33 extern int errno; /* just in case */
|
yuuji@0
|
34 #include <signal.h>
|
yuuji@0
|
35 #include <time.h>
|
yuuji@0
|
36 #include "c-client.h"
|
yuuji@0
|
37
|
yuuji@0
|
38
|
yuuji@0
|
39 /* Autologout timer */
|
yuuji@0
|
40 #define KODTIMEOUT 60*5
|
yuuji@0
|
41 #define LOGINTIMEOUT 60*3
|
yuuji@0
|
42 #define TIMEOUT 60*30
|
yuuji@0
|
43
|
yuuji@0
|
44
|
yuuji@0
|
45 /* Size of temporary buffers */
|
yuuji@0
|
46 #define TMPLEN 1024
|
yuuji@0
|
47
|
yuuji@0
|
48
|
yuuji@0
|
49 /* Server states */
|
yuuji@0
|
50
|
yuuji@0
|
51 #define LISN 0
|
yuuji@0
|
52 #define AUTH 1
|
yuuji@0
|
53 #define MBOX 2
|
yuuji@0
|
54 #define ITEM 3
|
yuuji@0
|
55 #define NEXT 4
|
yuuji@0
|
56 #define DONE 5
|
yuuji@0
|
57
|
yuuji@0
|
58 /* Global storage */
|
yuuji@0
|
59
|
yuuji@0
|
60 char *version = "75"; /* edit number of this server */
|
yuuji@0
|
61 short state = LISN; /* server state */
|
yuuji@0
|
62 short critical = NIL; /* non-zero if in critical code */
|
yuuji@0
|
63 MAILSTREAM *stream = NIL; /* mailbox stream */
|
yuuji@0
|
64 time_t idletime = 0; /* time we went idle */
|
yuuji@0
|
65 unsigned long nmsgs = 0; /* number of messages */
|
yuuji@0
|
66 unsigned long current = 1; /* current message number */
|
yuuji@0
|
67 unsigned long size = 0; /* size of current message */
|
yuuji@0
|
68 char status[MAILTMPLEN]; /* space for status string */
|
yuuji@0
|
69 char *user = ""; /* user name */
|
yuuji@0
|
70 char *pass = ""; /* password */
|
yuuji@0
|
71 unsigned long *msg = NIL; /* message translation vector */
|
yuuji@0
|
72 char *logout = "Logout";
|
yuuji@0
|
73 char *goodbye = "+ Sayonara\015\012";
|
yuuji@0
|
74
|
yuuji@0
|
75
|
yuuji@0
|
76 /* Function prototypes */
|
yuuji@0
|
77
|
yuuji@0
|
78 int main (int argc,char *argv[]);
|
yuuji@0
|
79 void sayonara (int status);
|
yuuji@0
|
80 void clkint ();
|
yuuji@0
|
81 void kodint ();
|
yuuji@0
|
82 void hupint ();
|
yuuji@0
|
83 void trmint ();
|
yuuji@0
|
84 short c_helo (char *t,int argc,char *argv[]);
|
yuuji@0
|
85 short c_fold (char *t);
|
yuuji@0
|
86 short c_read (char *t);
|
yuuji@0
|
87 short c_retr (char *t);
|
yuuji@0
|
88 short c_acks (char *t);
|
yuuji@0
|
89 short c_ackd (char *t);
|
yuuji@0
|
90 short c_nack (char *t);
|
yuuji@0
|
91
|
yuuji@0
|
92 /* Main program */
|
yuuji@0
|
93
|
yuuji@0
|
94 int main (int argc,char *argv[])
|
yuuji@0
|
95 {
|
yuuji@0
|
96 char *s,*t;
|
yuuji@0
|
97 char cmdbuf[TMPLEN];
|
yuuji@0
|
98 char *pgmname = (argc && argv[0]) ?
|
yuuji@0
|
99 (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
|
yuuji@0
|
100 s+1 : argv[0]) : "ipop2d";
|
yuuji@0
|
101 /* set service name before linkage */
|
yuuji@0
|
102 mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
|
yuuji@0
|
103 #include "linkage.c"
|
yuuji@0
|
104 if (mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)) {
|
yuuji@0
|
105 goodbye = "- POP2 server disabled on this system\015\012";
|
yuuji@0
|
106 sayonara (1);
|
yuuji@0
|
107 }
|
yuuji@0
|
108 /* initialize server */
|
yuuji@0
|
109 server_init (pgmname,"pop",NIL,clkint,kodint,hupint,trmint,NIL);
|
yuuji@0
|
110 /* There are reports of POP2 clients which get upset if anything appears
|
yuuji@0
|
111 * between the "+" and the "POP2" in the greeting.
|
yuuji@0
|
112 */
|
yuuji@0
|
113 printf ("+ POP2 %s %s.%s server ready\015\012",tcp_serverhost (),
|
yuuji@0
|
114 CCLIENTVERSION,version);
|
yuuji@0
|
115 fflush (stdout); /* dump output buffer */
|
yuuji@0
|
116 state = AUTH; /* initial server state */
|
yuuji@0
|
117 while (state != DONE) { /* command processing loop */
|
yuuji@0
|
118 idletime = time (0); /* get a command under timeout */
|
yuuji@0
|
119 alarm ((state != AUTH) ? TIMEOUT : LOGINTIMEOUT);
|
yuuji@0
|
120 clearerr (stdin); /* clear stdin errors */
|
yuuji@0
|
121 while (!fgets (cmdbuf,TMPLEN-1,stdin)) {
|
yuuji@0
|
122 if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
|
yuuji@0
|
123 else {
|
yuuji@0
|
124 char *e = ferror (stdin) ?
|
yuuji@0
|
125 strerror (errno) : "Unexpected client disconnect";
|
yuuji@0
|
126 alarm (0); /* disable all interrupts */
|
yuuji@0
|
127 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
128 sprintf (logout = cmdbuf,"%.80s while reading line",e);
|
yuuji@0
|
129 state = DONE;
|
yuuji@0
|
130 stream = mail_close (stream);
|
yuuji@0
|
131 goodbye = NIL;
|
yuuji@0
|
132 sayonara (1);
|
yuuji@0
|
133 }
|
yuuji@0
|
134 }
|
yuuji@0
|
135 alarm (0); /* make sure timeout disabled */
|
yuuji@0
|
136 idletime = 0; /* no longer idle */
|
yuuji@0
|
137 /* find end of line */
|
yuuji@0
|
138 if (!strchr (cmdbuf,'\012')) {
|
yuuji@0
|
139 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
140 logout = "- Command line too long\015\012";
|
yuuji@0
|
141 state = DONE;
|
yuuji@0
|
142 }
|
yuuji@0
|
143 else if (!(s = strtok (cmdbuf," \015\012"))) {
|
yuuji@0
|
144 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
145 goodbye = "- Missing or null command\015\012";
|
yuuji@0
|
146 state = DONE;
|
yuuji@0
|
147 }
|
yuuji@0
|
148 else { /* dispatch based on command */
|
yuuji@0
|
149 ucase (s); /* canonicalize case */
|
yuuji@0
|
150 /* snarf argument */
|
yuuji@0
|
151 t = strtok (NIL,"\015\012");
|
yuuji@0
|
152 if ((state == AUTH) && !strcmp (s,"HELO")) state = c_helo (t,argc,argv);
|
yuuji@0
|
153 else if ((state == MBOX || state == ITEM) && !strcmp (s,"FOLD"))
|
yuuji@0
|
154 state = c_fold (t);
|
yuuji@0
|
155 else if ((state == MBOX || state == ITEM) && !strcmp (s,"READ"))
|
yuuji@0
|
156 state = c_read (t);
|
yuuji@0
|
157 else if ((state == ITEM) && !strcmp (s,"RETR")) state = c_retr (t);
|
yuuji@0
|
158 else if ((state == NEXT) && !strcmp (s,"ACKS")) state = c_acks (t);
|
yuuji@0
|
159 else if ((state == NEXT) && !strcmp (s,"ACKD")) state = c_ackd (t);
|
yuuji@0
|
160 else if ((state == NEXT) && !strcmp (s,"NACK")) state = c_nack (t);
|
yuuji@0
|
161 else if ((state == AUTH || state == MBOX || state == ITEM) &&
|
yuuji@0
|
162 !strcmp (s,"QUIT")) {
|
yuuji@0
|
163 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
164 state = DONE; /* done in either case */
|
yuuji@0
|
165 if (t) goodbye = "- Bogus argument given to QUIT\015\012";
|
yuuji@0
|
166 else { /* expunge the stream */
|
yuuji@0
|
167 if (stream && nmsgs) stream = mail_close_full (stream,CL_EXPUNGE);
|
yuuji@0
|
168 stream = NIL; /* don't repeat it */
|
yuuji@0
|
169 }
|
yuuji@0
|
170 }
|
yuuji@0
|
171 else { /* some other or inappropriate command */
|
yuuji@0
|
172 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
173 goodbye = "- Bogus or out of sequence command\015\012";
|
yuuji@0
|
174 state = DONE;
|
yuuji@0
|
175 }
|
yuuji@0
|
176 }
|
yuuji@0
|
177 fflush (stdout); /* make sure output blatted */
|
yuuji@0
|
178 }
|
yuuji@0
|
179 /* clean up the stream */
|
yuuji@0
|
180 if (stream) mail_close (stream);
|
yuuji@0
|
181 sayonara (0);
|
yuuji@0
|
182 return 0; /* stupid compilers */
|
yuuji@0
|
183 }
|
yuuji@0
|
184
|
yuuji@0
|
185
|
yuuji@0
|
186 /* Say goodbye
|
yuuji@0
|
187 * Accepts: exit status
|
yuuji@0
|
188 *
|
yuuji@0
|
189 * Does not return
|
yuuji@0
|
190 */
|
yuuji@0
|
191
|
yuuji@0
|
192 void sayonara (int status)
|
yuuji@0
|
193 {
|
yuuji@0
|
194 logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
|
yuuji@0
|
195 if (goodbye) { /* have a goodbye message? */
|
yuuji@0
|
196 fputs (goodbye,stdout);
|
yuuji@0
|
197 fflush (stdout); /* make sure blatted */
|
yuuji@0
|
198 }
|
yuuji@0
|
199 syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
|
yuuji@0
|
200 user ? (char *) user : "???",tcp_clienthost ());
|
yuuji@0
|
201 /* do logout hook if needed */
|
yuuji@0
|
202 if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
|
yuuji@0
|
203 _exit (status); /* all done */
|
yuuji@0
|
204 }
|
yuuji@0
|
205
|
yuuji@0
|
206 /* Clock interrupt
|
yuuji@0
|
207 */
|
yuuji@0
|
208
|
yuuji@0
|
209 void clkint ()
|
yuuji@0
|
210 {
|
yuuji@0
|
211 alarm (0); /* disable all interrupts */
|
yuuji@0
|
212 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
213 goodbye = "- Autologout; idle for too long\015\012";
|
yuuji@0
|
214 logout = "Autologout";
|
yuuji@0
|
215 state = DONE; /* mark state done in either case */
|
yuuji@0
|
216 if (!critical) { /* badly host if in critical code */
|
yuuji@0
|
217 if (stream && !stream->lock) mail_close (stream);
|
yuuji@0
|
218 stream = NIL;
|
yuuji@0
|
219 sayonara (1); /* die die die */
|
yuuji@0
|
220 }
|
yuuji@0
|
221 }
|
yuuji@0
|
222
|
yuuji@0
|
223
|
yuuji@0
|
224 /* Kiss Of Death interrupt
|
yuuji@0
|
225 */
|
yuuji@0
|
226
|
yuuji@0
|
227 void kodint ()
|
yuuji@0
|
228 {
|
yuuji@0
|
229 /* only if in command wait */
|
yuuji@0
|
230 if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
|
yuuji@0
|
231 alarm (0); /* disable all interrupts */
|
yuuji@0
|
232 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
233 goodbye = "- Killed (lost mailbox lock)\015\012";
|
yuuji@0
|
234 logout = "Killed (lost mailbox lock)";
|
yuuji@0
|
235 state = DONE; /* mark state done in either case */
|
yuuji@0
|
236 if (!critical) { /* badly host if in critical code */
|
yuuji@0
|
237 if (stream && !stream->lock) mail_close (stream);
|
yuuji@0
|
238 stream = NIL;
|
yuuji@0
|
239 sayonara (1); /* die die die */
|
yuuji@0
|
240 }
|
yuuji@0
|
241 }
|
yuuji@0
|
242 }
|
yuuji@0
|
243
|
yuuji@0
|
244
|
yuuji@0
|
245 /* Hangup interrupt
|
yuuji@0
|
246 */
|
yuuji@0
|
247
|
yuuji@0
|
248 void hupint ()
|
yuuji@0
|
249 {
|
yuuji@0
|
250 alarm (0); /* disable all interrupts */
|
yuuji@0
|
251 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
252 goodbye = NIL;
|
yuuji@0
|
253 logout = "Hangup";
|
yuuji@0
|
254 state = DONE; /* mark state done in either case */
|
yuuji@0
|
255 if (!critical) { /* badly host if in critical code */
|
yuuji@0
|
256 if (stream && !stream->lock) mail_close (stream);
|
yuuji@0
|
257 stream = NIL;
|
yuuji@0
|
258 sayonara (1); /* die die die */
|
yuuji@0
|
259 }
|
yuuji@0
|
260 }
|
yuuji@0
|
261
|
yuuji@0
|
262
|
yuuji@0
|
263 /* Termination interrupt
|
yuuji@0
|
264 */
|
yuuji@0
|
265
|
yuuji@0
|
266 void trmint ()
|
yuuji@0
|
267 {
|
yuuji@0
|
268 alarm (0); /* disable all interrupts */
|
yuuji@0
|
269 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
270 goodbye = "- Killed (terminated)\015\012";
|
yuuji@0
|
271 logout = "Killed (terminated)";
|
yuuji@0
|
272 if (critical) state = DONE; /* mark state done in either case */
|
yuuji@0
|
273 /* Make no attempt at graceful closure since a shutdown may be in
|
yuuji@0
|
274 * progress, and we won't have any time to do mail_close() actions.
|
yuuji@0
|
275 */
|
yuuji@0
|
276 else sayonara (1); /* die die die */
|
yuuji@0
|
277 }
|
yuuji@0
|
278
|
yuuji@0
|
279 /* Parse HELO command
|
yuuji@0
|
280 * Accepts: pointer to command argument
|
yuuji@0
|
281 * Returns: new state
|
yuuji@0
|
282 */
|
yuuji@0
|
283
|
yuuji@0
|
284 short c_helo (char *t,int argc,char *argv[])
|
yuuji@0
|
285 {
|
yuuji@0
|
286 char *s,*u,*p;
|
yuuji@0
|
287 char tmp[TMPLEN];
|
yuuji@0
|
288 if ((!(t && *t && (u = strtok (t," ")) && (p = strtok (NIL,"\015\012")))) ||
|
yuuji@0
|
289 (strlen (p) >= TMPLEN)) { /* get user name and password */
|
yuuji@0
|
290 fputs ("- Missing user or password\015\012",stdout);
|
yuuji@0
|
291 return DONE;
|
yuuji@0
|
292 }
|
yuuji@0
|
293 /* copy password, handle quoting */
|
yuuji@0
|
294 for (s = tmp; *p; p++) *s++ = (*p == '\\') ? *++p : *p;
|
yuuji@0
|
295 *s = '\0'; /* tie off string */
|
yuuji@0
|
296 pass = cpystr (tmp);
|
yuuji@0
|
297 if (!(s = strchr (u,':'))) { /* want remote mailbox? */
|
yuuji@0
|
298 /* no, delimit user from possible admin */
|
yuuji@0
|
299 if (s = strchr (u,'*')) *s++ = '\0';
|
yuuji@0
|
300 if (server_login (user = cpystr (u),pass,s,argc,argv)) {
|
yuuji@0
|
301 syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s",s ? "Admin " : "",
|
yuuji@0
|
302 user,tcp_clienthost ());
|
yuuji@0
|
303 return c_fold ("INBOX"); /* local; select INBOX */
|
yuuji@0
|
304 }
|
yuuji@0
|
305 }
|
yuuji@0
|
306 #ifndef DISABLE_POP_PROXY
|
yuuji@0
|
307 /* can't do if can't log in as anonymous */
|
yuuji@0
|
308 else if (anonymous_login (argc,argv)) {
|
yuuji@0
|
309 *s++ = '\0'; /* separate host name from user name */
|
yuuji@0
|
310 user = cpystr (s); /* note user name */
|
yuuji@0
|
311 syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",u,user,
|
yuuji@0
|
312 tcp_clienthost ());
|
yuuji@0
|
313 /* initially remote INBOX */
|
yuuji@0
|
314 sprintf (tmp,"{%.128s/user=%.128s}INBOX",u,user);
|
yuuji@0
|
315 /* disable rimap just in case */
|
yuuji@0
|
316 mail_parameters (NIL,SET_RSHTIMEOUT,0);
|
yuuji@0
|
317 return c_fold (tmp);
|
yuuji@0
|
318 }
|
yuuji@0
|
319 #endif
|
yuuji@0
|
320 fputs ("- Bad login\015\012",stdout);
|
yuuji@0
|
321 return DONE;
|
yuuji@0
|
322 }
|
yuuji@0
|
323
|
yuuji@0
|
324 /* Parse FOLD command
|
yuuji@0
|
325 * Accepts: pointer to command argument
|
yuuji@0
|
326 * Returns: new state
|
yuuji@0
|
327 */
|
yuuji@0
|
328
|
yuuji@0
|
329 short c_fold (char *t)
|
yuuji@0
|
330 {
|
yuuji@0
|
331 unsigned long i,j,flags;
|
yuuji@0
|
332 char *s = NIL,tmp[2*TMPLEN];
|
yuuji@0
|
333 NETMBX mb;
|
yuuji@0
|
334 if (!(t && *t)) { /* make sure there's an argument */
|
yuuji@0
|
335 fputs ("- Missing mailbox name\015\012",stdout);
|
yuuji@0
|
336 return DONE;
|
yuuji@0
|
337 }
|
yuuji@0
|
338 myusername_full (&flags); /* get user type flags */
|
yuuji@0
|
339 /* expunge old stream */
|
yuuji@0
|
340 if (stream && nmsgs) mail_expunge (stream);
|
yuuji@0
|
341 nmsgs = 0; /* no more messages */
|
yuuji@0
|
342 if (msg) fs_give ((void **) &msg);
|
yuuji@0
|
343 #ifndef DISABLE_POP_PROXY
|
yuuji@0
|
344 if (flags == MU_ANONYMOUS) { /* don't permit proxy to leave IMAP */
|
yuuji@0
|
345 if (stream) { /* not first time */
|
yuuji@0
|
346 if (!(stream->mailbox && (s = strchr (stream->mailbox,'}'))))
|
yuuji@0
|
347 fatal ("bad previous mailbox name");
|
yuuji@0
|
348 strncpy (tmp,stream->mailbox,i = (++s - stream->mailbox));
|
yuuji@0
|
349 if (i >= TMPLEN) fatal ("ridiculous network prefix");
|
yuuji@0
|
350 strcpy (tmp+i,t); /* append mailbox to initial spec */
|
yuuji@0
|
351 t = tmp;
|
yuuji@0
|
352 }
|
yuuji@0
|
353 /* must be net name first time */
|
yuuji@0
|
354 else if (!mail_valid_net_parse (t,&mb)) fatal ("anonymous folder bogon");
|
yuuji@0
|
355 }
|
yuuji@0
|
356 #endif
|
yuuji@0
|
357 /* open mailbox, note # of messages */
|
yuuji@0
|
358 if (j = (stream = mail_open (stream,t,NIL)) ? stream->nmsgs : 0) {
|
yuuji@0
|
359 sprintf (tmp,"1:%lu",j); /* fetch fast information for all messages */
|
yuuji@0
|
360 mail_fetch_fast (stream,tmp,NIL);
|
yuuji@0
|
361 msg = (unsigned long *) fs_get ((stream->nmsgs + 1) *
|
yuuji@0
|
362 sizeof (unsigned long));
|
yuuji@0
|
363 for (i = 1; i <= j; i++) /* find undeleted messages, add to vector */
|
yuuji@0
|
364 if (!mail_elt (stream,i)->deleted) msg[++nmsgs] = i;
|
yuuji@0
|
365 }
|
yuuji@0
|
366 #ifndef DISABLE_POP_PROXY
|
yuuji@0
|
367 if (!stream && (flags == MU_ANONYMOUS)) {
|
yuuji@0
|
368 fputs ("- Bad login\015\012",stdout);
|
yuuji@0
|
369 return DONE;
|
yuuji@0
|
370 }
|
yuuji@0
|
371 #endif
|
yuuji@0
|
372 printf ("#%lu messages in %s\015\012",nmsgs,stream ? stream->mailbox :
|
yuuji@0
|
373 "<none>");
|
yuuji@0
|
374 return MBOX;
|
yuuji@0
|
375 }
|
yuuji@0
|
376
|
yuuji@0
|
377 /* Parse READ command
|
yuuji@0
|
378 * Accepts: pointer to command argument
|
yuuji@0
|
379 * Returns: new state
|
yuuji@0
|
380 */
|
yuuji@0
|
381
|
yuuji@0
|
382 short c_read (char *t)
|
yuuji@0
|
383 {
|
yuuji@0
|
384 MESSAGECACHE *elt = NIL;
|
yuuji@0
|
385 if (t && *t) { /* have a message number argument? */
|
yuuji@0
|
386 /* validity check message number */
|
yuuji@0
|
387 if (((current = strtoul (t,NIL,10)) < 1) || (current > nmsgs)) {
|
yuuji@0
|
388 fputs ("- Invalid message number given to READ\015\012",stdout);
|
yuuji@0
|
389 return DONE;
|
yuuji@0
|
390 }
|
yuuji@0
|
391 }
|
yuuji@0
|
392 else if (current > nmsgs) { /* at end of mailbox? */
|
yuuji@0
|
393 fputs ("=0 No more messages\015\012",stdout);
|
yuuji@0
|
394 return MBOX;
|
yuuji@0
|
395 }
|
yuuji@0
|
396 /* set size if message valid and exists */
|
yuuji@0
|
397 size = msg[current] ? (elt = mail_elt(stream,msg[current]))->rfc822_size : 0;
|
yuuji@0
|
398 if (elt) sprintf (status,"Status: %s%s\015\012",
|
yuuji@0
|
399 elt->seen ? "R" : " ",elt->recent ? " " : "O");
|
yuuji@0
|
400 else status[0] = '\0'; /* no status */
|
yuuji@0
|
401 size += strlen (status); /* update size to reflect status */
|
yuuji@0
|
402 /* display results */
|
yuuji@0
|
403 printf ("=%lu characters in message %lu\015\012",size + 2,current);
|
yuuji@0
|
404 return ITEM;
|
yuuji@0
|
405 }
|
yuuji@0
|
406
|
yuuji@0
|
407
|
yuuji@0
|
408 /* Parse RETR command
|
yuuji@0
|
409 * Accepts: pointer to command argument
|
yuuji@0
|
410 * Returns: new state
|
yuuji@0
|
411 */
|
yuuji@0
|
412
|
yuuji@0
|
413 short c_retr (char *t)
|
yuuji@0
|
414 {
|
yuuji@0
|
415 unsigned long i,j;
|
yuuji@0
|
416 STRING *bs;
|
yuuji@0
|
417 if (t) { /* disallow argument */
|
yuuji@0
|
418 fputs ("- Bogus argument given to RETR\015\012",stdout);
|
yuuji@0
|
419 return DONE;
|
yuuji@0
|
420 }
|
yuuji@0
|
421 if (size) { /* message size valid? */
|
yuuji@0
|
422 t = mail_fetch_header (stream,msg[current],NIL,NIL,&i,FT_PEEK);
|
yuuji@0
|
423 if (i > 2) { /* only if there is something */
|
yuuji@0
|
424 i -= 2; /* lop off last two octets */
|
yuuji@0
|
425 while (i) { /* blat the header */
|
yuuji@0
|
426 if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
|
yuuji@0
|
427 if (i -= j) t += j; /* advance to incomplete data */
|
yuuji@0
|
428 }
|
yuuji@0
|
429 }
|
yuuji@0
|
430 fputs (status,stdout); /* yes, output message */
|
yuuji@0
|
431 fputs ("\015\012",stdout); /* delimit header from text */
|
yuuji@0
|
432 if (t = mail_fetch_text (stream,msg[current],NIL,&i,FT_RETURNSTRINGSTRUCT))
|
yuuji@0
|
433 while (i) { /* blat the text */
|
yuuji@0
|
434 if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
|
yuuji@0
|
435 if (i -= j) t += j; /* advance to incomplete data */
|
yuuji@0
|
436 }
|
yuuji@0
|
437 else for (bs = &stream->private.string; i--; )
|
yuuji@0
|
438 if (putc (SNX (bs),stdout) == EOF) return DONE;
|
yuuji@0
|
439 fputs ("\015\012",stdout); /* trailer to coddle PCNFS' NFSMAIL */
|
yuuji@0
|
440 }
|
yuuji@0
|
441 else return DONE; /* otherwise go away */
|
yuuji@0
|
442 return NEXT;
|
yuuji@0
|
443 }
|
yuuji@0
|
444
|
yuuji@0
|
445 /* Parse ACKS command
|
yuuji@0
|
446 * Accepts: pointer to command argument
|
yuuji@0
|
447 * Returns: new state
|
yuuji@0
|
448 */
|
yuuji@0
|
449
|
yuuji@0
|
450 short c_acks (char *t)
|
yuuji@0
|
451 {
|
yuuji@0
|
452 char tmp[TMPLEN];
|
yuuji@0
|
453 if (t) { /* disallow argument */
|
yuuji@0
|
454 fputs ("- Bogus argument given to ACKS\015\012",stdout);
|
yuuji@0
|
455 return DONE;
|
yuuji@0
|
456 }
|
yuuji@0
|
457 /* mark message as seen */
|
yuuji@0
|
458 sprintf (tmp,"%lu",msg[current++]);
|
yuuji@0
|
459 mail_setflag (stream,tmp,"\\Seen");
|
yuuji@0
|
460 return c_read (NIL); /* end message reading transaction */
|
yuuji@0
|
461 }
|
yuuji@0
|
462
|
yuuji@0
|
463
|
yuuji@0
|
464 /* Parse ACKD command
|
yuuji@0
|
465 * Accepts: pointer to command argument
|
yuuji@0
|
466 * Returns: new state
|
yuuji@0
|
467 */
|
yuuji@0
|
468
|
yuuji@0
|
469 short c_ackd (char *t)
|
yuuji@0
|
470 {
|
yuuji@0
|
471 char tmp[TMPLEN];
|
yuuji@0
|
472 if (t) { /* disallow argument */
|
yuuji@0
|
473 fputs ("- Bogus argument given to ACKD\015\012",stdout);
|
yuuji@0
|
474 return DONE;
|
yuuji@0
|
475 }
|
yuuji@0
|
476 /* mark message as seen and deleted */
|
yuuji@0
|
477 sprintf (tmp,"%lu",msg[current]);
|
yuuji@0
|
478 mail_setflag (stream,tmp,"\\Seen \\Deleted");
|
yuuji@0
|
479 msg[current++] = 0; /* mark message as deleted */
|
yuuji@0
|
480 return c_read (NIL); /* end message reading transaction */
|
yuuji@0
|
481 }
|
yuuji@0
|
482
|
yuuji@0
|
483
|
yuuji@0
|
484 /* Parse NACK command
|
yuuji@0
|
485 * Accepts: pointer to command argument
|
yuuji@0
|
486 * Returns: new state
|
yuuji@0
|
487 */
|
yuuji@0
|
488
|
yuuji@0
|
489 short c_nack (char *t)
|
yuuji@0
|
490 {
|
yuuji@0
|
491 if (t) { /* disallow argument */
|
yuuji@0
|
492 fputs ("- Bogus argument given to NACK\015\012",stdout);
|
yuuji@0
|
493 return DONE;
|
yuuji@0
|
494 }
|
yuuji@0
|
495 return c_read (NIL); /* end message reading transaction */
|
yuuji@0
|
496 }
|
yuuji@0
|
497
|
yuuji@0
|
498 /* Co-routines from MAIL library */
|
yuuji@0
|
499
|
yuuji@0
|
500
|
yuuji@0
|
501 /* Message matches a search
|
yuuji@0
|
502 * Accepts: MAIL stream
|
yuuji@0
|
503 * message number
|
yuuji@0
|
504 */
|
yuuji@0
|
505
|
yuuji@0
|
506 void mm_searched (MAILSTREAM *stream,unsigned long msgno)
|
yuuji@0
|
507 {
|
yuuji@0
|
508 /* Never called */
|
yuuji@0
|
509 }
|
yuuji@0
|
510
|
yuuji@0
|
511
|
yuuji@0
|
512 /* Message exists (i.e. there are that many messages in the mailbox)
|
yuuji@0
|
513 * Accepts: MAIL stream
|
yuuji@0
|
514 * message number
|
yuuji@0
|
515 */
|
yuuji@0
|
516
|
yuuji@0
|
517 void mm_exists (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
518 {
|
yuuji@0
|
519 /* Can't use this mechanism. POP has no means of notifying the client of
|
yuuji@0
|
520 new mail during the session. */
|
yuuji@0
|
521 }
|
yuuji@0
|
522
|
yuuji@0
|
523
|
yuuji@0
|
524 /* Message expunged
|
yuuji@0
|
525 * Accepts: MAIL stream
|
yuuji@0
|
526 * message number
|
yuuji@0
|
527 */
|
yuuji@0
|
528
|
yuuji@0
|
529 void mm_expunged (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
530 {
|
yuuji@0
|
531 if (state != DONE) { /* ignore if closing */
|
yuuji@0
|
532 /* someone else screwed us */
|
yuuji@0
|
533 goodbye = "- Mailbox expunged from under me!\015\012";
|
yuuji@0
|
534 if (stream && !stream->lock) mail_close (stream);
|
yuuji@0
|
535 stream = NIL;
|
yuuji@0
|
536 sayonara (1);
|
yuuji@0
|
537 }
|
yuuji@0
|
538 }
|
yuuji@0
|
539
|
yuuji@0
|
540
|
yuuji@0
|
541 /* Message status changed
|
yuuji@0
|
542 * Accepts: MAIL stream
|
yuuji@0
|
543 * message number
|
yuuji@0
|
544 */
|
yuuji@0
|
545
|
yuuji@0
|
546 void mm_flags (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
547 {
|
yuuji@0
|
548 /* This isn't used */
|
yuuji@0
|
549 }
|
yuuji@0
|
550
|
yuuji@0
|
551
|
yuuji@0
|
552 /* Mailbox found
|
yuuji@0
|
553 * Accepts: MAIL stream
|
yuuji@0
|
554 * hierarchy delimiter
|
yuuji@0
|
555 * mailbox name
|
yuuji@0
|
556 * mailbox attributes
|
yuuji@0
|
557 */
|
yuuji@0
|
558
|
yuuji@0
|
559 void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
yuuji@0
|
560 {
|
yuuji@0
|
561 /* This isn't used */
|
yuuji@0
|
562 }
|
yuuji@0
|
563
|
yuuji@0
|
564
|
yuuji@0
|
565 /* Subscribe mailbox found
|
yuuji@0
|
566 * Accepts: MAIL stream
|
yuuji@0
|
567 * hierarchy delimiter
|
yuuji@0
|
568 * mailbox name
|
yuuji@0
|
569 * mailbox attributes
|
yuuji@0
|
570 */
|
yuuji@0
|
571
|
yuuji@0
|
572 void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
yuuji@0
|
573 {
|
yuuji@0
|
574 /* This isn't used */
|
yuuji@0
|
575 }
|
yuuji@0
|
576
|
yuuji@0
|
577
|
yuuji@0
|
578 /* Mailbox status
|
yuuji@0
|
579 * Accepts: MAIL stream
|
yuuji@0
|
580 * mailbox name
|
yuuji@0
|
581 * mailbox status
|
yuuji@0
|
582 */
|
yuuji@0
|
583
|
yuuji@0
|
584 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
|
yuuji@0
|
585 {
|
yuuji@0
|
586 /* This isn't used */
|
yuuji@0
|
587 }
|
yuuji@0
|
588
|
yuuji@0
|
589 /* Notification event
|
yuuji@0
|
590 * Accepts: MAIL stream
|
yuuji@0
|
591 * string to log
|
yuuji@0
|
592 * error flag
|
yuuji@0
|
593 */
|
yuuji@0
|
594
|
yuuji@0
|
595 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
|
yuuji@0
|
596 {
|
yuuji@0
|
597 mm_log (string,errflg); /* just do mm_log action */
|
yuuji@0
|
598 }
|
yuuji@0
|
599
|
yuuji@0
|
600
|
yuuji@0
|
601 /* Log an event for the user to see
|
yuuji@0
|
602 * Accepts: string to log
|
yuuji@0
|
603 * error flag
|
yuuji@0
|
604 */
|
yuuji@0
|
605
|
yuuji@0
|
606 void mm_log (char *string,long errflg)
|
yuuji@0
|
607 {
|
yuuji@0
|
608 switch (errflg) {
|
yuuji@0
|
609 case NIL: /* information message */
|
yuuji@0
|
610 case PARSE: /* parse glitch */
|
yuuji@0
|
611 break; /* too many of these to log */
|
yuuji@0
|
612 case WARN: /* warning */
|
yuuji@0
|
613 syslog (LOG_DEBUG,"%s",string);
|
yuuji@0
|
614 break;
|
yuuji@0
|
615 case BYE: /* driver broke connection */
|
yuuji@0
|
616 if (state != DONE) {
|
yuuji@0
|
617 char tmp[MAILTMPLEN];
|
yuuji@0
|
618 alarm (0); /* disable all interrupts */
|
yuuji@0
|
619 server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
|
yuuji@0
|
620 sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
|
yuuji@0
|
621 sayonara (1);
|
yuuji@0
|
622 }
|
yuuji@0
|
623 break;
|
yuuji@0
|
624 case ERROR: /* error that broke command */
|
yuuji@0
|
625 default: /* default should never happen */
|
yuuji@0
|
626 syslog (LOG_NOTICE,"%s",string);
|
yuuji@0
|
627 break;
|
yuuji@0
|
628 }
|
yuuji@0
|
629 }
|
yuuji@0
|
630
|
yuuji@0
|
631
|
yuuji@0
|
632 /* Log an event to debugging telemetry
|
yuuji@0
|
633 * Accepts: string to log
|
yuuji@0
|
634 */
|
yuuji@0
|
635
|
yuuji@0
|
636 void mm_dlog (char *string)
|
yuuji@0
|
637 {
|
yuuji@0
|
638 /* Not doing anything here for now */
|
yuuji@0
|
639 }
|
yuuji@0
|
640
|
yuuji@0
|
641
|
yuuji@0
|
642 /* Get user name and password for this host
|
yuuji@0
|
643 * Accepts: parse of network mailbox name
|
yuuji@0
|
644 * where to return user name
|
yuuji@0
|
645 * where to return password
|
yuuji@0
|
646 * trial count
|
yuuji@0
|
647 */
|
yuuji@0
|
648
|
yuuji@0
|
649 void mm_login (NETMBX *mb,char *username,char *password,long trial)
|
yuuji@0
|
650 {
|
yuuji@0
|
651 /* set user name */
|
yuuji@0
|
652 strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
|
yuuji@0
|
653 strncpy (password,pass,255); /* and password */
|
yuuji@0
|
654 username[NETMAXUSER] = password[255] = '\0';
|
yuuji@0
|
655 }
|
yuuji@0
|
656
|
yuuji@0
|
657 /* About to enter critical code
|
yuuji@0
|
658 * Accepts: stream
|
yuuji@0
|
659 */
|
yuuji@0
|
660
|
yuuji@0
|
661 void mm_critical (MAILSTREAM *stream)
|
yuuji@0
|
662 {
|
yuuji@0
|
663 ++critical;
|
yuuji@0
|
664 }
|
yuuji@0
|
665
|
yuuji@0
|
666
|
yuuji@0
|
667 /* About to exit critical code
|
yuuji@0
|
668 * Accepts: stream
|
yuuji@0
|
669 */
|
yuuji@0
|
670
|
yuuji@0
|
671 void mm_nocritical (MAILSTREAM *stream)
|
yuuji@0
|
672 {
|
yuuji@0
|
673 --critical;
|
yuuji@0
|
674 }
|
yuuji@0
|
675
|
yuuji@0
|
676
|
yuuji@0
|
677 /* Disk error found
|
yuuji@0
|
678 * Accepts: stream
|
yuuji@0
|
679 * system error code
|
yuuji@0
|
680 * flag indicating that mailbox may be clobbered
|
yuuji@0
|
681 * Returns: abort flag
|
yuuji@0
|
682 */
|
yuuji@0
|
683
|
yuuji@0
|
684 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
|
yuuji@0
|
685 {
|
yuuji@0
|
686 if (serious) { /* try your damnest if clobberage likely */
|
yuuji@0
|
687 syslog (LOG_ALERT,
|
yuuji@0
|
688 "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
|
yuuji@0
|
689 user,tcp_clienthost (),
|
yuuji@0
|
690 (stream && stream->mailbox) ? stream->mailbox : "???",
|
yuuji@0
|
691 strerror (errcode));
|
yuuji@0
|
692 alarm (0); /* make damn sure timeout disabled */
|
yuuji@0
|
693 sleep (60); /* give it some time to clear up */
|
yuuji@0
|
694 return NIL;
|
yuuji@0
|
695 }
|
yuuji@0
|
696 syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
|
yuuji@0
|
697 user,tcp_clienthost (),
|
yuuji@0
|
698 (stream && stream->mailbox) ? stream->mailbox : "???",
|
yuuji@0
|
699 strerror (errcode));
|
yuuji@0
|
700 return T;
|
yuuji@0
|
701 }
|
yuuji@0
|
702
|
yuuji@0
|
703
|
yuuji@0
|
704 /* Log a fatal error event
|
yuuji@0
|
705 * Accepts: string to log
|
yuuji@0
|
706 */
|
yuuji@0
|
707
|
yuuji@0
|
708 void mm_fatal (char *string)
|
yuuji@0
|
709 {
|
yuuji@0
|
710 mm_log (string,ERROR); /* shouldn't happen normally */
|
yuuji@0
|
711 }
|