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