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