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";
91 * Global MailDelivery file
93 char *maildelivery = nmhetcdir(/maildelivery);
97 * Aliasing Facility (doesn't belong here)
100 static char *everyone = "-1";
104 * Customize the MTS settings for nmh by adjusting
105 * the file mts.conf in the nmh etc directory.
113 static struct bind binds[] = {
114 { "localname", &localname },
115 { "localdomain", &localdomain },
116 { "systemname", &systemname },
117 { "mmdfldir", &mmdfldir },
118 { "mmdflfil", &mmdflfil },
119 { "uucpldir", &uucpldir },
120 { "uucplfil", &uucplfil },
121 { "mmdelim1", &mmdlm1 },
122 { "mmdelim2", &mmdlm2 },
123 { "masquerade", &masquerade },
126 { "mts", &sm_method },
127 { "hostable", &hostable },
128 { "sendmail", &sendmail },
131 { "clientname", &clientname },
132 { "servers", &servers },
133 { "pophost", &pophost },
135 { "maildelivery", &maildelivery },
136 { "everyone", &everyone },
137 { "noshell", &NoShell },
143 * Read the configuration file for the nmh interface
144 * to the mail transport system (MTS).
148 mts_init (char *name)
152 static int inited = 0;
154 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
156 mts_read_conf_file(fp);
159 cp = get_mtsuserconf_pathname();
161 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
162 mts_read_conf_file(fp);
166 Everyone = atoi (everyone);
168 if (strstr(masquerade, "draft_from") != NULL)
169 draft_from_masquerading = TRUE;
171 if (strstr(masquerade, "mmailid") != NULL)
172 mmailid_masquerading = TRUE;
174 if (strstr(masquerade, "username_extension") != NULL)
175 username_extension_masquerading = TRUE;
182 * Convert escaped values, malloc some new space,
183 * and copy string to malloc'ed memory.
187 tailor_value (unsigned char *s)
194 for (bp = buffer; *s; bp++, s++) {
199 case 'b': *bp = '\b'; break;
200 case 'f': *bp = '\f'; break;
201 case 'n': *bp = '\n'; break;
202 case 't': *bp = '\t'; break;
214 r = *s != '0' ? 10 : 8;
215 for (i = 0; isdigit (*s); s++)
216 i = i * r + *s - '0';
225 len = strlen (buffer) + 1;
226 bp = mh_xmalloc (len);
227 memcpy (bp, buffer, len);
233 * Get the fully qualified name of the local host.
239 static char buffer[BUFSIZ] = "";
240 struct addrinfo hints, *res;
245 /* check if we have cached the local name */
251 /* check if the mts.conf file specifies a "localname" */
253 strncpy (buffer, localname, sizeof(buffer));
255 memset(buffer, 0, sizeof(buffer));
257 /* first get our local name */
259 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
261 /* first get our local name */
262 gethostname (buffer, sizeof(buffer) - 1);
264 /* now fully qualify our name */
266 memset(&hints, 0, sizeof(hints));
267 hints.ai_flags = AI_CANONNAME;
268 hints.ai_family = PF_UNSPEC;
269 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
270 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
276 * If the mts.conf file specifies a "localdomain",
277 * we append that now. This should rarely be needed.
280 strcat (buffer, ".");
281 strcat (buffer, localdomain);
289 * This is only for UUCP mail. It gets the hostname
290 * as part of the UUCP "domain".
296 static char buffer[BUFSIZ] = "";
302 /* check if we have cached the system name */
308 /* check if mts.conf file specifies a "systemname" */
310 strncpy (buffer, systemname, sizeof(buffer));
316 strncpy (buffer, name.nodename, sizeof(buffer));
318 gethostname (buffer, sizeof(buffer));
326 * Get the username of current user
332 if (username[0] == '\0')
340 * Get full name of current user (typically from GECOS
341 * field of password file).
347 if (username[0] == '\0')
355 * Find the user's username and full name, and cache them.
356 * Also, handle "mmailid" username masquerading controlled from the GECOS field
357 * of the passwd file.
363 register unsigned char *cp;
365 register struct passwd *pw;
367 if ((pw = getpwuid (getuid ())) == NULL
368 || pw->pw_name == NULL
369 || *pw->pw_name == '\0') {
370 strncpy (username, "unknown", sizeof(username));
371 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
378 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
379 which some OSes use to separate other 'finger' information in the GECOS
380 field, like phone number. Also, if mmailid masquerading is turned on due
381 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
382 hit a '<' (which should precede any ','s). */
384 if (mmailid_masquerading)
385 /* Stop at ',' or '<'. */
386 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
390 /* Allow '<' as a legal character of the user's name. This code is
391 basically a duplicate of the code above the "else" -- we don't
392 collapse it down to one copy and put the mmailid_masquerading check
393 inside the loop with "(x ? y : z)" because that's inefficient and the
394 value'll never change while it's in there. */
395 for (cp = fullname; *np != '\0' && *np != ',';
399 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
400 field (finger, mail, sendmail, etc.) translate any '&' character in it to
401 the login name, with the first letter capitalized. So, for instance,
402 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
403 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
404 the translation for you, so we have to do it manually here. */
405 if (mmailid_masquerading)
406 /* Stop at ',' or '<'. */
408 *np != '\0' && *np != ',' && *np != '<';) {
409 if (*np == '&') { /* blech! */
410 strcpy (cp, pw->pw_name);
420 /* Allow '<' as a legal character of the user's name. This code is
421 basically a duplicate of the code above the "else" -- we don't
422 collapse it down to one copy and put the mmailid_masquerading check
423 inside the loop with "(x ? y : z)" because that's inefficient and the
424 value'll never change while it's in there. */
426 *np != '\0' && *np != ',';) {
427 if (*np == '&') { /* blech! */
428 strcpy (cp, pw->pw_name);
440 if (mmailid_masquerading) {
441 /* Do mmailid processing. The GECOS field should have the form
442 "Full Name <fakeusername>". For instance,
443 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
444 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
448 for (cp = username; *np && *np != '>'; *cp++ = *np++)
452 if (!mmailid_masquerading || *np == '\0')
453 strncpy (username, pw->pw_name, sizeof(username));
455 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
457 if ((cp = getenv ("SIGNATURE")) && *cp)
458 strncpy (fullname, cp, sizeof(fullname));
460 if (strchr(fullname, '.')) { /* quote any .'s */
463 /* should quote "'s too */
464 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
465 strncpy (fullname, tmp, sizeof(fullname));
472 get_mtsconf_pathname (void)
474 const char *cp = getenv ( "MHMTSCONF ");
475 if (cp != NULL && *cp != '\0') {
482 get_mtsuserconf_pathname (void)
484 const char *cp = getenv ( "MHMTSUSERCONF" );
485 if (cp != NULL && *cp != '\0') {
492 mts_read_conf_file (FILE *fp)
495 char *cp, buffer[BUFSIZ];
498 while (fgets (buffer, sizeof(buffer), fp)) {
499 if (!(cp = strchr(buffer, '\n')))
502 if (*buffer == '#' || *buffer == '\0')
504 if (!(bp = strchr(buffer, ':')))
507 while (isspace (*bp))
510 for (b = binds; b->keyword; b++)
511 if (!strcmp (buffer, b->keyword))
513 if (b->keyword && (cp = tailor_value (bp)))