comparison libpurple/protocols/jabber/jutil.c @ 27590:a08e84032814

merge of '2348ff22f0ff3453774b8b25b36238465580c609' and 'e76f11543c2a4aa05bdf584f087cbe3439029661'
author Paul Aurich <paul@darkrain42.org>
date Sun, 12 Jul 2009 05:43:38 +0000
parents f1f901b3d6f2
children aac25c66a843
comparison
equal deleted inserted replaced
27104:048bcf41deef 27590:a08e84032814
52 } 52 }
53 53
54 return TRUE; 54 return TRUE;
55 } 55 }
56 56
57 gboolean jabber_nameprep_validate(const char *str) 57 gboolean jabber_domain_validate(const char *str)
58 { 58 {
59 const char *c; 59 const char *c;
60 size_t len;
60 61
61 if(!str) 62 if(!str)
62 return TRUE; 63 return TRUE;
63 64
64 if(strlen(str) > 1023) 65 len = strlen(str);
66 if (len > 1023)
65 return FALSE; 67 return FALSE;
66 68
67 c = str; 69 c = str;
70
71 if (*c == '[') {
72 /* Check if str is a valid IPv6 identifier */
73 gboolean valid = FALSE;
74
75 if (*(c + len - 1) != ']')
76 return FALSE;
77
78 /* Ugly, but in-place */
79 *(gchar *)(c + len - 1) = '\0';
80 valid = purple_ipv6_address_is_valid(c + 1);
81 *(gchar *)(c + len - 1) = ']';
82
83 return valid;
84 }
85
68 while(c && *c) { 86 while(c && *c) {
69 gunichar ch = g_utf8_get_char(c); 87 gunichar ch = g_utf8_get_char(c);
70 if(!g_unichar_isgraph(ch)) 88 /* The list of characters allowed in domain names is pretty small */
89 if ((ch <= 0x7F && !( (ch >= 'a' && ch <= 'z')
90 || (ch >= '0' && ch <= '9')
91 || (ch >= 'A' && ch <= 'Z')
92 || ch == '.'
93 || ch == '-' )) || (ch >= 0x80 && !g_unichar_isgraph(ch)))
71 return FALSE; 94 return FALSE;
72 95
73 c = g_utf8_next_char(c); 96 c = g_utf8_next_char(c);
74 } 97 }
75
76 98
77 return TRUE; 99 return TRUE;
78 } 100 }
79 101
80 gboolean jabber_resourceprep_validate(const char *str) 102 gboolean jabber_resourceprep_validate(const char *str)
101 123
102 124
103 JabberID* 125 JabberID*
104 jabber_id_new(const char *str) 126 jabber_id_new(const char *str)
105 { 127 {
106 char *at; 128 const char *at = NULL;
107 char *slash; 129 const char *slash = NULL;
130 const char *c;
131 gboolean needs_validation = FALSE;
132 #if 0
133 gboolean node_is_required = FALSE;
134 #endif
108 char *node = NULL; 135 char *node = NULL;
109 char *domain; 136 char *domain;
110 JabberID *jid; 137 JabberID *jid;
111 138
112 if(!str || !g_utf8_validate(str, -1, NULL)) 139 if (!str)
140 return NULL;
141
142 for (c = str; *c != '\0'; c++)
143 {
144 switch (*c) {
145 case '@':
146 if (!slash) {
147 if (at) {
148 /* Multiple @'s in the node/domain portion, not a valid JID! */
149 return NULL;
150 }
151 if (c == str) {
152 /* JIDs cannot start with @ */
153 return NULL;
154 }
155 if (c[1] == '\0') {
156 /* JIDs cannot end with @ */
157 return NULL;
158 }
159 at = c;
160 }
161 break;
162
163 case '/':
164 if (!slash) {
165 if (c == str) {
166 /* JIDs cannot start with / */
167 return NULL;
168 }
169 if (c[1] == '\0') {
170 /* JIDs cannot end with / */
171 return NULL;
172 }
173 slash = c;
174 }
175 break;
176
177 default:
178 /* characters allowed everywhere */
179 if ((*c >= 'a' && *c <= 'z')
180 || (*c >= '0' && *c <= '9')
181 || (*c >= 'A' && *c <= 'Z')
182 || *c == '.' || *c == '-')
183 /* We're good */
184 break;
185
186 #if 0
187 if (slash != NULL) {
188 /* characters allowed only in the resource */
189 if (implement_me)
190 /* We're good */
191 break;
192 }
193
194 /* characters allowed only in the node */
195 if (implement_me) {
196 /*
197 * Ok, this character is valid, but only if it's a part
198 * of the node and not the domain. But we don't know
199 * if "c" is a part of the node or the domain until after
200 * we've found the @. So set a flag for now and check
201 * that we found an @ later.
202 */
203 node_is_required = TRUE;
204 break;
205 }
206 #endif
207
208 /*
209 * Hmm, this character is a bit more exotic. Better fall
210 * back to using the more expensive UTF-8 compliant
211 * stringprep functions.
212 */
213 needs_validation = TRUE;
214 break;
215 }
216 }
217
218 #if 0
219 if (node_is_required && at == NULL)
220 /* Found invalid characters in the domain */
221 return NULL;
222 #endif
223
224 if (!needs_validation) {
225 /* JID is made of only ASCII characters--just lowercase and return */
226 jid = g_new0(JabberID, 1);
227
228 if (at) {
229 jid->node = g_ascii_strdown(str, at - str);
230 if (slash) {
231 jid->domain = g_ascii_strdown(at + 1, slash - (at + 1));
232 jid->resource = g_strdup(slash + 1);
233 } else {
234 jid->domain = g_ascii_strdown(at + 1, -1);
235 }
236 } else {
237 if (slash) {
238 jid->domain = g_ascii_strdown(str, slash - str);
239 jid->resource = g_strdup(slash + 1);
240 } else {
241 jid->domain = g_ascii_strdown(str, -1);
242 }
243 }
244 return jid;
245 }
246
247 /*
248 * If we get here, there are some non-ASCII chars in the string, so
249 * we'll need to validate it, normalize, and finally do a full jabber
250 * nodeprep on the jid.
251 */
252
253 if (!g_utf8_validate(str, -1, NULL))
113 return NULL; 254 return NULL;
114 255
115 jid = g_new0(JabberID, 1); 256 jid = g_new0(JabberID, 1);
116 257
117 at = g_utf8_strchr(str, -1, '@'); 258 /* normalization */
118 slash = g_utf8_strchr(str, -1, '/');
119
120 if(at) { 259 if(at) {
121 node = g_utf8_normalize(str, at-str, G_NORMALIZE_NFKC); 260 node = g_utf8_normalize(str, at-str, G_NORMALIZE_NFKC);
122 if(slash) { 261 if(slash) {
123 domain = g_utf8_normalize(at+1, slash-(at+1), G_NORMALIZE_NFKC); 262 domain = g_utf8_normalize(at+1, slash-(at+1), G_NORMALIZE_NFKC);
124 jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC); 263 jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC);
142 if (domain) { 281 if (domain) {
143 jid->domain = g_utf8_strdown(domain, -1); 282 jid->domain = g_utf8_strdown(domain, -1);
144 g_free(domain); 283 g_free(domain);
145 } 284 }
146 285
286 /* and finally the jabber nodeprep */
147 if(!jabber_nodeprep_validate(jid->node) || 287 if(!jabber_nodeprep_validate(jid->node) ||
148 !jabber_nameprep_validate(jid->domain) || 288 !jabber_domain_validate(jid->domain) ||
149 !jabber_resourceprep_validate(jid->resource)) { 289 !jabber_resourceprep_validate(jid->resource)) {
150 jabber_id_free(jid); 290 jabber_id_free(jid);
151 return NULL; 291 return NULL;
152 } 292 }
153 293