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