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() */
16 #define nmhetcdir(file) NMHETCDIR#file
24 #ifdef HAVE_SYS_UTSNAME_H
25 # include <sys/utsname.h>
34 static char *tailor_value (unsigned char *);
35 static void getuserinfo (void);
38 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
39 * are kept in the user's home directory, then these should be empty
40 * strings. In this case, the appropriate ...lfil array should contain
41 * the name of the file in the user's home directory. Usually, this is
42 * something like ".mail".
46 * nmh mail transport interface customization file
48 static char *mtsconf = nmhetcdir(/mts.conf);
50 static char *localname = "";
51 static char *localdomain = "";
52 static char *systemname = "";
54 char *mmdfldir = MAILSPOOL;
56 char *uucpldir = "/usr/spool/mail";
59 char *mmdlm1 = "\001\001\001\001\n";
60 char *mmdlm2 = "\001\001\001\001\n";
62 /* Cache the username and fullname of the user */
63 static char username[BUFSIZ];
64 static char fullname[BUFSIZ];
66 /* Variables for username masquerading: */
67 boolean draft_from_masquerading = FALSE; /* also used from post.c */
68 static boolean mmailid_masquerading = FALSE;
69 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
70 static char* masquerade = "";
73 * MTS specific variables
76 static char *sm_method = "smtp";
77 int sm_mts = MTS_SMTP;
78 char *hostable = nmhetcdir(/hosts);
79 char *sendmail = SENDMAILPATH;
85 char *clientname = NULL;
86 char *servers = "localhost \01localnet";
90 * BBoards-specific variables
96 * POP BBoards-specific variables
100 char *popbbuser = "";
101 char *popbblist = nmhetcdir(/hosts.popbb);
105 * Global MailDelivery file
107 char *maildelivery = nmhetcdir(/maildelivery);
111 * Aliasing Facility (doesn't belong here)
113 int Everyone = NOTOK;
114 static char *everyone = "-1";
118 * Customize the MTS settings for nmh by adjusting
119 * the file mts.conf in the nmh etc directory.
127 static struct bind binds[] = {
128 { "localname", &localname },
129 { "localdomain", &localdomain },
130 { "systemname", &systemname },
131 { "mmdfldir", &mmdfldir },
132 { "mmdflfil", &mmdflfil },
133 { "uucpldir", &uucpldir },
134 { "uucplfil", &uucplfil },
135 { "mmdelim1", &mmdlm1 },
136 { "mmdelim2", &mmdlm2 },
137 { "masquerade", &masquerade },
140 { "mts", &sm_method },
141 { "hostable", &hostable },
142 { "sendmail", &sendmail },
145 { "clientname", &clientname },
146 { "servers", &servers },
147 { "pophost", &pophost },
148 { "bbdomain", &bb_domain },
151 { "popbbhost", &popbbhost },
152 { "popbbuser", &popbbuser },
153 { "popbblist", &popbblist },
157 { "nntphost", &popbbhost },
160 { "maildelivery", &maildelivery },
161 { "everyone", &everyone },
162 { "noshell", &NoShell },
168 * Read the configuration file for the nmh interface
169 * to the mail transport system (MTS).
173 mts_init (char *name)
176 char *cp, buffer[BUFSIZ];
179 static int inited = 0;
181 if (inited++ || (fp = fopen (mtsconf, "r")) == NULL)
184 while (fgets (buffer, sizeof(buffer), fp)) {
185 if (!(cp = strchr(buffer, '\n')))
188 if (*buffer == '#' || *buffer == '\0')
190 if (!(bp = strchr(buffer, ':')))
193 while (isspace (*bp))
196 for (b = binds; b->keyword; b++)
197 if (!strcmp (buffer, b->keyword))
199 if (b->keyword && (cp = tailor_value (bp)))
205 Everyone = atoi (everyone);
207 if (strstr(masquerade, "draft_from") != NULL)
208 draft_from_masquerading = TRUE;
210 if (strstr(masquerade, "mmailid") != NULL)
211 mmailid_masquerading = TRUE;
213 if (strstr(masquerade, "username_extension") != NULL)
214 username_extension_masquerading = TRUE;
217 if (strcmp(sm_method, "smtp") == 0)
219 else if (strcmp(sm_method, "sendmail") == 0)
220 sm_mts = MTS_SENDMAIL;
222 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
232 * Convert escaped values, malloc some new space,
233 * and copy string to malloc'ed memory.
237 tailor_value (unsigned char *s)
244 for (bp = buffer; *s; bp++, s++) {
249 case 'b': *bp = '\b'; break;
250 case 'f': *bp = '\f'; break;
251 case 'n': *bp = '\n'; break;
252 case 't': *bp = '\t'; break;
264 r = *s != '0' ? 10 : 8;
265 for (i = 0; isdigit (*s); s++)
266 i = i * r + *s - '0';
275 len = strlen (buffer) + 1;
276 bp = mh_xmalloc (len);
277 memcpy (bp, buffer, len);
283 * Get the fully qualified name of the local host.
289 static char buffer[BUFSIZ] = "";
290 struct addrinfo hints, *res;
295 /* check if we have cached the local name */
301 /* check if the mts.conf file specifies a "localname" */
303 strncpy (buffer, localname, sizeof(buffer));
305 memset(buffer, 0, sizeof(buffer));
307 /* first get our local name */
309 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
311 /* first get our local name */
312 gethostname (buffer, sizeof(buffer) - 1);
314 /* now fully qualify our name */
316 memset(&hints, 0, sizeof(hints));
317 hints.ai_flags = AI_CANONNAME;
318 hints.ai_family = PF_UNSPEC;
319 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
320 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
326 * If the mts.conf file specifies a "localdomain",
327 * we append that now. This should rarely be needed.
330 strcat (buffer, ".");
331 strcat (buffer, localdomain);
339 * This is only for UUCP mail. It gets the hostname
340 * as part of the UUCP "domain".
346 static char buffer[BUFSIZ] = "";
352 /* check if we have cached the system name */
358 /* check if mts.conf file specifies a "systemname" */
360 strncpy (buffer, systemname, sizeof(buffer));
366 strncpy (buffer, name.nodename, sizeof(buffer));
368 gethostname (buffer, sizeof(buffer));
376 * Get the username of current user
382 if (username[0] == '\0')
390 * Get full name of current user (typically from GECOS
391 * field of password file).
397 if (username[0] == '\0')
405 * Find the user's username and full name, and cache them.
406 * Also, handle "mmailid" username masquerading controlled from the GECOS field
407 * of the passwd file.
413 register unsigned char *cp;
415 register struct passwd *pw;
421 if (uid == geteuid () && (cp = getenv ("USER")) != NULL
422 && (pw = getpwnam (cp)) != NULL)
423 strncpy (username, cp, sizeof(username));
424 else if ((pw = getpwuid (uid)) == NULL
425 || pw->pw_name == NULL
426 || *pw->pw_name == '\0') {
428 if ((pw = getpwuid (getuid ())) == NULL
429 || pw->pw_name == NULL
430 || *pw->pw_name == '\0') {
432 strncpy (username, "unknown", sizeof(username));
433 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
440 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
441 which some OSes use to separate other 'finger' information in the GECOS
442 field, like phone number. Also, if mmailid masquerading is turned on due
443 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
444 hit a '<' (which should precede any ','s). */
446 if (mmailid_masquerading)
447 /* Stop at ',' or '<'. */
448 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
452 /* Allow '<' as a legal character of the user's name. This code is
453 basically a duplicate of the code above the "else" -- we don't
454 collapse it down to one copy and put the mmailid_masquerading check
455 inside the loop with "(x ? y : z)" because that's inefficient and the
456 value'll never change while it's in there. */
457 for (cp = fullname; *np != '\0' && *np != ',';
461 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
462 field (finger, mail, sendmail, etc.) translate any '&' character in it to
463 the login name, with the first letter capitalized. So, for instance,
464 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
465 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
466 the translation for you, so we have to do it manually here. */
467 if (mmailid_masquerading)
468 /* Stop at ',' or '<'. */
470 *np != '\0' && *np != ',' && *np != '<';) {
471 if (*np == '&') { /* blech! */
472 strcpy (cp, pw->pw_name);
482 /* Allow '<' as a legal character of the user's name. This code is
483 basically a duplicate of the code above the "else" -- we don't
484 collapse it down to one copy and put the mmailid_masquerading check
485 inside the loop with "(x ? y : z)" because that's inefficient and the
486 value'll never change while it's in there. */
488 *np != '\0' && *np != ',';) {
489 if (*np == '&') { /* blech! */
490 strcpy (cp, pw->pw_name);
502 if (mmailid_masquerading) {
503 /* Do mmailid processing. The GECOS field should have the form
504 "Full Name <fakeusername>". For instance,
505 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
506 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
510 for (cp = username; *np && *np != '>'; *cp++ = *np++)
514 if (!mmailid_masquerading || *np == '\0')
515 strncpy (username, pw->pw_name, sizeof(username));
517 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
519 if ((cp = getenv ("SIGNATURE")) && *cp)
520 strncpy (fullname, cp, sizeof(fullname));
522 if (strchr(fullname, '.')) { /* quote any .'s */
525 /* should quote "'s too */
526 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
527 strncpy (fullname, tmp, sizeof(fullname));