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