MSWSP: fix dissect_mswsp_smb()
[wireshark-wip.git] / epan / dissectors / packet-cups.c
blob9cc918a65f303ce6d73d64245fe48932df238538
1 /* packet-cups.c
2 * Routines for Common Unix Printing System (CUPS) Browsing Protocol
3 * packet disassembly for the Wireshark network traffic analyzer.
5 * Charles Levert <charles@comm.polymtl.ca>
6 * Copyright 2001 Charles Levert
8 * $Id$
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <ctype.h>
30 #include <glib.h>
31 #include <epan/packet.h>
33 /**********************************************************************/
35 void proto_register_cups(void);
36 void proto_reg_handoff_cups(void);
38 /* From cups/cups.h, GNU GPL, Copyright 1997-2001 by Easy Software Products. */
39 typedef guint32 cups_ptype_t; /**** Printer Type/Capability Bits ****/
40 enum /* Not a typedef'd enum so we can OR */
42 CUPS_PRINTER_LOCAL = 0x0000, /* Local printer or class */
43 CUPS_PRINTER_CLASS = 0x0001, /* Printer class */
44 CUPS_PRINTER_REMOTE = 0x0002, /* Remote printer or class */
45 CUPS_PRINTER_BW = 0x0004, /* Can do B&W printing */
46 CUPS_PRINTER_COLOR = 0x0008, /* Can do color printing */
47 CUPS_PRINTER_DUPLEX = 0x0010, /* Can do duplexing */
48 CUPS_PRINTER_STAPLE = 0x0020, /* Can staple output */
49 CUPS_PRINTER_COPIES = 0x0040, /* Can do copies */
50 CUPS_PRINTER_COLLATE = 0x0080, /* Can collage copies */
51 CUPS_PRINTER_PUNCH = 0x0100, /* Can punch output */
52 CUPS_PRINTER_COVER = 0x0200, /* Can cover output */
53 CUPS_PRINTER_BIND = 0x0400, /* Can bind output */
54 CUPS_PRINTER_SORT = 0x0800, /* Can sort output */
55 CUPS_PRINTER_SMALL = 0x1000, /* Can do Letter/Legal/A4 */
56 CUPS_PRINTER_MEDIUM = 0x2000, /* Can do Tabloid/B/C/A3/A2 */
57 CUPS_PRINTER_LARGE = 0x4000, /* Can do D/E/A1/A0 */
58 CUPS_PRINTER_VARIABLE = 0x8000, /* Can do variable sizes */
59 CUPS_PRINTER_IMPLICIT = 0x10000, /* Implicit class */
60 CUPS_PRINTER_DEFAULT = 0x20000, /* Default printer on network */
61 CUPS_PRINTER_OPTIONS = 0xfffc /* ~(CLASS | REMOTE | IMPLICIT) */
63 /* End insert from cups/cups.h */
65 typedef enum _cups_state {
66 CUPS_IDLE = 3,
67 CUPS_PROCESSING,
68 CUPS_STOPPED
69 } cups_state_t;
71 static const value_string cups_state_values[] = {
72 { CUPS_IDLE, "idle" },
73 { CUPS_PROCESSING, "processing" },
74 { CUPS_STOPPED, "stopped" },
75 { 0, NULL }
78 static const true_false_string tfs_implicit_explicit = { "Implicit class", "Explicit class" };
79 static const true_false_string tfs_printer_class = { "Printer class", "Single printer" };
81 static int proto_cups = -1;
82 static int hf_cups_ptype = -1;
83 static int hf_cups_ptype_default = -1;
84 static int hf_cups_ptype_implicit = -1;
85 static int hf_cups_ptype_variable = -1;
86 static int hf_cups_ptype_large = -1;
87 static int hf_cups_ptype_medium = -1;
88 static int hf_cups_ptype_small = -1;
89 static int hf_cups_ptype_sort = -1;
90 static int hf_cups_ptype_bind = -1;
91 static int hf_cups_ptype_cover = -1;
92 static int hf_cups_ptype_punch = -1;
93 static int hf_cups_ptype_collate = -1;
94 static int hf_cups_ptype_copies = -1;
95 static int hf_cups_ptype_staple = -1;
96 static int hf_cups_ptype_duplex = -1;
97 static int hf_cups_ptype_color = -1;
98 static int hf_cups_ptype_bw = -1;
99 static int hf_cups_ptype_remote = -1;
100 static int hf_cups_ptype_class = -1;
101 static int hf_cups_state = -1;
103 static gint ett_cups = -1;
104 static gint ett_cups_ptype = -1;
106 /* This protocol is heavily related to IPP, but it is CUPS-specific
107 and non-standard. */
108 #define UDP_PORT_CUPS 631
109 #define PROTO_TAG_CUPS "CUPS"
111 static guint get_hex_uint(tvbuff_t *tvb, gint offset, gint *next_offset);
112 static gboolean skip_space(tvbuff_t *tvb, gint offset, gint *next_offset);
113 static const guint8* get_quoted_string(tvbuff_t *tvb, gint offset,
114 gint *next_offset, guint *len);
115 static const guint8* get_unquoted_string(tvbuff_t *tvb, gint offset,
116 gint *next_offset, guint *len);
118 /**********************************************************************/
120 static void
121 dissect_cups(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
123 proto_tree *cups_tree = NULL;
124 proto_tree *ptype_subtree = NULL;
125 proto_item *ti = NULL;
126 gint offset = 0;
127 gint next_offset;
128 guint len;
129 const guint8 *str;
130 cups_ptype_t ptype;
131 unsigned int state;
133 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_CUPS);
134 col_clear(pinfo->cinfo, COL_INFO);
136 ti = proto_tree_add_item(tree, proto_cups, tvb, offset, -1, ENC_NA);
137 cups_tree = proto_item_add_subtree(ti, ett_cups);
139 /* Format (1450 bytes max.): */
140 /* type state uri ["location" ["info" ["make-and-model"]]]\n */
142 ptype = get_hex_uint(tvb, offset, &next_offset);
143 len = next_offset - offset;
144 if (len != 0) {
145 ti = proto_tree_add_uint(cups_tree, hf_cups_ptype, tvb, offset, len, ptype);
146 ptype_subtree = proto_item_add_subtree(ti, ett_cups_ptype);
147 proto_tree_add_item(ptype_subtree, hf_cups_ptype_default, tvb, offset, len, ENC_BIG_ENDIAN);
148 proto_tree_add_item(ptype_subtree, hf_cups_ptype_implicit, tvb, offset, len, ENC_BIG_ENDIAN);
149 proto_tree_add_item(ptype_subtree, hf_cups_ptype_variable, tvb, offset, len, ENC_BIG_ENDIAN);
150 proto_tree_add_item(ptype_subtree, hf_cups_ptype_large, tvb, offset, len, ENC_BIG_ENDIAN);
151 proto_tree_add_item(ptype_subtree, hf_cups_ptype_medium, tvb, offset, len, ENC_BIG_ENDIAN);
152 proto_tree_add_item(ptype_subtree, hf_cups_ptype_small, tvb, offset, len, ENC_BIG_ENDIAN);
153 proto_tree_add_item(ptype_subtree, hf_cups_ptype_sort, tvb, offset, len, ENC_BIG_ENDIAN);
154 proto_tree_add_item(ptype_subtree, hf_cups_ptype_bind, tvb, offset, len, ENC_BIG_ENDIAN);
155 proto_tree_add_item(ptype_subtree, hf_cups_ptype_cover, tvb, offset, len, ENC_BIG_ENDIAN);
156 proto_tree_add_item(ptype_subtree, hf_cups_ptype_punch, tvb, offset, len, ENC_BIG_ENDIAN);
157 proto_tree_add_item(ptype_subtree, hf_cups_ptype_collate, tvb, offset, len, ENC_BIG_ENDIAN);
158 proto_tree_add_item(ptype_subtree, hf_cups_ptype_copies, tvb, offset, len, ENC_BIG_ENDIAN);
159 proto_tree_add_item(ptype_subtree, hf_cups_ptype_staple, tvb, offset, len, ENC_BIG_ENDIAN);
160 proto_tree_add_item(ptype_subtree, hf_cups_ptype_duplex, tvb, offset, len, ENC_BIG_ENDIAN);
161 proto_tree_add_item(ptype_subtree, hf_cups_ptype_color, tvb, offset, len, ENC_BIG_ENDIAN);
162 proto_tree_add_item(ptype_subtree, hf_cups_ptype_bw, tvb, offset, len, ENC_BIG_ENDIAN);
163 proto_tree_add_item(ptype_subtree, hf_cups_ptype_remote, tvb, offset, len, ENC_BIG_ENDIAN);
164 proto_tree_add_item(ptype_subtree, hf_cups_ptype_class, tvb, offset, len, ENC_BIG_ENDIAN);
166 offset = next_offset;
168 if (!skip_space(tvb, offset, &next_offset))
169 return; /* end of packet */
170 offset = next_offset;
172 state = get_hex_uint(tvb, offset, &next_offset);
173 len = next_offset - offset;
174 if (len != 0) {
175 proto_tree_add_uint(cups_tree, hf_cups_state, tvb, offset, len, state);
177 offset = next_offset;
179 if (!skip_space(tvb, offset, &next_offset))
180 return; /* end of packet */
181 offset = next_offset;
183 str = get_unquoted_string(tvb, offset, &next_offset, &len);
184 if (str == NULL)
185 return; /* separator/terminator not found */
187 proto_tree_add_text(cups_tree, tvb, offset, len,
188 "URI: %.*s", (guint16) len, str);
189 col_add_fstr(pinfo->cinfo, COL_INFO, "%.*s (%s)",
190 (guint16) len, str, val_to_str(state, cups_state_values, "0x%x"));
191 offset = next_offset;
193 if (!cups_tree)
194 return;
196 if (!skip_space(tvb, offset, &next_offset))
197 return; /* end of packet */
198 offset = next_offset;
200 str = get_quoted_string(tvb, offset, &next_offset, &len);
201 if (str == NULL)
202 return; /* separator/terminator not found */
203 proto_tree_add_text(cups_tree, tvb, offset+1, len,
204 "Location: \"%.*s\"", (guint16) len, str);
205 offset = next_offset;
207 if (!skip_space(tvb, offset, &next_offset))
208 return; /* end of packet */
209 offset = next_offset;
211 str = get_quoted_string(tvb, offset, &next_offset, &len);
212 if (str == NULL)
213 return; /* separator/terminator not found */
214 proto_tree_add_text(cups_tree, tvb, offset+1, len,
215 "Information: \"%.*s\"", (guint16) len, str);
216 offset = next_offset;
218 if (!skip_space(tvb, offset, &next_offset))
219 return; /* end of packet */
220 offset = next_offset;
222 str = get_quoted_string(tvb, offset, &next_offset, &len);
223 if (str == NULL)
224 return; /* separator/terminator not found */
225 proto_tree_add_text(cups_tree, tvb, offset+1, len,
226 "Make and model: \"%.*s\"", (guint16) len, str);
229 static guint
230 get_hex_uint(tvbuff_t *tvb, gint offset, gint *next_offset)
232 int c;
233 guint u = 0;
235 while (isxdigit(c = tvb_get_guint8(tvb, offset))) {
236 if (isdigit(c))
237 c -= '0';
238 else if (isupper(c))
239 c -= 'A' - 10;
240 else if (islower(c))
241 c -= 'a' - 10;
242 else
243 c = 0; /* This should not happen. */
245 u = 16*u + c;
247 offset++;
250 *next_offset = offset;
252 return u;
255 static gboolean
256 skip_space(tvbuff_t *tvb, gint offset, gint *next_offset)
258 int c;
260 while ((c = tvb_get_guint8(tvb, offset)) == ' ')
261 offset++;
262 if (c == '\r' || c == '\n')
263 return FALSE; /* end of packet */
265 *next_offset = offset;
267 return TRUE;
270 static const guint8*
271 get_quoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len)
273 int c;
274 const guint8* s = NULL;
275 guint l = 0;
276 gint o;
278 c = tvb_get_guint8(tvb, offset);
279 if (c == '"') {
280 o = tvb_find_guint8(tvb, offset+1, -1, '"');
281 if (o != -1) {
282 offset++;
283 l = o - offset;
284 s = tvb_get_ptr(tvb, offset, l);
285 offset = o + 1;
289 *next_offset = offset;
290 *len = l;
292 return s;
295 static const guint8*
296 get_unquoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len)
298 const guint8* s = NULL;
299 guint l = 0;
300 gint o;
302 o = tvb_pbrk_guint8(tvb, offset, -1, " \t\r\n", NULL);
303 if (o != -1) {
304 l = o - offset;
305 s = tvb_get_ptr(tvb, offset, l);
306 offset = o;
309 *next_offset = offset;
310 *len = l;
312 return s;
315 /**********************************************************************/
317 void
318 proto_register_cups(void)
320 static hf_register_info hf[] = {
321 { &hf_cups_ptype,
322 { "Type", "cups.ptype", FT_UINT32, BASE_HEX,
323 NULL, 0x0, NULL, HFILL }},
324 { &hf_cups_ptype_default,
325 { "Default printer on network", "cups.ptype.default", FT_BOOLEAN, 32,
326 TFS(&tfs_yes_no), CUPS_PRINTER_DEFAULT, NULL, HFILL }},
327 { &hf_cups_ptype_implicit,
328 { "Class", "cups.ptype.implicit", FT_BOOLEAN, 32,
329 TFS(&tfs_implicit_explicit), CUPS_PRINTER_IMPLICIT, NULL, HFILL }},
330 { &hf_cups_ptype_variable,
331 { "Can print variable sizes", "cups.ptype.variable", FT_BOOLEAN, 32,
332 TFS(&tfs_yes_no), CUPS_PRINTER_VARIABLE, NULL, HFILL }},
333 { &hf_cups_ptype_large,
334 { "Can print up to 36x48 inches", "cups.ptype.large", FT_BOOLEAN, 32,
335 TFS(&tfs_yes_no), CUPS_PRINTER_LARGE, NULL, HFILL }},
336 { &hf_cups_ptype_medium,
337 { "Can print up to 18x24 inches", "cups.ptype.medium", FT_BOOLEAN, 32,
338 TFS(&tfs_yes_no), CUPS_PRINTER_MEDIUM, NULL, HFILL }},
339 { &hf_cups_ptype_small,
340 { "Can print up to 9x14 inches", "cups.ptype.small", FT_BOOLEAN, 32,
341 TFS(&tfs_yes_no), CUPS_PRINTER_SMALL, NULL, HFILL }},
342 { &hf_cups_ptype_sort,
343 { "Can sort", "cups.ptype.sort", FT_BOOLEAN, 32,
344 TFS(&tfs_yes_no), CUPS_PRINTER_SORT, NULL, HFILL }},
345 { &hf_cups_ptype_bind,
346 { "Can bind", "cups.ptype.bind", FT_BOOLEAN, 32,
347 TFS(&tfs_yes_no), CUPS_PRINTER_BIND, NULL, HFILL }},
348 { &hf_cups_ptype_cover,
349 { "Can cover", "cups.ptype.cover", FT_BOOLEAN, 32,
350 TFS(&tfs_yes_no), CUPS_PRINTER_COVER, NULL, HFILL }},
351 { &hf_cups_ptype_punch,
352 { "Can punch holes", "cups.ptype.punch", FT_BOOLEAN, 32,
353 TFS(&tfs_yes_no), CUPS_PRINTER_PUNCH, NULL, HFILL }},
354 { &hf_cups_ptype_collate,
355 { "Can do fast collating", "cups.ptype.collate", FT_BOOLEAN, 32,
356 TFS(&tfs_yes_no), CUPS_PRINTER_COLLATE, NULL, HFILL }},
357 { &hf_cups_ptype_copies,
358 { "Can do fast copies", "cups.ptype.copies", FT_BOOLEAN, 32,
359 TFS(&tfs_yes_no), CUPS_PRINTER_COPIES, NULL, HFILL }},
360 { &hf_cups_ptype_staple,
361 { "Can staple", "cups.ptype.staple", FT_BOOLEAN, 32,
362 TFS(&tfs_yes_no), CUPS_PRINTER_STAPLE, NULL, HFILL }},
363 { &hf_cups_ptype_duplex,
364 { "Can duplex", "cups.ptype.duplex", FT_BOOLEAN, 32,
365 TFS(&tfs_yes_no), CUPS_PRINTER_DUPLEX, NULL, HFILL }},
366 { &hf_cups_ptype_color,
367 { "Can print color", "cups.ptype.color", FT_BOOLEAN, 32,
368 TFS(&tfs_yes_no), CUPS_PRINTER_COLOR, NULL, HFILL }},
369 { &hf_cups_ptype_bw,
370 { "Can print black", "cups.ptype.bw", FT_BOOLEAN, 32,
371 TFS(&tfs_yes_no), CUPS_PRINTER_BW, NULL, HFILL }},
372 { &hf_cups_ptype_remote,
373 { "Remote", "cups.ptype.remote", FT_BOOLEAN, 32,
374 TFS(&tfs_yes_no), CUPS_PRINTER_REMOTE, NULL, HFILL }},
375 { &hf_cups_ptype_class,
376 { "Class", "cups.ptype.class", FT_BOOLEAN, 32,
377 TFS(&tfs_printer_class), CUPS_PRINTER_CLASS, NULL, HFILL }},
378 { &hf_cups_state,
379 { "State", "cups.state", FT_UINT8, BASE_HEX,
380 VALS(cups_state_values), 0x0, NULL, HFILL }}
383 static gint *ett[] = {
384 &ett_cups,
385 &ett_cups_ptype
388 proto_cups = proto_register_protocol(
389 "Common Unix Printing System (CUPS) Browsing Protocol",
390 "CUPS", "cups");
391 proto_register_field_array(proto_cups, hf, array_length(hf));
392 proto_register_subtree_array(ett, array_length(ett));
395 void
396 proto_reg_handoff_cups(void)
398 dissector_handle_t cups_handle;
400 cups_handle = create_dissector_handle(dissect_cups, proto_cups);
401 dissector_add_uint("udp.port", UDP_PORT_CUPS, cups_handle);
405 * Editor modelines - http://www.wireshark.org/tools/modelines.html
407 * Local variables:
408 * c-basic-offset: 4
409 * tab-width: 8
410 * indent-tabs-mode: nil
411 * End:
413 * vi: set shiftwidth=4 tabstop=8 expandtab:
414 * :indentSize=4:tabSize=8:noTabs=true: