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 *sendmail = SENDMAILPATH;
85 char *clientname = NULL;
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 { "sendmail", &sendmail },
127 { "clientname", &clientname },
129 { "maildelivery", &maildelivery },
130 { "everyone", &everyone },
131 { "noshell", &NoShell },
137 * Read the configuration file for the nmh interface
138 * to the mail transport system (MTS).
142 mts_init (char *name)
146 static int inited = 0;
148 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
150 mts_read_conf_file(fp);
153 cp = get_mtsuserconf_pathname();
155 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
156 mts_read_conf_file(fp);
160 Everyone = atoi (everyone);
162 if (strstr(masquerade, "draft_from") != NULL)
163 draft_from_masquerading = TRUE;
165 if (strstr(masquerade, "mmailid") != NULL)
166 mmailid_masquerading = TRUE;
168 if (strstr(masquerade, "username_extension") != NULL)
169 username_extension_masquerading = TRUE;
176 * Convert escaped values, malloc some new space,
177 * and copy string to malloc'ed memory.
181 tailor_value (unsigned char *s)
188 for (bp = buffer; *s; bp++, s++) {
193 case 'b': *bp = '\b'; break;
194 case 'f': *bp = '\f'; break;
195 case 'n': *bp = '\n'; break;
196 case 't': *bp = '\t'; break;
208 r = *s != '0' ? 10 : 8;
209 for (i = 0; isdigit (*s); s++)
210 i = i * r + *s - '0';
219 len = strlen (buffer) + 1;
220 bp = mh_xmalloc (len);
221 memcpy (bp, buffer, len);
227 * Get the fully qualified name of the local host.
233 static char buffer[BUFSIZ] = "";
234 struct addrinfo hints, *res;
239 /* check if we have cached the local name */
245 /* check if the mts.conf file specifies a "localname" */
247 strncpy (buffer, localname, sizeof(buffer));
249 memset(buffer, 0, sizeof(buffer));
251 /* first get our local name */
253 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
255 /* first get our local name */
256 gethostname (buffer, sizeof(buffer) - 1);
258 /* now fully qualify our name */
260 memset(&hints, 0, sizeof(hints));
261 hints.ai_flags = AI_CANONNAME;
262 hints.ai_family = PF_UNSPEC;
263 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
264 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
270 * If the mts.conf file specifies a "localdomain",
271 * we append that now. This should rarely be needed.
274 strcat (buffer, ".");
275 strcat (buffer, localdomain);
283 * This is only for UUCP mail. It gets the hostname
284 * as part of the UUCP "domain".
290 static char buffer[BUFSIZ] = "";
296 /* check if we have cached the system name */
302 /* check if mts.conf file specifies a "systemname" */
304 strncpy (buffer, systemname, sizeof(buffer));
310 strncpy (buffer, name.nodename, sizeof(buffer));
312 gethostname (buffer, sizeof(buffer));
320 * Get the username of current user
326 if (username[0] == '\0')
334 * Get full name of current user (typically from GECOS
335 * field of password file).
341 if (username[0] == '\0')
349 * Find the user's username and full name, and cache them.
350 * Also, handle "mmailid" username masquerading controlled from the GECOS field
351 * of the passwd file.
357 register unsigned char *cp;
359 register struct passwd *pw;
361 if ((pw = getpwuid (getuid ())) == NULL
362 || pw->pw_name == NULL
363 || *pw->pw_name == '\0') {
364 strncpy (username, "unknown", sizeof(username));
365 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
372 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
373 which some OSes use to separate other 'finger' information in the GECOS
374 field, like phone number. Also, if mmailid masquerading is turned on due
375 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
376 hit a '<' (which should precede any ','s). */
378 if (mmailid_masquerading)
379 /* Stop at ',' or '<'. */
380 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
384 /* Allow '<' as a legal character of the user's name. This code is
385 basically a duplicate of the code above the "else" -- we don't
386 collapse it down to one copy and put the mmailid_masquerading check
387 inside the loop with "(x ? y : z)" because that's inefficient and the
388 value'll never change while it's in there. */
389 for (cp = fullname; *np != '\0' && *np != ',';
393 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
394 field (finger, mail, sendmail, etc.) translate any '&' character in it to
395 the login name, with the first letter capitalized. So, for instance,
396 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
397 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
398 the translation for you, so we have to do it manually here. */
399 if (mmailid_masquerading)
400 /* Stop at ',' or '<'. */
402 *np != '\0' && *np != ',' && *np != '<';) {
403 if (*np == '&') { /* blech! */
404 strcpy (cp, pw->pw_name);
414 /* Allow '<' as a legal character of the user's name. This code is
415 basically a duplicate of the code above the "else" -- we don't
416 collapse it down to one copy and put the mmailid_masquerading check
417 inside the loop with "(x ? y : z)" because that's inefficient and the
418 value'll never change while it's in there. */
420 *np != '\0' && *np != ',';) {
421 if (*np == '&') { /* blech! */
422 strcpy (cp, pw->pw_name);
434 if (mmailid_masquerading) {
435 /* Do mmailid processing. The GECOS field should have the form
436 "Full Name <fakeusername>". For instance,
437 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
438 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
442 for (cp = username; *np && *np != '>'; *cp++ = *np++)
446 if (!mmailid_masquerading || *np == '\0')
447 strncpy (username, pw->pw_name, sizeof(username));
449 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
451 if ((cp = getenv ("SIGNATURE")) && *cp)
452 strncpy (fullname, cp, sizeof(fullname));
454 if (strchr(fullname, '.')) { /* quote any .'s */
457 /* should quote "'s too */
458 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
459 strncpy (fullname, tmp, sizeof(fullname));
466 get_mtsconf_pathname (void)
468 const char *cp = getenv ( "MHMTSCONF ");
469 if (cp != NULL && *cp != '\0') {
476 get_mtsuserconf_pathname (void)
478 const char *cp = getenv ( "MHMTSUSERCONF" );
479 if (cp != NULL && *cp != '\0') {
486 mts_read_conf_file (FILE *fp)
489 char *cp, buffer[BUFSIZ];
492 while (fgets (buffer, sizeof(buffer), fp)) {
493 if (!(cp = strchr(buffer, '\n')))
496 if (*buffer == '#' || *buffer == '\0')
498 if (!(bp = strchr(buffer, ':')))
501 while (isspace (*bp))
504 for (b = binds; b->keyword; b++)
505 if (!strcmp (buffer, b->keyword))
507 if (b->keyword && (cp = tailor_value (bp)))