]> diplodocus.org Git - nmh/blob - sbr/mts.c
Document argsplit changes in mh-profile man page.
[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 /* 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 (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 ((unsigned char) *s)) {
204 *bp++ = QUOTE;
205 *bp = *s;
206 }
207 r = ((unsigned char) *s) != '0' ? 10 : 8;
208 for (i = 0; isdigit ((unsigned char) *s); s++)
209 i = i * r + ((unsigned char) *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 char *cp, *np;
363 struct passwd *pw;
364
365 if ((pw = getpwuid (getuid ())) == NULL
366 || pw->pw_name == NULL
367 || *pw->pw_name == '\0') {
368 strncpy (username, "unknown", sizeof(username));
369 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
370 (int) getuid ());
371 return;
372 }
373
374
375 /* username */
376 /* If there's a Local-Mailbox profile component, try to extract
377 the username from it. But don't try very hard, this assumes
378 the very simple User Name <user@name.com> form.
379 Note that post(8) and whom(1) use context_foil (), so they
380 won't see the profile component. */
381 if ((np = context_find("Local-Mailbox")) != NULL) {
382 char *left_angle_bracket = strchr (np, '<');
383 char *at_sign = strchr (np, '@');
384 char *right_angle_bracket = strchr (np, '>');
385
386 strncpy(localmbox, np, sizeof(localmbox));
387
388 if (left_angle_bracket && at_sign && right_angle_bracket) {
389 if (at_sign > left_angle_bracket &&
390 at_sign - left_angle_bracket < BUFSIZ) {
391 strncpy(username, left_angle_bracket + 1,
392 at_sign - left_angle_bracket - 1);
393 }
394 }
395 }
396
397 if (username[0] == '\0') {
398 strncpy (username, pw->pw_name, sizeof(username));
399 }
400
401 username[sizeof(username) - 1] = '\0';
402
403 escape_local_part(username, sizeof(username));
404
405
406 /* fullname */
407 np = pw->pw_gecos;
408
409 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
410 which some OSes use to separate other 'finger' information in the GECOS
411 field, like phone number. */
412 for (cp = fullname; *np != '\0' && *np != ','; *cp++ = *np++)
413 continue;
414 *cp = '\0';
415
416 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
417 your real name. If SIGNATURE isn't set, use the Signature profile
418 setting if it exists.
419 Note that post(8) and whom(1) use context_foil (), so they
420 won't see the profile component. */
421 if ((cp = getenv ("SIGNATURE")) && *cp)
422 strncpy (fullname, cp, sizeof(fullname));
423 else if ((cp = context_find("Signature")))
424 strncpy (fullname, cp, sizeof(fullname));
425
426 fullname[sizeof(fullname) - 1] = '\0';
427
428 escape_display_name(fullname, sizeof(fullname));
429
430
431 /* localmbox, if not using Local-Mailbox */
432 if (localmbox[0] == '\0') {
433 snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname,
434 username, LocalName(0));
435 }
436
437 localmbox[sizeof(localmbox) - 1] = '\0';
438 }
439
440 static const char*
441 get_mtsconf_pathname (void)
442 {
443 const char *cp = getenv ( "MHMTSCONF" );
444 if (cp != NULL && *cp != '\0') {
445 return cp;
446 }
447 return mtsconf;
448 }
449
450 static const char*
451 get_mtsuserconf_pathname (void)
452 {
453 const char *cp = getenv ( "MHMTSUSERCONF" );
454 if (cp != NULL && *cp != '\0') {
455 return cp;
456 }
457 return NULL;
458 }
459
460 static void
461 mts_read_conf_file (FILE *fp)
462 {
463 char *bp, *cp, buffer[BUFSIZ];
464 struct bind *b;
465
466 while (fgets (buffer, sizeof(buffer), fp)) {
467 if (!(cp = strchr(buffer, '\n')))
468 break;
469 *cp = 0;
470 if (*buffer == '#' || *buffer == '\0')
471 continue;
472 if (!(bp = strchr(buffer, ':')))
473 break;
474 *bp++ = 0;
475 while (isspace ((unsigned char) *bp))
476 *bp++ = 0;
477
478 for (b = binds; b->keyword; b++)
479 if (!strcmp (buffer, b->keyword))
480 break;
481 if (b->keyword && (cp = tailor_value (bp)))
482 *b->value = cp;
483 }
484 }