Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-imf.c
blob2255843b82beaf1d8d90cb69f774f224e55c26d4
1 /* packet-imf.c
2 * Routines for Internet Message Format (IMF) packet disassembly
4 * Copyright (c) 2007 by Graeme Lunt
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1999 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/uat.h>
18 #include <epan/expert.h>
19 #include <wsutil/str_util.h>
20 #include <wsutil/array.h>
22 #include <epan/tap.h>
23 #include <epan/export_object.h>
25 #include "packet-ber.h"
26 #include "packet-media-type.h"
27 #include "packet-imf.h"
28 #include "packet-ess.h"
29 #include "packet-p1.h"
31 void proto_register_imf(void);
32 void proto_reg_handoff_imf(void);
34 static int imf_eo_tap;
36 #define PNAME "Internet Message Format"
37 #define PSNAME "IMF"
38 #define PFNAME "imf"
40 static int proto_imf;
42 static int hf_imf_date;
43 static int hf_imf_from;
44 static int hf_imf_sender;
45 static int hf_imf_reply_to;
46 static int hf_imf_to;
47 static int hf_imf_cc;
48 static int hf_imf_bcc;
49 static int hf_imf_message_id;
50 static int hf_imf_in_reply_to;
51 static int hf_imf_references;
52 static int hf_imf_subject;
53 static int hf_imf_comments;
54 static int hf_imf_user_agent;
55 static int hf_imf_keywords;
56 static int hf_imf_resent_date;
57 static int hf_imf_resent_from;
58 static int hf_imf_resent_sender;
59 static int hf_imf_resent_to;
60 static int hf_imf_resent_cc;
61 static int hf_imf_resent_bcc;
62 static int hf_imf_resent_message_id;
63 static int hf_imf_return_path;
64 static int hf_imf_received;
65 static int hf_imf_content_type;
66 static int hf_imf_content_type_type;
67 static int hf_imf_content_type_parameters;
68 static int hf_imf_content_id;
69 static int hf_imf_content_transfer_encoding;
70 static int hf_imf_content_description;
71 static int hf_imf_mime_version;
72 static int hf_imf_thread_index;
73 static int hf_imf_lines;
74 static int hf_imf_precedence;
75 static int hf_imf_ext_mailer;
76 static int hf_imf_ext_mimeole;
77 static int hf_imf_ext_tnef_correlator;
78 static int hf_imf_ext_expiry_date;
79 static int hf_imf_ext_uidl;
80 static int hf_imf_ext_authentication_warning;
81 static int hf_imf_ext_virus_scanned;
82 static int hf_imf_ext_original_to;
83 static int hf_imf_extension;
84 static int hf_imf_extension_type;
85 static int hf_imf_extension_value;
87 /* RFC 2156 */
88 static int hf_imf_autoforwarded;
89 static int hf_imf_autosubmitted;
90 static int hf_imf_x400_content_identifier;
91 static int hf_imf_content_language;
92 static int hf_imf_conversion;
93 static int hf_imf_conversion_with_loss;
94 static int hf_imf_delivery_date;
95 static int hf_imf_discarded_x400_ipms_extensions;
96 static int hf_imf_discarded_x400_mts_extensions;
97 static int hf_imf_dl_expansion_history;
98 static int hf_imf_deferred_delivery;
99 static int hf_imf_expires;
100 static int hf_imf_importance;
101 static int hf_imf_incomplete_copy;
102 static int hf_imf_latest_delivery_time;
103 static int hf_imf_message_type;
104 static int hf_imf_original_encoded_information_types;
105 static int hf_imf_originator_return_address;
106 static int hf_imf_priority;
107 static int hf_imf_reply_by;
108 static int hf_imf_sensitivity;
109 static int hf_imf_supersedes;
110 static int hf_imf_x400_content_type;
111 static int hf_imf_x400_mts_identifier;
112 static int hf_imf_x400_originator;
113 static int hf_imf_x400_received;
114 static int hf_imf_x400_recipients;
116 static int hf_imf_delivered_to;
118 static int hf_imf_message_text;
120 static int hf_imf_display_name;
121 static int hf_imf_address;
122 /* static int hf_imf_mailbox_list; */
123 static int hf_imf_mailbox_list_item;
124 /* static int hf_imf_address_list; */
125 static int hf_imf_address_list_item;
127 /* draft-zeilenga-email-seclabel-04 */
128 static int hf_imf_siolabel;
129 static int hf_imf_siolabel_marking;
130 static int hf_imf_siolabel_fgcolor;
131 static int hf_imf_siolabel_bgcolor;
132 static int hf_imf_siolabel_type;
133 static int hf_imf_siolabel_label;
134 static int hf_imf_siolabel_unknown;
136 static int ett_imf;
137 static int ett_imf_content_type;
138 static int ett_imf_mailbox;
139 static int ett_imf_group;
140 static int ett_imf_mailbox_list;
141 static int ett_imf_address_list;
142 static int ett_imf_siolabel;
143 static int ett_imf_extension;
144 static int ett_imf_message_text;
146 static dissector_handle_t imf_handle;
148 static expert_field ei_imf_unknown_param;
150 /* Used for IMF Export Object feature */
151 typedef struct _imf_eo_t {
152 char *filename;
153 char *sender_data;
154 char *subject_data;
155 uint32_t payload_len;
156 char *payload_data;
157 } imf_eo_t;
159 static tap_packet_status
160 imf_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
162 export_object_list_t *object_list = (export_object_list_t *)tapdata;
163 const imf_eo_t *eo_info = (const imf_eo_t *)data;
164 export_object_entry_t *entry;
166 if(eo_info) { /* We have data waiting for us */
167 /* These values will be freed when the Export Object window
168 * is closed. */
169 entry = g_new(export_object_entry_t, 1);
171 char *start = g_strrstr_len(eo_info->sender_data, -1, "<");
172 char *stop = g_strrstr_len(eo_info->sender_data, -1, ">");
173 /* Only include the string inside of the "<>" brackets. If there is nothing between
174 the two brackets use the sender_data string */
175 if(start && stop && stop > start && (stop - start) > 2){
176 entry->hostname = ws_strdup_printf("%.*s", (int) (stop - start - 1), start + 1);
177 } else {
178 entry->hostname = g_strdup(eo_info->sender_data);
181 entry->pkt_num = pinfo->num;
182 entry->content_type = g_strdup("EML file");
183 entry->filename = ws_strdup_printf("%s.eml", eo_info->subject_data);
184 entry->payload_len = eo_info->payload_len;
185 entry->payload_data = (uint8_t *)g_memdup2(eo_info->payload_data, eo_info->payload_len);
187 object_list->add_entry(object_list->gui_data, entry);
189 return TAP_PACKET_REDRAW; /* State changed - window should be redrawn */
190 } else {
191 return TAP_PACKET_DONT_REDRAW; /* State unchanged - no window updates needed */
196 struct imf_field {
197 char *name; /* field name - in lower case for matching purposes */
198 int *hf_id; /* wireshark field */
199 void (*subdissector)(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
200 bool add_to_col_info; /* add field to column info */
203 #define NO_SUBDISSECTION NULL
205 static void dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
206 static void dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
207 static void dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
208 static void dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
209 static void dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
211 static struct imf_field imf_fields[] = {
212 {"unknown-extension", &hf_imf_extension_type, NO_SUBDISSECTION, false}, /* unknown extension */
213 {"date", &hf_imf_date, NO_SUBDISSECTION, false}, /* date-time */
214 {"from", &hf_imf_from, dissect_imf_mailbox_list , true}, /* mailbox_list */
215 {"sender", &hf_imf_sender, dissect_imf_mailbox, false}, /* mailbox */
216 {"reply-to", &hf_imf_reply_to, dissect_imf_address_list , false}, /* address_list */
217 {"to", &hf_imf_to, dissect_imf_address_list , false}, /* address_list */
218 {"cc", &hf_imf_cc, dissect_imf_address_list , false}, /* address_list */
219 {"bcc", &hf_imf_bcc, dissect_imf_address_list , false}, /* address_list */
220 {"message-id", &hf_imf_message_id, NO_SUBDISSECTION, false}, /* msg-id */
221 {"in-reply-to", &hf_imf_in_reply_to, NO_SUBDISSECTION, false}, /* msg-id */
222 {"references", &hf_imf_references, NO_SUBDISSECTION, false}, /* msg-id */
223 {"subject", &hf_imf_subject, NO_SUBDISSECTION, true}, /* unstructured */
224 {"comments", &hf_imf_comments, NO_SUBDISSECTION, false}, /* unstructured */
225 {"user-agent", &hf_imf_user_agent, NO_SUBDISSECTION, false}, /* unstructured */
226 {"keywords", &hf_imf_keywords, NULL, false}, /* phrase_list */
227 {"resent-date", &hf_imf_resent_date, NO_SUBDISSECTION, false},
228 {"resent-from", &hf_imf_resent_from, dissect_imf_mailbox_list, false},
229 {"resent-sender", &hf_imf_resent_sender, dissect_imf_mailbox, false},
230 {"resent-to", &hf_imf_resent_to, dissect_imf_address_list, false},
231 {"resent-cc", &hf_imf_resent_cc, dissect_imf_address_list, false},
232 {"resent-bcc", &hf_imf_resent_bcc, dissect_imf_address_list, false},
233 {"resent-message-id", &hf_imf_resent_message_id, NO_SUBDISSECTION, false},
234 {"return-path", &hf_imf_return_path, NULL, false},
235 {"received", &hf_imf_received, NO_SUBDISSECTION, false},
236 /* these are really multi-part - but we parse them anyway */
237 {"content-type", &hf_imf_content_type, NULL, false}, /* handled separately as a special case */
238 {"content-id", &hf_imf_content_id, NULL, false},
239 {"content-description", &hf_imf_content_description, NULL, false},
240 {"content-transfer-encoding", &hf_imf_content_transfer_encoding, NULL, false},
241 {"mime-version", &hf_imf_mime_version, NO_SUBDISSECTION, false},
242 /* MIXER - RFC 2156 */
243 {"autoforwarded", &hf_imf_autoforwarded, NULL, false},
244 {"autosubmitted", &hf_imf_autosubmitted, NULL, false},
245 {"x400-content-identifier", &hf_imf_x400_content_identifier, NULL, false},
246 {"content-language", &hf_imf_content_language, NULL, false},
247 {"conversion", &hf_imf_conversion, NULL, false},
248 {"conversion-with-loss", &hf_imf_conversion_with_loss, NULL, false},
249 {"delivery-date", &hf_imf_delivery_date, NULL, false},
250 {"discarded-x400-ipms-extensions", &hf_imf_discarded_x400_ipms_extensions, NULL, false},
251 {"discarded-x400-mts-extensions", &hf_imf_discarded_x400_mts_extensions, NULL, false},
252 {"dl-expansion-history", &hf_imf_dl_expansion_history, NULL, false},
253 {"deferred-delivery", &hf_imf_deferred_delivery, NULL, false},
254 {"expires", &hf_imf_expires, NULL, false},
255 {"importance", &hf_imf_importance, NULL, false},
256 {"incomplete-copy", &hf_imf_incomplete_copy, NULL, false},
257 {"latest-delivery-time", &hf_imf_latest_delivery_time, NULL, false},
258 {"message-type", &hf_imf_message_type, NULL, false},
259 {"original-encoded-information-types", &hf_imf_original_encoded_information_types, NULL, false},
260 {"originator-return-address", &hf_imf_originator_return_address, NULL, false},
261 {"priority", &hf_imf_priority, NULL, false},
262 {"reply-by", &hf_imf_reply_by, NULL, false},
263 {"sensitivity", &hf_imf_sensitivity, NULL, false},
264 {"supersedes", &hf_imf_supersedes, NULL, false},
265 {"x400-content-type", &hf_imf_x400_content_type, NULL, false},
266 {"x400-mts-identifier", &hf_imf_x400_mts_identifier, NULL, false},
267 {"x400-originator", &hf_imf_x400_originator, NULL, false},
268 {"x400-received", &hf_imf_x400_received, NULL, false},
269 {"x400-recipients", &hf_imf_x400_recipients, NULL, false},
270 /* delivery */
271 {"delivered-to", &hf_imf_delivered_to, dissect_imf_mailbox, false}, /* mailbox */
272 /* some others */
273 {"x-mailer", &hf_imf_ext_mailer, NO_SUBDISSECTION, false}, /* unstructured */
274 {"thread-index", &hf_imf_thread_index, NO_SUBDISSECTION, false}, /* unstructured */
275 {"lines", &hf_imf_lines, NULL, false},
276 {"precedence", &hf_imf_precedence, NULL, false},
277 {"x-mimeole", &hf_imf_ext_mimeole, NO_SUBDISSECTION, false}, /* unstructured */
278 {"expiry-date", &hf_imf_ext_expiry_date, NO_SUBDISSECTION, false}, /* unstructured */
279 {"x-ms-tnef-correlator", &hf_imf_ext_tnef_correlator, NO_SUBDISSECTION, false}, /* unstructured */
280 {"x-uidl", &hf_imf_ext_uidl, NO_SUBDISSECTION, false}, /* unstructured */
281 {"x-authentication-warning", &hf_imf_ext_authentication_warning, NO_SUBDISSECTION, false}, /* unstructured */
282 {"x-virus-scanned", &hf_imf_ext_virus_scanned, NO_SUBDISSECTION, false}, /* unstructured */
283 {"x-original-to", &hf_imf_ext_original_to, dissect_imf_address_list, false},
284 {"sio-label", &hf_imf_siolabel, dissect_imf_siolabel, false}, /* sio-label */
285 {NULL, NULL, NULL, false},
288 static wmem_map_t *imf_field_table;
290 #define FORMAT_UNSTRUCTURED 0
291 #define FORMAT_MAILBOX 1
292 #define FORMAT_ADDRESS 2
293 #define FORMAT_MAILBOX_LIST 3
294 #define FORMAT_ADDRESS_LIST 4
295 #define FORMAT_SIO_LABEL 5
297 static const value_string header_format[] = {
298 { FORMAT_UNSTRUCTURED, "Unstructured" },
299 { FORMAT_MAILBOX, "Mailbox" },
300 { FORMAT_ADDRESS, "Address" },
301 { FORMAT_MAILBOX_LIST, "Mailbox List" },
302 { FORMAT_ADDRESS_LIST, "Address List" },
303 { FORMAT_SIO_LABEL, "SIO-Label" },
304 { 0, NULL }
307 static const value_string add_to_col_info[] = {
308 { 0, "No" },
309 { 1, "Yes" },
310 { 0, NULL }
313 typedef struct _header_field_t {
314 char *header_name;
315 char *description;
316 unsigned header_format;
317 unsigned add_to_col_info;
318 } header_field_t;
320 static header_field_t *header_fields;
321 static unsigned num_header_fields;
323 static GHashTable *custom_field_table;
324 static hf_register_info *dynamic_hf;
325 static unsigned dynamic_hf_size;
327 static bool
328 header_fields_update_cb(void *r, char **err)
330 header_field_t *rec = (header_field_t *)r;
331 char c;
333 if (rec->header_name == NULL) {
334 *err = g_strdup("Header name can't be empty");
335 return false;
338 g_strstrip(rec->header_name);
339 if (rec->header_name[0] == 0) {
340 *err = g_strdup("Header name can't be empty");
341 return false;
344 /* Check for invalid characters (to avoid asserting out when
345 * registering the field).
347 c = proto_check_field_name(rec->header_name);
348 if (c) {
349 *err = ws_strdup_printf("Header name can't contain '%c'", c);
350 return false;
353 *err = NULL;
354 return true;
357 static void *
358 header_fields_copy_cb(void *n, const void *o, size_t siz _U_)
360 header_field_t *new_rec = (header_field_t *)n;
361 const header_field_t *old_rec = (const header_field_t *)o;
363 new_rec->header_name = g_strdup(old_rec->header_name);
364 new_rec->description = g_strdup(old_rec->description);
365 new_rec->header_format = old_rec->header_format;
366 new_rec->add_to_col_info = old_rec->add_to_col_info;
368 return new_rec;
371 static void
372 header_fields_free_cb(void *r)
374 header_field_t *rec = (header_field_t *)r;
376 g_free(rec->header_name);
377 g_free(rec->description);
380 UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t)
381 UAT_CSTRING_CB_DEF(header_fields, description, header_field_t)
382 UAT_VS_DEF(header_fields, header_format, header_field_t, unsigned, 0, "Unstructured")
383 UAT_VS_DEF(header_fields, add_to_col_info, header_field_t, unsigned, 0, "No")
386 /* Define media_type/Content type table */
387 static dissector_table_t media_type_dissector_table;
389 static void
390 dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
392 proto_tree *group_tree;
393 proto_item *group_item;
394 int addr_pos;
396 /* if there is a colon present it is a group */
397 if((addr_pos = tvb_find_uint8(tvb, offset, length, ':')) == -1) {
399 /* there isn't - so it must be a mailbox */
400 dissect_imf_mailbox(tvb, offset, length, item, pinfo);
402 } else {
404 /* it is a group */
405 group_tree = proto_item_add_subtree(item, ett_imf_group);
407 /* the display-name is mandatory */
408 group_item = proto_tree_add_item(group_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII);
410 /* consume any whitespace */
411 for(addr_pos++ ;addr_pos < (offset + length); addr_pos++) {
412 if(!g_ascii_isspace(tvb_get_uint8(tvb, addr_pos))) {
413 break;
417 if(tvb_get_uint8(tvb, addr_pos) != ';') {
419 dissect_imf_mailbox_list(tvb, addr_pos, length - (addr_pos - offset), group_item, pinfo);
421 /* XXX: need to check for final ';' */
428 static void
429 dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo _U_)
431 proto_tree *mbox_tree;
432 int addr_pos, end_pos;
434 mbox_tree = proto_item_add_subtree(item, ett_imf_mailbox);
436 /* Here is the plan:
437 If we can't find and angle brackets, then the whole field is an address.
438 If we find angle brackets, then the address is between them and the display name is
439 anything before the opening angle bracket
442 if((addr_pos = tvb_find_uint8(tvb, offset, length, '<')) == -1) {
443 /* we can't find an angle bracket - the whole field is therefore the address */
445 (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, offset, length, ENC_ASCII);
447 } else {
448 /* we can find an angle bracket - let's see if we can find a display name */
449 /* XXX: the '<' could be in the display name */
451 for(; offset < addr_pos; offset++) {
452 if(!g_ascii_isspace(tvb_get_uint8(tvb, offset))) {
453 break;
457 if(offset != addr_pos) { /* there is a display name */
458 (void) proto_tree_add_item(mbox_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII);
460 end_pos = tvb_find_uint8(tvb, addr_pos + 1, length - (addr_pos + 1 - offset), '>');
462 if(end_pos != -1) {
463 (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, addr_pos + 1, end_pos - addr_pos - 1, ENC_ASCII);
468 static void
469 dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
471 proto_item *addr_item = NULL;
472 proto_tree *tree = NULL;
473 int count = 0;
474 int item_offset;
475 int end_offset;
476 int item_length;
478 /* a comma separated list of addresses */
479 tree = proto_item_add_subtree(item, ett_imf_address_list);
481 item_offset = offset;
483 do {
485 end_offset = tvb_find_uint8(tvb, item_offset, length - (item_offset - offset), ',');
487 count++; /* increase the number of items */
489 if(end_offset == -1) {
490 /* length is to the end of the buffer */
491 item_length = length - (item_offset - offset);
492 } else {
493 item_length = end_offset - item_offset;
495 addr_item = proto_tree_add_item(tree, hf_imf_address_list_item, tvb, item_offset, item_length, ENC_ASCII);
496 dissect_imf_address(tvb, item_offset, item_length, addr_item, pinfo);
498 if(end_offset != -1) {
499 item_offset = end_offset + 1;
501 } while(end_offset != -1);
503 /* now indicate the number of items found */
504 proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
507 static void
508 dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
510 proto_item *mbox_item = NULL;
511 proto_tree *tree = NULL;
512 int count = 0;
513 int item_offset;
514 int end_offset;
515 int item_length;
517 /* a comma separated list of mailboxes */
518 tree = proto_item_add_subtree(item, ett_imf_mailbox_list);
520 item_offset = offset;
522 do {
524 end_offset = tvb_find_uint8(tvb, item_offset, length - (item_offset - offset), ',');
526 count++; /* increase the number of items */
528 if(end_offset == -1) {
529 /* length is to the end of the buffer */
530 item_length = length - (item_offset - offset);
531 } else {
532 item_length = end_offset - item_offset;
534 mbox_item = proto_tree_add_item(tree, hf_imf_mailbox_list_item, tvb, item_offset, item_length, ENC_ASCII);
535 dissect_imf_mailbox(tvb, item_offset, item_length, mbox_item, pinfo);
537 if(end_offset != -1) {
538 item_offset = end_offset + 1;
540 } while(end_offset != -1);
542 /* now indicate the number of items found */
543 proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
546 static void
547 dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
549 proto_tree *tree = NULL;
550 proto_item *sub_item = NULL;
551 int item_offset, item_length;
552 int value_offset, value_length;
553 int end_offset;
554 tvbuff_t *label_tvb;
555 char *type = NULL;
556 wmem_strbuf_t *label_string = wmem_strbuf_new(pinfo->pool, "");
558 /* a semicolon separated list of attributes */
559 tree = proto_item_add_subtree(item, ett_imf_siolabel);
560 item_offset = offset;
562 do {
563 end_offset = tvb_find_uint8(tvb, item_offset, length - (item_offset - offset), ';');
565 /* skip leading space */
566 while (g_ascii_isspace(tvb_get_uint8(tvb, item_offset))) {
567 item_offset++;
570 if (end_offset == -1) {
571 /* length is to the end of the buffer */
572 item_length = tvb_find_line_end(tvb, item_offset, length - (item_offset - offset), NULL, false);
573 } else {
574 item_length = end_offset - item_offset;
577 value_offset = tvb_find_uint8(tvb, item_offset, length - (item_offset - offset), '=') + 1;
578 while (g_ascii_isspace(tvb_get_uint8(tvb, value_offset))) {
579 value_offset++;
582 value_length = item_length - (value_offset - item_offset);
583 while (g_ascii_isspace(tvb_get_uint8(tvb, value_offset + value_length - 1))) {
584 value_length--;
587 if (tvb_strneql(tvb, item_offset, "marking", 7) == 0) {
588 const uint8_t* marking;
589 proto_tree_add_item_ret_string(tree, hf_imf_siolabel_marking, tvb, value_offset, value_length, ENC_ASCII|ENC_NA, pinfo->pool, &marking);
590 proto_item_append_text(item, ": %s", marking);
592 } else if (tvb_strneql(tvb, item_offset, "fgcolor", 7) == 0) {
593 proto_tree_add_item(tree, hf_imf_siolabel_fgcolor, tvb, value_offset, value_length, ENC_ASCII);
595 } else if (tvb_strneql(tvb, item_offset, "bgcolor", 7) == 0) {
596 proto_tree_add_item(tree, hf_imf_siolabel_bgcolor, tvb, value_offset, value_length, ENC_ASCII);
598 } else if (tvb_strneql(tvb, item_offset, "type", 4) == 0) {
599 type = tvb_get_string_enc(pinfo->pool, tvb, value_offset + 1, value_length - 2, ENC_ASCII); /* quoted */
600 proto_tree_add_item(tree, hf_imf_siolabel_type, tvb, value_offset, value_length, ENC_ASCII);
602 } else if (tvb_strneql(tvb, item_offset, "label", 5) == 0) {
603 char *label = tvb_get_string_enc(pinfo->pool, tvb, value_offset + 1, value_length - 2, ENC_ASCII); /* quoted */
604 wmem_strbuf_append(label_string, label);
606 if (tvb_get_uint8(tvb, item_offset + 5) == '*') { /* continuations */
607 int num = (int)strtol(tvb_get_string_enc(pinfo->pool, tvb, item_offset + 6, value_offset - item_offset + 6, ENC_ASCII), NULL, 10);
608 proto_tree_add_string_format(tree, hf_imf_siolabel_label, tvb, value_offset, value_length,
609 label, "Label[%d]: \"%s\"", num, label);
610 } else {
611 proto_tree_add_item(tree, hf_imf_siolabel_label, tvb, value_offset, value_length, ENC_ASCII);
614 } else {
615 sub_item = proto_tree_add_item(tree, hf_imf_siolabel_unknown, tvb, item_offset, item_length, ENC_ASCII);
616 expert_add_info(pinfo, sub_item, &ei_imf_unknown_param);
619 if (end_offset != -1) {
620 item_offset = end_offset + 1;
622 } while (end_offset != -1);
624 if (type && wmem_strbuf_get_len(label_string) > 0) {
625 if (strcmp (type, ":ess") == 0) {
626 label_tvb = base64_to_tvb(tvb, wmem_strbuf_get_str(label_string));
627 add_new_data_source(pinfo, label_tvb, "ESS Security Label");
628 dissect_ess_ESSSecurityLabel_PDU(label_tvb, pinfo, tree, NULL);
629 } else if (strcmp (type, ":x411") == 0) {
630 label_tvb = base64_to_tvb(tvb, wmem_strbuf_get_str(label_string));
631 add_new_data_source(pinfo, label_tvb, "X.411 Security Label");
632 dissect_p1_MessageSecurityLabel_PDU(label_tvb, pinfo, tree, NULL);
637 static void
638 dissect_imf_content_type(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_item *item,
639 const uint8_t **type, const uint8_t **parameters)
641 int first_colon;
642 int end_offset;
643 int len;
644 int i;
645 proto_tree *ct_tree;
647 /* first strip any whitespace */
648 for(i = 0; i < length; i++) {
649 if(!g_ascii_isspace(tvb_get_uint8(tvb, offset + i))) {
650 offset += i;
651 break;
655 /* find the first colon - there has to be a colon as there will have to be a boundary */
656 first_colon = tvb_find_uint8(tvb, offset, length, ';');
658 if(first_colon != -1) {
659 ct_tree = proto_item_add_subtree(item, ett_imf_content_type);
661 len = first_colon - offset;
662 proto_tree_add_item_ret_string(ct_tree, hf_imf_content_type_type, tvb, offset, len, ENC_ASCII|ENC_NA, pinfo->pool, type);
663 end_offset = imf_find_field_end (tvb, first_colon + 1, offset + length, NULL);
664 if (end_offset == -1) {
665 /* No end found */
666 return;
668 len = end_offset - (first_colon + 1) - 2; /* Do not include the last CRLF */
669 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);
675 imf_find_field_end(tvbuff_t *tvb, int offset, int max_length, bool *last_field)
678 while(offset < max_length) {
680 /* look for CR */
681 offset = tvb_find_uint8(tvb, offset, max_length - offset, '\r');
683 if(offset != -1) {
684 /* protect against buffer overrun and only then look for next char */
685 if (++offset < max_length && tvb_get_uint8(tvb, offset) == '\n') {
686 /* OK - so we have found CRLF */
687 if (++offset >= max_length) {
688 /* end of buffer and also end of fields */
689 if (last_field) {
690 *last_field = true;
692 /* caller expects that there is CRLF after returned offset, if last_field is set */
693 return offset - 2;
695 /* peek the next character */
696 switch(tvb_get_uint8(tvb, offset)) {
697 case '\r':
698 /* probably end of the fields */
699 if ((offset + 1) < max_length && tvb_get_uint8(tvb, offset + 1) == '\n') {
700 if(last_field) {
701 *last_field = true;
704 return offset;
705 case ' ':
706 case '\t':
707 /* continuation line */
708 break;
709 default:
710 /* this is a new field */
711 return offset;
714 } else {
715 /* couldn't find a CR - strange */
716 break;
721 return -1; /* Fail: No CR found (other than possible continuation) */
725 static int
726 dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
728 proto_item *item;
729 proto_tree *unknown_tree, *text_tree;
730 const uint8_t *content_type_str = NULL;
731 char *content_encoding_str = NULL;
732 const uint8_t *parameters = NULL;
733 int hf_id;
734 int start_offset = 0;
735 int value_offset = 0;
736 int unknown_offset = 0;
737 int end_offset = 0;
738 int max_length;
739 uint8_t *key;
740 bool last_field = false;
741 tvbuff_t *next_tvb;
742 struct imf_field *f_info;
743 imf_eo_t *eo_info = NULL;
745 if (have_tap_listener(imf_eo_tap)) {
746 eo_info = wmem_new(pinfo->pool, imf_eo_t);
747 /* initialize the eo_info fields in case they are missing later */
748 eo_info->sender_data = "";
749 eo_info->subject_data = "";
752 /* Want to preserve existing protocol name and show that it is carrying IMF */
753 col_append_str(pinfo->cinfo, COL_PROTOCOL, "/");
754 col_set_fence(pinfo->cinfo, COL_PROTOCOL);
755 col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
757 col_clear(pinfo->cinfo, COL_INFO);
759 item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, ENC_NA);
760 tree = proto_item_add_subtree(item, ett_imf);
762 max_length = tvb_captured_length(tvb);
763 /* first go through the tvb until we find a blank line and extract the content type if
764 we find one */
766 /* XXX: What if the tvb contains encrypted data ? is there a way to bypass dissection if so ? */
767 /* As it is, the following code blithely tries to parse what may be binary data. */
769 while(!last_field) {
771 /* look for a colon first */
772 end_offset = tvb_find_uint8(tvb, start_offset, max_length - start_offset, ':');
774 if(end_offset == -1) {
775 /* we couldn't find another colon - strange - we should have broken out of here by now */
776 /* XXX: flag an error */
777 break;
778 } else {
779 key = tvb_get_string_enc(pinfo->pool, tvb, start_offset, end_offset - start_offset, ENC_ASCII);
781 /* convert to lower case */
782 ascii_strdown_inplace (key);
784 /* look up the key in built-in fields */
785 f_info = (struct imf_field *)wmem_map_lookup(imf_field_table, key);
787 if(f_info == NULL && custom_field_table) {
788 /* look up the key in custom fields */
789 f_info = (struct imf_field *)g_hash_table_lookup(custom_field_table, key);
792 if(f_info == NULL) {
793 /* set as an unknown extension */
794 f_info = imf_fields;
795 unknown_offset = start_offset;
798 hf_id = *(f_info->hf_id);
800 /* value starts immediately after the colon */
801 start_offset = end_offset+1;
803 end_offset = imf_find_field_end(tvb, start_offset, max_length, &last_field);
804 if(end_offset == -1) {
805 break; /* Something's fishy */
808 /* remove any leading whitespace */
810 for(value_offset = start_offset; value_offset < end_offset; value_offset++)
811 if(!g_ascii_isspace(tvb_get_uint8(tvb, value_offset))) {
812 break;
815 if(value_offset == end_offset) {
816 /* empty field - show whole value */
817 value_offset = start_offset;
820 if(hf_id == hf_imf_extension_type) {
822 /* remove 2 bytes to take off the final CRLF to make things a little prettier */
823 item = proto_tree_add_item(tree, hf_imf_extension, tvb, unknown_offset, end_offset - unknown_offset - 2, ENC_ASCII);
825 proto_item_append_text(item, " (Contact Wireshark developers if you want this supported.)");
827 unknown_tree = proto_item_add_subtree(item, ett_imf_extension);
829 proto_tree_add_item(unknown_tree, hf_imf_extension_type, tvb, unknown_offset, start_offset - 1 - unknown_offset, ENC_ASCII);
831 /* remove 2 bytes to take off the final CRLF to make things a little prettier */
832 item = proto_tree_add_item(unknown_tree, hf_imf_extension_value, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII);
834 } else {
835 /* remove 2 bytes to take off the final CRLF to make things a little prettier */
836 item = proto_tree_add_item(tree, hf_id, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
838 if(f_info->add_to_col_info) {
840 col_append_fstr(pinfo->cinfo, COL_INFO, "%s: %s, ", f_info->name,
841 tvb_format_text(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2));
843 /* if sender or subject, store for sending to the tap */
844 if (eo_info && have_tap_listener(imf_eo_tap)) {
845 if (*f_info->hf_id == hf_imf_from) {
846 eo_info->sender_data = tvb_get_string_enc(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
847 } else if(*f_info->hf_id == hf_imf_subject) {
848 eo_info->subject_data = tvb_get_string_enc(pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
853 if(hf_id == hf_imf_content_type) {
854 /* we need some additional processing to extract the content type and parameters */
856 dissect_imf_content_type(tvb, pinfo, start_offset, end_offset - start_offset, item,
857 &content_type_str, &parameters);
859 } else if (hf_id == hf_imf_content_transfer_encoding) {
860 content_encoding_str = tvb_get_string_enc (pinfo->pool, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII);
861 } else if(f_info->subdissector) {
863 /* we have a subdissector */
864 f_info->subdissector(tvb, value_offset, end_offset - value_offset, item, pinfo);
868 start_offset = end_offset;
871 if (last_field) {
872 /* Remove the extra CRLF after all the fields */
873 end_offset += 2;
876 if (end_offset == -1) {
877 end_offset = 0;
880 /* specify a content type until we can work it out for ourselves */
881 /* content_type_str = "multipart/mixed"; */
883 /* now dissect the MIME based upon the content type */
885 if(content_type_str && media_type_dissector_table) {
886 media_content_info_t content_info;
888 col_set_fence(pinfo->cinfo, COL_INFO);
890 if(content_encoding_str && !g_ascii_strncasecmp(content_encoding_str, "base64", 6)) {
891 char *string_data = tvb_get_string_enc(pinfo->pool, tvb, end_offset, tvb_reported_length(tvb) - end_offset, ENC_ASCII);
892 next_tvb = base64_to_tvb(tvb, string_data);
893 add_new_data_source(pinfo, next_tvb, content_encoding_str);
894 } else {
895 next_tvb = tvb_new_subset_remaining(tvb, end_offset);
898 content_info.type = MEDIA_CONTAINER_OTHER;
899 content_info.media_str = parameters;
900 content_info.data = NULL;
901 dissector_try_string_with_data(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree, true, (void*)&content_info);
902 } else {
904 /* just show the lines or highlight the rest of the buffer as message text */
906 item = proto_tree_add_item(tree, hf_imf_message_text, tvb, end_offset, tvb_reported_length_remaining(tvb, end_offset) , ENC_NA);
907 text_tree = proto_item_add_subtree(item, ett_imf_message_text);
909 start_offset = end_offset;
910 while (tvb_offset_exists(tvb, start_offset)) {
913 * Find the end of the line.
915 tvb_find_line_end(tvb, start_offset, -1, &end_offset, false);
918 * Put this line.
920 proto_tree_add_format_wsp_text(text_tree, tvb, start_offset, end_offset - start_offset);
921 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ",
922 tvb_format_text_wsp(pinfo->pool, tvb, start_offset, end_offset - start_offset));
925 * Step to the next line.
927 start_offset = end_offset;
931 if (eo_info && have_tap_listener(imf_eo_tap)) {
932 /* Set payload info */
933 eo_info->payload_len = max_length;
934 eo_info->payload_data = (char *) tvb_memdup(pinfo->pool, tvb, 0, max_length);
936 /* Send to tap */
937 tap_queue_packet(imf_eo_tap, pinfo, eo_info);
939 return tvb_captured_length(tvb);
942 static void
943 free_imf_field (void *data)
945 struct imf_field *imffield = (struct imf_field *) data;
947 g_free (imffield->name);
948 g_free (imffield);
951 static void
952 deregister_header_fields(void)
954 if (dynamic_hf) {
955 /* Deregister all fields */
956 for (unsigned i = 0; i < dynamic_hf_size; i++) {
957 proto_deregister_field (proto_imf, *(dynamic_hf[i].p_id));
958 g_free (dynamic_hf[i].p_id);
961 proto_add_deregistered_data (dynamic_hf);
962 dynamic_hf = NULL;
963 dynamic_hf_size = 0;
966 if (custom_field_table) {
967 g_hash_table_destroy (custom_field_table);
968 custom_field_table = NULL;
972 static void
973 header_fields_post_update_cb (void)
975 int *hf_id;
976 struct imf_field *imffield;
977 char *header_name;
979 deregister_header_fields();
981 if (num_header_fields) {
982 custom_field_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_imf_field);
983 dynamic_hf = g_new0(hf_register_info, num_header_fields);
984 dynamic_hf_size = num_header_fields;
986 for (unsigned i = 0; i < dynamic_hf_size; i++) {
987 hf_id = g_new(int, 1);
988 *hf_id = -1;
989 header_name = g_strdup (header_fields[i].header_name);
991 dynamic_hf[i].p_id = hf_id;
992 dynamic_hf[i].hfinfo.name = header_name;
993 dynamic_hf[i].hfinfo.abbrev = ws_strdup_printf ("imf.header.%s", header_name);
994 dynamic_hf[i].hfinfo.type = FT_STRING;
995 dynamic_hf[i].hfinfo.display = BASE_NONE;
996 dynamic_hf[i].hfinfo.strings = NULL;
997 dynamic_hf[i].hfinfo.bitmask = 0;
998 dynamic_hf[i].hfinfo.blurb = g_strdup (header_fields[i].description);
999 HFILL_INIT(dynamic_hf[i]);
1001 imffield = g_new(struct imf_field, 1);
1002 imffield->hf_id = hf_id;
1003 imffield->name = g_ascii_strdown(header_name, -1);
1004 switch (header_fields[i].header_format) {
1005 case FORMAT_UNSTRUCTURED:
1006 imffield->subdissector = NO_SUBDISSECTION;
1007 break;
1008 case FORMAT_MAILBOX:
1009 imffield->subdissector = dissect_imf_mailbox;
1010 break;
1011 case FORMAT_ADDRESS:
1012 imffield->subdissector = dissect_imf_address;
1013 break;
1014 case FORMAT_MAILBOX_LIST:
1015 imffield->subdissector = dissect_imf_mailbox_list;
1016 break;
1017 case FORMAT_ADDRESS_LIST:
1018 imffield->subdissector = dissect_imf_address_list;
1019 break;
1020 case FORMAT_SIO_LABEL:
1021 dynamic_hf[i].hfinfo.type = FT_NONE; /* constructed */
1022 imffield->subdissector = dissect_imf_siolabel;
1023 break;
1024 default:
1025 /* unknown */
1026 imffield->subdissector = NO_SUBDISSECTION;
1027 break;
1029 imffield->add_to_col_info = header_fields[i].add_to_col_info;
1030 g_hash_table_insert (custom_field_table, (void *)imffield->name, (void *)imffield);
1033 proto_register_field_array (proto_imf, dynamic_hf, dynamic_hf_size);
1037 static void
1038 header_fields_reset_cb(void)
1040 deregister_header_fields();
1043 /* Register all the bits needed by the filtering engine */
1045 void
1046 proto_register_imf(void)
1048 static hf_register_info hf[] = {
1049 { &hf_imf_date,
1050 { "Date", "imf.date", FT_STRING, BASE_NONE, NULL, 0x0,
1051 "DateTime", HFILL }},
1052 { &hf_imf_from,
1053 { "From", "imf.from", FT_STRING, BASE_NONE, NULL, 0x0,
1054 "MailboxList", HFILL }},
1055 { &hf_imf_sender,
1056 { "Sender", "imf.sender", FT_STRING, BASE_NONE, NULL, 0x0,
1057 NULL, HFILL }},
1058 { &hf_imf_reply_to,
1059 { "Reply-To", "imf.reply_to", FT_STRING, BASE_NONE, NULL, 0x0,
1060 NULL, HFILL }},
1061 { &hf_imf_to,
1062 { "To", "imf.to", FT_STRING, BASE_NONE, NULL, 0x0,
1063 NULL, HFILL }},
1064 { &hf_imf_cc,
1065 { "Cc", "imf.cc", FT_STRING, BASE_NONE, NULL, 0x0,
1066 NULL, HFILL }},
1067 { &hf_imf_bcc,
1068 { "Bcc", "imf.bcc", FT_STRING, BASE_NONE, NULL, 0x0,
1069 NULL, HFILL }},
1070 { &hf_imf_message_id,
1071 { "Message-ID", "imf.message_id", FT_STRING, BASE_NONE, NULL, 0x0,
1072 NULL, HFILL }},
1073 { &hf_imf_in_reply_to,
1074 { "In-Reply-To", "imf.in_reply_to", FT_STRING, BASE_NONE, NULL, 0x0,
1075 NULL, HFILL }},
1076 { &hf_imf_references,
1077 { "References", "imf.references", FT_STRING, BASE_NONE, NULL, 0x0,
1078 NULL, HFILL }},
1079 { &hf_imf_subject,
1080 { "Subject", "imf.subject", FT_STRING, BASE_NONE, NULL, 0x0,
1081 NULL, HFILL }},
1082 { &hf_imf_comments,
1083 { "Comments", "imf.comments", FT_STRING, BASE_NONE, NULL, 0x0,
1084 NULL, HFILL }},
1085 { &hf_imf_user_agent,
1086 { "User-Agent", "imf.user_agent", FT_STRING, BASE_NONE, NULL, 0x0,
1087 NULL, HFILL }},
1088 { &hf_imf_keywords,
1089 { "Keywords", "imf.keywords", FT_STRING, BASE_NONE, NULL, 0x0,
1090 NULL, HFILL }},
1091 { &hf_imf_resent_date,
1092 { "Resent-Date", "imf.resent.date", FT_STRING, BASE_NONE, NULL, 0x0,
1093 NULL, HFILL }},
1094 { &hf_imf_resent_from,
1095 { "Resent-From", "imf.resent.from", FT_STRING, BASE_NONE, NULL, 0x0,
1096 NULL, HFILL }},
1097 { &hf_imf_resent_sender,
1098 { "Resent-Sender", "imf.resent.sender", FT_STRING, BASE_NONE, NULL, 0x0,
1099 NULL, HFILL }},
1100 { &hf_imf_resent_to,
1101 { "Resent-To", "imf.resent.to", FT_STRING, BASE_NONE, NULL, 0x0,
1102 NULL, HFILL }},
1103 { &hf_imf_resent_cc,
1104 { "Resent-Cc", "imf.resent.cc", FT_STRING, BASE_NONE, NULL, 0x0,
1105 NULL, HFILL }},
1106 { &hf_imf_resent_bcc,
1107 { "Resent-Bcc", "imf.resent.bcc", FT_STRING, BASE_NONE, NULL, 0x0,
1108 NULL, HFILL }},
1109 { &hf_imf_resent_message_id,
1110 { "Resent-Message-ID", "imf.resent.message_id", FT_STRING, BASE_NONE, NULL, 0x0,
1111 NULL, HFILL }},
1112 { &hf_imf_return_path,
1113 { "Return-Path", "imf.return_path", FT_STRING, BASE_NONE, NULL, 0x0,
1114 NULL, HFILL }},
1115 { &hf_imf_received,
1116 { "Received", "imf.received", FT_STRING, BASE_NONE, NULL, 0x0,
1117 NULL, HFILL }},
1118 { &hf_imf_content_type,
1119 { "Content-Type", "imf.content.type", FT_STRING, BASE_NONE, NULL, 0x0,
1120 NULL, HFILL }},
1121 { &hf_imf_content_type_type,
1122 { "Type", "imf.content.type.type", FT_STRING, BASE_NONE, NULL, 0x0,
1123 NULL, HFILL }},
1124 { &hf_imf_content_type_parameters,
1125 { "Parameters", "imf.content.type.parameters", FT_STRING, BASE_NONE, NULL, 0x0,
1126 NULL, HFILL }},
1127 { &hf_imf_content_description,
1128 { "Content-Description", "imf.content.description", FT_STRING, BASE_NONE, NULL, 0x0,
1129 NULL, HFILL }},
1130 { &hf_imf_content_id,
1131 { "Content-ID", "imf.content.id", FT_STRING, BASE_NONE, NULL, 0x0,
1132 NULL, HFILL }},
1133 { &hf_imf_content_transfer_encoding,
1134 { "Content-Transfer-Encoding", "imf.content.transfer_encoding", FT_STRING, BASE_NONE, NULL, 0x0,
1135 NULL, HFILL }},
1136 { &hf_imf_mime_version,
1137 { "MIME-Version", "imf.mime_version", FT_STRING, BASE_NONE, NULL, 0x0,
1138 NULL, HFILL }},
1139 { &hf_imf_autoforwarded,
1140 { "Autoforwarded", "imf.autoforwarded", FT_STRING, BASE_NONE, NULL, 0x0,
1141 NULL, HFILL }},
1142 { &hf_imf_autosubmitted,
1143 { "Autosubmitted", "imf.autosubmitted", FT_STRING, BASE_NONE, NULL, 0x0,
1144 NULL, HFILL }},
1145 { &hf_imf_x400_content_identifier,
1146 { "X400-Content-Identifier", "imf.x400_content_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1147 NULL, HFILL }},
1148 { &hf_imf_content_language,
1149 { "Content-Language", "imf.content_language", FT_STRING, BASE_NONE, NULL, 0x0,
1150 NULL, HFILL }},
1151 { &hf_imf_conversion,
1152 { "Conversion", "imf.conversion", FT_STRING, BASE_NONE, NULL, 0x0,
1153 NULL, HFILL }},
1154 { &hf_imf_conversion_with_loss,
1155 { "Conversion-With-Loss", "imf.conversion_with_loss", FT_STRING, BASE_NONE, NULL, 0x0,
1156 NULL, HFILL }},
1157 { &hf_imf_delivery_date,
1158 { "Delivery-Date", "imf.delivery_date", FT_STRING, BASE_NONE, NULL, 0x0,
1159 NULL, HFILL }},
1160 { &hf_imf_discarded_x400_ipms_extensions,
1161 { "Discarded-X400-IPMS-Extensions", "imf.discarded_x400_ipms_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1162 NULL, HFILL }},
1163 { &hf_imf_discarded_x400_mts_extensions,
1164 { "Discarded-X400-MTS-Extensions", "imf.discarded_x400_mts_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1165 NULL, HFILL }},
1166 { &hf_imf_dl_expansion_history,
1167 { "DL-Expansion-History", "imf.dl_expansion_history", FT_STRING, BASE_NONE, NULL, 0x0,
1168 NULL, HFILL }},
1169 { &hf_imf_deferred_delivery,
1170 { "Deferred-Delivery", "imf.deferred_delivery", FT_STRING, BASE_NONE, NULL, 0x0,
1171 NULL, HFILL }},
1172 { &hf_imf_expires,
1173 { "Expires", "imf.expires", FT_STRING, BASE_NONE, NULL, 0x0,
1174 NULL, HFILL }},
1175 { &hf_imf_importance,
1176 { "Importance", "imf.importance", FT_STRING, BASE_NONE, NULL, 0x0,
1177 NULL, HFILL }},
1178 { &hf_imf_incomplete_copy,
1179 { "Incomplete-Copy", "imf.incomplete_copy", FT_STRING, BASE_NONE, NULL, 0x0,
1180 NULL, HFILL }},
1181 { &hf_imf_latest_delivery_time,
1182 { "Latest-Delivery-Time", "imf.latest_delivery_time", FT_STRING, BASE_NONE, NULL, 0x0,
1183 NULL, HFILL }},
1184 { &hf_imf_message_type,
1185 { "Message-Type", "imf.message_type", FT_STRING, BASE_NONE, NULL, 0x0,
1186 NULL, HFILL }},
1187 { &hf_imf_original_encoded_information_types,
1188 { "Original-Encoded-Information-Types", "imf.original_encoded_information_types", FT_STRING, BASE_NONE, NULL, 0x0,
1189 NULL, HFILL }},
1190 { &hf_imf_originator_return_address,
1191 { "Originator-Return-Address", "imf.originator_return_address", FT_STRING, BASE_NONE, NULL, 0x0,
1192 NULL, HFILL }},
1193 { &hf_imf_priority,
1194 { "Priority", "imf.priority", FT_STRING, BASE_NONE, NULL, 0x0,
1195 NULL, HFILL }},
1196 { &hf_imf_reply_by,
1197 { "Reply-By", "imf.reply_by", FT_STRING, BASE_NONE, NULL, 0x0,
1198 NULL, HFILL }},
1199 { &hf_imf_sensitivity,
1200 { "Sensitivity", "imf.sensitivity", FT_STRING, BASE_NONE, NULL, 0x0,
1201 NULL, HFILL }},
1202 { &hf_imf_supersedes,
1203 { "Supersedes", "imf.supersedes", FT_STRING, BASE_NONE, NULL, 0x0,
1204 NULL, HFILL }},
1205 { &hf_imf_x400_content_type,
1206 { "X400-Content-Type", "imf.x400_content_type", FT_STRING, BASE_NONE, NULL, 0x0,
1207 NULL, HFILL }},
1208 { &hf_imf_x400_mts_identifier,
1209 { "X400-MTS-Identifier", "imf.x400_mts_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1210 NULL, HFILL }},
1211 { &hf_imf_x400_originator,
1212 { "X400-Originator", "imf.x400_originator", FT_STRING, BASE_NONE, NULL, 0x0,
1213 NULL, HFILL }},
1214 { &hf_imf_x400_received,
1215 { "X400-Received", "imf.x400_received", FT_STRING, BASE_NONE, NULL, 0x0,
1216 NULL, HFILL }},
1217 { &hf_imf_x400_recipients,
1218 { "X400-Recipients", "imf.x400_recipients", FT_STRING, BASE_NONE, NULL, 0x0,
1219 NULL, HFILL }},
1220 { &hf_imf_delivered_to,
1221 { "Delivered-To", "imf.delivered_to", FT_STRING, BASE_NONE, NULL, 0x0,
1222 NULL, HFILL }},
1223 { &hf_imf_ext_mailer,
1224 { "X-Mailer", "imf.ext.mailer", FT_STRING, BASE_NONE, NULL, 0x0,
1225 NULL, HFILL }},
1226 { &hf_imf_ext_mimeole,
1227 { "X-MimeOLE", "imf.ext.mimeole", FT_STRING, BASE_NONE, NULL, 0x0,
1228 NULL, HFILL }},
1229 { &hf_imf_ext_expiry_date,
1230 { "Expiry-Date", "imf.ext.expiry-date", FT_STRING, BASE_NONE, NULL, 0x0,
1231 NULL, HFILL }},
1232 { &hf_imf_ext_tnef_correlator,
1233 { "X-MS-TNEF-Correlator", "imf.ext.tnef-correlator", FT_STRING, BASE_NONE, NULL, 0x0,
1234 NULL, HFILL }},
1235 { &hf_imf_ext_uidl,
1236 { "X-UIDL", "imf.ext.uidl", FT_STRING, BASE_NONE, NULL, 0x0,
1237 NULL, HFILL }},
1238 { &hf_imf_ext_authentication_warning,
1239 { "X-Authentication-Warning", "imf.ext.authentication_warning", FT_STRING, BASE_NONE,
1240 NULL, 0x0, NULL, HFILL }},
1241 { &hf_imf_ext_virus_scanned,
1242 { "X-Virus-Scanned", "imf.ext.virus_scanned", FT_STRING, BASE_NONE, NULL, 0x0,
1243 NULL, HFILL }},
1244 { &hf_imf_ext_original_to,
1245 { "X-Original-To", "imf.ext.original-to", FT_STRING, BASE_NONE, NULL, 0x0,
1246 NULL, HFILL }},
1247 { &hf_imf_thread_index,
1248 { "Thread-Index", "imf.thread-index", FT_STRING, BASE_NONE, NULL, 0x0,
1249 NULL, HFILL }},
1250 { &hf_imf_lines,
1251 { "Lines", "imf.lines", FT_STRING, BASE_NONE, NULL, 0x0,
1252 NULL, HFILL }},
1253 { &hf_imf_precedence,
1254 { "Precedence", "imf.precedence", FT_STRING, BASE_NONE, NULL, 0x0,
1255 NULL, HFILL }},
1256 { &hf_imf_extension,
1257 { "Unknown-Extension", "imf.extension", FT_STRING, BASE_NONE, NULL, 0x0,
1258 NULL, HFILL }},
1259 { &hf_imf_extension_type,
1260 { "Type", "imf.extension.type", FT_STRING, BASE_NONE, NULL, 0x0,
1261 NULL, HFILL }},
1262 { &hf_imf_extension_value,
1263 { "Value", "imf.extension.value", FT_STRING, BASE_NONE, NULL, 0x0,
1264 NULL, HFILL }},
1265 { &hf_imf_display_name,
1266 { "Display-Name", "imf.display_name", FT_STRING, BASE_NONE, NULL, 0x0,
1267 NULL, HFILL }},
1268 { &hf_imf_address,
1269 { "Address", "imf.address", FT_STRING, BASE_NONE, NULL, 0x0,
1270 NULL, HFILL }},
1271 #if 0
1272 { &hf_imf_address_list,
1273 { "Address List", "imf.address_list", FT_UINT32, BASE_DEC, NULL, 0x0,
1274 NULL, HFILL }},
1275 #endif
1276 { &hf_imf_address_list_item,
1277 { "Item", "imf.address_list.item", FT_STRING, BASE_NONE, NULL, 0x0,
1278 NULL, HFILL }},
1279 #if 0
1280 { &hf_imf_mailbox_list,
1281 { "Mailbox List", "imf.mailbox_list", FT_UINT32, BASE_DEC, NULL, 0x0,
1282 NULL, HFILL }},
1283 #endif
1284 { &hf_imf_mailbox_list_item,
1285 { "Item", "imf.mailbox_list.item", FT_STRING, BASE_NONE, NULL, 0x0,
1286 NULL, HFILL }},
1287 { &hf_imf_siolabel,
1288 { "SIO-Label", "imf.siolabel", FT_NONE, BASE_NONE, NULL, 0x0,
1289 NULL, HFILL }},
1290 { &hf_imf_siolabel_marking,
1291 { "Marking", "imf.siolabel.marking", FT_STRING, BASE_NONE, NULL, 0x0,
1292 NULL, HFILL }},
1293 { &hf_imf_siolabel_fgcolor,
1294 { "Foreground Color", "imf.siolabel.fgcolor", FT_STRING, BASE_NONE, NULL, 0x0,
1295 NULL, HFILL }},
1296 { &hf_imf_siolabel_bgcolor,
1297 { "Background Color", "imf.siolabel.bgcolor", FT_STRING, BASE_NONE, NULL, 0x0,
1298 NULL, HFILL }},
1299 { &hf_imf_siolabel_type,
1300 { "Type", "imf.siolabel.type", FT_STRING, BASE_NONE, NULL, 0x0,
1301 NULL, HFILL }},
1302 { &hf_imf_siolabel_label,
1303 { "Label", "imf.siolabel.label", FT_STRING, BASE_NONE, NULL, 0x0,
1304 NULL, HFILL }},
1305 { &hf_imf_siolabel_unknown,
1306 { "Unknown parameter", "imf.siolabel.unknown", FT_STRING, BASE_NONE, NULL, 0x0,
1307 NULL, HFILL }},
1308 { &hf_imf_message_text,
1309 { "Message-Text", "imf.message_text", FT_NONE, BASE_NONE, NULL, 0x0,
1310 NULL, HFILL }},
1312 static int *ett[] = {
1313 &ett_imf,
1314 &ett_imf_content_type,
1315 &ett_imf_group,
1316 &ett_imf_mailbox,
1317 &ett_imf_mailbox_list,
1318 &ett_imf_address_list,
1319 &ett_imf_siolabel,
1320 &ett_imf_extension,
1321 &ett_imf_message_text,
1324 static ei_register_info ei[] = {
1325 { &ei_imf_unknown_param, { "imf.unknown_param", PI_PROTOCOL, PI_WARN, "Unknown parameter", EXPFILL }},
1328 static uat_field_t attributes_flds[] = {
1329 UAT_FLD_CSTRING(header_fields, header_name, "Header name", "IMF header name"),
1330 UAT_FLD_CSTRING(header_fields, description, "Description", "Description of the value contained in the header"),
1331 UAT_FLD_VS(header_fields, header_format, "Format", header_format, 0),
1332 UAT_FLD_VS(header_fields, add_to_col_info, "Add to Info column", add_to_col_info, 0),
1333 UAT_END_FIELDS
1336 uat_t *headers_uat = uat_new("Custom IMF headers",
1337 sizeof(header_field_t),
1338 "imf_header_fields",
1339 true,
1340 &header_fields,
1341 &num_header_fields,
1342 /* specifies named fields, so affects dissection
1343 and the set of named fields */
1344 UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
1345 NULL,
1346 header_fields_copy_cb,
1347 header_fields_update_cb,
1348 header_fields_free_cb,
1349 header_fields_post_update_cb,
1350 header_fields_reset_cb,
1351 attributes_flds);
1353 module_t *imf_module;
1354 expert_module_t* expert_imf;
1355 struct imf_field *f;
1357 proto_imf = proto_register_protocol(PNAME, PSNAME, PFNAME);
1359 proto_register_field_array(proto_imf, hf, array_length(hf));
1360 proto_register_subtree_array(ett, array_length(ett));
1361 expert_imf = expert_register_protocol(proto_imf);
1362 expert_register_field_array(expert_imf, ei, array_length(ei));
1364 /* Allow dissector to find be found by name. */
1365 imf_handle = register_dissector(PFNAME, dissect_imf, proto_imf);
1367 imf_module = prefs_register_protocol(proto_imf, NULL);
1368 prefs_register_uat_preference(imf_module, "custom_header_fields", "Custom IMF headers",
1369 "A table to define custom IMF headers for which fields can be "
1370 "setup and used for filtering/data extraction etc.",
1371 headers_uat);
1373 imf_field_table=wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); /* oid to syntax */
1375 /* register the fields for lookup */
1376 for(f = imf_fields; f->name; f++)
1377 wmem_map_insert(imf_field_table, (void *)f->name, (void *)f);
1379 /* Register for tapping */
1380 imf_eo_tap = register_export_object(proto_imf, imf_eo_packet, NULL);
1384 /* The registration hand-off routine */
1385 void
1386 proto_reg_handoff_imf(void)
1388 dissector_add_string("media_type",
1389 "message/rfc822", imf_handle);
1391 register_ber_oid_dissector_handle("1.2.840.113549.1.7.1", imf_handle, proto_imf, "id-data");
1394 * Get the content type and Internet media type table
1396 media_type_dissector_table = find_dissector_table("media_type");
1401 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1403 * Local Variables:
1404 * c-basic-offset: 2
1405 * tab-width: 8
1406 * indent-tabs-mode: nil
1407 * End:
1409 * ex: set shiftwidth=2 tabstop=8 expandtab:
1410 * :indentSize=2:tabSize=8:noTabs=true: