Added include of mh.h for snprintf() prototype.
[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 static int MMailids = 0;
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  * It also handles mmailid processing (username masquerading)
379  */
380
381 static void
382 getuserinfo (void)
383 {
384     register char *cp, *np;
385     register struct passwd *pw;
386
387 #ifdef KPOP
388     uid_t uid;
389
390     uid = getuid ();
391     if (uid == geteuid () && (cp = getenv ("USER")) != NULL
392         && (pw = getpwnam (cp)) != NULL)
393       strncpy (username, cp, sizeof(username));
394     else if ((pw = getpwuid (uid)) == NULL
395              || pw->pw_name == NULL
396              || *pw->pw_name == '\0') {
397 #else /* KPOP */
398     if ((pw = getpwuid (getuid ())) == NULL
399             || pw->pw_name == NULL
400             || *pw->pw_name == '\0') {
401 #endif /* KPOP */
402
403         strncpy (username, "unknown", sizeof(username));
404         snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
405                 (int) getuid ());
406         return;
407     }
408
409     np = pw->pw_gecos;
410
411     /*
412      * Do mmailid (username masquerading) processing.  The GECOS
413      * field should have the form "Full Name <fakeusername>".
414      */
415 #ifndef GCOS_HACK
416     for (cp = fullname; *np && *np != (MMailids ? '<' : ','); *cp++ = *np++)
417         continue;
418 #else
419     for (cp = fullname; *np && *np != (MMailids ? '<' : ','); ) {
420         if (*np == '&') {       /* blech! */
421             strcpy (cp, pw->pw_name);
422             *cp = toupper(*cp);
423             while (*cp)
424                 cp++;
425             np++;
426         } else {
427             *cp++ = *np++;
428         }
429     }
430 #endif
431
432     *cp = '\0';
433     if (MMailids) {
434         if (*np)
435             np++;
436         for (cp = username; *np && *np != '>'; *cp++ = *np++)
437             continue;
438         *cp = '\0';
439     }
440     if (MMailids == 0 || *np == '\0')
441         strncpy (username, pw->pw_name, sizeof(username));
442
443     if ((cp = getenv ("SIGNATURE")) && *cp)
444         strncpy (fullname, cp, sizeof(fullname));
445
446     if (strchr(fullname, '.')) {                /*  quote any .'s */
447         char tmp[BUFSIZ];
448
449         /* should quote "'s too */
450         snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
451         strncpy (fullname, tmp, sizeof(fullname));
452     }
453
454     return;
455 }