Damn the torpedos[1], commit it anyway.
[obnox/wireshark/wip.git] / packet-mmse.c
1 /* packet-mmse.c
2  * Routines for MMS Message Encapsulation dissection
3  * Copyright 2001, Tom Uijldert <tom.uijldert@cmg.nl>
4  *
5  * $Id: packet-mmse.c,v 1.1 2001/09/25 21:32:41 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  * ----------
25  *
26  * Dissector of an encoded Multimedia message PDU, as defined by the WAPForum
27  * (http://www.wapforum.org) in "WAP-209.102-MMSEncapsulation" according
28  * the draft version of 8-February-2001.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46
47 #include <glib.h>
48
49 #ifdef NEED_SNPRINTF_H
50 # include "snprintf.h"
51 #endif
52
53 #include "packet.h"
54 #include "packet-wap.h"
55 /* #include "packet-mmse.h" */          /* We autoregister      */
56
57 #define MM_QUOTE                0x7F    /* Quoted string        */
58
59 /*
60  * Header field values
61  */
62 #define MM_BCC_HDR              0x81    /* Bcc                  */
63 #define MM_CC_HDR               0x82    /* Cc                   */
64 #define MM_CLOCATION_HDR        0x83    /* Content-Location     */
65 #define MM_CTYPE_HDR            0x84    /* Content-Type         */
66 #define MM_DATE_HDR             0x85    /* Date                 */
67 #define MM_DREPORT_HDR          0x86    /* Delivery-Report      */
68 #define MM_DTIME_HDR            0x87    /* Delivery-Time        */
69 #define MM_EXPIRY_HDR           0x88    /* Expiry               */
70 #define MM_FROM_HDR             0x89    /* From                 */
71 #define MM_MCLASS_HDR           0x8A    /* Message-Class        */
72 #define MM_MID_HDR              0x8B    /* Message-ID           */
73 #define MM_MTYPE_HDR            0x8C    /* Message-Type         */
74 #define MM_VERSION_HDR          0x8D    /* MMS-Version          */
75 #define MM_MSIZE_HDR            0x8E    /* Message-Size         */
76 #define MM_PRIORITY_HDR         0x8F    /* Priority             */
77 #define MM_RREPLY_HDR           0x90    /* Read-Reply           */
78 #define MM_RALLOWED_HDR         0x91    /* Report-Allowed       */
79 #define MM_RSTATUS_HDR          0x92    /* Response-Status      */
80 #define MM_RTEXT_HDR            0x93    /* Response-Text        */
81 #define MM_SVISIBILITY_HDR      0x94    /* Sender-Visibility    */
82 #define MM_STATUS_HDR           0x95    /* Status               */
83 #define MM_SUBJECT_HDR          0x96    /* Subject              */
84 #define MM_TO_HDR               0x97    /* To                   */
85 #define MM_TID_HDR              0x98    /* Transaction-Id       */
86
87 /*
88  * Initialize the protocol and registered fields
89  */
90 static int proto_mmse = -1;
91
92 static int hf_mmse_message_type         = -1;
93 static int hf_mmse_transaction_id       = -1;
94 static int hf_mmse_mms_version          = -1;
95 static int hf_mmse_bcc                  = -1;
96 static int hf_mmse_cc                   = -1;
97 static int hf_mmse_content_location     = -1;
98 static int hf_mmse_date                 = -1;
99 static int hf_mmse_delivery_report      = -1;
100 static int hf_mmse_delivery_time_abs    = -1;
101 static int hf_mmse_delivery_time_rel    = -1;
102 static int hf_mmse_expiry_abs           = -1;
103 static int hf_mmse_expiry_rel           = -1;
104 static int hf_mmse_from                 = -1;
105 static int hf_mmse_message_class_id     = -1;
106 static int hf_mmse_message_class_str    = -1;
107 static int hf_mmse_message_id           = -1;
108 static int hf_mmse_message_size         = -1;
109 static int hf_mmse_priority             = -1;
110 static int hf_mmse_read_reply           = -1;
111 static int hf_mmse_report_allowed       = -1;
112 static int hf_mmse_response_status      = -1;
113 static int hf_mmse_response_text        = -1;
114 static int hf_mmse_sender_visibility    = -1;
115 static int hf_mmse_status               = -1;
116 static int hf_mmse_subject              = -1;
117 static int hf_mmse_to                   = -1;
118 static int hf_mmse_content_type         = -1;
119 static int hf_mmse_ffheader             = -1;
120
121 /*
122  * Initialize the subtree pointers
123  */
124 static gint ett_mmse = -1;
125
126 /*
127  * Valuestrings for header contents
128  */
129 static const value_string vals_message_type[] = {
130     { 0x80, "m-send-req" },
131     { 0x81, "m-send-conf" },
132     { 0x82, "m-notification-ind" },
133     { 0x83, "m-notifyresp-ind" },
134     { 0x84, "m-retrieve-conf" },
135     { 0x85, "m-acknowledge-ind" },
136     { 0x86, "m-delivery-ind" },
137     { 0x00, NULL },
138 };
139
140 static const value_string vals_yes_no[] = {
141     { 0x80, "Yes" },
142     { 0x81, "No" },
143     { 0x00, NULL },
144 };
145
146 static const value_string vals_message_class[] = {
147     { 0x80, "Personal" },
148     { 0x81, "Advertisement" },
149     { 0x82, "Informational" },
150     { 0x82, "Auto" },
151     { 0x00, NULL },
152 };
153
154 static const value_string vals_priority[] = {
155     { 0x80, "Low" },
156     { 0x81, "Normal" },
157     { 0x81, "High" },
158     { 0x00, NULL },
159 };
160
161 static const value_string vals_response_status[] = {
162     { 0x80, "Ok" },
163     { 0x81, "Unspecified" },
164     { 0x82, "Service denied" },
165     { 0x83, "Message format corrupt" },
166     { 0x84, "sending address unresolved" },
167     { 0x85, "message not found" },
168     { 0x86, "Network problem" },
169     { 0x87, "Content not accepted" },
170     { 0x88, "Unsupported message" },
171     { 0x00, NULL },
172 };
173
174 static const value_string vals_sender_visibility[] = {
175     { 0x80, "Hide" },
176     { 0x81, "Show" },
177     { 0x00, NULL },
178 };
179
180 static const value_string vals_status[] = {
181     { 0x80, "Expired" },
182     { 0x81, "Retrieved" },
183     { 0x82, "Rejected" },
184     { 0x82, "Deferred" },
185     { 0x82, "Unrecognized" },
186     { 0x00, NULL },
187 };
188
189 /*!
190  * Decodes a Text-string from the protocol data
191  *      Text-string = [Quote] *TEXT End-of-string
192  *      Quote       = <Octet 127>
193  *      End-of-string = <Octet 0>
194  *
195  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
196  *
197  * \param       tvb     The buffer with PDU-data
198  * \param       offset  Offset within that buffer
199  * \param       strval  String buffer to receive the text, reserve memory!
200  *
201  * \return              The length in bytes of the entire field
202  */
203 static guint
204 get_text_string(tvbuff_t *tvb, guint offset, char *strval)
205 {
206     guint        len;
207
208     len = tvb_strsize(tvb, offset);
209     if (tvb_get_guint8(tvb, offset) == MM_QUOTE)
210         tvb_memcpy(tvb, strval, offset + 1, len - 1);
211     else
212         tvb_memcpy(tvb, strval, offset, len);
213     return len;
214 }
215
216 /*!
217  * Decodes a Value-length from the protocol data.
218  *      Value-length = Short-length | (Length-quote Length)
219  *      Short-length = <Any octet 0-30>
220  *      Length-quote = <Octet 31>
221  *      Length       = Uintvar-integer
222  *
223  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
224  *
225  * \param       tvb             The buffer with PDU-data
226  * \param       offset          Offset within that buffer
227  * \param       byte_count      Returns the length in bytes of
228  *                              the "Value-length" field.
229  *
230  * \return                      The actual value of "Value-length"
231  */
232 static guint
233 get_value_length(tvbuff_t *tvb, guint offset, guint *byte_count)
234 {
235     guint        field;
236
237     field = tvb_get_guint8(tvb, offset++);
238     if (field < 31)
239         *byte_count = 1;
240     else {                      /* Must be 31 so, Uintvar follows       */
241         field = tvb_get_guintvar(tvb, offset, byte_count);
242         (*byte_count)++;
243     }
244     return field;
245 }
246
247 /*!
248  * Decodes an Encoded-string-value from the protocol data
249  *      Encoded-string-value = Text-string | Value-length Char-set Text-string
250  *
251  * \param       tvb     The buffer with PDU-data
252  * \param       offset  Offset within that buffer
253  * \param       strval  String buffer to receive the text, reserve memory!
254  *
255  * \return              The length in bytes of the entire field
256  */
257 static guint
258 get_encoded_strval(tvbuff_t *tvb, guint offset, char *strval)
259 {
260     guint        field;
261     guint        length;
262     guint        count;
263
264     field = tvb_get_guint8(tvb, offset);
265
266     if (field < 32) {
267         length = get_value_length(tvb, offset, &count);
268         /* \todo        Something with "Char-set", skip for now */
269         tvb_memcpy(tvb, strval, offset + count + 1, length - 1);
270         strval[length - 1] = '\0';      /* Just to make sure    */
271         return offset + count + length;
272     } else
273         return get_text_string(tvb, offset, strval);
274 }
275
276 /*!
277  * Decodes a Long-integer from the protocol data
278  *      Long-integer = Short-length Multi-octet-integer
279  *      Short-length = <Any octet 0-30>
280  *      Multi-octet-integer = 1*30OCTET
281  *
282  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
283  *
284  * \param       tvb             The buffer with PDU-data
285  * \param       offset          Offset within that buffer
286  * \param       byte_count      Returns the length in bytes of the field
287  *
288  * \return                      The value of the Long-integer
289  *
290  * \note        A maximum of 4-byte integers will be handled.
291  */
292 static guint
293 get_long_integer(tvbuff_t *tvb, guint offset, guint *byte_count)
294 {
295     guint        val;
296
297     *byte_count = tvb_get_guint8(tvb, offset++);
298     switch (*byte_count) {
299         case 1:
300             val = tvb_get_guint8(tvb, offset);
301             break;
302         case 2:
303             val = tvb_get_ntohs(tvb, offset);
304             break;
305         case 3:
306             val = tvb_get_ntoh24(tvb, offset);
307             break;
308         case 4:
309             val = tvb_get_ntohl(tvb, offset);
310             break;
311         default:
312             val = 0;
313             break;
314     }
315     (*byte_count)++;
316     return val;
317 }
318
319 /* Code to actually dissect the packets */
320 static gboolean
321 dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
322 {
323     guint8       pdut;
324     guint        offset;
325     guint8       field = 0;
326     char         strval[BUFSIZ];
327     guint        length;
328     guint        count;
329
330     /* Set up structures needed to add the protocol subtree and manage it */
331     proto_item *ti;
332     proto_tree *mmse_tree;
333     /*
334      * Check if data makes sense for it to be dissected as MMSE:  Message-type
335      * field must make sense and followed by Transaction-Id header
336      */
337     if (tvb_get_guint8(tvb, 0) != MM_MTYPE_HDR)
338         return FALSE;
339     pdut = tvb_get_guint8(tvb, 1);
340     if (match_strval(pdut, vals_message_type) == NULL)
341         return FALSE;
342     if (tvb_get_guint8(tvb, 2) != MM_TID_HDR)
343         return FALSE;
344
345     /* Make entries in Protocol column and Info column on summary display */
346     if (check_col(pinfo->fd, COL_PROTOCOL))
347         col_set_str(pinfo->fd, COL_PROTOCOL, "mmse");
348
349     if (check_col(pinfo->fd, COL_INFO)) {
350         col_clear(pinfo->fd, COL_INFO);
351         col_add_fstr(pinfo->fd, COL_INFO, "MMS %s",
352                      match_strval(pdut, vals_message_type));
353     }
354
355     /* In the interest of speed, if "tree" is NULL, don't do any work not
356      * necessary to generate protocol tree items.
357      */
358     if (tree) {
359         offset = 2;                     /* Skip Message-Type    */
360
361         /* create display subtree for the protocol */
362         ti = proto_tree_add_item(tree, proto_mmse, tvb, 0,
363                                  tvb_length(tvb), FALSE);
364         mmse_tree = proto_item_add_subtree(ti, ett_mmse);
365
366         /* Report PDU-type      */
367         proto_tree_add_uint(mmse_tree, hf_mmse_message_type, tvb, 0, 2, pdut);
368         /*
369          * Cycle through MMS-headers
370          */
371         while ((offset < tvb_length(tvb)) &&
372                (field = tvb_get_guint8(tvb, offset++)) != MM_CTYPE_HDR)
373         {
374             switch (field)
375             {
376                 case MM_TID_HDR:                /* Text-string  */
377                     length = get_text_string(tvb, offset, strval);
378                     proto_tree_add_string(mmse_tree, hf_mmse_transaction_id,
379                                           tvb, offset - 1, length + 1,strval);
380                     offset += length;
381                     break;
382                 case MM_VERSION_HDR:            /* nibble-Major/nibble-minor*/
383                     field = tvb_get_guint8(tvb, offset++);
384                     {
385                         guint8   major, minor;
386
387                         major = (field & 0x70) >> 4;
388                         minor = field & 0x0F;
389                         if (minor == 0x0F)
390                             sprintf(strval, "%d", major);
391                         else
392                             sprintf(strval, "%d.%d", major, minor);
393                     }
394                     proto_tree_add_string(mmse_tree, hf_mmse_mms_version, tvb,
395                                           offset - 2, 2, strval);
396                     break;
397                 case MM_BCC_HDR:                /* Encoded-string-value */
398                     length = get_encoded_strval(tvb, offset, strval);
399                     proto_tree_add_string(mmse_tree, hf_mmse_bcc, tvb,
400                                         offset - 1, length + 1, strval);
401                     offset += length;
402                     break;
403                 case MM_CC_HDR:                 /* Encoded-string-value */
404                     length = get_encoded_strval(tvb, offset, strval);
405                     proto_tree_add_string(mmse_tree, hf_mmse_cc, tvb,
406                                         offset - 1, length + 1, strval);
407                     offset += length;
408                     break;
409                 case MM_CLOCATION_HDR:          /* Uri-value            */
410                     length = get_text_string(tvb, offset, strval);
411                     proto_tree_add_string(mmse_tree, hf_mmse_content_location,
412                                           tvb, offset - 1, length + 1,strval);
413                     offset += length;
414                     break;
415                 case MM_DATE_HDR:               /* Long-integer         */
416                     {
417                         guint            tval;
418                         nstime_t         tmptime;
419
420                         tval = get_long_integer(tvb, offset, &count);
421                         tmptime.secs = tval;
422                         tmptime.nsecs = 0;
423                         proto_tree_add_time(mmse_tree, hf_mmse_date, tvb,
424                                             offset - 1, count + 1, &tmptime);
425                     }
426                     offset += count;
427                     break;
428                 case MM_DREPORT_HDR:            /* Yes|No               */
429                     field = tvb_get_guint8(tvb, offset++);
430                     proto_tree_add_uint(mmse_tree, hf_mmse_delivery_report, tvb,
431                                         offset - 2, 2, field);
432                     break;
433                 case MM_DTIME_HDR:
434                     /*
435                      * Value-length(Absolute-token Date-value|
436                      *              Relative-token Delta-seconds-value)
437                      */
438                     length = get_value_length(tvb, offset, &count);
439                     field = tvb_get_guint8(tvb, offset + count);
440                     {
441                         guint            tval;
442                         nstime_t         tmptime;
443                         guint            cnt;
444
445                         tval =  get_long_integer(tvb, offset + count, &cnt);
446                         tmptime.secs = tval;
447                         tmptime.nsecs = 0;
448                         if (field == 0x80)
449                             proto_tree_add_time(mmse_tree,
450                                                 hf_mmse_delivery_time_abs,
451                                                 tvb, offset - 1,
452                                                 length + count + 1, &tmptime);
453                         else
454                             proto_tree_add_time(mmse_tree,
455                                                 hf_mmse_delivery_time_rel,
456                                                 tvb, offset - 1,
457                                                 length + count + 1, &tmptime);
458                     }
459                     offset += length + count;
460                     break;
461                 case MM_EXPIRY_HDR:
462                     /*
463                      * Value-length(Absolute-token Date-value|
464                      *              Relative-token Delta-seconds-value)
465                      */
466                     length = get_value_length(tvb, offset, &count);
467                     field = tvb_get_guint8(tvb, offset + count);
468                     {
469                         guint            tval;
470                         nstime_t         tmptime;
471                         guint            cnt;
472
473                         tval = get_long_integer(tvb, offset + count, &cnt);
474                         tmptime.secs = tval;
475                         tmptime.nsecs = 0;
476                         if (field == 0x80)
477                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_abs,
478                                                 tvb, offset - 1,
479                                                 length + count + 1, &tmptime);
480                         else
481                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_rel,
482                                                 tvb, offset - 1,
483                                                 length + count + 1, &tmptime);
484                     }
485                     offset += length + count;
486                     break;
487                 case MM_FROM_HDR:
488                     /*
489                      * Value-length(Address-present-token Encoded-string-value
490                      *              |Insert-address-token)
491                      */
492                     length = get_value_length(tvb, offset, &count);
493                     field = tvb_get_guint8(tvb, offset + count);
494                     if (field == 0x81) {
495                         strcpy(strval, "<insert address>");
496                     } else {
497                         (void) get_encoded_strval(tvb, offset + count + 1,
498                                                   strval);
499                     }
500                     proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
501                                           offset-1, length + 2, strval);
502                     offset += length + 1;
503                     break;
504                 case MM_MCLASS_HDR:
505                     /*
506                      * Class-identifier|Text-string
507                      */
508                     field = tvb_get_guint8(tvb, offset);
509                     if (field & 0x80) {
510                         offset++;
511                         proto_tree_add_uint(mmse_tree,
512                                             hf_mmse_message_class_id,
513                                             tvb, offset - 2, 2, field);
514                     } else {
515                         length = get_text_string(tvb, offset, strval);
516                         proto_tree_add_string(mmse_tree,
517                                               hf_mmse_message_class_str,
518                                               tvb, offset - 1, length + 1,
519                                               strval);
520                         offset += length;
521                     }
522                     break;
523                 case MM_MID_HDR:                /* Text-string          */
524                     length = get_text_string(tvb, offset, strval);
525                     proto_tree_add_string(mmse_tree, hf_mmse_message_id, tvb,
526                                           offset - 1, length + 1, strval);
527                     offset += length;
528                     break;
529                 case MM_MSIZE_HDR:              /* Long-integer         */
530                     length = get_long_integer(tvb, offset, &count);
531                     proto_tree_add_uint(mmse_tree, hf_mmse_message_size, tvb,
532                                         offset - 1, count + 1, length);
533                     offset += count;
534                     break;
535                 case MM_PRIORITY_HDR:           /* Low|Normal|High      */
536                     field = tvb_get_guint8(tvb, offset++);
537                     proto_tree_add_uint(mmse_tree, hf_mmse_priority, tvb,
538                                         offset - 2, 2, field);
539                     break;
540                 case MM_RREPLY_HDR:             /* Yes|No               */
541                     field = tvb_get_guint8(tvb, offset++);
542                     proto_tree_add_uint(mmse_tree, hf_mmse_read_reply, tvb,
543                                         offset - 2, 2, field);
544                     break;
545                 case MM_RALLOWED_HDR:           /* Yes|No               */
546                     field = tvb_get_guint8(tvb, offset++);
547                     proto_tree_add_uint(mmse_tree, hf_mmse_report_allowed, tvb,
548                                         offset - 2, 2, field);
549                     break;
550                 case MM_RSTATUS_HDR:
551                     field = tvb_get_guint8(tvb, offset++);
552                     proto_tree_add_uint(mmse_tree, hf_mmse_response_status, tvb,
553                                         offset - 2, 2, field);
554                     break;
555                 case MM_RTEXT_HDR:              /* Encoded-string-value */
556                     length = get_encoded_strval(tvb, offset, strval);
557                     proto_tree_add_string(mmse_tree, hf_mmse_response_text, tvb,
558                                         offset - 1, length + 1, strval);
559                     offset += length;
560                     break;
561                 case MM_SVISIBILITY_HDR:        /* Hide|Show            */
562                     field = tvb_get_guint8(tvb, offset++);
563                     proto_tree_add_uint(mmse_tree,hf_mmse_sender_visibility,
564                                         tvb, offset - 2, 2, field);
565                     break;
566                 case MM_STATUS_HDR:
567                     field = tvb_get_guint8(tvb, offset++);
568                     proto_tree_add_uint(mmse_tree, hf_mmse_status, tvb,
569                                         offset - 2, 2, field);
570                     break;
571                 case MM_SUBJECT_HDR:            /* Encoded-string-value */
572                     length = get_encoded_strval(tvb, offset, strval);
573                     proto_tree_add_string(mmse_tree, hf_mmse_subject, tvb,
574                                         offset - 1, length + 1, strval);
575                     offset += length;
576                     break;
577                 case MM_TO_HDR:                 /* Encoded-string-value */
578                     length = get_encoded_strval(tvb, offset, strval);
579                     proto_tree_add_string(mmse_tree, hf_mmse_to, tvb,
580                                         offset - 1, length + 1, strval);
581                     offset += length;
582                     break;
583                 default:
584                     if (field & 0x80) {
585                         fprintf(stderr,
586                                 "MMSE - Unknown field encountered (0x%02x)\n",
587                                 field);
588                     } else {
589                         guint    length2;
590                         char     strval2[BUFSIZ];
591
592                         --offset;
593                         length = get_text_string(tvb, offset, strval);
594                         length2= get_text_string(tvb, offset+length, strval2);
595
596                         proto_tree_add_string_format(mmse_tree,
597                                                      hf_mmse_ffheader,
598                                                      tvb, offset,
599                                                      length + length2, NULL,
600                                                      "%s : %s",strval,strval2);
601                         offset += length + length2;
602                     }
603                     break;
604             }
605         }
606         if (field == MM_CTYPE_HDR) {
607             /*
608              * \todo
609              * Eeehh, we're now actually back to good old WSP content-type
610              * encoding for multipart/related and multipart/mixed MIME-types.
611              * I'm not gonna do that work here again so maybe it's wise to
612              * share some more code with packet-wsp.c in the near future?
613              * Leave it as "Data" for now as it is the end of the PDU...
614              */
615             proto_tree_add_item(mmse_tree, hf_mmse_content_type, tvb,
616                                 offset - 1,
617                                 tvb_length_remaining(tvb, offset - 1), FALSE);
618             return TRUE;
619         }
620     }
621     return TRUE;
622
623     /* If this protocol has a sub-dissector call it here, see section 1.8 */
624 }
625
626
627 /* Register the protocol with Ethereal */
628
629 /* this format is required because a script is used to build the C function
630  * that calls all the protocol registration.
631  */
632 void
633 proto_register_mmse(void)
634 {
635     /* Setup list of header fields  See Section 1.6.1 for details       */
636     static hf_register_info hf[] = {
637         {   &hf_mmse_message_type,
638             {   "Message-Type", "mmse.message_length",
639                 FT_UINT8, BASE_HEX, VALS(vals_message_type), 0x00,
640                 "Specifies the transaction type. Effectively defines PDU.",
641                 HFILL
642             }
643         },
644         {   &hf_mmse_transaction_id,
645             {   "Transaction-ID", "mmse.transaction_id",
646                 FT_STRING, BASE_NONE, NULL, 0x00,
647                 "A unique identifier for this transaction. "
648                 "Identifies request and corresponding response only.",
649                 HFILL
650             }
651         },
652         {   &hf_mmse_mms_version,
653             {   "MMS-Version", "mmse.mms_version",
654                 FT_STRING, BASE_NONE, NULL, 0x00,
655                 "Version of the protocol used.",
656                 HFILL
657             }
658         },
659         {   &hf_mmse_bcc,
660             {   "Bcc", "mmse.bcc",
661                 FT_STRING, BASE_NONE, NULL, 0x00,
662                 "Blind carbon copy.",
663                 HFILL
664             }
665         },
666         {   &hf_mmse_cc,
667             {   "Bcc", "mmse.bcc",
668                 FT_STRING, BASE_NONE, NULL, 0x00,
669                 "Carbon copy.",
670                 HFILL
671             }
672         },
673         {   &hf_mmse_content_location,
674             {   "Content-Location", "mmse.content_location",
675                 FT_STRING, BASE_NONE, NULL, 0x00,
676                 "Defines the location of the message.",
677                 HFILL
678             }
679         },
680         {   &hf_mmse_date,
681             {   "Date", "mmse.date",
682                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
683                 "Arrival timestamp of the message or sending timestamp.",
684                 HFILL
685             }
686         },
687         {   &hf_mmse_delivery_report,
688             {   "Delivery-Report", "mmse.delivery_report",
689                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
690                 "Whether a report of message delivery is wanted or not.",
691                 HFILL
692             }
693         },
694         {   &hf_mmse_delivery_time_abs,
695             {   "Delivery-Time", "mmse.delivery_time.abs",
696                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
697                 "The time at which message delivery is desired.",
698                 HFILL
699             }
700         },
701         {   &hf_mmse_delivery_time_rel,
702             {   "Delivery-Time", "mmse.delivery_time.rel",
703                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
704                 "The desired message delivery delay.",
705                 HFILL
706             }
707         },
708         {   &hf_mmse_expiry_abs,
709             {   "Expiry", "mmse.expiry.abs",
710                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
711                 "Time when message expires and need not be delivered anymore.",
712                 HFILL
713             }
714         },
715         {   &hf_mmse_expiry_rel,
716             {   "Expiry", "mmse.expiry.rel",
717                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
718                 "Delay before message expires and need not be delivered anymore.",
719                 HFILL
720             }
721         },
722         {   &hf_mmse_from,
723             {   "From", "mmse.from",
724                 FT_STRING, BASE_NONE, NULL, 0x00,
725                 "Address of the message sender.",
726                 HFILL
727             }
728         },
729         {   &hf_mmse_message_class_id,
730             {   "Message-Class", "mmse.message_class.id",
731                 FT_UINT8, BASE_HEX, VALS(vals_message_class), 0x00,
732                 "Of what category is the message.",
733                 HFILL
734             }
735         },
736         {   &hf_mmse_message_class_str,
737             {   "Message-Class", "mmse.message_class.str",
738                 FT_STRING, BASE_NONE, NULL, 0x00,
739                 "Of what category is the message.",
740                 HFILL
741             }
742         },
743         {   &hf_mmse_message_id,
744             {   "Message-Id", "mmse.message_id",
745                 FT_STRING, BASE_NONE, NULL, 0x00,
746                 "Unique identification of the message.",
747                 HFILL
748             }
749         },
750         {   &hf_mmse_message_size,
751             {   "Message-Size", "mmse.message_size",
752                 FT_UINT32, BASE_DEC, NULL, 0x00,
753                 "The size of the message in octets.",
754                 HFILL
755             }
756         },
757         {   &hf_mmse_priority,
758             {   "Priority", "mmse.priority",
759                 FT_UINT8, BASE_HEX, VALS(vals_priority), 0x00,
760                 "Priority of the message.",
761                 HFILL
762             }
763         },
764         {   &hf_mmse_read_reply,
765             {   "Read-Reply", "mmse.read_reply",
766                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
767                 "Whether a read report from every recipient is wanted.",
768                 HFILL
769             }
770         },
771         {   &hf_mmse_report_allowed,
772             {   "Report-Allowed", "mmse.report_allowed",
773                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
774                 "Sending of delivery report allowed or not.",
775                 HFILL
776             }
777         },
778         {   &hf_mmse_response_status,
779             {   "Response-Status", "mmse.response_status",
780                 FT_UINT8, BASE_HEX, VALS(vals_response_status), 0x00,
781                 "MMS-specific result of a message submission or retrieval.",
782                 HFILL
783             }
784         },
785         {   &hf_mmse_response_text,
786             {   "Response-Text", "mmse.response_text",
787                 FT_STRING, BASE_NONE, NULL, 0x00,
788                 "Additional information on MMS-specific result.",
789                 HFILL
790             }
791         },
792         {   &hf_mmse_sender_visibility,
793             {   "Sender-Visibility", "mmse.sender_visibility",
794                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
795                 "Disclose sender identity to receiver or not.",
796                 HFILL
797             }
798         },
799         {   &hf_mmse_status,
800             {   "Status", "mmse.status",
801                 FT_UINT8, BASE_HEX, VALS(vals_status), 0x00,
802                 "Current status of the message.",
803                 HFILL
804             }
805         },
806         {   &hf_mmse_subject,
807             {   "Subject", "mmse.subject",
808                 FT_STRING, BASE_NONE, NULL, 0x00,
809                 "Subject of the message.",
810                 HFILL
811             }
812         },
813         {   &hf_mmse_to,
814             {   "To", "mmse.to",
815                 FT_STRING, BASE_NONE, NULL, 0x00,
816                 "Recipient(s) of the message.",
817                 HFILL
818             }
819         },
820         {   &hf_mmse_content_type,
821             {   "Data", "mmse.content_type",
822                 FT_NONE, BASE_NONE, NULL, 0x00,
823                 "Media content of the message.",
824                 HFILL
825             }
826         },
827         {   &hf_mmse_ffheader,
828             {   "Free format (not encoded) header", "mmse.ffheader",
829                 FT_STRING, BASE_NONE, NULL, 0x00,
830                 "Application header without corresponding encoding.",
831                 HFILL
832             }
833         },
834     };
835     /* Setup protocol subtree array */
836     static gint *ett[] = {
837         &ett_mmse,
838     };
839
840     /* Register the protocol name and description */
841     proto_mmse = proto_register_protocol("MMS Message Encapsulation",
842                                          "WAP-MMSE", "mmse");
843
844     /* Required function calls to register header fields and subtrees used */
845     proto_register_field_array(proto_mmse, hf, array_length(hf));
846     proto_register_subtree_array(ett, array_length(ett));
847 }
848
849 /* If this dissector uses sub-dissector registration add registration routine.
850  * This format is required because a script is used to find these routines and
851  * create the code that calls these routines.
852  */
853 void
854 proto_reg_handoff_mmse(void)
855 {
856     heur_dissector_add("wsp", dissect_mmse, proto_mmse);
857     /*!
858      * \todo
859      * Mmmmm, actually, it should register itself on the "wsp.content_type"
860      * protocol field. Especially when IANA finally registers the type
861      * 'application/wap.vnd.mms-message'. The wsp-dissector should then
862      * ofcourse be modified to cater for such subdissectors...
863      */
864     /*
865      * \todo
866      * The bearer could also be http (through the same content-type field).
867      * Same modifications would apply there.
868      */
869 }