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