wireshark/epan/dissectors/packet-xmpp-utils.c
Guy Harris 8ed7a73e22 Fix a bunch of warnings.
Cast away some implicit 64-bit-to-32-bit conversion errors due to use of
sizeof.

Cast away some implicit 64-bit-to-32-bit conversion errors due to use of
strtol() and strtoul().

Change some data types to avoid those implicit conversion warnings.

When assigning a constant to a float, make sure the constant isn't a
double, by appending "f" to the constant.

Constify a bunch of variables, parameters, and return values to
eliminate warnings due to strings being given const qualifiers.  Cast
away those warnings in some cases where an API we don't control forces
us to do so.

Enable a bunch of additional warnings by default.  Note why at least
some of the other warnings aren't enabled.

randpkt.c and text2pcap.c are used to build programs, so they don't need
to be in EXTRA_DIST.

If the user specifies --enable-warnings-as-errors, add -Werror *even if
the user specified --enable-extra-gcc-flags; assume they know what
they're doing and are willing to have the compile fail due to the extra
GCC warnings being treated as errors.

svn path=/trunk/; revision=46748
2012-12-26 05:57:06 +00:00

1138 lines
32 KiB
C

/* xmpp-utils.c
* Wireshark's XMPP dissector.
*
* Copyright 2011, Mariusz Okroj <okrojmariusz[]gmail.com>
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <epan/packet.h>
#include <epan/expert.h>
#include <epan/tvbparse.h>
#include <epan/strutil.h>
#include <epan/dissectors/packet-xml.h>
#include <packet-xmpp.h>
#include <packet-xmpp-core.h>
#include <packet-xmpp-utils.h>
void
xmpp_iq_reqresp_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
{
xmpp_transaction_t *xmpp_trans = NULL;
xmpp_attr_t *attr_id;
char *id;
attr_id = xmpp_get_attr(packet, "id");
if (!attr_id) {
return;
}
id = ep_strdup(attr_id->value);
if (!pinfo->fd->flags.visited) {
xmpp_trans = se_tree_lookup_string(xmpp_info->req_resp, id, EMEM_TREE_STRING_NOCASE);
if (xmpp_trans) {
xmpp_trans->resp_frame = pinfo->fd->num;
} else {
char *se_id = se_strdup(id);
xmpp_trans = se_alloc(sizeof (xmpp_transaction_t));
xmpp_trans->req_frame = pinfo->fd->num;
xmpp_trans->resp_frame = 0;
se_tree_insert_string(xmpp_info->req_resp, se_id, (void *) xmpp_trans, EMEM_TREE_STRING_NOCASE);
}
} else {
se_tree_lookup_string(xmpp_info->req_resp, id, EMEM_TREE_STRING_NOCASE);
}
}
void
xmpp_jingle_session_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
{
xmpp_element_t *jingle_packet;
GList *jingle_packet_l;
jingle_packet_l = xmpp_find_element_by_name(packet,"jingle");
jingle_packet = jingle_packet_l?jingle_packet_l->data:NULL;
if (jingle_packet && !pinfo->fd->flags.visited) {
xmpp_attr_t *attr_id;
xmpp_attr_t *attr_sid;
char *se_id;
char *se_sid;
attr_id = xmpp_get_attr(packet, "id");
if (!attr_id) {
return;
}
attr_sid = xmpp_get_attr(jingle_packet, "sid");
if (!attr_sid) {
return;
}
se_id = se_strdup(attr_id->value);
se_sid = se_strdup(attr_sid->value);
se_tree_insert_string(xmpp_info->jingle_sessions, se_id, (void*) se_sid, EMEM_TREE_STRING_NOCASE);
}
}
void
xmpp_gtalk_session_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
{
xmpp_element_t *gtalk_packet;
GList *gtalk_packet_l;
gtalk_packet_l = xmpp_find_element_by_name(packet,"session");
gtalk_packet = gtalk_packet_l?gtalk_packet_l->data:NULL;
if (gtalk_packet && !pinfo->fd->flags.visited) {
xmpp_attr_t *attr_id;
xmpp_attr_t *attr_sid;
char *se_id;
char *se_sid;
xmpp_attr_t *xmlns = xmpp_get_attr(gtalk_packet, "xmlns");
if(xmlns && strcmp(xmlns->value,"http://www.google.com/session") != 0)
return;
attr_id = xmpp_get_attr(packet, "id");
if (!attr_id) {
return;
}
attr_sid = xmpp_get_attr(gtalk_packet, "id");
if (!attr_sid) {
return;
}
se_id = se_strdup(attr_id->value);
se_sid = se_strdup(attr_sid->value);
se_tree_insert_string(xmpp_info->gtalk_sessions, se_id, (void*) se_sid, EMEM_TREE_STRING_NOCASE);
}
}
void
xmpp_ibb_session_track(packet_info *pinfo, xmpp_element_t *packet, xmpp_conv_info_t *xmpp_info)
{
xmpp_element_t *ibb_packet = NULL;
GList *ibb_packet_l;
if(strcmp(packet->name, "message") == 0)
{
ibb_packet_l = xmpp_find_element_by_name(packet,"data");
ibb_packet = ibb_packet_l?ibb_packet_l->data:NULL;
} else if(strcmp(packet->name, "iq") == 0)
{
ibb_packet_l = xmpp_find_element_by_name(packet,"open");
if(!ibb_packet_l)
ibb_packet_l = xmpp_find_element_by_name(packet,"close");
if(!ibb_packet_l)
ibb_packet_l = xmpp_find_element_by_name(packet,"data");
ibb_packet = ibb_packet_l?ibb_packet_l->data:NULL;
}
if (ibb_packet && !pinfo->fd->flags.visited) {
xmpp_attr_t *attr_id;
xmpp_attr_t *attr_sid;
char *se_id;
char *se_sid;
attr_id = xmpp_get_attr(packet, "id");
attr_sid = xmpp_get_attr(ibb_packet, "sid");
if(attr_id && attr_sid)
{
se_id = se_strdup(attr_id->value);
se_sid = se_strdup(attr_sid->value);
se_tree_insert_string(xmpp_info->ibb_sessions, se_id, (void*) se_sid, EMEM_TREE_STRING_NOCASE);
}
}
}
static void
xmpp_unknown_items(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, xmpp_element_t *element, guint level)
{
GList *childs = element->elements;
DISSECTOR_ASSERT( level < ETT_UNKNOWN_LEN );
xmpp_unknown_attrs(tree, tvb, pinfo, element, TRUE);
if(element->data)
{
proto_tree_add_text(tree, tvb, element->data->offset, element->data->length, "CDATA: %s",element->data->value);
}
while(childs)
{
xmpp_element_t *child = childs->data;
proto_item *child_item = proto_tree_add_text(tree, tvb, child->offset, child->length, "%s", xmpp_ep_string_upcase(child->name));
proto_tree *child_tree = proto_item_add_subtree(child_item, ett_unknown[level]);
if(child->default_ns_abbrev)
proto_item_append_text(child_item, "(%s)", child->default_ns_abbrev);
xmpp_unknown_items(child_tree, tvb, pinfo, child, level +1);
childs = childs->next;
}
}
void
xmpp_unknown(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, xmpp_element_t *element)
{
GList *childs = element->elements;
/*element has unrecognized elements*/
while(childs)
{
xmpp_element_t *child = childs->data;
if(!child->was_read)
{
proto_item *unknown_item;
proto_tree *unknown_tree;
#ifdef XMPP_DEBUG
unknown_item = proto_tree_add_string_format(tree,
hf_xmpp_unknown, tvb, child->offset, child->length, child->name,
"%s", xmpp_ep_string_upcase(child->name));
#else
unknown_item = proto_tree_add_text(tree, tvb, child->offset, child->length,
"%s", xmpp_ep_string_upcase(child->name));
#endif
unknown_tree = proto_item_add_subtree(unknown_item, ett_unknown[0]);
/*Add COL_INFO only if root element is IQ*/
if(strcmp(element->name,"iq")==0)
col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", xmpp_ep_string_upcase(child->name));
if(child->default_ns_abbrev)
proto_item_append_text(unknown_item,"(%s)",child->default_ns_abbrev);
xmpp_unknown_items(unknown_tree, tvb, pinfo, child, 1);
#ifdef XMPP_DEBUG
proto_item_append_text(unknown_item, " [UNKNOWN]");
expert_add_info_format(pinfo, unknown_item, PI_UNDECODED, PI_NOTE,"Unknown element: %s", child->name);
#endif
}
childs = childs->next;
}
}
void
xmpp_unknown_attrs(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, xmpp_element_t *element, gboolean displ_short_list)
{
proto_item *item = proto_tree_get_parent(tree);
GList *keys = g_hash_table_get_keys(element->attrs);
GList *values = g_hash_table_get_values(element->attrs);
GList *keys_head = keys, *values_head = values;
gboolean short_list_started = FALSE;
while(keys && values)
{
xmpp_attr_t *attr = (xmpp_attr_t*) values->data;
if (!attr->was_read) {
if (displ_short_list) {
if (!short_list_started)
proto_item_append_text(item, " [");
else
proto_item_append_text(item, " ");
proto_item_append_text(item, "%s=\"%s\"", (gchar*) keys->data, attr->value);
short_list_started = TRUE;
}
/*If unknown element has xmlns attrib then header field hf_xmpp_xmlns is added to the tree.
In other case only text.*/
if (strcmp(keys->data, "xmlns") == 0)
proto_tree_add_string(tree, hf_xmpp_xmlns, tvb, attr->offset, attr->length, attr->value);
else {
/*xmlns may looks like xmlns:abbrev="sth"*/
gchar* xmlns_needle = epan_strcasestr(keys->data, "xmlns:");
if (xmlns_needle && xmlns_needle == keys->data) {
proto_tree_add_string_format(tree, hf_xmpp_xmlns, tvb, attr->offset, attr->length, attr->value,"%s: %s", (gchar*)keys->data, attr->value);
} else {
#ifdef XMPP_DEBUG
proto_item* unknown_attr_item;
unknown_attr_item = proto_tree_add_string_format(tree,
hf_xmpp_unknown_attr, tvb, attr->offset, attr->length,
attr->name, "%s: %s", attr->name, attr->value);
proto_item_append_text(unknown_attr_item, " [UNKNOWN ATTR]");
expert_add_info_format(pinfo, unknown_attr_item, PI_UNDECODED, PI_NOTE, "Unknown attribute %s.", attr->name);
#else
proto_tree_add_text(tree, tvb, attr->offset, attr->length,
"%s: %s", attr->name, attr->value);
#endif
}
}
}
keys = keys->next;
values = values->next;
}
if(short_list_started && displ_short_list)
proto_item_append_text(item, "]");
g_list_free(keys_head);
g_list_free(values_head);
}
void
xmpp_cdata(proto_tree *tree, tvbuff_t *tvb, xmpp_element_t *element, gint hf)
{
if(element->data)
{
if (hf == -1) {
proto_tree_add_text(tree, tvb, element->data->offset, element->data->length, "CDATA: %s", element->data->value);
} else {
proto_tree_add_string(tree, hf, tvb, element->data->offset, element->data->length, element->data->value);
}
} else
{
if (hf == -1) {
proto_tree_add_text(tree, tvb, 0, 0, "CDATA: (empty)");
} else {
proto_tree_add_string(tree, hf, tvb, 0, 0, "");
}
}
}
/* displays element that looks like <element_name>element_value</element_name>
* ELEMENT_NAME: element_value as TEXT(proto_tree_add_text) int PROTO_TREE
*/
void
xmpp_simple_cdata_elem(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, xmpp_element_t *element)
{
proto_tree_add_text(tree, tvb, element->offset, element->length, "%s: %s", xmpp_ep_string_upcase(element->name), xmpp_elem_cdata(element));
}
xmpp_array_t*
xmpp_ep_init_array_t(const gchar** array, gint len)
{
xmpp_array_t *result;
result = ep_alloc(sizeof(xmpp_array_t));
result->data = (gpointer) array;
result->length = len;
return result;
}
xmpp_attr_t*
xmpp_ep_init_attr_t(const gchar *value, gint offset, gint length)
{
xmpp_attr_t *result;
result = ep_alloc(sizeof(xmpp_attr_t));
result->value = value;
result->offset = offset;
result->length = length;
result->name = NULL;
return result;
}
gchar*
xmpp_ep_string_upcase(const gchar* string)
{
gint len = (int)strlen(string);
gint i;
gchar* result = ep_alloc0(len+1);
for(i=0; i<len; i++)
{
result[i] = string[i];
if(string[i]>='a' && string[i]<='z')
result[i]-='a'-'A';
}
return result;
}
gint
xmpp_element_t_cmp(gconstpointer a, gconstpointer b)
{
gint result = strcmp(((xmpp_element_t*)a)->name,((xmpp_element_t*)b)->name);
if(result == 0 && ((xmpp_element_t*)a)->was_read)
result = -1;
return result;
}
GList*
xmpp_find_element_by_name(xmpp_element_t *packet,const gchar *name)
{
GList *found_elements;
xmpp_element_t *search_element;
/*create fake element only with name*/
search_element = ep_alloc(sizeof(xmpp_element_t));
search_element->name = ep_strdup(name);
found_elements = g_list_find_custom(packet->elements, search_element, xmpp_element_t_cmp);
if(found_elements)
return found_elements;
else
return NULL;
}
/* steal_*
* function searches element in packet and sets it as read.
* if element doesn't exist, NULL is returned.
* If element is set as read, it is invisible for these functions.*/
xmpp_element_t*
xmpp_steal_element_by_name(xmpp_element_t *packet,const gchar *name)
{
GList *element_l;
xmpp_element_t *element = NULL;
element_l = xmpp_find_element_by_name(packet, name);
if(element_l)
{
element = element_l->data;
element->was_read = TRUE;
}
return element;
}
xmpp_element_t*
xmpp_steal_element_by_names(xmpp_element_t *packet, const gchar **names, gint names_len)
{
gint i;
xmpp_element_t *el = NULL;
for(i = 0; i<names_len; i++)
{
if((el = xmpp_steal_element_by_name(packet, names[i])))
break;
}
return el;
}
xmpp_element_t*
xmpp_steal_element_by_attr(xmpp_element_t *packet, const gchar *attr_name, const gchar *attr_value)
{
GList *childs = packet->elements;
xmpp_element_t *result = NULL;
while (childs) {
xmpp_element_t *child_elem = childs->data;
xmpp_attr_t *attr = xmpp_get_attr(child_elem, attr_name);
if(attr)
attr->was_read = FALSE;
if (!child_elem->was_read && attr && strcmp(attr->value, attr_value) == 0) {
result = childs->data;
result->was_read = TRUE;
break;
} else
childs = childs->next;
}
return result;
}
xmpp_element_t*
xmpp_steal_element_by_name_and_attr(xmpp_element_t *packet, const gchar *name, const gchar *attr_name, const gchar *attr_value)
{
GList *childs = packet->elements;
xmpp_element_t *result = NULL;
while (childs) {
xmpp_element_t *child_elem = childs->data;
xmpp_attr_t *attr = xmpp_get_attr(child_elem, attr_name);
if(attr)
attr->was_read = FALSE;
if (!child_elem->was_read && attr && strcmp(child_elem->name, name) == 0 && strcmp(attr->value, attr_value) == 0) {
result = childs->data;
result->was_read = TRUE;
break;
} else
childs = childs->next;
}
return result;
}
xmpp_element_t*
xmpp_get_first_element(xmpp_element_t *packet)
{
if(packet->elements && packet->elements->data)
return packet->elements->data;
else
return NULL;
}
/*
Function converts xml_frame_t structure to xmpp_element_t (simpler representation)
*/
xmpp_element_t*
xmpp_xml_frame_to_element_t(xml_frame_t *xml_frame, xmpp_element_t *parent, tvbuff_t *tvb)
{
xml_frame_t *child;
xmpp_element_t *node = ep_alloc0(sizeof(xmpp_element_t));
tvbparse_t* tt;
tvbparse_elem_t* elem;
node->attrs = g_hash_table_new(g_str_hash, g_str_equal);
node->elements = NULL;
node->data = NULL;
node->was_read = FALSE;
node->default_ns_abbrev = NULL;
node->name = ep_strdup(xml_frame->name_orig_case);
node->offset = 0;
node->length = 0;
node->namespaces = g_hash_table_new(g_str_hash, g_str_equal);
if(parent)
{
xmpp_copy_hash_table(parent->namespaces, node->namespaces);
} else
{
g_hash_table_insert(node->namespaces, (gpointer)"", (gpointer)"jabber:client");
}
if(xml_frame->item != NULL)
{
node->length = xml_frame->item->finfo->length;
}
node->offset = xml_frame->start_offset;
tt = tvbparse_init(tvb,node->offset,-1,NULL,want_ignore);
if((elem = tvbparse_get(tt,want_stream_end_with_ns))!=NULL)
{
node->default_ns_abbrev = tvb_get_ephemeral_string(elem->sub->tvb, elem->sub->offset, elem->sub->len);
}
child = xml_frame->first_child;
while(child)
{
if(child->type != XML_FRAME_TAG)
{
if(child->type == XML_FRAME_ATTRIB)
{
gint l;
gchar *value = NULL;
gchar *xmlns_needle = NULL;
xmpp_attr_t *attr = ep_alloc(sizeof(xmpp_attr_t));
attr->length = 0;
attr->offset = 0;
attr->was_read = FALSE;
if (child->value != NULL) {
l = tvb_reported_length(child->value);
value = ep_alloc0(l + 1);
tvb_memcpy(child->value, value, 0, l);
}
if(child->item)
{
attr->length = child->item->finfo->length;
}
attr->offset = child->start_offset;
attr->value = value;
attr->name = ep_strdup(child->name_orig_case);
g_hash_table_insert(node->attrs,(gpointer)attr->name,(gpointer)attr);
/*checking that attr->name looks like xmlns:ns*/
xmlns_needle = epan_strcasestr(attr->name, "xmlns");
if(xmlns_needle == attr->name)
{
if(attr->name[5] == ':' && strlen(attr->name) > 6)
{
g_hash_table_insert(node->namespaces, (gpointer)ep_strdup(&attr->name[6]), (gpointer)ep_strdup(attr->value));
} else if(attr->name[5] == '\0')
{
g_hash_table_insert(node->namespaces, (gpointer)"", (gpointer)ep_strdup(attr->value));
}
}
}
else if( child->type == XML_FRAME_CDATA)
{
xmpp_data_t *data = NULL;
gint l;
gchar* value = NULL;
data = ep_alloc(sizeof(xmpp_data_t));
data->length = 0;
data->offset = 0;
if (child->value != NULL) {
l = tvb_reported_length(child->value);
value = ep_alloc0(l + 1);
tvb_memcpy(child->value, value, 0, l);
}
data->value = value;
if(child->item)
{
data->length = child->item->finfo->length;
}
data->offset = child->start_offset;
node->data = data;
}
} else
{
node->elements = g_list_append(node->elements,(gpointer)xmpp_xml_frame_to_element_t(child, node,tvb));
}
child = child->next_sibling;
}
return node;
}
void
xmpp_element_t_tree_free(xmpp_element_t *root)
{
GList *childs = root->elements;
g_hash_table_destroy(root->attrs);
g_hash_table_destroy(root->namespaces);
while(childs)
{
xmpp_element_t *child = childs->data;
xmpp_element_t_tree_free(child);
childs = childs->next;
}
g_list_free(root->elements);
}
/*Function recognize attribute names if they looks like xmlns:ns*/
static gboolean
attr_find_pred(gpointer key, gpointer value _U_, gpointer user_data)
{
gchar *attr_name = (gchar*) user_data;
if( strcmp(attr_name, "xmlns") == 0 )
{
gchar *first_occur = epan_strcasestr(key, "xmlns:");
if(first_occur && first_occur == key)
return TRUE;
else
return FALSE;
}
return FALSE;
}
/*Functions returns element's attibute by name and set as read*/
xmpp_attr_t*
xmpp_get_attr(xmpp_element_t *element, const gchar* attr_name)
{
xmpp_attr_t *result = g_hash_table_lookup(element->attrs, attr_name);
if(!result)
{
result = g_hash_table_find(element->attrs, attr_find_pred, (gpointer)attr_name);
}
if(result)
result->was_read = TRUE;
return result;
}
/*Functions returns element's attibute by name and namespace abbrev*/
static xmpp_attr_t*
xmpp_get_attr_ext(xmpp_element_t *element, const gchar* attr_name, const gchar* ns_abbrev)
{
gchar* search_phrase;
xmpp_attr_t *result;
if(strcmp(ns_abbrev,"")==0)
search_phrase = ep_strdup(attr_name);
else if(strcmp(attr_name, "xmlns") == 0)
search_phrase = ep_strdup_printf("%s:%s",attr_name, ns_abbrev);
else
search_phrase = ep_strdup_printf("%s:%s", ns_abbrev, attr_name);
result = g_hash_table_lookup(element->attrs, search_phrase);
if(!result)
{
result = g_hash_table_find(element->attrs, attr_find_pred, (gpointer)attr_name);
}
if(result)
result->was_read = TRUE;
return result;
}
gchar*
xmpp_element_to_string(tvbuff_t *tvb, xmpp_element_t *element)
{
gchar *buff = NULL;
if(tvb_offset_exists(tvb, element->offset+element->length-1))
{
buff = tvb_get_ephemeral_string(tvb, element->offset, element->length);
}
return buff;
}
gchar*
xmpp_attr_to_string(tvbuff_t *tvb, xmpp_attr_t *attr)
{
gchar *buff = NULL;
if(tvb_offset_exists(tvb, attr->offset + attr->length-1))
{
buff = tvb_get_ephemeral_string(tvb, attr->offset, attr->length);
}
return buff;
}
static void
children_foreach_hide_func(proto_node *node, gpointer data)
{
int *i = data;
if((*i) == 0)
PROTO_ITEM_SET_HIDDEN(node);
(*i)++;
}
static void
children_foreach_show_func(proto_node *node, gpointer data)
{
int *i = data;
if((*i) == 0)
PROTO_ITEM_SET_VISIBLE(node);
(*i)++;
}
void
xmpp_proto_tree_hide_first_child(proto_tree *tree)
{
int i = 0;
proto_tree_children_foreach(tree, children_foreach_hide_func, &i);
}
void
xmpp_proto_tree_show_first_child(proto_tree *tree)
{
int i = 0;
proto_tree_children_foreach(tree, children_foreach_show_func, &i);
}
gchar*
proto_item_get_text(proto_item *item)
{
field_info *fi = NULL;
gchar *result;
if(item == NULL)
return NULL;
fi = PITEM_FINFO(item);
if(fi==NULL)
return NULL;
if (fi->rep == NULL)
return NULL;
result = ep_strdup(fi->rep->representation);
return result;
}
void
xmpp_display_attrs(proto_tree *tree, xmpp_element_t *element, packet_info *pinfo, tvbuff_t *tvb, xmpp_attr_info *attrs, guint n)
{
proto_item *item = proto_tree_get_parent(tree);
xmpp_attr_t *attr;
guint i;
gboolean short_list_started = FALSE;
if(element->default_ns_abbrev)
proto_item_append_text(item, "(%s)",element->default_ns_abbrev);
proto_item_append_text(item," [");
for(i = 0; i < n && attrs!=NULL; i++)
{
attr = xmpp_get_attr(element, attrs[i].name);
if(attr)
{
if(attrs[i].hf != -1)
{
if(attr->name)
proto_tree_add_string_format(tree, attrs[i].hf, tvb, attr->offset, attr->length, attr->value,"%s: %s", attr->name, attr->value);
else
proto_tree_add_string(tree, attrs[i].hf, tvb, attr->offset, attr->length, attr->value);
}
else
{
proto_tree_add_text(tree, tvb, attr->offset, attr->length, "%s: %s", attr->name?attr->name:attrs[i].name, attr->value);
}
if(attrs[i].in_short_list)
{
if(short_list_started)
{
proto_item_append_text(item," ");
}
proto_item_append_text(item,"%s=\"%s\"",attr->name?attr->name:attrs[i].name, attr->value);
short_list_started = TRUE;
}
} else if(attrs[i].is_required)
{
expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN,
"Required attribute \"%s\" doesn't appear in \"%s\".",attrs[i].name,
element->name);
}
if(attrs[i].val_func)
{
if(attr)
attrs[i].val_func(pinfo, item, attrs[i].name, attr->value, attrs[i].data);
else
attrs[i].val_func(pinfo, item, attrs[i].name, NULL, attrs[i].data);
}
}
proto_item_append_text(item,"]");
/*displays attributes that weren't recognized*/
xmpp_unknown_attrs(tree, tvb, pinfo, element, FALSE);
}
void
xmpp_display_attrs_ext(proto_tree *tree, xmpp_element_t *element, packet_info *pinfo, tvbuff_t *tvb, xmpp_attr_info_ext *attrs, guint n)
{
proto_item *item = proto_tree_get_parent(tree);
xmpp_attr_t *attr;
guint i;
gboolean short_list_started = FALSE;
GList *ns_abbrevs_head, *ns_abbrevs = g_hash_table_get_keys(element->namespaces);
GList *ns_fullnames_head, *ns_fullnames = g_hash_table_get_values(element->namespaces);
ns_abbrevs_head = ns_abbrevs;
ns_fullnames_head = ns_fullnames;
if(element->default_ns_abbrev)
proto_item_append_text(item, "(%s)",element->default_ns_abbrev);
proto_item_append_text(item," [");
while(ns_abbrevs && ns_fullnames)
{
for (i = 0; i < n && attrs != NULL; i++) {
if(strcmp(ns_fullnames->data, attrs[i].ns) == 0)
{
attr = xmpp_get_attr_ext(element, attrs[i].info.name, ns_abbrevs->data);
if(!attr && element->default_ns_abbrev && strcmp(ns_abbrevs->data, element->default_ns_abbrev)==0)
attr = xmpp_get_attr_ext(element, attrs[i].info.name, "");
if (attr) {
if (attrs[i].info.hf != -1) {
if (attr->name)
proto_tree_add_string_format(tree, attrs[i].info.hf, tvb, attr->offset, attr->length, attr->value, "%s: %s", attr->name, attr->value);
else
proto_tree_add_string(tree, attrs[i].info.hf, tvb, attr->offset, attr->length, attr->value);
} else {
proto_tree_add_text(tree, tvb, attr->offset, attr->length, "%s: %s", attr->name ? attr->name : attrs[i].info.name, attr->value);
}
if (attrs[i].info.in_short_list) {
if (short_list_started) {
proto_item_append_text(item, " ");
}
proto_item_append_text(item, "%s=\"%s\"", attr->name ? attr->name : attrs[i].info.name, attr->value);
short_list_started = TRUE;
}
} else if (attrs[i].info.is_required) {
expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN,
"Required attribute \"%s\" doesn't appear in \"%s\".", attrs[i].info.name,
element->name);
}
if (attrs[i].info.val_func) {
if (attr)
attrs[i].info.val_func(pinfo, item, attrs[i].info.name, attr->value, attrs[i].info.data);
else
attrs[i].info.val_func(pinfo, item, attrs[i].info.name, NULL, attrs[i].info.data);
}
}
}
ns_abbrevs = ns_abbrevs->next;
ns_fullnames = ns_fullnames->next;
}
proto_item_append_text(item,"]");
/*displays attributes that weren't recognized*/
xmpp_unknown_attrs(tree, tvb, pinfo, element, FALSE);
g_list_free(ns_abbrevs_head);
g_list_free(ns_fullnames_head);
}
struct name_attr_t
{
const gchar *name;
const gchar *attr_name;
const gchar *attr_value;
};
/*
returns pointer to the struct that contains 3 strings(element name, attribute name, attribute value)
*/
gpointer
xmpp_name_attr_struct(const gchar *name, const gchar *attr_name, const gchar *attr_value)
{
struct name_attr_t *result;
result = ep_alloc(sizeof(struct name_attr_t));
result->name = name;
result->attr_name = attr_name;
result->attr_value = attr_value;
return result;
}
void
xmpp_display_elems(proto_tree *tree, xmpp_element_t *parent, packet_info *pinfo, tvbuff_t *tvb, xmpp_elem_info *elems, guint n)
{
guint i;
for(i = 0; i < n && elems!=NULL; i++)
{
xmpp_element_t *elem = NULL;
if(elems[i].type == NAME_AND_ATTR)
{
gboolean loop = TRUE;
const struct
{
gchar *name;
gchar *attr_name;
gchar *attr_value;
} *a;
a = elems[i].data;
while(loop && (elem = xmpp_steal_element_by_name_and_attr(parent, a->name, a->attr_name, a->attr_value))!=NULL)
{
elems[i].elem_func(tree, tvb, pinfo, elem);
if(elems[i].occurrence == ONE)
loop = FALSE;
}
} else if(elems[i].type == NAME)
{
gboolean loop = TRUE;
const gchar *name = elems[i].data;
while(loop && (elem = xmpp_steal_element_by_name(parent, name))!=NULL)
{
elems[i].elem_func(tree, tvb, pinfo, elem);
if(elems[i].occurrence == ONE)
loop = FALSE;
}
}
else if(elems[i].type == ATTR)
{
gboolean loop = TRUE;
const struct {
gchar *name;
gchar *attr_name;
gchar *attr_value;
} *attr = elems[i].data;
while(loop && (elem = xmpp_steal_element_by_attr(parent, attr->attr_name, attr->attr_value))!=NULL)
{
elems[i].elem_func(tree, tvb, pinfo, elem);
if(elems[i].occurrence == ONE)
loop = FALSE;
}
} else if(elems[i].type == NAMES)
{
gboolean loop = TRUE;
const xmpp_array_t *names = elems[i].data;
while(loop && (elem = xmpp_steal_element_by_names(parent, (const gchar**)names->data, names->length))!=NULL)
{
elems[i].elem_func(tree, tvb, pinfo, elem);
if(elems[i].occurrence == ONE)
loop = FALSE;
}
}
}
xmpp_unknown(tree, tvb, pinfo, parent);
}
/*
function checks that variable value is in array ((xmpp_array_t)data)->data
*/
void
xmpp_val_enum_list(packet_info *pinfo, proto_item *item, const gchar *name, const gchar *value, gconstpointer data)
{
const xmpp_array_t *enums_array = data;
gint i;
gboolean value_in_enums = FALSE;
gchar **enums = (char**)enums_array->data;
if (value != NULL) {
for (i = 0; i < enums_array->length; i++) {
if (strcmp(value, enums[i]) == 0) {
value_in_enums = TRUE;
break;
}
}
if (!value_in_enums) {
expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN,
"Field \"%s\" has unexpected value \"%s\"",
name, value);
}
}
}
void
xmpp_change_elem_to_attrib(const gchar *elem_name, const gchar *attr_name, xmpp_element_t *parent, xmpp_attr_t* (*transform_func)(xmpp_element_t *element))
{
xmpp_element_t *element = NULL;
xmpp_attr_t *fake_attr = NULL;
element = xmpp_steal_element_by_name(parent, elem_name);
if(element)
fake_attr = transform_func(element);
if(fake_attr)
g_hash_table_insert(parent->attrs, (gpointer)attr_name, fake_attr);
}
xmpp_attr_t*
xmpp_transform_func_cdata(xmpp_element_t *elem)
{
xmpp_attr_t *result = xmpp_ep_init_attr_t(elem->data?elem->data->value:"", elem->offset, elem->length);
return result;
}
static void
xmpp_copy_hash_table_func(gpointer key, gpointer value, gpointer user_data)
{
GHashTable *dst = user_data;
g_hash_table_insert(dst, key, value);
}
void xmpp_copy_hash_table(GHashTable *src, GHashTable *dst)
{
g_hash_table_foreach(src, xmpp_copy_hash_table_func, dst);
}
#if 0
static void
printf_hash_table_func(gpointer key, gpointer value, gpointer user_data _U_)
{
printf("'%s' '%s'\n", (gchar*)key, (gchar*)value);
}
void
printf_elements(xmpp_element_t *root)
{
GList *elems = root->elements;
printf("%s\n", root->name);
g_hash_table_foreach(root->namespaces, printf_hash_table_func, NULL);
while(elems)
{
printf_elements(elems->data);
elems = elems->next;
}
}
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/