dd193bc4e53a30a59b6d7479fcb1a965a8c8c4c6
[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 <pwd.h>
15 #include <netdb.h>
16
17 #ifdef HAVE_SYS_UTSNAME_H
18 # include <sys/utsname.h>
19 #endif
20
21 #define NOTOK  (-1)
22 #define OK     0
23
24 /*
25 ** static prototypes
26 */
27 static void getuserinfo(void);
28
29 /* Cache the username and fullname of the user */
30 static char username[BUFSIZ];
31 static char fullname[BUFSIZ];
32
33
34 /*
35 ** Get the fully qualified name of the local host.
36 */
37 char *
38 LocalName(void)
39 {
40         static char buffer[BUFSIZ] = "";
41         struct addrinfo hints, *res;
42 #ifdef HAVE_UNAME
43         struct utsname name;
44 #endif
45
46         /* check if we have cached the local name */
47         if (buffer[0])
48                 return buffer;
49
50         memset(buffer, 0, sizeof(buffer));
51 #ifdef HAVE_UNAME
52         /* first get our local name */
53         uname(&name);
54         strncpy(buffer, name.nodename, sizeof(buffer) - 1);
55 #else
56         /* first get our local name */
57         gethostname(buffer, sizeof(buffer) - 1);
58 #endif
59         /* now fully qualify our name */
60
61         memset(&hints, 0, sizeof(hints));
62         hints.ai_flags = AI_CANONNAME;
63         hints.ai_family = PF_UNSPEC;
64         if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
65                 strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
66                 freeaddrinfo(res);
67         }
68
69         return buffer;
70 }
71
72
73 /*
74 ** This is only for UUCP mail.  It gets the hostname
75 ** as part of the UUCP "domain".
76 */
77 char *
78 SystemName(void)
79 {
80         static char buffer[BUFSIZ] = "";
81
82 #ifdef HAVE_UNAME
83         struct utsname name;
84 #endif
85
86         /* check if we have cached the system name */
87         if (buffer[0])
88                 return buffer;
89
90 #ifdef HAVE_UNAME
91         uname(&name);
92         strncpy(buffer, name.nodename, sizeof(buffer));
93 #else
94         gethostname(buffer, sizeof(buffer));
95 #endif
96
97         return buffer;
98 }
99
100
101 /*
102 ** Get the username of current user
103 */
104 char *
105 getusername(void)
106 {
107         if (username[0] == '\0')
108                 getuserinfo();
109
110         return username;
111 }
112
113
114 /*
115 ** Get full name of current user (typically from GECOS
116 ** field of password file).
117 */
118 char *
119 getfullname(void)
120 {
121         if (username[0] == '\0')
122                 getuserinfo();
123
124         return fullname;
125 }
126
127
128 /*
129 ** Find the user's username and full name, and cache them.
130 */
131 static void
132 getuserinfo(void)
133 {
134         unsigned char *cp;
135         char *np;
136         struct passwd *pw;
137         int needquotes = 0;
138         char tmp[BUFSIZ];
139         char *tp;
140
141         if (!(pw = getpwuid(getuid())) || !pw->pw_name || !*pw->pw_name) {
142                 strncpy(username, "unknown", sizeof(username));
143                 snprintf(fullname, sizeof(fullname),
144                                 "The Unknown User-ID (%d)", (int)getuid());
145                 return;
146         }
147
148         np = pw->pw_gecos;
149
150         /*
151         ** Get the user's real name from the GECOS field.  Stop once
152         ** we hit a ',', which some OSes use to separate other 'finger'
153         ** information in the GECOS field, like phone number.
154         */
155         for (cp = tmp; *np != '\0' && *np != ',';) {
156 #ifndef BSD42
157                 *cp++ = *np++;
158 #else /* BSD42 */
159                 /*
160                 ** On BSD(-derived) systems, the system utilities that
161                 ** deal with the GECOS field (finger, mail, sendmail,
162                 ** etc.) translate any '&' character in it to the login name,
163                 ** with the first letter capitalized.  So, for instance,
164                 ** fingering a user "bob" with the GECOS field "& Jones"
165                 ** would reveal him to be "In real life: Bob Jones".
166                 ** Surprisingly, though, the OS doesn't do the translation
167                 ** for you, so we have to do it manually here.
168                 */
169                 if (*np == '&') {  /* blech! */
170                         strcpy(cp, pw->pw_name);
171                         *cp = toupper(*cp);
172                         while (*cp)
173                                 cp++;
174                         np++;
175                 } else {
176                         *cp++ = *np++;
177                 }
178 #endif /* BSD42 */
179         }
180         *cp = '\0';
181         strncpy(username, pw->pw_name, sizeof(username));
182
183         /*
184         ** The $SIGNATURE environment variable overrides the GECOS field's
185         ** idea of your real name.
186         */
187         if ((cp = getenv("SIGNATURE")) && *cp)
188                 strncpy(tmp, cp, sizeof(tmp));
189
190         /* quote the fullname as needed */
191         needquotes = 0;
192         for (tp=tmp; *tp; tp++) {
193                 switch (*tp) {
194                 case '(': case ')': case '<': case '>': case '[': case ']':
195                 case ':': case ';': case '@': case '\\': case ',': case '.':
196                 case '"':  /* cf. RFC 5322 */
197                         break;  /* ... the switch */
198                 default:
199                         continue;  /* ... the loop */
200                 }
201                 /* we've found a special char */
202                 needquotes = 1;
203                 break;
204         }
205         cp=fullname;
206         if (needquotes) {
207                 *cp++ = '"';
208         }
209         for (tp=tmp; *tp; *cp++=*tp++) {
210                 if (*tp == '"') {
211                         *cp++ = '\\';  /* prepend backslash */
212                 }
213         }
214         if (needquotes) {
215                 *cp++ = '"';
216         }
217         *cp = '\0';
218
219         return;
220 }