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 = "sendmail";
78 int sm_mts = MTS_SENDMAIL;
79 char *hostable = nmhetcdir(/hosts);
80 char *sendmail = SENDMAILPATH;
86 char *clientname = NULL;
87 char *servers = "localhost \01localnet";
90 * Global MailDelivery file
92 char *maildelivery = nmhetcdir(/maildelivery);
96 * Aliasing Facility (doesn't belong here)
99 static char *everyone = "-1";
103 * Customize the MTS settings for nmh by adjusting
104 * the file mts.conf in the nmh etc directory.
112 static struct bind binds[] = {
113 { "localname", &localname },
114 { "localdomain", &localdomain },
115 { "systemname", &systemname },
116 { "mmdfldir", &mmdfldir },
117 { "mmdflfil", &mmdflfil },
118 { "uucpldir", &uucpldir },
119 { "uucplfil", &uucplfil },
120 { "mmdelim1", &mmdlm1 },
121 { "mmdelim2", &mmdlm2 },
122 { "masquerade", &masquerade },
125 { "mts", &sm_method },
126 { "hostable", &hostable },
127 { "sendmail", &sendmail },
130 { "clientname", &clientname },
131 { "servers", &servers },
133 { "maildelivery", &maildelivery },
134 { "everyone", &everyone },
135 { "noshell", &NoShell },
141 * Read the configuration file for the nmh interface
142 * to the mail transport system (MTS).
146 mts_init (char *name)
150 static int inited = 0;
152 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
154 mts_read_conf_file(fp);
157 cp = get_mtsuserconf_pathname();
159 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
160 mts_read_conf_file(fp);
164 Everyone = atoi (everyone);
166 if (strstr(masquerade, "draft_from") != NULL)
167 draft_from_masquerading = TRUE;
169 if (strstr(masquerade, "mmailid") != NULL)
170 mmailid_masquerading = TRUE;
172 if (strstr(masquerade, "username_extension") != NULL)
173 username_extension_masquerading = TRUE;
180 * Convert escaped values, malloc some new space,
181 * and copy string to malloc'ed memory.
185 tailor_value (unsigned char *s)
192 for (bp = buffer; *s; bp++, s++) {
197 case 'b': *bp = '\b'; break;
198 case 'f': *bp = '\f'; break;
199 case 'n': *bp = '\n'; break;
200 case 't': *bp = '\t'; break;
212 r = *s != '0' ? 10 : 8;
213 for (i = 0; isdigit (*s); s++)
214 i = i * r + *s - '0';
223 len = strlen (buffer) + 1;
224 bp = mh_xmalloc (len);
225 memcpy (bp, buffer, len);
231 * Get the fully qualified name of the local host.
237 static char buffer[BUFSIZ] = "";
238 struct addrinfo hints, *res;
243 /* check if we have cached the local name */
249 /* check if the mts.conf file specifies a "localname" */
251 strncpy (buffer, localname, sizeof(buffer));
253 memset(buffer, 0, sizeof(buffer));
255 /* first get our local name */
257 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
259 /* first get our local name */
260 gethostname (buffer, sizeof(buffer) - 1);
262 /* now fully qualify our name */
264 memset(&hints, 0, sizeof(hints));
265 hints.ai_flags = AI_CANONNAME;
266 hints.ai_family = PF_UNSPEC;
267 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
268 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
274 * If the mts.conf file specifies a "localdomain",
275 * we append that now. This should rarely be needed.
278 strcat (buffer, ".");
279 strcat (buffer, localdomain);
287 * This is only for UUCP mail. It gets the hostname
288 * as part of the UUCP "domain".
294 static char buffer[BUFSIZ] = "";
300 /* check if we have cached the system name */
306 /* check if mts.conf file specifies a "systemname" */
308 strncpy (buffer, systemname, sizeof(buffer));
314 strncpy (buffer, name.nodename, sizeof(buffer));
316 gethostname (buffer, sizeof(buffer));
324 * Get the username of current user
330 if (username[0] == '\0')
338 * Get full name of current user (typically from GECOS
339 * field of password file).
345 if (username[0] == '\0')
353 * Find the user's username and full name, and cache them.
354 * Also, handle "mmailid" username masquerading controlled from the GECOS field
355 * of the passwd file.
361 register unsigned char *cp;
363 register struct passwd *pw;
365 if ((pw = getpwuid (getuid ())) == NULL
366 || pw->pw_name == NULL
367 || *pw->pw_name == '\0') {
368 strncpy (username, "unknown", sizeof(username));
369 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
376 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
377 which some OSes use to separate other 'finger' information in the GECOS
378 field, like phone number. Also, if mmailid masquerading is turned on due
379 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
380 hit a '<' (which should precede any ','s). */
382 if (mmailid_masquerading)
383 /* Stop at ',' or '<'. */
384 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
388 /* Allow '<' as a legal character of the user's name. This code is
389 basically a duplicate of the code above the "else" -- we don't
390 collapse it down to one copy and put the mmailid_masquerading check
391 inside the loop with "(x ? y : z)" because that's inefficient and the
392 value'll never change while it's in there. */
393 for (cp = fullname; *np != '\0' && *np != ',';
397 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
398 field (finger, mail, sendmail, etc.) translate any '&' character in it to
399 the login name, with the first letter capitalized. So, for instance,
400 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
401 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
402 the translation for you, so we have to do it manually here. */
403 if (mmailid_masquerading)
404 /* Stop at ',' or '<'. */
406 *np != '\0' && *np != ',' && *np != '<';) {
407 if (*np == '&') { /* blech! */
408 strcpy (cp, pw->pw_name);
418 /* Allow '<' as a legal character of the user's name. This code is
419 basically a duplicate of the code above the "else" -- we don't
420 collapse it down to one copy and put the mmailid_masquerading check
421 inside the loop with "(x ? y : z)" because that's inefficient and the
422 value'll never change while it's in there. */
424 *np != '\0' && *np != ',';) {
425 if (*np == '&') { /* blech! */
426 strcpy (cp, pw->pw_name);
438 if (mmailid_masquerading) {
439 /* Do mmailid processing. The GECOS field should have the form
440 "Full Name <fakeusername>". For instance,
441 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
442 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
446 for (cp = username; *np && *np != '>'; *cp++ = *np++)
450 if (!mmailid_masquerading || *np == '\0')
451 strncpy (username, pw->pw_name, sizeof(username));
453 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
455 if ((cp = getenv ("SIGNATURE")) && *cp)
456 strncpy (fullname, cp, sizeof(fullname));
458 if (strchr(fullname, '.')) { /* quote any .'s */
461 /* should quote "'s too */
462 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
463 strncpy (fullname, tmp, sizeof(fullname));
470 get_mtsconf_pathname (void)
472 const char *cp = getenv ( "MHMTSCONF ");
473 if (cp != NULL && *cp != '\0') {
480 get_mtsuserconf_pathname (void)
482 const char *cp = getenv ( "MHMTSUSERCONF" );
483 if (cp != NULL && *cp != '\0') {
490 mts_read_conf_file (FILE *fp)
493 char *cp, buffer[BUFSIZ];
496 while (fgets (buffer, sizeof(buffer), fp)) {
497 if (!(cp = strchr(buffer, '\n')))
500 if (*buffer == '#' || *buffer == '\0')
502 if (!(bp = strchr(buffer, ':')))
505 while (isspace (*bp))
508 for (b = binds; b->keyword; b++)
509 if (!strcmp (buffer, b->keyword))
511 if (b->keyword && (cp = tailor_value (bp)))