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 *mts_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", &mts_method },
110 { "sendmail", &sendmail },
111 { "clientname", &clientname },
112 { "servers", &servers },
113 { "pophost", &pophost },
115 { "maildelivery", &maildelivery },
116 { "everyone", &everyone },
117 { "noshell", &NoShell },
122 /* Convert name of mts method to integer value and store it. */
124 save_mts_method (const char *value) {
125 if (! mh_strcasecmp (value, "smtp")) {
128 } else if (! mh_strcasecmp (value, "sendmail/smtp") ||
129 ! mh_strcasecmp (value, "sendmail")) {
130 mts_method = "sendmail/smtp";
131 sm_mts = MTS_SENDMAIL_SMTP;
132 } else if (! mh_strcasecmp (value, "sendmail/pipe")) {
133 mts_method = "sendmail/pipe";
134 sm_mts = MTS_SENDMAIL_PIPE;
136 adios (NULL, "unsupported mts selection \"%s\"", value);
142 * Read the configuration file for the nmh interface
143 * to the mail transport system (MTS).
147 mts_init (char *name)
151 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 save_mts_method (mts_method);
175 * Convert escaped values, malloc some new space,
176 * and copy string to malloc'ed memory.
180 tailor_value (unsigned char *s)
187 for (bp = buffer; *s; bp++, s++) {
192 case 'b': *bp = '\b'; break;
193 case 'f': *bp = '\f'; break;
194 case 'n': *bp = '\n'; break;
195 case 't': *bp = '\t'; break;
207 r = *s != '0' ? 10 : 8;
208 for (i = 0; isdigit (*s); s++)
209 i = i * r + *s - '0';
218 len = strlen (buffer) + 1;
219 bp = mh_xmalloc (len);
220 memcpy (bp, buffer, len);
226 * Get the fully qualified name of the local host.
228 * If flag is 0, then use anything out of mts.conf (like localname).
229 * If flag is 1, then only use the "proper" local hostname.
235 static char buffer0[BUFSIZ] = "";
236 static char buffer1[BUFSIZ] = "";
237 static char *buffer[] = { buffer0, buffer1 };
239 struct addrinfo hints, *res;
241 if (flag < 0 || flag > 1)
246 /* check if we have cached the local name */
252 /* check if the mts.conf file specifies a "localname" */
253 if (*localname && flag == 0) {
254 strncpy (buf, localname, sizeof(buffer0));
256 memset(buf, 0, sizeof(buffer0));
257 /* first get our local name */
258 gethostname (buf, sizeof(buffer0) - 1);
259 /* now fully qualify our name */
261 memset(&hints, 0, sizeof(hints));
262 hints.ai_flags = AI_CANONNAME;
263 hints.ai_family = PF_UNSPEC;
264 if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
265 strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
271 * If the mts.conf file specifies a "localdomain",
272 * we append that now. This should rarely be needed.
276 strcat (buf, localdomain);
284 * This is only for UUCP mail. It gets the hostname
285 * as part of the UUCP "domain".
291 static char buffer[BUFSIZ] = "";
293 /* check if we have cached the system name */
299 /* check if mts.conf file specifies a "systemname" */
301 strncpy (buffer, systemname, sizeof(buffer));
305 gethostname (buffer, sizeof(buffer));
312 * Get the username of current user
318 if (username[0] == '\0')
326 * Get full name of current user (typically from GECOS
327 * field of password file).
333 if (username[0] == '\0')
341 * Get the full local mailbox name. This is in the form:
343 * User Name <user@name.com>
349 if (username[0] == '\0')
356 * Find the user's username and full name, and cache them.
362 register unsigned char *cp;
364 register struct passwd *pw;
366 if ((pw = getpwuid (getuid ())) == NULL
367 || pw->pw_name == NULL
368 || *pw->pw_name == '\0') {
369 strncpy (username, "unknown", sizeof(username));
370 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
377 /* If there's a Local-Mailbox profile component, try to extract
378 the username from it. But don't try very hard, this assumes
379 the very simple User Name <user@name.com> form.
380 Note that post(8) and whom(1) use context_foil (), so they
381 won't see the profile component. */
382 if ((np = context_find("Local-Mailbox")) != NULL) {
383 char *left_angle_bracket = strchr (np, '<');
384 char *at_sign = strchr (np, '@');
385 char *right_angle_bracket = strchr (np, '>');
387 strncpy(localmbox, np, sizeof(localmbox));
389 if (left_angle_bracket && at_sign && right_angle_bracket) {
390 if (at_sign > left_angle_bracket &&
391 at_sign - left_angle_bracket < BUFSIZ) {
392 strncpy(username, left_angle_bracket + 1,
393 at_sign - left_angle_bracket - 1);
398 if (username[0] == '\0') {
399 strncpy (username, pw->pw_name, sizeof(username));
402 username[sizeof(username) - 1] = '\0';
404 escape_local_part(username, sizeof(username));
410 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
411 which some OSes use to separate other 'finger' information in the GECOS
412 field, like phone number. */
413 for (cp = fullname; *np != '\0' && *np != ','; *cp++ = *np++)
417 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
418 your real name. If SIGNATURE isn't set, use the Signature profile
419 setting if it exists.
420 Note that post(8) and whom(1) use context_foil (), so they
421 won't see the profile component. */
422 if ((cp = getenv ("SIGNATURE")) && *cp)
423 strncpy (fullname, cp, sizeof(fullname));
424 else if ((cp = context_find("Signature")))
425 strncpy (fullname, cp, sizeof(fullname));
427 fullname[sizeof(fullname) - 1] = '\0';
429 escape_display_name(fullname, sizeof(fullname));
432 /* localmbox, if not using Local-Mailbox */
433 if (localmbox[0] == '\0') {
434 snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname,
435 username, LocalName(0));
438 localmbox[sizeof(localmbox) - 1] = '\0';
442 get_mtsconf_pathname (void)
444 const char *cp = getenv ( "MHMTSCONF" );
445 if (cp != NULL && *cp != '\0') {
452 get_mtsuserconf_pathname (void)
454 const char *cp = getenv ( "MHMTSUSERCONF" );
455 if (cp != NULL && *cp != '\0') {
462 mts_read_conf_file (FILE *fp)
465 char *cp, buffer[BUFSIZ];
468 while (fgets (buffer, sizeof(buffer), fp)) {
469 if (!(cp = strchr(buffer, '\n')))
472 if (*buffer == '#' || *buffer == '\0')
474 if (!(bp = strchr(buffer, ':')))
477 while (isspace (*bp))
480 for (b = binds; b->keyword; b++)
481 if (!strcmp (buffer, b->keyword))
483 if (b->keyword && (cp = tailor_value (bp)))