Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-xmpp-utils.c
blob4ca5e070575588f18e3924f0ecb79a5492da9400
1 /* packet-xmpp-utils.c
2 * Wireshark's XMPP dissector.
4 * Copyright 2011, Mariusz Okroj <okrojmariusz[]gmail.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
15 #include <epan/packet.h>
16 #include <epan/strutil.h>
17 #include <epan/exceptions.h>
19 #include "packet-xmpp.h"
20 #include "packet-xmpp-core.h"
21 #include "packet-xmpp-utils.h"
23 static void
24 xmpp_copy_hash_table_func(void *key, void *value, void *user_data)
26 GHashTable *dst = (GHashTable *)user_data;
27 g_hash_table_insert(dst, key, value);
30 static void xmpp_copy_hash_table(GHashTable *src, GHashTable *dst)
32 g_hash_table_foreach(src, xmpp_copy_hash_table_func, dst);
35 static GList* xmpp_find_element_by_name(xmpp_element_t *packet,const char *name);
36 static char* xmpp_ep_string_upcase(wmem_allocator_t *pool, const char* string);
37 static void xmpp_unknown_attrs(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, xmpp_element_t *element, bool displ_short_list);
40 void
41 xmpp_iq_reqresp_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
43 xmpp_transaction_t *xmpp_trans = NULL;
45 xmpp_attr_t *attr_id;
46 char *id;
48 attr_id = xmpp_get_attr(packet, "id");
50 if (!attr_id) {
51 return;
54 id = wmem_strdup(pinfo->pool, attr_id->value);
56 if (!pinfo->fd->visited) {
57 xmpp_trans = (xmpp_transaction_t *)wmem_tree_lookup_string(xmpp_info->req_resp, id, WMEM_TREE_STRING_NOCASE);
58 if (xmpp_trans) {
59 xmpp_trans->resp_frame = pinfo->num;
61 } else {
62 char *se_id = wmem_strdup(wmem_file_scope(), id);
64 xmpp_trans = wmem_new(wmem_file_scope(), xmpp_transaction_t);
65 xmpp_trans->req_frame = pinfo->num;
66 xmpp_trans->resp_frame = 0;
68 wmem_tree_insert_string(xmpp_info->req_resp, se_id, (void *) xmpp_trans, WMEM_TREE_STRING_NOCASE);
72 } else {
73 wmem_tree_lookup_string(xmpp_info->req_resp, id, WMEM_TREE_STRING_NOCASE);
77 void
78 xmpp_jingle_session_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
80 xmpp_element_t *jingle_packet;
81 GList *jingle_packet_l;
83 jingle_packet_l = xmpp_find_element_by_name(packet,"jingle");
84 jingle_packet = (xmpp_element_t *)(jingle_packet_l?jingle_packet_l->data:NULL);
86 if (jingle_packet && !pinfo->fd->visited) {
87 xmpp_attr_t *attr_id;
88 xmpp_attr_t *attr_sid;
90 char *se_id;
91 char *se_sid;
94 attr_id = xmpp_get_attr(packet, "id");
95 if (!attr_id) {
96 return;
99 attr_sid = xmpp_get_attr(jingle_packet, "sid");
100 if (!attr_sid) {
101 return;
104 se_id = wmem_strdup(wmem_file_scope(), attr_id->value);
105 se_sid = wmem_strdup(wmem_file_scope(), attr_sid->value);
107 wmem_tree_insert_string(xmpp_info->jingle_sessions, se_id, (void*) se_sid, WMEM_TREE_STRING_NOCASE);
111 void
112 xmpp_gtalk_session_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
114 xmpp_element_t *gtalk_packet;
115 GList *gtalk_packet_l;
117 gtalk_packet_l = xmpp_find_element_by_name(packet,"session");
118 gtalk_packet = (xmpp_element_t *)(gtalk_packet_l?gtalk_packet_l->data:NULL);
121 if (gtalk_packet && !pinfo->fd->visited) {
122 xmpp_attr_t *attr_id;
123 xmpp_attr_t *attr_sid;
125 char *se_id;
126 char *se_sid;
128 xmpp_attr_t *xmlns = xmpp_get_attr(gtalk_packet, "xmlns");
129 if(xmlns && strcmp(xmlns->value,"http://www.google.com/session") != 0)
130 return;
132 attr_id = xmpp_get_attr(packet, "id");
133 if (!attr_id) {
134 return;
137 attr_sid = xmpp_get_attr(gtalk_packet, "id");
138 if (!attr_sid) {
139 return;
142 se_id = wmem_strdup(wmem_file_scope(), attr_id->value);
143 se_sid = wmem_strdup(wmem_file_scope(), attr_sid->value);
145 wmem_tree_insert_string(xmpp_info->gtalk_sessions, se_id, (void*) se_sid, WMEM_TREE_STRING_NOCASE);
149 void
150 xmpp_ibb_session_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
152 xmpp_element_t *ibb_packet = NULL;
153 GList *ibb_packet_l;
155 if(strcmp(packet->name, "message") == 0)
157 ibb_packet_l = xmpp_find_element_by_name(packet,"data");
158 ibb_packet = (xmpp_element_t *)(ibb_packet_l?ibb_packet_l->data:NULL);
160 } else if(strcmp(packet->name, "iq") == 0)
162 ibb_packet_l = xmpp_find_element_by_name(packet,"open");
164 if(!ibb_packet_l)
165 ibb_packet_l = xmpp_find_element_by_name(packet,"close");
166 if(!ibb_packet_l)
167 ibb_packet_l = xmpp_find_element_by_name(packet,"data");
169 ibb_packet = (xmpp_element_t *)(ibb_packet_l?ibb_packet_l->data:NULL);
172 if (ibb_packet && !pinfo->fd->visited) {
173 xmpp_attr_t *attr_id;
174 xmpp_attr_t *attr_sid;
176 char *se_id;
177 char *se_sid;
180 attr_id = xmpp_get_attr(packet, "id");
181 attr_sid = xmpp_get_attr(ibb_packet, "sid");
182 if(attr_id && attr_sid)
184 se_id = wmem_strdup(wmem_file_scope(), attr_id->value);
185 se_sid = wmem_strdup(wmem_file_scope(), attr_sid->value);
186 wmem_tree_insert_string(xmpp_info->ibb_sessions, se_id, (void*) se_sid, WMEM_TREE_STRING_NOCASE);
191 static void
192 // NOLINTNEXTLINE(misc-no-recursion)
193 xmpp_unknown_items(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, xmpp_element_t *element, unsigned level)
195 GList *childs = element->elements;
197 DISSECTOR_ASSERT( level < ETT_UNKNOWN_LEN );
199 xmpp_unknown_attrs(tree, tvb, pinfo, element, true);
201 if(element->data)
203 proto_tree_add_string(tree, hf_xmpp_cdata, tvb, element->data->offset, element->data->length, element->data->value);
206 while(childs)
208 xmpp_element_t *child = (xmpp_element_t *)childs->data;
209 proto_item *child_item;
210 proto_tree *child_tree = proto_tree_add_subtree(tree, tvb, child->offset, child->length,
211 ett_unknown[level], &child_item, xmpp_ep_string_upcase(pinfo->pool, child->name));
213 if(child->default_ns_abbrev)
214 proto_item_append_text(child_item, "(%s)", child->default_ns_abbrev);
216 xmpp_unknown_items(child_tree, tvb, pinfo, child, level +1);
218 childs = childs->next;
222 void
223 xmpp_unknown(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, xmpp_element_t *element)
225 GList *childs = element->elements;
227 /*element has unrecognized elements*/
228 while(childs)
230 xmpp_element_t *child = (xmpp_element_t *)childs->data;
231 if(!child->was_read)
233 proto_item *unknown_item;
234 proto_tree *unknown_tree;
236 unknown_item = proto_tree_add_string_format(tree,
237 hf_xmpp_unknown, tvb, child->offset, child->length, child->name,
238 "%s", xmpp_ep_string_upcase(pinfo->pool, child->name));
240 unknown_tree = proto_item_add_subtree(unknown_item, ett_unknown[0]);
242 /*Add COL_INFO only if root element is IQ*/
243 if(strcmp(element->name,"iq")==0)
244 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", xmpp_ep_string_upcase(pinfo->pool, child->name));
246 if(child->default_ns_abbrev)
247 proto_item_append_text(unknown_item,"(%s)",child->default_ns_abbrev);
249 xmpp_unknown_items(unknown_tree, tvb, pinfo, child, 1);
250 proto_item_append_text(unknown_item, " [UNKNOWN]");
251 expert_add_info_format(pinfo, unknown_item, &ei_xmpp_unknown_element, "Unknown element: %s", child->name);
253 childs = childs->next;
257 static void
258 cleanup_glist_cb(void *user_data) {
259 GList *li = (GList*)user_data;
261 g_list_free(li);
264 static void
265 xmpp_unknown_attrs(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, xmpp_element_t *element, bool displ_short_list)
267 proto_item *item = proto_tree_get_parent(tree);
269 GList *keys = g_hash_table_get_keys(element->attrs);
270 GList *values = g_hash_table_get_values(element->attrs);
272 GList *keys_head = keys, *values_head = values;
274 CLEANUP_PUSH_PFX(k, cleanup_glist_cb, keys_head);
275 CLEANUP_PUSH_PFX(v, cleanup_glist_cb, values_head);
277 bool short_list_started = false;
279 while(keys && values)
281 xmpp_attr_t *attr = (xmpp_attr_t*) values->data;
282 if (!attr->was_read) {
283 if (displ_short_list) {
284 if (!short_list_started)
285 proto_item_append_text(item, " [");
286 else
287 proto_item_append_text(item, " ");
288 proto_item_append_text(item, "%s=\"%s\"", (char*) keys->data, attr->value);
290 short_list_started = true;
293 /*If unknown element has xmlns attrib then header field hf_xmpp_xmlns is added to the tree.
294 In other case only text.*/
295 if (strcmp((const char *)keys->data, "xmlns") == 0)
296 proto_tree_add_string(tree, hf_xmpp_xmlns, tvb, attr->offset, attr->length, attr->value);
297 else {
298 /*xmlns may looks like xmlns:abbrev="sth"*/
299 const char *xmlns_needle = ws_ascii_strcasestr((const char *)keys->data, "xmlns:");
300 if (xmlns_needle && xmlns_needle == keys->data) {
301 proto_tree_add_string_format(tree, hf_xmpp_xmlns, tvb, attr->offset, attr->length, attr->value,"%s: %s", (char*)keys->data, attr->value);
302 } else {
303 proto_item* unknown_attr_item;
304 unknown_attr_item = proto_tree_add_string_format(tree,
305 hf_xmpp_unknown_attr, tvb, attr->offset, attr->length,
306 attr->name, "%s: %s", attr->name, attr->value);
307 proto_item_append_text(unknown_attr_item, " [UNKNOWN ATTR]");
308 expert_add_info_format(pinfo, unknown_attr_item, &ei_xmpp_unknown_attribute, "Unknown attribute %s", attr->name);
312 keys = keys->next;
313 values = values->next;
316 if(short_list_started && displ_short_list)
317 proto_item_append_text(item, "]");
319 CLEANUP_CALL_AND_POP_PFX(v);
320 CLEANUP_CALL_AND_POP_PFX(k);
323 void
324 xmpp_cdata(proto_tree *tree, tvbuff_t *tvb, xmpp_element_t *element, int hf)
326 if(element->data)
328 if (hf == -1) {
329 proto_tree_add_string(tree, hf_xmpp_cdata, tvb, element->data->offset, element->data->length, element->data->value);
330 } else {
331 proto_tree_add_string(tree, hf, tvb, element->data->offset, element->data->length, element->data->value);
333 } else
335 if (hf == -1) {
336 proto_tree_add_string_format_value(tree, hf_xmpp_cdata, tvb, 0, 0, "", "(empty)");
337 } else {
338 proto_tree_add_string(tree, hf, tvb, 0, 0, "");
343 /* displays element that looks like <element_name>element_value</element_name>
344 * ELEMENT_NAME: element_value as TEXT in PROTO_TREE
346 void
347 xmpp_simple_cdata_elem(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, xmpp_element_t *element)
349 proto_tree_add_string_format(tree, hf_xmpp_cdata, tvb, element->offset, element->length, xmpp_elem_cdata(element),
350 "%s: %s", xmpp_ep_string_upcase(pinfo->pool, element->name), xmpp_elem_cdata(element));
353 xmpp_array_t*
354 xmpp_ep_init_array_t(wmem_allocator_t *pool, const char** array, int len)
356 xmpp_array_t *result;
358 result = wmem_new(pool, xmpp_array_t);
359 result->data = (void *) array;
360 result->length = len;
362 return result;
365 xmpp_attr_t*
366 xmpp_ep_init_attr_t(wmem_allocator_t *pool, const char *value, int offset, int length)
368 xmpp_attr_t *result;
369 result = wmem_new(pool, xmpp_attr_t);
370 result->value = value;
371 result->offset = offset;
372 result->length = length;
373 result->name = NULL;
375 return result;
378 static char*
379 xmpp_ep_string_upcase(wmem_allocator_t *pool, const char* string)
381 int len = (int)strlen(string);
382 int i;
383 char* result = (char *)wmem_alloc0(pool, len+1);
384 for(i=0; i<len; i++)
386 result[i] = string[i];
388 if(string[i]>='a' && string[i]<='z')
389 result[i]-='a'-'A';
392 return result;
395 static int
396 xmpp_element_t_cmp(const void *a, const void *b)
398 int result = strcmp(((const xmpp_element_t*)a)->name,((const xmpp_element_t*)b)->name);
400 if(result == 0 && ((const xmpp_element_t*)a)->was_read)
401 result = -1;
403 return result;
406 static GList*
407 xmpp_find_element_by_name(xmpp_element_t *packet,const char *name)
409 GList *found_elements;
410 xmpp_element_t *search_element;
412 /*create fake element only with name*/
413 search_element = wmem_new(wmem_packet_scope(), xmpp_element_t);
414 search_element->name = wmem_strdup(wmem_packet_scope(), name);
416 found_elements = g_list_find_custom(packet->elements, search_element, xmpp_element_t_cmp);
418 if(found_elements)
419 return found_elements;
420 else
421 return NULL;
425 /* steal_*
426 * function searches element in packet and sets it as read.
427 * if element doesn't exist, NULL is returned.
428 * If element is set as read, it is invisible for these functions.*/
429 xmpp_element_t*
430 xmpp_steal_element_by_name(xmpp_element_t *packet,const char *name)
432 GList *element_l;
433 xmpp_element_t *element = NULL;
435 element_l = xmpp_find_element_by_name(packet, name);
437 if(element_l)
439 element = (xmpp_element_t *)element_l->data;
440 element->was_read = true;
443 return element;
447 xmpp_element_t*
448 xmpp_steal_element_by_names(xmpp_element_t *packet, const char **names, int names_len)
450 int i;
451 xmpp_element_t *el = NULL;
453 for(i = 0; i<names_len; i++)
455 if((el = xmpp_steal_element_by_name(packet, names[i])))
456 break;
459 return el;
462 xmpp_element_t*
463 xmpp_steal_element_by_attr(xmpp_element_t *packet, const char *attr_name, const char *attr_value)
465 GList *childs = packet->elements;
466 xmpp_element_t *result = NULL;
468 while (childs) {
469 xmpp_element_t *child_elem = (xmpp_element_t *)childs->data;
470 xmpp_attr_t *attr = xmpp_get_attr(child_elem, attr_name);
472 if(attr)
473 attr->was_read = false;
475 if (!child_elem->was_read && attr && strcmp(attr->value, attr_value) == 0) {
477 result = (xmpp_element_t *)childs->data;
479 result->was_read = true;
481 break;
482 } else
483 childs = childs->next;
486 return result;
489 xmpp_element_t*
490 xmpp_steal_element_by_name_and_attr(xmpp_element_t *packet, const char *name, const char *attr_name, const char *attr_value)
492 GList *childs = packet->elements;
493 xmpp_element_t *result = NULL;
495 while (childs) {
496 xmpp_element_t *child_elem = (xmpp_element_t *)childs->data;
497 xmpp_attr_t *attr = xmpp_get_attr(child_elem, attr_name);
499 if(attr)
500 attr->was_read = false;
502 if (!child_elem->was_read && attr && strcmp(child_elem->name, name) == 0 && strcmp(attr->value, attr_value) == 0) {
504 result = (xmpp_element_t *)childs->data;
506 result->was_read = true;
508 break;
509 } else
510 childs = childs->next;
512 return result;
515 xmpp_element_t*
516 xmpp_get_first_element(xmpp_element_t *packet)
518 if(packet->elements && packet->elements->data)
519 return (xmpp_element_t *)packet->elements->data;
520 else
521 return NULL;
524 static void
525 xmpp_element_t_cleanup(void* userdata)
527 xmpp_element_t *node = (xmpp_element_t*)userdata;
529 xmpp_element_t_tree_free(node);
533 Function converts xml_frame_t structure to xmpp_element_t (simpler representation)
535 xmpp_element_t*
536 // NOLINTNEXTLINE(misc-no-recursion)
537 xmpp_xml_frame_to_element_t(packet_info *pinfo, xml_frame_t *xml_frame, xmpp_element_t *parent, tvbuff_t *tvb)
539 xml_frame_t *child;
540 xmpp_element_t *node = wmem_new0(pinfo->pool, xmpp_element_t);
542 tvbparse_t* tt;
543 tvbparse_elem_t* elem;
545 node->attrs = g_hash_table_new(g_str_hash, g_str_equal);
546 node->elements = NULL;
547 node->data = NULL;
548 node->was_read = false;
549 node->default_ns_abbrev = NULL;
551 node->name = wmem_strdup(pinfo->pool, xml_frame->name_orig_case);
552 node->offset = 0;
553 node->length = 0;
555 node->namespaces = g_hash_table_new(g_str_hash, g_str_equal);
556 if(parent)
558 xmpp_copy_hash_table(parent->namespaces, node->namespaces);
559 } else
561 g_hash_table_insert(node->namespaces, (void *)"", (void *)"jabber:client");
564 node->offset = xml_frame->start_offset;
565 node->length = xml_frame->length;
567 /* We might throw an exception recursively creating child nodes.
568 * Make sure we free the GHashTables created above (and the GList
569 * or child nodes already added) if that happens.
571 CLEANUP_PUSH(xmpp_element_t_cleanup, node);
573 tt = tvbparse_init(pinfo->pool, tvb,node->offset,-1,NULL,want_ignore);
575 if((elem = tvbparse_get(tt,want_stream_end_with_ns))!=NULL)
577 node->default_ns_abbrev = tvb_get_string_enc(pinfo->pool, elem->sub->tvb, elem->sub->offset, elem->sub->len, ENC_ASCII);
580 child = xml_frame->first_child;
582 while(child)
584 if(child->type != XML_FRAME_TAG)
586 if(child->type == XML_FRAME_ATTRIB)
588 int l;
589 char *value = NULL;
590 const char *xmlns_needle = NULL;
592 xmpp_attr_t *attr = wmem_new(pinfo->pool, xmpp_attr_t);
593 attr->length = 0;
594 attr->offset = 0;
595 attr->was_read = false;
597 if (child->value != NULL) {
598 l = tvb_reported_length(child->value);
599 value = (char *)wmem_alloc0(pinfo->pool, l + 1);
600 tvb_memcpy(child->value, value, 0, l);
603 attr->offset = child->start_offset;
604 attr->length = child->length;
605 attr->value = value;
606 attr->name = wmem_strdup(pinfo->pool, child->name_orig_case);
608 g_hash_table_insert(node->attrs,(void *)attr->name,(void *)attr);
610 /*checking that attr->name looks like xmlns:ns*/
611 xmlns_needle = ws_ascii_strcasestr(attr->name, "xmlns");
613 if(xmlns_needle == attr->name)
615 if(attr->name[5] == ':' && strlen(attr->name) > 6)
617 g_hash_table_insert(node->namespaces, (void *)wmem_strdup(pinfo->pool, &attr->name[6]), (void *)wmem_strdup(pinfo->pool, attr->value));
618 } else if(attr->name[5] == '\0')
620 g_hash_table_insert(node->namespaces, (void *)"", (void *)wmem_strdup(pinfo->pool, attr->value));
626 else if( child->type == XML_FRAME_CDATA)
628 xmpp_data_t *data = NULL;
629 int l;
630 char* value = NULL;
632 data = wmem_new(pinfo->pool, xmpp_data_t);
633 data->length = 0;
634 data->offset = 0;
636 if (child->value != NULL) {
637 l = tvb_reported_length(child->value);
638 value = (char *)wmem_alloc0(pinfo->pool, l + 1);
639 tvb_memcpy(child->value, value, 0, l);
642 data->value = value;
644 data->offset = child->start_offset;
645 data->length = child->length;
646 node->data = data;
648 } else
650 increment_dissection_depth(pinfo);
651 node->elements = g_list_append(node->elements,(void *)xmpp_xml_frame_to_element_t(pinfo, child, node,tvb));
652 decrement_dissection_depth(pinfo);
655 child = child->next_sibling;
658 CLEANUP_POP;
660 return node;
663 void
664 // NOLINTNEXTLINE(misc-no-recursion)
665 xmpp_element_t_tree_free(xmpp_element_t *root)
667 GList *childs = root->elements;
669 g_hash_table_destroy(root->attrs);
670 g_hash_table_destroy(root->namespaces);
672 while(childs)
674 xmpp_element_t *child = (xmpp_element_t *)childs->data;
676 // Our depth should be limited by the check in xmpp_xml_frame_to_element_t
677 xmpp_element_t_tree_free(child);
678 childs = childs->next;
680 g_list_free(root->elements);
683 /*Function recognize attribute names if they looks like xmlns:ns*/
684 static gboolean
685 attr_find_pred(void *key, void *value _U_, void *user_data)
687 char *attr_name = (char*) user_data;
689 if( strcmp(attr_name, "xmlns") == 0 )
691 const char *first_occur = ws_ascii_strcasestr((const char *)key, "xmlns:");
692 if(first_occur && first_occur == key)
693 return true;
694 else
695 return false;
697 return false;
700 /*Functions returns element's attribute by name and set as read*/
701 xmpp_attr_t*
702 xmpp_get_attr(xmpp_element_t *element, const char* attr_name)
704 xmpp_attr_t *result = (xmpp_attr_t *)g_hash_table_lookup(element->attrs, attr_name);
706 if(!result)
708 result = (xmpp_attr_t *)g_hash_table_find(element->attrs, attr_find_pred, (void *)attr_name);
711 if(result)
712 result->was_read = true;
714 return result;
717 /*Functions returns element's attribute by name and namespace abbrev*/
718 static xmpp_attr_t*
719 xmpp_get_attr_ext(packet_info *pinfo, xmpp_element_t *element, const char* attr_name, const char* ns_abbrev)
721 char* search_phrase;
722 xmpp_attr_t *result;
724 if(strcmp(ns_abbrev,"")==0)
725 search_phrase = wmem_strdup(pinfo->pool, attr_name);
726 else if(strcmp(attr_name, "xmlns") == 0)
727 search_phrase = wmem_strdup_printf(pinfo->pool, "%s:%s",attr_name, ns_abbrev);
728 else
729 search_phrase = wmem_strdup_printf(pinfo->pool, "%s:%s", ns_abbrev, attr_name);
731 result = (xmpp_attr_t *)g_hash_table_lookup(element->attrs, search_phrase);
733 if(!result)
735 result = (xmpp_attr_t *)g_hash_table_find(element->attrs, attr_find_pred, (void *)attr_name);
738 if(result)
739 result->was_read = true;
741 return result;
746 char*
747 xmpp_element_to_string(wmem_allocator_t *pool, tvbuff_t *tvb, xmpp_element_t *element)
749 char *buff = NULL;
751 if(tvb_offset_exists(tvb, element->offset+element->length-1))
753 buff = tvb_get_string_enc(pool, tvb, element->offset, element->length, ENC_ASCII);
755 return buff;
758 static void
759 children_foreach_hide_func(proto_node *node, void *data)
761 int *i = (int *)data;
762 if((*i) == 0)
763 proto_item_set_hidden(node);
764 (*i)++;
767 static void
768 children_foreach_show_func(proto_node *node, void *data)
770 int *i = (int *)data;
771 if((*i) == 0)
772 proto_item_set_visible(node);
773 (*i)++;
776 void
777 xmpp_proto_tree_hide_first_child(proto_tree *tree)
779 int i = 0;
780 proto_tree_children_foreach(tree, children_foreach_hide_func, &i);
783 void
784 xmpp_proto_tree_show_first_child(proto_tree *tree)
786 int i = 0;
787 proto_tree_children_foreach(tree, children_foreach_show_func, &i);
790 char*
791 proto_item_get_text(wmem_allocator_t *pool, proto_item *item)
793 field_info *fi = NULL;
794 char *result;
796 if(item == NULL)
797 return NULL;
799 fi = PITEM_FINFO(item);
801 if(fi==NULL)
802 return NULL;
804 if (fi->rep == NULL)
805 return NULL;
808 result = wmem_strdup(pool, fi->rep->representation);
809 return result;
813 void
814 xmpp_display_attrs(proto_tree *tree, xmpp_element_t *element, packet_info *pinfo, tvbuff_t *tvb, const xmpp_attr_info *attrs, unsigned n)
816 proto_item *item = proto_tree_get_parent(tree);
817 xmpp_attr_t *attr;
818 unsigned i;
819 bool short_list_started = false;
821 if(element->default_ns_abbrev)
822 proto_item_append_text(item, "(%s)",element->default_ns_abbrev);
824 proto_item_append_text(item," [");
825 for(i = 0; i < n && attrs!=NULL; i++)
827 attr = xmpp_get_attr(element, attrs[i].name);
828 if(attr)
830 if(attrs[i].phf != NULL)
832 if(attr->name)
833 proto_tree_add_string_format(tree, *attrs[i].phf, tvb, attr->offset, attr->length, attr->value,"%s: %s", attr->name, attr->value);
834 else
835 proto_tree_add_string(tree, *attrs[i].phf, tvb, attr->offset, attr->length, attr->value);
837 else
839 proto_tree_add_string_format(tree, hf_xmpp_attribute, tvb, attr->offset, attr->length, attr->value,
840 "%s: %s", attr->name?attr->name:attrs[i].name, attr->value);
843 if(attrs[i].in_short_list)
845 if(short_list_started)
847 proto_item_append_text(item," ");
849 proto_item_append_text(item,"%s=\"%s\"",attr->name?attr->name:attrs[i].name, attr->value);
850 short_list_started = true;
853 } else if(attrs[i].is_required)
855 expert_add_info_format(pinfo, item, &ei_xmpp_required_attribute, "Required attribute \"%s\" doesn't appear in \"%s\".", attrs[i].name, element->name);
858 if(attrs[i].val_func)
860 if(attr)
861 attrs[i].val_func(pinfo, item, attrs[i].name, attr->value, attrs[i].data);
862 else
863 attrs[i].val_func(pinfo, item, attrs[i].name, NULL, attrs[i].data);
866 proto_item_append_text(item,"]");
868 /*displays attributes that weren't recognized*/
869 xmpp_unknown_attrs(tree, tvb, pinfo, element, false);
872 void
873 xmpp_display_attrs_ext(proto_tree *tree, xmpp_element_t *element, packet_info *pinfo, tvbuff_t *tvb, const xmpp_attr_info_ext *attrs, unsigned n)
875 proto_item *item = proto_tree_get_parent(tree);
876 xmpp_attr_t *attr;
877 unsigned i;
878 bool short_list_started = false;
880 GList *ns_abbrevs_head, *ns_abbrevs = g_hash_table_get_keys(element->namespaces);
881 GList *ns_fullnames_head, *ns_fullnames = g_hash_table_get_values(element->namespaces);
882 ns_abbrevs_head = ns_abbrevs;
883 ns_fullnames_head = ns_fullnames;
885 if(element->default_ns_abbrev)
886 proto_item_append_text(item, "(%s)",element->default_ns_abbrev);
888 proto_item_append_text(item," [");
889 while(ns_abbrevs && ns_fullnames)
891 for (i = 0; i < n && attrs != NULL; i++) {
892 if(strcmp((const char *)(ns_fullnames->data), attrs[i].ns) == 0)
894 attr = xmpp_get_attr_ext(pinfo, element, attrs[i].info.name, (const char *)(ns_abbrevs->data));
895 if(!attr && element->default_ns_abbrev && strcmp((const char *)ns_abbrevs->data, element->default_ns_abbrev)==0)
896 attr = xmpp_get_attr_ext(pinfo, element, attrs[i].info.name, "");
898 if (attr) {
899 if (attrs[i].info.phf != NULL) {
900 if (attr->name)
901 proto_tree_add_string_format(tree, *attrs[i].info.phf, tvb, attr->offset, attr->length, attr->value, "%s: %s", attr->name, attr->value);
902 else
903 proto_tree_add_string(tree, *attrs[i].info.phf, tvb, attr->offset, attr->length, attr->value);
904 } else {
905 proto_tree_add_string_format(tree, hf_xmpp_attribute, tvb, attr->offset, attr->length, attr->value,
906 "%s: %s", attr->name ? attr->name : attrs[i].info.name, attr->value);
909 if (attrs[i].info.in_short_list) {
910 if (short_list_started) {
911 proto_item_append_text(item, " ");
913 proto_item_append_text(item, "%s=\"%s\"", attr->name ? attr->name : attrs[i].info.name, attr->value);
914 short_list_started = true;
917 } else if (attrs[i].info.is_required) {
918 expert_add_info_format(pinfo, item, &ei_xmpp_required_attribute, "Required attribute \"%s\" doesn't appear in \"%s\".", attrs[i].info.name, element->name);
921 if (attrs[i].info.val_func) {
922 if (attr)
923 attrs[i].info.val_func(pinfo, item, attrs[i].info.name, attr->value, attrs[i].info.data);
924 else
925 attrs[i].info.val_func(pinfo, item, attrs[i].info.name, NULL, attrs[i].info.data);
929 ns_abbrevs = ns_abbrevs->next;
930 ns_fullnames = ns_fullnames->next;
932 proto_item_append_text(item,"]");
934 /*displays attributes that weren't recognized*/
935 xmpp_unknown_attrs(tree, tvb, pinfo, element, false);
937 g_list_free(ns_abbrevs_head);
938 g_list_free(ns_fullnames_head);
941 typedef struct _name_attr_t
943 const char *name;
944 const char *attr_name;
945 const char *attr_value;
946 } name_attr_t;
949 returns pointer to the struct that contains 3 strings(element name, attribute name, attribute value)
951 void *
952 xmpp_name_attr_struct(wmem_allocator_t *pool, const char *name, const char *attr_name, const char *attr_value)
954 name_attr_t *result;
956 result = wmem_new(pool, name_attr_t);
957 result->name = name;
958 result->attr_name = attr_name;
959 result->attr_value = attr_value;
960 return result;
963 void
964 xmpp_display_elems(proto_tree *tree, xmpp_element_t *parent, packet_info *pinfo, tvbuff_t *tvb, xmpp_elem_info *elems, unsigned n)
966 unsigned i;
968 for(i = 0; i < n && elems!=NULL; i++)
970 xmpp_element_t *elem = NULL;
972 if(elems[i].type == NAME_AND_ATTR)
974 bool loop = true;
976 const name_attr_t *a = (const name_attr_t *)(elems[i].data);
978 while(loop && (elem = xmpp_steal_element_by_name_and_attr(parent, a->name, a->attr_name, a->attr_value))!=NULL)
980 elems[i].elem_func(tree, tvb, pinfo, elem);
981 if(elems[i].occurrence == ONE)
982 loop = false;
984 } else if(elems[i].type == NAME)
986 bool loop = true;
987 const char *name = (const char *)(elems[i].data);
989 while(loop && (elem = xmpp_steal_element_by_name(parent, name))!=NULL)
991 elems[i].elem_func(tree, tvb, pinfo, elem);
992 if(elems[i].occurrence == ONE)
993 loop = false;
996 else if(elems[i].type == ATTR)
998 bool loop = true;
999 const name_attr_t *attr = (const name_attr_t *)(elems[i].data);
1001 while(loop && (elem = xmpp_steal_element_by_attr(parent, attr->attr_name, attr->attr_value))!=NULL)
1003 elems[i].elem_func(tree, tvb, pinfo, elem);
1004 if(elems[i].occurrence == ONE)
1005 loop = false;
1008 } else if(elems[i].type == NAMES)
1010 bool loop = true;
1011 const xmpp_array_t *names = (const xmpp_array_t *)(elems[i].data);
1013 while(loop && (elem = xmpp_steal_element_by_names(parent, (const char**)names->data, names->length))!=NULL)
1015 elems[i].elem_func(tree, tvb, pinfo, elem);
1016 if(elems[i].occurrence == ONE)
1017 loop = false;
1022 xmpp_unknown(tree, tvb, pinfo, parent);
1026 function checks that variable value is in array ((xmpp_array_t)data)->data
1028 void
1029 xmpp_val_enum_list(packet_info *pinfo, proto_item *item, const char *name, const char *value, const void *data)
1031 const xmpp_array_t *enums_array = (const xmpp_array_t *)data;
1033 int i;
1034 bool value_in_enums = false;
1036 char **enums = (char**)enums_array->data;
1038 if (value != NULL) {
1039 for (i = 0; i < enums_array->length; i++) {
1040 if (strcmp(value, enums[i]) == 0) {
1041 value_in_enums = true;
1042 break;
1045 if (!value_in_enums) {
1046 expert_add_info_format(pinfo, item, &ei_xmpp_field_unexpected_value, "Field \"%s\" has unexpected value \"%s\"", name, value);
1052 void
1053 xmpp_change_elem_to_attrib(wmem_allocator_t *pool, const char *elem_name, const char *attr_name, xmpp_element_t *parent, xmpp_attr_t* (*transform_func)(wmem_allocator_t *pool, xmpp_element_t *element))
1055 xmpp_element_t *element = NULL;
1056 xmpp_attr_t *fake_attr = NULL;
1058 element = xmpp_steal_element_by_name(parent, elem_name);
1059 if(element)
1060 fake_attr = transform_func(pool, element);
1062 if(fake_attr)
1063 g_hash_table_insert(parent->attrs, (void *)attr_name, fake_attr);
1066 xmpp_attr_t*
1067 xmpp_transform_func_cdata(wmem_allocator_t *pool, xmpp_element_t *elem)
1069 xmpp_attr_t *result = xmpp_ep_init_attr_t(pool, elem->data?elem->data->value:"", elem->offset, elem->length);
1070 return result;
1073 #if 0
1074 static void
1075 printf_hash_table_func(void *key, void *value, void *user_data _U_)
1077 printf("'%s' '%s'\n", (char*)key, (char*)value);
1080 void
1081 printf_elements(xmpp_element_t *root)
1083 GList *elems = root->elements;
1085 printf("%s\n", root->name);
1086 g_hash_table_foreach(root->namespaces, printf_hash_table_func, NULL);
1087 while(elems)
1089 printf_elements(elems->data);
1090 elems = elems->next;
1093 #endif
1096 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1098 * Local variables:
1099 * c-basic-offset: 4
1100 * tab-width: 8
1101 * indent-tabs-mode: nil
1102 * End:
1104 * ex: set shiftwidth=4 tabstop=8 expandtab:
1105 * :indentSize=4:tabSize=8:noTabs=true: