Fix a number of proto_tree_add_item() encoding args.
[obnox/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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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
286   if (rec->header_name == NULL) {
287     *err = ep_strdup_printf("Header name can't be empty");
288   } else {
289     g_strstrip(rec->header_name);
290     if (rec->header_name[0] == 0) {
291       *err = ep_strdup_printf("Header name can't be empty");
292     } else {
293       *err = NULL;
294     }
295   }
296 }
297
298 static void *
299 header_fields_copy_cb(void *n, const void *o, size_t siz _U_)
300 {
301   header_field_t *new_rec = n;
302   const header_field_t *old_rec = o;
303
304   new_rec->header_name = g_strdup(old_rec->header_name);
305   new_rec->description = g_strdup(old_rec->description);
306   new_rec->header_format = old_rec->header_format;
307   new_rec->add_to_col_info = old_rec->add_to_col_info;
308
309   return new_rec;
310 }
311
312 static void
313 header_fields_free_cb(void *r)
314 {
315   header_field_t *rec = r;
316
317   g_free(rec->header_name);
318   g_free(rec->description);
319 }
320
321 UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t)
322 UAT_CSTRING_CB_DEF(header_fields, description, header_field_t)
323 UAT_VS_DEF(header_fields, header_format, header_field_t, 0, "Unstructured")
324 UAT_VS_DEF(header_fields, add_to_col_info, header_field_t, 0, "No")
325
326
327 /* Define media_type/Content type table */
328 static dissector_table_t media_type_dissector_table;
329
330 static void
331 dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
332 {
333   proto_tree *group_tree;
334   proto_item *group_item;
335   int addr_pos;
336
337   /* if there is a colon present it is a group */
338   if((addr_pos = tvb_find_guint8(tvb, offset, length, ':')) == -1) {
339
340     /* there isn't - so it must be a mailbox */
341     dissect_imf_mailbox(tvb, offset, length, item, pinfo);
342
343   } else {
344
345     /* it is a group */
346     group_tree = proto_item_add_subtree(item, ett_imf_group);
347
348     /* the display-name is mandatory */
349     group_item = proto_tree_add_item(group_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII|ENC_NA);
350
351     /* consume any whitespace */
352     for(addr_pos++ ;addr_pos < (offset + length); addr_pos++) {
353       if(!isspace(tvb_get_guint8(tvb, addr_pos))) {
354         break;
355       }
356     }
357
358     if(tvb_get_guint8(tvb, addr_pos) != ';') {
359
360       dissect_imf_mailbox_list(tvb, addr_pos, length - (addr_pos - offset), group_item, pinfo);
361
362       /* XXX: need to check for final ';' */
363
364     }
365
366   }
367 }
368
369 static void
370 dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo _U_)
371 {
372   proto_tree *mbox_tree;
373   int        addr_pos, end_pos;
374
375   mbox_tree = proto_item_add_subtree(item, ett_imf_mailbox);
376
377   /* Here is the plan:
378      If we can't find and angle brackets, then the whole field is an address.
379      If we find angle brackets, then the address is between them and the display name is
380      anything before the opening angle bracket
381   */
382
383   if((addr_pos = tvb_find_guint8(tvb, offset, length, '<')) == -1) {
384     /* we can't find an angle bracket - the whole field is therefore the address */
385
386     (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, offset, length, ENC_ASCII|ENC_NA);
387
388   } else {
389     /* we can find an angle bracket - let's see if we can find a display name */
390     /* XXX: the '<' could be in the display name */
391
392     for(; offset < addr_pos; offset++) {
393       if(!isspace(tvb_get_guint8(tvb, offset))) {
394         break;
395       }
396     }
397
398     if(offset != addr_pos) { /* there is a display name */
399       (void) proto_tree_add_item(mbox_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII|ENC_NA);
400     }
401     end_pos = tvb_find_guint8(tvb, addr_pos + 1, length - (addr_pos + 1 - offset), '>');
402
403     if(end_pos != -1) {
404       (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, addr_pos + 1, end_pos - addr_pos - 1, ENC_ASCII|ENC_NA);
405     }
406   }
407 }
408
409 static void
410 dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
411 {
412   proto_item *addr_item = NULL;
413   proto_tree *tree = NULL;
414   int         count = 0;
415   int         item_offset;
416   int         end_offset;
417   int         item_length;
418
419   /* a comma separated list of addresses */
420   tree = proto_item_add_subtree(item, ett_imf_address_list);
421
422   item_offset = offset;
423
424   do {
425
426     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
427
428     count++; /* increase the number of items */
429
430     if(end_offset == -1) {
431       /* length is to the end of the buffer */
432       item_length = length - (item_offset - offset);
433     } else {
434       item_length = end_offset - item_offset;
435     }
436     addr_item = proto_tree_add_item(tree, hf_imf_address_list_item, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
437     dissect_imf_address(tvb, item_offset, item_length, addr_item, pinfo);
438
439     if(end_offset != -1) {
440       item_offset = end_offset + 1;
441     }
442   } while(end_offset != -1);
443
444   /* now indicate the number of items found */
445   proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
446 }
447
448 static void
449 dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
450 {
451   proto_item *mbox_item = NULL;
452   proto_tree *tree = NULL;
453   int         count = 0;
454   int         item_offset;
455   int         end_offset;
456   int         item_length;
457
458   /* a comma separated list of mailboxes */
459   tree = proto_item_add_subtree(item, ett_imf_mailbox_list);
460
461   item_offset = offset;
462
463   do {
464
465     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
466
467     count++; /* increase the number of items */
468
469     if(end_offset == -1) {
470       /* length is to the end of the buffer */
471       item_length = length - (item_offset - offset);
472     } else {
473       item_length = end_offset - item_offset;
474     }
475     mbox_item = proto_tree_add_item(tree, hf_imf_mailbox_list_item, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
476     dissect_imf_mailbox(tvb, item_offset, item_length, mbox_item, pinfo);
477
478     if(end_offset != -1) {
479       item_offset = end_offset + 1;
480     }
481   } while(end_offset != -1);
482
483   /* now indicate the number of items found */
484   proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
485 }
486
487 static void
488 dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo)
489 {
490   proto_tree *tree = NULL;
491   proto_item *sub_item = NULL;
492   int         item_offset, item_length;
493   int         value_offset, value_length;
494   int         end_offset;
495   tvbuff_t   *label_tvb;
496   gchar      *type = NULL;
497   GString    *label_string = g_string_new ("");
498
499   /* a semicolon separated list of attributes */
500   tree = proto_item_add_subtree(item, ett_imf_siolabel);
501   item_offset = offset;
502
503   do {
504     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ';');
505
506     /* skip leading space */
507     while (isspace(tvb_get_guint8(tvb, item_offset))) {
508       item_offset++;
509     }
510
511     if (end_offset == -1) {
512       /* length is to the end of the buffer */
513       item_length = tvb_find_line_end(tvb, item_offset, length - (item_offset - offset), NULL, FALSE);
514     } else {
515       item_length = end_offset - item_offset;
516     }
517
518     value_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), '=') + 1;
519     while (isspace(tvb_get_guint8(tvb, value_offset))) {
520       value_offset++;
521     }
522
523     value_length = item_length - (value_offset - item_offset);
524     while (isspace(tvb_get_guint8(tvb, value_offset + value_length - 1))) {
525       value_length--;
526     }
527
528     if (tvb_strneql(tvb, item_offset, "marking", 7) == 0) {
529       proto_item_append_text(item, ": %s", tvb_get_ephemeral_string(tvb, value_offset, value_length));
530       proto_tree_add_item(tree, hf_imf_siolabel_marking, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
531
532     } else if (tvb_strneql(tvb, item_offset, "fgcolor", 7) == 0) {
533       proto_tree_add_item(tree, hf_imf_siolabel_fgcolor, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
534
535     } else if (tvb_strneql(tvb, item_offset, "bgcolor", 7) == 0) {
536       proto_tree_add_item(tree, hf_imf_siolabel_bgcolor, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
537
538     } else if (tvb_strneql(tvb, item_offset, "type", 4) == 0) {
539       type = tvb_get_ephemeral_string(tvb, value_offset + 1, value_length - 2); /* quoted */
540       proto_tree_add_item(tree, hf_imf_siolabel_type, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
541
542     } else if (tvb_strneql(tvb, item_offset, "label", 5) == 0) {
543       gchar *label = tvb_get_ephemeral_string(tvb, value_offset + 1, value_length - 2); /* quoted */
544       label_string = g_string_append(label_string, label);
545
546       if (tvb_get_guint8(tvb, item_offset + 5) == '*') { /* continuations */
547         int num = strtol(tvb_get_ephemeral_string(tvb, item_offset + 6, value_offset - item_offset + 6), NULL, 10);
548         proto_tree_add_string_format(tree, hf_imf_siolabel_label, tvb, value_offset, value_length,
549                                      label, "Label[%d]: \"%s\"", num, label);
550       } else {
551         proto_tree_add_item(tree, hf_imf_siolabel_label, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
552       }
553
554     } else {
555       sub_item = proto_tree_add_item(tree, hf_imf_siolabel_unknown, tvb, item_offset, item_length, ENC_ASCII|ENC_NA);
556       expert_add_info_format(pinfo, sub_item, PI_PROTOCOL, PI_WARN, "Unknown parameter");
557     }
558
559     if (end_offset != -1) {
560       item_offset = end_offset + 1;
561     }
562   } while (end_offset != -1);
563
564   if (type && label_string->len > 0) {
565     if (strcmp (type, ":ess") == 0) {
566       label_tvb = base64_to_tvb(tvb, label_string->str);
567       add_new_data_source(pinfo, label_tvb, "ESS Security Label");
568       dissect_ess_ESSSecurityLabel_PDU(label_tvb, pinfo, tree);
569     } else if (strcmp (type, ":x411") == 0) {
570       label_tvb = base64_to_tvb(tvb, label_string->str);
571       add_new_data_source(pinfo, label_tvb, "X.411 Security Label");
572       dissect_p1_MessageSecurityLabel_PDU(label_tvb, pinfo, tree);
573     }
574   }
575
576   g_string_free (label_string, TRUE);
577 }
578
579 static void
580 dissect_imf_content_type(tvbuff_t *tvb, int offset, int length, proto_item *item,
581                          char **type, char **parameters)
582 {
583   int first_colon;
584   int len;
585   int i;
586   proto_tree *ct_tree;
587
588   /* first strip any whitespace */
589   for(i = 0; i < length; i++) {
590     if(!isspace(tvb_get_guint8(tvb, offset + i))) {
591       offset += i;
592       break;
593     }
594   }
595
596   /* find the first colon - there has to be a colon as there will have to be a boundary */
597   first_colon = tvb_find_guint8(tvb, offset, length, ';');
598
599   if(first_colon != -1) {
600     ct_tree = proto_item_add_subtree(item, ett_imf_content_type);
601
602     len = first_colon - offset;
603     proto_tree_add_item(ct_tree, hf_imf_content_type_type, tvb, offset, len, ENC_ASCII|ENC_NA);
604     if(type) {
605       /* This string will be automatically freed */
606       (*type) = tvb_get_ephemeral_string(tvb, offset, len);
607     }
608     len = tvb_find_line_end(tvb, first_colon + 1, length, NULL, FALSE);
609     proto_tree_add_item(ct_tree, hf_imf_content_type_parameters, tvb, first_colon + 1, len, ENC_ASCII|ENC_NA);
610     if(parameters) {
611       /* This string will be automatically freed */
612       (*parameters) = tvb_get_ephemeral_string(tvb, first_colon + 1, len);
613     }
614   }
615 }
616
617
618 int
619 imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_field)
620 {
621
622   while(offset < max_length) {
623
624     /* look for CR */
625     offset = tvb_find_guint8(tvb, offset, max_length - offset, '\r');
626
627     if(offset != -1) {
628       if(tvb_get_guint8(tvb, ++offset) == '\n') {
629         /* OK - so we have found CRLF */
630         /* peek the next character */
631         switch(tvb_get_guint8(tvb, ++offset)) {
632         case '\r':
633           /* probably end of the fields */
634           if(tvb_get_guint8(tvb, ++offset) == '\n') {
635             offset++;
636           }
637           if(last_field) {
638             *last_field = TRUE;
639           }
640           return offset;
641         case  ' ':
642         case '\t':
643           /* continuation line */
644           break;
645         default:
646           /* this is a new field */
647           return offset;
648         }
649       }
650     } else {
651       /* couldn't find a CR - strange */
652       return offset;
653     }
654
655   }
656
657   return -1;  /* Fail: No CR found (other than possible continuation) */
658
659 }
660
661 static void
662 dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
663 {
664   proto_item  *item;
665   proto_tree  *unknown_tree, *text_tree;
666   char  *content_type_str = NULL;
667   char  *parameters = NULL;
668   int   hf_id;
669   gint  start_offset = 0;
670   gint  value_offset = 0;
671   gint  unknown_offset = 0;
672   gint  end_offset = 0;
673   gint   max_length;
674   guint8 *key;
675   gboolean last_field = FALSE;
676   tvbuff_t *next_tvb;
677   struct imf_field *f_info;
678
679   col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
680   col_clear(pinfo->cinfo, COL_INFO);
681
682   if(tree){
683     item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, ENC_NA);
684     tree = proto_item_add_subtree(item, ett_imf);
685   }
686
687   max_length = tvb_length(tvb);
688   /* first go through the tvb until we find a blank line and extract the content type if
689      we find one */
690
691   /* XXX: What if the tvb contains encrypted data ? is there a way to bypass dissection if so ?  */
692   /*      As it is, the following code blithely tries to parse what may be binary data.          */
693
694   while(!last_field) {
695
696     /* look for a colon first */
697     end_offset = tvb_find_guint8(tvb, start_offset, max_length - start_offset, ':');
698
699     if(end_offset == -1) {
700       /* we couldn't find another colon - strange - we should have broken out of here by now */
701       /* XXX: flag an error */
702       break;
703     } else {
704       key = tvb_get_ephemeral_string(tvb, start_offset, end_offset - start_offset);
705
706       /* convert to lower case */
707       ascii_strdown_inplace (key);
708
709       /* look up the key in built-in fields */
710       f_info = (struct imf_field *)g_hash_table_lookup(imf_field_table, key);
711
712       if(f_info == NULL && custom_field_table) {
713         /* look up the key in custom fields */
714         f_info = (struct imf_field *)g_hash_table_lookup(custom_field_table, key);
715       }
716
717       if(f_info == NULL) {
718         /* set as an unknown extension */
719         f_info = imf_fields;
720         unknown_offset = start_offset;
721       }
722
723       hf_id = *(f_info->hf_id);
724
725       /* value starts immediately after the colon */
726       start_offset = end_offset+1;
727
728       end_offset = imf_find_field_end(tvb, start_offset, max_length, &last_field);
729       if(end_offset == -1) {
730         break;   /* Something's fishy */
731       }
732
733       /* remove any leading whitespace */
734
735       for(value_offset = start_offset; value_offset < end_offset; value_offset++)
736         if(!isspace(tvb_get_guint8(tvb, value_offset))) {
737           break;
738         }
739
740       if(value_offset == end_offset) {
741         /* empty field - show whole value */
742         value_offset = start_offset;
743       }
744
745       if(hf_id == hf_imf_extension_type) {
746
747         /* remove 2 bytes to take off the final CRLF to make things a little prettier */
748         item = proto_tree_add_item(tree, hf_imf_extension, tvb, unknown_offset, end_offset - unknown_offset - 2, ENC_ASCII|ENC_NA);
749
750         proto_item_append_text(item, " (Contact Wireshark developers if you want this supported.)");
751
752         unknown_tree = proto_item_add_subtree(item, ett_imf_extension);
753
754         proto_tree_add_item(unknown_tree, hf_imf_extension_type, tvb, unknown_offset, start_offset - 1 - unknown_offset, ENC_ASCII|ENC_NA);
755
756         /* remove 2 bytes to take off the final CRLF to make things a little prettier */
757         item = proto_tree_add_item(unknown_tree, hf_imf_extension_value, tvb, start_offset, end_offset - start_offset - 2, ENC_ASCII|ENC_NA);
758
759       } else {
760         /* remove 2 bytes to take off the final CRLF to make things a little prettier */
761         item = proto_tree_add_item(tree, hf_id, tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
762       }
763       if(f_info->add_to_col_info && check_col(pinfo->cinfo, COL_INFO)) {
764
765         col_append_fstr(pinfo->cinfo, COL_INFO, "%s: %s, ", f_info->name,
766                         tvb_format_text(tvb, value_offset, end_offset - value_offset - 2));
767       }
768
769       if(hf_id == hf_imf_content_type) {
770         /* we need some additional processing to extract the content type and parameters */
771
772         dissect_imf_content_type(tvb, start_offset, end_offset - start_offset, item,
773                                  &content_type_str, &parameters);
774
775       } else if(f_info->subdissector) {
776
777         /* we have a subdissector */
778         f_info->subdissector(tvb, value_offset, end_offset - value_offset, item, pinfo);
779
780       }
781     }
782     start_offset = end_offset;
783   }
784
785   if (end_offset == -1) {
786     end_offset = 0;
787   }
788
789   /* specify a content type until we can work it out for ourselves */
790   /* content_type_str = "multipart/mixed"; */
791
792   /* now dissect the MIME based upon the content type */
793
794   if(content_type_str && media_type_dissector_table) {
795     void* pd_save;
796     pd_save = pinfo->private_data;
797     pinfo->private_data = parameters;
798
799     next_tvb = tvb_new_subset_remaining(tvb, end_offset);
800
801     dissector_try_string(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree);
802
803     pinfo->private_data = pd_save;
804   } else {
805
806     /* just show the lines or highlight the rest of the buffer as message text */
807
808     item = proto_tree_add_item(tree, hf_imf_message_text, tvb, end_offset, -1 , ENC_NA);
809     text_tree = proto_item_add_subtree(item, ett_imf_message_text);
810
811     start_offset = end_offset;
812     while (tvb_offset_exists(tvb, start_offset)) {
813
814       /*
815        * Find the end of the line.
816        */
817       tvb_find_line_end(tvb, start_offset, -1, &end_offset, FALSE);
818
819       /*
820        * Put this line.
821        */
822       proto_tree_add_text(text_tree, tvb, start_offset, end_offset - start_offset,
823                           "%s",
824                           tvb_format_text_wsp(tvb, start_offset, end_offset - start_offset));
825       col_append_sep_str(pinfo->cinfo, COL_INFO, ", ",
826                          tvb_format_text_wsp(tvb, start_offset, end_offset - start_offset));
827
828       /*
829        * Step to the next line.
830        */
831       start_offset = end_offset;
832     }
833   }
834 }
835
836 static void
837 free_imf_field (gpointer data)
838 {
839   struct imf_field *imffield = (struct imf_field *) data;
840
841   g_free ((char *) imffield->name);
842   g_free (imffield);
843 }
844
845 static void
846 header_fields_initialize_cb (void)
847 {
848   static hf_register_info *hf;
849   gint *hf_id;
850   struct imf_field *imffield;
851   guint i;
852   gchar *header_name;
853
854   if (custom_field_table) {
855     guint hf_size = g_hash_table_size (custom_field_table);
856     /* Unregister all fields */
857     for (i = 0; i < hf_size; i++) {
858       proto_unregister_field (proto_imf, *(hf[i].p_id));
859
860       g_free (hf[i].p_id);
861       g_free ((char *) hf[i].hfinfo.name);
862       g_free ((char *) hf[i].hfinfo.abbrev);
863       g_free ((char *) hf[i].hfinfo.blurb);
864     }
865     g_hash_table_destroy (custom_field_table);
866     g_free (hf);
867     custom_field_table = NULL;
868   }
869
870   if (num_header_fields) {
871     custom_field_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_imf_field);
872     hf = g_malloc0 (sizeof (hf_register_info) * num_header_fields);
873
874     for (i = 0; i < num_header_fields; i++) {
875       hf_id = g_malloc (sizeof (gint));
876       *hf_id = -1;
877       header_name = g_strdup (header_fields[i].header_name);
878
879       hf[i].p_id = hf_id;
880       hf[i].hfinfo.name = header_name;
881       hf[i].hfinfo.abbrev = g_strdup_printf ("imf.header.%s", header_name);
882       hf[i].hfinfo.type = FT_STRING;
883       hf[i].hfinfo.display = BASE_NONE;
884       hf[i].hfinfo.strings = NULL;
885       hf[i].hfinfo.blurb = g_strdup (header_fields[i].description);
886       hf[i].hfinfo.same_name_prev = NULL;
887       hf[i].hfinfo.same_name_next = NULL;
888
889       imffield = g_malloc (sizeof (struct imf_field));
890       imffield->hf_id = hf_id;
891       imffield->name = ascii_strdown_inplace (g_strdup (header_name));
892       switch (header_fields[i].header_format) {
893       case FORMAT_UNSTRUCTURED:
894         imffield->subdissector = NO_SUBDISSECTION;
895         break;
896       case FORMAT_MAILBOX:
897         imffield->subdissector = dissect_imf_mailbox;
898         break;
899       case FORMAT_ADDRESS:
900         imffield->subdissector = dissect_imf_address;
901         break;
902       case FORMAT_MAILBOX_LIST:
903         imffield->subdissector = dissect_imf_mailbox_list;
904         break;
905       case FORMAT_ADDRESS_LIST:
906         imffield->subdissector = dissect_imf_address_list;
907         break;
908       case FORMAT_SIO_LABEL:
909         hf[i].hfinfo.type = FT_NONE; /* constructed */
910         imffield->subdissector = dissect_imf_siolabel;
911         break;
912       default:
913         /* unknown */
914         imffield->subdissector = NO_SUBDISSECTION;
915         break;
916       }
917       imffield->add_to_col_info = header_fields[i].add_to_col_info;
918       g_hash_table_insert (custom_field_table, (gpointer)imffield->name, (gpointer)imffield);
919     }
920
921     proto_register_field_array (proto_imf, hf, num_header_fields);
922   }
923 }
924
925 /* Register all the bits needed by the filtering engine */
926
927 void
928 proto_register_imf(void)
929 {
930   static hf_register_info hf[] = {
931     { &hf_imf_date,
932       { "Date", "imf.date", FT_STRING,  BASE_NONE, NULL, 0x0,
933         "DateTime", HFILL }},
934     { &hf_imf_from,
935       { "From", "imf.from", FT_STRING,  BASE_NONE, NULL, 0x0,
936         "MailboxList", HFILL }},
937     { &hf_imf_sender,
938       { "Sender", "imf.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
939         NULL, HFILL }},
940     { &hf_imf_reply_to,
941       { "Reply-To", "imf.reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
942         NULL, HFILL }},
943     { &hf_imf_to,
944       { "To", "imf.to", FT_STRING,  BASE_NONE, NULL, 0x0,
945         NULL, HFILL }},
946     { &hf_imf_cc,
947       { "Cc", "imf.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
948         NULL, HFILL }},
949     { &hf_imf_bcc,
950       { "Bcc", "imf.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
951         NULL, HFILL }},
952     { &hf_imf_message_id,
953       { "Message-ID", "imf.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
954         NULL, HFILL }},
955     { &hf_imf_in_reply_to,
956       { "In-Reply-To", "imf.in_reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
957         NULL, HFILL }},
958     { &hf_imf_references,
959       { "References", "imf.references", FT_STRING,  BASE_NONE, NULL, 0x0,
960         NULL, HFILL }},
961     { &hf_imf_subject,
962       { "Subject", "imf.subject", FT_STRING,  BASE_NONE, NULL, 0x0,
963         NULL, HFILL }},
964     { &hf_imf_comments,
965       { "Comments", "imf.comments", FT_STRING,  BASE_NONE, NULL, 0x0,
966         NULL, HFILL }},
967     { &hf_imf_user_agent,
968       { "User-Agent", "imf.user_agent", FT_STRING,  BASE_NONE, NULL, 0x0,
969         NULL, HFILL }},
970     { &hf_imf_keywords,
971       { "Keywords", "imf.keywords", FT_STRING,  BASE_NONE, NULL, 0x0,
972         NULL, HFILL }},
973     { &hf_imf_resent_date,
974       { "Resent-Date", "imf.resent.date", FT_STRING,  BASE_NONE, NULL, 0x0,
975         NULL, HFILL }},
976     { &hf_imf_resent_from,
977       { "Resent-From", "imf.resent.from", FT_STRING,  BASE_NONE, NULL, 0x0,
978         NULL, HFILL }},
979     { &hf_imf_resent_sender,
980       { "Resent-Sender", "imf.resent.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
981         NULL, HFILL }},
982     { &hf_imf_resent_to,
983       { "Resent-To", "imf.resent.to", FT_STRING,  BASE_NONE, NULL, 0x0,
984         NULL, HFILL }},
985     { &hf_imf_resent_cc,
986       { "Resent-Cc", "imf.resent.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
987         NULL, HFILL }},
988     { &hf_imf_resent_bcc,
989       { "Resent-Bcc", "imf.resent.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
990         NULL, HFILL }},
991     { &hf_imf_resent_message_id,
992       { "Resent-Message-ID", "imf.resent.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
993         NULL, HFILL }},
994     { &hf_imf_return_path,
995       { "Return-Path", "imf.return_path", FT_STRING,  BASE_NONE, NULL, 0x0,
996         NULL, HFILL }},
997     { &hf_imf_received,
998       { "Received", "imf.received", FT_STRING,  BASE_NONE, NULL, 0x0,
999         NULL, HFILL }},
1000     { &hf_imf_content_type,
1001       { "Content-Type", "imf.content.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1002         NULL, HFILL }},
1003     { &hf_imf_content_type_type,
1004       { "Type", "imf.content.type.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1005         NULL, HFILL }},
1006     { &hf_imf_content_type_parameters,
1007       { "Parameters", "imf.content.type.parameters", FT_STRING,  BASE_NONE, NULL, 0x0,
1008         NULL, HFILL }},
1009     { &hf_imf_content_description,
1010       { "Content-Description", "imf.content.description", FT_STRING,  BASE_NONE, NULL, 0x0,
1011         NULL, HFILL }},
1012     { &hf_imf_content_id,
1013       { "Content-ID", "imf.content.id", FT_STRING,  BASE_NONE, NULL, 0x0,
1014         NULL, HFILL }},
1015     { &hf_imf_content_transfer_encoding,
1016       { "Content-Transfer-Encoding", "imf.content.transfer_encoding", FT_STRING,  BASE_NONE, NULL, 0x0,
1017         NULL, HFILL }},
1018     { &hf_imf_mime_version,
1019       { "MIME-Version", "imf.mime_version", FT_STRING,  BASE_NONE, NULL, 0x0,
1020         NULL, HFILL }},
1021     { &hf_imf_autoforwarded,
1022       { "Autoforwarded", "imf.autoforwarded", FT_STRING, BASE_NONE, NULL, 0x0,
1023         NULL, HFILL }},
1024     { &hf_imf_autosubmitted,
1025       { "Autosubmitted", "imf.autosubmitted", FT_STRING, BASE_NONE, NULL, 0x0,
1026         NULL, HFILL }},
1027     { &hf_imf_x400_content_identifier,
1028       { "X400-Content-Identifier", "imf.x400_content_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1029         NULL, HFILL }},
1030     { &hf_imf_content_language,
1031       { "Content-Language", "imf.content_language", FT_STRING, BASE_NONE, NULL, 0x0,
1032         NULL, HFILL }},
1033     { &hf_imf_conversion,
1034         { "Conversion", "imf.conversion", FT_STRING, BASE_NONE, NULL, 0x0,
1035           NULL, HFILL }},
1036     { &hf_imf_conversion_with_loss,
1037         { "Conversion-With-Loss", "imf.conversion_with_loss", FT_STRING, BASE_NONE, NULL, 0x0,
1038           NULL, HFILL }},
1039     { &hf_imf_delivery_date,
1040         { "Delivery-Date", "imf.delivery_date", FT_STRING, BASE_NONE, NULL, 0x0,
1041           NULL, HFILL }},
1042     { &hf_imf_discarded_x400_ipms_extensions,
1043         { "Discarded-X400-IPMS-Extensions", "imf.discarded_x400_ipms_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1044           NULL, HFILL }},
1045     { &hf_imf_discarded_x400_mts_extensions,
1046       { "Discarded-X400-MTS-Extensions", "imf.discarded_x400_mts_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
1047         NULL, HFILL }},
1048     { &hf_imf_dl_expansion_history,
1049         { "DL-Expansion-History", "imf.dl_expansion_history", FT_STRING, BASE_NONE, NULL, 0x0,
1050           NULL, HFILL }},
1051     { &hf_imf_deferred_delivery,
1052         { "Deferred-Delivery", "imf.deferred_delivery", FT_STRING, BASE_NONE, NULL, 0x0,
1053           NULL, HFILL }},
1054     { &hf_imf_expires,
1055         { "Expires", "imf.expires", FT_STRING, BASE_NONE, NULL, 0x0,
1056           NULL, HFILL }},
1057     { &hf_imf_importance,
1058       { "Importance", "imf.importance", FT_STRING, BASE_NONE, NULL, 0x0,
1059         NULL, HFILL }},
1060     { &hf_imf_incomplete_copy,
1061         { "Incomplete-Copy", "imf.incomplete_copy", FT_STRING, BASE_NONE, NULL, 0x0,
1062           NULL, HFILL }},
1063     { &hf_imf_latest_delivery_time,
1064       { "Latest-Delivery-Time", "imf.latest_delivery_time", FT_STRING, BASE_NONE, NULL, 0x0,
1065         NULL, HFILL }},
1066     { &hf_imf_message_type,
1067         { "Message-Type", "imf.message_type", FT_STRING, BASE_NONE, NULL, 0x0,
1068           NULL, HFILL }},
1069     { &hf_imf_original_encoded_information_types,
1070         { "Original-Encoded-Information-Types", "imf.original_encoded_information_types", FT_STRING, BASE_NONE, NULL, 0x0,
1071           NULL, HFILL }},
1072     { &hf_imf_originator_return_address,
1073         { "Originator-Return-Address", "imf.originator_return_address", FT_STRING, BASE_NONE, NULL, 0x0,
1074           NULL, HFILL }},
1075     { &hf_imf_priority,
1076         { "Priority", "imf.priority", FT_STRING, BASE_NONE, NULL, 0x0,
1077           NULL, HFILL }},
1078     { &hf_imf_reply_by,
1079         { "Reply-By", "imf.reply_by", FT_STRING, BASE_NONE, NULL, 0x0,
1080           NULL, HFILL }},
1081     { &hf_imf_sensitivity,
1082         { "Sensitivity", "imf.sensitivity", FT_STRING, BASE_NONE, NULL, 0x0,
1083           NULL, HFILL }},
1084     { &hf_imf_supersedes,
1085         { "Supersedes", "imf.supersedes", FT_STRING, BASE_NONE, NULL, 0x0,
1086           NULL, HFILL }},
1087     { &hf_imf_x400_content_type,
1088         { "X400-Content-Type", "imf.x400_content_type", FT_STRING, BASE_NONE, NULL, 0x0,
1089           NULL, HFILL }},
1090     { &hf_imf_x400_mts_identifier,
1091         { "X400-MTS-Identifier", "imf.x400_mts_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
1092           NULL, HFILL }},
1093     { &hf_imf_x400_originator,
1094         { "X400-Originator", "imf.x400_originator", FT_STRING, BASE_NONE, NULL, 0x0,
1095         NULL, HFILL }},
1096     { &hf_imf_x400_received,
1097         { "X400-Received", "imf.x400_received", FT_STRING, BASE_NONE, NULL, 0x0,
1098         NULL, HFILL }},
1099     { &hf_imf_x400_recipients,
1100         { "X400-Recipients", "imf.x400_recipients", FT_STRING, BASE_NONE, NULL, 0x0,
1101         NULL, HFILL }},
1102     { &hf_imf_delivered_to,
1103       { "Delivered-To", "imf.delivered_to", FT_STRING,  BASE_NONE, NULL, 0x0,
1104         NULL, HFILL }},
1105     { &hf_imf_ext_mailer,
1106       { "X-Mailer", "imf.ext.mailer", FT_STRING,  BASE_NONE, NULL, 0x0,
1107         NULL, HFILL }},
1108     { &hf_imf_ext_mimeole,
1109       { "X-MimeOLE", "imf.ext.mimeole", FT_STRING,  BASE_NONE, NULL, 0x0,
1110         NULL, HFILL }},
1111     { &hf_imf_ext_expiry_date,
1112       { "Expiry-Date", "imf.ext.expiry-date", FT_STRING,  BASE_NONE, NULL, 0x0,
1113         NULL, HFILL }},
1114     { &hf_imf_ext_tnef_correlator,
1115       { "X-MS-TNEF-Correlator", "imf.ext.tnef-correlator", FT_STRING,  BASE_NONE, NULL, 0x0,
1116         NULL, HFILL }},
1117     { &hf_imf_ext_uidl,
1118       { "X-UIDL", "imf.ext.uidl", FT_STRING,  BASE_NONE, NULL, 0x0,
1119         NULL, HFILL }},
1120     { &hf_imf_ext_authentication_warning,
1121       { "X-Authentication-Warning", "imf.ext.authentication_warning", FT_STRING,  BASE_NONE,
1122         NULL, 0x0, NULL, HFILL }},
1123     { &hf_imf_ext_virus_scanned,
1124       { "X-Virus-Scanned", "imf.ext.virus_scanned", FT_STRING,  BASE_NONE, NULL, 0x0,
1125         NULL, HFILL }},
1126     { &hf_imf_thread_index,
1127       { "Thread-Index", "imf.thread-index", FT_STRING,  BASE_NONE, NULL, 0x0,
1128         NULL, HFILL }},
1129     { &hf_imf_extension,
1130       { "Unknown-Extension", "imf.extension", FT_STRING,  BASE_NONE, NULL, 0x0,
1131         NULL, HFILL }},
1132     { &hf_imf_extension_type,
1133       { "Type", "imf.extension.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1134         NULL, HFILL }},
1135     { &hf_imf_extension_value,
1136       { "Value", "imf.extension.value", FT_STRING,  BASE_NONE, NULL, 0x0,
1137         NULL, HFILL }},
1138     { &hf_imf_display_name,
1139       { "Display-Name", "imf.display_name", FT_STRING,  BASE_NONE, NULL, 0x0,
1140         NULL, HFILL }},
1141     { &hf_imf_address,
1142       { "Address", "imf.address", FT_STRING,  BASE_NONE, NULL, 0x0,
1143         NULL, HFILL }},
1144     { &hf_imf_address_list,
1145       { "Address List", "imf.address_list", FT_UINT32,  BASE_DEC, NULL, 0x0,
1146         NULL, HFILL }},
1147     { &hf_imf_address_list_item,
1148       { "Item", "imf.address_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
1149         NULL, HFILL }},
1150     { &hf_imf_mailbox_list,
1151       { "Mailbox List", "imf.mailbox_list", FT_UINT32,  BASE_DEC, NULL, 0x0,
1152         NULL, HFILL }},
1153     { &hf_imf_mailbox_list_item,
1154       { "Item", "imf.mailbox_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
1155         NULL, HFILL }},
1156     { &hf_imf_siolabel,
1157       { "SIO-Label", "imf.siolabel", FT_NONE,  BASE_NONE, NULL, 0x0,
1158         NULL, HFILL }},
1159     { &hf_imf_siolabel_marking,
1160       { "Marking", "imf.siolabel.marking", FT_STRING,  BASE_NONE, NULL, 0x0,
1161         NULL, HFILL }},
1162     { &hf_imf_siolabel_fgcolor,
1163       { "Foreground Color", "imf.siolabel.fgcolor", FT_STRING,  BASE_NONE, NULL, 0x0,
1164         NULL, HFILL }},
1165     { &hf_imf_siolabel_bgcolor,
1166       { "Background Color", "imf.siolabel.bgcolor", FT_STRING,  BASE_NONE, NULL, 0x0,
1167         NULL, HFILL }},
1168     { &hf_imf_siolabel_type,
1169       { "Type", "imf.siolabel.type", FT_STRING,  BASE_NONE, NULL, 0x0,
1170         NULL, HFILL }},
1171     { &hf_imf_siolabel_label,
1172       { "Label", "imf.siolabel.label", FT_STRING,  BASE_NONE, NULL, 0x0,
1173         NULL, HFILL }},
1174     { &hf_imf_siolabel_unknown,
1175       { "Unknown parameter", "imf.siolabel.unknown", FT_STRING,  BASE_NONE, NULL, 0x0,
1176         NULL, HFILL }},
1177     { &hf_imf_message_text,
1178       { "Message-Text", "imf.message_text", FT_NONE,  BASE_NONE, NULL, 0x0,
1179         NULL, HFILL }},
1180   };
1181   static gint *ett[] = {
1182     &ett_imf,
1183     &ett_imf_content_type,
1184     &ett_imf_group,
1185     &ett_imf_mailbox,
1186     &ett_imf_mailbox_list,
1187     &ett_imf_address_list,
1188     &ett_imf_siolabel,
1189     &ett_imf_extension,
1190     &ett_imf_message_text,
1191   };
1192
1193   static uat_field_t attributes_flds[] = {
1194     UAT_FLD_CSTRING(header_fields, header_name, "Header name", "IMF header name"),
1195     UAT_FLD_CSTRING(header_fields, description, "Description", "Description of the value contained in the header"),
1196     UAT_FLD_VS(header_fields, header_format, "Format", header_format, 0),
1197     UAT_FLD_VS(header_fields, add_to_col_info, "Add to Info column", add_to_col_info, 0),
1198     UAT_END_FIELDS
1199   };
1200
1201   uat_t *headers_uat = uat_new("Custom IMF headers",
1202                                sizeof(header_field_t),
1203                                "imf_header_fields",
1204                                TRUE,
1205                                (void*) &header_fields,
1206                                &num_header_fields,
1207                                UAT_CAT_GENERAL,
1208                                NULL,
1209                                header_fields_copy_cb,
1210                                header_fields_update_cb,
1211                                header_fields_free_cb,
1212                                header_fields_initialize_cb,
1213                                attributes_flds);
1214
1215   module_t *imf_module;
1216   struct imf_field *f;
1217
1218   proto_imf = proto_register_protocol(PNAME, PSNAME, PFNAME);
1219
1220   proto_register_field_array(proto_imf, hf, array_length(hf));
1221   proto_register_subtree_array(ett, array_length(ett));
1222
1223   /* Allow dissector to find be found by name. */
1224   register_dissector(PFNAME, dissect_imf, proto_imf);
1225
1226   imf_module = prefs_register_protocol(proto_imf, NULL);
1227   prefs_register_uat_preference(imf_module, "custom_header_fields", "Custom IMF headers",
1228                                 "A table to define custom IMF headers for which fields can be "
1229                                 "setup and used for filtering/data extraction etc.",
1230                                 headers_uat);
1231
1232   imf_field_table=g_hash_table_new(g_str_hash, g_str_equal); /* oid to syntax */
1233
1234   /* register the fields for lookup */
1235   for(f = imf_fields; f->name; f++)
1236     g_hash_table_insert(imf_field_table, (gpointer)f->name, (gpointer)f);
1237
1238 }
1239
1240 /* The registration hand-off routine */
1241 void
1242 proto_reg_handoff_imf(void)
1243 {
1244   dissector_handle_t imf_handle;
1245
1246   imf_handle = find_dissector(PFNAME);
1247
1248   dissector_add_string("media_type",
1249                        "message/rfc822", imf_handle);
1250
1251   register_ber_oid_dissector("1.2.840.113549.1.7.1", dissect_imf, proto_imf, "id-data");
1252
1253   /*
1254    * Get the content type and Internet media type table
1255    */
1256   media_type_dissector_table = find_dissector_table("media_type");
1257
1258 }