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 = "smtp";
78 int sm_mts = MTS_SMTP;
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;
178 if (strcmp(sm_method, "smtp") == 0)
180 else if (strcmp(sm_method, "sendmail") == 0)
181 sm_mts = MTS_SENDMAIL;
183 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
193 * Convert escaped values, malloc some new space,
194 * and copy string to malloc'ed memory.
198 tailor_value (unsigned char *s)
205 for (bp = buffer; *s; bp++, s++) {
210 case 'b': *bp = '\b'; break;
211 case 'f': *bp = '\f'; break;
212 case 'n': *bp = '\n'; break;
213 case 't': *bp = '\t'; break;
225 r = *s != '0' ? 10 : 8;
226 for (i = 0; isdigit (*s); s++)
227 i = i * r + *s - '0';
236 len = strlen (buffer) + 1;
237 bp = mh_xmalloc (len);
238 memcpy (bp, buffer, len);
244 * Get the fully qualified name of the local host.
250 static char buffer[BUFSIZ] = "";
251 struct addrinfo hints, *res;
256 /* check if we have cached the local name */
262 /* check if the mts.conf file specifies a "localname" */
264 strncpy (buffer, localname, sizeof(buffer));
266 memset(buffer, 0, sizeof(buffer));
268 /* first get our local name */
270 strncpy (buffer, name.nodename, sizeof(buffer) - 1);
272 /* first get our local name */
273 gethostname (buffer, sizeof(buffer) - 1);
275 /* now fully qualify our name */
277 memset(&hints, 0, sizeof(hints));
278 hints.ai_flags = AI_CANONNAME;
279 hints.ai_family = PF_UNSPEC;
280 if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
281 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
287 * If the mts.conf file specifies a "localdomain",
288 * we append that now. This should rarely be needed.
291 strcat (buffer, ".");
292 strcat (buffer, localdomain);
300 * This is only for UUCP mail. It gets the hostname
301 * as part of the UUCP "domain".
307 static char buffer[BUFSIZ] = "";
313 /* check if we have cached the system name */
319 /* check if mts.conf file specifies a "systemname" */
321 strncpy (buffer, systemname, sizeof(buffer));
327 strncpy (buffer, name.nodename, sizeof(buffer));
329 gethostname (buffer, sizeof(buffer));
337 * Get the username of current user
343 if (username[0] == '\0')
351 * Get full name of current user (typically from GECOS
352 * field of password file).
358 if (username[0] == '\0')
366 * Find the user's username and full name, and cache them.
367 * Also, handle "mmailid" username masquerading controlled from the GECOS field
368 * of the passwd file.
374 register unsigned char *cp;
376 register struct passwd *pw;
378 if ((pw = getpwuid (getuid ())) == NULL
379 || pw->pw_name == NULL
380 || *pw->pw_name == '\0') {
381 strncpy (username, "unknown", sizeof(username));
382 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
389 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
390 which some OSes use to separate other 'finger' information in the GECOS
391 field, like phone number. Also, if mmailid masquerading is turned on due
392 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
393 hit a '<' (which should precede any ','s). */
395 if (mmailid_masquerading)
396 /* Stop at ',' or '<'. */
397 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
401 /* Allow '<' as a legal character of the user's name. This code is
402 basically a duplicate of the code above the "else" -- we don't
403 collapse it down to one copy and put the mmailid_masquerading check
404 inside the loop with "(x ? y : z)" because that's inefficient and the
405 value'll never change while it's in there. */
406 for (cp = fullname; *np != '\0' && *np != ',';
410 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
411 field (finger, mail, sendmail, etc.) translate any '&' character in it to
412 the login name, with the first letter capitalized. So, for instance,
413 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
414 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
415 the translation for you, so we have to do it manually here. */
416 if (mmailid_masquerading)
417 /* Stop at ',' or '<'. */
419 *np != '\0' && *np != ',' && *np != '<';) {
420 if (*np == '&') { /* blech! */
421 strcpy (cp, pw->pw_name);
431 /* Allow '<' as a legal character of the user's name. This code is
432 basically a duplicate of the code above the "else" -- we don't
433 collapse it down to one copy and put the mmailid_masquerading check
434 inside the loop with "(x ? y : z)" because that's inefficient and the
435 value'll never change while it's in there. */
437 *np != '\0' && *np != ',';) {
438 if (*np == '&') { /* blech! */
439 strcpy (cp, pw->pw_name);
451 if (mmailid_masquerading) {
452 /* Do mmailid processing. The GECOS field should have the form
453 "Full Name <fakeusername>". For instance,
454 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
455 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
459 for (cp = username; *np && *np != '>'; *cp++ = *np++)
463 if (!mmailid_masquerading || *np == '\0')
464 strncpy (username, pw->pw_name, sizeof(username));
466 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
468 if ((cp = getenv ("SIGNATURE")) && *cp)
469 strncpy (fullname, cp, sizeof(fullname));
471 if (strchr(fullname, '.')) { /* quote any .'s */
474 /* should quote "'s too */
475 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
476 strncpy (fullname, tmp, sizeof(fullname));
483 get_mtsconf_pathname (void)
485 const char *cp = getenv ( "MHMTSCONF ");
486 if (cp != NULL && *cp != '\0') {
493 get_mtsuserconf_pathname (void)
495 const char *cp = getenv ( "MHMTSUSERCONF" );
496 if (cp != NULL && *cp != '\0') {
503 mts_read_conf_file (FILE *fp)
506 char *cp, buffer[BUFSIZ];
509 while (fgets (buffer, sizeof(buffer), fp)) {
510 if (!(cp = strchr(buffer, '\n')))
513 if (*buffer == '#' || *buffer == '\0')
515 if (!(bp = strchr(buffer, ':')))
518 while (isspace (*bp))
521 for (b = binds; b->keyword; b++)
522 if (!strcmp (buffer, b->keyword))
524 if (b->keyword && (cp = tailor_value (bp)))