]> diplodocus.org Git - nmh/blob - sbr/mts.c
Disabled the optimization to stop stat'ing directory entries in
[nmh] / sbr / mts.c
1
2 /*
3 * mts.c -- definitions for the mail transport system
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h> /* for snprintf() */
11 #include <h/nmh.h>
12 #include <h/utils.h>
13
14 #define nmhetcdir(file) NMHETCDIR#file
15
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <h/mts.h>
19 #include <pwd.h>
20 #include <sys/socket.h>
21 #include <netdb.h>
22
23 /*
24 * static prototypes
25 */
26 static char *tailor_value (unsigned char *);
27 static void getuserinfo (void);
28 static const char *get_mtsconf_pathname(void);
29 static const char *get_mtsuserconf_pathname(void);
30 static void mts_read_conf_file (FILE *fp);
31
32 /*
33 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
34 * are kept in the user's home directory, then these should be empty
35 * strings. In this case, the appropriate ...lfil array should contain
36 * the name of the file in the user's home directory. Usually, this is
37 * something like ".mail".
38 */
39
40 /*
41 * nmh mail transport interface customization file
42 */
43 static char *mtsconf = nmhetcdir(/mts.conf);
44
45 static char *localname = "";
46 static char *localdomain = "";
47 static char *systemname = "";
48
49 char *mmdfldir = MAILSPOOL;
50 char *mmdflfil = "";
51 char *uucpldir = "/usr/spool/mail";
52 char *uucplfil = "";
53
54 char *mmdlm1 = "\001\001\001\001\n";
55 char *mmdlm2 = "\001\001\001\001\n";
56
57 /* Cache the username, fullname, and mailbox of the user */
58 static char username[BUFSIZ];
59 static char fullname[BUFSIZ];
60 static char localmbox[BUFSIZ];
61
62 /* Variables for username masquerading: */
63 boolean draft_from_masquerading = FALSE; /* also used from post.c */
64 static boolean mmailid_masquerading = FALSE;
65 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
66 static char* masquerade = "";
67
68 /*
69 * MTS specific variables
70 */
71 static char *sm_method = "smtp";
72 int sm_mts = MTS_SMTP;
73 char *hostable = nmhetcdir(/hosts);
74 char *sendmail = SENDMAILPATH;
75
76 /*
77 * SMTP/POP stuff
78 */
79 char *clientname = NULL;
80 char *servers = "localhost";
81 char *pophost = "";
82
83 /*
84 * Global MailDelivery file
85 */
86 char *maildelivery = nmhetcdir(/maildelivery);
87
88
89 /*
90 * Aliasing Facility (doesn't belong here)
91 */
92 int Everyone = NOTOK;
93 static char *everyone = "-1";
94 char *NoShell = "";
95
96 /*
97 * Customize the MTS settings for nmh by adjusting
98 * the file mts.conf in the nmh etc directory.
99 */
100
101 struct bind {
102 char *keyword;
103 char **value;
104 };
105
106 static struct bind binds[] = {
107 { "localname", &localname },
108 { "localdomain", &localdomain },
109 { "systemname", &systemname },
110 { "mmdfldir", &mmdfldir },
111 { "mmdflfil", &mmdflfil },
112 { "uucpldir", &uucpldir },
113 { "uucplfil", &uucplfil },
114 { "mmdelim1", &mmdlm1 },
115 { "mmdelim2", &mmdlm2 },
116 { "masquerade", &masquerade },
117 { "mts", &sm_method },
118 { "hostable", &hostable },
119 { "sendmail", &sendmail },
120 { "clientname", &clientname },
121 { "servers", &servers },
122 { "pophost", &pophost },
123
124 { "maildelivery", &maildelivery },
125 { "everyone", &everyone },
126 { "noshell", &NoShell },
127 { NULL, NULL }
128 };
129
130
131 /*
132 * Read the configuration file for the nmh interface
133 * to the mail transport system (MTS).
134 */
135
136 void
137 mts_init (char *name)
138 {
139 NMH_UNUSED (name);
140
141 const char *cp;
142 FILE *fp;
143 static int inited = 0;
144
145 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
146 return;
147 mts_read_conf_file(fp);
148 fclose (fp);
149
150 cp = get_mtsuserconf_pathname();
151 if (cp != NULL &&
152 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
153 mts_read_conf_file(fp);
154 fclose (fp);
155 }
156
157 Everyone = atoi (everyone);
158
159 if (strstr(masquerade, "draft_from") != NULL)
160 draft_from_masquerading = TRUE;
161
162 if (strstr(masquerade, "mmailid") != NULL)
163 mmailid_masquerading = TRUE;
164
165 if (strstr(masquerade, "username_extension") != NULL)
166 username_extension_masquerading = TRUE;
167
168 if (strcmp(sm_method, "smtp") == 0)
169 sm_mts = MTS_SMTP;
170 else if (strcmp(sm_method, "sendmail") == 0)
171 sm_mts = MTS_SENDMAIL;
172 else {
173 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
174 sm_mts = MTS_SMTP;
175 }
176 }
177
178
179 #define QUOTE '\\'
180
181 /*
182 * Convert escaped values, malloc some new space,
183 * and copy string to malloc'ed memory.
184 */
185
186 static char *
187 tailor_value (unsigned char *s)
188 {
189 int i, r;
190 char *bp;
191 char buffer[BUFSIZ];
192 size_t len;
193
194 for (bp = buffer; *s; bp++, s++) {
195 if (*s != QUOTE) {
196 *bp = *s;
197 } else {
198 switch (*++s) {
199 case 'b': *bp = '\b'; break;
200 case 'f': *bp = '\f'; break;
201 case 'n': *bp = '\n'; break;
202 case 't': *bp = '\t'; break;
203
204 case 0: s--;
205 case QUOTE:
206 *bp = QUOTE;
207 break;
208
209 default:
210 if (!isdigit (*s)) {
211 *bp++ = QUOTE;
212 *bp = *s;
213 }
214 r = *s != '0' ? 10 : 8;
215 for (i = 0; isdigit (*s); s++)
216 i = i * r + *s - '0';
217 s--;
218 *bp = toascii (i);
219 break;
220 }
221 }
222 }
223 *bp = 0;
224
225 len = strlen (buffer) + 1;
226 bp = mh_xmalloc (len);
227 memcpy (bp, buffer, len);
228
229 return bp;
230 }
231
232 /*
233 * Get the fully qualified name of the local host.
234 *
235 * If flag is 0, then use anything out of mts.conf (like localname).
236 * If flag is 1, then only use the "proper" local hostname.
237 */
238
239 char *
240 LocalName (int flag)
241 {
242 static char buffer0[BUFSIZ] = "";
243 static char buffer1[BUFSIZ] = "";
244 static char *buffer[] = { buffer0, buffer1 };
245 char *buf;
246 struct addrinfo hints, *res;
247
248 if (flag < 0 || flag > 1)
249 return NULL;
250
251 buf = buffer[flag];
252
253 /* check if we have cached the local name */
254 if (buf[0])
255 return buf;
256
257 mts_init ("mts");
258
259 /* check if the mts.conf file specifies a "localname" */
260 if (*localname && flag == 0) {
261 strncpy (buf, localname, sizeof(buffer0));
262 } else {
263 memset(buf, 0, sizeof(buffer0));
264 /* first get our local name */
265 gethostname (buf, sizeof(buffer0) - 1);
266 /* now fully qualify our name */
267
268 memset(&hints, 0, sizeof(hints));
269 hints.ai_flags = AI_CANONNAME;
270 hints.ai_family = PF_UNSPEC;
271 if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
272 strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
273 freeaddrinfo(res);
274 }
275 }
276
277 /*
278 * If the mts.conf file specifies a "localdomain",
279 * we append that now. This should rarely be needed.
280 */
281 if (*localdomain) {
282 strcat (buf, ".");
283 strcat (buf, localdomain);
284 }
285
286 return buf;
287 }
288
289
290 /*
291 * This is only for UUCP mail. It gets the hostname
292 * as part of the UUCP "domain".
293 */
294
295 char *
296 SystemName (void)
297 {
298 static char buffer[BUFSIZ] = "";
299
300 /* check if we have cached the system name */
301 if (buffer[0])
302 return buffer;
303
304 mts_init ("mts");
305
306 /* check if mts.conf file specifies a "systemname" */
307 if (*systemname) {
308 strncpy (buffer, systemname, sizeof(buffer));
309 return buffer;
310 }
311
312 gethostname (buffer, sizeof(buffer));
313
314 return buffer;
315 }
316
317
318 /*
319 * Get the username of current user
320 */
321
322 char *
323 getusername (void)
324 {
325 if (username[0] == '\0')
326 getuserinfo();
327
328 return username;
329 }
330
331
332 /*
333 * Get full name of current user (typically from GECOS
334 * field of password file).
335 */
336
337 char *
338 getfullname (void)
339 {
340 if (username[0] == '\0')
341 getuserinfo();
342
343 return fullname;
344 }
345
346
347 /*
348 * Get the full local mailbox name. This is in the form:
349 *
350 * User Name <user@name.com>
351 */
352
353 char *
354 getlocalmbox (void)
355 {
356 if (username[0] == '\0')
357 getuserinfo();
358
359 if (localmbox[0] == '\0') {
360 char *cp;
361
362 if ((cp = context_find("Local-Mailbox")) != NULL) {
363 strncpy(localmbox, cp, sizeof(localmbox));
364 } else {
365 snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname,
366 username, LocalName(0));
367 }
368
369 localmbox[sizeof(localmbox) - 1] = '\0';
370 }
371
372 return localmbox;
373 }
374
375 /*
376 * Find the user's username and full name, and cache them.
377 * Also, handle "mmailid" username masquerading controlled from the GECOS field
378 * of the passwd file.
379 */
380
381 static void
382 getuserinfo (void)
383 {
384 register unsigned char *cp;
385 register char *np;
386 register struct passwd *pw;
387
388 if ((pw = getpwuid (getuid ())) == NULL
389 || pw->pw_name == NULL
390 || *pw->pw_name == '\0') {
391 strncpy (username, "unknown", sizeof(username));
392 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
393 (int) getuid ());
394 return;
395 }
396
397 np = pw->pw_gecos;
398
399 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
400 which some OSes use to separate other 'finger' information in the GECOS
401 field, like phone number. Also, if mmailid masquerading is turned on due
402 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
403 hit a '<' (which should precede any ','s). */
404 if (mmailid_masquerading)
405 /* Stop at ',' or '<'. */
406 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
407 *cp++ = *np++)
408 continue;
409 else
410 /* Allow '<' as a legal character of the user's name. This code is
411 basically a duplicate of the code above the "else" -- we don't
412 collapse it down to one copy and put the mmailid_masquerading check
413 inside the loop with "(x ? y : z)" because that's inefficient and the
414 value'll never change while it's in there. */
415 for (cp = fullname; *np != '\0' && *np != ',';
416 *cp++ = *np++)
417 continue;
418 *cp = '\0';
419
420 if (mmailid_masquerading) {
421 /* Do mmailid processing. The GECOS field should have the form
422 "Full Name <fakeusername>". For instance,
423 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
424 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
425 account name. */
426 if (*np)
427 np++;
428 for (cp = username; *np && *np != '>'; *cp++ = *np++)
429 continue;
430 *cp = '\0';
431 }
432 if (!mmailid_masquerading || *np == '\0')
433 strncpy (username, pw->pw_name, sizeof(username));
434
435 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
436 your real name. If SIGNATURE isn't set, use the Signature profile
437 setting if it exists. */
438 if ((cp = getenv ("SIGNATURE")) && *cp)
439 strncpy (fullname, cp, sizeof(fullname));
440 else if ((cp = context_find("Signature")))
441 strncpy (fullname, cp, sizeof(fullname));
442
443 if (strchr(fullname, '.')) { /* quote any .'s */
444 char tmp[BUFSIZ];
445
446 /* should quote "'s too */
447 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
448 strncpy (fullname, tmp, sizeof(fullname));
449 }
450
451 fullname[sizeof(fullname) - 1] = '\0';
452
453 localmbox[0] = '\0';
454
455 return;
456 }
457
458 static const char*
459 get_mtsconf_pathname (void)
460 {
461 const char *cp = getenv ( "MHMTSCONF" );
462 if (cp != NULL && *cp != '\0') {
463 return cp;
464 }
465 return mtsconf;
466 }
467
468 static const char*
469 get_mtsuserconf_pathname (void)
470 {
471 const char *cp = getenv ( "MHMTSUSERCONF" );
472 if (cp != NULL && *cp != '\0') {
473 return cp;
474 }
475 return NULL;
476 }
477
478 static void
479 mts_read_conf_file (FILE *fp)
480 {
481 unsigned char *bp;
482 char *cp, buffer[BUFSIZ];
483 struct bind *b;
484
485 while (fgets (buffer, sizeof(buffer), fp)) {
486 if (!(cp = strchr(buffer, '\n')))
487 break;
488 *cp = 0;
489 if (*buffer == '#' || *buffer == '\0')
490 continue;
491 if (!(bp = strchr(buffer, ':')))
492 break;
493 *bp++ = 0;
494 while (isspace (*bp))
495 *bp++ = 0;
496
497 for (b = binds; b->keyword; b++)
498 if (!strcmp (buffer, b->keyword))
499 break;
500 if (b->keyword && (cp = tailor_value (bp)))
501 *b->value = cp;
502 }
503 }