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