8881214d075b09379c06eb702b302e5c53050af0
[citadel.git] / citadel / internet_addressing.c
1 /*
2  * $Id$
3  *
4  * This file contains functions which handle the mapping of Internet addresses
5  * to users on the Citadel system.
6  */
7
8 #include "sysdep.h"
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <pwd.h>
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/wait.h>
19 #include <string.h>
20 #include <limits.h>
21 #include "citadel.h"
22 #include "server.h"
23 #include <time.h>
24 #include "sysdep_decls.h"
25 #include "citserver.h"
26 #include "support.h"
27 #include "config.h"
28 #include "tools.h"
29 #include "internet_addressing.h"
30 #include "user_ops.h"
31
32
33 /*
34  * Return 0 if a given string fuzzy-matches a Citadel user account
35  *
36  * FIX ... this needs to be updated to match any and all address syntaxes.
37  */
38 int fuzzy_match(struct usersupp *us, char *matchstring) {
39         int a;
40
41         for (a=0; a<strlen(us->fullname); ++a) {
42                 if (!strncasecmp(&us->fullname[a],
43                    matchstring, strlen(matchstring))) {
44                         return 0;
45                 }
46         }
47         return -1;
48 }
49
50
51
52
53 /*
54  * Split an RFC822-style address into userid, host, and full name
55  * (Originally from citmail.c, and unchanged so far)
56  *
57  */
58 void process_rfc822_addr(char *rfc822, char *user, char *node, char *name)
59 {
60         int a;
61
62         /* extract full name - first, it's From minus <userid> */
63         strcpy(name, rfc822);
64         for (a = 0; a < strlen(name); ++a) {
65                 if (name[a] == '<') {
66                         do {
67                                 strcpy(&name[a], &name[a + 1]);
68                         } while ((strlen(name) > 0) && (name[a] != '>'));
69                         strcpy(&name[a], &name[a + 1]);
70                 }
71         }
72         /* strip anything to the left of a bang */
73         while ((strlen(name) > 0) && (haschar(name, '!') > 0))
74                 strcpy(name, &name[1]);
75
76         /* and anything to the right of a @ or % */
77         for (a = 0; a < strlen(name); ++a) {
78                 if (name[a] == '@')
79                         name[a] = 0;
80                 if (name[a] == '%')
81                         name[a] = 0;
82         }
83
84         /* but if there are parentheses, that changes the rules... */
85         if ((haschar(rfc822, '(') == 1) && (haschar(rfc822, ')') == 1)) {
86                 strcpy(name, rfc822);
87                 while ((strlen(name) > 0) && (name[0] != '(')) {
88                         strcpy(&name[0], &name[1]);
89                 }
90                 strcpy(&name[0], &name[1]);
91                 for (a = 0; a < strlen(name); ++a) {
92                         if (name[a] == ')') {
93                                 name[a] = 0;
94                         }
95                 }
96         }
97         /* but if there are a set of quotes, that supersedes everything */
98         if (haschar(rfc822, 34) == 2) {
99                 strcpy(name, rfc822);
100                 while ((strlen(name) > 0) && (name[0] != 34)) {
101                         strcpy(&name[0], &name[1]);
102                 }
103                 strcpy(&name[0], &name[1]);
104                 for (a = 0; a < strlen(name); ++a)
105                         if (name[a] == 34)
106                                 name[a] = 0;
107         }
108         /* extract user id */
109         strcpy(user, rfc822);
110
111         /* first get rid of anything in parens */
112         for (a = 0; a < strlen(user); ++a)
113                 if (user[a] == '(') {
114                         do {
115                                 strcpy(&user[a], &user[a + 1]);
116                         } while ((strlen(user) > 0) && (user[a] != ')'));
117                         strcpy(&user[a], &user[a + 1]);
118                 }
119         /* if there's a set of angle brackets, strip it down to that */
120         if ((haschar(user, '<') == 1) && (haschar(user, '>') == 1)) {
121                 while ((strlen(user) > 0) && (user[0] != '<')) {
122                         strcpy(&user[0], &user[1]);
123                 }
124                 strcpy(&user[0], &user[1]);
125                 for (a = 0; a < strlen(user); ++a)
126                         if (user[a] == '>')
127                                 user[a] = 0;
128         }
129         /* strip anything to the left of a bang */
130         while ((strlen(user) > 0) && (haschar(user, '!') > 0))
131                 strcpy(user, &user[1]);
132
133         /* and anything to the right of a @ or % */
134         for (a = 0; a < strlen(user); ++a) {
135                 if (user[a] == '@')
136                         user[a] = 0;
137                 if (user[a] == '%')
138                         user[a] = 0;
139         }
140
141
142         /* extract node name */
143         strcpy(node, rfc822);
144
145         /* first get rid of anything in parens */
146         for (a = 0; a < strlen(node); ++a)
147                 if (node[a] == '(') {
148                         do {
149                                 strcpy(&node[a], &node[a + 1]);
150                         } while ((strlen(node) > 0) && (node[a] != ')'));
151                         strcpy(&node[a], &node[a + 1]);
152                 }
153         /* if there's a set of angle brackets, strip it down to that */
154         if ((haschar(node, '<') == 1) && (haschar(node, '>') == 1)) {
155                 while ((strlen(node) > 0) && (node[0] != '<')) {
156                         strcpy(&node[0], &node[1]);
157                 }
158                 strcpy(&node[0], &node[1]);
159                 for (a = 0; a < strlen(node); ++a)
160                         if (node[a] == '>')
161                                 node[a] = 0;
162         }
163         /* strip anything to the left of a @ */
164         while ((strlen(node) > 0) && (haschar(node, '@') > 0))
165                 strcpy(node, &node[1]);
166
167         /* strip anything to the left of a % */
168         while ((strlen(node) > 0) && (haschar(node, '%') > 0))
169                 strcpy(node, &node[1]);
170
171         /* reduce multiple system bang paths to node!user */
172         while ((strlen(node) > 0) && (haschar(node, '!') > 1))
173                 strcpy(node, &node[1]);
174
175         /* now get rid of the user portion of a node!user string */
176         for (a = 0; a < strlen(node); ++a)
177                 if (node[a] == '!')
178                         node[a] = 0;
179
180         /* strip leading and trailing spaces in all strings */
181         striplt(user);
182         striplt(node);
183         striplt(name);
184 }
185
186
187
188 /*
189  * Back end for convert_internet_address()
190  * (Compares an internet name [buffer1] and stores in [buffer2] if found)
191  */
192 void try_name(struct usersupp *us) {
193         
194         if (!strncasecmp(CC->buffer1, "cit", 3))
195                 if (atol(&CC->buffer1[3]) == us->usernum)
196                         strcpy(CC->buffer2, us->fullname);
197
198         if (!collapsed_strcmp(CC->buffer1, us->fullname)) 
199                         strcpy(CC->buffer2, us->fullname);
200
201         if (us->uid != BBSUID)
202                 if (!strcasecmp(CC->buffer1, getpwuid(us->uid)->pw_name))
203                         strcpy(CC->buffer2, us->fullname);
204 }
205
206
207 /*
208  * Convert an Internet email address to a Citadel user/host combination
209  */
210 int convert_internet_address(char *destuser, char *desthost, char *source)
211 {
212         char user[256];
213         char node[256];
214         char name[256];
215
216         /* Split it up */
217         process_rfc822_addr(source, user, node, name);
218
219         /* Map the FQDN to a Citadel node name
220          * FIX ... we have to check for all known aliases for the local
221          *         system, and also handle gateway domains, etc. etc.
222          */
223         if (!strcasecmp(node, config.c_fqdn)) {
224                 strcpy(node, config.c_nodename);
225         }
226
227         /* Return an error condition if the node is not known.
228          * FIX ... make this work for non-local systems
229          */
230         if (strcasecmp(node, config.c_nodename)) {
231                 return(1);
232         }
233         
234         /* Now try to resolve the name
235          * FIX ... do the multiple-addresses thing
236          */
237         if (!strcasecmp(node, config.c_nodename)) {
238                 strcpy(destuser, user);
239                 strcpy(desthost, config.c_nodename);
240                 strcpy(CC->buffer1, user);
241                 strcpy(CC->buffer2, "");
242                 ForEachUser(try_name);
243                 if (strlen(CC->buffer2) == 0) return(2);
244                 strcpy(destuser, CC->buffer2);
245                 return(0);
246         }
247
248         return(3);      /* unknown error */
249 }