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>
23 #ifdef HAVE_SYS_UTSNAME_H
24 # include <sys/utsname.h>
33 static char *tailor_value (unsigned char *);
34 static void getuserinfo (void);
35 static const char *get_mtsconf_pathname(void);
36 static const char *get_mtsuserconf_pathname(void);
37 static void mts_read_conf_file (FILE *fp);
40 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
41 * are kept in the user's home directory, then these should be empty
42 * strings. In this case, the appropriate ...lfil array should contain
43 * the name of the file in the user's home directory. Usually, this is
44 * something like ".mail".
48 * nmh mail transport interface customization file
50 static char *mtsconf = nmhetcdir(/mts.conf);
52 static char *localname = "";
53 static char *localdomain = "";
54 static char *systemname = "";
56 char *mmdfldir = MAILSPOOL;
58 char *uucpldir = "/usr/spool/mail";
61 char *mmdlm1 = "\001\001\001\001\n";
62 char *mmdlm2 = "\001\001\001\001\n";
64 /* Cache the username and fullname of the user */
65 static char username[BUFSIZ];
66 static char fullname[BUFSIZ];
68 /* Variables for username masquerading: */
69 boolean draft_from_masquerading = FALSE; /* also used from post.c */
70 static boolean mmailid_masquerading = FALSE;
71 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
72 static char* masquerade = "";
75 * MTS specific variables
78 static char *sm_method = "smtp";
79 int sm_mts = MTS_SMTP;
80 char *hostable = nmhetcdir(/hosts);
81 char *sendmail = SENDMAILPATH;
87 char *clientname = NULL;
88 char *servers = "localhost \01localnet";
92 * Global MailDelivery file
94 char *maildelivery = nmhetcdir(/maildelivery);
98 * Aliasing Facility (doesn't belong here)
100 int Everyone = NOTOK;
101 static char *everyone = "-1";
105 * Customize the MTS settings for nmh by adjusting
106 * the file mts.conf in the nmh etc directory.
114 static struct bind binds[] = {
115 { "localname", &localname },
116 { "localdomain", &localdomain },
117 { "systemname", &systemname },
118 { "mmdfldir", &mmdfldir },
119 { "mmdflfil", &mmdflfil },
120 { "uucpldir", &uucpldir },
121 { "uucplfil", &uucplfil },
122 { "mmdelim1", &mmdlm1 },
123 { "mmdelim2", &mmdlm2 },
124 { "masquerade", &masquerade },
127 { "mts", &sm_method },
128 { "hostable", &hostable },
129 { "sendmail", &sendmail },
132 { "clientname", &clientname },
133 { "servers", &servers },
134 { "pophost", &pophost },
136 { "maildelivery", &maildelivery },
137 { "everyone", &everyone },
138 { "noshell", &NoShell },
144 * Read the configuration file for the nmh interface
145 * to the mail transport system (MTS).
149 mts_init (char *name)
153 static int inited = 0;
155 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
157 mts_read_conf_file(fp);
160 cp = get_mtsuserconf_pathname();
162 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
163 mts_read_conf_file(fp);
167 Everyone = atoi (everyone);
169 if (strstr(masquerade, "draft_from") != NULL)
170 draft_from_masquerading = TRUE;
172 if (strstr(masquerade, "mmailid") != NULL)
173 mmailid_masquerading = TRUE;
175 if (strstr(masquerade, "username_extension") != NULL)
176 username_extension_masquerading = TRUE;
179 if (strcmp(sm_method, "smtp") == 0)
181 else if (strcmp(sm_method, "sendmail") == 0)
182 sm_mts = MTS_SENDMAIL;
184 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
194 * Convert escaped values, malloc some new space,
195 * and copy string to malloc'ed memory.
199 tailor_value (unsigned char *s)
206 for (bp = buffer; *s; bp++, s++) {
211 case 'b': *bp = '\b'; break;
212 case 'f': *bp = '\f'; break;
213 case 'n': *bp = '\n'; break;
214 case 't': *bp = '\t'; break;
226 r = *s != '0' ? 10 : 8;
227 for (i = 0; isdigit (*s); s++)
228 i = i * r + *s - '0';
237 len = strlen (buffer) + 1;
238 bp = mh_xmalloc (len);
239 memcpy (bp, buffer, len);
245 * Get the fully qualified name of the local host.
251 static char buffer[BUFSIZ] = "";
252 struct addrinfo hints, *res;
257 /* check if we have cached the local name */
263 /* check if the mts.conf file specifies a "localname" */
265 strncpy (buffer, localname, sizeof(buffer));
267 memset(buffer, 0, sizeof(buffer));
269 /* first get our local name */
271 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
273 /* first get our local name */
274 gethostname (buffer, sizeof(buffer) - 1);
276 /* now fully qualify our name */
278 memset(&hints, 0, sizeof(hints));
279 hints.ai_flags = AI_CANONNAME;
280 hints.ai_family = PF_UNSPEC;
281 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
282 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
288 * If the mts.conf file specifies a "localdomain",
289 * we append that now. This should rarely be needed.
292 strcat (buffer, ".");
293 strcat (buffer, localdomain);
301 * This is only for UUCP mail. It gets the hostname
302 * as part of the UUCP "domain".
308 static char buffer[BUFSIZ] = "";
314 /* check if we have cached the system name */
320 /* check if mts.conf file specifies a "systemname" */
322 strncpy (buffer, systemname, sizeof(buffer));
328 strncpy (buffer, name.nodename, sizeof(buffer));
330 gethostname (buffer, sizeof(buffer));
338 * Get the username of current user
344 if (username[0] == '\0')
352 * Get full name of current user (typically from GECOS
353 * field of password file).
359 if (username[0] == '\0')
367 * Find the user's username and full name, and cache them.
368 * Also, handle "mmailid" username masquerading controlled from the GECOS field
369 * of the passwd file.
375 register unsigned char *cp;
377 register struct passwd *pw;
379 if ((pw = getpwuid (getuid ())) == NULL
380 || pw->pw_name == NULL
381 || *pw->pw_name == '\0') {
382 strncpy (username, "unknown", sizeof(username));
383 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
390 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
391 which some OSes use to separate other 'finger' information in the GECOS
392 field, like phone number. Also, if mmailid masquerading is turned on due
393 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
394 hit a '<' (which should precede any ','s). */
396 if (mmailid_masquerading)
397 /* Stop at ',' or '<'. */
398 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
402 /* Allow '<' as a legal character of the user's name. This code is
403 basically a duplicate of the code above the "else" -- we don't
404 collapse it down to one copy and put the mmailid_masquerading check
405 inside the loop with "(x ? y : z)" because that's inefficient and the
406 value'll never change while it's in there. */
407 for (cp = fullname; *np != '\0' && *np != ',';
411 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
412 field (finger, mail, sendmail, etc.) translate any '&' character in it to
413 the login name, with the first letter capitalized. So, for instance,
414 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
415 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
416 the translation for you, so we have to do it manually here. */
417 if (mmailid_masquerading)
418 /* Stop at ',' or '<'. */
420 *np != '\0' && *np != ',' && *np != '<';) {
421 if (*np == '&') { /* blech! */
422 strcpy (cp, pw->pw_name);
432 /* Allow '<' as a legal character of the user's name. This code is
433 basically a duplicate of the code above the "else" -- we don't
434 collapse it down to one copy and put the mmailid_masquerading check
435 inside the loop with "(x ? y : z)" because that's inefficient and the
436 value'll never change while it's in there. */
438 *np != '\0' && *np != ',';) {
439 if (*np == '&') { /* blech! */
440 strcpy (cp, pw->pw_name);
452 if (mmailid_masquerading) {
453 /* Do mmailid processing. The GECOS field should have the form
454 "Full Name <fakeusername>". For instance,
455 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
456 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
460 for (cp = username; *np && *np != '>'; *cp++ = *np++)
464 if (!mmailid_masquerading || *np == '\0')
465 strncpy (username, pw->pw_name, sizeof(username));
467 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
469 if ((cp = getenv ("SIGNATURE")) && *cp)
470 strncpy (fullname, cp, sizeof(fullname));
472 if (strchr(fullname, '.')) { /* quote any .'s */
475 /* should quote "'s too */
476 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
477 strncpy (fullname, tmp, sizeof(fullname));
484 get_mtsconf_pathname (void)
486 const char *cp = getenv ( "MHMTSCONF ");
487 if (cp != NULL && *cp != '\0') {
494 get_mtsuserconf_pathname (void)
496 const char *cp = getenv ( "MHMTSUSERCONF" );
497 if (cp != NULL && *cp != '\0') {
504 mts_read_conf_file (FILE *fp)
507 char *cp, buffer[BUFSIZ];
510 while (fgets (buffer, sizeof(buffer), fp)) {
511 if (!(cp = strchr(buffer, '\n')))
514 if (*buffer == '#' || *buffer == '\0')
516 if (!(bp = strchr(buffer, ':')))
519 while (isspace (*bp))
522 for (b = binds; b->keyword; b++)
523 if (!strcmp (buffer, b->keyword))
525 if (b->keyword && (cp = tailor_value (bp)))