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