Ethereal-dev: [ethereal-dev] Packet-icq.c update

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Kojak <kojak@xxxxxxxxxx>
Date: Thu, 04 Nov 1999 22:57:17 +0100
Hi,

I've updated and extended the ICQ decoder a lot further. Included in
this message is the diff, I hope it can be applied...

Grtz
--
Kojak

Index: packet-icq.c
===================================================================
RCS file: /cvsroot/ethereal/packet-icq.c,v
retrieving revision 1.4
diff -c -r1.4 packet-icq.c
*** packet-icq.c	1999/11/03 06:21:35	1.4
--- packet-icq.c	1999/11/04 21:51:43
***************
*** 74,80 ****
--- 74,95 ----
  int hf_icq_sessionid =-1;
  int hf_icq_checkcode =-1;
  int hf_icq_decode = -1;
+ int hf_icq_type = -1;
  
+ enum { ICQ5_client, ICQ5_server};
+ 
+ void dissect_icqv5(const u_char *pd,
+ 		   int offset,
+ 		   frame_data *fd,
+ 		   proto_tree *tree);
+ 
+ static void
+ dissect_icqv5Server(const u_char *pd,
+ 		    int offset,
+ 		    frame_data *fd,
+ 		    proto_tree *tree,
+ 		    guint32 pktsize);
+ 
  /* Offsets of fields in the ICQ headers */
  /* Can be 0x0002 or 0x0005 */
  #define ICQ_VERSION		0x00
***************
*** 105,124 ****
      int code;
  } cmdcode;
  
  cmdcode serverCmdCode[] = {
!     { "SRV_ACK", 10 },
!     { "SRV_GO_AWAY", 40 },
!     { "SRV_NEW_UIN", 70 },
!     { "SRV_LOGIN_REPLY", 90 },
!     { "SRV_BAD_PASS", 100 },
!     { "SRV_USER_ONLINE", 110 },
!     { "SRV_USER_OFFLINE", 120 },
      { "SRV_QUERY", 130 },
      { "SRV_USER_FOUND", 140 },
      { "SRV_END_OF_SEARCH", 160 },
      { "SRV_NEW_USER", 180 },
      { "SRV_UPDATE_EXT", 200 },
!     { "SRV_RECV_MESSAGE", 220 },
      { "SRV_X2", 230 },
      { "SRV_NOT_CONNECTED", 240 },
      { "SRV_TRY_AGAIN", 250 },
--- 120,199 ----
      int code;
  } cmdcode;
  
+ #define SRV_ACK			0x000a
+ 
+ #define SRV_GO_AWAY		0x0028
+ 
+ #define SRV_NEW_UIN		0x0046
+ 
+ /* LOGIN_REPLY is very scary. It has a lot of fields that are undocumented
+  * Only the IP field makes sense */
+ #define SRV_LOGIN_REPLY		0x005a
+ #define SRV_LOGIN_REPLY_IP	0x000c
+ 
+ #define SRV_BAD_PASS		0x0064
+ 
+ #define SRV_USER_ONLINE		0x006e
+ #define SRV_USER_ONL_UIN	0x0000
+ #define SRV_USER_ONL_IP		0x0004
+ #define SRV_USER_ONL_PORT	0x0008
+ #define SRV_USER_ONL_REALIP	0x000c
+ #define SRV_USER_ONL_X1		0x0010
+ #define SRV_USER_ONL_STATUS	0x0011
+ #define SRV_USER_ONL_X2		0x0015
+ 
+ #define SRV_USER_OFFLINE	0x0078
+ #define SRV_USER_OFFLINE_UIN	0x0000
+ 
+ #define SRV_MULTI		0x0212
+ #define SRV_MULTI_NUM		0x0000
+ 
+ #define SRV_META_USER		0x03de
+ #define SRV_META_USER_SUBCMD	0x0000
+ #define SRV_META_USER_RESULT	0x0002
+ #define SRV_META_USER_DATA	0x0003
+ 
+ #define SRV_UPDATE_SUCCESS	0x01e0
+ 
+ #define SRV_UPDATE_FAIL		0x01ea
+ 
+ /*
+  * ICQv5 SRV_META_USER subcommands
+  */
+ #define META_USER_FOUND		0x019a
+ #define META_ABOUT		0x00e6
+ #define META_USER_INFO		0x00c8
+ 
+ #define SRV_RECV_MESSAGE	0x00dc
+ #define SRV_RECV_MSG_UIN	0x0000
+ #define SRV_RECV_MSG_YEAR	0x0004
+ #define SRV_RECV_MSG_MONTH	0x0006
+ #define SRV_RECV_MSG_DAY	0x0007
+ #define SRV_RECV_MSG_HOUR	0x0008
+ #define SRV_RECV_MSG_MINUTE	0x0009
+ #define SRV_RECV_MSG_MSG_TYPE	0x000a
+ 
+ cmdcode serverMetaSubCmdCode[] = {
+     { "META_USER_FOUND", META_USER_FOUND },
+     { "META_ABOUT", META_ABOUT },
+     { "META_USER_INFO", META_USER_INFO },
+     { NULL, -1 }
+ };
+ 
  cmdcode serverCmdCode[] = {
!     { "SRV_ACK", SRV_ACK },
!     { "SRV_GO_AWAY", SRV_GO_AWAY },
!     { "SRV_NEW_UIN", SRV_NEW_UIN },
!     { "SRV_LOGIN_REPLY", SRV_LOGIN_REPLY },
!     { "SRV_BAD_PASS", SRV_BAD_PASS },
!     { "SRV_USER_ONLINE", SRV_USER_ONLINE },
!     { "SRV_USER_OFFLINE", SRV_USER_OFFLINE },
      { "SRV_QUERY", 130 },
      { "SRV_USER_FOUND", 140 },
      { "SRV_END_OF_SEARCH", 160 },
      { "SRV_NEW_USER", 180 },
      { "SRV_UPDATE_EXT", 200 },
!     { "SRV_RECV_MESSAGE", SRV_RECV_MESSAGE },
      { "SRV_X2", 230 },
      { "SRV_NOT_CONNECTED", 240 },
      { "SRV_TRY_AGAIN", 250 },
***************
*** 127,140 ****
      { "SRV_EXT_INFO_REPLY", 290 },
      { "SRV_STATUS_UPDATE", 420 },
      { "SRV_SYSTEM_MESSAGE", 450 },
!     { "SRV_UPDATE_SUCCESS", 480 },
!     { "SRV_UPDATE_FAIL", 490 },
      { "SRV_AUTH_UPDATE", 500 },
!     { "SRV_MULTI_PACKET", 530 },
      { "SRV_X1", 540 },
      { "SRV_RAND_USER", 590 },
!     { "SRV_META_USER", 990 },
!     { NULL, 0 }
  };
  
  #define MSG_TEXT		0x0001
--- 202,215 ----
      { "SRV_EXT_INFO_REPLY", 290 },
      { "SRV_STATUS_UPDATE", 420 },
      { "SRV_SYSTEM_MESSAGE", 450 },
!     { "SRV_UPDATE_SUCCESS", SRV_UPDATE_SUCCESS },
!     { "SRV_UPDATE_FAIL", SRV_UPDATE_FAIL },
      { "SRV_AUTH_UPDATE", 500 },
!     { "SRV_MULTI_PACKET", SRV_MULTI },
      { "SRV_X1", 540 },
      { "SRV_RAND_USER", 590 },
!     { "SRV_META_USER", SRV_META_USER },
!     { NULL, -1 }
  };
  
  #define MSG_TEXT		0x0001
***************
*** 142,147 ****
--- 217,223 ----
  #define MSG_AUTH_REQ		0x0006
  #define MSG_AUTH		0x0008
  #define MSG_USER_ADDED		0x000c
+ #define MSG_EMAIL		0x000e
  #define MSG_CONTACTS		0x0013
  
  #define STATUS_ONLINE		0x00000000
***************
*** 176,188 ****
--- 252,296 ----
  #define CMD_LOGIN_IP		0x0004
  #define CMD_LOGIN_STATUS	0x0009
  
+ #define CMD_CONTACT_LIST	0x0406
+ #define CMD_CONTACT_LIST_NUM	0x0000
+ 
+ #define CMD_USER_META		0x064a
+ 
+ #define CMD_REG_NEW_USER	0x03fc
+ 
+ #define CMD_ACK_MESSAGES	0x0442
+ #define CMD_ACK_MESSAGES_RANDOM	0x0000
+ 
+ #define CMD_KEEP_ALIVE		0x042e
+ #define CMD_KEEP_ALIVE_RANDOM	0x0000
+ 
+ #define CMD_SEND_TEXT_CODE	0x0438
+ #define CMD_SEND_TEXT_CODE_LEN	0x0000
+ #define CMD_SEND_TEXT_CODE_TEXT	0x0002
+ 
+ #define CMD_QUERY_SERVERS	0x04ba
+ 
+ #define CMD_QUERY_ADDONS	0x04c4
  
+ #define CMD_STATUS_CHANGE	0x04d8
+ #define CMD_STATUS_CHANGE_STATUS	0x0000
+ 
+ #define CMD_ADD_TO_LIST		0x053c
+ #define CMD_ADD_TO_LIST_UIN	0x0000
+ 
+ #define CMD_RAND_SEARCH		0x056e
+ #define CMD_RAND_SEARCH_GROUP	0x0000
+ 
+ #define CMD_META_USER		0x064a
+ 
  cmdcode msgTypeCode[] = {
      { "MSG_TEXT", MSG_TEXT },
      { "MSG_URL", MSG_URL },
      { "MSG_AUTH_REQ", MSG_AUTH_REQ },
      { "MSG_AUTH", MSG_AUTH },
      { "MSG_USER_ADDED", MSG_USER_ADDED},
+     { "MSG_EMAIL", MSG_EMAIL},
      { "MSG_CONTACTS", MSG_CONTACTS},
      { NULL, 0}
  };
***************
*** 202,214 ****
      { "CMD_ACK", CMD_ACK },
      { "CMD_SEND_MESSAGE", CMD_SEND_MSG },
      { "CMD_LOGIN", CMD_LOGIN },
!     { "CMD_REG_NEW_USER", 1020 },
      { "CMD_CONTACT_LIST", 1030 },
      { "CMD_SEARCH_UIN", 1050 },
      { "CMD_SEARCH_USER", 1060 },
      { "CMD_KEEP_ALIVE", 1070 },
!     { "CMD_SEND_TEXT_CODE", 1080 },
!     { "CMD_ACK_MESSAGES", 1090 },
      { "CMD_LOGIN_1", 1100 },
      { "CMD_MSG_TO_NEW_USER", 1110 },
      { "CMD_INFO_REQ", 1120 },
--- 310,322 ----
      { "CMD_ACK", CMD_ACK },
      { "CMD_SEND_MESSAGE", CMD_SEND_MSG },
      { "CMD_LOGIN", CMD_LOGIN },
!     { "CMD_REG_NEW_USER", CMD_REG_NEW_USER },
      { "CMD_CONTACT_LIST", 1030 },
      { "CMD_SEARCH_UIN", 1050 },
      { "CMD_SEARCH_USER", 1060 },
      { "CMD_KEEP_ALIVE", 1070 },
!     { "CMD_SEND_TEXT_CODE", CMD_SEND_TEXT_CODE },
!     { "CMD_ACK_MESSAGES", CMD_ACK_MESSAGES },
      { "CMD_LOGIN_1", 1100 },
      { "CMD_MSG_TO_NEW_USER", 1110 },
      { "CMD_INFO_REQ", 1120 },
***************
*** 216,233 ****
      { "CMD_CHANGE_PW", 1180 },
      { "CMD_NEW_USER_INFO", 1190 },
      { "CMD_UPDATE_EXT_INFO", 1200 },
!     { "CMD_QUERY_SERVERS", 1210 },
!     { "CMD_QUERY_ADDONS", 1220 },
!     { "CMD_STATUS_CHANGE", 1240 },
      { "CMD_NEW_USER_1", 1260 },
      { "CMD_UPDATE_INFO", 1290 },
      { "CMD_AUTH_UPDATE", 1300 },
      { "CMD_KEEP_ALIVE2", 1310 },
      { "CMD_LOGIN_2", 1320 },
!     { "CMD_ADD_TO_LIST", 1340 },
      { "CMD_RAND_SET", 1380 },
!     { "CMD_RAND_SEARCH", 1390 },
!     { "CMD_META_USER", 1610 },
      { "CMD_INVIS_LIST", 1700 },
      { "CMD_VIS_LIST", 1710 },
      { "CMD_UPDATE_LIST", 1720 },
--- 324,341 ----
      { "CMD_CHANGE_PW", 1180 },
      { "CMD_NEW_USER_INFO", 1190 },
      { "CMD_UPDATE_EXT_INFO", 1200 },
!     { "CMD_QUERY_SERVERS", CMD_QUERY_SERVERS },
!     { "CMD_QUERY_ADDONS", CMD_QUERY_ADDONS },
!     { "CMD_STATUS_CHANGE", CMD_STATUS_CHANGE },
      { "CMD_NEW_USER_1", 1260 },
      { "CMD_UPDATE_INFO", 1290 },
      { "CMD_AUTH_UPDATE", 1300 },
      { "CMD_KEEP_ALIVE2", 1310 },
      { "CMD_LOGIN_2", 1320 },
!     { "CMD_ADD_TO_LIST", CMD_ADD_TO_LIST },
      { "CMD_RAND_SET", 1380 },
!     { "CMD_RAND_SEARCH", CMD_RAND_SEARCH },
!     { "CMD_META_USER", CMD_META_USER },
      { "CMD_INVIS_LIST", 1700 },
      { "CMD_VIS_LIST", 1710 },
      { "CMD_UPDATE_LIST", 1720 },
***************
*** 278,283 ****
--- 386,397 ----
  }
  
  static char*
+ findSubCmd(int num)
+ {
+     return findcmd(serverMetaSubCmdCode, num);
+ };
+ 
+ static char*
  findClientCmd(int num)
  {
      return findcmd(clientCmdCode, num);
***************
*** 447,453 ****
--- 561,815 ----
      return p;
  }
  
+ 
  static void
+ icqv5_decode_msgType(proto_tree* tree,
+ 		     const unsigned char* pd, /* From start of messageType */
+ 		     int offset,
+ 		     int size)
+ {
+     proto_item* ti = NULL;
+     proto_tree* subtree = NULL;
+     int left = size;
+     char *msgText = NULL;
+     guint16 msgType = -1;
+     guint16 msgLen = -1;
+     int i,j,n;
+     static char* auth_req_field_descr[] = {
+ 	"Nickname",
+ 	"First name",
+ 	"Last name",
+ 	"Email address",
+ 	"Reason"};
+     static char* emain_field_descr[] = {
+ 	"Nickname",
+ 	"First name",
+ 	"Last name",
+ 	"Email address",
+ 	"Unknown",
+ 	"Text\n"
+     };
+     
+     enum {OFF_MSG_TYPE=0,
+ 	  OFF_MSG_LEN=2,
+ 	  OFF_MSG_TEXT=4};
+ 
+     
+     if (left >= sizeof(guint16)) {
+ 	msgType = pletohs(pd + OFF_MSG_TYPE);
+ 	left -= sizeof(guint16);
+     }
+     if (left >= sizeof(guint16)) {
+ 	msgLen = pletohs(pd + OFF_MSG_LEN);
+ 	left -= sizeof(guint16);
+     }
+ 
+     ti = proto_tree_add_text(tree,
+ 			     offset ,
+ 			     2,
+ 			     "Type: %d (%s)", msgType, findMsgType(msgType));
+     /* Create a new subtree */
+     subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY_PARTS);
+ 
+     switch(msgType) {
+     case 0xffff:           /* Field unknown */
+ 	break;
+     default:
+ 	fprintf(stderr, "Unknown msgType: %d (%04x)\n", msgType, msgType);
+ 	break;
+     case MSG_TEXT:
+ 	msgText = g_malloc(left + 1);
+ 	strncpy(msgText, pd + OFF_MSG_TEXT, left);
+ 	msgText[left] = '\0';
+ 	proto_tree_add_text(subtree,
+ 			    offset + OFF_MSG_TEXT,
+ 			    left,
+ 			    "Msg: %s", msgText);
+ 	g_free(msgText);
+ 	break;
+     case MSG_URL:
+ 	/* Two parts, a description and the URL. Separeted by FE */
+ 	for (i=0;i<left;i++) {
+ 	    if (pd[OFF_MSG_TEXT + i] == 0xfe)
+ 		break;
+ 	}
+ 	msgText = g_malloc(i + 1);
+ 	strncpy(msgText, pd + OFF_MSG_TEXT, i);
+ 	if (i==left)
+ 	    msgText[i] = '\0';
+ 	else
+ 	    msgText[i-1] = '\0';
+ 	proto_tree_add_text(subtree,
+ 			    offset + OFF_MSG_TEXT,
+ 			    i,
+ 			    "Description: %s", msgText);
+ 	if (i==left)
+ 	    break;
+ 	msgText = g_realloc(msgText, left - i);
+ 	strncpy(msgText, pd + OFF_MSG_TEXT + i + 1, left - i - 1);
+ 	msgText[left - i] = '\0';
+ 	proto_tree_add_text(subtree,
+ 			    offset + OFF_MSG_TEXT,
+ 			    i,
+ 			    "URL: %s", msgText);
+ 	g_free(msgText);
+ 	break;
+     case MSG_EMAIL:
+ 	i = 0;
+ 	j = 0;
+ 	msgText = NULL;
+ 	for (n = 0; n < 6; n++) {
+ 	    for (;
+ 		 (i<left) && (pd[OFF_MSG_TEXT+i]!=0xfe);
+ 		 i++)
+ 		;
+ 	    if (i>j) {
+ 		msgText = g_realloc(msgText, i-j);
+ 		strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j - 1);
+ 		msgText[i-j-1] = '\0';
+ 		proto_tree_add_text(subtree,
+ 				    offset + OFF_MSG_TEXT + j,
+ 				    i - j - 1,
+ 				    "%s: %s", emain_field_descr[n], msgText);
+ 	    } else {
+ 		proto_tree_add_text(subtree,
+ 				    offset + OFF_MSG_TEXT + j,
+ 				    0,
+ 				    "%s: %s", emain_field_descr[n], "(empty)");
+ 	    }
+ 	    j = ++i;
+ 	}
+ 	if (msgText != NULL)
+ 	    g_free(msgText);
+ 	break;
+ 	
+     case MSG_AUTH:
+     {
+ 	/* Three bytes, first is a char signifying success */
+ 	unsigned char auth_suc = pd[OFF_MSG_LEN];
+ 	guint16 x1 = pd[OFF_MSG_LEN+1];
+ 	proto_tree_add_text(subtree,
+ 			    offset + OFF_MSG_LEN,
+ 			    1,
+ 			    "Authorization: (%d) %s",auth_suc,
+ 			    (auth_suc==0)?"Denied":"Allowed");
+ 	proto_tree_add_text(subtree,
+ 			    offset + OFF_MSG_LEN + 1,
+ 			    sizeof(guint16),
+ 			    "x1: 0x%04x",x1);
+ 	break;
+     }
+     case MSG_AUTH_REQ:
+ 	/* Five parts, separated by FE */
+ 	i = 0;
+ 	j = 0;
+ 	msgText = NULL;
+ 	for (n = 0; n < 5; n++) {
+ 	    for (;
+ 		 (i<left) && (pd[OFF_MSG_TEXT+i]!=0xfe);
+ 		 i++)
+ 		;
+ 	    msgText = g_realloc(msgText, i-j);
+ 	    strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j - 1);
+ 	    msgText[i-j-1] = '\0';
+ 	    proto_tree_add_text(subtree,
+ 				offset + OFF_MSG_TEXT + j,
+ 				i - j - 1,
+ 				"%s: %s", auth_req_field_descr[n], msgText);
+ 	    j = ++i;
+ 	}
+ 	if (msgText != NULL)
+ 	    g_free(msgText);
+ 	break;
+     case MSG_USER_ADDED:
+ 	/* Four parts, separated by FE */
+ 	i = 0;
+ 	j = 0;
+ 	/* This is necessary, because g_realloc does not behave like
+ 	     * g_malloc if the first parameter == NULL */
+ 	msgText = g_malloc(64);
+ 	for (n = 0; n < 4; n++) {
+ 	    for (;
+ 		 (i<left) && (pd[OFF_MSG_TEXT+i]!=0xfe);
+ 		 i++)
+ 		;
+ 	    msgText = g_realloc(msgText, i-j+1);
+ 	    strncpy(msgText, pd + OFF_MSG_TEXT + j, i - j);
+ 	    msgText[i-j] = '\0';
+ 	    proto_tree_add_text(subtree,
+ 				offset + OFF_MSG_TEXT + j,
+ 				i - j,
+ 				"%s: %s", auth_req_field_descr[n], msgText);
+ 	    j = ++i;
+ 	}
+ 	if (msgText != NULL)
+ 	    g_free(msgText);
+ 	break;
+     case MSG_CONTACTS:
+     {
+ 	u_char* p = (u_char*) &pd[OFF_MSG_TEXT];
+ 	u_char* pprev = p;
+ 	int sz = 0;            /* Size of the current element */
+ 	int n = 0;             /* The nth element */
+ 	int done = 0;          /* Number of chars processed */
+ 	u_char* msgText2 = NULL;
+ 	msgText = NULL;
+ 	/* Create a new subtree */
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY_PARTS);
+ 	while (p!=NULL) {
+ 	    p = strnchr(pprev, 0xfe, left);
+ 	    
+ 	    if (p!=NULL)
+ 		sz = (int)(p - pprev);
+ 	    else
+ 		sz = left;
+ 	    msgText = g_realloc(msgText, sz+1);
+ 	    strncpy(msgText, pprev, sz);
+ 	    msgText[sz] = '\0';
+ 	    
+ 	    if (n == 0) {
+ 		/* The first element is the number of Nick/UIN pairs follow */
+ 		proto_tree_add_text(subtree,
+ 				    offset + OFF_MSG_TEXT + done,
+ 				    sz,
+ 				    "Number of pairs: %s", msgText);
+ 		n++;
+ 	    } else if (p!=NULL) {
+ 		int svsz = sz;
+ 		left -= (sz+1);
+ 		pprev = p + 1;
+ 		p = strnchr(pprev, 0xfe, left);
+ 		if (p!=NULL)
+ 		    sz = (int)(p - pprev);
+ 		else
+ 		    sz = left;
+ 		msgText2 = g_malloc(sz+1);
+ 		strncpy(msgText2, pprev, sz);
+ 		msgText2[sz] = '\0';
+ 		
+ 		proto_tree_add_text(subtree,
+ 				    offset + OFF_MSG_TEXT + done,
+ 				    sz + svsz + 2,
+ 				    "%s:%s", msgText, msgText2);
+ 		n+=2;
+ 		g_free(msgText2);
+ 	    }
+ 	    
+ 	    left -= (sz+1);
+ 	    pprev = p+1;
+ 	}
+ 	if (msgText != NULL)
+ 	    g_free(msgText);
+ 	break;
+     }}
+ }
+ 
+ /*********************************
+  * 
+  * Client commands
+  *
+  *********************************/
+ static void
  icqv5_cmd_ack(proto_tree* tree,/* Tree to put the data in */
  		     const u_char* pd, /* Packet content */
  		     int offset, /* Offset from the start of the packet to the content */
***************
*** 463,472 ****
  					offset,
  					4,
  					CMD_ACK,
! 					"%s : %d",
! 					findClientCmd(CMD_ACK),
! 					CMD_ACK);
! 	subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
  	proto_tree_add_text(subtree,
  			    offset + CMD_ACK_RANDOM,
  			    4,
--- 825,832 ----
  					offset,
  					4,
  					CMD_ACK,
! 					"Body");
! 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
  	proto_tree_add_text(subtree,
  			    offset + CMD_ACK_RANDOM,
  			    4,
***************
*** 475,480 ****
--- 835,1041 ----
  }
  
  static void
+ icqv5_cmd_rand_search(proto_tree* tree,       /* Tree to put the data in */
+ 		      const u_char* pd,       /* Packet content */
+ 		      int offset,             /* Offset from the start of the packet to the content */
+ 		      int size)               /* Number of chars left to do */
+ {
+     guint16 group = pletohs(pd + CMD_RAND_SEARCH_GROUP);
+     proto_tree* subtree;
+     proto_item* ti;
+ 
+     static const char* groups[] = {
+ 	"Name",
+ 	"General",
+ 	"Romance",
+ 	"Games",
+ 	"Students",
+ 	"20 Something",
+ 	"30 Something",
+ 	"40 Something",
+ 	"50 or worse",
+ 	"Man want women",
+ 	"Women want men"
+     };
+     
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					4,
+ 					CMD_RAND_SEARCH,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
+ 	    proto_tree_add_text(subtree,
+ 				offset + CMD_RAND_SEARCH_GROUP,
+ 				4,
+ 				"Group: (%d) %s", group, groups[group-1]);
+ 	else
+ 	    proto_tree_add_text(subtree,
+ 				offset + CMD_RAND_SEARCH_GROUP,
+ 				4,
+ 				"Group: (%d)", group);
+     }
+ }
+ 
+ static void
+ icqv5_cmd_ack_messages(proto_tree* tree,/* Tree to put the data in */
+ 		       const u_char* pd,      /* Packet content */
+ 		       int offset,              /* Offset from the start of the packet to the content */
+ 		       int size)                  /* Number of chars left to do */
+ {
+     guint32 random = pletohl(pd + CMD_ACK_MESSAGES_RANDOM);
+     proto_tree* subtree;
+     proto_item* ti;
+ 
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					4,
+ 					CMD_ACK_MESSAGES,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + CMD_ACK_MESSAGES_RANDOM,
+ 			    4,
+ 			    "Random: 0x%08lx", random);
+     }
+ }
+ 
+ static void
+ icqv5_cmd_keep_alive(proto_tree* tree,/* Tree to put the data in */
+ 		       const u_char* pd,      /* Packet content */
+ 		       int offset,              /* Offset from the start of the packet to the content */
+ 		       int size)                  /* Number of chars left to do */
+ {
+     guint32 random = pletohl(pd + CMD_KEEP_ALIVE_RANDOM);
+     proto_tree* subtree;
+     proto_item* ti;
+ 
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					4,
+ 					CMD_KEEP_ALIVE,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + CMD_KEEP_ALIVE_RANDOM,
+ 			    4,
+ 			    "Random: 0x%08lx", random);
+     }
+ }
+ 
+ static void
+ icqv5_cmd_send_text_code(proto_tree* tree,/* Tree to put the data in */
+ 			 const u_char* pd,      /* Packet content */
+ 			 int offset,              /* Offset from the start of the packet to the content */
+ 			 int size)                  /* Number of chars left to do */
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+     gint16 len = -1;
+     guint16 x1 = -1;
+     char* text = NULL;
+     int left = size;		/* The amount of data left to analyse */
+ 
+     if (left>=sizeof(gint16)) {
+ 	len = pletohs(pd+CMD_SEND_TEXT_CODE_LEN);
+ 	left -= sizeof(gint16);
+     }
+     if (len>=0) {
+ 	len = MIN(len, left);
+ 	text = g_malloc(len+1);
+ 	memcpy(text, pd + CMD_SEND_TEXT_CODE_TEXT, len);
+ 	text[len] = '\0';
+ 	left -= len;
+     }
+     if (left>=sizeof(gint16)) {
+ 	x1 = pletohs(pd + size - left);
+ 	left -= sizeof(gint16);
+     }
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					left,
+ 					CMD_KEEP_ALIVE,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + CMD_SEND_TEXT_CODE_LEN,
+ 			    2,
+ 			    "Length: %d", len);
+ 	proto_tree_add_text(subtree,
+ 			    offset + CMD_SEND_TEXT_CODE_TEXT,
+ 			    len,
+ 			    "Text: %s",text);
+ 	proto_tree_add_text(subtree,
+ 			    offset + CMD_SEND_TEXT_CODE_TEXT + len,
+ 			    2,
+ 			    "X1: 0x%04x", x1);
+     }
+     if (text!=NULL)
+ 	g_free(text);
+ }
+ 
+ static void
+ icqv5_cmd_add_to_list(proto_tree* tree,/* Tree to put the data in */
+ 		      const u_char* pd,      /* Packet content */
+ 		      int offset,            /* Offset from the start of the packet to the content */
+ 		      int size)              /* Number of chars left to do */
+ {
+     guint32 uin = -1;
+     proto_tree* subtree;
+     proto_item* ti;
+     if (size>=4)
+ 	uin = pletohl(pd + CMD_ADD_TO_LIST);
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					4,
+ 					CMD_ADD_TO_LIST,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + CMD_ADD_TO_LIST_UIN,
+ 			    4,
+ 			    "UIN: %ld", uin);
+     }
+ }
+ 
+ static void
+ icqv5_cmd_status_change(proto_tree* tree,/* Tree to put the data in */
+ 			const u_char* pd,       /* Packet content */
+ 			int offset,                /* Offset from the start of the packet to the content */
+ 			int size)                     /* Number of chars left to do */
+ {
+     guint32 status = -1;
+     proto_tree* subtree;
+     proto_item* ti;
+ 
+     if (size >= CMD_STATUS_CHANGE_STATUS + 4)
+ 	status = pletohl(pd + CMD_STATUS_CHANGE_STATUS);
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					4,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	if (status!=-1)
+ 	    proto_tree_add_text(subtree,
+ 				offset + CMD_STATUS_CHANGE_STATUS,
+ 				4,
+ 				"Status: %08x (%s)", status, findStatus(status));
+     }
+ }
+ 
+ static void
  icqv5_cmd_send_msg(proto_tree* tree,
  		   const u_char* pd,
  		   int offset,
***************
*** 485,499 ****
      guint32 receiverUIN = 0xffffffff;
      guint16 msgType = 0xffff;
      guint16 msgLen = 0xffff;
-     u_char* msgText = NULL;
      int left = size;		/* left chars to do */
-     int i,n,j;
-     static char* auth_req_field_descr[] = {
- 	"Nickname",
- 	"First name",
- 	"Last name",
- 	"Email address",
- 	"Reason"};
      
      if (left >= 4) {
  	receiverUIN = pletohl(pd + CMD_SEND_MSG_RECV_UIN);
--- 1046,1052 ----
***************
*** 514,684 ****
  					size,
  					CMD_SEND_MSG,
  					"Body");
! 	subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
  	proto_tree_add_text(subtree,
  			    offset + CMD_SEND_MSG_RECV_UIN,
  			    4,
  			    "Receiver UIN: %ld", receiverUIN);
- 	ti = proto_tree_add_text(subtree,
- 				 offset + CMD_SEND_MSG_MSG_TYPE,
- 				 2,
- 				 "Type: %d (%s)", msgType, findMsgType(msgType));
  	proto_tree_add_text(subtree,
  			    offset + CMD_SEND_MSG_MSG_LEN,
  			    2,
  			    "Length: %d", msgLen);
  
! 	/* It's silly to do anything if there's nothing left */
! 	if (left==0)
! 	    return;
! 	if (msgLen == 0)
! 	    return;
! 	/* Create a subtree for every message type */
! 	switch(msgType) {
! 	case 0xffff:		/* Field unknown */
! 	    break;
! 	case MSG_TEXT:
! 	    msgText = g_malloc(left + 1);
! 	    strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT, left);
! 	    msgText[left] = '\0';
! 	    proto_tree_add_text(subtree,
! 				offset + CMD_SEND_MSG_MSG_TEXT,
! 				left,
! 				"Msg: %s", msgText);
! 	    g_free(msgText);
! 	    break;
! 	case MSG_URL:
! 	    /* Two parts, a description and the URL. Separeted by FE */
! 	    for (i=0;i<left;i++) {
! 		if (pd[CMD_SEND_MSG_MSG_TEXT + i] == 0xfe)
! 		    break;
! 	    }
! 	    msgText = g_malloc(i + 1);
! 	    strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT, i);
! 	    if (i==left)
! 		msgText[i] = '\0';
! 	    else
! 		msgText[i-1] = '\0';
! 	    proto_tree_add_text(subtree,
! 				offset + CMD_SEND_MSG_MSG_TEXT,
! 				i,
! 				"Description: %s", msgText);
! 	    if (i==left)
! 		break;
! 	    msgText = g_realloc(msgText, left - i);
! 	    strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT + i + 1, left - i - 1);
! 	    msgText[left - i] = '\0';
! 	    proto_tree_add_text(subtree,
! 				offset + CMD_SEND_MSG_MSG_TEXT,
! 				i,
! 				"URL: %s", msgText);
! 	    g_free(msgText);
! 	    break;
! 	case MSG_AUTH_REQ:
! 	    /* Five parts, separated by FE */
! 	    i = 0;
! 	    j = 0;
! 	    msgText = NULL;
! 	    for (n = 0; n < 5; n++) {
! 		for (;
! 		     (i<left) && (pd[CMD_SEND_MSG_MSG_TEXT+i]!=0xfe);
! 		     i++)
! 		    ;
! 		msgText = g_realloc(msgText, i-j);
! 		strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT + j, i - j - 1);
! 		msgText[i-j-1] = '\0';
! 		proto_tree_add_text(subtree,
! 				    offset + CMD_SEND_MSG_MSG_TEXT + j,
! 				    i - j - 1,
! 				    "%s: %s", auth_req_field_descr[n], msgText);
! 		j = ++i;
! 	    }
! 	    if (msgText != NULL)
! 		g_free(msgText);
! 	    break;
! 	case MSG_USER_ADDED:
! 	    /* Create a new subtree */
! 	    subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
! 	    /* Four parts, separated by FE */
! 	    i = 0;
! 	    j = 0;
!             /* This is necessary, because g_realloc does not behave like
! 	     * g_malloc if the first parameter == NULL */
! 	    msgText = g_malloc(64);
! 	    for (n = 0; n < 4; n++) {
! 		for (;
! 		     (i<left) && (pd[CMD_SEND_MSG_MSG_TEXT+i]!=0xfe);
! 		     i++)
! 		    ;
! 		msgText = g_realloc(msgText, i-j+1);
! 		strncpy(msgText, pd + CMD_SEND_MSG_MSG_TEXT + j, i - j);
! 		msgText[i-j] = '\0';
! 		proto_tree_add_text(subtree,
! 				    offset + CMD_SEND_MSG_MSG_TEXT + j,
! 				    i - j,
! 				    "%s: %s", auth_req_field_descr[n], msgText);
! 		j = ++i;
! 	    }
! 	    if (msgText != NULL)
! 		g_free(msgText);
! 	    break;
! 	case MSG_CONTACTS:
! 	{
! 	    u_char* p = (u_char*) &pd[CMD_SEND_MSG_MSG_TEXT];
! 	    u_char* pprev = p;
! 	    int sz = 0;		/* Size of the current element */
! 	    int n = 0;		/* The nth element */
! 	    int done = 0;	/* Number of chars processed */
! 	    u_char* msgText2 = NULL;
! 	    msgText = NULL;
! 	    /* Create a new subtree */
! 	    subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
! 	    while (p!=NULL) {
! 		p = strnchr(pprev, 0xfe, left);
! 		
! 		if (p!=NULL)
! 		    sz = (int)(p - pprev);
! 		else
! 		    sz = left;
! 		msgText = g_realloc(msgText, sz+1);
! 		strncpy(msgText, pprev, sz);
! 		msgText[sz] = '\0';
! 
! 		if (n == 0) {
! 		    /* The first element is the number of Nick/UIN pairs follow */
! 		    proto_tree_add_text(subtree,
! 					offset + CMD_SEND_MSG_MSG_TEXT + done,
! 					sz,
! 					"Number of pairs: %s", msgText);
! 		    n++;
! 		} else if (p!=NULL) {
! 		    int svsz = sz;
! 		    left -= (sz+1);
! 		    pprev = p + 1;
! 		    p = strnchr(pprev, 0xfe, left);
! 		    if (p!=NULL)
! 			sz = (int)(p - pprev);
! 		    else
! 			sz = left;
! 		    msgText2 = g_malloc(sz+1);
! 		    strncpy(msgText2, pprev, sz);
! 		    msgText2[sz] = '\0';
! 
! 		    proto_tree_add_text(subtree,
! 					offset + CMD_SEND_MSG_MSG_TEXT + done,
! 					sz + svsz + 2,
! 					"%s:%s", msgText, msgText2);
! 		    n+=2;
! 		    g_free(msgText2);
! 		}
! 		
! 		left -= (sz+1);
! 		pprev = p+1;
! 	    }
! 	    if (msgText != NULL)
! 		g_free(msgText);
! 	    break;
! 	}}
      }
  }
  
--- 1067,1086 ----
  					size,
  					CMD_SEND_MSG,
  					"Body");
! 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
  	proto_tree_add_text(subtree,
  			    offset + CMD_SEND_MSG_RECV_UIN,
  			    4,
  			    "Receiver UIN: %ld", receiverUIN);
  	proto_tree_add_text(subtree,
  			    offset + CMD_SEND_MSG_MSG_LEN,
  			    2,
  			    "Length: %d", msgLen);
  
! 	icqv5_decode_msgType(subtree,
! 			     pd + CMD_SEND_MSG_MSG_TYPE,
! 			     offset + CMD_SEND_MSG_MSG_TYPE,
! 			     left+4); /* There are 4 bytes more... */
      }
  }
  
***************
*** 726,732 ****
  					size,
  					CMD_SEND_MSG,
  					"Body");
! 	subtree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
  	if (theTime!=-1)
  	    proto_tree_add_text(subtree,
  				offset + CMD_LOGIN_TIME,
--- 1128,1134 ----
  					size,
  					CMD_SEND_MSG,
  					"Body");
! 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
  	if (theTime!=-1)
  	    proto_tree_add_text(subtree,
  				offset + CMD_LOGIN_TIME,
***************
*** 757,762 ****
--- 1159,1817 ----
  	g_free(password);
  }
  
+ static void
+ icqv5_cmd_contact_list(proto_tree* tree,
+ 		       const u_char* pd,
+ 		       int offset,
+ 		       int size)
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+     unsigned char num = -1;
+     int i, left;
+     guint32 uin;
+     const u_char* p = NULL;
+ 
+     if (size >= CMD_CONTACT_LIST_NUM + 1) 
+ 	num = pd[CMD_CONTACT_LIST_NUM];
+ 
+     if (tree) {
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					size,
+ 					CMD_CONTACT_LIST,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + CMD_CONTACT_LIST,
+ 			    1,
+ 			    "Number of uins: %d", num);
+ 	/*
+ 	 * A sequence of num times UIN follows
+ 	 */
+ 	offset += (CMD_CONTACT_LIST_NUM + 1);
+ 	left = size;
+ 	p = &pd[CMD_CONTACT_LIST_NUM + 1];
+ 	for (i = 0; (i<num) && (left>0);i++) {
+ 	    if (left>=4) {
+ 		uin = pletohl(p);
+ 		proto_tree_add_text(subtree,
+ 				    offset,
+ 				    4,
+ 				    "UIN[%d]: %ld",i,uin);
+ 		p += 4;
+ 		offset += 4;
+ 		left -= 4;
+ 	    }
+ 	}
+     }
+ }
+ 
+ static void
+ icqv5_cmd_no_params(proto_tree* tree,/* Tree to put the data in */
+ 		    const u_char* pd,      /* Packet content */
+ 		    int offset,            /* Offset from the start of the packet to the content */
+ 		    int size,              /* Number of chars left to do */
+ 		    int cmd)
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+ 
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					0,
+ 					cmd,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset,
+ 			    0,
+ 			    "No parameters");
+     }
+ }
+ 
+ /**********************
+  *
+  * Server commands
+  *
+  **********************
+  */
+ static void
+ icqv5_srv_no_params(proto_tree* tree,/* Tree to put the data in */
+ 		    const u_char* pd,      /* Packet content */
+ 		    int offset,            /* Offset from the start of the packet to the content */
+ 		    int size,              /* Number of chars left to do */
+ 		    int cmd)
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+ 
+     if (tree){
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					0,
+ 					cmd,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset,
+ 			    0,
+ 			    "No Parameters");
+     }
+ }
+ 
+ static void
+ icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
+ 		      const u_char* pd,       /* Packet content */
+ 		      int offset,                /* Offset from the start of the packet to the content */
+ 		      int size)                     /* Number of chars left to do */
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+     const u_char *ipAddrp = NULL;
+ 
+     if (size >= SRV_LOGIN_REPLY_IP + 4) 
+ 	ipAddrp = &pd[SRV_LOGIN_REPLY_IP];
+ 
+     if (tree) {
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					SRV_LOGIN_REPLY_IP + 8,
+ 					SRV_LOGIN_REPLY,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_LOGIN_REPLY_IP,
+ 			    4,
+ 			    "IP: %s", ip_to_str(ipAddrp));
+     }
+ }
+ 
+ static void
+ icqv5_srv_user_online(proto_tree* tree,/* Tree to put the data in */
+ 		      const u_char* pd,       /* Packet content */
+ 		      int offset,                /* Offset from the start of the packet to the content */
+ 		      int size)                     /* Number of chars left to do */
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+     guint32 uin = -1;
+     const u_char *ipAddrp = NULL;
+     guint32 port = -1;
+     const u_char *realipAddrp = NULL;
+     guint32 status = -1;
+     guint32 version = -1;
+ 
+     if (size >= SRV_USER_ONL_UIN + 4)
+ 	uin = pletohl(pd + SRV_USER_ONL_UIN);
+     
+     if (size >= SRV_USER_ONL_IP + 4) 
+ 	ipAddrp = &pd[SRV_USER_ONL_IP];
+ 
+     if (size >= SRV_USER_ONL_PORT + 4)
+ 	port = pletohl(pd + SRV_USER_ONL_PORT);
+ 
+     if (size >= SRV_USER_ONL_REALIP + 4)
+ 	realipAddrp = &pd[SRV_USER_ONL_REALIP];
+ 
+     if (size >= SRV_USER_ONL_STATUS + 4)
+ 	status = pletohl(pd + SRV_USER_ONL_STATUS);
+ 
+     /*
+      * Kojak: Hypothesis is that this field might be an encoding for the
+      * version used by the UIN that changed. To test this, I included
+      * this line to the code.
+      */
+     if (size >= SRV_USER_ONL_X2 + 4)
+ 	version = pletohl(pd + SRV_USER_ONL_X2);
+ 
+     if (tree) {
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					SRV_LOGIN_REPLY_IP + 8,
+ 					SRV_LOGIN_REPLY,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_USER_ONL_UIN,
+ 			    4,
+ 			    "UIN: %d", uin);
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_USER_ONL_IP,
+ 			    4,
+ 			    "IP: %s", ip_to_str(ipAddrp));
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_USER_ONL_PORT,
+ 			    4,
+ 			    "Port: %d", port);
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_USER_ONL_REALIP,
+ 			    4,
+ 			    "RealIP: %s", ip_to_str(realipAddrp));
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_USER_ONL_STATUS,
+ 			    4,
+ 			    "Status: %s", findStatus(status));
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_USER_ONL_X2,
+ 			    4,
+ 			    "Version: %08x", version);
+     }
+ }
+ 
+ static void
+ icqv5_srv_user_offline(proto_tree* tree,/* Tree to put the data in */
+ 		      const u_char* pd,       /* Packet content */
+ 		      int offset,                /* Offset from the start of the packet to the content */
+ 		      int size)                     /* Number of chars left to do */
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+     guint32 uin = -1;
+ 
+     if (size >= SRV_USER_OFFLINE + 4) 
+ 	uin = pletohl(&pd[SRV_USER_OFFLINE]);
+ 
+     if (tree) {
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					SRV_USER_OFFLINE_UIN + 4,
+ 					SRV_USER_OFFLINE,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_USER_OFFLINE_UIN,
+ 			    4,
+ 			    "UIN: %d", uin);
+     }
+ }
+ 
+ static void
+ icqv5_srv_multi(proto_tree* tree,/* Tree to put the data in */
+ 		const u_char* pd,      /* Packet content */
+ 		int offset,            /* Offset from the start of the packet to the content */
+ 		int size,              /* Number of chars left to do */
+ 		frame_data* fd)
+ {
+     proto_tree* subtree;
+     proto_item* ti;
+     unsigned char num = -1;
+     guint16 pktSz;
+     int i, left;
+     const u_char* p = NULL;
+ 
+     if (size >= SRV_MULTI_NUM + 1) 
+ 	num = pd[SRV_MULTI_NUM];
+ 
+     if (tree) {
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					size,
+ 					SRV_MULTI,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_MULTI_NUM,
+ 			    1,
+ 			    "Number of pkts: %d", num);
+ 	/*
+ 	 * A sequence of num times ( pktsize, packetData) follows
+ 	 */
+ 	offset += (SRV_MULTI_NUM + 1);
+ 	left = size;
+ 	p = &pd[SRV_MULTI_NUM + 1];
+ 	for (i = 0; (i<num) && (left>0);i++) {
+ 	    if (left>=2) {
+ 		pktSz = pletohs(p);
+ 		p += 2;
+ 		offset += 2;
+ 		left -= 2;
+ 		if (left>=pktSz) {
+ 		    dissect_icqv5Server(p, offset, fd, subtree, pktSz);
+ 		    p += pktSz;
+ 		    offset += pktSz;
+ 		    left -= pktSz;
+ 		}
+ 	    }
+ 	}
+     }
+ }
+ 
+ static void
+ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
+ 		    const u_char* pd,      /* Packet content */
+ 		    int offset,            /* Offset from the start of the packet to the content */
+ 		    int size)              /* Number of chars left to do */
+ {
+     proto_tree* subtree = NULL;
+     proto_item* ti = NULL;
+     int left = size;
+     const char* p = pd;
+ 
+     guint16 subcmd = -1;
+     unsigned char result = -1;
+ 
+     if (size>=SRV_META_USER_SUBCMD + 2)
+ 	subcmd = pletohs(pd+SRV_META_USER_SUBCMD);
+     if (size>=SRV_META_USER_RESULT + 1)
+ 	result = pd[SRV_META_USER_RESULT];
+ 
+     if (tree) {
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					size,
+ 					SRV_META_USER,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	ti = proto_tree_add_text(subtree,
+ 				 offset + SRV_META_USER_SUBCMD,
+ 				 2,
+ 				 "%s", findSubCmd(subcmd));
+ 	proto_tree_add_text(subtree,
+ 			    offset + SRV_META_USER_RESULT,
+ 			    1,
+ 			    "%s", (result==0x0a)?"Success":"Failure");
+ 	switch(subcmd) {
+ 	case META_USER_FOUND:
+ 	{
+ 	    /* The goto mentioned in this block should be local to this
+ 	     * block if C'd allow it.
+ 	     *
+ 	     * They are used to "implement" a poorman's exception handling
+ 	     */
+ 	    guint32 uin = -1;
+ 	    char* nick = NULL;	/* Nick */
+ 	    char* first = NULL;	/* First name */
+ 	    char* last = NULL;	/* Last name */
+ 	    char* email = NULL;
+ 	    unsigned char auth = -1;
+ 	    int len = 0;
+ 	    guint16 x2 = -1;
+ 	    guint32 x3 = -1;
+ 	    proto_tree* sstree = proto_item_add_subtree(ti, ETT_ICQ_BODY_PARTS);
+ 
+ 	    /* Skip over META_USER header */
+ 	    left -= 3;
+ 	    p += 3;
+ 	    /* Get the uin */
+ 	    if (left<sizeof(guint32))
+ 		goto stopMetaUser;
+ 	    uin = pletohl(p);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint32),
+ 				"UIN: %ld", uin);
+ 	    p+=sizeof(guint32);left-=sizeof(guint32);
+ 	    /* Get the nickname */
+ 	    if (left<sizeof(guint16))
+ 		goto stopMetaUser;
+ 	    len = pletohs(p);
+ 	    p+=sizeof(guint16);left-=sizeof(guint16);
+ 	    if ((len<=0) || (left<len))
+ 		goto stopMetaUser;
+ 	    nick = g_malloc(len);
+ 	    strncpy(nick, p, len);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint16)+len,
+ 				"Nick(%d): %s", len, nick);
+ 	    p+=len;left-=len;
+ 	    /* Get the first name */
+ 	    if (left<sizeof(guint16))
+ 		goto stopMetaUser;
+ 	    len = pletohs(p);
+ 	    p+=sizeof(guint16);left-=sizeof(guint16);
+ 	    if ((len<=0) || (left<len))
+ 		goto stopMetaUser;
+ 	    first = g_malloc(len);
+ 	    strncpy(first, p, len);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint16)+len,
+ 				"First(%d): %s", len, first);
+ 	    p+=len;left-=len;
+ 	    /* Get last name */
+ 	    if (left<sizeof(guint16))
+ 		goto stopMetaUser;
+ 	    len = pletohs(p);
+ 	    p+=sizeof(guint16);left-=sizeof(guint16);
+ 	    if ((len<=0) || (left<len))
+ 		goto stopMetaUser;
+ 	    last = g_malloc(len);
+ 	    strncpy(last, p, len);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint16)+len,
+ 				"Last(%d): %s", len, last);
+ 	    p+=len;left-=len;
+ 	    /* Get email address */
+ 	    if (left<sizeof(guint16))
+ 		goto stopMetaUser;
+ 	    len = pletohs(p);
+ 	    p+=sizeof(guint16);left-=sizeof(guint16);
+ 	    if ((len<=0) || (left<len))
+ 		goto stopMetaUser;
+ 	    email = g_malloc(len);
+ 	    strncpy(email, p, len);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint16)+len,
+ 				"Email(%d): %s", len, email);
+ 	    p+=len;left-=len;
+ 	    /* Get the authorize setting */
+ 	    if (left<sizeof(unsigned char))
+ 		goto stopMetaUser;
+ 	    auth = *p;
+ 	    p++; left--;
+ 	    /* Get x2 */
+ 	    if (left<sizeof(guint16))
+ 		goto stopMetaUser;
+ 	    x2 = pletohs(p);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint16),
+ 				"x2: %04x", x2);
+ 	    p+=sizeof(guint16);left-=sizeof(guint16);
+ 	    /* Get x3 */
+ 	    if (left<sizeof(guint32))
+ 		goto stopMetaUser;
+ 	    x3 = pletohl(p);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint32),
+ 				"x3: %08x", x3);
+ 	    p+=sizeof(guint32);left-=sizeof(guint32);
+ 
+ 	stopMetaUser:
+ 	    if (nick!=NULL)
+ 		g_free(nick);
+ 	    if (first!=NULL)
+ 		g_free(first);
+ 	    if (last!=NULL)
+ 		g_free(last);
+ 	    if (email!=NULL)
+ 		g_free(last);
+ 	    break;
+ 	}
+ 	case META_ABOUT:
+ 	{
+ 	    int len;
+ 	    char* about = NULL;
+ 	    proto_tree* sstree = proto_item_add_subtree(ti, ETT_ICQ_BODY_PARTS);
+ 
+ 	    /* Skip over META_USER header */
+ 	    left -= 3;
+ 	    p += 3;
+ 	    /* Get the about information */
+ 	    if (left<sizeof(guint16))
+ 		break;
+ 	    len = pletohs(p);
+ 	    p+=sizeof(guint16);left-=sizeof(guint16);
+ 	    if ((len<=0) || (left<len))
+ 		break;
+ 	    about = g_malloc(len);
+ 	    strncpy(about, p, len);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint16)+len,
+ 				"About(%d): %s", len, about);
+ 	    p+=len;left-=len;
+ 	    left -= 3;
+ 	    g_free(about);
+ 	    break;
+ 	}
+ 	case META_USER_INFO:
+ 	{
+ 	    /* The goto mentioned in this block should be local to this
+ 	     * block if C'd allow it.
+ 	     *
+ 	     * They are used to "implement" a poorman's exception handling
+ 	     */
+ 	    static const char* descr[] = {
+ 		"Nick",
+ 		"First name",
+ 		"Last name",
+ 		"Primary email",
+ 		"Secundary email",
+ 		"Old email",
+ 		"City",
+ 		"State",
+ 		"Phone",
+ 		"Fax",
+ 		"Street",
+ 		"Cellphone",
+ 		"Zip",
+ 		NULL};
+ 	    const char** d = descr;
+ 	    char* item = NULL;
+ 	    guint16 country;
+ 	    unsigned char user_timezone = -1;
+ 	    unsigned char auth = -1;
+ 	    int len = 0;
+ 	    proto_tree* sstree = proto_item_add_subtree(ti, ETT_ICQ_BODY_PARTS);
+ 
+ 	    /* Skip over META_USER header */
+ 	    left -= 3;
+ 	    p += 3;
+ #if 0
+ 	    /* Get the uin */
+ 	    if (left<sizeof(guint32))
+ 		break;
+ 	    uin = pletohl(p);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint32),
+ 				"UIN: %ld", uin);
+ 	    p+=sizeof(guint32);left-=sizeof(guint32);
+ #endif
+ 	    
+ 	    /*
+ 	     * Get every field from the description
+ 	     */
+ 	    while ((*d)!=NULL) {
+ 		if (left<sizeof(guint16))
+ 		    break;
+ 		len = pletohs(p);
+ 		p+=sizeof(guint16);left-=sizeof(guint16);
+ 		if ((len<0) || (left<len))
+ 		    break;
+ 		if (len>0) {
+ 		    item = g_malloc(len);
+ 		    strncpy(item, p, len);
+ 		    proto_tree_add_text(sstree,
+ 					offset + size - left - sizeof(guint16),
+ 					sizeof(guint16)+len,
+ 					"%s(%d): %s",*d, len, item);
+ 		    g_free(item);
+ 		    p+=len;left-=len;
+ 		}
+ 		d++;
+ 	    }
+ 	    /* Get country code */
+ 	    if (left<sizeof(guint16))
+ 		break;
+ 	    country = pletohs(p);
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(guint16),
+ 				"Countrycode: %d", country);
+ 	    p+=sizeof(guint16); left-=sizeof(guint16);
+ 	    /* Get the timezone setting */
+ 	    if (left<sizeof(unsigned char))
+ 		break;
+ 	    user_timezone = *p;
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(unsigned char),
+ 				"Timezone: %d", user_timezone);
+ 	    p++; left--;
+ 	    /* Get the authorize setting */
+ 	    if (left<sizeof(unsigned char))
+ 		break;
+ 	    auth = *p;
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(unsigned char),
+ 				"Authorization: (%d) %s",
+ 				auth, (auth==0)?"No":"Yes");
+ 	    p++; left--;
+ 	    /* Get the webaware setting */
+ 	    if (left<sizeof(unsigned char))
+ 		break;
+ 	    auth = *p;
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(unsigned char),
+ 				"Webaware: (%d) %s",
+ 				auth, (auth==0)?"No":"Yes");
+ 	    p++; left--;
+ 	    /* Get the authorize setting */
+ 	    if (left<sizeof(unsigned char))
+ 		break;
+ 	    auth = *p;
+ 	    proto_tree_add_text(sstree,
+ 				offset + size - left,
+ 				sizeof(unsigned char),
+ 				"HideIP: (%d) %s",
+ 				auth, (auth==0)?"No":"Yes");
+ 	    p++; left--;
+ 	    break;
+ 	}
+ 	default:
+ 	    /* This information is already printed in the tree */
+ 	    fprintf(stderr, "Meta subcmd: %04x\n", subcmd);
+ 	    break;
+ 	}
+     }
+ }
+ 
+ static void
+ icqv5_srv_recv_message(proto_tree* tree,      /* Tree to put the data in */
+ 		       const u_char* pd,      /* Packet content */
+ 		       int offset,            /* Offset from the start of the packet to the content */
+ 		       int size)              /* Number of chars left to do */
+ {
+     proto_tree* subtree = NULL;
+     proto_item* ti = NULL;
+     int left = size;
+     guint32 uin = -1;
+     guint16 year = -1;
+     unsigned char month = -1;
+     unsigned char day = -1;
+     unsigned char hour = -1;
+     unsigned char minute = -1;
+     
+     if (tree) {
+ 	ti = proto_tree_add_item_format(tree,
+ 					hf_icq_cmd,
+ 					offset,
+ 					4,
+ 					SRV_RECV_MESSAGE,
+ 					"Body");
+ 	subtree = proto_item_add_subtree(ti, ETT_ICQ_BODY);
+ 	if (left>=sizeof(guint32)) {
+ 	    uin = pletohl(pd + SRV_RECV_MSG_UIN);
+ 	    proto_tree_add_item_format(subtree,
+ 				       hf_icq_uin,
+ 				       offset + SRV_RECV_MSG_UIN,
+ 				       sizeof(guint32),
+ 				       uin,
+ 				       "UIN: %d", uin);
+ 	    left -= sizeof(guint32);
+ 	} else
+ 	    return;
+ 	if (left>=(sizeof(guint16)+4*sizeof(unsigned char))) {
+ 	    year = pletohs(pd + SRV_RECV_MSG_YEAR);
+ 	    month = pd[SRV_RECV_MSG_MONTH];
+ 	    day = pd[SRV_RECV_MSG_DAY];
+ 	    hour = pd[SRV_RECV_MSG_HOUR];
+ 	    minute = pd[SRV_RECV_MSG_MINUTE];
+ 
+ 	    proto_tree_add_text(subtree,
+ 				offset + SRV_RECV_MSG_YEAR,
+ 				sizeof(guint16) + 4*sizeof(unsigned char),
+ 				"Time: %d-%d-%d %02d:%02d",
+ 				day, month, year, hour, minute);
+ 	    
+ 	    left -= (sizeof(guint16)+4*sizeof(unsigned char));
+ 	} else
+ 	    return;
+ 	icqv5_decode_msgType(subtree,
+ 			     pd + SRV_RECV_MSG_MSG_TYPE,
+ 			     offset + SRV_RECV_MSG_MSG_TYPE,
+ 			     left);
+     }
+ }
+ 
  /*
   * Dissect all the v5 client traffic. This is encrypted, so be careful.
   */
***************
*** 808,819 ****
  				 "ICQv5 %s (len %d)",
  				 findClientCmd(cmd),
  				 pktsize);
!         icq_tree = proto_item_add_subtree(ti, ETT_CL_ICQ);
! 	ti = proto_tree_add_text(icq_tree,
! 				 offset,
! 				 ICQ5_CL_HDRSIZE,
! 				 "Header");
! 	icq_header_tree = proto_item_add_subtree(ti, ETT_ICQ_SUBTREE);
  					
  	proto_tree_add_item_format(icq_header_tree,
  				   hf_icq_sessionid,
--- 1863,1876 ----
  				 "ICQv5 %s (len %d)",
  				 findClientCmd(cmd),
  				 pktsize);
!         icq_tree = proto_item_add_subtree(ti, ETT_ICQ);
! 	ti = proto_tree_add_item_format(icq_tree,
! 					hf_icq_type,
! 					offset,
! 					ICQ5_CL_HDRSIZE,
! 					ICQ5_client,
! 					"Header");
! 	icq_header_tree = proto_item_add_subtree(ti, ETT_ICQ_HEADER);
  					
  	proto_tree_add_item_format(icq_header_tree,
  				   hf_icq_sessionid,
***************
*** 857,875 ****
  			       offset + ICQ5_CL_HDRSIZE,
  			       pktsize - ICQ5_CL_HDRSIZE);
  	    break;
  	case CMD_LOGIN:
  	    icqv5_cmd_login(icq_tree,
  			    decr_pd + ICQ5_CL_HDRSIZE,
  			    offset + ICQ5_CL_HDRSIZE,
  			    pktsize - ICQ5_CL_HDRSIZE);
  	    break;
  	default:
  	    proto_tree_add_item_format(icq_tree,
  				       hf_icq_cmd,
  				       offset+ICQ5_CL_CMD,
  				       2,
  				       cmd,
! 				       "Command: %d (%s)", cmd, findcmd(clientCmdCode, cmd));
  	    break;
  	}
  	ti = proto_tree_add_text(icq_tree,
--- 1914,1986 ----
  			       offset + ICQ5_CL_HDRSIZE,
  			       pktsize - ICQ5_CL_HDRSIZE);
  	    break;
+ 	case CMD_RAND_SEARCH:
+ 	    icqv5_cmd_rand_search(icq_tree,
+ 				  decr_pd + ICQ5_CL_HDRSIZE,
+ 				  offset + ICQ5_CL_HDRSIZE,
+ 				  pktsize - ICQ5_CL_HDRSIZE);
+ 	    break;
  	case CMD_LOGIN:
  	    icqv5_cmd_login(icq_tree,
  			    decr_pd + ICQ5_CL_HDRSIZE,
  			    offset + ICQ5_CL_HDRSIZE,
  			    pktsize - ICQ5_CL_HDRSIZE);
  	    break;
+ 	case CMD_SEND_TEXT_CODE:
+ 	    icqv5_cmd_send_text_code(icq_tree,
+ 				     decr_pd + ICQ5_CL_HDRSIZE,
+ 				     offset + ICQ5_CL_HDRSIZE,
+ 				     pktsize - ICQ5_CL_HDRSIZE);
+ 	    break;
+ 	case CMD_STATUS_CHANGE:
+ 	    icqv5_cmd_status_change(icq_tree,
+ 				    decr_pd + ICQ5_CL_HDRSIZE,
+ 				    offset + ICQ5_CL_HDRSIZE,
+ 				    pktsize - ICQ5_CL_HDRSIZE);
+ 	    break;
+ 	case CMD_ACK_MESSAGES:
+ 	    icqv5_cmd_ack_messages(icq_tree,
+ 				   decr_pd + ICQ5_CL_HDRSIZE,
+ 				   offset + ICQ5_CL_HDRSIZE,
+ 				   pktsize - ICQ5_CL_HDRSIZE);
+ 	    break;
+ 	case CMD_KEEP_ALIVE:
+ 	    icqv5_cmd_keep_alive(icq_tree,
+ 				 decr_pd + ICQ5_CL_HDRSIZE,
+ 				 offset + ICQ5_CL_HDRSIZE,
+ 				 pktsize - ICQ5_CL_HDRSIZE);
+ 	    break;
+ 	case CMD_ADD_TO_LIST:
+ 	    icqv5_cmd_add_to_list(icq_tree,
+ 				   decr_pd + ICQ5_CL_HDRSIZE,
+ 				   offset + ICQ5_CL_HDRSIZE,
+ 				   pktsize - ICQ5_CL_HDRSIZE);
+ 	    break;
+ 	case CMD_CONTACT_LIST:
+ 	    icqv5_cmd_contact_list(icq_tree,
+ 				   decr_pd + ICQ5_CL_HDRSIZE,
+ 				   offset + ICQ5_CL_HDRSIZE,
+ 				   pktsize - ICQ5_CL_HDRSIZE);
+ 	    break;
+ 	case CMD_META_USER:
+ 	case CMD_REG_NEW_USER:
+ 	case CMD_QUERY_SERVERS:
+ 	case CMD_QUERY_ADDONS:
+ 	    icqv5_cmd_no_params(icq_tree,
+ 				decr_pd + ICQ5_CL_HDRSIZE,
+ 				offset + ICQ5_CL_HDRSIZE,
+ 				pktsize - ICQ5_CL_HDRSIZE,
+ 				cmd);
+ 	    break;
  	default:
  	    proto_tree_add_item_format(icq_tree,
  				       hf_icq_cmd,
  				       offset+ICQ5_CL_CMD,
  				       2,
  				       cmd,
! 				       "Command: %d (%s)",
! 				       cmd, findClientCmd(cmd));
! 	    fprintf(stderr,"Missing: %s\n", findClientCmd(cmd));
  	    break;
  	}
  	ti = proto_tree_add_text(icq_tree,
***************
*** 877,883 ****
  				 pktsize,
  				 "Decoded packet");
          icq_decode_tree = proto_item_add_subtree(ti,
! 						 ETT_CL_ICQ_DECODE);
  	proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
  
      }
--- 1988,1994 ----
  				 pktsize,
  				 "Decoded packet");
          icq_decode_tree = proto_item_add_subtree(ti,
! 						 ETT_ICQ_DECODE);
  	proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
  
      }
***************
*** 887,949 ****
  dissect_icqv5Server(const u_char *pd,
  		    int offset,
  		    frame_data *fd, 
! 		    proto_tree *tree)
  {
      /* Server traffic is easy, not encrypted */
      proto_tree *icq_tree = NULL;
      proto_tree *icq_decode_tree = NULL;
      proto_item *ti = NULL;
  
      guint16 version, cmd;
      guint32 uin, sessionid;
!     guint32 pktsize;
      
!     uin = pletohl(&pd[offset + ICQ5_SRV_UIN]);
!     cmd = pletohs(&pd[offset + ICQ5_SRV_CMD]);
!     sessionid = pletohl(&pd[offset + ICQ5_SRV_SESSIONID]);
!     version = pletohs(&pd[offset + ICQ_VERSION]);
!     pktsize = fd->pkt_len - offset;
      
!     if (check_col(fd, COL_INFO))
  	col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
  
      if (tree) {
          ti = proto_tree_add_item_format(tree,
  					proto_icq,
  					offset,
! 					pktsize,
! 					NULL,
! 					"ICQv5 Server: len %d", pktsize);
  	
!         icq_tree = proto_item_add_subtree(ti, ETT_SRV_ICQ);
! 	proto_tree_add_item_format(icq_tree,
! 				   hf_icq_cmd,
! 				   offset + ICQ5_SRV_CMD,
! 				   2,
! 				   cmd,
! 				   "Command: %d (%s)",
! 				   cmd, findServerCmd(cmd));
! 	proto_tree_add_item_format(icq_tree,
  				   hf_icq_uin,
  				   offset+ICQ5_SRV_UIN,
  				   4,
  				   uin,
  				   "UIN: %ld",
  				   uin);
! 	proto_tree_add_item_format(icq_tree,
! 				   hf_icq_sessionid,
! 				   offset+ICQ5_SRV_SESSIONID,
  				   4,
! 				   sessionid,
! 				   "Session ID: 0x%08x",
! 				   sessionid);
  	ti = proto_tree_add_text(icq_tree,
  				 offset,
  				 pktsize,
  				 "Decoded packet");
          icq_decode_tree = proto_item_add_subtree(ti,
! 						 ETT_CL_ICQ_DECODE);
! 	proto_tree_add_hexdump(icq_decode_tree, offset, pd+offset, pktsize);
      }
  }
  
--- 1998,2151 ----
  dissect_icqv5Server(const u_char *pd,
  		    int offset,
  		    frame_data *fd, 
! 		    proto_tree *tree,
! 		    guint32 pktsize)
  {
      /* Server traffic is easy, not encrypted */
      proto_tree *icq_tree = NULL;
+     proto_tree *icq_header_tree = NULL;
      proto_tree *icq_decode_tree = NULL;
      proto_item *ti = NULL;
+     const u_char* decr_pd;
+     int changeCol = (pktsize==(guint32)-1);
  
      guint16 version, cmd;
      guint32 uin, sessionid;
!     guint16 seq_num1, seq_num2;
!     guint32 checkcode;
      
!     uin = pletohl(&pd[ICQ5_SRV_UIN]);
!     sessionid = pletohl(&pd[ICQ5_SRV_SESSIONID]);
!     cmd = pletohs(&pd[ICQ5_SRV_CMD]);
!     version = pletohs(&pd[ICQ_VERSION]);
!     checkcode = pletohl(&pd[ICQ5_SRV_CHECKCODE]);
!     seq_num1 = pletohs(&pd[ICQ5_SRV_SEQNUM1]);
!     seq_num2 = pletohs(&pd[ICQ5_SRV_SEQNUM2]);
!     if (pktsize == -1)
! 	pktsize = fd->pkt_len - offset;
!     decr_pd = pd;
      
!     if (changeCol && check_col(fd, COL_INFO))
  	col_add_fstr(fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
  
      if (tree) {
          ti = proto_tree_add_item_format(tree,
  					proto_icq,
  					offset,
! 					pktsize, NULL,
! 					"ICQv5 %s (len %d)",
! 					findServerCmd(cmd),
! 					pktsize);
  	
!         icq_tree = proto_item_add_subtree(ti, ETT_ICQ);
! 
! 	ti = proto_tree_add_item_format(icq_tree,
! 					hf_icq_type,
! 					offset,
! 					ICQ5_SRV_HDRSIZE,
! 					ICQ5_server,
! 					"Header");
! 	icq_header_tree = proto_item_add_subtree(ti, ETT_ICQ_HEADER);
! 					
! 	proto_tree_add_item_format(icq_header_tree,
! 				   hf_icq_sessionid,
! 				   offset+ICQ5_SRV_SESSIONID,
! 				   4,
! 				   sessionid,
! 				   "Session ID: 0x%08x",
! 				   sessionid);
! 	proto_tree_add_text(icq_header_tree,
! 			    offset+ICQ5_SRV_SEQNUM1,
! 			    2,
! 			    "Seq Number1: 0x%04x",
! 			    seq_num1);
! 	proto_tree_add_text(icq_header_tree,
! 			    offset+ICQ5_SRV_SEQNUM2,
! 			    2,
! 			    "Seq Number2: 0x%04x",
! 			    seq_num2);
! 	proto_tree_add_item_format(icq_header_tree,
  				   hf_icq_uin,
  				   offset+ICQ5_SRV_UIN,
  				   4,
  				   uin,
  				   "UIN: %ld",
  				   uin);
! 	proto_tree_add_item_format(icq_header_tree,
! 				   hf_icq_checkcode,
! 				   offset+ICQ5_SRV_CHECKCODE,
  				   4,
! 				   checkcode,
! 				   "Checkcode: 0x%08x",
! 				   checkcode);
! 	switch (cmd) {
! 	case SRV_USER_ONLINE:
! 	    icqv5_srv_user_online(icq_tree,
! 			       decr_pd + ICQ5_SRV_HDRSIZE,
! 			       offset + ICQ5_SRV_HDRSIZE,
! 			       pktsize - ICQ5_SRV_HDRSIZE);
! 	    break;
! 	case SRV_USER_OFFLINE:
! 	    icqv5_srv_user_offline(icq_tree,
! 			       decr_pd + ICQ5_SRV_HDRSIZE,
! 			       offset + ICQ5_SRV_HDRSIZE,
! 			       pktsize - ICQ5_SRV_HDRSIZE);
! 	    break;
! 	case SRV_LOGIN_REPLY:
! 	    icqv5_srv_login_reply(icq_tree,
! 			       decr_pd + ICQ5_SRV_HDRSIZE,
! 			       offset + ICQ5_SRV_HDRSIZE,
! 			       pktsize - ICQ5_SRV_HDRSIZE);
! 	    break;
! 	case SRV_META_USER:
! 	    icqv5_srv_meta_user(icq_tree,
! 			       decr_pd + ICQ5_SRV_HDRSIZE,
! 			       offset + ICQ5_SRV_HDRSIZE,
! 			       pktsize - ICQ5_SRV_HDRSIZE);
! 	    break;
! 	case SRV_RECV_MESSAGE:
! 	    icqv5_srv_recv_message(icq_tree,
! 				   decr_pd + ICQ5_SRV_HDRSIZE,
! 				   offset + ICQ5_SRV_HDRSIZE,
! 				   pktsize - ICQ5_SRV_HDRSIZE);
! 	    break;
! 	case SRV_MULTI:
! 	    icqv5_srv_multi(icq_tree,
! 			    decr_pd + ICQ5_SRV_HDRSIZE,
! 			    offset + ICQ5_SRV_HDRSIZE,
! 			    pktsize - ICQ5_SRV_HDRSIZE,
! 			    fd);
! 	    break;
! 	case SRV_ACK:
! 	case SRV_GO_AWAY:
! 	case SRV_NEW_UIN:
! 	case SRV_BAD_PASS:
! 	case SRV_UPDATE_SUCCESS:
! 	    icqv5_srv_no_params(icq_tree,
! 				decr_pd + ICQ5_SRV_HDRSIZE,
! 				offset + ICQ5_SRV_HDRSIZE,
! 				pktsize - ICQ5_SRV_HDRSIZE,
! 				cmd);
! 	    break;
! 	default:
! 	    proto_tree_add_item_format(icq_tree,
! 				       hf_icq_cmd,
! 				       offset + ICQ5_SRV_CMD,
! 				       2,
! 				       cmd,
! 				       "Command: %d (%s)",
! 				       cmd, findServerCmd(cmd));
! 	    fprintf(stderr,"Missing: %s\n", findServerCmd(cmd));
! 	    break;
! 	}
! 
  	ti = proto_tree_add_text(icq_tree,
  				 offset,
  				 pktsize,
  				 "Decoded packet");
          icq_decode_tree = proto_item_add_subtree(ti,
! 						 ETT_ICQ_DECODE);
! 	proto_tree_add_hexdump(icq_decode_tree, offset, decr_pd, pktsize);
      }
  }
  
***************
*** 961,967 ****
    if (unknown == 0x0L) {
        dissect_icqv5Client(pd, offset, fd, tree);
    } else {
!       dissect_icqv5Server(pd, offset, fd, tree);
    }
  }
  
--- 2163,2169 ----
    if (unknown == 0x0L) {
        dissect_icqv5Client(pd, offset, fd, tree);
    } else {
!       dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1);
    }
  }
  
***************
*** 991,996 ****
--- 2193,2200 ----
  proto_register_icq(void)
  {
      static hf_register_info hf[] = {
+ 	{ &hf_icq_type,
+ 	  {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
  	{ &hf_icq_uin,
  	  {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
  	{ &hf_icq_sessionid,
Index: packet-tcp.c
===================================================================
RCS file: /cvsroot/ethereal/packet-tcp.c,v
retrieving revision 1.40
diff -c -r1.40 packet-tcp.c
*** packet-tcp.c	1999/11/02 07:04:46	1.40
--- packet-tcp.c	1999/11/04 21:51:44
***************
*** 495,501 ****
        pi.match_port = TCP_PORT_PPTP;
        dissect_pptp(pd, offset, fd, tree);
      } else if (PORT_IS(TCP_PORT_HTTP) || PORT_IS(TCP_ALT_PORT_HTTP)
!             || PORT_IS(631))
        dissect_http(pd, offset, fd, tree);
      else if (PORT_IS(TCP_PORT_NBSS)) {
        pi.match_port = TCP_PORT_NBSS;
--- 495,501 ----
        pi.match_port = TCP_PORT_PPTP;
        dissect_pptp(pd, offset, fd, tree);
      } else if (PORT_IS(TCP_PORT_HTTP) || PORT_IS(TCP_ALT_PORT_HTTP)
!             || PORT_IS(631) || PORT_IS(800))
        dissect_http(pd, offset, fd, tree);
      else if (PORT_IS(TCP_PORT_NBSS)) {
        pi.match_port = TCP_PORT_NBSS;
Index: packet.h
===================================================================
RCS file: /cvsroot/ethereal/packet.h,v
retrieving revision 1.124
diff -c -r1.124 packet.h
*** packet.h	1999/10/30 06:10:32	1.124
--- packet.h	1999/11/04 21:51:44
***************
*** 251,260 ****
  	ETT_DNS_ANS,
  	ETT_DNS_RR,
  	ETT_EIGRP,
! 	ETT_CL_ICQ,
! 	ETT_CL_ICQ_DECODE,
! 	ETT_ICQ_SUBTREE,
! 	ETT_SRV_ICQ,
  	ETT_ISAKMP,
  	ETT_ISAKMP_FLAGS,
  	ETT_ISAKMP_PAYLOAD,
--- 251,261 ----
  	ETT_DNS_ANS,
  	ETT_DNS_RR,
  	ETT_EIGRP,
! 	ETT_ICQ,
! 	ETT_ICQ_DECODE,
! 	ETT_ICQ_HEADER,
! 	ETT_ICQ_BODY,
! 	ETT_ICQ_BODY_PARTS,
  	ETT_ISAKMP,
  	ETT_ISAKMP_FLAGS,
  	ETT_ISAKMP_PAYLOAD,