Remove all masquerade support (draft_from is now the default, and the other
[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, fullname, and mailbox of the user */
58 static char username[BUFSIZ];
59 static char fullname[BUFSIZ];
60 static char localmbox[BUFSIZ];
61
62 /*
63  * MTS specific variables
64  */
65 static char *sm_method = "smtp";
66 int  sm_mts    = MTS_SMTP;
67 char *hostable = nmhetcdir(/hosts);
68 char *sendmail = SENDMAILPATH;
69
70 /*
71  * SMTP/POP stuff
72  */
73 char *clientname = NULL;
74 char *servers    = "localhost";
75 char *pophost    = "";
76
77 /*
78  * Global MailDelivery file
79  */
80 char *maildelivery = nmhetcdir(/maildelivery);
81
82
83 /*
84  * Aliasing Facility (doesn't belong here)
85  */
86 int Everyone = NOTOK;
87 static char *everyone = "-1";
88 char *NoShell = "";
89
90 /*
91  * Customize the MTS settings for nmh by adjusting
92  * the file mts.conf in the nmh etc directory.
93  */
94
95 struct bind {
96     char *keyword;
97     char **value;
98 };
99
100 static struct bind binds[] = {
101     { "localname", &localname },
102     { "localdomain", &localdomain },
103     { "systemname", &systemname },
104     { "mmdfldir", &mmdfldir },
105     { "mmdflfil", &mmdflfil },
106     { "uucpldir", &uucpldir },
107     { "uucplfil", &uucplfil },
108     { "mmdelim1", &mmdlm1 },
109     { "mmdelim2", &mmdlm2 },
110     { "mts",      &sm_method },
111     { "hostable", &hostable  },
112     { "sendmail", &sendmail  },
113     { "clientname",  &clientname },
114     { "servers", &servers },
115     { "pophost", &pophost },
116
117     { "maildelivery", &maildelivery },
118     { "everyone", &everyone },
119     { "noshell", &NoShell },
120     { NULL, NULL }
121 };
122
123
124 /*
125  * Read the configuration file for the nmh interface
126  * to the mail transport system (MTS).
127  */
128
129 void
130 mts_init (char *name)
131 {
132     NMH_UNUSED (name);
133
134     const char *cp;
135     FILE *fp;
136     static int inited = 0;
137
138     if (inited++ || (fp = fopen (get_mtsconf_pathname(), "r")) == NULL)
139         return;
140     mts_read_conf_file(fp);
141     fclose (fp);
142
143     cp = get_mtsuserconf_pathname();
144     if (cp != NULL &&
145             ((fp = fopen (get_mtsuserconf_pathname(), "r")) != NULL)) {
146         mts_read_conf_file(fp);
147         fclose (fp);
148     }
149
150     Everyone = atoi (everyone);
151
152     if (strcmp(sm_method, "smtp") == 0)
153         sm_mts = MTS_SMTP;
154     else if (strcmp(sm_method, "sendmail") == 0)
155         sm_mts = MTS_SENDMAIL;
156     else {
157         advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
158         sm_mts = MTS_SMTP;
159     }
160 }
161
162
163 #define QUOTE   '\\'
164
165 /*
166  * Convert escaped values, malloc some new space,
167  * and copy string to malloc'ed memory.
168  */
169
170 static char *
171 tailor_value (unsigned char *s)
172 {
173     int i, r;
174     char *bp;
175     char buffer[BUFSIZ];
176     size_t len;
177
178     for (bp = buffer; *s; bp++, s++) {
179         if (*s != QUOTE) {
180             *bp = *s;
181         } else {
182             switch (*++s) {
183                 case 'b': *bp = '\b'; break;
184                 case 'f': *bp = '\f'; break;
185                 case 'n': *bp = '\n'; break;
186                 case 't': *bp = '\t'; break;
187
188                 case 0: s--;
189                 case QUOTE: 
190                     *bp = QUOTE;
191                     break;
192
193                 default: 
194                     if (!isdigit (*s)) {
195                         *bp++ = QUOTE;
196                         *bp = *s;
197                     }
198                     r = *s != '0' ? 10 : 8;
199                     for (i = 0; isdigit (*s); s++)
200                         i = i * r + *s - '0';
201                     s--;
202                     *bp = toascii (i);
203                     break;
204             }
205         }
206     }
207     *bp = 0;
208
209     len = strlen (buffer) + 1;
210     bp = mh_xmalloc (len);
211     memcpy (bp, buffer, len);
212
213     return bp;
214 }
215
216 /*
217  * Get the fully qualified name of the local host.
218  *
219  * If flag is 0, then use anything out of mts.conf (like localname).
220  * If flag is 1, then only use the "proper" local hostname.
221  */
222
223 char *
224 LocalName (int flag)
225 {
226     static char buffer0[BUFSIZ] = "";
227     static char buffer1[BUFSIZ] = "";
228     static char *buffer[] = { buffer0, buffer1 };
229     char *buf;
230     struct addrinfo hints, *res;
231
232     if (flag < 0 || flag > 1)
233         return NULL;
234
235     buf = buffer[flag];
236
237     /* check if we have cached the local name */
238     if (buf[0])
239         return buf;
240
241     mts_init ("mts");
242
243     /* check if the mts.conf file specifies a "localname" */
244     if (*localname && flag == 0) {
245         strncpy (buf, localname, sizeof(buffer0));
246     } else {
247         memset(buf, 0, sizeof(buffer0));
248         /* first get our local name */
249         gethostname (buf, sizeof(buffer0) - 1);
250         /* now fully qualify our name */
251
252         memset(&hints, 0, sizeof(hints));
253         hints.ai_flags = AI_CANONNAME;
254         hints.ai_family = PF_UNSPEC;
255         if (getaddrinfo(buf, NULL, &hints, &res) == 0) {
256             strncpy(buf, res->ai_canonname, sizeof(buffer0) - 1);
257             freeaddrinfo(res);
258         }
259     }
260
261     /*
262      * If the mts.conf file specifies a "localdomain",
263      * we append that now.  This should rarely be needed.
264      */
265     if (*localdomain) {
266         strcat (buf, ".");
267         strcat (buf, localdomain);
268     }
269
270     return buf;
271 }
272
273
274 /*
275  * This is only for UUCP mail.  It gets the hostname
276  * as part of the UUCP "domain".
277  */
278
279 char *
280 SystemName (void)
281 {
282     static char buffer[BUFSIZ] = "";
283
284     /* check if we have cached the system name */
285     if (buffer[0])
286         return buffer;
287
288     mts_init ("mts");
289
290     /* check if mts.conf file specifies a "systemname" */
291     if (*systemname) {
292         strncpy (buffer, systemname, sizeof(buffer));
293         return buffer;
294     }
295
296     gethostname (buffer, sizeof(buffer));
297
298     return buffer;
299 }
300
301
302 /*
303  * Get the username of current user
304  */
305
306 char *
307 getusername (void)
308 {
309     if (username[0] == '\0')
310         getuserinfo();
311
312     return username;
313 }
314
315
316 /*
317  * Get full name of current user (typically from GECOS
318  * field of password file).
319  */
320
321 char *
322 getfullname (void)
323 {
324     if (username[0] == '\0')
325         getuserinfo();
326
327     return fullname;
328 }
329
330
331 /*
332  * Get the full local mailbox name.  This is in the form:
333  *
334  * User Name <user@name.com>
335  */
336
337 char *
338 getlocalmbox (void)
339 {
340     if (username[0] == '\0')
341         getuserinfo();
342
343     if (localmbox[0] == '\0') {
344         char *cp;
345
346         if ((cp = context_find("Local-Mailbox")) != NULL) {
347             strncpy(localmbox, cp, sizeof(localmbox));
348         } else {
349             snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname,
350                      username, LocalName(0));
351         }
352
353         localmbox[sizeof(localmbox) - 1] = '\0';
354     }
355
356     return localmbox;
357 }
358
359 /*
360  * Find the user's username and full name, and cache them.
361  */
362
363 static void
364 getuserinfo (void)
365 {
366     register unsigned char *cp;
367     register char *np;
368     register struct passwd *pw;
369
370     if ((pw = getpwuid (getuid ())) == NULL
371             || pw->pw_name == NULL
372             || *pw->pw_name == '\0') {
373         strncpy (username, "unknown", sizeof(username));
374         snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
375                 (int) getuid ());
376         return;
377     }
378
379     np = pw->pw_gecos;
380
381     /* Get the user's real name from the GECOS field.  Stop once we hit a ',',
382        which some OSes use to separate other 'finger' information in the GECOS
383        field, like phone number. */
384     for (cp = fullname; *np != '\0' && *np != ','; *cp++ = *np++)
385         continue;
386     *cp = '\0';
387
388     strncpy (username, pw->pw_name, sizeof(username));
389
390     /* The $SIGNATURE environment variable overrides the GECOS field's idea of
391        your real name. If SIGNATURE isn't set, use the Signature profile
392        setting if it exists. */
393     if ((cp = getenv ("SIGNATURE")) && *cp)
394         strncpy (fullname, cp, sizeof(fullname));
395     else if ((cp = context_find("Signature")))
396         strncpy (fullname, cp, sizeof(fullname));
397
398     if (strchr(fullname, '.')) {                /*  quote any .'s */
399         char tmp[BUFSIZ];
400
401         /* should quote "'s too */
402         snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
403         strncpy (fullname, tmp, sizeof(fullname));
404     }
405
406     fullname[sizeof(fullname) - 1] = '\0';
407
408     localmbox[0] = '\0';
409
410     return;
411 }
412
413 static const char*
414 get_mtsconf_pathname (void)
415 {
416     const char *cp = getenv ( "MHMTSCONF" );
417     if (cp != NULL && *cp != '\0') {
418         return cp;
419     }
420     return mtsconf;
421 }
422
423 static const char*
424 get_mtsuserconf_pathname (void)
425 {
426     const char *cp = getenv ( "MHMTSUSERCONF" );
427     if (cp != NULL && *cp != '\0') {
428         return cp;
429     }
430     return NULL;
431 }
432
433 static void
434 mts_read_conf_file (FILE *fp)
435 {
436     unsigned char *bp;
437     char *cp, buffer[BUFSIZ];
438     struct bind *b;
439
440     while (fgets (buffer, sizeof(buffer), fp)) {
441         if (!(cp = strchr(buffer, '\n')))
442             break;
443         *cp = 0;
444         if (*buffer == '#' || *buffer == '\0')
445             continue;
446         if (!(bp = strchr(buffer, ':')))
447             break;
448         *bp++ = 0;
449         while (isspace (*bp))
450             *bp++ = 0;
451
452         for (b = binds; b->keyword; b++)
453             if (!strcmp (buffer, b->keyword))
454                 break;
455         if (b->keyword && (cp = tailor_value (bp)))
456             *b->value = cp;
457     }
458 }