The "next_submsg" argument passed to "get_bitmap()" is an offset within
[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  * Copyright 2004, Olivier Biot
5  *
6  * $Id: packet-mmse.c,v 1.33 2004/04/13 22:07:34 obiot Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 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  * Dissector of an encoded Multimedia message PDU, as defined by the WAPForum
28  * (http://www.wapforum.org) in "WAP-209-MMSEncapsulation-20020105-a".
29  * Subsequent releases of MMS are in control of the Open Mobile Alliance (OMA):
30  * Dissection of MMS 1.1 as in OMA-MMS-ENC-v1.1 (not finished yet).
31  * Dissection of MMS 1.2 as in OMA-MMS-ENC-v1.2 (not finished yet).
32  */
33
34 /* This file has been edited with 8-space tabs and 4-space indentation */
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include <glib.h>
45
46 #include <epan/packet.h>
47 #include "packet-wap.h"
48 #include "packet-wsp.h"
49 /* #include "packet-mmse.h" */          /* We autoregister      */
50
51 #define MM_QUOTE                0x7F    /* Quoted string        */
52
53 #define MMS_CONTENT_TYPE        0x3E    /* WINA-value for mms-message   */
54
55 /* General-purpose debug logger.
56  * Requires double parentheses because of variable arguments of printf().
57  *
58  * Enable debug logging for MMSE by defining AM_CFLAGS
59  * so that it contains "-DDEBUG_mmse"
60  */
61 #ifdef DEBUG_mmse
62 #define DebugLog(x) \
63         printf("%s:%u: ", __FILE__, __LINE__); \
64         printf x; \
65         fflush(stdout)
66 #else
67 #define DebugLog(x) ;
68 #endif
69
70
71 /*
72  * Forward declarations
73  */
74 static void dissect_mmse_standalone(tvbuff_t *, packet_info *, proto_tree *);
75 static void dissect_mmse_encapsulated(tvbuff_t *, packet_info *, proto_tree *);
76 static void dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
77         guint8 pdut, char *message_type);
78
79 /*
80  * Header field values
81  */
82 /* MMS 1.0 */
83 #define MM_BCC_HDR              0x81    /* Bcc                  */
84 #define MM_CC_HDR               0x82    /* Cc                   */
85 #define MM_CLOCATION_HDR        0x83    /* X-Mms-Content-Location       */
86 #define MM_CTYPE_HDR            0x84    /* Content-Type         */
87 #define MM_DATE_HDR             0x85    /* Date                         */
88 #define MM_DREPORT_HDR          0x86    /* X-Mms-Delivery-Report        */
89 #define MM_DTIME_HDR            0x87    /* X-Mms-Delivery-Time          */
90 #define MM_EXPIRY_HDR           0x88    /* X-Mms-Expiry                 */
91 #define MM_FROM_HDR             0x89    /* From                         */
92 #define MM_MCLASS_HDR           0x8A    /* X-Mms-Message-Class          */
93 #define MM_MID_HDR              0x8B    /* Message-ID                   */
94 #define MM_MTYPE_HDR            0x8C    /* X-Mms-Message-Type           */
95 #define MM_VERSION_HDR          0x8D    /* X-Mms-MMS-Version            */
96 #define MM_MSIZE_HDR            0x8E    /* X-Mms-Message-Size           */
97 #define MM_PRIORITY_HDR         0x8F    /* X-Mms-Priority               */
98 #define MM_RREPLY_HDR           0x90    /* X-Mms-Read-Reply             */
99 #define MM_RALLOWED_HDR         0x91    /* X-Mms-Report-Allowed         */
100 #define MM_RSTATUS_HDR          0x92    /* X-Mms-Response-Status        */
101 #define MM_RTEXT_HDR            0x93    /* X-Mms-Response-Text          */
102 #define MM_SVISIBILITY_HDR      0x94    /* X-Mms-Sender-Visibility      */
103 #define MM_STATUS_HDR           0x95    /* X-Mms-Status                 */
104 #define MM_SUBJECT_HDR          0x96    /* Subject                      */
105 #define MM_TO_HDR               0x97    /* To                           */
106 #define MM_TID_HDR              0x98    /* X-Mms-Transaction-Id         */
107 /* MMS 1.1 */
108 #define MM_RETRIEVE_STATUS_HDR  0x99    /* X-Mms-Retrieve-Status        */
109 #define MM_RETRIEVE_TEXT_HDR    0x9A    /* X-Mms-Retrieve-Text          */
110 #define MM_READ_STATUS_HDR      0x9B    /* X-Mms-Read-Status            */
111 #define MM_REPLY_CHARGING_HDR   0x9C    /* X-Mms-Reply-Charging         */
112 #define MM_REPLY_CHARGING_DEADLINE_HDR  \
113                                 0x9D    /* X-Mms-Reply-Charging-Deadline*/
114 #define MM_REPLY_CHARGING_ID_HDR        \
115                                 0x9E    /* X-Mms-Reply-Charging-ID      */
116 #define MM_REPLY_CHARGING_SIZE_HDR      \
117                                 0x9F    /* X-Mms-Reply-Charging-Size    */
118 #define MM_PREV_SENT_BY_HDR     0xA0    /* X-Mms-Previously-Sent-By     */
119 #define MM_PREV_SENT_DATE_HDR   0xA1    /* X-Mms-Previously-Sent-Date   */
120 /* MMS 1.2 */
121 #define MM_STORE_HDR            0xA2    /* X-Mms-Store                  */
122 #define MM_MM_STATE_HDR         0xA3    /* X-Mms-MM-State               */
123 #define MM_MM_FLAGS_HDR         0xA4    /* X-Mms-MM-Flags               */
124 #define MM_STORE_STATUS_HDR     0xA5    /* X-Mms-Store-Status           */
125 #define MM_STORE_STATUS_TEXT_HDR        \
126                                 0xA6    /* X-Mms-Store-Status-Text      */
127 #define MM_STORED_HDR           0xA7    /* X-Mms-Stored                 */
128 #define MM_ATTRIBUTES_HDR       0xA8    /* X-Mms-Attributes             */
129 #define MM_TOTALS_HDR           0xA9    /* X-Mms-Totals                 */
130 #define MM_MBOX_TOTALS_HDR      0xAA    /* X-Mms-Mbox-Totals            */
131 #define MM_QUOTAS_HDR           0xAB    /* X-Mms-Quotas                 */
132 #define MM_MBOX_QUOTAS_HDR      0xAC    /* X-Mms-Mbox-Quotas            */
133 #define MM_MBOX_MSG_COUNT_HDR   0xAD    /* X-Mms-Message-Count          */
134 #define MM_CONTENT_HDR          0xAE    /* Content                      */
135 #define MM_START_HDR            0xAF    /* X-Mms-Start                  */
136 #define MM_ADDITIONAL_HDR       0xB0    /* Additional-headers           */
137 #define MM_DISTRIBUION_IND_HDR  0xB1    /* X-Mms-Distribution-Indcator  */
138 #define MM_ELEMENT_DESCR_HDR    0xB2    /* X-Mms-Element-Descriptor     */
139 #define MM_LIMIT_HDR            0xB3    /* X-Mms-Limit                  */
140
141 static const value_string vals_mm_header_names[] = {
142         /* MMS 1.0 */
143         { MM_BCC_HDR,                   "Bcc" },
144         { MM_CC_HDR,                    "Cc" },
145         { MM_CLOCATION_HDR,             "X-Mms-Content-Location" },
146         { MM_CTYPE_HDR,                 "X-Mms-Content-Type" },
147         { MM_DATE_HDR,                  "Date" },
148         { MM_DREPORT_HDR,               "X-Mms-Delivery-Report" },
149         { MM_DTIME_HDR,                 "X-Mms-Delivery-Time" },
150         { MM_EXPIRY_HDR,                "X-Mms-Expiry" },
151         { MM_FROM_HDR,                  "From" },
152         { MM_MCLASS_HDR,                "X-Mms-Message-Class" },
153         { MM_MID_HDR,                   "Message-ID" },
154         { MM_MTYPE_HDR,                 "X-Mms-Message-Type" },
155         { MM_VERSION_HDR,               "X-Mms-MMS-Version" },
156         { MM_MSIZE_HDR,                 "X-Mms-Message-Size" },
157         { MM_PRIORITY_HDR,              "X-Mms-Priority" },
158         { MM_RREPLY_HDR,                "X-Mms-Read-Reply" },
159         { MM_RALLOWED_HDR,              "X-Mms-Report-Allowed" },
160         { MM_RSTATUS_HDR,               "X-Mms-Response-Status" },
161         { MM_RTEXT_HDR,                 "X-Mms-Response-Text" },
162         { MM_SVISIBILITY_HDR,           "X-Mms-Sender-Visibility" },
163         { MM_STATUS_HDR,                "X-Mms-Status" },
164         { MM_SUBJECT_HDR,               "Subject" },
165         { MM_TO_HDR,                    "To" },
166         { MM_TID_HDR,                   "X-Mms-Transaction-Id" },
167         /* MMS 1.1 */
168         { MM_RETRIEVE_STATUS_HDR,       "X-Mms-Retrieve-Status" },
169         { MM_RETRIEVE_TEXT_HDR,         "X-Mms-Retrieve-Text" },
170         { MM_READ_STATUS_HDR,           "X-Mms-Read-Status" },
171         { MM_REPLY_CHARGING_HDR,        "X-Mms-Reply-Charging" },
172         { MM_REPLY_CHARGING_DEADLINE_HDR,
173                                         "X-Mms-Reply-Charging-Deadline" },
174         { MM_REPLY_CHARGING_ID_HDR,     "X-Mms-Reply-Charging-ID" },
175         { MM_REPLY_CHARGING_SIZE_HDR,   "X-Mms-Reply-Charging-Size" },
176         { MM_PREV_SENT_BY_HDR,          "X-Mms-Previously-Sent-By" },
177         { MM_PREV_SENT_DATE_HDR,        "X-Mms-Previously-Sent-Date" },
178         /* MMS 1.2 */
179         { MM_STORE_HDR,                 "X-Mms-Store" },
180         { MM_MM_STATE_HDR,              "X-Mms-MM-State " },
181         { MM_MM_FLAGS_HDR,              "X-Mms-MM-Flags " },
182         { MM_STORE_STATUS_HDR,          "X-Mms-Store-Status" },
183         { MM_STORE_STATUS_TEXT_HDR,     "X-Mms-Store-Status-Text" },
184         { MM_STORED_HDR,                "X-Mms-Stored" },
185         { MM_ATTRIBUTES_HDR,            "X-Mms-Attributes" },
186         { MM_TOTALS_HDR,                "X-Mms-Totals" },
187         { MM_MBOX_TOTALS_HDR,           "X-Mms-Mbox-Totals" },
188         { MM_QUOTAS_HDR,                "X-Mms-Quotas" },
189         { MM_MBOX_QUOTAS_HDR,           "X-Mms-Mbox-Quotas" },
190         { MM_MBOX_MSG_COUNT_HDR,        "X-Mms-Message-Count" },
191         { MM_CONTENT_HDR,               "Content" },
192         { MM_START_HDR,                 "X-Mms-Start" },
193         { MM_ADDITIONAL_HDR,            "Additional-headers" },
194         { MM_DISTRIBUION_IND_HDR,       "X-Mms-Distribution-Indcator" },
195         { MM_ELEMENT_DESCR_HDR,         "X-Mms-Element-Descriptor" },
196         { MM_LIMIT_HDR,                 "X-Mms-Limit" },
197
198         { 0x00, NULL },
199 };
200 /*
201  * Initialize the protocol and registered fields
202  */
203 static int proto_mmse = -1;
204
205 static int hf_mmse_message_type         = -1;
206 static int hf_mmse_transaction_id       = -1;
207 static int hf_mmse_mms_version          = -1;
208 static int hf_mmse_bcc                  = -1;
209 static int hf_mmse_cc                   = -1;
210 static int hf_mmse_content_location     = -1;
211 static int hf_mmse_date                 = -1;
212 static int hf_mmse_delivery_report      = -1;
213 static int hf_mmse_delivery_time_abs    = -1;
214 static int hf_mmse_delivery_time_rel    = -1;
215 static int hf_mmse_expiry_abs           = -1;
216 static int hf_mmse_expiry_rel           = -1;
217 static int hf_mmse_from                 = -1;
218 static int hf_mmse_message_class_id     = -1;
219 static int hf_mmse_message_class_str    = -1;
220 static int hf_mmse_message_id           = -1;
221 static int hf_mmse_message_size         = -1;
222 static int hf_mmse_priority             = -1;
223 static int hf_mmse_read_reply           = -1;
224 static int hf_mmse_report_allowed       = -1;
225 static int hf_mmse_response_status      = -1;
226 static int hf_mmse_response_text        = -1;
227 static int hf_mmse_sender_visibility    = -1;
228 static int hf_mmse_status               = -1;
229 static int hf_mmse_subject              = -1;
230 static int hf_mmse_to                   = -1;
231 static int hf_mmse_content_type         = -1;
232 static int hf_mmse_ffheader             = -1;
233
234 /*
235  * Initialize the subtree pointers
236  */
237 static gint ett_mmse = -1;
238
239 /*
240  * Valuestrings for PDU types
241  */
242 /* MMS 1.0 */
243 #define PDU_M_SEND_REQ          0x80
244 #define PDU_M_SEND_CONF         0x81
245 #define PDU_M_NOTIFICATION_IND  0x82
246 #define PDU_M_NOTIFYRESP_IND    0x83
247 #define PDU_M_RETRIEVE_CONF     0x84
248 #define PDU_M_ACKNOWLEDGE_IND   0x85
249 #define PDU_M_DELIVERY_IND      0x86
250 /* MMS 1.1 */
251 #define PDU_M_READ_REC_IND      0x87
252 #define PDU_M_READ_ORIG_IND     0x88
253 #define PDU_M_FORWARD_REQ       0x89
254 #define PDU_M_FORWARD_CONF      0x8A
255 /* MMS 1.2 */
256 #define PDU_M_MBOX_STORE_REQ    0x8B
257 #define PDU_M_MBOX_STORE_CONF   0x8C
258 #define PDU_M_MBOX_VIEW_REQ     0x8D
259 #define PDU_M_MBOX_VIEW_CONF    0x8E
260 #define PDU_M_MBOX_UPLOAD_REQ   0x8F
261 #define PDU_M_MBOX_UPLOAD_CONF  0x90
262 #define PDU_M_MBOX_DELETE_REQ   0x91
263 #define PDU_M_MBOX_DELETE_CONF  0x92
264 #define PDU_M_MBOX_DESCR        0x93
265
266 #define pdu_has_content(pdut) \
267         (  ((pdut) == PDU_M_SEND_REQ) \
268         || ((pdut) == PDU_M_DELIVERY_IND) \
269         || ((pdut) == PDU_M_RETRIEVE_CONF) \
270         || ((pdut) == PDU_M_MBOX_VIEW_CONF) \
271         || ((pdut) == PDU_M_MBOX_DESCR) \
272         || ((pdut) == PDU_M_MBOX_UPLOAD_REQ) \
273         )
274
275 static const value_string vals_message_type[] = {
276     /* MMS 1.0 */
277     { PDU_M_SEND_REQ,           "m-send-req" },
278     { PDU_M_SEND_CONF,          "m-send-conf" },
279     { PDU_M_NOTIFICATION_IND,   "m-notification-ind" },
280     { PDU_M_NOTIFYRESP_IND,     "m-notifyresp-ind" },
281     { PDU_M_RETRIEVE_CONF,      "m-retrieve-conf" },
282     { PDU_M_ACKNOWLEDGE_IND,    "m-acknowledge-ind" },
283     { PDU_M_DELIVERY_IND,       "m-delivery-ind" },
284     /* MMS 1.1 */
285     { PDU_M_READ_REC_IND,       "m-read-rec-ind" },
286     { PDU_M_READ_ORIG_IND,      "m-read-orig-ind" },
287     { PDU_M_FORWARD_REQ,        "m-forward-req" },
288     { PDU_M_FORWARD_CONF,       "m-forward-conf" },
289     /* MMS 1.2 */
290     { PDU_M_MBOX_STORE_REQ,     "m-mbox-store-req" },
291     { PDU_M_MBOX_STORE_CONF,    "m-mbox-store-conf" },
292     { PDU_M_MBOX_VIEW_REQ,      "m-mbox-view-req" },
293     { PDU_M_MBOX_VIEW_CONF,     "m-mbox-view-conf" },
294     { PDU_M_MBOX_UPLOAD_REQ,    "m-mbox-upload-req" },
295     { PDU_M_MBOX_UPLOAD_CONF,   "m-mbox-upload-conf" },
296     { PDU_M_MBOX_DELETE_REQ,    "m-mbox-delete-req" },
297     { PDU_M_MBOX_DELETE_CONF,   "m-mbox-delete-conf" },
298     { PDU_M_MBOX_DESCR,         "m-mbox-descr" },
299     { 0x00, NULL },
300 };
301
302 static const value_string vals_yes_no[] = {
303     { 0x80, "Yes" },
304     { 0x81, "No" },
305     { 0x00, NULL },
306 };
307
308 static const value_string vals_message_class[] = {
309     { 0x80, "Personal" },
310     { 0x81, "Advertisement" },
311     { 0x82, "Informational" },
312     { 0x83, "Auto" },
313     { 0x00, NULL },
314 };
315
316 static const value_string vals_priority[] = {
317     { 0x80, "Low" },
318     { 0x81, "Normal" },
319     { 0x82, "High" },
320     { 0x00, NULL },
321 };
322
323 static const value_string vals_response_status[] = {
324     /* MMS 1.0 - obsolete as from MMS 1.1 */
325     { 0x80, "Ok" },
326     { 0x81, "Unspecified" },
327     { 0x82, "Service denied" },
328     { 0x83, "Message format corrupt" },
329     { 0x84, "Sending address unresolved" },
330     { 0x85, "Message not found" },
331     { 0x86, "Network problem" },
332     { 0x87, "Content not accepted" },
333     { 0x88, "Unsupported message" },
334
335     /*
336      * Transient errors
337      */
338     /* MMS 1.1 */
339     { 0xC0, "Transient failure" },
340     { 0xC1, "Transient: Sending address unresolved" },
341     { 0xC2, "Transient: Message not found" },
342     { 0xC3, "Transient: Network problem" },
343     /* MMS 1.2 */
344     { 0xC4, "Transient: Partial success" },
345
346     /*
347      * Permanent errors
348      */
349     /* MMS 1.1 */
350     { 0xE0, "Permanent failure" },
351     { 0xE1, "Permanent: Service denied" },
352     { 0xE2, "Permanent: Message format corrupt" },
353     { 0xE3, "Permanent: Sending address unresolved" },
354     { 0xE4, "Permanent: Message not found" },
355     { 0xE5, "Permanent: Content not accepted" },
356     { 0xE6, "Permanent: Reply charging limitations not met" },
357     { 0xE7, "Permanent: Reply charging request not accepted" },
358     { 0xE8, "Permanent: Reply charging forwarding denied" },
359     { 0xE9, "Permanent: Reply charging not supported" },
360     /* MMS 1.2 */
361     { 0xEA, "Permanent: Address hiding not supported" },
362     
363     { 0x00, NULL },
364 };
365
366 static const value_string vals_sender_visibility[] = {
367     { 0x80, "Hide" },
368     { 0x81, "Show" },
369     { 0x00, NULL },
370 };
371
372 static const value_string vals_message_status[] = {
373     /* MMS 1.0 */
374     { 0x80, "Expired" },
375     { 0x81, "Retrieved" },
376     { 0x82, "Rejected" },
377     { 0x83, "Deferred" },
378     { 0x84, "Unrecognized" },
379     /* MMS 1.1 */
380     { 0x85, "Indeterminate" },
381     { 0x86, "Forwarded" },
382     /* MMS 1.2 */
383     { 0x87, "Unreachable" },
384     
385     { 0x00, NULL },
386 };
387
388 /*!
389  * Decodes a Text-string from the protocol data
390  *      Text-string = [Quote] *TEXT End-of-string
391  *      Quote       = <Octet 127>
392  *      End-of-string = <Octet 0>
393  *
394  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
395  *
396  * \param       tvb     The buffer with PDU-data
397  * \param       offset  Offset within that buffer
398  * \param       strval  Pointer to variable into which to put pointer to
399  *                      buffer allocated to hold the text; must be freed
400  *                      when no longer used
401  *
402  * \return              The length in bytes of the entire field
403  */
404 static guint
405 get_text_string(tvbuff_t *tvb, guint offset, char **strval)
406 {
407     guint        len;
408
409     DebugLog(("get_text_string(tvb = %p, offset = %u, **strval) - start\n", 
410                 vb, offset));
411     len = tvb_strsize(tvb, offset);
412     DebugLog((" [1] tvb_strsize(tvb, offset) == %u\n", len));
413     if (tvb_get_guint8(tvb, offset) == MM_QUOTE)
414         *strval = (char *)tvb_memdup(tvb, offset + 1, len - 1);
415     else
416         *strval = (char *)tvb_memdup(tvb, offset, len);
417     DebugLog((" [3] Return(len) == %u\n", len));
418     return len;
419 }
420
421 /*!
422  * Decodes a Value-length from the protocol data.
423  *      Value-length = Short-length | (Length-quote Length)
424  *      Short-length = <Any octet 0-30>
425  *      Length-quote = <Octet 31>
426  *      Length       = Uintvar-integer
427  *
428  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
429  *
430  * \param       tvb             The buffer with PDU-data
431  * \param       offset          Offset within that buffer
432  * \param       byte_count      Returns the length in bytes of
433  *                              the "Value-length" field.
434  *
435  * \return                      The actual value of "Value-length"
436  */
437 static guint
438 get_value_length(tvbuff_t *tvb, guint offset, guint *byte_count)
439 {
440     guint        field;
441
442     field = tvb_get_guint8(tvb, offset++);
443     if (field < 31)
444         *byte_count = 1;
445     else {                      /* Must be 31 so, Uintvar follows       */
446         field = tvb_get_guintvar(tvb, offset, byte_count);
447         (*byte_count)++;
448     }
449     return field;
450 }
451
452 /*!
453  * Decodes an Encoded-string-value from the protocol data
454  *      Encoded-string-value = Text-string | Value-length Char-set Text-string
455  *
456  * \param       tvb     The buffer with PDU-data
457  * \param       offset  Offset within that buffer
458  * \param       strval  Pointer to variable into which to put pointer to
459  *                      buffer allocated to hold the text; must be freed
460  *                      when no longer used
461  *
462  * \return              The length in bytes of the entire field
463  */
464 static guint
465 get_encoded_strval(tvbuff_t *tvb, guint offset, char **strval)
466 {
467     guint        field;
468     guint        length;
469     guint        count;
470
471     field = tvb_get_guint8(tvb, offset);
472
473     if (field < 32) {
474         length = get_value_length(tvb, offset, &count);
475         /* \todo        Something with "Char-set", skip for now */
476         *strval = (char *)tvb_get_string(tvb, offset + count + 1, length - 1);
477         return count + length;
478     } else
479         return get_text_string(tvb, offset, strval);
480 }
481
482 /*!
483  * Decodes a Long-integer from the protocol data
484  *      Long-integer = Short-length Multi-octet-integer
485  *      Short-length = <Any octet 0-30>
486  *      Multi-octet-integer = 1*30OCTET
487  *
488  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
489  *
490  * \param       tvb             The buffer with PDU-data
491  * \param       offset          Offset within that buffer
492  * \param       byte_count      Returns the length in bytes of the field
493  *
494  * \return                      The value of the Long-integer
495  *
496  * \note        A maximum of 4-byte integers will be handled.
497  */
498 static guint
499 get_long_integer(tvbuff_t *tvb, guint offset, guint *byte_count)
500 {
501     guint        val;
502
503     *byte_count = tvb_get_guint8(tvb, offset++);
504     switch (*byte_count) {
505         case 1:
506             val = tvb_get_guint8(tvb, offset);
507             break;
508         case 2:
509             val = tvb_get_ntohs(tvb, offset);
510             break;
511         case 3:
512             val = tvb_get_ntoh24(tvb, offset);
513             break;
514         case 4:
515             val = tvb_get_ntohl(tvb, offset);
516             break;
517         default:
518             val = 0;
519             break;
520     }
521     (*byte_count)++;
522     return val;
523 }
524
525 /* Code to actually dissect the packets */
526 static gboolean
527 dissect_mmse_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
528 {
529     guint8       pdut;
530
531         DebugLog(("dissect_mmse_heur()\n"));
532     /*
533      * Check if data makes sense for it to be dissected as MMSE:  Message-type
534      * field must make sense and followed by either Transaction-Id
535      * or MMS-Version header
536      */
537     if (tvb_get_guint8(tvb, 0) != MM_MTYPE_HDR)
538         return FALSE;
539     pdut = tvb_get_guint8(tvb, 1);
540     if (match_strval(pdut, vals_message_type) == NULL)
541         return FALSE;
542     if ((tvb_get_guint8(tvb, 2) != MM_TID_HDR) &&
543         (tvb_get_guint8(tvb, 2) != MM_VERSION_HDR))
544         return FALSE;
545     dissect_mmse_standalone(tvb, pinfo, tree);
546     return TRUE;
547 }
548
549 static void
550 dissect_mmse_standalone(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
551 {
552     guint8       pdut;
553     char         *message_type;
554
555     DebugLog(("dissect_mmse_standalone() - START (Packet %u)\n",
556                 pinfo->fd->num));
557
558     pdut = tvb_get_guint8(tvb, 1);
559     message_type = match_strval(pdut, vals_message_type);
560
561     /* Make entries in Protocol column and Info column on summary display */
562     if (check_col(pinfo->cinfo, COL_PROTOCOL))
563         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MMSE");
564
565     if (check_col(pinfo->cinfo, COL_INFO)) {
566         col_clear(pinfo->cinfo, COL_INFO);
567         col_add_fstr(pinfo->cinfo, COL_INFO, "MMS %s", message_type);
568     }
569
570     dissect_mmse(tvb, pinfo, tree, pdut, message_type);
571 }
572
573 static void
574 dissect_mmse_encapsulated(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
575 {
576     guint8       pdut;
577     char         *message_type;
578
579     DebugLog(("dissect_mmse_encapsulated() - START (Packet %u)\n",
580                 pinfo->fd->num));
581
582     pdut = tvb_get_guint8(tvb, 1);
583     message_type = match_strval(pdut, vals_message_type);
584
585     /* Make entries in Info column on summary display */
586     if (check_col(pinfo->cinfo, COL_INFO)) {
587         col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(MMS %s)",
588                 message_type);
589     }
590
591     dissect_mmse(tvb, pinfo, tree, pdut, message_type);
592 }
593
594 static void
595 dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 pdut,
596         char *message_type)
597 {
598     guint        offset;
599     guint8       field = 0;
600     char         *strval;
601     guint        length;
602     guint        count;
603
604     /* Set up structures needed to add the protocol subtree and manage it */
605     proto_item  *ti = NULL;
606     proto_tree  *mmse_tree = NULL;
607
608     DebugLog(("dissect_mmse() - START (Packet %u)\n", pinfo->fd->num));
609
610     /* If tree == NULL then we are only interested in protocol dissection
611      * up to reassembly and handoff to subdissectors if applicable; the
612      * columns must be set appropriately too.
613      * If tree != NULL then we also want to display the protocol tree
614      * with its fields.
615      * 
616      * In the interest of speed, skip protocol tree item generation
617      * if tree is NULL.
618      */
619     if (tree) {
620         DebugLog(("tree != NULL\n"));
621
622         ti = proto_tree_add_item(tree, proto_mmse, tvb, 0, -1, FALSE);
623         proto_item_append_text(ti, ", Type: %s", message_type);
624         /* create display subtree for the protocol */
625         mmse_tree = proto_item_add_subtree(ti, ett_mmse);
626
627         /* Report PDU-type      */
628         proto_tree_add_uint(mmse_tree, hf_mmse_message_type, tvb, 0, 2, pdut);
629     }
630
631     offset = 2;                 /* Skip Message-Type    */
632
633     /*
634      * Cycle through MMS-headers
635      *
636      * NOTE - some PDUs may convey content which can be handed off
637      *        to subdissectors.
638      */
639     if (tree || pdu_has_content(pdut)) {
640         while ((offset < tvb_reported_length(tvb)) &&
641                (field = tvb_get_guint8(tvb, offset++)) != MM_CTYPE_HDR)
642         {
643             DebugLog(("\tField =  0x%02X (offset = %u): %s\n",
644                         field, offset,
645                         val_to_str(field, vals_mm_header_names,
646                             "Unknown MMS header 0x%02X")));
647             switch (field)
648             {
649                 case MM_TID_HDR:                /* Text-string  */
650                     length = get_text_string(tvb, offset, &strval);
651                     if (tree) {
652                         proto_tree_add_string(mmse_tree, hf_mmse_transaction_id,
653                                 tvb, offset - 1, length + 1,strval);
654                     }
655                     g_free(strval);
656                     offset += length;
657                     break;
658                 case MM_VERSION_HDR:            /* nibble-Major/nibble-minor*/
659                     field = tvb_get_guint8(tvb, offset++);
660                     if (tree) {
661                         guint8   major, minor;
662
663                         major = (field & 0x70) >> 4;
664                         minor = field & 0x0F;
665                         if (minor == 0x0F)
666                             strval = g_strdup_printf("%u", major);
667                         else
668                             strval = g_strdup_printf("%u.%u", major, minor);
669                         proto_tree_add_string(mmse_tree, hf_mmse_mms_version,
670                                 tvb, offset - 2, 2, strval);
671                         g_free(strval);
672                     }
673                     break;
674                 case MM_BCC_HDR:                /* Encoded-string-value */
675                     length = get_encoded_strval(tvb, offset, &strval);
676                     if (tree) {
677                         proto_tree_add_string(mmse_tree, hf_mmse_bcc, tvb,
678                                 offset - 1, length + 1, strval);
679                     }
680                     g_free(strval);
681                     offset += length;
682                     break;
683                 case MM_CC_HDR:                 /* Encoded-string-value */
684                     length = get_encoded_strval(tvb, offset, &strval);
685                     if (tree) {
686                         proto_tree_add_string(mmse_tree, hf_mmse_cc, tvb,
687                                 offset - 1, length + 1, strval);
688                     }
689                     g_free(strval);
690                     offset += length;
691                     break;
692                 case MM_CLOCATION_HDR:          /* Uri-value            */
693                     if (pdut == PDU_M_MBOX_DELETE_CONF) {
694                         /* General form with length */
695                         length = tvb_get_guint8(tvb, offset);
696                         if (length == 0x1F) {
697                             guint length_len = 0;
698                             length = tvb_get_guintvar(tvb, offset + 1,
699                                     &length_len);
700                             length += 1 + length_len;
701                         } else {
702                             length += 1;
703                         }
704                         if (tree) {
705                             proto_tree_add_string(mmse_tree,
706                                     hf_mmse_content_location,
707                                     tvb, offset - 1, length + 1,
708                                     "<Undecoded value for m-mbox-delete-conf>");
709                         }
710                     } else {
711                         length = get_text_string(tvb, offset, &strval);
712                         if (tree) {
713                             proto_tree_add_string(mmse_tree,
714                                     hf_mmse_content_location,
715                                     tvb, offset - 1, length + 1, strval);
716                         }
717                         g_free(strval);
718                     }
719                     offset += length;
720                     break;
721                 case MM_DATE_HDR:               /* Long-integer         */
722                     {
723                         guint            tval;
724                         nstime_t         tmptime;
725
726                         tval = get_long_integer(tvb, offset, &count);
727                         tmptime.secs = tval;
728                         tmptime.nsecs = 0;
729                         if (tree) {
730                             proto_tree_add_time(mmse_tree, hf_mmse_date, tvb,
731                                     offset - 1, count + 1, &tmptime);
732                         }
733                     }
734                     offset += count;
735                     break;
736                 case MM_DREPORT_HDR:            /* Yes|No               */
737                     field = tvb_get_guint8(tvb, offset++);
738                     if (tree) {
739                         proto_tree_add_uint(mmse_tree,
740                                 hf_mmse_delivery_report,
741                                 tvb, offset - 2, 2, field);
742                     }
743                     break;
744                 case MM_DTIME_HDR:
745                     /*
746                      * Value-length(Absolute-token Date-value|
747                      *              Relative-token Delta-seconds-value)
748                      */
749                     length = get_value_length(tvb, offset, &count);
750                     field = tvb_get_guint8(tvb, offset + count);
751                     if (tree) {
752                         guint            tval;
753                         nstime_t         tmptime;
754                         guint            cnt;
755
756                         tval =  get_long_integer(tvb, offset + count + 1, &cnt);
757                         tmptime.secs = tval;
758                         tmptime.nsecs = 0;
759
760                         if (field == 0x80)
761                             proto_tree_add_time(mmse_tree,
762                                     hf_mmse_delivery_time_abs,
763                                     tvb, offset - 1,
764                                     length + count + 1, &tmptime);
765                         else
766                             proto_tree_add_time(mmse_tree,
767                                     hf_mmse_delivery_time_rel,
768                                     tvb, offset - 1,
769                                     length + count + 1, &tmptime);
770                     }
771                     offset += length + count;
772                     break;
773                 case MM_EXPIRY_HDR:
774                     /*
775                      * Value-length(Absolute-token Date-value|
776                      *              Relative-token Delta-seconds-value)
777                      */
778                     length = get_value_length(tvb, offset, &count);
779                     field = tvb_get_guint8(tvb, offset + count);
780                     if (tree) {
781                         guint            tval;
782                         nstime_t         tmptime;
783                         guint            cnt;
784
785                         tval = get_long_integer(tvb, offset + count + 1, &cnt);
786                         tmptime.secs = tval;
787                         tmptime.nsecs = 0;
788
789                         if (field == 0x80)
790                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_abs,
791                                     tvb, offset - 1,
792                                     length + count + 1, &tmptime);
793                         else
794                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_rel,
795                                     tvb, offset - 1,
796                                     length + count + 1, &tmptime);
797                     }
798                     offset += length + count;
799                     break;
800                 case MM_FROM_HDR:
801                     /*
802                      * Value-length(Address-present-token Encoded-string-value
803                      *              |Insert-address-token)
804                      */
805                     length = get_value_length(tvb, offset, &count);
806                     if (tree) {
807                         field = tvb_get_guint8(tvb, offset + count);
808                         if (field == 0x81) {
809                             proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
810                                     offset-1, length + count + 1,
811                                     "<insert address>");
812                         } else {
813                             (void) get_encoded_strval(tvb, offset + count + 1,
814                                                       &strval);
815                             proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
816                                     offset-1, length + count + 1, strval);
817                             g_free(strval);
818                         }
819                     }
820                     offset += length + count;
821                     break;
822                 case MM_MCLASS_HDR:
823                     /*
824                      * Class-identifier|Text-string
825                      */
826                     field = tvb_get_guint8(tvb, offset);
827                     if (field & 0x80) {
828                         offset++;
829                         if (tree) {
830                             proto_tree_add_uint(mmse_tree,
831                                     hf_mmse_message_class_id,
832                                     tvb, offset - 2, 2, field);
833                         }
834                     } else {
835                         length = get_text_string(tvb, offset, &strval);
836                         if (tree) {
837                             proto_tree_add_string(mmse_tree,
838                                     hf_mmse_message_class_str,
839                                     tvb, offset - 1, length + 1,
840                                     strval);
841                         }
842                         g_free(strval);
843                         offset += length;
844                     }
845                     break;
846                 case MM_MID_HDR:                /* Text-string          */
847                     length = get_text_string(tvb, offset, &strval);
848                     if (tree) {
849                         proto_tree_add_string(mmse_tree, hf_mmse_message_id,
850                                 tvb, offset - 1, length + 1, strval);
851                     }
852                     g_free(strval);
853                     offset += length;
854                     break;
855                 case MM_MSIZE_HDR:              /* Long-integer         */
856                     length = get_long_integer(tvb, offset, &count);
857                     if (tree) {
858                         proto_tree_add_uint(mmse_tree, hf_mmse_message_size,
859                                 tvb, offset - 1, count + 1, length);
860                     }
861                     offset += count;
862                     break;
863                 case MM_PRIORITY_HDR:           /* Low|Normal|High      */
864                     field = tvb_get_guint8(tvb, offset++);
865                     if (tree) {
866                         proto_tree_add_uint(mmse_tree, hf_mmse_priority, tvb,
867                                 offset - 2, 2, field);
868                     }
869                     break;
870                 case MM_RREPLY_HDR:             /* Yes|No               */
871                     field = tvb_get_guint8(tvb, offset++);
872                     if (tree) {
873                         proto_tree_add_uint(mmse_tree, hf_mmse_read_reply, tvb,
874                                 offset - 2, 2, field);
875                     }
876                     break;
877                 case MM_RALLOWED_HDR:           /* Yes|No               */
878                     field = tvb_get_guint8(tvb, offset++);
879                     if (tree) {
880                         proto_tree_add_uint(mmse_tree, hf_mmse_report_allowed,
881                                 tvb, offset - 2, 2, field);
882                     }
883                     break;
884                 case MM_RSTATUS_HDR:
885                     field = tvb_get_guint8(tvb, offset++);
886                     if (tree) {
887                         proto_tree_add_uint(mmse_tree, hf_mmse_response_status,
888                                 tvb, offset - 2, 2, field);
889                     }
890                     break;
891                 case MM_RTEXT_HDR:              /* Encoded-string-value */
892                     if (pdut == PDU_M_MBOX_DELETE_CONF) {
893                         /* General form with length */
894                         length = tvb_get_guint8(tvb, offset);
895                         if (length == 0x1F) {
896                             guint length_len = 0;
897                             length = tvb_get_guintvar(tvb, offset + 1,
898                                     &length_len);
899                             length += 1 + length_len;
900                         } else {
901                             length += 1;
902                         }
903                         if (tree) {
904                             proto_tree_add_string(mmse_tree,
905                                     hf_mmse_content_location,
906                                     tvb, offset - 1, length + 1,
907                                     "<Undecoded value for m-mbox-delete-conf>");
908                         }
909                     } else {
910                         length = get_encoded_strval(tvb, offset, &strval);
911                         if (tree) {
912                             proto_tree_add_string(mmse_tree,
913                                     hf_mmse_response_text, tvb, offset - 1,
914                                     length + 1, strval);
915                         }
916                         g_free(strval);
917                     }
918                     offset += length;
919                     break;
920                 case MM_SVISIBILITY_HDR:        /* Hide|Show            */
921                     field = tvb_get_guint8(tvb, offset++);
922                     if (tree) {
923                         proto_tree_add_uint(mmse_tree,hf_mmse_sender_visibility,
924                                 tvb, offset - 2, 2, field);
925                     }
926                     break;
927                 case MM_STATUS_HDR:
928                     field = tvb_get_guint8(tvb, offset++);
929                     if (tree) {
930                         proto_tree_add_uint(mmse_tree, hf_mmse_status, tvb,
931                                 offset - 2, 2, field);
932                     }
933                     break;
934                 case MM_SUBJECT_HDR:            /* Encoded-string-value */
935                     length = get_encoded_strval(tvb, offset, &strval);
936                     if (tree) {
937                         proto_tree_add_string(mmse_tree, hf_mmse_subject, tvb,
938                                 offset - 1, length + 1, strval);
939                     }
940                     g_free(strval);
941                     offset += length;
942                     break;
943                 case MM_TO_HDR:                 /* Encoded-string-value */
944                     length = get_encoded_strval(tvb, offset, &strval);
945                     if (tree) {
946                         proto_tree_add_string(mmse_tree, hf_mmse_to, tvb,
947                                 offset - 1, length + 1, strval);
948                     }
949                     g_free(strval);
950                     offset += length;
951                     break;
952                 default:
953                     if (field & 0x80) { /* Well-known WSP header encoding */
954                         guint8 peek = tvb_get_guint8(tvb, offset);
955                         char *hdr_name = val_to_str(field, vals_mm_header_names,
956                                 "Unknown field (0x%02x)");
957                         DebugLog(("\t\tUndecoded well-known header: %s\n",
958                                     hdr_name));
959
960                         if (peek & 0x80) { /* Well-known value */
961                             length = 1;
962                             if (tree) {
963                                 proto_tree_add_text(mmse_tree, tvb, offset - 1,
964                                         length + 1,
965                                         "%s: <Well-known value 0x%02x>"
966                                         " (not decoded)",
967                                         hdr_name, peek);
968                             }
969                         } else if ((peek == 0) || (peek >= 0x20)) { /* Text */
970                             length = get_text_string(tvb, offset, &strval);
971                             if (tree) {
972                                 proto_tree_add_text(mmse_tree, tvb, offset - 1,
973                                         length + 1, "%s: %s (Not decoded)",
974                                         hdr_name, strval);
975                                 g_free(strval);
976                             }
977                         } else { /* General form with length */
978                             if (peek == 0x1F) { /* Value length in guintvar */
979                                 guint length_len = 0;
980                                 length = 1 + tvb_get_guintvar(tvb, offset + 1,
981                                         &length_len);
982                                 length += length_len;
983                             } else { /* Value length in octet */
984                                 length = 1 + tvb_get_guint8(tvb, offset);
985                             }
986                             if (tree) {
987                                 proto_tree_add_text(mmse_tree, tvb, offset - 1,
988                                         length + 1, "%s: "
989                                         "<Value in general form> (not decoded)",
990                                         hdr_name);
991                             }
992                         }
993                         offset += length;
994                     } else { /* Literal WSP header encoding */
995                         guint    length2;
996                         char     *strval2;
997
998                         --offset;
999                         length = get_text_string(tvb, offset, &strval);
1000                         DebugLog(("\t\tUndecoded literal header: %s\n",
1001                                     strval));
1002                         CLEANUP_PUSH(g_free, strval);
1003                         length2= get_text_string(tvb, offset+length, &strval2);
1004
1005                         if (tree) {
1006                             proto_tree_add_string_format(mmse_tree,
1007                                     hf_mmse_ffheader, tvb, offset,
1008                                     length + length2,
1009                                     (const char *) tvb_get_ptr(
1010                                             tvb, offset, length + length2),
1011                                     "%s: %s", strval, strval2);
1012                         }
1013                         g_free(strval2);
1014                         offset += length + length2;
1015                         CLEANUP_CALL_AND_POP;
1016                     }
1017                     break;
1018             }
1019             DebugLog(("\tEnd(case)\n"));
1020         }
1021         DebugLog(("\tEnd(switch)\n"));
1022         if (field == MM_CTYPE_HDR) {
1023             /*
1024              * Eeehh, we're now actually back to good old WSP content-type
1025              * encoding. Let's steal that from the WSP-dissector.
1026              */
1027             tvbuff_t    *tmp_tvb;
1028             guint        type;
1029             const char  *type_str;
1030
1031             DebugLog(("Content-Type: [from WSP dissector]\n"));
1032             DebugLog(("Calling add_content_type() in WSP dissector\n"));
1033             offset = add_content_type(mmse_tree, tvb, offset, &type, &type_str);
1034             DebugLog(("Generating new TVB subset (offset = %u)\n", offset));
1035             tmp_tvb = tvb_new_subset(tvb, offset, -1, -1);
1036             DebugLog(("Add POST data\n"));
1037             add_post_data(mmse_tree, tmp_tvb, type, type_str, pinfo);
1038             DebugLog(("Done!\n"));
1039         }
1040     } else {
1041         DebugLog(("tree == NULL and PDU has no potential content\n"));
1042     }
1043
1044     /* If this protocol has a sub-dissector call it here, see section 1.8 */
1045     DebugLog(("dissect_mmse() - END\n"));
1046 }
1047
1048
1049 /* Register the protocol with Ethereal */
1050
1051 /* this format is required because a script is used to build the C function
1052  * that calls all the protocol registration.
1053  */
1054 void
1055 proto_register_mmse(void)
1056 {
1057     /* Setup list of header fields  See Section 1.6.1 for details       */
1058     static hf_register_info hf[] = {
1059         {   &hf_mmse_message_type,
1060             {   "Message-Type", "mmse.message_type",
1061                 FT_UINT8, BASE_HEX, VALS(vals_message_type), 0x00,
1062                 "Specifies the transaction type. Effectively defines PDU.",
1063                 HFILL
1064             }
1065         },
1066         {   &hf_mmse_transaction_id,
1067             {   "Transaction-ID", "mmse.transaction_id",
1068                 FT_STRING, BASE_NONE, NULL, 0x00,
1069                 "A unique identifier for this transaction. "
1070                 "Identifies request and corresponding response only.",
1071                 HFILL
1072             }
1073         },
1074         {   &hf_mmse_mms_version,
1075             {   "MMS-Version", "mmse.mms_version",
1076                 FT_STRING, BASE_NONE, NULL, 0x00,
1077                 "Version of the protocol used.",
1078                 HFILL
1079             }
1080         },
1081         {   &hf_mmse_bcc,
1082             {   "Bcc", "mmse.bcc",
1083                 FT_STRING, BASE_NONE, NULL, 0x00,
1084                 "Blind carbon copy.",
1085                 HFILL
1086             }
1087         },
1088         {   &hf_mmse_cc,
1089             {   "Cc", "mmse.cc",
1090                 FT_STRING, BASE_NONE, NULL, 0x00,
1091                 "Carbon copy.",
1092                 HFILL
1093             }
1094         },
1095         {   &hf_mmse_content_location,
1096             {   "Content-Location", "mmse.content_location",
1097                 FT_STRING, BASE_NONE, NULL, 0x00,
1098                 "Defines the location of the message.",
1099                 HFILL
1100             }
1101         },
1102         {   &hf_mmse_date,
1103             {   "Date", "mmse.date",
1104                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
1105                 "Arrival timestamp of the message or sending timestamp.",
1106                 HFILL
1107             }
1108         },
1109         {   &hf_mmse_delivery_report,
1110             {   "Delivery-Report", "mmse.delivery_report",
1111                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
1112                 "Whether a report of message delivery is wanted or not.",
1113                 HFILL
1114             }
1115         },
1116         {   &hf_mmse_delivery_time_abs,
1117             {   "Delivery-Time", "mmse.delivery_time.abs",
1118                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
1119                 "The time at which message delivery is desired.",
1120                 HFILL
1121             }
1122         },
1123         {   &hf_mmse_delivery_time_rel,
1124             {   "Delivery-Time", "mmse.delivery_time.rel",
1125                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
1126                 "The desired message delivery delay.",
1127                 HFILL
1128             }
1129         },
1130         {   &hf_mmse_expiry_abs,
1131             {   "Expiry", "mmse.expiry.abs",
1132                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
1133                 "Time when message expires and need not be delivered anymore.",
1134                 HFILL
1135             }
1136         },
1137         {   &hf_mmse_expiry_rel,
1138             {   "Expiry", "mmse.expiry.rel",
1139                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
1140                 "Delay before message expires and need not be delivered anymore.",
1141                 HFILL
1142             }
1143         },
1144         {   &hf_mmse_from,
1145             {   "From", "mmse.from",
1146                 FT_STRING, BASE_NONE, NULL, 0x00,
1147                 "Address of the message sender.",
1148                 HFILL
1149             }
1150         },
1151         {   &hf_mmse_message_class_id,
1152             {   "Message-Class", "mmse.message_class.id",
1153                 FT_UINT8, BASE_HEX, VALS(vals_message_class), 0x00,
1154                 "Of what category is the message.",
1155                 HFILL
1156             }
1157         },
1158         {   &hf_mmse_message_class_str,
1159             {   "Message-Class", "mmse.message_class.str",
1160                 FT_STRING, BASE_NONE, NULL, 0x00,
1161                 "Of what category is the message.",
1162                 HFILL
1163             }
1164         },
1165         {   &hf_mmse_message_id,
1166             {   "Message-Id", "mmse.message_id",
1167                 FT_STRING, BASE_NONE, NULL, 0x00,
1168                 "Unique identification of the message.",
1169                 HFILL
1170             }
1171         },
1172         {   &hf_mmse_message_size,
1173             {   "Message-Size", "mmse.message_size",
1174                 FT_UINT32, BASE_DEC, NULL, 0x00,
1175                 "The size of the message in octets.",
1176                 HFILL
1177             }
1178         },
1179         {   &hf_mmse_priority,
1180             {   "Priority", "mmse.priority",
1181                 FT_UINT8, BASE_HEX, VALS(vals_priority), 0x00,
1182                 "Priority of the message.",
1183                 HFILL
1184             }
1185         },
1186         {   &hf_mmse_read_reply,
1187             {   "Read-Reply", "mmse.read_reply",
1188                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
1189                 "Whether a read report from every recipient is wanted.",
1190                 HFILL
1191             }
1192         },
1193         {   &hf_mmse_report_allowed,
1194             {   "Report-Allowed", "mmse.report_allowed",
1195                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
1196                 "Sending of delivery report allowed or not.",
1197                 HFILL
1198             }
1199         },
1200         {   &hf_mmse_response_status,
1201             {   "Response-Status", "mmse.response_status",
1202                 FT_UINT8, BASE_HEX, VALS(vals_response_status), 0x00,
1203                 "MMS-specific result of a message submission or retrieval.",
1204                 HFILL
1205             }
1206         },
1207         {   &hf_mmse_response_text,
1208             {   "Response-Text", "mmse.response_text",
1209                 FT_STRING, BASE_NONE, NULL, 0x00,
1210                 "Additional information on MMS-specific result.",
1211                 HFILL
1212             }
1213         },
1214         {   &hf_mmse_sender_visibility,
1215             {   "Sender-Visibility", "mmse.sender_visibility",
1216                 FT_UINT8, BASE_HEX, VALS(vals_sender_visibility), 0x00,
1217                 "Disclose sender identity to receiver or not.",
1218                 HFILL
1219             }
1220         },
1221         {   &hf_mmse_status,
1222             {   "Status", "mmse.status",
1223                 FT_UINT8, BASE_HEX, VALS(vals_message_status), 0x00,
1224                 "Current status of the message.",
1225                 HFILL
1226             }
1227         },
1228         {   &hf_mmse_subject,
1229             {   "Subject", "mmse.subject",
1230                 FT_STRING, BASE_NONE, NULL, 0x00,
1231                 "Subject of the message.",
1232                 HFILL
1233             }
1234         },
1235         {   &hf_mmse_to,
1236             {   "To", "mmse.to",
1237                 FT_STRING, BASE_NONE, NULL, 0x00,
1238                 "Recipient(s) of the message.",
1239                 HFILL
1240             }
1241         },
1242         {   &hf_mmse_content_type,
1243             {   "Data", "mmse.content_type",
1244                 FT_NONE, BASE_NONE, NULL, 0x00,
1245                 "Media content of the message.",
1246                 HFILL
1247             }
1248         },
1249         {   &hf_mmse_ffheader,
1250             {   "Free format (not encoded) header", "mmse.ffheader",
1251                 FT_STRING, BASE_NONE, NULL, 0x00,
1252                 "Application header without corresponding encoding.",
1253                 HFILL
1254             }
1255         },
1256     };
1257     /* Setup protocol subtree array */
1258     static gint *ett[] = {
1259         &ett_mmse,
1260     };
1261
1262     /* Register the protocol name and description */
1263     proto_mmse = proto_register_protocol("MMS Message Encapsulation",
1264                                          "MMSE", "mmse");
1265
1266     /* Required function calls to register header fields and subtrees used */
1267     proto_register_field_array(proto_mmse, hf, array_length(hf));
1268     proto_register_subtree_array(ett, array_length(ett));
1269 }
1270
1271 /* If this dissector uses sub-dissector registration add registration routine.
1272  * This format is required because a script is used to find these routines and
1273  * create the code that calls these routines.
1274  */
1275 void
1276 proto_reg_handoff_mmse(void)
1277 {
1278     dissector_handle_t mmse_standalone_handle;
1279     dissector_handle_t mmse_encapsulated_handle;
1280
1281     heur_dissector_add("wsp", dissect_mmse_heur, proto_mmse);
1282     mmse_standalone_handle = create_dissector_handle(
1283             dissect_mmse_standalone, proto_mmse);
1284     mmse_encapsulated_handle = create_dissector_handle(
1285             dissect_mmse_encapsulated, proto_mmse);
1286         /* As the media types for WSP and HTTP are the same, the WSP dissector
1287          * uses the same string dissector table as the HTTP protocol. */
1288     dissector_add_string("media_type",
1289             "application/vnd.wap.mms-message", mmse_standalone_handle);
1290     dissector_add_string("multipart_media_type",
1291             "application/vnd.wap.mms-message", mmse_encapsulated_handle);
1292 }