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
20 #include <sys/socket.h>
29 static char *tailor_value (unsigned char *);
30 static void getuserinfo (void);
31 static const char *get_mtsconf_pathname(void);
32 static const char *get_mtsuserconf_pathname(void);
33 static void mts_read_conf_file (FILE *fp);
36 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
37 * are kept in the user's home directory, then these should be empty
38 * strings. In this case, the appropriate ...lfil array should contain
39 * the name of the file in the user's home directory. Usually, this is
40 * something like ".mail".
44 * nmh mail transport interface customization file
46 static char *mtsconf = nmhetcdir(/mts.conf);
48 static char *localname = "";
49 static char *localdomain = "";
50 static char *systemname = "";
52 char *mmdfldir = MAILSPOOL;
54 char *uucpldir = "/usr/spool/mail";
57 char *mmdlm1 = "\001\001\001\001\n";
58 char *mmdlm2 = "\001\001\001\001\n";
60 /* Cache the username and fullname of the user */
61 static char username[BUFSIZ];
62 static char fullname[BUFSIZ];
64 /* Variables for username masquerading: */
65 boolean draft_from_masquerading = FALSE; /* also used from post.c */
66 static boolean mmailid_masquerading = FALSE;
67 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
68 static char* masquerade = "";
71 * MTS specific variables
74 static char *sm_method = "smtp";
75 int sm_mts = MTS_SMTP;
76 char *hostable = nmhetcdir(/hosts);
77 char *sendmail = SENDMAILPATH;
83 char *clientname = NULL;
84 char *servers = "localhost \01localnet";
88 * Global MailDelivery file
90 char *maildelivery = nmhetcdir(/maildelivery);
94 * Aliasing Facility (doesn't belong here)
97 static char *everyone = "-1";
101 * Customize the MTS settings for nmh by adjusting
102 * the file mts.conf in the nmh etc directory.
110 static struct bind binds[] = {
111 { "localname", &localname },
112 { "localdomain", &localdomain },
113 { "systemname", &systemname },
114 { "mmdfldir", &mmdfldir },
115 { "mmdflfil", &mmdflfil },
116 { "uucpldir", &uucpldir },
117 { "uucplfil", &uucplfil },
118 { "mmdelim1", &mmdlm1 },
119 { "mmdelim2", &mmdlm2 },
120 { "masquerade", &masquerade },
123 { "mts", &sm_method },
124 { "hostable", &hostable },
125 { "sendmail", &sendmail },
128 { "clientname", &clientname },
129 { "servers", &servers },
130 { "pophost", &pophost },
132 { "maildelivery", &maildelivery },
133 { "everyone", &everyone },
134 { "noshell", &NoShell },
140 * Read the configuration file for the nmh interface
141 * to the mail transport system (MTS).
145 mts_init (char *name)
149 static int inited = 0;
151 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
153 mts_read_conf_file(fp);
156 cp = get_mtsuserconf_pathname();
158 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
159 mts_read_conf_file(fp);
163 Everyone = atoi (everyone);
165 if (strstr(masquerade, "draft_from") != NULL)
166 draft_from_masquerading = TRUE;
168 if (strstr(masquerade, "mmailid") != NULL)
169 mmailid_masquerading = TRUE;
171 if (strstr(masquerade, "username_extension") != NULL)
172 username_extension_masquerading = TRUE;
175 if (strcmp(sm_method, "smtp") == 0)
177 else if (strcmp(sm_method, "sendmail") == 0)
178 sm_mts = MTS_SENDMAIL;
180 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
190 * Convert escaped values, malloc some new space,
191 * and copy string to malloc'ed memory.
195 tailor_value (unsigned char *s)
202 for (bp = buffer; *s; bp++, s++) {
207 case 'b': *bp = '\b'; break;
208 case 'f': *bp = '\f'; break;
209 case 'n': *bp = '\n'; break;
210 case 't': *bp = '\t'; break;
222 r = *s != '0' ? 10 : 8;
223 for (i = 0; isdigit (*s); s++)
224 i = i * r + *s - '0';
233 len = strlen (buffer) + 1;
234 bp = mh_xmalloc (len);
235 memcpy (bp, buffer, len);
241 * Get the fully qualified name of the local host.
247 static char buffer[BUFSIZ] = "";
248 struct addrinfo hints, *res;
250 /* check if we have cached the local name */
256 /* check if the mts.conf file specifies a "localname" */
258 strncpy (buffer, localname, sizeof(buffer));
260 memset(buffer, 0, sizeof(buffer));
261 /* first get our local name */
262 gethostname (buffer, sizeof(buffer) - 1);
263 /* now fully qualify our name */
265 memset(&hints, 0, sizeof(hints));
266 hints.ai_flags = AI_CANONNAME;
267 hints.ai_family = PF_UNSPEC;
268 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
269 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
275 * If the mts.conf file specifies a "localdomain",
276 * we append that now. This should rarely be needed.
279 strcat (buffer, ".");
280 strcat (buffer, localdomain);
288 * This is only for UUCP mail. It gets the hostname
289 * as part of the UUCP "domain".
295 static char buffer[BUFSIZ] = "";
297 /* check if we have cached the system name */
303 /* check if mts.conf file specifies a "systemname" */
305 strncpy (buffer, systemname, sizeof(buffer));
309 gethostname (buffer, sizeof(buffer));
316 * Get the username of current user
322 if (username[0] == '\0')
330 * Get full name of current user (typically from GECOS
331 * field of password file).
337 if (username[0] == '\0')
345 * Find the user's username and full name, and cache them.
346 * Also, handle "mmailid" username masquerading controlled from the GECOS field
347 * of the passwd file.
353 register unsigned char *cp;
355 register struct passwd *pw;
357 if ((pw = getpwuid (getuid ())) == NULL
358 || pw->pw_name == NULL
359 || *pw->pw_name == '\0') {
360 strncpy (username, "unknown", sizeof(username));
361 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
368 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
369 which some OSes use to separate other 'finger' information in the GECOS
370 field, like phone number. Also, if mmailid masquerading is turned on due
371 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
372 hit a '<' (which should precede any ','s). */
374 if (mmailid_masquerading)
375 /* Stop at ',' or '<'. */
376 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
380 /* Allow '<' as a legal character of the user's name. This code is
381 basically a duplicate of the code above the "else" -- we don't
382 collapse it down to one copy and put the mmailid_masquerading check
383 inside the loop with "(x ? y : z)" because that's inefficient and the
384 value'll never change while it's in there. */
385 for (cp = fullname; *np != '\0' && *np != ',';
389 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
390 field (finger, mail, sendmail, etc.) translate any '&' character in it to
391 the login name, with the first letter capitalized. So, for instance,
392 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
393 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
394 the translation for you, so we have to do it manually here. */
395 if (mmailid_masquerading)
396 /* Stop at ',' or '<'. */
398 *np != '\0' && *np != ',' && *np != '<';) {
399 if (*np == '&') { /* blech! */
400 strcpy (cp, pw->pw_name);
410 /* Allow '<' as a legal character of the user's name. This code is
411 basically a duplicate of the code above the "else" -- we don't
412 collapse it down to one copy and put the mmailid_masquerading check
413 inside the loop with "(x ? y : z)" because that's inefficient and the
414 value'll never change while it's in there. */
416 *np != '\0' && *np != ',';) {
417 if (*np == '&') { /* blech! */
418 strcpy (cp, pw->pw_name);
430 if (mmailid_masquerading) {
431 /* Do mmailid processing. The GECOS field should have the form
432 "Full Name <fakeusername>". For instance,
433 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
434 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
438 for (cp = username; *np && *np != '>'; *cp++ = *np++)
442 if (!mmailid_masquerading || *np == '\0')
443 strncpy (username, pw->pw_name, sizeof(username));
445 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
447 if ((cp = getenv ("SIGNATURE")) && *cp)
448 strncpy (fullname, cp, sizeof(fullname));
450 if (strchr(fullname, '.')) { /* quote any .'s */
453 /* should quote "'s too */
454 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
455 strncpy (fullname, tmp, sizeof(fullname));
462 get_mtsconf_pathname (void)
464 const char *cp = getenv ( "MHMTSCONF ");
465 if (cp != NULL && *cp != '\0') {
472 get_mtsuserconf_pathname (void)
474 const char *cp = getenv ( "MHMTSUSERCONF" );
475 if (cp != NULL && *cp != '\0') {
482 mts_read_conf_file (FILE *fp)
485 char *cp, buffer[BUFSIZ];
488 while (fgets (buffer, sizeof(buffer), fp)) {
489 if (!(cp = strchr(buffer, '\n')))
492 if (*buffer == '#' || *buffer == '\0')
494 if (!(bp = strchr(buffer, ':')))
497 while (isspace (*bp))
500 for (b = binds; b->keyword; b++)
501 if (!strcmp (buffer, b->keyword))
503 if (b->keyword && (cp = tailor_value (bp)))