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, fullname, and mailbox of the user */
58 static char username[BUFSIZ];
59 static char fullname[BUFSIZ];
60 static char localmbox[BUFSIZ];
63 * MTS specific variables
65 static char *sm_method = "smtp";
66 int sm_mts = MTS_SENDMAIL_SMTP;
67 char *sendmail = SENDMAILPATH;
72 char *clientname = NULL;
73 char *servers = "localhost";
77 * Global MailDelivery file
79 char *maildelivery = nmhetcdir(/maildelivery);
83 * Aliasing Facility (doesn't belong here)
86 static char *everyone = "-1";
90 * Customize the MTS settings for nmh by adjusting
91 * the file mts.conf in the nmh etc directory.
99 static struct bind binds[] = {
100 { "localname", &localname },
101 { "localdomain", &localdomain },
102 { "systemname", &systemname },
103 { "mmdfldir", &mmdfldir },
104 { "mmdflfil", &mmdflfil },
105 { "uucpldir", &uucpldir },
106 { "uucplfil", &uucplfil },
107 { "mmdelim1", &mmdlm1 },
108 { "mmdelim2", &mmdlm2 },
109 { "mts", &sm_method },
110 { "sendmail", &sendmail },
111 { "clientname", &clientname },
112 { "servers", &servers },
113 { "pophost", &pophost },
115 { "maildelivery", &maildelivery },
116 { "everyone", &everyone },
117 { "noshell", &NoShell },
123 * Read the configuration file for the nmh interface
124 * to the mail transport system (MTS).
128 mts_init (char *name)
132 static int inited = 0;
135 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
137 mts_read_conf_file(fp);
140 cp = get_mtsuserconf_pathname();
142 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
143 mts_read_conf_file(fp);
147 Everyone = atoi (everyone);
149 if (strcmp(sm_method, "smtp") == 0)
151 else if (strcmp(sm_method, "sendmail/smtp") == 0)
152 sm_mts = MTS_SENDMAIL_SMTP;
153 else if (strcmp(sm_method, "sendmail/pipe") == 0)
154 sm_mts = MTS_SENDMAIL_PIPE;
156 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
157 sm_mts = MTS_SENDMAIL_SMTP;
165 * Convert escaped values, malloc some new space,
166 * and copy string to malloc'ed memory.
170 tailor_value (unsigned char *s)
177 for (bp = buffer; *s; bp++, s++) {
182 case 'b': *bp = '\b'; break;
183 case 'f': *bp = '\f'; break;
184 case 'n': *bp = '\n'; break;
185 case 't': *bp = '\t'; break;
197 r = *s != '0' ? 10 : 8;
198 for (i = 0; isdigit (*s); s++)
199 i = i * r + *s - '0';
208 len = strlen (buffer) + 1;
209 bp = mh_xmalloc (len);
210 memcpy (bp, buffer, len);
216 * Get the fully qualified name of the local host.
218 * If flag is 0, then use anything out of mts.conf (like localname).
219 * If flag is 1, then only use the "proper" local hostname.
225 static char buffer0[BUFSIZ] = "";
226 static char buffer1[BUFSIZ] = "";
227 static char *buffer[] = { buffer0, buffer1 };
229 struct addrinfo hints, *res;
231 if (flag < 0 || flag > 1)
236 /* check if we have cached the local name */
242 /* check if the mts.conf file specifies a "localname" */
243 if (*localname && flag == 0) {
244 strncpy (buf, localname, sizeof(buffer0));
246 memset(buf, 0, sizeof(buffer0));
247 /* first get our local name */
248 gethostname (buf, sizeof(buffer0) - 1);
249 /* now fully qualify our name */
251 memset(&hints, 0, sizeof(hints));
252 hints.ai_flags = AI_CANONNAME;
253 hints.ai_family = PF_UNSPEC;
254 if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
255 strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
261 * If the mts.conf file specifies a "localdomain",
262 * we append that now. This should rarely be needed.
266 strcat (buf, localdomain);
274 * This is only for UUCP mail. It gets the hostname
275 * as part of the UUCP "domain".
281 static char buffer[BUFSIZ] = "";
283 /* check if we have cached the system name */
289 /* check if mts.conf file specifies a "systemname" */
291 strncpy (buffer, systemname, sizeof(buffer));
295 gethostname (buffer, sizeof(buffer));
302 * Get the username of current user
308 if (username[0] == '\0')
316 * Get full name of current user (typically from GECOS
317 * field of password file).
323 if (username[0] == '\0')
331 * Get the full local mailbox name. This is in the form:
333 * User Name <user@name.com>
339 if (username[0] == '\0')
346 * Find the user's username and full name, and cache them.
352 register unsigned char *cp;
354 register struct passwd *pw;
356 if ((pw = getpwuid (getuid ())) == NULL
357 || pw->pw_name == NULL
358 || *pw->pw_name == '\0') {
359 strncpy (username, "unknown", sizeof(username));
360 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
367 /* If there's a Local-Mailbox profile component, try to extract
368 the username from it. But don't try very hard, this assumes
369 the very simple User Name <user@name.com> form.
370 Note that post(8) and whom(1) use context_foil (), so they
371 won't see the profile component. */
372 if ((np = context_find("Local-Mailbox")) != NULL) {
373 char *left_angle_bracket = strchr (np, '<');
374 char *at_sign = strchr (np, '@');
375 char *right_angle_bracket = strchr (np, '>');
377 strncpy(localmbox, np, sizeof(localmbox));
379 if (left_angle_bracket && at_sign && right_angle_bracket) {
380 if (at_sign > left_angle_bracket &&
381 at_sign - left_angle_bracket < BUFSIZ) {
382 strncpy(username, left_angle_bracket + 1,
383 at_sign - left_angle_bracket - 1);
388 if (username[0] == '\0') {
389 strncpy (username, pw->pw_name, sizeof(username));
392 username[sizeof(username) - 1] = '\0';
394 escape_local_part(username, sizeof(username));
400 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
401 which some OSes use to separate other 'finger' information in the GECOS
402 field, like phone number. */
403 for (cp = fullname; *np != '\0' && *np != ','; *cp++ = *np++)
407 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
408 your real name. If SIGNATURE isn't set, use the Signature profile
409 setting if it exists.
410 Note that post(8) and whom(1) use context_foil (), so they
411 won't see the profile component. */
412 if ((cp = getenv ("SIGNATURE")) && *cp)
413 strncpy (fullname, cp, sizeof(fullname));
414 else if ((cp = context_find("Signature")))
415 strncpy (fullname, cp, sizeof(fullname));
417 fullname[sizeof(fullname) - 1] = '\0';
419 escape_display_name(fullname, sizeof(fullname));
422 /* localmbox, if not using Local-Mailbox */
423 if (localmbox[0] == '\0') {
424 snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname,
425 username, LocalName(0));
428 localmbox[sizeof(localmbox) - 1] = '\0';
432 get_mtsconf_pathname (void)
434 const char *cp = getenv ( "MHMTSCONF" );
435 if (cp != NULL && *cp != '\0') {
442 get_mtsuserconf_pathname (void)
444 const char *cp = getenv ( "MHMTSUSERCONF" );
445 if (cp != NULL && *cp != '\0') {
452 mts_read_conf_file (FILE *fp)
455 char *cp, buffer[BUFSIZ];
458 while (fgets (buffer, sizeof(buffer), fp)) {
459 if (!(cp = strchr(buffer, '\n')))
462 if (*buffer == '#' || *buffer == '\0')
464 if (!(bp = strchr(buffer, ':')))
467 while (isspace (*bp))
470 for (b = binds; b->keyword; b++)
471 if (!strcmp (buffer, b->keyword))
473 if (b->keyword && (cp = tailor_value (bp)))