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