e7c759ca669dcc42587b29bad67d13ea3aff2576
[obnox/wireshark/wip.git] / epan / dissectors / packet-msrp.c
1 /* packet-msrp.c
2  * Routines for Message Session Relay Protocol(MSRP) dissection
3  * Copyright 2005, Anders Broman <anders.broman[at]ericsson.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  *
25  * References:
26  * http://www.ietf.org/internet-drafts/draft-ietf-simple-message-sessions-10.txt
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include <glib.h>
39 #include <epan/conversation.h>
40
41 #include <epan/packet.h>
42 #include <epan/emem.h>
43 #include "prefs.h"
44
45 #include "packet-msrp.h"
46
47 #define TCP_PORT_MSRP 0
48
49 #define MSRP_HDR "MSRP"
50 #define MSRP_HDR_LEN (strlen (MSRP_HDR))
51
52 /* Initialize the protocol and registered fields */
53 static int proto_msrp           = -1;
54
55 /* Initialize the subtree pointers */
56 static int ett_msrp                                     = -1;
57 static int ett_raw_text                         = -1;
58 static int ett_msrp_reqresp                     = -1;
59 static int ett_msrp_hdr                         = -1;
60 static int ett_msrp_element                     = -1;
61 static int ett_msrp_data                        = -1;
62 static int ett_msrp_end_line            = -1;
63 static int ett_msrp_setup                       = -1;
64
65 static int hf_msrp_response_line        = -1;
66 static int hf_msrp_request_line         = -1;
67 static int hf_msrp_transactionID        = -1;
68 static int hf_msrp_method                       = -1;
69 static int hf_msrp_status_code          = -1;
70 static int hf_msrp_msg_hdr                      = -1;
71 static int hf_msrp_end_line                     = -1;
72 static int hf_msrp_cnt_flg                      = -1;
73
74 static int hf_msrp_data                         = -1;
75
76 /* MSRP setup fields */
77 static int hf_msrp_setup        = -1;
78 static int hf_msrp_setup_frame  = -1;
79 static int hf_msrp_setup_method = -1;
80
81 typedef struct {
82         const char *name;
83 } msrp_header_t;
84
85 static const msrp_header_t msrp_headers[] = {
86         { "Unknown-header"},
87         { "From-Path"},                         /*  1 */
88         { "To-Path"},                           /*  2 */
89         { "Message-ID"},                        /*  3 */
90         { "Success-Report"},            /*  4 */
91         { "Failure-Report"},            /*  5 */
92         { "Byte-Range"},                        /*  6 */
93         { "Status"},                            /*  7 */
94         { "Content-Type"},                      /*  8 */
95         { "Content-ID"},                        /*  9 */
96         { "Content-Description"},       /*  10 */
97         { "Content-Disposition"},       /*  11 */
98         { "Use-Path"},                          /*  12 */
99         { "WWW-Authenticate"},          /*  13 */
100         { "Authorization"},                     /*  14 */
101         { "Authentication-Info"},       /*  15 */
102 };
103
104 static gint hf_header_array[] = {
105         -1, /* 0"Unknown-header" - Pad so that the real headers start at index 1 */
106         -1, /* 1"From-Path                                                                                                               */
107         -1, /* 2"To-Path                                                                                                                 */
108         -1, /* 3"Message-ID"                                                                                                     */
109         -1, /* 4"Success-Report"                                                                                                 */
110         -1, /* 5"Failure-Report"                                                                                                 */
111         -1, /* 6"Byte-Range"                                                                                                     */
112         -1, /* 7"Status"                                                                                                                 */
113         -1, /* 8"Content-Type"                                                                                                   */
114         -1, /* 9"Content-ID"                                                                                                     */
115         -1, /* 10"Content-Description"                                                                                   */
116         -1, /* 11"Content-Disposition"                                                                                   */
117         -1, /* 12"Use-Path"                                                                                                              */
118         -1, /* 13"WWW-Authenticate"                                                                                              */
119         -1, /* 14"Authorization"                                                                                                 */
120         -1, /* 15"Authentication-Info"                                                                                   */
121 };
122
123 #define MSRP_FROM_PATH                                                  1
124 #define MSRP_TO_PATH                                                    2
125 #define MSRP_MESSAGE_ID                                                 3
126 #define MSRP_SUCCESS_REPORT                                             4
127 #define MSRP_FAILURE_REPORT                                             5
128 #define MSRP_BYTE_RANGE                                                 6
129 #define MSRP_STATUS                                                             7
130 #define MSRP_CONTENT_TYPE                                               8
131 #define MSRP_CONTENT_ID                                                 9
132 #define MSRP_CONTENT_DISCRIPTION                                10
133 #define MSRP_CONTENT_DISPOSITION                                11
134 #define MSRP_USE_PATH                                                   12
135 #define MSRP_WWW_AUTHENTICATE                                   13
136 #define MSRP_AUTHORIZATION                                              14
137 #define MSRP_AUTHENTICATION_INFO                                15
138
139 static dissector_handle_t msrp_handle;
140 gboolean global_msrp_raw_text = TRUE;
141
142 /* MSRP content type and internet media type used by other dissectors
143  * are the same.  List of media types from IANA at:
144  * http://www.iana.org/assignments/media-types/index.html */
145 static dissector_table_t media_type_dissector_table;
146
147 static int dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
148
149
150 /* Displaying conversation setup info */
151 static gboolean global_msrp_show_setup_info = TRUE;
152 static void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
153
154 /* Set up an MSRP conversation using the info given */
155 void msrp_add_address( packet_info *pinfo,
156                        address *addr, int port,
157                        const gchar *setup_method, guint32 setup_frame_number)
158 {
159         address null_addr;
160         conversation_t* p_conv;
161         struct _msrp_conversation_info *p_conv_data = NULL;
162
163         /*
164          * If this isn't the first time this packet has been processed,
165          * we've already done this work, so we don't need to do it
166          * again.
167          */
168         if (pinfo->fd->flags.visited)
169         {
170                 return;
171         }
172
173         SET_ADDRESS(&null_addr, AT_NONE, 0, NULL);
174
175         /*
176          * Check if the ip address and port combination is not
177          * already registered as a conversation.
178          */
179         p_conv = find_conversation( pinfo->fd->num, addr, &null_addr, PT_TCP, port, 0,
180                                     NO_ADDR_B | NO_PORT_B);
181
182         /*
183          * If not, create a new conversation.
184          */
185         if (!p_conv) {
186                 p_conv = conversation_new( pinfo->fd->num, addr, &null_addr, PT_TCP,
187                                            (guint32)port, 0,
188                                            NO_ADDR2 | NO_PORT2);
189         }
190
191         /* Set dissector */
192         conversation_set_dissector(p_conv, msrp_handle);
193
194         /*
195          * Check if the conversation has data associated with it.
196          */
197         p_conv_data = conversation_get_proto_data(p_conv, proto_msrp);
198
199         /*
200          * If not, add a new data item.
201          */
202         if (!p_conv_data) {
203                 /* Create conversation data */
204                 p_conv_data = se_alloc(sizeof(struct _msrp_conversation_info));
205                 if (!p_conv_data)
206                 {
207                         return;
208                 }
209                 memset(p_conv_data, 0, sizeof(struct _msrp_conversation_info));
210                 conversation_add_proto_data(p_conv, proto_msrp, p_conv_data);
211         }
212
213         /*
214          * Update the conversation data.
215          */
216         p_conv_data->setup_method_set = TRUE;
217         strncpy(p_conv_data->setup_method, setup_method, MAX_MSRP_SETUP_METHOD_SIZE);
218         p_conv_data->setup_method[MAX_MSRP_SETUP_METHOD_SIZE] = '\0';
219         p_conv_data->setup_frame_number = setup_frame_number;
220 }
221
222
223
224 /* Look for conversation info and display any setup info found */
225 void show_setup_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
226 {
227         /* Conversation and current data */
228         conversation_t *p_conv = NULL;
229         struct _msrp_conversation_info *p_conv_data = NULL;
230
231         /* Use existing packet data if available */
232         p_conv_data = p_get_proto_data(pinfo->fd, proto_msrp);
233
234         if (!p_conv_data)
235         {
236                 /* First time, get info from conversation */
237                 p_conv = find_conversation(pinfo->fd->num, &pinfo->net_dst, &pinfo->net_src,
238                                            PT_TCP,
239                                            pinfo->destport, pinfo->srcport, 0);
240
241                 if (p_conv)
242                 {
243                         /* Look for data in conversation */
244                         struct _msrp_conversation_info *p_conv_packet_data;
245                         p_conv_data = conversation_get_proto_data(p_conv, proto_msrp);
246
247                         if (p_conv_data)
248                         {
249                                 /* Save this conversation info into packet info */
250                                 p_conv_packet_data = se_alloc(sizeof(struct _msrp_conversation_info));
251                                 if (!p_conv_packet_data)
252                                 {
253                                         return;
254                                 }
255                                 memcpy(p_conv_packet_data, p_conv_data,
256                                        sizeof(struct _msrp_conversation_info));
257
258                                 p_add_proto_data(pinfo->fd, proto_msrp, p_conv_packet_data);
259                         }
260                 }                                                           
261         }
262
263         /* Create setup info subtree with summary info. */
264         if (p_conv_data && p_conv_data->setup_method_set)
265         {
266                 proto_tree *msrp_setup_tree;
267                 proto_item *ti =  proto_tree_add_string_format(tree, hf_msrp_setup, tvb, 0, 0,
268                                                                "",
269                                                                "Stream setup by %s (frame %u)",
270                                                                p_conv_data->setup_method,
271                                                                p_conv_data->setup_frame_number);
272                 PROTO_ITEM_SET_GENERATED(ti);
273                 msrp_setup_tree = proto_item_add_subtree(ti, ett_msrp_setup);
274                 if (msrp_setup_tree)
275                 {
276                         /* Add details into subtree */
277                         proto_item* item = proto_tree_add_uint(msrp_setup_tree, hf_msrp_setup_frame,
278                                                                tvb, 0, 0, p_conv_data->setup_frame_number);
279                         PROTO_ITEM_SET_GENERATED(item);
280                         item = proto_tree_add_string(msrp_setup_tree, hf_msrp_setup_method,
281                                                      tvb, 0, 0, p_conv_data->setup_method);
282                         PROTO_ITEM_SET_GENERATED(item);
283                 }
284         }
285 }
286
287
288
289 /* Returns index of headers */
290 static gint msrp_is_known_msrp_header(tvbuff_t *tvb, int offset, guint header_len)
291 {
292         guint i;
293
294         for (i = 1; i < array_length(msrp_headers); i++) {
295                 if (header_len == strlen(msrp_headers[i].name) &&
296                     tvb_strncaseeql(tvb, offset, msrp_headers[i].name, header_len) == 0)
297                 {
298                         return i;
299                 }
300         }
301
302         return -1;
303 }
304
305
306 /*
307  * Display the entire message as raw text.
308  */
309 static void
310 tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
311 {
312         int offset, next_offset, linelen;
313         offset = 0;
314
315         while (tvb_offset_exists(tvb, offset)) {
316                 /* 'desegment' is FALSE so will set next_offset to beyond the end of
317                    the buffer if no line ending is found */
318                 tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
319                 linelen = next_offset - offset;
320                 if(tree) {
321                         proto_tree_add_text(tree, tvb, offset, linelen,
322                                             "%s", tvb_format_text(tvb, offset, linelen));
323                 }
324                 offset = next_offset;
325         }
326 }
327
328 /* This code is modeled on the code in packet-sip.c 
329  *  ABNF code for the MSRP header:
330  *  The following syntax specification uses the augmented Backus-Naur
331  *  Form (BNF) as described in RFC-2234 [6].
332  *
333  *
334  *  msrp-req-or-resp = msrp-request / msrp-response
335  *  msrp-request = req-start headers [content-stuff] end-line
336  *  msrp-response = resp-start headers end-line
337  *
338  *  req-start  = pMSRP SP transact-id SP method CRLF
339  *  resp-start = pMSRP SP transact-id SP status-code [SP phrase] CRLF
340  *  phrase = utf8text
341  *
342  *  pMSRP = %x4D.53.52.50 ; MSRP in caps
343  *  transact-id = ident
344  *  method = mSEND / mREPORT / other-method
345  *  mSEND = %x53.45.4e.44 ; SEND in caps
346  *  mREPORT = %x52.45.50.4f.52.54; REPORT in caps
347  *  other-method = 1*UPALPHA
348  *  Examples:
349  *  "MSRP 1234 SEND(CRLF)"
350  *      "MSRP 1234 200 OK(CRLF)
351  */     
352 static gboolean
353 check_msrp_header(tvbuff_t *tvb)
354 {       
355         gint offset = 0;
356         gint linelen;
357         gint space_offset;
358         gint next_offset = 0;
359         guint token_1_len;
360         gint token_2_start;
361
362         /*
363          * Note that "tvb_find_line_end()" will return a value that
364          * is not longer than what's in the buffer, so the
365          * "tvb_get_ptr()" calls below won't throw exceptions.   *
366          */
367         offset = 0;
368         linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
369         /* Find the first SP */
370         space_offset = tvb_find_guint8(tvb, 0, -1, ' ');
371
372         if (space_offset <= 0) {
373                 /*
374                  * Either there's no space in the line (which means
375                  * the line is empty or doesn't have a token followed
376                  * by a space; neither is valid for a request or response), or
377                  * the first character in the line is a space ( which isn't valid
378                  * for a MSRP header.)
379                  */
380                 return FALSE;
381         }
382
383         token_1_len = space_offset;
384         token_2_start = space_offset + 1;
385         space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' ');
386         if (space_offset == -1) {
387                 /*
388                  * There's no space after the second token, so we don't
389                  * have a third token.
390                  */
391                 return FALSE;
392         }
393         /*
394          * Is the first token "MSRP"?
395          */
396         if (token_1_len == MSRP_HDR_LEN && tvb_strneql(tvb, 0, MSRP_HDR, MSRP_HDR_LEN) == 0){
397                 /* This check can be made more strict but accept we do have MSRP for now */
398                 return TRUE;
399
400         }
401         return FALSE;
402 }
403
404 /* ABNF of line-end:
405  * end-line = "-------" transact-id continuation-flag CRLF
406  * This code is modeled on the code in packet-multipart.c
407  */
408 static int
409 find_end_line(tvbuff_t *tvb, gint start)
410 {
411         gint offset = start, next_offset, linelen;
412
413         while (tvb_length_remaining(tvb, offset) > 0) {
414                 /* 'desegment' is FALSE so will set next_offset to beyond the end of
415                    the buffer if no line ending is found */
416                 linelen =  tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
417                 if (linelen == -1) {
418                         return -1;
419                 }
420                 if (tvb_strneql(tvb, next_offset, (const gchar *)"-------", 7) == 0)
421                         return next_offset;
422                 offset = next_offset;
423         }
424
425         return -1;
426 }
427
428 static gboolean
429 dissect_msrp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
430 {
431         gint offset = 0;
432         conversation_t* conversation;
433
434         if ( check_msrp_header(tvb)){
435                 /*
436                  * TODO Set up conversation here
437                  */
438                 if (pinfo->fd->flags.visited){
439                         /* Look for existing conversation */
440                         conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
441                                 pinfo->srcport, pinfo->destport, 0);
442                         /* Create new one if not found */
443                         if (conversation == NULL){
444                                 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
445                                         pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
446                                 /* Set dissector */
447                                 conversation_set_dissector(conversation, msrp_handle);
448                         }
449                 }
450                 offset = dissect_msrp(tvb, pinfo, tree);
451                 return TRUE;
452         }
453         return FALSE;
454 }
455
456 /* Code to actually dissect the packets */
457 static int
458 dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
459 {
460         gint offset = 0;
461         gint next_offset = 0;
462         proto_item *ti, *th, *msrp_headers_item, *msrp_element_item;
463         proto_tree *msrp_tree, *reqresp_tree, *raw_tree, *msrp_hdr_tree, *msrp_end_tree;
464         proto_tree *msrp_element_tree, *msrp_data_tree;
465         gint linelen;
466         gint space_offset;
467         gint token_2_start;
468         guint token_2_len;
469         gint token_3_start;
470         guint token_3_len;
471         gint token_4_start = 0;
472         guint token_4_len = 0;
473         gboolean is_msrp_response;
474         gint end_line_offset;
475         gint end_line_len;
476         gint line_end_offset;
477         gint message_end_offset;
478         gint colon_offset;
479         char *transaction_id_str = NULL;
480         gint header_len;
481         gint hf_index;
482         gint value_offset;
483         guchar c;
484         size_t value_len;
485         char *value;
486         gboolean have_body = FALSE;
487         gboolean found_match = FALSE;
488         gint content_type_len, content_type_parameter_str_len;
489         char *media_type_str = NULL;
490         char *media_type_str_lower_case = NULL;
491         char *content_type_parameter_str = NULL;
492         tvbuff_t *next_tvb;
493         gint parameter_offset;
494         gint semi_colon_offset;
495
496         if ( !check_msrp_header(tvb)){
497                 return 0;
498         }
499         /* We have a MSRP header with at least three tokens 
500          *
501          * Note that "tvb_find_line_end()" will return a value that
502          * is not longer than what's in the buffer, so the
503          * "tvb_get_ptr()" calls below won't throw exceptions.   *
504          */
505         offset = 0;
506         linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
507
508         /* Find the first SP and skip the first token */
509         token_2_start = tvb_find_guint8(tvb, 0, linelen, ' ') + 1;
510
511         /* Work out 2nd token's length by finding next space */
512         space_offset = tvb_find_guint8(tvb, token_2_start, linelen-token_2_start, ' ');
513         token_2_len = space_offset - token_2_start;
514
515         /* Transaction ID found store it for later use */
516         transaction_id_str = tvb_get_ephemeral_string(tvb, token_2_start, token_2_len);
517
518         /* Look for another space in this line to indicate a 4th token */
519         token_3_start = space_offset + 1;
520         space_offset = tvb_find_guint8(tvb, token_3_start,linelen-token_3_start, ' ');
521         if ( space_offset == -1){
522                 /* 3rd token runs to the end of the line */
523                 token_3_len = linelen - token_3_start;
524         }else{
525                 /* We have a fourth token */
526                 token_3_len = space_offset - token_3_start;
527                 token_4_start = space_offset + 1;
528                 token_4_len = linelen - token_4_start;
529         }
530
531         /*
532          * Yes, so this is either a msrp-request or msrp-response.
533          * To be a msrp-response, the second token must be
534          * a 3-digit number.
535          */
536         is_msrp_response = FALSE;
537         if (token_3_len == 3) {
538                         if (isdigit(tvb_get_guint8(tvb, token_3_start)) &&
539                             isdigit(tvb_get_guint8(tvb, token_3_start + 1)) &&
540                             isdigit(tvb_get_guint8(tvb, token_3_start + 2))) {
541                                 is_msrp_response = TRUE;
542                         }
543         }
544
545         /* Make entries in Protocol column and Info column on summary display */
546         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
547                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSRP");
548         if (is_msrp_response){
549                 if (check_col(pinfo->cinfo, COL_INFO)) {
550                         col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s ",
551                                         tvb_format_text(tvb, token_3_start, token_3_len));
552
553                         if (token_4_len )
554                                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
555                                         tvb_format_text(tvb, token_4_start, token_4_len));
556
557                         col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s",
558                                         tvb_format_text(tvb, token_2_start, token_2_len));
559                 }
560         }else{
561                 if (check_col(pinfo->cinfo, COL_INFO)) {
562                         proto_tree_add_text(tree, tvb, token_3_start, token_3_len,
563                                         "Col %s L=%u", tvb_format_text(tvb, token_3_start, token_3_len),token_3_len);
564
565                         col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s ",
566                                         tvb_format_text(tvb, token_3_start, token_3_len));
567
568                         col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s",
569                                         tvb_format_text(tvb, token_2_start, token_2_len));
570                 }
571         }
572
573         /* Find the end line to be able to process the headers
574          * Note that in case of [content-stuff] headers and [content-stuff] is separated by CRLF
575          */
576
577         offset = next_offset;
578         end_line_offset = find_end_line(tvb,offset);
579         /* TODO if -1 (No end line found, is returned do something) */
580         end_line_len =  tvb_find_line_end(tvb, end_line_offset, -1, &next_offset, FALSE);
581         message_end_offset = end_line_offset + end_line_len + 2;
582
583
584         if (tree) {
585                 ti = proto_tree_add_item(tree, proto_msrp, tvb, 0, message_end_offset, FALSE);
586                 msrp_tree = proto_item_add_subtree(ti, ett_msrp);
587
588                 if (is_msrp_response){
589                         th = proto_tree_add_item(msrp_tree,hf_msrp_response_line,tvb,0,linelen,FALSE);
590                         reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp);
591                         proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE);
592                         proto_tree_add_uint(reqresp_tree,hf_msrp_status_code,tvb,token_3_start,token_3_len,
593                                             atoi(tvb_get_string(tvb, token_3_start, token_3_len)));
594
595                 }else{
596                         th = proto_tree_add_item(msrp_tree,hf_msrp_request_line,tvb,0,linelen,FALSE);
597                         reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp);
598                         proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE);
599                         proto_tree_add_item(reqresp_tree,hf_msrp_method,tvb,token_3_start,token_3_len,FALSE);
600                 }
601
602                 /* Conversation setup info */
603                 if (global_msrp_show_setup_info)
604                 {
605                         show_setup_info(tvb, pinfo, msrp_tree);
606                 }
607
608                 /* Headers */
609                 msrp_headers_item = proto_tree_add_item(msrp_tree, hf_msrp_msg_hdr, tvb, offset,(end_line_offset - offset), FALSE);
610                 msrp_hdr_tree = proto_item_add_subtree(msrp_headers_item, ett_msrp_hdr);
611
612                 /* 
613                  * Process the headers
614                  */
615                 while (tvb_reported_length_remaining(tvb, offset) > 0 && offset < end_line_offset  ) {
616                         /* 'desegment' is FALSE so will set next_offset to beyond the end of
617                            the buffer if no line ending is found */
618                         linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
619                         if (linelen == 0) {
620                                 /*
621                                  * This is a blank line separating the
622                                  * message header from the message body.
623                                  */
624                                 have_body = TRUE;
625                                 break;
626                         }
627                         line_end_offset = offset + linelen;
628                         colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
629                         if (colon_offset == -1) {
630                                 /*
631                                  * Malformed header - no colon after the name.
632                                  */
633                                 proto_tree_add_text(msrp_hdr_tree, tvb, offset,
634                                                         next_offset - offset, "%s",
635                                                             tvb_format_text(tvb, offset, linelen));
636                         } else {
637                                 header_len = colon_offset - offset;
638                                 hf_index = msrp_is_known_msrp_header(tvb, offset, header_len);
639
640                                 if (hf_index == -1) {
641                                         proto_tree_add_text(msrp_hdr_tree, tvb,
642                                                     offset, next_offset - offset, "%s",
643                                                     tvb_format_text(tvb, offset, linelen));
644                                 } else {
645                                         /*
646                                          * Skip whitespace after the colon.
647                                          */
648                                         value_offset = colon_offset + 1;
649                                         while (value_offset < line_end_offset &&
650                                                ((c = tvb_get_guint8(tvb, value_offset)) == ' ' ||
651                                                  c == '\t'))
652                                                 value_offset++;
653                                         /*
654                                          * Fetch the value.
655                                          */
656                                         value_len = line_end_offset - value_offset;
657                                         value = tvb_get_ephemeral_string(tvb, value_offset,
658                                                        value_len);
659
660                                         /*
661                                          * Add it to the protocol tree,
662                                          * but display the line as is.
663                                          */
664                                         msrp_element_item = proto_tree_add_string_format(msrp_hdr_tree,
665                                                    hf_header_array[hf_index], tvb,
666                                                    offset, next_offset - offset,
667                                                    value, "%s",
668                                                    tvb_format_text(tvb, offset, linelen));
669                                         msrp_element_tree = proto_item_add_subtree( msrp_element_item, ett_msrp_element);
670
671                                         switch ( hf_index ) {
672
673                                                 case MSRP_CONTENT_TYPE :
674                                                         content_type_len = value_len;
675                                                         semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';');
676                                                         if ( semi_colon_offset != -1) {
677                                                                 parameter_offset = semi_colon_offset +1;
678                                                                 /*
679                                                                  * Skip whitespace after the semicolon.
680                                                                  */
681                                                                 while (parameter_offset < line_end_offset
682                                                                        && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' '
683                                                                          || c == '\t'))
684                                                                         parameter_offset++;
685                                                                 content_type_len = semi_colon_offset - value_offset;
686                                                                 content_type_parameter_str_len = line_end_offset - parameter_offset;
687                                                                 content_type_parameter_str = tvb_get_ephemeral_string(tvb,
688                                                                                      parameter_offset, content_type_parameter_str_len);
689                                                         }
690                                                         media_type_str = tvb_get_ephemeral_string(tvb, value_offset, content_type_len);
691 #if GLIB_MAJOR_VERSION < 2
692                                                         media_type_str_lower_case = g_strdup(media_type_str);
693                                                         g_strdown(media_type_str_lower_case);
694 #else
695                                                         media_type_str_lower_case = g_ascii_strdown(media_type_str, -1);
696 #endif
697                                                         break;
698
699                                                 default:
700                                                         break;
701                                         }
702                                 }
703                         }
704                         offset = next_offset;
705                 }/* End while */
706
707                 if ( have_body ){
708                         /*
709                          * There's a message body starting at "next_offset".
710                          * Set the length of the header item.
711                          */
712                         proto_item_set_end(msrp_headers_item, tvb, next_offset);
713
714                         /* Create new tree & tvb for data */
715                         next_tvb = tvb_new_subset(tvb, next_offset, -1, -1);
716                         ti = proto_tree_add_item(msrp_tree, hf_msrp_data, tvb,
717                                                  next_offset, -1, FALSE);
718                         msrp_data_tree = proto_item_add_subtree(ti, ett_msrp_data);
719
720                         /* give the content type parameters to sub dissectors */
721
722                         if ( media_type_str_lower_case != NULL ) {
723                                 void *save_private_data = pinfo->private_data;
724                                 pinfo->private_data = content_type_parameter_str;
725                                 found_match = dissector_try_string(media_type_dissector_table,
726                                                            media_type_str_lower_case,
727                                                            next_tvb, pinfo,
728                                                            msrp_data_tree);
729                                 g_free(media_type_str_lower_case);
730                                 pinfo->private_data = save_private_data;
731                                 /* If no match dump as text */
732                         }
733                         if ( found_match != TRUE )
734                         {
735                                 offset = 0;
736                                 while (tvb_offset_exists(next_tvb, offset)) {
737                                         tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE);
738                                         linelen = next_offset - offset;
739                                         proto_tree_add_text(msrp_data_tree, next_tvb, offset, linelen,
740                                                     "%s", tvb_format_text(next_tvb, offset, linelen));
741                                         offset = next_offset;
742                                 }/* end while */
743                         }
744
745                 }
746
747
748
749                 /* End line */
750                 ti = proto_tree_add_item(msrp_tree,hf_msrp_end_line,tvb,end_line_offset,end_line_len,FALSE);
751                 msrp_end_tree = proto_item_add_subtree(ti, ett_msrp_end_line);
752
753                 proto_tree_add_item(msrp_end_tree,hf_msrp_transactionID,tvb,end_line_offset + 7,token_2_len,FALSE);
754                 /* continuation-flag */ 
755                 proto_tree_add_item(msrp_end_tree,hf_msrp_cnt_flg,tvb,end_line_offset+end_line_len-1,1,FALSE);
756                         
757                 if (global_msrp_raw_text){
758                         ti = proto_tree_add_text(tree, tvb, 0, -1,"Message Session Relay Protocol(as raw text)");
759                         raw_tree = proto_item_add_subtree(ti, ett_msrp);
760                         tvb_raw_text_add(tvb,raw_tree);
761                 }
762
763         }/* if tree */
764         return message_end_offset;
765         /*      return tvb_length(tvb); */
766
767 /* If this protocol has a sub-dissector call it here, see section 1.8 */
768 }
769
770
771 /* Register the protocol with Wireshark */
772 /* If this dissector uses sub-dissector registration add a registration routine.
773    This format is required because a script is used to find these routines and
774    create the code that calls these routines.
775 */
776 void
777 proto_reg_handoff_msrp(void)
778 {
779         msrp_handle = new_create_dissector_handle(dissect_msrp, proto_msrp);
780         dissector_add("tcp.port", 0, msrp_handle);
781         heur_dissector_add("tcp", dissect_msrp_heur, proto_msrp);
782 }
783
784 void
785 proto_register_msrp(void)
786 {
787 /* Setup protocol subtree array */
788         static gint *ett[] = {
789                 &ett_msrp,
790                 &ett_raw_text,
791                 &ett_msrp_reqresp,
792                 &ett_msrp_hdr,
793                 &ett_msrp_element,
794                 &ett_msrp_data,
795                 &ett_msrp_end_line,
796                 &ett_msrp_setup
797         };
798
799         /* Setup list of header fields */
800         static hf_register_info hf[] = {
801                 { &hf_msrp_request_line,
802                         { "Request Line",               "msrp.request.line",
803                         FT_STRING, BASE_NONE,NULL,0x0,
804                         "Request Line", HFILL }
805                 },
806                 { &hf_msrp_response_line,
807                         { "Response Line",              "msrp.response.line",
808                         FT_STRING, BASE_NONE,NULL,0x0,
809                         "Response Line", HFILL }
810                 },
811                 { &hf_msrp_transactionID,
812                         { "Transaction Id",             "msrp.transaction.id",
813                         FT_STRING, BASE_NONE,NULL,0x0,
814                         "Transaction Id", HFILL }
815                 },
816                 { &hf_msrp_method,
817                         { "Method",                             "msrp.method",
818                         FT_STRING, BASE_NONE,NULL,0x0,
819                         "Method", HFILL }
820                 },
821                 { &hf_msrp_status_code,
822                         { "Status code",                "msrp.status.code",
823                         FT_UINT16, BASE_DEC,NULL,0x0,
824                         "Status code", HFILL }
825                 },
826                 { &hf_msrp_msg_hdr,
827                         { "Message Header",             "msrp.msg.hdr",
828                         FT_NONE, 0,NULL,0x0,
829                         "Message Header", HFILL }
830                 },
831                 { &hf_msrp_end_line,
832                         { "End Line",           "msrp.end.line",
833                         FT_STRING, BASE_NONE,NULL,0x0,
834                         "End Line", HFILL }
835                 },
836                 { &hf_msrp_cnt_flg,
837                         { "Continuation-flag",          "msrp.cnt.flg",
838                         FT_STRING, BASE_NONE,NULL,0x0,
839                         "Continuation-flag", HFILL }
840                 },
841                 { &hf_header_array[MSRP_FROM_PATH],
842                         { "From Path",          "msrp.from.path",
843                         FT_STRING, BASE_NONE,NULL,0x0,
844                         "From Path", HFILL }
845                 },
846                 { &hf_header_array[MSRP_TO_PATH],
847                         { "To Path",            "msrp.to.path",
848                         FT_STRING, BASE_NONE,NULL,0x0,
849                         "To Path", HFILL }
850                 },
851                 { &hf_header_array[MSRP_MESSAGE_ID],
852                         { "Message ID",                 "msrp.messageid",
853                         FT_STRING, BASE_NONE,NULL,0x0,
854                         "Message ID", HFILL }
855                 },
856                 { &hf_header_array[MSRP_SUCCESS_REPORT],
857                         { "Success Report",             "msrp.success.report",
858                         FT_STRING, BASE_NONE,NULL,0x0,
859                         "Success Report", HFILL }
860                 },
861                 { &hf_header_array[MSRP_FAILURE_REPORT],
862                         { "Failure Report",             "msrp.failure.report",
863                         FT_STRING, BASE_NONE,NULL,0x0,
864                         "Failure Report", HFILL }
865                 },
866                 { &hf_header_array[MSRP_BYTE_RANGE],
867                         { "Byte Range",                 "msrp.byte.range",
868                         FT_STRING, BASE_NONE,NULL,0x0,
869                         "Byte Range", HFILL }
870                 },
871                 { &hf_header_array[MSRP_STATUS],
872                         { "Status",             "msrp.status",
873                         FT_STRING, BASE_NONE,NULL,0x0,
874                         "Status", HFILL }
875                 },
876                 { &hf_header_array[MSRP_CONTENT_TYPE],
877                         { "Content-Type",               "msrp.content.type",
878                         FT_STRING, BASE_NONE,NULL,0x0,
879                         "Content-Type", HFILL }
880                 },
881                 { &hf_header_array[MSRP_CONTENT_ID],
882                         { "Content-ID",                 "msrp.content.id",
883                         FT_STRING, BASE_NONE,NULL,0x0,
884                         "Content-ID", HFILL }
885                 },
886                 { &hf_header_array[MSRP_CONTENT_DISCRIPTION],
887                         { "Content-Description",                "msrp.content.description",
888                         FT_STRING, BASE_NONE,NULL,0x0,
889                         "Content-Description", HFILL }
890                 },
891                 { &hf_header_array[MSRP_CONTENT_DISPOSITION],
892                         { "Content-Disposition",                "msrp.content.disposition",
893                         FT_STRING, BASE_NONE,NULL,0x0,
894                         "Content-Disposition", HFILL }
895                 },
896                 { &hf_header_array[MSRP_USE_PATH],
897                         { "Use-Path",           "msrp.use.path",
898                         FT_STRING, BASE_NONE,NULL,0x0,
899                         "Use-Path", HFILL }
900                 },
901                 { &hf_header_array[MSRP_WWW_AUTHENTICATE],
902                         { "WWW-Authenticate",           "msrp.www.authenticate",
903                         FT_STRING, BASE_NONE,NULL,0x0,
904                         "WWW-Authenticate", HFILL }
905                 },
906                 { &hf_header_array[MSRP_AUTHORIZATION],
907                         { "Authorization",              "msrp.authorization",
908                         FT_STRING, BASE_NONE,NULL,0x0,
909                         "Authorization", HFILL }
910                 },
911                 { &hf_header_array[MSRP_AUTHENTICATION_INFO],
912                         { "Authentication-Info",                "msrp.authentication.info",
913                         FT_STRING, BASE_NONE,NULL,0x0,
914                         "Authentication-Info", HFILL }
915                 },
916                 { &hf_msrp_data,
917                         { "Data", "msrp.data",
918                         FT_STRING, BASE_NONE, NULL, 0x0,
919                         "Data", HFILL}
920         },
921                 { &hf_msrp_setup,
922                         { "Stream setup", "msrp.setup",
923                         FT_STRING, BASE_NONE, NULL, 0x0,
924                         "Stream setup, method and frame number", HFILL}
925                 },
926                 { &hf_msrp_setup_frame,
927                         { "Setup frame", "msrp.setup-frame",
928                         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
929                         "Frame that set up this stream", HFILL}
930                 },
931                 { &hf_msrp_setup_method,
932                         { "Setup Method", "msrp.setup-method",
933                         FT_STRING, BASE_NONE, NULL, 0x0,
934                         "Method used to set up this stream", HFILL}
935                 },
936         };
937
938         module_t *msrp_module;
939         /* Register the protocol name and description */
940         proto_msrp = proto_register_protocol("Message Session Relay Protocol","MSRP", "msrp");
941
942         /* Required function calls to register the header fields and subtrees used */
943         proto_register_field_array(proto_msrp, hf, array_length(hf));
944         proto_register_subtree_array(ett, array_length(ett));
945
946         media_type_dissector_table = find_dissector_table("media_type");
947
948         msrp_module = prefs_register_protocol(proto_msrp, NULL);
949
950         prefs_register_bool_preference(msrp_module, "display_raw_text",
951                 "Display raw text for MSRP message",
952                 "Specifies that the raw text of the "
953                 "MSRP message should be displayed "
954                 "in addition to the dissection tree",
955                 &global_msrp_raw_text);
956
957         prefs_register_bool_preference(msrp_module, "show_setup_info",
958                 "Show stream setup information",
959                 "Where available, show which protocol and frame caused "
960                 "this MSRP stream to be created",
961                 &global_msrp_show_setup_info);
962
963
964         /*
965          * Register the dissector by name, so other dissectors can
966          * grab it by name rather than just referring to it directly.
967          */
968         new_register_dissector("msrp", dissect_msrp, proto_msrp);
969 }
970
971