rev |
line source |
yuuji@0
|
1 /* ========================================================================
|
yuuji@0
|
2 * Copyright 1988-2007 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: Mail Delivery Module
|
yuuji@0
|
16 *
|
yuuji@0
|
17 * Author: Mark Crispin
|
yuuji@0
|
18 * Networks and Distributed Computing
|
yuuji@0
|
19 * Computing & Communications
|
yuuji@0
|
20 * University of Washington
|
yuuji@0
|
21 * Administration Building, AG-44
|
yuuji@0
|
22 * Seattle, WA 98195
|
yuuji@0
|
23 * Internet: MRC@CAC.Washington.EDU
|
yuuji@0
|
24 *
|
yuuji@0
|
25 * Date: 5 April 1993
|
yuuji@0
|
26 * Last Edited: 30 October 2008
|
yuuji@0
|
27 */
|
yuuji@0
|
28
|
yuuji@0
|
29 #include <stdio.h>
|
yuuji@0
|
30 #include <pwd.h>
|
yuuji@0
|
31 #include <errno.h>
|
yuuji@0
|
32 extern int errno; /* just in case */
|
yuuji@0
|
33 #include <sysexits.h>
|
yuuji@0
|
34 #include <sys/file.h>
|
yuuji@0
|
35 #include <sys/stat.h>
|
yuuji@0
|
36 #include "c-client.h"
|
yuuji@0
|
37 #include "tquota.h"
|
yuuji@0
|
38
|
yuuji@0
|
39
|
yuuji@0
|
40 /* Globals */
|
yuuji@0
|
41
|
yuuji@0
|
42 char *version = "22"; /* tmail edit version */
|
yuuji@0
|
43 int debug = NIL; /* debugging (don't fork) */
|
yuuji@0
|
44 int trycreate = NIL; /* flag saying gotta create before appending */
|
yuuji@0
|
45 int critical = NIL; /* flag saying in critical code */
|
yuuji@0
|
46 char *sender = NIL; /* message origin */
|
yuuji@0
|
47 char *inbox = NIL; /* inbox file */
|
yuuji@0
|
48 long precedence = 0; /* delivery precedence - used by quota hook */
|
yuuji@0
|
49 DRIVER *format = NIL; /* desired format */
|
yuuji@0
|
50
|
yuuji@0
|
51
|
yuuji@0
|
52 /* Function prototypes */
|
yuuji@0
|
53
|
yuuji@0
|
54 void file_string_init (STRING *s,void *data,unsigned long size);
|
yuuji@0
|
55 char file_string_next (STRING *s);
|
yuuji@0
|
56 void file_string_setpos (STRING *s,unsigned long i);
|
yuuji@0
|
57 int main (int argc,char *argv[]);
|
yuuji@0
|
58 int deliver (FILE *f,unsigned long msglen,char *user);
|
yuuji@0
|
59 long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
|
yuuji@0
|
60 int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
|
yuuji@0
|
61 uid_t uid,char *tmp);
|
yuuji@0
|
62 int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp);
|
yuuji@0
|
63 int fail (char *string,int code);
|
yuuji@0
|
64 char *getusername (char *s,char **t);
|
yuuji@0
|
65
|
yuuji@0
|
66
|
yuuji@0
|
67 /* File string driver for file stringstructs */
|
yuuji@0
|
68
|
yuuji@0
|
69 STRINGDRIVER file_string = {
|
yuuji@0
|
70 file_string_init, /* initialize string structure */
|
yuuji@0
|
71 file_string_next, /* get next byte in string structure */
|
yuuji@0
|
72 file_string_setpos /* set position in string structure */
|
yuuji@0
|
73 };
|
yuuji@0
|
74
|
yuuji@0
|
75
|
yuuji@0
|
76 /* Cache buffer for file stringstructs */
|
yuuji@0
|
77
|
yuuji@0
|
78 #define CHUNKLEN 16384
|
yuuji@0
|
79 char chunk[CHUNKLEN];
|
yuuji@0
|
80
|
yuuji@0
|
81 /* Initialize file string structure for file stringstruct
|
yuuji@0
|
82 * Accepts: string structure
|
yuuji@0
|
83 * pointer to string
|
yuuji@0
|
84 * size of string
|
yuuji@0
|
85 */
|
yuuji@0
|
86
|
yuuji@0
|
87 void file_string_init (STRING *s,void *data,unsigned long size)
|
yuuji@0
|
88 {
|
yuuji@0
|
89 s->data = data; /* note fd */
|
yuuji@0
|
90 s->size = size; /* note size */
|
yuuji@0
|
91 s->chunk = chunk;
|
yuuji@0
|
92 s->chunksize = (unsigned long) CHUNKLEN;
|
yuuji@0
|
93 SETPOS (s,0); /* set initial position */
|
yuuji@0
|
94 }
|
yuuji@0
|
95
|
yuuji@0
|
96
|
yuuji@0
|
97 /* Get next character from file stringstruct
|
yuuji@0
|
98 * Accepts: string structure
|
yuuji@0
|
99 * Returns: character, string structure chunk refreshed
|
yuuji@0
|
100 */
|
yuuji@0
|
101
|
yuuji@0
|
102 char file_string_next (STRING *s)
|
yuuji@0
|
103 {
|
yuuji@0
|
104 char c = *s->curpos++; /* get next byte */
|
yuuji@0
|
105 SETPOS (s,GETPOS (s)); /* move to next chunk */
|
yuuji@0
|
106 return c; /* return the byte */
|
yuuji@0
|
107 }
|
yuuji@0
|
108
|
yuuji@0
|
109
|
yuuji@0
|
110 /* Set string pointer position for file stringstruct
|
yuuji@0
|
111 * Accepts: string structure
|
yuuji@0
|
112 * new position
|
yuuji@0
|
113 */
|
yuuji@0
|
114
|
yuuji@0
|
115 void file_string_setpos (STRING *s,unsigned long i)
|
yuuji@0
|
116 {
|
yuuji@0
|
117 if (i > s->size) i = s->size; /* don't permit setting beyond EOF */
|
yuuji@0
|
118 s->offset = i; /* set new offset */
|
yuuji@0
|
119 s->curpos = s->chunk; /* reset position */
|
yuuji@0
|
120 /* set size of data */
|
yuuji@0
|
121 if (s->cursize = min (s->chunksize,SIZE (s))) {
|
yuuji@0
|
122 /* move to that position in the file */
|
yuuji@0
|
123 fseek ((FILE *) s->data,s->offset,SEEK_SET);
|
yuuji@0
|
124 fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
|
yuuji@0
|
125 }
|
yuuji@0
|
126 }
|
yuuji@0
|
127
|
yuuji@0
|
128 /* Main program */
|
yuuji@0
|
129
|
yuuji@0
|
130 int main (int argc,char *argv[])
|
yuuji@0
|
131 {
|
yuuji@0
|
132 FILE *f = NIL;
|
yuuji@0
|
133 int pid,c,ret = 0;
|
yuuji@0
|
134 unsigned long msglen,status = 0;
|
yuuji@0
|
135 char *s,tmp[MAILTMPLEN];
|
yuuji@0
|
136 uid_t ruid = getuid ();
|
yuuji@0
|
137 struct passwd *pwd;
|
yuuji@0
|
138 openlog ("tmail",LOG_PID,LOG_MAIL);
|
yuuji@0
|
139 #include "linkage.c"
|
yuuji@0
|
140 /* make sure have some arguments */
|
yuuji@0
|
141 if (--argc < 1) _exit (fail ("usage: tmail [-D] user[+folder]",EX_USAGE));
|
yuuji@0
|
142 /* process all flags */
|
yuuji@0
|
143 while (argc && (*(s = *++argv)) == '-') {
|
yuuji@0
|
144 argc--; /* gobble this argument */
|
yuuji@0
|
145 switch (s[1]) { /* what is this flag? */
|
yuuji@0
|
146 case 'D': /* debug */
|
yuuji@0
|
147 debug = T; /* don't fork */
|
yuuji@0
|
148 break;
|
yuuji@0
|
149 case 'I': /* inbox specifier */
|
yuuji@0
|
150 if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
|
yuuji@0
|
151 if (argc--) inbox = cpystr (*++argv);
|
yuuji@0
|
152 else _exit (fail ("missing argument to -I",EX_USAGE));
|
yuuji@0
|
153 break;
|
yuuji@0
|
154 case 'f': /* new name for this flag */
|
yuuji@0
|
155 case 'r': /* flag giving return path */
|
yuuji@0
|
156 if (sender) _exit (fail ("duplicate -f or -r",EX_USAGE));
|
yuuji@0
|
157 if (argc--) sender = cpystr (*++argv);
|
yuuji@0
|
158 else _exit (fail ("missing argument to -f or -r",EX_USAGE));
|
yuuji@0
|
159 break;
|
yuuji@0
|
160 case 'b': /* create INBOX in this format */
|
yuuji@0
|
161 if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
|
yuuji@0
|
162 if (!argc--) _exit (fail ("missing argument to -b",EX_USAGE));
|
yuuji@0
|
163 if (!(format = mail_parameters (NIL,GET_DRIVER,*++argv)))
|
yuuji@0
|
164 _exit (fail ("unknown format to -b",EX_USAGE));
|
yuuji@0
|
165 else if (!(format->flags & DR_LOCAL) ||
|
yuuji@0
|
166 !compare_cstring (format->name,"dummy"))
|
yuuji@0
|
167 _exit (fail ("invalid format to -b",EX_USAGE));
|
yuuji@0
|
168 break;
|
yuuji@0
|
169 /* following flags are undocumented */
|
yuuji@0
|
170 case 'p': /* precedence for quota */
|
yuuji@0
|
171 if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
|
yuuji@0
|
172 else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
|
yuuji@0
|
173 precedence = atol (s);
|
yuuji@0
|
174 else _exit (fail ("missing argument to -p",EX_USAGE));
|
yuuji@0
|
175 break;
|
yuuji@0
|
176 case 'd': /* obsolete flag meaning multiple users */
|
yuuji@0
|
177 break; /* ignore silently */
|
yuuji@0
|
178 /* -s has been deprecated and replaced by the -s and -k flags in dmail.
|
yuuji@0
|
179 * dmail's -k flag does what -s once did in tmail; dmail's -s flag
|
yuuji@0
|
180 * takes no argument and just sets \Seen. Flag setting is more properly
|
yuuji@0
|
181 * done in dmail which runs as the user and is clearly at the user's
|
yuuji@0
|
182 * behest. Since tmail runs privileged, -s would have to be disabled
|
yuuji@0
|
183 * unless the caller is also privileged.
|
yuuji@0
|
184 */
|
yuuji@0
|
185 case 's': /* obsolete flag meaning delivery flags */
|
yuuji@0
|
186 if (!argc--) /* takes an argument */
|
yuuji@0
|
187 _exit (fail ("missing argument to deprecated flag",EX_USAGE));
|
yuuji@0
|
188 syslog (LOG_INFO,"tmail called with deprecated flag: -s %.200s",*++argv);
|
yuuji@0
|
189 break;
|
yuuji@0
|
190 default: /* anything else */
|
yuuji@0
|
191 _exit (fail ("unknown switch",EX_USAGE));
|
yuuji@0
|
192 }
|
yuuji@0
|
193 }
|
yuuji@0
|
194
|
yuuji@0
|
195 if (!argc) ret = fail ("no recipients",EX_USAGE);
|
yuuji@0
|
196 else if (!(f = tmpfile ())) ret = fail ("can't make temp file",EX_TEMPFAIL);
|
yuuji@0
|
197 else { /* build delivery headers */
|
yuuji@0
|
198 if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
|
yuuji@0
|
199 /* start Received line: */
|
yuuji@0
|
200 fprintf (f,"Received: via tmail-%s.%s",CCLIENTVERSION,version);
|
yuuji@0
|
201 /* not root or daemon? */
|
yuuji@0
|
202 if (ruid && !((pwd = getpwnam ("daemon")) && (ruid == pwd->pw_uid))) {
|
yuuji@0
|
203 pwd = getpwuid (ruid); /* get unprivileged user's information */
|
yuuji@0
|
204 if (inbox || format) {
|
yuuji@0
|
205 if (pwd) sprintf (tmp,"user %.80s",pwd->pw_name);
|
yuuji@0
|
206 else sprintf (tmp,"UID %ld",(long) ruid);
|
yuuji@0
|
207 strcat (tmp," is not privileged to use -b or -I");
|
yuuji@0
|
208 _exit (fail (tmp,EX_USAGE));
|
yuuji@0
|
209 }
|
yuuji@0
|
210 fputs (" (invoked by ",f);
|
yuuji@0
|
211 if (pwd) fprintf (f,"user %s",pwd->pw_name);
|
yuuji@0
|
212 else fprintf (f,"UID %ld",(long) ruid);
|
yuuji@0
|
213 fputs (")",f);
|
yuuji@0
|
214 }
|
yuuji@0
|
215 /* write "for" if single recipient */
|
yuuji@0
|
216 if (argc == 1) fprintf (f," for %s",*argv);
|
yuuji@0
|
217 fputs ("; ",f);
|
yuuji@0
|
218 rfc822_date (tmp);
|
yuuji@0
|
219 fputs (tmp,f);
|
yuuji@0
|
220 fputs ("\015\012",f);
|
yuuji@0
|
221 /* copy text from standard input */
|
yuuji@0
|
222 if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
|
yuuji@0
|
223 (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
|
yuuji@0
|
224 if (s[-1] == '\015') { /* nuke leading "From " line */
|
yuuji@0
|
225 if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
|
yuuji@0
|
226 (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
|
yuuji@0
|
227 while ((c = getchar ()) != EOF) putc (c,f);
|
yuuji@0
|
228 }
|
yuuji@0
|
229 else {
|
yuuji@0
|
230 mm_log ("tmail called with LF-only newlines",WARN);
|
yuuji@0
|
231 if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
|
yuuji@0
|
232 (tmp[3] != 'm') || (tmp[4] != ' ')) {
|
yuuji@0
|
233 *s++ = '\015'; /* overwrite NL with CRLF */
|
yuuji@0
|
234 *s++ = '\012';
|
yuuji@0
|
235 *s = '\0'; /* tie off string */
|
yuuji@0
|
236 fputs (tmp,f); /* write line */
|
yuuji@0
|
237 }
|
yuuji@0
|
238 /* copy text from standard input */
|
yuuji@0
|
239 while ((c = getchar ()) != EOF) {
|
yuuji@0
|
240 /* add CR if needed */
|
yuuji@0
|
241 if (c == '\012') putc ('\015',f);
|
yuuji@0
|
242 putc (c,f);
|
yuuji@0
|
243 }
|
yuuji@0
|
244 }
|
yuuji@0
|
245 msglen = ftell (f); /* size of message */
|
yuuji@0
|
246 fflush (f); /* make sure all changes written out */
|
yuuji@0
|
247
|
yuuji@0
|
248 if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
|
yuuji@0
|
249 else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
|
yuuji@0
|
250 /* single delivery */
|
yuuji@0
|
251 else if (argc == 1) ret = deliver (f,msglen,*argv);
|
yuuji@0
|
252 else do { /* multiple delivery uses daughter forks */
|
yuuji@0
|
253 if ((pid = fork ()) < 0) ret = fail (strerror (errno),EX_OSERR);
|
yuuji@0
|
254 else if (pid) { /* mother process */
|
yuuji@0
|
255 grim_pid_reap_status (pid,NIL,(void *) status);
|
yuuji@0
|
256 /* normal termination? */
|
yuuji@0
|
257 if (!ret) ret = (status & 0xff) ? EX_SOFTWARE : (status & 0xff00) >> 8;
|
yuuji@0
|
258 }
|
yuuji@0
|
259 /* daughter process */
|
yuuji@0
|
260 else _exit (deliver (f,msglen,*argv));
|
yuuji@0
|
261 } while (--argc && *argv++);
|
yuuji@0
|
262 mm_dlog (ret ? "error in delivery" : "all recipients delivered");
|
yuuji@0
|
263 }
|
yuuji@0
|
264 if (f) fclose (f); /* all done with temporary file */
|
yuuji@0
|
265 _exit (ret); /* normal exit */
|
yuuji@0
|
266 return 0; /* stupid gcc */
|
yuuji@0
|
267 }
|
yuuji@0
|
268
|
yuuji@0
|
269 /* Deliver message to recipient list
|
yuuji@0
|
270 * Accepts: file description of message temporary file
|
yuuji@0
|
271 * size of message temporary file in bytes
|
yuuji@0
|
272 * recipient name
|
yuuji@0
|
273 * Returns: NIL if success, else error code
|
yuuji@0
|
274 */
|
yuuji@0
|
275
|
yuuji@0
|
276 int deliver (FILE *f,unsigned long msglen,char *user)
|
yuuji@0
|
277 {
|
yuuji@0
|
278 MAILSTREAM *ds = NIL;
|
yuuji@0
|
279 char *s,*t,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
|
yuuji@0
|
280 struct passwd *pwd;
|
yuuji@0
|
281 STRING st;
|
yuuji@0
|
282 struct stat sbuf;
|
yuuji@0
|
283 uid_t duid;
|
yuuji@0
|
284 uid_t euid = geteuid ();
|
yuuji@0
|
285 /* get user record */
|
yuuji@0
|
286 if (!(pwd = getpwnam (getusername (user,&mailbox)))) {
|
yuuji@0
|
287 sprintf (tmp,"no such user as %.80s",user);
|
yuuji@0
|
288 return fail (tmp,EX_NOUSER);
|
yuuji@0
|
289 }
|
yuuji@0
|
290 /* absurd is absurd */
|
yuuji@0
|
291 if (mailbox && (strlen (mailbox) > 256))
|
yuuji@0
|
292 return fail ("absurd folder name",EX_NOUSER);
|
yuuji@0
|
293 /* big security hole if this is allowed */
|
yuuji@0
|
294 if (!(duid = pwd->pw_uid)) return fail ("mail to root prohibited",EX_NOUSER);
|
yuuji@0
|
295 /* log in as user if different than euid */
|
yuuji@0
|
296 if ((duid != euid) && !loginpw (pwd,1,&user)) {
|
yuuji@0
|
297 sprintf (tmp,"unable to log in UID %ld from UID %ld",
|
yuuji@0
|
298 (long) duid,(long) euid);
|
yuuji@0
|
299 return fail (tmp,EX_NOUSER);
|
yuuji@0
|
300 }
|
yuuji@0
|
301 /* can't use pwd after this point */
|
yuuji@0
|
302 env_init (pwd->pw_name,pwd->pw_dir);
|
yuuji@0
|
303 sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
|
yuuji@0
|
304 mm_dlog (tmp);
|
yuuji@0
|
305 /* prepare stringstruct */
|
yuuji@0
|
306 INIT (&st,file_string,(void *) f,msglen);
|
yuuji@0
|
307 if (mailbox) { /* non-INBOX name */
|
yuuji@0
|
308 switch (mailbox[0]) { /* make sure a valid name */
|
yuuji@0
|
309 default: /* other names, try to deliver if not INBOX */
|
yuuji@0
|
310 if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
|
yuuji@0
|
311 !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
|
yuuji@0
|
312 !deliver_safely (NIL,&st,mailbox,path,duid,tmp)) return NIL;
|
yuuji@0
|
313 case '%': case '*': /* wildcards not valid */
|
yuuji@0
|
314 case '#': /* namespace name not valid */
|
yuuji@0
|
315 case '/': /* absolute path names not valid */
|
yuuji@0
|
316 case '~': /* user names not valid */
|
yuuji@0
|
317 sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
|
yuuji@0
|
318 mm_log (tmp,WARN);
|
yuuji@0
|
319 break;
|
yuuji@0
|
320 }
|
yuuji@0
|
321 mm_dlog ("retrying delivery to INBOX");
|
yuuji@0
|
322 SETPOS (&st,0); /* rewind stringstruct just in case */
|
yuuji@0
|
323 }
|
yuuji@0
|
324
|
yuuji@0
|
325 /* -I specified and not "-I INBOX"? */
|
yuuji@0
|
326 if (inbox && !(((inbox[0] == 'I') || (inbox[0] == 'i')) &&
|
yuuji@0
|
327 ((inbox[1] == 'N') || (inbox[1] == 'n')) &&
|
yuuji@0
|
328 ((inbox[2] == 'B') || (inbox[2] == 'b')) &&
|
yuuji@0
|
329 ((inbox[3] == 'O') || (inbox[3] == 'o')) &&
|
yuuji@0
|
330 ((inbox[4] == 'X') || (inbox[4] == 'x')) && !inbox[5])) {
|
yuuji@0
|
331 DRIVER *dv = NIL;
|
yuuji@0
|
332 /* "-I #driver.xxx/name"? */
|
yuuji@0
|
333 if ((*inbox == '#') && ((inbox[1] == 'd') || (inbox[1] == 'D')) &&
|
yuuji@0
|
334 ((inbox[2] == 'r') || (inbox[2] == 'R')) &&
|
yuuji@0
|
335 ((inbox[3] == 'i') || (inbox[3] == 'I')) &&
|
yuuji@0
|
336 ((inbox[4] == 'v') || (inbox[4] == 'V')) &&
|
yuuji@0
|
337 ((inbox[5] == 'e') || (inbox[5] == 'E')) &&
|
yuuji@0
|
338 ((inbox[6] == 'r') || (inbox[6] == 'R')) && (inbox[7] == '.') &&
|
yuuji@0
|
339 (s = strchr (inbox+8,'/'))) {
|
yuuji@0
|
340 *s = '\0'; /* temporarily tie off driver name */
|
yuuji@0
|
341 if (!((dv = mail_parameters (NIL,GET_DRIVER,(void *) (inbox+8))) &&
|
yuuji@0
|
342 (mailboxfile (path,s[1] ? s + 1 : "&&&&&") == path) &&
|
yuuji@0
|
343 (s[1] || ((t = strstr (path,"&&&&&")) && strcpy (t,"INBOX"))))) {
|
yuuji@0
|
344 path[0] = '\0'; /* bad -I argument, no path resolved */
|
yuuji@0
|
345 sprintf (tmp,"Unable to resolve driver in %.80s, -I ignored",inbox);
|
yuuji@0
|
346 mm_log (tmp,WARN);
|
yuuji@0
|
347 }
|
yuuji@0
|
348 *s = '/'; /* restore delimiter */
|
yuuji@0
|
349 }
|
yuuji@0
|
350 /* resolve "-I other" specification */
|
yuuji@0
|
351 else if (mailboxfile (path,inbox) && path[0]) {
|
yuuji@0
|
352 /* resolution succeeded, impute driver */
|
yuuji@0
|
353 if (!strcmp (inbox,"mail.txt"))
|
yuuji@0
|
354 dv = mail_parameters (NIL,GET_DRIVER,(void *) "tenex");
|
yuuji@0
|
355 else if (!strcmp (inbox,"INBOX.MTX"))
|
yuuji@0
|
356 dv = mail_parameters (NIL,GET_DRIVER,(void *) "mtx");
|
yuuji@0
|
357 else if (!strcmp (inbox,"mbox"))
|
yuuji@0
|
358 dv = mail_parameters (NIL,GET_DRIVER,(void *) "unix");
|
yuuji@0
|
359 }
|
yuuji@0
|
360 else { /* bad -I argument */
|
yuuji@0
|
361 path[0] = '\0'; /* no path resolved */
|
yuuji@0
|
362 sprintf (tmp,"Unable to resolve %.80s, -I ignored",inbox);
|
yuuji@0
|
363 mm_log (tmp,WARN);
|
yuuji@0
|
364 }
|
yuuji@0
|
365 if (*path) { /* -I successfully resolved a path? */
|
yuuji@0
|
366 MAILSTREAM dpr;
|
yuuji@0
|
367 dpr.dtb = dv;
|
yuuji@0
|
368 if (dv) ds = &dpr;
|
yuuji@0
|
369 /* supplicate to the Evil One if necessary */
|
yuuji@0
|
370 if (lstat (path,&sbuf) && !path_create (ds,path)) {
|
yuuji@0
|
371 /* the Evil One rejected the plea */
|
yuuji@0
|
372 sprintf (tmp,"Unable to create %.80s, -I ignored",path);
|
yuuji@0
|
373 mm_log (tmp,WARN);
|
yuuji@0
|
374 }
|
yuuji@0
|
375 /* now attempt delivery */
|
yuuji@0
|
376 else return deliver_safely (ds,&st,inbox,path,duid,tmp);
|
yuuji@0
|
377 }
|
yuuji@0
|
378 }
|
yuuji@0
|
379
|
yuuji@0
|
380 /* no -I, resolve "INBOX" into path */
|
yuuji@0
|
381 if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
|
yuuji@0
|
382 /* clear box, get generic INBOX prototype */
|
yuuji@0
|
383 if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
|
yuuji@0
|
384 fatal ("no INBOX prototype");
|
yuuji@0
|
385 /* standard system driver? */
|
yuuji@0
|
386 if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
|
yuuji@0
|
387 strcpy (path,sysinbox ());/* use system INBOX */
|
yuuji@0
|
388 if (!lstat (path,&sbuf)) /* deliver to existing system INBOX */
|
yuuji@0
|
389 return deliver_safely (ds,&st,mailbox,path,duid,tmp);
|
yuuji@0
|
390 }
|
yuuji@0
|
391 else { /* other driver, try ~/INBOX */
|
yuuji@0
|
392 if ((mailboxfile (path,"&&&&&") == path) &&
|
yuuji@0
|
393 (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
|
yuuji@0
|
394 !lstat (path,&sbuf)){ /* deliver to existing ~/INBOX */
|
yuuji@0
|
395 sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
|
yuuji@0
|
396 return deliver_safely (ds,&st,cpystr (tmp),path,duid,tmp);
|
yuuji@0
|
397 }
|
yuuji@0
|
398 }
|
yuuji@0
|
399 /* not dummy, deliver to driver imputed path */
|
yuuji@0
|
400 if (strcmp (ds->dtb->name,"dummy"))
|
yuuji@0
|
401 return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
|
yuuji@0
|
402 deliver_safely (ds,&st,mailbox,path,duid,tmp) :
|
yuuji@0
|
403 fail ("unable to resolve INBOX path",EX_CANTCREAT);
|
yuuji@0
|
404 /* dummy, empty imputed append path exist? */
|
yuuji@0
|
405 if (ibxpath (ds = default_proto (T),&mailbox,path) &&
|
yuuji@0
|
406 !lstat (path,&sbuf) && !sbuf.st_size)
|
yuuji@0
|
407 return deliver_safely (ds,&st,mailbox,path,duid,tmp);
|
yuuji@0
|
408 /* impute path that we will create */
|
yuuji@0
|
409 if (!ibxpath (ds = format ? (format->open) (NIL) : default_proto (NIL),
|
yuuji@0
|
410 &mailbox,path))
|
yuuji@0
|
411 return fail ("unable to resolve INBOX",EX_CANTCREAT);
|
yuuji@0
|
412 }
|
yuuji@0
|
413 /* black box, must create, get create proto */
|
yuuji@0
|
414 else if (lstat (path,&sbuf)) ds = default_proto (NIL);
|
yuuji@0
|
415 else { /* black box, existing file */
|
yuuji@0
|
416 /* empty file, get append prototype */
|
yuuji@0
|
417 if (!sbuf.st_size) ds = default_proto (T);
|
yuuji@0
|
418 /* non-empty, get prototype from its data */
|
yuuji@0
|
419 else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
|
yuuji@0
|
420 fatal ("no INBOX prototype");
|
yuuji@0
|
421 /* error if unknown format */
|
yuuji@0
|
422 if (!strcmp (ds->dtb->name,"phile"))
|
yuuji@0
|
423 return fail ("unknown format INBOX",EX_UNAVAILABLE);
|
yuuji@0
|
424 /* otherwise can deliver to it */
|
yuuji@0
|
425 return deliver_safely (ds,&st,mailbox,path,duid,tmp);
|
yuuji@0
|
426 }
|
yuuji@0
|
427 sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
|
yuuji@0
|
428 mm_dlog (tmp);
|
yuuji@0
|
429 /* supplicate to the Evil One */
|
yuuji@0
|
430 if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
|
yuuji@0
|
431 sprintf (tmp,"created %.80s",path);
|
yuuji@0
|
432 mm_dlog (tmp);
|
yuuji@0
|
433 /* deliver the message */
|
yuuji@0
|
434 return deliver_safely (ds,&st,mailbox,path,duid,tmp);
|
yuuji@0
|
435 }
|
yuuji@0
|
436
|
yuuji@0
|
437 /* Resolve INBOX from driver prototype into mailbox name and filesystem path
|
yuuji@0
|
438 * Accepts: driver prototype
|
yuuji@0
|
439 * pointer to mailbox name string pointer
|
yuuji@0
|
440 * buffer to return mailbox path
|
yuuji@0
|
441 * Returns: T if success, NIL if error
|
yuuji@0
|
442 */
|
yuuji@0
|
443
|
yuuji@0
|
444 long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
|
yuuji@0
|
445 {
|
yuuji@0
|
446 char *s,tmp[MAILTMPLEN];
|
yuuji@0
|
447 long ret = T;
|
yuuji@0
|
448 if (!ds) ret = NIL;
|
yuuji@0
|
449 else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
|
yuuji@0
|
450 strcpy (path,sysinbox ()); /* use system INBOX for unix and MMDF */
|
yuuji@0
|
451 else if (!strcmp (ds->dtb->name,"tenex"))
|
yuuji@0
|
452 ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
|
yuuji@0
|
453 else if (!strcmp (ds->dtb->name,"mtx"))
|
yuuji@0
|
454 ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
|
yuuji@0
|
455 else if (!strcmp (ds->dtb->name,"mbox"))
|
yuuji@0
|
456 ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
|
yuuji@0
|
457 /* better not be a namespace driver */
|
yuuji@0
|
458 else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
|
yuuji@0
|
459 /* INBOX in home directory */
|
yuuji@0
|
460 else ret = ((mailboxfile (path,"&&&&&") == path) &&
|
yuuji@0
|
461 (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
|
yuuji@0
|
462 if (ret) { /* don't bother if lossage */
|
yuuji@0
|
463 sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
|
yuuji@0
|
464 *mailbox = cpystr (tmp); /* name of INBOX in this namespace */
|
yuuji@0
|
465 }
|
yuuji@0
|
466 return ret;
|
yuuji@0
|
467 }
|
yuuji@0
|
468
|
yuuji@0
|
469 /* Deliver safely
|
yuuji@0
|
470 * Accepts: prototype stream to force mailbox format
|
yuuji@0
|
471 * stringstruct of message temporary file
|
yuuji@0
|
472 * mailbox name
|
yuuji@0
|
473 * filesystem path name
|
yuuji@0
|
474 * user id
|
yuuji@0
|
475 * scratch buffer for messages
|
yuuji@0
|
476 * Returns: NIL if success, else error code
|
yuuji@0
|
477 */
|
yuuji@0
|
478
|
yuuji@0
|
479 int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
|
yuuji@0
|
480 uid_t uid,char *tmp)
|
yuuji@0
|
481 {
|
yuuji@0
|
482 struct stat sbuf;
|
yuuji@0
|
483 int i = delivery_unsafe (path,uid,&sbuf,tmp);
|
yuuji@0
|
484 if (i) return i; /* give up now if delivery unsafe */
|
yuuji@0
|
485 /* directory, not file */
|
yuuji@0
|
486 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
|
yuuji@0
|
487 if (sbuf.st_mode & 0001) { /* listable directories may be worrisome */
|
yuuji@0
|
488 sprintf (tmp,"WARNING: directory %.80s is listable",path);
|
yuuji@0
|
489 mm_log (tmp,WARN);
|
yuuji@0
|
490 }
|
yuuji@0
|
491 }
|
yuuji@0
|
492 else { /* file, not directory */
|
yuuji@0
|
493 if (sbuf.st_nlink != 1) { /* multiple links may be worrisome */
|
yuuji@0
|
494 sprintf (tmp,"WARNING: multiple links to file %.80s",path);
|
yuuji@0
|
495 mm_log (tmp,WARN);
|
yuuji@0
|
496 }
|
yuuji@0
|
497 if (sbuf.st_mode & 0111) { /* executable files may be worrisome */
|
yuuji@0
|
498 sprintf (tmp,"WARNING: file %.80s is executable",path);
|
yuuji@0
|
499 mm_log (tmp,WARN);
|
yuuji@0
|
500 }
|
yuuji@0
|
501 }
|
yuuji@0
|
502 if (sbuf.st_mode & 0002) { /* public-write files may be worrisome */
|
yuuji@0
|
503 sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
|
yuuji@0
|
504 mm_log (tmp,WARN);
|
yuuji@0
|
505 }
|
yuuji@0
|
506 if (sbuf.st_mode & 0004) { /* public-write files may be worrisome */
|
yuuji@0
|
507 sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
|
yuuji@0
|
508 mm_log (tmp,WARN);
|
yuuji@0
|
509 }
|
yuuji@0
|
510 /* check site-written quota procedure */
|
yuuji@0
|
511 if (!tmail_quota (st,path,uid,tmp,sender,precedence)) return fail (tmp,-1);
|
yuuji@0
|
512 /* so far, so good */
|
yuuji@0
|
513 sprintf (tmp,"%s appending to %.80s (%s %.80s)",
|
yuuji@0
|
514 prt ? prt->dtb->name : "default",mailbox,
|
yuuji@0
|
515 ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
|
yuuji@0
|
516 mm_dlog (tmp);
|
yuuji@0
|
517 /* do the append now! */
|
yuuji@0
|
518 if (!mail_append (prt,mailbox,st)) {
|
yuuji@0
|
519 sprintf (tmp,"message delivery failed to %.80s",path);
|
yuuji@0
|
520 return fail (tmp,EX_CANTCREAT);
|
yuuji@0
|
521 }
|
yuuji@0
|
522 /* note success */
|
yuuji@0
|
523 sprintf (tmp,"delivered to %.80s",path);
|
yuuji@0
|
524 mm_log (tmp,NIL);
|
yuuji@0
|
525 /* make sure nothing evil this way comes */
|
yuuji@0
|
526 return delivery_unsafe (path,uid,&sbuf,tmp);
|
yuuji@0
|
527 }
|
yuuji@0
|
528
|
yuuji@0
|
529 /* Verify that delivery is safe
|
yuuji@0
|
530 * Accepts: path name
|
yuuji@0
|
531 * user id
|
yuuji@0
|
532 * stat buffer
|
yuuji@0
|
533 * scratch buffer for messages
|
yuuji@0
|
534 * Returns: NIL if delivery is safe, error code if unsafe
|
yuuji@0
|
535 */
|
yuuji@0
|
536
|
yuuji@0
|
537 int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp)
|
yuuji@0
|
538 {
|
yuuji@0
|
539 u_short type;
|
yuuji@0
|
540 sprintf (tmp,"Verifying safe delivery to %.80s by UID %ld",path,(long) uid);
|
yuuji@0
|
541 mm_dlog (tmp);
|
yuuji@0
|
542 /* prepare message just in case */
|
yuuji@0
|
543 sprintf (tmp,"delivery to %.80s unsafe: ",path);
|
yuuji@0
|
544 /* unsafe if can't get its status */
|
yuuji@0
|
545 if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
|
yuuji@0
|
546 else if (sbuf->st_uid != uid) /* unsafe if UID does not match */
|
yuuji@0
|
547 sprintf (tmp + strlen (tmp),"uid mismatch (%ld != %ld)",
|
yuuji@0
|
548 (long) sbuf->st_uid,(long) uid);
|
yuuji@0
|
549 /* check file type */
|
yuuji@0
|
550 else switch (sbuf->st_mode & S_IFMT) {
|
yuuji@0
|
551 case S_IFDIR: /* directory is always OK */
|
yuuji@0
|
552 return NIL;
|
yuuji@0
|
553 case S_IFREG: /* file is unsafe if setuid */
|
yuuji@0
|
554 if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
|
yuuji@0
|
555 /* or setgid */
|
yuuji@0
|
556 else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
|
yuuji@0
|
557 else return NIL; /* otherwise safe */
|
yuuji@0
|
558 break;
|
yuuji@0
|
559 case S_IFCHR: strcat (tmp,"character special"); break;
|
yuuji@0
|
560 case S_IFBLK: strcat (tmp,"block special"); break;
|
yuuji@0
|
561 case S_IFLNK: strcat (tmp,"symbolic link"); break;
|
yuuji@0
|
562 case S_IFSOCK: strcat (tmp,"socket"); break;
|
yuuji@0
|
563 default:
|
yuuji@0
|
564 sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
|
yuuji@0
|
565 }
|
yuuji@0
|
566 return fail (tmp,EX_CANTCREAT);
|
yuuji@0
|
567 }
|
yuuji@0
|
568
|
yuuji@0
|
569 /* Report an error
|
yuuji@0
|
570 * Accepts: string to output
|
yuuji@0
|
571 */
|
yuuji@0
|
572
|
yuuji@0
|
573 int fail (char *string,int code)
|
yuuji@0
|
574 {
|
yuuji@0
|
575 mm_log (string,ERROR); /* pass up the string */
|
yuuji@0
|
576 switch (code) {
|
yuuji@0
|
577 #if T
|
yuuji@0
|
578 case EX_USAGE:
|
yuuji@0
|
579 case EX_OSERR:
|
yuuji@0
|
580 case EX_SOFTWARE:
|
yuuji@0
|
581 case EX_NOUSER:
|
yuuji@0
|
582 case EX_CANTCREAT:
|
yuuji@0
|
583 case EX_UNAVAILABLE:
|
yuuji@0
|
584 code = EX_TEMPFAIL; /* coerce these to TEMPFAIL */
|
yuuji@0
|
585 #endif
|
yuuji@0
|
586 break;
|
yuuji@0
|
587 case -1: /* quota failure... */
|
yuuji@0
|
588 code = EX_CANTCREAT; /* ...really returns this code */
|
yuuji@0
|
589 break;
|
yuuji@0
|
590 default:
|
yuuji@0
|
591 break;
|
yuuji@0
|
592 }
|
yuuji@0
|
593 return code; /* error code to return */
|
yuuji@0
|
594 }
|
yuuji@0
|
595
|
yuuji@0
|
596
|
yuuji@0
|
597 /* Get user name from username+mailbox specifier
|
yuuji@0
|
598 * Accepts: username/mailbox specifier
|
yuuji@0
|
599 * pointer to return location for mailbox specifier
|
yuuji@0
|
600 * Returns: user name, mailbox specifier value NIL if INBOX, patches out +
|
yuuji@0
|
601 */
|
yuuji@0
|
602
|
yuuji@0
|
603 char *getusername (char *s,char **t)
|
yuuji@0
|
604 {
|
yuuji@0
|
605 if (*t = strchr (s,'+')) { /* have a mailbox specifier? */
|
yuuji@0
|
606 *(*t)++ = '\0'; /* yes, tie off user name */
|
yuuji@0
|
607 /* user+ and user+INBOX same as user */
|
yuuji@0
|
608 if (!**t || !compare_cstring ((unsigned char *) *t,"INBOX")) *t = NIL;
|
yuuji@0
|
609 }
|
yuuji@0
|
610 return s; /* return user name */
|
yuuji@0
|
611 }
|
yuuji@0
|
612
|
yuuji@0
|
613 /* Co-routines from MAIL library */
|
yuuji@0
|
614
|
yuuji@0
|
615
|
yuuji@0
|
616 /* Message matches a search
|
yuuji@0
|
617 * Accepts: MAIL stream
|
yuuji@0
|
618 * message number
|
yuuji@0
|
619 */
|
yuuji@0
|
620
|
yuuji@0
|
621 void mm_searched (MAILSTREAM *stream,unsigned long msgno)
|
yuuji@0
|
622 {
|
yuuji@0
|
623 fatal ("mm_searched() call");
|
yuuji@0
|
624 }
|
yuuji@0
|
625
|
yuuji@0
|
626
|
yuuji@0
|
627 /* Message exists (i.e. there are that many messages in the mailbox)
|
yuuji@0
|
628 * Accepts: MAIL stream
|
yuuji@0
|
629 * message number
|
yuuji@0
|
630 */
|
yuuji@0
|
631
|
yuuji@0
|
632 void mm_exists (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
633 {
|
yuuji@0
|
634 fatal ("mm_exists() call");
|
yuuji@0
|
635 }
|
yuuji@0
|
636
|
yuuji@0
|
637
|
yuuji@0
|
638 /* Message expunged
|
yuuji@0
|
639 * Accepts: MAIL stream
|
yuuji@0
|
640 * message number
|
yuuji@0
|
641 */
|
yuuji@0
|
642
|
yuuji@0
|
643 void mm_expunged (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
644 {
|
yuuji@0
|
645 fatal ("mm_expunged() call");
|
yuuji@0
|
646 }
|
yuuji@0
|
647
|
yuuji@0
|
648
|
yuuji@0
|
649 /* Message flags update seen
|
yuuji@0
|
650 * Accepts: MAIL stream
|
yuuji@0
|
651 * message number
|
yuuji@0
|
652 */
|
yuuji@0
|
653
|
yuuji@0
|
654 void mm_flags (MAILSTREAM *stream,unsigned long number)
|
yuuji@0
|
655 {
|
yuuji@0
|
656 }
|
yuuji@0
|
657
|
yuuji@0
|
658 /* Mailbox found
|
yuuji@0
|
659 * Accepts: MAIL stream
|
yuuji@0
|
660 * delimiter
|
yuuji@0
|
661 * mailbox name
|
yuuji@0
|
662 * mailbox attributes
|
yuuji@0
|
663 */
|
yuuji@0
|
664
|
yuuji@0
|
665 void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
yuuji@0
|
666 {
|
yuuji@0
|
667 fatal ("mm_list() call");
|
yuuji@0
|
668 }
|
yuuji@0
|
669
|
yuuji@0
|
670
|
yuuji@0
|
671 /* Subscribed mailbox found
|
yuuji@0
|
672 * Accepts: MAIL stream
|
yuuji@0
|
673 * delimiter
|
yuuji@0
|
674 * mailbox name
|
yuuji@0
|
675 * mailbox attributes
|
yuuji@0
|
676 */
|
yuuji@0
|
677
|
yuuji@0
|
678 void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
yuuji@0
|
679 {
|
yuuji@0
|
680 fatal ("mm_lsub() call");
|
yuuji@0
|
681 }
|
yuuji@0
|
682
|
yuuji@0
|
683
|
yuuji@0
|
684 /* Mailbox status
|
yuuji@0
|
685 * Accepts: MAIL stream
|
yuuji@0
|
686 * mailbox name
|
yuuji@0
|
687 * mailbox status
|
yuuji@0
|
688 */
|
yuuji@0
|
689
|
yuuji@0
|
690 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
|
yuuji@0
|
691 {
|
yuuji@0
|
692 fatal ("mm_status() call");
|
yuuji@0
|
693 }
|
yuuji@0
|
694
|
yuuji@0
|
695 /* Notification event
|
yuuji@0
|
696 * Accepts: MAIL stream
|
yuuji@0
|
697 * string to log
|
yuuji@0
|
698 * error flag
|
yuuji@0
|
699 */
|
yuuji@0
|
700
|
yuuji@0
|
701 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
|
yuuji@0
|
702 {
|
yuuji@0
|
703 char tmp[MAILTMPLEN];
|
yuuji@0
|
704 tmp[11] = '\0'; /* see if TRYCREATE */
|
yuuji@0
|
705 if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
|
yuuji@0
|
706 mm_log (string,errflg); /* just do mm_log action */
|
yuuji@0
|
707 }
|
yuuji@0
|
708
|
yuuji@0
|
709
|
yuuji@0
|
710 /* Log an event for the user to see
|
yuuji@0
|
711 * Accepts: string to log
|
yuuji@0
|
712 * error flag
|
yuuji@0
|
713 */
|
yuuji@0
|
714
|
yuuji@0
|
715 void mm_log (char *string,long errflg)
|
yuuji@0
|
716 {
|
yuuji@0
|
717 if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
|
yuuji@0
|
718 else { /* ordinary logging */
|
yuuji@0
|
719 fprintf (stderr,"%s\n",string);
|
yuuji@0
|
720 switch (errflg) {
|
yuuji@0
|
721 case NIL: /* no error */
|
yuuji@0
|
722 syslog (LOG_INFO,"%s",string);
|
yuuji@0
|
723 break;
|
yuuji@0
|
724 case PARSE: /* parsing problem */
|
yuuji@0
|
725 case WARN: /* warning */
|
yuuji@0
|
726 syslog (LOG_WARNING,"%s",string);
|
yuuji@0
|
727 break;
|
yuuji@0
|
728 case ERROR: /* error */
|
yuuji@0
|
729 default:
|
yuuji@0
|
730 syslog (LOG_ERR,"%s",string);
|
yuuji@0
|
731 break;
|
yuuji@0
|
732 }
|
yuuji@0
|
733 }
|
yuuji@0
|
734 }
|
yuuji@0
|
735
|
yuuji@0
|
736
|
yuuji@0
|
737 /* Log an event to debugging telemetry
|
yuuji@0
|
738 * Accepts: string to log
|
yuuji@0
|
739 */
|
yuuji@0
|
740
|
yuuji@0
|
741 void mm_dlog (char *string)
|
yuuji@0
|
742 {
|
yuuji@0
|
743 if (debug) fprintf (stderr,"%s\n",string);
|
yuuji@0
|
744 syslog (LOG_DEBUG,"%s",string);
|
yuuji@0
|
745 }
|
yuuji@0
|
746
|
yuuji@0
|
747 /* Get user name and password for this host
|
yuuji@0
|
748 * Accepts: parse of network mailbox name
|
yuuji@0
|
749 * where to return user name
|
yuuji@0
|
750 * where to return password
|
yuuji@0
|
751 * trial count
|
yuuji@0
|
752 */
|
yuuji@0
|
753
|
yuuji@0
|
754 void mm_login (NETMBX *mb,char *username,char *password,long trial)
|
yuuji@0
|
755 {
|
yuuji@0
|
756 fatal ("mm_login() call");
|
yuuji@0
|
757 }
|
yuuji@0
|
758
|
yuuji@0
|
759
|
yuuji@0
|
760 /* About to enter critical code
|
yuuji@0
|
761 * Accepts: stream
|
yuuji@0
|
762 */
|
yuuji@0
|
763
|
yuuji@0
|
764 void mm_critical (MAILSTREAM *stream)
|
yuuji@0
|
765 {
|
yuuji@0
|
766 critical = T; /* note in critical code */
|
yuuji@0
|
767 }
|
yuuji@0
|
768
|
yuuji@0
|
769
|
yuuji@0
|
770 /* About to exit critical code
|
yuuji@0
|
771 * Accepts: stream
|
yuuji@0
|
772 */
|
yuuji@0
|
773
|
yuuji@0
|
774 void mm_nocritical (MAILSTREAM *stream)
|
yuuji@0
|
775 {
|
yuuji@0
|
776 critical = NIL; /* note not in critical code */
|
yuuji@0
|
777 }
|
yuuji@0
|
778
|
yuuji@0
|
779
|
yuuji@0
|
780 /* Disk error found
|
yuuji@0
|
781 * Accepts: stream
|
yuuji@0
|
782 * system error code
|
yuuji@0
|
783 * flag indicating that mailbox may be clobbered
|
yuuji@0
|
784 * Returns: T if user wants to abort
|
yuuji@0
|
785 */
|
yuuji@0
|
786
|
yuuji@0
|
787 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
|
yuuji@0
|
788 {
|
yuuji@0
|
789 return T;
|
yuuji@0
|
790 }
|
yuuji@0
|
791
|
yuuji@0
|
792
|
yuuji@0
|
793 /* Log a fatal error event
|
yuuji@0
|
794 * Accepts: string to log
|
yuuji@0
|
795 */
|
yuuji@0
|
796
|
yuuji@0
|
797 void mm_fatal (char *string)
|
yuuji@0
|
798 {
|
yuuji@0
|
799 printf ("?%s\n",string); /* shouldn't happen normally */
|
yuuji@0
|
800 }
|