From Mariusz Okrój and Sebastien Vincent via https://bugs.wireshark.org/bugzilla...
[obnox/wireshark/wip.git] / epan / dissectors / packet-xmpp-core.c
1 /* xmpp-core.c
2  * Wireshark's XMPP dissector.
3  *
4  * Copyright 2011, Mariusz Okroj <okrojmariusz[]gmail.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31
32 #include<stdio.h>
33 #include<string.h>
34 #include <glib.h>
35
36 #include <epan/packet.h>
37 #include <epan/proto.h>
38 #include <epan/tvbuff.h>
39 #include <epan/emem.h>
40 #include <epan/conversation.h>
41 #include <epan/strutil.h>
42 #include <epan/expert.h>
43
44 #include <epan/dissectors/packet-xml.h>
45
46 #include <packet-xmpp-utils.h>
47 #include <packet-xmpp.h>
48 #include <packet-xmpp-core.h>
49 #include <packet-xmpp-jingle.h>
50 #include <packet-xmpp-other.h>
51 #include <packet-xmpp-gtalk.h>
52 #include <packet-xmpp-conference.h>
53
54 #include <epan/strutil.h>
55
56 #include "epan/tvbparse.h"
57
58
59 void xmpp_auth(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet);
60 void xmpp_challenge_response_success(proto_tree *tree, tvbuff_t *tvb,
61     packet_info *pinfo, element_t *packet, gint hf, gint ett, const char *col_info);
62
63 void xmpp_iq(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet);
64
65 static void xmpp_error(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element);
66 static void xmpp_error_text(proto_tree *tree, tvbuff_t *tvb, element_t *element);
67
68 void xmpp_presence(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet);
69 static void xmpp_presence_status(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element);
70
71 void xmpp_message(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet);
72 static void xmpp_message_thread(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element);
73 static void xmpp_message_body(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element);
74 static void xmpp_message_subject(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element);
75
76 void xmpp_failure(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet);
77 static void xmpp_failure_text(proto_tree *tree, tvbuff_t *tvb, element_t *element);
78
79 static void xmpp_features_mechanisms(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet);
80
81 void
82 xmpp_iq(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
83 {
84     proto_item *xmpp_iq_item;
85     proto_tree *xmpp_iq_tree;
86
87     attr_t *attr_id, *attr_type;
88
89     attr_info attrs_info[] = {
90         {"xmlns", hf_xmpp_xmlns, FALSE, FALSE, NULL, NULL},
91         {"id", hf_xmpp_id, TRUE, TRUE, NULL, NULL},
92         {"type", hf_xmpp_type, TRUE, TRUE, NULL, NULL},
93         {"from", hf_xmpp_from, FALSE, TRUE, NULL, NULL},
94         {"to", hf_xmpp_to, FALSE, TRUE, NULL, NULL},
95         {"xml:lang", -1, FALSE, FALSE, NULL, NULL}
96     };
97
98     conversation_t *conversation = NULL;
99     xmpp_conv_info_t *xmpp_info = NULL;
100     xmpp_transaction_t *reqresp_trans = NULL;
101
102     elem_info elems_info [] = {
103         {NAME_AND_ATTR, name_attr_struct("query", "xmlns","http://jabber.org/protocol/disco#items"), xmpp_disco_items_query, ONE},
104         {NAME_AND_ATTR, name_attr_struct("query", "xmlns", "jabber:iq:roster"), xmpp_roster_query, ONE},
105         {NAME_AND_ATTR, name_attr_struct("query", "xmlns", "http://jabber.org/protocol/disco#info"), xmpp_disco_info_query, ONE},
106         {NAME_AND_ATTR, name_attr_struct("query", "xmlns", "http://jabber.org/protocol/bytestreams"), xmpp_bytestreams_query, ONE},
107         {NAME_AND_ATTR, name_attr_struct("query", "xmlns", "http://jabber.org/protocol/muc#owner"), xmpp_muc_owner_query, ONE},
108         {NAME_AND_ATTR, name_attr_struct("query", "xmlns", "http://jabber.org/protocol/muc#admin"), xmpp_muc_admin_query, ONE},
109         {NAME, "bind", xmpp_iq_bind, ONE},
110         {NAME_AND_ATTR, name_attr_struct("session", "xmlns", "urn:ietf:params:xml:ns:xmpp-session"), xmpp_session, ONE},
111         {NAME, "vCard", xmpp_vcard, ONE},
112         {NAME, "jingle", xmpp_jingle, ONE},
113         {NAME_AND_ATTR, name_attr_struct("services", "xmlns", "http://jabber.org/protocol/jinglenodes"), xmpp_jinglenodes_services, ONE},
114         {NAME_AND_ATTR, name_attr_struct("channel", "xmlns", "http://jabber.org/protocol/jinglenodes#channel"), xmpp_jinglenodes_channel, ONE},
115         {NAME_AND_ATTR, name_attr_struct("open", "xmlns", "http://jabber.org/protocol/ibb"), xmpp_ibb_open, ONE},
116         {NAME_AND_ATTR, name_attr_struct("close", "xmlns", "http://jabber.org/protocol/ibb"), xmpp_ibb_close, ONE},
117         {NAME_AND_ATTR, name_attr_struct("data", "xmlns", "http://jabber.org/protocol/ibb"), xmpp_ibb_data, ONE},
118         {NAME, "si", xmpp_si, ONE},
119         {NAME, "error", xmpp_error, ONE},
120         {NAME_AND_ATTR, name_attr_struct("session", "xmlns", "http://www.google.com/session"), xmpp_gtalk_session, ONE},
121         {NAME_AND_ATTR, name_attr_struct("query", "xmlns","google:jingleinfo"), xmpp_gtalk_jingleinfo_query, ONE},
122         {NAME_AND_ATTR, name_attr_struct("usersetting", "xmlns","google:setting"), xmpp_gtalk_usersetting, ONE},
123         {NAME_AND_ATTR, name_attr_struct("query", "xmlns","jabber:iq:last"), xmpp_last_query, ONE},
124         {NAME_AND_ATTR, name_attr_struct("query", "xmlns","jabber:iq:version"), xmpp_version_query, ONE},
125         {NAME_AND_ATTR, name_attr_struct("query", "xmlns","google:mail:notify"), xmpp_gtalk_mail_query, ONE},
126         {NAME, "mailbox", xmpp_gtalk_mail_mailbox, ONE},
127         {NAME, "new-mail", xmpp_gtalk_mail_new_mail, ONE},
128         {NAME_AND_ATTR, name_attr_struct("query", "xmlns","google:shared-status"), xmpp_gtalk_status_query, ONE},
129         {NAME, "conference-info", xmpp_conference_info, ONE},
130         {NAME_AND_ATTR, name_attr_struct("ping", "xmlns","urn:xmpp:ping"), xmpp_ping, ONE},
131         {NAME_AND_ATTR, name_attr_struct("inputevt", "xmlns","http://jitsi.org/protocol/inputevt"), xmpp_jitsi_inputevt, ONE},
132     };
133
134     attr_id = get_attr(packet, "id");
135     attr_type = get_attr(packet, "type");
136
137     conversation = find_or_create_conversation(pinfo);
138     xmpp_info = conversation_get_proto_data(conversation, proto_xmpp);
139
140     xmpp_iq_item = proto_tree_add_item(tree, hf_xmpp_iq, tvb, packet->offset, packet->length, ENC_LITTLE_ENDIAN);
141     xmpp_iq_tree = proto_item_add_subtree(xmpp_iq_item,ett_xmpp_iq);
142
143     display_attrs(xmpp_iq_tree, packet, pinfo, tvb, attrs_info,  array_length(attrs_info));
144
145
146     col_clear(pinfo->cinfo, COL_INFO);
147     col_add_fstr(pinfo->cinfo, COL_INFO, "IQ(%s) ", attr_type?attr_type->value:"");
148
149     display_elems(xmpp_iq_tree, packet, pinfo, tvb, elems_info, array_length(elems_info));
150
151     /*displays generated info such as req/resp tracking, jingle sid
152      * in each packet related to specified jingle session and IBB sid in packet related to it*/
153     if(xmpp_info && attr_id)
154     {
155         gchar *jingle_sid, *ibb_sid, *gtalk_sid;
156
157         jingle_sid = se_tree_lookup_string(xmpp_info->jingle_sessions, attr_id->value, EMEM_TREE_STRING_NOCASE);
158
159         if (jingle_sid) {
160             proto_item *it = proto_tree_add_string(tree, hf_xmpp_jingle_session, tvb, 0, 0, jingle_sid);
161             PROTO_ITEM_SET_GENERATED(it);
162         }
163
164         ibb_sid = se_tree_lookup_string(xmpp_info->ibb_sessions, attr_id->value, EMEM_TREE_STRING_NOCASE);
165
166         if (ibb_sid) {
167             proto_item *it = proto_tree_add_string(tree, hf_xmpp_ibb, tvb, 0, 0, ibb_sid);
168             PROTO_ITEM_SET_GENERATED(it);
169         }
170
171         gtalk_sid = se_tree_lookup_string(xmpp_info->gtalk_sessions, attr_id->value, EMEM_TREE_STRING_NOCASE);
172
173         if (gtalk_sid) {
174             proto_item *it = proto_tree_add_string(tree, hf_xmpp_gtalk, tvb, 0, 0, gtalk_sid);
175             PROTO_ITEM_SET_GENERATED(it);
176         }
177
178         reqresp_trans = se_tree_lookup_string(xmpp_info->req_resp, attr_id->value, EMEM_TREE_STRING_NOCASE);
179         /*displays request/response field in each iq packet*/
180         if (reqresp_trans) {
181
182             if (reqresp_trans->req_frame == pinfo->fd->num) {
183                 if (reqresp_trans->resp_frame) {
184                     proto_item *it = proto_tree_add_uint(tree, hf_xmpp_response_in, tvb, 0, 0, reqresp_trans->resp_frame);
185                     PROTO_ITEM_SET_GENERATED(it);
186                 } else
187                 {
188                     expert_add_info_format(pinfo, xmpp_iq_item , PI_PROTOCOL, PI_CHAT, "Packet without response");
189                 }
190
191             } else {
192                 if (reqresp_trans->req_frame) {
193                     proto_item *it = proto_tree_add_uint(tree, hf_xmpp_response_to, tvb, 0, 0, reqresp_trans->req_frame);
194                     PROTO_ITEM_SET_GENERATED(it);
195                 } else
196                 {
197                     expert_add_info_format(pinfo, xmpp_iq_item , PI_PROTOCOL, PI_CHAT, "Packet without response");
198                 }
199             }
200         }
201     }
202
203
204 }
205
206
207 static void
208 xmpp_error(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element)
209 {
210     proto_item *error_item;
211     proto_tree *error_tree;
212
213     element_t *text_element, *cond_element;
214
215     attr_info attrs_info[] = {
216         {"type", hf_xmpp_error_type, TRUE, TRUE, NULL, NULL},
217         {"code", hf_xmpp_error_code, FALSE, TRUE, NULL, NULL},
218         {"condition", hf_xmpp_error_condition, TRUE, TRUE, NULL, NULL} /*TODO: validate list to the condition element*/
219     };
220
221     gchar *error_info;
222
223     attr_t *fake_condition = NULL;
224
225     error_info = ep_strdup("Stanza error");
226
227     error_item = proto_tree_add_item(tree, hf_xmpp_error, tvb, element->offset, element->length, ENC_BIG_ENDIAN);
228     error_tree = proto_item_add_subtree(error_item, ett_xmpp_query_item);
229
230     cond_element = steal_element_by_attr(element, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
231     if(cond_element)
232     {
233         fake_condition = ep_init_attr_t(cond_element->name, cond_element->offset, cond_element->length);
234         g_hash_table_insert(element->attrs,"condition", fake_condition);
235
236         error_info = ep_strdup_printf("%s: %s;", error_info, cond_element->name);
237     }
238
239
240     display_attrs(error_tree, element, pinfo, tvb, attrs_info, array_length(attrs_info));
241
242     while((text_element = steal_element_by_name(element, "text")) != NULL)
243     {
244         xmpp_error_text(error_tree, tvb, text_element);
245
246         error_info = ep_strdup_printf("%s Text: %s", error_info, text_element->data?text_element->data->value:"");
247     }
248
249     expert_add_info_format(pinfo, error_item, PI_RESPONSE_CODE, PI_CHAT,"%s", error_info);
250
251     xmpp_unknown(error_tree, tvb, pinfo, element);
252 }
253
254 static void
255 xmpp_error_text(proto_tree *tree, tvbuff_t *tvb, element_t *element)
256 {
257     proto_tree_add_string(tree, hf_xmpp_error_text, tvb, element->offset, element->length, element->data?element->data->value:"");
258 }
259
260
261 void
262 xmpp_presence(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
263 {
264     proto_item *presence_item;
265     proto_tree *presence_tree;
266
267     const gchar *type_enums[] = {"error", "probe", "subscribe", "subscribed",
268         "unavailable", "unsubscribe", "unsubscribed"};
269     array_t *type_array = ep_init_array_t(type_enums, array_length(type_enums));
270
271     const gchar *show_enums[] = {"away", "chat", "dnd", "xa"};
272     array_t *show_array = ep_init_array_t(show_enums, array_length(show_enums));
273
274     attr_info attrs_info[] = {
275         {"from", hf_xmpp_from, FALSE, FALSE, NULL, NULL},
276         {"id", hf_xmpp_id, FALSE, TRUE, NULL, NULL},
277         {"to", hf_xmpp_to, FALSE, FALSE, NULL, NULL},
278         {"type", hf_xmpp_type, FALSE, TRUE, val_enum_list, type_array},
279         {"xml:lang",-1, FALSE, FALSE, NULL,NULL},
280         {"show", hf_xmpp_presence_show, FALSE, TRUE, val_enum_list, show_array},
281         {"priority", -1, FALSE, FALSE, NULL, NULL}
282     };
283
284     elem_info elems_info[] = {
285         {NAME, "status", xmpp_presence_status, MANY},
286         {NAME_AND_ATTR, name_attr_struct("c","xmlns","http://jabber.org/protocol/caps"), xmpp_presence_caps, ONE},
287         {NAME, "delay", xmpp_delay, ONE},
288         {NAME_AND_ATTR, name_attr_struct("x","xmlns", "jabber:x:delay"), xmpp_delay, ONE},
289         {NAME_AND_ATTR, name_attr_struct("x","xmlns", "vcard-temp:x:update"), xmpp_vcard_x_update, ONE},
290         {NAME_AND_ATTR, name_attr_struct("x","xmlns","http://jabber.org/protocol/muc"), xmpp_muc_x, ONE},
291         {NAME_AND_ATTR, name_attr_struct("x","xmlns","http://jabber.org/protocol/muc#user"), xmpp_muc_user_x, ONE},
292         {NAME, "error", xmpp_error, ONE},
293         {NAME_AND_ATTR, name_attr_struct("query", "xmlns","jabber:iq:last"), xmpp_last_query, ONE}
294     };
295
296
297     element_t *show, *priority;
298
299     col_clear(pinfo->cinfo, COL_INFO);
300     col_append_fstr(pinfo->cinfo, COL_INFO, "PRESENCE ");
301
302     presence_item = proto_tree_add_item(tree, hf_xmpp_presence, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
303     presence_tree = proto_item_add_subtree(presence_item, ett_xmpp_presence);
304
305     if((show = steal_element_by_name(packet, "show"))!=NULL)
306     {
307         attr_t *fake_show = ep_init_attr_t(show->data?show->data->value:"",show->offset, show->length);
308         g_hash_table_insert(packet->attrs, "show", fake_show);
309     }
310
311     if((priority = steal_element_by_name(packet, "priority"))!=NULL)
312     {
313         attr_t *fake_priority = ep_init_attr_t(priority->data?priority->data->value:"",priority->offset, priority->length);
314         g_hash_table_insert(packet->attrs, "priority", fake_priority);
315     }
316     display_attrs(presence_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
317
318     display_elems(presence_tree, packet, pinfo, tvb, elems_info, array_length(elems_info));
319 }
320
321 static void
322 xmpp_presence_status(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element)
323 {
324     proto_item *status_item;
325     proto_tree *status_tree;
326
327     attr_info attrs_info[] = {
328         {"xml:lang", -1, FALSE, TRUE, NULL, NULL},
329         {"value", -1, TRUE, TRUE, NULL, NULL}
330     };
331
332     attr_t *fake_value;
333
334     status_item = proto_tree_add_item(tree, hf_xmpp_presence_status, tvb, element->offset, element->length, ENC_BIG_ENDIAN);
335     status_tree = proto_item_add_subtree(status_item, ett_xmpp_presence_status);
336
337     if(element->data)
338         fake_value = ep_init_attr_t(element->data->value, element->offset, element->length);
339     else
340         fake_value = ep_init_attr_t("(empty)", element->offset, element->length);
341
342
343     g_hash_table_insert(element->attrs, "value", fake_value);
344
345     display_attrs(status_tree, element, pinfo, tvb, attrs_info, array_length(attrs_info));
346
347     xmpp_unknown(status_tree, tvb, pinfo, element);
348 }
349
350
351 void
352 xmpp_message(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
353 {
354     proto_item *message_item;
355     proto_tree *message_tree;
356
357     const gchar *type_enums[] = {"chat", "error", "groupchat", "headline", "normal"};
358     array_t *type_array = ep_init_array_t(type_enums, array_length(type_enums));
359
360     attr_info attrs_info[] = {
361         {"from", hf_xmpp_from, FALSE, FALSE, NULL, NULL},
362         {"id", hf_xmpp_id, FALSE, TRUE, NULL, NULL},
363         {"to", hf_xmpp_to, FALSE, FALSE, NULL, NULL},
364         {"type", hf_xmpp_type, FALSE, TRUE, val_enum_list, type_array},
365         {"xml:lang",-1, FALSE, FALSE, NULL,NULL},
366         {"chatstate", hf_xmpp_message_chatstate, FALSE, TRUE, NULL, NULL}
367     };
368
369     elem_info elems_info [] = {
370         {NAME_AND_ATTR, name_attr_struct("data", "xmlns", "http://jabber.org/protocol/ibb"), xmpp_ibb_data, ONE},
371         {NAME, "thread", xmpp_message_thread, ONE},
372         {NAME, "body", xmpp_message_body, MANY},
373         {NAME, "subject", xmpp_message_subject, MANY},
374         {NAME, "delay", xmpp_delay, ONE},
375         {NAME_AND_ATTR, name_attr_struct("x","xmlns","jabber:x:event"), xmpp_x_event, ONE},
376         {NAME_AND_ATTR, name_attr_struct("x","xmlns","http://jabber.org/protocol/muc#user"), xmpp_muc_user_x, ONE},
377         {NAME_AND_ATTR, name_attr_struct("x","xmlns","google:nosave"), xmpp_gtalk_nosave_x, ONE},
378         {NAME, "error", xmpp_error, ONE}
379     };
380
381     element_t *chatstate;
382
383     attr_t *id = NULL;
384
385     conversation_t *conversation = NULL;
386     xmpp_conv_info_t *xmpp_info = NULL;
387
388     col_clear(pinfo->cinfo, COL_INFO);
389     col_append_fstr(pinfo->cinfo, COL_INFO, "MESSAGE ");
390
391     id = get_attr(packet, "id");
392
393     conversation = find_or_create_conversation(pinfo);
394     xmpp_info = conversation_get_proto_data(conversation, proto_xmpp);
395
396     message_item = proto_tree_add_item(tree, hf_xmpp_message, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
397     message_tree = proto_item_add_subtree(message_item, ett_xmpp_message);
398
399     if((chatstate = steal_element_by_attr(packet, "xmlns", "http://jabber.org/protocol/chatstates"))!=NULL)
400     {
401         attr_t *fake_chatstate_attr = ep_init_attr_t(chatstate->name, chatstate->offset, chatstate->length);
402         g_hash_table_insert(packet->attrs, "chatstate", fake_chatstate_attr);
403     }
404
405     display_attrs(message_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
406
407     display_elems(message_tree, packet, pinfo, tvb, elems_info, array_length(elems_info));
408
409     /*Displays data about IBB session*/
410     if(xmpp_info && id)
411     {
412         gchar *ibb_sid;
413
414         ibb_sid = se_tree_lookup_string(xmpp_info->ibb_sessions, id->value, EMEM_TREE_STRING_NOCASE);
415
416         if (ibb_sid) {
417             proto_item *it = proto_tree_add_string(tree, hf_xmpp_ibb, tvb, 0, 0, ibb_sid);
418             PROTO_ITEM_SET_GENERATED(it);
419         }
420
421     }
422 }
423
424 static void
425 xmpp_message_body(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element)
426 {
427     proto_item *body_item;
428     proto_tree *body_tree;
429
430     attr_info attrs_info[] = {
431         {"xml:lang", -1, FALSE, TRUE, NULL, NULL},
432         {"value", -1, TRUE, TRUE, NULL, NULL}
433     };
434
435     attr_t *fake_data_attr;
436
437     body_item = proto_tree_add_item(tree, hf_xmpp_message_body, tvb, element->offset, element->length, ENC_BIG_ENDIAN);
438     body_tree = proto_item_add_subtree(body_item, ett_xmpp_message_body);
439
440     fake_data_attr = ep_init_attr_t(element->data?element->data->value:"", element->offset, element->length);
441     g_hash_table_insert(element->attrs, "value", fake_data_attr);
442
443
444     display_attrs(body_tree, element, pinfo, tvb, attrs_info, array_length(attrs_info));
445
446     xmpp_unknown(body_tree, tvb, pinfo, element);
447 }
448
449 static void
450 xmpp_message_subject(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element) {
451     proto_item *subject_item;
452     proto_tree *subject_tree;
453
454     attr_info attrs_info[] = {
455         {"xml:lang", -1, FALSE, TRUE, NULL, NULL},
456         {"value", -1, TRUE, FALSE, NULL, NULL}
457     };
458
459     attr_t *fake_data_attr;
460
461     subject_item = proto_tree_add_item(tree, hf_xmpp_message_subject, tvb, element->offset, element->length, ENC_BIG_ENDIAN);
462     subject_tree = proto_item_add_subtree(subject_item, ett_xmpp_message_subject);
463
464     fake_data_attr = ep_init_attr_t(element->data?element->data->value:"", element->offset, element->length);
465     g_hash_table_insert(element->attrs, "value", fake_data_attr);
466
467
468     display_attrs(subject_tree, element, pinfo, tvb, attrs_info, array_length(attrs_info));
469
470     xmpp_unknown(subject_tree, tvb, pinfo, element);
471 }
472
473 static void
474 xmpp_message_thread(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *element)
475 {
476     proto_item *thread_item;
477     proto_tree *thread_tree;
478
479     attr_info attrs_info[] = {
480         {"parent", hf_xmpp_message_thread_parent, FALSE, TRUE, NULL, NULL},
481         {"value", -1, TRUE, TRUE, NULL, NULL}
482     };
483
484     attr_t *fake_value;
485
486     thread_item = proto_tree_add_item(tree, hf_xmpp_message_thread, tvb, element->offset, element->length, ENC_BIG_ENDIAN);
487     thread_tree = proto_item_add_subtree(thread_item, ett_xmpp_message_thread);
488
489     fake_value = ep_init_attr_t(element->data?element->data->value:"", element->offset, element->length);
490     g_hash_table_insert(element->attrs, "value", fake_value);
491
492
493     display_attrs(thread_tree, element, pinfo, tvb, attrs_info, array_length(attrs_info));
494
495     xmpp_unknown(thread_tree, tvb, pinfo, element);
496 }
497
498 void
499 xmpp_auth(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
500 {
501     proto_item *auth_item;
502     proto_tree *auth_tree;
503
504     attr_info_ext attrs_info[]={
505         {"urn:ietf:params:xml:ns:xmpp-sasl", {"xmlns", hf_xmpp_xmlns, TRUE, TRUE, NULL, NULL}},
506         {"urn:ietf:params:xml:ns:xmpp-sasl", {"mechanism", -1, TRUE, TRUE, NULL, NULL}},
507         {"http://www.google.com/talk/protocol/auth", {"xmlns", hf_xmpp_xmlns, TRUE, TRUE, NULL, NULL}},
508         {"http://www.google.com/talk/protocol/auth", {"client-uses-full-bind-result", -1, TRUE, TRUE, NULL, NULL}},
509     };
510
511     if (check_col(pinfo->cinfo, COL_INFO))
512             col_set_str(pinfo->cinfo, COL_INFO, "AUTH");
513
514     auth_item = proto_tree_add_item(tree, hf_xmpp_auth, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
515     auth_tree = proto_item_add_subtree(auth_item, ett_xmpp_auth);
516
517     display_attrs_ext(auth_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
518
519     xmpp_cdata(auth_tree, tvb, packet, -1);
520
521     xmpp_unknown(auth_tree, tvb, pinfo, packet);
522 }
523
524 void
525 xmpp_challenge_response_success(proto_tree *tree, tvbuff_t *tvb,
526     packet_info *pinfo, element_t *packet, gint hf, gint ett,  const char *col_info)
527 {
528     proto_item *item;
529     proto_tree *subtree;
530
531     attr_info attrs_info[] = {
532         {"xmlns", hf_xmpp_xmlns, TRUE, TRUE, NULL, NULL}
533     };
534
535     if (check_col(pinfo->cinfo, COL_INFO))
536             col_set_str(pinfo->cinfo, COL_INFO, col_info);
537
538     item = proto_tree_add_item(tree, hf, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
539     subtree = proto_item_add_subtree(item, ett);
540
541     display_attrs(subtree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
542     xmpp_cdata(subtree, tvb, packet, -1);
543
544     xmpp_unknown(subtree, tvb, pinfo, packet);
545 }
546
547 void
548 xmpp_failure(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
549 {
550     proto_item *fail_item;
551     proto_tree *fail_tree;
552
553     attr_info attrs_info[] = {
554         {"xmlns", hf_xmpp_xmlns, TRUE, TRUE, NULL, NULL},
555         {"condition", -1, FALSE, TRUE, NULL, NULL}
556     };
557
558     const gchar *fail_names[] = {"aborted","account-disabled", "credentials-expired",
559         "encryption-required", "incorrect-encoding", "invalid-authzid", "invalid-mechanism",
560         "malformed-request", "mechanism-too-weak", "not-authorized", "temporary-auth-failure",
561         "transition-needed"
562     };
563
564     element_t *fail_condition, *text;
565
566     col_add_fstr(pinfo->cinfo, COL_INFO, "FAILURE ");
567
568     fail_item = proto_tree_add_item(tree, hf_xmpp_failure, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
569     fail_tree = proto_item_add_subtree(fail_item, ett_xmpp_failure);
570
571     if((fail_condition = steal_element_by_names(packet, fail_names, array_length(fail_names)))!=NULL)
572     {
573         attr_t *fake_cond = ep_init_attr_t(fail_condition->name, fail_condition->offset, fail_condition->length);
574         g_hash_table_insert(packet->attrs, "condition", fake_cond);
575     }
576
577     if((text = steal_element_by_name(packet, "text"))!=NULL)
578     {
579         xmpp_failure_text(fail_tree, tvb, text);
580     }
581
582     display_attrs(fail_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
583
584     xmpp_unknown(fail_tree, tvb, pinfo, packet);
585 }
586
587 static void
588 xmpp_failure_text(proto_tree *tree, tvbuff_t *tvb, element_t *element)
589 {
590     attr_t *lang = get_attr(element,"xml:lang");
591
592     proto_tree_add_text(tree, tvb, element->offset, element->length, "TEXT%s: %s",
593             lang?ep_strdup_printf("(%s)",lang->value):"",
594             element->data?element->data->value:"");
595 }
596
597 void
598 xmpp_xml_header(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, element_t *packet)
599 {
600     col_add_fstr(pinfo->cinfo, COL_INFO, "XML ");
601     proto_tree_add_text(tree, tvb, packet->offset, packet->length, "XML HEADER VER. %s","1.0");
602 }
603
604 void
605 xmpp_stream(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
606 {
607     proto_item *stream_item;
608     proto_tree *stream_tree;
609
610     attr_info_ext attrs_info [] = {
611         {"http://etherx.jabber.org/streams",{"xmlns", hf_xmpp_xmlns, FALSE, TRUE, NULL, NULL}},
612         {"http://etherx.jabber.org/streams",{"version", -1, FALSE, TRUE, NULL, NULL}},
613         {"http://etherx.jabber.org/streams",{"from",-1, FALSE, TRUE, NULL, NULL}},
614         {"http://etherx.jabber.org/streams",{"to",-1, FALSE, TRUE, NULL, NULL}},
615         {"http://etherx.jabber.org/streams",{"id",-1, FALSE, TRUE, NULL, NULL}},
616         {"http://etherx.jabber.org/streams",{"xml:lang",-1, FALSE, TRUE, NULL, NULL}},
617         {"jabber:client",{"xmlns", hf_xmpp_xmlns, FALSE, TRUE, NULL, NULL}},
618
619     };
620
621     col_add_fstr(pinfo->cinfo, COL_INFO, "STREAM ");
622
623     stream_item = proto_tree_add_item(tree, hf_xmpp_stream, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
624     stream_tree = proto_item_add_subtree(stream_item, ett_xmpp_stream);
625
626     display_attrs_ext(stream_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
627     display_elems(stream_tree, packet, pinfo, tvb, NULL, 0);
628 }
629
630 /*returns TRUE if stream end occurs*/
631 gboolean
632 xmpp_stream_close(proto_tree *tree, tvbuff_t *tvb, packet_info* pinfo)
633 {
634     tvbparse_t* tt;
635     tvbparse_elem_t* elem;
636     tvbparse_wanted_t* want_ignore = tvbparse_chars(1,1,0," \t\r\n",NULL,NULL,NULL);
637     tvbparse_wanted_t* want_name = tvbparse_chars(2,1,0,"abcdefghijklmnopqrstuvwxyz.-_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",NULL,NULL,NULL);
638     tvbparse_wanted_t* want_stream_end_with_ns = tvbparse_set_seq(3, NULL, NULL, NULL,
639                                                                want_name,
640                                                                tvbparse_char(4, ":", NULL, NULL, NULL),
641                                                                want_name,
642                                                                NULL);
643
644     tvbparse_wanted_t* want_stream_end = tvbparse_set_oneof(5, NULL, NULL, NULL,
645                                                                want_stream_end_with_ns,
646                                                                want_name,
647                                                                NULL);
648
649     tvbparse_wanted_t* want_stream_end_tag = tvbparse_set_seq(6, NULL, NULL, NULL,
650                                                                tvbparse_string(-1,"</",NULL,NULL,NULL),
651                                                                want_stream_end,
652                                                                tvbparse_char(-1,">",NULL,NULL,NULL),
653                                                                NULL);
654     tt = tvbparse_init(tvb,0,-1,NULL,want_ignore);
655
656     if((elem = tvbparse_get(tt,want_stream_end_tag))!=NULL)
657     {
658         proto_tree_add_text(tree, tvb, elem->offset, elem->len, "STREAM END");
659         col_add_fstr(pinfo->cinfo, COL_INFO, "STREAM END");
660
661         return TRUE;
662     }
663     return FALSE;
664 }
665
666 void
667 xmpp_features(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
668 {
669     proto_item *features_item;
670     proto_tree *features_tree;
671
672     elem_info elems_info [] = {
673         {NAME, "mechanisms", xmpp_features_mechanisms, MANY}
674     };
675
676     features_item = proto_tree_add_item(tree, hf_xmpp_features, tvb, packet->offset, packet->length, 
677         ENC_BIG_ENDIAN);
678     features_tree = proto_item_add_subtree(features_item, ett_xmpp_features);
679
680     col_add_fstr(pinfo->cinfo, COL_INFO, "FEATURES ");
681
682     display_attrs(features_tree, packet, pinfo, tvb, NULL, 0);
683     display_elems(features_tree, packet, pinfo, tvb, elems_info, array_length(elems_info));
684 }
685
686 static void
687 xmpp_features_mechanisms(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
688 {
689     proto_item *mechanisms_item;
690     proto_tree *mechanisms_tree;
691
692     attr_info attrs_info [] = {
693         {"xmlns", hf_xmpp_xmlns, TRUE, TRUE, NULL, NULL}
694     };
695
696     elem_info elems_info [] = {
697         {NAME, "mechanism", xmpp_simple_cdata_elem, MANY},
698     };
699
700     mechanisms_item = proto_tree_add_text(tree, tvb, packet->offset, packet->length, "MECHANISMS");
701     mechanisms_tree = proto_item_add_subtree(mechanisms_item, ett_xmpp_features_mechanisms);
702
703     display_attrs(mechanisms_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
704     display_elems(mechanisms_tree, packet, pinfo, tvb, elems_info, array_length(elems_info));
705 }
706
707 void
708 xmpp_starttls(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
709 {
710     proto_item *tls_item;
711     proto_tree *tls_tree;
712
713     attr_info attrs_info [] = {
714         {"xmlns", hf_xmpp_xmlns, TRUE, TRUE, NULL, NULL},
715     };
716
717     col_add_fstr(pinfo->cinfo, COL_INFO, "STARTTLS ");
718
719     tls_item = proto_tree_add_item(tree, hf_xmpp_starttls, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
720     tls_tree = proto_item_add_subtree(tls_item, ett_xmpp_starttls);
721
722     display_attrs(tls_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
723     display_elems(tls_tree, packet, pinfo, tvb, NULL, 0);
724 }
725
726 void
727 xmpp_proceed(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, element_t *packet)
728 {
729     proto_item *proceed_item;
730     proto_tree *proceed_tree;
731
732     attr_info attrs_info [] = {
733         {"xmlns", hf_xmpp_xmlns, TRUE, TRUE, NULL, NULL},
734     };
735
736     col_add_fstr(pinfo->cinfo, COL_INFO, "PROCEED ");
737
738     proceed_item = proto_tree_add_item(tree, hf_xmpp_proceed, tvb, packet->offset, packet->length, ENC_BIG_ENDIAN);
739     proceed_tree = proto_item_add_subtree(proceed_item, ett_xmpp_proceed);
740
741     display_attrs(proceed_tree, packet, pinfo, tvb, attrs_info, array_length(attrs_info));
742     display_elems(proceed_tree, packet, pinfo, tvb, NULL, 0);
743 }
744 /*
745 * Editor modelines - http://www.wireshark.org/tools/modelines.html
746 *
747 * Local variables:
748 * c-basic-offset: 4
749 * tab-width: 8
750 * indent-tabs-mode: nil
751 * End:
752 *
753 * ex: set shiftwidth=4 tabstop=8 expandtab:
754 * :indentSize=4:tabSize=8:noTabs=true:
755 */