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 char *mmdfldir = MAILSPOOL;
53 char *uucpldir = "/usr/spool/mail";
56 char *mmdlm1 = "\001\001\001\001\n";
57 char *mmdlm2 = "\001\001\001\001\n";
59 /* Cache the username and fullname of the user */
60 static char username[BUFSIZ];
61 static char fullname[BUFSIZ];
63 /* Variables for username masquerading: */
64 boolean draft_from_masquerading = FALSE;
65 static boolean mmailid_masquerading = FALSE;
66 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
67 static char* masquerade = "";
70 * MTS specific variables
72 char *sendmail = SENDMAILPATH;
75 * Global MailDelivery file
77 char *maildelivery = nmhetcdir(/maildelivery);
81 * Aliasing Facility (doesn't belong here)
84 static char *everyone = "-1";
88 * Customize the MTS settings for nmh by adjusting
89 * the file mts.conf in the nmh etc directory.
97 static struct bind binds[] = {
98 { "mmdfldir", &mmdfldir },
99 { "mmdflfil", &mmdflfil },
100 { "uucpldir", &uucpldir },
101 { "uucplfil", &uucplfil },
102 { "mmdelim1", &mmdlm1 },
103 { "mmdelim2", &mmdlm2 },
104 { "masquerade", &masquerade },
105 { "sendmail", &sendmail },
106 { "maildelivery", &maildelivery },
107 { "everyone", &everyone },
108 { "noshell", &NoShell },
114 * Read the configuration file for the nmh interface
115 * to the mail transport system (MTS).
119 mts_init (char *name)
123 static int inited = 0;
125 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
127 mts_read_conf_file(fp);
130 cp = get_mtsuserconf_pathname();
132 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
133 mts_read_conf_file(fp);
137 Everyone = atoi (everyone);
139 if (strstr(masquerade, "draft_from") != NULL)
140 draft_from_masquerading = TRUE;
142 if (strstr(masquerade, "mmailid") != NULL)
143 mmailid_masquerading = TRUE;
145 if (strstr(masquerade, "username_extension") != NULL)
146 username_extension_masquerading = TRUE;
153 * Convert escaped values, malloc some new space,
154 * and copy string to malloc'ed memory.
158 tailor_value (unsigned char *s)
165 for (bp = buffer; *s; bp++, s++) {
170 case 'b': *bp = '\b'; break;
171 case 'f': *bp = '\f'; break;
172 case 'n': *bp = '\n'; break;
173 case 't': *bp = '\t'; break;
185 r = *s != '0' ? 10 : 8;
186 for (i = 0; isdigit (*s); s++)
187 i = i * r + *s - '0';
196 len = strlen (buffer) + 1;
197 bp = mh_xmalloc (len);
198 memcpy (bp, buffer, len);
204 * Get the fully qualified name of the local host.
210 static char buffer[BUFSIZ] = "";
211 struct addrinfo hints, *res;
216 /* check if we have cached the local name */
222 memset(buffer, 0, sizeof(buffer));
224 /* first get our local name */
226 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
228 /* first get our local name */
229 gethostname (buffer, sizeof(buffer) - 1);
231 /* now fully qualify our name */
233 memset(&hints, 0, sizeof(hints));
234 hints.ai_flags = AI_CANONNAME;
235 hints.ai_family = PF_UNSPEC;
236 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
237 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
246 * This is only for UUCP mail. It gets the hostname
247 * as part of the UUCP "domain".
253 static char buffer[BUFSIZ] = "";
259 /* check if we have cached the system name */
267 strncpy (buffer, name.nodename, sizeof(buffer));
269 gethostname (buffer, sizeof(buffer));
277 * Get the username of current user
283 if (username[0] == '\0')
291 * Get full name of current user (typically from GECOS
292 * field of password file).
298 if (username[0] == '\0')
306 * Find the user's username and full name, and cache them.
307 * Also, handle "mmailid" username masquerading controlled from the GECOS field
308 * of the passwd file.
314 register unsigned char *cp;
316 register struct passwd *pw;
318 if ((pw = getpwuid (getuid ())) == NULL
319 || pw->pw_name == NULL
320 || *pw->pw_name == '\0') {
321 strncpy (username, "unknown", sizeof(username));
322 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
329 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
330 which some OSes use to separate other 'finger' information in the GECOS
331 field, like phone number. Also, if mmailid masquerading is turned on due
332 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
333 hit a '<' (which should precede any ','s). */
335 if (mmailid_masquerading)
336 /* Stop at ',' or '<'. */
337 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
341 /* Allow '<' as a legal character of the user's name. This code is
342 basically a duplicate of the code above the "else" -- we don't
343 collapse it down to one copy and put the mmailid_masquerading check
344 inside the loop with "(x ? y : z)" because that's inefficient and the
345 value'll never change while it's in there. */
346 for (cp = fullname; *np != '\0' && *np != ',';
350 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
351 field (finger, mail, sendmail, etc.) translate any '&' character in it to
352 the login name, with the first letter capitalized. So, for instance,
353 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
354 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
355 the translation for you, so we have to do it manually here. */
356 if (mmailid_masquerading)
357 /* Stop at ',' or '<'. */
359 *np != '\0' && *np != ',' && *np != '<';) {
360 if (*np == '&') { /* blech! */
361 strcpy (cp, pw->pw_name);
371 /* Allow '<' as a legal character of the user's name. This code is
372 basically a duplicate of the code above the "else" -- we don't
373 collapse it down to one copy and put the mmailid_masquerading check
374 inside the loop with "(x ? y : z)" because that's inefficient and the
375 value'll never change while it's in there. */
377 *np != '\0' && *np != ',';) {
378 if (*np == '&') { /* blech! */
379 strcpy (cp, pw->pw_name);
391 if (mmailid_masquerading) {
392 /* Do mmailid processing. The GECOS field should have the form
393 "Full Name <fakeusername>". For instance,
394 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
395 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
399 for (cp = username; *np && *np != '>'; *cp++ = *np++)
403 if (!mmailid_masquerading || *np == '\0')
404 strncpy (username, pw->pw_name, sizeof(username));
406 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
408 if ((cp = getenv ("SIGNATURE")) && *cp)
409 strncpy (fullname, cp, sizeof(fullname));
411 if (strchr(fullname, '.')) { /* quote any .'s */
414 /* should quote "'s too */
415 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
416 strncpy (fullname, tmp, sizeof(fullname));
423 get_mtsconf_pathname (void)
425 const char *cp = getenv ( "MHMTSCONF ");
426 if (cp != NULL && *cp != '\0') {
433 get_mtsuserconf_pathname (void)
435 const char *cp = getenv ( "MHMTSUSERCONF" );
436 if (cp != NULL && *cp != '\0') {
443 mts_read_conf_file (FILE *fp)
446 char *cp, buffer[BUFSIZ];
449 while (fgets (buffer, sizeof(buffer), fp)) {
450 if (!(cp = strchr(buffer, '\n')))
453 if (*buffer == '#' || *buffer == '\0')
455 if (!(bp = strchr(buffer, ':')))
458 while (isspace (*bp))
461 for (b = binds; b->keyword; b++)
462 if (!strcmp (buffer, b->keyword))
464 if (b->keyword && (cp = tailor_value (bp)))