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