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);
36 static const char *get_mtsconf_pathname(void);
37 static const char *get_mtsuserconf_pathname(void);
38 static void mts_read_conf_file (FILE *fp);
41 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
42 * are kept in the user's home directory, then these should be empty
43 * strings. In this case, the appropriate ...lfil array should contain
44 * the name of the file in the user's home directory. Usually, this is
45 * something like ".mail".
49 * nmh mail transport interface customization file
51 static char *mtsconf = nmhetcdir(/mts.conf);
53 static char *localname = "";
54 static char *localdomain = "";
55 static char *systemname = "";
57 char *mmdfldir = MAILSPOOL;
59 char *uucpldir = "/usr/spool/mail";
62 char *mmdlm1 = "\001\001\001\001\n";
63 char *mmdlm2 = "\001\001\001\001\n";
65 /* Cache the username and fullname of the user */
66 static char username[BUFSIZ];
67 static char fullname[BUFSIZ];
69 /* Variables for username masquerading: */
70 boolean draft_from_masquerading = FALSE; /* also used from post.c */
71 static boolean mmailid_masquerading = FALSE;
72 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
73 static char* masquerade = "";
76 * MTS specific variables
79 static char *sm_method = "smtp";
80 int sm_mts = MTS_SMTP;
81 char *hostable = nmhetcdir(/hosts);
82 char *sendmail = SENDMAILPATH;
88 char *clientname = NULL;
89 char *servers = "localhost \01localnet";
93 * BBoards-specific variables
99 * POP BBoards-specific variables
102 char *popbbhost = "";
103 char *popbbuser = "";
104 char *popbblist = nmhetcdir(/hosts.popbb);
108 * Global MailDelivery file
110 char *maildelivery = nmhetcdir(/maildelivery);
114 * Aliasing Facility (doesn't belong here)
116 int Everyone = NOTOK;
117 static char *everyone = "-1";
121 * Customize the MTS settings for nmh by adjusting
122 * the file mts.conf in the nmh etc directory.
130 static struct bind binds[] = {
131 { "localname", &localname },
132 { "localdomain", &localdomain },
133 { "systemname", &systemname },
134 { "mmdfldir", &mmdfldir },
135 { "mmdflfil", &mmdflfil },
136 { "uucpldir", &uucpldir },
137 { "uucplfil", &uucplfil },
138 { "mmdelim1", &mmdlm1 },
139 { "mmdelim2", &mmdlm2 },
140 { "masquerade", &masquerade },
143 { "mts", &sm_method },
144 { "hostable", &hostable },
145 { "sendmail", &sendmail },
148 { "clientname", &clientname },
149 { "servers", &servers },
150 { "pophost", &pophost },
151 { "bbdomain", &bb_domain },
154 { "popbbhost", &popbbhost },
155 { "popbbuser", &popbbuser },
156 { "popbblist", &popbblist },
160 { "nntphost", &popbbhost },
163 { "maildelivery", &maildelivery },
164 { "everyone", &everyone },
165 { "noshell", &NoShell },
171 * Read the configuration file for the nmh interface
172 * to the mail transport system (MTS).
176 mts_init (char *name)
180 static int inited = 0;
182 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
184 mts_read_conf_file(fp);
187 cp = get_mtsuserconf_pathname();
189 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
190 mts_read_conf_file(fp);
194 Everyone = atoi (everyone);
196 if (strstr(masquerade, "draft_from") != NULL)
197 draft_from_masquerading = TRUE;
199 if (strstr(masquerade, "mmailid") != NULL)
200 mmailid_masquerading = TRUE;
202 if (strstr(masquerade, "username_extension") != NULL)
203 username_extension_masquerading = TRUE;
206 if (strcmp(sm_method, "smtp") == 0)
208 else if (strcmp(sm_method, "sendmail") == 0)
209 sm_mts = MTS_SENDMAIL;
211 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
221 * Convert escaped values, malloc some new space,
222 * and copy string to malloc'ed memory.
226 tailor_value (unsigned char *s)
233 for (bp = buffer; *s; bp++, s++) {
238 case 'b': *bp = '\b'; break;
239 case 'f': *bp = '\f'; break;
240 case 'n': *bp = '\n'; break;
241 case 't': *bp = '\t'; break;
253 r = *s != '0' ? 10 : 8;
254 for (i = 0; isdigit (*s); s++)
255 i = i * r + *s - '0';
264 len = strlen (buffer) + 1;
265 bp = mh_xmalloc (len);
266 memcpy (bp, buffer, len);
272 * Get the fully qualified name of the local host.
278 static char buffer[BUFSIZ] = "";
279 struct addrinfo hints, *res;
284 /* check if we have cached the local name */
290 /* check if the mts.conf file specifies a "localname" */
292 strncpy (buffer, localname, sizeof(buffer));
294 memset(buffer, 0, sizeof(buffer));
296 /* first get our local name */
298 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
300 /* first get our local name */
301 gethostname (buffer, sizeof(buffer) - 1);
303 /* now fully qualify our name */
305 memset(&hints, 0, sizeof(hints));
306 hints.ai_flags = AI_CANONNAME;
307 hints.ai_family = PF_UNSPEC;
308 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
309 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
315 * If the mts.conf file specifies a "localdomain",
316 * we append that now. This should rarely be needed.
319 strcat (buffer, ".");
320 strcat (buffer, localdomain);
328 * This is only for UUCP mail. It gets the hostname
329 * as part of the UUCP "domain".
335 static char buffer[BUFSIZ] = "";
341 /* check if we have cached the system name */
347 /* check if mts.conf file specifies a "systemname" */
349 strncpy (buffer, systemname, sizeof(buffer));
355 strncpy (buffer, name.nodename, sizeof(buffer));
357 gethostname (buffer, sizeof(buffer));
365 * Get the username of current user
371 if (username[0] == '\0')
379 * Get full name of current user (typically from GECOS
380 * field of password file).
386 if (username[0] == '\0')
394 * Find the user's username and full name, and cache them.
395 * Also, handle "mmailid" username masquerading controlled from the GECOS field
396 * of the passwd file.
402 register unsigned char *cp;
404 register struct passwd *pw;
410 if (uid == geteuid () && (cp = getenv ("USER")) != NULL
411 && (pw = getpwnam (cp)) != NULL)
412 strncpy (username, cp, sizeof(username));
413 else if ((pw = getpwuid (uid)) == NULL
414 || pw->pw_name == NULL
415 || *pw->pw_name == '\0') {
417 if ((pw = getpwuid (getuid ())) == NULL
418 || pw->pw_name == NULL
419 || *pw->pw_name == '\0') {
421 strncpy (username, "unknown", sizeof(username));
422 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
429 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
430 which some OSes use to separate other 'finger' information in the GECOS
431 field, like phone number. Also, if mmailid masquerading is turned on due
432 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
433 hit a '<' (which should precede any ','s). */
435 if (mmailid_masquerading)
436 /* Stop at ',' or '<'. */
437 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
441 /* Allow '<' as a legal character of the user's name. This code is
442 basically a duplicate of the code above the "else" -- we don't
443 collapse it down to one copy and put the mmailid_masquerading check
444 inside the loop with "(x ? y : z)" because that's inefficient and the
445 value'll never change while it's in there. */
446 for (cp = fullname; *np != '\0' && *np != ',';
450 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
451 field (finger, mail, sendmail, etc.) translate any '&' character in it to
452 the login name, with the first letter capitalized. So, for instance,
453 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
454 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
455 the translation for you, so we have to do it manually here. */
456 if (mmailid_masquerading)
457 /* Stop at ',' or '<'. */
459 *np != '\0' && *np != ',' && *np != '<';) {
460 if (*np == '&') { /* blech! */
461 strcpy (cp, pw->pw_name);
471 /* Allow '<' as a legal character of the user's name. This code is
472 basically a duplicate of the code above the "else" -- we don't
473 collapse it down to one copy and put the mmailid_masquerading check
474 inside the loop with "(x ? y : z)" because that's inefficient and the
475 value'll never change while it's in there. */
477 *np != '\0' && *np != ',';) {
478 if (*np == '&') { /* blech! */
479 strcpy (cp, pw->pw_name);
491 if (mmailid_masquerading) {
492 /* Do mmailid processing. The GECOS field should have the form
493 "Full Name <fakeusername>". For instance,
494 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
495 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
499 for (cp = username; *np && *np != '>'; *cp++ = *np++)
503 if (!mmailid_masquerading || *np == '\0')
504 strncpy (username, pw->pw_name, sizeof(username));
506 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
508 if ((cp = getenv ("SIGNATURE")) && *cp)
509 strncpy (fullname, cp, sizeof(fullname));
511 if (strchr(fullname, '.')) { /* quote any .'s */
514 /* should quote "'s too */
515 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
516 strncpy (fullname, tmp, sizeof(fullname));
523 get_mtsconf_pathname (void)
525 const char *cp = getenv ( "MHMTSCONF ");
526 if (cp != NULL && *cp != '\0') {
533 get_mtsuserconf_pathname (void)
535 const char *cp = getenv ( "MHMTSUSERCONF" );
536 if (cp != NULL && *cp != '\0') {
543 mts_read_conf_file (FILE *fp)
546 char *cp, buffer[BUFSIZ];
549 while (fgets (buffer, sizeof(buffer), fp)) {
550 if (!(cp = strchr(buffer, '\n')))
553 if (*buffer == '#' || *buffer == '\0')
555 if (!(bp = strchr(buffer, ':')))
558 while (isspace (*bp))
561 for (b = binds; b->keyword; b++)
562 if (!strcmp (buffer, b->keyword))
564 if (b->keyword && (cp = tailor_value (bp)))