99687c85176e07b84466d7c7c79b4dc9590403a5
[obnox/wireshark/wip.git] / epan / dissectors / 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$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
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.
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 <epan/strutil.h>
48 #include "packet-wap.h"
49 #include "packet-wsp.h"
50 /* #include "packet-mmse.h" */          /* We autoregister      */
51
52 #define MM_QUOTE                0x7F    /* Quoted string        */
53
54 #define MMS_CONTENT_TYPE        0x3E    /* WINA-value for mms-message   */
55
56 /* General-purpose debug logger.
57  * Requires double parentheses because of variable arguments of printf().
58  *
59  * Enable debug logging for MMSE by defining AM_CFLAGS
60  * so that it contains "-DDEBUG_mmse"
61  */
62 #ifdef DEBUG_mmse
63 #define DebugLog(x) \
64         g_print("%s:%u: ", __FILE__, __LINE__); \
65         g_print x
66 #else
67 #define DebugLog(x) ;
68 #endif
69
70 /*
71  * Forward declarations
72  */
73 static void dissect_mmse_standalone(tvbuff_t *, packet_info *, proto_tree *);
74 static void dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
75         guint8 pdut, const char *message_type);
76
77 /*
78  * Header field values
79  */
80 /* MMS 1.0 */
81 #define MM_BCC_HDR              0x81    /* Bcc                          */
82 #define MM_CC_HDR               0x82    /* Cc                           */
83 #define MM_CLOCATION_HDR        0x83    /* X-Mms-Content-Location       */
84 #define MM_CTYPE_HDR            0x84    /* Content-Type                 */
85 #define MM_DATE_HDR             0x85    /* Date                         */
86 #define MM_DREPORT_HDR          0x86    /* X-Mms-Delivery-Report        */
87 #define MM_DTIME_HDR            0x87    /* X-Mms-Delivery-Time          */
88 #define MM_EXPIRY_HDR           0x88    /* X-Mms-Expiry                 */
89 #define MM_FROM_HDR             0x89    /* From                         */
90 #define MM_MCLASS_HDR           0x8A    /* X-Mms-Message-Class          */
91 #define MM_MID_HDR              0x8B    /* Message-ID                   */
92 #define MM_MTYPE_HDR            0x8C    /* X-Mms-Message-Type           */
93 #define MM_VERSION_HDR          0x8D    /* X-Mms-MMS-Version            */
94 #define MM_MSIZE_HDR            0x8E    /* X-Mms-Message-Size           */
95 #define MM_PRIORITY_HDR         0x8F    /* X-Mms-Priority               */
96 #define MM_RREPLY_HDR           0x90    /* X-Mms-Read-Reply             */
97 #define MM_RALLOWED_HDR         0x91    /* X-Mms-Report-Allowed         */
98 #define MM_RSTATUS_HDR          0x92    /* X-Mms-Response-Status        */
99 #define MM_RTEXT_HDR            0x93    /* X-Mms-Response-Text          */
100 #define MM_SVISIBILITY_HDR      0x94    /* X-Mms-Sender-Visibility      */
101 #define MM_STATUS_HDR           0x95    /* X-Mms-Status                 */
102 #define MM_SUBJECT_HDR          0x96    /* Subject                      */
103 #define MM_TO_HDR               0x97    /* To                           */
104 #define MM_TID_HDR              0x98    /* X-Mms-Transaction-Id         */
105 /* MMS 1.1 */
106 #define MM_RETRIEVE_STATUS_HDR  0x99    /* X-Mms-Retrieve-Status        */
107 #define MM_RETRIEVE_TEXT_HDR    0x9A    /* X-Mms-Retrieve-Text          */
108 #define MM_READ_STATUS_HDR      0x9B    /* X-Mms-Read-Status            */
109 #define MM_REPLY_CHARGING_HDR   0x9C    /* X-Mms-Reply-Charging         */
110 #define MM_REPLY_CHARGING_DEADLINE_HDR  \
111                                 0x9D    /* X-Mms-Reply-Charging-Deadline*/
112 #define MM_REPLY_CHARGING_ID_HDR        \
113                                 0x9E    /* X-Mms-Reply-Charging-ID      */
114 #define MM_REPLY_CHARGING_SIZE_HDR      \
115                                 0x9F    /* X-Mms-Reply-Charging-Size    */
116 #define MM_PREV_SENT_BY_HDR     0xA0    /* X-Mms-Previously-Sent-By     */
117 #define MM_PREV_SENT_DATE_HDR   0xA1    /* X-Mms-Previously-Sent-Date   */
118 /* MMS 1.2 */
119 #define MM_STORE_HDR            0xA2    /* X-Mms-Store                  */
120 #define MM_MM_STATE_HDR         0xA3    /* X-Mms-MM-State               */
121 #define MM_MM_FLAGS_HDR         0xA4    /* X-Mms-MM-Flags               */
122 #define MM_STORE_STATUS_HDR     0xA5    /* X-Mms-Store-Status           */
123 #define MM_STORE_STATUS_TEXT_HDR        \
124                                 0xA6    /* X-Mms-Store-Status-Text      */
125 #define MM_STORED_HDR           0xA7    /* X-Mms-Stored                 */
126 #define MM_ATTRIBUTES_HDR       0xA8    /* X-Mms-Attributes             */
127 #define MM_TOTALS_HDR           0xA9    /* X-Mms-Totals                 */
128 #define MM_MBOX_TOTALS_HDR      0xAA    /* X-Mms-Mbox-Totals            */
129 #define MM_QUOTAS_HDR           0xAB    /* X-Mms-Quotas                 */
130 #define MM_MBOX_QUOTAS_HDR      0xAC    /* X-Mms-Mbox-Quotas            */
131 #define MM_MBOX_MSG_COUNT_HDR   0xAD    /* X-Mms-Message-Count          */
132 #define MM_CONTENT_HDR          0xAE    /* Content                      */
133 #define MM_START_HDR            0xAF    /* X-Mms-Start                  */
134 #define MM_ADDITIONAL_HDR       0xB0    /* Additional-headers           */
135 #define MM_DISTRIBUION_IND_HDR  0xB1    /* X-Mms-Distribution-Indcator  */
136 #define MM_ELEMENT_DESCR_HDR    0xB2    /* X-Mms-Element-Descriptor     */
137 #define MM_LIMIT_HDR            0xB3    /* X-Mms-Limit                  */
138
139 static const value_string vals_mm_header_names[] = {
140         /* MMS 1.0 */
141         { MM_BCC_HDR,                   "Bcc" },
142         { MM_CC_HDR,                    "Cc" },
143         { MM_CLOCATION_HDR,             "X-Mms-Content-Location" },
144         { MM_CTYPE_HDR,                 "X-Mms-Content-Type" },
145         { MM_DATE_HDR,                  "Date" },
146         { MM_DREPORT_HDR,               "X-Mms-Delivery-Report" },
147         { MM_DTIME_HDR,                 "X-Mms-Delivery-Time" },
148         { MM_EXPIRY_HDR,                "X-Mms-Expiry" },
149         { MM_FROM_HDR,                  "From" },
150         { MM_MCLASS_HDR,                "X-Mms-Message-Class" },
151         { MM_MID_HDR,                   "Message-ID" },
152         { MM_MTYPE_HDR,                 "X-Mms-Message-Type" },
153         { MM_VERSION_HDR,               "X-Mms-MMS-Version" },
154         { MM_MSIZE_HDR,                 "X-Mms-Message-Size" },
155         { MM_PRIORITY_HDR,              "X-Mms-Priority" },
156         { MM_RREPLY_HDR,                "X-Mms-Read-Reply" },
157         { MM_RALLOWED_HDR,              "X-Mms-Report-Allowed" },
158         { MM_RSTATUS_HDR,               "X-Mms-Response-Status" },
159         { MM_RTEXT_HDR,                 "X-Mms-Response-Text" },
160         { MM_SVISIBILITY_HDR,           "X-Mms-Sender-Visibility" },
161         { MM_STATUS_HDR,                "X-Mms-Status" },
162         { MM_SUBJECT_HDR,               "Subject" },
163         { MM_TO_HDR,                    "To" },
164         { MM_TID_HDR,                   "X-Mms-Transaction-Id" },
165         /* MMS 1.1 */
166         { MM_RETRIEVE_STATUS_HDR,       "X-Mms-Retrieve-Status" },
167         { MM_RETRIEVE_TEXT_HDR,         "X-Mms-Retrieve-Text" },
168         { MM_READ_STATUS_HDR,           "X-Mms-Read-Status" },
169         { MM_REPLY_CHARGING_HDR,        "X-Mms-Reply-Charging" },
170         { MM_REPLY_CHARGING_DEADLINE_HDR,
171                                         "X-Mms-Reply-Charging-Deadline" },
172         { MM_REPLY_CHARGING_ID_HDR,     "X-Mms-Reply-Charging-ID" },
173         { MM_REPLY_CHARGING_SIZE_HDR,   "X-Mms-Reply-Charging-Size" },
174         { MM_PREV_SENT_BY_HDR,          "X-Mms-Previously-Sent-By" },
175         { MM_PREV_SENT_DATE_HDR,        "X-Mms-Previously-Sent-Date" },
176         /* MMS 1.2 */
177         { MM_STORE_HDR,                 "X-Mms-Store" },
178         { MM_MM_STATE_HDR,              "X-Mms-MM-State" },
179         { MM_MM_FLAGS_HDR,              "X-Mms-MM-Flags" },
180         { MM_STORE_STATUS_HDR,          "X-Mms-Store-Status" },
181         { MM_STORE_STATUS_TEXT_HDR,     "X-Mms-Store-Status-Text" },
182         { MM_STORED_HDR,                "X-Mms-Stored" },
183         { MM_ATTRIBUTES_HDR,            "X-Mms-Attributes" },
184         { MM_TOTALS_HDR,                "X-Mms-Totals" },
185         { MM_MBOX_TOTALS_HDR,           "X-Mms-Mbox-Totals" },
186         { MM_QUOTAS_HDR,                "X-Mms-Quotas" },
187         { MM_MBOX_QUOTAS_HDR,           "X-Mms-Mbox-Quotas" },
188         { MM_MBOX_MSG_COUNT_HDR,        "X-Mms-Message-Count" },
189         { MM_CONTENT_HDR,               "Content" },
190         { MM_START_HDR,                 "X-Mms-Start" },
191         { MM_ADDITIONAL_HDR,            "Additional-headers" },
192         { MM_DISTRIBUION_IND_HDR,       "X-Mms-Distribution-Indcator" },
193         { MM_ELEMENT_DESCR_HDR,         "X-Mms-Element-Descriptor" },
194         { MM_LIMIT_HDR,                 "X-Mms-Limit" },
195
196         { 0x00, NULL },
197 };
198 /*
199  * Initialize the protocol and registered fields
200  */
201 static int proto_mmse = -1;
202
203 static int hf_mmse_message_type         = -1;
204 static int hf_mmse_transaction_id       = -1;
205 static int hf_mmse_mms_version          = -1;
206 static int hf_mmse_bcc                  = -1;
207 static int hf_mmse_cc                   = -1;
208 static int hf_mmse_content_location     = -1;
209 static int hf_mmse_date                 = -1;
210 static int hf_mmse_delivery_report      = -1;
211 static int hf_mmse_delivery_time_abs    = -1;
212 static int hf_mmse_delivery_time_rel    = -1;
213 static int hf_mmse_expiry_abs           = -1;
214 static int hf_mmse_expiry_rel           = -1;
215 static int hf_mmse_from                 = -1;
216 static int hf_mmse_message_class_id     = -1;
217 static int hf_mmse_message_class_str    = -1;
218 static int hf_mmse_message_id           = -1;
219 static int hf_mmse_message_size         = -1;
220 static int hf_mmse_priority             = -1;
221 static int hf_mmse_read_reply           = -1;
222 static int hf_mmse_report_allowed       = -1;
223 static int hf_mmse_response_status      = -1;
224 static int hf_mmse_response_text        = -1;
225 static int hf_mmse_sender_visibility    = -1;
226 static int hf_mmse_status               = -1;
227 static int hf_mmse_subject              = -1;
228 static int hf_mmse_to                   = -1;
229 static int hf_mmse_content_type         = -1;
230 static int hf_mmse_ffheader             = -1;
231 /* MMSE 1.1 */
232 static int hf_mmse_read_report          = -1;
233 static int hf_mmse_retrieve_status      = -1;
234 static int hf_mmse_retrieve_text        = -1;
235 static int hf_mmse_read_status          = -1;
236 static int hf_mmse_reply_charging       = -1;
237 static int hf_mmse_reply_charging_deadline_abs  = -1;
238 static int hf_mmse_reply_charging_deadline_rel  = -1;
239 static int hf_mmse_reply_charging_id    = -1;
240 static int hf_mmse_reply_charging_size  = -1;
241 static int hf_mmse_prev_sent_by = -1;
242 static int hf_mmse_prev_sent_by_fwd_count       = -1;
243 static int hf_mmse_prev_sent_by_address = -1;
244 static int hf_mmse_prev_sent_date       = -1;
245 static int hf_mmse_prev_sent_date_fwd_count     = -1;
246 static int hf_mmse_prev_sent_date_date  = -1;
247
248 /*
249  * Initialize the subtree pointers
250  */
251 static gint ett_mmse                    = -1;
252 static gint ett_mmse_hdr_details        = -1;
253
254 /*
255  * Valuestrings for PDU types
256  */
257 /* MMS 1.0 */
258 #define PDU_M_SEND_REQ          0x80
259 #define PDU_M_SEND_CONF         0x81
260 #define PDU_M_NOTIFICATION_IND  0x82
261 #define PDU_M_NOTIFYRESP_IND    0x83
262 #define PDU_M_RETRIEVE_CONF     0x84
263 #define PDU_M_ACKNOWLEDGE_IND   0x85
264 #define PDU_M_DELIVERY_IND      0x86
265 /* MMS 1.1 */
266 #define PDU_M_READ_REC_IND      0x87
267 #define PDU_M_READ_ORIG_IND     0x88
268 #define PDU_M_FORWARD_REQ       0x89
269 #define PDU_M_FORWARD_CONF      0x8A
270 /* MMS 1.2 */
271 #define PDU_M_MBOX_STORE_REQ    0x8B
272 #define PDU_M_MBOX_STORE_CONF   0x8C
273 #define PDU_M_MBOX_VIEW_REQ     0x8D
274 #define PDU_M_MBOX_VIEW_CONF    0x8E
275 #define PDU_M_MBOX_UPLOAD_REQ   0x8F
276 #define PDU_M_MBOX_UPLOAD_CONF  0x90
277 #define PDU_M_MBOX_DELETE_REQ   0x91
278 #define PDU_M_MBOX_DELETE_CONF  0x92
279 #define PDU_M_MBOX_DESCR        0x93
280
281 #define pdu_has_content(pdut) \
282         (  ((pdut) == PDU_M_SEND_REQ) \
283         || ((pdut) == PDU_M_DELIVERY_IND) \
284         || ((pdut) == PDU_M_RETRIEVE_CONF) \
285         || ((pdut) == PDU_M_MBOX_VIEW_CONF) \
286         || ((pdut) == PDU_M_MBOX_DESCR) \
287         || ((pdut) == PDU_M_MBOX_UPLOAD_REQ) \
288         )
289
290 static const value_string vals_message_type[] = {
291     /* MMS 1.0 */
292     { PDU_M_SEND_REQ,           "m-send-req" },
293     { PDU_M_SEND_CONF,          "m-send-conf" },
294     { PDU_M_NOTIFICATION_IND,   "m-notification-ind" },
295     { PDU_M_NOTIFYRESP_IND,     "m-notifyresp-ind" },
296     { PDU_M_RETRIEVE_CONF,      "m-retrieve-conf" },
297     { PDU_M_ACKNOWLEDGE_IND,    "m-acknowledge-ind" },
298     { PDU_M_DELIVERY_IND,       "m-delivery-ind" },
299     /* MMS 1.1 */
300     { PDU_M_READ_REC_IND,       "m-read-rec-ind" },
301     { PDU_M_READ_ORIG_IND,      "m-read-orig-ind" },
302     { PDU_M_FORWARD_REQ,        "m-forward-req" },
303     { PDU_M_FORWARD_CONF,       "m-forward-conf" },
304     /* MMS 1.2 */
305     { PDU_M_MBOX_STORE_REQ,     "m-mbox-store-req" },
306     { PDU_M_MBOX_STORE_CONF,    "m-mbox-store-conf" },
307     { PDU_M_MBOX_VIEW_REQ,      "m-mbox-view-req" },
308     { PDU_M_MBOX_VIEW_CONF,     "m-mbox-view-conf" },
309     { PDU_M_MBOX_UPLOAD_REQ,    "m-mbox-upload-req" },
310     { PDU_M_MBOX_UPLOAD_CONF,   "m-mbox-upload-conf" },
311     { PDU_M_MBOX_DELETE_REQ,    "m-mbox-delete-req" },
312     { PDU_M_MBOX_DELETE_CONF,   "m-mbox-delete-conf" },
313     { PDU_M_MBOX_DESCR,         "m-mbox-descr" },
314     { 0x00, NULL },
315 };
316
317 static const value_string vals_yes_no[] = {
318     { 0x80, "Yes" },
319     { 0x81, "No" },
320     { 0x00, NULL },
321 };
322
323 static const value_string vals_message_class[] = {
324     { 0x80, "Personal" },
325     { 0x81, "Advertisement" },
326     { 0x82, "Informational" },
327     { 0x83, "Auto" },
328     { 0x00, NULL },
329 };
330
331 static const value_string vals_priority[] = {
332     { 0x80, "Low" },
333     { 0x81, "Normal" },
334     { 0x82, "High" },
335     { 0x00, NULL },
336 };
337
338 static const value_string vals_response_status[] = {
339     /* MMS 1.0 - obsolete as from MMS 1.1 */
340     { 0x80, "Ok" },
341     { 0x81, "Unspecified" },
342     { 0x82, "Service denied" },
343     { 0x83, "Message format corrupt" },
344     { 0x84, "Sending address unresolved" },
345     { 0x85, "Message not found" },
346     { 0x86, "Network problem" },
347     { 0x87, "Content not accepted" },
348     { 0x88, "Unsupported message" },
349
350     /*
351      * Transient errors
352      */
353     /* MMS 1.1 */
354     { 0xC0, "Transient failure" },
355     { 0xC1, "Transient: Sending address unresolved" },
356     { 0xC2, "Transient: Message not found" },
357     { 0xC3, "Transient: Network problem" },
358     /* MMS 1.2 */
359     { 0xC4, "Transient: Partial success" },
360
361     /*
362      * Permanent errors
363      */
364     /* MMS 1.1 */
365     { 0xE0, "Permanent failure" },
366     { 0xE1, "Permanent: Service denied" },
367     { 0xE2, "Permanent: Message format corrupt" },
368     { 0xE3, "Permanent: Sending address unresolved" },
369     { 0xE4, "Permanent: Message not found" },
370     { 0xE5, "Permanent: Content not accepted" },
371     { 0xE6, "Permanent: Reply charging limitations not met" },
372     { 0xE7, "Permanent: Reply charging request not accepted" },
373     { 0xE8, "Permanent: Reply charging forwarding denied" },
374     { 0xE9, "Permanent: Reply charging not supported" },
375     /* MMS 1.2 */
376     { 0xEA, "Permanent: Address hiding not supported" },
377
378     { 0x00, NULL },
379 };
380
381 static const value_string vals_sender_visibility[] = {
382     { 0x80, "Hide" },
383     { 0x81, "Show" },
384     { 0x00, NULL },
385 };
386
387 static const value_string vals_message_status[] = {
388     /* MMS 1.0 */
389     { 0x80, "Expired" },
390     { 0x81, "Retrieved" },
391     { 0x82, "Rejected" },
392     { 0x83, "Deferred" },
393     { 0x84, "Unrecognized" },
394     /* MMS 1.1 */
395     { 0x85, "Indeterminate" },
396     { 0x86, "Forwarded" },
397     /* MMS 1.2 */
398     { 0x87, "Unreachable" },
399
400     { 0x00, NULL },
401 };
402
403 static const value_string vals_retrieve_status[] = {
404     /*
405      * Transient errors
406      */
407     /* MMS 1.1 */
408     { 0xC0, "Transient failure" },
409     { 0xC1, "Transient: Message not found" },
410     { 0xC2, "Transient: Network problem" },
411
412     /*
413      * Permanent errors
414      */
415     /* MMS 1.1 */
416     { 0xE0, "Permanent failure" },
417     { 0xE1, "Permanent: Service denied" },
418     { 0xE2, "Permanent: Message not found" },
419     { 0xE3, "Permanent: Content unsupported" },
420
421     { 0x00, NULL },
422 };
423
424 static const value_string vals_read_status[] = {
425     { 0x80, "Read" },
426     { 0x81, "Deleted without being read" },
427
428     { 0x00, NULL },
429 };
430
431 static const value_string vals_reply_charging[] = {
432     { 0x80, "Requested" },
433     { 0x81, "Requested text only" },
434     { 0x82, "Accepted" },
435     { 0x83, "Accepted text only" },
436
437     { 0x00, NULL },
438 };
439
440 /*!
441  * Decodes a Text-string from the protocol data
442  *      Text-string = [Quote] *TEXT End-of-string
443  *      Quote       = <Octet 127>
444  *      End-of-string = <Octet 0>
445  *
446  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
447  *
448  * \param       tvb     The buffer with PDU-data
449  * \param       offset  Offset within that buffer
450  * \param       strval  Pointer to variable into which to put pointer to
451  *                      buffer allocated to hold the text; must be freed
452  *                      when no longer used
453  *
454  * \return              The length in bytes of the entire field
455  */
456 static guint
457 get_text_string(tvbuff_t *tvb, guint offset, const char **strval)
458 {
459     guint        len;
460
461     DebugLog(("get_text_string(tvb = %p, offset = %u, **strval) - start\n",
462                 tvb, offset));
463     len = tvb_strsize(tvb, offset);
464     DebugLog((" [1] tvb_strsize(tvb, offset) == %u\n", len));
465     if (tvb_get_guint8(tvb, offset) == MM_QUOTE)
466         *strval = ep_tvb_memdup(tvb, offset+1, len-1);
467     else
468         *strval = ep_tvb_memdup(tvb, offset, len);
469     DebugLog((" [3] Return(len) == %u\n", len));
470     return len;
471 }
472
473 /*!
474  * Decodes a Value-length from the protocol data.
475  *      Value-length = Short-length | (Length-quote Length)
476  *      Short-length = <Any octet 0-30>
477  *      Length-quote = <Octet 31>
478  *      Length       = Uintvar-integer
479  *
480  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
481  *
482  * \param       tvb             The buffer with PDU-data
483  * \param       offset          Offset within that buffer
484  * \param       byte_count      Returns the length in bytes of
485  *                              the "Value-length" field.
486  *
487  * \return                      The actual value of "Value-length"
488  */
489 static guint
490 get_value_length(tvbuff_t *tvb, guint offset, guint *byte_count)
491 {
492     guint        field;
493
494     field = tvb_get_guint8(tvb, offset++);
495     if (field < 31)
496         *byte_count = 1;
497     else {                      /* Must be 31 so, Uintvar follows       */
498         field = tvb_get_guintvar(tvb, offset, byte_count);
499         (*byte_count)++;
500     }
501     return field;
502 }
503
504 /*!
505  * Decodes an Encoded-string-value from the protocol data
506  *      Encoded-string-value = Text-string | Value-length Char-set Text-string
507  *
508  * \param       tvb     The buffer with PDU-data
509  * \param       offset  Offset within that buffer
510  * \param       strval  Pointer to variable into which to put pointer to
511  *                      buffer allocated to hold the text; must be freed
512  *                      when no longer used
513  *
514  * \return              The length in bytes of the entire field
515  */
516 static guint
517 get_encoded_strval(tvbuff_t *tvb, guint offset, const char **strval)
518 {
519     guint        field;
520     guint        length;
521     guint        count;
522
523     field = tvb_get_guint8(tvb, offset);
524
525     if (field < 32) {
526         length = get_value_length(tvb, offset, &count);
527         if (length < 2) {
528             *strval = "";
529         } else {
530             /* \todo    Something with "Char-set", skip for now */
531             *strval = (char *)tvb_get_ephemeral_string(tvb, offset + count + 1, length - 1);
532         }
533         return count + length;
534     } else
535         return get_text_string(tvb, offset, strval);
536 }
537
538 /*!
539  * Decodes a Long-integer from the protocol data
540  *      Long-integer = Short-length Multi-octet-integer
541  *      Short-length = <Any octet 0-30>
542  *      Multi-octet-integer = 1*30OCTET
543  *
544  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
545  *
546  * \param       tvb             The buffer with PDU-data
547  * \param       offset          Offset within that buffer
548  * \param       byte_count      Returns the length in bytes of the field
549  *
550  * \return                      The value of the Long-integer
551  *
552  * \note        A maximum of 4-byte integers will be handled.
553  */
554 static guint
555 get_long_integer(tvbuff_t *tvb, guint offset, guint *byte_count)
556 {
557     guint        val;
558
559     *byte_count = tvb_get_guint8(tvb, offset++);
560     switch (*byte_count) {
561         case 1:
562             val = tvb_get_guint8(tvb, offset);
563             break;
564         case 2:
565             val = tvb_get_ntohs(tvb, offset);
566             break;
567         case 3:
568             val = tvb_get_ntoh24(tvb, offset);
569             break;
570         case 4:
571             val = tvb_get_ntohl(tvb, offset);
572             break;
573         default:
574             val = 0;
575             break;
576     }
577     (*byte_count)++;
578     return val;
579 }
580
581 /*!
582  * Decodes an Integer-value from the protocol data
583  *      Integer-value = Short-integer | Long-integer
584  *      Short-integer = OCTET
585  *      Long-integer = Short-length Multi-octet-integer
586  *      Short-length = <Any octet 0-30>
587  *      Multi-octet-integer = 1*30OCTET
588  *
589  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
590  *
591  * \param       tvb             The buffer with PDU-data
592  * \param       offset          Offset within that buffer
593  * \param       byte_count      Returns the length in bytes of the field
594  *
595  * \return                      The value of the Long-integer
596  *
597  * \note        A maximum of 4-byte integers will be handled.
598  */
599 static guint
600 get_integer_value(tvbuff_t *tvb, guint offset, guint *byte_count)
601 {
602     guint        val;
603     guint8 peek;
604
605     peek = tvb_get_guint8(tvb, offset++);
606     if (peek & 0x80) {
607         val = peek & 0x7F;
608         *byte_count = 1;
609         return val;
610     } else {
611         *byte_count = peek;
612         switch (peek) {
613         case 1:
614             val = tvb_get_guint8(tvb, offset);
615             break;
616         case 2:
617             val = tvb_get_ntohs(tvb, offset);
618             break;
619         case 3:
620             val = tvb_get_ntoh24(tvb, offset);
621             break;
622         case 4:
623             val = tvb_get_ntohl(tvb, offset);
624             break;
625         default:
626             val = 0;
627             break;
628         }
629     }
630     (*byte_count)++;
631     return val;
632 }
633
634 /* Code to actually dissect the packets */
635 static gboolean
636 dissect_mmse_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
637 {
638     guint8       pdut;
639
640         DebugLog(("dissect_mmse_heur()\n"));
641     /*
642      * Check if data makes sense for it to be dissected as MMSE:  Message-type
643      * field must make sense and followed by either Transaction-Id
644      * or MMS-Version header
645      */
646     if (tvb_get_guint8(tvb, 0) != MM_MTYPE_HDR)
647         return FALSE;
648     pdut = tvb_get_guint8(tvb, 1);
649     if (match_strval(pdut, vals_message_type) == NULL)
650         return FALSE;
651     if ((tvb_get_guint8(tvb, 2) != MM_TID_HDR) &&
652         (tvb_get_guint8(tvb, 2) != MM_VERSION_HDR))
653         return FALSE;
654     dissect_mmse_standalone(tvb, pinfo, tree);
655     return TRUE;
656 }
657
658 static void
659 dissect_mmse_standalone(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
660 {
661     guint8       pdut;
662     const char   *message_type;
663
664     DebugLog(("dissect_mmse_standalone() - START (Packet %u)\n",
665                 pinfo->fd->num));
666
667     pdut = tvb_get_guint8(tvb, 1);
668     message_type = val_to_str(pdut, vals_message_type, "Unknown type %u");
669
670     /* Make entries in Protocol column and Info column on summary display */
671     col_set_str(pinfo->cinfo, COL_PROTOCOL, "MMSE");
672
673     if (check_col(pinfo->cinfo, COL_INFO)) {
674         col_clear(pinfo->cinfo, COL_INFO);
675         col_add_fstr(pinfo->cinfo, COL_INFO, "MMS %s", message_type);
676     }
677
678     dissect_mmse(tvb, pinfo, tree, pdut, message_type);
679 }
680
681 static void
682 dissect_mmse_encapsulated(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
683 {
684     guint8       pdut;
685     const char   *message_type;
686
687     DebugLog(("dissect_mmse_encapsulated() - START (Packet %u)\n",
688                 pinfo->fd->num));
689
690     pdut = tvb_get_guint8(tvb, 1);
691     message_type = val_to_str(pdut, vals_message_type, "Unknown type %u");
692
693     /* Make entries in Info column on summary display */
694     if (check_col(pinfo->cinfo, COL_INFO)) {
695         col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(MMS %s)",
696                 message_type);
697     }
698
699     dissect_mmse(tvb, pinfo, tree, pdut, message_type);
700 }
701
702 static void
703 dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 pdut,
704         const char *message_type)
705 {
706     guint        offset;
707     guint8       field = 0;
708     const char   *strval;
709     guint        length;
710     guint        count;
711     guint8       version = 0x80; /* Default to MMSE 1.0 */
712
713     /* Set up structures needed to add the protocol subtree and manage it */
714     proto_item  *ti = NULL;
715     proto_tree  *mmse_tree = NULL;
716
717     DebugLog(("dissect_mmse() - START (Packet %u)\n", pinfo->fd->num));
718
719     /* If tree == NULL then we are only interested in protocol dissection
720      * up to reassembly and handoff to subdissectors if applicable; the
721      * columns must be set appropriately too.
722      * If tree != NULL then we also want to display the protocol tree
723      * with its fields.
724      *
725      * In the interest of speed, skip protocol tree item generation
726      * if tree is NULL.
727      */
728     if (tree) {
729         DebugLog(("tree != NULL\n"));
730
731         ti = proto_tree_add_item(tree, proto_mmse, tvb, 0, -1, FALSE);
732         proto_item_append_text(ti, ", Type: %s", message_type);
733         /* create display subtree for the protocol */
734         mmse_tree = proto_item_add_subtree(ti, ett_mmse);
735
736         /* Report PDU-type      */
737         proto_tree_add_uint(mmse_tree, hf_mmse_message_type, tvb, 0, 2, pdut);
738     }
739
740     offset = 2;                 /* Skip Message-Type    */
741
742     /*
743      * Cycle through MMS-headers
744      *
745      * NOTE - some PDUs may convey content which can be handed off
746      *        to subdissectors.
747      */
748     if (tree || pdu_has_content(pdut)) {
749         while ((offset < tvb_reported_length(tvb)) &&
750                (field = tvb_get_guint8(tvb, offset++)) != MM_CTYPE_HDR)
751         {
752             DebugLog(("\tField =  0x%02X (offset = %u): %s\n",
753                         field, offset,
754                         val_to_str(field, vals_mm_header_names,
755                             "Unknown MMS header 0x%02X")));
756             switch (field)
757             {
758                 case MM_TID_HDR:                /* Text-string  */
759                     length = get_text_string(tvb, offset, &strval);
760                     if (tree) {
761                         proto_tree_add_string(mmse_tree, hf_mmse_transaction_id,
762                                 tvb, offset - 1, length + 1,strval);
763                     }
764                     offset += length;
765                     break;
766                 case MM_VERSION_HDR:            /* nibble-Major/nibble-minor*/
767                     version = tvb_get_guint8(tvb, offset++);
768                     if (tree) {
769                         guint8   major, minor;
770                         char    *vers_string;
771
772                         major = (version & 0x70) >> 4;
773                         minor = version & 0x0F;
774                         if (minor == 0x0F)
775                             vers_string = g_strdup_printf("%u", major);
776                         else
777                             vers_string = g_strdup_printf("%u.%u", major, minor);
778                         proto_tree_add_string(mmse_tree, hf_mmse_mms_version,
779                                 tvb, offset - 2, 2, vers_string);
780                         g_free(vers_string);
781                     }
782                     break;
783                 case MM_BCC_HDR:                /* Encoded-string-value */
784                     length = get_encoded_strval(tvb, offset, &strval);
785                     if (tree) {
786                         proto_tree_add_string(mmse_tree, hf_mmse_bcc, tvb,
787                                 offset - 1, length + 1, strval);
788                     }
789                     offset += length;
790                     break;
791                 case MM_CC_HDR:                 /* Encoded-string-value */
792                     length = get_encoded_strval(tvb, offset, &strval);
793                     if (tree) {
794                         proto_tree_add_string(mmse_tree, hf_mmse_cc, tvb,
795                                 offset - 1, length + 1, strval);
796                     }
797                     offset += length;
798                     break;
799                 case MM_CLOCATION_HDR:          /* Uri-value            */
800                     if (pdut == PDU_M_MBOX_DELETE_CONF) {
801                         /* General form with length */
802                         length = tvb_get_guint8(tvb, offset);
803                         if (length == 0x1F) {
804                             guint length_len = 0;
805                             length = tvb_get_guintvar(tvb, offset + 1,
806                                     &length_len);
807                             length += 1 + length_len;
808                         } else {
809                             length += 1;
810                         }
811                         if (tree) {
812                             tvb_ensure_bytes_exist(tvb, offset - 1, length + 1);
813                             proto_tree_add_string(mmse_tree,
814                                     hf_mmse_content_location,
815                                     tvb, offset - 1, length + 1,
816                                     "<Undecoded value for m-mbox-delete-conf>");
817                         }
818                     } else {
819                         length = get_text_string(tvb, offset, &strval);
820                         if (tree) {
821                             proto_tree_add_string(mmse_tree,
822                                     hf_mmse_content_location,
823                                     tvb, offset - 1, length + 1, strval);
824                         }
825                     }
826                     offset += length;
827                     break;
828                 case MM_DATE_HDR:               /* Long-integer         */
829                     {
830                         guint            tval;
831                         nstime_t         tmptime;
832
833                         tval = get_long_integer(tvb, offset, &count);
834                         tmptime.secs = tval;
835                         tmptime.nsecs = 0;
836                         if (tree) {
837                             tvb_ensure_bytes_exist(tvb, offset - 1, count + 1);
838                             proto_tree_add_time(mmse_tree, hf_mmse_date, tvb,
839                                     offset - 1, count + 1, &tmptime);
840                         }
841                     }
842                     offset += count;
843                     break;
844                 case MM_DREPORT_HDR:            /* Yes|No               */
845                     field = tvb_get_guint8(tvb, offset++);
846                     if (tree) {
847                         proto_tree_add_uint(mmse_tree,
848                                 hf_mmse_delivery_report,
849                                 tvb, offset - 2, 2, field);
850                     }
851                     break;
852                 case MM_DTIME_HDR:
853                     /*
854                      * Value-length(Absolute-token Date-value|
855                      *              Relative-token Delta-seconds-value)
856                      */
857                     length = get_value_length(tvb, offset, &count);
858                     field = tvb_get_guint8(tvb, offset + count);
859                     if (tree) {
860                         guint            tval;
861                         nstime_t         tmptime;
862                         guint            cnt;
863
864                         tval =  get_long_integer(tvb, offset + count + 1, &cnt);
865                         tmptime.secs = tval;
866                         tmptime.nsecs = 0;
867
868                         tvb_ensure_bytes_exist(tvb, offset - 1, length + count + 1);
869                         if (field == 0x80)
870                             proto_tree_add_time(mmse_tree,
871                                     hf_mmse_delivery_time_abs,
872                                     tvb, offset - 1,
873                                     length + count + 1, &tmptime);
874                         else
875                             proto_tree_add_time(mmse_tree,
876                                     hf_mmse_delivery_time_rel,
877                                     tvb, offset - 1,
878                                     length + count + 1, &tmptime);
879                     }
880                     offset += length + count;
881                     break;
882                 case MM_EXPIRY_HDR:
883                     /*
884                      * Value-length(Absolute-token Date-value|
885                      *              Relative-token Delta-seconds-value)
886                      */
887                     length = get_value_length(tvb, offset, &count);
888                     field = tvb_get_guint8(tvb, offset + count);
889                     if (tree) {
890                         guint            tval;
891                         nstime_t         tmptime;
892                         guint            cnt;
893
894                         tval = get_long_integer(tvb, offset + count + 1, &cnt);
895                         tmptime.secs = tval;
896                         tmptime.nsecs = 0;
897
898                         tvb_ensure_bytes_exist(tvb, offset - 1, length + count + 1);
899                         if (field == 0x80)
900                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_abs,
901                                     tvb, offset - 1,
902                                     length + count + 1, &tmptime);
903                         else
904                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_rel,
905                                     tvb, offset - 1,
906                                     length + count + 1, &tmptime);
907                     }
908                     offset += length + count;
909                     break;
910                 case MM_FROM_HDR:
911                     /*
912                      * Value-length(Address-present-token Encoded-string-value
913                      *              |Insert-address-token)
914                      */
915                     length = get_value_length(tvb, offset, &count);
916                     if (tree) {
917                         field = tvb_get_guint8(tvb, offset + count);
918                         tvb_ensure_bytes_exist(tvb, offset - 1, length + count + 1);
919                         if (field == 0x81) {
920                             proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
921                                     offset-1, length + count + 1,
922                                     "<insert address>");
923                         } else {
924                             (void) get_encoded_strval(tvb, offset + count + 1,
925                                                       &strval);
926                             proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
927                                     offset-1, length + count + 1, strval);
928                         }
929                     }
930                     offset += length + count;
931                     break;
932                 case MM_MCLASS_HDR:
933                     /*
934                      * Class-identifier|Text-string
935                      */
936                     field = tvb_get_guint8(tvb, offset);
937                     if (field & 0x80) {
938                         offset++;
939                         if (tree) {
940                             proto_tree_add_uint(mmse_tree,
941                                     hf_mmse_message_class_id,
942                                     tvb, offset - 2, 2, field);
943                         }
944                     } else {
945                         length = get_text_string(tvb, offset, &strval);
946                         if (tree) {
947                             proto_tree_add_string(mmse_tree,
948                                     hf_mmse_message_class_str,
949                                     tvb, offset - 1, length + 1,
950                                     strval);
951                         }
952                         offset += length;
953                     }
954                     break;
955                 case MM_MID_HDR:                /* Text-string          */
956                     length = get_text_string(tvb, offset, &strval);
957                     if (tree) {
958                         proto_tree_add_string(mmse_tree, hf_mmse_message_id,
959                                 tvb, offset - 1, length + 1, strval);
960                     }
961                     offset += length;
962                     break;
963                 case MM_MSIZE_HDR:              /* Long-integer         */
964                     length = get_long_integer(tvb, offset, &count);
965                     if (tree) {
966                         proto_tree_add_uint(mmse_tree, hf_mmse_message_size,
967                                 tvb, offset - 1, count + 1, length);
968                     }
969                     offset += count;
970                     break;
971                 case MM_PRIORITY_HDR:           /* Low|Normal|High      */
972                     field = tvb_get_guint8(tvb, offset++);
973                     if (tree) {
974                         proto_tree_add_uint(mmse_tree, hf_mmse_priority, tvb,
975                                 offset - 2, 2, field);
976                     }
977                     break;
978                 case MM_RREPLY_HDR:             /* Yes|No               */
979                     field = tvb_get_guint8(tvb, offset++);
980                     if (tree) {
981                         if (version == 0x80) { /* MMSE 1.0 */
982                             proto_tree_add_uint(mmse_tree, hf_mmse_read_reply,
983                                     tvb, offset - 2, 2, field);
984                         } else {
985                             proto_tree_add_uint(mmse_tree, hf_mmse_read_report,
986                                     tvb, offset - 2, 2, field);
987                         }
988                     }
989                     break;
990                 case MM_RALLOWED_HDR:           /* Yes|No               */
991                     field = tvb_get_guint8(tvb, offset++);
992                     if (tree) {
993                         proto_tree_add_uint(mmse_tree, hf_mmse_report_allowed,
994                                 tvb, offset - 2, 2, field);
995                     }
996                     break;
997                 case MM_RSTATUS_HDR:
998                     field = tvb_get_guint8(tvb, offset++);
999                     if (tree) {
1000                         proto_tree_add_uint(mmse_tree, hf_mmse_response_status,
1001                                 tvb, offset - 2, 2, field);
1002                     }
1003                     break;
1004                 case MM_RTEXT_HDR:              /* Encoded-string-value */
1005                     if (pdut == PDU_M_MBOX_DELETE_CONF) {
1006                         /* General form with length */
1007                         length = tvb_get_guint8(tvb, offset);
1008                         if (length == 0x1F) {
1009                             guint length_len = 0;
1010                             length = tvb_get_guintvar(tvb, offset + 1,
1011                                     &length_len);
1012                             length += 1 + length_len;
1013                         } else {
1014                             length += 1;
1015                         }
1016                         if (tree) {
1017                             proto_tree_add_string(mmse_tree,
1018                                     hf_mmse_content_location,
1019                                     tvb, offset - 1, length + 1,
1020                                     "<Undecoded value for m-mbox-delete-conf>");
1021                         }
1022                     } else {
1023                         length = get_encoded_strval(tvb, offset, &strval);
1024                         if (tree) {
1025                             proto_tree_add_string(mmse_tree,
1026                                     hf_mmse_response_text, tvb, offset - 1,
1027                                     length + 1, strval);
1028                         }
1029                     }
1030                     offset += length;
1031                     break;
1032                 case MM_SVISIBILITY_HDR:        /* Hide|Show            */
1033                     field = tvb_get_guint8(tvb, offset++);
1034                     if (tree) {
1035                         proto_tree_add_uint(mmse_tree,hf_mmse_sender_visibility,
1036                                 tvb, offset - 2, 2, field);
1037                     }
1038                     break;
1039                 case MM_STATUS_HDR:
1040                     field = tvb_get_guint8(tvb, offset++);
1041                     if (tree) {
1042                         proto_tree_add_uint(mmse_tree, hf_mmse_status, tvb,
1043                                 offset - 2, 2, field);
1044                     }
1045                     break;
1046                 case MM_SUBJECT_HDR:            /* Encoded-string-value */
1047                     length = get_encoded_strval(tvb, offset, &strval);
1048                     if (tree) {
1049                         proto_tree_add_string(mmse_tree, hf_mmse_subject, tvb,
1050                                 offset - 1, length + 1, strval);
1051                     }
1052                     offset += length;
1053                     break;
1054                 case MM_TO_HDR:                 /* Encoded-string-value */
1055                     length = get_encoded_strval(tvb, offset, &strval);
1056                     if (tree) {
1057                         proto_tree_add_string(mmse_tree, hf_mmse_to, tvb,
1058                                 offset - 1, length + 1, strval);
1059                     }
1060                     offset += length;
1061                     break;
1062
1063                 /*
1064                  * MMS Encapsulation 1.1
1065                  */
1066                 case MM_RETRIEVE_STATUS_HDR:    /* Well-known-value */
1067                     field = tvb_get_guint8(tvb, offset++);
1068                     if (tree) {
1069                         proto_tree_add_uint(mmse_tree, hf_mmse_retrieve_status,
1070                                 tvb, offset - 2, 2, field);
1071                     }
1072                     break;
1073                 case MM_RETRIEVE_TEXT_HDR:
1074                     if (pdut == PDU_M_MBOX_DELETE_CONF) {
1075                         /* General form with length */
1076                         length = tvb_get_guint8(tvb, offset);
1077                         if (length == 0x1F) {
1078                             guint length_len = 0;
1079                             length = tvb_get_guintvar(tvb, offset + 1,
1080                                     &length_len);
1081                             length += 1 + length_len;
1082                         } else {
1083                             length += 1;
1084                         }
1085                         if (tree) {
1086                             proto_tree_add_string(mmse_tree,
1087                                     hf_mmse_content_location,
1088                                     tvb, offset - 1, length + 1,
1089                                     "<Undecoded value for m-mbox-delete-conf>");
1090                         }
1091                     } else {
1092                         /* Encoded-string-value */
1093                         length = get_encoded_strval(tvb, offset, &strval);
1094                         if (tree) {
1095                             proto_tree_add_string(mmse_tree,
1096                                     hf_mmse_retrieve_text, tvb, offset - 1,
1097                                     length + 1, strval);
1098                         }
1099                     }
1100                     offset += length;
1101                     break;
1102                 case MM_READ_STATUS_HDR:        /* Well-known-value */
1103                     field = tvb_get_guint8(tvb, offset++);
1104                     if (tree) {
1105                         proto_tree_add_uint(mmse_tree, hf_mmse_read_status,
1106                                 tvb, offset - 2, 2, field);
1107                     }
1108                     break;
1109                 case MM_REPLY_CHARGING_HDR:     /* Well-known-value */
1110                     field = tvb_get_guint8(tvb, offset++);
1111                     if (tree) {
1112                         proto_tree_add_uint(mmse_tree, hf_mmse_reply_charging,
1113                                 tvb, offset - 2, 2, field);
1114                     }
1115                     break;
1116                 case MM_REPLY_CHARGING_DEADLINE_HDR:    /* Well-known-value */
1117                     /*
1118                      * Value-length(Absolute-token Date-value|
1119                      *              Relative-token Delta-seconds-value)
1120                      */
1121                     length = get_value_length(tvb, offset, &count);
1122                     field = tvb_get_guint8(tvb, offset + count);
1123                     if (tree) {
1124                         guint            tval;
1125                         nstime_t         tmptime;
1126                         guint            cnt;
1127
1128                         tval = get_long_integer(tvb, offset + count + 1, &cnt);
1129                         tmptime.secs = tval;
1130                         tmptime.nsecs = 0;
1131
1132                         tvb_ensure_bytes_exist(tvb, offset - 1, length + count + 1);
1133                         if (field == 0x80)
1134                             proto_tree_add_time(mmse_tree, hf_mmse_reply_charging_deadline_abs,
1135                                     tvb, offset - 1,
1136                                     length + count + 1, &tmptime);
1137                         else
1138                             proto_tree_add_time(mmse_tree, hf_mmse_reply_charging_deadline_rel,
1139                                     tvb, offset - 1,
1140                                     length + count + 1, &tmptime);
1141                     }
1142                     offset += length + count;
1143                     break;
1144                 case MM_REPLY_CHARGING_ID_HDR:  /* Text-string */
1145                     length = get_text_string(tvb, offset, &strval);
1146                     if (tree) {
1147                         proto_tree_add_string(mmse_tree,
1148                                 hf_mmse_reply_charging_id,
1149                                 tvb, offset - 1, length + 1, strval);
1150                     }
1151                     offset += length;
1152                     break;
1153                 case MM_REPLY_CHARGING_SIZE_HDR:        /* Long-integer */
1154                     length = get_long_integer(tvb, offset, &count);
1155                     if (tree) {
1156                         proto_tree_add_uint(mmse_tree,
1157                                 hf_mmse_reply_charging_size,
1158                                 tvb, offset - 1, count + 1, length);
1159                     }
1160                     offset += count;
1161                     break;
1162                 case MM_PREV_SENT_BY_HDR:
1163                     /* Value-length Integer-value Encoded-string-value */
1164                     length = get_value_length(tvb, offset, &count);
1165                     if (tree) {
1166                         guint32 fwd_count, count1, count2;
1167                         proto_tree *subtree = NULL;
1168                         proto_item *tii = NULL;
1169                         /* 1. Forwarded-count-value := Integer-value */
1170                         fwd_count = get_integer_value(tvb, offset + count,
1171                             &count1);
1172                         /* 2. Encoded-string-value */
1173                         count2 = get_encoded_strval(tvb,
1174                                 offset + count + count1, &strval);
1175                         /* Now render the fields */
1176                         tii = proto_tree_add_string_format(mmse_tree,
1177                                 hf_mmse_prev_sent_by,
1178                                 tvb, offset - 1, 1 + count + length,
1179                                 strval, "%s (Forwarded-count=%u)",
1180                                 format_text(strval, strlen(strval)),
1181                                 fwd_count);
1182                         subtree = proto_item_add_subtree(tii,
1183                                 ett_mmse_hdr_details);
1184                         proto_tree_add_uint(subtree,
1185                                 hf_mmse_prev_sent_by_fwd_count,
1186                                 tvb, offset + count, count1, fwd_count);
1187                         proto_tree_add_string(subtree,
1188                                 hf_mmse_prev_sent_by_address,
1189                                 tvb, offset + count + count1, count2, strval);
1190                     }
1191                     offset += length + count;
1192                     break;
1193                 case MM_PREV_SENT_DATE_HDR:
1194                     /* Value-Length Forwarded-count-value Date-value */
1195                     length = get_value_length(tvb, offset, &count);
1196                     if (tree) {
1197                         guint32 fwd_count, count1, count2;
1198                         guint            tval;
1199                         nstime_t         tmptime;
1200                         proto_tree *subtree = NULL;
1201                         proto_item *tii = NULL;
1202                         /* 1. Forwarded-count-value := Integer-value */
1203                         fwd_count = get_integer_value(tvb, offset + count,
1204                             &count1);
1205                         /* 2. Date-value := Long-integer */
1206                         tval = get_long_integer(tvb, offset + count + count1,
1207                                 &count2);
1208                         tmptime.secs = tval;
1209                         tmptime.nsecs = 0;
1210                         strval = abs_time_to_str(&tmptime, ABSOLUTE_TIME_LOCAL,
1211                             TRUE);
1212                         /* Now render the fields */
1213                         tvb_ensure_bytes_exist(tvb, offset - 1, length + count + 1);
1214                         tii = proto_tree_add_string_format(mmse_tree,
1215                                 hf_mmse_prev_sent_date,
1216                                 tvb, offset - 1, 1 + count + length,
1217                                 strval, "%s (Forwarded-count=%u)",
1218                                 format_text(strval, strlen(strval)),
1219                                 fwd_count);
1220                         subtree = proto_item_add_subtree(tii,
1221                                 ett_mmse_hdr_details);
1222                         proto_tree_add_uint(subtree,
1223                                 hf_mmse_prev_sent_date_fwd_count,
1224                                 tvb, offset + count, count1, fwd_count);
1225                         proto_tree_add_string(subtree,
1226                                 hf_mmse_prev_sent_date_date,
1227                                 tvb, offset + count + count1, count2, strval);
1228                     }
1229                     offset += length + count;
1230                     break;
1231
1232                 /* MMS Encapsulation 1.2 */
1233
1234                 default:
1235                     if (field & 0x80) { /* Well-known WSP header encoding */
1236                         guint8 peek = tvb_get_guint8(tvb, offset);
1237                         const char *hdr_name = val_to_str(field, vals_mm_header_names,
1238                                 "Unknown field (0x%02x)");
1239                         DebugLog(("\t\tUndecoded well-known header: %s\n",
1240                                     hdr_name));
1241
1242                         if (peek & 0x80) { /* Well-known value */
1243                             length = 1;
1244                             if (tree) {
1245                                 proto_tree_add_text(mmse_tree, tvb, offset - 1,
1246                                         length + 1,
1247                                         "%s: <Well-known value 0x%02x>"
1248                                         " (not decoded)",
1249                                         hdr_name, peek);
1250                             }
1251                         } else if ((peek == 0) || (peek >= 0x20)) { /* Text */
1252                             length = get_text_string(tvb, offset, &strval);
1253                             if (tree) {
1254                                 proto_tree_add_text(mmse_tree, tvb, offset - 1,
1255                                         length + 1, "%s: %s (Not decoded)",
1256                                         hdr_name,
1257                                         format_text(strval, strlen(strval)));
1258                             }
1259                         } else { /* General form with length */
1260                             if (peek == 0x1F) { /* Value length in guintvar */
1261                                 guint length_len = 0;
1262                                 length = 1 + tvb_get_guintvar(tvb, offset + 1,
1263                                         &length_len);
1264                                 length += length_len;
1265                             } else { /* Value length in octet */
1266                                 length = 1 + tvb_get_guint8(tvb, offset);
1267                             }
1268                             if (tree) {
1269                                 proto_tree_add_text(mmse_tree, tvb, offset - 1,
1270                                         length + 1, "%s: "
1271                                         "<Value in general form> (not decoded)",
1272                                         hdr_name);
1273                             }
1274                         }
1275                         offset += length;
1276                     } else { /* Literal WSP header encoding */
1277                         guint            length2;
1278                         const char       *strval2;
1279
1280                         --offset;
1281                         length = get_text_string(tvb, offset, &strval);
1282                         DebugLog(("\t\tUndecoded literal header: %s\n",
1283                                     strval));
1284                         length2= get_text_string(tvb, offset+length, &strval2);
1285
1286                         if (tree) {
1287                             proto_tree_add_string_format(mmse_tree,
1288                                     hf_mmse_ffheader, tvb, offset,
1289                                     length + length2,
1290                                     tvb_get_ephemeral_string(tvb, offset,
1291                                             length + length2),
1292                                     "%s: %s",
1293                                     format_text(strval, strlen(strval)),
1294                                     format_text(strval2, strlen(strval2)));
1295                         }
1296                         offset += length + length2;
1297                     }
1298                     break;
1299             }
1300             DebugLog(("\tEnd(case)\n"));
1301         }
1302         DebugLog(("\tEnd(switch)\n"));
1303         if (field == MM_CTYPE_HDR) {
1304             /*
1305              * Eeehh, we're now actually back to good old WSP content-type
1306              * encoding. Let's steal that from the WSP-dissector.
1307              */
1308             tvbuff_t    *tmp_tvb;
1309             guint        type;
1310             const char  *type_str;
1311
1312             DebugLog(("Content-Type: [from WSP dissector]\n"));
1313             DebugLog(("Calling add_content_type() in WSP dissector\n"));
1314             offset = add_content_type(mmse_tree, tvb, offset, &type, &type_str);
1315             DebugLog(("Generating new TVB subset (offset = %u)\n", offset));
1316             tmp_tvb = tvb_new_subset_remaining(tvb, offset);
1317             DebugLog(("Add POST data\n"));
1318             add_post_data(mmse_tree, tmp_tvb, type, type_str, pinfo);
1319             DebugLog(("Done!\n"));
1320         }
1321     } else {
1322         DebugLog(("tree == NULL and PDU has no potential content\n"));
1323     }
1324
1325     /* If this protocol has a sub-dissector call it here, see section 1.8 */
1326     DebugLog(("dissect_mmse() - END\n"));
1327 }
1328
1329
1330 /* Register the protocol with Wireshark */
1331
1332 /* this format is required because a script is used to build the C function
1333  * that calls all the protocol registration.
1334  */
1335 void
1336 proto_register_mmse(void)
1337 {
1338     /* Setup list of header fields  See Section 1.6.1 for details       */
1339     static hf_register_info hf[] = {
1340         {   &hf_mmse_message_type,
1341             {   "X-Mms-Message-Type", "mmse.message_type",
1342                 FT_UINT8, BASE_HEX, VALS(vals_message_type), 0x00,
1343                 "Specifies the transaction type. Effectively defines PDU.",
1344                 HFILL
1345             }
1346         },
1347         {   &hf_mmse_transaction_id,
1348             {   "X-Mms-Transaction-ID", "mmse.transaction_id",
1349                 FT_STRING, BASE_NONE, NULL, 0x00,
1350                 "A unique identifier for this transaction. Identifies request and corresponding response only.",
1351                 HFILL
1352             }
1353         },
1354         {   &hf_mmse_mms_version,
1355             {   "X-Mms-MMS-Version", "mmse.mms_version",
1356                 FT_STRING, BASE_NONE, NULL, 0x00,
1357                 "Version of the protocol used.",
1358                 HFILL
1359             }
1360         },
1361         {   &hf_mmse_bcc,
1362             {   "Bcc", "mmse.bcc",
1363                 FT_STRING, BASE_NONE, NULL, 0x00,
1364                 "Blind carbon copy.",
1365                 HFILL
1366             }
1367         },
1368         {   &hf_mmse_cc,
1369             {   "Cc", "mmse.cc",
1370                 FT_STRING, BASE_NONE, NULL, 0x00,
1371                 "Carbon copy.",
1372                 HFILL
1373             }
1374         },
1375         {   &hf_mmse_content_location,
1376             {   "X-Mms-Content-Location", "mmse.content_location",
1377                 FT_STRING, BASE_NONE, NULL, 0x00,
1378                 "Defines the location of the message.",
1379                 HFILL
1380             }
1381         },
1382         {   &hf_mmse_date,
1383             {   "Date", "mmse.date",
1384                 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
1385                 "Arrival timestamp of the message or sending timestamp.",
1386                 HFILL
1387             }
1388         },
1389         {   &hf_mmse_delivery_report,
1390             {   "X-Mms-Delivery-Report", "mmse.delivery_report",
1391                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
1392                 "Whether a report of message delivery is wanted or not.",
1393                 HFILL
1394             }
1395         },
1396         {   &hf_mmse_delivery_time_abs,
1397             {   "X-Mms-Delivery-Time", "mmse.delivery_time.abs",
1398                 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
1399                 "The time at which message delivery is desired.",
1400                 HFILL
1401             }
1402         },
1403         {   &hf_mmse_delivery_time_rel,
1404             {   "X-Mms-Delivery-Time", "mmse.delivery_time.rel",
1405                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
1406                 "The desired message delivery delay.",
1407                 HFILL
1408             }
1409         },
1410         {   &hf_mmse_expiry_abs,
1411             {   "X-Mms-Expiry", "mmse.expiry.abs",
1412                 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
1413                 "Time when message expires and need not be delivered anymore.",
1414                 HFILL
1415             }
1416         },
1417         {   &hf_mmse_expiry_rel,
1418             {   "X-Mms-Expiry", "mmse.expiry.rel",
1419                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
1420                 "Delay before message expires and need not be delivered anymore.",
1421                 HFILL
1422             }
1423         },
1424         {   &hf_mmse_from,
1425             {   "From", "mmse.from",
1426                 FT_STRING, BASE_NONE, NULL, 0x00,
1427                 "Address of the message sender.",
1428                 HFILL
1429             }
1430         },
1431         {   &hf_mmse_message_class_id,
1432             {   "X-Mms-Message-Class", "mmse.message_class.id",
1433                 FT_UINT8, BASE_HEX, VALS(vals_message_class), 0x00,
1434                 "Of what category is the message.",
1435                 HFILL
1436             }
1437         },
1438         {   &hf_mmse_message_class_str,
1439             {   "X-Mms-Message-Class", "mmse.message_class.str",
1440                 FT_STRING, BASE_NONE, NULL, 0x00,
1441                 "Of what category is the message.",
1442                 HFILL
1443             }
1444         },
1445         {   &hf_mmse_message_id,
1446             {   "Message-Id", "mmse.message_id",
1447                 FT_STRING, BASE_NONE, NULL, 0x00,
1448                 "Unique identification of the message.",
1449                 HFILL
1450             }
1451         },
1452         {   &hf_mmse_message_size,
1453             {   "X-Mms-Message-Size", "mmse.message_size",
1454                 FT_UINT32, BASE_DEC, NULL, 0x00,
1455                 "The size of the message in octets.",
1456                 HFILL
1457             }
1458         },
1459         {   &hf_mmse_priority,
1460             {   "X-Mms-Priority", "mmse.priority",
1461                 FT_UINT8, BASE_HEX, VALS(vals_priority), 0x00,
1462                 "Priority of the message.",
1463                 HFILL
1464             }
1465         },
1466         {   &hf_mmse_read_reply,
1467             {   "X-Mms-Read-Reply", "mmse.read_reply",
1468                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
1469                 "Whether a read report from every recipient is wanted.",
1470                 HFILL
1471             }
1472         },
1473         {   &hf_mmse_read_report,
1474             {   "X-Mms-Read-Report", "mmse.read_report",
1475                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
1476                 "Whether a read report from every recipient is wanted.",
1477                 HFILL
1478             }
1479         },
1480         {   &hf_mmse_report_allowed,
1481             {   "X-Mms-Report-Allowed", "mmse.report_allowed",
1482                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
1483                 "Sending of delivery report allowed or not.",
1484                 HFILL
1485             }
1486         },
1487         {   &hf_mmse_response_status,
1488             {   "Response-Status", "mmse.response_status",
1489                 FT_UINT8, BASE_HEX, VALS(vals_response_status), 0x00,
1490                 "MMS-specific result of a message submission or retrieval.",
1491                 HFILL
1492             }
1493         },
1494         {   &hf_mmse_response_text,
1495             {   "Response-Text", "mmse.response_text",
1496                 FT_STRING, BASE_NONE, NULL, 0x00,
1497                 "Additional information on MMS-specific result.",
1498                 HFILL
1499             }
1500         },
1501         {   &hf_mmse_sender_visibility,
1502             {   "Sender-Visibility", "mmse.sender_visibility",
1503                 FT_UINT8, BASE_HEX, VALS(vals_sender_visibility), 0x00,
1504                 "Disclose sender identity to receiver or not.",
1505                 HFILL
1506             }
1507         },
1508         {   &hf_mmse_status,
1509             {   "Status", "mmse.status",
1510                 FT_UINT8, BASE_HEX, VALS(vals_message_status), 0x00,
1511                 "Current status of the message.",
1512                 HFILL
1513             }
1514         },
1515         {   &hf_mmse_subject,
1516             {   "Subject", "mmse.subject",
1517                 FT_STRING, BASE_NONE, NULL, 0x00,
1518                 "Subject of the message.",
1519                 HFILL
1520             }
1521         },
1522         {   &hf_mmse_to,
1523             {   "To", "mmse.to",
1524                 FT_STRING, BASE_NONE, NULL, 0x00,
1525                 "Recipient(s) of the message.",
1526                 HFILL
1527             }
1528         },
1529         {   &hf_mmse_content_type,
1530             {   "Data", "mmse.content_type",
1531                 FT_NONE, BASE_NONE, NULL, 0x00,
1532                 "Media content of the message.",
1533                 HFILL
1534             }
1535         },
1536         {   &hf_mmse_ffheader,
1537             {   "Free format (not encoded) header", "mmse.ffheader",
1538                 FT_STRING, BASE_NONE, NULL, 0x00,
1539                 "Application header without corresponding encoding.",
1540                 HFILL
1541             }
1542         },
1543         /* MMSE 1.1 */
1544         {   &hf_mmse_retrieve_status,
1545             {   "X-Mms-Retrieve-Status", "mmse.retrieve_status",
1546                 FT_UINT8, BASE_HEX, VALS(vals_retrieve_status), 0x00,
1547                 "MMS-specific result of a message retrieval.",
1548                 HFILL
1549             }
1550         },
1551         {   &hf_mmse_retrieve_text,
1552             {   "X-Mms-Retrieve-Text", "mmse.retrieve_text",
1553                 FT_STRING, BASE_NONE, NULL, 0x00,
1554                 "Status text of a MMS message retrieval.",
1555                 HFILL
1556             }
1557         },
1558         {   &hf_mmse_read_status,
1559             {   "X-Mms-Read-Status", "mmse.read_status",
1560                 FT_UINT8, BASE_HEX, VALS(vals_read_status), 0x00,
1561                 "MMS-specific message read status.",
1562                 HFILL
1563             }
1564         },
1565         {   &hf_mmse_reply_charging,
1566             {   "X-Mms-Reply-Charging", "mmse.reply_charging",
1567                 FT_UINT8, BASE_HEX, VALS(vals_reply_charging), 0x00,
1568                 "MMS-specific message reply charging method.",
1569                 HFILL
1570             }
1571         },
1572         {   &hf_mmse_reply_charging_deadline_abs,
1573             {   "X-Mms-Reply-Charging-Deadline", "mmse.reply_charging_deadline.abs",
1574                 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
1575                 "The latest time of the recipient(s) to submit the Reply MM.",
1576                 HFILL
1577             }
1578         },
1579         {   &hf_mmse_reply_charging_deadline_rel,
1580             {   "X-Mms-Reply-Charging-Deadline", "mmse.reply_charging_deadline.rel",
1581                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
1582                 "The latest time of the recipient(s) to submit the Reply MM.",
1583                 HFILL
1584             }
1585         },
1586         {   &hf_mmse_reply_charging_id,
1587             {   "X-Mms-Reply-Charging-Id", "mmse.reply_charging_id",
1588                 FT_STRING, BASE_NONE, NULL, 0x00,
1589                 "Unique reply charging identification of the message.",
1590                 HFILL
1591             }
1592         },
1593         {   &hf_mmse_reply_charging_size,
1594             {   "X-Mms-Reply-Charging-Size", "mmse.reply_charging_size",
1595                 FT_UINT32, BASE_DEC, NULL, 0x00,
1596                 "The size of the reply charging in octets.",
1597                 HFILL
1598             }
1599         },
1600         {   &hf_mmse_prev_sent_by,
1601             {   "X-Mms-Previously-Sent-By", "mmse.previously_sent_by",
1602                 FT_STRING, BASE_NONE, NULL, 0x00,
1603                 "Indicates that the MM has been previously sent by this user.",
1604                 HFILL
1605             }
1606         },
1607         {   &hf_mmse_prev_sent_by_fwd_count,
1608             {   "Forward Count", "mmse.previously_sent_by.forward_count",
1609                 FT_UINT32, BASE_DEC, NULL, 0x00,
1610                 "Forward count of the previously sent MM.",
1611                 HFILL
1612             }
1613         },
1614         {   &hf_mmse_prev_sent_by_address,
1615             {   "Address", "mmse.previously_sent_by.address",
1616                 FT_STRING, BASE_NONE, NULL, 0x00,
1617                 "Indicates from whom the MM has been previously sent.",
1618                 HFILL
1619             }
1620         },
1621         {   &hf_mmse_prev_sent_date,
1622             {   "X-Mms-Previously-Sent-Date", "mmse.previously_sent_date",
1623                 FT_STRING, BASE_NONE, NULL, 0x00,
1624                 "Indicates the date that the MM has been previously sent.",
1625                 HFILL
1626             }
1627         },
1628         {   &hf_mmse_prev_sent_date_fwd_count,
1629             {   "Forward Count", "mmse.previously_sent_date.forward_count",
1630                 FT_UINT32, BASE_DEC, NULL, 0x00,
1631                 "Forward count of the previously sent MM.",
1632                 HFILL
1633             }
1634         },
1635         {   &hf_mmse_prev_sent_date_date,
1636             {   "Date", "mmse.previously_sent_date.date",
1637                 FT_STRING, BASE_NONE, NULL, 0x00,
1638                 "Time when the MM has been previously sent.",
1639                 HFILL
1640             }
1641         },
1642
1643
1644
1645     };
1646     /* Setup protocol subtree array */
1647     static gint *ett[] = {
1648         &ett_mmse,
1649         &ett_mmse_hdr_details,
1650     };
1651
1652     /* Register the protocol name and description */
1653     proto_mmse = proto_register_protocol("MMS Message Encapsulation",
1654                                          "MMSE", "mmse");
1655
1656     /* Required function calls to register header fields and subtrees used */
1657     proto_register_field_array(proto_mmse, hf, array_length(hf));
1658     proto_register_subtree_array(ett, array_length(ett));
1659 }
1660
1661 /* If this dissector uses sub-dissector registration add registration routine.
1662  * This format is required because a script is used to find these routines and
1663  * create the code that calls these routines.
1664  */
1665 void
1666 proto_reg_handoff_mmse(void)
1667 {
1668     dissector_handle_t mmse_standalone_handle;
1669     dissector_handle_t mmse_encapsulated_handle;
1670
1671     heur_dissector_add("wsp", dissect_mmse_heur, proto_mmse);
1672     mmse_standalone_handle = create_dissector_handle(
1673             dissect_mmse_standalone, proto_mmse);
1674     mmse_encapsulated_handle = create_dissector_handle(
1675             dissect_mmse_encapsulated, proto_mmse);
1676         /* As the media types for WSP and HTTP are the same, the WSP dissector
1677          * uses the same string dissector table as the HTTP protocol. */
1678     dissector_add_string("media_type",
1679             "application/vnd.wap.mms-message", mmse_standalone_handle);
1680     dissector_add_string("multipart_media_type",
1681             "application/vnd.wap.mms-message", mmse_encapsulated_handle);
1682 }