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