31
33
#include "presence.h"
38
#include <stringprep.h>
39
static char idn_buffer[1024];
43
static gboolean jabber_nodeprep(char *str, size_t buflen)
45
return stringprep_xmpp_nodeprep(str, buflen) == STRINGPREP_OK;
48
static gboolean jabber_resourceprep(char *str, size_t buflen)
50
return stringprep_xmpp_resourceprep(str, buflen) == STRINGPREP_OK;
54
jabber_idn_validate(const char *str, const char *at, const char *slash,
57
const char *node = NULL;
58
const char *domain = NULL;
59
const char *resource = NULL;
66
/* Ensure no parts are > 1023 bytes */
73
domain_len = slash - (at + 1);
75
resource_len = null - (slash + 1);
77
domain_len = null - (at + 1);
83
domain_len = slash - str;
85
resource_len = null - (slash + 1);
87
domain_len = null - (str + 1);
91
if (node && node_len > 1023)
93
if (domain_len > 1023)
95
if (resource && resource_len > 1023)
98
jid = g_new0(JabberID, 1);
101
strncpy(idn_buffer, node, node_len);
102
idn_buffer[node_len] = '\0';
104
if (!jabber_nodeprep(idn_buffer, sizeof(idn_buffer))) {
110
jid->node = g_strdup(idn_buffer);
113
/* domain *must* be here */
114
strncpy(idn_buffer, domain, domain_len);
115
idn_buffer[domain_len] = '\0';
116
if (domain[0] == '[') { /* IPv6 address */
117
gboolean valid = FALSE;
119
if (idn_buffer[domain_len - 1] == ']') {
120
idn_buffer[domain_len - 1] = '\0';
121
valid = purple_ipv6_address_is_valid(idn_buffer + 1);
131
if (stringprep_nameprep(idn_buffer, sizeof(idn_buffer)) != STRINGPREP_OK) {
137
/* And now ToASCII */
138
if (idna_to_ascii_8z(idn_buffer, &out, IDNA_USE_STD3_ASCII_RULES) != IDNA_SUCCESS) {
144
/* This *MUST* be freed using 'free', not 'g_free' */
146
jid->domain = g_strdup(idn_buffer);
150
strncpy(idn_buffer, resource, resource_len);
151
idn_buffer[resource_len] = '\0';
153
if (!jabber_resourceprep(idn_buffer, sizeof(idn_buffer))) {
159
jid->resource = g_strdup(idn_buffer);
34
168
gboolean jabber_nodeprep_validate(const char *str)
57
gboolean jabber_nameprep_validate(const char *str)
202
gboolean jabber_domain_validate(const char *str)
64
if(strlen(str) > 1023)
217
/* Check if str is a valid IPv6 identifier */
218
gboolean valid = FALSE;
220
if (*(c + len - 1) != ']')
223
/* Ugly, but in-place */
224
*(gchar *)(c + len - 1) = '\0';
225
valid = purple_ipv6_address_is_valid(c + 1);
226
*(gchar *)(c + len - 1) = ']';
69
232
gunichar ch = g_utf8_get_char(c);
70
if(!g_unichar_isgraph(ch))
233
/* The list of characters allowed in domain names is pretty small */
234
if ((ch <= 0x7F && !( (ch >= 'a' && ch <= 'z')
235
|| (ch >= '0' && ch <= '9')
236
|| (ch >= 'A' && ch <= 'Z')
238
|| ch == '-' )) || (ch >= 0x80 && !g_unichar_isgraph(ch)))
73
241
c = g_utf8_next_char(c);
80
247
gboolean jabber_resourceprep_validate(const char *str)
104
jabber_id_new(const char *str)
281
jabber_id_new_internal(const char *str, gboolean allow_terminating_slash)
283
const char *at = NULL;
284
const char *slash = NULL;
286
gboolean needs_validation = FALSE;
288
gboolean node_is_required = FALSE;
110
if(!str || !g_utf8_validate(str, -1, NULL))
299
for (c = str; *c != '\0'; c++)
305
/* Multiple @'s in the node/domain portion, not a valid JID! */
309
/* JIDs cannot start with @ */
313
/* JIDs cannot end with @ */
323
/* JIDs cannot start with / */
326
if (c[1] == '\0' && !allow_terminating_slash) {
327
/* JIDs cannot end with / */
335
/* characters allowed everywhere */
336
if ((*c >= 'a' && *c <= 'z')
337
|| (*c >= '0' && *c <= '9')
338
|| (*c >= 'A' && *c <= 'Z')
339
|| *c == '.' || *c == '-')
345
/* characters allowed only in the resource */
351
/* characters allowed only in the node */
354
* Ok, this character is valid, but only if it's a part
355
* of the node and not the domain. But we don't know
356
* if "c" is a part of the node or the domain until after
357
* we've found the @. So set a flag for now and check
358
* that we found an @ later.
360
node_is_required = TRUE;
366
* Hmm, this character is a bit more exotic. Better fall
367
* back to using the more expensive UTF-8 compliant
368
* stringprep functions.
370
needs_validation = TRUE;
376
if (node_is_required && at == NULL)
377
/* Found invalid characters in the domain */
381
if (!needs_validation) {
382
/* JID is made of only ASCII characters--just lowercase and return */
383
jid = g_new0(JabberID, 1);
386
jid->node = g_ascii_strdown(str, at - str);
388
jid->domain = g_ascii_strdown(at + 1, slash - (at + 1));
390
jid->resource = g_strdup(slash + 1);
392
jid->domain = g_ascii_strdown(at + 1, -1);
396
jid->domain = g_ascii_strdown(str, slash - str);
398
jid->resource = g_strdup(slash + 1);
400
jid->domain = g_ascii_strdown(str, -1);
407
* If we get here, there are some non-ASCII chars in the string, so
408
* we'll need to validate it, normalize, and finally do a full jabber
409
* nodeprep on the jid.
412
if (!g_utf8_validate(str, -1, NULL))
416
return jabber_idn_validate(str, at, slash, c /* points to the null */);
113
419
jid = g_new0(JabberID, 1);
115
at = g_utf8_strchr(str, -1, '@');
116
slash = g_utf8_strchr(str, -1, '/');
119
jid->node = g_utf8_normalize(str, at-str, G_NORMALIZE_NFKC);
423
node = g_utf8_casefold(str, at-str);
121
jid->domain = g_utf8_normalize(at+1, slash-(at+1), G_NORMALIZE_NFKC);
122
jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC);
425
domain = g_utf8_casefold(at+1, slash-(at+1));
427
jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC);
124
jid->domain = g_utf8_normalize(at+1, -1, G_NORMALIZE_NFKC);
429
domain = g_utf8_casefold(at+1, -1);
128
jid->domain = g_utf8_normalize(str, slash-str, G_NORMALIZE_NFKC);
129
jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC);
433
domain = g_utf8_casefold(str, slash-str);
435
jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC);
131
jid->domain = g_utf8_normalize(str, -1, G_NORMALIZE_NFKC);
437
domain = g_utf8_casefold(str, -1);
442
jid->node = g_utf8_normalize(node, -1, G_NORMALIZE_NFKC);
447
jid->domain = g_utf8_normalize(domain, -1, G_NORMALIZE_NFKC);
451
/* and finally the jabber nodeprep */
136
452
if(!jabber_nodeprep_validate(jid->node) ||
137
!jabber_nameprep_validate(jid->domain) ||
453
!jabber_domain_validate(jid->domain) ||
138
454
!jabber_resourceprep_validate(jid->resource)) {
139
455
jabber_id_free(jid);
175
char *jabber_get_bare_jid(const char *in)
493
jabber_get_bare_jid(const char *in)
177
495
JabberID *jid = jabber_id_new(in);
183
out = g_strdup_printf("%s%s%s", jid->node ? jid->node : "",
184
jid->node ? "@" : "", jid->domain);
500
out = jabber_id_get_bare_jid(jid);
185
501
jabber_id_free(jid);
507
jabber_id_get_bare_jid(const JabberID *jid)
509
g_return_val_if_fail(jid != NULL, NULL);
511
return g_strconcat(jid->node ? jid->node : "",
512
jid->node ? "@" : "",
518
jabber_id_new(const char *str)
520
return jabber_id_new_internal(str, FALSE);
190
523
const char *jabber_normalize(const PurpleAccount *account, const char *in)
192
525
PurpleConnection *gc = account ? account->gc : NULL;
193
526
JabberStream *js = gc ? gc->proto_data : NULL;
194
527
static char buf[3072]; /* maximum legal length of a jabber jid */
198
jid = jabber_id_new(in);
530
jid = jabber_id_new_internal(in, TRUE);
203
node = jid->node ? g_utf8_strdown(jid->node, -1) : NULL;
204
domain = g_utf8_strdown(jid->domain, -1);
207
if(js && node && jid->resource &&
208
jabber_chat_find(js, node, domain))
209
g_snprintf(buf, sizeof(buf), "%s@%s/%s", node, domain,
534
if(js && jid->node && jid->resource &&
535
jabber_chat_find(js, jid->node, jid->domain))
536
g_snprintf(buf, sizeof(buf), "%s@%s/%s", jid->node, jid->domain,
212
g_snprintf(buf, sizeof(buf), "%s%s%s", node ? node : "",
213
node ? "@" : "", domain);
539
g_snprintf(buf, sizeof(buf), "%s%s%s", jid->node ? jid->node : "",
540
jid->node ? "@" : "", jid->domain);
215
542
jabber_id_free(jid);
548
jabber_is_own_server(JabberStream *js, const char *str)
556
g_return_val_if_fail(*str != '\0', FALSE);
558
jid = jabber_id_new(str);
562
equal = (jid->node == NULL &&
563
g_str_equal(jid->domain, js->user->domain) &&
564
jid->resource == NULL);
570
jabber_is_own_account(JabberStream *js, const char *str)
578
g_return_val_if_fail(*str != '\0', FALSE);
580
jid = jabber_id_new(str);
584
equal = (purple_strequal(jid->node, js->user->node) &&
585
g_str_equal(jid->domain, js->user->domain) &&
586
(jid->resource == NULL ||
587
g_str_equal(jid->resource, js->user->resource)));
222
592
PurpleConversation *
223
593
jabber_find_unnormalized_conv(const char *name, PurpleAccount *account)