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>
26 static char *tailor_value (unsigned char *);
27 static void getuserinfo (void);
28 static const char *get_mtsconf_pathname(void);
29 static const char *get_mtsuserconf_pathname(void);
30 static void mts_read_conf_file (FILE *fp);
33 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
34 * are kept in the user's home directory, then these should be empty
35 * strings. In this case, the appropriate ...lfil array should contain
36 * the name of the file in the user's home directory. Usually, this is
37 * something like ".mail".
41 * nmh mail transport interface customization file
43 static char *mtsconf = nmhetcdir(/mts.conf);
45 static char *localname = "";
46 static char *localdomain = "";
47 static char *systemname = "";
49 char *mmdfldir = MAILSPOOL;
51 char *uucpldir = "/usr/spool/mail";
54 char *mmdlm1 = "\001\001\001\001\n";
55 char *mmdlm2 = "\001\001\001\001\n";
57 /* Cache the username and fullname of the user */
58 static char username[BUFSIZ];
59 static char fullname[BUFSIZ];
61 /* Variables for username masquerading: */
62 boolean draft_from_masquerading = FALSE; /* also used from post.c */
63 static boolean mmailid_masquerading = FALSE;
64 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
65 static char* masquerade = "";
68 * MTS specific variables
71 static char *sm_method = "smtp";
72 int sm_mts = MTS_SMTP;
73 char *hostable = nmhetcdir(/hosts);
74 char *sendmail = SENDMAILPATH;
80 char *clientname = NULL;
81 char *servers = "localhost";
85 * Global MailDelivery file
87 char *maildelivery = nmhetcdir(/maildelivery);
91 * Aliasing Facility (doesn't belong here)
94 static char *everyone = "-1";
98 * Customize the MTS settings for nmh by adjusting
99 * the file mts.conf in the nmh etc directory.
107 static struct bind binds[] = {
108 { "localname", &localname },
109 { "localdomain", &localdomain },
110 { "systemname", &systemname },
111 { "mmdfldir", &mmdfldir },
112 { "mmdflfil", &mmdflfil },
113 { "uucpldir", &uucpldir },
114 { "uucplfil", &uucplfil },
115 { "mmdelim1", &mmdlm1 },
116 { "mmdelim2", &mmdlm2 },
117 { "masquerade", &masquerade },
120 { "mts", &sm_method },
121 { "hostable", &hostable },
122 { "sendmail", &sendmail },
125 { "clientname", &clientname },
126 { "servers", &servers },
127 { "pophost", &pophost },
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)
148 static int inited = 0;
150 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
152 mts_read_conf_file(fp);
155 cp = get_mtsuserconf_pathname();
157 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
158 mts_read_conf_file(fp);
162 Everyone = atoi (everyone);
164 if (strstr(masquerade, "draft_from") != NULL)
165 draft_from_masquerading = TRUE;
167 if (strstr(masquerade, "mmailid") != NULL)
168 mmailid_masquerading = TRUE;
170 if (strstr(masquerade, "username_extension") != NULL)
171 username_extension_masquerading = TRUE;
174 if (strcmp(sm_method, "smtp") == 0)
176 else if (strcmp(sm_method, "sendmail") == 0)
177 sm_mts = MTS_SENDMAIL;
179 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
189 * Convert escaped values, malloc some new space,
190 * and copy string to malloc'ed memory.
194 tailor_value (unsigned char *s)
201 for (bp = buffer; *s; bp++, s++) {
206 case 'b': *bp = '\b'; break;
207 case 'f': *bp = '\f'; break;
208 case 'n': *bp = '\n'; break;
209 case 't': *bp = '\t'; break;
221 r = *s != '0' ? 10 : 8;
222 for (i = 0; isdigit (*s); s++)
223 i = i * r + *s - '0';
232 len = strlen (buffer) + 1;
233 bp = mh_xmalloc (len);
234 memcpy (bp, buffer, len);
240 * Get the fully qualified name of the local host.
242 * If flag is 0, then use anything out of mts.conf (like localname).
243 * If flag is 1, then only use the "proper" local hostname.
249 static char buffer0[BUFSIZ] = "";
250 static char buffer1[BUFSIZ] = "";
251 static char *buffer[] = { buffer0, buffer1 };
253 struct addrinfo hints, *res;
255 if (flag < 0 || flag > 1)
260 /* check if we have cached the local name */
266 /* check if the mts.conf file specifies a "localname" */
267 if (*localname && flag == 0) {
268 strncpy (buf, localname, sizeof(buffer0));
270 memset(buf, 0, sizeof(buffer0));
271 /* first get our local name */
272 gethostname (buf, sizeof(buffer0) - 1);
273 /* now fully qualify our name */
275 memset(&hints, 0, sizeof(hints));
276 hints.ai_flags = AI_CANONNAME;
277 hints.ai_family = PF_UNSPEC;
278 if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
279 strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
285 * If the mts.conf file specifies a "localdomain",
286 * we append that now. This should rarely be needed.
290 strcat (buf, localdomain);
298 * This is only for UUCP mail. It gets the hostname
299 * as part of the UUCP "domain".
305 static char buffer[BUFSIZ] = "";
307 /* check if we have cached the system name */
313 /* check if mts.conf file specifies a "systemname" */
315 strncpy (buffer, systemname, sizeof(buffer));
319 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). */
383 if (mmailid_masquerading)
384 /* Stop at ',' or '<'. */
385 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
389 /* Allow '<' as a legal character of the user's name. This code is
390 basically a duplicate of the code above the "else" -- we don't
391 collapse it down to one copy and put the mmailid_masquerading check
392 inside the loop with "(x ? y : z)" because that's inefficient and the
393 value'll never change while it's in there. */
394 for (cp = fullname; *np != '\0' && *np != ',';
399 if (mmailid_masquerading) {
400 /* Do mmailid processing. The GECOS field should have the form
401 "Full Name <fakeusername>". For instance,
402 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
403 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
407 for (cp = username; *np && *np != '>'; *cp++ = *np++)
411 if (!mmailid_masquerading || *np == '\0')
412 strncpy (username, pw->pw_name, sizeof(username));
414 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
416 if ((cp = getenv ("SIGNATURE")) && *cp)
417 strncpy (fullname, cp, sizeof(fullname));
419 if (strchr(fullname, '.')) { /* quote any .'s */
422 /* should quote "'s too */
423 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
424 strncpy (fullname, tmp, sizeof(fullname));
431 get_mtsconf_pathname (void)
433 const char *cp = getenv ( "MHMTSCONF" );
434 if (cp != NULL && *cp != '\0') {
441 get_mtsuserconf_pathname (void)
443 const char *cp = getenv ( "MHMTSUSERCONF" );
444 if (cp != NULL && *cp != '\0') {
451 mts_read_conf_file (FILE *fp)
454 char *cp, buffer[BUFSIZ];
457 while (fgets (buffer, sizeof(buffer), fp)) {
458 if (!(cp = strchr(buffer, '\n')))
461 if (*buffer == '#' || *buffer == '\0')
463 if (!(bp = strchr(buffer, ':')))
466 while (isspace (*bp))
469 for (b = binds; b->keyword; b++)
470 if (!strcmp (buffer, b->keyword))
472 if (b->keyword && (cp = tailor_value (bp)))