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