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