1 /* packet-slsk.c
2  * Routines for SoulSeek Protocol dissection
3  * Copyright 2003, Christian Wagner <Christian.Wagner@stud.uni-karlsruhe.de>
4  * Institute of Telematics - University of Karlsruhe
5  * part of this work supported by
6  *  Deutsche Forschungsgemeinschaft (DFG) Grant Number FU448/1
7  *
8  * SoulSeek Protocol dissector based on protocol descriptions from SoleSeek Project:
9  * http://cvs.sourceforge.net/viewcvs.py/soleseek/SoleSeek/doc/protocol.html?rev=HEAD
10  * Updated for SoulSeek client version 151
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * SPDX-License-Identifier: GPL-2.0-or-later
17  */
18 
19 #include "config.h"
20 
21 
22 #include <epan/packet.h>
23 #include <epan/prefs.h>
24 #include <epan/strutil.h>
25 #include <epan/expert.h>
26 #include "packet-tcp.h"
27 
28 void proto_register_slsk(void);
29 void proto_reg_handoff_slsk(void);
Atom(Index resnr,std::string md_atom_name,Index atom_id,Eigen::Vector3d pos,std::string type)30 
31 /* Initialize the protocol and registered fields */
32 static int proto_slsk = -1;
33 
34 static int hf_slsk_integer = -1;
35 static int hf_slsk_string = -1;
36 static int hf_slsk_byte = -1;
37 static int hf_slsk_message_length = -1;
38 static int hf_slsk_message_code = -1;
39 static int hf_slsk_embedded_message_type = -1;
40 static int hf_slsk_client_ip = -1;
41 /* static int hf_slsk_server_ip = -1; */
42 static int hf_slsk_directory_name = -1;
43 static int hf_slsk_username = -1;
44 static int hf_slsk_password = -1;
45 static int hf_slsk_version = -1;
46 static int hf_slsk_login_successful = -1;
47 static int hf_slsk_login_message = -1;
48 static int hf_slsk_port = -1;
49 static int hf_slsk_ip = -1;
50 static int hf_slsk_user_exists = -1;
51 static int hf_slsk_status_code = -1;
52 static int hf_slsk_room = -1;
53 static int hf_slsk_chat_message = -1;
54 static int hf_slsk_users_in_room = -1;
55 static int hf_slsk_token = -1;
56 static int hf_slsk_connection_type = -1;
57 static int hf_slsk_chat_message_id = -1;
58 static int hf_slsk_timestamp = -1;
59 static int hf_slsk_search_text = -1;
60 static int hf_slsk_folder_count = -1;
61 static int hf_slsk_file_count = -1;
62 static int hf_slsk_average_speed = -1;
63 static int hf_slsk_download_number = -1;
64 static int hf_slsk_files = -1;
65 static int hf_slsk_directories = -1;
66 static int hf_slsk_slotsfull = -1;
67 static int hf_slsk_place_in_queue = -1;
Atom(Index atom_id,std::string element,Eigen::Vector3d pos)68 static int hf_slsk_number_of_rooms = -1;
69 static int hf_slsk_filename = -1;
70 static int hf_slsk_filename_ext = -1;
GetElementFromString(const std::string & MDName)71 static int hf_slsk_directory = -1;
72 static int hf_slsk_size = -1;
73 /* static int hf_slsk_checksum = -1; */
74 static int hf_slsk_code = -1;
75 static int hf_slsk_number_of_users = -1;
76 static int hf_slsk_number_of_days = -1;
77 static int hf_slsk_transfer_direction = -1;
78 static int hf_slsk_user_description = -1;
79 static int hf_slsk_picture_exists = -1;
80 static int hf_slsk_picture = -1;
81 /* static int hf_slsk_user_uploads = -1; */
Rotate(const Eigen::Matrix3d & R,const Eigen::Vector3d & refPos)82 static int hf_slsk_total_uploads = -1;
83 static int hf_slsk_queued_uploads = -1;
84 static int hf_slsk_slots_available = -1;
85 static int hf_slsk_allowed = -1;
86 static int hf_slsk_compr_packet = -1;
87 static int hf_slsk_parent_min_speed = -1;
SetupCptTable(CptTable & table)88 static int hf_slsk_parent_speed_connection_ratio = -1;
89 static int hf_slsk_seconds_parent_inactivity_before_disconnect = -1;
90 static int hf_slsk_seconds_server_inactivity_before_disconnect = -1;
91 static int hf_slsk_nodes_in_cache_before_disconnect = -1;
92 static int hf_slsk_seconds_before_ping_children = -1;
93 static int hf_slsk_recommendation = -1;
94 static int hf_slsk_user = -1;
95 static int hf_slsk_ranking = -1;
96 static int hf_slsk_compressed_packet_length = -1;
97 static int hf_slsk_uncompressed_packet_length = -1;
WriteData(data & d) const98 static int hf_slsk_num_directories = -1;
99 static int hf_slsk_upload_speed = -1;
100 static int hf_slsk_in_queue = -1;
101 static int hf_slsk_num_slotsfull_records = -1;
102 static int hf_slsk_num_recommendations = -1;
103 static int hf_slsk_num_files = -1;
104 static int hf_slsk_num_strings = -1;
105 static int hf_slsk_file_code = -1;
106 static int hf_slsk_file_size1 = -1;
107 static int hf_slsk_file_size2 = -1;
ReadData(const data & d)108 static int hf_slsk_file_num_attributes = -1;
109 static int hf_slsk_file_attribute_type = -1;
110 static int hf_slsk_file_attribute_value = -1;
111 static int hf_slsk_free_upload_slots = -1;
112 static int hf_slsk_bytes = -1;
113 static int hf_slsk_same_recommendation = -1;
114 static int hf_slsk_number_of_priv_users = -1;
115 static int hf_slsk_num_parent_address = -1;
116 
117 /* Initialize the subtree pointers */
118 static gint ett_slsk = -1;
119 static gint ett_slsk_compr_packet = -1;
120 static gint ett_slsk_directory = -1;
121 static gint ett_slsk_file = -1;
122 static gint ett_slsk_file_attribute = -1;
123 static gint ett_slsk_user = -1;
124 static gint ett_slsk_recommendation = -1;
125 static gint ett_slsk_room = -1;
126 static gint ett_slsk_string = -1;
127 
128 static expert_field ei_slsk_unknown_data = EI_INIT;
129 static expert_field ei_slsk_zlib_decompression_failed = EI_INIT;
130 static expert_field ei_slsk_decompression_failed = EI_INIT;
131 
132 #define SLSK_TCP_PORT_RANGE   "2234,2240,5534"
133 
134 
135 /* desegmentation of SoulSeek Message over TCP */
136 static gboolean slsk_desegment = TRUE;
137 #ifdef HAVE_ZLIB
138 static gboolean slsk_decompress = TRUE;
139 #else
140 static gboolean slsk_decompress = FALSE;
141 #endif
142 
143 static const value_string slsk_tcp_msgs[] = {
144   { 1, "Login"},
145   { 2, "Set Wait Port"},
146   { 3, "Get Peer Address"},
147   { 4, "Get Shared File List"},
148   { 5, "User Exists / Shared File List"},
149   { 7, "Get User Status"},
150   { 9, "File Search Result"},
151   { 13, "Say ChatRoom"},
152   { 14, "Join Room"},
153   { 15, "Leave Room / User Info Request"},
154   { 16, "User Joined Room / User Info Reply"},
155   { 17, "User Left Room"},
156   { 18, "Connect To Peer"},
157   { 22, "Message User"},
158   { 23, "Message User Ack"},
159   { 26, "File Search"},
160   { 28, "Set Status"},
161   { 32, "Ping"},
162   { 34, "Update Upload Speed"},
163   { 35, "Shared Files & Folders"},
164   { 36, "Get User Stats / Folder Contents Request"},
165   { 37, "Folder Contents Response"},
166   { 40, "Queued Downloads / Transfer Request"},
167   { 41, "Transfer Response"},
168   { 42, "Placehold Upload"},
169   { 43, "Queue Upload"},
170   { 44, "Place In Queue"},
171   { 46, "Upload Failed"},
172   { 50, "Queue Failed / Own Recommendation"},
173   { 51, "Add Things I like / Place In Queue Request"},
174   { 52, "Remove Things I like"},
175   { 54, "Get Recommendations"},
176   { 55, "Type 55"},
177   { 56, "Get Global Rankings"},
178   { 57, "Get User Recommendations"},
179   { 58, "Admin Command"},
180   { 60, "Place In Line Response"},
181   { 62, "Room Added"},
182   { 63, "Room Removed"},
183   { 64, "Room List"},
184   { 65, "Exact File Search"},
185   { 66, "Admin Message"},
186   { 67, "Global User List"},
187   { 68, "Tunneled Message"},
188   { 69, "Privileged User List"},
189   { 71, "Get Parent List"},
190   { 73, "Type 73"},
191   { 83, "Parent Min Speed"},
192   { 84, "Parent Speed Connection Ratio"},
193   { 86, "Parent Inactivity Before Disconnect"},
194   { 87, "Server Inactivity Before Disconnect"},
195   { 88, "Nodes In Cache Before Disconnect"},
196   { 90, "Seconds Before Ping Children"},
197   { 91, "Add To Privileged"},
198   { 92, "Check Privileges"},
199   { 93, "Embedded Message"},
200   { 100, "Become Parent"},
201   { 102, "Random Parent Addresses"},
202   { 103, "Send Wishlist Entry"},
203   { 104, "Type 104"},
204   { 110, "Get Similar Users"},
205   { 111, "Get Recommendations for Item"},
206   { 112, "Get Similar Users for Item"},
207   { 1001, "Can't Connect To Peer"},
208   { 0, NULL }
209 };
210 
211 static const value_string slsk_status_codes[] = {
212   { -1, "Unknown"},
213   { 0, "Offline"},
214   { 1, "Away"},
215   { 2, "Online"},
216   { 0, NULL }
217 };
218 
219 static const value_string slsk_transfer_direction[] = {
220   { 0, "Download"},
221   { 1, "Upload"},
222   { 0, NULL }
223 };
224 
225 static const value_string slsk_yes_no[] = {
226   { 0, "No"},
227   { 1, "Yes"},
228   { 0, NULL }
229 };
230 
231 static const value_string slsk_attr_type[] = {
232   { 0, "Bitrate"},
233   { 1, "Length"},
234   { 2, "VBR"},
235   { 0, NULL }
236 };
237 
238 static const char* connection_type(char con_type[]) {
239   if (strlen(con_type) != 1) return "Unknown";
240   if (con_type[0] == 'D') return "Distributed Search";
241   if (con_type[0] == 'P') return "Peer Connection";    /* "File Search Result / User Info Request / Get Shared File List" */
242   if (con_type[0] == 'F') return "File Transfer";
243   return "Unknown";
244 }
245 
246 static gboolean check_slsk_format(tvbuff_t *tvb, int offset, const char format[]){
247 
248   /*
249   * Returns TRUE if tvbuff beginning at offset matches a certain format
250   * The format is given by an array of characters standing for a special field type
251   *     i - integer  (4 bytes)
252   *     b - byte  (1 byte)
253   *    s - string  (string_length + 4 bytes)
254   *
255   *    * - can be used at the end of a format to ignore any following bytes
256   */
257 
258   switch ( format[0] ) {
259     case 'i':
260       if (tvb_captured_length_remaining(tvb, offset) < 4) return FALSE;
261       offset += 4;
262     break;
263     case 'b':
264       if (tvb_captured_length_remaining(tvb, offset) < 1) return FALSE;
265       offset += 1;
266     break;
267     case 's':
268       if (tvb_captured_length_remaining(tvb, offset) < 4) return FALSE;
269       if (tvb_captured_length_remaining(tvb, offset) < (int)tvb_get_letohl(tvb, offset)+4) return FALSE;
270       offset += tvb_get_letohl(tvb, offset)+4;
271     break;
272     case '*':
273       return TRUE;
274     default:
275       return FALSE;
276   }
277 
278   if (format[1] == '\0' ) {
279     if (tvb_captured_length_remaining(tvb, offset) > 0) /* Checks for additional bytes at the end */
280       return FALSE;
281     return TRUE;
282   }
283   return check_slsk_format(tvb, offset, &format[1]);
284 
285 }
286 
287 static const char* get_message_type(tvbuff_t *tvb) {
288   /*
289   * Checks if the Message Code is known.
290   * If unknown checks if the Message Code is stored in a byte.
291   * Returns the Message Type.
292   */
293   int msg_code = tvb_get_letohl(tvb, 4);
294   const gchar *message_type =  try_val_to_str(msg_code, slsk_tcp_msgs);
295   if (message_type == NULL) {
296     if (check_slsk_format(tvb, 4, "bisis"))
297       message_type = "Distributed Search";
298     else if (check_slsk_format(tvb, 4, "bssi"))
299       message_type = "Peer Init";
300     else if (check_slsk_format(tvb, 4, "bi"))
301       message_type = "Pierce Fw";
302     else
303       message_type = "Unknown";
304   }
305   return message_type;
306 }
307 
308 static guint get_slsk_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
309                               int offset, void *data _U_)
310 {
311   guint32 msg_len;
312   msg_len = tvb_get_letohl(tvb, offset);
313   /* That length doesn't include the length field itself; add that in. */
314   msg_len += 4;
315   return msg_len;
316 }
317 
318 /* Code to actually dissect the packets */
319 
320 static int dissect_slsk_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
321 {
322 
323 /* Set up structures needed to add the protocol subtree and manage it */
324   proto_item *ti, *ti_len, *ti_subtree, *ti_subtree2;
325   proto_tree *slsk_tree, *subtree, *subtree2, *subtree3;
326 
327   int offset = 0, i, j;
328   guint32 msg_len, msg_code;
329   guint8 *str;
330   int str_len, start_offset, start_offset2;
331 
332   int comprlen = 0, uncomprlen = 0, uncompr_tvb_offset = 0;
333   int i2 = 0, j2 = 0;
334   int i3 = 0, j3 = 0;
335 
336 /* Make entries in Protocol column and Info column on summary display */
337   col_set_str(pinfo->cinfo, COL_PROTOCOL, "slsk");
338 
339 /* This field shows up as the "Info" column in the display  */
340 
341   col_set_str(pinfo->cinfo, COL_INFO, "SoulSeek Message");
342 
343   col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", get_message_type(tvb));
344 
345 /* create display subtree for the protocol */
346     ti = proto_tree_add_item(tree, proto_slsk, tvb, 0, -1, ENC_NA);
347     slsk_tree = proto_item_add_subtree(ti, ett_slsk);
348 
349 /* Continue adding tree items to process the packet here */
350 
351     ti_len = proto_tree_add_item_ret_uint(slsk_tree, hf_slsk_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &msg_len);
352     offset += 4;
353     msg_code = tvb_get_letohl(tvb, offset);
354 
355     switch (msg_code) {
356 
357       case  1:
358         if (check_slsk_format(tvb, offset, "issi")) {
359           /* Client-to-Server */
360           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
361                      "Login (Code: %02d)", msg_code);
362           offset += 4;
363           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
364           offset += str_len;
365           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_password, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
366           offset += str_len;
367           proto_tree_add_item(slsk_tree, hf_slsk_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
368           offset += 4;
369         }
370         else if (check_slsk_format(tvb, offset, "ibs") || check_slsk_format(tvb, offset, "ibsi")) {
371           /* Server-to-Client */
372           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
373                      "Login Reply (Code: %02d)", msg_code);
374           offset += 4;
375           i=tvb_get_guint8(tvb, offset);
376           proto_tree_add_item(slsk_tree, hf_slsk_login_successful, tvb, offset, 1, ENC_NA);
377           offset += 1;
378           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_login_message, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
379           offset += str_len;
380           if (i == 1){
381             proto_tree_add_item(slsk_tree, hf_slsk_client_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
382             offset += 4;
383           }
384         }
385       break;
386 
387       case  2:
388         if (check_slsk_format(tvb, offset, "ii")) {
389           /* Client-to-Server */
390           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
391                      "Set Wait Port (Code: %02d)", msg_code);
392           offset += 4;
393           proto_tree_add_item(slsk_tree, hf_slsk_port, tvb, offset, 4, ENC_LITTLE_ENDIAN);
394           offset += 4;
395         }
396       break;
397 
398       case  3:
399         if (check_slsk_format(tvb, offset, "isii")) {
400           /* Server-to-Client */
401           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
402                      "Get Peer Address Reply (Code: %02d)", msg_code);
403           offset += 4;
404           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
405           offset += str_len;
406           proto_tree_add_item(slsk_tree, hf_slsk_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
407           offset += 4;
408           proto_tree_add_item(slsk_tree, hf_slsk_port, tvb, offset, 4, ENC_LITTLE_ENDIAN);
409           offset += 4;
410         }
411         else if (check_slsk_format(tvb, offset, "is")) {
412           /* Client-to-Server */
413           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
414                      "Get Peer Address (Code: %02d)", msg_code);
415           offset += 4;
416           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
417           offset += str_len;
418         }
419       break;
420 
421       case 4:
422         if (check_slsk_format(tvb, offset, "i")) {
423           /* Client-to-Client */
424           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
425                      "Get Shared File List (Code: %02d)", msg_code);
426           offset += 4;
427         }
428       break;
429 
430       case  5:
431         if (check_slsk_format(tvb, offset, "isb")) {
432           /* Server-to-Client */
433           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
434                      "User Exists Reply (Code: %02d)", msg_code);
435           offset += 4;
436           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
437           offset += str_len;
438           proto_tree_add_item(slsk_tree, hf_slsk_user_exists, tvb, offset, 1, ENC_NA);
439           offset += 1;
440         }
441         else if (check_slsk_format(tvb, offset, "is")) {
442           /* Client-to-Server */
443           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
444                      "User Exists Request (Code: %02d)", msg_code);
445           offset += 4;
446           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
447           offset += str_len;
448         }
449         else if (check_slsk_format(tvb, offset, "i*")) {
450           /* Client-to-Client */
451           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
452                      "Shared File List (Code: %02d)", msg_code);
453           offset += 4;
454 
455           /* [zlib compressed] */
456           comprlen = tvb_captured_length_remaining(tvb, offset);
457 
458           if (slsk_decompress == TRUE){
459 
460             tvbuff_t *uncompr_tvb = tvb_child_uncompress(tvb, tvb, offset, comprlen);
461 
462             if (uncompr_tvb == NULL) {
463               proto_tree_add_expert(slsk_tree, pinfo, &ei_slsk_zlib_decompression_failed, tvb, offset, -1);
464               offset += tvb_captured_length_remaining(tvb, offset);
465             } else {
466 
467               proto_item *ti2 = proto_tree_add_item(slsk_tree, hf_slsk_compr_packet, tvb, offset, -1, ENC_NA);
468               proto_tree *slsk_compr_packet_tree = proto_item_add_subtree(ti2, ett_slsk_compr_packet);
469               proto_item_set_generated(ti2);
470 
471               ti = proto_tree_add_uint(slsk_tree, hf_slsk_compressed_packet_length, tvb, offset, 0, comprlen);
472               proto_item_set_generated(ti);
473               uncomprlen = tvb_reported_length_remaining(uncompr_tvb, 0);
474               ti = proto_tree_add_uint(slsk_tree, hf_slsk_uncompressed_packet_length, tvb, offset, 0, uncomprlen);
475               proto_item_set_generated(ti);
476 
477               add_new_data_source(pinfo, uncompr_tvb, "Uncompressed SoulSeek data");
478               uncompr_tvb_offset = 0;
479               if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "i*")) {
480                 proto_tree_add_item_ret_int(slsk_compr_packet_tree, hf_slsk_num_directories, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j);
481                 uncompr_tvb_offset += 4;
482                 for (i = 0; i < j; i++) {
483                   if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "si*")) {
484                     start_offset = uncompr_tvb_offset;
485                     subtree = proto_tree_add_subtree_format(slsk_compr_packet_tree, uncompr_tvb, uncompr_tvb_offset, 1, ett_slsk_directory, &ti_subtree, "Directory #%d", i+1);
486                     proto_tree_add_item_ret_length(subtree, hf_slsk_directory_name, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
487                     uncompr_tvb_offset += str_len;
488                     proto_tree_add_item_ret_int(subtree, hf_slsk_num_files, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j2);
489                     uncompr_tvb_offset += 4;
490                     for (i2 = 0; i2 < j2; i2++) {
491                       if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "bsiisi*")) {
492                         start_offset2 = uncompr_tvb_offset;
493                         subtree2 = proto_tree_add_subtree_format(subtree, uncompr_tvb, uncompr_tvb_offset, 1, ett_slsk_file, &ti_subtree2, "File #%d", i2+1);
494                         proto_tree_add_item(subtree2, hf_slsk_file_code, uncompr_tvb, uncompr_tvb_offset, 1, ENC_NA);
495                         uncompr_tvb_offset += 1;
496                         proto_tree_add_item_ret_length(subtree2, hf_slsk_filename, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
497                         uncompr_tvb_offset += str_len;
498                         proto_tree_add_item(subtree2, hf_slsk_file_size1, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
499                         uncompr_tvb_offset += 4;
500                         proto_tree_add_item(subtree2, hf_slsk_file_size2, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
501                         uncompr_tvb_offset += 4;
502                         proto_tree_add_item_ret_length(subtree2, hf_slsk_filename_ext, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
503                         uncompr_tvb_offset += str_len;
504                         proto_tree_add_item_ret_int(subtree2, hf_slsk_file_num_attributes, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j3);
505                         uncompr_tvb_offset += 4;
506                         for (i3 = 0; i3 < j3; i3++) {
507                           if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "ii*")) {
508                             subtree3 = proto_tree_add_subtree_format(subtree2, uncompr_tvb, uncompr_tvb_offset, 8, ett_slsk_file_attribute, NULL, "Attribute #%d", i3+1);
509                             proto_tree_add_item(subtree3, hf_slsk_file_attribute_type, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
510                             uncompr_tvb_offset += 4;
511                             proto_tree_add_item(subtree3, hf_slsk_file_attribute_value, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
512                             uncompr_tvb_offset += 4;
513                           } else {
514                             break; /* invalid format */
515                           }
516                         }
517                         proto_item_set_len(ti_subtree2, uncompr_tvb_offset-start_offset2);
518                       } else {
519                         break; /* invalid format */
520                       }
521                     }
522                     proto_item_set_len(ti_subtree, uncompr_tvb_offset-start_offset);
523                   } else {
524                     break; /* invalid format */
525                   }
526                 }
527               }
528             }
529           }else {
530             ti = proto_tree_add_item(slsk_tree, hf_slsk_compr_packet, tvb, offset, -1, ENC_NA);
531             proto_item_set_generated(ti);
532             ti = proto_tree_add_uint(slsk_tree, hf_slsk_compressed_packet_length, tvb, offset, 0, comprlen);
533             proto_item_set_generated(ti);
534             offset += tvb_captured_length_remaining(tvb, offset);
535           }
536         }
537       break;
538 
539       case  7:
540         if (check_slsk_format(tvb, offset, "isi")) {
541           /* Server-to-Client */
542           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
543                      "Get User Status Reply (Code: %02d)", msg_code);
544           offset += 4;
545           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
546           offset += str_len;
547           proto_tree_add_item(slsk_tree, hf_slsk_status_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
548           offset += 4;
549         }
550         else if (check_slsk_format(tvb, offset, "is")) {
551           /* Client-to-Server */
552           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
553                      "Get User Status (Code: %02d)", msg_code);
554           offset += 4;
555           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
556           offset += str_len;
557         }
558       break;
559 
560       case 9:
561         if (check_slsk_format(tvb, offset, "i*")) {
562           /* Client-to-Client */
563           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
564                      "File Search Result (Code: %02d)", msg_code);
565           offset += 4;
566 
567           /* [zlib compressed] */
568           comprlen = tvb_captured_length_remaining(tvb, offset);
569 
570           if (slsk_decompress == TRUE){
571 
572             tvbuff_t *uncompr_tvb = tvb_child_uncompress(tvb, tvb, offset, comprlen);
573 
574             if (uncompr_tvb == NULL) {
575               ti = proto_tree_add_item(slsk_tree, hf_slsk_compr_packet, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
576               proto_item_set_generated(ti);
577               offset += tvb_captured_length_remaining(tvb, offset);
578               expert_add_info(pinfo, ti, &ei_slsk_decompression_failed);
579             } else {
580 
581               proto_item *ti2 = proto_tree_add_item(slsk_tree, hf_slsk_compr_packet, tvb, offset, -1, ENC_NA);
582               proto_tree *slsk_compr_packet_tree = proto_item_add_subtree(ti2, ett_slsk_compr_packet);
583               proto_item_set_generated(ti2);
584 
585               ti = proto_tree_add_uint(slsk_tree, hf_slsk_compressed_packet_length, tvb, offset, 0, comprlen);
586               proto_item_set_generated(ti);
587               uncomprlen = tvb_captured_length_remaining(uncompr_tvb, 0);
588               ti = proto_tree_add_uint(slsk_tree, hf_slsk_uncompressed_packet_length, tvb, offset, 0, uncomprlen);
589               proto_item_set_generated(ti);
590 
591               add_new_data_source(pinfo, uncompr_tvb, "Uncompressed SoulSeek data");
592               uncompr_tvb_offset = 0;
593               if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "sii*")) {
594                 proto_tree_add_item_ret_length(slsk_compr_packet_tree, hf_slsk_username, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_NA, &str_len);
595                 uncompr_tvb_offset += str_len;
596                 proto_tree_add_item(slsk_compr_packet_tree, hf_slsk_token, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
597                 uncompr_tvb_offset += 4;
598                 proto_tree_add_item_ret_int(slsk_compr_packet_tree, hf_slsk_num_files, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j);
599                 uncompr_tvb_offset += 4;
600                 for (i = 0; i < j; i++) {
601                   if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "bsiisi*")) {
602                     start_offset2 = uncompr_tvb_offset;
603                     subtree2 = proto_tree_add_subtree_format(slsk_compr_packet_tree, uncompr_tvb, uncompr_tvb_offset, 1, ett_slsk_file, &ti_subtree2, "File #%d", i+1);
604                     proto_tree_add_item(subtree2, hf_slsk_file_code, uncompr_tvb, uncompr_tvb_offset, 1, ENC_NA);
605                     uncompr_tvb_offset += 1;
606                     proto_tree_add_item_ret_length(subtree2, hf_slsk_filename, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
607                     uncompr_tvb_offset += str_len;
608                     proto_tree_add_item(subtree2, hf_slsk_file_size1, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
609                     uncompr_tvb_offset += 4;
610                     proto_tree_add_item(subtree2, hf_slsk_file_size2, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
611                     uncompr_tvb_offset += 4;
612                     proto_tree_add_item_ret_length(subtree2, hf_slsk_filename_ext, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
613                     uncompr_tvb_offset += str_len;
614                     proto_tree_add_item_ret_int(subtree2, hf_slsk_file_num_attributes, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j2);
615                     uncompr_tvb_offset += 4;
616                     for (i2 = 0; i2 < j2; i2++) {
617                       if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "ii*")) {
618                         subtree3 = proto_tree_add_subtree_format(subtree2, uncompr_tvb, uncompr_tvb_offset, 8, ett_slsk_file_attribute, NULL, "Attribute #%d", i2+1);
619                         proto_tree_add_item(subtree3, hf_slsk_file_attribute_type, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
620                         uncompr_tvb_offset += 4;
621                         proto_tree_add_item(subtree3, hf_slsk_file_attribute_value, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
622                         uncompr_tvb_offset += 4;
623                       } else {
624                         break; /* invalid format */
625                       }
626                     }
627                     proto_item_set_len(ti_subtree2, uncompr_tvb_offset-start_offset2);
628                   } else {
629                     break; /* invalid format */
630                   }
631                 }
632 
633                 proto_tree_add_item(slsk_compr_packet_tree, hf_slsk_free_upload_slots, uncompr_tvb, uncompr_tvb_offset, 1, ENC_LITTLE_ENDIAN);
634                 uncompr_tvb_offset += 1;
635                 proto_tree_add_item(slsk_compr_packet_tree, hf_slsk_upload_speed, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
636                 uncompr_tvb_offset += 4;
637                 proto_tree_add_item(slsk_compr_packet_tree, hf_slsk_in_queue, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
638               }
639             }
640           }else {
641             ti = proto_tree_add_item(slsk_tree, hf_slsk_compr_packet, tvb, offset, -1, ENC_NA);
642             proto_item_set_generated(ti);
643             ti = proto_tree_add_uint(slsk_tree, hf_slsk_compressed_packet_length, tvb, offset, 0, comprlen);
644             proto_item_set_generated(ti);
645             offset += tvb_captured_length_remaining(tvb, offset);
646           }
647         }
648       break;
649 
650       case 13:
651         if (check_slsk_format(tvb, offset, "isss")) {
652           /* Server-to-Client */
653           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
654                      "Say ChatRoom (Code: %02d)", msg_code);
655           offset += 4;
656           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
657           offset += str_len;
658           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
659           offset += str_len;
660           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_chat_message, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
661           offset += str_len;
662         }
663         else if (check_slsk_format(tvb, offset, "iss")) {
664           /* Client-to-Server */
665           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
666                      "Say ChatRoom (Code: %02d)", msg_code);
667           offset += 4;
668           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
669           offset += str_len;
670           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_chat_message, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
671           offset += str_len;
672         }
673       break;
674 
675       case 14:
676         if (check_slsk_format(tvb, offset, "is")) {
677           /* Client-to-Server */
678           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
679                      "Join/Add Room (Code: %02d)", msg_code);
680           offset += 4;
681           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
682           offset += str_len;
683         }
684         else if (check_slsk_format(tvb, offset, "isi*")) {
685           /* Server-to-Client */
686           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
687                      "Join Room User List (Code: %02d)", msg_code);
688           offset += 4;
689           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
690           offset += str_len;
691           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
692           offset += 4;
693           if (j > tvb_reported_length_remaining(tvb, offset))
694             break;
695           for (i = 0; i < j; i++) {
696             if (check_slsk_format(tvb, offset, "s*")) {
697               proto_tree_add_item_ret_length(slsk_tree, hf_slsk_user, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
698               offset += str_len;
699             } else {
700               break; /* invalid format */
701             }
702           }
703           if (check_slsk_format(tvb, offset, "i*")) {
704             proto_tree_add_item_ret_int(slsk_tree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
705             offset += 4;
706             if (j > tvb_reported_length_remaining(tvb, offset))
707               break;
708             for (i = 0; i < j; i++) {
709               if (check_slsk_format(tvb, offset, "i*")) {
710                 proto_tree_add_item(slsk_tree, hf_slsk_status_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
711                 offset += 4;
712               } else {
713                 break; /* invalid format */
714               }
715             }
716           }
717           if (check_slsk_format(tvb, offset, "i*")) {
718             proto_tree_add_item_ret_int(slsk_tree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
719             offset += 4;
720             if (j > tvb_reported_length_remaining(tvb, offset))
721               break;
722             for (i = 0; i < j; i++) {
723               if (check_slsk_format(tvb, offset, "iiiii*")) {
724                 subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 20, ett_slsk_user, NULL, "User #%d", i+1);
725                 proto_tree_add_item(subtree, hf_slsk_average_speed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
726                 offset += 4;
727                 proto_tree_add_item(subtree, hf_slsk_download_number, tvb, offset, 4, ENC_LITTLE_ENDIAN);
728                 offset += 4;
729                 proto_tree_add_item(subtree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
730                 offset += 4;
731                 proto_tree_add_item(subtree, hf_slsk_files, tvb, offset, 4, ENC_LITTLE_ENDIAN);
732                 offset += 4;
733                 proto_tree_add_item(subtree, hf_slsk_directories, tvb, offset, 4, ENC_LITTLE_ENDIAN);
734                 offset += 4;
735               } else {
736                 break; /* invalid format */
737               }
738             }
739           }
740           if (check_slsk_format(tvb, offset, "i*")) {
741             proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_slotsfull_records, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
742             offset += 4;
743             if (j > tvb_reported_length_remaining(tvb, offset))
744               break;
745             for (i = 0; i < j; i++) {
746               if (check_slsk_format(tvb, offset, "i*")) {
747                 subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 4, ett_slsk_user, NULL, "User #%d", i+1);
748                 proto_tree_add_item(subtree, hf_slsk_slotsfull, tvb, offset, 4, ENC_LITTLE_ENDIAN);
749                 offset += 4;
750               } else {
751                 break; /* invalid format */
752               }
753             }
754           }
755         }
756       break;
757 
758       case 15:
759         if (check_slsk_format(tvb, offset, "is")) {
760           /* Client-to-Server & Server-to-Client */
761           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
762                      "Leave Room (Code: %02d)", msg_code);
763           offset += 4;
764           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
765           offset += str_len;
766         }
767         else if (check_slsk_format(tvb, offset, "i")) {
768           /* Client-to-Client */
769           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
770                      "User Info Request (Code: %02d)", msg_code);
771           offset += 4;
772         }
773       break;
774 
775       case 16:
776         if (check_slsk_format(tvb, offset, "issiiiiiii")) {
777           /* Server-to-Client */
778           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
779                      "User Joined Room (Code: %02d)", msg_code);
780           offset += 4;
781           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
782           offset += str_len;
783           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
784           offset += str_len;
785           proto_tree_add_item(slsk_tree, hf_slsk_total_uploads, tvb, offset, 4, ENC_LITTLE_ENDIAN);
786           offset += 4;
787           proto_tree_add_item(slsk_tree, hf_slsk_average_speed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
788           offset += 4;
789           proto_tree_add_item(slsk_tree, hf_slsk_download_number, tvb, offset, 4, ENC_LITTLE_ENDIAN);
790           offset += 4;
791           proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
792           offset += 4;
793           proto_tree_add_item(slsk_tree, hf_slsk_files, tvb, offset, 4, ENC_LITTLE_ENDIAN);
794           offset += 4;
795           proto_tree_add_item(slsk_tree, hf_slsk_directories, tvb, offset, 4, ENC_LITTLE_ENDIAN);
796           offset += 4;
797           proto_tree_add_item(slsk_tree, hf_slsk_slotsfull, tvb, offset, 4, ENC_LITTLE_ENDIAN);
798           offset += 4;
799         }
800         else if (check_slsk_format(tvb, offset, "isbiib") || check_slsk_format(tvb, offset, "isbsiib")) {
801           /* Client-to-Client */
802           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
803                      "User Info Reply (Code: %02d)", msg_code);
804           offset += 4;
805           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_user_description, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
806           offset += str_len;
807           proto_tree_add_item(slsk_tree, hf_slsk_picture_exists, tvb, offset, 1, ENC_NA);
808           offset += 1;
809           if ( tvb_get_guint8(tvb, offset -1 ) == 1 ) {
810             proto_tree_add_item_ret_length(slsk_tree, hf_slsk_picture, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
811             offset += str_len;
812           }
813           proto_tree_add_item(slsk_tree, hf_slsk_total_uploads, tvb, offset, 4, ENC_LITTLE_ENDIAN);
814           offset += 4;
815           proto_tree_add_item(slsk_tree, hf_slsk_queued_uploads, tvb, offset, 4, ENC_LITTLE_ENDIAN);
816           offset += 4;
817           proto_tree_add_item(slsk_tree, hf_slsk_slots_available, tvb, offset, 1, ENC_NA);
818           offset += 1;
819         }
820       break;
821 
822       case 17:
823         if (check_slsk_format(tvb, offset, "iss")) {
824           /* Server-to-Client */
825           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
826                      "User Left Room (Code: %02d)", msg_code);
827           offset += 4;
828           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
829           offset += str_len;
830           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
831           offset += str_len;
832         }
833       break;
834 
835       case 18:
836         if (check_slsk_format(tvb, offset, "iiss")) {
837           /* Client-to-Server */
838           guint32 len;
839 
840           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
841                      "Connect To Peer (Code: %02d)", msg_code);
842           offset += 4;
843           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
844           offset += 4;
845           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
846           offset += str_len;
847           len = tvb_get_letohl(tvb, offset);
848           str = tvb_get_string_enc(pinfo->pool, tvb, offset+4, len, ENC_ASCII);
849           proto_tree_add_string_format_value(slsk_tree, hf_slsk_connection_type, tvb, offset, 4+len, str,
850             "%s (Char: %s)", connection_type(str),
851             format_text(pinfo->pool, str, len));
852           offset += 4+len;
853         }
854         else if (check_slsk_format(tvb, offset, "issiii")) {
855           /* Server-to-Client */
856           guint32 len;
857 
858           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
859                      "Connect To Peer (Code: %02d)", msg_code);
860           offset += 4;
861           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
862           offset += str_len;
863           len = tvb_get_letohl(tvb, offset);
864           str = tvb_get_string_enc(pinfo->pool, tvb, offset+4, len, ENC_ASCII);
865           proto_tree_add_string_format_value(slsk_tree, hf_slsk_connection_type, tvb, offset, 4+len, str,
866             "%s (Char: %s)", connection_type(str),
867             format_text(pinfo->pool, str, len));
868           offset += 4+len;
869           proto_tree_add_item(slsk_tree, hf_slsk_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
870           offset += 4;
871           proto_tree_add_item(slsk_tree, hf_slsk_port, tvb, offset, 4, ENC_LITTLE_ENDIAN);
872           offset += 4;
873           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
874           offset += 4;
875         }
876       break;
877 
878       case 22:
879         if (check_slsk_format(tvb, offset, "iss")) {
880           /* Client-to-Server */
881           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
882                      "Message User Send (Code: %02d)", msg_code);
883           offset += 4;
884           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
885           offset += str_len;
886           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_chat_message, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
887           offset += str_len;
888         }
889         else if (check_slsk_format(tvb, offset, "iiiss")) {
890           /* Server-to-Client */
891           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
892                      "Message User Receive (Code: %02d)", msg_code);
893           offset += 4;
894           proto_tree_add_item(slsk_tree, hf_slsk_chat_message_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
895           offset += 4;
896           proto_tree_add_item(slsk_tree, hf_slsk_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
897           offset += 4;
898           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
899           offset += str_len;
900           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_chat_message, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
901           offset += str_len;
902         }
903       break;
904 
905       case 23:
906         if (check_slsk_format(tvb, offset, "ii")) {
907           /* Client-to-Server */
908           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
909                      "Message User Receive Ack (Code: %02d)", msg_code);
910           offset += 4;
911           proto_tree_add_item(slsk_tree, hf_slsk_chat_message_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
912           offset += 4;
913         }
914       break;
915 
916       case 26:
917         if (check_slsk_format(tvb, offset, "iis")) {
918           /* Client-to-Server */
919           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
920                      "File Search (Code: %02d)", msg_code);
921           offset += 4;
922           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
923           offset += 4;
924           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_search_text, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
925           offset += str_len;
926         }
927       break;
928 
929       case 28:
930         if (check_slsk_format(tvb, offset, "ii")) {
931           /* Client-to-Server */
932           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
933                      "Set Status (Code: %02d)", msg_code);
934           offset += 4;
935           proto_tree_add_item(slsk_tree, hf_slsk_status_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
936           offset += 4;
937         }
938       break;
939 
940       case 32:
941         if (check_slsk_format(tvb, offset, "i")) {
942           /* Client-to-Server */
943           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
944                      "Ping (Code: %02d)", msg_code);
945           offset += 4;
946         }
947       break;
948 
949       case 34:
950         if (check_slsk_format(tvb, offset, "isi")) {
951           /* Client-to-Server */
952           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
953                      "Update Upload Speed (Code: %02d)", msg_code);
954           offset += 4;
955           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
956           offset += str_len;
957           proto_tree_add_item(slsk_tree, hf_slsk_average_speed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
958           offset += 4;
959         }
960       break;
961 
962       case 35:
963         if (check_slsk_format(tvb, offset, "iii")) {
964           /* Client-to-Server */
965           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
966                      "Shared Files & Folders (Code: %02d)", msg_code);
967           offset += 4;
968           proto_tree_add_item(slsk_tree, hf_slsk_folder_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
969           offset += 4;
970           proto_tree_add_item(slsk_tree, hf_slsk_file_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
971           offset += 4;
972         }
973       break;
974 
975       case 36:
976         if (check_slsk_format(tvb, offset, "isiiiii")) {
977           /* Server-to-Client */
978           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
979                      "Get User Stats Reply (Code: %02d)", msg_code);
980           offset += 4;
981           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
982           offset += str_len;
983           proto_tree_add_item(slsk_tree, hf_slsk_average_speed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
984           offset += 4;
985           proto_tree_add_item(slsk_tree, hf_slsk_download_number, tvb, offset, 4, ENC_LITTLE_ENDIAN);
986           offset += 4;
987           proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
988           offset += 4;
989           proto_tree_add_item(slsk_tree, hf_slsk_files, tvb, offset, 4, ENC_LITTLE_ENDIAN);
990           offset += 4;
991           proto_tree_add_item(slsk_tree, hf_slsk_directories, tvb, offset, 4, ENC_LITTLE_ENDIAN);
992           offset += 4;
993         }
994         else if (check_slsk_format(tvb, offset, "is")) {
995           /* Client-to-Client */
996           /* Client-to-Server: send after login successful */
997           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
998                      "Get User Stats (Code: %02d)", msg_code);
999           offset += 4;
1000           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1001           offset += str_len;
1002         }
1003         else if (check_slsk_format(tvb, offset, "iis")) {
1004           /* Client-to-Client */
1005           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1006                      "Folder Contents Request (Code: %02d)", msg_code);
1007           offset += 4;
1008           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1009           offset += 4;
1010           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_directory, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1011           offset += str_len;
1012         }
1013       break;
1014 
1015       case 37:
1016         if (check_slsk_format(tvb, offset, "i*")) {
1017           /* Client-to-Client */
1018           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1019                      "Folder Contents Response (Code: %02d)", msg_code);
1020           offset += 4;
1021 
1022           /* [zlib compressed] */
1023           comprlen = tvb_captured_length_remaining(tvb, offset);
1024 
1025           if (slsk_decompress == TRUE){
1026 
1027             tvbuff_t *uncompr_tvb = tvb_child_uncompress(tvb, tvb, offset, comprlen);
1028 
1029             if (uncompr_tvb == NULL) {
1030               proto_tree_add_expert(slsk_tree, pinfo, &ei_slsk_zlib_decompression_failed, tvb, offset, -1);
1031               offset += tvb_captured_length_remaining(tvb, offset);
1032             } else {
1033 
1034               proto_item *ti2 = proto_tree_add_item(slsk_tree, hf_slsk_compr_packet, tvb, offset, -1, ENC_NA);
1035               proto_tree *slsk_compr_packet_tree = proto_item_add_subtree(ti2, ett_slsk_compr_packet);
1036               proto_item_set_generated(ti2);
1037 
1038               ti = proto_tree_add_uint(slsk_tree, hf_slsk_compressed_packet_length, tvb, offset, 0, comprlen);
1039               proto_item_set_generated(ti);
1040               uncomprlen = tvb_captured_length_remaining(uncompr_tvb, 0);
1041               ti = proto_tree_add_uint(slsk_tree, hf_slsk_uncompressed_packet_length, tvb, offset, 0, uncomprlen);
1042               proto_item_set_generated(ti);
1043               add_new_data_source(pinfo, uncompr_tvb, "Uncompressed SoulSeek data");
1044 
1045               uncompr_tvb_offset = 0;
1046               if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "isi*")) {
1047                 guint32 len;
1048 
1049                 proto_tree_add_item(slsk_compr_packet_tree, hf_slsk_token, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
1050                 uncompr_tvb_offset += 4;
1051                 proto_tree_add_item_ret_length(slsk_compr_packet_tree, hf_slsk_directory_name, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &len);
1052                 uncompr_tvb_offset += len;
1053 
1054                 proto_tree_add_item_ret_int(slsk_compr_packet_tree, hf_slsk_num_directories, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j);
1055                 uncompr_tvb_offset += 4;
1056                 for (i = 0; i < j; i++) {
1057                   if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "si*")) {
1058                     start_offset = uncompr_tvb_offset;
1059                     subtree = proto_tree_add_subtree_format(slsk_compr_packet_tree, uncompr_tvb, uncompr_tvb_offset, 1, ett_slsk_directory, &ti_subtree, "Directory #%d", i+1);
1060                     proto_tree_add_item_ret_length(subtree, hf_slsk_directory_name, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1061                     uncompr_tvb_offset += str_len;
1062                     proto_tree_add_item_ret_int(subtree, hf_slsk_num_files, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j2);
1063                     uncompr_tvb_offset += 4;
1064                     for (i2 = 0; i2 < j2; i2++) {
1065                       if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "bsiisi*")) {
1066                         start_offset2 = uncompr_tvb_offset;
1067                         subtree2 = proto_tree_add_subtree_format(subtree, uncompr_tvb, uncompr_tvb_offset, 1, ett_slsk_file, &ti_subtree2, "File #%d", i2+1);
1068                         proto_tree_add_item(subtree2, hf_slsk_file_code, uncompr_tvb, uncompr_tvb_offset, 1, ENC_NA);
1069                         uncompr_tvb_offset += 1;
1070                         proto_tree_add_item_ret_length(subtree2, hf_slsk_filename, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1071                         uncompr_tvb_offset += str_len;
1072                         proto_tree_add_item(subtree2, hf_slsk_file_size1, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
1073                         uncompr_tvb_offset += 4;
1074                         proto_tree_add_item(subtree2, hf_slsk_file_size2, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
1075                         uncompr_tvb_offset += 4;
1076                         proto_tree_add_item_ret_length(subtree2, hf_slsk_filename_ext, uncompr_tvb, uncompr_tvb_offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1077                         uncompr_tvb_offset += str_len;
1078                         proto_tree_add_item_ret_int(subtree2, hf_slsk_file_num_attributes, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN, &j3);
1079                         uncompr_tvb_offset += 4;
1080                         for (i3 = 0; i3 < j3; i3++) {
1081                           if (check_slsk_format(uncompr_tvb, uncompr_tvb_offset, "ii*")) {
1082                             subtree3 = proto_tree_add_subtree_format(subtree2, uncompr_tvb, uncompr_tvb_offset, 8, ett_slsk_file_attribute, NULL, "Attribute #%d", i3+1);
1083                             proto_tree_add_item(subtree3, hf_slsk_file_attribute_type, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
1084                             uncompr_tvb_offset += 4;
1085                             proto_tree_add_item(subtree3, hf_slsk_file_attribute_value, uncompr_tvb, uncompr_tvb_offset, 4, ENC_LITTLE_ENDIAN);
1086                             uncompr_tvb_offset += 4;
1087                           } else {
1088                             break; /* invalid format */
1089                           }
1090                         }
1091                         proto_item_set_len(ti_subtree2, uncompr_tvb_offset-start_offset2);
1092                       } else {
1093                         break; /* invalid format */
1094                       }
1095                     }
1096                     proto_item_set_len(ti_subtree, uncompr_tvb_offset-start_offset);
1097                   } else {
1098                     break; /* invalid format */
1099                   }
1100                 }
1101               }
1102             }
1103           }else {
1104             ti = proto_tree_add_item(slsk_tree, hf_slsk_compr_packet, tvb, offset, -1, ENC_NA);
1105             proto_item_set_generated(ti);
1106             ti = proto_tree_add_uint(slsk_tree, hf_slsk_compressed_packet_length, tvb, offset, 0, comprlen);
1107             proto_item_set_generated(ti);
1108             offset += tvb_captured_length_remaining(tvb, offset);
1109           }
1110         }
1111       break;
1112 
1113       case 40:
1114         if (check_slsk_format(tvb, offset, "isi")) {
1115           /* Server-to-Client */
1116           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1117                      "Queued Downloads (Code: %02d)", msg_code);
1118           offset += 4;
1119           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1120           offset += str_len;
1121           proto_tree_add_item(slsk_tree, hf_slsk_slotsfull, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1122           offset += 4;
1123         }
1124         else if (check_slsk_format(tvb, offset, "iiis") || check_slsk_format(tvb, offset, "iiisii")) {
1125           /* Client-to-Client */
1126           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1127                      "Transfer Request (Code: %02d)", msg_code);
1128           offset += 4;
1129           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_transfer_direction, tvb, offset, 4, ENC_LITTLE_ENDIAN, &i);
1130           offset += 4;
1131           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1132           offset += 4;
1133           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1134           offset += str_len;
1135           if (i == 1){
1136             proto_tree_add_item(slsk_tree, hf_slsk_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1137             offset += 4;
1138             proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1139             offset += 4;
1140           }
1141         }
1142 
1143       break;
1144 
1145       case 41:
1146         if (check_slsk_format(tvb, offset, "iibs") || check_slsk_format(tvb, offset, "iibii") || check_slsk_format(tvb, offset, "iib")) {
1147           /* Client-to-Client */
1148           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1149                      "Transfer Response (Code: %02d)", msg_code);
1150           offset += 4;
1151           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1152           offset += 4;
1153           i = tvb_get_guint8(tvb, offset);
1154           proto_tree_add_item(slsk_tree, hf_slsk_allowed, tvb, offset, 1, ENC_NA);
1155           offset += 1;
1156           if ( i == 1 ) {
1157             if ( tvb_reported_length_remaining(tvb, offset) == 8 ) {
1158               proto_tree_add_item(slsk_tree, hf_slsk_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1159               offset += 4;
1160               proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1161               offset += 4;
1162             }
1163           } else {
1164             proto_tree_add_item_ret_length(slsk_tree, hf_slsk_string, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1165             offset += str_len;
1166           }
1167         }
1168       break;
1169 
1170       case 42:
1171         if (check_slsk_format(tvb, offset, "is")) {
1172           /* Client-to-Client */
1173           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1174                      "Placehold Upload (Code: %02d)", msg_code);
1175           offset += 4;
1176           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1177           offset += str_len;
1178         }
1179       break;
1180 
1181       case 43:
1182         if (check_slsk_format(tvb, offset, "is")) {
1183           /* Client-to-Client */
1184           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1185                      "Queue Upload (Code: %02d)", msg_code);
1186           offset += 4;
1187           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1188           offset += str_len;
1189         }
1190       break;
1191 
1192       case 44:
1193         if (check_slsk_format(tvb, offset, "isi")) {
1194           /* Client-to-Client */
1195           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1196                      "Place In Queue (Code: %02d)", msg_code);
1197           offset += 4;
1198           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1199           offset += str_len;
1200           proto_tree_add_item(slsk_tree, hf_slsk_place_in_queue, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1201           offset += 4;
1202         }
1203       break;
1204 
1205       case 46:
1206         if (check_slsk_format(tvb, offset, "is")) {
1207           /* Client-to-Client */
1208           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1209                      "Upload Failed (Code: %02d)", msg_code);
1210           offset += 4;
1211           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1212           offset += str_len;
1213         }
1214       break;
1215 
1216       case 50:
1217         if (check_slsk_format(tvb, offset, "is")) {
1218           /* Client-to-Server */
1219           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1220                      "Make Own Recommendation (Code: %02d)", msg_code);
1221           offset += 4;
1222           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1223           offset += str_len;
1224         }
1225         else if (check_slsk_format(tvb, offset, "isi")) {
1226           /* Client-to-Server */
1227           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1228                      "Remove Own Recommendation (Code: %02d)", msg_code);
1229           offset += 4;
1230           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1231           offset += str_len;
1232           proto_tree_add_item(slsk_tree, hf_slsk_ranking, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1233           offset += 4;
1234         }
1235         else if (check_slsk_format(tvb, offset, "iss")) {
1236           /* Client-to-Client */
1237           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1238                      "Queue Failed (Code: %02d)", msg_code);
1239           offset += 4;
1240           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1241           offset += str_len;
1242           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_string, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1243           offset += str_len;
1244         }
1245       break;
1246 
1247       case 51:
1248         if (check_slsk_format(tvb, offset, "is")) {
1249           /* Client-to-Server: "Add Things I like" */
1250           /* Client-to-Client:  "Place In Queue Request" */
1251           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1252                      "Add Things I like / Place In Queue Request (Code: %02d)", msg_code);
1253           offset += 4;
1254           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1255           offset += str_len;
1256         }
1257       break;
1258 
1259       case 52:
1260         if (check_slsk_format(tvb, offset, "is")) {
1261           /* Client-to-Server */
1262           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1263                      "Remove Things I like (Code: %02d)", msg_code);
1264           offset += 4;
1265           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1266           offset += str_len;
1267         }
1268       break;
1269 
1270       case 54:
1271         if (check_slsk_format(tvb, offset, "i")) {
1272           /* Client-to-Server */
1273           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1274                      "Get Recommendations (Code: %02d)", msg_code);
1275           offset += 4;
1276         }
1277         else if (check_slsk_format(tvb, offset, "ii*")) {
1278           /* Server-to-Client */
1279           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1280                      "Get Recommendations Reply (Code: %02d)", msg_code);
1281           offset += 4;
1282           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_recommendations, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1283           offset += 4;
1284           if (j > tvb_reported_length_remaining(tvb, offset))
1285             break;
1286           for (i = 0; i < j; i++) {
1287             if (check_slsk_format(tvb, offset, "si*")) {
1288               start_offset = offset;
1289               subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 1, ett_slsk_recommendation, &ti_subtree, "Recommendation #%d", i+1);
1290               proto_tree_add_item_ret_length(subtree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1291               offset += str_len;
1292               proto_tree_add_item(subtree, hf_slsk_ranking, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1293               offset += 4;
1294               proto_item_set_len(ti_subtree, offset-start_offset);
1295             } else {
1296               break; /* invalid format */
1297             }
1298           }
1299         }
1300       break;
1301 
1302       case 55:
1303         if (check_slsk_format(tvb, offset, "i")) {
1304           /* Client-to-Server */
1305           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1306                      "Type 55 (Code: %02d)", msg_code);
1307           offset += 4;
1308         }
1309       break;
1310 
1311       case 56:
1312         if (check_slsk_format(tvb, offset, "i")) {
1313           /* Client-to-Server */
1314           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1315                      "Get Global Rankings (Code: %02d)", msg_code);
1316           offset += 4;
1317         }
1318         else if (check_slsk_format(tvb, offset, "ii*")) {
1319           /* Server-to-Client */
1320           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1321                      "Get Global Rankings Reply (Code: %02d)", msg_code);
1322           offset += 4;
1323           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_recommendations, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1324           offset += 4;
1325           if (j > tvb_reported_length_remaining(tvb, offset))
1326             break;
1327           for (i = 0; i < j; i++) {
1328             if (check_slsk_format(tvb, offset, "si*")) {
1329               start_offset = offset;
1330               subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 1, ett_slsk_recommendation, &ti_subtree, "Recommendation #%d", i+1);
1331               proto_tree_add_item_ret_length(subtree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1332               offset += str_len;
1333               proto_tree_add_item(subtree, hf_slsk_ranking, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1334               offset += 4;
1335               proto_item_set_len(ti_subtree, offset-start_offset);
1336             } else {
1337               break; /* invalid format */
1338             }
1339           }
1340         }
1341       break;
1342 
1343       case 57:
1344         if (check_slsk_format(tvb, offset, "is")) {
1345           /* Client-to-Server */
1346           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1347                      "Get User Recommendations (Code: %02d)", msg_code);
1348           offset += 4;
1349           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1350           offset += str_len;
1351         }
1352         else if (check_slsk_format(tvb, offset, "isi*")) {
1353           /* Server-to-Client */
1354           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1355                      "Get User Recommendations Reply (Code: %02d)", msg_code);
1356           offset += 4;
1357           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1358           offset += str_len;
1359           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_recommendations, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1360           offset += 4;
1361           if (j > tvb_reported_length_remaining(tvb, offset))
1362             break;
1363           for (i = 0; i < j; i++) {
1364             if (check_slsk_format(tvb, offset, "s*")) {
1365               start_offset = offset;
1366               subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 1, ett_slsk_recommendation, &ti_subtree, "Recommendation #%d", i+1);
1367               proto_tree_add_item_ret_length(subtree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1368               offset += str_len;
1369               proto_item_set_len(ti_subtree, offset-start_offset);
1370             } else {
1371               break; /* invalid format */
1372             }
1373           }
1374         }
1375       break;
1376 
1377       case 58:
1378         if (check_slsk_format(tvb, offset, "isi*")) {
1379           /* Client-to-Server */
1380           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1381                      "Admin Command (Code: %02d)", msg_code);
1382           offset += 4;
1383           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_string, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1384           offset += str_len;
1385           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_strings, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1386           offset += 4;
1387           if (j > tvb_reported_length_remaining(tvb, offset))
1388             break;
1389           for (i = 0; i < j; i++) {
1390             if (check_slsk_format(tvb, offset, "s*")) {
1391               start_offset = offset;
1392               subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 1, ett_slsk_string, &ti_subtree, "String #%d", i+1);
1393               proto_tree_add_item_ret_length(subtree, hf_slsk_string, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1394               offset += str_len;
1395               proto_item_set_len(ti_subtree, offset-start_offset);
1396             } else {
1397               break; /* invalid format */
1398             }
1399           }
1400         }
1401       break;
1402 
1403       case 60:
1404         if (check_slsk_format(tvb, offset, "isii")) {
1405           /* Client-to-Server & Server-to-Client */
1406           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1407                      "Place In Line Response (Code: %02d)", msg_code);
1408           offset += 4;
1409           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1410           offset += str_len;
1411           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1412           offset += 4;
1413           proto_tree_add_item(slsk_tree, hf_slsk_place_in_queue, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1414           offset += 4;
1415         }
1416       break;
1417 
1418       case 62:
1419         if (check_slsk_format(tvb, offset, "is")) {
1420           /* Server-to-Client */
1421           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1422                      "Room Added (Code: %02d)", msg_code);
1423           offset += 4;
1424           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1425           offset += str_len;
1426         }
1427       break;
1428 
1429       case 63:
1430         if (check_slsk_format(tvb, offset, "is")) {
1431           /* Server-to-Client */
1432           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1433                      "Room Removed (Code: %02d)", msg_code);
1434           offset += 4;
1435           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1436           offset += str_len;
1437         }
1438       break;
1439 
1440       case 64:
1441         if (check_slsk_format(tvb, offset, "i")) {
1442           /* Client-to-Server */
1443           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1444                      "Room List Request (Code: %02d)", msg_code);
1445           offset += 4;
1446         }
1447         else if (check_slsk_format(tvb, offset, "ii*")) {
1448           /* Server-to-Client */
1449           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1450                      "Room List (Code: %02d)", msg_code);
1451           offset += 4;
1452           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_number_of_rooms, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1453           offset += 4;
1454           if (j > tvb_reported_length_remaining(tvb, offset))
1455             break;
1456           for (i = 0; i < j; i++) {
1457             if (check_slsk_format(tvb, offset, "s*")) {
1458               start_offset = offset;
1459               subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 1, ett_slsk_room, &ti_subtree, "Room #%d", i+1);
1460               proto_tree_add_item_ret_length(subtree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1461               offset += str_len;
1462               proto_item_set_len(ti_subtree, offset-start_offset);
1463             } else {
1464               break; /* invalid format */
1465             }
1466           }
1467           if (check_slsk_format(tvb, offset, "i*")) {
1468             proto_tree_add_item_ret_int(slsk_tree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1469             offset += 4;
1470             for (i = 0; i < j; i++) {
1471               if (check_slsk_format(tvb, offset, "i*")) {
1472                 subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 4, ett_slsk_room, &ti_subtree, "Room #%d", i+1);
1473                 proto_tree_add_item(subtree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1474                 offset += 4;
1475               } else {
1476                 break; /* invalid format */
1477               }
1478             }
1479           }
1480         }
1481       break;
1482 
1483       case 65:
1484         if (check_slsk_format(tvb, offset, "isissiii")) {
1485           /* Server-to-Client */
1486           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1487                      "Exact File Search (Code: %02d)", msg_code);
1488           offset += 4;
1489           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1490           offset += str_len;
1491           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1492           offset += 4;
1493           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1494           offset += str_len;
1495           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_directory, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1496           offset += str_len;
1497           proto_tree_add_item(slsk_tree, hf_slsk_bytes, tvb, offset, 16, ENC_NA);
1498           offset += 12;
1499         }
1500         else if (check_slsk_format(tvb, offset, "iissiiib")) {
1501           /* Client-to-Server */
1502           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1503                      "Exact File Search (Code: %02d)", msg_code);
1504           offset += 4;
1505           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1506           offset += 4;
1507           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_filename, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1508           offset += str_len;
1509           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_directory, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1510           offset += str_len;
1511           proto_tree_add_item(slsk_tree, hf_slsk_bytes, tvb, offset, 13, ENC_NA);
1512           offset += 13;
1513         }
1514       break;
1515 
1516       case 66:
1517         if (check_slsk_format(tvb, offset, "is")) {
1518           /* Server-to-Client */
1519           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1520                      "Admin Message (Code: %02d)", msg_code);
1521           offset += 4;
1522           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_chat_message, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1523           offset += str_len;
1524         }
1525       break;
1526 
1527       case 67:
1528         if (check_slsk_format(tvb, offset, "i")) {
1529           /* Client-to-Server */
1530           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1531                      "Global User List Request (Code: %02d)", msg_code);
1532           offset += 4;
1533         }
1534         else if (check_slsk_format(tvb, offset, "isi*")) {     /* same as case 14 */
1535           /* Server-to-Client */
1536           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1537                      "Global User List (Code: %02d)", msg_code);
1538           offset += 4;
1539           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_room, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1540           offset += str_len;
1541           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1542           offset += 4;
1543           if (j > tvb_reported_length_remaining(tvb, offset))
1544             break;
1545           for (i = 0; i < j; i++) {
1546             if (check_slsk_format(tvb, offset, "s*")) {
1547               proto_tree_add_item_ret_length(slsk_tree, hf_slsk_user, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1548               offset += str_len;
1549             } else {
1550               break; /* invalid format */
1551             }
1552           }
1553           if (check_slsk_format(tvb, offset, "i*")) {
1554             proto_tree_add_item_ret_int(slsk_tree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1555             offset += 4;
1556             for (i = 0; i < j; i++) {
1557               if (check_slsk_format(tvb, offset, "i*")) {
1558                 proto_tree_add_item(slsk_tree, hf_slsk_status_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1559                 offset += 4;
1560               } else {
1561                 break; /* invalid format */
1562               }
1563             }
1564           }
1565           if (check_slsk_format(tvb, offset, "i*")) {
1566             proto_tree_add_item_ret_int(slsk_tree, hf_slsk_users_in_room, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1567             offset += 4;
1568             if (j > tvb_reported_length_remaining(tvb, offset))
1569               break;
1570             for (i = 0; i < j; i++) {
1571               if (check_slsk_format(tvb, offset, "iiiii*")) {
1572                 subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 20, ett_slsk_user, NULL, "User #%d", i+1);
1573                 proto_tree_add_item(subtree, hf_slsk_average_speed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1574                 offset += 4;
1575                 proto_tree_add_item(subtree, hf_slsk_download_number, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1576                 offset += 4;
1577                 proto_tree_add_item(subtree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1578                 offset += 4;
1579                 proto_tree_add_item(subtree, hf_slsk_files, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1580                 offset += 4;
1581                 proto_tree_add_item(subtree, hf_slsk_directories, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1582                 offset += 4;
1583               } else {
1584                 break; /* invalid format */
1585               }
1586             }
1587           }
1588           if (check_slsk_format(tvb, offset, "i*")) {
1589             proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_slotsfull_records, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1590             offset += 4;
1591             if (j > tvb_reported_length_remaining(tvb, offset))
1592               break;
1593             for (i = 0; i < j; i++) {
1594               if (check_slsk_format(tvb, offset, "i*")) {
1595                 subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 4, ett_slsk_user, NULL, "User #%d", i+1);
1596                 proto_tree_add_item(subtree, hf_slsk_slotsfull, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1597                 offset += 4;
1598               } else {
1599                 break; /* invalid format */
1600               }
1601             }
1602           }
1603         }
1604       break;
1605 
1606       case 68:
1607         if (check_slsk_format(tvb, offset, "isiiiis")) {
1608           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1609                      "Tunneled Message (Code: %02d)", msg_code);
1610           offset += 4;
1611           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1612           offset += str_len;
1613           proto_tree_add_item(slsk_tree, hf_slsk_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1614           offset += 4;
1615           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1616           offset += 4;
1617           proto_tree_add_item(slsk_tree, hf_slsk_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1618           offset += 4;
1619           proto_tree_add_item(slsk_tree, hf_slsk_port, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1620           offset += 4;
1621           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_chat_message, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1622           offset += str_len;
1623         }
1624       break;
1625 
1626       case 69:
1627         if (check_slsk_format(tvb, offset, "i")) {
1628           /* Client-to-Server */
1629           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1630                      "Privileged User List Request (Code: %02d)", msg_code);
1631           offset += 4;
1632         }
1633         else if (check_slsk_format(tvb, offset, "ii*")) {
1634           /* Server-to-Client */
1635           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1636                      "Privileged User List (Code: %02d)", msg_code);
1637           offset += 4;
1638           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_number_of_priv_users, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1639           offset += 4;
1640           if (j > tvb_reported_length_remaining(tvb, offset))
1641             break;
1642           for (i = 0; i < j; i++) {
1643             if (check_slsk_format(tvb, offset, "s*")) {
1644               proto_tree_add_item_ret_length(slsk_tree, hf_slsk_user, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1645               offset += str_len;
1646             } else {
1647               break; /* invalid format */
1648             }
1649           }
1650         }
1651       break;
1652 
1653       case 71:
1654         if (check_slsk_format(tvb, offset, "ib")) {
1655           /* Client-to-Server */
1656           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1657                      "Get Parent List (Code: %02d)", msg_code);
1658           offset += 4;
1659           proto_tree_add_item(slsk_tree, hf_slsk_byte, tvb, offset, 1, ENC_NA);
1660           offset += 1;
1661         }
1662       break;
1663 
1664       case 73:
1665         if (check_slsk_format(tvb, offset, "ii")) {
1666           /* Client-to-Server */
1667           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1668                      "Type 73 (Code: %02d)", msg_code);
1669           offset += 4;
1670           proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1671           offset += 4;
1672         }
1673       break;
1674 
1675       case 83:
1676         if (check_slsk_format(tvb, offset, "ii")) {
1677           /* Server-to-Client */
1678           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1679                      "Parent Min Speed (Code: %02d)", msg_code);
1680           offset += 4;
1681           proto_tree_add_item(slsk_tree, hf_slsk_parent_min_speed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1682           offset += 4;
1683         }
1684       break;
1685 
1686       case 84:
1687         if (check_slsk_format(tvb, offset, "ii")) {
1688           /* Server-to-Client */
1689           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1690                      "Parent Speed Connection Ratio (Code: %02d)", msg_code);
1691           offset += 4;
1692           proto_tree_add_item(slsk_tree, hf_slsk_parent_speed_connection_ratio, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1693           offset += 4;
1694         }
1695       break;
1696 
1697       case 86:
1698         if (check_slsk_format(tvb, offset, "ii")) {
1699           /* Server-to-Client */
1700           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1701                      "Parent Inactivity Before Disconnect (Code: %02d)", msg_code);
1702           offset += 4;
1703           proto_tree_add_item(slsk_tree, hf_slsk_seconds_parent_inactivity_before_disconnect, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1704           offset += 4;
1705         }
1706       break;
1707 
1708       case 87:
1709         if (check_slsk_format(tvb, offset, "ii")) {
1710           /* Server-to-Client */
1711           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1712                      "Server Inactivity Before Disconnect (Code: %02d)", msg_code);
1713           offset += 4;
1714           proto_tree_add_item(slsk_tree, hf_slsk_seconds_server_inactivity_before_disconnect, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1715           offset += 4;
1716         }
1717       break;
1718 
1719       case 88:
1720         if (check_slsk_format(tvb, offset, "ii")) {
1721           /* Server-to-Client */
1722           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1723                      "Nodes In Cache Before Disconnect (Code: %02d)", msg_code);
1724           offset += 4;
1725           proto_tree_add_item(slsk_tree, hf_slsk_nodes_in_cache_before_disconnect, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1726           offset += 4;
1727         }
1728       break;
1729 
1730       case 90:
1731         if (check_slsk_format(tvb, offset, "ii")) {
1732           /* Server-to-Client */
1733           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1734                      "Seconds Before Ping Children (Code: %02d)", msg_code);
1735           offset += 4;
1736           proto_tree_add_item(slsk_tree, hf_slsk_seconds_before_ping_children, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1737           offset += 4;
1738         }
1739       break;
1740 
1741       case 91:
1742         if (check_slsk_format(tvb, offset, "is")) {
1743           /* Server-to-Client */
1744           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1745                      "Add To Privileged (Code: %02d)", msg_code);
1746           offset += 4;
1747           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1748           offset += str_len;
1749         }
1750       break;
1751 
1752       case 92:
1753         if (check_slsk_format(tvb, offset, "i")) {
1754           /* Client-to-Server */
1755           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1756                      "Check Privileges (Code: %02d)", msg_code);
1757           offset += 4;
1758         }
1759         else if (check_slsk_format(tvb, offset, "ii")) {
1760           /* Server-to-Client */
1761           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1762                      "Check Privileges Reply (Code: %02d)", msg_code);
1763           offset += 4;
1764           proto_tree_add_item(slsk_tree, hf_slsk_number_of_days, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1765           offset += 4;
1766         }
1767       break;
1768 
1769       case 93:
1770         if (check_slsk_format(tvb, offset, "ibisis")) {
1771           /* Server-to-Client */
1772           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1773                      "Embedded Message (Code: %02d)", msg_code);
1774           offset += 4;
1775           if ( tvb_get_guint8(tvb, offset) == 3 ){
1776             /* Client-to-Client */
1777             proto_tree_add_uint_format_value(slsk_tree, hf_slsk_embedded_message_type, tvb, offset, 1, msg_code,
1778                        "Distributed Search (Byte: %d)", 3);
1779             offset += 1;
1780             proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1781             offset += 4;
1782             proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1783             offset += str_len;
1784             proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1785             offset += 4;
1786             proto_tree_add_item_ret_length(slsk_tree, hf_slsk_search_text, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1787             offset += str_len;
1788           }
1789         }
1790       break;
1791 
1792       case 100:
1793         if (check_slsk_format(tvb, offset, "ib")) {
1794           /* Client-to-Server */
1795           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1796                      "Become Parent (Code: %02d)", msg_code);
1797           offset += 4;
1798           proto_tree_add_item(slsk_tree, hf_slsk_byte, tvb, offset, 1, ENC_NA);
1799           offset += 1;
1800         }
1801       break;
1802 
1803       case 102:
1804         if (check_slsk_format(tvb, offset, "ii*")) {
1805           /* Server-to-Client */
1806           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1807                      "Random Parent Addresses (Code: %02d)", msg_code);
1808           offset += 4;
1809           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_parent_address, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1810           offset += 4;
1811           if (j > tvb_reported_length_remaining(tvb, offset))
1812             break;
1813           for (i = 0; i < j; i++) {
1814             if (check_slsk_format(tvb, offset, "sii*")) {
1815 
1816               proto_tree_add_item_ret_length(slsk_tree, hf_slsk_user, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1817               offset += str_len;
1818               proto_tree_add_item(slsk_tree, hf_slsk_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1819               offset += 4;
1820               proto_tree_add_item(slsk_tree, hf_slsk_port, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1821               offset += 4;
1822             } else {
1823               break; /* invalid format */
1824             }
1825           }
1826         }
1827       break;
1828 
1829       case 103:
1830         if (check_slsk_format(tvb, offset, "iis")) {
1831           /* Server-to-Client */
1832           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1833                      "Send Wishlist Entry (Code: %02d)", msg_code);
1834           offset += 4;
1835           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1836           offset += 4;
1837           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_search_text, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1838           offset += str_len;
1839         }
1840       break;
1841 
1842       case 104:
1843         if (check_slsk_format(tvb, offset, "ii")) {
1844           /* Server-to-Client */
1845           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1846                      "Type 104 (Code: %02d)", msg_code);
1847           offset += 4;
1848           proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1849           offset += 4;
1850         }
1851       break;
1852 
1853       case 110:
1854         if (check_slsk_format(tvb, offset, "i")) {
1855           /* Client-to-Server */
1856           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1857                      "Get Similar Users (Code: %02d)", msg_code);
1858           offset += 4;
1859         }
1860         else if (check_slsk_format(tvb, offset, "ii*")) {
1861           /* Server-to-Client */
1862           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1863                      "Get Similar Users Reply (Code: %02d)", msg_code);
1864           offset += 4;
1865           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_number_of_users, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1866           offset += 4;
1867           if (j > tvb_reported_length_remaining(tvb, offset))
1868             break;
1869           for (i = 0; i < j; i++) {
1870             if (check_slsk_format(tvb, offset, "si*")) {
1871               start_offset = offset;
1872               subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 4, ett_slsk_user, &ti_subtree, "User #%d", i+1);
1873               proto_tree_add_item_ret_length(subtree, hf_slsk_user, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1874               offset += str_len;
1875               proto_tree_add_item(subtree, hf_slsk_same_recommendation, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1876               offset += 4;
1877               proto_item_set_len(ti_subtree, offset-start_offset);
1878             } else {
1879               break; /* invalid format */
1880             }
1881           }
1882         }
1883       break;
1884 
1885       case 111:
1886         if (check_slsk_format(tvb, offset, "is")) {
1887           /* Client-to-Server */
1888           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1889                      "Get Recommendations for Item (Code: %02d)", msg_code);
1890           offset += 4;
1891           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1892           offset += str_len;
1893         }
1894         else if (check_slsk_format(tvb, offset, "isi*")) {
1895           /* Server-to-Client */
1896           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1897                      "Get Recommendations for Item Reply (Code: %02d)", msg_code);
1898           offset += 4;
1899           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1900           offset += str_len;
1901           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_recommendations, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1902           offset += 4;
1903           if (j > tvb_reported_length_remaining(tvb, offset))
1904             break;
1905           for (i = 0; i < j; i++) {
1906             if (check_slsk_format(tvb, offset, "si*")) {
1907               start_offset = offset;
1908               subtree = proto_tree_add_subtree_format(slsk_tree, tvb, offset, 1, ett_slsk_recommendation, &ti_subtree, "Recommendation #%d", i+1);
1909               proto_tree_add_item_ret_length(subtree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1910               offset += str_len;
1911               proto_tree_add_item(subtree, hf_slsk_ranking, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1912               offset += 4;
1913               proto_item_set_len(ti_subtree, offset-start_offset);
1914             } else {
1915               break; /* invalid format */
1916             }
1917           }
1918         }
1919       break;
1920 
1921       case 112:
1922         if (check_slsk_format(tvb, offset, "is")) {
1923           /* Client-to-Server */
1924           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1925                      "Get Similar Users for Item (Code: %02d)", msg_code);
1926           offset += 4;
1927           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1928           offset += str_len;
1929         }
1930         else if (check_slsk_format(tvb, offset, "isi*")) {
1931           /* Server-to-Client */
1932           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1933                      "Get Similar Users for Item Reply (Code: %02d)", msg_code);
1934           offset += 4;
1935           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_recommendation, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1936           offset += str_len;
1937           proto_tree_add_item_ret_int(slsk_tree, hf_slsk_num_recommendations, tvb, offset, 4, ENC_LITTLE_ENDIAN, &j);
1938           offset += 4;
1939           if (j > tvb_reported_length_remaining(tvb, offset))
1940             break;
1941           for (i = 0; i < j; i++) {
1942             if (check_slsk_format(tvb, offset, "s*")) {
1943               proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1944               offset += str_len;
1945             } else {
1946               break; /* invalid format */
1947             }
1948           }
1949         }
1950       break;
1951 
1952       case 1001:
1953         if (check_slsk_format(tvb, offset, "iis")) {
1954           /* Client-to-Server */
1955           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1956                      "Can't Connect To Peer (Code: %02d)", msg_code);
1957           offset += 4;
1958           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1959           offset += 4;
1960           proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1961           offset += str_len;
1962         }
1963         else if (check_slsk_format(tvb, offset, "ii")) {
1964           /* Server-to-Client */
1965           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
1966                      "Can't Connect To Peer (Code: %02d)", msg_code);
1967           offset += 4;
1968           proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1969           offset += 4;
1970         }
1971       break;
1972 
1973       default:
1974         if (check_slsk_format(tvb, offset, "bisis")) {
1975           if ( tvb_get_guint8(tvb, offset) == 3 ){
1976             /* Client-to-Client */
1977             proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 1, msg_code,
1978                        "Distributed Search (Byte: %d)", 3);
1979             offset += 1;
1980             proto_tree_add_item(slsk_tree, hf_slsk_integer, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1981             offset += 4;
1982             proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1983             offset += str_len;
1984             proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1985             offset += 4;
1986             proto_tree_add_item_ret_length(slsk_tree, hf_slsk_search_text, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1987             offset += str_len;
1988           }
1989         }
1990         else if (check_slsk_format(tvb, offset, "bssi")) {
1991           if ( tvb_get_guint8(tvb, offset) == 1 ){
1992             /* Client-to-Client */
1993             guint32 len;
1994 
1995             proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 1, msg_code,
1996                        "Peer Init (Byte: %d)", 1);
1997             offset += 1;
1998             proto_tree_add_item_ret_length(slsk_tree, hf_slsk_username, tvb, offset, 4, ENC_ASCII|ENC_LITTLE_ENDIAN, &str_len);
1999             offset += str_len;
2000             len = tvb_get_letohl(tvb, offset);
2001             str = tvb_get_string_enc(pinfo->pool, tvb, offset+4, len, ENC_ASCII);
2002             proto_tree_add_string_format_value(slsk_tree, hf_slsk_connection_type, tvb, offset, 4+len, str,
2003               "%s (Char: %s)", connection_type(str),
2004               format_text(pinfo->pool, str, len));
2005             offset += 4+len;
2006             proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2007             offset += 4;
2008           }
2009         }
2010         else if (check_slsk_format(tvb, offset, "bi")) {
2011           if ( tvb_get_guint8(tvb, offset) == 0 ){
2012             /* Client-to-Client */
2013             proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 1, msg_code,
2014                        "Pierce Fw (Byte: %d)", 0);
2015             offset += 1;
2016             proto_tree_add_item(slsk_tree, hf_slsk_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2017             offset += 4;
2018           }
2019         }
2020         else {
2021           proto_tree_add_uint_format_value(slsk_tree, hf_slsk_message_code, tvb, offset, 4, msg_code,
2022                      "Unknown (Code: %02d)", msg_code);
2023           offset += 4;
2024         }
2025       break;
2026 
2027     }
2028 
2029   if(offset < (int)msg_len){
2030    expert_add_info(pinfo, ti_len, &ei_slsk_unknown_data);
2031   }
2032 
2033   return tvb_captured_length(tvb);
2034 }
2035 
2036 
2037 static int dissect_slsk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
2038 {
2039   tcp_dissect_pdus(tvb, pinfo, tree, slsk_desegment, 4, get_slsk_pdu_len, dissect_slsk_pdu, data);
2040   return tvb_captured_length(tvb);
2041 }
2042 
2043 
2044 /* Register the protocol with Wireshark */
2045 
2046 void
2047 proto_register_slsk(void)
2048 {
2049 
2050 /* Setup list of header fields  */
2051   static hf_register_info hf[] = {
2052     { &hf_slsk_integer,
2053       { "Integer", "slsk.integer",
2054       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2055     { &hf_slsk_string,
2056       { "String", "slsk.string",
2057       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2058     { &hf_slsk_byte,
2059       { "Byte", "slsk.byte",
2060       FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
2061     { &hf_slsk_message_length,
2062       { "Message Length", "slsk.message.length",
2063       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2064     { &hf_slsk_message_code,
2065       { "Message Type", "slsk.message.code",
2066       FT_UINT32, BASE_DEC, NULL, 0, "Message Code with type string", HFILL } },
2067     { &hf_slsk_embedded_message_type,
2068       { "Embedded Message Type", "slsk.embedded_message.code",
2069       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2070     { &hf_slsk_client_ip,
2071       { "Client IP", "slsk.client.ip",
2072       FT_IPv4, BASE_NONE, NULL, 0, "Client IP Address", HFILL } },
2073 #if 0
2074     { &hf_slsk_server_ip,
2075       { "SoulSeek Server IP", "slsk.server.ip",
2076       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2077 #endif
2078     { &hf_slsk_directory_name,
2079       { "Directory name", "slsk.directory_name",
2080       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2081     { &hf_slsk_username,
2082       { "Username", "slsk.username",
2083       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2084     { &hf_slsk_password,
2085       { "Password", "slsk.password",
2086       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2087     { &hf_slsk_version,
2088       { "Version", "slsk.version",
2089       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2090     { &hf_slsk_login_successful,
2091       { "Login successful", "slsk.login.successful",
2092       FT_UINT8, BASE_DEC, VALS(slsk_yes_no), 0, NULL, HFILL } },
2093     { &hf_slsk_login_message,
2094       { "Login Message", "slsk.login.message",
2095       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2096     { &hf_slsk_port,
2097       { "Port Number", "slsk.port.number",
2098       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2099     { &hf_slsk_ip,
2100       { "IP Address", "slsk.ip.address",
2101       FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL } },
2102     { &hf_slsk_user_exists,
2103       { "User exists", "slsk.user.exists",
2104       FT_UINT8, BASE_DEC, VALS(slsk_yes_no), 0, NULL, HFILL } },
2105     { &hf_slsk_status_code,
2106       { "Status Code", "slsk.status.code",
2107       FT_UINT32, BASE_DEC, VALS(slsk_status_codes), 0, NULL, HFILL } },
2108     { &hf_slsk_room,
2109       { "Room", "slsk.room",
2110       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2111     { &hf_slsk_chat_message,
2112       { "Chat Message", "slsk.chat.message",
2113       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2114     { &hf_slsk_users_in_room,
2115       { "Users in Room", "slsk.room.users",
2116       FT_INT32, BASE_DEC, NULL, 0, "Number of Users in Room", HFILL } },
2117     { &hf_slsk_token,
2118       { "Token", "slsk.token",
2119       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2120     { &hf_slsk_connection_type,
2121       { "Connection Type", "slsk.connection.type",
2122       FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2123     { &hf_slsk_chat_message_id,
2124       { "Chat Message ID", "slsk.chat.message.id",
2125       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2126     { &hf_slsk_timestamp,
2127       { "Timestamp", "slsk.timestamp",
2128       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2129     { &hf_slsk_search_text,
2130       { "Search Text", "slsk.search.text",
2131       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2132     { &hf_slsk_folder_count,
2133       { "Folder Count", "slsk.folder.count",
2134       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2135     { &hf_slsk_file_count,
2136       { "File Count", "slsk.file.count",
2137       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2138     { &hf_slsk_average_speed,
2139       { "Average Speed", "slsk.average.speed",
2140       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2141     { &hf_slsk_download_number,
2142       { "Download Number", "slsk.download.number",
2143       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2144     { &hf_slsk_files,
2145       { "Files", "slsk.files",
2146       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2147     { &hf_slsk_directories,
2148       { "Directories", "slsk.directories",
2149       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2150     { &hf_slsk_slotsfull,
2151       { "Slots full", "slsk.slots.full",
2152       FT_UINT32, BASE_DEC, NULL, 0, "Upload Slots Full", HFILL } },
2153     { &hf_slsk_place_in_queue,
2154       { "Place in Queue", "slsk.queue.place",
2155       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2156     { &hf_slsk_number_of_rooms,
2157       { "Number of Rooms", "slsk.room.count",
2158       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2159     { &hf_slsk_filename,
2160       { "Filename", "slsk.filename",
2161       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2162     { &hf_slsk_filename_ext,
2163       { "Filename ext", "slsk.filename_ext",
2164       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2165     { &hf_slsk_directory,
2166       { "Directory", "slsk.directory",
2167       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2168     { &hf_slsk_size,
2169       { "Size", "slsk.size",
2170       FT_UINT32, BASE_DEC, NULL, 0, "File Size", HFILL } },
2171 #if 0
2172     { &hf_slsk_checksum,
2173       { "Checksum", "slsk.checksum",
2174       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2175 #endif
2176     { &hf_slsk_code,
2177       { "Code", "slsk.code",
2178       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2179     { &hf_slsk_number_of_users,
2180       { "Number of Users", "slsk.user.count",
2181       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2182     { &hf_slsk_number_of_days,
2183       { "Number of Days", "slsk.day.count",
2184       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2185     { &hf_slsk_transfer_direction,
2186       { "Transfer Direction", "slsk.transfer.direction",
2187       FT_INT32, BASE_DEC, VALS(slsk_transfer_direction), 0, NULL, HFILL } },
2188     { &hf_slsk_user_description,
2189       { "User Description", "slsk.user.description",
2190       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2191     { &hf_slsk_picture_exists,
2192       { "Picture exists", "slsk.user.picture.exists",
2193       FT_UINT8, BASE_DEC, VALS(slsk_yes_no), 0, "User has a picture", HFILL } },
2194     { &hf_slsk_picture,
2195       { "User Picture", "slsk.user.picture",
2196       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2197 #if 0
2198     { &hf_slsk_user_uploads,
2199       { "User uploads", "slsk.uploads.user",
2200       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2201 #endif
2202     { &hf_slsk_total_uploads,
2203       { "Total uploads allowed", "slsk.uploads.total",
2204       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2205     { &hf_slsk_queued_uploads,
2206       { "Queued uploads", "slsk.uploads.queued",
2207       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2208     { &hf_slsk_slots_available,
2209       { "Upload Slots available", "slsk.uploads.available",
2210       FT_UINT8, BASE_DEC, VALS(slsk_yes_no), 0, NULL, HFILL } },
2211     { &hf_slsk_allowed,
2212       { "Download allowed", "slsk.user.allowed",
2213       FT_UINT8, BASE_DEC, VALS(slsk_yes_no), 0, NULL, HFILL } },
2214     { &hf_slsk_compr_packet,
2215       { "zlib compressed packet", "slsk.compr.packet",
2216       FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } },
2217     { &hf_slsk_parent_min_speed,
2218       { "Parent Min Speed", "slsk.parent.min.speed",
2219       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2220     { &hf_slsk_parent_speed_connection_ratio,
2221       { "Parent Speed Connection Ratio", "slsk.parent.speed.connection.ratio",
2222       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2223     { &hf_slsk_seconds_parent_inactivity_before_disconnect,
2224       { "Seconds Parent Inactivity Before Disconnect", "slsk.seconds.parent.inactivity.before.disconnect",
2225       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2226     { &hf_slsk_seconds_server_inactivity_before_disconnect,
2227       { "Seconds Server Inactivity Before Disconnect", "slsk.seconds.server.inactivity.before.disconnect",
2228       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2229     { &hf_slsk_nodes_in_cache_before_disconnect,
2230       { "Nodes In Cache Before Disconnect", "slsk.nodes.in.cache.before.disconnect",
2231       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2232     { &hf_slsk_seconds_before_ping_children,
2233       { "Seconds Before Ping Children", "slsk.seconds.before.ping.children",
2234       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2235     { &hf_slsk_recommendation,
2236       { "Recommendation", "slsk.recommendation",
2237       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2238     { &hf_slsk_user,
2239       { "User", "slsk.user",
2240       FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
2241     { &hf_slsk_ranking,
2242       { "Ranking", "slsk.ranking",
2243       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2244     { &hf_slsk_compressed_packet_length,
2245       { "Compressed packet length", "slsk.compressed_packet_length",
2246       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2247     { &hf_slsk_uncompressed_packet_length,
2248       { "Uncompressed packet length", "slsk.uncompressed_packet_length",
2249       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2250     { &hf_slsk_num_directories,
2251       { "Number of directories", "slsk.num_directories",
2252       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2253     { &hf_slsk_upload_speed,
2254       { "Upload speed", "slsk.upload_speed",
2255       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2256     { &hf_slsk_in_queue,
2257       { "In Queue", "slsk.in_queue",
2258       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2259     { &hf_slsk_num_slotsfull_records,
2260       { "Number of Slotsfull Records", "slsk.num_slotsfull_records",
2261       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2262     { &hf_slsk_num_recommendations,
2263       { "Number of Recommendations", "slsk.num_recommendations",
2264       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2265     { &hf_slsk_num_files,
2266       { "Number of Files", "slsk.num_files",
2267       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2268     { &hf_slsk_num_strings,
2269       { "Number of strings", "slsk.num_strings",
2270       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2271     { &hf_slsk_file_code,
2272       { "Code", "slsk.file_code",
2273       FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
2274     { &hf_slsk_file_size1,
2275       { "Size1", "slsk.file_size1",
2276       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2277     { &hf_slsk_file_size2,
2278       { "Size2", "slsk.file_size2",
2279       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2280     { &hf_slsk_file_num_attributes,
2281       { "Number of attributes", "slsk.file_num_attributes",
2282       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2283     { &hf_slsk_file_attribute_type,
2284       { "File attribute type", "slsk.file_attribute_type",
2285       FT_UINT32, BASE_DEC, VALS(slsk_attr_type), 0, NULL, HFILL } },
2286     { &hf_slsk_file_attribute_value,
2287       { "File attribute value", "slsk.file_attribute_value",
2288       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2289     { &hf_slsk_free_upload_slots,
2290       { "Free upload slots", "slsk.free_upload_slots",
2291       FT_UINT32, BASE_DEC, VALS(slsk_yes_no), 0, NULL, HFILL } },
2292     { &hf_slsk_bytes,
2293       { "Bytes", "slsk.bytes",
2294       FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
2295     { &hf_slsk_same_recommendation,
2296       { "Same Recommendation", "slsk.same_recommendation",
2297       FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2298     { &hf_slsk_number_of_priv_users,
2299       { "Number of Privileged Users", "slsk.priv_user.count",
2300       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2301     { &hf_slsk_num_parent_address,
2302       { "Number of Parent Addresses", "slsk.parent_addr.count",
2303       FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2304 
2305   };
2306 
2307 /* Setup protocol subtree array */
2308   static gint *ett[] = {
2309     &ett_slsk,
2310     &ett_slsk_compr_packet,
2311     &ett_slsk_directory,
2312     &ett_slsk_file,
2313     &ett_slsk_file_attribute,
2314     &ett_slsk_user,
2315     &ett_slsk_recommendation,
2316     &ett_slsk_room,
2317     &ett_slsk_string,
2318   };
2319 
2320   static ei_register_info ei[] = {
2321      { &ei_slsk_unknown_data, { "slsk.unknown_data", PI_UNDECODED, PI_WARN, "Unknown Data (not interpreted)", EXPFILL }},
2322      { &ei_slsk_zlib_decompression_failed, { "slsk.zlib_decompression_failed", PI_PROTOCOL, PI_WARN, "zlib compressed packet failed to decompress", EXPFILL }},
2323      { &ei_slsk_decompression_failed, { "slsk.decompression_failed", PI_PROTOCOL, PI_WARN, "decompression failed", EXPFILL }},
2324   };
2325 
2326   module_t *slsk_module;
2327   expert_module_t* expert_slsk;
2328 
2329 /* Registers the protocol name and description */
2330   proto_slsk = proto_register_protocol("SoulSeek Protocol", "SoulSeek", "slsk");
2331 
2332 /* Required function calls to register the header fields and subtrees used */
2333   proto_register_field_array(proto_slsk, hf, array_length(hf));
2334   proto_register_subtree_array(ett, array_length(ett));
2335   expert_slsk = expert_register_protocol(proto_slsk);
2336   expert_register_field_array(expert_slsk, ei, array_length(ei));
2337 
2338   slsk_module = prefs_register_protocol(proto_slsk, NULL);
2339 
2340 /* Registers the options in the menu preferences */
2341   prefs_register_bool_preference(slsk_module, "desegment",
2342       "Reassemble SoulSeek messages spanning multiple TCP segments",
2343       "Whether the SoulSeek dissector should reassemble messages spanning multiple TCP segments."
2344       " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2345       &slsk_desegment);
2346 #ifdef HAVE_ZLIB
2347   prefs_register_bool_preference(slsk_module, "decompress",
2348       "Decompress zlib compressed packets inside SoulSeek messages",
2349       "Whether the SoulSeek dissector should decompress all zlib compressed packets inside messages",
2350       &slsk_decompress);
2351 #endif
2352 
2353 }
2354 
2355 
2356 void
2357 proto_reg_handoff_slsk(void)
2358 {
2359   dissector_handle_t slsk_handle;
2360 
2361   slsk_handle = create_dissector_handle(dissect_slsk, proto_slsk);
2362   dissector_add_uint_range_with_preference("tcp.port", SLSK_TCP_PORT_RANGE, slsk_handle);
2363 }
2364 
2365 /*
2366  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2367  *
2368  * Local Variables:
2369  * c-basic-offset: 2
2370  * tab-width: 8
2371  * indent-tabs-mode: nil
2372  * End:
2373  *
2374  * ex: set shiftwidth=2 tabstop=8 expandtab:
2375  * :indentSize=2:tabSize=8:noTabs=true:
2376  */
2377