Get rid of an unused variable.
[obnox/wireshark/wip.git] / packet-x11.c
1 /* packet-x11.c
2  * Routines for X11 dissection
3  * Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
4  *
5  * $Id: packet-x11.c,v 1.43 2002/04/23 06:06:03 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from README.developer
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 /* TODO (in no particular order):
29  *
30  * - keep track of Atom creation by server to be able to display
31  *   non-predefined atoms
32  * - Idem for keysym <-> keycode ???
33  * - Idem for fonts 
34  * - Subtree the request ids (that is x11.create-window.window and
35  *   x11.change-window.window should be  distinct), and add hidden fields
36  *   (so we still have x11.window).
37  * - add hidden fields so we can have x11.circulate-window in addition to
38  *   x11.opcode == 13 (but you could match on x11.opcode == "CirculateWindow"
39  *   now)
40  * - add hidden fields so we have x11.listOfStuff.length
41  * - use a faster scheme that linear list searching for the opcode.
42  * - correct display of Unicode chars.
43  * - Not everything is homogeneous, in particular the handling of items in
44  *   list is a total mess.
45  */
46
47 /* By the way, I wrote a program to generate every request and test
48  * that stuff. If you're interested, you can get it at
49  * http://tronche.com/gui/x/
50  */
51
52 #ifdef HAVE_CONFIG_H
53 # include "config.h"
54 #endif
55
56 #include <assert.h>
57 #include <ctype.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60
61 #ifdef HAVE_SYS_TYPES_H
62 # include <sys/types.h>
63 #endif
64
65 #include <string.h>
66 #include <glib.h>
67 #include <epan/packet.h>
68 #include <epan/conversation.h>
69
70 #include "prefs.h"
71 #include "packet-frame.h"
72
73 #define cVALS(x) (const value_string*)(x)
74
75 /* Initialize the protocol and registered fields */
76 static int proto_x11 = -1;
77
78 #include "x11-declarations.h"
79
80 /* Initialize the subtree pointers */
81 static gint ett_x11 = -1;
82 static gint ett_x11_color_flags = -1;
83 static gint ett_x11_list_of_arc = -1;
84 static gint ett_x11_arc = -1;
85 static gint ett_x11_list_of_atom = -1;
86 static gint ett_x11_list_of_card32 = -1;
87 static gint ett_x11_list_of_color_item = -1;
88 static gint ett_x11_color_item = -1;
89 static gint ett_x11_list_of_keycode = -1;
90 static gint ett_x11_list_of_keysyms = -1;
91 static gint ett_x11_keysym = -1;
92 static gint ett_x11_list_of_point = -1;
93 static gint ett_x11_point = -1;
94 static gint ett_x11_list_of_rectangle = -1;
95 static gint ett_x11_rectangle = -1;
96 static gint ett_x11_list_of_segment = -1;
97 static gint ett_x11_segment = -1;
98 static gint ett_x11_list_of_string8 = -1;
99 static gint ett_x11_list_of_text_item = -1;
100 static gint ett_x11_text_item = -1;
101 static gint ett_x11_gc_value_mask = -1;
102 static gint ett_x11_event_mask = -1;
103 static gint ett_x11_do_not_propagate_mask = -1;
104 static gint ett_x11_set_of_key_mask = -1;
105 static gint ett_x11_pointer_event_mask = -1;
106 static gint ett_x11_window_value_mask = -1;
107 static gint ett_x11_configure_window_mask = -1;
108 static gint ett_x11_keyboard_value_mask = -1;
109
110 /* desegmentation of X11 messages */
111 static gboolean x11_desegment = TRUE;
112
113 static dissector_handle_t data_handle;
114
115 #define TCP_PORT_X11                    6000
116 #define TCP_PORT_X11_2                  6001
117 #define TCP_PORT_X11_3                  6002
118
119 /*
120  * Round a length to a multiple of 4 bytes.
121  */
122 #define ROUND_LENGTH(n) ((((n) + 3)/4) * 4)
123
124 /************************************************************************
125  ***                                                                  ***
126  ***         E N U M   T A B L E S   D E F I N I T I O N S            ***
127  ***                                                                  ***
128  ************************************************************************/
129
130 static const value_string byte_order_vals[] = {
131      { 'B', "Big-endian" },
132      { 'l', "Little-endian" },
133      { 0,   NULL }
134 };
135
136 static const value_string access_mode_vals[] = {
137       { 0, "Disable" },
138       { 1, "Enable" },
139       { 0, NULL }
140 };
141
142 static const value_string all_temporary_vals[] = {
143       { 0, "AllTemporary" },
144       { 0, NULL }
145 };
146
147 static const value_string alloc_vals[] = {
148       { 0, "None" },
149       { 1, "All" },
150       { 0, NULL }
151 };
152
153 static const value_string allow_events_mode_vals[] = {
154       { 0, "AsyncPointer" },
155       { 1, "SyncPointer" },
156       { 2, "ReplayPointer" },
157       { 3, "AsyncKeyboard" },
158       { 4, "SyncKeyboard" },
159       { 5, "ReplayKeyboard" },
160       { 6, "AsyncBoth" },
161       { 7, "SyncBoth" },
162       { 0, NULL }
163 };
164
165 static const value_string arc_mode_vals[] = {
166       { 0, "Chord" },
167       { 1, "PieSlice" },
168       { 0, NULL }
169 };
170
171 static const char *atom_predefined_interpretation[] = {
172       "<error>",
173       "PRIMARY",
174       "SECONDARY",
175       "ARC",
176       "ATOM",
177       "BITMAP",
178       "CARDINAL",
179       "COLORMAP",
180       "CURSOR",
181       "CUT_BUFFER0",
182       "CUT_BUFFER1",
183       "CUT_BUFFER2",
184       "CUT_BUFFER3",
185       "CUT_BUFFER4",
186       "CUT_BUFFER5",
187       "CUT_BUFFER6",
188       "CUT_BUFFER7",
189       "DRAWABLE",
190       "FONT",
191       "INTEGER",
192       "PIXMAP",
193       "POINT",
194       "RECTANGLE",
195       "RESOURCE_MANAGER",
196       "RGB_COLOR_MAP",
197       "RGB_BEST_MAP",
198       "RGB_BLUE_MAP",
199       "RGB_DEFAULT_MAP",
200       "RGB_GRAY_MAP",
201       "RGB_GREEN_MAP",
202       "RGB_RED_MAP",
203       "STRING",
204       "VISUALID",
205       "WINDOW",
206       "WM_COMMAND",
207       "WM_HINTS",
208       "WM_CLIENT_MACHINE",
209       "WM_ICON_NAME",
210       "WM_ICON_SIZE",
211       "WM_NAME",
212       "WM_NORMAL_HINTS",
213       "WM_SIZE_HINTS",
214       "WM_ZOOM_HINTS",
215       "MIN_SPACE",
216       "NORM_SPACE",
217       "MAX_SPACE",
218       "END_SPACE",
219       "SUPERSCRIPT_X",
220       "SUPERSCRIPT_Y",
221       "SUBSCRIPT_X",
222       "SUBSCRIPT_Y",
223       "UNDERLINE_POSITION",
224       "UNDERLINE_THICKNESS",
225       "STRIKEOUT_ASCENT",
226       "STRIKEOUT_DESCENT",
227       "ITALIC_ANGLE",
228       "X_HEIGHT",
229       "QUAD_WIDTH",
230       "WEIGHT",
231       "POINT_SIZE",
232       "RESOLUTION",
233       "COPYRIGHT",
234       "NOTICE",
235       "FONT_NAME",
236       "FAMILY_NAME",
237       "FULL_NAME",
238       "CAP_HEIGHT",
239       "WM_CLASS",
240       "WM_TRANSIENT_FOR",
241 };
242
243 static const value_string auto_repeat_mode_vals[] = {
244       { 0, "Off" },
245       { 1, "On" },
246       { 2, "Default" },
247       { 0, NULL }
248 };
249
250 static const value_string background_pixmap_vals[] = { 
251       { 0, "None" },
252       { 1, "ParentRelative" },
253       { 0, NULL }
254 };
255
256 static const value_string backing_store_vals[] = {
257       { 0, "NotUseful" },
258       { 1, "WhenMapped" },
259       { 2, "Always" },
260       { 0, NULL }
261 };
262
263 static const value_string border_pixmap_vals[] = { 
264       { 0, "CopyFromParent" },
265       { 0, NULL }
266 };
267
268 static const value_string button_vals[] = {
269       { 0x8000, "AnyButton" },
270       { 0, NULL }
271 };
272
273 static const value_string cap_style_vals[] = {
274       { 0, "NotLast" },
275       { 1, "Butt" },
276       { 2, "Round" },
277       { 3, "Projecting" },
278       { 0, NULL }
279 };
280
281 static const value_string class_vals[] = {
282       { 0, "Cursor" },
283       { 1, "Tile" },
284       { 2, "Stipple" },
285       { 0, NULL }
286 };
287
288 static const value_string close_down_mode_vals[] = {
289       { 0, "Destroy" },
290       { 1, "RetainPermanent" },
291       { 2, "RetainTemporary" },
292       { 0, NULL }
293 };
294
295 static const value_string coordinate_mode_vals[] = {
296       { 0, "Origin" },
297       { 1, "Previous" },
298       { 0, NULL }
299 };
300
301 static const value_string direction_vals[] = { 
302       { 0, "RaiseLowest" },
303       { 1, "LowerHighest" },
304       { 0, NULL }
305 };
306
307 #define FAMILY_INTERNET 0
308 #define FAMILY_DECNET   1
309 #define FAMILY_CHAOS    2
310
311 static const value_string family_vals[] = {
312       { FAMILY_INTERNET, "Internet" },
313       { FAMILY_DECNET,   "DECnet" },
314       { FAMILY_CHAOS,    "Chaos" },
315       { 0, NULL }
316 };
317
318 static const value_string fill_rule_vals[] = {
319       { 0, "EvenOdd" },
320       { 1, "Winding" },
321       { 0, NULL }
322 };
323
324 static const value_string fill_style_vals[] = {
325       { 0, "Solid" },
326       { 1, "Tiled" },
327       { 2, "Stippled" },
328       { 3, "OpaqueStippled" },
329       { 0, NULL }
330 };
331
332 static const value_string focus_vals[] = {
333       { 0, "None" },
334       { 1, "PointerRoot" },
335       { 0, NULL }
336 };
337
338 static const value_string function_vals[] = {
339       {  0, "Clear" },
340       {  1, "And" },
341       {  2, "AndReverse" },
342       {  3, "Copy" },
343       {  4, "AndInverted" },
344       {  5, "NoOp" },
345       {  6, "Xor" },
346       {  7, "Or" },
347       {  8, "Nor" },
348       {  9, "Equiv" },
349       { 10, "Invert" },
350       { 11, "OrReverse" },
351       { 12, "CopyInverted" },
352       { 13, "OrInverted" },
353       { 14, "Nand" },
354       { 15, "Set" },  
355       {  0, NULL }
356 };
357
358 static const value_string gravity_vals[] = {
359       {  1, "NorthWest" },
360       {  2, "North" },
361       {  3, "NorthEast" },
362       {  4, "West" },
363       {  5, "Center" },
364       {  6, "East" },
365       {  7, "SouthWest" },
366       {  8, "South" },
367       {  9, "SouthEast" },
368       { 10, "Static" },
369       {  0, NULL }
370 };
371
372 static const value_string image_format_vals[] = {
373       { 0, "Bitmap" },
374       { 1, "XYPixmap" },
375       { 2, "ZPixmap" },
376       { 0, NULL }
377 };
378
379 static const value_string image_pixmap_format_vals[] = {
380       { 1, "XYPixmap" },
381       { 2, "ZPixmap" },
382       { 0, NULL }
383 };
384
385 static const value_string join_style_vals[] = {
386       { 0, "Miter" },
387       { 1, "Round" },
388       { 2, "Bevel" },
389       { 0, NULL }
390 };
391
392 static const value_string key_vals[] = {
393       { 0, "AnyKey" },
394       { 0, NULL }
395 };
396
397 #include "packet-x11-keysym.h"
398
399 static const value_string line_style_vals[] = {
400       { 0, "Solid" },
401       { 1, "OnOffDash" },
402       { 2, "DoubleDash" },
403       { 0, NULL }
404 };
405
406 static const value_string mode_vals[] = {
407       { 0, "Replace" },
408       { 1, "Prepend" },
409       { 2, "Append" },
410       { 0, NULL }
411 };
412
413 static const value_string on_off_vals[] = {
414       { 0, "Off" },
415       { 1, "On" },
416       { 0, NULL }
417 };
418
419 static const value_string opcode_vals[] = {
420       {   1, "CreateWindow" },
421       {   2, "ChangeWindowAttributes" },
422       {   3, "GetWindowAttributes" }, 
423       {   4, "DestroyWindow" },
424       {   5, "DestroySubwindows" },
425       {   6, "ChangeSaveSet" },
426       {   7, "ReparentWindow" },
427       {   8, "MapWindow" },
428       {   9, "MapSubwindows" },
429       {  10, "UnmapWindow" },
430       {  11, "UnmapSubwindows" },
431       {  12, "ConfigureWindow" },
432       {  13, "CirculateWindow" },
433       {  14, "GetGeometry" },
434       {  15, "QueryTree" },
435       {  16, "InternAtom" },
436       {  17, "GetAtomName" },
437       {  18, "ChangeProperty" },
438       {  19, "DeleteProperty" },
439       {  20, "GetProperty" },
440       {  21, "ListProperties" },
441       {  22, "SetSelectionOwner" },
442       {  23, "GetSelectionOwner" },
443       {  24, "ConvertSelection" },
444
445       {  26, "GrabPointer" },
446       {  27, "UngrabPointer" },
447       {  28, "GrabButton" },
448       {  29, "UngrabButton" },
449       {  30, "ChangeActivePointerGrab" },
450       {  31, "GrabKeyboard" },
451       {  32, "UngrabKeyboard" },
452       {  33, "GrabKey" },
453       {  34, "UngrabKey" },
454       {  35, "AllowEvents" },
455       {  36, "GrabServer" },
456       {  37, "UngrabServer" },
457       {  38, "QueryPointer" },
458       {  39, "GetMotionEvents" },
459       {  40, "TranslateCoordinates" },
460       {  41, "WarpPointer" },
461       {  42, "SetInputFocus" },
462       {  43, "GetInputFocus" },
463       {  44, "QueryKeymap" },
464       {  45, "OpenFont" },
465       {  46, "CloseFont" },
466       {  47, "QueryFont" },
467       {  48, "QueryTextExtents" },
468       {  49, "ListFonts" },
469       {  50, "ListFontsWithInfo" },
470       {  51, "SetFontPath" },
471       {  52, "GetFontPath" },
472       {  53, "CreatePixmap" },
473       {  54, "FreePixmap" },
474       {  55, "CreateGC" },
475       {  56, "ChangeGC" },
476       {  57, "CopyGC" },
477       {  58, "SetDashes" },
478       {  59, "SetClipRectangles" },
479       {  60, "FreeGC" },
480       {  61, "ClearArea" },
481       {  62, "CopyArea" },
482       {  63, "CopyPlane" },
483       {  64, "PolyPoint" },
484       {  65, "PolyLine" },
485       {  66, "PolySegment" },
486       {  67, "PolyRectangle" },
487       {  68, "PolyArc" },
488       {  69, "FillPoly" },
489       {  70, "PolyFillRectangle" },
490       {  71, "PolyFillArc" },
491       {  72, "PutImage" },
492       {  73, "GetImage" },
493       {  74, "PolyText8" },
494       {  75, "PolyText16" },
495       {  76, "ImageText8" },
496       {  77, "ImageText16" },
497       {  78, "CreateColormap" },
498       {  79, "FreeColormap" },
499       {  80, "CopyColormapAndFree" },
500       {  81, "InstallColormap" },
501       {  82, "UninstallColormap" },
502       {  83, "ListInstalledColormaps" },
503       {  84, "AllocColor" },
504       {  85, "AllocNamedColor" },
505       {  86, "AllocColorCells" },
506       {  87, "AllocColorPlanes" },
507       {  88, "FreeColors" },
508       {  89, "StoreColors" },
509       {  90, "StoreNamedColor" },
510       {  91, "QueryColors" },
511       {  92, "LookupColor" },
512       {  93, "CreateCursor" },
513       {  94, "CreateGlyphCursor" },
514       {  95, "FreeCursor" },
515       {  96, "RecolorCursor" },
516       {  97, "QueryBestSize" },
517       {  98, "QueryExtension" },
518       {  99, "ListExtensions" },
519       { 100, "ChangeKeyboardMapping" },
520       { 101, "GetKeyboardMapping" },
521       { 102, "ChangeKeyboardControl" },
522       { 103, "GetKeyboardControl" },
523       { 104, "Bell" },
524       { 105, "ChangePointerControl" },
525       { 106, "GetPointerControl" },
526       { 107, "SetScreenSaver" },
527       { 108, "GetScreenSaver" },
528       { 109, "ChangeHosts" },
529       { 110, "ListHosts" },
530       { 111, "SetAccessControl" },
531       { 112, "SetCloseDownMode" },
532       { 113, "KillClient" },
533       { 114, "RotateProperties" },
534       { 115, "ForceScreenSaver" },
535       { 116, "SetPointerMapping" },
536       { 117, "GetPointerMapping" },
537       { 118, "SetModifierMapping" },
538       { 119, "GetModifierMapping" },
539       { 127, "NoOperation" },
540       { 0, NULL }
541 };
542
543 static const value_string ordering_vals[] = {
544       { 0, "UnSorted" },
545       { 1, "YSorted" },
546       { 2, "YXSorted" },
547       { 3, "YXBanded" },
548       { 0, NULL }
549 };
550
551 static const value_string plane_mask_vals[] = {
552       { 0xFFFFFFFF, "AllPlanes" },
553       { 0, NULL }
554 };
555
556 static const value_string pointer_keyboard_mode_vals[] = {
557       { 0, "Synchronous" },
558       { 1, "Asynchronous" },
559       { 0, NULL }
560 };
561
562 static const value_string revert_to_vals[] = {
563       { 0, "None" },
564       { 1, "PointerRoot" },
565       { 2, "Parent" },
566       { 0, NULL }
567 };
568
569 static const value_string insert_delete_vals[] = {
570       { 0, "Insert" },
571       { 1, "Delete" },
572       { 0, NULL }
573 };
574
575 static const value_string screen_saver_mode_vals[] = {
576       { 0, "Reset" },
577       { 1, "Activate" },
578       { 0, NULL }
579 };
580
581 static const value_string shape_vals[] = {
582       { 0, "Complex" },
583       { 1, "Nonconvex" },
584       { 2, "Convex" },
585       { 0, NULL }
586 };
587
588 static const value_string stack_mode_vals[] = {
589       { 0, "Above" },
590       { 1, "Below" },
591       { 2, "TopIf" },
592       { 3, "BottomIf" },
593       { 4, "Opposite" },
594       { 0, NULL }
595 };
596
597 static const value_string subwindow_mode_vals[] = {
598       { 0, "ClipByChildren" },
599       { 1, "IncludeInferiors" },
600       { 0, NULL }
601 };
602
603 static const value_string window_class_vals[] = {
604       { 0, "CopyFromParent" },
605       { 1, "InputOutput" },
606       { 2, "InputOnly" },
607       { 0, NULL }
608 };
609
610 static const value_string yes_no_default_vals[] = {
611       { 0, "No" },
612       { 1, "Yes" },
613       { 2, "Default" },
614       { 0, NULL }
615 };
616
617 static const value_string zero_is_any_property_type_vals[] = {
618       { 0, "AnyPropertyType" },
619       { 0, NULL }
620 };
621
622 static const value_string zero_is_none_vals[] = {
623       { 0, "None" },
624       { 0, NULL }
625 };
626
627 /************************************************************************
628  ***                                                                  ***
629  ***           F I E L D   D E C O D I N G   M A C R O S              ***
630  ***                                                                  ***
631  ************************************************************************/
632
633 #define VALUE8(tvb, offset) (tvb_get_guint8(tvb, offset))
634 #define VALUE16(tvb, offset) (little_endian ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset))
635 #define VALUE32(tvb, offset) (little_endian ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset))
636
637 #define FIELD8(name)  (field8(tvb, offsetp, t, hf_x11_##name, little_endian))
638 #define FIELD16(name) (field16(tvb, offsetp, t, hf_x11_##name, little_endian))
639 #define FIELD32(name) (field32(tvb, offsetp, t, hf_x11_##name, little_endian))
640
641 #define BITFIELD(TYPE, position, name) {\
642   int unused;\
643   int save = *offsetp;\
644   proto_tree_add_item(bitmask_tree, hf_x11_##position##_##name, tvb, bitmask_offset, \
645                       bitmask_size, little_endian); \
646   if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\
647        TYPE(name);\
648        unused = save + 4 - *offsetp;\
649        if (unused)\
650            proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, unused, little_endian);\
651        *offsetp = save + 4;\
652  }\
653 }
654
655 #define FLAG(position, name) {\
656        proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
657
658 #define FLAG_IF_NONZERO(position, name) {\
659   if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask)\
660        proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
661
662 #define ATOM(name)     { atom(tvb, offsetp, t, hf_x11_##name, little_endian); }
663 #define BITGRAVITY(name) { gravity(tvb, offsetp, t, hf_x11_##name, "Forget"); }
664 #define BITMASK(name, size) {\
665       proto_item *ti; \
666       guint32 bitmask_value; \
667       int bitmask_offset; \
668       int bitmask_size; \
669       proto_tree *bitmask_tree; \
670       bitmask_value = ((size == 1) ? VALUE8(tvb, *offsetp) : \
671                        ((size == 2) ? VALUE16(tvb, *offsetp) : \
672                                       VALUE32(tvb, *offsetp))); \
673       bitmask_offset = *offsetp; \
674       bitmask_size = size; \
675       ti = proto_tree_add_uint(t, hf_x11_##name##_mask, tvb, *offsetp, size, bitmask_value); \
676       bitmask_tree = proto_item_add_subtree(ti, ett_x11_##name##_mask); \
677       *offsetp += size;
678 #define ENDBITMASK      }
679 #define BITMASK8(name)  BITMASK(name, 1);
680 #define BITMASK16(name) BITMASK(name, 2);
681 #define BITMASK32(name) BITMASK(name, 4);
682 #define BOOL(name)     (add_boolean(tvb, offsetp, t, hf_x11_##name))
683 #define BUTTON(name)   { FIELD8(name); }
684 #define CARD8(name)    { FIELD8(name); }
685 #define CARD16(name)   (FIELD16(name))
686 #define CARD32(name)   (FIELD32(name))
687 #define COLOR_FLAGS(name) { colorFlags(tvb, offsetp, t); }
688 #define COLORMAP(name) { FIELD32(name); }
689 #define CURSOR(name)   { FIELD32(name); }
690 #define DRAWABLE(name) { FIELD32(name); }
691 #define ENUM8(name)    (FIELD8(name))
692 #define ENUM16(name)   { FIELD16(name); }
693 #define FONT(name)     { FIELD32(name); }
694 #define FONTABLE(name) { FIELD32(name); }
695 #define GCONTEXT(name) { FIELD32(name); }
696 #define INT8(name)     { FIELD8(name); }
697 #define INT16(name)    { FIELD16(name); }
698 #define KEYCODE(name)  { FIELD8(name); }
699 #define LISTofARC(name) { listOfArc(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 12, little_endian); }
700 #define LISTofATOM(name, length) { listOfAtom(tvb, offsetp, t, hf_x11_##name, (length) / 4, little_endian); }
701 #define LISTofBYTE(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
702 #define LISTofCARD8(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
703 #define LISTofCARD32(name, length) { listOfCard32(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 4, little_endian); }
704 #define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, offsetp, t, hf_x11_##name, (length) / 12, little_endian); }
705 #define LISTofKEYCODE(name, length) { listOfKeycode(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
706 #define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \
707       listOfKeysyms(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode), little_endian); }
708 #define LISTofPOINT(name, length) { listOfPoint(tvb, offsetp, t, hf_x11_##name, (length) / 4, little_endian); }
709 #define LISTofRECTANGLE(name) { listOfRectangle(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, little_endian); }
710 #define LISTofSEGMENT(name) { listOfSegment(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, little_endian); }
711 #define LISTofSTRING8(name, length) { listOfString8(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_string, (length), little_endian); }
712 #define LISTofTEXTITEM8(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, FALSE, next_offset, little_endian); }
713 #define LISTofTEXTITEM16(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, TRUE, next_offset, little_endian); }
714 #define OPCODE()       { opcode = FIELD8(opcode); }
715 #define PIXMAP(name)   { FIELD32(name); }
716 #define REQUEST_LENGTH() (requestLength(tvb, offsetp, t, little_endian))
717 #define SETofEVENT(name) { setOfEvent(tvb, offsetp, t, little_endian); }
718 #define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb, offsetp, t, little_endian);}
719 #define SETofKEYMASK(name) { setOfKeyMask(tvb, offsetp, t, little_endian); }
720 #define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb, offsetp, t, little_endian); }
721 #define STRING8(name, length)  { string8(tvb, offsetp, t, hf_x11_##name, length); }
722 #define STRING16(name, length)  { string16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_bytes, length, little_endian); }
723 #define TIMESTAMP(name){ timestamp(tvb, offsetp, t, hf_x11_##name, little_endian); }
724 #define UNDECODED(x)   { proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp,  x, little_endian); *offsetp += x; }
725 #define UNUSED(x)      { proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp,  x, little_endian); *offsetp += x; }
726 #define PAD()          { if (next_offset - *offsetp > 0) proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, next_offset - *offsetp, little_endian); *offsetp = next_offset; }
727 #define WINDOW(name)   { FIELD32(name); }
728 #define WINGRAVITY(name) { gravity(tvb, offsetp, t, hf_x11_##name, "Unmap"); }
729
730 #define VISUALID(name) { gint32 v = VALUE32(tvb, *offsetp); \
731     proto_tree_add_uint_format(t, hf_x11_##name, tvb, *offsetp, 4, v, "Visualid: 0x%08x%s", v, \
732                                v ? "" : " (CopyFromParent)"); *offsetp += 4; }
733
734 /************************************************************************
735  ***                                                                  ***
736  ***                  D E C O D I N G   F I E L D S                   ***
737  ***                                                                  ***
738  ************************************************************************/
739
740 static void atom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
741                  gboolean little_endian)
742 {
743       const char *interpretation = NULL;
744
745       guint32 v = VALUE32(tvb, *offsetp);
746       if (v >= 1 && v < array_length(atom_predefined_interpretation))
747             interpretation = atom_predefined_interpretation[v];
748       else if (v)
749             interpretation = "Not a predefined atom";
750       else {
751             header_field_info *hfi = proto_registrar_get_nth(hf);
752             if (hfi -> strings)
753                   interpretation = match_strval(v, cVALS(hfi -> strings));
754       }
755       if (!interpretation) interpretation = "error in Xlib client program ?";
756       proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: %u (%s)", 
757                                  proto_registrar_get_nth(hf) -> name, v, interpretation);
758       *offsetp += 4;
759 }
760
761 static guint32 add_boolean(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
762 {
763       guint32 v = VALUE8(tvb, *offsetp);
764       proto_tree_add_boolean(t, hf, tvb, *offsetp, 1, v);
765       *offsetp += 1;
766       return v;
767 }
768
769 static void colorFlags(tvbuff_t *tvb, int *offsetp, proto_tree *t)
770 {
771       unsigned do_red_green_blue = VALUE8(tvb, *offsetp);
772       proto_item *ti;
773       proto_tree *tt;
774       
775       if (do_red_green_blue) {
776             int sep = FALSE;
777             char buffer[512];
778             char *bp = buffer + sprintf(buffer, "flags: ");
779
780             if (do_red_green_blue & 0x1) {
781                   bp += sprintf(bp, "DoRed");
782                   sep = TRUE;
783             }
784
785             if (do_red_green_blue & 0x2) {
786                   if (sep) bp += sprintf(bp, " | ");
787                   bp += sprintf(bp, "DoGreen");
788                   sep = TRUE;
789             }
790
791             if (do_red_green_blue & 0x4) {
792                   if (sep) bp += sprintf(bp, " | ");
793                   bp += sprintf(bp, "DoBlue");
794                   sep = TRUE;
795             }
796
797             if (do_red_green_blue & 0xf8) {
798                   if (sep) bp += sprintf(bp, " + ");
799                   sprintf(bp, "trash");
800             }
801
802             ti = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
803                                             "%s", buffer);
804             tt = proto_item_add_subtree(ti, ett_x11_color_flags);
805             if (do_red_green_blue & 0x1)
806                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, *offsetp, 1, 
807                                          do_red_green_blue & 0x1);
808             if (do_red_green_blue & 0x2)
809                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, *offsetp, 1, 
810                                          do_red_green_blue & 0x2);
811             if (do_red_green_blue & 0x4)
812                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, *offsetp, 1, 
813                                          do_red_green_blue & 0x4);
814             if (do_red_green_blue & 0xf8)
815                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, *offsetp, 1, 
816                                          do_red_green_blue & 0xf8);
817       } else
818             proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
819                                        "flags: none");
820       *offsetp += 1;
821 }
822
823 static void gravity(tvbuff_t *tvb, int *offsetp, proto_tree *t,
824     int hf, const char *nullInterpretation)
825 {
826       guint8 v = VALUE8(tvb, *offsetp);
827
828       if (!v)
829             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: 0 (%s)",
830                                        proto_registrar_get_nth(hf) -> name,
831                                        nullInterpretation);
832       else
833             proto_tree_add_uint(t, hf, tvb, *offsetp, 1, v);
834       *offsetp += 1;
835 }
836
837 static void listOfArc(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
838                       int length, gboolean little_endian)
839 {
840       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
841       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_arc);
842       while(length--) {
843             gint16 x = VALUE16(tvb, *offsetp);
844             gint16 y = VALUE16(tvb, *offsetp + 2);
845             guint16 width = VALUE16(tvb, *offsetp + 4);
846             guint16 height = VALUE16(tvb, *offsetp + 6);
847             gint16 angle1 = VALUE16(tvb, *offsetp + 8);
848             gint16 angle2 = VALUE16(tvb, *offsetp + 10);
849
850             proto_item *tti = proto_tree_add_none_format(tt, hf_x11_arc, tvb, *offsetp, 12, 
851                                                              "arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)",
852                                                              width, height, x, y, angle1, angle2,
853                                                              angle1 / 64.0, angle2 / 64.0);
854             proto_tree *ttt = proto_item_add_subtree(tti, ett_x11_arc);
855             proto_tree_add_int(ttt, hf_x11_arc_x, tvb, *offsetp, 2, x);
856             *offsetp += 2;
857             proto_tree_add_int(ttt, hf_x11_arc_y, tvb, *offsetp, 2, y);
858             *offsetp += 2;
859             proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, *offsetp, 2, y);
860             *offsetp += 2;
861             proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, *offsetp, 2, y);
862             *offsetp += 2;
863             proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, *offsetp, 2, y);
864             *offsetp += 2;
865             proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, *offsetp, 2, y);
866             *offsetp += 2;
867       }
868 }
869
870 static void listOfAtom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
871                        int length, gboolean little_endian)
872 {
873       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
874       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_atom);
875       while(length--)
876             atom(tvb, offsetp, tt, hf_x11_properties_item, little_endian);
877 }
878
879 static void listOfByte(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
880                        int length, gboolean little_endian)
881 {
882       if (length <= 0) length = 1;
883       proto_tree_add_item(t, hf, tvb, *offsetp, length, little_endian);
884       *offsetp += length;
885 }
886
887 static void listOfCard32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
888                          int hf_item, int length, gboolean little_endian)
889 {
890       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
891       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32);
892       while(length--) {
893             proto_tree_add_uint(tt, hf_item, tvb, *offsetp, 4, VALUE32(tvb, *offsetp));
894             *offsetp += 4;
895       }
896 }
897
898 static void listOfColorItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
899                             int length, gboolean little_endian)
900 {
901       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
902       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_color_item);
903       while(length--) {
904             proto_item *tti;
905             proto_tree *ttt;
906             unsigned do_red_green_blue;
907             guint16 red, green, blue;
908             char buffer[1024];
909             char *bp;
910             const char *sep;
911
912             red = VALUE16(tvb, *offsetp + 4);
913             green = VALUE16(tvb, *offsetp + 6);
914             blue = VALUE16(tvb, *offsetp + 8);
915             do_red_green_blue = VALUE8(tvb, *offsetp + 10);
916
917             bp = buffer + sprintf(buffer, "colorItem: ");
918             sep = "";
919             if (do_red_green_blue & 0x1) {
920                 bp += sprintf(bp, "red = %d", red);
921                 sep = ", ";
922             }
923             if (do_red_green_blue & 0x2) {
924                 bp += sprintf(bp, "%sgreen = %d", sep, green);
925                 sep = ", ";
926             }
927             if (do_red_green_blue & 0x4)
928                 bp += sprintf(bp, "%sblue = %d", sep, blue);
929
930             tti = proto_tree_add_none_format(tt, hf_x11_coloritem, tvb, *offsetp, 12, "%s", buffer);
931             ttt = proto_item_add_subtree(tti, ett_x11_color_item);
932             proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, *offsetp, 4, little_endian);
933             *offsetp += 4;
934             proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, *offsetp, 2, little_endian);
935             *offsetp += 2;
936             proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, *offsetp, 2, little_endian);
937             *offsetp += 2;
938             proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, *offsetp, 2, little_endian);
939             *offsetp += 2;
940             colorFlags(tvb, offsetp, ttt);
941             proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, *offsetp, 1, little_endian);
942             *offsetp += 1;
943       }
944 }
945
946 static GTree *keysymTable = NULL;
947
948 static gint compareGuint32(gconstpointer a, gconstpointer b)
949 {
950       return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a);;
951 }
952
953 static const char *keysymString(guint32 v)
954 {
955       gpointer res;
956       if (!keysymTable) {
957
958             /* This table is so big that we built it only if necessary */
959
960             const value_string *p = keysym_vals_source;
961             keysymTable = g_tree_new(compareGuint32);
962             for(; p -> strptr; p++)
963                   g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), p -> strptr);
964       }
965       res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v));
966       return res ? res : "Unknown";
967 }
968
969 static const char *modifiers[] = { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
970
971 static void listOfKeycode(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
972                           int length, gboolean little_endian)
973 {
974       char buffer[1024];
975       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
976       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keycode);
977
978       while(length--) {
979             char *bp = buffer;
980             const char **m;
981             int i;
982
983             for(i = 8, m = modifiers; i; i--, m++) {
984                 u_char c = tvb_get_guint8(tvb, *offsetp);
985                 *offsetp += 1;
986                 if (c)
987                     bp += sprintf(bp, "  %s=%d", *m, c);
988             }
989
990             proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, *offsetp - 8, 8, tvb_get_ptr(tvb, *offsetp - 8, 8),      "item: %s", buffer);
991       }
992 }
993
994 static void listOfKeysyms(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
995                           int hf_item, int keycode_count,
996                           int keysyms_per_keycode, gboolean little_endian)
997 {
998       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, keycode_count * keysyms_per_keycode * 4, little_endian);
999       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keysyms);
1000       proto_item *tti;
1001       proto_tree *ttt;
1002       int i;
1003
1004       while(keycode_count--) {
1005             tti = proto_tree_add_none_format(tt, hf_item, tvb, *offsetp, keysyms_per_keycode * 4,
1006                                                  "keysyms:");
1007             ttt = proto_item_add_subtree(tti, ett_x11_keysym);
1008             for(i = keysyms_per_keycode; i; i--) {
1009                   guint32 v = VALUE32(tvb, *offsetp);
1010                   proto_item_append_text(tti, " %s", keysymString(v));
1011                   proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, *offsetp, 4, v,
1012                                              "keysym: 0x%08x (%s)", v, keysymString(v));
1013                   *offsetp += 4;
1014             }
1015       }
1016 }
1017
1018 static void listOfPoint(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1019                         int length, gboolean little_endian)
1020 {
1021       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
1022       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_point);
1023       while(length--) {
1024             gint16 x, y;
1025             proto_item *tti;
1026             proto_tree *ttt;
1027
1028             x = VALUE16(tvb, *offsetp);
1029             y = VALUE16(tvb, *offsetp + 2);
1030
1031             tti = proto_tree_add_none_format(tt, hf_x11_point, tvb, *offsetp, 4, "point: (%d,%d)", x, y);
1032             ttt = proto_item_add_subtree(tti, ett_x11_point);
1033             proto_tree_add_int(ttt, hf_x11_point_x, tvb, *offsetp, 2, x);
1034             *offsetp += 2;
1035             proto_tree_add_int(ttt, hf_x11_point_y, tvb, *offsetp, 2, y);
1036             *offsetp += 2;
1037       }
1038 }
1039
1040 static void listOfRectangle(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1041                             int length, gboolean little_endian)
1042 {
1043       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1044       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle);
1045       while(length--) {
1046             gint16 x, y;
1047             unsigned width, height;
1048             proto_item *tti;
1049             proto_tree *ttt;
1050
1051             x = VALUE16(tvb, *offsetp);
1052             y = VALUE16(tvb, *offsetp + 2);
1053             width = VALUE16(tvb, *offsetp + 4);
1054             height = VALUE16(tvb, *offsetp + 6);
1055
1056             tti = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, *offsetp, 8, 
1057                                                  "rectangle: %dx%d+%d+%d", width, height, x, y);
1058             ttt = proto_item_add_subtree(tti, ett_x11_rectangle);
1059             proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, *offsetp, 2, x);
1060             *offsetp += 2;
1061             proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, *offsetp, 2, y);
1062             *offsetp += 2;
1063             proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, *offsetp, 2, width);
1064             *offsetp += 2;
1065             proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, *offsetp, 2, height);
1066             *offsetp += 2;
1067       }
1068 }
1069
1070 static void listOfSegment(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1071                           int length, gboolean little_endian)
1072 {
1073       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1074       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_segment);
1075       while(length--) {
1076             gint16 x1, y1, x2, y2;
1077             proto_item *tti;
1078             proto_tree *ttt;
1079
1080             x1 = VALUE16(tvb, *offsetp);
1081             y1 = VALUE16(tvb, *offsetp + 2);
1082             x2 = VALUE16(tvb, *offsetp + 4);
1083             y2 = VALUE16(tvb, *offsetp + 6);
1084
1085             tti = proto_tree_add_none_format(tt, hf_x11_segment, tvb, *offsetp, 8, 
1086                                                  "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2);
1087             ttt = proto_item_add_subtree(tti, ett_x11_segment);
1088             proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, *offsetp, 2, little_endian);
1089             *offsetp += 2;
1090             proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, *offsetp, 2, little_endian);
1091             *offsetp += 2;
1092             proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, *offsetp, 2, little_endian);
1093             *offsetp += 2;
1094             proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, *offsetp, 2, little_endian);
1095             *offsetp += 2;
1096       }
1097 }
1098
1099 /* XXX - the protocol tree code should handle non-printable characters.
1100    Note that "non-printable characters" may depend on your locale.... */
1101 static void stringCopy(char *dest, const char *source, int length)
1102 {
1103       u_char c;
1104       while(length--) {
1105             c = *source++;
1106             if (!isgraph(c) && c != ' ') c = '.';
1107             *dest++ = c;
1108       }
1109       *dest++ = '\0';
1110 }
1111
1112 static void listOfString8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1113                           int hf_item, int length, gboolean little_endian)
1114 {
1115       char *s = NULL;
1116       guint allocated = 0;
1117       proto_item *ti;
1118       proto_tree *tt;
1119       int i;
1120
1121       /* Compute total length */
1122       
1123       int scanning_offset = *offsetp; /* Scanning pointer */
1124       int l;
1125       for(i = length; i; i--) {
1126             l = tvb_get_guint8(tvb, scanning_offset);
1127             scanning_offset += 1 + l;
1128       }
1129
1130       ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1131       tt = proto_item_add_subtree(ti, ett_x11_list_of_string8);
1132
1133       /*
1134        * In case we throw an exception, clean up whatever stuff we've
1135        * allocated (if any).
1136        */
1137       CLEANUP_PUSH(g_free, s);
1138
1139       while(length--) {
1140             unsigned l = VALUE8(tvb, *offsetp);
1141             if (allocated < (l + 1)) {
1142                   /* g_realloc doesn't work ??? */
1143                   g_free(s);
1144                   s = g_malloc(l + 1);
1145                   allocated = l + 1;
1146             }
1147             stringCopy(s, tvb_get_ptr(tvb, *offsetp + 1, l), l); /* Nothing better for now. We need a better string handling API. */
1148             proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s);
1149             *offsetp += l + 1;
1150       }
1151
1152       /*
1153        * Call the cleanup handler to free the string and pop the handler.
1154        */
1155       CLEANUP_CALL_AND_POP;
1156 }
1157
1158 #define STRING16_MAX_DISPLAYED_LENGTH 150
1159
1160 static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
1161 {
1162       if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
1163       for(; length > 0; offset += 2, length--) {
1164             if (tvb_get_guint8(tvb, offset))
1165                 return FALSE;
1166       }
1167       return TRUE;
1168 }
1169
1170 /* length is the length of the _byte_zone_ (that is, twice the length of the string) */
1171
1172 static void string16_with_buffer_preallocated(tvbuff_t *tvb, proto_tree *t,
1173                                               int hf, int hf_bytes,
1174                                               int offset, unsigned length,
1175                                               char **s, int *sLength,
1176                                               gboolean little_endian)
1177 {
1178       int truncated = FALSE;
1179       unsigned l = length / 2;
1180
1181       if (stringIsActuallyAn8BitString(tvb, offset, l)) {
1182             char *dp;
1183             int soffset = offset;
1184
1185             if (l > STRING16_MAX_DISPLAYED_LENGTH) {
1186                   truncated = TRUE;
1187                   l = STRING16_MAX_DISPLAYED_LENGTH;
1188             }
1189             if (*sLength < (int) l + 3) {
1190                   g_free(*s);
1191                   *s = g_malloc(l + 3);
1192                   *sLength = l + 3;
1193             }
1194             dp = *s;
1195             *dp++ = '"';
1196             if (truncated) l -= 3;
1197
1198             while(l--) {
1199                   soffset++;
1200                   *dp++ = tvb_get_guint8(tvb, soffset);
1201                   soffset++;
1202             }
1203             *dp++ = '"';
1204
1205             /* If truncated, add an ellipsis */
1206             if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
1207
1208             *dp++ = '\0';
1209             proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s", 
1210                                         proto_registrar_get_nth(hf) -> name, *s);
1211       } else
1212             proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
1213
1214 }
1215
1216 static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1217     int sizeIs16, int next_offset, gboolean little_endian)
1218 {
1219       int allocated = 0;
1220       char *s = NULL;
1221       proto_item *ti;
1222       proto_tree *tt;
1223       guint32 fid;
1224
1225       /* Compute total length */
1226       
1227       int scanning_offset = *offsetp; /* Scanning pointer */
1228       int l;                            /* Length of an individual item */
1229       int n = 0;                        /* Number of items */
1230
1231       while(scanning_offset < next_offset) {
1232             l = tvb_get_guint8(tvb, scanning_offset);
1233             scanning_offset++;
1234             if (!l) break;
1235             n++;
1236             scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
1237       }
1238
1239       ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1240       tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item);
1241
1242       /*
1243        * In case we throw an exception, clean up whatever stuff we've
1244        * allocated (if any).
1245        */
1246       CLEANUP_PUSH(g_free, s);
1247
1248       while(n--) {
1249             unsigned l = VALUE8(tvb, *offsetp);
1250             if (l == 255) { /* Item is a font */
1251                   fid = tvb_get_ntohl(tvb, *offsetp + 1);
1252                   proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid);
1253                   *offsetp += 5;
1254             } else { /* Item is a string */
1255                   proto_item *tti;
1256                   proto_tree *ttt;
1257                   gint8 delta = VALUE8(tvb, *offsetp + 1);
1258                   if (sizeIs16) l += l;
1259                   if ((unsigned) allocated < l + 1) {
1260                         /* g_realloc doesn't work ??? */
1261                         g_free(s);
1262                         s = g_malloc(l + 1);
1263                         allocated = l + 1;
1264                   }
1265                   stringCopy(s, tvb_get_ptr(tvb, *offsetp + 2, l), l);
1266                   tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2,
1267                                                        "textitem (string): delta = %d, \"%s\"",
1268                                                        delta, s);
1269                   ttt = proto_item_add_subtree(tti, ett_x11_text_item);
1270                   proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, little_endian);
1271                   if (sizeIs16)
1272                         string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16, 
1273                                                           hf_x11_textitem_string_string16_bytes,
1274                                                           *offsetp + 2, l,
1275                                                           &s, &allocated,
1276                                                           little_endian);
1277                   else
1278                         proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb, 
1279                                                      *offsetp + 2, l, s, "\"%s\"", s);
1280                   *offsetp += l + 2;
1281             }
1282       }
1283
1284       /*
1285        * Call the cleanup handler to free the string and pop the handler.
1286        */
1287       CLEANUP_CALL_AND_POP;
1288 }
1289
1290 static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1291                       gboolean little_endian)
1292 {
1293       guint32 v = VALUE8(tvb, *offsetp);
1294       header_field_info *hfi = proto_registrar_get_nth(hf);
1295       gchar *enumValue = NULL;
1296
1297       if (hfi -> strings)
1298             enumValue = match_strval(v, cVALS(hfi -> strings));
1299       if (enumValue)
1300             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v,
1301                                        hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%02x (%s)",
1302                                        hfi -> name, v, enumValue);
1303       else
1304             proto_tree_add_item(t, hf, tvb, *offsetp, 1, little_endian);
1305       *offsetp += 1;
1306       return v;
1307 }
1308
1309 static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1310                        gboolean little_endian)
1311 {
1312       guint32 v = VALUE16(tvb, *offsetp);
1313       proto_tree_add_item(t, hf, tvb, *offsetp, 2, little_endian);
1314       *offsetp += 2;
1315       return v;
1316 }
1317
1318 static guint32 field32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1319                        gboolean little_endian)
1320 {
1321       guint32 v = VALUE32(tvb, *offsetp);
1322       header_field_info *hfi = proto_registrar_get_nth(hf);
1323       gchar *enumValue = NULL;
1324       gchar *nameAsChar = hfi -> name;
1325
1326       if (hfi -> strings)
1327             enumValue = match_strval(v, cVALS(hfi -> strings));
1328       if (enumValue)
1329             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1330                                        hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%08x (%s)",
1331                                        nameAsChar, v, enumValue);
1332       else
1333             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, 
1334                                        hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
1335                                        nameAsChar, v);
1336       *offsetp += 4;
1337       return v;
1338 }
1339
1340 static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1341                          gboolean little_endian)
1342 {
1343       BITMASK32(gc_value);
1344       BITFIELD(ENUM8,  gc_value_mask, function);
1345       BITFIELD(CARD32, gc_value_mask, plane_mask);
1346       BITFIELD(CARD32, gc_value_mask, foreground);
1347       BITFIELD(CARD32, gc_value_mask, background);
1348       BITFIELD(CARD16, gc_value_mask, line_width);
1349       BITFIELD(ENUM8,  gc_value_mask, line_style);
1350       BITFIELD(ENUM8,  gc_value_mask, cap_style);
1351       BITFIELD(ENUM8,  gc_value_mask, join_style);
1352       BITFIELD(ENUM8,  gc_value_mask, fill_style);
1353       BITFIELD(ENUM8,  gc_value_mask, fill_rule);
1354       BITFIELD(PIXMAP, gc_value_mask, tile);
1355       BITFIELD(PIXMAP, gc_value_mask, stipple);
1356       BITFIELD(INT16,  gc_value_mask, tile_stipple_x_origin);
1357       BITFIELD(INT16,  gc_value_mask, tile_stipple_y_origin);
1358       BITFIELD(FONT,   gc_value_mask, font);
1359       BITFIELD(ENUM8,  gc_value_mask, subwindow_mode);
1360       BITFIELD(BOOL,   gc_value_mask, graphics_exposures);
1361       BITFIELD(INT16,  gc_value_mask, clip_x_origin);
1362       BITFIELD(INT16,  gc_value_mask, clip_y_origin);
1363       BITFIELD(PIXMAP, gc_value_mask, clip_mask);
1364       BITFIELD(CARD16, gc_value_mask, dash_offset);
1365       BITFIELD(CARD8,  gc_value_mask, gc_dashes);
1366       BITFIELD(ENUM8,  gc_value_mask, arc_mode);
1367       ENDBITMASK;
1368 }
1369
1370 static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1371                    gboolean little_endian)
1372 {
1373       BITMASK32(gc_value);
1374       FLAG(gc_value, function);
1375       FLAG(gc_value, plane_mask);
1376       FLAG(gc_value, foreground);
1377       FLAG(gc_value, background);
1378       FLAG(gc_value, line_width);
1379       FLAG(gc_value, line_style);
1380       FLAG(gc_value, cap_style);
1381       FLAG(gc_value, join_style);
1382       FLAG(gc_value, fill_style);
1383       FLAG(gc_value, fill_rule);
1384       FLAG(gc_value, tile);
1385       FLAG(gc_value, stipple);
1386       FLAG(gc_value, tile_stipple_x_origin);
1387       FLAG(gc_value, tile_stipple_y_origin);
1388       FLAG(gc_value, font);
1389       FLAG(gc_value, subwindow_mode);
1390       FLAG(gc_value, graphics_exposures);
1391       FLAG(gc_value, clip_x_origin);
1392       FLAG(gc_value, clip_y_origin);
1393       FLAG(gc_value, clip_mask);
1394       FLAG(gc_value, dash_offset);
1395       FLAG(gc_value, gc_dashes);
1396       FLAG(gc_value, arc_mode);
1397       ENDBITMASK;
1398 }
1399
1400 static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1401                              gboolean little_endian)
1402 {
1403       guint32 res = VALUE16(tvb, *offsetp) * 4;
1404       proto_tree_add_uint(t, hf_x11_request_length, tvb, *offsetp, 2, res);
1405       *offsetp += 2;
1406       return res;
1407 }
1408
1409 static void setOfEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1410                        gboolean little_endian)
1411 {
1412       BITMASK32(event);
1413       FLAG(event, KeyPress);
1414       FLAG(event, KeyRelease);
1415       FLAG(event, ButtonPress);
1416       FLAG(event, ButtonRelease);
1417       FLAG(event, EnterWindow);
1418       FLAG(event, LeaveWindow);
1419       FLAG(event, PointerMotion);
1420       FLAG(event, PointerMotionHint);
1421       FLAG(event, Button1Motion);
1422       FLAG(event, Button2Motion);
1423       FLAG(event, Button3Motion);
1424       FLAG(event, Button4Motion);
1425       FLAG(event, Button5Motion);
1426       FLAG(event, ButtonMotion);
1427       FLAG(event, KeymapState);
1428       FLAG(event, Exposure);
1429       FLAG(event, VisibilityChange);
1430       FLAG(event, StructureNotify);
1431       FLAG(event, ResizeRedirect);
1432       FLAG(event, SubstructureNotify);
1433       FLAG(event, SubstructureRedirect);
1434       FLAG(event, FocusChange);
1435       FLAG(event, PropertyChange);
1436       FLAG(event, ColormapChange);
1437       FLAG(event, OwnerGrabButton);
1438       FLAG_IF_NONZERO(event, erroneous_bits);
1439       ENDBITMASK;
1440 }
1441
1442 static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1443                              gboolean little_endian)
1444 {
1445       BITMASK32(do_not_propagate);
1446       FLAG(do_not_propagate, KeyPress);
1447       FLAG(do_not_propagate, KeyRelease);
1448       FLAG(do_not_propagate, ButtonPress);
1449       FLAG(do_not_propagate, ButtonRelease);
1450       FLAG(do_not_propagate, PointerMotion);
1451       FLAG(do_not_propagate, Button1Motion);
1452       FLAG(do_not_propagate, Button2Motion);
1453       FLAG(do_not_propagate, Button3Motion);
1454       FLAG(do_not_propagate, Button4Motion);
1455       FLAG(do_not_propagate, Button5Motion);
1456       FLAG(do_not_propagate, ButtonMotion);
1457       FLAG_IF_NONZERO(do_not_propagate, erroneous_bits);
1458       ENDBITMASK;
1459 }
1460
1461 static void setOfKeyMask(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1462                          gboolean little_endian)
1463 {
1464       proto_item *ti;
1465       guint32 bitmask_value;
1466       int bitmask_offset;
1467       int bitmask_size;
1468       proto_tree *bitmask_tree;
1469
1470       bitmask_value = VALUE16(tvb, *offsetp);
1471       bitmask_offset = *offsetp;
1472       bitmask_size = 2;
1473       if (bitmask_value == 0x8000)
1474             proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000,
1475                                        "modifiers-masks: 0x8000 (AnyModifier)");
1476       else {
1477             ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2, 
1478                                                  bitmask_value);
1479             bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask);
1480             FLAG(modifiers, Shift);
1481             FLAG(modifiers, Lock);
1482             FLAG(modifiers, Control);
1483             FLAG(modifiers, Mod1);
1484             FLAG(modifiers, Mod2);
1485             FLAG(modifiers, Mod3);
1486             FLAG(modifiers, Mod4);
1487             FLAG(modifiers, Mod5);
1488             FLAG_IF_NONZERO(modifiers, erroneous_bits);
1489       }
1490       *offsetp += 2; 
1491 }
1492
1493 static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1494                               gboolean little_endian)
1495 {
1496       BITMASK16(pointer_event);
1497       FLAG(pointer_event, ButtonPress);
1498       FLAG(pointer_event, ButtonRelease);
1499       FLAG(pointer_event, EnterWindow);
1500       FLAG(pointer_event, LeaveWindow);
1501       FLAG(pointer_event, PointerMotion);
1502       FLAG(pointer_event, PointerMotionHint);
1503       FLAG(pointer_event, Button1Motion);
1504       FLAG(pointer_event, Button2Motion);
1505       FLAG(pointer_event, Button3Motion);
1506       FLAG(pointer_event, Button4Motion);
1507       FLAG(pointer_event, Button5Motion);
1508       FLAG(pointer_event, ButtonMotion);
1509       FLAG(pointer_event, KeymapState);
1510       FLAG_IF_NONZERO(pointer_event, erroneous_bits);
1511       ENDBITMASK;
1512 }
1513
1514 static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1515     int hf, unsigned length)
1516 {
1517       char *s = g_malloc(length + 1);
1518
1519       /*
1520        * In case we throw an exception, clean up whatever stuff we've
1521        * allocated (if any).
1522        */
1523       CLEANUP_PUSH(g_free, s);
1524
1525       stringCopy(s, tvb_get_ptr(tvb, *offsetp, length), length);
1526       proto_tree_add_string(t, hf, tvb, *offsetp, length, s);
1527
1528       /*
1529        * Call the cleanup handler to free the string and pop the handler.
1530        */
1531       CLEANUP_CALL_AND_POP;
1532
1533       *offsetp += length;
1534 }
1535
1536 /* The length is the length of the _byte_zone_ (twice the length of the string) */
1537
1538 static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1539     int hf_bytes, unsigned length, gboolean little_endian)
1540 {
1541       char *s = NULL;
1542       unsigned l = 0;
1543
1544       /*
1545        * In case we throw an exception, clean up whatever stuff we've
1546        * allocated (if any).
1547        */
1548       CLEANUP_PUSH(g_free, s);
1549
1550       length += length;
1551       string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, *offsetp, length,
1552                                         &s, &l, little_endian);
1553
1554       /*
1555        * Call the cleanup handler to free the string and pop the handler.
1556        */
1557       CLEANUP_CALL_AND_POP;
1558
1559       *offsetp += length;
1560 }
1561
1562 static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1563                       gboolean little_endian)
1564 {
1565       guint32 v = VALUE32(tvb, *offsetp);
1566
1567       if (!v)
1568             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)",
1569                 proto_registrar_get_nth(hf) -> name);
1570       else
1571             proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v);
1572       *offsetp += 4;
1573 }
1574
1575 static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1576                              gboolean little_endian)
1577 {
1578       BITMASK32(window_value);
1579       BITFIELD(PIXMAP, window_value_mask, background_pixmap);
1580       BITFIELD(CARD32, window_value_mask, background_pixel);
1581       BITFIELD(PIXMAP, window_value_mask, border_pixmap);
1582       BITFIELD(CARD32, window_value_mask, border_pixel);
1583       BITFIELD(BITGRAVITY, window_value_mask, bit_gravity);
1584       BITFIELD(WINGRAVITY, window_value_mask, win_gravity);
1585       BITFIELD(ENUM8, window_value_mask, backing_store);
1586       BITFIELD(CARD32, window_value_mask, backing_planes);
1587       BITFIELD(CARD32, window_value_mask, backing_pixel);
1588       BITFIELD(BOOL,   window_value_mask, override_redirect);
1589       BITFIELD(BOOL,   window_value_mask, save_under);
1590       BITFIELD(SETofEVENT, window_value_mask, event_mask);
1591       BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask);
1592       BITFIELD(COLORMAP, window_value_mask, colormap);
1593       BITFIELD(CURSOR, window_value_mask, cursor);
1594       ENDBITMASK;
1595 }
1596
1597 /*
1598  * Data structure associated with a conversation; keeps track of the
1599  * request for which we're expecting a reply, the frame number of
1600  * the initial connection request, and the byte order of the connection.
1601  *
1602  * An opcode of -3 means we haven't yet seen any requests yet.
1603  * An opcode of -2 means we're not expecting a reply.
1604  * An opcode of -1 means means we're waiting for a reply to the initial
1605  * connection request.
1606  * Other values are the opcode of the request for which we're expecting
1607  * a reply.
1608  *
1609  * XXX - assumes only one outstanding request is awaiting a reply,
1610  * which should always be the case.
1611  */
1612 #define NOTHING_SEEN            -3
1613 #define NOTHING_EXPECTED        -2
1614 #define INITIAL_CONN            -1
1615
1616 #define BYTE_ORDER_BE           0
1617 #define BYTE_ORDER_LE           1
1618 #define BYTE_ORDER_UNKNOWN      -1
1619
1620 typedef struct {
1621       int       opcode;         /* opcode for which we're awaiting a reply */
1622       guint32   iconn_frame;    /* frame # of initial connection request */
1623       int       byte_order;     /* byte order of connection */
1624 } x11_conv_data_t;
1625
1626 static GMemChunk *x11_state_chunk = NULL;
1627
1628 static void x11_init_protocol(void)
1629 {
1630       if (x11_state_chunk != NULL)
1631             g_mem_chunk_destroy(x11_state_chunk);
1632
1633       x11_state_chunk = g_mem_chunk_new("x11_state_chunk",
1634                                         sizeof (x11_conv_data_t),
1635                                         128 * sizeof (x11_conv_data_t),
1636                                         G_ALLOC_ONLY);
1637 }
1638
1639 /************************************************************************
1640  ***                                                                  ***
1641  ***         G U E S S I N G   T H E   B Y T E   O R D E R I N G      ***
1642  ***                                                                  ***
1643  ************************************************************************/
1644
1645 /* If we can't guess, we return TRUE (that is little_endian), cause
1646    I'm developing on a Linux box :-). The (non-)guess isn't cached
1647    however, so we may have more luck next time. I'm quite conservative
1648    in my assertions, cause once it's cached, it's stay in cache, and
1649    we may be fooled up by a packet starting with the end of a request
1650    started in a previous packet...
1651 */
1652
1653 static int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
1654
1655 static int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
1656 {
1657       int res = 0;
1658       while(maskLength--) {
1659             int c = tvb_get_guint8(tvb, offset);
1660             offset++;
1661             res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
1662       }
1663       return res;
1664 }
1665
1666 static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
1667 {
1668       if (listLength > length) return FALSE;
1669       while(listLength--) {
1670             int l;
1671             if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
1672             l = tvb_get_guint8(tvb, offset);
1673             if (!l) break;
1674             l++;
1675             if (l > length) return FALSE;
1676             if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
1677             offset += l;
1678             length -= l;
1679       }
1680       if (length > 3) return FALSE;
1681       return TRUE;
1682 }
1683
1684 static int rounded4(int n)
1685 {
1686       int remainder = n % 4;
1687       int res = n / 4;
1688       if (remainder) res++;
1689       return res;
1690 }
1691
1692 /* We assume the order to be consistent, until proven wrong. */
1693
1694 static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
1695 {
1696       switch(tvb_get_guint8(tvb, offset)) {
1697           case 1: /* CreateWindow */
1698             return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
1699
1700           case 2: /* ChangeWindowAttributes */
1701           case 56: /* ChangeGC */
1702             return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4);
1703
1704           case 3: /* GetWindowAttributes */
1705           case 4: /* DestroyWindow */
1706           case 5: /* DestroySubwindows */
1707           case 6: /* ChangeSaveSet */
1708           case 8: /* MapWindow */
1709           case 9: /* MapSubWindow */
1710           case 10: /* UnmapWindow */
1711           case 11: /* UnmapSubwindows */
1712           case 13: /* CirculateWindow */
1713           case 14: /* GetGeometry */
1714           case 15: /* QueryTree */
1715           case 17: /* GetAtomName */
1716           case 21: /* ListProperties */
1717           case 23: /* GetSelectionOwner */
1718           case 27: /* UngrabPointer */
1719           case 32: /* UngrabKeyboard */
1720           case 35: /* AllowEvents */
1721           case 38: /* QueryPointer */
1722           case 46: /* CloseFont */
1723           case 47: /* QueryFont */
1724           case 54: /* FreePixmap */
1725           case 60: /* FreeGC */
1726           case 79: /* FreeColormap */
1727           case 81: /* InstallColormap */
1728           case 82: /* UninstallColormap */
1729           case 83: /* ListInstalledColormaps */
1730           case 95: /* FreeCursor */
1731           case 101: /* GetKeyboardMapping */
1732           case 113: /* KillClient */
1733             return length == 2;
1734
1735           case 7: /* ReparentWindow */
1736           case 22: /* SetSelectionOwner */
1737           case 30: /* ChangeActivePointerGrab */
1738           case 31: /* GrabKeyboard */
1739           case 33: /* GrabKey */
1740           case 39: /* GetMotionEvents */
1741           case 40: /* TranslateCoordinates */
1742           case 53: /* CreatePixmap */
1743           case 57: /* CopyGC */
1744           case 61: /* ClearArea */
1745           case 78: /* CreateColormap */
1746           case 84: /* AllocColor */
1747           case 87: /* AllocColorPlanes */
1748             return length == 4;
1749
1750           case 12: /* ConfigureWindow */
1751             return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
1752
1753           case 16: /* InternAtom */
1754           case 98: /* QueryExtension */
1755             return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
1756
1757           case 18: /* ChangeProperty */
1758             {
1759                   int multiplier, type;
1760                   if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
1761                   type = tvb_get_guint8(tvb, 16);
1762                   if (type != 8 && type != 16 && type != 32) return FALSE;
1763                   multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
1764                   if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
1765                   return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 20) * multiplier);
1766             }
1767
1768           case 19: /* DeleteProperty */
1769           case 29: /* UngrabButton */
1770           case 34: /* UngrabKey */
1771           case 42: /* SetInputFocus */
1772           case 80: /* CopyColormapAndFree */
1773           case 86: /* AllocColorCells */
1774           case 97: /* QueryBestSize */
1775           case 105: /* ChangePointerControl */
1776           case 107: /* SetScreenSaver */
1777             return length == 3;
1778
1779           case 20: /* GetProperty */
1780           case 24: /* ConvertSelection */
1781           case 26: /* GrabPointer */
1782           case 28: /* GrabButton */
1783           case 41: /* WarpPointer */
1784             return length == 6;
1785
1786           case 25: /* SendEvent */
1787             return length == 11;
1788
1789           case 36: /* GrabServer */
1790           case 37: /* UngrabServer */
1791           case 43: /* GetInputFocus */
1792           case 44: /* QueryKeymap */
1793           case 52: /* GetFontPath */
1794           case 99: /* ListExtensions */
1795           case 103: /* GetKeyboardControl */
1796           case 104: /* Bell */
1797           case 106: /* GetPointerControl */
1798           case 108: /* GetScreenSaver */
1799           case 110: /* ListHosts */
1800           case 111: /* SetAccessControl */
1801           case 112: /* SetCloseDownMode */
1802           case 115: /* ForceScreenSaver */
1803           case 117: /* GetPointerMapping */
1804           case 119: /* GetModifierMapping */
1805             return length == 1;
1806
1807           case 45: /* OpenFont */
1808           case 85: /* AllocNamedColor */
1809           case 92: /* LookupColor */
1810             return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
1811
1812           case 48: /* QueryTextExtents */
1813             return length >= 2;
1814
1815           case 49: /* ListFonts */
1816           case 50: /* ListFontsWithInfo */
1817           case 109: /* ChangeHosts */
1818             return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
1819
1820           case 51: /* SetFontPath */
1821             if (length < 2) return FALSE;
1822             if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
1823             return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
1824
1825           case 55: /* CreateGC */
1826             return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
1827
1828           case 58: /* SetDashes */
1829             return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 10));
1830
1831           case 59: /* SetClipRectangles */
1832           case 66: /* PolySegment */
1833           case 67: /* PolyRectangle */
1834           case 70: /* PolyFillRectangle */
1835             return length >= 3 && (length - 3) % 2 == 0;
1836
1837           case 62: /* CopyArea */
1838             return length == 7;
1839
1840           case 63: /* CopyPlane */
1841           case 93: /* CreateCursor */
1842           case 94: /* CreateGlyphCursor */
1843             return length == 8;
1844
1845           case 64: /* PolyPoint */
1846           case 65: /* PolyLine */
1847           case 88: /* FreeColors */
1848             return length >= 3;
1849
1850           case 68: /* PolyArc */
1851           case 71: /* PolyFillArc */
1852             return length >= 3 && (length - 3) % 3 == 0;
1853
1854           case 69: /* FillPoly */
1855           case 76: /* ImageText8 */
1856             return length >= 4;
1857
1858           case 72: /* PutImage */
1859             return length >= 6;
1860
1861           case 73: /* GetImage */
1862           case 96: /* RecolorCursor */
1863             return length == 5;
1864
1865           case 74: /* PolyText8 */
1866             if (length < 4) return FALSE;
1867             return TRUE; /* We don't perform many controls on this one */
1868
1869           case 75: /* PolyText16 */
1870             if (length < 4) return FALSE;
1871             return TRUE; /* We don't perform many controls on this one */
1872
1873           case 77: /* ImageText16 */
1874             return length >= 4;
1875
1876           case 89: /* StoreColors */
1877             return length > 2 && (length - 2) % 3 == 0;
1878
1879           case 90: /* StoreNamedColor */
1880             return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
1881
1882           case 91: /* QueryColors */
1883             return length >= 2;
1884
1885           case 100: /* ChangeKeyboardMapping */
1886             return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
1887
1888           case 102: /* ChangeKeyboardControl */
1889             return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
1890
1891           case 114: /* RotateProperties */
1892             return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
1893
1894           case 116: /* SetPointerMapping */
1895             return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
1896
1897           case 118: /* SetModifierMapping */
1898             return length == 1 + tvb_get_guint8(tvb, 1) * 2;
1899             
1900           case 127: /* NoOperation */
1901             return length >= 1;
1902
1903           default:
1904             return TRUE;
1905       }
1906 }
1907
1908 /* -1 means doesn't match, +1 means match, 0 means don't know */
1909
1910 static int x_endian_match(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
1911 {
1912       int offset, nextoffset;
1913       int atLeastOne = 0;
1914
1915       for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
1916             int length;
1917             length = v16(tvb, offset + 2);
1918             if (!length) return -1;
1919             nextoffset = offset + length * 4;
1920             if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
1921             atLeastOne = 1;
1922       }
1923       return atLeastOne;
1924 }
1925
1926 static gboolean
1927 guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo,
1928                     x11_conv_data_t *state_info)
1929 {
1930       /* With X the client gives the byte ordering for the protocol,
1931          and the port on the server tells us we're speaking X. */
1932
1933       int le, be, decision, decisionToCache;
1934
1935       if (state_info->byte_order == BYTE_ORDER_BE)
1936             return FALSE;       /* known to be big-endian */
1937       else if (state_info->byte_order == BYTE_ORDER_LE)
1938             return TRUE;        /* known to be little-endian */
1939
1940       if (pinfo->srcport == pinfo->match_port) {
1941             /*
1942              * This is a reply or event; we don't try to guess the
1943              * byte order on it for now.
1944              */
1945             return TRUE;
1946       }
1947
1948       le = x_endian_match(tvb, tvb_get_letohs);
1949       be = x_endian_match(tvb, tvb_get_ntohs);
1950
1951       /* remember that "decision" really means "little_endian". */
1952       if (le == be) {
1953             /* We have no reason to believe it's little- rather than
1954                big-endian, so we guess the shortest length is the
1955                right one.
1956             */
1957             if (!tvb_bytes_exist(tvb, 0, 4))
1958                   /* Not even a way to get the length. We're biased
1959                      toward little endianness here (essentially the
1960                      x86 world right now). Decoding won't go very far
1961                      anyway.
1962                   */
1963                   decision = TRUE;
1964             else
1965                   decision = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2);
1966       } else
1967           decision = le >= be;
1968
1969       decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0);
1970       if (decisionToCache) {
1971             /*
1972              * Remember the decision.
1973              */
1974             state_info->byte_order = decision ? BYTE_ORDER_LE : BYTE_ORDER_BE;
1975       }
1976             
1977       /*
1978       fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n", 
1979               pinfo->fd -> num, le, be, decision, decisionToCache);
1980       */
1981       return decision;
1982 }
1983
1984 /************************************************************************
1985  ***                                                                  ***
1986  ***              D E C O D I N G   O N E   P A C K E T               ***
1987  ***                                                                  ***
1988  ************************************************************************/
1989
1990 /*
1991  * Decode an initial connection request.
1992  */
1993 static void dissect_x11_initial_conn(tvbuff_t *tvb, packet_info *pinfo,
1994     proto_tree *tree, x11_conv_data_t *state_info, gboolean little_endian)
1995 {
1996       int offset = 0;
1997       int *offsetp = &offset;
1998       proto_item *ti;
1999       proto_tree *t;
2000       guint16 auth_proto_name_length, auth_proto_data_length;
2001       gint left;
2002
2003       ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2004       t = proto_item_add_subtree(ti, ett_x11);
2005
2006       CARD8(byte_order);
2007       UNUSED(1);
2008       CARD16(protocol_major_version);
2009       CARD16(protocol_minor_version);
2010       auth_proto_name_length = CARD16(authorization_protocol_name_length);
2011       auth_proto_data_length = CARD16(authorization_protocol_data_length);
2012       UNUSED(2);
2013       if (auth_proto_name_length != 0) {
2014             STRING8(authorization_protocol_name, auth_proto_name_length);
2015             offset = ROUND_LENGTH(offset);
2016       }
2017       if (auth_proto_data_length != 0) {
2018             STRING8(authorization_protocol_data, auth_proto_data_length);
2019             offset = ROUND_LENGTH(offset);
2020       }
2021       left = tvb_length_remaining(tvb, offset);
2022       if (left)
2023             proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
2024
2025       /*
2026        * This is the initial connection request...
2027        */
2028       state_info->iconn_frame = pinfo->fd->num;
2029
2030       /*
2031        * ...and we're expecting a reply to it.
2032        */
2033       state_info->opcode = INITIAL_CONN;
2034 }
2035
2036 static void dissect_x11_request(tvbuff_t *tvb, packet_info *pinfo,
2037     proto_tree *tree, const char *sep, x11_conv_data_t *state_info,
2038     gboolean little_endian)
2039 {
2040       int offset = 0;
2041       int *offsetp = &offset;
2042       int next_offset;
2043       proto_item *ti;
2044       proto_tree *t;
2045       int length, opcode;
2046       guint8 v8, v8_2;
2047       guint16 v16;
2048       guint32 v32;
2049       gint left;
2050
2051       length = VALUE16(tvb, 2) * 4;
2052
2053       if (length < 4) {
2054             /* Bogus message length? */
2055             return;
2056       }
2057
2058       next_offset = offset + length;
2059
2060       ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2061       t = proto_item_add_subtree(ti, ett_x11);
2062
2063       OPCODE();
2064
2065       if (check_col(pinfo->cinfo, COL_INFO)) 
2066           col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", sep,
2067                           val_to_str(opcode, opcode_vals, "Unknown (%u)"));
2068
2069       /*
2070        * Does this request expect a reply?
2071        */
2072       switch(opcode) {
2073
2074       case 3: /* GetWindowAttributes */
2075       case 14: /* GetGeometry */
2076       case 15: /* QueryTree */
2077       case 16: /* InternAtom */
2078       case 17: /* GetAtomName */
2079       case 20: /* GetProperty */
2080       case 21: /* ListProperties */
2081       case 23: /* GetSelectionOwner */
2082       case 26: /* GrabPointer */
2083       case 31: /* GrabKeyboard */
2084       case 38: /* QueryPointer */
2085       case 39: /* GetMotionEvents */
2086       case 40: /* TranslateCoordinates */
2087       case 44: /* QueryKeymap */
2088       case 47: /* QueryFont */
2089       case 48: /* QueryTextExtents */
2090       case 49: /* ListFonts */
2091       case 73: /* GetImage */
2092       case 83: /* ListInstalledColormaps */
2093       case 84: /* AllocColor */
2094       case 91: /* QueryColors */
2095       case 92: /* LookupColor */
2096       case 97: /* QueryBestSize */
2097       case 98: /* QueryExtension */
2098       case 99: /* ListExtensions */
2099       case 101: /* GetKeyboardMapping */
2100       case 103: /* GetKeyboardControl */
2101       case 106: /* GetPointerControl */
2102       case 108: /* GetScreenSaver */
2103       case 110: /* ListHosts */
2104       case 116: /* SetPointerMapping */
2105       case 117: /* GetPointerMapping */
2106       case 118: /* SetModifierMapping */
2107       case 119: /* GetModifierMapping */
2108             /*
2109              * Those requests expect a reply.
2110              */
2111             state_info->opcode = opcode;
2112             break;
2113
2114       default:
2115             /*
2116              * No reply is expected from any other request.
2117              */
2118             state_info->opcode = NOTHING_EXPECTED;
2119             break;
2120       }
2121
2122       if (!tree) return;
2123
2124       switch(opcode) {
2125
2126       case 1: /* CreateWindow */
2127             CARD8(depth);
2128             REQUEST_LENGTH();
2129             WINDOW(wid);
2130             WINDOW(parent);
2131             INT16(x);
2132             INT16(y);
2133             CARD16(width);
2134             CARD16(height);
2135             CARD16(border_width);
2136             ENUM16(window_class);
2137             VISUALID(visual);
2138             windowAttributes(tvb, offsetp, t, little_endian);
2139             break;
2140
2141       case 2: /* ChangeWindowAttributes */
2142             UNUSED(1);
2143             REQUEST_LENGTH();
2144             WINDOW(window);
2145             windowAttributes(tvb, offsetp, t, little_endian);
2146             break;
2147
2148       case 3: /* GetWindowAttributes */
2149       case 4: /* DestroyWindow */
2150       case 5: /* DestroySubwindows */
2151             UNUSED(1);
2152             REQUEST_LENGTH();
2153             WINDOW(window);
2154             break;
2155
2156       case 6: /* ChangeSaveSet */
2157             ENUM8(save_set_mode);
2158             REQUEST_LENGTH();
2159             WINDOW(window);
2160             break;
2161
2162       case 7: /* ReparentWindow */
2163             UNUSED(1);
2164             REQUEST_LENGTH();
2165             WINDOW(window);
2166             WINDOW(parent);
2167             INT16(x);
2168             INT16(y);
2169             break;
2170
2171       case 8: /* MapWindow */
2172       case 9: /* MapSubWindow */
2173       case 10: /* UnmapWindow */
2174       case 11: /* UnmapSubwindows */
2175             UNUSED(1);
2176             REQUEST_LENGTH();
2177             WINDOW(window);
2178             break;
2179
2180       case 12: /* ConfigureWindow */
2181             UNUSED(1);
2182             REQUEST_LENGTH();
2183             WINDOW(window);
2184             BITMASK16(configure_window);
2185             UNUSED(2); 
2186             BITFIELD(INT16,  configure_window_mask, x);
2187             BITFIELD(INT16,  configure_window_mask, y);
2188             BITFIELD(CARD16, configure_window_mask, width);
2189             BITFIELD(CARD16, configure_window_mask, height);
2190             BITFIELD(CARD16, configure_window_mask, border_width);
2191             BITFIELD(WINDOW, configure_window_mask, sibling);
2192             BITFIELD(ENUM8,  configure_window_mask, stack_mode);
2193             ENDBITMASK;
2194             PAD();
2195             break;
2196
2197       case 13: /* CirculateWindow */
2198             ENUM8(direction);
2199             REQUEST_LENGTH();
2200             WINDOW(window);
2201             break;
2202
2203       case 14: /* GetGeometry */
2204       case 15: /* QueryTree */
2205             UNUSED(1);
2206             REQUEST_LENGTH();
2207             DRAWABLE(drawable);
2208             break;
2209
2210       case 16: /* InternAtom */
2211             BOOL(only_if_exists);
2212             REQUEST_LENGTH();
2213             v16 = FIELD16(name_length);
2214             UNUSED(2);
2215             STRING8(name, v16);
2216             PAD();
2217             break;
2218
2219       case 17: /* GetAtomName */
2220             UNUSED(1);
2221             REQUEST_LENGTH();
2222             ATOM(atom);
2223             break;
2224
2225       case 18: /* ChangeProperty */
2226             ENUM8(mode);
2227             REQUEST_LENGTH();
2228             WINDOW(window);
2229             ATOM(property);
2230             ATOM(type);
2231             CARD8(format);
2232             UNUSED(3);
2233             v32 = CARD32(data_length);
2234             LISTofBYTE(data, v32);
2235             PAD();
2236             break;
2237
2238       case 19: /* DeleteProperty */
2239             UNUSED(1);
2240             REQUEST_LENGTH();
2241             WINDOW(window);
2242             ATOM(property);
2243             break;
2244
2245       case 20: /* GetProperty */
2246             BOOL(delete);
2247             REQUEST_LENGTH();
2248             WINDOW(window);
2249             ATOM(property);
2250             ATOM(get_property_type);
2251             CARD32(long_offset);
2252             CARD32(long_length);
2253             break;
2254
2255       case 21: /* ListProperties */
2256             UNUSED(1);
2257             REQUEST_LENGTH();
2258             WINDOW(window);
2259             break;
2260
2261       case 22: /* SetSelectionOwner */
2262             UNUSED(1);
2263             REQUEST_LENGTH();
2264             WINDOW(owner);
2265             ATOM(selection);
2266             TIMESTAMP(time);
2267             break;
2268
2269       case 23: /* GetSelectionOwner */
2270             UNUSED(1);
2271             REQUEST_LENGTH();
2272             ATOM(selection);
2273             break;
2274
2275       case 24: /* ConvertSelection */
2276             UNUSED(1);
2277             REQUEST_LENGTH();
2278             WINDOW(requestor);
2279             ATOM(selection);
2280             ATOM(target);
2281             ATOM(property);
2282             TIMESTAMP(time);
2283             break;
2284
2285       case 26: /* GrabPointer */
2286             BOOL(owner_events);
2287             REQUEST_LENGTH();
2288             WINDOW(grab_window);
2289             SETofPOINTEREVENT(pointer_event_mask);
2290             ENUM8(pointer_mode);
2291             ENUM8(keyboard_mode);
2292             WINDOW(confine_to);
2293             CURSOR(cursor);
2294             TIMESTAMP(time);
2295             break;
2296
2297       case 27: /* UngrabPointer */
2298             UNUSED(1);
2299             REQUEST_LENGTH();
2300             TIMESTAMP(time);
2301             break;
2302
2303       case 28: /* GrabButton */
2304             BOOL(owner_events);
2305             REQUEST_LENGTH();
2306             WINDOW(grab_window);
2307             SETofPOINTEREVENT(event_mask);
2308             ENUM8(pointer_mode);
2309             ENUM8(keyboard_mode);
2310             WINDOW(confine_to);
2311             CURSOR(cursor);
2312             BUTTON(button);
2313             UNUSED(1);
2314             SETofKEYMASK(modifiers);
2315             break;
2316
2317       case 29: /* UngrabButton */
2318             BUTTON(button);
2319             REQUEST_LENGTH();
2320             WINDOW(grab_window);
2321             SETofKEYMASK(modifiers);
2322             UNUSED(2);
2323             break;
2324
2325       case 30: /* ChangeActivePointerGrab */
2326             UNUSED(1);
2327             REQUEST_LENGTH();
2328             CURSOR(cursor);
2329             TIMESTAMP(time);
2330             SETofPOINTEREVENT(event_mask);
2331             UNUSED(2);
2332             break;
2333
2334       case 31: /* GrabKeyboard */
2335             BOOL(owner_events);
2336             REQUEST_LENGTH();
2337             WINDOW(grab_window);
2338             TIMESTAMP(time);
2339             ENUM8(pointer_mode);
2340             ENUM8(keyboard_mode);
2341             UNUSED(2);
2342             break;
2343
2344       case 32: /* UngrabKeyboard */
2345             UNUSED(1);
2346             REQUEST_LENGTH();
2347             TIMESTAMP(time);
2348             break;
2349
2350       case 33: /* GrabKey */
2351             BOOL(owner_events);
2352             REQUEST_LENGTH();
2353             WINDOW(grab_window);
2354             SETofKEYMASK(modifiers);
2355             KEYCODE(key);
2356             ENUM8(pointer_mode);
2357             ENUM8(keyboard_mode);
2358             UNUSED(3);
2359             break;
2360
2361       case 34: /* UngrabKey */
2362             KEYCODE(key);
2363             REQUEST_LENGTH();
2364             WINDOW(grab_window);
2365             SETofKEYMASK(modifiers);
2366             UNUSED(2);
2367             break;
2368
2369       case 35: /* AllowEvents */
2370             ENUM8(allow_events_mode);
2371             REQUEST_LENGTH();
2372             TIMESTAMP(time);
2373             break;
2374
2375       case 36: /* GrabServer */
2376             UNUSED(1);
2377             REQUEST_LENGTH();
2378             break;
2379
2380       case 37: /* UngrabServer */
2381             UNUSED(1);
2382             REQUEST_LENGTH();
2383             break;
2384
2385       case 38: /* QueryPointer */
2386             UNUSED(1);
2387             REQUEST_LENGTH();
2388             WINDOW(window);
2389             break;
2390
2391       case 39: /* GetMotionEvents */
2392             UNUSED(1);
2393             REQUEST_LENGTH();
2394             WINDOW(window);
2395             TIMESTAMP(start);
2396             TIMESTAMP(stop);
2397             break;
2398
2399       case 40: /* TranslateCoordinates */
2400             UNUSED(1);
2401             REQUEST_LENGTH();
2402             WINDOW(src_window);
2403             WINDOW(dst_window);
2404             INT16(src_x);
2405             INT16(src_y);
2406             break;
2407
2408       case 41: /* WarpPointer */
2409             UNUSED(1);
2410             REQUEST_LENGTH();
2411             WINDOW(warp_pointer_src_window);
2412             WINDOW(warp_pointer_dst_window);
2413             INT16(src_x);
2414             INT16(src_y);
2415             CARD16(src_width);
2416             CARD16(src_height);
2417             INT16(dst_x);
2418             INT16(dst_y);
2419             break;
2420
2421       case 42: /* SetInputFocus */
2422             ENUM8(revert_to);
2423             REQUEST_LENGTH();
2424             WINDOW(focus);
2425             TIMESTAMP(time);
2426             break;
2427
2428       case 43: /* GetInputFocus */
2429             UNUSED(1);
2430             REQUEST_LENGTH();
2431             break;
2432
2433       case 44: /* QueryKeymap */
2434             UNUSED(1);
2435             REQUEST_LENGTH();
2436             break;
2437
2438       case 45: /* OpenFont */
2439             UNUSED(1);
2440             REQUEST_LENGTH();
2441             FONT(fid);
2442             v16 = FIELD16(name_length);
2443             UNUSED(2);
2444             STRING8(name, v16);
2445             PAD();
2446             break;
2447
2448       case 46: /* CloseFont */
2449             UNUSED(1);
2450             REQUEST_LENGTH();
2451             FONT(font);
2452             break;
2453
2454       case 47: /* QueryFont */
2455             UNUSED(1);
2456             REQUEST_LENGTH();
2457             FONTABLE(font);
2458             break;
2459
2460       case 48: /* QueryTextExtents */
2461             v8 = BOOL(odd_length);
2462             REQUEST_LENGTH();
2463             FONTABLE(font);
2464             STRING16(string16, (next_offset - offset - (v8 ? 2 : 0)) / 2);
2465             PAD();
2466             break;
2467
2468       case 49: /* ListFonts */
2469             UNUSED(1);
2470             REQUEST_LENGTH();
2471             CARD16(max_names);
2472             v16 = FIELD16(pattern_length);
2473             STRING8(pattern, v16);
2474             PAD();
2475             break;
2476
2477       case 50: /* ListFontsWithInfo */
2478             UNUSED(1);
2479             REQUEST_LENGTH();
2480             CARD16(max_names);
2481             v16 = FIELD16(pattern_length);
2482             STRING8(pattern, v16);
2483             PAD();
2484             break;
2485
2486       case 51: /* SetFontPath */
2487             UNUSED(1);
2488             REQUEST_LENGTH();
2489             v16 = CARD16(str_number_in_path);
2490             UNUSED(2);
2491             LISTofSTRING8(path, v16);
2492             PAD();
2493             break;
2494
2495       case 52: /* GetFontPath */
2496             UNUSED(1);
2497             REQUEST_LENGTH();
2498             break;
2499
2500       case 53: /* CreatePixmap */
2501             CARD8(depth);
2502             REQUEST_LENGTH();
2503             PIXMAP(pid);
2504             DRAWABLE(drawable);
2505             CARD16(width);
2506             CARD16(height);
2507             break;
2508
2509       case 54: /* FreePixmap */
2510             UNUSED(1);
2511             REQUEST_LENGTH();
2512             PIXMAP(pixmap);
2513             break;
2514
2515       case 55: /* CreateGC */
2516             UNUSED(1);
2517             REQUEST_LENGTH();
2518             GCONTEXT(cid);
2519             DRAWABLE(drawable);
2520             gcAttributes(tvb, offsetp, t, little_endian);
2521             break;
2522
2523       case 56: /* ChangeGC */
2524             UNUSED(1);
2525             REQUEST_LENGTH();
2526             GCONTEXT(gc);
2527             gcAttributes(tvb, offsetp, t, little_endian);
2528             break;
2529
2530       case 57: /* CopyGC */
2531             UNUSED(1);
2532             REQUEST_LENGTH();
2533             GCONTEXT(src_gc);
2534             GCONTEXT(dst_gc);
2535             gcMask(tvb, offsetp, t, little_endian);
2536             break;
2537
2538       case 58: /* SetDashes */
2539             UNUSED(1);
2540             REQUEST_LENGTH();
2541             GCONTEXT(gc);
2542             CARD16(dash_offset);
2543             v16 = FIELD16(dashes_length);
2544             LISTofCARD8(dashes, v16);
2545             PAD();
2546             break;
2547
2548       case 59: /* SetClipRectangles */
2549             ENUM8(ordering);
2550             REQUEST_LENGTH();
2551             GCONTEXT(gc);
2552             INT16(clip_x_origin);
2553             INT16(clip_y_origin);
2554             LISTofRECTANGLE(rectangles);
2555             break;
2556
2557       case 60: /* FreeGC */
2558             UNUSED(1);
2559             REQUEST_LENGTH();
2560             GCONTEXT(gc);
2561             break;
2562
2563       case 61: /* ClearArea */
2564             BOOL(exposures);
2565             REQUEST_LENGTH();
2566             WINDOW(window);
2567             INT16(x);
2568             INT16(y);
2569             CARD16(width);
2570             CARD16(height);
2571             break;
2572
2573       case 62: /* CopyArea */
2574             UNUSED(1);
2575             REQUEST_LENGTH();
2576             DRAWABLE(src_drawable);
2577             DRAWABLE(dst_drawable);
2578             GCONTEXT(gc);
2579             INT16(src_x);
2580             INT16(src_y);
2581             INT16(dst_x);
2582             INT16(dst_y);
2583             CARD16(width);
2584             CARD16(height);
2585             break;
2586
2587       case 63: /* CopyPlane */
2588             UNUSED(1);
2589             REQUEST_LENGTH();
2590             DRAWABLE(src_drawable);
2591             DRAWABLE(dst_drawable);
2592             GCONTEXT(gc);
2593             INT16(src_x);
2594             INT16(src_y);
2595             INT16(dst_x);
2596             INT16(dst_y);
2597             CARD16(width);
2598             CARD16(height);
2599             CARD32(bit_plane);
2600             break;
2601
2602       case 64: /* PolyPoint */
2603             ENUM8(coordinate_mode);
2604             v16 = REQUEST_LENGTH();
2605             DRAWABLE(drawable);
2606             GCONTEXT(gc);
2607             LISTofPOINT(points, v16 - 12);
2608             break;
2609
2610       case 65: /* PolyLine */
2611             ENUM8(coordinate_mode);
2612             v16 = REQUEST_LENGTH();
2613             DRAWABLE(drawable);
2614             GCONTEXT(gc);
2615             LISTofPOINT(points, v16 - 12);
2616             break;
2617
2618       case 66: /* PolySegment */
2619             UNUSED(1);
2620             REQUEST_LENGTH();
2621             DRAWABLE(drawable);
2622             GCONTEXT(gc);
2623             LISTofSEGMENT(segments);
2624             break;
2625
2626       case 67: /* PolyRectangle */
2627             UNUSED(1);
2628             REQUEST_LENGTH();
2629             DRAWABLE(drawable);
2630             GCONTEXT(gc);
2631             LISTofRECTANGLE(rectangles);
2632             break;
2633
2634       case 68: /* PolyArc */
2635             UNUSED(1);
2636             REQUEST_LENGTH();
2637             DRAWABLE(drawable);
2638             GCONTEXT(gc);
2639             LISTofARC(arcs);
2640             break;
2641
2642       case 69: /* FillPoly */
2643             UNUSED(1);
2644             v16 = REQUEST_LENGTH();
2645             DRAWABLE(drawable);
2646             GCONTEXT(gc);
2647             ENUM8(shape);
2648             ENUM8(coordinate_mode);
2649             UNUSED(2);
2650             LISTofPOINT(points, v16 - 16);
2651             break;
2652
2653       case 70: /* PolyFillRectangle */
2654             UNUSED(1);
2655             REQUEST_LENGTH();
2656             DRAWABLE(drawable);
2657             GCONTEXT(gc);
2658             LISTofRECTANGLE(rectangles);
2659             break;
2660
2661       case 71: /* PolyFillArc */
2662             UNUSED(1);
2663             REQUEST_LENGTH();
2664             DRAWABLE(drawable);
2665             GCONTEXT(gc);
2666             LISTofARC(arcs);
2667             break;
2668
2669       case 72: /* PutImage */
2670             ENUM8(image_format);
2671             v16 = REQUEST_LENGTH();
2672             DRAWABLE(drawable);
2673             GCONTEXT(gc);
2674             CARD16(width);
2675             CARD16(height);
2676             INT16(dst_x);
2677             INT16(dst_y);
2678             CARD8(left_pad);
2679             CARD8(depth);
2680             UNUSED(2);
2681             LISTofBYTE(data, v16 - 24);
2682             PAD();
2683             break;
2684
2685       case 73: /* GetImage */
2686             ENUM8(image_pixmap_format);
2687             REQUEST_LENGTH();
2688             DRAWABLE(drawable);
2689             INT16(x);
2690             INT16(y);
2691             CARD16(width);
2692             CARD16(height);
2693             CARD32(plane_mask);
2694             break;
2695
2696       case 74: /* PolyText8 */
2697             UNUSED(1);
2698             v16 = REQUEST_LENGTH();
2699             DRAWABLE(drawable);
2700             GCONTEXT(gc);
2701             INT16(x);
2702             INT16(y);
2703             LISTofTEXTITEM8(items);
2704             PAD();
2705             break;
2706
2707       case 75: /* PolyText16 */
2708             UNUSED(1);
2709             v16 = REQUEST_LENGTH();
2710             DRAWABLE(drawable);
2711             GCONTEXT(gc);
2712             INT16(x);
2713             INT16(y);
2714             LISTofTEXTITEM16(items);
2715             PAD();
2716             break;
2717
2718       case 76: /* ImageText8 */
2719             v8 = FIELD8(string_length);
2720             REQUEST_LENGTH();
2721             DRAWABLE(drawable);
2722             GCONTEXT(gc);
2723             INT16(x);
2724             INT16(y);
2725             STRING8(string, v8);
2726             PAD();
2727             break;
2728
2729       case 77: /* ImageText16 */
2730             v8 = FIELD8(string_length);
2731             REQUEST_LENGTH();
2732             DRAWABLE(drawable);
2733             GCONTEXT(gc);
2734             INT16(x);
2735             INT16(y);
2736             STRING16(string16, v8);
2737             PAD();
2738             break;
2739
2740       case 78: /* CreateColormap */
2741             ENUM8(alloc);
2742             REQUEST_LENGTH();
2743             COLORMAP(mid);
2744             WINDOW(window);
2745             VISUALID(visual);
2746             break;
2747
2748       case 79: /* FreeColormap */
2749             UNUSED(1);
2750             REQUEST_LENGTH();
2751             COLORMAP(cmap);
2752             break;
2753
2754       case 80: /* CopyColormapAndFree */
2755             UNUSED(1);
2756             REQUEST_LENGTH();
2757             COLORMAP(mid);
2758             COLORMAP(src_cmap);
2759             break;
2760
2761       case 81: /* InstallColormap */
2762             UNUSED(1);
2763             REQUEST_LENGTH();
2764             COLORMAP(cmap);
2765             break;
2766
2767       case 82: /* UninstallColormap */
2768             UNUSED(1);
2769             REQUEST_LENGTH();
2770             COLORMAP(cmap);
2771             break;
2772
2773       case 83: /* ListInstalledColormaps */
2774             UNUSED(1);
2775             REQUEST_LENGTH();
2776             WINDOW(window);
2777             break;
2778
2779       case 84: /* AllocColor */
2780             UNUSED(1);
2781             REQUEST_LENGTH();
2782             COLORMAP(cmap);
2783             CARD16(red);
2784             CARD16(green);
2785             CARD16(blue);
2786             UNUSED(2);
2787             break;
2788
2789       case 85: /* AllocNamedColor */
2790             UNUSED(1);
2791             REQUEST_LENGTH();
2792             COLORMAP(cmap);
2793             v16 = FIELD16(name_length);
2794             UNUSED(2);
2795             STRING8(name, v16);
2796             PAD();
2797             break;
2798
2799       case 86: /* AllocColorCells */
2800             BOOL(contiguous);
2801             REQUEST_LENGTH();
2802             COLORMAP(cmap);
2803             CARD16(colors);
2804             CARD16(planes);
2805             break;
2806
2807       case 87: /* AllocColorPlanes */
2808             BOOL(contiguous);
2809             REQUEST_LENGTH();
2810             COLORMAP(cmap);
2811             CARD16(colors);
2812             CARD16(reds);
2813             CARD16(greens);
2814             CARD16(blues);
2815             break;
2816
2817       case 88: /* FreeColors */
2818             UNUSED(1);
2819             v16 = REQUEST_LENGTH();
2820             COLORMAP(cmap);
2821             CARD32(plane_mask);
2822             LISTofCARD32(pixels, v16 - 12);
2823             break;
2824
2825       case 89: /* StoreColors */
2826             UNUSED(1);
2827             v16 = REQUEST_LENGTH();
2828             COLORMAP(cmap);
2829             LISTofCOLORITEM(color_items, v16 - 8);
2830             break;
2831
2832       case 90: /* StoreNamedColor */
2833             COLOR_FLAGS(color);
2834             REQUEST_LENGTH();
2835             COLORMAP(cmap);
2836             CARD32(pixel);      
2837             v16 = FIELD16(name_length);
2838             UNUSED(2);
2839             STRING8(name, v16);
2840             PAD();
2841             break;
2842
2843       case 91: /* QueryColors */
2844             UNUSED(1);
2845             v16 = REQUEST_LENGTH();
2846             COLORMAP(cmap);
2847             LISTofCARD32(pixels, v16 - 8);
2848             break;
2849
2850       case 92: /* LookupColor */
2851             UNUSED(1);
2852             REQUEST_LENGTH();
2853             COLORMAP(cmap);
2854             v16 = FIELD16(name_length);
2855             UNUSED(2);
2856             STRING8(name, v16);
2857             PAD();
2858             break;
2859
2860       case 93: /* CreateCursor */
2861             UNUSED(1);
2862             REQUEST_LENGTH();
2863             CURSOR(cid);
2864             PIXMAP(source_pixmap);
2865             PIXMAP(mask);
2866             CARD16(fore_red);
2867             CARD16(fore_green);
2868             CARD16(fore_blue);
2869             CARD16(back_red);
2870             CARD16(back_green);
2871             CARD16(back_blue);
2872             CARD16(x);
2873             CARD16(y);
2874             break;
2875
2876       case 94: /* CreateGlyphCursor */
2877             UNUSED(1);
2878             REQUEST_LENGTH();
2879             CURSOR(cid);
2880             FONT(source_font);
2881             FONT(mask_font);
2882             CARD16(source_char);
2883             CARD16(mask_char);
2884             CARD16(fore_red);
2885             CARD16(fore_green);
2886             CARD16(fore_blue);
2887             CARD16(back_red);
2888             CARD16(back_green);
2889             CARD16(back_blue);
2890             break;
2891
2892       case 95: /* FreeCursor */
2893             UNUSED(1);
2894             REQUEST_LENGTH();
2895             CURSOR(cursor);
2896             break;
2897
2898       case 96: /* RecolorCursor */
2899             UNUSED(1);
2900             REQUEST_LENGTH();
2901             CURSOR(cursor);
2902             CARD16(fore_red);
2903             CARD16(fore_green);
2904             CARD16(fore_blue);
2905             CARD16(back_red);
2906             CARD16(back_green);
2907             CARD16(back_blue);
2908             break;
2909
2910       case 97: /* QueryBestSize */
2911             ENUM8(class);
2912             REQUEST_LENGTH();
2913             DRAWABLE(drawable);
2914             CARD16(width);
2915             CARD16(height);
2916             break;
2917
2918       case 98: /* QueryExtension */
2919             UNUSED(1);
2920             REQUEST_LENGTH();
2921             v16 = FIELD16(name_length);
2922             UNUSED(2);
2923             STRING8(name, v16);
2924             PAD();
2925             break;
2926
2927       case 99: /* ListExtensions */
2928             UNUSED(1);
2929             REQUEST_LENGTH();
2930             break;
2931
2932       case 100: /* ChangeKeyboardMapping */
2933             v8 = FIELD8(keycode_count);
2934             REQUEST_LENGTH();
2935             KEYCODE(first_keycode);
2936             v8_2 = FIELD8(keysyms_per_keycode);
2937             UNUSED(2);
2938             LISTofKEYSYM(keysyms, v8, v8_2);
2939             break;
2940
2941       case 101: /* GetKeyboardMapping */
2942             UNUSED(1);
2943             REQUEST_LENGTH();
2944             KEYCODE(first_keycode);
2945             FIELD8(count);
2946             UNUSED(2);
2947             break;
2948
2949       case 102: /* ChangeKeyboardControl */
2950             UNUSED(1);
2951             REQUEST_LENGTH();
2952             BITMASK32(keyboard_value);
2953             BITFIELD(INT8, keyboard_value_mask, key_click_percent);
2954             BITFIELD(INT8, keyboard_value_mask, bell_percent);
2955             BITFIELD(INT16, keyboard_value_mask, bell_pitch);
2956             BITFIELD(INT16, keyboard_value_mask, bell_duration);
2957             BITFIELD(INT16, keyboard_value_mask, led);
2958             BITFIELD(ENUM8, keyboard_value_mask, led_mode);
2959             BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key);
2960             BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode);
2961             ENDBITMASK;
2962             break;
2963
2964       case 103: /* GetKeyboardControl */
2965             UNUSED(1);
2966             REQUEST_LENGTH();
2967             break;
2968
2969       case 104: /* Bell */
2970             INT8(percent);
2971             REQUEST_LENGTH();
2972             break;
2973
2974       case 105: /* ChangePointerControl */
2975             UNUSED(1);
2976             REQUEST_LENGTH();
2977             INT16(acceleration_numerator);
2978             INT16(acceleration_denominator);
2979             INT16(threshold);
2980             BOOL(do_acceleration);
2981             BOOL(do_threshold);
2982             break;
2983
2984       case 106: /* GetPointerControl */
2985             UNUSED(1);
2986             REQUEST_LENGTH();
2987             break;
2988
2989       case 107: /* SetScreenSaver */
2990             UNUSED(1);
2991             REQUEST_LENGTH();
2992             INT16(timeout);
2993             INT16(interval);
2994             ENUM8(prefer_blanking);
2995             ENUM8(allow_exposures);
2996             UNUSED(2);
2997             break;
2998
2999       case 108: /* GetScreenSaver */
3000             UNUSED(1);
3001             REQUEST_LENGTH();
3002             break;
3003
3004       case 109: /* ChangeHosts */
3005             ENUM8(change_host_mode);
3006             REQUEST_LENGTH();
3007             v8 = ENUM8(family);
3008             UNUSED(1);
3009             v16 = CARD16(address_length);
3010             if (v8 == FAMILY_INTERNET && v16 == 4) {
3011                   /*
3012                    * IPv4 addresses.
3013                    * XXX - what about IPv6?  Is that a family of
3014                    * FAMILY_INTERNET (0) with a length of 16?
3015                    */
3016                   LISTofCARD8(ip_address, v16);
3017             } else
3018                   LISTofCARD8(address, v16);
3019             break;
3020
3021       case 110: /* ListHosts */
3022             UNUSED(1);
3023             REQUEST_LENGTH();
3024             break;
3025
3026       case 111: /* SetAccessControl */
3027             ENUM8(access_mode);
3028             REQUEST_LENGTH();
3029             break;
3030
3031       case 112: /* SetCloseDownMode */
3032             ENUM8(close_down_mode);
3033             REQUEST_LENGTH();
3034             break;
3035
3036       case 113: /* KillClient */
3037             UNUSED(1);
3038             REQUEST_LENGTH();
3039             CARD32(resource);
3040             break;
3041
3042       case 114: /* RotateProperties */
3043             UNUSED(1);
3044             v16 = REQUEST_LENGTH();
3045             WINDOW(window);
3046             CARD16(property_number);
3047             INT16(delta);
3048             LISTofATOM(properties, (v16 - 12));
3049             break;
3050
3051       case 115: /* ForceScreenSaver */
3052             ENUM8(screen_saver_mode);
3053             REQUEST_LENGTH();
3054             break;
3055
3056       case 116: /* SetPointerMapping */
3057             v8 = FIELD8(map_length);
3058             REQUEST_LENGTH();
3059             LISTofCARD8(map, v8);
3060             PAD();
3061             break;
3062
3063       case 117: /* GetPointerMapping */
3064             UNUSED(1);
3065             REQUEST_LENGTH();
3066             break;
3067
3068       case 118: /* SetModifierMapping */
3069             v8 = FIELD8(keycodes_per_modifier);
3070             REQUEST_LENGTH();
3071             LISTofKEYCODE(keycodes, v8);
3072             break;
3073
3074       case 119: /* GetModifierMapping */
3075             UNUSED(1);
3076             REQUEST_LENGTH();
3077             break;
3078             
3079       case 127: /* NoOperation */
3080             UNUSED(1);
3081             REQUEST_LENGTH();
3082             break;
3083       }
3084       left = tvb_length_remaining(tvb, offset);
3085       if (left)
3086             proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
3087 }
3088
3089 static void dissect_x11_requests(tvbuff_t *tvb, packet_info *pinfo,
3090     proto_tree *tree)
3091 {
3092       volatile int offset = 0;
3093       int length_remaining;
3094       volatile gboolean little_endian;
3095       guint8 opcode;
3096       volatile int plen;
3097       proto_item *ti;
3098       proto_tree *t;
3099       volatile gboolean is_initial_creq;
3100       guint16 auth_proto_len, auth_data_len;
3101       const char *volatile sep = NULL;
3102       conversation_t *conversation;
3103       x11_conv_data_t *volatile state_info;
3104       int length;
3105       tvbuff_t *next_tvb;
3106
3107       while (tvb_reported_length_remaining(tvb, offset) != 0) {
3108             length_remaining = tvb_length_remaining(tvb, offset);
3109
3110             /*
3111              * Can we do reassembly?
3112              */
3113             if (x11_desegment && pinfo->can_desegment) {
3114                   /*
3115                    * Yes - is the X11 request header split across
3116                    * segment boundaries?
3117                    */
3118                   if (length_remaining < 4) {
3119                         /*
3120                          * Yes.  Tell the TCP dissector where the data
3121                          * for this message starts in the data it handed
3122                          * us, and how many more bytes we need, and return.
3123                          */
3124                         pinfo->desegment_offset = offset;
3125                         pinfo->desegment_len = 4 - length_remaining;
3126                         return;
3127                   }
3128             }
3129
3130             /*
3131              * Get the state for this conversation; create the conversation
3132              * if we don't have one, and create the state if we don't have
3133              * any.
3134              */
3135             conversation = find_conversation(&pinfo->src, &pinfo->dst,
3136                 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
3137             if (conversation == NULL) {
3138                   /*
3139                    * No - create one.
3140                    */
3141                   conversation = conversation_new(&pinfo->src,
3142                         &pinfo->dst, pinfo->ptype, pinfo->srcport,
3143                         pinfo->destport, 0);
3144             }
3145
3146             /*
3147              * Is there state attached to this conversation?
3148              */
3149             state_info = conversation_get_proto_data(conversation, proto_x11);
3150             if (state_info == NULL) {
3151                   /*
3152                    * No - create a state structure and attach it.
3153                    */
3154                   state_info = g_mem_chunk_alloc(x11_state_chunk);
3155                   state_info->opcode = NOTHING_SEEN;    /* nothing seen yet */
3156                   state_info->iconn_frame = 0;  /* don't know it yet */
3157                   state_info->byte_order = BYTE_ORDER_UNKNOWN;  /* don't know it yet */
3158                   conversation_add_proto_data(conversation, proto_x11,
3159                         state_info);
3160             }
3161
3162             /*
3163              * Guess the byte order if we don't already know it.
3164              */
3165             little_endian = guess_byte_ordering(tvb, pinfo, state_info);
3166
3167             /*
3168              * Get the opcode and length of the putative X11 request.
3169              */
3170             opcode = VALUE8(tvb, 0);
3171             plen = VALUE16(tvb, offset + 2);
3172
3173             if (plen == 0) {
3174                   /*
3175                    * This can't be 0, as it includes the header length.
3176                    * A different choice of byte order wouldn't have
3177                    * helped.
3178                    * Give up.
3179                    */
3180                   ti = proto_tree_add_item(tree, proto_x11, tvb, offset, -1, FALSE);
3181                   t = proto_item_add_subtree(ti, ett_x11);
3182                   proto_tree_add_text(t, tvb, offset, -1, "Bogus request length (0)");
3183                   return;
3184             }
3185
3186             if (state_info->iconn_frame == pinfo->fd->num ||
3187                 (state_info->opcode == NOTHING_SEEN &&
3188                  (opcode == 'B' || opcode == 'l') &&
3189                  (plen == 11 || plen == 2816))) {
3190                   /*
3191                    * Either
3192                    *
3193                    *    we saw this on the first pass and this is
3194                    *    it again
3195                    *
3196                    * or
3197                    *    we haven't already seen any requests, the first
3198                    *    byte of the message is 'B' or 'l', and the 16-bit
3199                    *    integer 2 bytes into the data stream is either 11
3200                    *    or a byte-swapped 11.
3201                    *
3202                    * This means it's probably an initial connection
3203                    * request, not a message.
3204                    *
3205                    * 'B' is decimal 66, which is the opcode for a
3206                    * PolySegment request; unfortunately, 11 is a valid
3207                    * length for a PolySegment request request, so we
3208                    * might mis-identify that request.  (Are there any
3209                    * other checks we can do?)
3210                    *
3211                    * 'l' is decimal 108, which is the opcode for a
3212                    * GetScreenSaver request; the only valid length
3213                    * for that request is 1.
3214                    */
3215                   is_initial_creq = TRUE;
3216
3217                   /*
3218                    * We now know the byte order.  Override the guess.
3219                    */
3220                   if (state_info->byte_order == BYTE_ORDER_UNKNOWN) {
3221                         if (opcode == 'B') {
3222                               /*
3223                                * Big-endian.
3224                                */
3225                               state_info->byte_order = BYTE_ORDER_BE;
3226                               little_endian = FALSE;
3227                         } else {
3228                               /*
3229                                * Little-endian.
3230                                */
3231                               state_info->byte_order = BYTE_ORDER_LE;
3232                               little_endian = TRUE;
3233                         }
3234                   }
3235
3236                   /*
3237                    * Can we do reassembly?
3238                    */
3239                   if (x11_desegment && pinfo->can_desegment) {
3240                         /*
3241                          * Yes - is the fixed-length portion of the
3242                          * initial connection header split across
3243                          * segment boundaries?
3244                          */
3245                         if (length_remaining < 10) {
3246                               /*
3247                                * Yes.  Tell the TCP dissector where the
3248                                * data for this message starts in the data
3249                                * it handed us, and how many more bytes we
3250                                * need, and return.
3251                                */
3252                               pinfo->desegment_offset = offset;
3253                               pinfo->desegment_len = 10 - length_remaining;
3254                               return;
3255                         }
3256                   }
3257
3258                   /*
3259                    * Get the lengths of the authorization protocol and
3260                    * the authorization data.
3261                    */
3262                   auth_proto_len = VALUE16(tvb, offset + 6);
3263                   auth_data_len = VALUE16(tvb, offset + 8);
3264                   plen = 12 + ROUND_LENGTH(auth_proto_len) +
3265                         ROUND_LENGTH(auth_data_len);
3266             } else {
3267                   /*
3268                    * This is probably an ordinary request.
3269                    */
3270                   is_initial_creq = FALSE;
3271
3272                   /*
3273                    * The length of a request is in 4-byte words.
3274                    */
3275                   plen *= 4;
3276             }
3277
3278             /*
3279              * Can we do reassembly?
3280              */
3281             if (x11_desegment && pinfo->can_desegment) {
3282                   /*
3283                    * Yes - is the X11 request split across segment
3284                    * boundaries?
3285                    */
3286                   if (length_remaining < plen) {
3287                         /*
3288                          * Yes.  Tell the TCP dissector where the data
3289                          * for this message starts in the data it handed
3290                          * us, and how many more bytes we need, and return.
3291                          */
3292                         pinfo->desegment_offset = offset;
3293                         pinfo->desegment_len = plen - length_remaining;
3294                         return;
3295                   }
3296             }
3297
3298             /*
3299              * Construct a tvbuff containing the amount of the payload
3300              * we have available.  Make its reported length the
3301              * amount of data in the X11 request.
3302              *
3303              * XXX - if reassembly isn't enabled. the subdissector
3304              * will throw a BoundsError exception, rather than a
3305              * ReportedBoundsError exception.  We really want a tvbuff
3306              * where the length is "length", the reported length is "plen",
3307              * and the "if the snapshot length were infinite" length is the
3308              * minimum of the reported length of the tvbuff handed to us
3309              * and "plen", with a new type of exception thrown if the offset
3310              * is within the reported length but beyond that third length,
3311              * with that exception getting the "Unreassembled Packet" error.
3312              */
3313             length = length_remaining;
3314             if (length > plen)
3315                   length = plen;
3316             next_tvb = tvb_new_subset(tvb, offset, length, plen);
3317
3318             /*
3319              * Set the column appropriately.
3320              */
3321             if (is_initial_creq) {
3322                   if (check_col(pinfo->cinfo, COL_INFO)) 
3323                         col_set_str(pinfo->cinfo, COL_INFO, "Initial connection request");
3324             } else {
3325                   if (sep == NULL) {
3326                         /*
3327                          * We haven't set the column yet; set it.
3328                          */
3329                         if (check_col(pinfo->cinfo, COL_INFO)) 
3330                               col_add_str(pinfo->cinfo, COL_INFO, "Requests");
3331
3332                         /*
3333                          * Initialize the separator.
3334                          */
3335                         sep = ":";
3336                   }
3337             }
3338
3339             /*
3340              * Dissect the X11 request.
3341              *
3342              * Catch the ReportedBoundsError exception; if this
3343              * particular message happens to get a ReportedBoundsError
3344              * exception, that doesn't mean that we should stop
3345              * dissecting X11 requests within this frame or chunk of
3346              * reassembled data.
3347              *
3348              * If it gets a BoundsError, we can stop, as there's nothing
3349              * more to see, so we just re-throw it.
3350              */
3351             TRY {
3352                   if (is_initial_creq) {
3353                         dissect_x11_initial_conn(next_tvb, pinfo, tree,
3354                             state_info, little_endian);
3355                   } else {
3356                         dissect_x11_request(next_tvb, pinfo, tree, sep,
3357                             state_info, little_endian);
3358                   }
3359             }
3360             CATCH(BoundsError) {
3361                   RETHROW;
3362             }
3363             CATCH(ReportedBoundsError) {
3364                   show_reported_bounds_error(tvb, pinfo, tree);
3365             }
3366             ENDTRY;
3367
3368             /*
3369              * Skip the X11 message.
3370              */
3371             offset += plen;
3372
3373             sep = ",";
3374       }
3375 }
3376
3377 static void
3378 dissect_x11_replies(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3379 {
3380 /* Set up structures we will need to add the protocol subtree and manage it */
3381       proto_item *ti;
3382       proto_tree *x11_tree;
3383         
3384 /* This field shows up as the "Info" column in the display; you should make
3385    it, if possible, summarize what's in the packet, so that a user looking
3386    at the list of packets can tell what type of packet it is. */
3387       if (check_col(pinfo->cinfo, COL_INFO)) 
3388             col_set_str(pinfo->cinfo, COL_INFO, "Replies/events");
3389
3390 /* In the interest of speed, if "tree" is NULL, don't do any work not
3391    necessary to generate protocol tree items. */
3392       if (!tree) return;
3393       ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
3394       x11_tree = proto_item_add_subtree(ti, ett_x11);
3395
3396       /*
3397        * XXX - dissect these in a loop, like the requests.
3398        */
3399       call_dissector(data_handle,tvb, pinfo, x11_tree);
3400 }
3401
3402 /************************************************************************
3403  ***                                                                  ***
3404  ***         I N I T I A L I Z A T I O N   A N D   M A I N            ***
3405  ***                                                                  ***
3406  ************************************************************************/
3407
3408 static void
3409 dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3410 {
3411       if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
3412             col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
3413     
3414       if (pinfo->match_port == pinfo->destport)
3415             dissect_x11_requests(tvb, pinfo, tree);
3416       else
3417             dissect_x11_replies(tvb, pinfo, tree);
3418 }
3419
3420 /* Register the protocol with Ethereal */
3421 void proto_register_x11(void)
3422 {                 
3423
3424 /* Setup list of header fields */
3425       static hf_register_info hf[] = {
3426 /*
3427   { &hf_x11_FIELDABBREV,
3428   { "FIELDNAME",           "x11.FIELDABBREV",
3429   FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,          
3430   "FIELDDESCR", HFILL }
3431   },
3432 */
3433 #include "x11-register-info.h"
3434       };
3435
3436 /* Setup protocol subtree array */
3437       static gint *ett[] = {
3438             &ett_x11,
3439             &ett_x11_color_flags,
3440             &ett_x11_list_of_arc,
3441             &ett_x11_arc,
3442             &ett_x11_list_of_atom,
3443             &ett_x11_list_of_card32,
3444             &ett_x11_list_of_color_item,
3445             &ett_x11_color_item,
3446             &ett_x11_list_of_keycode,
3447             &ett_x11_list_of_keysyms,
3448             &ett_x11_keysym,
3449             &ett_x11_list_of_point,
3450             &ett_x11_point,
3451             &ett_x11_list_of_rectangle,
3452             &ett_x11_rectangle,
3453             &ett_x11_list_of_segment,
3454             &ett_x11_segment,
3455             &ett_x11_list_of_string8,
3456             &ett_x11_list_of_text_item,
3457             &ett_x11_text_item,
3458             &ett_x11_gc_value_mask,
3459             &ett_x11_event_mask,
3460             &ett_x11_do_not_propagate_mask,
3461             &ett_x11_set_of_key_mask,
3462             &ett_x11_pointer_event_mask,
3463             &ett_x11_window_value_mask,
3464             &ett_x11_configure_window_mask,
3465             &ett_x11_keyboard_value_mask,
3466       };
3467       module_t *x11_module;
3468
3469 /* Register the protocol name and description */
3470       proto_x11 = proto_register_protocol("X11", "X11", "x11");
3471
3472 /* Required function calls to register the header fields and subtrees used */
3473       proto_register_field_array(proto_x11, hf, array_length(hf));
3474       proto_register_subtree_array(ett, array_length(ett));
3475
3476       register_init_routine(x11_init_protocol);
3477
3478       x11_module = prefs_register_protocol(proto_x11, NULL);
3479       prefs_register_bool_preference(x11_module, "desegment",
3480             "Desegment all X11 messages spanning multiple TCP segments",
3481             "Whether the X11 dissector should desegment all messages spanning multiple TCP segments",
3482             &x11_desegment);
3483 }
3484
3485 void
3486 proto_reg_handoff_x11(void)
3487 {
3488   dissector_handle_t x11_handle;
3489
3490   x11_handle = create_dissector_handle(dissect_x11, proto_x11);
3491   dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
3492   dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
3493   dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
3494   data_handle = find_dissector("data");
3495 }