Removed mmailid masquerading.
[mmh] / sbr / mts.c
1 /*
2 ** mts.c -- definitions for the mail transport system
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>   /* for snprintf() */
10 #include <h/nmh.h>
11 #include <h/utils.h>
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <h/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 /*
26 ** static prototypes
27 */
28 static char *tailor_value(unsigned char *);
29 static void getuserinfo(void);
30 static const char *get_mtsconf_pathname(void);
31 static const char *get_mtsuserconf_pathname(void);
32 static void mts_read_conf_file(FILE *fp);
33
34 /*
35 ** nmh mail transport interface customization file
36 */
37 static char *mtsconf = NMHETCDIR"/mts.conf";
38
39
40 /* Cache the username and fullname of the user */
41 static char username[BUFSIZ];
42 static char fullname[BUFSIZ];
43
44 /* Variables for username masquerading: */
45 boolean  draft_from_masquerading = FALSE;
46 boolean  username_extension_masquerading = FALSE;  /* " from addrsbr.c */
47 static char* masquerade = "";
48
49 /*
50 ** Global MailDelivery file
51 */
52 char *maildelivery = NMHETCDIR"/maildelivery";
53
54 /*
55 ** Customize the MTS settings for nmh by adjusting
56 ** the file mts.conf in the nmh etc directory.
57 */
58
59 struct bind {
60         char *keyword;
61         char **value;
62 };
63
64 static struct bind binds[] = {
65         { "masquerade", &masquerade },
66         { "maildelivery", &maildelivery },
67         { NULL, NULL }
68 };
69
70
71 /*
72 ** Read the configuration file for the nmh interface
73 ** to the mail transport system (MTS).
74 */
75
76 void
77 mts_init(char *name)
78 {
79         const char *cp;
80         FILE *fp;
81         static int inited = 0;
82
83         if (inited++ || (fp = fopen(get_mtsconf_pathname(), "r")) == NULL)
84                 return;
85         mts_read_conf_file(fp);
86         fclose(fp);
87
88         cp = get_mtsuserconf_pathname();
89         if (cp != NULL &&
90                 ((fp = fopen(get_mtsuserconf_pathname(), "r")) != NULL)) {
91                 mts_read_conf_file(fp);
92                 fclose(fp);
93         }
94
95         if (strstr(masquerade, "draft_from") != NULL)
96                 draft_from_masquerading = TRUE;
97
98         if (strstr(masquerade, "username_extension") != NULL)
99                 username_extension_masquerading = TRUE;
100 }
101
102
103 #define QUOTE  '\\'
104
105 /*
106 ** Convert escaped values, malloc some new space,
107 ** and copy string to malloc'ed memory.
108 */
109
110 static char *
111 tailor_value(unsigned char *s)
112 {
113         int i, r;
114         char *bp;
115         char buffer[BUFSIZ];
116         size_t len;
117
118         for (bp = buffer; *s; bp++, s++) {
119                 if (*s != QUOTE) {
120                         *bp = *s;
121                 } else {
122                         switch (*++s) {
123                         case 'b': *bp = '\b'; break;
124                         case 'f': *bp = '\f'; break;
125                         case 'n': *bp = '\n'; break;
126                         case 't': *bp = '\t'; break;
127
128                         case 0: s--;
129                         case QUOTE:
130                                 *bp = QUOTE;
131                                 break;
132
133                         default:
134                                 if (!isdigit(*s)) {
135                                         *bp++ = QUOTE;
136                                         *bp = *s;
137                                 }
138                                 r = *s != '0' ? 10 : 8;
139                                 for (i = 0; isdigit(*s); s++)
140                                         i = i * r + *s - '0';
141                                 s--;
142                                 *bp = toascii(i);
143                                 break;
144                         }
145                 }
146         }
147         *bp = 0;
148
149         len = strlen(buffer) + 1;
150         bp = mh_xmalloc(len);
151         memcpy(bp, buffer, len);
152
153         return bp;
154 }
155
156 /*
157 ** Get the fully qualified name of the local host.
158 */
159
160 char *
161 LocalName(void)
162 {
163         static char buffer[BUFSIZ] = "";
164         struct addrinfo hints, *res;
165 #ifdef HAVE_UNAME
166         struct utsname name;
167 #endif
168
169         /* check if we have cached the local name */
170         if (buffer[0])
171                 return buffer;
172
173         mts_init("mts");
174
175         memset(buffer, 0, sizeof(buffer));
176 #ifdef HAVE_UNAME
177         /* first get our local name */
178         uname(&name);
179         strncpy(buffer, name.nodename, sizeof(buffer) - 1);
180 #else
181         /* first get our local name */
182         gethostname(buffer, sizeof(buffer) - 1);
183 #endif
184         /* now fully qualify our name */
185
186         memset(&hints, 0, sizeof(hints));
187         hints.ai_flags = AI_CANONNAME;
188         hints.ai_family = PF_UNSPEC;
189         if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
190                 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
191                 freeaddrinfo(res);
192         }
193
194         return buffer;
195 }
196
197
198 /*
199 ** This is only for UUCP mail.  It gets the hostname
200 ** as part of the UUCP "domain".
201 */
202
203 char *
204 SystemName(void)
205 {
206         static char buffer[BUFSIZ] = "";
207
208 #ifdef HAVE_UNAME
209         struct utsname name;
210 #endif
211
212         /* check if we have cached the system name */
213         if (buffer[0])
214                 return buffer;
215
216         mts_init("mts");
217
218 #ifdef HAVE_UNAME
219         uname(&name);
220         strncpy(buffer, name.nodename, sizeof(buffer));
221 #else
222         gethostname(buffer, sizeof(buffer));
223 #endif
224
225         return buffer;
226 }
227
228
229 /*
230 ** Get the username of current user
231 */
232
233 char *
234 getusername(void)
235 {
236         if (username[0] == '\0')
237                 getuserinfo();
238
239         return username;
240 }
241
242
243 /*
244 ** Get full name of current user (typically from GECOS
245 ** field of password file).
246 */
247
248 char *
249 getfullname(void)
250 {
251         if (username[0] == '\0')
252                 getuserinfo();
253
254         return fullname;
255 }
256
257
258 /*
259 ** Find the user's username and full name, and cache them.
260 */
261 static void
262 getuserinfo(void)
263 {
264         register unsigned char *cp;
265         register char *np;
266         register struct passwd *pw;
267
268         if ((pw = getpwuid(getuid())) == NULL
269                 || pw->pw_name == NULL
270                 || *pw->pw_name == '\0') {
271                 strncpy(username, "unknown", sizeof(username));
272                 snprintf(fullname, sizeof(fullname), "The Unknown User-ID (%d)",
273                         (int) getuid());
274                 return;
275         }
276
277         np = pw->pw_gecos;
278
279         /*
280         ** Get the user's real name from the GECOS field.  Stop once
281         ** we hit a ',', which some OSes use to separate other 'finger'
282         ** information in the GECOS field, like phone number.
283         */
284         for (cp = fullname; *np != '\0' && *np != ',';) {
285 #ifndef BSD42
286                 *cp++ = *np++;
287 #else /* BSD42 */
288                 /*
289                 ** On BSD(-derived) systems, the system utilities that
290                 ** deal with the GECOS field (finger, mail, sendmail,
291                 ** etc.) translate any '&' character in it to the login name,
292                 ** with the first letter capitalized.  So, for instance,
293                 ** fingering a user "bob" with the GECOS field "& Jones"
294                 ** would reveal him to be "In real life: Bob Jones".
295                 ** Surprisingly, though, the OS doesn't do the translation
296                 ** for you, so we have to do it manually here.
297                 */
298                 if (*np == '&') {  /* blech! */
299                         strcpy(cp, pw->pw_name);
300                         *cp = toupper(*cp);
301                         while (*cp)
302                                 cp++;
303                         np++;
304                 } else {
305                         *cp++ = *np++;
306                 }
307 #endif /* BSD42 */
308         }
309         *cp = '\0';
310         strncpy(username, pw->pw_name, sizeof(username));
311
312         /*
313         ** The $SIGNATURE environment variable overrides the GECOS field's
314         ** idea of your real name.
315         */
316         if ((cp = getenv("SIGNATURE")) && *cp)
317                 strncpy(fullname, cp, sizeof(fullname));
318
319         if (strchr(fullname, '.')) {  /*  quote any .'s */
320                 char tmp[BUFSIZ];
321
322                 /* should quote "'s too */
323                 snprintf(tmp, sizeof(tmp), "\"%s\"", fullname);
324                 strncpy(fullname, tmp, sizeof(fullname));
325         }
326
327         return;
328 }
329
330 static const char*
331 get_mtsconf_pathname(void)
332 {
333         const char *cp = getenv( "MHMTSCONF ");
334         if (cp != NULL && *cp != '\0') {
335                 return cp;
336         }
337         return mtsconf;
338 }
339
340 static const char*
341 get_mtsuserconf_pathname(void)
342 {
343         const char *cp = getenv( "MHMTSUSERCONF" );
344         if (cp != NULL && *cp != '\0') {
345                 return cp;
346         }
347         return NULL;
348 }
349
350 static void
351 mts_read_conf_file(FILE *fp)
352 {
353         unsigned char *bp;
354         char *cp, buffer[BUFSIZ];
355         struct bind *b;
356
357         while (fgets(buffer, sizeof(buffer), fp)) {
358                 if (!(cp = strchr(buffer, '\n')))
359                         break;
360                 *cp = 0;
361                 if (*buffer == '#' || *buffer == '\0')
362                         continue;
363                 if (!(bp = strchr(buffer, ':')))
364                         break;
365                 *bp++ = 0;
366                 while (isspace(*bp))
367                         *bp++ = 0;
368
369                 for (b = binds; b->keyword; b++)
370                         if (strcmp(buffer, b->keyword)==0)
371                                 break;
372                 if (b->keyword && (cp = tailor_value(bp)))
373                         *b->value = cp;
374         }
375 }