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