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