3 * mts.c -- definitions for the mail transport system
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.
10 #include <h/mh.h> /* for snprintf() */
14 #define nmhetcdir(file) NMHETCDIR#file
22 #ifdef HAVE_SYS_UTSNAME_H
23 # include <sys/utsname.h>
32 static char *tailor_value (unsigned char *);
33 static void getuserinfo (void);
34 static const char *get_mtsconf_pathname(void);
35 static const char *get_mtsuserconf_pathname(void);
36 static void mts_read_conf_file (FILE *fp);
39 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
40 * are kept in the user's home directory, then these should be empty
41 * strings. In this case, the appropriate ...lfil array should contain
42 * the name of the file in the user's home directory. Usually, this is
43 * something like ".mail".
47 * nmh mail transport interface customization file
49 static char *mtsconf = nmhetcdir(/mts.conf);
51 static char *localname = "";
52 static char *localdomain = "";
53 static char *systemname = "";
55 char *mmdfldir = MAILSPOOL;
57 char *uucpldir = "/usr/spool/mail";
60 char *mmdlm1 = "\001\001\001\001\n";
61 char *mmdlm2 = "\001\001\001\001\n";
63 /* Cache the username and fullname of the user */
64 static char username[BUFSIZ];
65 static char fullname[BUFSIZ];
67 /* Variables for username masquerading: */
68 boolean draft_from_masquerading = FALSE; /* also used from post.c */
69 static boolean mmailid_masquerading = FALSE;
70 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
71 static char* masquerade = "";
74 * MTS specific variables
77 static char *sm_method = "smtp";
78 int sm_mts = MTS_SMTP;
79 char *hostable = nmhetcdir(/hosts);
80 char *sendmail = SENDMAILPATH;
86 char *clientname = NULL;
87 char *servers = "localhost \01localnet";
91 * BBoards-specific variables
97 * POP BBoards-specific variables
100 char *popbbhost = "";
101 char *popbbuser = "";
102 char *popbblist = nmhetcdir(/hosts.popbb);
106 * Global MailDelivery file
108 char *maildelivery = nmhetcdir(/maildelivery);
112 * Aliasing Facility (doesn't belong here)
114 int Everyone = NOTOK;
115 static char *everyone = "-1";
119 * Customize the MTS settings for nmh by adjusting
120 * the file mts.conf in the nmh etc directory.
128 static struct bind binds[] = {
129 { "localname", &localname },
130 { "localdomain", &localdomain },
131 { "systemname", &systemname },
132 { "mmdfldir", &mmdfldir },
133 { "mmdflfil", &mmdflfil },
134 { "uucpldir", &uucpldir },
135 { "uucplfil", &uucplfil },
136 { "mmdelim1", &mmdlm1 },
137 { "mmdelim2", &mmdlm2 },
138 { "masquerade", &masquerade },
141 { "mts", &sm_method },
142 { "hostable", &hostable },
143 { "sendmail", &sendmail },
146 { "clientname", &clientname },
147 { "servers", &servers },
148 { "pophost", &pophost },
149 { "bbdomain", &bb_domain },
152 { "popbbhost", &popbbhost },
153 { "popbbuser", &popbbuser },
154 { "popbblist", &popbblist },
158 { "nntphost", &popbbhost },
161 { "maildelivery", &maildelivery },
162 { "everyone", &everyone },
163 { "noshell", &NoShell },
169 * Read the configuration file for the nmh interface
170 * to the mail transport system (MTS).
174 mts_init (char *name)
178 static int inited = 0;
180 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
182 mts_read_conf_file(fp);
185 cp = get_mtsuserconf_pathname();
187 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
188 mts_read_conf_file(fp);
192 Everyone = atoi (everyone);
194 if (strstr(masquerade, "draft_from") != NULL)
195 draft_from_masquerading = TRUE;
197 if (strstr(masquerade, "mmailid") != NULL)
198 mmailid_masquerading = TRUE;
200 if (strstr(masquerade, "username_extension") != NULL)
201 username_extension_masquerading = TRUE;
204 if (strcmp(sm_method, "smtp") == 0)
206 else if (strcmp(sm_method, "sendmail") == 0)
207 sm_mts = MTS_SENDMAIL;
209 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
219 * Convert escaped values, malloc some new space,
220 * and copy string to malloc'ed memory.
224 tailor_value (unsigned char *s)
231 for (bp = buffer; *s; bp++, s++) {
236 case 'b': *bp = '\b'; break;
237 case 'f': *bp = '\f'; break;
238 case 'n': *bp = '\n'; break;
239 case 't': *bp = '\t'; break;
251 r = *s != '0' ? 10 : 8;
252 for (i = 0; isdigit (*s); s++)
253 i = i * r + *s - '0';
262 len = strlen (buffer) + 1;
263 bp = mh_xmalloc (len);
264 memcpy (bp, buffer, len);
270 * Get the fully qualified name of the local host.
276 static char buffer[BUFSIZ] = "";
277 struct addrinfo hints, *res;
282 /* check if we have cached the local name */
288 /* check if the mts.conf file specifies a "localname" */
290 strncpy (buffer, localname, sizeof(buffer));
292 memset(buffer, 0, sizeof(buffer));
294 /* first get our local name */
296 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
298 /* first get our local name */
299 gethostname (buffer, sizeof(buffer) - 1);
301 /* now fully qualify our name */
303 memset(&hints, 0, sizeof(hints));
304 hints.ai_flags = AI_CANONNAME;
305 hints.ai_family = PF_UNSPEC;
306 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
307 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
313 * If the mts.conf file specifies a "localdomain",
314 * we append that now. This should rarely be needed.
317 strcat (buffer, ".");
318 strcat (buffer, localdomain);
326 * This is only for UUCP mail. It gets the hostname
327 * as part of the UUCP "domain".
333 static char buffer[BUFSIZ] = "";
339 /* check if we have cached the system name */
345 /* check if mts.conf file specifies a "systemname" */
347 strncpy (buffer, systemname, sizeof(buffer));
353 strncpy (buffer, name.nodename, sizeof(buffer));
355 gethostname (buffer, sizeof(buffer));
363 * Get the username of current user
369 if (username[0] == '\0')
377 * Get full name of current user (typically from GECOS
378 * field of password file).
384 if (username[0] == '\0')
392 * Find the user's username and full name, and cache them.
393 * Also, handle "mmailid" username masquerading controlled from the GECOS field
394 * of the passwd file.
400 register unsigned char *cp;
402 register struct passwd *pw;
408 if (uid == geteuid () && (cp = getenv ("USER")) != NULL
409 && (pw = getpwnam (cp)) != NULL)
410 strncpy (username, cp, sizeof(username));
411 else if ((pw = getpwuid (uid)) == NULL
412 || pw->pw_name == NULL
413 || *pw->pw_name == '\0') {
415 if ((pw = getpwuid (getuid ())) == NULL
416 || pw->pw_name == NULL
417 || *pw->pw_name == '\0') {
419 strncpy (username, "unknown", sizeof(username));
420 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
427 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
428 which some OSes use to separate other 'finger' information in the GECOS
429 field, like phone number. Also, if mmailid masquerading is turned on due
430 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
431 hit a '<' (which should precede any ','s). */
433 if (mmailid_masquerading)
434 /* Stop at ',' or '<'. */
435 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
439 /* Allow '<' as a legal character of the user's name. This code is
440 basically a duplicate of the code above the "else" -- we don't
441 collapse it down to one copy and put the mmailid_masquerading check
442 inside the loop with "(x ? y : z)" because that's inefficient and the
443 value'll never change while it's in there. */
444 for (cp = fullname; *np != '\0' && *np != ',';
448 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
449 field (finger, mail, sendmail, etc.) translate any '&' character in it to
450 the login name, with the first letter capitalized. So, for instance,
451 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
452 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
453 the translation for you, so we have to do it manually here. */
454 if (mmailid_masquerading)
455 /* Stop at ',' or '<'. */
457 *np != '\0' && *np != ',' && *np != '<';) {
458 if (*np == '&') { /* blech! */
459 strcpy (cp, pw->pw_name);
469 /* Allow '<' as a legal character of the user's name. This code is
470 basically a duplicate of the code above the "else" -- we don't
471 collapse it down to one copy and put the mmailid_masquerading check
472 inside the loop with "(x ? y : z)" because that's inefficient and the
473 value'll never change while it's in there. */
475 *np != '\0' && *np != ',';) {
476 if (*np == '&') { /* blech! */
477 strcpy (cp, pw->pw_name);
489 if (mmailid_masquerading) {
490 /* Do mmailid processing. The GECOS field should have the form
491 "Full Name <fakeusername>". For instance,
492 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
493 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
497 for (cp = username; *np && *np != '>'; *cp++ = *np++)
501 if (!mmailid_masquerading || *np == '\0')
502 strncpy (username, pw->pw_name, sizeof(username));
504 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
506 if ((cp = getenv ("SIGNATURE")) && *cp)
507 strncpy (fullname, cp, sizeof(fullname));
509 if (strchr(fullname, '.')) { /* quote any .'s */
512 /* should quote "'s too */
513 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
514 strncpy (fullname, tmp, sizeof(fullname));
521 get_mtsconf_pathname (void)
523 const char *cp = getenv ( "MHMTSCONF ");
524 if (cp != NULL && *cp != '\0') {
531 get_mtsuserconf_pathname (void)
533 const char *cp = getenv ( "MHMTSUSERCONF" );
534 if (cp != NULL && *cp != '\0') {
541 mts_read_conf_file (FILE *fp)
544 char *cp, buffer[BUFSIZ];
547 while (fgets (buffer, sizeof(buffer), fp)) {
548 if (!(cp = strchr(buffer, '\n')))
551 if (*buffer == '#' || *buffer == '\0')
553 if (!(bp = strchr(buffer, ':')))
556 while (isspace (*bp))
559 for (b = binds; b->keyword; b++)
560 if (!strcmp (buffer, b->keyword))
562 if (b->keyword && (cp = tailor_value (bp)))