1 /* mts.c -- definitions for the mail transport system
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include <h/mh.h> /* for snprintf() */
9 #include <h/utils.h>
10
11 #define nmhetcdir(file) NMHETCDIR#file
12
13 #include <h/mts.h>
14 #include <pwd.h>
15 #include <sys/socket.h>
16 #include <netdb.h>
17
18 /*
19 * static prototypes
20 */
21 static char *tailor_value (char *);
22 static void getuserinfo (void);
23 static const char *get_mtsconf_pathname(void);
24 static const char *get_mtsuserconf_pathname(void);
25 static void mts_read_conf_file (FILE *fp);
26
27 /*
28 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
29 * are kept in the user's home directory, then these should be empty
30 * strings. In this case, the appropriate ...lfil array should contain
31 * the name of the file in the user's home directory. Usually, this is
32 * something like ".mail".
33 */
34
35 /*
36 * nmh mail transport interface customization file
37 */
38 static char *mtsconf = nmhetcdir(/mts.conf);
39
40 static char *localname = "";
41 static char *localdomain = "";
42 static char *systemname = "";
43
44 char *mmdfldir = MAILSPOOL;
45 char *mmdflfil = "";
46 char *uucpldir = "/usr/spool/mail";
47 char *uucplfil = "";
48
49 char *spoollocking = DEFAULT_LOCKING;
50
51 /* Cache the username, fullname, and mailbox of the user */
52 static char username[BUFSIZ];
53 static char fullname[BUFSIZ];
54 static char localmbox[BUFSIZ];
55
56 /*
57 * MTS specific variables
58 */
59 static char *mts_method = "smtp";
60 int sm_mts = MTS_SMTP;
61 char *sendmail = SENDMAILPATH;
62
63 /*
64 * SMTP/POP stuff
65 */
66 char *clientname = NULL;
67 char *servers = "localhost";
68 char *pophost = "";
69
70 /*
71 * Global MailDelivery file
72 */
73 char *maildelivery = nmhetcdir(/maildelivery);
74
75
76 /*
77 * Customize the MTS settings for nmh by adjusting
78 * the file mts.conf in the nmh etc directory.
79 */
80
81 struct bind {
82 char *keyword;
83 char **value;
84 };
85
86 static struct bind binds[] = {
87 { "localname", &localname },
88 { "localdomain", &localdomain },
89 { "systemname", &systemname },
90 { "mmdfldir", &mmdfldir },
91 { "mmdflfil", &mmdflfil },
92 { "spoollocking", &spoollocking },
93 { "uucpldir", &uucpldir },
94 { "uucplfil", &uucplfil },
95 { "mts", &mts_method },
96 { "sendmail", &sendmail },
97 { "clientname", &clientname },
98 { "servers", &servers },
99 { "pophost", &pophost },
100
101 { "maildelivery", &maildelivery },
102 { NULL, NULL }
103 };
104
105
106 /* Convert name of mts method to integer value and store it. */
107 void
save_mts_method(const char * value)108 save_mts_method (const char *value) {
109 if (! strcasecmp (value, "smtp")) {
110 mts_method = "smtp";
111 sm_mts = MTS_SMTP;
112 } else if (! strcasecmp (value, "sendmail/smtp") ||
113 ! strcasecmp (value, "sendmail")) {
114 mts_method = "sendmail/smtp";
115 sm_mts = MTS_SENDMAIL_SMTP;
116 } else if (! strcasecmp (value, "sendmail/pipe")) {
117 mts_method = "sendmail/pipe";
118 sm_mts = MTS_SENDMAIL_PIPE;
119 } else {
120 adios (NULL, "unsupported mts selection \"%s\"", value);
121 }
122 }
123
124
125 /*
126 * Read the configuration file for the nmh interface
127 * to the mail transport system (MTS).
128 */
129
130 void
mts_init(void)131 mts_init (void)
132 {
133 const char *cp;
134 FILE *fp;
135 static int inited = 0;
136
137 if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
138 return;
139 mts_read_conf_file(fp);
140 fclose (fp);
141
142 cp = get_mtsuserconf_pathname();
143 if (cp != NULL &&
144 ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
145 mts_read_conf_file(fp);
146 fclose (fp);
147 }
148
149 save_mts_method (mts_method);
150 }
151
152
153 #define QUOTE '\\'
154
155 /*
156 * Convert escaped values, malloc some new space,
157 * and copy string to malloc'ed memory.
158 */
159
160 static char *
tailor_value(char * s)161 tailor_value (char *s)
162 {
163 int i, r;
164 char *bp;
165 char buffer[BUFSIZ];
166
167 for (bp = buffer; *s; bp++, s++) {
168 if (*s != QUOTE) {
169 *bp = *s;
170 } else {
171 switch (*++s) {
172 case 'b': *bp = '\b'; break;
173 case 'f': *bp = '\f'; break;
174 case 'n': *bp = '\n'; break;
175 case 't': *bp = '\t'; break;
176
177 case 0: s--;
178 /* FALLTHRU */
179 case QUOTE:
180 *bp = QUOTE;
181 break;
182
183 default:
184 if (!isdigit ((unsigned char) *s)) {
185 *bp++ = QUOTE;
186 *bp = *s;
187 }
188 r = ((unsigned char) *s) != '0' ? 10 : 8;
189 for (i = 0; isdigit ((unsigned char) *s); s++)
190 i *= r + ((unsigned char) *s) - '0';
191 s--;
192 *bp = toascii (i);
193 break;
194 }
195 }
196 }
197 *bp = 0;
198
199 return mh_xstrdup(buffer);
200 }
201
202 /*
203 * Get the fully qualified name of the local host.
204 *
205 * If flag is 0, then use anything out of mts.conf (like localname).
206 * If flag is 1, then only use the "proper" local hostname.
207 */
208
209 char *
LocalName(int flag)210 LocalName (int flag)
211 {
212 static char buffer0[BUFSIZ] = "";
213 static char buffer1[BUFSIZ] = "";
214 static char *buffer[] = { buffer0, buffer1 };
215 char *buf;
216 struct addrinfo hints, *res;
217
218 if (flag < 0 || flag > 1)
219 return NULL;
220
221 buf = buffer[flag];
222
223 /* check if we have cached the local name */
224 if (buf[0])
225 return buf;
226
227 mts_init ();
228
229 /* check if the mts.conf file specifies a "localname" */
230 if (*localname && flag == 0) {
231 strncpy (buf, localname, sizeof(buffer0));
232 } else {
233 memset(buf, 0, sizeof(buffer0));
234 /* first get our local name */
235 gethostname (buf, sizeof(buffer0) - 1);
236 /* now fully qualify our name */
237
238 memset(&hints, 0, sizeof(hints));
239 hints.ai_flags = AI_CANONNAME;
240 hints.ai_family = PF_UNSPEC;
241 if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
242 strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
243 freeaddrinfo(res);
244 }
245 }
246
247 /*
248 * If the mts.conf file specifies a "localdomain",
249 * we append that now. This should rarely be needed.
250 */
251 if (*localdomain) {
252 strcat (buf, ".");
253 strcat (buf, localdomain);
254 }
255
256 return buf;
257 }
258
259
260 /*
261 * This is only for UUCP mail. It gets the hostname
262 * as part of the UUCP "domain".
263 */
264
265 char *
SystemName(void)266 SystemName (void)
267 {
268 static char buffer[BUFSIZ] = "";
269
270 /* check if we have cached the system name */
271 if (buffer[0])
272 return buffer;
273
274 mts_init ();
275
276 /* check if mts.conf file specifies a "systemname" */
277 if (*systemname) {
278 strncpy (buffer, systemname, sizeof(buffer));
279 return buffer;
280 }
281
282 gethostname (buffer, sizeof(buffer));
283
284 return buffer;
285 }
286
287
288 /*
289 * Get the username of current user
290 */
291
292 char *
getusername(void)293 getusername (void)
294 {
295 if (username[0] == '\0')
296 getuserinfo();
297
298 return username;
299 }
300
301
302 /*
303 * Get full name of current user (typically from GECOS
304 * field of password file).
305 */
306
307 char *
getfullname(void)308 getfullname (void)
309 {
310 if (username[0] == '\0')
311 getuserinfo();
312
313 return fullname;
314 }
315
316
317 /*
318 * Get the full local mailbox name. This is in the form:
319 *
320 * User Name <user@name.com>
321 */
322
323 char *
getlocalmbox(void)324 getlocalmbox (void)
325 {
326 if (username[0] == '\0')
327 getuserinfo();
328
329 return localmbox;
330 }
331
332 /*
333 * Find the user's username and full name, and cache them.
334 */
335
336 static void
getuserinfo(void)337 getuserinfo (void)
338 {
339 char *cp, *np;
340 struct passwd *pw;
341
342 if ((pw = getpwuid (getuid ())) == NULL
343 || pw->pw_name == NULL
344 || *pw->pw_name == '\0') {
345 strncpy (username, "unknown", sizeof(username));
346 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
347 (int) getuid ());
348 return;
349 }
350
351
352 /* username */
353 /* If there's a Local-Mailbox profile component, try to extract
354 the username from it. But don't try very hard, this assumes
355 the very simple User Name <user@name.com> form.
356 Note that post(8) and whom(1) use context_foil (), so they
357 won't see the profile component. */
358 if ((np = context_find("Local-Mailbox")) != NULL) {
359 char *left_angle_bracket = strchr (np, '<');
360 char *at_sign = strchr (np, '@');
361 char *right_angle_bracket = strchr (np, '>');
362
363 strncpy(localmbox, np, sizeof(localmbox));
364
365 if (left_angle_bracket && at_sign && right_angle_bracket) {
366 if (at_sign > left_angle_bracket &&
367 at_sign - left_angle_bracket < BUFSIZ) {
368 strncpy(username, left_angle_bracket + 1,
369 at_sign - left_angle_bracket - 1);
370 }
371 }
372 }
373
374 if (username[0] == '\0') {
375 strncpy (username, pw->pw_name, sizeof(username));
376 }
377
378 username[sizeof(username) - 1] = '\0';
379
380 escape_local_part(username, sizeof(username));
381
382
383 /* fullname */
384 np = pw->pw_gecos;
385
386 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
387 which some OSes use to separate other 'finger' information in the GECOS
388 field, like phone number. */
389 for (cp = fullname; *np != '\0' && *np != ','; *cp++ = *np++)
390 continue;
391 *cp = '\0';
392
393 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
394 your real name. If SIGNATURE isn't set, use the Signature profile
395 setting if it exists.
396 Note that post(8) and whom(1) use context_foil (), so they
397 won't see the profile component. */
398 if ((cp = getenv ("SIGNATURE")) && *cp)
399 strncpy (fullname, cp, sizeof(fullname));
400 else if ((cp = context_find("Signature")))
401 strncpy (fullname, cp, sizeof(fullname));
402
403 fullname[sizeof(fullname) - 1] = '\0';
404
405 escape_display_name(fullname, sizeof(fullname));
406
407
408 /* localmbox, if not using Local-Mailbox */
409 if (localmbox[0] == '\0') {
410 snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname,
411 username, LocalName(0));
412 }
413
414 localmbox[sizeof(localmbox) - 1] = '\0';
415 }
416
417 static const char*
get_mtsconf_pathname(void)418 get_mtsconf_pathname (void)
419 {
420 const char *cp = getenv ( "MHMTSCONF" );
421 if (cp != NULL && *cp != '\0') {
422 return cp;
423 }
424 return mtsconf;
425 }
426
427 static const char*
get_mtsuserconf_pathname(void)428 get_mtsuserconf_pathname (void)
429 {
430 const char *cp = getenv ( "MHMTSUSERCONF" );
431 if (cp != NULL && *cp != '\0') {
432 return cp;
433 }
434 return NULL;
435 }
436
437 static void
mts_read_conf_file(FILE * fp)438 mts_read_conf_file (FILE *fp)
439 {
440 char *bp, *cp, buffer[BUFSIZ];
441 struct bind *b;
442
443 while (fgets (buffer, sizeof(buffer), fp)) {
444 if (!(cp = strchr(buffer, '\n')))
445 break;
446 *cp = 0;
447 if (*buffer == '#' || *buffer == '\0')
448 continue;
449 if (!(bp = strchr(buffer, ':')))
450 break;
451 *bp++ = 0;
452 while (isspace ((unsigned char) *bp))
453 *bp++ = 0;
454
455 for (b = binds; b->keyword; b++)
456 if (!strcmp (buffer, b->keyword))
457 break;
458 if (b->keyword && (cp = tailor_value (bp)))
459 *b->value = cp;
460 }
461 }
462