1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or
5  *  (at your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  *
16  *  Jabber
17  *  Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
18  */
19 
20 #include "jabber.h"
21 
jid_safe(jid id)22 jid jid_safe(jid id)
23 {
24     char *str;
25 
26     if(strlen(id->server) == 0 || strlen(id->server) > 255)
27 	return NULL;
28 
29     /* lowercase the hostname, make sure it's valid characters */
30     for(str = id->server; *str != '\0'; str++)
31     {
32 	*str = tolower(*str);
33 	if(!(isalnum(*str) || *str == '.' || *str == '-' || *str == '_')) return NULL;
34     }
35 
36     /* cut off the user */
37     if(id->user != NULL && strlen(id->user) > 64)
38 	id->user[64] = '\0';
39 
40     /* check for low and invalid ascii characters in the username */
41     if(id->user != NULL)
42 	for(str = id->user; *str != '\0'; str++)
43 	    if(*str <= 32 || *str == ':' || *str == '@' || *str == '<' || *str == '>' || *str == '\'' || *str == '"' || *str == '&') return NULL;
44 
45     return id;
46 }
47 
jid_new(pool p,char * idstr)48 jid jid_new(pool p, char *idstr)
49 {
50     char *server, *resource, *type, *str;
51     jid id;
52 
53     if(p == NULL || idstr == NULL || strlen(idstr) == 0)
54 	return NULL;
55 
56     /* user@server/resource */
57 
58     str = pstrdup(p, idstr);
59 
60     id = pmalloc(p,sizeof(struct jid_struct));
61     id->full = id->server = id->user = id->resource = NULL;
62     id->p = p;
63     id->next = NULL;
64 
65     resource = strstr(str,"/");
66     if(resource != NULL)
67     {
68 	*resource = '\0';
69 	++resource;
70 	if(strlen(resource) > 0)
71 	    id->resource = resource;
72     }else{
73 	resource = str + strlen(str); /* point to end */
74     }
75 
76     type = strstr(str,":");
77     if(type != NULL && type < resource)
78     {
79 	*type = '\0';
80 	++type;
81 	str = type; /* ignore the type: prefix */
82     }
83 
84     server = strstr(str,"@");
85     if(server == NULL || server > resource)
86     { /* if there's no @, it's just the server address */
87 	id->server = str;
88     }else{
89 	*server = '\0';
90 	++server;
91 	id->server = server;
92 	if(strlen(str) > 0)
93 	    id->user = str;
94     }
95 
96     return jid_safe(id);
97 }
98 
jid_set(jid id,char * str,int item)99 void jid_set(jid id, char *str, int item)
100 {
101     char *old;
102 
103     if(id == NULL)
104 	return;
105 
106     /* invalidate the cached copy */
107     id->full = NULL;
108 
109     switch(item)
110     {
111     case JID_RESOURCE:
112 	if(str != NULL && strlen(str) != 0)
113 	    id->resource = pstrdup(id->p, str);
114 	else
115 	    id->resource = NULL;
116 	break;
117     case JID_USER:
118 	old = id->user;
119 	if(str != NULL && strlen(str) != 0)
120 	    id->user = pstrdup(id->p, str);
121 	else
122 	    id->user = NULL;
123 	if(jid_safe(id) == NULL)
124 	    id->user = old; /* revert if invalid */
125 	break;
126     case JID_SERVER:
127 	old = id->server;
128 	id->server = pstrdup(id->p, str);
129 	if(jid_safe(id) == NULL)
130 	    id->server = old; /* revert if invalid */
131 	break;
132     }
133 
134 }
135 
jid_full(jid id)136 char *jid_full(jid id)
137 {
138     spool s;
139 
140     if(id == NULL)
141 	return NULL;
142 
143     /* use cached copy */
144     if(id->full != NULL)
145 	return id->full;
146 
147     s = spool_new(id->p);
148 
149     if(id->user != NULL)
150 	spooler(s, id->user,"@",s);
151 
152     spool_add(s, id->server);
153 
154     if(id->resource != NULL)
155 	spooler(s, "/",id->resource,s);
156 
157     id->full = spool_print(s);
158     return id->full;
159 }
160 
161 /* parses a /resource?name=value&foo=bar into an xmlnode representing <resource name="value" foo="bar"/> */
jid_xres(jid id)162 xmlnode jid_xres(jid id)
163 {
164     char *cur, *qmark, *amp, *eq;
165     xmlnode x;
166 
167     if(id == NULL || id->resource == NULL) return NULL;
168 
169     cur = pstrdup(id->p, id->resource);
170     qmark = strstr(cur, "?");
171     if(qmark == NULL) return NULL;
172     *qmark = '\0';
173     qmark++;
174 
175     x = _xmlnode_new(id->p, cur, NTYPE_TAG);
176 
177     cur = qmark;
178     while(cur != '\0')
179     {
180 	eq = strstr(cur, "=");
181 	if(eq == NULL) break;
182 	*eq = '\0';
183 	eq++;
184 
185 	amp = strstr(eq, "&");
186 	if(amp != NULL)
187 	{
188 	    *amp = '\0';
189 	    amp++;
190 	}
191 
192 	xmlnode_put_attrib(x,cur,eq);
193 
194 	if(amp != NULL)
195 	    cur = amp;
196 	else
197 	    break;
198     }
199 
200     return x;
201 }
202 
203 /* local utils */
_jid_nullstrcmp(char * a,char * b)204 int _jid_nullstrcmp(char *a, char *b)
205 {
206     if(a == NULL && b == NULL) return 0;
207     if(a == NULL || b == NULL) return -1;
208     return strcmp(a,b);
209 }
_jid_nullstrcasecmp(char * a,char * b)210 int _jid_nullstrcasecmp(char *a, char *b)
211 {
212     if(a == NULL && b == NULL) return 0;
213     if(a == NULL || b == NULL) return -1;
214     return strcasecmp(a,b);
215 }
216 
jid_cmp(jid a,jid b)217 int jid_cmp(jid a, jid b)
218 {
219     if(a == NULL || b == NULL)
220 	return -1;
221 
222     if(_jid_nullstrcmp(a->resource, b->resource) != 0) return -1;
223     if(_jid_nullstrcasecmp(a->user, b->user) != 0) return -1;
224     if(_jid_nullstrcmp(a->server, b->server) != 0) return -1;
225 
226     return 0;
227 }
228 
229 /* suggested by Anders Qvist <quest@valdez.netg.se> */
jid_cmpx(jid a,jid b,int parts)230 int jid_cmpx(jid a, jid b, int parts)
231 {
232     if(a == NULL || b == NULL)
233 	return -1;
234 
235     if(parts & JID_RESOURCE && _jid_nullstrcmp(a->resource, b->resource) != 0) return -1;
236     if(parts & JID_USER && _jid_nullstrcasecmp(a->user, b->user) != 0) return -1;
237     if(parts & JID_SERVER && _jid_nullstrcmp(a->server, b->server) != 0) return -1;
238 
239     return 0;
240 }
241 
242 /* makes a copy of b in a's pool, requires a valid a first! */
jid_append(jid a,jid b)243 jid jid_append(jid a, jid b)
244 {
245     jid next;
246 
247     if(a == NULL)
248 	return NULL;
249 
250     if(b == NULL)
251 	return a;
252 
253     next = a;
254     while(next != NULL)
255     {
256 	/* check for dups */
257 	if(jid_cmp(next,b) == 0)
258 	    break;
259 	if(next->next == NULL)
260 	    next->next = jid_new(a->p,jid_full(b));
261 	next = next->next;
262     }
263     return a;
264 }
265 
jid_nodescan(jid id,xmlnode x)266 xmlnode jid_nodescan(jid id, xmlnode x)
267 {
268     xmlnode cur;
269     pool p;
270     jid tmp;
271 
272     if(id == NULL || xmlnode_get_firstchild(x) == NULL) return NULL;
273 
274     p = pool_new();
275     for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur))
276     {
277 	if(xmlnode_get_type(cur) != NTYPE_TAG) continue;
278 
279 	tmp = jid_new(p,xmlnode_get_attrib(cur,"jid"));
280 	if(tmp == NULL) continue;
281 
282 	if(jid_cmp(tmp,id) == 0) break;
283     }
284     pool_free(p);
285 
286     return cur;
287 }
288