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