]> diplodocus.org Git - nmh/blob - sbr/mts.c
We're not using the .Bu macro anymore.
[nmh] / sbr / mts.c
1
2 /*
3 * mts.c -- definitions for the mail transport system
4 *
5 * $Id$
6 *
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
10 */
11
12 #include <h/mh.h> /* for snprintf() */
13 #include <h/nmh.h>
14 #include <h/utils.h>
15
16 #define nmhetcdir(file) NMHETCDIR#file
17
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <h/mts.h>
21 #include <pwd.h>
22 #include <netdb.h>
23
24 #ifdef HAVE_SYS_UTSNAME_H
25 # include <sys/utsname.h>
26 #endif
27
28 #define NOTOK (-1)
29 #define OK 0
30
31 /*
32 * static prototypes
33 */
34 static char *tailor_value (char *);
35 static void getuserinfo (void);
36
37 /*
38 * *mmdfldir and *uucpldir are the maildrop directories. If maildrops
39 * are kept in the user's home directory, then these should be empty
40 * strings. In this case, the appropriate ...lfil array should contain
41 * the name of the file in the user's home directory. Usually, this is
42 * something like ".mail".
43 */
44
45 /*
46 * nmh mail transport interface customization file
47 */
48 static char *mtsconf = nmhetcdir(/mts.conf);
49
50 static char *localname = "";
51 static char *localdomain = "";
52 static char *systemname = "";
53
54 char *mmdfldir = MAILSPOOL;
55 char *mmdflfil = "";
56 char *uucpldir = "/usr/spool/mail";
57 char *uucplfil = "";
58
59 char *mmdlm1 = "\001\001\001\001\n";
60 char *mmdlm2 = "\001\001\001\001\n";
61
62 /* Cache the username and fullname of the user */
63 static char username[BUFSIZ];
64 static char fullname[BUFSIZ];
65
66 /* Variables for username masquerading: */
67 boolean draft_from_masquerading = FALSE; /* also used from post.c */
68 static boolean mmailid_masquerading = FALSE;
69 boolean username_extension_masquerading = FALSE; /* " from addrsbr.c */
70 static char* masquerade = "";
71
72 /*
73 * MTS specific variables
74 */
75 #if defined(SMTPMTS)
76 static char *sm_method = "smtp";
77 int sm_mts = MTS_SMTP;
78 char *hostable = nmhetcdir(/hosts);
79 char *sendmail = SENDMAILPATH;
80 #endif
81
82 /*
83 * SMTP/POP stuff
84 */
85 char *clientname = NULL;
86 char *servers = "localhost \01localnet";
87 char *pophost = "";
88
89 /*
90 * BBoards-specific variables
91 */
92 char *bb_domain = "";
93
94
95 /*
96 * POP BBoards-specific variables
97 */
98 #ifdef BPOP
99 char *popbbhost = "";
100 char *popbbuser = "";
101 char *popbblist = nmhetcdir(/hosts.popbb);
102 #endif /* BPOP */
103
104 /*
105 * Global MailDelivery file
106 */
107 char *maildelivery = nmhetcdir(/maildelivery);
108
109
110 /*
111 * Aliasing Facility (doesn't belong here)
112 */
113 int Everyone = NOTOK;
114 static char *everyone = "-1";
115 char *NoShell = "";
116
117 /*
118 * Customize the MTS settings for nmh by adjusting
119 * the file mts.conf in the nmh etc directory.
120 */
121
122 struct bind {
123 char *keyword;
124 char **value;
125 };
126
127 static struct bind binds[] = {
128 { "localname", &localname },
129 { "localdomain", &localdomain },
130 { "systemname", &systemname },
131 { "mmdfldir", &mmdfldir },
132 { "mmdflfil", &mmdflfil },
133 { "uucpldir", &uucpldir },
134 { "uucplfil", &uucplfil },
135 { "mmdelim1", &mmdlm1 },
136 { "mmdelim2", &mmdlm2 },
137 { "masquerade", &masquerade },
138
139 #if defined(SMTPMTS)
140 { "mts", &sm_method },
141 { "hostable", &hostable },
142 { "sendmail", &sendmail },
143 #endif
144
145 { "clientname", &clientname },
146 { "servers", &servers },
147 { "pophost", &pophost },
148 { "bbdomain", &bb_domain },
149
150 #ifdef BPOP
151 { "popbbhost", &popbbhost },
152 { "popbbuser", &popbbuser },
153 { "popbblist", &popbblist },
154 #endif
155
156 #ifdef NNTP
157 { "nntphost", &popbbhost },
158 #endif
159
160 { "maildelivery", &maildelivery },
161 { "everyone", &everyone },
162 { "noshell", &NoShell },
163 { NULL, NULL }
164 };
165
166
167 /*
168 * Read the configuration file for the nmh interface
169 * to the mail transport system (MTS).
170 */
171
172 void
173 mts_init (char *name)
174 {
175 char *bp, *cp, buffer[BUFSIZ];
176 struct bind *b;
177 FILE *fp;
178 static int inited = 0;
179
180 if (inited++ || (fp = fopen (mtsconf, "r")) == NULL)
181 return;
182
183 while (fgets (buffer, sizeof(buffer), fp)) {
184 if (!(cp = strchr(buffer, '\n')))
185 break;
186 *cp = 0;
187 if (*buffer == '#' || *buffer == '\0')
188 continue;
189 if (!(bp = strchr(buffer, ':')))
190 break;
191 *bp++ = 0;
192 while (isspace (*bp))
193 *bp++ = 0;
194
195 for (b = binds; b->keyword; b++)
196 if (!strcmp (buffer, b->keyword))
197 break;
198 if (b->keyword && (cp = tailor_value (bp)))
199 *b->value = cp;
200 }
201
202 fclose (fp);
203
204 Everyone = atoi (everyone);
205
206 if (strstr(masquerade, "draft_from") != NULL)
207 draft_from_masquerading = TRUE;
208
209 if (strstr(masquerade, "mmailid") != NULL)
210 mmailid_masquerading = TRUE;
211
212 if (strstr(masquerade, "username_extension") != NULL)
213 username_extension_masquerading = TRUE;
214
215 #ifdef SMTPMTS
216 if (strcmp(sm_method, "smtp") == 0)
217 sm_mts = MTS_SMTP;
218 else if (strcmp(sm_method, "sendmail") == 0)
219 sm_mts = MTS_SENDMAIL;
220 else {
221 advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
222 sm_mts = MTS_SMTP;
223 }
224 #endif
225 }
226
227
228 #define QUOTE '\\'
229
230 /*
231 * Convert escaped values, malloc some new space,
232 * and copy string to malloc'ed memory.
233 */
234
235 static char *
236 tailor_value (char *s)
237 {
238 int i, r;
239 char *bp;
240 char buffer[BUFSIZ];
241 size_t len;
242
243 for (bp = buffer; *s; bp++, s++) {
244 if (*s != QUOTE) {
245 *bp = *s;
246 } else {
247 switch (*++s) {
248 case 'b': *bp = '\b'; break;
249 case 'f': *bp = '\f'; break;
250 case 'n': *bp = '\n'; break;
251 case 't': *bp = '\t'; break;
252
253 case 0: s--;
254 case QUOTE:
255 *bp = QUOTE;
256 break;
257
258 default:
259 if (!isdigit (*s)) {
260 *bp++ = QUOTE;
261 *bp = *s;
262 }
263 r = *s != '0' ? 10 : 8;
264 for (i = 0; isdigit (*s); s++)
265 i = i * r + *s - '0';
266 s--;
267 *bp = toascii (i);
268 break;
269 }
270 }
271 }
272 *bp = 0;
273
274 len = strlen (buffer) + 1;
275 bp = mh_xmalloc (len);
276 memcpy (bp, buffer, len);
277
278 return bp;
279 }
280
281 /*
282 * Get the fully qualified name of the local host.
283 */
284
285 char *
286 LocalName (void)
287 {
288 static char buffer[BUFSIZ] = "";
289 struct hostent *hp;
290
291 #ifdef HAVE_UNAME
292 struct utsname name;
293 #endif
294
295 /* check if we have cached the local name */
296 if (buffer[0])
297 return buffer;
298
299 mts_init ("mts");
300
301 /* check if the mts.conf file specifies a "localname" */
302 if (*localname) {
303 strncpy (buffer, localname, sizeof(buffer));
304 } else {
305 #ifdef HAVE_UNAME
306 /* first get our local name */
307 uname (&name);
308 strncpy (buffer, name.nodename, sizeof(buffer));
309 #else
310 /* first get our local name */
311 gethostname (buffer, sizeof(buffer));
312 #endif
313 #ifdef HAVE_SETHOSTENT
314 sethostent (1);
315 #endif
316 /* now fully qualify our name */
317 if ((hp = gethostbyname (buffer)))
318 strncpy (buffer, hp->h_name, sizeof(buffer));
319 }
320
321 /*
322 * If the mts.conf file specifies a "localdomain",
323 * we append that now. This should rarely be needed.
324 */
325 if (*localdomain) {
326 strcat (buffer, ".");
327 strcat (buffer, localdomain);
328 }
329
330 return buffer;
331 }
332
333
334 /*
335 * This is only for UUCP mail. It gets the hostname
336 * as part of the UUCP "domain".
337 */
338
339 char *
340 SystemName (void)
341 {
342 static char buffer[BUFSIZ] = "";
343
344 #ifdef HAVE_UNAME
345 struct utsname name;
346 #endif
347
348 /* check if we have cached the system name */
349 if (buffer[0])
350 return buffer;
351
352 mts_init ("mts");
353
354 /* check if mts.conf file specifies a "systemname" */
355 if (*systemname) {
356 strncpy (buffer, systemname, sizeof(buffer));
357 return buffer;
358 }
359
360 #ifdef HAVE_UNAME
361 uname (&name);
362 strncpy (buffer, name.nodename, sizeof(buffer));
363 #else
364 gethostname (buffer, sizeof(buffer));
365 #endif
366
367 return buffer;
368 }
369
370
371 /*
372 * Get the username of current user
373 */
374
375 char *
376 getusername (void)
377 {
378 if (username[0] == '\0')
379 getuserinfo();
380
381 return username;
382 }
383
384
385 /*
386 * Get full name of current user (typically from GECOS
387 * field of password file).
388 */
389
390 char *
391 getfullname (void)
392 {
393 if (username[0] == '\0')
394 getuserinfo();
395
396 return fullname;
397 }
398
399
400 /*
401 * Find the user's username and full name, and cache them.
402 * Also, handle "mmailid" username masquerading controlled from the GECOS field
403 * of the passwd file.
404 */
405
406 static void
407 getuserinfo (void)
408 {
409 register char *cp, *np;
410 register struct passwd *pw;
411
412 #ifdef KPOP
413 uid_t uid;
414
415 uid = getuid ();
416 if (uid == geteuid () && (cp = getenv ("USER")) != NULL
417 && (pw = getpwnam (cp)) != NULL)
418 strncpy (username, cp, sizeof(username));
419 else if ((pw = getpwuid (uid)) == NULL
420 || pw->pw_name == NULL
421 || *pw->pw_name == '\0') {
422 #else /* KPOP */
423 if ((pw = getpwuid (getuid ())) == NULL
424 || pw->pw_name == NULL
425 || *pw->pw_name == '\0') {
426 #endif /* KPOP */
427 strncpy (username, "unknown", sizeof(username));
428 snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
429 (int) getuid ());
430 return;
431 }
432
433 np = pw->pw_gecos;
434
435 /* Get the user's real name from the GECOS field. Stop once we hit a ',',
436 which some OSes use to separate other 'finger' information in the GECOS
437 field, like phone number. Also, if mmailid masquerading is turned on due
438 to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
439 hit a '<' (which should precede any ','s). */
440 #ifndef BSD42
441 if (mmailid_masquerading)
442 /* Stop at ',' or '<'. */
443 for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
444 *cp++ = *np++)
445 continue;
446 else
447 /* Allow '<' as a legal character of the user's name. This code is
448 basically a duplicate of the code above the "else" -- we don't
449 collapse it down to one copy and put the mmailid_masquerading check
450 inside the loop with "(x ? y : z)" because that's inefficient and the
451 value'll never change while it's in there. */
452 for (cp = fullname; *np != '\0' && *np != ',';
453 *cp++ = *np++)
454 continue;
455 #else /* BSD42 */
456 /* On BSD(-derived) systems, the system utilities that deal with the GECOS
457 field (finger, mail, sendmail, etc.) translate any '&' character in it to
458 the login name, with the first letter capitalized. So, for instance,
459 fingering a user "bob" with the GECOS field "& Jones" would reveal him to
460 be "In real life: Bob Jones". Surprisingly, though, the OS doesn't do
461 the translation for you, so we have to do it manually here. */
462 if (mmailid_masquerading)
463 /* Stop at ',' or '<'. */
464 for (cp = fullname;
465 *np != '\0' && *np != ',' && *np != '<';) {
466 if (*np == '&') { /* blech! */
467 strcpy (cp, pw->pw_name);
468 *cp = toupper(*cp);
469 while (*cp)
470 cp++;
471 np++;
472 } else {
473 *cp++ = *np++;
474 }
475 }
476 else
477 /* Allow '<' as a legal character of the user's name. This code is
478 basically a duplicate of the code above the "else" -- we don't
479 collapse it down to one copy and put the mmailid_masquerading check
480 inside the loop with "(x ? y : z)" because that's inefficient and the
481 value'll never change while it's in there. */
482 for (cp = fullname;
483 *np != '\0' && *np != ',';) {
484 if (*np == '&') { /* blech! */
485 strcpy (cp, pw->pw_name);
486 *cp = toupper(*cp);
487 while (*cp)
488 cp++;
489 np++;
490 } else {
491 *cp++ = *np++;
492 }
493 }
494 #endif /* BSD42 */
495 *cp = '\0';
496
497 if (mmailid_masquerading) {
498 /* Do mmailid processing. The GECOS field should have the form
499 "Full Name <fakeusername>". For instance,
500 "Dan Harkless <Dan.Harkless>". Naturally, you'll want your MTA to
501 have an alias (e.g. in /etc/aliases) from "fakeusername" to your
502 account name. */
503 if (*np)
504 np++;
505 for (cp = username; *np && *np != '>'; *cp++ = *np++)
506 continue;
507 *cp = '\0';
508 }
509 if (!mmailid_masquerading || *np == '\0')
510 strncpy (username, pw->pw_name, sizeof(username));
511
512 /* The $SIGNATURE environment variable overrides the GECOS field's idea of
513 your real name. */
514 if ((cp = getenv ("SIGNATURE")) && *cp)
515 strncpy (fullname, cp, sizeof(fullname));
516
517 if (strchr(fullname, '.')) { /* quote any .'s */
518 char tmp[BUFSIZ];
519
520 /* should quote "'s too */
521 snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
522 strncpy (fullname, tmp, sizeof(fullname));
523 }
524
525 return;
526 }