Removed, or added use of, unused macros to prevent warnings from gcc -Wunused-macros.
[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     const char *cp;
145     FILE *fp;
146     static int inited = 0;
147
148     if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
149         return;
150     mts_read_conf_file(fp);
151     fclose (fp);
152
153     cp = get_mtsuserconf_pathname();
154     if (cp != NULL &&
155             ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
156         mts_read_conf_file(fp);
157         fclose (fp);
158     }
159
160     Everyone = atoi (everyone);
161
162     if (strstr(masquerade, "draft_from") != NULL)
163         draft_from_masquerading = TRUE;
164
165     if (strstr(masquerade, "mmailid") != NULL)
166         mmailid_masquerading = TRUE;
167
168     if (strstr(masquerade, "username_extension") != NULL)
169         username_extension_masquerading = TRUE;
170
171 #ifdef SMTPMTS
172     if (strcmp(sm_method, "smtp") == 0)
173         sm_mts = MTS_SMTP;
174     else if (strcmp(sm_method, "sendmail") == 0)
175         sm_mts = MTS_SENDMAIL;
176     else {
177         advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
178         sm_mts = MTS_SMTP;
179     }
180 #endif
181 }
182
183
184 #define QUOTE   '\\'
185
186 /*
187  * Convert escaped values, malloc some new space,
188  * and copy string to malloc'ed memory.
189  */
190
191 static char *
192 tailor_value (unsigned char *s)
193 {
194     int i, r;
195     char *bp;
196     char buffer[BUFSIZ];
197     size_t len;
198
199     for (bp = buffer; *s; bp++, s++) {
200         if (*s != QUOTE) {
201             *bp = *s;
202         } else {
203             switch (*++s) {
204                 case 'b': *bp = '\b'; break;
205                 case 'f': *bp = '\f'; break;
206                 case 'n': *bp = '\n'; break;
207                 case 't': *bp = '\t'; break;
208
209                 case 0: s--;
210                 case QUOTE: 
211                     *bp = QUOTE;
212                     break;
213
214                 default: 
215                     if (!isdigit (*s)) {
216                         *bp++ = QUOTE;
217                         *bp = *s;
218                     }
219                     r = *s != '0' ? 10 : 8;
220                     for (i = 0; isdigit (*s); s++)
221                         i = i * r + *s - '0';
222                     s--;
223                     *bp = toascii (i);
224                     break;
225             }
226         }
227     }
228     *bp = 0;
229
230     len = strlen (buffer) + 1;
231     bp = mh_xmalloc (len);
232     memcpy (bp, buffer, len);
233
234     return bp;
235 }
236
237 /*
238  * Get the fully qualified name of the local host.
239  */
240
241 char *
242 LocalName (void)
243 {
244     static char buffer[BUFSIZ] = "";
245     struct addrinfo hints, *res;
246
247     /* check if we have cached the local name */
248     if (buffer[0])
249         return buffer;
250
251     mts_init ("mts");
252
253     /* check if the mts.conf file specifies a "localname" */
254     if (*localname) {
255         strncpy (buffer, localname, sizeof(buffer));
256     } else {
257         memset(buffer, 0, sizeof(buffer));
258         /* first get our local name */
259         gethostname (buffer, sizeof(buffer) - 1);
260         /* now fully qualify our name */
261
262         memset(&hints, 0, sizeof(hints));
263         hints.ai_flags = AI_CANONNAME;
264         hints.ai_family = PF_UNSPEC;
265         if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
266             strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
267             freeaddrinfo(res);
268         }
269     }
270
271     /*
272      * If the mts.conf file specifies a "localdomain",
273      * we append that now.  This should rarely be needed.
274      */
275     if (*localdomain) {
276         strcat (buffer, ".");
277         strcat (buffer, localdomain);
278     }
279
280     return buffer;
281 }
282
283
284 /*
285  * This is only for UUCP mail.  It gets the hostname
286  * as part of the UUCP "domain".
287  */
288
289 char *
290 SystemName (void)
291 {
292     static char buffer[BUFSIZ] = "";
293
294     /* check if we have cached the system name */
295     if (buffer[0])
296         return buffer;
297
298     mts_init ("mts");
299
300     /* check if mts.conf file specifies a "systemname" */
301     if (*systemname) {
302         strncpy (buffer, systemname, sizeof(buffer));
303         return buffer;
304     }
305
306     gethostname (buffer, sizeof(buffer));
307
308     return buffer;
309 }
310
311
312 /*
313  * Get the username of current user
314  */
315
316 char *
317 getusername (void)
318 {
319     if (username[0] == '\0')
320         getuserinfo();
321
322     return username;
323 }
324
325
326 /*
327  * Get full name of current user (typically from GECOS
328  * field of password file).
329  */
330
331 char *
332 getfullname (void)
333 {
334     if (username[0] == '\0')
335         getuserinfo();
336
337     return fullname;
338 }
339
340
341 /*
342  * Find the user's username and full name, and cache them.
343  * Also, handle "mmailid" username masquerading controlled from the GECOS field
344  * of the passwd file. 
345  */
346
347 static void
348 getuserinfo (void)
349 {
350     register unsigned char *cp;
351     register char *np;
352     register struct passwd *pw;
353
354     if ((pw = getpwuid (getuid ())) == NULL
355             || pw->pw_name == NULL
356             || *pw->pw_name == '\0') {
357         strncpy (username, "unknown", sizeof(username));
358         snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
359                 (int) getuid ());
360         return;
361     }
362
363     np = pw->pw_gecos;
364
365     /* Get the user's real name from the GECOS field.  Stop once we hit a ',',
366        which some OSes use to separate other 'finger' information in the GECOS
367        field, like phone number.  Also, if mmailid masquerading is turned on due
368        to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
369        hit a '<' (which should precede any ','s). */
370     if (mmailid_masquerading)
371         /* Stop at ',' or '<'. */
372         for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
373              *cp++ = *np++)
374             continue;
375     else
376         /* Allow '<' as a legal character of the user's name.  This code is
377            basically a duplicate of the code above the "else" -- we don't
378            collapse it down to one copy and put the mmailid_masquerading check
379            inside the loop with "(x ? y : z)" because that's inefficient and the
380            value'll never change while it's in there. */
381         for (cp = fullname; *np != '\0' && *np != ',';
382              *cp++ = *np++)
383             continue;
384     *cp = '\0';
385
386     if (mmailid_masquerading) {
387         /* Do mmailid processing.  The GECOS field should have the form
388            "Full Name <fakeusername>".  For instance,
389            "Dan Harkless <Dan.Harkless>".  Naturally, you'll want your MTA to
390            have an alias (e.g. in /etc/aliases) from "fakeusername" to your
391            account name.  */ 
392         if (*np)
393             np++;
394         for (cp = username; *np && *np != '>'; *cp++ = *np++)
395             continue;
396         *cp = '\0';
397     }
398     if (!mmailid_masquerading || *np == '\0')
399         strncpy (username, pw->pw_name, sizeof(username));
400
401     /* The $SIGNATURE environment variable overrides the GECOS field's idea of
402        your real name. */
403     if ((cp = getenv ("SIGNATURE")) && *cp)
404         strncpy (fullname, cp, sizeof(fullname));
405
406     if (strchr(fullname, '.')) {                /*  quote any .'s */
407         char tmp[BUFSIZ];
408
409         /* should quote "'s too */
410         snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
411         strncpy (fullname, tmp, sizeof(fullname));
412     }
413
414     return;
415 }
416
417 static const char*
418 get_mtsconf_pathname (void)
419 {
420     const char *cp = getenv ( "MHMTSCONF ");
421     if (cp != NULL && *cp != '\0') {
422         return cp;
423     }
424     return mtsconf;
425 }
426
427 static const char*
428 get_mtsuserconf_pathname (void)
429 {
430     const char *cp = getenv ( "MHMTSUSERCONF" );
431     if (cp != NULL && *cp != '\0') {
432         return cp;
433     }
434     return NULL;
435 }
436
437 static void
438 mts_read_conf_file (FILE *fp)
439 {
440     unsigned char *bp;
441     char *cp, buffer[BUFSIZ];
442     struct bind *b;
443
444     while (fgets (buffer, sizeof(buffer), fp)) {
445         if (!(cp = strchr(buffer, '\n')))
446             break;
447         *cp = 0;
448         if (*buffer == '#' || *buffer == '\0')
449             continue;
450         if (!(bp = strchr(buffer, ':')))
451             break;
452         *bp++ = 0;
453         while (isspace (*bp))
454             *bp++ = 0;
455
456         for (b = binds; b->keyword; b++)
457             if (!strcmp (buffer, b->keyword))
458                 break;
459         if (b->keyword && (cp = tailor_value (bp)))
460             *b->value = cp;
461     }
462 }