Switch a bunch of dissectors over to using tvb_new_subset_remaining()
[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 <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <glib.h>
36 #include <string.h>
37 #include <epan/packet.h>
38 #include <epan/addr_resolv.h>
39 #include <epan/strutil.h>
40
41
42 #include "packet-ber.h"
43 #include "packet-imf.h"
44
45 #define PNAME  "Internet Message Format"
46 #define PSNAME "IMF"
47 #define PFNAME "imf"
48
49 static int proto_imf = -1;
50
51 static int hf_imf_date = -1;
52 static int hf_imf_from = -1;
53 static int hf_imf_sender = -1;
54 static int hf_imf_reply_to = -1;
55 static int hf_imf_to = -1;
56 static int hf_imf_cc = -1;
57 static int hf_imf_bcc = -1;
58 static int hf_imf_message_id = -1;
59 static int hf_imf_in_reply_to = -1;
60 static int hf_imf_references = -1;
61 static int hf_imf_subject = -1;
62 static int hf_imf_comments = -1;
63 static int hf_imf_keywords = -1;
64 static int hf_imf_resent_date = -1;
65 static int hf_imf_resent_from = -1;
66 static int hf_imf_resent_sender = -1;
67 static int hf_imf_resent_to = -1;
68 static int hf_imf_resent_cc = -1;
69 static int hf_imf_resent_bcc = -1;
70 static int hf_imf_resent_message_id = -1;
71 static int hf_imf_return_path = -1;
72 static int hf_imf_received = -1;
73 static int hf_imf_content_type = -1;
74 static int hf_imf_content_type_type = -1;
75 static int hf_imf_content_type_parameters = -1;
76 static int hf_imf_content_id = -1;
77 static int hf_imf_content_transfer_encoding = -1;
78 static int hf_imf_content_description = -1;
79 static int hf_imf_mime_version = -1;
80 static int hf_imf_thread_index = -1;
81 static int hf_imf_ext_mailer = -1;
82 static int hf_imf_ext_mimeole = -1;
83 static int hf_imf_ext_tnef_correlator = -1;
84 static int hf_imf_ext_expiry_date = -1;
85 static int hf_imf_ext_uidl = -1;
86 static int hf_imf_ext_authentication_warning = -1;
87 static int hf_imf_ext_virus_scanned = -1;
88 static int hf_imf_extension = -1;
89 static int hf_imf_extension_type = -1;
90 static int hf_imf_extension_value = -1;
91
92 /* RFC 2156 */
93 static int hf_imf_autoforwarded = -1;
94 static int hf_imf_autosubmitted = -1;
95 static int hf_imf_x400_content_identifier = -1;
96 static int hf_imf_content_language = -1;
97 static int hf_imf_conversion = -1;
98 static int hf_imf_conversion_with_loss = -1;
99 static int hf_imf_delivery_date = -1;
100 static int hf_imf_discarded_x400_ipms_extensions = -1;
101 static int hf_imf_discarded_x400_mts_extensions = -1;
102 static int hf_imf_dl_expansion_history = -1;
103 static int hf_imf_deferred_delivery = -1;
104 static int hf_imf_expires = -1;
105 static int hf_imf_importance = -1;
106 static int hf_imf_incomplete_copy = -1;
107 static int hf_imf_latest_delivery_time = -1;
108 static int hf_imf_message_type = -1;
109 static int hf_imf_original_encoded_information_types = -1;
110 static int hf_imf_originator_return_address = -1;
111 static int hf_imf_priority = -1;
112 static int hf_imf_reply_by = -1;
113 static int hf_imf_sensitivity = -1;
114 static int hf_imf_supersedes = -1;
115 static int hf_imf_x400_content_type = -1;
116 static int hf_imf_x400_mts_identifier = -1;
117 static int hf_imf_x400_originator = -1;
118 static int hf_imf_x400_received = -1;
119 static int hf_imf_x400_recipients = -1;
120
121 static int hf_imf_delivered_to = -1;
122
123 static int hf_imf_message_text = -1;
124
125 static int hf_imf_display_name = -1;
126 static int hf_imf_address = -1;
127 static int hf_imf_mailbox_list = -1;
128 static int hf_imf_mailbox_list_item = -1;
129 static int hf_imf_address_list = -1;
130 static int hf_imf_address_list_item = -1;
131
132 static int ett_imf = -1;
133 static int ett_imf_content_type = -1;
134 static int ett_imf_mailbox = -1;
135 static int ett_imf_group = -1;
136 static int ett_imf_mailbox_list = -1;
137 static int ett_imf_address_list = -1;
138 static int ett_imf_extension = -1;
139 static int ett_imf_message_text = -1;
140
141 struct imf_field {
142   const char   *name;     /* field name - in lower case for matching purposes */
143   int          *hf_id;       /* wireshark field */
144   void         (*subdissector)(tvbuff_t *tvb, int offset, int length, proto_item *item);
145   gboolean     add_to_col_info; /* add field to column info */
146 };
147
148 #define NO_SUBDISSECTION NULL
149
150 static void dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item);
151 static void dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item);
152 static void dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item);
153 static void dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item);
154
155 struct imf_field imf_fields[] = {
156   {"unknown-extension", &hf_imf_extension_type, NO_SUBDISSECTION, FALSE}, /* unknown extension */
157   {"date", &hf_imf_date, NO_SUBDISSECTION, FALSE}, /* date-time */
158   {"from", &hf_imf_from, dissect_imf_mailbox_list , TRUE}, /* mailbox_list */
159   {"sender", &hf_imf_sender, dissect_imf_mailbox, FALSE}, /* mailbox */
160   {"reply-to", &hf_imf_reply_to, dissect_imf_address_list , FALSE}, /* address_list */
161   {"to", &hf_imf_to, dissect_imf_address_list , FALSE}, /* address_list */
162   {"cc", &hf_imf_cc, dissect_imf_address_list , FALSE}, /* address_list */
163   {"bcc", &hf_imf_bcc, dissect_imf_address_list , FALSE}, /* address_list */
164   {"message-id", &hf_imf_message_id, NO_SUBDISSECTION, FALSE}, /* msg-id */
165   {"in-reply-to", &hf_imf_in_reply_to, NO_SUBDISSECTION, FALSE}, /* msg-id */
166   {"references", &hf_imf_references, NO_SUBDISSECTION, FALSE}, /* msg-id */
167   {"subject", &hf_imf_subject, NO_SUBDISSECTION, TRUE}, /* unstructured */
168   {"comments", &hf_imf_comments, NO_SUBDISSECTION, FALSE}, /* unstructured */
169   {"keywords", &hf_imf_keywords, NULL, FALSE}, /* phrase_list */
170   {"resent-date", &hf_imf_resent_date, NO_SUBDISSECTION, FALSE},
171   {"resent-from", &hf_imf_resent_from, dissect_imf_mailbox_list, FALSE},
172   {"resent-sender", &hf_imf_resent_sender, dissect_imf_mailbox, FALSE},
173   {"resent-to", &hf_imf_resent_to, dissect_imf_address_list, FALSE},
174   {"resent-cc", &hf_imf_resent_cc, dissect_imf_address_list, FALSE},
175   {"resent-bcc", &hf_imf_resent_bcc, dissect_imf_address_list, FALSE},
176   {"resent-message-id", &hf_imf_resent_message_id, NO_SUBDISSECTION, FALSE},
177   {"return-path", &hf_imf_return_path, NULL, FALSE},
178   {"received", &hf_imf_received, NO_SUBDISSECTION, FALSE},
179   /* these are really multi-part - but we parse them anyway */
180   {"content-type", &hf_imf_content_type, NULL, FALSE}, /* handled separately as a special case */
181   {"content-id", &hf_imf_content_id, NULL, FALSE},
182   {"content-description", &hf_imf_content_description, NULL, FALSE},
183   {"content-transfer-encoding", &hf_imf_content_transfer_encoding, NULL, FALSE},
184   {"mime-version", &hf_imf_mime_version, NO_SUBDISSECTION, FALSE},
185   /* MIXER - RFC 2156 */
186   {"autoforwarded", &hf_imf_autoforwarded, NULL, FALSE},
187   {"autosubmitted", &hf_imf_autosubmitted, NULL, FALSE},
188   {"x400-content-identifier", &hf_imf_x400_content_identifier, NULL, FALSE},
189   {"content-language", &hf_imf_content_language, NULL, FALSE},
190   {"conversion", &hf_imf_conversion, NULL, FALSE},
191   {"conversion-with-loss", &hf_imf_conversion_with_loss, NULL, FALSE},
192   {"delivery-date", &hf_imf_delivery_date, NULL, FALSE},
193   {"discarded-x400-ipms-extensions", &hf_imf_discarded_x400_ipms_extensions, NULL, FALSE},
194   {"discarded-x400-mts-extensions", &hf_imf_discarded_x400_mts_extensions, NULL, FALSE},
195   {"dl-expansion-history", &hf_imf_dl_expansion_history, NULL, FALSE},
196   {"deferred-delivery", &hf_imf_deferred_delivery, NULL, FALSE},
197   {"expires", &hf_imf_expires, NULL, FALSE},
198   {"importance", &hf_imf_importance, NULL, FALSE},
199   {"incomplete-copy", &hf_imf_incomplete_copy, NULL, FALSE},
200   {"latest-delivery-time", &hf_imf_latest_delivery_time, NULL, FALSE},
201   {"message-type", &hf_imf_message_type, NULL, FALSE},
202   {"original-encoded-information-types", &hf_imf_original_encoded_information_types, NULL, FALSE},
203   {"originator-return-address", &hf_imf_originator_return_address, NULL, FALSE},
204   {"priority", &hf_imf_priority, NULL, FALSE},
205   {"reply-by", &hf_imf_reply_by, NULL, FALSE},
206   {"sensitivity", &hf_imf_sensitivity, NULL, FALSE},
207   {"supersedes", &hf_imf_supersedes, NULL, FALSE},
208   {"x400-content-type", &hf_imf_x400_content_type, NULL, FALSE},
209   {"x400-mts-identifier", &hf_imf_x400_mts_identifier, NULL, FALSE},
210   {"x400-originator", &hf_imf_x400_originator, NULL, FALSE},
211   {"x400-received", &hf_imf_x400_received, NULL, FALSE},
212   {"x400-recipients", &hf_imf_x400_recipients, NULL, FALSE},
213   /* delivery */
214   {"delivered-to", &hf_imf_delivered_to, dissect_imf_mailbox, FALSE}, /* mailbox */
215   /* some others */
216   {"x-mailer", &hf_imf_ext_mailer, NO_SUBDISSECTION, FALSE}, /* unstructured */
217   {"thread-index", &hf_imf_thread_index, NO_SUBDISSECTION, FALSE}, /* unstructured */
218   {"x-mimeole", &hf_imf_ext_mimeole, NO_SUBDISSECTION, FALSE}, /* unstructured */
219   {"expiry-date", &hf_imf_ext_expiry_date, NO_SUBDISSECTION, FALSE}, /* unstructured */
220   {"x-ms-tnef-correlator", &hf_imf_ext_tnef_correlator, NO_SUBDISSECTION, FALSE}, /* unstructured */
221   {"x-uidl", &hf_imf_ext_uidl, NO_SUBDISSECTION, FALSE}, /* unstructured */
222   {"x-authentication-warning", &hf_imf_ext_authentication_warning, NO_SUBDISSECTION, FALSE}, /* unstructured */
223   {"x-virus-scanned", &hf_imf_ext_virus_scanned, NO_SUBDISSECTION, FALSE}, /* unstructured */
224   {NULL, NULL, NULL, FALSE},
225 };
226
227 static GHashTable *imf_field_table=NULL;
228
229 /* Define media_type/Content type table */
230 static dissector_table_t media_type_dissector_table;
231
232 static void dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item)
233 {
234   proto_tree *group_tree;
235   proto_item *group_item;
236   int addr_pos;
237
238   /* if there is a colon present it is a group */
239   if((addr_pos = tvb_find_guint8(tvb, offset, length, ':')) == -1) {
240
241     /* there isn't - so it must be a mailbox */
242     dissect_imf_mailbox(tvb, offset, length, item);
243
244   } else {
245
246     /* it is a group */
247     group_tree = proto_item_add_subtree(item, ett_imf_group);
248
249     /* the display-name is mandatory */
250     group_item = proto_tree_add_item(group_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, FALSE);
251
252     /* consume any whitespace */
253     for(addr_pos++ ;addr_pos < (offset + length); addr_pos++) {
254       if(!isspace(tvb_get_guint8(tvb, addr_pos))) {
255         break;
256       }
257     }
258
259     if(tvb_get_guint8(tvb, addr_pos) != ';') {
260
261       dissect_imf_mailbox_list(tvb, addr_pos, length - (addr_pos - offset), group_item);
262
263       /* XXX: need to check for final ';' */
264
265     }
266
267   }
268
269
270   return;
271
272 }
273
274 static void dissect_imf_mailbox(tvbuff_t *tvb, int offset, int length, proto_item *item)
275 {
276   proto_tree *mbox_tree;
277   int        addr_pos, end_pos;
278
279   mbox_tree = proto_item_add_subtree(item, ett_imf_mailbox);
280
281   /* Here is the plan:
282      If we can't find and angle brackets, then the whole field is an address.
283      If we find angle brackets, then the address is between them and the display name is
284      anything before the opening angle bracket
285   */
286
287   if((addr_pos = tvb_find_guint8(tvb, offset, length, '<')) == -1) {
288     /* we can't find an angle bracket - the whole field is therefore the address */
289
290     (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, offset, length, FALSE);
291
292   } else {
293     /* we can find an angle bracket - let's see if we can find a display name */
294     /* XXX: the '<' could be in the display name */
295
296     for(; offset < addr_pos; offset++) {
297       if(!isspace(tvb_get_guint8(tvb, offset))) {
298         break;
299       }
300     }
301
302     if(offset != addr_pos) /* there is a display name */
303       (void) proto_tree_add_item(mbox_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, FALSE);
304
305     end_pos = tvb_find_guint8(tvb, addr_pos + 1, length - (addr_pos + 1 - offset), '>');
306
307     if(end_pos != -1)
308       (void) proto_tree_add_item(mbox_tree, hf_imf_address, tvb, addr_pos + 1, end_pos - addr_pos - 1, FALSE);
309
310   }
311 }
312
313 static void dissect_imf_address_list(tvbuff_t *tvb, int offset, int length, proto_item *item)
314 {
315   proto_item *addr_item = NULL;
316   proto_tree *tree = NULL;
317   int         count = 0;
318   int         item_offset;
319   int         end_offset;
320   int         item_length;
321
322   /* a comma separated list of addresses */
323   tree = proto_item_add_subtree(item, ett_imf_address_list);
324
325   item_offset = offset;
326
327   do {
328
329     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
330
331     count++; /* increase the number of items */
332
333     if(end_offset == -1)
334       /* length is to the end of the buffer */
335       item_length = length - (item_offset - offset);
336     else
337       item_length = end_offset - item_offset;
338
339     addr_item = proto_tree_add_item(tree, hf_imf_address_list_item, tvb, item_offset, item_length, FALSE);
340     dissect_imf_address(tvb, item_offset, item_length, addr_item);
341
342     if(end_offset != -1)
343       item_offset = end_offset + 1;
344
345   } while(end_offset != -1);
346
347   /* now indicate the number of items found */
348   proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
349
350   return;
351 }
352
353 static void dissect_imf_mailbox_list(tvbuff_t *tvb, int offset, int length, proto_item *item)
354 {
355   proto_item *mbox_item = NULL;
356   proto_tree *tree = NULL;
357   int         count = 0;
358   int         item_offset;
359   int         end_offset;
360   int         item_length;
361
362   /* a comma separated list of mailboxes */
363   tree = proto_item_add_subtree(item, ett_imf_mailbox_list);
364
365   item_offset = offset;
366
367   do {
368
369     end_offset = tvb_find_guint8(tvb, item_offset, length - (item_offset - offset), ',');
370
371     count++; /* increase the number of items */
372
373     if(end_offset == -1)
374       /* length is to the end of the buffer */
375       item_length = length - (item_offset - offset);
376     else
377       item_length = end_offset - item_offset;
378
379     mbox_item = proto_tree_add_item(tree, hf_imf_mailbox_list_item, tvb, item_offset, item_length, FALSE);
380     dissect_imf_mailbox(tvb, item_offset, item_length, mbox_item);
381
382     if(end_offset != -1)
383       item_offset = end_offset + 1;
384
385   } while(end_offset != -1);
386
387   /* now indicate the number of items found */
388   proto_item_append_text(item, ", %d item%s", count, plurality(count, "", "s"));
389
390   return;
391 }
392
393
394 static void dissect_imf_content_type(tvbuff_t *tvb, int offset, int length, proto_item *item,
395                                      char **type, char **parameters)
396 {
397   int first_colon;
398   int len;
399   int i;
400   proto_tree *ct_tree;
401
402   /* first strip any whitespace */
403   for(i = 0; i < length; i++) {
404     if(!isspace(tvb_get_guint8(tvb, offset + i))) {
405       offset += i;
406       break;
407     }
408   }
409
410   /* find the first colon - there has to be a colon as there will have to be a boundary */
411   first_colon = tvb_find_guint8(tvb, offset, length, ';');
412
413   if(first_colon != -1) {
414     ct_tree = proto_item_add_subtree(item, ett_imf_content_type);
415
416     len = first_colon - offset;
417     proto_tree_add_item(ct_tree, hf_imf_content_type_type, tvb, offset, len, FALSE);
418     if(type)
419       /* This string will be automatically freed */
420       (*type) = tvb_get_ephemeral_string(tvb, offset, len);
421
422     len = length - (first_colon + 1 - offset);
423     proto_tree_add_item(ct_tree, hf_imf_content_type_parameters, tvb, first_colon + 1, len, FALSE);
424     if(parameters)
425       /* This string will be automatically freed */
426       (*parameters) = tvb_get_ephemeral_string(tvb, first_colon + 1, len);
427   }
428 }
429
430
431 int imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_field)
432 {
433
434   while(offset < max_length) {
435
436     /* look for CR */
437     offset = tvb_find_guint8(tvb, offset, max_length - offset, '\r');
438
439     if(offset != -1) {
440       if(tvb_get_guint8(tvb, ++offset) == '\n') {
441                   /* OK - so we have found CRLF */
442                   /* peek the next character */
443                   switch(tvb_get_guint8(tvb, ++offset)) {
444                   case '\r':
445                           /* probably end of the fields */
446                           if(tvb_get_guint8(tvb, ++offset) == '\n')
447                                   offset++;
448                           if(last_field)
449                                   *last_field = TRUE;
450                           return offset;
451                   case  ' ':
452                   case '\t':
453                           /* continuation line */
454                           break;
455                   default:
456                           /* this is a new field */
457                           return offset;
458                   }
459           }
460         }else {
461                 /* couldn't find a CR - strange */
462                 return offset;
463     }
464
465   }
466
467   return offset;
468
469 }
470
471 static void dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
472 {
473   proto_item  *item;
474   proto_tree  *unknown_tree, *text_tree;
475   char  *content_type_str = NULL;
476   char  *parameters = NULL;
477   int   hf_id;
478   gint  start_offset = 0;
479   gint  value_offset = 0;
480   gint  unknown_offset = 0;
481   gint  end_offset = 0;
482   gint   max_length;
483   guint8 *key;
484   gboolean last_field = FALSE;
485   gboolean dissected = FALSE;
486   tvbuff_t *next_tvb;
487   struct imf_field *f_info;
488
489   if (check_col(pinfo->cinfo, COL_PROTOCOL))
490     col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
491   col_clear(pinfo->cinfo, COL_INFO);
492
493   if(tree){
494     item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, FALSE);
495     tree = proto_item_add_subtree(item, ett_imf);
496   }
497
498   max_length = tvb_length(tvb);
499   /* first go through the tvb until we find a blank line and extract the content type if
500      we find one */
501
502   while(!last_field) {
503
504     /* look for a colon first */
505     end_offset = tvb_find_guint8(tvb, start_offset, max_length - start_offset, ':');
506
507     if(end_offset == -1) {
508       /* we couldn't find another colon - strange - we should have broken out of here by now */
509       /* XXX: flag an error */
510       break;
511     } else {
512       guint8 *p;
513
514       key = tvb_get_ephemeral_string(tvb, start_offset, end_offset - start_offset);
515
516       /* convert to lower case */
517
518       for(p=key; *p; p++)
519         if(isupper(*p))
520           *p = tolower(*p);
521
522       /* look up the key */
523       f_info = (struct imf_field *)g_hash_table_lookup(imf_field_table, key);
524
525       if(f_info == (struct imf_field *)NULL) {
526         /* set as an unknown extension */
527         f_info = imf_fields;
528         unknown_offset = start_offset;
529       }
530
531       hf_id = *(f_info->hf_id);
532
533       /* value starts immediately after the colon */
534       start_offset = end_offset+1;
535
536       end_offset = imf_find_field_end(tvb, start_offset, max_length, &last_field);
537
538       if(end_offset != -1) {
539
540         /* remove any leading whitespace */
541
542         for(value_offset = start_offset; value_offset < end_offset; value_offset++)
543           if(!isspace(tvb_get_guint8(tvb, value_offset))) {
544             break;
545           }
546
547         if(value_offset == end_offset) {
548           /* empty field - show whole value */
549           value_offset = start_offset;
550         }
551
552         if(hf_id == hf_imf_extension_type) {
553
554           /* remove 2 bytes to take off the final CRLF to make things a little prettier */
555           item = proto_tree_add_item(tree, hf_imf_extension, tvb, unknown_offset, end_offset - unknown_offset - 2, FALSE);
556
557           proto_item_append_text(item, " (Contact Wireshark developers if you want this supported.)");
558
559           unknown_tree = proto_item_add_subtree(item, ett_imf_extension);
560
561           item = proto_tree_add_item(unknown_tree, hf_imf_extension_type, tvb, unknown_offset, start_offset - 1 - unknown_offset, FALSE);
562
563           /* remove 2 bytes to take off the final CRLF to make things a little prettier */
564           item = proto_tree_add_item(unknown_tree, hf_imf_extension_value, tvb, start_offset, end_offset - start_offset - 2, FALSE);
565
566         } else
567
568           /* remove 2 bytes to take off the final CRLF to make things a little prettier */
569           item = proto_tree_add_item(tree, hf_id, tvb, value_offset, end_offset - value_offset - 2, FALSE);
570
571         if(f_info->add_to_col_info && check_col(pinfo->cinfo, COL_INFO)) {
572
573           col_append_fstr(pinfo->cinfo, COL_INFO, "%s: %s, ", f_info->name,
574                           tvb_format_text(tvb, value_offset, end_offset - value_offset - 2));
575         }
576
577         if(hf_id == hf_imf_content_type) {
578           /* we need some additional processing to extract the content type and parameters */
579
580           dissect_imf_content_type(tvb, start_offset, end_offset - start_offset, item,
581                                    &content_type_str, &parameters);
582
583         } else if(f_info && f_info->subdissector) {
584
585           /* we have a subdissector */
586           f_info->subdissector(tvb, value_offset, end_offset - value_offset, item);
587
588         }
589       }
590     }
591     start_offset = end_offset;
592   }
593
594   /* specify a content type until we can work it out for ourselves */
595   /* content_type_str = "multipart/mixed"; */
596
597   /* now dissect the MIME based upon the content type */
598
599   if(content_type_str && media_type_dissector_table) {
600     void* pd_save;
601     pd_save = pinfo->private_data;
602     pinfo->private_data = parameters; 
603
604     next_tvb = tvb_new_subset_remaining(tvb, end_offset);
605
606     dissected = dissector_try_string(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree);
607
608     pinfo->private_data = pd_save;
609   } else {
610
611     /* just show the lines or highlight the rest of the buffer as message text */
612
613     item = proto_tree_add_item(tree, hf_imf_message_text, tvb, start_offset, -1 , FALSE);
614     text_tree = proto_item_add_subtree(item, ett_imf_message_text);
615
616     start_offset = end_offset;
617     while (tvb_offset_exists(tvb, start_offset)) {
618
619       /*
620        * Find the end of the line.
621        */
622       tvb_find_line_end(tvb, start_offset, -1, &end_offset, FALSE);
623
624       /*
625        * Put this line.
626        */
627       proto_tree_add_text(text_tree, tvb, start_offset, end_offset - start_offset,
628                           "%s",
629                           tvb_format_text(tvb, start_offset, end_offset - start_offset - 2));
630
631       /*
632        * Step to the next line.
633        */
634       start_offset = end_offset;
635     }
636   }
637 }
638
639
640 /* Register all the bits needed by the filtering engine */
641
642 void
643 proto_register_imf(void)
644 {
645   static hf_register_info hf[] = {
646     { &hf_imf_date,
647       { "Date", "imf.date", FT_STRING,  BASE_NONE, NULL, 0x0,
648         "imf.DateTime", HFILL }},
649     { &hf_imf_from,
650       { "From", "imf.from", FT_STRING,  BASE_NONE, NULL, 0x0,
651         "imf.MailboxList", HFILL }},
652     { &hf_imf_sender,
653       { "Sender", "imf.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
654         NULL, HFILL }},
655     { &hf_imf_reply_to,
656       { "Reply-To", "imf.reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
657         NULL, HFILL }},
658     { &hf_imf_to,
659       { "To", "imf.to", FT_STRING,  BASE_NONE, NULL, 0x0,
660         NULL, HFILL }},
661     { &hf_imf_cc,
662       { "Cc", "imf.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
663         NULL, HFILL }},
664     { &hf_imf_bcc,
665       { "Bcc", "imf.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
666         NULL, HFILL }},
667     { &hf_imf_message_id,
668       { "Message-ID", "imf.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
669         NULL, HFILL }},
670     { &hf_imf_in_reply_to,
671       { "In-Reply-To", "imf.in_reply_to", FT_STRING,  BASE_NONE, NULL, 0x0,
672         NULL, HFILL }},
673     { &hf_imf_references,
674       { "References", "imf.references", FT_STRING,  BASE_NONE, NULL, 0x0,
675         NULL, HFILL }},
676     { &hf_imf_subject,
677       { "Subject", "imf.subject", FT_STRING,  BASE_NONE, NULL, 0x0,
678         NULL, HFILL }},
679     { &hf_imf_comments,
680       { "Comments", "imf.comments", FT_STRING,  BASE_NONE, NULL, 0x0,
681         NULL, HFILL }},
682     { &hf_imf_keywords,
683       { "Keywords", "imf.keywords", FT_STRING,  BASE_NONE, NULL, 0x0,
684         NULL, HFILL }},
685     { &hf_imf_resent_date,
686       { "Resent-Date", "imf.resent.date", FT_STRING,  BASE_NONE, NULL, 0x0,
687         NULL, HFILL }},
688     { &hf_imf_resent_from,
689       { "Resent-From", "imf.resent.from", FT_STRING,  BASE_NONE, NULL, 0x0,
690         NULL, HFILL }},
691     { &hf_imf_resent_sender,
692       { "Resent-Sender", "imf.resent.sender", FT_STRING,  BASE_NONE, NULL, 0x0,
693         NULL, HFILL }},
694     { &hf_imf_resent_to,
695       { "Resent-To", "imf.resent.to", FT_STRING,  BASE_NONE, NULL, 0x0,
696         NULL, HFILL }},
697     { &hf_imf_resent_cc,
698       { "Resent-Cc", "imf.resent.cc", FT_STRING,  BASE_NONE, NULL, 0x0,
699         NULL, HFILL }},
700     { &hf_imf_resent_bcc,
701       { "Resent-Bcc", "imf.resent.bcc", FT_STRING,  BASE_NONE, NULL, 0x0,
702         NULL, HFILL }},
703     { &hf_imf_resent_message_id,
704       { "Resent-Message-ID", "imf.resent.message_id", FT_STRING,  BASE_NONE, NULL, 0x0,
705         NULL, HFILL }},
706     { &hf_imf_return_path,
707       { "Return-Path", "imf.return_path", FT_STRING,  BASE_NONE, NULL, 0x0,
708         NULL, HFILL }},
709     { &hf_imf_received,
710       { "Received", "imf.received", FT_STRING,  BASE_NONE, NULL, 0x0,
711         NULL, HFILL }},
712     { &hf_imf_content_type,
713       { "Content-Type", "imf.content.type", FT_STRING,  BASE_NONE, NULL, 0x0,
714         NULL, HFILL }},
715     { &hf_imf_content_type_type,
716       { "Type", "imf.content.type.type", FT_STRING,  BASE_NONE, NULL, 0x0,
717         NULL, HFILL }},
718     { &hf_imf_content_type_parameters,
719       { "Parameters", "imf.content.type.parameters", FT_STRING,  BASE_NONE, NULL, 0x0,
720         NULL, HFILL }},
721     { &hf_imf_content_description,
722       { "Content-Description", "imf.content.description", FT_STRING,  BASE_NONE, NULL, 0x0,
723         NULL, HFILL }},
724     { &hf_imf_content_id,
725       { "Content-ID", "imf.content.id", FT_STRING,  BASE_NONE, NULL, 0x0,
726         NULL, HFILL }},
727     { &hf_imf_content_transfer_encoding,
728       { "Content-Transfer-Encoding", "imf.content.transfer_encoding", FT_STRING,  BASE_NONE, NULL, 0x0,
729         NULL, HFILL }},
730     { &hf_imf_mime_version,
731       { "MIME-Version", "imf.mime_version", FT_STRING,  BASE_NONE, NULL, 0x0,
732         NULL, HFILL }},
733     { &hf_imf_autoforwarded,
734       { "Autoforwarded", "imf.autoforwarded", FT_STRING, BASE_NONE, NULL, 0x0,
735         NULL, HFILL }},
736     { &hf_imf_autosubmitted,
737       { "Autosubmitted", "imf.autosubmitted", FT_STRING, BASE_NONE, NULL, 0x0,
738         NULL, HFILL }},
739     { &hf_imf_x400_content_identifier,
740       { "X400-Content-Identifier", "imf.x400_content_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
741         NULL, HFILL }},
742     { &hf_imf_content_language,
743       { "Content-Language", "imf.content_language", FT_STRING, BASE_NONE, NULL, 0x0,
744         NULL, HFILL }},
745     { &hf_imf_conversion,
746         { "Conversion", "imf.conversion", FT_STRING, BASE_NONE, NULL, 0x0,
747           NULL, HFILL }},
748     { &hf_imf_conversion_with_loss,
749         { "Conversion-With-Loss", "imf.conversion_with_loss", FT_STRING, BASE_NONE, NULL, 0x0,
750           NULL, HFILL }},
751     { &hf_imf_delivery_date,
752         { "Delivery-Date", "imf.delivery_date", FT_STRING, BASE_NONE, NULL, 0x0,
753           NULL, HFILL }},
754     { &hf_imf_discarded_x400_ipms_extensions,
755         { "Discarded-X400-IPMS-Extensions", "imf.discarded_x400_ipms_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
756           NULL, HFILL }},
757     { &hf_imf_discarded_x400_mts_extensions,
758       { "Discarded-X400-MTS-Extensions", "imf.discarded_x400_mts_extensions", FT_STRING, BASE_NONE, NULL, 0x0,
759         NULL, HFILL }},
760     { &hf_imf_dl_expansion_history,
761         { "DL-Expansion-History", "imf.dl_expansion_history", FT_STRING, BASE_NONE, NULL, 0x0,
762           NULL, HFILL }},
763     { &hf_imf_deferred_delivery,
764         { "Deferred-Delivery", "imf.deferred_delivery", FT_STRING, BASE_NONE, NULL, 0x0,
765           NULL, HFILL }},
766     { &hf_imf_expires,
767         { "Expires", "imf.expires", FT_STRING, BASE_NONE, NULL, 0x0,
768           NULL, HFILL }},
769     { &hf_imf_importance,
770       { "Importance", "imf.importance", FT_STRING, BASE_NONE, NULL, 0x0,
771         NULL, HFILL }},
772     { &hf_imf_incomplete_copy,
773         { "Incomplete-Copy", "imf.incomplete_copy", FT_STRING, BASE_NONE, NULL, 0x0,
774           NULL, HFILL }},
775     { &hf_imf_latest_delivery_time,
776       { "Latest-Delivery-Time", "imf.latest_delivery_time", FT_STRING, BASE_NONE, NULL, 0x0,
777         NULL, HFILL }},
778     { &hf_imf_message_type,
779         { "Message-Type", "imf.message_type", FT_STRING, BASE_NONE, NULL, 0x0,
780           NULL, HFILL }},
781     { &hf_imf_original_encoded_information_types,
782         { "Original-Encoded-Information-Types", "imf.original_encoded_information_types", FT_STRING, BASE_NONE, NULL, 0x0,
783           NULL, HFILL }},
784     { &hf_imf_originator_return_address,
785         { "Originator-Return-Address", "imf.originator_return_address", FT_STRING, BASE_NONE, NULL, 0x0,
786           NULL, HFILL }},
787     { &hf_imf_priority,
788         { "Priority", "imf.priority", FT_STRING, BASE_NONE, NULL, 0x0,
789           NULL, HFILL }},
790     { &hf_imf_reply_by,
791         { "Reply-By", "imf.reply_by", FT_STRING, BASE_NONE, NULL, 0x0,
792           NULL, HFILL }},
793     { &hf_imf_sensitivity,
794         { "Sensitivity", "imf.sensitivity", FT_STRING, BASE_NONE, NULL, 0x0,
795           NULL, HFILL }},
796     { &hf_imf_supersedes,
797         { "Supersedes", "imf.supersedes", FT_STRING, BASE_NONE, NULL, 0x0,
798           NULL, HFILL }},
799     { &hf_imf_x400_content_type,
800         { "X400-Content-Type", "imf.x400_content_type", FT_STRING, BASE_NONE, NULL, 0x0,
801           NULL, HFILL }},
802     { &hf_imf_x400_mts_identifier,
803         { "X400-MTS-Identifier", "imf.x400_mts_identifier", FT_STRING, BASE_NONE, NULL, 0x0,
804           NULL, HFILL }},
805     { &hf_imf_x400_originator,
806         { "X400-Originator", "imf.x400_originator", FT_STRING, BASE_NONE, NULL, 0x0,
807         NULL, HFILL }},
808     { &hf_imf_x400_received,
809         { "X400-Received", "imf.x400_received", FT_STRING, BASE_NONE, NULL, 0x0,
810         NULL, HFILL }},
811     { &hf_imf_x400_recipients,
812         { "X400-Recipients", "imf.x400_recipients", FT_STRING, BASE_NONE, NULL, 0x0,
813         NULL, HFILL }},
814     { &hf_imf_delivered_to,
815       { "Delivered-To", "imf.delivered_to", FT_STRING,  BASE_NONE, NULL, 0x0,
816         NULL, HFILL }},
817     { &hf_imf_ext_mailer,
818       { "X-Mailer", "imf.ext.mailer", FT_STRING,  BASE_NONE, NULL, 0x0,
819         NULL, HFILL }},
820     { &hf_imf_ext_mimeole,
821       { "X-MimeOLE", "imf.ext.mimeole", FT_STRING,  BASE_NONE, NULL, 0x0,
822         NULL, HFILL }},
823     { &hf_imf_ext_expiry_date,
824       { "Expiry-Date", "imf.ext.expiry-date", FT_STRING,  BASE_NONE, NULL, 0x0,
825         NULL, HFILL }},
826     { &hf_imf_ext_tnef_correlator,
827       { "X-MS-TNEF-Correlator", "imf.ext.tnef-correlator", FT_STRING,  BASE_NONE, NULL, 0x0,
828         NULL, HFILL }},
829     { &hf_imf_ext_uidl,
830       { "X-UIDL", "imf.ext.uidl", FT_STRING,  BASE_NONE, NULL, 0x0,
831         NULL, HFILL }},
832     { &hf_imf_ext_authentication_warning,
833       { "X-Authentication-Warning", "imf.ext.authentication_warning", FT_STRING,  BASE_NONE,
834         NULL, 0x0, NULL, HFILL }},
835     { &hf_imf_ext_virus_scanned,
836       { "X-Virus-Scanned", "imf.ext.virus_scanned", FT_STRING,  BASE_NONE, NULL, 0x0,
837         NULL, HFILL }},
838     { &hf_imf_thread_index,
839       { "Thread-Index", "imf.thread-index", FT_STRING,  BASE_NONE, NULL, 0x0,
840         NULL, HFILL }},
841     { &hf_imf_extension,
842       { "Unknown-Extension", "imf.extension", FT_STRING,  BASE_NONE, NULL, 0x0,
843         NULL, HFILL }},
844     { &hf_imf_extension_type,
845       { "Type", "imf.extension.type", FT_STRING,  BASE_NONE, NULL, 0x0,
846         NULL, HFILL }},
847     { &hf_imf_extension_value,
848       { "Value", "imf.extension.value", FT_STRING,  BASE_NONE, NULL, 0x0,
849         NULL, HFILL }},
850     { &hf_imf_display_name,
851       { "Display-Name", "imf.display_name", FT_STRING,  BASE_NONE, NULL, 0x0,
852         NULL, HFILL }},
853     { &hf_imf_address,
854       { "Address", "imf.address", FT_STRING,  BASE_NONE, NULL, 0x0,
855         NULL, HFILL }},
856     { &hf_imf_address_list,
857       { "Address List", "imf.address_list", FT_UINT32,  BASE_DEC, NULL, 0x0,
858         NULL, HFILL }},
859     { &hf_imf_address_list_item,
860       { "Item", "imf.address_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
861         NULL, HFILL }},
862     { &hf_imf_mailbox_list,
863       { "Mailbox List", "imf.mailbox_list", FT_UINT32,  BASE_DEC, NULL, 0x0,
864         NULL, HFILL }},
865     { &hf_imf_mailbox_list_item,
866       { "Item", "imf.mailbox_list.item", FT_STRING,  BASE_NONE, NULL, 0x0,
867         NULL, HFILL }},
868     { &hf_imf_message_text,
869       { "Message-Text", "imf.message_text", FT_NONE,  BASE_NONE, NULL, 0x0,
870         NULL, HFILL }},
871   };
872   static gint *ett[] = {
873     &ett_imf,
874     &ett_imf_content_type,
875     &ett_imf_group,
876     &ett_imf_mailbox,
877     &ett_imf_mailbox_list,
878     &ett_imf_address_list,
879     &ett_imf_extension,
880     &ett_imf_message_text,
881   };
882
883   struct imf_field *f;
884
885   proto_imf = proto_register_protocol(PNAME, PSNAME, PFNAME);
886
887   proto_register_field_array(proto_imf, hf, array_length(hf));
888   proto_register_subtree_array(ett, array_length(ett));
889
890   /* Allow dissector to find be found by name. */
891   register_dissector(PFNAME, dissect_imf, proto_imf);
892
893   imf_field_table=g_hash_table_new(g_str_hash, g_str_equal); /* oid to syntax */
894
895   /* register the fields for lookup */
896   for(f = imf_fields; f->name; f++)
897     g_hash_table_insert(imf_field_table, (const gpointer)f->name, (const gpointer)f);
898
899 }
900
901 /* The registration hand-off routine */
902 void
903 proto_reg_handoff_imf(void)
904 {
905   dissector_handle_t imf_handle;
906
907   imf_handle = find_dissector(PFNAME);
908
909   dissector_add_string("media_type",
910                        "message/rfc822", imf_handle);
911
912   register_ber_oid_dissector("1.2.840.113549.1.7.1", dissect_imf, proto_imf, "id-data");
913
914   /*
915    * Get the content type and Internet media type table
916    */
917   media_type_dissector_table = find_dissector_table("media_type");
918
919 }