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