s/artnet/rtnet/g.
[metze/wireshark/wip.git] / packet-pop.c
1 /* packet-pop.c
2  * Routines for pop packet dissection
3  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
4  *
5  * $Id: packet-pop.c,v 1.33 2002/08/28 21:00:25 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-tftp.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33
34 #include <string.h>
35 #include <glib.h>
36 #include <epan/packet.h>
37 #include <epan/strutil.h>
38
39 static int proto_pop = -1;
40 static int hf_pop_response = -1;
41 static int hf_pop_request = -1;
42
43 static gint ett_pop = -1;
44
45 static dissector_handle_t data_handle;
46
47 #define TCP_PORT_POP                    110
48
49 static gboolean response_is_continuation(const guchar *data);
50
51 static void
52 dissect_pop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
53 {
54         gboolean        is_request;
55         gboolean        is_continuation;
56         proto_tree      *pop_tree;
57         proto_item      *ti;
58         gint            offset = 0;
59         const guchar    *line;
60         gint            next_offset;
61         int             linelen;
62         int             tokenlen;
63         const guchar    *next_token;
64
65         if (check_col(pinfo->cinfo, COL_PROTOCOL))
66                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "POP");
67
68         /*
69          * Find the end of the first line.
70          *
71          * Note that "tvb_find_line_end()" will return a value that is
72          * not longer than what's in the buffer, so the "tvb_get_ptr()"
73          * call won't throw an exception.
74          */
75         linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
76         line = tvb_get_ptr(tvb, offset, linelen);
77
78         if (pinfo->match_port == pinfo->destport) {
79                 is_request = TRUE;
80                 is_continuation = FALSE;
81         } else {
82                 is_request = FALSE;
83                 is_continuation = response_is_continuation(line);
84         }
85
86         if (check_col(pinfo->cinfo, COL_INFO)) {
87                 /*
88                  * Put the first line from the buffer into the summary
89                  * if it's a POP request or reply (but leave out the
90                  * line terminator).
91                  * Otherwise, just call it a continuation.
92                  */
93                 if (is_continuation)
94                         col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
95                 else
96                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
97                             is_request ? "Request" : "Response",
98                             format_text(line, linelen));
99         }
100
101         if (tree) {
102                 ti = proto_tree_add_item(tree, proto_pop, tvb, offset, -1,
103                     FALSE);
104                 pop_tree = proto_item_add_subtree(ti, ett_pop);
105
106                 if (is_continuation) {
107                         /*
108                          * Put the whole packet into the tree as data.
109                          */
110                         call_dissector(data_handle,tvb, pinfo, pop_tree);
111                         return;
112                 }
113
114                 if (is_request) {
115                         proto_tree_add_boolean_hidden(pop_tree,
116                             hf_pop_request, tvb, 0, 0, TRUE);
117                 } else {
118                         proto_tree_add_boolean_hidden(pop_tree,
119                             hf_pop_response, tvb, 0, 0, TRUE);
120                 }
121
122                 /*
123                  * Extract the first token, and, if there is a first
124                  * token, add it as the request or reply code.
125                  */
126                 tokenlen = get_token_len(line, line + linelen, &next_token);
127                 if (tokenlen != 0) {
128                         if (is_request) {
129                                 proto_tree_add_text(pop_tree, tvb, offset,
130                                     tokenlen, "Request: %s",
131                                     format_text(line, tokenlen));
132                         } else {
133                                 proto_tree_add_text(pop_tree, tvb, offset,
134                                     tokenlen, "Response: %s",
135                                     format_text(line, tokenlen));
136                         }
137                         offset += next_token - line;
138                         linelen -= next_token - line;
139                         line = next_token;
140                 }
141
142                 /*
143                  * Add the rest of the first line as request or
144                  * reply data.
145                  */
146                 if (linelen != 0) {
147                         if (is_request) {
148                                 proto_tree_add_text(pop_tree, tvb, offset,
149                                     linelen, "Request Arg: %s",
150                                     format_text(line, linelen));
151                         } else {
152                                 proto_tree_add_text(pop_tree, tvb, offset,
153                                     linelen, "Response Arg: %s",
154                                     format_text(line, linelen));
155                         }
156                 }
157                 offset = next_offset;
158
159                 /*
160                  * Show the rest of the request or response as text,
161                  * a line at a time.
162                  */
163                 while (tvb_offset_exists(tvb, offset)) {
164                         /*
165                          * Find the end of the line.
166                          */
167                         linelen = tvb_find_line_end(tvb, offset, -1,
168                             &next_offset, FALSE);
169
170                         /*
171                          * Put this line.
172                          */
173                         proto_tree_add_text(pop_tree, tvb, offset,
174                             next_offset - offset, "%s",
175                             tvb_format_text(tvb, offset, next_offset - offset));
176                         offset = next_offset;
177                 }
178         }
179 }
180
181 static gboolean response_is_continuation(const guchar *data)
182 {
183   if (strncmp(data, "+OK", strlen("+OK")) == 0)
184     return FALSE;
185
186   if (strncmp(data, "-ERR", strlen("-ERR")) == 0)
187     return FALSE;
188
189   return TRUE;
190 }
191
192 void
193 proto_register_pop(void)
194 {
195
196   static hf_register_info hf[] = {
197     { &hf_pop_response,
198       { "Response",           "pop.response",
199         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
200         "TRUE if POP response", HFILL }},
201
202     { &hf_pop_request,
203       { "Request",            "pop.request",
204         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
205         "TRUE if POP request", HFILL }}
206   };
207   static gint *ett[] = {
208     &ett_pop,
209   };
210
211   proto_pop = proto_register_protocol("Post Office Protocol", "POP", "pop");
212   proto_register_field_array(proto_pop, hf, array_length(hf));
213   proto_register_subtree_array(ett, array_length(ett));
214 }
215
216 void
217 proto_reg_handoff_pop(void)
218 {
219   dissector_handle_t pop_handle;
220
221   pop_handle = create_dissector_handle(dissect_pop, proto_pop);
222   dissector_add("tcp.port", TCP_PORT_POP, pop_handle);
223   data_handle = find_dissector("data");
224 }