3 * mts.c -- definitions for the mail transport system
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
12 #include <h/mh.h> /* for snprintf() */
15 #define nmhetcdir(file) NMHETCDIR#file
23 #ifdef HAVE_SYS_UTSNAME_H
24 # include <sys/utsname.h>
33 static char *tailor_value (char *);
34 static void getuserinfo (void);
37 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
38 * are kept in the user's home directory, then these should be empty
39 * strings. In this case, the appropriate ...lfil array should contain
40 * the name of the file in the user's home directory. Usually, this is
41 * something like ".mail".
45 * nmh mail transport interface customization file
47 static char *mtsconf = nmhetcdir(/mts.conf);
49 static char *localname = "";
50 static char *localdomain = "";
51 static char *systemname = "";
53 char *mmdfldir = MAILSPOOL;
55 char *uucpldir = "/usr/spool/mail";
58 char *mmdlm1 = "\001\001\001\001\n";
59 char *mmdlm2 = "\001\001\001\001\n";
61 /* Cache the username and fullname of the user */
62 static char username[BUFSIZ];
63 static char fullname[BUFSIZ];
65 /* Variables for username masquerading: */
66 boolean draft_from_masquerading = FALSE; /* also used from post.c */
67 static boolean mmailid_masquerading = FALSE;
68 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
69 static char* masquerade = "";
72 * MTS specific variables
75 static char *sm_method = "smtp";
76 int sm_mts = MTS_SMTP;
77 char *hostable = nmhetcdir(/hosts);
78 char *sendmail = SENDMAILPATH;
84 char *clientname = NULL;
85 char *servers = "localhost \01localnet";
89 * BBoards-specific variables
95 * POP BBoards-specific variables
100 char *popbblist = nmhetcdir(/hosts.popbb);
104 * Global MailDelivery file
106 char *maildelivery = nmhetcdir(/maildelivery);
110 * Aliasing Facility (doesn't belong here)
112 int Everyone = NOTOK;
113 static char *everyone = "-1";
117 * Customize the MTS settings for nmh by adjusting
118 * the file mts.conf in the nmh etc directory.
126 static struct bind binds[] = {
127 { "localname", &localname },
128 { "localdomain", &localdomain },
129 { "systemname", &systemname },
130 { "mmdfldir", &mmdfldir },
131 { "mmdflfil", &mmdflfil },
132 { "uucpldir", &uucpldir },
133 { "uucplfil", &uucplfil },
134 { "mmdelim1", &mmdlm1 },
135 { "mmdelim2", &mmdlm2 },
136 { "masquerade", &masquerade },
139 { "mts", &sm_method },
140 { "hostable", &hostable },
141 { "sendmail", &sendmail },
144 { "clientname", &clientname },
145 { "servers", &servers },
146 { "pophost", &pophost },
147 { "bbdomain", &bb_domain },
150 { "popbbhost", &popbbhost },
151 { "popbbuser", &popbbuser },
152 { "popbblist", &popbblist },
156 { "nntphost", &popbbhost },
159 { "maildelivery", &maildelivery },
160 { "everyone", &everyone },
161 { "noshell", &NoShell },
167 * Read the configuration file for the nmh interface
168 * to the mail transport system (MTS).
172 mts_init (char *name)
174 char *bp, *cp, buffer[BUFSIZ];
177 static int inited = 0;
179 if (inited++ || (fp = fopen (mtsconf, "r")) == NULL)
182 while (fgets (buffer, sizeof(buffer), fp)) {
183 if (!(cp = strchr(buffer, '\n')))
186 if (*buffer == '#' || *buffer == '\0')
188 if (!(bp = strchr(buffer, ':')))
191 while (isspace (*bp))
194 for (b = binds; b->keyword; b++)
195 if (!strcmp (buffer, b->keyword))
197 if (b->keyword && (cp = tailor_value (bp)))
203 Everyone = atoi (everyone);
205 if (strstr(masquerade, "draft_from") != NULL)
206 draft_from_masquerading = TRUE;
208 if (strstr(masquerade, "mmailid") != NULL)
209 mmailid_masquerading = TRUE;
211 if (strstr(masquerade, "username_extension") != NULL)
212 username_extension_masquerading = TRUE;
215 if (strcmp(sm_method, "smtp") == 0)
217 else if (strcmp(sm_method, "sendmail") == 0)
218 sm_mts = MTS_SENDMAIL;
220 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
230 * Convert escaped values, malloc some new space,
231 * and copy string to malloc'ed memory.
235 tailor_value (char *s)
242 for (bp = buffer; *s; bp++, s++) {
247 case 'b': *bp = '\b'; break;
248 case 'f': *bp = '\f'; break;
249 case 'n': *bp = '\n'; break;
250 case 't': *bp = '\t'; break;
262 r = *s != '0' ? 10 : 8;
263 for (i = 0; isdigit (*s); s++)
264 i = i * r + *s - '0';
273 len = strlen (buffer) + 1;
274 if ((bp = malloc (len)))
275 memcpy (bp, buffer, len);
281 * Get the fully qualified name of the local host.
287 static char buffer[BUFSIZ] = "";
294 /* check if we have cached the local name */
300 /* check if the mts.conf file specifies a "localname" */
302 strncpy (buffer, localname, sizeof(buffer));
305 /* first get our local name */
307 strncpy (buffer, name.nodename, sizeof(buffer));
309 /* first get our local name */
310 gethostname (buffer, sizeof(buffer));
312 #ifdef HAVE_SETHOSTENT
315 /* now fully qualify our name */
316 if ((hp = gethostbyname (buffer)))
317 strncpy (buffer, hp->h_name, sizeof(buffer));
321 * If the mts.conf file specifies a "localdomain",
322 * we append that now. This should rarely be needed.
325 strcat (buffer, ".");
326 strcat (buffer, localdomain);
334 * This is only for UUCP mail. It gets the hostname
335 * as part of the UUCP "domain".
341 static char buffer[BUFSIZ] = "";
347 /* check if we have cached the system name */
353 /* check if mts.conf file specifies a "systemname" */
355 strncpy (buffer, systemname, sizeof(buffer));
361 strncpy (buffer, name.nodename, sizeof(buffer));
363 gethostname (buffer, sizeof(buffer));
371 * Get the username of current user
377 if (username[0] == '\0')
385 * Get full name of current user (typically from GECOS
386 * field of password file).
392 if (username[0] == '\0')
400 * Find the user's username and full name, and cache them.
401 * Also, handle "mmailid" username masquerading controlled from the GECOS field
402 * of the passwd file.
408 register char *cp, *np;
409 register struct passwd *pw;
415 if (uid == geteuid () && (cp = getenv ("USER")) != NULL
416 && (pw = getpwnam (cp)) != NULL)
417 strncpy (username, cp, sizeof(username));
418 else if ((pw = getpwuid (uid)) == NULL
419 || pw->pw_name == NULL
420 || *pw->pw_name == '\0') {
422 if ((pw = getpwuid (getuid ())) == NULL
423 || pw->pw_name == NULL
424 || *pw->pw_name == '\0') {
426 strncpy (username, "unknown", sizeof(username));
427 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
434 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
435 which some OSes use to separate other 'finger' information in the GECOS
436 field, like phone number. Also, if mmailid masquerading is turned on due
437 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
438 hit a '<' (which should precede any ','s). */
440 if (mmailid_masquerading)
441 /* Stop at ',' or '<'. */
442 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
446 /* Allow '<' as a legal character of the user's name. This code is
447 basically a duplicate of the code above the "else" -- we don't
448 collapse it down to one copy and put the mmailid_masquerading check
449 inside the loop with "(x ? y : z)" because that's inefficient and the
450 value'll never change while it's in there. */
451 for (cp = fullname; *np != '\0' && *np != ',';
455 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
456 field (finger, mail, sendmail, etc.) translate any '&' character in it to
457 the login name, with the first letter capitalized. So, for instance,
458 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
459 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
460 the translation for you, so we have to do it manually here. */
461 if (mmailid_masquerading)
462 /* Stop at ',' or '<'. */
464 *np != '\0' && *np != ',' && *np != '<';) {
465 if (*np == '&') { /* blech! */
466 strcpy (cp, pw->pw_name);
476 /* Allow '<' as a legal character of the user's name. This code is
477 basically a duplicate of the code above the "else" -- we don't
478 collapse it down to one copy and put the mmailid_masquerading check
479 inside the loop with "(x ? y : z)" because that's inefficient and the
480 value'll never change while it's in there. */
482 *np != '\0' && *np != ',';) {
483 if (*np == '&') { /* blech! */
484 strcpy (cp, pw->pw_name);
496 if (mmailid_masquerading) {
497 /* Do mmailid processing. The GECOS field should have the form
498 "Full Name <fakeusername>". For instance,
499 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
500 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
504 for (cp = username; *np && *np != '>'; *cp++ = *np++)
508 if (!mmailid_masquerading || *np == '\0')
509 strncpy (username, pw->pw_name, sizeof(username));
511 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
513 if ((cp = getenv ("SIGNATURE")) && *cp)
514 strncpy (fullname, cp, sizeof(fullname));
516 if (strchr(fullname, '.')) { /* quote any .'s */
519 /* should quote "'s too */
520 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
521 strncpy (fullname, tmp, sizeof(fullname));