Get rid of a now-unused variable; it's the only variable of type
[obnox/wireshark/wip.git] / packet-icq.c
index c4b3fa54a5dc260d090af5e8e658e2aeb464fd68..f10b78778a5e6af13a6f46f68367498746d7abe6 100644 (file)
@@ -1,11 +1,12 @@
 /* packet-icq.c
  * Routines for ICQ packet disassembly
  *
- * $Id: packet-icq.c,v 1.9 1999/12/05 22:59:55 guy Exp $
+ * $Id: packet-icq.c,v 1.34 2001/06/18 06:31:05 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Johan Feyaerts
- * Copyright 1999 Johan Feyaerts
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
 #include <glib.h>
 
 #ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-#  include <stdarg.h>
-# else
-#  include <varargs.h>
-# endif
 # include "snprintf.h"
 #endif
 
@@ -82,19 +78,20 @@ static gint ett_icq_decode = -1;
 static gint ett_icq_body = -1;
 static gint ett_icq_body_parts = -1;
 
+#define UDP_PORT_ICQ   4000
+
 enum { ICQ5_client, ICQ5_server};
 
-void dissect_icqv5(const u_char *pd,
-                  int offset,
-                  frame_data *fd,
+static void dissect_icqv5(tvbuff_t *tvb,
+                  packet_info *pinfo,
                   proto_tree *tree);
 
 static void
-dissect_icqv5Server(const u_char *pd,
+dissect_icqv5Server(tvbuff_t *tvb,
                    int offset,
-                   frame_data *fd,
+                   packet_info *pinfo,
                    proto_tree *tree,
-                   guint32 pktsize);
+                   int pktsize);
 
 /* Offsets of fields in the ICQ headers */
 /* Can be 0x0002 or 0x0005 */
@@ -128,6 +125,8 @@ typedef struct _cmdcode {
 
 #define SRV_ACK                        0x000a
 
+#define SRV_SILENT_TOO_LONG    0x001e
+
 #define SRV_GO_AWAY            0x0028
 
 #define SRV_NEW_UIN            0x0046
@@ -203,6 +202,7 @@ cmdcode serverMetaSubCmdCode[] = {
 
 cmdcode serverCmdCode[] = {
     { "SRV_ACK", SRV_ACK },
+    { "SRV_SILENT_TOO_LONG", SRV_SILENT_TOO_LONG },
     { "SRV_GO_AWAY", SRV_GO_AWAY },
     { "SRV_NEW_UIN", SRV_NEW_UIN },
     { "SRV_LOGIN_REPLY", SRV_LOGIN_REPLY },
@@ -215,7 +215,7 @@ cmdcode serverCmdCode[] = {
     { "SRV_NEW_USER", 180 },
     { "SRV_UPDATE_EXT", 200 },
     { "SRV_RECV_MESSAGE", SRV_RECV_MESSAGE },
-    { "SRV_X2", 230 },
+    { "SRV_END_OFFLINE_MESSAGES", 230 },
     { "SRV_NOT_CONNECTED", 240 },
     { "SRV_TRY_AGAIN", 250 },
     { "SRV_SYS_DELIVERED_MESS", SRV_SYS_DELIVERED_MESS },
@@ -227,7 +227,7 @@ cmdcode serverCmdCode[] = {
     { "SRV_UPDATE_FAIL", SRV_UPDATE_FAIL },
     { "SRV_AUTH_UPDATE", 500 },
     { "SRV_MULTI_PACKET", SRV_MULTI },
-    { "SRV_X1", 540 },
+    { "SRV_END_CONTACTLIST_STATUS", 540 },
     { "SRV_RAND_USER", SRV_RAND_USER },
     { "SRV_META_USER", SRV_META_USER },
     { NULL, -1 }
@@ -432,90 +432,13 @@ findStatus(int num)
     return findcmd(statusCode, num);
 }
 
-static void
-proto_tree_add_hexdump(proto_tree* t,
-                      guint32 offset,
-                      const u_char *data,
-                      int size)
-{
-    int i;
-    char buf[96];
-    int n;
-    int done = 0, line = 0;
-    int added = 0;
-
-    if (size==0)
-       return;
-    
-    line = size / 16;
-    
-    for (i=0;i<line;i++) {
-       added = 0;
-       done = 0;
-       for (n = i * 16; n < (i+1)*16; n++) {
-           added = sprintf(buf+done, "%02x", data[n]);
-           if ((n%8)==7)
-               added += sprintf(buf + done + added, "  ");
-           else
-               added += sprintf(buf + done + added, " ");
-           done += added;
-       }
-       for (n = i * 16; n < (i+1)*16; n++) {
-           if (isprint(data[n]))
-               added = sprintf(buf + done, "%c", data[n]);
-           else
-               added = sprintf(buf + done, ".");
-           done += added;
-       }
-       proto_tree_add_text(t,
-                           offset + i*16,
-                           16,
-                           buf);
-    }
-    if ((size%16)!=0) {
-       done = 0;
-       for (n = line * 16 ; n < size ; n++) {
-           added = sprintf(buf+done, "%02x", data[n]);
-           if ((n%8)==7)
-               added += sprintf(buf + done + added, "  ");
-           else
-               added += sprintf(buf + done + added, " ");
-           done += added;
-       }
-       for (n = size ; (n%16)!=0;n++) {
-           added = 0;
-           if ((n%8)==7)
-               added += sprintf(buf + done + added, "    ");
-           else
-               added += sprintf(buf + done + added, "   ");
-           done += added;
-       }
-       for (n = line * 16; n < (line+1)*16; n++) {
-           added = 0;
-           if (n<size) {
-               if (isprint(data[n]))
-                   added = sprintf(buf + done, "%c", data[n]);
-               else
-                   added = sprintf(buf + done, ".");
-           } else {
-               added = sprintf(buf + done, " ");
-           }
-           done += added;
-       }
-       proto_tree_add_text(t,
-                           offset + line*16,
-                           size % 16,
-                           buf);
-    }
-}
-
 static guint32
-get_v5key(const u_char* pd, int len)
+get_v5key(tvbuff_t *tvb, int len)
 {
     guint32 a1, a2, a3, a4, a5;
     guint32 code, check, key;
 
-    code = pletohl(&pd[ICQ5_CL_CHECKCODE]);
+    code = tvb_get_letohl(tvb, ICQ5_CL_CHECKCODE);
 
     a1 = code & 0x0001f000;
     a2 = code & 0x07c007c0;
@@ -540,7 +463,8 @@ decrypt_v5(u_char *bfr, guint32 size,guint32 key)
 {
     guint32 i;
     guint32 k;
-    for (i=0x0a; i < size+3; i+=4 ) {
+
+    for (i=ICQ5_CL_SESSIONID; i < size; i+=4 ) {
        k = key+table_v5[i&0xff];
        if ( i != 0x16 ) {
            bfr[i] ^= (u_char)(k & 0xff);
@@ -554,343 +478,332 @@ decrypt_v5(u_char *bfr, guint32 size,guint32 key)
 }
 
 static void
-dissect_icqv2(const u_char *pd,
-             int offset,
-             frame_data *fd, 
+dissect_icqv4(tvbuff_t *tvb,
+             packet_info *pinfo,
              proto_tree *tree)
 {
     /* Not really implemented yet */
-    if (check_col(fd, COL_PROTOCOL)) {
-       col_add_str(fd, COL_PROTOCOL, "ICQv2 (UDP)");
+    if (check_col(pinfo->fd, COL_PROTOCOL)) {
+       col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv4 (UDP)");
     }
-    if (check_col(fd, COL_INFO)) {
-       col_add_str(fd, COL_INFO, "ICQ Version 2 protocol");
+    if (check_col(pinfo->fd, COL_INFO)) {
+       col_set_str(pinfo->fd, COL_INFO, "ICQ Version 4 protocol");
     }
 }
 
-/*
- * Find first occurrence of ch in buf
- * Buf is max size big.
- */
-static char*
-strnchr(const u_char* buf, u_char ch, int size)
+static void
+dissect_icqv3(tvbuff_t *tvb,
+             packet_info *pinfo,
+             proto_tree *tree)
 {
-    int i;
-    u_char* p = (u_char*) buf;
-    for (i=0;(*p) && (*p!=ch) && (i<size); p++, i++)
-       ;
-    if ((*p == '\0') || (i>=size))
-       return NULL;
-    return p;
+    /* Not really implemented yet */
+    if (check_col(pinfo->fd, COL_PROTOCOL)) {
+       col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv3 (UDP)");
+    }
+    if (check_col(pinfo->fd, COL_INFO)) {
+       col_set_str(pinfo->fd, COL_INFO, "ICQ Version 3 protocol");
+    }
+}
+
+static void
+dissect_icqv2(tvbuff_t *tvb,
+             packet_info *pinfo,
+             proto_tree *tree)
+{
+    /* Not really implemented yet */
+    if (check_col(pinfo->fd, COL_PROTOCOL)) {
+       col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv2 (UDP)");
+    }
+    if (check_col(pinfo->fd, COL_INFO)) {
+       col_set_str(pinfo->fd, COL_INFO, "ICQ Version 2 protocol");
+    }
 }
 
 /*
- * The packet at pd has a (len, string) pair.
- * Copy the string to a buffer, and display it in the tree.
- * Observe any limits you might cross.
+ * The packet has, at offset "offset" a (len, string) pair.
+ * Display the length and string in the tree.
  *
  * If anything is wrong, return -1, since -1 is not a valid string
  * length. Else, return the number of chars processed.
  */
 static guint16
 proto_add_icq_attr(proto_tree* tree, /* The tree to add to */
-                  const char* pd, /* Pointer to the field */
-                  const int offset, /* Offset from the start of packet */
-                  const int size, /* The number of bytes left in pd */
+                  tvbuff_t *tvb,    /* Tvbuff with packet */
+                  const int offset, /* Offset from the start of packet of field */
                   char* descr) /* The description to use in the tree */
 {
     guint16 len;
-    char* data;
-    int left = size;
     
-    if (size<sizeof(guint16))
-       return -1;
-    len = pletohs(pd);
-    left -= sizeof(guint16);
-    if (left<len) {
-       proto_tree_add_text(tree,
-                           offset,
-                           sizeof(guint16),
-                           "Length: %d", len);
-       return -1;
-    }
-                           
-    data = g_malloc(len);
-
-    strncpy(data, pd + sizeof(guint16), len);
-    data[len - 1] = '\0';
-
-    proto_tree_add_text(tree,
+    len = tvb_get_letohs(tvb, offset);
+    if (len > tvb_reported_length_remaining(tvb, offset))
+       return -1;      /* length goes past end of packet */
+    proto_tree_add_text(tree, tvb,
                        offset,
                        sizeof(guint16) + len,
-                       "%s[%d]: %s", descr, len, data);
-    g_free(data);
-
+                       "%s[%u]: %.*s", descr, len, len,
+                       tvb_get_ptr(tvb, offset + sizeof(guint16), len));
     return len + sizeof(guint16);
 }
 
 static void
 icqv5_decode_msgType(proto_tree* tree,
-                    const unsigned char* pd, /* From start of messageType */
+                    tvbuff_t *tvb,
                     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[] = {
+    guint16 msgType;
+    gint sep_offset;
+    int sz;            /* Size of the current element */
+    unsigned int n;
+    static char* url_field_descr[] = {
+       "Description",
+       "URL",
+    };
+#define N_URL_FIELDS   (sizeof url_field_descr / sizeof url_field_descr[0])
+    static char* email_field_descr[] = {
        "Nickname",
        "First name",
        "Last name",
        "Email address",
        "Unknown",
-       "Reason"};
-    static char* emain_field_descr[] = {
+       "Text"
+    };
+#define N_EMAIL_FIELDS (sizeof email_field_descr / sizeof email_field_descr[0])
+    static char* auth_req_field_descr[] = {
        "Nickname",
        "First name",
        "Last name",
        "Email address",
        "Unknown",
-       "Text\n"
+       "Reason"
     };
+#define N_AUTH_REQ_FIELDS      (sizeof auth_req_field_descr / sizeof auth_req_field_descr[0])
+    static char* user_added_field_descr[] = {
+       "Nickname",
+       "First name",
+       "Last name",
+       "Email address",
+    };
+#define N_USER_ADDED_FIELDS    (sizeof user_added_field_descr / sizeof user_added_field_descr[0])
     
-    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));
+    msgType = tvb_get_letohs(tvb, offset);
+    ti = proto_tree_add_text(tree, tvb,
+                            offset,
+                            size,
+                            "Message: Type = %u (%s)", msgType, findMsgType(msgType));
     /* Create a new subtree */
     subtree = proto_item_add_subtree(ti, ett_icq_body_parts);
 
+    proto_tree_add_text(subtree, tvb,
+                       offset,
+                       2,
+                       "Type: %u (%s)", msgType, findMsgType(msgType));
+    offset += 2;
+    left -= 2;
+    if (msgType != MSG_AUTH) {
+       /*
+        * XXX - does a MSG_AUTH message really have 3 bytes of information
+        * rather than a length field?
+        */
+       proto_tree_add_text(subtree, tvb,
+                           offset,
+                           2,
+                           "Length: %u",
+                           tvb_get_letohs(tvb, offset));
+       offset += 2;
+       left -= 2;
+    }
+
     switch(msgType) {
     case 0xffff:           /* Field unknown */
        break;
     default:
-       fprintf(stderr, "Unknown msgType: %d (%04x)\n", msgType, msgType);
+       fprintf(stderr, "Unknown msgType: %u (%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,
+       proto_tree_add_text(subtree, tvb,
+                           offset,
                            left,
-                           "Msg: %s", msgText);
-       g_free(msgText);
+                           "Msg: %.*s", left-1,
+                           tvb_get_ptr(tvb, offset, left));
        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;
+       for (n = 0; n < N_URL_FIELDS; n++) {
+           if (n != N_URL_FIELDS - 1) {
+               sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
+               sz = sep_offset - offset + 1;
+           } else
+               sz = left;
+           if (sz != 0) {
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   sz,
+                                   "%s: %.*s",
+                                   url_field_descr[n],
+                                   sz - 1,
+                                   tvb_get_ptr(tvb, offset, sz));
+           } else {
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   0,
+                                   "%s: %s", url_field_descr[n], "(empty)");
+           }
+           offset += sz;
+           left -= sz;
        }
-       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);
+       for (n = 0; n < N_EMAIL_FIELDS; n++) {
+           if (n != N_EMAIL_FIELDS - 1) {
+               sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
+               sz = sep_offset - offset + 1;
+           } else
+               sz = left;
+           if (sz != 0) {
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   sz,
+                                   "%s: %.*s",
+                                   email_field_descr[n],
+                                   sz - 1,
+                                   tvb_get_ptr(tvb, offset, sz));
            } else {
-               proto_tree_add_text(subtree,
-                                   offset + OFF_MSG_TEXT + j,
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
                                    0,
-                                   "%s: %s", emain_field_descr[n], "(empty)");
+                                   "%s: %s", email_field_descr[n], "(empty)");
            }
-           j = ++i;
+           offset += sz;
+           left -= sz;
        }
-       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,
+       unsigned char auth_suc;
+
+       auth_suc = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(subtree, tvb,
+                           offset,
                            1,
-                           "Authorization: (%d) %s",auth_suc,
+                           "Authorization: (%u) %s",auth_suc,
                            (auth_suc==0)?"Denied":"Allowed");
-       proto_tree_add_text(subtree,
-                           offset + OFF_MSG_LEN + 1,
+       offset++;
+       proto_tree_add_text(subtree, tvb,
+                           offset,
                            sizeof(guint16),
-                           "x1: 0x%04x",x1);
+                           "x1: 0x%04x",
+                           tvb_get_letohs(tvb, offset));
        break;
     }
     case MSG_AUTH_REQ:
-       /* Six parts, separated by FE */
-       i = 0;
-       j = 0;
-       msgText = g_malloc(64);
-       for (n = 0; n < 6 && i<left; n++) {
-            while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
-                i++;
-            if (i<=left) {
-                /* pd[OFF_MSG_TEXT+i] == 0xfe */
-                if (i!=j) {   
-                    /* Otherwise, it'd be a null string */
-                    msgText = g_realloc(msgText, i - j);
-                    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);
-                } else {
-                    proto_tree_add_text(subtree,
-                                        offset + OFF_MSG_TEXT + j,
-                                        i - j,
-                                        "%s: %s", auth_req_field_descr[n], "(null)");
-                }
-                j = ++i;
-                /* i and j point after the 0xfe character */
-            }
-        }    
-
-       if (msgText != NULL)
-           g_free(msgText);
+       for (n = 0; n < N_AUTH_REQ_FIELDS; n++) {
+           if (n != N_AUTH_REQ_FIELDS - 1) {
+               sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
+               sz = sep_offset - offset + 1;
+           } else
+               sz = left;
+           if (sz != 0) {
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   sz,
+                                   "%s: %.*s",
+                                   auth_req_field_descr[n],
+                                   sz - 1,
+                                   tvb_get_ptr(tvb, offset, sz));
+           } else {
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   0,
+                                   "%s: %s", auth_req_field_descr[n], "(empty)");
+           }
+           offset += sz;
+           left -= sz;
+       }
        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 && i<left; n++) {
-            while (i<left && pd[OFF_MSG_TEXT+i]!=0xfe)
-                i++;
-            if (i<=left) {
-                /* pd[OFF_MSG_TEXT+i] == 0xfe */
-                if (i!=j) {   
-                    /* Otherwise, it'd be a null string */
-                    msgText = g_realloc(msgText, i - j);
-                    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);
-                } else {
-                    proto_tree_add_text(subtree,
-                                        offset + OFF_MSG_TEXT + j,
-                                        i - j,
-                                        "%s: %s", auth_req_field_descr[n], "(null)");
-                }
-                j = ++i;
-                /* i and j point after the 0xfe character */
-            }
-        }    
-       if (msgText != NULL)
-           g_free(msgText);
+       for (n = 0; n < N_USER_ADDED_FIELDS; n++) {
+           if (n != N_USER_ADDED_FIELDS - 1) {
+               sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
+               sz = sep_offset - offset + 1;
+           } else
+               sz = left;
+           if (sz != 0) {
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   sz,
+                                   "%s: %.*s",
+                                   user_added_field_descr[n],
+                                   sz - 1,
+                                   tvb_get_ptr(tvb, offset, sz));
+           } else {
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   0,
+                                   "%s: %s", user_added_field_descr[n], "(empty)");
+           }
+           offset += sz;
+           left -= sz;
+       }
        break;
     case MSG_CONTACTS:
     {
-       u_char* p = (u_char*) &pd[OFF_MSG_TEXT];
-       u_char* pprev = p;
+       gint sep_offset_prev;
        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
+       gboolean last = FALSE;
+
+       while (!last) {
+           sep_offset = tvb_find_guint8(tvb, offset, left, 0xfe);
+           if (sep_offset != -1)
+               sz = sep_offset - offset + 1;
+           else {
                sz = left;
-           msgText = g_realloc(msgText, sz+1);
-           strncpy(msgText, pprev, sz);
-           msgText[sz] = '\0';
-           
+               last = TRUE;
+           }
            if (n == 0) {
                /* The first element is the number of Nick/UIN pairs follow */
-               proto_tree_add_text(subtree,
-                                   offset + OFF_MSG_TEXT + done,
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
                                    sz,
-                                   "Number of pairs: %s", msgText);
+                                   "Number of pairs: %.*s",
+                                   sz - 1,
+                                   tvb_get_ptr(tvb, offset, sz));
                n++;
-           } else if (p!=NULL) {
+           } else if (!last) {
                int svsz = sz;
-               left -= (sz+1);
-               pprev = p + 1;
-               p = strnchr(pprev, 0xfe, left);
-               if (p!=NULL)
-                   sz = (int)(p - pprev);
-               else
+
+               left -= sz;
+               sep_offset_prev = sep_offset;
+               sep_offset = tvb_find_guint8(tvb, sep_offset_prev, left,
+                                            0xfe);
+               if (sep_offset != -1)
+                   sz = sep_offset - offset + 1;
+               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);
+                   last = TRUE;
+               }
+               proto_tree_add_text(subtree, tvb,
+                                   offset,
+                                   sz + svsz,
+                                   "%.*s: %.*s",
+                                   svsz - 1,
+                                   tvb_get_ptr(tvb, offset, svsz),
+                                   sz - 1,
+                                   tvb_get_ptr(tvb, sep_offset_prev + 1, sz));
+               n += 2;
            }
            
            left -= (sz+1);
-           pprev = p+1;
+           offset = sep_offset + 1;
        }
-       if (msgText != NULL)
-           g_free(msgText);
        break;
-    }}
+    }
+    }
 }
 
 /*********************************
@@ -900,36 +813,36 @@ icqv5_decode_msgType(proto_tree* tree,
  *********************************/
 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 */
-                    int size)  /* Number of chars left to do */
+             tvbuff_t *tvb, /* Tvbuff with decrypted packet data */
+             int offset) /* Offset from the start of the packet to the content */
 {
-    guint32 random = pletohl(pd + CMD_ACK_RANDOM);
     proto_tree* subtree;
     proto_item* ti;
 
     if (tree){
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        4,
                                        CMD_ACK,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset + CMD_ACK_RANDOM,
                            4,
-                           "Random: 0x%08lx", random);
+                           "Random: 0x%08x",
+                           tvb_get_letohl(tvb, offset + CMD_ACK_RANDOM));
     }
 }
 
 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 */
+icqv5_cmd_rand_search(proto_tree* tree, /* Tree to put the data in */
+                     tvbuff_t *tvb,    /* Decrypted 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);
+    guint16 group;
     proto_tree* subtree;
     proto_item* ti;
 
@@ -948,377 +861,336 @@ icqv5_cmd_rand_search(proto_tree* tree,       /* Tree to put the data in */
     };
     
     if (tree){
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        4,
                                        CMD_RAND_SEARCH,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
+       group = tvb_get_letohs(tvb, offset + CMD_RAND_SEARCH_GROUP);
        if (group>0 && (group<=sizeof(groups)/sizeof(const char*)))
-           proto_tree_add_text(subtree,
+           proto_tree_add_text(subtree, tvb,
                                offset + CMD_RAND_SEARCH_GROUP,
                                4,
-                               "Group: (%d) %s", group, groups[group-1]);
+                               "Group: (%u) %s", group, groups[group-1]);
        else
-           proto_tree_add_text(subtree,
+           proto_tree_add_text(subtree, tvb,
                                offset + CMD_RAND_SEARCH_GROUP,
                                4,
-                               "Group: (%d)", group);
+                               "Group: (%u)", 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 */
+icqv5_cmd_ack_messages(proto_tree* tree, /* Tree to put the data in */
+                      tvbuff_t *tvb,    /* Decrypted packet content */
+                      int offset)       /* Offset from the start of the packet to the content */
 {
-    guint32 random = pletohl(pd + CMD_ACK_MESSAGES_RANDOM);
     proto_tree* subtree;
     proto_item* ti;
 
     if (tree){
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        4,
                                        CMD_ACK_MESSAGES,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset + CMD_ACK_MESSAGES_RANDOM,
                            4,
-                           "Random: 0x%08lx", random);
+                           "Random: 0x%08x",
+                           tvb_get_letohl(tvb, offset + CMD_ACK_MESSAGES_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 */
+icqv5_cmd_keep_alive(proto_tree* tree, /* Tree to put the data in */
+                    tvbuff_t *tvb,    /* Decrypted packet content */
+                    int offset)       /* Offset from the start of the packet to the content */
 {
-    guint32 random = pletohl(pd + CMD_KEEP_ALIVE_RANDOM);
+    guint32 random;
     proto_tree* subtree;
     proto_item* ti;
 
     if (tree){
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        4,
                                        CMD_KEEP_ALIVE,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       random = tvb_get_letohl(tvb, offset + CMD_KEEP_ALIVE_RANDOM);
+       proto_tree_add_text(subtree, tvb,
                            offset + CMD_KEEP_ALIVE_RANDOM,
                            4,
-                           "Random: 0x%08lx", random);
+                           "Random: 0x%08x", 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 */
+icqv5_cmd_send_text_code(proto_tree* tree, /* Tree to put the data in */
+                        tvbuff_t *tvb,    /* Decrypted 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;
+    proto_tree* subtree = NULL;
+    proto_item* ti = NULL;
+    guint16 len = 0;
     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,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
-                                       left,
+                                       size,
                                        CMD_KEEP_ALIVE,
                                        "Body");
+    }
+
+    len = tvb_get_letohs(tvb, offset+CMD_SEND_TEXT_CODE_LEN);
+    if (tree){
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset + CMD_SEND_TEXT_CODE_LEN,
                            2,
                            "Length: %d", len);
-       proto_tree_add_text(subtree,
+    }
+
+    if (len>0) {
+       if (tree){
+           proto_tree_add_text(subtree, tvb,
                            offset + CMD_SEND_TEXT_CODE_TEXT,
                            len,
-                           "Text: %s",text);
-       proto_tree_add_text(subtree,
+                           "Text: %.*s",
+                           len,
+                           tvb_get_ptr(tvb, offset + CMD_SEND_TEXT_CODE_TEXT,
+                                       len));
+       }
+    }
+
+    x1 = tvb_get_letohs(tvb, offset + CMD_SEND_TEXT_CODE_TEXT + len);
+    if (tree){
+       proto_tree_add_text(subtree, tvb,
                            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 */
+icqv5_cmd_add_to_list(proto_tree* tree, /* Tree to put the data in */
+                     tvbuff_t *tvb,    /* Decrypted packet content */
+                     int offset)       /* Offset from the start of the packet to the content */
 {
     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,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        4,
                                        CMD_ADD_TO_LIST,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       uin = tvb_get_letohl(tvb, offset + CMD_ADD_TO_LIST);
+       proto_tree_add_text(subtree, tvb,
                            offset + CMD_ADD_TO_LIST_UIN,
                            4,
-                           "UIN: %ld", uin);
+                           "UIN: %u", 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 */
+icqv5_cmd_status_change(proto_tree* tree, /* Tree to put the data in */
+                       tvbuff_t *tvb,    /* Decrypted packet content */
+                       int offset)       /* Offset from the start of the packet to the content */
 {
-    guint32 status = -1;
+    guint32 status;
     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,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        4,
                                        CMD_STATUS_CHANGE,
                                        "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));
+       status = tvb_get_letohl(tvb, offset + CMD_STATUS_CHANGE_STATUS);
+       proto_tree_add_text(subtree, tvb,
+                           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,
+                  tvbuff_t *tvb,
                   int offset,
                   int size,
                   int cmd)
 {
     proto_tree* subtree;
     proto_item* ti;
-    guint32 receiverUIN = 0xffffffff;
-    guint16 msgType = 0xffff;
-    guint16 msgLen = 0xffff;
     int left = size;           /* left chars to do */
-    
-    if (left < 4)
-       return;
-    receiverUIN = pletohl(pd + CMD_SEND_MSG_RECV_UIN);
-    left -= 4;
-    if (left < 2) 
-       return;
-    msgType = pletohs(pd + CMD_SEND_MSG_MSG_TYPE);
-    left -= 2;
-    if (left < 2) 
-       return;
-    msgLen = pletohs(pd + CMD_SEND_MSG_MSG_LEN);
-    left -= 2;
 
     if (tree) {
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        size,
                                        cmd,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            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);
+                           "Receiver UIN: %u",
+                           tvb_get_letohl(tvb, offset + CMD_SEND_MSG_RECV_UIN));
+       left -= 4;
 
        icqv5_decode_msgType(subtree,
-                            pd + CMD_SEND_MSG_MSG_TYPE,
+                            tvb,
                             offset + CMD_SEND_MSG_MSG_TYPE,
-                            left+4); /* There are 4 bytes more... */
+                            left);
     }
 }
 
 static void
 icqv5_cmd_login(proto_tree* tree,
-               const u_char* pd,
+               tvbuff_t *tvb,
                int offset,
                int size)
 {
     proto_item* ti;
     proto_tree* subtree;
-    time_t theTime = -1;
-    guint32 port = -1;
-    guint32 passwdLen = -1;
-    char* password = NULL;
-    const u_char *ipAddrp = NULL;
-    guint32 status = -1;
-    guint32 left = size;
-
-    if (left>=4) {
-       theTime = pletohl(pd + CMD_LOGIN_TIME);
-    }
-    if (left>=8) {
-       port = pletohl(pd + CMD_LOGIN_PORT);
-    }
-    if (left>=10) {
-       passwdLen = pletohs(pd + CMD_LOGIN_PASSLEN);
-    }
-    if (left>=10+passwdLen) {
-       password = g_malloc(passwdLen + 1);
-       strncpy(password, pd + CMD_LOGIN_PASSWD, passwdLen);
-       password[passwdLen] = '\0';
-    }
+    time_t theTime;
+    char *aTime;
+    guint32 port;
+    guint32 passwdLen;
+    const u_char *ipAddrp;
+    guint32 status;
 
-    if (left>=10+passwdLen+CMD_LOGIN_IP+4) {
-       ipAddrp = pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP;
-    }
-    if (left>=10+passwdLen+CMD_LOGIN_STATUS+4) {
-       status = pletohs(pd + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
-    }
     if (tree) {
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        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,
-                               4,
-                               "Time: %d = %s", theTime, ctime(&theTime));
-       if (port!=-1)
-           proto_tree_add_text(subtree,
-                               offset + CMD_LOGIN_PORT,
-                               4,
-                               "Port: %d", port);
-       if ((passwdLen!=-1) && (password!=NULL))
-           proto_tree_add_text(subtree,
-                               offset + CMD_LOGIN_PASSLEN,
-                               2 + passwdLen,
-                               "Passwd: %s", password);
-       if (ipAddrp!=NULL)
-           proto_tree_add_text(subtree,
-                               offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
-                               4,
-                               "IP: %s", ip_to_str(ipAddrp));
-       if (status!=-1)
-           proto_tree_add_text(subtree,
-                               offset + CMD_LOGIN_PASSWD + CMD_LOGIN_IP,
-                               4,
-                               "Status: %s", findStatus(status));
+       theTime = tvb_get_letohl(tvb, offset + CMD_LOGIN_TIME);
+       aTime = ctime(&theTime);
+       aTime[strlen(aTime)-1] = '\0';
+       proto_tree_add_text(subtree, tvb,
+                           offset + CMD_LOGIN_TIME,
+                           4,
+                           "Time: %ld = %s", (long)theTime, aTime);
+       port = tvb_get_letohl(tvb, offset + CMD_LOGIN_PORT);
+       proto_tree_add_text(subtree, tvb,
+                           offset + CMD_LOGIN_PORT,
+                           4,
+                           "Port: %u", port);
+       passwdLen = tvb_get_letohs(tvb, offset + CMD_LOGIN_PASSLEN);
+       proto_tree_add_text(subtree, tvb,
+                           offset + CMD_LOGIN_PASSLEN,
+                           2 + passwdLen,
+                           "Passwd: %.*s",
+                           (int)passwdLen,
+                           tvb_get_ptr(tvb, offset + CMD_LOGIN_PASSWD,
+                                       passwdLen));
+       ipAddrp = tvb_get_ptr(tvb,
+                       offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
+                       4);
+       proto_tree_add_text(subtree, tvb,
+                           offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_IP,
+                           4,
+                           "IP: %s", ip_to_str(ipAddrp));
+       status = tvb_get_letohs(tvb,
+           offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS);
+       proto_tree_add_text(subtree, tvb,
+                           offset + CMD_LOGIN_PASSWD + passwdLen + CMD_LOGIN_STATUS,
+                           4,
+                           "Status: %s", findStatus(status));
     }
-    if (password!=NULL)
-       g_free(password);
 }
 
 static void
 icqv5_cmd_contact_list(proto_tree* tree,
-                      const u_char* pd,
+                      tvbuff_t *tvb,
                       int offset,
                       int size)
 {
     proto_tree* subtree;
     proto_item* ti;
-    unsigned char num = -1;
-    int i, left;
+    unsigned char num;
+    int i;
     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,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        size,
                                        CMD_CONTACT_LIST,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       num = tvb_get_guint8(tvb, offset + CMD_CONTACT_LIST_NUM);
+       proto_tree_add_text(subtree, tvb,
                            offset + CMD_CONTACT_LIST,
                            1,
-                           "Number of uins: %d", num);
+                           "Number of uins: %u", 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;
-           }
+       for (i = 0; i < num; i++) {
+           uin = tvb_get_letohl(tvb, offset);
+           proto_tree_add_text(subtree, tvb,
+                               offset,
+                               4,
+                               "UIN[%d]: %u", i ,uin);
+           offset += 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 */
+icqv5_cmd_no_params(proto_tree* tree, /* Tree to put the data in */
+                   tvbuff_t *tvb,    /* Decrypted packet content */
+                   int offset,       /* Offset from the start of the packet to the content */
                    int cmd)
 {
     proto_tree* subtree;
     proto_item* ti;
 
     if (tree){
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        0,
                                        cmd,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset,
                            0,
                            "No parameters");
@@ -1332,24 +1204,25 @@ icqv5_cmd_no_params(proto_tree* tree,/* Tree to put the data in */
  **********************
  */
 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 */
+icqv5_srv_no_params(proto_tree* tree, /* Tree to put the data in */
+                   tvbuff_t *tvb,    /* 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,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        0,
                                        cmd,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset,
                            0,
                            "No Parameters");
@@ -1358,26 +1231,25 @@ icqv5_srv_no_params(proto_tree* tree,/* Tree to put the data in */
 
 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 */
+                     tvbuff_t *tvb,   /* Tvbuff with packet */
+                     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];
+    const u_char *ipAddrp;
 
     if (tree) {
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        SRV_LOGIN_REPLY_IP + 8,
                                        SRV_LOGIN_REPLY,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       ipAddrp = tvb_get_ptr(tvb, offset + SRV_LOGIN_REPLY_IP, 4);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_LOGIN_REPLY_IP,
                            4,
                            "IP: %s", ip_to_str(ipAddrp));
@@ -1386,149 +1258,128 @@ icqv5_srv_login_reply(proto_tree* tree,/* Tree to put the data in */
 
 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 */
+                     tvbuff_t *tvb,   /* Tvbuff with packet */
+                     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 + 2)
-       status = pletohs(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);
+    const u_char *ipAddrp;
+    const u_char *realipAddrp;
+    guint32 status;
 
     if (tree) {
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        SRV_LOGIN_REPLY_IP + 8,
                                        SRV_LOGIN_REPLY,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_USER_ONL_UIN,
                            4,
-                           "UIN: %d", uin);
-       proto_tree_add_text(subtree,
+                           "UIN: %u",
+                           tvb_get_letohl(tvb, offset + SRV_USER_ONL_UIN));
+       ipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_IP, 4);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_USER_ONL_IP,
                            4,
                            "IP: %s", ip_to_str(ipAddrp));
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_USER_ONL_PORT,
                            4,
-                           "Port: %d", port);
-       proto_tree_add_text(subtree,
+                           "Port: %u",
+                           tvb_get_letohl(tvb, offset + SRV_USER_ONL_PORT));
+       realipAddrp = tvb_get_ptr(tvb, offset + SRV_USER_ONL_REALIP, 4);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_USER_ONL_REALIP,
                            4,
                            "RealIP: %s", ip_to_str(realipAddrp));
-       proto_tree_add_text(subtree,
+       status = tvb_get_letohs(tvb, offset + SRV_USER_ONL_STATUS);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_USER_ONL_STATUS,
                            2,
                            "Status: %s", findStatus(status));
-       proto_tree_add_text(subtree,
+       /*
+        * 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.
+        */
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_USER_ONL_X2,
                            4,
-                           "Version: %08x", version);
+                           "Version: %08x",
+                           tvb_get_letohl(tvb, offset + SRV_USER_ONL_X2));
     }
 }
 
 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 */
+                     tvbuff_t *tvb,    /* Tvbuff with packet */
+                     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,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        SRV_USER_OFFLINE_UIN + 4,
                                        SRV_USER_OFFLINE,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_USER_OFFLINE_UIN,
                            4,
-                           "UIN: %d", uin);
+                           "UIN: %u",
+                           tvb_get_letohl(tvb, offset + SRV_USER_OFFLINE));
     }
 }
 
 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)
+icqv5_srv_multi(proto_tree* tree, /* Tree to put the data in */
+               tvbuff_t *tvb,    /* Packet content */
+               int offset,       /* Offset from the start of the packet to the content */
+               int size,         /* Number of chars left to do */
+               packet_info* pinfo)
 {
     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,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        size,
                                        SRV_MULTI,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       proto_tree_add_text(subtree,
+       num = tvb_get_guint8(tvb, offset + SRV_MULTI_NUM);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_MULTI_NUM,
                            1,
-                           "Number of pkts: %d", num);
+                           "Number of pkts: %u", 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;
+               pktSz = tvb_get_letohs(tvb, offset);
                offset += 2;
                left -= 2;
                if (left>=pktSz) {
-                   dissect_icqv5Server(p, offset, fd, subtree, pktSz);
-                   p += pktSz;
+                   dissect_icqv5Server(tvb, offset, pinfo, subtree, pktSz);
                    offset += pktSz;
                    left -= pktSz;
                }
@@ -1538,10 +1389,10 @@ icqv5_srv_multi(proto_tree* tree,/* Tree to put the data in */
 }
 
 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 */
+icqv5_srv_meta_user(proto_tree* tree, /* Tree to put the data in */
+                   tvbuff_t *tvb,    /* Tvbuff with packet */
+                   int offset,       /* Offset from the start of the packet to the content */
+                   int size)         /* Number of chars left to do */
 {
 #if 0
     proto_tree* subtree = NULL;
@@ -1549,41 +1400,39 @@ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
     proto_tree* sstree = 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];
+    guint16 subcmd;
+    unsigned char result;
 
     if (tree) {
 #if 0
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        size,
                                        SRV_META_USER,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
-       ti = proto_tree_add_text(subtree,
+       subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
+       ti = proto_tree_add_text(subtree, tvb,
                                 offset + SRV_META_USER_SUBCMD,
                                 2,
                                 "%s", findSubCmd(subcmd));
-       proto_tree_add_text(subtree,
+       result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_META_USER_RESULT,
                            1,
                            "%s", (result==0x0a)?"Success":"Failure");
        sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
 #else
-       ti = proto_tree_add_text(tree,
+       subcmd = tvb_get_letohs(tvb, offset + SRV_META_USER_SUBCMD);
+       ti = proto_tree_add_text(tree, tvb,
                                 offset + SRV_META_USER_SUBCMD,
                                 2,
                                 "%s", findSubCmd(subcmd));
        sstree = proto_item_add_subtree(ti, ett_icq_body_parts);
-       proto_tree_add_text(sstree,
+       result = tvb_get_guint8(tvb, offset + SRV_META_USER_RESULT);
+       proto_tree_add_text(sstree, tvb,
                            offset + SRV_META_USER_RESULT,
                            1,
                            "%s", (result==0x0a)?"Success":"Failure");
@@ -1591,7 +1440,7 @@ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
 
        /* Skip the META_USER header */
        left -= 3;
-       p += 3;
+       offset += 3;
 
        switch(subcmd) {
        case META_EX_USER_FOUND:
@@ -1601,14 +1450,14 @@ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
             */
            guint16 pktLen = -1;
 
-           /* Read the lenght field */
-           pktLen = pletohs(p);
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           /* Read the length field */
+           pktLen = tvb_get_letohs(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(guint16),
-                               "Length: %d", pktLen);
+                               "Length: %u", pktLen);
            
-           p += sizeof(guint16); left -= sizeof(guint16);
+           offset += sizeof(guint16); left -= sizeof(guint16);
        }
        case META_USER_FOUND:
        {
@@ -1617,7 +1466,6 @@ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
             *
             * They are used to "implement" a poorman's exception handling
             */
-           guint32 uin = -1;
            int len = 0;
            char *descr[] = {
                "Nick",
@@ -1626,80 +1474,62 @@ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
                "Email",
                NULL};
            char** d = descr;
-           guint16 x2 = -1;
-           guint32 x3 = -1;
            unsigned char auth;
            /*
             * Read UIN
             */
-           if (left<sizeof(guint32))
-               break;
-           uin = pletohl(p);
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(guint32),
-                               "UIN: %ld", uin);
-           p+=sizeof(guint32);left-=sizeof(guint32);
+                               "UIN: %u",
+                               tvb_get_letohl(tvb, offset));
+           offset+=sizeof(guint32);left-=sizeof(guint32);
 
            for ( ; *d!=NULL; d++) {
                len = proto_add_icq_attr(sstree,
-                                        p,
-                                        offset + size - left,
-                                        left,
+                                        tvb,
+                                        offset,
                                         *d);
                if (len == -1)
                    return;
-               p += len; left -= len;
+               offset += len; left -= len;
            }
            /* Get the authorize setting */
-           if (left<sizeof(unsigned char))
-               break;
-           auth = *p;
-           proto_tree_add_text(sstree,
-                               offset + size - left,
-                               sizeof(guint16),
+           auth = tvb_get_guint8(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
+                               1,
                                "authorization: %s", (auth==0x01)?"Neccessary":"Who needs it");
-           p++; left--;
+           offset++; left--;
            /* Get x2 */
-           if (left<sizeof(guint16))
-               break;
-           x2 = pletohs(p);
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(guint16),
-                               "x2: %04x", x2);
-           p+=sizeof(guint16);left-=sizeof(guint16);
+                               "x2: 0x%04x",
+                               tvb_get_letohs(tvb, offset));
+           offset+=sizeof(guint16);left-=sizeof(guint16);
            /* Get x3 */
-           if (left<sizeof(guint32))
-               break;
-           x3 = pletohl(p);
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(guint32),
-                               "x3: %08x", x3);
-           p+=sizeof(guint32);left-=sizeof(guint32);
+                               "x3: 0x%08x",
+                               tvb_get_letohl(tvb, offset));
+           offset+=sizeof(guint32);left-=sizeof(guint32);
            break;
        }
        case META_ABOUT:
        {
            int len;
-           char* about = NULL;
+
            /* 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,
+           len = tvb_get_letohs(tvb, offset);
+           offset+=sizeof(guint16);left-=sizeof(guint16);
+           proto_tree_add_text(sstree, tvb,
+                               offset - sizeof(guint16),
                                sizeof(guint16)+len,
-                               "About(%d): %s", len, about);
-           p+=len;left-=len;
-           left -= 3;
-           g_free(about);
+                               "About(%d): %.*s", len,
+                               len, tvb_get_ptr(tvb, offset, len));
+           offset+=len;left-=len;
            break;
        }
        case META_USER_INFO:
@@ -1725,93 +1555,75 @@ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
                "Zip",
                NULL};
            const char** d = descr;
-           char* item = NULL;
            guint16 country;
            unsigned char user_timezone = -1;
            unsigned char auth = -1;
            int len = 0;
 #if 0
            /* Get the uin */
-           if (left<sizeof(guint32))
-               break;
-           uin = pletohl(p);
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           uin = tvb_get_letohl(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(guint32),
-                               "UIN: %ld", uin);
-           p+=sizeof(guint32);left-=sizeof(guint32);
+                               "UIN: %u", uin);
+           offset+=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;
+               len = tvb_get_letohs(tvb, offset);
+               offset+=sizeof(guint16);left-=sizeof(guint16);
                if (len>0) {
-                   item = g_malloc(len);
-                   strncpy(item, p, len);
-                   proto_tree_add_text(sstree,
-                                       offset + size - left - sizeof(guint16),
+                   proto_tree_add_text(sstree, tvb,
+                                       offset - sizeof(guint16),
                                        sizeof(guint16)+len,
-                                       "%s(%d): %s",*d, len, item);
-                   g_free(item);
-                   p+=len;left-=len;
+                                       "%s(%d): %.*s",*d, len,
+                                       len - 1,
+                                       tvb_get_ptr(tvb, offset, len - 1));
+                   offset+=len;left-=len;
                }
                d++;
            }
            /* Get country code */
-           if (left<sizeof(guint16))
-               break;
-           country = pletohs(p);
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           country = tvb_get_letohs(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(guint16),
-                               "Countrycode: %d", country);
-           p+=sizeof(guint16); left-=sizeof(guint16);
+                               "Countrycode: %u", country);
+           offset+=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,
+           user_timezone = tvb_get_guint8(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(unsigned char),
-                               "Timezone: %d", user_timezone);
-           p++; left--;
+                               "Timezone: %u", user_timezone);
+           offset++; left--;
            /* Get the authorize setting */
-           if (left<sizeof(unsigned char))
-               break;
-           auth = *p;
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           auth = tvb_get_guint8(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(unsigned char),
-                               "Authorization: (%d) %s",
+                               "Authorization: (%u) %s",
                                auth, (auth==0)?"No":"Yes");
-           p++; left--;
+           offset++; left--;
            /* Get the webaware setting */
-           if (left<sizeof(unsigned char))
-               break;
-           auth = *p;
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           auth = tvb_get_guint8(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(unsigned char),
-                               "Webaware: (%d) %s",
+                               "Webaware: (%u) %s",
                                auth, (auth==0)?"No":"Yes");
-           p++; left--;
+           offset++; left--;
            /* Get the authorize setting */
-           if (left<sizeof(unsigned char))
-               break;
-           auth = *p;
-           proto_tree_add_text(sstree,
-                               offset + size - left,
+           auth = tvb_get_guint8(tvb, offset);
+           proto_tree_add_text(sstree, tvb,
+                               offset,
                                sizeof(unsigned char),
-                               "HideIP: (%d) %s",
+                               "HideIP: (%u) %s",
                                auth, (auth==0)?"No":"Yes");
-           p++; left--;
+           offset++; left--;
            break;
        }
        default:
@@ -1823,10 +1635,10 @@ icqv5_srv_meta_user(proto_tree* tree,      /* Tree to put the data in */
 }
 
 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 */
+icqv5_srv_recv_message(proto_tree* tree, /* Tree to put the data in */
+                      tvbuff_t* tvb,    /* 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;
@@ -1839,42 +1651,35 @@ icqv5_srv_recv_message(proto_tree* tree,      /* Tree to put the data in */
     unsigned char minute = -1;
     
     if (tree) {
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        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;
+       uin = tvb_get_letohl(tvb, offset + SRV_RECV_MSG_UIN);
+       proto_tree_add_uint_format(subtree,
+                                  hf_icq_uin,
+                                  tvb,
+                                  offset + SRV_RECV_MSG_UIN,
+                                  sizeof(guint32),
+                                  uin,
+                                  "UIN: %u", uin);
+       year = tvb_get_letohs(tvb, offset + SRV_RECV_MSG_YEAR);
+       month = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MONTH);
+       day = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_DAY);
+       hour = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_HOUR);
+       minute = tvb_get_guint8(tvb, offset + SRV_RECV_MSG_MINUTE);
+
+       proto_tree_add_text(subtree, tvb,
+                           offset + SRV_RECV_MSG_YEAR,
+                           sizeof(guint16) + 4*sizeof(unsigned char),
+                           "Time: %u-%u-%u %02u:%02u",
+                           day, month, year, hour, minute);
        icqv5_decode_msgType(subtree,
-                            pd + SRV_RECV_MSG_MSG_TYPE,
+                            tvb,
                             offset + SRV_RECV_MSG_MSG_TYPE,
                             left);
     }
@@ -1882,9 +1687,8 @@ icqv5_srv_recv_message(proto_tree* tree,      /* Tree to put the data in */
 
 static void
 icqv5_srv_rand_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 */
+                   tvbuff_t *tvb,         /* Tvbuff with packet */
+                   int offset)            /* Offset from the start of the packet to the content */
 {
     proto_tree* subtree = NULL;
     proto_item* ti = NULL;
@@ -1895,78 +1699,59 @@ icqv5_srv_rand_user(proto_tree* tree,      /* Tree to put the data in */
     unsigned char commClass = -1;
     guint32 status;
     guint16 tcpVer;
-    int left = size;
     
     if (tree) {
-       ti = proto_tree_add_item_format(tree,
+       ti = proto_tree_add_uint_format(tree,
                                        hf_icq_cmd,
+                                       tvb,
                                        offset,
                                        SRV_RAND_USER_TCP_VER + 2,
                                        SRV_RAND_USER,
                                        "Body");
        subtree = proto_item_add_subtree(ti, ett_icq_body);
        /* guint32 UIN */
-       if (left<sizeof(guint32))
-           return;
-       uin = pletohl(pd + SRV_RAND_USER_UIN);
-       proto_tree_add_text(subtree,
+       uin = tvb_get_letohl(tvb, offset + SRV_RAND_USER_UIN);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_RAND_USER_UIN,
                            sizeof(guint32),
-                           "UIN: %ld", uin);
-       left -= sizeof(guint32);
+                           "UIN: %u", uin);
        /* guint32 IP */
-       if (left<sizeof(guint32))
-           return;
-       IP = pd + SRV_RAND_USER_IP;
-       proto_tree_add_text(subtree,
+       IP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_IP, 4);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_RAND_USER_IP,
                            sizeof(guint32),
-                           "IP: %s", ip_to_str(IP));
-       left -= sizeof(guint32);
+                           "IP: %s",
+                           ip_to_str(IP));
        /* guint32 portNum */
-       if (left<sizeof(guint32))
-           return;
-       port = pletohs(pd + SRV_RAND_USER_PORT);
-       proto_tree_add_text(subtree,
+       port = tvb_get_letohs(tvb, offset + SRV_RAND_USER_PORT);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_RAND_USER_UIN,
                            sizeof(guint32),
-                           "Port: %ld", port);
-       left -= sizeof(guint32);
-       /* guint32 realIP */                        
-       if (left<sizeof(guint32))
-           return;
-       realIP = pd + SRV_RAND_USER_REAL_IP;
-       proto_tree_add_text(subtree,
+                           "Port: %u", port);
+       /* guint32 realIP */                
+       realIP = tvb_get_ptr(tvb, offset + SRV_RAND_USER_REAL_IP, 4);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_RAND_USER_REAL_IP,
                            sizeof(guint32),
                            "RealIP: %s", ip_to_str(realIP));
-       left -= sizeof(guint32);
        /* guit16 Communication Class */
-       if (left<sizeof(unsigned char))
-           return;
-       commClass = pd[SRV_RAND_USER_CLASS];
-       proto_tree_add_text(subtree,
+       commClass = tvb_get_guint8(tvb, offset + SRV_RAND_USER_CLASS);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_RAND_USER_CLASS,
                            sizeof(unsigned char),
                            "Class: %s", (commClass!=4)?"User to User":"Through Server");
-       left -= sizeof(unsigned char);
        /* guint32 status */
-       if (left<sizeof(guint32))
-           return;
-       status = pletohs(pd + SRV_RAND_USER_STATUS);
-       proto_tree_add_text(subtree,
+       status = tvb_get_letohs(tvb, offset + SRV_RAND_USER_STATUS);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_RAND_USER_STATUS,
                            sizeof(guint32),
-                           "Status: (%ld) %s", status, findStatus(status));
+                           "Status: (%u) %s", status, findStatus(status));
        /* guint16 tcpVersion */
-       if (left<sizeof(guint16))
-           return;
-       tcpVer = pletohs(pd + SRV_RAND_USER_TCP_VER);
-       proto_tree_add_text(subtree,
+       tcpVer = tvb_get_letohs(tvb, offset + SRV_RAND_USER_TCP_VER);
+       proto_tree_add_text(subtree, tvb,
                            offset + SRV_RAND_USER_TCP_VER,
                            sizeof(guint16),
-                           "TCPVersion: %d", tcpVer);
-       left -= sizeof(guint16);
+                           "TCPVersion: %u", tcpVer);
     }
 }
 
@@ -1974,152 +1759,176 @@ icqv5_srv_rand_user(proto_tree* tree,      /* Tree to put the data in */
  * Dissect all the v5 client traffic. This is encrypted, so be careful.
  */
 static void
-dissect_icqv5Client(const u_char *pd,
-                   int offset,
-                   frame_data *fd, 
+dissect_icqv5Client(tvbuff_t *tvb,
+                   packet_info *pinfo,
                    proto_tree *tree)
 {
     proto_tree *icq_tree = NULL;
     proto_tree *icq_header_tree = NULL;
-    proto_tree *icq_decode_tree = NULL;
     proto_item *ti = NULL;
 
-    guint16 version = -1, cmd = -1;
-    guint16 seqnum1 = 0 , seqnum2 = 0;
-    guint32 uin = -1, sessionid = -1;
-    guint32 key = -1;
-    guint16 pktsize = -1;      /* The size of the ICQ content */
-    u_char decr_pd[1600];      /* Decrypted content, size should be dynamic */
+    guint16 pktsize;           /* The size of the ICQ content */
+    guint32 rounded_size;
+    guint32 key;
+    guint16 cmd;
+    guint8 *decr_pd;           /* Decrypted content */
+    tvbuff_t *decr_tvb;
     
-    pktsize = fd->pkt_len - offset;
-    /* First copy the memory, we don't want to overwrite the old content */
-    memcpy(decr_pd, &pd[offset], pktsize);
-    if (fd->pkt_len > fd->cap_len) {
-       pktsize -= (fd->pkt_len - fd->cap_len);
-    }
-    if (pktsize>0x14) {
-       key = get_v5key(decr_pd, pktsize);
-       decrypt_v5(decr_pd, pktsize, key);
+    pktsize = tvb_length(tvb);
+
+    /* Get the encryption key */
+    key = get_v5key(tvb, pktsize);
+
+    /*
+     * Make a copy of the packet data, and decrypt it.
+     * The decryption processes 4 bytes at a time, and starts at
+     * an offset of ICQ5_CL_SESSIONID (which isn't a multiple of 4),
+     * so we make sure that there are
+     *
+     * (ICQ5_CL_SESSIONID + a multiple of 4)
+     *
+     * bytes in the buffer.
+     */
+    rounded_size = ((((pktsize - ICQ5_CL_SESSIONID) + 3)/4)*4) + ICQ5_CL_SESSIONID;
+    decr_pd = g_malloc(rounded_size);
+    tvb_memcpy(tvb, decr_pd, 0, pktsize);
+    decrypt_v5(decr_pd, rounded_size, key);
     
-       /* This information only makes sense in the decrypted version */
-       uin = pletohl(&decr_pd[ICQ5_CL_UIN]);
-       cmd = pletohs(&decr_pd[ICQ5_CL_CMD]);
-       sessionid = pletohl(&decr_pd[ICQ5_CL_SESSIONID]);
-       version = pletohs(&decr_pd[ICQ_VERSION]);
-       seqnum1 = pletohs(&decr_pd[ICQ5_CL_SEQNUM1]);
-       seqnum2 = pletohs(&decr_pd[ICQ5_CL_SEQNUM2]);
-
-       if (check_col(fd, COL_INFO))
-           col_add_fstr(fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
-    }
+    /* Allocate a new tvbuff, referring to the decrypted data. */
+    decr_tvb = tvb_new_real_data(decr_pd, pktsize, tvb_reported_length(tvb),
+       "Decrypted");
+
+    /* Arrange that the allocated packet data copy be freed when the
+       tvbuff is freed. */
+    tvb_set_free_cb(decr_tvb, g_free);
+
+    /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
+       were handed refers, so it'll get cleaned up when that tvbuff
+       is cleaned up. */
+    tvb_set_child_real_data_tvbuff(tvb, decr_tvb);
+
+    /* Add the decrypted data to the data source list. */
+    pinfo->fd->data_src = g_slist_append(pinfo->fd->data_src, decr_tvb);
+
+    cmd = tvb_get_letohs(decr_tvb, ICQ5_CL_CMD);
+
+    if (check_col(pinfo->fd, COL_INFO))
+        col_add_fstr(pinfo->fd, COL_INFO, "ICQv5 %s", findClientCmd(cmd));
     
     if (tree) {
-        ti = proto_tree_add_item_format(tree,
+        ti = proto_tree_add_protocol_format(tree,
                                 proto_icq,
-                                offset,
-                                pktsize, NULL,
-                                "ICQv5 %s (len %d)",
+                                tvb,
+                                0,
+                                pktsize,
+                                "ICQv5 %s (len %u)",
                                 findClientCmd(cmd),
                                 pktsize);
         icq_tree = proto_item_add_subtree(ti, ett_icq);
-       ti = proto_tree_add_item_format(icq_tree,
+       ti = proto_tree_add_uint_format(icq_tree,
                                        hf_icq_type,
-                                       offset,
+                                       tvb,
+                                       0,
                                        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,
-                                  offset+ICQ5_CL_SESSIONID,
-                                  4,
-                                  sessionid,
-                                  "Session ID: 0x%08x",
-                                  sessionid);
-       proto_tree_add_item_format(icq_header_tree,
+       proto_tree_add_text(icq_header_tree, tvb,
+                           ICQ_VERSION,
+                           2,
+                           "Version: %u",
+                           tvb_get_letohs(tvb, ICQ_VERSION));
+       proto_tree_add_item(icq_header_tree,
+                           hf_icq_uin,
+                           tvb,
+                           ICQ5_CL_UIN,
+                           4,
+                           TRUE);
+       proto_tree_add_item(icq_header_tree,
+                           hf_icq_sessionid,
+                           decr_tvb,
+                           ICQ5_CL_SESSIONID,
+                           4,
+                           TRUE);
+       proto_tree_add_text(icq_header_tree, decr_tvb,
+                           ICQ5_CL_CMD,
+                           2,
+                           "Command: %s (%u)", findClientCmd(cmd), cmd);
+       proto_tree_add_text(icq_header_tree, decr_tvb,
+                           ICQ5_CL_SEQNUM1,
+                           2,
+                           "Seq Number 1: 0x%04x",
+                           tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM1));
+       proto_tree_add_text(icq_header_tree, decr_tvb,
+                           ICQ5_CL_SEQNUM2,
+                           2,
+                           "Seq Number 2: 0x%04x",
+                           tvb_get_letohs(decr_tvb, ICQ5_CL_SEQNUM2));
+       proto_tree_add_uint_format(icq_header_tree,
                                   hf_icq_checkcode,
-                                  offset+ICQ5_CL_CHECKCODE,
+                                  tvb,
+                                  ICQ5_CL_CHECKCODE,
                                   4,
                                   key,
                                   "Key: 0x%08x",
                                   key);
-       proto_tree_add_item_format(icq_header_tree,
-                                  hf_icq_uin,
-                                  offset+ICQ5_CL_UIN,
-                                  4,
-                                  uin,
-                                  "UIN: %ld (0x%08X)",
-                                  uin, uin);
-       proto_tree_add_text(icq_header_tree,
-                           offset + ICQ5_CL_SEQNUM1,
-                           2,
-                           "Seqnum1: 0x%04x", seqnum1);
-       proto_tree_add_text(icq_header_tree,
-                           offset + ICQ5_CL_SEQNUM1,
-                           2,
-                           "Seqnum2: 0x%04x", seqnum2);
        switch(cmd) {
        case CMD_ACK:
            icqv5_cmd_ack(icq_tree,
-                         decr_pd + ICQ5_CL_HDRSIZE,
-                         offset + ICQ5_CL_HDRSIZE,
-                         pktsize - ICQ5_CL_HDRSIZE);
+                         decr_tvb,
+                         ICQ5_CL_HDRSIZE);
            break;
        case CMD_SEND_MSG:
        case CMD_MSG_TO_NEW_USER:
            icqv5_cmd_send_msg(icq_tree,
-                              decr_pd + ICQ5_CL_HDRSIZE,
-                              offset + ICQ5_CL_HDRSIZE,
+                              decr_tvb,
+                              ICQ5_CL_HDRSIZE,
                               pktsize - ICQ5_CL_HDRSIZE,
                               cmd);
            break;
        case CMD_RAND_SEARCH:
            icqv5_cmd_rand_search(icq_tree,
-                                 decr_pd + ICQ5_CL_HDRSIZE,
-                                 offset + ICQ5_CL_HDRSIZE,
+                                 decr_tvb,
+                                 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,
+                           decr_tvb,
+                           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,
+                                    decr_tvb,
+                                    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);
+                                   decr_tvb,
+                                   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);
+                                  decr_tvb,
+                                  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);
+                                decr_tvb,
+                                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);
+                                  decr_tvb,
+                                  ICQ5_CL_HDRSIZE);
            break;
        case CMD_CONTACT_LIST:
            icqv5_cmd_contact_list(icq_tree,
-                                  decr_pd + ICQ5_CL_HDRSIZE,
-                                  offset + ICQ5_CL_HDRSIZE,
+                                  decr_tvb,
+                                  ICQ5_CL_HDRSIZE,
                                   pktsize - ICQ5_CL_HDRSIZE);
            break;
        case CMD_META_USER:
@@ -2127,235 +1936,230 @@ dissect_icqv5Client(const u_char *pd,
        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,
+                               decr_tvb,
+                               ICQ5_CL_HDRSIZE,
                                cmd);
            break;
        default:
-           proto_tree_add_item_format(icq_tree,
+           proto_tree_add_uint_format(icq_tree,
                                       hf_icq_cmd,
-                                      offset+ICQ5_CL_CMD,
+                                      decr_tvb,
+                                      ICQ5_CL_CMD,
                                       2,
                                       cmd,
-                                      "Command: %d (%s)",
+                                      "Command: %u (%s)",
                                       cmd, findClientCmd(cmd));
            fprintf(stderr,"Missing: %s\n", findClientCmd(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);
-
     }
 }
 
 static void
-dissect_icqv5Server(const u_char *pd,
+dissect_icqv5Server(tvbuff_t *tvb,
                    int offset,
-                   frame_data *fd, 
+                   packet_info *pinfo,
                    proto_tree *tree,
-                   guint32 pktsize)
+                   int 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);
+    int changeCol = (pktsize==-1);
 
-    guint16 version, cmd;
-    guint32 uin, sessionid;
-    guint16 seq_num1, seq_num2;
-    guint32 checkcode;
+    guint16 cmd;
     
-    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]);
+    cmd = tvb_get_letohs(tvb, offset + ICQ5_SRV_CMD);
+    if (changeCol && check_col(pinfo->fd, COL_INFO))
+       col_add_fstr(pinfo->fd, COL_INFO, "ICQv5 %s", findServerCmd(cmd));
+
     if (pktsize == -1)
-       pktsize = fd->pkt_len - offset;
-    decr_pd = pd;
+       pktsize = tvb_reported_length(tvb);
     
-    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,
+        ti = proto_tree_add_protocol_format(tree,
                                        proto_icq,
+                                       tvb,
                                        offset,
-                                       pktsize, NULL,
-                                       "ICQv5 %s (len %d)",
+                                       pktsize,
+                                       "ICQv5 %s (len %u)",
                                        findServerCmd(cmd),
                                        pktsize);
        
         icq_tree = proto_item_add_subtree(ti, ett_icq);
 
-       ti = proto_tree_add_item_format(icq_tree,
+       ti = proto_tree_add_uint_format(icq_tree,
                                        hf_icq_type,
+                                       tvb,
                                        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,
+       proto_tree_add_text(icq_header_tree, tvb,
+                           offset + ICQ_VERSION,
                            2,
-                           "Seq Number1: 0x%04x",
-                           seq_num1);
-       proto_tree_add_text(icq_header_tree,
-                           offset+ICQ5_SRV_SEQNUM2,
+                           "Version: %u",
+                           tvb_get_letohs(tvb, ICQ_VERSION));
+       proto_tree_add_item(icq_header_tree,
+                           hf_icq_sessionid,
+                           tvb,
+                           offset + ICQ5_SRV_SESSIONID,
+                           4,
+                           TRUE);
+       proto_tree_add_text(icq_header_tree, tvb,
+                           offset + ICQ5_SRV_CMD,
                            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);
+                           "Command: %s (%u)", findServerCmd(cmd), cmd);
+       proto_tree_add_text(icq_header_tree, tvb,
+                           offset + ICQ5_SRV_SEQNUM1,
+                           2,
+                           "Seq Number 1: 0x%04x",
+                           tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM1));
+       proto_tree_add_text(icq_header_tree, tvb,
+                           offset + ICQ5_SRV_SEQNUM2,
+                           2,
+                           "Seq Number 2: 0x%04x",
+                           tvb_get_letohs(tvb, offset + ICQ5_SRV_SEQNUM2));
+       proto_tree_add_item(icq_header_tree,
+                           hf_icq_uin,
+                           tvb,
+                           offset + ICQ5_SRV_UIN,
+                           4,
+                           TRUE);
+       proto_tree_add_item(icq_header_tree,
+                           hf_icq_checkcode,
+                           tvb,
+                           offset + ICQ5_SRV_CHECKCODE,
+                           4,
+                           TRUE);
        switch (cmd) {
        case SRV_RAND_USER:
            icqv5_srv_rand_user(icq_tree,
-                              decr_pd + ICQ5_SRV_HDRSIZE,
-                              offset + ICQ5_SRV_HDRSIZE,
-                              pktsize - ICQ5_SRV_HDRSIZE);
+                              tvb,
+                              offset + ICQ5_SRV_HDRSIZE);
            break;
        case SRV_SYS_DELIVERED_MESS:
            /* The message structures are all the same. Why not run
             * the same routine? */
            icqv5_cmd_send_msg(icq_tree,
-                              decr_pd + ICQ5_SRV_HDRSIZE,
+                              tvb,
                               offset + ICQ5_SRV_HDRSIZE,
                               pktsize - ICQ5_SRV_HDRSIZE,
                               cmd);
            break;
        case SRV_USER_ONLINE:
            icqv5_srv_user_online(icq_tree,
-                              decr_pd + ICQ5_SRV_HDRSIZE,
+                              tvb,
                               offset + ICQ5_SRV_HDRSIZE,
                               pktsize - ICQ5_SRV_HDRSIZE);
            break;
        case SRV_USER_OFFLINE:
            icqv5_srv_user_offline(icq_tree,
-                              decr_pd + ICQ5_SRV_HDRSIZE,
+                              tvb,
                               offset + ICQ5_SRV_HDRSIZE,
                               pktsize - ICQ5_SRV_HDRSIZE);
            break;
        case SRV_LOGIN_REPLY:
            icqv5_srv_login_reply(icq_tree,
-                              decr_pd + ICQ5_SRV_HDRSIZE,
+                              tvb,
                               offset + ICQ5_SRV_HDRSIZE,
                               pktsize - ICQ5_SRV_HDRSIZE);
            break;
        case SRV_META_USER:
            icqv5_srv_meta_user(icq_tree,
-                              decr_pd + ICQ5_SRV_HDRSIZE,
+                              tvb,
                               offset + ICQ5_SRV_HDRSIZE,
                               pktsize - ICQ5_SRV_HDRSIZE);
            break;
        case SRV_RECV_MESSAGE:
            icqv5_srv_recv_message(icq_tree,
-                                  decr_pd + ICQ5_SRV_HDRSIZE,
+                                  tvb,
                                   offset + ICQ5_SRV_HDRSIZE,
                                   pktsize - ICQ5_SRV_HDRSIZE);
            break;
        case SRV_MULTI:
            icqv5_srv_multi(icq_tree,
-                           decr_pd + ICQ5_SRV_HDRSIZE,
+                           tvb,
                            offset + ICQ5_SRV_HDRSIZE,
                            pktsize - ICQ5_SRV_HDRSIZE,
-                           fd);
+                           pinfo);
            break;
        case SRV_ACK:
+       case SRV_SILENT_TOO_LONG:
        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,
+                               tvb,
                                offset + ICQ5_SRV_HDRSIZE,
                                pktsize - ICQ5_SRV_HDRSIZE,
                                cmd);
            break;
        default:
-           proto_tree_add_item_format(icq_tree,
+           proto_tree_add_uint_format(icq_tree,
                                       hf_icq_cmd,
-                                      offset + ICQ5_SRV_CMD,
+                                      tvb,
+                                      ICQ5_SRV_CMD,
                                       2,
                                       cmd,
-                                      "Command: %d (%s)",
+                                      "Command: %u (%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);
     }
 }
 
-void dissect_icqv5(const u_char *pd,
-                  int offset,
-                  frame_data *fd, 
-                  proto_tree *tree)
+static void dissect_icqv5(tvbuff_t *tvb,
+                         packet_info *pinfo,
+                         proto_tree *tree)
 {
-  guint32 unknown = pletohl(&pd[offset + ICQ5_UNKNOWN]);
+  guint32 unknown;
   
-  if (check_col(fd, COL_PROTOCOL))
-      col_add_str(fd, COL_PROTOCOL, "ICQv5 (UDP)");
-  if (check_col(fd, COL_INFO))
-      col_add_str(fd, COL_INFO, "ICQv5 packet");
+  if (check_col(pinfo->fd, COL_PROTOCOL))
+      col_set_str(pinfo->fd, COL_PROTOCOL, "ICQv5 (UDP)");
+  if (check_col(pinfo->fd, COL_INFO))
+      col_set_str(pinfo->fd, COL_INFO, "ICQv5 packet");
+
+  unknown = tvb_get_letohl(tvb, ICQ5_UNKNOWN);
+
   if (unknown == 0x0L) {
-      dissect_icqv5Client(pd, offset, fd, tree);
+      dissect_icqv5Client(tvb, pinfo, tree);
   } else {
-      dissect_icqv5Server(pd + offset, offset, fd, tree, (guint32) -1);
+      dissect_icqv5Server(tvb, 0, pinfo, tree, -1);
   }
 }
 
-void dissect_icq(const u_char *pd,
-                int offset,
-                frame_data *fd, 
-                proto_tree *tree)
+static void dissect_icq(tvbuff_t *tvb,
+                       packet_info *pinfo,
+                       proto_tree *tree)
 {
-  int version = 0;
+  int version;
 
-  version = pletohs(&pd[offset + ICQ_VERSION]);
+  if (check_col(pinfo->fd, COL_PROTOCOL)) {
+    col_set_str(pinfo->fd, COL_PROTOCOL, "ICQ");
+  }
+  if (check_col(pinfo->fd, COL_INFO)) {
+    col_clear(pinfo->fd, COL_INFO);
+  }
+
+  version = tvb_get_letohs(tvb, ICQ_VERSION);
   switch (version) {
   case 0x0005:
-      dissect_icqv5(pd, offset, fd, tree);
+      dissect_icqv5(tvb, pinfo, tree);
+      break;
+  case 0x0004:
+      dissect_icqv4(tvb, pinfo, tree);
+      break;
+  case 0x0003:
+      dissect_icqv3(tvb, pinfo, tree);
       break;
   case 0x0002:
-      dissect_icqv2(pd, offset, fd, tree);
+      dissect_icqv2(tvb, pinfo, tree);
       break;
   default:
       fprintf(stderr, "ICQ: Unknown version (%d)\n", version);
@@ -2369,17 +2173,17 @@ proto_register_icq(void)
 {
     static hf_register_info hf[] = {
        { &hf_icq_type,
-         {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
+         {"Type", "icq.type", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
        { &hf_icq_uin,
-         {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, ""}},
+         {"UIN", "icq.uin", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
        { &hf_icq_sessionid,
-         {"SessionID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
+         {"Session ID", "icq.sessionid", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
        { &hf_icq_cmd,
-         {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, ""}},
+         {"Command", "icq.cmd", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
        { &hf_icq_checkcode,
-         {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, ""}},
+         {"Checkcode", "icq.checkcode", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
        { &hf_icq_decode,
-         {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, ""}}
+         {"Decode", "icq.decode", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}
     };
     static gint *ett[] = {
         &ett_icq,
@@ -2389,9 +2193,15 @@ proto_register_icq(void)
         &ett_icq_body_parts,
     };
     
-    proto_icq = proto_register_protocol ("ICQ Protocol", "icq");
+    proto_icq = proto_register_protocol("ICQ Protocol", "ICQ", "icq");
     
     proto_register_field_array(proto_icq, hf, array_length(hf));
 
     proto_register_subtree_array(ett, array_length(ett));
 }
+
+void
+proto_reg_handoff_icq(void)
+{
+    dissector_add("udp.port", UDP_PORT_ICQ, dissect_icq, proto_icq);
+}