diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-imf.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-imf.c')
-rw-r--r-- | epan/dissectors/packet-imf.c | 1410 |
1 files changed, 1410 insertions, 0 deletions
diff --git a/epan/dissectors/packet-imf.c b/epan/dissectors/packet-imf.c new file mode 100644 index 00000000..95be6b1a --- /dev/null +++ b/epan/dissectors/packet-imf.c @@ -0,0 +1,1410 @@ +/* packet-imf.c + * Routines for Internet Message Format (IMF) packet disassembly + * + * Copyright (c) 2007 by Graeme Lunt + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/uat.h> +#include <epan/expert.h> +#include <wsutil/str_util.h> + +#include <epan/tap.h> +#include <epan/export_object.h> + +#include "packet-ber.h" +#include "packet-media-type.h" +#include "packet-imf.h" +#include "packet-ess.h" +#include "packet-p1.h" + +void proto_register_imf(void); +void proto_reg_handoff_imf(void); + +static int imf_eo_tap = -1; + +#define PNAME "Internet Message Format" +#define PSNAME "IMF" +#define PFNAME "imf" + +static int proto_imf = -1; + +static int hf_imf_date = -1; +static int hf_imf_from = -1; +static int hf_imf_sender = -1; +static int hf_imf_reply_to = -1; +static int hf_imf_to = -1; +static int hf_imf_cc = -1; +static int hf_imf_bcc = -1; +static int hf_imf_message_id = -1; +static int hf_imf_in_reply_to = -1; +static int hf_imf_references = -1; +static int hf_imf_subject = -1; +static int hf_imf_comments = -1; +static int hf_imf_user_agent = -1; +static int hf_imf_keywords = -1; +static int hf_imf_resent_date = -1; +static int hf_imf_resent_from = -1; +static int hf_imf_resent_sender = -1; +static int hf_imf_resent_to = -1; +static int hf_imf_resent_cc = -1; +static int hf_imf_resent_bcc = -1; +static int hf_imf_resent_message_id = -1; +static int hf_imf_return_path = -1; +static int hf_imf_received = -1; +static int hf_imf_content_type = -1; +static int hf_imf_content_type_type = -1; +static int hf_imf_content_type_parameters = -1; +static int hf_imf_content_id = -1; +static int hf_imf_content_transfer_encoding = -1; +static int hf_imf_content_description = -1; +static int hf_imf_mime_version = -1; +static int hf_imf_thread_index = -1; +static int hf_imf_lines = -1; +static int hf_imf_precedence = -1; +static int hf_imf_ext_mailer = -1; +static int hf_imf_ext_mimeole = -1; +static int hf_imf_ext_tnef_correlator = -1; +static int hf_imf_ext_expiry_date = -1; +static int hf_imf_ext_uidl = -1; +static int hf_imf_ext_authentication_warning = -1; +static int hf_imf_ext_virus_scanned = -1; +static int hf_imf_ext_original_to = -1; +static int hf_imf_extension = -1; +static int hf_imf_extension_type = -1; +static int hf_imf_extension_value = -1; + +/* RFC 2156 */ +static int hf_imf_autoforwarded = -1; +static int hf_imf_autosubmitted = -1; +static int hf_imf_x400_content_identifier = -1; +static int hf_imf_content_language = -1; +static int hf_imf_conversion = -1; +static int hf_imf_conversion_with_loss = -1; +static int hf_imf_delivery_date = -1; +static int hf_imf_discarded_x400_ipms_extensions = -1; +static int hf_imf_discarded_x400_mts_extensions = -1; +static int hf_imf_dl_expansion_history = -1; +static int hf_imf_deferred_delivery = -1; +static int hf_imf_expires = -1; +static int hf_imf_importance = -1; +static int hf_imf_incomplete_copy = -1; +static int hf_imf_latest_delivery_time = -1; +static int hf_imf_message_type = -1; +static int hf_imf_original_encoded_information_types = -1; +static int hf_imf_originator_return_address = -1; +static int hf_imf_priority = -1; +static int hf_imf_reply_by = -1; +static int hf_imf_sensitivity = -1; +static int hf_imf_supersedes = -1; +static int hf_imf_x400_content_type = -1; +static int hf_imf_x400_mts_identifier = -1; +static int hf_imf_x400_originator = -1; +static int hf_imf_x400_received = -1; +static int hf_imf_x400_recipients = -1; + +static int hf_imf_delivered_to = -1; + +static int hf_imf_message_text = -1; + +static int hf_imf_display_name = -1; +static int hf_imf_address = -1; +/* static int hf_imf_mailbox_list = -1; */ +static int hf_imf_mailbox_list_item = -1; +/* static int hf_imf_address_list = -1; */ +static int hf_imf_address_list_item = -1; + +/* draft-zeilenga-email-seclabel-04 */ +static int hf_imf_siolabel = -1; +static int hf_imf_siolabel_marking = -1; +static int hf_imf_siolabel_fgcolor = -1; +static int hf_imf_siolabel_bgcolor = -1; +static int hf_imf_siolabel_type = -1; +static int hf_imf_siolabel_label = -1; +static int hf_imf_siolabel_unknown = -1; + +static int ett_imf = -1; +static int ett_imf_content_type = -1; +static int ett_imf_mailbox = -1; +static int ett_imf_group = -1; +static int ett_imf_mailbox_list = -1; +static int ett_imf_address_list = -1; +static int ett_imf_siolabel = -1; +static int ett_imf_extension = -1; +static int ett_imf_message_text = -1; + +static dissector_handle_t imf_handle; + +static expert_field ei_imf_unknown_param = EI_INIT; + +/* Used for IMF Export Object feature */ +typedef struct _imf_eo_t { + gchar *filename; + gchar *sender_data; + gchar *subject_data; + guint32 payload_len; + gchar *payload_data; +} imf_eo_t; + +static tap_packet_status +imf_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_) +{ + export_object_list_t *object_list = (export_object_list_t *)tapdata; + const imf_eo_t *eo_info = (const imf_eo_t *)data; + export_object_entry_t *entry; + + if(eo_info) { /* We have data waiting for us */ + /* These values will be freed when the Export Object window + * is closed. */ + entry = g_new(export_object_entry_t, 1); + + gchar *start = g_strrstr_len(eo_info->sender_data, -1, "<"); + gchar *stop = g_strrstr_len(eo_info->sender_data, -1, ">"); + /* Only include the string inside of the "<>" brackets. If there is nothing between + the two brackets use the sender_data string */ + if(start && stop && stop > start && (stop - start) > 2){ + entry->hostname = ws_strdup_printf("%.*s", (int) (stop - start - 1), start + 1); + } else { + entry->hostname = g_strdup(eo_info->sender_data); + } + + entry->pkt_num = pinfo->num; + entry->content_type = g_strdup("EML file"); + entry->filename = ws_strdup_printf("%s.eml", eo_info->subject_data); + entry->payload_len = eo_info->payload_len; + entry->payload_data = (guint8 *)g_memdup2(eo_info->payload_data, eo_info->payload_len); + + object_list->add_entry(object_list->gui_data, entry); + + return TAP_PACKET_REDRAW; /* State changed - window should be redrawn */ + } else { + return TAP_PACKET_DONT_REDRAW; /* State unchanged - no window updates needed */ + } +} + + +struct imf_field { + char *name; /* field name - in lower case for matching purposes */ + int *hf_id; /* wireshark field */ + void (*subdissector)(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo); + gboolean add_to_col_info; /* add field to column info */ +}; + +#define NO_SUBDISSECTION NULL + +static void dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo); +static void dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo); +static void dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo); +static void dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo); +static void dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo); + +static struct imf_field imf_fields[] = { + {"unknown-extension", &hf_imf_extension_type, NO_SUBDISSECTION, FALSE}, /* unknown extension */ + {"date", &hf_imf_date, NO_SUBDISSECTION, FALSE}, /* date-time */ + {"from", &hf_imf_from, dissect_imf_mailbox_list , TRUE}, /* mailbox_list */ + {"sender", &hf_imf_sender, dissect_imf_mailbox, FALSE}, /* mailbox */ + {"reply-to", &hf_imf_reply_to, dissect_imf_address_list , FALSE}, /* address_list */ + {"to", &hf_imf_to, dissect_imf_address_list , FALSE}, /* address_list */ + {"cc", &hf_imf_cc, dissect_imf_address_list , FALSE}, /* address_list */ + {"bcc", &hf_imf_bcc, dissect_imf_address_list , FALSE}, /* address_list */ + {"message-id", &hf_imf_message_id, NO_SUBDISSECTION, FALSE}, /* msg-id */ + {"in-reply-to", &hf_imf_in_reply_to, NO_SUBDISSECTION, FALSE}, /* msg-id */ + {"references", &hf_imf_references, NO_SUBDISSECTION, FALSE}, /* msg-id */ + {"subject", &hf_imf_subject, NO_SUBDISSECTION, TRUE}, /* unstructured */ + {"comments", &hf_imf_comments, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"user-agent", &hf_imf_user_agent, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"keywords", &hf_imf_keywords, NULL, FALSE}, /* phrase_list */ + {"resent-date", &hf_imf_resent_date, NO_SUBDISSECTION, FALSE}, + {"resent-from", &hf_imf_resent_from, dissect_imf_mailbox_list, FALSE}, + {"resent-sender", &hf_imf_resent_sender, dissect_imf_mailbox, FALSE}, + {"resent-to", &hf_imf_resent_to, dissect_imf_address_list, FALSE}, + {"resent-cc", &hf_imf_resent_cc, dissect_imf_address_list, FALSE}, + {"resent-bcc", &hf_imf_resent_bcc, dissect_imf_address_list, FALSE}, + {"resent-message-id", &hf_imf_resent_message_id, NO_SUBDISSECTION, FALSE}, + {"return-path", &hf_imf_return_path, NULL, FALSE}, + {"received", &hf_imf_received, NO_SUBDISSECTION, FALSE}, + /* these are really multi-part - but we parse them anyway */ + {"content-type", &hf_imf_content_type, NULL, FALSE}, /* handled separately as a special case */ + {"content-id", &hf_imf_content_id, NULL, FALSE}, + {"content-description", &hf_imf_content_description, NULL, FALSE}, + {"content-transfer-encoding", &hf_imf_content_transfer_encoding, NULL, FALSE}, + {"mime-version", &hf_imf_mime_version, NO_SUBDISSECTION, FALSE}, + /* MIXER - RFC 2156 */ + {"autoforwarded", &hf_imf_autoforwarded, NULL, FALSE}, + {"autosubmitted", &hf_imf_autosubmitted, NULL, FALSE}, + {"x400-content-identifier", &hf_imf_x400_content_identifier, NULL, FALSE}, + {"content-language", &hf_imf_content_language, NULL, FALSE}, + {"conversion", &hf_imf_conversion, NULL, FALSE}, + {"conversion-with-loss", &hf_imf_conversion_with_loss, NULL, FALSE}, + {"delivery-date", &hf_imf_delivery_date, NULL, FALSE}, + {"discarded-x400-ipms-extensions", &hf_imf_discarded_x400_ipms_extensions, NULL, FALSE}, + {"discarded-x400-mts-extensions", &hf_imf_discarded_x400_mts_extensions, NULL, FALSE}, + {"dl-expansion-history", &hf_imf_dl_expansion_history, NULL, FALSE}, + {"deferred-delivery", &hf_imf_deferred_delivery, NULL, FALSE}, + {"expires", &hf_imf_expires, NULL, FALSE}, + {"importance", &hf_imf_importance, NULL, FALSE}, + {"incomplete-copy", &hf_imf_incomplete_copy, NULL, FALSE}, + {"latest-delivery-time", &hf_imf_latest_delivery_time, NULL, FALSE}, + {"message-type", &hf_imf_message_type, NULL, FALSE}, + {"original-encoded-information-types", &hf_imf_original_encoded_information_types, NULL, FALSE}, + {"originator-return-address", &hf_imf_originator_return_address, NULL, FALSE}, + {"priority", &hf_imf_priority, NULL, FALSE}, + {"reply-by", &hf_imf_reply_by, NULL, FALSE}, + {"sensitivity", &hf_imf_sensitivity, NULL, FALSE}, + {"supersedes", &hf_imf_supersedes, NULL, FALSE}, + {"x400-content-type", &hf_imf_x400_content_type, NULL, FALSE}, + {"x400-mts-identifier", &hf_imf_x400_mts_identifier, NULL, FALSE}, + {"x400-originator", &hf_imf_x400_originator, NULL, FALSE}, + {"x400-received", &hf_imf_x400_received, NULL, FALSE}, + {"x400-recipients", &hf_imf_x400_recipients, NULL, FALSE}, + /* delivery */ + {"delivered-to", &hf_imf_delivered_to, dissect_imf_mailbox, FALSE}, /* mailbox */ + /* some others */ + {"x-mailer", &hf_imf_ext_mailer, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"thread-index", &hf_imf_thread_index, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"lines", &hf_imf_lines, NULL, FALSE}, + {"precedence", &hf_imf_precedence, NULL, FALSE}, + {"x-mimeole", &hf_imf_ext_mimeole, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"expiry-date", &hf_imf_ext_expiry_date, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"x-ms-tnef-correlator", &hf_imf_ext_tnef_correlator, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"x-uidl", &hf_imf_ext_uidl, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"x-authentication-warning", &hf_imf_ext_authentication_warning, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"x-virus-scanned", &hf_imf_ext_virus_scanned, NO_SUBDISSECTION, FALSE}, /* unstructured */ + {"x-original-to", &hf_imf_ext_original_to, dissect_imf_address_list, FALSE}, + {"sio-label", &hf_imf_siolabel, dissect_imf_siolabel, FALSE}, /* sio-label */ + {NULL, NULL, NULL, FALSE}, +}; + +static wmem_map_t *imf_field_table=NULL; + +#define FORMAT_UNSTRUCTURED 0 +#define FORMAT_MAILBOX 1 +#define FORMAT_ADDRESS 2 +#define FORMAT_MAILBOX_LIST 3 +#define FORMAT_ADDRESS_LIST 4 +#define FORMAT_SIO_LABEL 5 + +static const value_string header_format[] = { + { FORMAT_UNSTRUCTURED, "Unstructured" }, + { FORMAT_MAILBOX, "Mailbox" }, + { FORMAT_ADDRESS, "Address" }, + { FORMAT_MAILBOX_LIST, "Mailbox List" }, + { FORMAT_ADDRESS_LIST, "Address List" }, + { FORMAT_SIO_LABEL, "SIO-Label" }, + { 0, NULL } +}; + +static const value_string add_to_col_info[] = { + { 0, "No" }, + { 1, "Yes" }, + { 0, NULL } +}; + +typedef struct _header_field_t { + gchar *header_name; + gchar *description; + guint header_format; + guint add_to_col_info; +} header_field_t; + +static header_field_t *header_fields; +static guint num_header_fields; + +static GHashTable *custom_field_table; +static hf_register_info *dynamic_hf; +static guint dynamic_hf_size; + +static bool +header_fields_update_cb(void *r, char **err) +{ + header_field_t *rec = (header_field_t *)r; + char c; + + if (rec->header_name == NULL) { + *err = g_strdup("Header name can't be empty"); + return FALSE; + } + + g_strstrip(rec->header_name); + if (rec->header_name[0] == 0) { + *err = g_strdup("Header name can't be empty"); + return FALSE; + } + + /* Check for invalid characters (to avoid asserting out when + * registering the field). + */ + c = proto_check_field_name(rec->header_name); + if (c) { + *err = ws_strdup_printf("Header name can't contain '%c'", c); + return FALSE; + } + + *err = NULL; + return TRUE; +} + +static void * +header_fields_copy_cb(void *n, const void *o, size_t siz _U_) +{ + header_field_t *new_rec = (header_field_t *)n; + const header_field_t *old_rec = (const header_field_t *)o; + + new_rec->header_name = g_strdup(old_rec->header_name); + new_rec->description = g_strdup(old_rec->description); + new_rec->header_format = old_rec->header_format; + new_rec->add_to_col_info = old_rec->add_to_col_info; + + return new_rec; +} + +static void +header_fields_free_cb(void *r) +{ + header_field_t *rec = (header_field_t *)r; + + g_free(rec->header_name); + g_free(rec->description); +} + +UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t) +UAT_CSTRING_CB_DEF(header_fields, description, header_field_t) +UAT_VS_DEF(header_fields, header_format, header_field_t, guint, 0, "Unstructured") +UAT_VS_DEF(header_fields, add_to_col_info, header_field_t, guint, 0, "No") + + +/* Define media_type/Content type table */ +static dissector_table_t media_type_dissector_table; + +static void +dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo) +{ + proto_tree *group_tree; + proto_item *group_item; + int addr_pos; + + /* if there is a colon present it is a group */ + if((addr_pos = tvb_find_guint8(tvb, offset, length, ':')) == -1) { + + /* there isn't - so it must be a mailbox */ + dissect_imf_mailbox(tvb, offset, length, item, pinfo); + + } else { + + /* it is a group */ + group_tree = proto_item_add_subtree(item, ett_imf_group); + + /* the display-name is mandatory */ + group_item = proto_tree_add_item(group_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII); + + /* consume any whitespace */ + for(addr_pos++ ;addr_pos < (offset + length); addr_pos++) { + if(!g_ascii_isspace(tvb_get_guint8(tvb, addr_pos))) { + break; + } + } + + if(tvb_get_guint8(tvb, addr_pos) != ';') { + + dissect_imf_mailbox_list(tvb, addr_pos, length - (addr_pos - offset), group_item, pinfo); + + /* XXX: need to check for final ';' */ + + } + + } +} + +static void +dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo _U_) +{ + proto_tree *mbox_tree; + int addr_pos, end_pos; + + mbox_tree = proto_item_add_subtree(item, ett_imf_mailbox); + + /* Here is the plan: + If we can't find and angle brackets, then the whole field is an address. + If we find angle brackets, then the address is between them and the display name is + anything before the opening angle bracket + */ + + if((addr_pos = tvb_find_guint8(tvb, offset, length, '<')) == -1) { + /* we can't find an angle bracket - the whole field is therefore the address */ + + (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, offset, length, ENC_ASCII); + + } else { + /* we can find an angle bracket - let's see if we can find a display name */ + /* XXX: the '<' could be in the display name */ + + for(; offset < addr_pos; offset++) { + if(!g_ascii_isspace(tvb_get_guint8(tvb, offset))) { + break; + } + } + + if(offset != addr_pos) { /* there is a display name */ + (void) proto_tree_add_item(mbox_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII); + } + end_pos = tvb_find_guint8(tvb, addr_pos + 1, length - (addr_pos + 1 - offset), '>'); + + if(end_pos != -1) { + (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, addr_pos + 1, end_pos - addr_pos - 1, ENC_ASCII); + } + } +} + +static void +dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo) +{ + proto_item *addr_item = NULL; + proto_tree *tree = NULL; + int count = 0; + int item_offset; + int end_offset; + int item_length; + + /* a comma separated list of addresses */ + tree = proto_item_add_subtree(item, ett_imf_address_list); + + item_offset = offset; + + do { + + end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ','); + + count++; /* increase the number of items */ + + if(end_offset == -1) { + /* length is to the end of the buffer */ + item_length = length - (item_offset - offset); + } else { + item_length = end_offset - item_offset; + } + addr_item = proto_tree_add_item(tree, hf_imf_address_list_item, tvb, item_offset, item_length, ENC_ASCII); + dissect_imf_address(tvb, item_offset, item_length, addr_item, pinfo); + + if(end_offset != -1) { + item_offset = end_offset + 1; + } + } while(end_offset != -1); + + /* now indicate the number of items found */ + proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s")); +} + +static void +dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo) +{ + proto_item *mbox_item = NULL; + proto_tree *tree = NULL; + int count = 0; + int item_offset; + int end_offset; + int item_length; + + /* a comma separated list of mailboxes */ + tree = proto_item_add_subtree(item, ett_imf_mailbox_list); + + item_offset = offset; + + do { + + end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ','); + + count++; /* increase the number of items */ + + if(end_offset == -1) { + /* length is to the end of the buffer */ + item_length = length - (item_offset - offset); + } else { + item_length = end_offset - item_offset; + } + mbox_item = proto_tree_add_item(tree, hf_imf_mailbox_list_item, tvb, item_offset, item_length, ENC_ASCII); + dissect_imf_mailbox(tvb, item_offset, item_length, mbox_item, pinfo); + + if(end_offset != -1) { + item_offset = end_offset + 1; + } + } while(end_offset != -1); + + /* now indicate the number of items found */ + proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s")); +} + +static void +dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo) +{ + proto_tree *tree = NULL; + proto_item *sub_item = NULL; + int item_offset, item_length; + int value_offset, value_length; + int end_offset; + tvbuff_t *label_tvb; + gchar *type = NULL; + wmem_strbuf_t *label_string = wmem_strbuf_new(pinfo->pool, ""); + + /* a semicolon separated list of attributes */ + tree = proto_item_add_subtree(item, ett_imf_siolabel); + item_offset = offset; + + do { + end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ';'); + + /* skip leading space */ + while (g_ascii_isspace(tvb_get_guint8(tvb, item_offset))) { + item_offset++; + } + + if (end_offset == -1) { + /* length is to the end of the buffer */ + item_length = tvb_find_line_end(tvb, item_offset, length - (item_offset - offset), NULL, FALSE); + } else { + item_length = end_offset - item_offset; + } + + value_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), '=') + 1; + while (g_ascii_isspace(tvb_get_guint8(tvb, value_offset))) { + value_offset++; + } + + value_length = item_length - (value_offset - item_offset); + while (g_ascii_isspace(tvb_get_guint8(tvb, value_offset + value_length - 1))) { + value_length--; + } + + if (tvb_strneql(tvb, item_offset, "marking", 7) == 0) { + const guint8* marking; + proto_tree_add_item_ret_string(tree, hf_imf_siolabel_marking, tvb, value_offset, value_length, ENC_ASCII|ENC_NA, pinfo->pool, &marking); + proto_item_append_text(item, ": %s", marking); + + } else if (tvb_strneql(tvb, item_offset, "fgcolor", 7) == 0) { + proto_tree_add_item(tree, hf_imf_siolabel_fgcolor, tvb, value_offset, value_length, ENC_ASCII); + + } else if (tvb_strneql(tvb, item_offset, "bgcolor", 7) == 0) { + proto_tree_add_item(tree, hf_imf_siolabel_bgcolor, tvb, value_offset, value_length, ENC_ASCII); + + } else if (tvb_strneql(tvb, item_offset, "type", 4) == 0) { + type = tvb_get_string_enc(pinfo->pool, tvb, value_offset + 1, value_length - 2, ENC_ASCII); /* quoted */ + proto_tree_add_item(tree, hf_imf_siolabel_type, tvb, value_offset, value_length, ENC_ASCII); + + } else if (tvb_strneql(tvb, item_offset, "label", 5) == 0) { + gchar *label = tvb_get_string_enc(pinfo->pool, tvb, value_offset + 1, value_length - 2, ENC_ASCII); /* quoted */ + wmem_strbuf_append(label_string, label); + + if (tvb_get_guint8(tvb, item_offset + 5) == '*') { /* continuations */ + int num = (int)strtol(tvb_get_string_enc(pinfo->pool, tvb, item_offset + 6, value_offset - item_offset + 6, ENC_ASCII), NULL, 10); + proto_tree_add_string_format(tree, hf_imf_siolabel_label, tvb, value_offset, value_length, + label, "Label[%d]: \"%s\"", num, label); + } else { + proto_tree_add_item(tree, hf_imf_siolabel_label, tvb, value_offset, value_length, ENC_ASCII); + } + + } else { + sub_item = proto_tree_add_item(tree, hf_imf_siolabel_unknown, tvb, item_offset, item_length, ENC_ASCII); + expert_add_info(pinfo, sub_item, &ei_imf_unknown_param); + } + + if (end_offset != -1) { + item_offset = end_offset + 1; + } + } while (end_offset != -1); + + if (type && wmem_strbuf_get_len(label_string) > 0) { + if (strcmp (type, ":ess") == 0) { + label_tvb = base64_to_tvb(tvb, wmem_strbuf_get_str(label_string)); + add_new_data_source(pinfo, label_tvb, "ESS Security Label"); + dissect_ess_ESSSecurityLabel_PDU(label_tvb, pinfo, tree, NULL); + } else if (strcmp (type, ":x411") == 0) { + label_tvb = base64_to_tvb(tvb, wmem_strbuf_get_str(label_string)); + add_new_data_source(pinfo, label_tvb, "X.411 Security Label"); + dissect_p1_MessageSecurityLabel_PDU(label_tvb, pinfo, tree, NULL); + } + } +} + +static void +dissect_imf_content_type(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_item *item, + const guint8 **type, const guint8 **parameters) +{ + int first_colon; + int end_offset; + int len; + int i; + proto_tree *ct_tree; + + /* first strip any whitespace */ + for(i = 0; i < length; i++) { + if(!g_ascii_isspace(tvb_get_guint8(tvb, offset + i))) { + offset += i; + break; + } + } + + /* find the first colon - there has to be a colon as there will have to be a boundary */ + first_colon = tvb_find_guint8(tvb, offset, length, ';'); + + if(first_colon != -1) { + ct_tree = proto_item_add_subtree(item, ett_imf_content_type); + + len = first_colon - offset; + proto_tree_add_item_ret_string(ct_tree, hf_imf_content_type_type, tvb, offset, len, ENC_ASCII|ENC_NA, pinfo->pool, type); + end_offset = imf_find_field_end (tvb, first_colon + 1, offset + length, NULL); + if (end_offset == -1) { + /* No end found */ + return; + } + len = end_offset - (first_colon + 1) - 2; /* Do not include the last CRLF */ + proto_tree_add_item_ret_string(ct_tree, hf_imf_content_type_parameters, tvb, first_colon + 1, len, ENC_ASCII|ENC_NA, pinfo->pool, parameters); + } +} + + +int +imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_field) +{ + + while(offset < max_length) { + + /* look for CR */ + offset = tvb_find_guint8(tvb, offset, max_length - offset, '\r'); + + if(offset != -1) { + /* protect against buffer overrun and only then look for next char */ + if (++offset < max_length && tvb_get_guint8(tvb, offset) == '\n') { + /* OK - so we have found CRLF */ + if (++offset >= max_length) { + /* end of buffer and also end of fields */ + if (last_field) { + *last_field = TRUE; + } + /* caller expects that there is CRLF after returned offset, if last_field is set */ + return offset - 2; + } + /* peek the next character */ + switch(tvb_get_guint8(tvb, offset)) { + case '\r': + /* probably end of the fields */ + if ((offset + 1) < max_length && tvb_get_guint8(tvb, offset + 1) == '\n') { + if(last_field) { + *last_field = TRUE; + } + } + return offset; + case ' ': + case '\t': + /* continuation line */ + break; + default: + /* this is a new field */ + return offset; + } + } + } else { + /* couldn't find a CR - strange */ + break; + } + + } + + return -1; /* Fail: No CR found (other than possible continuation) */ + +} + +static int +dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + proto_item *item; + proto_tree *unknown_tree, *text_tree; + const guint8 *content_type_str = NULL; + char *content_encoding_str = NULL; + const guint8 *parameters = NULL; + int hf_id; + gint start_offset = 0; + gint value_offset = 0; + gint unknown_offset = 0; + gint end_offset = 0; + gint max_length; + guint8 *key; + gboolean last_field = FALSE; + tvbuff_t *next_tvb; + struct imf_field *f_info; + imf_eo_t *eo_info = NULL; + + if (have_tap_listener(imf_eo_tap)) { + eo_info = wmem_new(pinfo->pool, imf_eo_t); + /* initialize the eo_info fields in case they are missing later */ + eo_info->sender_data = ""; + eo_info->subject_data = ""; + } + + /* Want to preserve existing protocol name and show that it is carrying IMF */ + col_append_str(pinfo->cinfo, COL_PROTOCOL, "/"); + col_set_fence(pinfo->cinfo, COL_PROTOCOL); + col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME); + + col_clear(pinfo->cinfo, COL_INFO); + + item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, ENC_NA); + tree = proto_item_add_subtree(item, ett_imf); + + max_length = tvb_captured_length(tvb); + /* first go through the tvb until we find a blank line and extract the content type if + we find one */ + + /* XXX: What if the tvb contains encrypted data ? is there a way to bypass dissection if so ? */ + /* As it is, the following code blithely tries to parse what may be binary data. */ + + while(!last_field) { + + /* look for a colon first */ + end_offset = tvb_find_guint8(tvb, start_offset, max_length - start_offset, ':'); + + if(end_offset == -1) { + /* we couldn't find another colon - strange - we should have broken out of here by now */ + /* XXX: flag an error */ + break; + } else { + key = tvb_get_string_enc(pinfo->pool, tvb, start_offset, end_offset - start_offset, ENC_ASCII); + + /* convert to lower case */ + ascii_strdown_inplace (key); + + /* look up the key in built-in fields */ + f_info = (struct imf_field *)wmem_map_lookup(imf_field_table, key); + + if(f_info == NULL && custom_field_table) { + /* look up the key in custom fields */ + f_info = (struct imf_field *)g_hash_table_lookup(custom_field_table, key); + } + + if(f_info == NULL) { + /* set as an unknown extension */ + f_info = imf_fields; + unknown_offset = start_offset; + } + + hf_id = *(f_info->hf_id); + + /* value starts immediately after the colon */ + start_offset = end_offset+1; + + end_offset = imf_find_field_end(tvb, start_offset, max_length, &last_field); + if(end_offset == -1) { + break; /* Something's fishy */ + } + + /* remove any leading whitespace */ + + for(value_offset = start_offset; value_offset < end_offset; value_offset++) + if(!g_ascii_isspace(tvb_get_guint8(tvb, value_offset))) { + break; + } + + if(value_offset == end_offset) { + /* empty field - show whole value */ + value_offset = start_offset; + } + + if(hf_id == hf_imf_extension_type) { + + /* remove 2 bytes to take off the final CRLF to make things a little prettier */ + item = proto_tree_add_item(tree, hf_imf_extension, tvb, unknown_offset, end_offset - unknown_offset - 2, ENC_ASCII); + + proto_item_append_text(item, " (Contact Wireshark developers if you want this supported.)"); + + unknown_tree = proto_item_add_subtree(item, ett_imf_extension); + + proto_tree_add_item(unknown_tree, hf_imf_extension_type, tvb, unknown_offset, start_offset - 1 - unknown_offset, ENC_ASCII); + + /* remove 2 bytes to take off the final CRLF to make things a little prettier */ + item = proto_tree_add_item(unknown_tree, hf_imf_extension_value, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII); + + } else { + /* remove 2 bytes to take off the final CRLF to make things a little prettier */ + item = proto_tree_add_item(tree, hf_id, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA); + } + if(f_info->add_to_col_info) { + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s: %s, ", f_info->name, + tvb_format_text(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2)); + + /* if sender or subject, store for sending to the tap */ + if (eo_info && have_tap_listener(imf_eo_tap)) { + if (*f_info->hf_id == hf_imf_from) { + eo_info->sender_data = tvb_get_string_enc(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA); + } else if(*f_info->hf_id == hf_imf_subject) { + eo_info->subject_data = tvb_get_string_enc(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA); + } + } + } + + if(hf_id == hf_imf_content_type) { + /* we need some additional processing to extract the content type and parameters */ + + dissect_imf_content_type(tvb, pinfo, start_offset, end_offset - start_offset, item, + &content_type_str, ¶meters); + + } else if (hf_id == hf_imf_content_transfer_encoding) { + content_encoding_str = tvb_get_string_enc (pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII); + } else if(f_info->subdissector) { + + /* we have a subdissector */ + f_info->subdissector(tvb, value_offset, end_offset - value_offset, item, pinfo); + + } + } + start_offset = end_offset; + } + + if (last_field) { + /* Remove the extra CRLF after all the fields */ + end_offset += 2; + } + + if (end_offset == -1) { + end_offset = 0; + } + + /* specify a content type until we can work it out for ourselves */ + /* content_type_str = "multipart/mixed"; */ + + /* now dissect the MIME based upon the content type */ + + if(content_type_str && media_type_dissector_table) { + media_content_info_t content_info; + + col_set_fence(pinfo->cinfo, COL_INFO); + + if(content_encoding_str && !g_ascii_strncasecmp(content_encoding_str, "base64", 6)) { + char *string_data = tvb_get_string_enc(pinfo->pool, tvb, end_offset, tvb_reported_length(tvb) - end_offset, ENC_ASCII); + next_tvb = base64_to_tvb(tvb, string_data); + add_new_data_source(pinfo, next_tvb, content_encoding_str); + } else { + next_tvb = tvb_new_subset_remaining(tvb, end_offset); + } + + content_info.type = MEDIA_CONTAINER_OTHER; + content_info.media_str = parameters; + content_info.data = NULL; + dissector_try_string(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree, (void*)&content_info); + } else { + + /* just show the lines or highlight the rest of the buffer as message text */ + + item = proto_tree_add_item(tree, hf_imf_message_text, tvb, end_offset, tvb_reported_length_remaining(tvb, end_offset) , ENC_NA); + text_tree = proto_item_add_subtree(item, ett_imf_message_text); + + start_offset = end_offset; + while (tvb_offset_exists(tvb, start_offset)) { + + /* + * Find the end of the line. + */ + tvb_find_line_end(tvb, start_offset, -1, &end_offset, FALSE); + + /* + * Put this line. + */ + proto_tree_add_format_wsp_text(text_tree, tvb, start_offset, end_offset - start_offset); + col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", + tvb_format_text_wsp(pinfo->pool, tvb, start_offset, end_offset - start_offset)); + + /* + * Step to the next line. + */ + start_offset = end_offset; + } + } + + if (eo_info && have_tap_listener(imf_eo_tap)) { + /* Set payload info */ + eo_info->payload_len = max_length; + eo_info->payload_data = (gchar *) tvb_memdup(pinfo->pool, tvb, 0, max_length); + + /* Send to tap */ + tap_queue_packet(imf_eo_tap, pinfo, eo_info); + } + return tvb_captured_length(tvb); +} + +static void +free_imf_field (gpointer data) +{ + struct imf_field *imffield = (struct imf_field *) data; + + g_free (imffield->name); + g_free (imffield); +} + +static void +deregister_header_fields(void) +{ + if (dynamic_hf) { + /* Deregister all fields */ + for (guint i = 0; i < dynamic_hf_size; i++) { + proto_deregister_field (proto_imf, *(dynamic_hf[i].p_id)); + g_free (dynamic_hf[i].p_id); + } + + proto_add_deregistered_data (dynamic_hf); + dynamic_hf = NULL; + dynamic_hf_size = 0; + } + + if (custom_field_table) { + g_hash_table_destroy (custom_field_table); + custom_field_table = NULL; + } +} + +static void +header_fields_post_update_cb (void) +{ + gint *hf_id; + struct imf_field *imffield; + gchar *header_name; + + deregister_header_fields(); + + if (num_header_fields) { + custom_field_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_imf_field); + dynamic_hf = g_new0(hf_register_info, num_header_fields); + dynamic_hf_size = num_header_fields; + + for (guint i = 0; i < dynamic_hf_size; i++) { + hf_id = g_new(gint, 1); + *hf_id = -1; + header_name = g_strdup (header_fields[i].header_name); + + dynamic_hf[i].p_id = hf_id; + dynamic_hf[i].hfinfo.name = header_name; + dynamic_hf[i].hfinfo.abbrev = ws_strdup_printf ("imf.header.%s", header_name); + dynamic_hf[i].hfinfo.type = FT_STRING; + dynamic_hf[i].hfinfo.display = BASE_NONE; + dynamic_hf[i].hfinfo.strings = NULL; + dynamic_hf[i].hfinfo.bitmask = 0; + dynamic_hf[i].hfinfo.blurb = g_strdup (header_fields[i].description); + HFILL_INIT(dynamic_hf[i]); + + imffield = g_new(struct imf_field, 1); + imffield->hf_id = hf_id; + imffield->name = g_ascii_strdown(header_name, -1); + switch (header_fields[i].header_format) { + case FORMAT_UNSTRUCTURED: + imffield->subdissector = NO_SUBDISSECTION; + break; + case FORMAT_MAILBOX: + imffield->subdissector = dissect_imf_mailbox; + break; + case FORMAT_ADDRESS: + imffield->subdissector = dissect_imf_address; + break; + case FORMAT_MAILBOX_LIST: + imffield->subdissector = dissect_imf_mailbox_list; + break; + case FORMAT_ADDRESS_LIST: + imffield->subdissector = dissect_imf_address_list; + break; + case FORMAT_SIO_LABEL: + dynamic_hf[i].hfinfo.type = FT_NONE; /* constructed */ + imffield->subdissector = dissect_imf_siolabel; + break; + default: + /* unknown */ + imffield->subdissector = NO_SUBDISSECTION; + break; + } + imffield->add_to_col_info = header_fields[i].add_to_col_info; + g_hash_table_insert (custom_field_table, (gpointer)imffield->name, (gpointer)imffield); + } + + proto_register_field_array (proto_imf, dynamic_hf, dynamic_hf_size); + } +} + +static void +header_fields_reset_cb(void) +{ + deregister_header_fields(); +} + +/* Register all the bits needed by the filtering engine */ + +void +proto_register_imf(void) +{ + static hf_register_info hf[] = { + { &hf_imf_date, + { "Date", "imf.date", FT_STRING, BASE_NONE, NULL, 0x0, + "DateTime", HFILL }}, + { &hf_imf_from, + { "From", "imf.from", FT_STRING, BASE_NONE, NULL, 0x0, + "MailboxList", HFILL }}, + { &hf_imf_sender, + { "Sender", "imf.sender", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_reply_to, + { "Reply-To", "imf.reply_to", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_to, + { "To", "imf.to", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_cc, + { "Cc", "imf.cc", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_bcc, + { "Bcc", "imf.bcc", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_message_id, + { "Message-ID", "imf.message_id", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_in_reply_to, + { "In-Reply-To", "imf.in_reply_to", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_references, + { "References", "imf.references", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_subject, + { "Subject", "imf.subject", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_comments, + { "Comments", "imf.comments", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_user_agent, + { "User-Agent", "imf.user_agent", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_keywords, + { "Keywords", "imf.keywords", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_resent_date, + { "Resent-Date", "imf.resent.date", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_resent_from, + { "Resent-From", "imf.resent.from", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_resent_sender, + { "Resent-Sender", "imf.resent.sender", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_resent_to, + { "Resent-To", "imf.resent.to", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_resent_cc, + { "Resent-Cc", "imf.resent.cc", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_resent_bcc, + { "Resent-Bcc", "imf.resent.bcc", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_resent_message_id, + { "Resent-Message-ID", "imf.resent.message_id", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_return_path, + { "Return-Path", "imf.return_path", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_received, + { "Received", "imf.received", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_content_type, + { "Content-Type", "imf.content.type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_content_type_type, + { "Type", "imf.content.type.type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_content_type_parameters, + { "Parameters", "imf.content.type.parameters", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_content_description, + { "Content-Description", "imf.content.description", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_content_id, + { "Content-ID", "imf.content.id", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_content_transfer_encoding, + { "Content-Transfer-Encoding", "imf.content.transfer_encoding", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_mime_version, + { "MIME-Version", "imf.mime_version", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_autoforwarded, + { "Autoforwarded", "imf.autoforwarded", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_autosubmitted, + { "Autosubmitted", "imf.autosubmitted", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_x400_content_identifier, + { "X400-Content-Identifier", "imf.x400_content_identifier", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_content_language, + { "Content-Language", "imf.content_language", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_conversion, + { "Conversion", "imf.conversion", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_conversion_with_loss, + { "Conversion-With-Loss", "imf.conversion_with_loss", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_delivery_date, + { "Delivery-Date", "imf.delivery_date", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_discarded_x400_ipms_extensions, + { "Discarded-X400-IPMS-Extensions", "imf.discarded_x400_ipms_extensions", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_discarded_x400_mts_extensions, + { "Discarded-X400-MTS-Extensions", "imf.discarded_x400_mts_extensions", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_dl_expansion_history, + { "DL-Expansion-History", "imf.dl_expansion_history", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_deferred_delivery, + { "Deferred-Delivery", "imf.deferred_delivery", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_expires, + { "Expires", "imf.expires", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_importance, + { "Importance", "imf.importance", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_incomplete_copy, + { "Incomplete-Copy", "imf.incomplete_copy", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_latest_delivery_time, + { "Latest-Delivery-Time", "imf.latest_delivery_time", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_message_type, + { "Message-Type", "imf.message_type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_original_encoded_information_types, + { "Original-Encoded-Information-Types", "imf.original_encoded_information_types", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_originator_return_address, + { "Originator-Return-Address", "imf.originator_return_address", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_priority, + { "Priority", "imf.priority", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_reply_by, + { "Reply-By", "imf.reply_by", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_sensitivity, + { "Sensitivity", "imf.sensitivity", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_supersedes, + { "Supersedes", "imf.supersedes", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_x400_content_type, + { "X400-Content-Type", "imf.x400_content_type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_x400_mts_identifier, + { "X400-MTS-Identifier", "imf.x400_mts_identifier", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_x400_originator, + { "X400-Originator", "imf.x400_originator", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_x400_received, + { "X400-Received", "imf.x400_received", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_x400_recipients, + { "X400-Recipients", "imf.x400_recipients", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_delivered_to, + { "Delivered-To", "imf.delivered_to", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_ext_mailer, + { "X-Mailer", "imf.ext.mailer", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_ext_mimeole, + { "X-MimeOLE", "imf.ext.mimeole", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_ext_expiry_date, + { "Expiry-Date", "imf.ext.expiry-date", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_ext_tnef_correlator, + { "X-MS-TNEF-Correlator", "imf.ext.tnef-correlator", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_ext_uidl, + { "X-UIDL", "imf.ext.uidl", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_ext_authentication_warning, + { "X-Authentication-Warning", "imf.ext.authentication_warning", FT_STRING, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + { &hf_imf_ext_virus_scanned, + { "X-Virus-Scanned", "imf.ext.virus_scanned", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_ext_original_to, + { "X-Original-To", "imf.ext.original-to", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_thread_index, + { "Thread-Index", "imf.thread-index", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_lines, + { "Lines", "imf.lines", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_precedence, + { "Precedence", "imf.precedence", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_extension, + { "Unknown-Extension", "imf.extension", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_extension_type, + { "Type", "imf.extension.type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_extension_value, + { "Value", "imf.extension.value", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_display_name, + { "Display-Name", "imf.display_name", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_address, + { "Address", "imf.address", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, +#if 0 + { &hf_imf_address_list, + { "Address List", "imf.address_list", FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, +#endif + { &hf_imf_address_list_item, + { "Item", "imf.address_list.item", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, +#if 0 + { &hf_imf_mailbox_list, + { "Mailbox List", "imf.mailbox_list", FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, +#endif + { &hf_imf_mailbox_list_item, + { "Item", "imf.mailbox_list.item", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_siolabel, + { "SIO-Label", "imf.siolabel", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_siolabel_marking, + { "Marking", "imf.siolabel.marking", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_siolabel_fgcolor, + { "Foreground Color", "imf.siolabel.fgcolor", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_siolabel_bgcolor, + { "Background Color", "imf.siolabel.bgcolor", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_siolabel_type, + { "Type", "imf.siolabel.type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_siolabel_label, + { "Label", "imf.siolabel.label", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_siolabel_unknown, + { "Unknown parameter", "imf.siolabel.unknown", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_imf_message_text, + { "Message-Text", "imf.message_text", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + }; + static gint *ett[] = { + &ett_imf, + &ett_imf_content_type, + &ett_imf_group, + &ett_imf_mailbox, + &ett_imf_mailbox_list, + &ett_imf_address_list, + &ett_imf_siolabel, + &ett_imf_extension, + &ett_imf_message_text, + }; + + static ei_register_info ei[] = { + { &ei_imf_unknown_param, { "imf.unknown_param", PI_PROTOCOL, PI_WARN, "Unknown parameter", EXPFILL }}, + }; + + static uat_field_t attributes_flds[] = { + UAT_FLD_CSTRING(header_fields, header_name, "Header name", "IMF header name"), + UAT_FLD_CSTRING(header_fields, description, "Description", "Description of the value contained in the header"), + UAT_FLD_VS(header_fields, header_format, "Format", header_format, 0), + UAT_FLD_VS(header_fields, add_to_col_info, "Add to Info column", add_to_col_info, 0), + UAT_END_FIELDS + }; + + uat_t *headers_uat = uat_new("Custom IMF headers", + sizeof(header_field_t), + "imf_header_fields", + TRUE, + &header_fields, + &num_header_fields, + /* specifies named fields, so affects dissection + and the set of named fields */ + UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS, + NULL, + header_fields_copy_cb, + header_fields_update_cb, + header_fields_free_cb, + header_fields_post_update_cb, + header_fields_reset_cb, + attributes_flds); + + module_t *imf_module; + expert_module_t* expert_imf; + struct imf_field *f; + + proto_imf = proto_register_protocol(PNAME, PSNAME, PFNAME); + + proto_register_field_array(proto_imf, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_imf = expert_register_protocol(proto_imf); + expert_register_field_array(expert_imf, ei, array_length(ei)); + + /* Allow dissector to find be found by name. */ + imf_handle = register_dissector(PFNAME, dissect_imf, proto_imf); + + imf_module = prefs_register_protocol(proto_imf, NULL); + prefs_register_uat_preference(imf_module, "custom_header_fields", "Custom IMF headers", + "A table to define custom IMF headers for which fields can be " + "setup and used for filtering/data extraction etc.", + headers_uat); + + imf_field_table=wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); /* oid to syntax */ + + /* register the fields for lookup */ + for(f = imf_fields; f->name; f++) + wmem_map_insert(imf_field_table, (gpointer)f->name, (gpointer)f); + + /* Register for tapping */ + imf_eo_tap = register_export_object(proto_imf, imf_eo_packet, NULL); + +} + +/* The registration hand-off routine */ +void +proto_reg_handoff_imf(void) +{ + dissector_add_string("media_type", + "message/rfc822", imf_handle); + + register_ber_oid_dissector_handle("1.2.840.113549.1.7.1", imf_handle, proto_imf, "id-data"); + + /* + * Get the content type and Internet media type table + */ + media_type_dissector_table = find_dissector_table("media_type"); + +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local Variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */ |