254a758e6e90862bf1982b8017df7563a236c941
[mmh] / zotnet / mts / mts.c
1
2 /*
3  * mts.c -- definitions for the mail transport system
4  *
5  * $Id$
6  */
7
8 #include "h/mh.h"   /* for snprintf() */
9 #include <h/nmh.h>
10
11 #define nmhetcdir(file) NMHETCDIR#file
12
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <mts.h>
16 #include <pwd.h>
17 #include <netdb.h>
18
19 #ifdef HAVE_SYS_UTSNAME_H
20 # include <sys/utsname.h>
21 #endif
22
23 #define NOTOK   (-1)
24 #define OK        0
25
26 extern int errno;
27
28 /*
29  * static prototypes
30  */
31 static char *tailor_value (char *);
32 static void getuserinfo (void);
33
34 /*
35  * *mmdfldir and *uucpldir are the maildrop directories.  If maildrops
36  * are kept in the user's home directory, then these should be empty
37  * strings.  In this case, the appropriate ...lfil array should contain
38  * the name of the file in the user's home directory.  Usually, this is
39  * something like ".mail".
40  */
41
42 /*
43  * nmh mail transport interface customization file
44  */
45 static char *mtsconf = nmhetcdir(/mts.conf);
46
47 static char *localname   = "";
48 static char *localdomain = "";
49 static char *systemname  = "";
50
51 char *mmdfldir = MAILSPOOL;
52 char *mmdflfil = "";
53 char *uucpldir = "/usr/spool/mail";
54 char *uucplfil = "";
55
56 char *mmdlm1 = "\001\001\001\001\n";
57 char *mmdlm2 = "\001\001\001\001\n";
58
59 /* Cache the username and fullname of the user */
60 static char username[BUFSIZ];
61 static char fullname[BUFSIZ];
62
63 /* variables for username masquerading */
64 int MMailids = 0;  /* used from post.c as well as here */
65 static char *mmailid = "0";
66
67
68 /*
69  * MTS specific variables
70  */
71 #if defined(SENDMTS) || defined(SMTPMTS)
72 char *hostable = nmhetcdir(/hosts);
73 char *sendmail = SENDMAILPATH;
74 #endif
75
76 /*
77  * SMTP/POP stuff
78  */
79 char *clientname = NULL;
80 char *servers    = "localhost \01localnet";
81 char *pophost    = "";
82
83 /*
84  * BBoards-specific variables
85  */
86 char *bb_domain = "";
87
88
89 /*
90  * POP BBoards-specific variables
91  */
92 #ifdef  BPOP
93 char *popbbhost = "";
94 char *popbbuser = "";
95 char *popbblist = nmhetcdir(/hosts.popbb);
96 #endif /* BPOP */
97
98 /*
99  * Global MailDelivery file
100  */
101 char *maildelivery = nmhetcdir(/maildelivery);
102
103
104 /*
105  * Aliasing Facility (doesn't belong here)
106  */
107 int Everyone = NOTOK;
108 static char *everyone = "-1";
109 char *NoShell = "";
110
111 /*
112  * Customize the MTS settings for nmh by adjusting
113  * the file mts.conf in the nmh etc directory.
114  */
115
116 struct bind {
117     char *keyword;
118     char **value;
119 };
120
121 static struct bind binds[] = {
122     { "localname", &localname },
123     { "localdomain", &localdomain },
124     { "systemname", &systemname },
125     { "mmdfldir", &mmdfldir },
126     { "mmdflfil", &mmdflfil },
127     { "uucpldir", &uucpldir },
128     { "uucplfil", &uucplfil },
129     { "mmdelim1", &mmdlm1 },
130     { "mmdelim2", &mmdlm2 },
131     { "mmailid", &mmailid },
132
133 #if defined(SENDMTS) || defined(SMTPMTS)
134     { "hostable", &hostable },
135 #endif
136
137 #ifdef SENDMTS
138     { "sendmail", &sendmail },
139 #endif
140
141     { "clientname",  &clientname },
142     { "servers", &servers },
143     { "pophost", &pophost },
144     { "bbdomain", &bb_domain },
145
146 #ifdef BPOP
147     { "popbbhost", &popbbhost },
148     { "popbbuser", &popbbuser },
149     { "popbblist", &popbblist },
150 #endif
151
152 #ifdef NNTP
153     { "nntphost", &popbbhost },
154 #endif
155
156     { "maildelivery", &maildelivery },
157     { "everyone", &everyone },
158     { "noshell", &NoShell },
159     { NULL, NULL }
160 };
161
162
163 /*
164  * Read the configuration file for the nmh interface
165  * to the mail transport system (MTS).
166  */
167
168 void
169 mts_init (char *name)
170 {
171     char *bp, *cp, buffer[BUFSIZ];
172     struct bind *b;
173     FILE *fp;
174     static int inited = 0;
175
176     if (inited++ || (fp = fopen (mtsconf, "r")) == NULL)
177         return;
178
179     while (fgets (buffer, sizeof(buffer), fp)) {
180         if (!(cp = strchr(buffer, '\n')))
181             break;
182         *cp = 0;
183         if (*buffer == '#' || *buffer == '\0')
184             continue;
185         if (!(bp = strchr(buffer, ':')))
186             break;
187         *bp++ = 0;
188         while (isspace (*bp))
189             *bp++ = 0;
190
191         for (b = binds; b->keyword; b++)
192             if (!strcmp (buffer, b->keyword))
193                 break;
194         if (b->keyword && (cp = tailor_value (bp)))
195             *b->value = cp;
196     }
197
198     fclose (fp);
199     MMailids = atoi (mmailid);
200     Everyone = atoi (everyone);
201 }
202
203
204 #define QUOTE   '\\'
205
206 /*
207  * Convert escaped values, malloc some new space,
208  * and copy string to malloc'ed memory.
209  */
210
211 static char *
212 tailor_value (char *s)
213 {
214     int i, r;
215     char *bp;
216     char buffer[BUFSIZ];
217     size_t len;
218
219     for (bp = buffer; *s; bp++, s++) {
220         if (*s != QUOTE) {
221             *bp = *s;
222         } else {
223             switch (*++s) {
224                 case 'b': *bp = '\b'; break;
225                 case 'f': *bp = '\f'; break;
226                 case 'n': *bp = '\n'; break;
227                 case 't': *bp = '\t'; break;
228
229                 case 0: s--;
230                 case QUOTE: 
231                     *bp = QUOTE;
232                     break;
233
234                 default: 
235                     if (!isdigit (*s)) {
236                         *bp++ = QUOTE;
237                         *bp = *s;
238                     }
239                     r = *s != '0' ? 10 : 8;
240                     for (i = 0; isdigit (*s); s++)
241                         i = i * r + *s - '0';
242                     s--;
243                     *bp = toascii (i);
244                     break;
245             }
246         }
247     }
248     *bp = 0;
249
250     len = strlen (buffer) + 1;
251     if ((bp = malloc (len)))
252         memcpy (bp, buffer, len);
253
254     return bp;
255 }
256
257 /*
258  * Get the fully qualified name of the local host.
259  */
260
261 char *
262 LocalName (void)
263 {
264     static char buffer[BUFSIZ] = "";
265     struct hostent *hp;
266
267 #ifdef HAVE_UNAME
268     struct utsname name;
269 #endif
270
271     /* check if we have cached the local name */
272     if (buffer[0])
273         return buffer;
274
275     mts_init ("mts");
276
277     /* check if the mts.conf file specifies a "localname" */
278     if (*localname) {
279         strncpy (buffer, localname, sizeof(buffer));
280     } else {
281 #ifdef HAVE_UNAME
282         /* first get our local name */
283         uname (&name);
284         strncpy (buffer, name.nodename, sizeof(buffer));
285 #else
286         /* first get our local name */
287         gethostname (buffer, sizeof(buffer));
288 #endif
289 #ifdef HAVE_SETHOSTENT
290         sethostent (1);
291 #endif 
292         /* now fully qualify our name */
293         if ((hp = gethostbyname (buffer)))
294             strncpy (buffer, hp->h_name, sizeof(buffer));
295     }
296
297     /*
298      * If the mts.conf file specifies a "localdomain",
299      * we append that now.  This should rarely be needed.
300      */
301     if (*localdomain) {
302         strcat (buffer, ".");
303         strcat (buffer, localdomain);
304     }
305
306     return buffer;
307 }
308
309
310 /*
311  * This is only for UUCP mail.  It gets the hostname
312  * as part of the UUCP "domain".
313  */
314
315 char *
316 SystemName (void)
317 {
318     static char buffer[BUFSIZ] = "";
319
320 #ifdef HAVE_UNAME
321     struct utsname name;
322 #endif
323
324     /* check if we have cached the system name */
325     if (buffer[0])
326         return buffer;
327
328     mts_init ("mts");
329
330     /* check if mts.conf file specifies a "systemname" */
331     if (*systemname) {
332         strncpy (buffer, systemname, sizeof(buffer));
333         return buffer;
334     }
335
336 #ifdef HAVE_UNAME
337     uname (&name);
338     strncpy (buffer, name.nodename, sizeof(buffer));
339 #else
340     gethostname (buffer, sizeof(buffer));
341 #endif
342
343     return buffer;
344 }
345
346
347 /*
348  * Get the username of current user
349  */
350
351 char *
352 getusername (void)
353 {
354     if (username[0] == '\0')
355         getuserinfo();
356
357     return username;
358 }
359
360
361 /*
362  * Get full name of current user (typically from GECOS
363  * field of password file).
364  */
365
366 char *
367 getfullname (void)
368 {
369     if (username[0] == '\0')
370         getuserinfo();
371
372     return fullname;
373 }
374
375
376 /*
377  * Find the user's username and full name, and cache them.
378  * Also, handle "mmailid" username masquerading controlled from the GECOS field
379  * of the passwd file. 
380  */
381
382 static void
383 getuserinfo (void)
384 {
385     register char *cp, *np;
386     register struct passwd *pw;
387
388 #ifdef KPOP
389     uid_t uid;
390
391     uid = getuid ();
392     if (uid == geteuid () && (cp = getenv ("USER")) != NULL
393         && (pw = getpwnam (cp)) != NULL)
394       strncpy (username, cp, sizeof(username));
395     else if ((pw = getpwuid (uid)) == NULL
396              || pw->pw_name == NULL
397              || *pw->pw_name == '\0') {
398 #else /* KPOP */
399     if ((pw = getpwuid (getuid ())) == NULL
400             || pw->pw_name == NULL
401             || *pw->pw_name == '\0') {
402 #endif /* KPOP */
403
404         strncpy (username, "unknown", sizeof(username));
405         snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
406                 (int) getuid ());
407         return;
408     }
409
410     np = pw->pw_gecos;
411
412     /*
413      * Do mmailid (username masquerading) processing.  The GECOS
414      * field should have the form "Full Name <fakeusername>".  For instance,
415      * "Dan Harkless <Dan.Harkless>".  Naturally, you'll want your MTA to have
416      * an alias (e.g. in /etc/aliases) from "fakeusername" to your account name.
417      */
418 #ifndef GCOS_HACK
419     /* What is this code here for?  As of 2000-01-25, GCOS_HACK doesn't appear
420        anywhere else in nmh.  -- Dan Harkless <dan-nmh@dilvish.speed.net> */
421     for (cp = fullname; *np && *np != (MMailids ? '<' : ','); *cp++ = *np++)
422         continue;
423 #else
424     for (cp = fullname; *np && *np != (MMailids ? '<' : ','); ) {
425         if (*np == '&') {       /* blech! */
426             strcpy (cp, pw->pw_name);
427             *cp = toupper(*cp);
428             while (*cp)
429                 cp++;
430             np++;
431         } else {
432             *cp++ = *np++;
433         }
434     }
435 #endif
436
437     *cp = '\0';
438     if (MMailids) {
439         if (*np)
440             np++;
441         for (cp = username; *np && *np != '>'; *cp++ = *np++)
442             continue;
443         *cp = '\0';
444     }
445     if (MMailids == 0 || *np == '\0')
446         strncpy (username, pw->pw_name, sizeof(username));
447
448     if ((cp = getenv ("SIGNATURE")) && *cp)
449         strncpy (fullname, cp, sizeof(fullname));
450
451     if (strchr(fullname, '.')) {                /*  quote any .'s */
452         char tmp[BUFSIZ];
453
454         /* should quote "'s too */
455         snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
456         strncpy (fullname, tmp, sizeof(fullname));
457     }
458
459     return;
460 }