Update Free Software Foundation address.
[metze/wireshark/wip.git] / epan / dissectors / packet-imf.c
1 /* packet-imf.c
2  * Routines for Internet Message Format (IMF) packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2007 by Graeme Lunt
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <ctype.h>
32
33 #include <epan/packet.h>
34 #include <epan/addr_resolv.h>
35 #include <epan/strutil.h>
36 #include <epan/prefs.h>
37 #include <epan/uat.h>
38 #include <epan/base64.h>
39 #include <epan/expert.h>
40
41 #include <wsutil/str_util.h>
42
43 #include "packet-ber.h"
44 #include "packet-imf.h"
45 #include "packet-ess.h"
46 #include "packet-p1.h"
47
48 #define PNAME  "Internet Message Format"
49 #define PSNAME "IMF"
50 #define PFNAME "imf"
51
52 static int proto_imf = -1;
53
54 static int hf_imf_date = -1;
55 static int hf_imf_from = -1;
56 static int hf_imf_sender = -1;
57 static int hf_imf_reply_to = -1;
58 static int hf_imf_to = -1;
59 static int hf_imf_cc = -1;
60 static int hf_imf_bcc = -1;
61 static int hf_imf_message_id = -1;
62 static int hf_imf_in_reply_to = -1;
63 static int hf_imf_references = -1;
64 static int hf_imf_subject = -1;
65 static int hf_imf_comments = -1;
66 static int hf_imf_user_agent = -1;
67 static int hf_imf_keywords = -1;
68 static int hf_imf_resent_date = -1;
69 static int hf_imf_resent_from = -1;
70 static int hf_imf_resent_sender = -1;
71 static int hf_imf_resent_to = -1;
72 static int hf_imf_resent_cc = -1;
73 static int hf_imf_resent_bcc = -1;
74 static int hf_imf_resent_message_id = -1;
75 static int hf_imf_return_path = -1;
76 static int hf_imf_received = -1;
77 static int hf_imf_content_type = -1;
78 static int hf_imf_content_type_type = -1;
79 static int hf_imf_content_type_parameters = -1;
80 static int hf_imf_content_id = -1;
81 static int hf_imf_content_transfer_encoding = -1;
82 static int hf_imf_content_description = -1;
83 static int hf_imf_mime_version = -1;
84 static int hf_imf_thread_index = -1;
85 static int hf_imf_ext_mailer = -1;
86 static int hf_imf_ext_mimeole = -1;
87 static int hf_imf_ext_tnef_correlator = -1;
88 static int hf_imf_ext_expiry_date = -1;
89 static int hf_imf_ext_uidl = -1;
90 static int hf_imf_ext_authentication_warning = -1;
91 static int hf_imf_ext_virus_scanned = -1;
92 static int hf_imf_extension = -1;
93 static int hf_imf_extension_type = -1;
94 static int hf_imf_extension_value = -1;
95
96 /* RFC 2156 */
97 static int hf_imf_autoforwarded = -1;
98 static int hf_imf_autosubmitted = -1;
99 static int hf_imf_x400_content_identifier = -1;
100 static int hf_imf_content_language = -1;
101 static int hf_imf_conversion = -1;
102 static int hf_imf_conversion_with_loss = -1;
103 static int hf_imf_delivery_date = -1;
104 static int hf_imf_discarded_x400_ipms_extensions = -1;
105 static int hf_imf_discarded_x400_mts_extensions = -1;
106 static int hf_imf_dl_expansion_history = -1;
107 static int hf_imf_deferred_delivery = -1;
108 static int hf_imf_expires = -1;
109 static int hf_imf_importance = -1;
110 static int hf_imf_incomplete_copy = -1;
111 static int hf_imf_latest_delivery_time = -1;
112 static int hf_imf_message_type = -1;
113 static int hf_imf_original_encoded_information_types = -1;
114 static int hf_imf_originator_return_address = -1;
115 static int hf_imf_priority = -1;
116 static int hf_imf_reply_by = -1;
117 static int hf_imf_sensitivity = -1;
118 static int hf_imf_supersedes = -1;
119 static int hf_imf_x400_content_type = -1;
120 static int hf_imf_x400_mts_identifier = -1;
121 static int hf_imf_x400_originator = -1;
122 static int hf_imf_x400_received = -1;
123 static int hf_imf_x400_recipients = -1;
124
125 static int hf_imf_delivered_to = -1;
126
127 static int hf_imf_message_text = -1;
128
129 static int hf_imf_display_name = -1;
130 static int hf_imf_address = -1;
131 static int hf_imf_mailbox_list = -1;
132 static int hf_imf_mailbox_list_item = -1;
133 static int hf_imf_address_list = -1;
134 static int hf_imf_address_list_item = -1;
135
136 /* draft-zeilenga-email-seclabel-04 */
137 static int hf_imf_siolabel = -1;
138 static int hf_imf_siolabel_marking = -1;
139 static int hf_imf_siolabel_fgcolor = -1;
140 static int hf_imf_siolabel_bgcolor = -1;
141 static int hf_imf_siolabel_type = -1;
142 static int hf_imf_siolabel_label = -1;
143 static int hf_imf_siolabel_unknown = -1;
144
145 static int ett_imf = -1;
146 static int ett_imf_content_type = -1;
147 static int ett_imf_mailbox = -1;
148 static int ett_imf_group = -1;
149 static int ett_imf_mailbox_list = -1;
150 static int ett_imf_address_list = -1;
151 static int ett_imf_siolabel = -1;
152 static int ett_imf_extension = -1;
153 static int ett_imf_message_text = -1;
154
155 struct imf_field {
156   const char   *name;           /* field name - in lower case for matching purposes */
157   int          *hf_id;          /* wireshark field */
158   void         (*subdissector)(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
159   gboolean     add_to_col_info; /* add field to column info */
160 };
161
162 #define NO_SUBDISSECTION NULL
163
164 static void dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
165 static void dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
166 static void dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
167 static void dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
168 static void dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
169
170 static struct imf_field imf_fields[] = {
171   {"unknown-extension",                   &hf_imf_extension_type, NO_SUBDISSECTION, FALSE}, /* unknown extension */
172   {"date",                                &hf_imf_date, NO_SUBDISSECTION, FALSE}, /* date-time */
173   {"from",                                &hf_imf_from, dissect_imf_mailbox_list , TRUE}, /* mailbox_list */
174   {"sender",                              &hf_imf_sender, dissect_imf_mailbox, FALSE}, /* mailbox */
175   {"reply-to",                            &hf_imf_reply_to, dissect_imf_address_list , FALSE}, /* address_list */
176   {"to",                                  &hf_imf_to, dissect_imf_address_list , FALSE}, /* address_list */
177   {"cc",                                  &hf_imf_cc, dissect_imf_address_list , FALSE}, /* address_list */
178   {"bcc",                                 &hf_imf_bcc, dissect_imf_address_list , FALSE}, /* address_list */
179   {"message-id",                          &hf_imf_message_id, NO_SUBDISSECTION, FALSE}, /* msg-id */
180   {"in-reply-to",                         &hf_imf_in_reply_to, NO_SUBDISSECTION, FALSE}, /* msg-id */
181   {"references",                          &hf_imf_references, NO_SUBDISSECTION, FALSE}, /* msg-id */
182   {"subject",                             &hf_imf_subject, NO_SUBDISSECTION, TRUE}, /* unstructured */
183   {"comments",                            &hf_imf_comments, NO_SUBDISSECTION, FALSE}, /* unstructured */
184   {"user-agent",                          &hf_imf_user_agent, NO_SUBDISSECTION, FALSE}, /* unstructured */
185   {"keywords",                            &hf_imf_keywords, NULL, FALSE}, /* phrase_list */
186   {"resent-date",                         &hf_imf_resent_date, NO_SUBDISSECTION, FALSE},
187   {"resent-from",                         &hf_imf_resent_from, dissect_imf_mailbox_list, FALSE},
188   {"resent-sender",                       &hf_imf_resent_sender, dissect_imf_mailbox, FALSE},
189   {"resent-to",                           &hf_imf_resent_to, dissect_imf_address_list, FALSE},
190   {"resent-cc",                           &hf_imf_resent_cc, dissect_imf_address_list, FALSE},
191   {"resent-bcc",                          &hf_imf_resent_bcc, dissect_imf_address_list, FALSE},
192   {"resent-message-id",                   &hf_imf_resent_message_id, NO_SUBDISSECTION, FALSE},
193   {"return-path",                         &hf_imf_return_path, NULL, FALSE},
194   {"received",                            &hf_imf_received, NO_SUBDISSECTION, FALSE},
195   /* these are really multi-part - but we parse them anyway */
196   {"content-type",                        &hf_imf_content_type, NULL, FALSE}, /* handled separately as a special case */
197   {"content-id",                          &hf_imf_content_id, NULL, FALSE},
198   {"content-description",                 &hf_imf_content_description, NULL, FALSE},
199   {"content-transfer-encoding",           &hf_imf_content_transfer_encoding, NULL, FALSE},
200   {"mime-version",                        &hf_imf_mime_version, NO_SUBDISSECTION, FALSE},
201   /* MIXER - RFC 2156 */
202   {"autoforwarded",                       &hf_imf_autoforwarded, NULL, FALSE},
203   {"autosubmitted",                       &hf_imf_autosubmitted, NULL, FALSE},
204   {"x400-content-identifier",             &hf_imf_x400_content_identifier, NULL, FALSE},
205   {"content-language",                    &hf_imf_content_language, NULL, FALSE},
206   {"conversion",                          &hf_imf_conversion, NULL, FALSE},
207   {"conversion-with-loss",                &hf_imf_conversion_with_loss, NULL, FALSE},
208   {"delivery-date",                       &hf_imf_delivery_date, NULL, FALSE},
209   {"discarded-x400-ipms-extensions",      &hf_imf_discarded_x400_ipms_extensions, NULL, FALSE},
210   {"discarded-x400-mts-extensions",       &hf_imf_discarded_x400_mts_extensions, NULL, FALSE},
211   {"dl-expansion-history",                &hf_imf_dl_expansion_history, NULL, FALSE},
212   {"deferred-delivery",                   &hf_imf_deferred_delivery, NULL, FALSE},
213   {"expires",                             &hf_imf_expires, NULL, FALSE},
214   {"importance",                          &hf_imf_importance, NULL, FALSE},
215   {"incomplete-copy",                     &hf_imf_incomplete_copy, NULL, FALSE},
216   {"latest-delivery-time",                &hf_imf_latest_delivery_time, NULL, FALSE},
217   {"message-type",                        &hf_imf_message_type, NULL, FALSE},
218   {"original-encoded-information-types",  &hf_imf_original_encoded_information_types, NULL, FALSE},
219   {"originator-return-address",           &hf_imf_originator_return_address, NULL, FALSE},
220   {"priority",                            &hf_imf_priority, NULL, FALSE},
221   {"reply-by",                            &hf_imf_reply_by, NULL, FALSE},
222   {"sensitivity",                         &hf_imf_sensitivity, NULL, FALSE},
223   {"supersedes",                          &hf_imf_supersedes, NULL, FALSE},
224   {"x400-content-type",                   &hf_imf_x400_content_type, NULL, FALSE},
225   {"x400-mts-identifier",                 &hf_imf_x400_mts_identifier, NULL, FALSE},
226   {"x400-originator",                     &hf_imf_x400_originator, NULL, FALSE},
227   {"x400-received",                       &hf_imf_x400_received, NULL, FALSE},
228   {"x400-recipients",                     &hf_imf_x400_recipients, NULL, FALSE},
229   /* delivery */
230   {"delivered-to",                        &hf_imf_delivered_to, dissect_imf_mailbox, FALSE}, /* mailbox */
231   /* some others */
232   {"x-mailer",                            &hf_imf_ext_mailer, NO_SUBDISSECTION, FALSE}, /* unstructured */
233   {"thread-index",                        &hf_imf_thread_index, NO_SUBDISSECTION, FALSE}, /* unstructured */
234   {"x-mimeole",                           &hf_imf_ext_mimeole, NO_SUBDISSECTION, FALSE}, /* unstructured */
235   {"expiry-date",                         &hf_imf_ext_expiry_date, NO_SUBDISSECTION, FALSE}, /* unstructured */
236   {"x-ms-tnef-correlator",                &hf_imf_ext_tnef_correlator, NO_SUBDISSECTION, FALSE}, /* unstructured */
237   {"x-uidl",                              &hf_imf_ext_uidl, NO_SUBDISSECTION, FALSE}, /* unstructured */
238   {"x-authentication-warning",            &hf_imf_ext_authentication_warning, NO_SUBDISSECTION, FALSE}, /* unstructured */
239   {"x-virus-scanned",                     &hf_imf_ext_virus_scanned, NO_SUBDISSECTION, FALSE}, /* unstructured */
240   {"sio-label",                           &hf_imf_siolabel, dissect_imf_siolabel, FALSE}, /* sio-label */
241   {NULL, NULL, NULL, FALSE},
242 };
243
244 static GHashTable *imf_field_table=NULL;
245
246 #define FORMAT_UNSTRUCTURED  0
247 #define FORMAT_MAILBOX       1
248 #define FORMAT_ADDRESS       2
249 #define FORMAT_MAILBOX_LIST  3
250 #define FORMAT_ADDRESS_LIST  4
251 #define FORMAT_SIO_LABEL     5
252
253 static const value_string header_format[] = {
254   { FORMAT_UNSTRUCTURED, "Unstructured" },
255   { FORMAT_MAILBOX,      "Mailbox"      },
256   { FORMAT_ADDRESS,      "Address"      },
257   { FORMAT_MAILBOX_LIST, "Mailbox List" },
258   { FORMAT_ADDRESS_LIST, "Address List" },
259   { FORMAT_SIO_LABEL,    "SIO-Label"    },
260   { 0, NULL }
261 };
262
263 static const value_string add_to_col_info[] = {
264   { 0, "No"  },
265   { 1, "Yes" },
266   { 0, NULL }
267 };
268
269 typedef struct _header_field_t {
270   gchar *header_name;
271   gchar *description;
272   guint  header_format;
273   guint  add_to_col_info;
274 } header_field_t;
275
276 static header_field_t *header_fields = NULL;
277 static guint num_header_fields = 0;
278
279 static GHashTable *custom_field_table = NULL;
280
281 static void
282 header_fields_update_cb(void *r, const char **err)
283 {
284   header_field_t *rec = r;
285   char c;
286
287   if (rec->header_name == NULL) {
288     *err = ep_strdup_printf("Header name can't be empty");
289     return;
290   }
291
292   g_strstrip(rec->header_name);
293   if (rec->header_name[0] == 0) {
294     *err = ep_strdup_printf("Header name can't be empty");
295     return;
296   }
297
298   /* Check for invalid characters (to avoid asserting out when
299    * registering the field).
300    */
301   c = proto_check_field_name(rec->header_name);
302   if (c) {
303     *err = ep_strdup_printf("Header name can't contain '%c'", c);
304     return;
305   }
306
307   *err = NULL;
308 }
309
310 static void *
311 header_fields_copy_cb(void *n, const void *o, size_t siz _U_)
312 {
313   header_field_t *new_rec = n;
314   const header_field_t *old_rec = o;
315
316   new_rec->header_name = g_strdup(old_rec->header_name);
317   new_rec->description = g_strdup(old_rec->description);
318   new_rec->header_format = old_rec->header_format;
319   new_rec->add_to_col_info = old_rec->add_to_col_info;
320
321   return new_rec;
322 }
323
324 static void
325 header_fields_free_cb(void *r)
326 {
327   header_field_t *rec = r;
328
329   g_free(rec->header_name);
330   g_free(rec->description);
331 }
332
333 UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t)
334 UAT_CSTRING_CB_DEF(header_fields, description, header_field_t)
335 UAT_VS_DEF(header_fields, header_format, header_field_t, 0, "Unstructured")
336 UAT_VS_DEF(header_fields, add_to_col_info, header_field_t, 0, "No")
337
338
339 /* Define media_type/Content type table */
340 static dissector_table_t media_type_dissector_table;
341
342 static void
343 dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
344 {
345   proto_tree *group_tree;
346   proto_item *group_item;
347   int addr_pos;
348
349   /* if there is a colon present it is a group */
350   if((addr_pos = tvb_find_guint8(tvb, offset, length, ':')) == -1) {
351
352     /* there isn't - so it must be a mailbox */
353     dissect_imf_mailbox(tvb, offset, length, item, pinfo);
354
355   } else {
356
357     /* it is a group */
358     group_tree = proto_item_add_subtree(item, ett_imf_group);
359
360     /* the display-name is mandatory */
361     group_item = proto_tree_add_item(group_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII|ENC_NA);
362
363     /* consume any whitespace */
364     for(addr_pos++ ;addr_pos < (offset + length); addr_pos++) {
365       if(!isspace(tvb_get_guint8(tvb, addr_pos))) {
366         break;
367       }
368     }
369
370     if(tvb_get_guint8(tvb, addr_pos) != ';') {
371
372       dissect_imf_mailbox_list(tvb, addr_pos, length - (addr_pos - offset), group_item, pinfo);
373
374       /* XXX: need to check for final ';' */
375
376     }
377
378   }
379 }
380
381 static void
382 dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo _U_)
383 {
384   proto_tree *mbox_tree;
385   int        addr_pos, end_pos;
386
387   mbox_tree = proto_item_add_subtree(item, ett_imf_mailbox);
388
389   /* Here is the plan:
390      If we can't find and angle brackets, then the whole field is an address.
391      If we find angle brackets, then the address is between them and the display name is
392      anything before the opening angle bracket
393   */
394
395   if((addr_pos = tvb_find_guint8(tvb, offset, length, '<')) == -1) {
396     /* we can't find an angle bracket - the whole field is therefore the address */
397
398     (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, offset, length, ENC_ASCII|ENC_NA);
399
400   } else {
401     /* we can find an angle bracket - let's see if we can find a display name */
402     /* XXX: the '<' could be in the display name */
403
404     for(; offset < addr_pos; offset++) {
405       if(!isspace(tvb_get_guint8(tvb, offset))) {
406         break;
407       }
408     }
409
410     if(offset != addr_pos) { /* there is a display name */
411       (void) proto_tree_add_item(mbox_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII|ENC_NA);
412     }
413     end_pos = tvb_find_guint8(tvb, addr_pos + 1, length - (addr_pos + 1 - offset), '>');
414
415     if(end_pos != -1) {
416       (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, addr_pos + 1, end_pos - addr_pos - 1, ENC_ASCII|ENC_NA);
417     }
418   }
419 }
420
421 static void
422 dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
423 {
424   proto_item *addr_item = NULL;
425   proto_tree *tree = NULL;
426   int         count = 0;
427   int         item_offset;
428   int         end_offset;
429   int         item_length;
430
431   /* a comma separated list of addresses */
432   tree = proto_item_add_subtree(item, ett_imf_address_list);
433
434   item_offset = offset;
435
436   do {
437
438     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
439
440     count++; /* increase the number of items */
441
442     if(end_offset == -1) {
443       /* length is to the end of the buffer */
444       item_length = length - (item_offset - offset);
445     } else {
446       item_length = end_offset - item_offset;
447     }
448     addr_item = proto_tree_add_item(tree, hf_imf_address_list_item, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
449     dissect_imf_address(tvb, item_offset, item_length, addr_item, pinfo);
450
451     if(end_offset != -1) {
452       item_offset = end_offset + 1;
453     }
454   } while(end_offset != -1);
455
456   /* now indicate the number of items found */
457   proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
458 }
459
460 static void
461 dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
462 {
463   proto_item *mbox_item = NULL;
464   proto_tree *tree = NULL;
465   int         count = 0;
466   int         item_offset;
467   int         end_offset;
468   int         item_length;
469
470   /* a comma separated list of mailboxes */
471   tree = proto_item_add_subtree(item, ett_imf_mailbox_list);
472
473   item_offset = offset;
474
475   do {
476
477     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
478
479     count++; /* increase the number of items */
480
481     if(end_offset == -1) {
482       /* length is to the end of the buffer */
483       item_length = length - (item_offset - offset);
484     } else {
485       item_length = end_offset - item_offset;
486     }
487     mbox_item = proto_tree_add_item(tree, hf_imf_mailbox_list_item, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
488     dissect_imf_mailbox(tvb, item_offset, item_length, mbox_item, pinfo);
489
490     if(end_offset != -1) {
491       item_offset = end_offset + 1;
492     }
493   } while(end_offset != -1);
494
495   /* now indicate the number of items found */
496   proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
497 }
498
499 static void
500 dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
501 {
502   proto_tree *tree = NULL;
503   proto_item *sub_item = NULL;
504   int         item_offset, item_length;
505   int         value_offset, value_length;
506   int         end_offset;
507   tvbuff_t   *label_tvb;
508   gchar      *type = NULL;
509   GString    *label_string = g_string_new ("");
510
511   /* a semicolon separated list of attributes */
512   tree = proto_item_add_subtree(item, ett_imf_siolabel);
513   item_offset = offset;
514
515   do {
516     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ';');
517
518     /* skip leading space */
519     while (isspace(tvb_get_guint8(tvb, item_offset))) {
520       item_offset++;
521     }
522
523     if (end_offset == -1) {
524       /* length is to the end of the buffer */
525       item_length = tvb_find_line_end(tvb, item_offset, length - (item_offset - offset), NULL, FALSE);
526     } else {
527       item_length = end_offset - item_offset;
528     }
529
530     value_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), '=') + 1;
531     while (isspace(tvb_get_guint8(tvb, value_offset))) {
532       value_offset++;
533     }
534
535     value_length = item_length - (value_offset - item_offset);
536     while (isspace(tvb_get_guint8(tvb, value_offset + value_length - 1))) {
537       value_length--;
538     }
539
540     if (tvb_strneql(tvb, item_offset, "marking", 7) == 0) {
541       proto_item_append_text(item, ": %s", tvb_get_ephemeral_string(tvb, value_offset, value_length));
542       proto_tree_add_item(tree, hf_imf_siolabel_marking, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
543
544     } else if (tvb_strneql(tvb, item_offset, "fgcolor", 7) == 0) {
545       proto_tree_add_item(tree, hf_imf_siolabel_fgcolor, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
546
547     } else if (tvb_strneql(tvb, item_offset, "bgcolor", 7) == 0) {
548       proto_tree_add_item(tree, hf_imf_siolabel_bgcolor, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
549
550     } else if (tvb_strneql(tvb, item_offset, "type", 4) == 0) {
551       type = tvb_get_ephemeral_string(tvb, value_offset + 1, value_length - 2); /* quoted */
552       proto_tree_add_item(tree, hf_imf_siolabel_type, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
553
554     } else if (tvb_strneql(tvb, item_offset, "label", 5) == 0) {
555       gchar *label = tvb_get_ephemeral_string(tvb, value_offset + 1, value_length - 2); /* quoted */
556       label_string = g_string_append(label_string, label);
557
558       if (tvb_get_guint8(tvb, item_offset + 5) == '*') { /* continuations */
559         int num = strtol(tvb_get_ephemeral_string(tvb, item_offset + 6, value_offset - item_offset + 6), NULL, 10);
560         proto_tree_add_string_format(tree, hf_imf_siolabel_label, tvb, value_offset, value_length,
561                                      label, "Label[%d]: \"%s\"", num, label);
562       } else {
563         proto_tree_add_item(tree, hf_imf_siolabel_label, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
564       }
565
566     } else {
567       sub_item = proto_tree_add_item(tree, hf_imf_siolabel_unknown, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
568       expert_add_info_format(pinfo, sub_item, PI_PROTOCOL, PI_WARN, "Unknown parameter");
569     }
570
571     if (end_offset != -1) {
572       item_offset = end_offset + 1;
573     }
574   } while (end_offset != -1);
575
576   if (type && label_string->len > 0) {
577     if (strcmp (type, ":ess") == 0) {
578       label_tvb = base64_to_tvb(tvb, label_string->str);
579       add_new_data_source(pinfo, label_tvb, "ESS Security Label");
580       dissect_ess_ESSSecurityLabel_PDU(label_tvb, pinfo, tree);
581     } else if (strcmp (type, ":x411") == 0) {
582       label_tvb = base64_to_tvb(tvb, label_string->str);
583       add_new_data_source(pinfo, label_tvb, "X.411 Security Label");
584       dissect_p1_MessageSecurityLabel_PDU(label_tvb, pinfo, tree);
585     }
586   }
587
588   g_string_free (label_string, TRUE);
589 }
590
591 static void
592 dissect_imf_content_type(tvbuff_t *tvb, int offset, int length, proto_item *item,
593                          char **type, char **parameters)
594 {
595   int first_colon;
596   int len;
597   int i;
598   proto_tree *ct_tree;
599
600   /* first strip any whitespace */
601   for(i = 0; i < length; i++) {
602     if(!isspace(tvb_get_guint8(tvb, offset + i))) {
603       offset += i;
604       break;
605     }
606   }
607
608   /* find the first colon - there has to be a colon as there will have to be a boundary */
609   first_colon = tvb_find_guint8(tvb, offset, length, ';');
610
611   if(first_colon != -1) {
612     ct_tree = proto_item_add_subtree(item, ett_imf_content_type);
613
614     len = first_colon - offset;
615     proto_tree_add_item(ct_tree, hf_imf_content_type_type, tvb, offset, len, ENC_ASCII|ENC_NA);
616     if(type) {
617       /* This string will be automatically freed */
618       (*type) = tvb_get_ephemeral_string(tvb, offset, len);
619     }
620     len = tvb_find_line_end(tvb, first_colon + 1, length, NULL, FALSE);
621     proto_tree_add_item(ct_tree, hf_imf_content_type_parameters, tvb, first_colon + 1, len, ENC_ASCII|ENC_NA);
622     if(parameters) {
623       /* This string will be automatically freed */
624       (*parameters) = tvb_get_ephemeral_string(tvb, first_colon + 1, len);
625     }
626   }
627 }
628
629
630 int
631 imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_field)
632 {
633
634   while(offset < max_length) {
635
636     /* look for CR */
637     offset = tvb_find_guint8(tvb, offset, max_length - offset, '\r');
638
639     if(offset != -1) {
640       if(tvb_get_guint8(tvb, ++offset) == '\n') {
641         /* OK - so we have found CRLF */
642         /* peek the next character */
643         switch(tvb_get_guint8(tvb, ++offset)) {
644         case '\r':
645           /* probably end of the fields */
646           if(tvb_get_guint8(tvb, ++offset) == '\n') {
647             offset++;
648           }
649           if(last_field) {
650             *last_field = TRUE;
651           }
652           return offset;
653         case  ' ':
654         case '\t':
655           /* continuation line */
656           break;
657         default:
658           /* this is a new field */
659           return offset;
660         }
661       }
662     } else {
663       /* couldn't find a CR - strange */
664       return offset;
665     }
666
667   }
668
669   return -1;  /* Fail: No CR found (other than possible continuation) */
670
671 }
672
673 static void
674 dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
675 {
676   proto_item  *item;
677   proto_tree  *unknown_tree, *text_tree;
678   char  *content_type_str = NULL;
679   char  *parameters = NULL;
680   int   hf_id;
681   gint  start_offset = 0;
682   gint  value_offset = 0;
683   gint  unknown_offset = 0;
684   gint  end_offset = 0;
685   gint   max_length;
686   guint8 *key;
687   gboolean last_field = FALSE;
688   tvbuff_t *next_tvb;
689   struct imf_field *f_info;
690
691   col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
692   col_clear(pinfo->cinfo, COL_INFO);
693
694   if(tree){
695     item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, ENC_NA);
696     tree = proto_item_add_subtree(item, ett_imf);
697   }
698
699   max_length = tvb_length(tvb);
700   /* first go through the tvb until we find a blank line and extract the content type if
701      we find one */
702
703   /* XXX: What if the tvb contains encrypted data ? is there a way to bypass dissection if so ?  */
704   /*      As it is, the following code blithely tries to parse what may be binary data.          */
705
706   while(!last_field) {
707
708     /* look for a colon first */
709     end_offset = tvb_find_guint8(tvb, start_offset, max_length - start_offset, ':');
710
711     if(end_offset == -1) {
712       /* we couldn't find another colon - strange - we should have broken out of here by now */
713       /* XXX: flag an error */
714       break;
715     } else {
716       key = tvb_get_ephemeral_string(tvb, start_offset, end_offset - start_offset);
717
718       /* convert to lower case */
719       ascii_strdown_inplace (key);
720
721       /* look up the key in built-in fields */
722       f_info = (struct imf_field *)g_hash_table_lookup(imf_field_table, key);
723
724       if(f_info == NULL && custom_field_table) {
725         /* look up the key in custom fields */
726         f_info = (struct imf_field *)g_hash_table_lookup(custom_field_table, key);
727       }
728
729       if(f_info == NULL) {
730         /* set as an unknown extension */
731         f_info = imf_fields;
732         unknown_offset = start_offset;
733       }
734
735       hf_id = *(f_info->hf_id);
736
737       /* value starts immediately after the colon */
738       start_offset = end_offset+1;
739
740       end_offset = imf_find_field_end(tvb, start_offset, max_length, &last_field);
741       if(end_offset == -1) {
742         break;   /* Something's fishy */
743       }
744
745       /* remove any leading whitespace */
746
747       for(value_offset = start_offset; value_offset < end_offset; value_offset++)
748         if(!isspace(tvb_get_guint8(tvb, value_offset))) {
749           break;
750         }
751
752       if(value_offset == end_offset) {
753         /* empty field - show whole value */
754         value_offset = start_offset;
755       }
756
757       if(hf_id == hf_imf_extension_type) {
758
759         /* remove 2 bytes to take off the final CRLF to make things a little prettier */
760         item = proto_tree_add_item(tree, hf_imf_extension, tvb, unknown_offset, end_offset - unknown_offset - 2, ENC_ASCII|ENC_NA);
761
762         proto_item_append_text(item, " (Contact Wireshark developers if you want this supported.)");
763
764         unknown_tree = proto_item_add_subtree(item, ett_imf_extension);
765
766         proto_tree_add_item(unknown_tree, hf_imf_extension_type, tvb, unknown_offset, start_offset - 1 - unknown_offset, ENC_ASCII|ENC_NA);
767
768         /* remove 2 bytes to take off the final CRLF to make things a little prettier */
769         item = proto_tree_add_item(unknown_tree, hf_imf_extension_value, tvb, start_offset, end_offset - start_offset - 2, ENC_ASCII|ENC_NA);
770
771       } else {
772         /* remove 2 bytes to take off the final CRLF to make things a little prettier */
773         item = proto_tree_add_item(tree, hf_id, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
774       }
775       if(f_info->add_to_col_info && check_col(pinfo->cinfo, COL_INFO)) {
776
777         col_append_fstr(pinfo->cinfo, COL_INFO, "%s: %s, ", f_info->name,
778                         tvb_format_text(tvb, value_offset, end_offset - value_offset - 2));
779       }
780
781       if(hf_id == hf_imf_content_type) {
782         /* we need some additional processing to extract the content type and parameters */
783
784         dissect_imf_content_type(tvb, start_offset, end_offset - start_offset, item,
785                                  &content_type_str, &parameters);
786
787       } else if(f_info->subdissector) {
788
789         /* we have a subdissector */
790         f_info->subdissector(tvb, value_offset, end_offset - value_offset, item, pinfo);
791
792       }
793     }
794     start_offset = end_offset;
795   }
796
797   if (end_offset == -1) {
798     end_offset = 0;
799   }
800
801   /* specify a content type until we can work it out for ourselves */
802   /* content_type_str = "multipart/mixed"; */
803
804   /* now dissect the MIME based upon the content type */
805
806   if(content_type_str && media_type_dissector_table) {
807     void* pd_save;
808     pd_save = pinfo->private_data;
809     pinfo->private_data = parameters;
810
811     next_tvb = tvb_new_subset_remaining(tvb, end_offset);
812
813     dissector_try_string(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree);
814
815     pinfo->private_data = pd_save;
816   } else {
817
818     /* just show the lines or highlight the rest of the buffer as message text */
819
820     item = proto_tree_add_item(tree, hf_imf_message_text, tvb, end_offset, -1 , ENC_NA);
821     text_tree = proto_item_add_subtree(item, ett_imf_message_text);
822
823     start_offset = end_offset;
824     while (tvb_offset_exists(tvb, start_offset)) {
825
826       /*
827        * Find the end of the line.
828        */
829       tvb_find_line_end(tvb, start_offset, -1, &end_offset, FALSE);
830
831       /*
832        * Put this line.
833        */
834       proto_tree_add_text(text_tree, tvb, start_offset, end_offset - start_offset,
835                           "%s",
836                           tvb_format_text_wsp(tvb, start_offset, end_offset - start_offset));
837       col_append_sep_str(pinfo->cinfo, COL_INFO, ", ",
838                          tvb_format_text_wsp(tvb, start_offset, end_offset - start_offset));
839
840       /*
841        * Step to the next line.
842        */
843       start_offset = end_offset;
844     }
845   }
846 }
847
848 static void
849 free_imf_field (gpointer data)
850 {
851   struct imf_field *imffield = (struct imf_field *) data;
852
853   g_free ((char *) imffield->name);
854   g_free (imffield);
855 }
856
857 static void
858 header_fields_initialize_cb (void)
859 {
860   static hf_register_info *hf;
861   gint *hf_id;
862   struct imf_field *imffield;
863   guint i;
864   gchar *header_name;
865
866   if (custom_field_table && hf) {
867     guint hf_size = g_hash_table_size (custom_field_table);
868     /* Unregister all fields */
869     for (i = 0; i < hf_size; i++) {
870       proto_unregister_field (proto_imf, *(hf[i].p_id));
871
872       g_free (hf[i].p_id);
873       g_free ((char *) hf[i].hfinfo.name);
874       g_free ((char *) hf[i].hfinfo.abbrev);
875       g_free ((char *) hf[i].hfinfo.blurb);
876     }
877     g_hash_table_destroy (custom_field_table);
878     g_free (hf);
879     custom_field_table = NULL;
880   }
881
882   if (num_header_fields) {
883     custom_field_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_imf_field);
884     hf = g_malloc0 (sizeof (hf_register_info) * num_header_fields);
885
886     for (i = 0; i < num_header_fields; i++) {
887       hf_id = g_malloc (sizeof (gint));
888       *hf_id = -1;
889       header_name = g_strdup (header_fields[i].header_name);
890
891       hf[i].p_id = hf_id;
892       hf[i].hfinfo.name = header_name;
893       hf[i].hfinfo.abbrev = g_strdup_printf ("imf.header.%s", header_name);
894       hf[i].hfinfo.type = FT_STRING;
895       hf[i].hfinfo.display = BASE_NONE;
896       hf[i].hfinfo.strings = NULL;
897       hf[i].hfinfo.blurb = g_strdup (header_fields[i].description);
898       hf[i].hfinfo.same_name_prev = NULL;
899       hf[i].hfinfo.same_name_next = NULL;
900
901       imffield = g_malloc (sizeof (struct imf_field));
902       imffield->hf_id = hf_id;
903       imffield->name = ascii_strdown_inplace (g_strdup (header_name));
904       switch (header_fields[i].header_format) {
905       case FORMAT_UNSTRUCTURED:
906         imffield->subdissector = NO_SUBDISSECTION;
907         break;
908       case FORMAT_MAILBOX:
909         imffield->subdissector = dissect_imf_mailbox;
910         break;
911       case FORMAT_ADDRESS:
912         imffield->subdissector = dissect_imf_address;
913         break;
914       case FORMAT_MAILBOX_LIST:
915         imffield->subdissector = dissect_imf_mailbox_list;
916         break;
917       case FORMAT_ADDRESS_LIST:
918         imffield->subdissector = dissect_imf_address_list;
919         break;
920       case FORMAT_SIO_LABEL:
921         hf[i].hfinfo.type = FT_NONE; /* constructed */
922         imffield->subdissector = dissect_imf_siolabel;
923         break;
924       default:
925         /* unknown */
926         imffield->subdissector = NO_SUBDISSECTION;
927         break;
928       }
929       imffield->add_to_col_info = header_fields[i].add_to_col_info;
930       g_hash_table_insert (custom_field_table, (gpointer)imffield->name, (gpointer)imffield);
931     }
932
933     proto_register_field_array (proto_imf, hf, num_header_fields);
934   }
935 }
936
937 /* Register all the bits needed by the filtering engine */
938
939 void
940 proto_register_imf(void)
941 {
942   static hf_register_info hf[] = {
943     { &hf_imf_date,
944       { "Date", "imf.date", FT_STRING,  BASE_NONE, NULL, 0x0,
945         "DateTime", HFILL }},
946     { &hf_imf_from,
947       { "From", "imf.from", FT_STRING,  BASE_NONE, NULL, 0x0,
948         "MailboxList", HFILL }},
949     { &hf_imf_sender,
950       { "Sender", "imf.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
951         NULL, HFILL }},
952     { &hf_imf_reply_to,
953       { "Reply-To", "imf.reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
954         NULL, HFILL }},
955     { &hf_imf_to,
956       { "To", "imf.to", FT_STRING,  BASE_NONE, NULL, 0x0,
957         NULL, HFILL }},
958     { &hf_imf_cc,
959       { "Cc", "imf.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
960         NULL, HFILL }},
961     { &hf_imf_bcc,
962       { "Bcc", "imf.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
963         NULL, HFILL }},
964     { &hf_imf_message_id,
965       { "Message-ID", "imf.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
966         NULL, HFILL }},
967     { &hf_imf_in_reply_to,
968       { "In-Reply-To", "imf.in_reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
969         NULL, HFILL }},
970     { &hf_imf_references,
971       { "References", "imf.references", FT_STRING,  BASE_NONE, NULL, 0x0,
972         NULL, HFILL }},
973     { &hf_imf_subject,
974       { "Subject", "imf.subject", FT_STRING,  BASE_NONE, NULL, 0x0,
975         NULL, HFILL }},
976     { &hf_imf_comments,
977       { "Comments", "imf.comments", FT_STRING,  BASE_NONE, NULL, 0x0,
978         NULL, HFILL }},
979     { &hf_imf_user_agent,
980       { "User-Agent", "imf.user_agent", FT_STRING,  BASE_NONE, NULL, 0x0,
981         NULL, HFILL }},
982     { &hf_imf_keywords,
983       { "Keywords", "imf.keywords", FT_STRING,  BASE_NONE, NULL, 0x0,
984         NULL, HFILL }},
985     { &hf_imf_resent_date,
986       { "Resent-Date", "imf.resent.date", FT_STRING,  BASE_NONE, NULL, 0x0,
987         NULL, HFILL }},
988     { &hf_imf_resent_from,
989       { "Resent-From", "imf.resent.from", FT_STRING,  BASE_NONE, NULL, 0x0,
990         NULL, HFILL }},
991     { &hf_imf_resent_sender,
992       { "Resent-Sender", "imf.resent.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
993         NULL, HFILL }},
994     { &hf_imf_resent_to,
995       { "Resent-To", "imf.resent.to", FT_STRING,  BASE_NONE, NULL, 0x0,
996         NULL, HFILL }},
997     { &hf_imf_resent_cc,
998       { "Resent-Cc", "imf.resent.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
999         NULL, HFILL }},
1000     { &hf_imf_resent_bcc,
1001       { "Resent-Bcc", "imf.resent.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
1002         NULL, HFILL }},
1003     { &hf_imf_resent_message_id,
1004       { "Resent-Message-ID", "imf.resent.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
1005         NULL, HFILL }},
1006     { &hf_imf_return_path,
1007       { "Return-Path", "imf.return_path", FT_STRING,  BASE_NONE, NULL, 0x0,
1008         NULL, HFILL }},
1009     { &hf_imf_received,
1010       { "Received", "imf.received", FT_STRING,  BASE_NONE, NULL, 0x0,
1011         NULL, HFILL }},
1012     { &hf_imf_content_type,
1013       { "Content-Type", "imf.content.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1014         NULL, HFILL }},
1015     { &hf_imf_content_type_type,
1016       { "Type", "imf.content.type.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1017         NULL, HFILL }},
1018     { &hf_imf_content_type_parameters,
1019       { "Parameters", "imf.content.type.parameters", FT_STRING,  BASE_NONE, NULL, 0x0,
1020         NULL, HFILL }},
1021     { &hf_imf_content_description,
1022       { "Content-Description", "imf.content.description", FT_STRING,  BASE_NONE, NULL, 0x0,
1023         NULL, HFILL }},
1024     { &hf_imf_content_id,
1025       { "Content-ID", "imf.content.id", FT_STRING,  BASE_NONE, NULL, 0x0,
1026         NULL, HFILL }},
1027     { &hf_imf_content_transfer_encoding,
1028       { "Content-Transfer-Encoding", "imf.content.transfer_encoding", FT_STRING,  BASE_NONE, NULL, 0x0,
1029         NULL, HFILL }},
1030     { &hf_imf_mime_version,
1031       { "MIME-Version", "imf.mime_version", FT_STRING,  BASE_NONE, NULL, 0x0,
1032         NULL, HFILL }},
1033     { &hf_imf_autoforwarded,
1034       { "Autoforwarded", "imf.autoforwarded", FT_STRING, BASE_NONE, NULL, 0x0,
1035         NULL, HFILL }},
1036     { &hf_imf_autosubmitted,
1037       { "Autosubmitted", "imf.autosubmitted", FT_STRING, BASE_NONE, NULL, 0x0,
1038         NULL, HFILL }},
1039     { &hf_imf_x400_content_identifier,
1040       { "X400-Content-Identifier", "imf.x400_content_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1041         NULL, HFILL }},
1042     { &hf_imf_content_language,
1043       { "Content-Language", "imf.content_language", FT_STRING, BASE_NONE, NULL, 0x0,
1044         NULL, HFILL }},
1045     { &hf_imf_conversion,
1046         { "Conversion", "imf.conversion", FT_STRING, BASE_NONE, NULL, 0x0,
1047           NULL, HFILL }},
1048     { &hf_imf_conversion_with_loss,
1049         { "Conversion-With-Loss", "imf.conversion_with_loss", FT_STRING, BASE_NONE, NULL, 0x0,
1050           NULL, HFILL }},
1051     { &hf_imf_delivery_date,
1052         { "Delivery-Date", "imf.delivery_date", FT_STRING, BASE_NONE, NULL, 0x0,
1053           NULL, HFILL }},
1054     { &hf_imf_discarded_x400_ipms_extensions,
1055         { "Discarded-X400-IPMS-Extensions", "imf.discarded_x400_ipms_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1056           NULL, HFILL }},
1057     { &hf_imf_discarded_x400_mts_extensions,
1058       { "Discarded-X400-MTS-Extensions", "imf.discarded_x400_mts_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1059         NULL, HFILL }},
1060     { &hf_imf_dl_expansion_history,
1061         { "DL-Expansion-History", "imf.dl_expansion_history", FT_STRING, BASE_NONE, NULL, 0x0,
1062           NULL, HFILL }},
1063     { &hf_imf_deferred_delivery,
1064         { "Deferred-Delivery", "imf.deferred_delivery", FT_STRING, BASE_NONE, NULL, 0x0,
1065           NULL, HFILL }},
1066     { &hf_imf_expires,
1067         { "Expires", "imf.expires", FT_STRING, BASE_NONE, NULL, 0x0,
1068           NULL, HFILL }},
1069     { &hf_imf_importance,
1070       { "Importance", "imf.importance", FT_STRING, BASE_NONE, NULL, 0x0,
1071         NULL, HFILL }},
1072     { &hf_imf_incomplete_copy,
1073         { "Incomplete-Copy", "imf.incomplete_copy", FT_STRING, BASE_NONE, NULL, 0x0,
1074           NULL, HFILL }},
1075     { &hf_imf_latest_delivery_time,
1076       { "Latest-Delivery-Time", "imf.latest_delivery_time", FT_STRING, BASE_NONE, NULL, 0x0,
1077         NULL, HFILL }},
1078     { &hf_imf_message_type,
1079         { "Message-Type", "imf.message_type", FT_STRING, BASE_NONE, NULL, 0x0,
1080           NULL, HFILL }},
1081     { &hf_imf_original_encoded_information_types,
1082         { "Original-Encoded-Information-Types", "imf.original_encoded_information_types", FT_STRING, BASE_NONE, NULL, 0x0,
1083           NULL, HFILL }},
1084     { &hf_imf_originator_return_address,
1085         { "Originator-Return-Address", "imf.originator_return_address", FT_STRING, BASE_NONE, NULL, 0x0,
1086           NULL, HFILL }},
1087     { &hf_imf_priority,
1088         { "Priority", "imf.priority", FT_STRING, BASE_NONE, NULL, 0x0,
1089           NULL, HFILL }},
1090     { &hf_imf_reply_by,
1091         { "Reply-By", "imf.reply_by", FT_STRING, BASE_NONE, NULL, 0x0,
1092           NULL, HFILL }},
1093     { &hf_imf_sensitivity,
1094         { "Sensitivity", "imf.sensitivity", FT_STRING, BASE_NONE, NULL, 0x0,
1095           NULL, HFILL }},
1096     { &hf_imf_supersedes,
1097         { "Supersedes", "imf.supersedes", FT_STRING, BASE_NONE, NULL, 0x0,
1098           NULL, HFILL }},
1099     { &hf_imf_x400_content_type,
1100         { "X400-Content-Type", "imf.x400_content_type", FT_STRING, BASE_NONE, NULL, 0x0,
1101           NULL, HFILL }},
1102     { &hf_imf_x400_mts_identifier,
1103         { "X400-MTS-Identifier", "imf.x400_mts_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1104           NULL, HFILL }},
1105     { &hf_imf_x400_originator,
1106         { "X400-Originator", "imf.x400_originator", FT_STRING, BASE_NONE, NULL, 0x0,
1107         NULL, HFILL }},
1108     { &hf_imf_x400_received,
1109         { "X400-Received", "imf.x400_received", FT_STRING, BASE_NONE, NULL, 0x0,
1110         NULL, HFILL }},
1111     { &hf_imf_x400_recipients,
1112         { "X400-Recipients", "imf.x400_recipients", FT_STRING, BASE_NONE, NULL, 0x0,
1113         NULL, HFILL }},
1114     { &hf_imf_delivered_to,
1115       { "Delivered-To", "imf.delivered_to", FT_STRING,  BASE_NONE, NULL, 0x0,
1116         NULL, HFILL }},
1117     { &hf_imf_ext_mailer,
1118       { "X-Mailer", "imf.ext.mailer", FT_STRING,  BASE_NONE, NULL, 0x0,
1119         NULL, HFILL }},
1120     { &hf_imf_ext_mimeole,
1121       { "X-MimeOLE", "imf.ext.mimeole", FT_STRING,  BASE_NONE, NULL, 0x0,
1122         NULL, HFILL }},
1123     { &hf_imf_ext_expiry_date,
1124       { "Expiry-Date", "imf.ext.expiry-date", FT_STRING,  BASE_NONE, NULL, 0x0,
1125         NULL, HFILL }},
1126     { &hf_imf_ext_tnef_correlator,
1127       { "X-MS-TNEF-Correlator", "imf.ext.tnef-correlator", FT_STRING,  BASE_NONE, NULL, 0x0,
1128         NULL, HFILL }},
1129     { &hf_imf_ext_uidl,
1130       { "X-UIDL", "imf.ext.uidl", FT_STRING,  BASE_NONE, NULL, 0x0,
1131         NULL, HFILL }},
1132     { &hf_imf_ext_authentication_warning,
1133       { "X-Authentication-Warning", "imf.ext.authentication_warning", FT_STRING,  BASE_NONE,
1134         NULL, 0x0, NULL, HFILL }},
1135     { &hf_imf_ext_virus_scanned,
1136       { "X-Virus-Scanned", "imf.ext.virus_scanned", FT_STRING,  BASE_NONE, NULL, 0x0,
1137         NULL, HFILL }},
1138     { &hf_imf_thread_index,
1139       { "Thread-Index", "imf.thread-index", FT_STRING,  BASE_NONE, NULL, 0x0,
1140         NULL, HFILL }},
1141     { &hf_imf_extension,
1142       { "Unknown-Extension", "imf.extension", FT_STRING,  BASE_NONE, NULL, 0x0,
1143         NULL, HFILL }},
1144     { &hf_imf_extension_type,
1145       { "Type", "imf.extension.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1146         NULL, HFILL }},
1147     { &hf_imf_extension_value,
1148       { "Value", "imf.extension.value", FT_STRING,  BASE_NONE, NULL, 0x0,
1149         NULL, HFILL }},
1150     { &hf_imf_display_name,
1151       { "Display-Name", "imf.display_name", FT_STRING,  BASE_NONE, NULL, 0x0,
1152         NULL, HFILL }},
1153     { &hf_imf_address,
1154       { "Address", "imf.address", FT_STRING,  BASE_NONE, NULL, 0x0,
1155         NULL, HFILL }},
1156     { &hf_imf_address_list,
1157       { "Address List", "imf.address_list", FT_UINT32,  BASE_DEC, NULL, 0x0,
1158         NULL, HFILL }},
1159     { &hf_imf_address_list_item,
1160       { "Item", "imf.address_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
1161         NULL, HFILL }},
1162     { &hf_imf_mailbox_list,
1163       { "Mailbox List", "imf.mailbox_list", FT_UINT32,  BASE_DEC, NULL, 0x0,
1164         NULL, HFILL }},
1165     { &hf_imf_mailbox_list_item,
1166       { "Item", "imf.mailbox_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
1167         NULL, HFILL }},
1168     { &hf_imf_siolabel,
1169       { "SIO-Label", "imf.siolabel", FT_NONE,  BASE_NONE, NULL, 0x0,
1170         NULL, HFILL }},
1171     { &hf_imf_siolabel_marking,
1172       { "Marking", "imf.siolabel.marking", FT_STRING,  BASE_NONE, NULL, 0x0,
1173         NULL, HFILL }},
1174     { &hf_imf_siolabel_fgcolor,
1175       { "Foreground Color", "imf.siolabel.fgcolor", FT_STRING,  BASE_NONE, NULL, 0x0,
1176         NULL, HFILL }},
1177     { &hf_imf_siolabel_bgcolor,
1178       { "Background Color", "imf.siolabel.bgcolor", FT_STRING,  BASE_NONE, NULL, 0x0,
1179         NULL, HFILL }},
1180     { &hf_imf_siolabel_type,
1181       { "Type", "imf.siolabel.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1182         NULL, HFILL }},
1183     { &hf_imf_siolabel_label,
1184       { "Label", "imf.siolabel.label", FT_STRING,  BASE_NONE, NULL, 0x0,
1185         NULL, HFILL }},
1186     { &hf_imf_siolabel_unknown,
1187       { "Unknown parameter", "imf.siolabel.unknown", FT_STRING,  BASE_NONE, NULL, 0x0,
1188         NULL, HFILL }},
1189     { &hf_imf_message_text,
1190       { "Message-Text", "imf.message_text", FT_NONE,  BASE_NONE, NULL, 0x0,
1191         NULL, HFILL }},
1192   };
1193   static gint *ett[] = {
1194     &ett_imf,
1195     &ett_imf_content_type,
1196     &ett_imf_group,
1197     &ett_imf_mailbox,
1198     &ett_imf_mailbox_list,
1199     &ett_imf_address_list,
1200     &ett_imf_siolabel,
1201     &ett_imf_extension,
1202     &ett_imf_message_text,
1203   };
1204
1205   static uat_field_t attributes_flds[] = {
1206     UAT_FLD_CSTRING(header_fields, header_name, "Header name", "IMF header name"),
1207     UAT_FLD_CSTRING(header_fields, description, "Description", "Description of the value contained in the header"),
1208     UAT_FLD_VS(header_fields, header_format, "Format", header_format, 0),
1209     UAT_FLD_VS(header_fields, add_to_col_info, "Add to Info column", add_to_col_info, 0),
1210     UAT_END_FIELDS
1211   };
1212
1213   uat_t *headers_uat = uat_new("Custom IMF headers",
1214                                sizeof(header_field_t),
1215                                "imf_header_fields",
1216                                TRUE,
1217                                (void*) &header_fields,
1218                                &num_header_fields,
1219                                UAT_CAT_FIELDS,
1220                                NULL,
1221                                header_fields_copy_cb,
1222                                header_fields_update_cb,
1223                                header_fields_free_cb,
1224                                header_fields_initialize_cb,
1225                                attributes_flds);
1226
1227   module_t *imf_module;
1228   struct imf_field *f;
1229
1230   proto_imf = proto_register_protocol(PNAME, PSNAME, PFNAME);
1231
1232   proto_register_field_array(proto_imf, hf, array_length(hf));
1233   proto_register_subtree_array(ett, array_length(ett));
1234
1235   /* Allow dissector to find be found by name. */
1236   register_dissector(PFNAME, dissect_imf, proto_imf);
1237
1238   imf_module = prefs_register_protocol(proto_imf, NULL);
1239   prefs_register_uat_preference(imf_module, "custom_header_fields", "Custom IMF headers",
1240                                 "A table to define custom IMF headers for which fields can be "
1241                                 "setup and used for filtering/data extraction etc.",
1242                                 headers_uat);
1243
1244   imf_field_table=g_hash_table_new(g_str_hash, g_str_equal); /* oid to syntax */
1245
1246   /* register the fields for lookup */
1247   for(f = imf_fields; f->name; f++)
1248     g_hash_table_insert(imf_field_table, (gpointer)f->name, (gpointer)f);
1249
1250 }
1251
1252 /* The registration hand-off routine */
1253 void
1254 proto_reg_handoff_imf(void)
1255 {
1256   dissector_handle_t imf_handle;
1257
1258   imf_handle = find_dissector(PFNAME);
1259
1260   dissector_add_string("media_type",
1261                        "message/rfc822", imf_handle);
1262
1263   register_ber_oid_dissector("1.2.840.113549.1.7.1", dissect_imf, proto_imf, "id-data");
1264
1265   /*
1266    * Get the content type and Internet media type table
1267    */
1268   media_type_dissector_table = find_dissector_table("media_type");
1269
1270 }