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