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