Add {0, NULL} to the isup_Pass_on_not_possible_indicator_vals and
[obnox/wireshark/wip.git] / packet-afp.c
index 739a2f329b375083b28ec605e952487b6995a425..944766f4a2362a380f17550fcd782e390a280649 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for afp packet dissection
  * Copyright 2002, Didier Gautheron <dgautheron@magic.fr>
  *
- * $Id: packet-afp.c,v 1.2 2002/04/28 19:21:38 guy Exp $
+ * $Id: packet-afp.c,v 1.32 2003/06/26 18:18:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include <stdio.h>
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
 #ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-#  include <stdarg.h>
-# else
-#  include <varargs.h>
-# endif
 # include "snprintf.h"
 #endif
 
 
   AFP 2.1 & 2.2.pdf contained in AppleShare_IP_6.3_SDK
   available from http://www.apple.com
+
   AFP3.0.pdf from http://www.apple.com
-  
+  AFP3.1.pdf from http://www.apple.com
+
   The netatalk source code by Wesley Craig & Adrian Sun
        http://netatalk.sf.net
 */
 #define AFPTRANS_TCP          (1 << 1)
 #define AFPTRANS_ALL          (AFPTRANS_DDP | AFPTRANS_TCP)
 
-/* server flags */
-#define AFPSRVRINFO_COPY                       (1<<0)  /* supports copyfile */
-#define AFPSRVRINFO_PASSWD                     (1<<1)  /* supports change password */
-#define AFPSRVRINFO_NOSAVEPASSWD       (1<<2)  /* don't allow save password */
-#define AFPSRVRINFO_SRVMSGS            (1<<3)  /* supports server messages */
-#define AFPSRVRINFO_SRVSIGNATURE       (1<<4)  /* supports server signature */
-#define AFPSRVRINFO_TCPIP              (1<<5)  /* supports tcpip */
-#define AFPSRVRINFO_SRVNOTIFY          (1<<6)  /* supports server notifications */ 
-#define AFPSRVRINFO_FASTBOZO           (1<<15) /* fast copying */
-
 /* AFP Attention Codes -- 4 bits */
 #define AFPATTN_SHUTDOWN     (1 << 15)            /* shutdown/disconnect */
 #define AFPATTN_CRASH        (1 << 14)            /* server crashed */
 #define AFPATTN_MESG         (1 << 13)            /* server has message */
 #define AFPATTN_NORECONNECT  (1 << 12)            /* don't reconnect */
 /* server notification */
-#define AFPATTN_NOTIFY       (AFPATTN_MESG | AFPATTN_NORECONNECT) 
+#define AFPATTN_NOTIFY       (AFPATTN_MESG | AFPATTN_NORECONNECT)
 
 /* extended bitmap -- 12 bits. volchanged is only useful w/ a server
  * notification, and time is only useful for shutdown. */
 #define AFP_GETFLDRPARAM       34
 #define AFP_SETFLDRPARAM       35
 #define AFP_CHANGEPW           36
+#define AFP_GETUSERINFO                37
 #define AFP_GETSRVRMSG         38
 #define AFP_CREATEID           39
 #define AFP_DELETEID           40
 #define AFP_ADDCMT          56
 #define AFP_RMVCMT          57
 #define AFP_GETCMT          58
+#define AFP_ZZZ            122
 #define AFP_ADDICON        192
 
+/* AFP 3.0 new calls */
+#define AFP_BYTELOCK_EXT       59
+#define AFP_CATSEARCH_EXT      67
+#define AFP_ENUMERATE_EXT      66
+#define AFP_READ_EXT           60
+#define AFP_WRITE_EXT          61
+#define AFP_LOGIN_EXT          63
+#define AFP_GETSESSTOKEN       64
+#define AFP_DISCTOLDSESS        65
+
+/* AFP 3.1 new calls */
+#define AFP_ENUMERATE_EXT2     68
+
 /* ----------------------------- */
 static int proto_afp = -1;
-static int hf_afp_requestid = -1;
-static int hf_afp_code = -1;
-static int hf_afp_length = -1;
 static int hf_afp_reserved = -1;
 
 static int hf_afp_command = -1;                /* CommandCode */
-static int hf_afp_AFPVersion = -1; 
-static int hf_afp_UAM = -1; 
-static int hf_afp_user = -1; 
-static int hf_afp_passwd = -1; 
+static int hf_afp_AFPVersion = -1;
+static int hf_afp_UAM = -1;
+static int hf_afp_user = -1;
+static int hf_afp_passwd = -1;
+static int hf_afp_random = -1;
+
+static int hf_afp_login_flags = -1;
 static int hf_afp_pad = -1;
 
+static int hf_afp_user_type = -1;
+static int hf_afp_user_len = -1;
+static int hf_afp_user_name = -1;
+
+static int hf_afp_vol_flag_passwd       = -1;
+static int hf_afp_vol_flag_unix_priv = -1;
+static int hf_afp_server_time           = -1;
+
 static int hf_afp_vol_bitmap = -1;
-static int hf_afp_bitmap_offset = -1;
+static int hf_afp_vol_name_offset = -1;
 static int hf_afp_vol_id = -1;
 static int hf_afp_vol_attribute = -1;
 static int hf_afp_vol_name = -1;
@@ -195,7 +196,6 @@ static int hf_afp_file_DataForkLen    = -1;
 static int hf_afp_file_RsrcForkLen    = -1;
 static int hf_afp_file_ExtDataForkLen = -1;
 static int hf_afp_file_ExtRsrcForkLen = -1;
-static int hf_afp_file_UnixPrivs      = -1;
 
 static int hf_afp_dir_bitmap    = -1;
 static int hf_afp_dir_offspring  = -1;
@@ -205,27 +205,46 @@ static int hf_afp_dir_GroupID    = -1;
 static int hf_afp_file_bitmap = -1;
 static int hf_afp_req_count = -1;
 static int hf_afp_start_index = -1;
+static int hf_afp_start_index32 = -1;
 static int hf_afp_max_reply_size = -1;
+static int hf_afp_max_reply_size32 = -1;
 static int hf_afp_file_flag = -1;
 static int hf_afp_create_flag = -1;
 static int hf_afp_struct_size = -1;
+static int hf_afp_struct_size16 = -1;
+
+static int hf_afp_cat_count            = -1;
+static int hf_afp_cat_req_matches   = -1;
+static int hf_afp_cat_position         = -1;
 
 static int hf_afp_creation_date = -1;
 static int hf_afp_modification_date = -1;
 static int hf_afp_backup_date = -1;
 static int hf_afp_finder_info = -1;
+static int hf_afp_long_name_offset = -1;
+static int hf_afp_short_name_offset = -1;
+static int hf_afp_unicode_name_offset = -1;
+static int hf_afp_unix_privs_uid = -1;
+static int hf_afp_unix_privs_gid = -1;
+static int hf_afp_unix_privs_permissions = -1;
+static int hf_afp_unix_privs_ua_permissions = -1;
 
 static int hf_afp_path_type = -1;
 static int hf_afp_path_len = -1;
 static int hf_afp_path_name = -1;
-
-static int hf_afp_flag         = -1;
-static int hf_afp_dt_ref       = -1;
-static int hf_afp_ofork        = -1;
-static int hf_afp_ofork_len = -1;
-static int hf_afp_offset       = -1;
-static int hf_afp_rw_count     = -1;
-static int hf_afp_actual_count = -1;
+static int hf_afp_path_unicode_hint = -1;
+static int hf_afp_path_unicode_len = -1;
+
+static int hf_afp_flag         = -1;
+static int hf_afp_dt_ref       = -1;
+static int hf_afp_ofork                = -1;
+static int hf_afp_ofork_len    = -1;
+static int hf_afp_offset       = -1;
+static int hf_afp_rw_count     = -1;
+static int hf_afp_newline_mask = -1;
+static int hf_afp_newline_char = -1;
+static int hf_afp_last_written = -1;
+static int hf_afp_actual_count = -1;
 
 static int hf_afp_fork_type                    = -1;
 static int hf_afp_access_mode          = -1;
@@ -252,113 +271,254 @@ static gint ett_afp_dir_bitmap = -1;
 static gint ett_afp_dir_attribute = -1;
 static gint ett_afp_file_attribute = -1;
 static gint ett_afp_file_bitmap = -1;
+static gint ett_afp_unix_privs = -1;
 static gint ett_afp_path_name = -1;
 static gint ett_afp_lock_flags = -1;
 static gint ett_afp_dir_ar = -1;
 
-static dissector_handle_t afp_handle;
+static gint ett_afp_server_vol         = -1;
+static gint ett_afp_vol_list           = -1;
+static gint ett_afp_vol_flag           = -1;
+static gint ett_afp_cat_search                 = -1;
+static gint ett_afp_cat_r_bitmap       = -1;
+static gint ett_afp_cat_spec           = -1;
+static gint ett_afp_vol_did    = -1;
+
+/* AFP 3.0 parameters */
+static gint hf_afp_lock_offset64       = -1;
+static gint hf_afp_lock_len64          = -1;
+static gint hf_afp_lock_range_start64  = -1;
+
+static int hf_afp_offset64             = -1;
+static int hf_afp_rw_count64           = -1;
+
+static int hf_afp_last_written64       = -1;
+
+static int hf_afp_ofork_len64           = -1;
+static int hf_afp_session_token_type   = -1;
+static int hf_afp_session_token_len    = -1;
+static int hf_afp_session_token                = -1;
+static int hf_afp_session_token_timestamp = -1;
+
 static dissector_handle_t data_handle;
 
 static const value_string vol_signature_vals[] = {
        {1, "Flat"},
-       {2,  "Fixed Directory ID"},
-       {3,  "Variable Directory ID (deprecated)"},
-       {0,                              NULL } };
+       {2, "Fixed Directory ID"},
+       {3, "Variable Directory ID (deprecated)"},
+       {0, NULL }
+};
 
 static const value_string CommandCode_vals[] = {
-  {AFP_BYTELOCK,       "afpByteRangeLock" },
-  {AFP_CLOSEVOL,       "afpVolClose" },
-  {AFP_CLOSEDIR,       "afpDirClose" },
-  {AFP_CLOSEFORK,      "afpForkClose" },
-  {AFP_COPYFILE,       "afpCopyFile" },
-  {AFP_CREATEDIR,      "afpDirCreate" },
-  {AFP_CREATEFILE,     "afpFileCreate" },
-  {AFP_DELETE,         "afpDelete" },
-  {AFP_ENUMERATE,      "afpEnumerate" },
-  {AFP_FLUSH,          "afpFlush" },
-  {AFP_FLUSHFORK,      "afpForkFlush" },
-  {AFP_GETFORKPARAM,"afpGetForkParms" },
-  {AFP_GETSRVINFO,     "afpGetSInfo" },
-  {AFP_GETSRVPARAM,    "afpGetSParms" },
-  {AFP_GETVOLPARAM,    "afpGetVolParms" },
-  {AFP_LOGIN,          "afpLogin" },
-  {AFP_LOGINCONT,      "afpContLogin" },
-  {AFP_LOGOUT,         "afpLogout" },
-  {AFP_MAPID,          "afpMapID" },
-  {AFP_MAPNAME,                "afpMapName" },
-  {AFP_MOVE,           "afpMove" },
-  {AFP_OPENVOL,                "afpOpenVol" },
-  {AFP_OPENDIR,                "afpOpenDir" },
-  {AFP_OPENFORK,       "afpOpenFork" },
-  {AFP_READ,           "afpRead" },
-  {AFP_RENAME,         "afpRename" },
-  {AFP_SETDIRPARAM,    "afpSetDirParms" },
-  {AFP_SETFILEPARAM,"afpSetFileParms" },
-  {AFP_SETFORKPARAM,"afpSetForkParms" },
-  {AFP_SETVOLPARAM,    "afpSetVolParms" },
-  {AFP_WRITE,          "afpWrite" },
-  {AFP_GETFLDRPARAM,"afpGetFlDrParms" },
-  {AFP_SETFLDRPARAM,"afpSetFlDrParms" },
-  {AFP_CHANGEPW,       "afpChangePw" },
-  {AFP_GETSRVRMSG,     "afpGetSrvrMsg" },
-  {AFP_CREATEID,       "afpCreateID" },
-  {AFP_DELETEID,       "afpDeleteID" },
-  {AFP_RESOLVEID,      "afpResolveID" },
-  {AFP_EXCHANGEFILE,"afpExchangeFiles" },
-  {AFP_CATSEARCH,      "afpCatSearch" },
-  {AFP_OPENDT,         "afpDTOpen" },
-  {AFP_CLOSEDT,                "afpDTClose" },
-  {AFP_GETICON,                "afpGetIcon" },
-  {AFP_GTICNINFO,      "afpGtIcnInfo" },
-  {AFP_ADDAPPL,                "afpAddAPPL" },
-  {AFP_RMVAPPL,                "afpRmvAPPL" },
-  {AFP_GETAPPL,                "afpGetAPPL" },
-  {AFP_ADDCMT,         "afpAddCmt" },
-  {AFP_RMVCMT,         "afpRmvCmt" },
-  {AFP_GETCMT,         "afpGetCmt" },
-  {AFP_ADDICON,                "afpAddIcon" },
-  {0,                           NULL } };
-
+  {AFP_BYTELOCK,       "FPByteRangeLock" },
+  {AFP_CLOSEVOL,       "FPCloseVol" },
+  {AFP_CLOSEDIR,       "FPCloseDir" },
+  {AFP_CLOSEFORK,      "FPCloseFork" },
+  {AFP_COPYFILE,       "FPCopyFile" },
+  {AFP_CREATEDIR,      "FPCreateDir" },
+  {AFP_CREATEFILE,     "FPCreateFile" },
+  {AFP_DELETE,         "FPDelete" },
+  {AFP_ENUMERATE,      "FPEnumerate" },
+  {AFP_FLUSH,          "FPFlush" },
+  {AFP_FLUSHFORK,      "FPFlushFork" },
+  {AFP_GETFORKPARAM,   "FPGetForkParms" },
+  {AFP_GETSRVINFO,     "FPGetSrvrInfo" },
+  {AFP_GETSRVPARAM,    "FPGetSrvrParms" },
+  {AFP_GETVOLPARAM,    "FPGetVolParms" },
+  {AFP_LOGIN,          "FPLogin" },
+  {AFP_LOGINCONT,      "FPLoginCont" },
+  {AFP_LOGOUT,         "FPLogout" },
+  {AFP_MAPID,          "FPMapID" },
+  {AFP_MAPNAME,                "FPMapName" },
+  {AFP_MOVE,           "FPMoveAndRename" },
+  {AFP_OPENVOL,                "FPOpenVol" },
+  {AFP_OPENDIR,                "FPOpenDir" },
+  {AFP_OPENFORK,       "FPOpenFork" },
+  {AFP_READ,           "FPRead" },
+  {AFP_RENAME,         "FPRename" },
+  {AFP_SETDIRPARAM,    "FPSetDirParms" },
+  {AFP_SETFILEPARAM,   "FPSetFileParms" },
+  {AFP_SETFORKPARAM,   "FPSetForkParms" },
+  {AFP_SETVOLPARAM,    "FPSetVolParms" },
+  {AFP_WRITE,          "FPWrite" },
+  {AFP_GETFLDRPARAM,   "FPGetFileDirParms" },
+  {AFP_SETFLDRPARAM,   "FPSetFileDirParms" },
+  {AFP_CHANGEPW,       "FPChangePassword" },
+  {AFP_GETUSERINFO,     "FPGetUserInfo" },
+  {AFP_GETSRVRMSG,     "FPGetSrvrMsg" },
+  {AFP_CREATEID,       "FPCreateID" },
+  {AFP_DELETEID,       "FPDeleteID" },
+  {AFP_RESOLVEID,      "FPResolveID" },
+  {AFP_EXCHANGEFILE,   "FPExchangeFiles" },
+  {AFP_CATSEARCH,      "FPCatSearch" },
+  {AFP_OPENDT,         "FPOpenDT" },
+  {AFP_CLOSEDT,                "FPCloseDT" },
+  {AFP_GETICON,                "FPGetIcon" },
+  {AFP_GTICNINFO,      "FPGetIconInfo" },
+  {AFP_ADDAPPL,                "FPAddAPPL" },
+  {AFP_RMVAPPL,                "FPRemoveAPPL" },
+  {AFP_GETAPPL,                "FPGetAPPL" },
+  {AFP_ADDCMT,         "FPAddComment" },
+  {AFP_RMVCMT,         "FPRemoveComment" },
+  {AFP_GETCMT,         "FPGetComment" },
+  {AFP_BYTELOCK_EXT,   "FPByteRangeLockExt" },
+  {AFP_CATSEARCH_EXT,  "FPCatSearchExt" },
+  {AFP_ENUMERATE_EXT,  "FPEnumerateExt" },
+  {AFP_ENUMERATE_EXT2, "FPEnumerateExt2" },
+  {AFP_READ_EXT,       "FPReadExt" },
+  {AFP_WRITE_EXT,      "FPWriteExt" },
+  {AFP_LOGIN_EXT,      "FPLoginExt" },
+  {AFP_GETSESSTOKEN,   "FPGetSessionToken" },
+  {AFP_DISCTOLDSESS,    "FPDisconnectOldSession" },
+  {AFP_ZZZ,             "FPzzz" },
+  {AFP_ADDICON,                "FPAddIcon" },
+  {0,                   NULL }
+};
+
+static const value_string unicode_hint_vals[] = {
+   { 0,           "MacRoman" },
+   { 1,           "MacJapanese" },
+   { 2,           "MacChineseTrad" },
+   { 3,           "MacKorean" },
+   { 4,           "MacArabic" },
+   { 5,           "MacHebrew" },
+   { 6,           "MacGreek" },
+   { 7,           "MacCyrillic" },
+   { 9,           "MacDevanagari" },
+   { 10,   "MacGurmukhi" },
+   { 11,   "MacGujarati" },
+   { 12,   "MacOriya" },
+   { 13,   "MacBengali" },
+   { 14,   "MacTamil" },
+   { 15,   "MacTelugu" },
+   { 16,   "MacKannada" },
+   { 17,   "MacMalayalam" },
+   { 18,   "MacSinhalese" },
+   { 19,   "MacBurmese" },
+   { 20,   "MacKhmer" },
+   { 21,   "MacThai" },
+   { 22,   "MacLaotian" },
+   { 23,   "MacGeorgian" },
+   { 24,   "MacArmenian" },
+   { 25,   "MacChineseSimp" },
+   { 26,   "MacTibetan" },
+   { 27,   "MacMongolian" },
+   { 28,   "MacEthiopic" },
+   { 29,   "MacCentralEurRoman" },
+   { 30,   "MacVietnamese" },
+   { 31,   "MacExtArabic" },
+   { 33,   "MacSymbol" },
+   { 34,   "MacDingbats" },
+   { 35,   "MacTurkish" },
+   { 36,   "MacCroatian" },
+   { 37,   "MacIcelandic" },
+   { 38,   "MacRomanian" },
+   { 39,   "MacCeltic" },
+   { 40,   "MacGaelic" },
+   { 41,   "MacKeyboardGlyphs" },
+   { 126,  "MacUnicode" },
+   { 140,  "MacFarsi" },
+   { 152,  "MacUkrainian" },
+   { 236,  "MacInuit" },
+   { 252,  "MacVT100" },
+   { 255,  "MacHFS" },
+   { 256,  "UnicodeDefault" },
+/* { 257,  "UnicodeV1_1" },  */
+   { 257,  "ISO10646_1993" },
+   { 259,  "UnicodeV2_0" },
+   { 259,  "UnicodeV2_1" },
+   { 260,  "UnicodeV3_0" },
+   { 513,  "ISOLatin1" },
+   { 514,  "ISOLatin2" },
+   { 515,  "ISOLatin3" },
+   { 516,  "ISOLatin4" },
+   { 517,  "ISOLatinCyrillic" },
+   { 518,  "ISOLatinArabic" },
+   { 519,  "ISOLatinGreek" },
+   { 520,  "ISOLatinHebrew" },
+   { 521,  "ISOLatin5" },
+   { 522,  "ISOLatin6" },
+   { 525,  "ISOLatin7" },
+   { 526,  "ISOLatin8" },
+   { 527,  "ISOLatin9" },
+   { 1024, "DOSLatinUS" },
+   { 1029, "DOSGreek" },
+   { 1030, "DOSBalticRim" },
+   { 1040, "DOSLatin1" },
+   { 1041, "DOSGreek1" },
+   { 1042, "DOSLatin2" },
+   { 1043, "DOSCyrillic" },
+   { 1044, "DOSTurkish" },
+   { 1045, "DOSPortuguese" },
+   { 1046, "DOSIcelandic" },
+   { 1047, "DOSHebrew" },
+   { 1048, "DOSCanadianFrench" },
+   { 1049, "DOSArabic" },
+   { 1050, "DOSNordic" },
+   { 1051, "DOSRussian" },
+   { 1052, "DOSGreek2" },
+   { 1053, "DOSThai" },
+   { 1056, "DOSJapanese" },
+   { 1057, "DOSChineseSimplif" },
+   { 1058, "DOSKorean" },
+   { 1059, "DOSChineseTrad" },
+   { 1280, "WindowsLatin1" },
+/* { 1280, "WindowsANSI" }, */
+   { 1281, "WindowsLatin2" },
+   { 1282, "WindowsCyrillic" },
+   { 1283, "WindowsGreek" },
+   { 1284, "WindowsLatin5" },
+   { 1285, "WindowsHebrew" },
+   { 1286, "WindowsArabic" },
+   { 1287, "WindowsBalticRim" },
+   { 1288, "WindowsVietnamese" },
+   { 1296, "WindowsKoreanJohab" },
+   { 1536, "US_ASCII" },
+   { 1568, "JIS_X0201_76" },
+   { 1569, "JIS_X0208_83" },
+   { 1570, "JIS_X0208_90" },
+   { 0,           NULL }
+};
 
 /* volume bitmap
-  from Apple AFP3.0.pdf 
+  from Apple AFP3.0.pdf
   Table 1-2 p. 20
 */
 #define kFPVolAttributeBit             (1 << 0)
 #define kFPVolSignatureBit             (1 << 1)
-#define kFPVolCreateDateBit    (1 << 2)
+#define kFPVolCreateDateBit            (1 << 2)
 #define kFPVolModDateBit               (1 << 3)
-#define kFPVolBackupDateBit    (1 << 4)
+#define kFPVolBackupDateBit            (1 << 4)
 #define kFPVolIDBit                    (1 << 5)
-#define kFPVolBytesFreeBit     (1 << 6)
+#define kFPVolBytesFreeBit             (1 << 6)
 #define kFPVolBytesTotalBit            (1 << 7)
 #define kFPVolNameBit                  (1 << 8)
-#define kFPVolExtBytesFreeBit  (1 << 9)
-#define kFPVolExtBytesTotalBit (1 << 10)
+#define kFPVolExtBytesFreeBit          (1 << 9)
+#define kFPVolExtBytesTotalBit         (1 << 10)
 #define kFPVolBlockSizeBit             (1 << 11)
 
-static int hf_afp_vol_bitmap_Attribute                 = -1;
+static int hf_afp_vol_bitmap_Attributes        = -1;
 static int hf_afp_vol_bitmap_Signature                 = -1;
 static int hf_afp_vol_bitmap_CreateDate        = -1;
 static int hf_afp_vol_bitmap_ModDate           = -1;
 static int hf_afp_vol_bitmap_BackupDate        = -1;
-static int hf_afp_vol_bitmap_ID                        = -1;
+static int hf_afp_vol_bitmap_ID                = -1;
 static int hf_afp_vol_bitmap_BytesFree                 = -1;
 static int hf_afp_vol_bitmap_BytesTotal        = -1;
-static int hf_afp_vol_bitmap_Name                      = -1;
+static int hf_afp_vol_bitmap_Name              = -1;
 static int hf_afp_vol_bitmap_ExtBytesFree      = -1;
 static int hf_afp_vol_bitmap_ExtBytesTotal     = -1;
 static int hf_afp_vol_bitmap_BlockSize                 = -1;
 
-static int hf_afp_vol_attribute_ReadOnly                    = -1;
-static int hf_afp_vol_attribute_HasVolumePassword                      = -1;
-static int hf_afp_vol_attribute_SupportsFileIDs             = -1;
-static int hf_afp_vol_attribute_SupportsCatSearch           = -1;
-static int hf_afp_vol_attribute_SupportsBlankAccessPrivs    = -1;
-static int hf_afp_vol_attribute_SupportsUnixPrivs           = -1;
-static int hf_afp_vol_attribute_SupportsUTF8Names           = -1;
+static int hf_afp_vol_attribute_ReadOnly                       = -1;
+static int hf_afp_vol_attribute_HasVolumePassword              = -1;
+static int hf_afp_vol_attribute_SupportsFileIDs                        = -1;
+static int hf_afp_vol_attribute_SupportsCatSearch              = -1;
+static int hf_afp_vol_attribute_SupportsBlankAccessPrivs       = -1;
+static int hf_afp_vol_attribute_SupportsUnixPrivs              = -1;
+static int hf_afp_vol_attribute_SupportsUTF8Names              = -1;
 
-static int hf_afp_dir_bitmap_Attribute         = -1;
+static int hf_afp_dir_bitmap_Attributes     = -1;
 static int hf_afp_dir_bitmap_ParentDirID    = -1;
 static int hf_afp_dir_bitmap_CreateDate     = -1;
 static int hf_afp_dir_bitmap_ModDate        = -1;
@@ -386,7 +546,7 @@ static int hf_afp_dir_attribute_RenameInhibit = -1;
 static int hf_afp_dir_attribute_DeleteInhibit = -1;
 static int hf_afp_dir_attribute_SetClear      = -1;
 
-static int hf_afp_file_bitmap_Attribute                 = -1;
+static int hf_afp_file_bitmap_Attributes     = -1;
 static int hf_afp_file_bitmap_ParentDirID    = -1;
 static int hf_afp_file_bitmap_CreateDate     = -1;
 static int hf_afp_file_bitmap_ModDate        = -1;
@@ -416,46 +576,52 @@ static int hf_afp_file_attribute_DeleteInhibit = -1;
 static int hf_afp_file_attribute_CopyProtect   = -1;
 static int hf_afp_file_attribute_SetClear      = -1;
 
-static const value_string vol_bitmap_vals[] = {
-  {kFPVolAttributeBit,          "VolAttribute"},
-  {kFPVolSignatureBit,                 "VolSignature"},
-  {kFPVolCreateDateBit,                        "VolCreateDate"},
-  {kFPVolModDateBit,                   "VolModDate"},
-  {kFPVolBackupDateBit,                        "VolBackupDate"},
-  {kFPVolIDBit,                                        "VolID"},
-  {kFPVolBytesFreeBit,                 "VolBytesFree"},
-  {kFPVolBytesTotalBit,                        "VolBytesTotal"},
-  {kFPVolNameBit,                              "VolNameBit"},
-  {kFPVolExtBytesFreeBit,              "VolExtBytesFree"},
-  {kFPVolExtBytesTotalBit,             "VolExtBytesTotal"},
-  {kFPVolBlockSizeBit,                 "VolBlockSize"},
-  {0,                           NULL } };
+static int hf_afp_map_name_type = -1;
+static int hf_afp_map_name     = -1;
+static int hf_afp_map_id       = -1;
+static int hf_afp_map_id_type  = -1;
 
 static const value_string flag_vals[] = {
   {0,  "Start" },
   {1,  "End" },
-  {0,                  NULL } };
+  {0,  NULL } };
 
 static const value_string path_type_vals[] = {
   {1,  "Short names" },
   {2,  "Long names" },
   {3,  "Unicode names" },
-  {0,                  NULL } };
+  {0,  NULL } };
+
+static const value_string map_name_type_vals[] = {
+  {1,  "Unicode user name to a user ID" },
+  {2,  "Unicode group name to a group ID" },
+  {3,  "Macintosh roman user name to a user ID" },
+  {4,  "Macintosh roman group name to a group ID" },
+  {0,  NULL } };
+
+static const value_string map_id_type_vals[] = {
+  {1,  "User ID to a Macintosh roman user name" },
+  {2,  "Group ID to a Macintosh roman group name" },
+  {3,  "User ID to a unicode user name" },
+  {4,  "Group ID to a unicode group name" },
+  {0,  NULL } };
 
 /*
-  volume attribute from Apple AFP3.0.pdf 
+  volume attribute from Apple AFP3.0.pdf
   Table 1-3 p. 22
 */
-#define kReadOnly                                      (1 << 0)
+#define kReadOnly                              (1 << 0)
 #define kHasVolumePassword                     (1 << 1)
 #define kSupportsFileIDs                       (1 << 2)
 #define kSupportsCatSearch                     (1 << 3)
-#define kSupportsBlankAccessPrivs      (1 << 4)
+#define kSupportsBlankAccessPrivs              (1 << 4)
 #define kSupportsUnixPrivs                     (1 << 5)
 #define kSupportsUTF8Names                     (1 << 6)
+/* AFP3.1 */
+#define kNoNetworkUserIDs                      (1 << 7)
 
 /*
-  directory bitmap from Apple AFP3.0.pdf 
+  directory bitmap from Apple AFP3.0.pdf
   Table 1-4 p. 31
 */
 #define kFPAttributeBit                (1 << 0)
@@ -467,12 +633,15 @@ static const value_string path_type_vals[] = {
 #define kFPLongNameBit                 (1 << 6)
 #define kFPShortNameBit                (1 << 7)
 #define kFPNodeIDBit                   (1 << 8)
-#define kFPOffspringCountBit   (1 << 9)
+#define kFPOffspringCountBit           (1 << 9)
 #define kFPOwnerIDBit                  (1 << 10)
 #define kFPGroupIDBit                  (1 << 11)
 #define kFPAccessRightsBit             (1 << 12)
 #define kFPUTF8NameBit                         (1 << 13)
-#define kFPUnixPrivsBit                (1 << 14)
+
+/* FIXME AFP3.0 bit 14, AFP3.1 bit 15 */
+
+#define kFPUnixPrivsBit                (1 << 15)
 
 /*
        directory Access Rights parameter AFP3.0.pdf
@@ -493,7 +662,7 @@ static const value_string path_type_vals[] = {
 
 #define AR_U_SEARCH    (1 << 24)   /* user has search access */
 #define AR_U_READ      (1 << 25)   /* user has read access */
-#define AR_U_WRITE     (1 << 26)       /* user has write access */ 
+#define AR_U_WRITE     (1 << 26)       /* user has write access */
 
 #define AR_BLANK       (1 << 28)       /* Blank Access Privileges (use parent dir privileges) */
 #define AR_U_OWN       (1 << 31)       /* user is the owner */
@@ -514,8 +683,22 @@ static int hf_afp_dir_ar_u_write  = -1;
 static int hf_afp_dir_ar_blank    = -1;
 static int hf_afp_dir_ar_u_own    = -1;
 
+static int hf_afp_user_flag       = -1;
+static int hf_afp_user_ID         = -1;
+static int hf_afp_group_ID        = -1;
+static int hf_afp_user_bitmap     = -1;
+static int hf_afp_user_bitmap_UID = -1;
+static int hf_afp_user_bitmap_GID = -1;
+
+static gint ett_afp_user_bitmap   = -1;
+
+static const value_string user_flag_vals[] = {
+  {0,  "Use user ID" },
+  {1,  "Default user" },
+  {0,  NULL } };
+
 /*
-  file bitmap AFP3.0.pdf 
+  file bitmap AFP3.0.pdf
   Table 1-7 p. 36
 same as dir
 kFPAttributeBit                (bit 0)
@@ -531,16 +714,15 @@ kFPNodeIDBit                      (bit 8)
 kFPUTF8NameBit                         (bit 13)
 */
 
-#define kFPDataForkLenBit                      (1 << 9)
-#define kFPRsrcForkLenBit                      (1 << 10)
+#define kFPDataForkLenBit              (1 << 9)
+#define kFPRsrcForkLenBit              (1 << 10)
 #define kFPExtDataForkLenBit           (1 << 11)
-#define kFPLaunchLimitBit                      (1 << 12)
+#define kFPLaunchLimitBit              (1 << 12)
 
 #define kFPExtRsrcForkLenBit           (1 << 14)
-#define kFPUnixPrivsBit_file           (1 << 15)       /* :( */
 
 /*
-  file attribute AFP3.0.pdf 
+  file attribute AFP3.0.pdf
   Table 1-8 p. 37
 */
 #define kFPInvisibleBit                        (1 << 0)
@@ -550,42 +732,60 @@ kFPUTF8NameBit                    (bit 13)
 #define kFPRAlreadyOpenBit                     (1 << 4)
 #define kFPWriteInhibitBit                     (1 << 5)
 #define kFPBackUpNeededBit                     (1 << 6)
-#define kFPRenameInhibitBit            (1 << 7)
-#define kFPDeleteInhibitBit            (1 << 8)
+#define kFPRenameInhibitBit                    (1 << 7)
+#define kFPDeleteInhibitBit                    (1 << 8)
 #define kFPCopyProtectBit                      (1 << 10)
 #define kFPSetClearBit                                 (1 << 15)
 
 /* dir attribute */
 #define kIsExpFolder   (1 << 1)
-#define kMounted               (1 << 3)
+#define kMounted       (1 << 3)
 #define kInExpFolder   (1 << 4)
 
+/* AFP 3.1 getsession token type */
+#define kLoginWithoutID         0
+#define kLoginWithID            1      
+#define kReconnWithID           2
+#define kLoginWithTimeAndID     3
+#define kReconnWithTimeAndID    4
+
+static const value_string token_type_vals[] = {
+  {kLoginWithoutID,            "LoginWithoutID"},
+  {kLoginWithID,                "LoginWithID"},
+  {kReconnWithID,               "ReconnWithID"},
+  {kLoginWithTimeAndID,         "LoginWithTimeAndID"},
+  {kReconnWithTimeAndID,        "ReconnWithTimeAndID"},
+  {0,                           NULL } };
+                                      
 #define hash_init_count 20
 
 /* Hash functions */
 static gint  afp_equal (gconstpointer v, gconstpointer v2);
 static guint afp_hash  (gconstpointer v);
+
 static guint afp_packet_init_count = 200;
 
 typedef struct {
        guint32 conversation;
        guint16 seq;
 } afp_request_key;
+
 typedef struct {
        guint8  command;
 } afp_request_val;
+
 static GHashTable *afp_request_hash = NULL;
 static GMemChunk *afp_request_keys = NULL;
 static GMemChunk *afp_request_vals = NULL;
 
+static guint Vol;      /* volume */
+static guint Did;      /* parent directory ID */
+
 /* Hash Functions */
 static gint  afp_equal (gconstpointer v, gconstpointer v2)
 {
-       afp_request_key *val1 = (afp_request_key*)v;
-       afp_request_key *val2 = (afp_request_key*)v2;
+       const afp_request_key *val1 = (const afp_request_key*)v;
+       const afp_request_key *val2 = (const afp_request_key*)v2;
 
        if (val1->conversation == val2->conversation &&
                        val1->seq == val2->seq) {
@@ -596,11 +796,11 @@ static gint  afp_equal (gconstpointer v, gconstpointer v2)
 
 static guint afp_hash  (gconstpointer v)
 {
-        afp_request_key *afp_key = (afp_request_key*)v;
+        const afp_request_key *afp_key = (const afp_request_key*)v;
         return afp_key->seq;
 }
 
-/* -------------------------- 
+/* --------------------------
 */
 #define PAD(x)      { proto_tree_add_item(tree, hf_afp_pad, tvb, offset,  x, FALSE); offset += x; }
 
@@ -616,16 +816,16 @@ decode_vol_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
                item = proto_tree_add_item(tree, hf_afp_vol_bitmap, tvb, offset, 2,FALSE);
                sub_tree = proto_item_add_subtree(item, ett_afp_vol_bitmap);
        }
-       
-       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_Attribute,              tvb, offset, 2,FALSE);
-       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_Signature,              tvb, offset, 2,FALSE);
+
+       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_Attributes,     tvb, offset, 2,FALSE);
+       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_Signature,      tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_CreateDate,     tvb, offset, 2,FALSE);
-       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_ModDate,                tvb, offset, 2,FALSE);
+       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_ModDate,        tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_BackupDate,     tvb, offset, 2,FALSE);
-       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_ID,                     tvb, offset, 2,FALSE);
-       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_BytesFree,              tvb, offset, 2,FALSE);
+       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_ID,             tvb, offset, 2,FALSE);
+       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_BytesFree,      tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_BytesTotal,     tvb, offset, 2,FALSE);
-       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_Name,                   tvb, offset, 2,FALSE);
+       proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_Name,           tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_ExtBytesFree,   tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_ExtBytesTotal,  tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_bitmap_BlockSize ,     tvb, offset, 2,FALSE);
@@ -653,26 +853,27 @@ decode_vol_attribute (proto_tree *tree, tvbuff_t *tvb, gint offset)
        proto_tree_add_item(sub_tree, hf_afp_vol_attribute_SupportsBlankAccessPrivs,tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_attribute_SupportsUnixPrivs       ,tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_vol_attribute_SupportsUTF8Names       ,tvb, offset, 2,FALSE);
-                                                                               
-       return bitmap;                                                             
-}                                                                              
 
-/* -------------------------- 
+       return bitmap;
+}
+
+/* --------------------------
        cf AFP3.0.pdf page 38
        date  are number of seconds from 12:00am on 01.01.2000 GMT
        backup : 0x8000000 not set
-       from netatalk adouble.h 
+       from netatalk adouble.h
 */
-#define DATE_NOT_SET         0x80000000 
-#define AD_DATE_DELTA         946684800  
-#define AD_DATE_TO_UNIX(x)    (x + AD_DATE_DELTA)  
+#define DATE_NOT_SET         0x80000000
+#define AD_DATE_DELTA         946684800
+#define AD_DATE_TO_UNIX(x)    (x + AD_DATE_DELTA)
 static guint32
 print_date(proto_tree *tree,int id, tvbuff_t *tvb, gint offset)
 {
-time_t date = tvb_get_ntohl(tvb, offset);
-nstime_t tv;
+       time_t date = tvb_get_ntohl(tvb, offset);
+       nstime_t tv;
 
        tv.secs = AD_DATE_TO_UNIX(date);
+       tv.nsecs = 0;
        proto_tree_add_time(tree, id, tvb, offset, 4, &tv);
 
        return date;
@@ -682,7 +883,7 @@ nstime_t tv;
 static gint
 parse_vol_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
 {
-guint16 nameoff = 0;
+       guint16 nameoff = 0;
 
        if ((bitmap & kFPVolAttributeBit)) {
                decode_vol_attribute(tree,tvb,offset);
@@ -718,9 +919,8 @@ guint16 nameoff = 0;
        }
        if ((bitmap & kFPVolNameBit)) {
                nameoff = tvb_get_ntohs(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_bitmap_offset,tvb, offset, 2, FALSE);
+               proto_tree_add_item(tree, hf_afp_vol_name_offset,tvb, offset, 2, FALSE);
                offset += 2;
-
        }
        if ((bitmap & kFPVolExtBytesFreeBit)) {
                proto_tree_add_item(tree, hf_afp_vol_ex_bytes_free,tvb, offset, 8, FALSE);
@@ -735,7 +935,7 @@ guint16 nameoff = 0;
                offset += 4;
        }
        if (nameoff) {
-       guint8 len;
+               guint8 len;
 
                len = tvb_get_guint8(tvb, offset);
                proto_tree_add_item(tree, hf_afp_vol_name, tvb, offset, 1,FALSE);
@@ -758,7 +958,7 @@ decode_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
                item = proto_tree_add_item(tree, hf_afp_file_bitmap, tvb, offset, 2,FALSE);
                sub_tree = proto_item_add_subtree(item, ett_afp_file_bitmap);
        }
-       proto_tree_add_item(sub_tree, hf_afp_file_bitmap_Attribute      , tvb, offset, 2,FALSE);  
+       proto_tree_add_item(sub_tree, hf_afp_file_bitmap_Attributes      , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_ParentDirID    , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_CreateDate     , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_ModDate        , tvb, offset, 2,FALSE);
@@ -768,7 +968,7 @@ decode_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_ShortName      , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_NodeID         , tvb, offset, 2,FALSE);
 
-       proto_tree_add_item(sub_tree, hf_afp_file_bitmap_DataForkLen    , tvb, offset, 2,FALSE);   
+       proto_tree_add_item(sub_tree, hf_afp_file_bitmap_DataForkLen    , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_RsrcForkLen    , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_ExtDataForkLen , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_bitmap_LaunchLimit    , tvb, offset, 2,FALSE);
@@ -781,21 +981,21 @@ decode_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
 }
 
 /* -------------------------- */
-static guint16 
+static guint16
 decode_file_attribute(proto_tree *tree, tvbuff_t *tvb, gint offset, int shared)
 {
        proto_tree *sub_tree = NULL;
        proto_item *item;
        guint16         attribute;
-       
+
        attribute = tvb_get_ntohs(tvb, offset);
        if (tree) {
                item = proto_tree_add_text(tree, tvb, offset, 2,
-                                       "file Attributes: 0x%04x", attribute);
+                                       "File Attributes: 0x%04x", attribute);
                sub_tree = proto_item_add_subtree(item, ett_afp_file_attribute);
        }
-       proto_tree_add_item(sub_tree, hf_afp_file_attribute_Invisible    , tvb, offset, 2,FALSE);  
-       if (!shared) 
+       proto_tree_add_item(sub_tree, hf_afp_file_attribute_Invisible    , tvb, offset, 2,FALSE);
+       if (!shared)
                proto_tree_add_item(sub_tree, hf_afp_file_attribute_MultiUser    , tvb, offset, 2,FALSE);
 
        proto_tree_add_item(sub_tree, hf_afp_file_attribute_System       , tvb, offset, 2,FALSE);
@@ -803,13 +1003,14 @@ decode_file_attribute(proto_tree *tree, tvbuff_t *tvb, gint offset, int shared)
        if (!shared) {
                proto_tree_add_item(sub_tree, hf_afp_file_attribute_DAlreadyOpen , tvb, offset, 2,FALSE);
                proto_tree_add_item(sub_tree, hf_afp_file_attribute_RAlreadyOpen , tvb, offset, 2,FALSE);
-               proto_tree_add_item(sub_tree, hf_afp_file_attribute_WriteInhibit , tvb, offset, 2,FALSE);
        }
+       /* writeinhibit is file only but Macs are setting it with FPSetFileDirParms too */
+       proto_tree_add_item(sub_tree, hf_afp_file_attribute_WriteInhibit , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_attribute_BackUpNeeded , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_attribute_RenameInhibit, tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_file_attribute_DeleteInhibit, tvb, offset, 2,FALSE);
 
-       if (!shared) 
+       if (!shared)
                proto_tree_add_item(sub_tree, hf_afp_file_attribute_CopyProtect  , tvb, offset, 2,FALSE);
 
        proto_tree_add_item(sub_tree, hf_afp_file_attribute_SetClear     , tvb, offset, 2,FALSE);
@@ -817,13 +1018,120 @@ decode_file_attribute(proto_tree *tree, tvbuff_t *tvb, gint offset, int shared)
        return(attribute);
 }
 
+static void
+decode_access_rights (proto_tree *tree, tvbuff_t *tvb, int hf, gint offset)
+{
+       proto_tree *sub_tree;
+       proto_item *item;
+
+       if (tree) {
+               item = proto_tree_add_item(tree, hf, tvb, offset, 4, FALSE);
+               sub_tree = proto_item_add_subtree(item, ett_afp_dir_ar);
+
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_o_search, tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_o_read  , tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_o_write , tvb, offset, 4,   FALSE);
+
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_g_search, tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_g_read  , tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_g_write , tvb, offset, 4,   FALSE);
+
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_e_search, tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_e_read  , tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_e_write , tvb, offset, 4,   FALSE);
+
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_search, tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_read  , tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_write , tvb, offset, 4,   FALSE);
+
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_blank   , tvb, offset, 4,   FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_own   , tvb, offset, 4,   FALSE);
+       }
+}
+
+static void
+decode_unix_privs (proto_tree *tree, tvbuff_t *tvb, gint offset)
+{
+       proto_tree *sub_tree;
+       proto_item *item;
+
+       if (tree) {
+               item = proto_tree_add_text(tree, tvb, offset, 16,
+                   "UNIX privileges");
+               sub_tree = proto_item_add_subtree(item, ett_afp_unix_privs);
+
+               proto_tree_add_item(sub_tree, hf_afp_unix_privs_uid, tvb, offset, 4, FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_unix_privs_gid, tvb, offset+4, 4, FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_unix_privs_permissions, tvb, offset+8, 4, FALSE);
+               decode_access_rights(sub_tree, tvb, hf_afp_unix_privs_ua_permissions, offset+12);
+       }
+}
+
+/* -------------------------- */
+static gint
+parse_long_filename(proto_tree *tree, tvbuff_t *tvb, gint offset, gint org_offset)
+{
+       guint16 lnameoff;
+       gint tp_ofs = 0;
+       guint8 len;
+
+       lnameoff = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_long_name_offset,tvb, offset, 2, FALSE);
+       if (lnameoff) {
+               tp_ofs = lnameoff +org_offset;
+               len = tvb_get_guint8(tvb, tp_ofs);
+               proto_tree_add_item(tree, hf_afp_path_len, tvb, tp_ofs,  1,FALSE);
+               tp_ofs++;
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
+               tp_ofs += len;
+       }
+       return tp_ofs;
+}
+
+/* -------------------------- */
+static gint
+parse_UTF8_filename(proto_tree *tree, tvbuff_t *tvb, gint offset, gint org_offset)
+{
+       guint16 unameoff;
+       gint tp_ofs = 0;
+       guint16 len;
+
+       unameoff = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_unicode_name_offset,tvb, offset, 2, FALSE);
+       offset += 2;
+       if (unameoff) {
+             /* FIXME AFP3.x reuses PDINFO bit for UTF8. 
+              * In enumerate_ext it's pad with 4 bytes, PDINFO was 6 bytes,
+              * but not in catsearch_ext. 
+              * Last but not least there's a bug in OSX catsearch_ext for spec2
+              * offset is off by 2 bytes.
+              */
+              
+               tp_ofs = unameoff +org_offset;
+              if (tp_ofs > offset) {
+                  PAD(4);
+               }
+               else if (tp_ofs < offset) {
+                   tp_ofs = offset;
+               }
+               proto_tree_add_item( tree, hf_afp_path_unicode_hint, tvb, tp_ofs, 4,FALSE);
+               tp_ofs += 4;
+
+               len = tvb_get_ntohs(tvb, tp_ofs);
+               proto_tree_add_item( tree, hf_afp_path_unicode_len, tvb, tp_ofs, 2,FALSE);
+               tp_ofs += 2;
+
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
+               tp_ofs += len;
+       }
+       return tp_ofs;
+}
+
 /* -------------------------- */
 static gint
 parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap, int shared)
 {
-       guint16 lnameoff = 0;
        guint16 snameoff = 0;
-       guint16 unameoff = 0;
        gint    max_offset = 0;
 
        gint    org_offset = offset;
@@ -854,24 +1162,16 @@ parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap,
        }
        if ((bitmap & kFPLongNameBit)) {
                gint tp_ofs;
-               guint8 len;
 
-               lnameoff = tvb_get_ntohs(tvb, offset);
-               if (lnameoff) {
-                       tp_ofs = lnameoff +org_offset;
-                       proto_tree_add_item(tree, hf_afp_bitmap_offset,tvb, offset, 2, FALSE);
-                       len = tvb_get_guint8(tvb, tp_ofs);
-                       proto_tree_add_item(tree, hf_afp_path_len, tvb, tp_ofs,  1,FALSE);
-                       tp_ofs++;
-                       proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
-                       tp_ofs += len;
-                       max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
-               }
+               tp_ofs = parse_long_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+
                offset += 2;
+
        }
        if ((bitmap & kFPShortNameBit)) {
                snameoff = tvb_get_ntohs(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_bitmap_offset,tvb, offset, 2, FALSE);
+               proto_tree_add_item(tree, hf_afp_short_name_offset,tvb, offset, 2, FALSE);
                offset += 2;
        }
        if ((bitmap & kFPNodeIDBit)) {
@@ -883,7 +1183,7 @@ parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap,
                proto_tree_add_item(tree, hf_afp_file_DataForkLen, tvb, offset, 4,FALSE);
                offset += 4;
        }
-       
+
        if ((bitmap & kFPRsrcForkLenBit)) {
                proto_tree_add_item(tree, hf_afp_file_RsrcForkLen, tvb, offset, 4,FALSE);
                offset += 4;
@@ -899,7 +1199,11 @@ parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap,
        }
 
        if ((bitmap & kFPUTF8NameBit)) {
-               offset += 2;
+               gint tp_ofs;
+
+               tp_ofs = parse_UTF8_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+               offset += 6;
        }
 
        if ((bitmap & kFPExtRsrcForkLenBit)) {
@@ -907,29 +1211,36 @@ parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap,
                offset += 8;
        }
 
-       if ((bitmap & kFPUnixPrivsBit_file)) {
-               proto_tree_add_item(tree, hf_afp_file_UnixPrivs, tvb, offset, 4,FALSE);
-               offset += 4;
+       if ((bitmap & kFPUnixPrivsBit)) {
+               /*
+                * XXX - the AFP 3.0 spec says this is "Four bytes", but
+                * also says the privileges are "stored in an FPUnixPrivs
+                * structure", which is 16 bytes long.
+                *
+                * We assume, for now, that the latter is true.
+                */
+               decode_unix_privs(tree, tvb, offset);
+               offset += 16;
        }
 
        return (max_offset)?max_offset:offset;
 }
 
 /* -------------------------- */
-static guint16 
+static guint16
 decode_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
 {
        proto_tree *sub_tree = NULL;
        proto_item *item;
        guint16         bitmap;
-       
+
        bitmap = tvb_get_ntohs(tvb, offset);
        if (tree) {
                item = proto_tree_add_item(tree, hf_afp_dir_bitmap, tvb, offset, 2,FALSE);
                sub_tree = proto_item_add_subtree(item, ett_afp_dir_bitmap);
        }
-       
-       proto_tree_add_item(sub_tree, hf_afp_dir_bitmap_Attribute      , tvb, offset, 2,FALSE);  
+
+       proto_tree_add_item(sub_tree, hf_afp_dir_bitmap_Attributes      , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_dir_bitmap_ParentDirID    , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_dir_bitmap_CreateDate     , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_dir_bitmap_ModDate        , tvb, offset, 2,FALSE);
@@ -949,20 +1260,20 @@ decode_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
 }
 
 /* -------------------------- */
-static guint16 
+static guint16
 decode_dir_attribute(proto_tree *tree, tvbuff_t *tvb, gint offset)
 {
        proto_tree *sub_tree = NULL;
        proto_item *item;
        guint16         attribute;
-       
+
        attribute = tvb_get_ntohs(tvb, offset);
        if (tree) {
                item = proto_tree_add_text(tree, tvb, offset, 2,
-                                       "dir Attributes: 0x%04x", attribute);
+                                       "Directory Attributes: 0x%04x", attribute);
                sub_tree = proto_item_add_subtree(item, ett_afp_dir_attribute);
        }
-       proto_tree_add_item(sub_tree, hf_afp_dir_attribute_Invisible    , tvb, offset, 2,FALSE);  
+       proto_tree_add_item(sub_tree, hf_afp_dir_attribute_Invisible    , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_dir_attribute_IsExpFolder  , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_dir_attribute_System       , tvb, offset, 2,FALSE);
        proto_tree_add_item(sub_tree, hf_afp_dir_attribute_Mounted      , tvb, offset, 2,FALSE);
@@ -978,9 +1289,7 @@ decode_dir_attribute(proto_tree *tree, tvbuff_t *tvb, gint offset)
 static gint
 parse_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
 {
-       guint16 lnameoff = 0;
        guint16 snameoff = 0;
-       guint16 unameoff = 0;
        gint    max_offset = 0;
 
        gint    org_offset = offset;
@@ -1011,23 +1320,15 @@ parse_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
        }
        if ((bitmap & kFPLongNameBit)) {
                gint tp_ofs;
-               guint8 len;
-               lnameoff = tvb_get_ntohs(tvb, offset);
-               if (lnameoff) {
-                       tp_ofs = lnameoff +org_offset;
-                       proto_tree_add_item(tree, hf_afp_bitmap_offset,tvb, offset, 2, FALSE);
-                       len = tvb_get_guint8(tvb, tp_ofs);
-                       proto_tree_add_item(tree, hf_afp_path_len, tvb, tp_ofs,  1,FALSE);
-                       tp_ofs++;
-                       proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
-                       tp_ofs += len;
-                       max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
-               }
+
+               tp_ofs = parse_long_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+
                offset += 2;
        }
        if ((bitmap & kFPShortNameBit)) {
                snameoff = tvb_get_ntohs(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_bitmap_offset,tvb, offset, 2, FALSE);
+               proto_tree_add_item(tree, hf_afp_short_name_offset,tvb, offset, 2, FALSE);
                offset += 2;
        }
        if ((bitmap & kFPNodeIDBit)) {
@@ -1039,77 +1340,65 @@ parse_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
                offset += 2;            /* error in AFP3.0.pdf */
        }
        if ((bitmap & kFPOwnerIDBit)) {
-               proto_tree_add_item(tree, hf_afp_dir_OwnerID, tvb, offset, 4,   FALSE);  
+               proto_tree_add_item(tree, hf_afp_dir_OwnerID, tvb, offset, 4,   FALSE);
                offset += 4;
        }
        if ((bitmap & kFPGroupIDBit)) {
-               proto_tree_add_item(tree, hf_afp_dir_GroupID, tvb, offset, 4,   FALSE);  
+               proto_tree_add_item(tree, hf_afp_dir_GroupID, tvb, offset, 4,   FALSE);
                offset += 4;
        }
        if ((bitmap & kFPAccessRightsBit)) {
-               proto_tree *sub_tree = NULL;
-               proto_item *item;
-                       
-               if (tree) {
-                       item = proto_tree_add_item(tree, hf_afp_dir_ar, tvb, offset, 4, FALSE);
-                       sub_tree = proto_item_add_subtree(item, ett_afp_dir_ar);
-               }
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_o_search, tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_o_read  , tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_o_write , tvb, offset, 4,   FALSE);  
-
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_g_search, tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_g_read  , tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_g_write , tvb, offset, 4,   FALSE);  
-
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_e_search, tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_e_read  , tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_e_write , tvb, offset, 4,   FALSE);  
-
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_search, tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_read  , tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_write , tvb, offset, 4,   FALSE);  
-
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_blank   , tvb, offset, 4,   FALSE);  
-               proto_tree_add_item(sub_tree, hf_afp_dir_ar_u_own   , tvb, offset, 4,   FALSE);  
-               
+               decode_access_rights(tree, tvb, hf_afp_dir_ar, offset);
                offset += 4;
        }
        if ((bitmap & kFPUTF8NameBit)) {
-               offset += 2;
+               gint tp_ofs;
+
+               tp_ofs = parse_UTF8_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+               offset += 6;
        }
        if ((bitmap & kFPUnixPrivsBit)) {
-               offset += 4;
+               /*
+                * XXX - the AFP 3.0 spec says this is "Four bytes", but
+                * also says the privileges are "stored in an FPUnixPrivs
+                * structure", which is 16 bytes long.
+                *
+                * We assume, for now, that the latter is true.
+                */
+               decode_unix_privs(tree, tvb, offset);
+               offset += 16;
        }
        return (max_offset)?max_offset:offset;
 }
 
 /* -------------------------- */
 static gchar *
-name_in_bitmap(tvbuff_t *tvb, gint *offset, guint16 bitmap)
+name_in_bitmap(tvbuff_t *tvb, gint offset, guint16 bitmap, int isdir)
 {
        gchar *name;
-       gint    org_offset = *offset;
+       gint    org_offset = offset;
        guint16 nameoff;
        guint8  len;
+       guint16 len16;
        gint    tp_ofs;
-       
+
        name = NULL;
-       if ((bitmap & kFPAttributeBit)) 
-               *offset += 2;
-       if ((bitmap & kFPParentDirIDBit))
-               *offset += 4;
-       if ((bitmap & kFPCreateDateBit)) 
-               *offset += 4;
-       if ((bitmap & kFPModDateBit))
-               *offset += 4;
-       if ((bitmap & kFPBackupDateBit)) 
-               *offset += 4;
-       if ((bitmap & kFPFinderInfoBit)) 
-               *offset += 32;
-       
-       if ((bitmap & kFPLongNameBit)) {
-               nameoff = tvb_get_ntohs(tvb, *offset);
+       if ((bitmap & kFPAttributeBit))         /* 0 */
+               offset += 2;
+       if ((bitmap & kFPParentDirIDBit))       /* 1 */
+               offset += 4;
+       if ((bitmap & kFPCreateDateBit))        /* 2 */
+               offset += 4;
+       if ((bitmap & kFPModDateBit))           /* 3 */
+               offset += 4;
+       if ((bitmap & kFPBackupDateBit))        /* 4 */
+               offset += 4;
+       if ((bitmap & kFPFinderInfoBit))        /* 5 */
+               offset += 32;
+
+       if ((bitmap & kFPLongNameBit)) {        /* 6 */
+               nameoff = tvb_get_ntohs(tvb, offset);
                if (nameoff) {
                        tp_ofs = nameoff +org_offset;
                        len = tvb_get_guint8(tvb, tp_ofs);
@@ -1120,8 +1409,48 @@ name_in_bitmap(tvbuff_t *tvb, gint *offset, guint16 bitmap)
                        *(name +len) = 0;
                        return name;
                }
+               offset += 2;
+       }
+       
+       if ((bitmap & kFPShortNameBit))         /* 7 */
+               offset += 2;
+       if ((bitmap & kFPNodeIDBit))            /* 8 */
+               offset += 4;
+
+        if (isdir) {
+               if ((bitmap & kFPOffspringCountBit))    /* 9 */
+                       offset += 2;
+               if ((bitmap & kFPOwnerIDBit))           /* 10*/
+                       offset += 4;
+               if ((bitmap & kFPGroupIDBit))           /* 11*/
+                       offset += 4;
+               if ((bitmap & kFPAccessRightsBit))      /* 12*/
+                       offset += 4;
+        }
+        else {
+               if ((bitmap & kFPDataForkLenBit))       /* 9 */
+                       offset += 4;
+               if ((bitmap & kFPRsrcForkLenBit))       /* 10*/
+                       offset += 4;
+               if ((bitmap & kFPExtDataForkLenBit))    /* 11*/
+                       offset += 8;
+               if ((bitmap & kFPLaunchLimitBit))       /* 12*/
+                       offset += 2; /* FIXME ? */
+        }
+
+       if ((bitmap & kFPUTF8NameBit)) {                /* 13 */
+               nameoff = tvb_get_ntohs(tvb, offset);
+               if (nameoff) {
+                       tp_ofs = nameoff +org_offset +4;
+                       len16 = tvb_get_ntohs(tvb, tp_ofs);
+                       tp_ofs += 2;
+                       if (!(name = g_malloc(len16 +1)))
+                               return name;
+                       tvb_memcpy(tvb, name, tp_ofs, len16);
+                       *(name +len16) = 0;
+                       return name;
+               }
        }
-       /* short name ? */
        return name;
 }
 
@@ -1130,14 +1459,14 @@ static gchar *
 name_in_dbitmap(tvbuff_t *tvb, gint offset, guint16 bitmap)
 {
        gchar *name;
-       
-       name = name_in_bitmap(tvb, &offset, bitmap);
+
+       name = name_in_bitmap(tvb, offset, bitmap, 1);
        if (name != NULL)
                return name;
        /*
-               check UTF8 name 
+               check UTF8 name
        */
-       
+
        return name;
 }
 
@@ -1146,14 +1475,14 @@ static gchar *
 name_in_fbitmap(tvbuff_t *tvb, gint offset, guint16 bitmap)
 {
        gchar *name;
-       
-       name = name_in_bitmap(tvb, &offset, bitmap);
+
+       name = name_in_bitmap(tvb, offset, bitmap, 0);
        if (name != NULL)
                return name;
        /*
-               check UTF8 name 
+               check UTF8 name
        */
-       
+
        return name;
 }
 
@@ -1161,9 +1490,11 @@ name_in_fbitmap(tvbuff_t *tvb, gint offset, guint16 bitmap)
 static gint
 decode_vol_did(proto_tree *tree, tvbuff_t *tvb, gint offset)
 {
+       Vol = tvb_get_ntohs(tvb, offset);
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
 
+       Did = tvb_get_ntohl(tvb, offset);
        proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
        offset += 4;
        return offset;
@@ -1177,76 +1508,88 @@ decode_vol_did_file_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
 
        decode_file_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        decode_dir_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        return offset;
 }
 
-/* ------------------------
- * idea from packet-smb
- *
- */
+/* ------------------------ */
 static gchar *
 get_name(tvbuff_t *tvb, int offset, int type)
 {
-       static gchar  str[3][256];
-       static int    cur;
+       int   len;
        gchar *string;
-       guint8 len;
-       int i;
-       len = tvb_get_guint8(tvb, offset);
-       offset++;
-       string = str[cur];
+
        switch (type) {
        case 1:
        case 2:
-       tvb_memcpy(tvb, (guint8 *)string, offset, len);
-       string[len] = 0;
-               /* FIXME should use something else as separator ?
-               */
-       for (i = 0; i < len; i++) if (!string[i])
-               string[i] = ':';        
-       break;
-    case 3:
-       strcpy(string, "error Unicode...,next time ");
-       break;
-    }
-
-       cur = ++cur % 3;
-       return string;
+               len = tvb_get_guint8(tvb, offset);
+               offset++;
+               string = tvb_format_text(tvb,offset, len);
+               break;
+       case 3:
+               len = tvb_get_ntohs(tvb, offset +4);
+               offset += 6;
+               string = tvb_format_text(tvb,offset, len);
+               break;
+       default:
+               string = "unknow type";
+               break;
+       }
+       return string;
 }
-
 /* -------------------------- */
 static gint
 decode_name_label (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, const gchar *label)
 {
        int len;
+       int header;
        gchar *name;
        guint8 type;
        proto_tree *sub_tree = NULL;
        proto_item *item;
-               
+
        type = tvb_get_guint8(tvb, offset);
-       len = tvb_get_guint8(tvb, offset +1);
+       if (type == 3) {
+               header = 7;
+               len = tvb_get_ntohs(tvb, offset +5);
+       }
+       else {
+               header = 2;
+               len = tvb_get_guint8(tvb, offset +1);
+       }
        name = get_name(tvb, offset +1, type);
 
        if (pinfo && check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", name);
+               col_append_fstr(pinfo->cinfo, COL_INFO, ": Vol=%u Did=%u", Vol, Did);
+               if (len) {
+                       col_append_fstr(pinfo->cinfo, COL_INFO, " Name=%s", name);
+               }
        }
 
        if (tree) {
-               item = proto_tree_add_text(tree, tvb, offset, len +2, label, name);
+               item = proto_tree_add_text(tree, tvb, offset, len +header, label, name);
                sub_tree = proto_item_add_subtree(item, ett_afp_path_name);
+
                proto_tree_add_item(  sub_tree, hf_afp_path_type, tvb, offset,   1,FALSE);
                offset++;
-               proto_tree_add_item(  sub_tree, hf_afp_path_len,  tvb, offset,   1,FALSE);
-               offset++;
+               if (type == 3) {
+                       proto_tree_add_item( sub_tree, hf_afp_path_unicode_hint,  tvb, offset,  4,FALSE);
+                       offset += 4;
+                       proto_tree_add_item( sub_tree, hf_afp_path_unicode_len,  tvb, offset,   2,FALSE);
+                       offset += 2;
+               }
+               else {
+                       proto_tree_add_item( sub_tree, hf_afp_path_len,  tvb, offset,   1,FALSE);
+                       offset++;
+               }
+
                proto_tree_add_string(sub_tree, hf_afp_path_name, tvb, offset, len,name);
        }
-       else 
-               offset += 2;
+       else
+               offset += header;
 
        return offset +len;
 }
@@ -1255,7 +1598,31 @@ decode_name_label (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint off
 static gint
 decode_name (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset)
 {
-       return decode_name_label(tree, pinfo, tvb, offset," path : %s");
+       return decode_name_label(tree, pinfo, tvb, offset, "Path: %s");
+}
+
+/* -------------------------- */
+static void
+add_info_fork(tvbuff_t *tvb, packet_info *pinfo, gint offset)
+{
+       guint16 ofork;
+
+       ofork = tvb_get_ntohs(tvb, offset);
+       if (ofork && check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, ": Fork=%u", ofork);
+       }
+}
+
+/* -------------------------- */
+static void
+add_info_vol(tvbuff_t *tvb, packet_info *pinfo, gint offset)
+{
+       guint16 vol;
+
+       vol = tvb_get_ntohs(tvb, offset);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, ": Vol=%u", vol);
+       }
 }
 
 /* ************************** */
@@ -1263,26 +1630,26 @@ static gint
 dissect_query_afp_open_vol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        int len;
-       
+
        PAD(1);
 
        decode_vol_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        len = tvb_get_guint8(tvb, offset);
 
        if (check_col(pinfo->cinfo, COL_INFO)) {
-       const gchar *rep;
+               const gchar *rep;
                rep = get_name(tvb, offset, 2);
                col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", rep);
        }
 
        if (!tree)
                return offset;
-               
+
        proto_tree_add_item(tree, hf_afp_vol_name, tvb, offset, 1,FALSE);
        offset += len +1;
-               
+
        len = tvb_reported_length_remaining(tvb,offset);
        if (len >= 8) {
                /* optionnal password */
@@ -1294,10 +1661,10 @@ dissect_query_afp_open_vol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_open_vol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_open_vol(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        guint16 bitmap;
-       
+
        if (!tree)
                return offset;
        bitmap = decode_vol_bitmap(tree, tvb, offset);
@@ -1307,22 +1674,72 @@ dissect_reply_afp_open_vol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
-/* ************************** 
+/* ************************** */
+static gint
+dissect_reply_afp_get_server_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       guint8 num;
+       guint8 len;
+       guint8 flag;
+       guint8 i;
+       proto_tree *sub_tree = NULL;
+       proto_tree *flag_tree;
+       proto_item *item;
+       proto_item *ti;
+
+       if (!tree)
+               return offset;
+
+       print_date(tree, hf_afp_server_time,tvb, offset);
+       offset += 4;
+
+       num = tvb_get_guint8(tvb, offset);
+       item = proto_tree_add_text(tree, tvb, offset, 1, "Volumes : %d", num);
+       sub_tree = proto_item_add_subtree(item, ett_afp_server_vol);
+       offset++;
+
+       for (i = 0; i < num; i++) {
+               const gchar *rep;
+
+               item = proto_tree_add_text(sub_tree, tvb, offset, -1,"Volume");
+               tree = proto_item_add_subtree(item, ett_afp_vol_list);
+
+               flag = tvb_get_guint8(tvb, offset);
+
+               ti = proto_tree_add_text(tree, tvb, offset , 1,"Flags : 0x%02x", flag);
+               flag_tree = proto_item_add_subtree(ti, ett_afp_vol_flag);
+               proto_tree_add_item(flag_tree, hf_afp_vol_flag_passwd, tvb, offset, 1,FALSE);
+               proto_tree_add_item(flag_tree, hf_afp_vol_flag_unix_priv ,tvb, offset, 1,FALSE);
+               offset++;
+
+               len  = tvb_get_guint8(tvb, offset) +1;
+               rep = get_name(tvb, offset, 2);
+               proto_item_set_text(item, rep);
+               proto_item_set_len(item, len +1);
+
+               proto_tree_add_item(tree, hf_afp_vol_name, tvb, offset, 1,FALSE);
+
+               offset += len;
+       }
+       return offset;
+}
+
+/* **************************
        next calls use the same format :
-               1 pad byte 
+               1 pad byte
                volume id
        AFP_FLUSH
        AFP_CLOSEVOL
        AFP_OPENDT
 */
 static gint
-dissect_query_afp_with_vol_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_with_vol_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
 
        if (!tree)
                return offset;
        PAD(1);
-       
+
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
        return offset;
@@ -1339,7 +1756,7 @@ dissect_query_afp_open_fork(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        offset++;
 
        offset = decode_vol_did(tree, tvb, offset);
-       
+
        decode_file_bitmap(tree, tvb, offset);
        offset += 2;
        if (tree) {
@@ -1363,10 +1780,11 @@ static gint
 dissect_reply_afp_open_fork(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        int f_bitmap;
-
+       
        f_bitmap = decode_file_bitmap(tree, tvb, offset);
        offset += 2;
 
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1375,11 +1793,33 @@ dissect_reply_afp_open_fork(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
+/* ************************** */
+static gint
+dissect_query_afp_enumerate_ext2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+
+       PAD(1);
+       offset = decode_vol_did_file_dir_bitmap(tree, tvb, offset);
+
+       proto_tree_add_item(tree, hf_afp_req_count, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       proto_tree_add_item(tree, hf_afp_start_index32, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       proto_tree_add_item(tree, hf_afp_max_reply_size32, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       offset = decode_name(tree, pinfo, tvb, offset);
+
+       return offset;
+}
+
 /* ************************** */
 static gint
 dissect_query_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
-       
+
        PAD(1);
        offset = decode_vol_did_file_dir_bitmap(tree, tvb, offset);
 
@@ -1398,92 +1838,279 @@ dissect_query_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 }
 
 /* -------------------------- */
-static gint
-dissect_reply_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+static int
+loop_record(tvbuff_t *tvb, proto_tree *ptree, gint offset,
+               int count, guint16 d_bitmap, guint16 f_bitmap, int add, int ext)
 {
-       proto_tree *sub_tree = NULL;
+       proto_tree *tree = NULL;
        proto_item *item;
-       int count;
-       int f_bitmap;
-       int d_bitmap;
+       gchar   *name;
        guint8  flags;
-       guint8  size;
+       guint   size;
        gint    org;
        int i;
-       gchar *name;
-       
-       f_bitmap = decode_file_bitmap(tree, tvb, offset);
-       offset += 2;
-       
-       d_bitmap = decode_dir_bitmap(tree, tvb, offset);
-       offset += 2;
+       int decal; 
 
-       count = tvb_get_ntohs(tvb, offset);
-       if (tree) {
-               item = proto_tree_add_item(tree, hf_afp_req_count, tvb, offset, 2,FALSE);
-               sub_tree = proto_item_add_subtree(item, ett_afp_enumerate);
-       }
-       offset += 2;
-       /* loop */
        for (i = 0; i < count; i++) {
                org = offset;
-               name = NULL;
-               size = tvb_get_guint8(tvb, offset);
-               flags = tvb_get_guint8(tvb, offset +1);
+               if (ext) {
+                       size = tvb_get_ntohs(tvb, offset) +add *2;
+                       decal = 2;
+               }
+               else {
+                       size = tvb_get_guint8(tvb, offset) +add;
+                       decal = 1;
+               }
+               if (!size)
+                       return offset;  /* packet is malformed */
+               flags = tvb_get_guint8(tvb, offset +decal);
+
+               decal += (ext)?2:1;
 
-               if (sub_tree) {
+               if (ptree) {
                        if (flags) {
-                               name = name_in_dbitmap(tvb, offset +2, d_bitmap);
-                       }       
+                               name = name_in_dbitmap(tvb, offset +decal, d_bitmap);
+                       }
                        else {
-                               name = name_in_fbitmap(tvb, offset +2, f_bitmap);
+                               name = name_in_fbitmap(tvb, offset +decal, f_bitmap);
                        }
                        if (!name) {
                                if (!(name = g_malloc(50))) { /* no memory ! */
                                }
                                snprintf(name, 50,"line %d", i +1);
                        }
-                       item = proto_tree_add_text(sub_tree, tvb, offset, size, name);
+                       item = proto_tree_add_text(ptree, tvb, offset, size, name);
                        tree = proto_item_add_subtree(item, ett_afp_enumerate_line);
+                       g_free((gpointer)name);
+               }
+               if (ext) {
+                       proto_tree_add_item(tree, hf_afp_struct_size16, tvb, offset, 2,FALSE);
+                       offset += 2;
+               }
+               else {
+                       proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
+                       offset++;
                }
-               proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
-               offset++;
 
                proto_tree_add_item(tree, hf_afp_file_flag, tvb, offset, 1,FALSE);
                offset++;
+               if (ext) {
+                       PAD(1);
+               }
                if (flags) {
                        offset = parse_dir_bitmap(tree, tvb, offset, d_bitmap);
                }
                else {
                        offset = parse_file_bitmap(tree, tvb, offset, f_bitmap,0);
                }
-               if ((offset & 1)) 
+               if ((offset & 1))
                        PAD(1);
                offset = org +size;             /* play safe */
-               if (sub_tree)
-                       g_free((gpointer)name);
-       }       
-       return(offset);
+       }
+       return offset;
+}
+/* ------------------------- */
+static gint
+reply_enumerate(tvbuff_t *tvb, proto_tree *tree, gint offset, int ext)
+{
+       proto_tree *sub_tree = NULL;
+       proto_item *item;
+       int count;
+       guint16 f_bitmap;
+       guint16 d_bitmap;
+
+       f_bitmap = decode_file_bitmap(tree, tvb, offset);
+       offset += 2;
+
+       d_bitmap = decode_dir_bitmap(tree, tvb, offset);
+       offset += 2;
+
+       count = tvb_get_ntohs(tvb, offset);
+       if (tree) {
+               item = proto_tree_add_item(tree, hf_afp_req_count, tvb, offset, 2,FALSE);
+               sub_tree = proto_item_add_subtree(item, ett_afp_enumerate);
+       }
+       offset += 2;
+
+       return loop_record(tvb,sub_tree, offset, count, d_bitmap, f_bitmap,0, ext);
+}
+
+/* ------------------------- */
+static gint
+dissect_reply_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_enumerate(tvb, tree, offset, 0);
+}
+
+/* **************************/
+static gint
+dissect_reply_afp_enumerate_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_enumerate(tvb, tree, offset, 1);
+}
+
+/* **************************/
+static gint
+catsearch_spec(tvbuff_t *tvb, proto_tree *ptree, gint offset, int ext, guint32 bitmap, const gchar *label)
+{
+       proto_tree *tree = NULL;
+       proto_item *item;
+       guint16 size;
+       gint    org;
+
+       org = offset;
+
+       if (ext) {
+               size = tvb_get_ntohs(tvb, offset) +2;
+       }
+       else {
+               size = tvb_get_guint8(tvb, offset) +2;
+       }
+
+       item = proto_tree_add_text(ptree, tvb, offset, size, label);
+       tree = proto_item_add_subtree(item, ett_afp_cat_spec);
+
+       if (ext) {
+               proto_tree_add_item(tree, hf_afp_struct_size16, tvb, offset, 2,FALSE);
+               offset += 2;
+       }
+       else {
+               proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
+               offset++;
+               PAD(1);
+       }
+
+       offset = parse_file_bitmap(tree, tvb, offset, bitmap,0);
+       offset = org +size;
+
+       return offset;
+}
+
+/* ------------------------- */
+static gint
+query_catsearch(tvbuff_t *tvb, proto_tree *ptree, gint offset, int ext)
+{
+       proto_tree *tree = NULL;
+       proto_item *item;
+       guint16 f_bitmap;
+       guint16 d_bitmap;
+       guint32 r_bitmap;
+
+       if (!ptree)
+               return offset;
+       PAD(1);
+
+       proto_tree_add_item(ptree, hf_afp_vol_id, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       proto_tree_add_item(ptree, hf_afp_cat_req_matches, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       proto_tree_add_item(ptree, hf_afp_reserved, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       proto_tree_add_item(ptree, hf_afp_cat_position, tvb, offset, 16,FALSE);
+       offset += 16;
+
+       f_bitmap = decode_file_bitmap(ptree, tvb, offset);
+       offset += 2;
+
+       d_bitmap = decode_dir_bitmap(ptree, tvb, offset);
+       offset += 2;
+
+       /* FIXME it's req bitmap and first bit is for partial match */
+       item = proto_tree_add_text(ptree, tvb, offset, 4, "Request bitmap");
+       tree = proto_item_add_subtree(item, ett_afp_cat_r_bitmap);
+       r_bitmap = decode_file_bitmap(tree, tvb, offset+2);
+       offset += 4;
+
+       /* spec 1 */
+       offset = catsearch_spec(tvb, ptree, offset, ext, r_bitmap, "Spec 1");
+
+       /* spec 2 */
+       offset = catsearch_spec(tvb, ptree, offset, ext, r_bitmap, "Spec 2");
+       
+       return offset;
+}
+
+/* ------------------------- */
+static gint
+dissect_query_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ptree, gint offset)
+{
+       return query_catsearch(tvb, ptree, offset, 0);
+
+}
+/* **************************/
+static gint
+dissect_query_afp_cat_search_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ptree, gint offset)
+{
+       return query_catsearch(tvb, ptree, offset, 1);
+
+}
+
+/* **************************/
+static gint
+reply_catsearch(tvbuff_t *tvb, proto_tree *tree, gint offset, int ext)
+{
+       proto_tree *sub_tree = NULL;
+       proto_item *item;
+       guint16 f_bitmap;
+       guint16 d_bitmap;
+       int count;
+
+       proto_tree_add_item(tree, hf_afp_cat_position, tvb, offset, 16,FALSE);
+       offset += 16;
+
+       f_bitmap = decode_file_bitmap(tree, tvb, offset);
+       offset += 2;
+
+       d_bitmap = decode_dir_bitmap(tree, tvb, offset);
+       offset += 2;
+
+       count = tvb_get_ntohl(tvb, offset);
+       if (tree) {
+               item = proto_tree_add_item(tree, hf_afp_cat_count, tvb, offset, 4,FALSE);
+               sub_tree = proto_item_add_subtree(item, ett_afp_cat_search);
+       }
+       offset += 4;
+
+       return loop_record(tvb,sub_tree, offset, count, d_bitmap, f_bitmap, 2, ext);
+}
+
+/* -------------------------- */
+static gint
+dissect_reply_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_catsearch(tvb, tree, offset, 0);
+}
 
+/* **************************/
+static gint
+dissect_reply_afp_cat_search_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_catsearch(tvb, tree, offset, 1);
 }
 
 /* **************************/
 static gint
 dissect_query_afp_get_vol_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
+
        PAD(1)
+        add_info_vol(tvb, pinfo, offset);
+       
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
 
        decode_vol_bitmap(tree, tvb, offset);
        offset += 2;
-       
-       return offset;  
+
+       return offset;
 }
 
 /* ------------------------ */
 static gint
-dissect_reply_afp_get_vol_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_get_vol_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        guint16 bitmap;
 
@@ -1502,56 +2129,145 @@ dissect_query_afp_set_vol_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
        guint16 bitmap;
 
        PAD(1)
+
+        add_info_vol(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
 
        bitmap = decode_vol_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        offset = parse_vol_bitmap(tree, tvb, offset, bitmap);
 
-       return offset;  
+       return offset;
 }
 
 /* ***************************/
 static gint
-dissect_query_afp_login(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+decode_uam_parameters(const char *uam, int len_uam, tvbuff_t *tvb, proto_tree *tree, gint offset)
 {
        int len;
-    const char *uam;
-    
+
+       if (!strncasecmp(uam, "Cleartxt passwrd", len_uam)) {
+               if ((offset & 1))
+                       PAD(1);
+
+               len = 8; /* tvb_strsize(tvb, offset);*/
+               proto_tree_add_item(tree, hf_afp_passwd, tvb, offset, len,FALSE);
+               offset += len;
+       }
+       else if (!strncasecmp(uam, "DHCAST128", len_uam)) {
+               if ((offset & 1))
+                       PAD(1);
+
+               len = 16;
+               proto_tree_add_item(tree, hf_afp_random, tvb, offset, len,FALSE);
+               offset += len;
+        }
+       else if (!strncasecmp(uam, "2-Way Randnum exchange", len_uam)) {
+               /* nothing */
+               return offset;
+       }
+       return offset;
+}
+
+/* ---------------- */
+static gint
+dissect_query_afp_login(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       int len;
+       int len_uam;
+       const char *uam;
+
        len = tvb_get_guint8(tvb, offset);
        proto_tree_add_item(tree, hf_afp_AFPVersion, tvb, offset, 1,FALSE);
        offset += len +1;
-       len = tvb_get_guint8(tvb, offset);
-       uam = tvb_get_ptr(tvb, offset +1, len);
+       len_uam = tvb_get_guint8(tvb, offset);
+       uam = tvb_get_ptr(tvb, offset +1, len_uam);
        proto_tree_add_item(tree, hf_afp_UAM, tvb, offset, 1,FALSE);
+       offset += len_uam +1;
+
+       if (!strncasecmp(uam, "No User Authent", len_uam)) {
+               return offset;
+       }
+
+       len = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_user, tvb, offset, 1,FALSE);
        offset += len +1;
+       
+       return decode_uam_parameters(uam, len_uam, tvb, tree, offset);
+}
 
-       if (!strncmp(uam, "Cleartxt passwrd", len)) {
-               /* clear text */
-               len = tvb_get_guint8(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_user, tvb, offset, 1,FALSE);
-               offset += len +1;
+/* ***************************/
+static gint
+dissect_query_afp_login_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       int len;
+       int len_uam;
+       const char *uam;
+       guint8 type;
 
-               len = tvb_strsize(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_passwd, tvb, offset, len,FALSE);
+       type = tvb_get_guint8(tvb, offset);
+
+       PAD(1);
+       proto_tree_add_item(tree, hf_afp_login_flags, tvb, offset, 2,FALSE);
+       offset += 2;
+       
+       len = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_AFPVersion, tvb, offset, 1,FALSE);
+       offset += len +1;
+
+       len_uam = tvb_get_guint8(tvb, offset);
+       uam = tvb_get_ptr(tvb, offset +1, len_uam);
+       proto_tree_add_item(tree, hf_afp_UAM, tvb, offset, 1,FALSE);
+       offset += len_uam +1;
+
+       type = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_user_type, tvb, offset, 1,FALSE);
+       offset++;
+       /* only type 3 */
+       len = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_user_len, tvb, offset, 2,FALSE);
+       offset += 2;
+       proto_tree_add_item(tree, hf_afp_user_name, tvb, offset, len,FALSE);
+       offset += len;
+
+       /* directory service */
+       type = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_path_type, tvb, offset, 1,FALSE);
+       offset++;
+       /* FIXME use 16 bit len + unicode from smb dissector */
+       switch (type) {
+       case 1:
+       case 2:
+               len = tvb_get_guint8(tvb, offset);
+               proto_tree_add_item(tree, hf_afp_path_len, tvb, offset,  1,FALSE);
+               offset++;
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, offset, len,FALSE);
                offset += len;
-       }
-       else if (!strncmp(uam, "No User Authent", len)) {
-       }
-       return(offset);
+               break;
+       case 3:
+               len = tvb_get_ntohs(tvb, offset);
+               proto_tree_add_item( tree, hf_afp_path_unicode_len, tvb, offset, 2,FALSE);
+               offset += 2;
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, offset, len,FALSE);
+               offset += len;
+               break;
+       default:
+               break;
+       }
+       
+       return decode_uam_parameters(uam, len_uam, tvb, tree, offset);
 }
 
 /* ************************** */
 static gint
-dissect_query_afp_write(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_write(tvbuff_t *tvb, packet_info *pinfo , proto_tree *tree, gint offset)
 {
-       int len;
-       
        proto_tree_add_item(tree, hf_afp_flag, tvb, offset, 1,FALSE);
        offset += 1;
 
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1564,14 +2280,51 @@ dissect_query_afp_write(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gin
        return offset;
 }
 
+static gint
+dissect_reply_afp_write(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       proto_tree_add_item(tree, hf_afp_last_written, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       return offset;
+}
+
 /* ************************** */
 static gint
-dissect_query_afp_read(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_write_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       proto_tree_add_item(tree, hf_afp_flag, tvb, offset, 1,FALSE);
+       offset += 1;
+
+        add_info_fork(tvb, pinfo, offset);
+       proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       proto_tree_add_item(tree, hf_afp_offset64, tvb, offset, 8,FALSE);
+       offset += 8;
+
+       proto_tree_add_item(tree, hf_afp_rw_count64, tvb, offset, 8,FALSE);
+       offset += 8;
+
+       return offset;
+}
+
+static gint
+dissect_reply_afp_write_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       proto_tree_add_item(tree, hf_afp_last_written64, tvb, offset, 8, FALSE);
+       offset += 8;
+
+       return offset;
+}
+
+/* ************************** */
+static gint
+dissect_query_afp_read(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
-       int len;
-       
        PAD(1);
-       
+
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1581,20 +2334,41 @@ dissect_query_afp_read(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint
        proto_tree_add_item(tree, hf_afp_rw_count, tvb, offset, 4,FALSE);
        offset += 4;
 
-       /* FIXME */
+       proto_tree_add_item(tree, hf_afp_newline_mask, tvb, offset, 1,FALSE);
        offset++;
-       
+
+       proto_tree_add_item(tree, hf_afp_newline_char, tvb, offset, 1,FALSE);
        offset++;
+
+       return offset;
+}
+
+/* ************************** */
+static gint
+dissect_query_afp_read_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       PAD(1);
+
+        add_info_fork(tvb, pinfo, offset);
+       proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       proto_tree_add_item(tree, hf_afp_offset64, tvb, offset, 8,FALSE);
+       offset += 8;
+
+       proto_tree_add_item(tree, hf_afp_rw_count64, tvb, offset, 8,FALSE);
+       offset += 8;
+
        return offset;
 }
 
-/* ************************** 
-   Open desktop call 
+/* **************************
+   Open desktop call
    query is the same than      AFP_FLUSH, AFP_CLOSEVOL
 
 */
 static gint
-dissect_reply_afp_open_dt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_open_dt(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
        offset += 2;
@@ -1602,11 +2376,11 @@ dissect_reply_afp_open_dt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
        return offset;
 }
 
-/* ************************** 
+/* **************************
        no reply
 */
 static gint
-dissect_query_afp_close_dt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_close_dt(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        PAD(1);
        proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
@@ -1615,10 +2389,10 @@ dissect_query_afp_close_dt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
-/* ************************** 
+/* **************************
        calls using the same format :
-               1 pad byte 
-               fork number 
+               1 pad byte
+               fork number
        AFP_FLUSHFORK
        AFP_CLOSEFORK
 */
@@ -1626,6 +2400,7 @@ static gint
 dissect_query_afp_with_fork(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        PAD(1);
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1646,14 +2421,14 @@ dissect_query_afp_get_fldr_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_get_fldr_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_get_fldr_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        guint8  flags;
        guint16 f_bitmap, d_bitmap;
 
        f_bitmap = decode_file_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        d_bitmap = decode_dir_bitmap(tree, tvb, offset);
        offset += 2;
 
@@ -1670,46 +2445,48 @@ dissect_reply_afp_get_fldr_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
        return offset;
 }
 
-/* ************************** 
+/* **************************
        no reply
 */
 static gint
 dissect_query_afp_set_fldr_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        guint16 f_bitmap;
-       
+
        PAD(1);
        offset = decode_vol_did(tree, tvb, offset);
 
        f_bitmap = decode_file_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        offset = decode_name(tree, pinfo, tvb, offset);
 
        if ((offset & 1))
                PAD(1);
-       /* did:name can be a file or a folder but only the intersection between 
-        * file bitmap and dir bitmap can be set
+       /* did:name can be a file or a folder but only the intersection between
+        * file bitmap and dir bitmap can be set.
+        * Well it's in afp spec, but clients (Mac) are setting 'file only' bits with this call
+        * (WriteInhibit for example).
         */
        offset = parse_file_bitmap(tree, tvb, offset, f_bitmap, 1);
 
        return offset;
 }
 
-/* ************************** 
+/* **************************
        no reply
 */
 static gint
 dissect_query_afp_set_file_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        guint16 f_bitmap;
-       
+
        PAD(1);
        offset = decode_vol_did(tree, tvb, offset);
 
        f_bitmap = decode_file_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        offset = decode_name(tree, pinfo, tvb, offset);
 
        if ((offset & 1))
@@ -1719,7 +2496,7 @@ dissect_query_afp_set_file_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
        return offset;
 }
 
-/* ************************** 
+/* **************************
        no reply
 */
 static gint
@@ -1732,7 +2509,7 @@ dissect_query_afp_set_dir_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
 
        d_bitmap = decode_dir_bitmap(tree, tvb, offset);
        offset += 2;
-       
+
        offset = decode_name(tree, pinfo, tvb, offset);
 
        if ((offset & 1))
@@ -1757,48 +2534,48 @@ dissect_query_afp_create_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
-/* -------------------------- 
+/* --------------------------
        AFP_MOVE
 */
 static gint
-dissect_reply_afp_create_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_create_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        proto_tree_add_item(tree, hf_afp_file_id, tvb, offset, 4,FALSE);
        offset += 4;
-       
+
        return offset;
 }
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_create_dir(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_create_dir(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
        offset += 4;
-       
+
        return offset;
 }
 
-/* ************************** 
+/* **************************
        no reply
 */
 static gint
-dissect_query_afp_delete_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_delete_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        PAD(1);
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
        proto_tree_add_item(tree, hf_afp_file_id, tvb, offset, 4,FALSE);
        offset += 4;
-       
+
        return offset;
 }
 
-/* ************************** 
+/* **************************
        same reply as get_fork_param
 */
 static gint
-dissect_query_afp_resolve_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_resolve_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        PAD(1);
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
@@ -1818,6 +2595,7 @@ dissect_query_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 {
 
        PAD(1);
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1828,7 +2606,7 @@ dissect_query_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        guint16 f_bitmap;
 
@@ -1844,16 +2622,24 @@ dissect_reply_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 static gint
 dissect_query_afp_set_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
+       guint16 bitmap;
 
        PAD(1);
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
-       decode_file_bitmap(tree, tvb, offset);
+       bitmap = decode_file_bitmap(tree, tvb, offset);
        offset += 2;
 
-       proto_tree_add_item(tree, hf_afp_ofork_len, tvb, offset, 4,FALSE);
-       offset += 4;
+       if ((bitmap & kFPExtDataForkLenBit) || (bitmap & kFPExtRsrcForkLenBit)) {
+               proto_tree_add_item(tree, hf_afp_ofork_len64, tvb, offset, 8, FALSE);
+               offset += 8;
+       }
+       else {
+               proto_tree_add_item(tree, hf_afp_ofork_len, tvb, offset, 4,FALSE);
+               offset += 4;
+       }
        return offset;
 }
 
@@ -1861,16 +2647,59 @@ dissect_query_afp_set_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 static gint
 dissect_query_afp_move(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
-               
+
        PAD(1);
        offset = decode_vol_did(tree, tvb, offset);
 
        proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
        offset += 4;
 
-       offset = decode_name_label(tree, pinfo, tvb, offset," source path : %s");
-       offset = decode_name_label(tree, NULL, tvb, offset," dest dir    : %s");
-       offset = decode_name_label(tree, NULL, tvb, offset," new name    : %s");
+       offset = decode_name_label(tree, pinfo, tvb, offset, "Source path: %s");
+       offset = decode_name_label(tree, NULL, tvb, offset,  "Dest dir:    %s");
+       offset = decode_name_label(tree, NULL, tvb, offset,  "New name:    %s");
+
+       return offset;
+}
+
+/* ************************** */
+static gint
+dissect_query_afp_exchange_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+
+       PAD(1);
+       offset = decode_vol_did(tree, tvb, offset);
+
+       proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       offset = decode_name_label(tree, pinfo, tvb, offset, "Source path: %s");
+       offset = decode_name_label(tree, NULL, tvb, offset,  "Dest path:   %s");
+
+       return offset;
+}
+/* ************************** */
+static gint
+dissect_query_afp_copy_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+       proto_tree *sub_tree = NULL;
+       proto_item *item;
+
+       PAD(1);
+       if (tree) {
+               item = proto_tree_add_text(tree, tvb, offset, 6,"Source volume");
+               sub_tree = proto_item_add_subtree(item, ett_afp_vol_did);
+       }
+       offset = decode_vol_did(sub_tree, tvb, offset);
+
+       if (tree) {
+               item = proto_tree_add_text(tree, tvb, offset, 6,"Dest volume");
+               sub_tree = proto_item_add_subtree(item, ett_afp_vol_did);
+       }
+       offset = decode_vol_did(sub_tree, tvb, offset);
+
+       offset = decode_name_label(tree, pinfo, tvb, offset, "Source path: %s");
+       offset = decode_name_label(tree, NULL, tvb, offset,  "Dest dir:    %s");
+       offset = decode_name_label(tree, NULL, tvb, offset,  "New name:    %s");
 
        return offset;
 }
@@ -1879,27 +2708,27 @@ dissect_query_afp_move(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint
 static gint
 dissect_query_afp_rename(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
-               
+
        PAD(1);
        offset = decode_vol_did(tree, tvb, offset);
 
-       offset = decode_name_label(tree, pinfo, tvb, offset," old name    : %s");
-       offset = decode_name_label(tree, NULL, tvb, offset," new name    : %s");
+       offset = decode_name_label(tree, pinfo, tvb, offset, "Old name: %s");
+       offset = decode_name_label(tree, NULL, tvb, offset,  "New name: %s");
 
        return offset;
 }
 
 /* ************************** */
 static gint
-dissect_query_afp_byte_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_byte_lock(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        proto_tree *sub_tree = NULL;
        proto_item *item;
        guint8 flag;
-       
+
        flag = tvb_get_guint8(tvb, offset);
        if (tree) {
-               item = proto_tree_add_text(tree, tvb, offset, 1, "flags : 0x%02x", flag);
+               item = proto_tree_add_text(tree, tvb, offset, 1, "Flags: 0x%02x", flag);
                sub_tree = proto_item_add_subtree(item, ett_afp_lock_flags);
        }
 
@@ -1909,7 +2738,7 @@ dissect_query_afp_byte_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
-       
+
        proto_tree_add_item(tree, hf_afp_lock_offset, tvb, offset, 4,FALSE);
        offset += 4;
 
@@ -1920,7 +2749,7 @@ dissect_query_afp_byte_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_byte_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_byte_lock(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        proto_tree_add_item(tree, hf_afp_lock_range_start, tvb, offset, 4,FALSE);
        offset += 4;
@@ -1928,6 +2757,45 @@ dissect_reply_afp_byte_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
+/* ************************** */
+static gint
+dissect_query_afp_byte_lock_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       proto_tree *sub_tree = NULL;
+       proto_item *item;
+       guint8 flag;
+
+       flag = tvb_get_guint8(tvb, offset);
+       if (tree) {
+               item = proto_tree_add_text(tree, tvb, offset, 1, "Flags: 0x%02x", flag);
+               sub_tree = proto_item_add_subtree(item, ett_afp_lock_flags);
+       }
+
+       proto_tree_add_item(sub_tree, hf_afp_lock_op, tvb, offset, 1,FALSE);
+       proto_tree_add_item(sub_tree, hf_afp_lock_from, tvb, offset, 1,FALSE);
+       offset += 1;
+
+       proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       proto_tree_add_item(tree, hf_afp_lock_offset64, tvb, offset, 8,FALSE);
+       offset += 8;
+
+       proto_tree_add_item(tree, hf_afp_lock_len64, tvb, offset, 8,FALSE);
+       offset += 8;
+       return offset;
+}
+
+/* -------------------------- */
+static gint
+dissect_reply_afp_byte_lock_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       proto_tree_add_item(tree, hf_afp_lock_range_start64, tvb, offset, 8,FALSE);
+       offset += 8;
+
+       return offset;
+}
+
 /* ************************** */
 static gint
 dissect_query_afp_add_cmt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
@@ -1943,7 +2811,7 @@ dissect_query_afp_add_cmt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
 
        offset = decode_name(tree, pinfo, tvb, offset);
 
-       if ((offset & 1)) 
+       if ((offset & 1))
                PAD(1);
 
        len = tvb_get_guint8(tvb, offset);
@@ -1972,7 +2840,7 @@ dissect_query_afp_get_cmt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_get_cmt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_get_cmt(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        guint8 len;
 
@@ -1985,7 +2853,7 @@ dissect_reply_afp_get_cmt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
 
 /* ************************** */
 static gint
-dissect_query_afp_get_icon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_get_icon(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
 
        PAD(1);
@@ -1996,7 +2864,7 @@ dissect_query_afp_get_icon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
        proto_tree_add_item(tree, hf_afp_file_type, tvb, offset, 4,FALSE);
        offset += 4;
-       
+
        proto_tree_add_item(tree, hf_afp_icon_type, tvb, offset, 1,FALSE);
        offset += 1;
        PAD(1);
@@ -2007,18 +2875,9 @@ dissect_query_afp_get_icon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
-/* -------------------------- 
-       fallback to data in afp dissector
-*/
-static gint
-dissect_reply_afp_get_icon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
-{
-       return offset;
-}
-
 /* ************************** */
 static gint
-dissect_query_afp_get_icon_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_get_icon_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
 
        PAD(1);
@@ -2035,7 +2894,7 @@ dissect_query_afp_get_icon_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_get_icon_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_get_icon_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
 
        proto_tree_add_item(tree, hf_afp_icon_tag, tvb, offset, 4,FALSE);
@@ -2043,7 +2902,7 @@ dissect_reply_afp_get_icon_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
 
        proto_tree_add_item(tree, hf_afp_file_type, tvb, offset, 4,FALSE);
        offset += 4;
-       
+
        proto_tree_add_item(tree, hf_afp_icon_type, tvb, offset, 1,FALSE);
        offset += 1;
 
@@ -2056,7 +2915,7 @@ dissect_reply_afp_get_icon_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
 
 /* ************************** */
 static gint
-dissect_query_afp_add_icon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_add_icon(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
 
        PAD(1);
@@ -2067,116 +2926,297 @@ dissect_query_afp_add_icon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
        proto_tree_add_item(tree, hf_afp_file_type, tvb, offset, 4,FALSE);
        offset += 4;
-       
+
        proto_tree_add_item(tree, hf_afp_icon_type, tvb, offset, 1,FALSE);
        offset += 1;
-       
+
        PAD(1);
        proto_tree_add_item(tree, hf_afp_icon_tag, tvb, offset, 4,FALSE);
        offset += 4;
-       
+
        proto_tree_add_item(tree, hf_afp_icon_length, tvb, offset, 2,FALSE);
        offset += 2;
 
        return offset;
 }
 
-/* ************************** 
+/* **************************
        no reply
 */
 static gint
+decode_dt_did(proto_tree *tree, tvbuff_t *tvb, gint offset)
+{
+       /* FIXME it's not volume but dt cf decode_name*/
+       Vol = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       Did = tvb_get_ntohl(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
+       offset += 4;
+       return offset;
+}
+
+/* -------------------------- */
+static gint
 dissect_query_afp_add_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+
+       PAD(1);
+       offset = decode_dt_did(tree, tvb, offset);
+
+       proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       proto_tree_add_item(tree, hf_afp_appl_tag, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       offset = decode_name(tree, pinfo, tvb, offset);
+
+       return offset;
+}
+
+/* **************************
+       no reply
+*/
+static gint
+dissect_query_afp_rmv_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+
+       PAD(1);
+       offset = decode_dt_did(tree, tvb, offset);
+
+       proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       offset = decode_name(tree, pinfo, tvb, offset);
+
+       return offset;
+}
+
+/* ************************** */
+static gint
+dissect_query_afp_get_appl(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
 
        PAD(1);
        proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
        offset += 2;
 
-       proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
+       proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
        offset += 4;
 
-       proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
+       proto_tree_add_item(tree, hf_afp_appl_index, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       decode_file_bitmap(tree, tvb, offset);
+       offset += 2;
+
+       return offset;
+}
+
+/* -------------------------- */
+static gint
+dissect_reply_afp_get_appl(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       proto_tree_add_item(tree, hf_afp_appl_tag, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       return offset;
+}
+
+/* ************************** */
+static gint
+dissect_query_afp_create_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+       proto_tree_add_item(tree, hf_afp_create_flag, tvb, offset, 1,FALSE);
+       offset++;
+
+       offset = decode_vol_did(tree, tvb, offset);
+
+       offset = decode_name(tree, pinfo, tvb, offset);
+
+       return offset;
+}
+
+/* ************************** */
+static gint
+dissect_query_afp_map_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       proto_tree_add_item(tree, hf_afp_map_id_type, tvb, offset, 1,FALSE);
+       offset++;
+
+       proto_tree_add_item(tree, hf_afp_map_id, tvb, offset, 4,FALSE);
        offset += 4;
 
-       proto_tree_add_item(tree, hf_afp_appl_tag, tvb, offset, 4,FALSE);
+       return offset;
+}
+
+/* -------------------------- */
+static gint
+dissect_reply_afp_map_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+int len;
+
+       len = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_map_name, tvb, offset, 1,FALSE);
+       offset += len +1;
+       return offset;
+}
+
+/* ************************** */
+static gint
+dissect_query_afp_map_name(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+int len;
+       proto_tree_add_item(tree, hf_afp_map_name_type, tvb, offset, 1,FALSE);
+       offset++;
+
+       len = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_map_name, tvb, offset, 1,FALSE);
+       offset += len +1;
+
+       return offset;
+}
+
+/* -------------------------- */
+static gint
+dissect_reply_afp_map_name(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+
+       proto_tree_add_item(tree, hf_afp_map_id, tvb, offset, 4,FALSE);
        offset += 4;
-       
-       offset = decode_name(tree, pinfo, tvb, offset);
-
        return offset;
 }
 
-/* ************************** 
-       no reply
-*/
+/* ************************** */
 static gint
-dissect_query_afp_rmv_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_disconnect_old_session(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
+int len;
 
        PAD(1);
-       proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
-       offset += 2;
 
-       proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
-       offset += 4;
+       proto_tree_add_item(tree, hf_afp_session_token_type, tvb, offset, 2,FALSE);
+       offset += 2;
 
-       proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
+       len = tvb_get_ntohl(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_session_token_len, tvb, offset, 4,FALSE);
        offset += 4;
 
-       offset = decode_name(tree, pinfo, tvb, offset);
+       proto_tree_add_item(tree, hf_afp_session_token, tvb, offset, len,FALSE);
+       offset += len;
 
        return offset;
 }
 
 /* ************************** */
 static gint
-dissect_query_afp_get_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_get_session_token(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
+guint16        token;
+int len;
 
        PAD(1);
-       proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
+       token = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_session_token_type, tvb, offset, 2,FALSE);
        offset += 2;
+       if (token == kLoginWithoutID) /* 0 */
+               return offset;
 
-       proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
+       len = tvb_get_ntohl(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_session_token_len, tvb, offset, 4,FALSE);
        offset += 4;
 
-       proto_tree_add_item(tree, hf_afp_appl_index, tvb, offset, 2,FALSE);
-       offset += 2;
+       switch (token) {
+       case kLoginWithTimeAndID:
+       case kReconnWithTimeAndID:
+               proto_tree_add_item(tree, hf_afp_session_token_timestamp, tvb, offset, 4,FALSE);
+               offset += 4;
+       }
 
-       decode_file_bitmap(tree, tvb, offset);
-       offset += 2;
+       proto_tree_add_item(tree, hf_afp_session_token, tvb, offset, len,FALSE);
+       offset += len;
 
        return offset;
 }
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_get_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_get_session_token(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
-       proto_tree_add_item(tree, hf_afp_appl_tag, tvb, offset, 4,FALSE);
-       offset += 4;
+int len;
+int size;
+
+       /* FIXME spec and capture disagree : or it's 4 bytes with no token type, or it's 2 bytes */
+       size = 4;
+       if (size == 2) {
+               proto_tree_add_item(tree, hf_afp_session_token_type, tvb, offset, 2,FALSE);
+               offset += 2;
+       }
+       len = tvb_get_ntohl(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_session_token_len, tvb, offset, size,FALSE);
+       offset += size;
+
+       proto_tree_add_item(tree, hf_afp_session_token, tvb, offset, len,FALSE);
+       offset += len;
 
        return offset;
 }
 
 /* ************************** */
 static gint
-dissect_query_afp_create_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_query_afp_get_user_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
-       proto_tree_add_item(tree, hf_afp_create_flag, tvb, offset, 1,FALSE);
+       proto_tree *sub_tree = NULL;
+       proto_item *item;
+       guint16  bitmap;
+
+
+       proto_tree_add_item(tree, hf_afp_user_flag, tvb, offset, 1,FALSE);
        offset++;
 
-       offset = decode_vol_did(tree, tvb, offset);
+       proto_tree_add_item(tree, hf_afp_user_ID, tvb, offset, 4,FALSE);
+       offset += 4;
 
-       offset = decode_name(tree, pinfo, tvb, offset);
+       bitmap = tvb_get_ntohs(tvb, offset);
+       if (tree) {
+               item = proto_tree_add_item(tree, hf_afp_user_bitmap, tvb, offset, 2,FALSE);
+               sub_tree = proto_item_add_subtree(item, ett_afp_user_bitmap);
+               proto_tree_add_item(sub_tree, hf_afp_user_bitmap_UID, tvb, offset, 2,FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_user_bitmap_GID, tvb, offset, 2,FALSE);
+       }
+       offset += 2;
 
        return offset;
 }
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_create_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+dissect_reply_afp_get_user_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
+       proto_tree *sub_tree = NULL;
+       proto_item *item;
+       guint16  bitmap;
+
+       bitmap = tvb_get_ntohs(tvb, offset);
+       if (tree) {
+               item = proto_tree_add_item(tree, hf_afp_user_bitmap, tvb, offset, 2,FALSE);
+               sub_tree = proto_item_add_subtree(item, ett_afp_user_bitmap);
+               proto_tree_add_item(sub_tree, hf_afp_user_bitmap_UID, tvb, offset, 2,FALSE);
+               proto_tree_add_item(sub_tree, hf_afp_user_bitmap_GID, tvb, offset, 2,FALSE);
+       }
+
+       offset += 2;
+       if ((bitmap & 1)) {
+               proto_tree_add_item(tree, hf_afp_user_ID, tvb, offset, 4,FALSE);
+               offset += 4;
+       }
+
+       if ((bitmap & 2)) {
+               proto_tree_add_item(tree, hf_afp_group_ID, tvb, offset, 4,FALSE);
+               offset += 4;
+       }
        return offset;
 }
 
@@ -2191,16 +3231,10 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        gint            offset = 0;
        afp_request_key request_key, *new_request_key;
        afp_request_val *request_val;
-
-       gchar   *func_str;
-
        guint8  afp_command;
-       guint16 afp_requestid;
-       gint32  afp_code;
-       guint32 afp_length;
-       guint32 afp_reserved;
+
        int     len =  tvb_reported_length_remaining(tvb,0);
-       
+
        if (check_col(pinfo->cinfo, COL_PROTOCOL))
                col_set_str(pinfo->cinfo, COL_PROTOCOL, "AFP");
        if (check_col(pinfo->cinfo, COL_INFO))
@@ -2215,7 +3249,7 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
        }
 
-       request_key.conversation = conversation->index; 
+       request_key.conversation = conversation->index;
        request_key.seq = aspinfo->seq;
 
        request_val = (afp_request_val *) g_hash_table_lookup(
@@ -2234,16 +3268,21 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
 
        if (!request_val) {     /* missing request */
+               if (check_col(pinfo->cinfo, COL_INFO))
+                       col_add_fstr(pinfo->cinfo, COL_INFO, "[Reply without query?]");
                return;
        }
 
        afp_command = request_val->command;
        if (check_col(pinfo->cinfo, COL_INFO)) {
-               gchar   *func_str;
-
-               if ((func_str = match_strval(afp_command, CommandCode_vals)))
-               {
-                       col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s", func_str, aspinfo->reply?"reply":"");
+               col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
+                            val_to_str(afp_command, CommandCode_vals,
+                                       "Unknown command (%u)"),
+                            aspinfo->reply ? "reply" : "request");
+               if (aspinfo->reply && aspinfo->code != 0) {
+                       col_append_fstr(pinfo->cinfo, COL_INFO, ": %s (%d)",
+                               val_to_str(aspinfo->code, asp_error_vals,
+                                       "Unknown error (%u)"), aspinfo->code);
                }
        }
 
@@ -2253,44 +3292,74 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                afp_tree = proto_item_add_subtree(ti, ett_afp);
        }
        if (!aspinfo->reply)  {
+               
                proto_tree_add_uint(afp_tree, hf_afp_command, tvb,offset, 1, afp_command);
+               if (afp_command != tvb_get_guint8(tvb, offset))
+               {
+                       /* we have the same conversation for different connections eg:
+                        * ip1:2048 --> ip2:548
+                        * ip1:2048 --> ip2:548 <RST>
+                        * ....
+                        * ip1:2048 --> ip2:548 <SYN> use the same port but it's a new session!
+                        */
+                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                               col_add_fstr(pinfo->cinfo, COL_INFO, 
+                                 "[Error!IP port reused, you need to split the capture file]");
+                               return;
+                       }
+               }
                offset++;
                switch(afp_command) {
                case AFP_BYTELOCK:
-                       offset = dissect_query_afp_byte_lock(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_byte_lock(tvb, pinfo, afp_tree, offset);break;
+               case AFP_BYTELOCK_EXT:
+                       offset = dissect_query_afp_byte_lock_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_OPENDT:        /* same as close vol */
-               case AFP_FLUSH:         
+               case AFP_FLUSH:
                case AFP_CLOSEVOL:
                        offset = dissect_query_afp_with_vol_id(tvb, pinfo, afp_tree, offset);break;
                case AFP_CLOSEDIR:
                        /* offset = dissect_query_afp_close_dir(tvb, pinfo, afp_tree, offset);break; */
                        break;
-               case AFP_CLOSEDT:       
+               case AFP_CLOSEDT:
                        offset = dissect_query_afp_close_dt(tvb, pinfo, afp_tree, offset);break;
                case AFP_FLUSHFORK: /* same packet as closefork */
                case AFP_CLOSEFORK:
                        offset = dissect_query_afp_with_fork(tvb, pinfo, afp_tree, offset);break;
                case AFP_COPYFILE:
-                       /* offset = dissect_query_afp_copy_file(tvb, pinfo, afp_tree, offset);break; */
+                       offset = dissect_query_afp_copy_file(tvb, pinfo, afp_tree, offset);break;
                case AFP_CREATEFILE:
-                       offset = dissect_query_afp_create_file(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_create_file(tvb, pinfo, afp_tree, offset);break;
+               case AFP_DISCTOLDSESS:
+                       offset = dissect_query_afp_disconnect_old_session(tvb, pinfo, afp_tree, offset);break;
+               case AFP_ENUMERATE_EXT2:
+                       offset = dissect_query_afp_enumerate_ext2(tvb, pinfo, afp_tree, offset);break;
+               case AFP_ENUMERATE_EXT:
                case AFP_ENUMERATE:
                        offset = dissect_query_afp_enumerate(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETFORKPARAM:
-                       offset = dissect_query_afp_get_fork_param(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_get_fork_param(tvb, pinfo, afp_tree, offset);break;
+               case AFP_GETSESSTOKEN:
+                       offset = dissect_query_afp_get_session_token(tvb, pinfo, afp_tree, offset);break;
+               case AFP_GETUSERINFO:
+                       offset = dissect_query_afp_get_user_info(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETSRVINFO:
                        /* offset = dissect_query_afp_get_server_info(tvb, pinfo, afp_tree, offset);break; */
                case AFP_GETSRVPARAM:
                        break;                                  /* no parameters */
                case AFP_GETVOLPARAM:
                        offset = dissect_query_afp_get_vol_param(tvb, pinfo, afp_tree, offset);break;
+               case AFP_LOGIN_EXT:
+                       offset = dissect_query_afp_login_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_LOGIN:
                        offset = dissect_query_afp_login(tvb, pinfo, afp_tree, offset);break;
                case AFP_LOGINCONT:
                case AFP_LOGOUT:
+                       break;
                case AFP_MAPID:
+                       offset = dissect_query_afp_map_id(tvb, pinfo, afp_tree, offset);break;
                case AFP_MAPNAME:
-                       break;
+                       offset = dissect_query_afp_map_name(tvb, pinfo, afp_tree, offset);break;
                case AFP_MOVE:
                        offset = dissect_query_afp_move(tvb, pinfo, afp_tree, offset);break;
                case AFP_OPENVOL:
@@ -2301,18 +3370,22 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        offset = dissect_query_afp_open_fork(tvb, pinfo, afp_tree, offset);break;
                case AFP_READ:
                        offset = dissect_query_afp_read(tvb, pinfo, afp_tree, offset);break;
+               case AFP_READ_EXT:
+                       offset = dissect_query_afp_read_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_RENAME:
                        offset = dissect_query_afp_rename(tvb, pinfo, afp_tree, offset);break;
                case AFP_SETDIRPARAM:
-                       offset = dissect_query_afp_set_dir_param(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_set_dir_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_SETFILEPARAM:
-                       offset = dissect_query_afp_set_file_param(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_set_file_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_SETFORKPARAM:
-                       offset = dissect_query_afp_set_fork_param(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_set_fork_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_SETVOLPARAM:
                        offset = dissect_query_afp_set_vol_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_WRITE:
                        offset = dissect_query_afp_write(tvb, pinfo, afp_tree, offset);break;
+               case AFP_WRITE_EXT:
+                       offset = dissect_query_afp_write_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETFLDRPARAM:
                        offset = dissect_query_afp_get_fldr_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_SETFLDRPARAM:
@@ -2323,38 +3396,52 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                case AFP_DELETE:        /* same as create_id */
                case AFP_CREATEDIR:
                case AFP_CREATEID:
-                       offset = dissect_query_afp_create_id(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_create_id(tvb, pinfo, afp_tree, offset);break;
                case AFP_DELETEID:
-                       offset = dissect_query_afp_delete_id(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_delete_id(tvb, pinfo, afp_tree, offset);break;
                case AFP_RESOLVEID:
-                       offset = dissect_query_afp_resolve_id(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_resolve_id(tvb, pinfo, afp_tree, offset);break;
                case AFP_EXCHANGEFILE:
+                       offset = dissect_query_afp_exchange_file(tvb, pinfo, afp_tree, offset);break;
+               case AFP_CATSEARCH_EXT:
+                       offset = dissect_query_afp_cat_search_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_CATSEARCH:
-                       break;
+                       offset = dissect_query_afp_cat_search(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETICON:
-                       offset = dissect_query_afp_get_icon(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_get_icon(tvb, pinfo, afp_tree, offset);break;
                case AFP_GTICNINFO:
-                       offset = dissect_query_afp_get_icon_info(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_get_icon_info(tvb, pinfo, afp_tree, offset);break;
                case AFP_ADDAPPL:
-                       offset = dissect_query_afp_add_appl(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_add_appl(tvb, pinfo, afp_tree, offset);break;
                case AFP_RMVAPPL:
-                       offset = dissect_query_afp_rmv_appl(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_rmv_appl(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETAPPL:
-                       offset = dissect_query_afp_get_appl(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_get_appl(tvb, pinfo, afp_tree, offset);break;
                case AFP_ADDCMT:
-                       offset = dissect_query_afp_add_cmt(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_add_cmt(tvb, pinfo, afp_tree, offset);break;
                case AFP_RMVCMT: /* same as get_cmt */
                case AFP_GETCMT:
-                       offset = dissect_query_afp_get_cmt(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_get_cmt(tvb, pinfo, afp_tree, offset);break;
                case AFP_ADDICON:
-                       offset = dissect_query_afp_add_icon(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_query_afp_add_icon(tvb, pinfo, afp_tree, offset);break;
                        break;
                }
        }
        else {
+               proto_tree_add_uint(afp_tree, hf_afp_command, tvb, 0, 0, afp_command);
+               if (!len) {
+                       /* for some calls if the reply is an error there's no data
+                       */
+                       return;
+               }
                switch(afp_command) {
                case AFP_BYTELOCK:
-                       offset = dissect_reply_afp_byte_lock(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_reply_afp_byte_lock(tvb, pinfo, afp_tree, offset);break;
+               case AFP_BYTELOCK_EXT:
+                       offset = dissect_reply_afp_byte_lock_ext(tvb, pinfo, afp_tree, offset);break;
+               case AFP_ENUMERATE_EXT2:
+               case AFP_ENUMERATE_EXT:
+                       offset = dissect_reply_afp_enumerate_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_ENUMERATE:
                        offset = dissect_reply_afp_enumerate(tvb, pinfo, afp_tree, offset);break;
                case AFP_OPENVOL:
@@ -2364,32 +3451,47 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                case AFP_RESOLVEID:
                case AFP_GETFORKPARAM:
                        offset =dissect_reply_afp_get_fork_param(tvb, pinfo, afp_tree, offset);break;
-               case AFP_GETSRVINFO:
+               case AFP_GETUSERINFO:
+                       offset = dissect_reply_afp_get_user_info(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETSRVPARAM:
-                       break;
+                       offset = dissect_reply_afp_get_server_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_CREATEDIR:
-                       offset = dissect_reply_afp_create_dir(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_reply_afp_create_dir(tvb, pinfo, afp_tree, offset);break;
+               case AFP_MAPID:
+                       offset = dissect_reply_afp_map_id(tvb, pinfo, afp_tree, offset);break;
+               case AFP_MAPNAME:
+                       offset = dissect_reply_afp_map_name(tvb, pinfo, afp_tree, offset);break;
                case AFP_MOVE:          /* same as create_id */
                case AFP_CREATEID:
-                       offset = dissect_reply_afp_create_id(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_reply_afp_create_id(tvb, pinfo, afp_tree, offset);break;
+               case AFP_GETSESSTOKEN:
+                       offset = dissect_reply_afp_get_session_token(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETVOLPARAM:
                        offset = dissect_reply_afp_get_vol_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETFLDRPARAM:
                        offset = dissect_reply_afp_get_fldr_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_OPENDT:
                        offset = dissect_reply_afp_open_dt(tvb, pinfo, afp_tree, offset);break;
-               case AFP_GETICON:
-                       offset = dissect_reply_afp_get_icon(tvb, pinfo, afp_tree, offset);break; 
+               case AFP_CATSEARCH_EXT:
+                       offset = dissect_reply_afp_cat_search_ext(tvb, pinfo, afp_tree, offset);break;
+               case AFP_CATSEARCH:
+                       offset = dissect_reply_afp_cat_search(tvb, pinfo, afp_tree, offset);break;
                case AFP_GTICNINFO:
-                       offset = dissect_reply_afp_get_icon_info(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_reply_afp_get_icon_info(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETAPPL:
-                       offset = dissect_reply_afp_get_appl(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_reply_afp_get_appl(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETCMT:
-                       offset = dissect_reply_afp_get_cmt(tvb, pinfo, afp_tree, offset);break; 
+                       offset = dissect_reply_afp_get_cmt(tvb, pinfo, afp_tree, offset);break;
+               case AFP_WRITE:
+                       offset = dissect_reply_afp_write(tvb, pinfo, afp_tree, offset);break;
+               case AFP_WRITE_EXT:
+                       offset = dissect_reply_afp_write_ext(tvb, pinfo, afp_tree, offset);break;
                }
        }
-       if (tree && offset < len)
-               call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, afp_tree);
+       if (tree && offset < len) {
+               call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
+                   pinfo, afp_tree);
+       }
 }
 
 static void afp_reinit( void)
@@ -2425,699 +3527,1035 @@ proto_register_afp(void)
                FT_UINT8, BASE_DEC, VALS(CommandCode_vals), 0x0,
        "AFP function", HFILL }},
 
-       { &hf_afp_pad,    
-         { "pad",              "afp.pad",    
-               FT_NONE,   BASE_NONE, NULL, 0, 
-               "Pad Byte",     HFILL }},
+    { &hf_afp_pad,
+      { "Pad",         "afp.pad",
+               FT_NONE,   BASE_NONE, NULL, 0,
+       "Pad Byte",     HFILL }},
 
     { &hf_afp_AFPVersion,
       { "AFP Version",  "afp.AFPVersion",
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
-       "client AFP version", HFILL }},
+       "Client AFP version", HFILL }},
 
     { &hf_afp_UAM,
       { "UAM",          "afp.UAM",
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
-       "USer Authentication method", HFILL }},
+       "User Authentication Method", HFILL }},
 
     { &hf_afp_user,
-      { "user",         "afp.user",
+      { "User",         "afp.user",
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
        "User", HFILL }},
 
+    { &hf_afp_user_type,
+      { "Type",         "afp.user_type",
+               FT_UINT8, BASE_HEX, VALS(path_type_vals), 0,
+       "Type of user name", HFILL }},
+    { &hf_afp_user_len,
+      { "Len",  "afp.user_len",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+       "User name length (unicode)", HFILL }},
+    { &hf_afp_user_name,
+      { "User",  "afp.user_name",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+       "User name (unicode)", HFILL }},
+
     { &hf_afp_passwd,
-      { "password",     "afp.passwd",
+      { "Password",     "afp.passwd",
                FT_STRINGZ, BASE_NONE, NULL, 0x0,
-       "password", HFILL }},
+       "Password", HFILL }},
+
+    { &hf_afp_random,
+      { "Random number",         "afp.random",
+               FT_BYTES, BASE_HEX, NULL, 0x0,
+       "UAM random number", HFILL }},
+
+    { &hf_afp_login_flags,
+      { "Flags",         "afp.afp_login_flags",
+               FT_UINT16, BASE_HEX, NULL, 0 /* 0x0FFF*/,
+       "Login flags", HFILL }},
 
     { &hf_afp_vol_bitmap,
-      { "bitmap",         "afp.vol_bitmap",
+      { "Bitmap",         "afp.vol_bitmap",
                FT_UINT16, BASE_HEX, NULL, 0 /* 0x0FFF*/,
        "Volume bitmap", HFILL }},
 
-       { &hf_afp_vol_bitmap_Attribute,
-      { "attribute",         "afp.vol_bitmap.attribute",
+    { &hf_afp_vol_bitmap_Attributes,
+      { "Attributes",      "afp.vol_bitmap.attributes",
                FT_BOOLEAN, 16, NULL, kFPVolAttributeBit,
-       "Volume attribute", HFILL }},
+       "Volume attributes", HFILL }},
 
-           { &hf_afp_vol_attribute, { "attribute",         "afp.vol_attribute",
-                       FT_UINT16, BASE_HEX, NULL, 0 , "Volume attribute", HFILL }},
+    { &hf_afp_vol_attribute,
+      { "Attributes",         "afp.vol_attributes",
+               FT_UINT16, BASE_HEX, NULL, 0,
+       "Volume attributes", HFILL }},
 
-           { &hf_afp_vol_attribute_ReadOnly, 
-            { "read only",         "afp.vol_attribute.read_only",
+    { &hf_afp_vol_attribute_ReadOnly,
+      { "Read only",         "afp.vol_attribute.read_only",
                 FT_BOOLEAN, 16, NULL, kReadOnly,
-        "Read only volume", HFILL }},
+        "Read only volume", HFILL }},
 
-           { &hf_afp_vol_attribute_HasVolumePassword,
-            { "volume password",         "afp.vol_attribute.passwd",
+    { &hf_afp_vol_attribute_HasVolumePassword,
+      { "Volume password",         "afp.vol_attribute.passwd",
                 FT_BOOLEAN, 16, NULL, kHasVolumePassword,
-        "Has a volume password", HFILL }},
+       "Has a volume password", HFILL }},
 
-           { &hf_afp_vol_attribute_SupportsFileIDs,
-            { "files ID",         "afp.vol_attribute.fileIDs",
+    { &hf_afp_vol_attribute_SupportsFileIDs,
+      { "File IDs",         "afp.vol_attribute.fileIDs",
                 FT_BOOLEAN, 16, NULL, kSupportsFileIDs,
-        "Supports files ID", HFILL }},
+       "Supports file IDs", HFILL }},
 
-           { &hf_afp_vol_attribute_SupportsCatSearch,
-            { "cat search",         "afp.vol_attribute.cat_search",
+    { &hf_afp_vol_attribute_SupportsCatSearch,
+      { "Catalog search",         "afp.vol_attribute.cat_search",
                 FT_BOOLEAN, 16, NULL, kSupportsCatSearch,
-        "Supports cat search call", HFILL }},
+       "Supports catalog search operations", HFILL }},
 
-           { &hf_afp_vol_attribute_SupportsBlankAccessPrivs,
-            { "blank access privs",         "afp.vol_attribute.blank_access_privs",
+    { &hf_afp_vol_attribute_SupportsBlankAccessPrivs,
+      { "Blank access privileges",         "afp.vol_attribute.blank_access_privs",
                 FT_BOOLEAN, 16, NULL, kSupportsBlankAccessPrivs,
-        "Supports blank access priv.", HFILL }},
+        "Supports blank access privileges", HFILL }},
 
-           { &hf_afp_vol_attribute_SupportsUnixPrivs,
-           { "blank access privs",         "afp.vol_attribute.unix_privs",
+    { &hf_afp_vol_attribute_SupportsUnixPrivs,
+      { "UNIX access privileges",         "afp.vol_attribute.unix_privs",
                 FT_BOOLEAN, 16, NULL, kSupportsUnixPrivs,
-        "Supports Unix access priv.", HFILL }},
+       "Supports UNIX access privileges", HFILL }},
 
-           { &hf_afp_vol_attribute_SupportsUTF8Names,
-           { "blank access privs",         "afp.vol_attribute.utf8_names",
+    { &hf_afp_vol_attribute_SupportsUTF8Names,
+      { "UTF-8 names",         "afp.vol_attribute.utf8_names",
                 FT_BOOLEAN, 16, NULL, kSupportsUTF8Names,
-        "Supports UTF8 names.", HFILL }},
+       "Supports UTF-8 names", HFILL }},
 
     { &hf_afp_vol_bitmap_Signature,
-      { "signature",         "afp.vol_bitmap.signature",
+      { "Signature",         "afp.vol_bitmap.signature",
                FT_BOOLEAN, 16, NULL, kFPVolSignatureBit,
        "Volume signature", HFILL }},
+
     { &hf_afp_vol_bitmap_CreateDate,
-      { "creation date",      "afp.vol_bitmap.create_date",
+      { "Creation date",      "afp.vol_bitmap.create_date",
                FT_BOOLEAN, 16, NULL, kFPVolCreateDateBit,
        "Volume creation date", HFILL }},
+
     { &hf_afp_vol_bitmap_ModDate,
-      { "modification date",  "afp.vol_bitmap.mod_date",
+      { "Modification date",  "afp.vol_bitmap.mod_date",
                FT_BOOLEAN, 16, NULL, kFPVolModDateBit,
        "Volume modification date", HFILL }},
+
     { &hf_afp_vol_bitmap_BackupDate,
-      { "backup date",        "afp.vol_bitmap.backup_date",
+      { "Backup date",        "afp.vol_bitmap.backup_date",
                FT_BOOLEAN, 16, NULL, kFPVolBackupDateBit,
        "Volume backup date", HFILL }},
+
     { &hf_afp_vol_bitmap_ID,
       { "ID",         "afp.vol_bitmap.id",
                FT_BOOLEAN, 16, NULL,  kFPVolIDBit,
        "Volume ID", HFILL }},
+
     { &hf_afp_vol_bitmap_BytesFree,
-      { "bytes free",         "afp.vol_bitmap.bytes_free",
+      { "Bytes free",         "afp.vol_bitmap.bytes_free",
                FT_BOOLEAN, 16, NULL,  kFPVolBytesFreeBit,
        "Volume free bytes", HFILL }},
+
     { &hf_afp_vol_bitmap_BytesTotal,
-      { "bytes total",         "afp.vol_bitmap.bytes_total",
+      { "Bytes total",         "afp.vol_bitmap.bytes_total",
                FT_BOOLEAN, 16, NULL,  kFPVolBytesTotalBit,
        "Volume total bytes", HFILL }},
+
     { &hf_afp_vol_bitmap_Name,
-      { "name",         "afp.vol_bitmap.name",
+      { "Name",         "afp.vol_bitmap.name",
                FT_BOOLEAN, 16, NULL,  kFPVolNameBit,
        "Volume name", HFILL }},
+
     { &hf_afp_vol_bitmap_ExtBytesFree,
-      { "ex. bytes free",         "afp.vol_bitmap.ex_bytes_free",
+      { "Extended bytes free",         "afp.vol_bitmap.ex_bytes_free",
                FT_BOOLEAN, 16, NULL,  kFPVolExtBytesFreeBit,
-       "Volume ext. free bytes", HFILL }},
+       "Volume extended (>2GB) free bytes", HFILL }},
+
     { &hf_afp_vol_bitmap_ExtBytesTotal,
-      { "ex bytes total",         "afp.vol_bitmap.ex_bytes_total",
+      { "Extended bytes total",         "afp.vol_bitmap.ex_bytes_total",
                FT_BOOLEAN, 16, NULL,  kFPVolExtBytesTotalBit,
-       "Volume ex. total byte", HFILL }},
+       "Volume extended (>2GB) total bytes", HFILL }},
+
     { &hf_afp_vol_bitmap_BlockSize,
-      { "block size",         "afp.vol_bitmap.block_size",
+      { "Block size",         "afp.vol_bitmap.block_size",
                FT_BOOLEAN, 16, NULL,  kFPVolBlockSizeBit,
        "Volume block size", HFILL }},
 
-    { &hf_afp_dir_bitmap_Attribute,        
-      { "attribute",         "afp.dir_bitmap.attribute",
+    { &hf_afp_dir_bitmap_Attributes,
+      { "Attributes",         "afp.dir_bitmap.attributes",
            FT_BOOLEAN, 16, NULL,  kFPAttributeBit,
-       "directory attribute", HFILL }},
-    { &hf_afp_dir_bitmap_ParentDirID,     
+       "Return attributes if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_ParentDirID,
       { "DID",         "afp.dir_bitmap.did",
        FT_BOOLEAN, 16, NULL,  kFPParentDirIDBit,
-       "parent directory ID", HFILL }},
-    { &hf_afp_dir_bitmap_CreateDate,      
-      { "creation date",         "afp.dir_bitmap.create_date",
+       "Return parent directory ID if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_CreateDate,
+      { "Creation date",         "afp.dir_bitmap.create_date",
            FT_BOOLEAN, 16, NULL,  kFPCreateDateBit,
-       "directory creation date", HFILL }},
-    { &hf_afp_dir_bitmap_ModDate,                 
-      { "modification date",         "afp.dir_bitmap.mod_date",
+       "Return creation date if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_ModDate,
+      { "Modification date",         "afp.dir_bitmap.mod_date",
        FT_BOOLEAN, 16, NULL,  kFPModDateBit,
-       "directory modification date", HFILL }},
-    { &hf_afp_dir_bitmap_BackupDate,      
-      { "backup date",         "afp.dir_bitmap.backup_date",
+       "Return modification date if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_BackupDate,
+      { "Backup date",         "afp.dir_bitmap.backup_date",
            FT_BOOLEAN, 16, NULL,  kFPBackupDateBit,
-       "directory backup date", HFILL }},
-    { &hf_afp_dir_bitmap_FinderInfo,      
+       "Return backup date if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_FinderInfo,
       { "Finder info",         "afp.dir_bitmap.finder_info",
        FT_BOOLEAN, 16, NULL,  kFPFinderInfoBit,
-       "directory finder info", HFILL }},
-    { &hf_afp_dir_bitmap_LongName,                
-      { "long name",         "afp.dir_bitmap.long_name",
+       "Return finder info if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_LongName,
+      { "Long name",         "afp.dir_bitmap.long_name",
            FT_BOOLEAN, 16, NULL,  kFPLongNameBit,
-       "directory long name", HFILL }},
-    { &hf_afp_dir_bitmap_ShortName,               
-      { "short name",         "afp.dir_bitmap.short_name",
+       "Return long name if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_ShortName,
+      { "Short name",         "afp.dir_bitmap.short_name",
        FT_BOOLEAN, 16, NULL,  kFPShortNameBit,
-       "directory short name", HFILL }},
-    { &hf_afp_dir_bitmap_NodeID,                  
-      { "file ID",         "afp.dir_bitmap.fid",
+       "Return short name if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_NodeID,
+      { "File ID",         "afp.dir_bitmap.fid",
            FT_BOOLEAN, 16, NULL,  kFPNodeIDBit,
-       "directory file ID", HFILL }},
-    { &hf_afp_dir_bitmap_OffspringCount,   
-      { "offspring count",         "afp.dir_bitmap.offspring_count",
+       "Return file ID if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_OffspringCount,
+      { "Offspring count",         "afp.dir_bitmap.offspring_count",
        FT_BOOLEAN, 16, NULL,  kFPOffspringCountBit,
-       "directory offSpring count", HFILL }},
-    { &hf_afp_dir_bitmap_OwnerID,                 
-      { "owner id",         "afp.dir_bitmap.owner_id",
+       "Return offspring count if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_OwnerID,
+      { "Owner id",         "afp.dir_bitmap.owner_id",
            FT_BOOLEAN, 16, NULL,  kFPOwnerIDBit,
-       "directory owner id", HFILL }},
-    { &hf_afp_dir_bitmap_GroupID,                 
-      { "group id",         "afp.dir_bitmap.group_id",
+       "Return owner id if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_GroupID,
+      { "Group id",         "afp.dir_bitmap.group_id",
        FT_BOOLEAN, 16, NULL,  kFPGroupIDBit,
-       "directory group id", HFILL }},
-    { &hf_afp_dir_bitmap_AccessRights,    
-      { "access rights",         "afp.dir_bitmap.access_rights",
+       "Return group id if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_AccessRights,
+      { "Access rights",         "afp.dir_bitmap.access_rights",
            FT_BOOLEAN, 16, NULL,  kFPAccessRightsBit,
-       "directory access rights", HFILL }},
-    { &hf_afp_dir_bitmap_UTF8Name,                
-      { "UTF8 name",         "afp.dir_bitmap.UTF8_name",
+       "Return access rights if directory", HFILL }},
+
+    { &hf_afp_dir_bitmap_UTF8Name,
+      { "UTF-8 name",         "afp.dir_bitmap.UTF8_name",
        FT_BOOLEAN, 16, NULL,  kFPUTF8NameBit,
-       "directory UTF8 name", HFILL }},
-    { &hf_afp_dir_bitmap_UnixPrivs,               
-      { "unix privs",         "afp.dir_bitmap.unix_privs",
+       "Return UTF-8 name if diectory", HFILL }},
+
+    { &hf_afp_dir_bitmap_UnixPrivs,
+      { "UNIX privileges",         "afp.dir_bitmap.unix_privs",
            FT_BOOLEAN, 16, NULL,  kFPUnixPrivsBit,
-       "directory unix privs", HFILL }},
+       "Return UNIX privileges if directory", HFILL }},
 
     { &hf_afp_dir_attribute_Invisible,
-      { "invisible",         "afp.dir_attribute.invisible",
+      { "Invisible",         "afp.dir_attribute.invisible",
            FT_BOOLEAN, 16, NULL,  kFPInvisibleBit,
-       "dir is not visible", HFILL }},
+       "Directory is not visible", HFILL }},
+
     { &hf_afp_dir_attribute_IsExpFolder,
-      { "share point",         "afp.dir_attribute.share",
+      { "Share point",         "afp.dir_attribute.share",
            FT_BOOLEAN, 16, NULL,  kFPMultiUserBit,
-       "share point", HFILL }},
+       "Directory is a share point", HFILL }},
+
     { &hf_afp_dir_attribute_System,
-      { "sytem",                "afp.dir_attribute.system",
+      { "System",               "afp.dir_attribute.system",
            FT_BOOLEAN, 16, NULL,  kFPSystemBit,
-       "sytem dir", HFILL }},
+       "Directory is a system directory", HFILL }},
+
     { &hf_afp_dir_attribute_Mounted,
-      { "mounted",         "afp.dir_attribute.mounted",
+      { "Mounted",         "afp.dir_attribute.mounted",
            FT_BOOLEAN, 16, NULL,  kFPDAlreadyOpenBit,
-       "dir is mounted", HFILL }},
+       "Directory is mounted", HFILL }},
+
     { &hf_afp_dir_attribute_InExpFolder,
-      { "shared area",         "afp.dir_attribute.in_exported_folder",
+      { "Shared area",         "afp.dir_attribute.in_exported_folder",
            FT_BOOLEAN, 16, NULL,  kFPRAlreadyOpenBit,
-       "in a shared dir", HFILL }},
+       "Directory is in a shared area", HFILL }},
+
     { &hf_afp_dir_attribute_BackUpNeeded,
-      { "backup needed",         "afp.dir_attribute.backup_needed",
+      { "Backup needed",         "afp.dir_attribute.backup_needed",
            FT_BOOLEAN, 16, NULL,  kFPBackUpNeededBit,
-       "backup needed", HFILL }},
+       "Directory needs to be backed up", HFILL }},
+
     { &hf_afp_dir_attribute_RenameInhibit,
-      { "rename inhibit",         "afp.dir_attribute.rename_inhibit",
+      { "Rename inhibit",         "afp.dir_attribute.rename_inhibit",
            FT_BOOLEAN, 16, NULL,  kFPRenameInhibitBit,
-       "rename inhibit", HFILL }},
+       "Rename inhibit", HFILL }},
+
     { &hf_afp_dir_attribute_DeleteInhibit,
-      { "delete inhibit",         "afp.dir_attribute.delete_inhibit",
+      { "Delete inhibit",         "afp.dir_attribute.delete_inhibit",
            FT_BOOLEAN, 16, NULL,  kFPDeleteInhibitBit,
-       "delete inhibit", HFILL }},
+       "Delete inhibit", HFILL }},
+
     { &hf_afp_dir_attribute_SetClear,
-      { "set",         "afp.dir_attribute.set_clear",
+      { "Set",         "afp.dir_attribute.set_clear",
            FT_BOOLEAN, 16, NULL,  kFPSetClearBit,
-       "clear/set attribute", HFILL }},
+       "Clear/set attribute", HFILL }},
 
-    { &hf_afp_file_bitmap_Attribute,        
-      { "attribute",         "afp.file_bitmap.attribute",
+    { &hf_afp_file_bitmap_Attributes,
+      { "Attributes",         "afp.file_bitmap.attributes",
            FT_BOOLEAN, 16, NULL,  kFPAttributeBit,
-       "file attribute", HFILL }},
-    { &hf_afp_file_bitmap_ParentDirID,    
+       "Return attributes if file", HFILL }},
+
+    { &hf_afp_file_bitmap_ParentDirID,
       { "DID",         "afp.file_bitmap.did",
        FT_BOOLEAN, 16, NULL,  kFPParentDirIDBit,
-       "parent directory ID", HFILL }},
-    { &hf_afp_file_bitmap_CreateDate,     
-      { "creation date",         "afp.file_bitmap.create_date",
+       "Return parent directory ID if file", HFILL }},
+
+    { &hf_afp_file_bitmap_CreateDate,
+      { "Creation date",         "afp.file_bitmap.create_date",
            FT_BOOLEAN, 16, NULL,  kFPCreateDateBit,
-       "file creation date", HFILL }},
-    { &hf_afp_file_bitmap_ModDate,                
-      { "modification date",         "afp.file_bitmap.mod_date",
+       "Return creation date if file", HFILL }},
+
+    { &hf_afp_file_bitmap_ModDate,
+      { "Modification date",         "afp.file_bitmap.mod_date",
        FT_BOOLEAN, 16, NULL,  kFPModDateBit,
-       "file modification date", HFILL }},
-    { &hf_afp_file_bitmap_BackupDate,     
-      { "backup date",         "afp.file_bitmap.backup_date",
+       "Return modification date if file", HFILL }},
+
+    { &hf_afp_file_bitmap_BackupDate,
+      { "Backup date",         "afp.file_bitmap.backup_date",
            FT_BOOLEAN, 16, NULL,  kFPBackupDateBit,
-       "file backup date", HFILL }},
-    { &hf_afp_file_bitmap_FinderInfo,     
+       "Return backup date if file", HFILL }},
+
+    { &hf_afp_file_bitmap_FinderInfo,
       { "Finder info",         "afp.file_bitmap.finder_info",
        FT_BOOLEAN, 16, NULL,  kFPFinderInfoBit,
-       "file finder info", HFILL }},
-    { &hf_afp_file_bitmap_LongName,               
-      { "long name",         "afp.file_bitmap.long_name",
+       "Return finder info if file", HFILL }},
+
+    { &hf_afp_file_bitmap_LongName,
+      { "Long name",         "afp.file_bitmap.long_name",
            FT_BOOLEAN, 16, NULL,  kFPLongNameBit,
-       "file long name", HFILL }},
-    { &hf_afp_file_bitmap_ShortName,              
-      { "short name",         "afp.file_bitmap.short_name",
+       "Return long name if file", HFILL }},
+
+    { &hf_afp_file_bitmap_ShortName,
+      { "Short name",         "afp.file_bitmap.short_name",
        FT_BOOLEAN, 16, NULL,  kFPShortNameBit,
-       "file short name", HFILL }},
-    { &hf_afp_file_bitmap_NodeID,                 
-      { "file ID",         "afp.file_bitmap.fid",
+       "Return short name if file", HFILL }},
+
+    { &hf_afp_file_bitmap_NodeID,
+      { "File ID",         "afp.file_bitmap.fid",
            FT_BOOLEAN, 16, NULL,  kFPNodeIDBit,
-       "file file ID", HFILL }},
+       "Return file ID if file", HFILL }},
 
     { &hf_afp_file_bitmap_DataForkLen,
-       { "data size",         "afp.file_bitmap.data_fork_len",
+      { "Data fork size",         "afp.file_bitmap.data_fork_len",
            FT_BOOLEAN, 16, NULL,  kFPDataForkLenBit,
-       "data fork size", HFILL }},
+       "Return data fork size if file", HFILL }},
+
     { &hf_afp_file_bitmap_RsrcForkLen,
-       { "ressource size",         "afp.file_bitmap.ressource_fork_len",
+      { "Resource fork size",         "afp.file_bitmap.resource_fork_len",
            FT_BOOLEAN, 16, NULL,  kFPRsrcForkLenBit,
-       "ressource fork size", HFILL }},
+       "Return resource fork size if file", HFILL }},
+
     { &hf_afp_file_bitmap_ExtDataForkLen,
-       { "ext. data size",         "afp.file_bitmap.ex_data_fork_len",
+      { "Extended data fork size",         "afp.file_bitmap.ex_data_fork_len",
            FT_BOOLEAN, 16, NULL,  kFPExtDataForkLenBit,
-       ">2Gbyte data fork size", HFILL }},
+       "Return extended (>2GB) data fork size if file", HFILL }},
+
     { &hf_afp_file_bitmap_LaunchLimit,
-       { "launch limit",         "afp.file_bitmap.launch_limit",
+      { "Launch limit",         "afp.file_bitmap.launch_limit",
            FT_BOOLEAN, 16, NULL,  kFPLaunchLimitBit,
-       "launch limit", HFILL }},
-    { &hf_afp_file_bitmap_UTF8Name,               
-      { "UTF8 name",         "afp.file_bitmap.UTF8_name",
+       "Return launch limit if file", HFILL }},
+
+    { &hf_afp_file_bitmap_UTF8Name,
+      { "UTF-8 name",         "afp.file_bitmap.UTF8_name",
        FT_BOOLEAN, 16, NULL,  kFPUTF8NameBit,
-       "file UTF8 name", HFILL }},
+       "Return UTF-8 name if file", HFILL }},
+
     { &hf_afp_file_bitmap_ExtRsrcForkLen,
-       { "ext. ressource size",         "afp.file_bitmap.ex_ressource_fork_len",
+       { "Extended resource fork size",         "afp.file_bitmap.ex_resource_fork_len",
            FT_BOOLEAN, 16, NULL,  kFPExtRsrcForkLenBit,
-       ">2Gbyte ressource fork size", HFILL }},
-    { &hf_afp_file_bitmap_UnixPrivs,              
-      { "unix privs",         "afp.file_bitmap.unix_privs",
-           FT_BOOLEAN, 16, NULL,  kFPUnixPrivsBit_file,
-       "file unix privs", HFILL }},
+       "Return extended (>2GB) resource fork size if file", HFILL }},
+
+    { &hf_afp_file_bitmap_UnixPrivs,
+      { "UNIX privileges",    "afp.file_bitmap.unix_privs",
+           FT_BOOLEAN, 16, NULL,  kFPUnixPrivsBit,
+       "Return UNIX privileges if file", HFILL }},
+
        /* ---------- */
     { &hf_afp_file_attribute_Invisible,
-      { "invisible",         "afp.file_attribute.invisible",
+      { "Invisible",         "afp.file_attribute.invisible",
            FT_BOOLEAN, 16, NULL,  kFPInvisibleBit,
-       "file is not visible", HFILL }},
+       "File is not visible", HFILL }},
+
     { &hf_afp_file_attribute_MultiUser,
-      { "multi user",         "afp.file_attribute.multi_user",
+      { "Multi user",         "afp.file_attribute.multi_user",
            FT_BOOLEAN, 16, NULL,  kFPMultiUserBit,
        "multi user", HFILL }},
+
     { &hf_afp_file_attribute_System,
-      { "sytem",                "afp.file_attribute.system",
+      { "System",               "afp.file_attribute.system",
            FT_BOOLEAN, 16, NULL,  kFPSystemBit,
-       "system file", HFILL }},
+       "File is a system file", HFILL }},
+
     { &hf_afp_file_attribute_DAlreadyOpen,
-      { "df open",         "afp.file_attribute.df_open",
+      { "Data fork open",         "afp.file_attribute.df_open",
            FT_BOOLEAN, 16, NULL,  kFPDAlreadyOpenBit,
-       "data fork already open", HFILL }},
+       "Data fork already open", HFILL }},
+
     { &hf_afp_file_attribute_RAlreadyOpen,
-      { "rf open",         "afp.file_attribute.rf_open",
+      { "Resource fork open",         "afp.file_attribute.rf_open",
            FT_BOOLEAN, 16, NULL,  kFPRAlreadyOpenBit,
-       "ressource fork already open", HFILL }},
+       "Resource fork already open", HFILL }},
+
     { &hf_afp_file_attribute_WriteInhibit,
-      { "write inhibit",         "afp.file_attribute.write_inhibit",
+      { "Write inhibit",         "afp.file_attribute.write_inhibit",
            FT_BOOLEAN, 16, NULL,  kFPWriteInhibitBit,
-       "write inhibit", HFILL }},
+       "Write inhibit", HFILL }},
+
     { &hf_afp_file_attribute_BackUpNeeded,
-      { "backup needed",         "afp.file_attribute.backup_needed",
+      { "Backup needed",         "afp.file_attribute.backup_needed",
            FT_BOOLEAN, 16, NULL,  kFPBackUpNeededBit,
-       "backup needed", HFILL }},
+       "File needs to be backed up", HFILL }},
+
     { &hf_afp_file_attribute_RenameInhibit,
-      { "rename inhibit",         "afp.file_attribute.rename_inhibit",
+      { "Rename inhibit",         "afp.file_attribute.rename_inhibit",
            FT_BOOLEAN, 16, NULL,  kFPRenameInhibitBit,
        "rename inhibit", HFILL }},
+
     { &hf_afp_file_attribute_DeleteInhibit,
-      { "delete inhibit",         "afp.file_attribute.delete_inhibit",
+      { "Delete inhibit",         "afp.file_attribute.delete_inhibit",
            FT_BOOLEAN, 16, NULL,  kFPDeleteInhibitBit,
        "delete inhibit", HFILL }},
+
     { &hf_afp_file_attribute_CopyProtect,
-      { "copy protect",         "afp.file_attribute.copy_protect",
+      { "Copy protect",         "afp.file_attribute.copy_protect",
            FT_BOOLEAN, 16, NULL,  kFPCopyProtectBit,
        "copy protect", HFILL }},
+
     { &hf_afp_file_attribute_SetClear,
-      { "set",         "afp.file_attribute.set_clear",
+      { "Set",         "afp.file_attribute.set_clear",
            FT_BOOLEAN, 16, NULL,  kFPSetClearBit,
-       "clear/set attribute", HFILL }},
+       "Clear/set attribute", HFILL }},
        /* ---------- */
+
     { &hf_afp_vol_name,
       { "Volume",         "afp.vol_name",
        FT_UINT_STRING, BASE_NONE, NULL, 0x0,
        "Volume name", HFILL }},
+
+    { &hf_afp_vol_flag_passwd,
+      { "Password",         "afp.vol_flag_passwd",
+           FT_BOOLEAN, 8, NULL,  1,
+       "Volume is password-protected", HFILL }},
+
+    { &hf_afp_vol_flag_unix_priv,
+      { "Unix privs",         "afp.vol_flag_unix_priv",
+           FT_BOOLEAN, 8, NULL,  2,
+       "Volume has unix privileges", HFILL }},
+
     { &hf_afp_vol_id,
-      { "volume id",         "afp.vol_id",
+      { "Volume id",         "afp.vol_id",
                FT_UINT16, BASE_DEC, NULL, 0x0,
        "Volume id", HFILL }},
+
     { &hf_afp_vol_signature,
-      { "signature",         "afp.vol_signature",
+      { "Signature",         "afp.vol_signature",
                FT_UINT16, BASE_DEC, VALS(vol_signature_vals), 0x0,
        "Volume signature", HFILL }},
-    { &hf_afp_bitmap_offset,
-      { "offset",         "afp.bitmap_offset",
+
+    { &hf_afp_vol_name_offset,
+      { "Volume name offset","afp.vol_name_offset",
                FT_UINT16, BASE_DEC, NULL, 0x0,
-       "name offset in packet", HFILL }},
+       "Volume name offset in packet", HFILL }},
+
     { &hf_afp_vol_creation_date,
-      { "creation date",         "afp.vol_creation_date",
+      { "Creation date",         "afp.vol_creation_date",
                FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
-       "volume creation date", HFILL }},
+       "Volume creation date", HFILL }},
+
     { &hf_afp_vol_modification_date,
-      { "modification date",         "afp.vol_modification_date",
+      { "Modification date",         "afp.vol_modification_date",
                FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
-       "volume modification date", HFILL }},
+       "Volume modification date", HFILL }},
+
     { &hf_afp_vol_backup_date,
-      { "backup date",         "afp.vol_backup_date",
+      { "Backup date",         "afp.vol_backup_date",
                FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
-       "volume backup date", HFILL }},
+       "Volume backup date", HFILL }},
+
     { &hf_afp_vol_bytes_free,
-      { "bytes free",         "afp.vol_bytes_free",
+      { "Bytes free",         "afp.vol_bytes_free",
                FT_UINT32, BASE_DEC, NULL, 0x0,
-       "free space", HFILL }},
+       "Free space", HFILL }},
+
     { &hf_afp_vol_bytes_total,
-      { "bytes total",         "afp.vol_bytes_total",
+      { "Bytes total",         "afp.vol_bytes_total",
                FT_UINT32, BASE_DEC, NULL, 0x0,
-       "volume size ", HFILL }},
+       "Volume size", HFILL }},
+
     { &hf_afp_vol_ex_bytes_free,
-      { "ex. bytes free",         "afp.vol_ex_bytes_free",
+      { "Extended bytes free",         "afp.vol_ex_bytes_free",
                FT_UINT64, BASE_DEC, NULL, 0x0,
-       "ex. free space", HFILL }},
+       "Extended (>2GB) free space", HFILL }},
+
     { &hf_afp_vol_ex_bytes_total,
-      { "ex. bytes total",         "afp.vol_ex_bytes_total",
+      { "Extended bytes total",         "afp.vol_ex_bytes_total",
                FT_UINT64, BASE_DEC, NULL, 0x0,
-       "ex. volume size ", HFILL }},
+       "Extended (>2GB) volume size", HFILL }},
+
     { &hf_afp_vol_block_size,
-      { "block size",         "afp.vol_block_size",
+      { "Block size",         "afp.vol_block_size",
                FT_UINT32, BASE_DEC, NULL, 0x0,
-       "volume block size", HFILL }},
+       "Volume block size", HFILL }},
 
     { &hf_afp_did,
-      { "did",         "afp.did",
+      { "DID",         "afp.did",
                FT_UINT32, BASE_DEC, NULL, 0x0,
-       "parent directory id", HFILL }},
+       "Parent directory ID", HFILL }},
 
     { &hf_afp_dir_bitmap,
-      { "dir bitmap",         "afp.dir_bitmap",
+      { "Directory bitmap",         "afp.dir_bitmap",
                FT_UINT16, BASE_HEX, NULL, 0x0,
-       "directory bitmap", HFILL }},
+       "Directory bitmap", HFILL }},
+
     { &hf_afp_dir_offspring,
-      { "off spring",         "afp.dir_offspring",
+      { "Offspring",         "afp.dir_offspring",
                FT_UINT16, BASE_DEC, NULL, 0x0,
-       "directory offspring", HFILL }},
+       "Directory offspring", HFILL }},
+
     { &hf_afp_dir_OwnerID,
-      { "owner ID",         "afp.dir_owner_id",
+      { "Owner ID",         "afp.dir_owner_id",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "directory owner ID", HFILL }},
+       "Directory owner ID", HFILL }},
+
     { &hf_afp_dir_GroupID,
-      { "group ID",         "afp.dir_group_id",
+      { "Group ID",         "afp.dir_group_id",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "directory group ID", HFILL }},
+       "Directory group ID", HFILL }},
 
     { &hf_afp_creation_date,
-      { "creation date",         "afp.creation_date",
+      { "Creation date",         "afp.creation_date",
                FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
-       "creation date", HFILL }},
+       "Creation date", HFILL }},
+
     { &hf_afp_modification_date,
-      { "modification date",         "afp.modification_date",
+      { "Modification date",         "afp.modification_date",
                FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
-       "modification date", HFILL }},
+       "Modification date", HFILL }},
+
     { &hf_afp_backup_date,
-      { "backup date",         "afp.backup_date",
+      { "Backup date",         "afp.backup_date",
                FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
-       "backup date", HFILL }},
+       "Backup date", HFILL }},
 
     { &hf_afp_finder_info,
-      { "finder info",         "afp.finder_info",
+      { "Finder info",         "afp.finder_info",
                FT_BYTES, BASE_HEX, NULL, 0x0,
-       "finder info", HFILL }},
+       "Finder info", HFILL }},
+
+    { &hf_afp_long_name_offset,
+      { "Long name offset",    "afp.long_name_offset",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Long name offset in packet", HFILL }},
+
+    { &hf_afp_short_name_offset,
+      { "Short name offset",   "afp.short_name_offset",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Short name offset in packet", HFILL }},
+
+    { &hf_afp_unicode_name_offset,
+      { "Unicode name offset", "afp.unicode_name_offset",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Unicode name offset in packet", HFILL }},
+
+    { &hf_afp_unix_privs_uid,
+      { "UID",             "afp.unix_privs.uid",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "User ID", HFILL }},
+
+    { &hf_afp_unix_privs_gid,
+      { "GID",             "afp.unix_privs.gid",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "Group ID", HFILL }},
+
+    { &hf_afp_unix_privs_permissions,
+      { "Permissions",     "afp.unix_privs.permissions",
+               FT_UINT32, BASE_OCT, NULL, 0x0,
+       "Permissions", HFILL }},
+
+    { &hf_afp_unix_privs_ua_permissions,
+      { "User's access rights",     "afp.unix_privs.ua_permissions",
+               FT_UINT32, BASE_HEX, NULL, 0x0,
+       "User's access rights", HFILL }},
 
     { &hf_afp_file_id,
-      { "file id",         "afp.file_id",
+      { "File ID",         "afp.file_id",
                FT_UINT32, BASE_DEC, NULL, 0x0,
-       "file/directory id", HFILL }},
+       "File/directory ID", HFILL }},
+
     { &hf_afp_file_DataForkLen,
-      { "df size",         "afp.data_fork_len",
+      { "Data fork size",         "afp.data_fork_len",
                FT_UINT32, BASE_DEC, NULL, 0x0,
-       "data fork size", HFILL }},
+       "Data fork size", HFILL }},
+
     { &hf_afp_file_RsrcForkLen,
-      { "rf size",         "afp.ressource_fork_len",
+      { "Resource fork size",         "afp.resource_fork_len",
                FT_UINT32, BASE_DEC, NULL, 0x0,
-       "ressource fork size", HFILL }},
+       "Resource fork size", HFILL }},
+
     { &hf_afp_file_ExtDataForkLen,
-      { "ext df size",         "afp.ext_data_fork_len",
+      { "Extended data fork size",         "afp.ext_data_fork_len",
                FT_UINT64, BASE_DEC, NULL, 0x0,
-       ">2GByte data fork len", HFILL }},
+       "Extended (>2GB) data fork length", HFILL }},
+
     { &hf_afp_file_ExtRsrcForkLen,
-      { "ext rf size",         "afp.ext_ressource_fork_len",
+      { "Extended resource fork size",         "afp.ext_resource_fork_len",
                FT_UINT64, BASE_DEC, NULL, 0x0,
-       ">2GByte ressource fork len", HFILL }},
-    { &hf_afp_file_UnixPrivs,
-      { "unix privs",         "afp.unix_privs",
-               FT_UINT32, BASE_DEC, NULL, 0x0,
-       "Unix privs", HFILL }},
-    
+       "Extended (>2GB) resource fork length", HFILL }},
+
     { &hf_afp_file_bitmap,
-      { "file bitmap",         "afp.file_bitmap",
+      { "File bitmap",         "afp.file_bitmap",
                FT_UINT16, BASE_HEX, NULL, 0x0,
-       "file bitmap", HFILL }},
-    
+       "File bitmap", HFILL }},
+
     { &hf_afp_req_count,
-      { "req count",         "afp.req_count",
+      { "Req count",         "afp.req_count",
                FT_UINT16, BASE_DEC, NULL, 0x0,
        "Maximum number of structures returned", HFILL }},
 
-    { & hf_afp_start_index, 
-      { "start index",         "afp.start_index",
+    { &hf_afp_start_index,
+      { "Start index",         "afp.start_index",
                FT_UINT16, BASE_DEC, NULL, 0x0,
-       "first structure returned", HFILL }},
-    
+       "First structure returned", HFILL }},
+
     { &hf_afp_max_reply_size,
-      { "reply size",         "afp.reply_size",
+      { "Reply size",         "afp.reply_size",
                FT_UINT16, BASE_DEC, NULL, 0x0,
-       "first structure returned", HFILL }},
+       "Reply size", HFILL }},
+
+    { &hf_afp_start_index32,
+      { "Start index",         "afp.start_index32",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "First structure returned", HFILL }},
+
+    { &hf_afp_max_reply_size32,
+      { "Reply size",         "afp.reply_size32",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "Reply size", HFILL }},
 
     { &hf_afp_file_flag,
-      { "dir",         "afp.flag",
+      { "Dir",         "afp.file_flag",
                FT_BOOLEAN, 8, NULL, 0x80,
-       "is a dir", HFILL }},
+       "Is a dir", HFILL }},
 
     { &hf_afp_create_flag,
-      { "hard create",         "afp.create_flag",
+      { "Hard create",         "afp.create_flag",
                FT_BOOLEAN, 8, NULL, 0x80,
-       "soft/hard create file", HFILL }},
+       "Soft/hard create file", HFILL }},
 
     { &hf_afp_struct_size,
-      { "struct size",         "afp.struct_size",
+      { "Struct size",         "afp.struct_size",
                FT_UINT8, BASE_DEC, NULL,0,
-       "sizeof of struct", HFILL }},
-    
+       "Sizeof of struct", HFILL }},
+
+    { &hf_afp_struct_size16,
+      { "Struct size",         "afp.struct_size16",
+               FT_UINT16, BASE_DEC, NULL,0,
+       "Sizeof of struct", HFILL }},
+
     { &hf_afp_flag,
-      { "from",         "afp.flag",
+      { "From",         "afp.flag",
                FT_UINT8, BASE_HEX, VALS(flag_vals), 0x80,
-       "offset is relative to start/end of the fork", HFILL }},
+       "Offset is relative to start/end of the fork", HFILL }},
+
     { &hf_afp_dt_ref,
       { "DT ref",         "afp.dt_ref",
                FT_UINT16, BASE_DEC, NULL, 0x0,
        "Desktop database reference num", HFILL }},
 
     { &hf_afp_ofork,
-      { "fork",         "afp.ofork",
+      { "Fork",         "afp.ofork",
                FT_UINT16, BASE_DEC, NULL, 0x0,
        "Open fork reference number", HFILL }},
 
     { &hf_afp_offset,
-      { "offset",         "afp.offset",
+      { "Offset",         "afp.offset",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "offset ", HFILL }},
-    
+       "Offset", HFILL }},
+
     { &hf_afp_rw_count,
-      { "count",         "afp.rw_count",
+      { "Count",         "afp.rw_count",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "number of bytes to be read/written ", HFILL }},
+       "Number of bytes to be read/written", HFILL }},
+
+    { &hf_afp_newline_mask,
+      { "Newline mask",  "afp.newline_mask",
+               FT_UINT8, BASE_HEX, NULL, 0x0,
+       "Value to AND bytes with when looking for newline", HFILL }},
+
+    { &hf_afp_newline_char,
+      { "Newline char",  "afp.newline_char",
+               FT_UINT8, BASE_HEX, NULL, 0x0,
+       "Value to compare ANDed bytes with when looking for newline", HFILL }},
+
+    { &hf_afp_last_written,
+      { "Last written",  "afp.last_written",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "Offset of the last byte written", HFILL }},
 
     { &hf_afp_actual_count,
-      { "count",         "afp.actual_count",
+      { "Count",         "afp.actual_count",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "number of bytes returned by read/write", HFILL }},
-      
+       "Number of bytes returned by read/write", HFILL }},
+
     { &hf_afp_ofork_len,
-      { "new length",         "afp.ofork_len",
+      { "New length",         "afp.ofork_len",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "new length ", HFILL }},
+       "New length", HFILL }},
 
     { &hf_afp_path_type,
-      { "type ",         "afp.path_type",
+      { "Type",         "afp.path_type",
                FT_UINT8, BASE_HEX, VALS(path_type_vals), 0,
-       "type of names", HFILL }},
+       "Type of names", HFILL }},
 
     { &hf_afp_path_len,
-      { "len",  "afp.path_len",
+      { "Len",  "afp.path_len",
                FT_UINT8, BASE_DEC, NULL, 0x0,
-       "path len", HFILL }},
+       "Path length", HFILL }},
+
+    { &hf_afp_path_unicode_len,
+      { "Len",  "afp.path_unicode_len",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Path length (unicode)", HFILL }},
+
+    { &hf_afp_path_unicode_hint,
+      { "Unicode hint",  "afp.path_unicode_hint",
+               FT_UINT32, BASE_HEX, VALS(unicode_hint_vals), 0x0,
+       "Unicode hint", HFILL }},
 
     { &hf_afp_path_name,
-      { "Name ",  "afp.path_name",
+      { "Name",  "afp.path_name",
                FT_STRING, BASE_NONE, NULL, 0x0,
-       "path name", HFILL }},
+       "Path name", HFILL }},
 
     { &hf_afp_fork_type,
-      { "ressource fork",         "afp.fork_type",
+      { "Resource fork",         "afp.fork_type",
                FT_BOOLEAN, 8, NULL, 0x80,
-       "data/ressource fork", HFILL }},
+       "Data/resource fork", HFILL }},
 
     { &hf_afp_access_mode,
-      { "access mode",         "afp.access",
+      { "Access mode",         "afp.access",
                FT_UINT8, BASE_HEX, NULL, 0x0,
-       "fork access mode", HFILL }},
+       "Fork access mode", HFILL }},
+
     { &hf_afp_access_read,
-      { "read",         "afp.access.read",
+      { "Read",         "afp.access.read",
        FT_BOOLEAN, 8, NULL,  1,
-       "open for reading", HFILL }},
+       "Open for reading", HFILL }},
+
     { &hf_afp_access_write,
-      { "write",         "afp.access.write",
+      { "Write",         "afp.access.write",
        FT_BOOLEAN, 8, NULL,  2,
-       "open for writing", HFILL }},
+       "Open for writing", HFILL }},
+
     { &hf_afp_access_deny_read,
-      { "deny read",         "afp.access.deny_read",
+      { "Deny read",         "afp.access.deny_read",
        FT_BOOLEAN, 8, NULL,  0x10,
-       "deny read", HFILL }},
+       "Deny read", HFILL }},
+
     { &hf_afp_access_deny_write,
-      { "deny write",         "afp.access.deny_write",
+      { "Deny write",         "afp.access.deny_write",
        FT_BOOLEAN, 8, NULL,  0x20,
-       "deny write", HFILL }},
+       "Deny write", HFILL }},
 
     { &hf_afp_comment,
-      { "comment",         "afp.comment",
+      { "Comment",         "afp.comment",
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
-       "file/folder comment", HFILL }},
+       "File/folder comment", HFILL }},
 
     { &hf_afp_file_creator,
-      { "file creator",         "afp.file_creator",
+      { "File creator",         "afp.file_creator",
                FT_STRING, BASE_NONE, NULL, 0x0,
-       "file creator", HFILL }},
+       "File creator", HFILL }},
 
     { &hf_afp_file_type,
-      { "file type",         "afp.file_type",
+      { "File type",         "afp.file_type",
                FT_STRING, BASE_NONE, NULL, 0x0,
-       "file type", HFILL }},
+       "File type", HFILL }},
 
     { &hf_afp_icon_type,
-      { "icon type",         "afp.icon_type",
+      { "Icon type",         "afp.icon_type",
                FT_UINT8, BASE_HEX, NULL , 0,
-       "icon type", HFILL }},
+       "Icon type", HFILL }},
 
     { &hf_afp_icon_length,
-      { "size",         "afp.icon_length",
+      { "Size",         "afp.icon_length",
                FT_UINT16, BASE_DEC, NULL, 0x0,
-       "size for icon bitmap", HFILL }},
+       "Size for icon bitmap", HFILL }},
 
     { &hf_afp_icon_index,
-      { "index",         "afp.icon_index",
+      { "Index",         "afp.icon_index",
                FT_UINT16, BASE_DEC, NULL, 0x0,
-       "icon index in desktop database", HFILL }},
+       "Icon index in desktop database", HFILL }},
 
     { &hf_afp_icon_tag,
-      { "tag",         "afp.icon_tag",
+      { "Tag",         "afp.icon_tag",
                FT_UINT32, BASE_HEX, NULL, 0x0,
-       "icon tag", HFILL }},
+       "Icon tag", HFILL }},
 
     { &hf_afp_appl_index,
-      { "index",         "afp.appl_index",
+      { "Index",         "afp.appl_index",
                FT_UINT16, BASE_DEC, NULL, 0x0,
-       "appl index ", HFILL }},
+       "Application index", HFILL }},
 
     { &hf_afp_appl_tag,
-      { "tag",         "afp.appl_tag",
+      { "Tag",         "afp.appl_tag",
                FT_UINT32, BASE_HEX, NULL, 0x0,
-       "appl tag", HFILL }},
-       
+       "Application tag", HFILL }},
+
     { &hf_afp_lock_op,
       { "unlock",         "afp.lock_op",
                FT_BOOLEAN, 8, NULL, 0x1,
-       "lock/unlock op", HFILL }},
+       "Lock/unlock op", HFILL }},
+
     { &hf_afp_lock_from,
-      { "end",         "afp.lock_from",
+      { "End",         "afp.lock_from",
                FT_BOOLEAN, 8, NULL, 0x80,
-       "relative start/end of the fork", HFILL }},
-    
+       "Offset is relative to the end of the fork", HFILL }},
+
     { &hf_afp_lock_offset,
-       { "offset",         "afp.lock_offset",
+      { "Offset",         "afp.lock_offset",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "first byte to be locked", HFILL }},
+       "First byte to be locked", HFILL }},
 
     { &hf_afp_lock_len,
-       { "length",         "afp.lock_len",
+      { "Length",         "afp.lock_len",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "number of bytes to be locked/unlocked", HFILL }},
+       "Number of bytes to be locked/unlocked", HFILL }},
 
     { &hf_afp_lock_range_start,
-       { "start",         "afp.lock_range_start",
+      { "Start",         "afp.lock_range_start",
                FT_INT32, BASE_DEC, NULL, 0x0,
-       "first byte locked/unlocked", HFILL }},
+       "First byte locked/unlocked", HFILL }},
 
     { &hf_afp_dir_ar,
-       { "access right",         "afp.dir_ar",
+      { "Access rights",         "afp.dir_ar",
                FT_UINT32, BASE_HEX, NULL, 0x0,
-       "directory access right", HFILL }},
+       "Directory access rights", HFILL }},
 
     { &hf_afp_dir_ar_o_search,
-       { "owner has search access",      "afp.dir_ar.o_search",
+      { "Owner has search access",      "afp.dir_ar.o_search",
                FT_BOOLEAN, 32, NULL, AR_O_SEARCH,
-       "owner search access", HFILL }},
+       "Owner has search access", HFILL }},
+
     { &hf_afp_dir_ar_o_read,
-       { "owner has read access",        "afp.dir_ar.o_read",
+      { "Owner has read access",        "afp.dir_ar.o_read",
                FT_BOOLEAN, 32, NULL, AR_O_READ,
-       "owner read access", HFILL }},
+       "Owner has read access", HFILL }},
+
     { &hf_afp_dir_ar_o_write,
-       { "owner has write access",       "afp.dir_ar.o_write",
+      { "Owner has write access",       "afp.dir_ar.o_write",
                FT_BOOLEAN, 32, NULL, AR_O_WRITE,
-       "owner write access", HFILL }},
+       "Gwner has write access", HFILL }},
 
     { &hf_afp_dir_ar_g_search,
-       { "group has search access",      "afp.dir_ar.g_search",
+      { "Group has search access",      "afp.dir_ar.g_search",
                FT_BOOLEAN, 32, NULL, AR_G_SEARCH,
-       "group search access", HFILL }},
+       "Group has search access", HFILL }},
+
     { &hf_afp_dir_ar_g_read,
-       { "group has read access",        "afp.dir_ar.g_read",
+      { "Group has read access",        "afp.dir_ar.g_read",
                FT_BOOLEAN, 32, NULL, AR_G_READ,
-       "group read access", HFILL }},
+       "Group has read access", HFILL }},
+
     { &hf_afp_dir_ar_g_write,
-       { "group has write access",       "afp.dir_ar.g_write",
+      { "Group has write access",       "afp.dir_ar.g_write",
                FT_BOOLEAN, 32, NULL, AR_G_WRITE,
-       "group write access", HFILL }},
+       "Group has write access", HFILL }},
 
     { &hf_afp_dir_ar_e_search,
-       { "everyone has search access",   "afp.dir_ar.e_search",
+      { "Everyone has search access",   "afp.dir_ar.e_search",
                FT_BOOLEAN, 32, NULL, AR_E_SEARCH,
-       "everyone search access", HFILL }},
+       "Everyone has search access", HFILL }},
+
     { &hf_afp_dir_ar_e_read,
-       { "everyone has read access",     "afp.dir_ar.e_read",
+      { "Everyone has read access",     "afp.dir_ar.e_read",
                FT_BOOLEAN, 32, NULL, AR_E_READ,
-       "everyone read access", HFILL }},
+       "Everyone has read access", HFILL }},
+
     { &hf_afp_dir_ar_e_write,
-       { "everyone has write access",    "afp.dir_ar.e_write",
+      { "Everyone has write access",    "afp.dir_ar.e_write",
                FT_BOOLEAN, 32, NULL, AR_E_WRITE,
-       "everyone write access", HFILL }},
+       "Everyone has write access", HFILL }},
 
     { &hf_afp_dir_ar_u_search,
-       { "user has search access",   "afp.dir_ar.u_search",
+      { "User has search access",   "afp.dir_ar.u_search",
                FT_BOOLEAN, 32, NULL, AR_U_SEARCH,
-       "user search access", HFILL }},
+       "User has search access", HFILL }},
+
     { &hf_afp_dir_ar_u_read,
-       { "user has read access",     "afp.dir_ar.u_read",
+      { "User has read access",     "afp.dir_ar.u_read",
                FT_BOOLEAN, 32, NULL, AR_U_READ,
-       "user read access", HFILL }},
+       "User has read access", HFILL }},
+
     { &hf_afp_dir_ar_u_write,
-       { "user has write access",     "afp.dir_ar.u_write",
+      { "User has write access",     "afp.dir_ar.u_write",
                FT_BOOLEAN, 32, NULL, AR_U_WRITE,
-       "user has write access", HFILL }},
+       "User has write access", HFILL }},
 
     { &hf_afp_dir_ar_blank,
-       { "blank access right",     "afp.dir_ar.blank",
+      { "Blank access right",     "afp.dir_ar.blank",
                FT_BOOLEAN, 32, NULL, AR_BLANK,
-       "blank access right", HFILL }},
+       "Blank access right", HFILL }},
+
     { &hf_afp_dir_ar_u_own,
-       { "user is the owner",     "afp.dir_ar.u_owner",
+      { "User is the owner",     "afp.dir_ar.u_owner",
                FT_BOOLEAN, 32, NULL, AR_U_OWN,
-       "current user is the directory owner", HFILL }},
+       "Current user is the directory owner", HFILL }},
+
+    { &hf_afp_server_time,
+      { "Server time",         "afp.server_time",
+               FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+       "Server time", HFILL }},
+
+    { &hf_afp_cat_req_matches,
+      { "Max answers",         "afp.cat_req_matches",
+               FT_INT32, BASE_DEC, NULL, 0x0,
+       "Maximum number of matches to return.", HFILL }},
+
+    { &hf_afp_reserved,
+      { "Reserved",         "afp.reserved",
+               FT_BYTES, BASE_HEX, NULL, 0x0,
+       "Reserved", HFILL }},
+
+    { &hf_afp_cat_count,
+      { "Cat count",         "afp.cat_count",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "Number of structures returned", HFILL }},
+
+    { &hf_afp_cat_position,
+      { "Position",         "afp.cat_position",
+               FT_BYTES, BASE_HEX, NULL, 0x0,
+       "Reserved", HFILL }},
+
+
+    { &hf_afp_map_name_type,
+      { "Type",      "afp.map_name_type",
+               FT_UINT8, BASE_DEC, VALS(map_name_type_vals), 0x0,
+       "Map name type", HFILL }},
+
+    { &hf_afp_map_id_type,
+      { "Type",      "afp.map_id_type",
+               FT_UINT8, BASE_DEC, VALS(map_id_type_vals), 0x0,
+       "Map ID type", HFILL }},
+
+    { &hf_afp_map_id,
+      { "ID",             "afp.map_id",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "User/Group ID", HFILL }},
+
+    { &hf_afp_map_name,
+      { "Name",             "afp.map_name",
+               FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+       "User/Group name", HFILL }},
+
+    /* AFP 3.0 */
+    { &hf_afp_lock_offset64,
+      { "Offset",         "afp.lock_offset64",
+               FT_INT64, BASE_DEC, NULL, 0x0,
+       "First byte to be locked (64 bits)", HFILL }},
+
+    { &hf_afp_lock_len64,
+      { "Length",         "afp.lock_len64",
+               FT_INT64, BASE_DEC, NULL, 0x0,
+       "Number of bytes to be locked/unlocked (64 bits)", HFILL }},
+
+    { &hf_afp_lock_range_start64,
+      { "Start",         "afp.lock_range_start64",
+               FT_INT64, BASE_DEC, NULL, 0x0,
+       "First byte locked/unlocked (64 bits)", HFILL }},
+
+    { &hf_afp_offset64,
+      { "Offset",         "afp.offset64",
+               FT_INT64, BASE_DEC, NULL, 0x0,
+       "Offset (64 bits)", HFILL }},
+
+    { &hf_afp_rw_count64,
+      { "Count",         "afp.rw_count64",
+               FT_INT64, BASE_DEC, NULL, 0x0,
+       "Number of bytes to be read/written (64 bits)", HFILL }},
+
+    { &hf_afp_last_written64,
+      { "Last written",  "afp.last_written64",
+               FT_UINT64, BASE_DEC, NULL, 0x0,
+       "Offset of the last byte written (64 bits)", HFILL }},
+
+    { &hf_afp_ofork_len64,
+      { "New length",         "afp.ofork_len64",
+               FT_INT64, BASE_DEC, NULL, 0x0,
+       "New length (64 bits)", HFILL }},
+
+    { &hf_afp_session_token_type,
+      { "Type",         "afp.session_token_type",
+               FT_UINT16, BASE_HEX, VALS(token_type_vals), 0x0,
+       "Session token type", HFILL }},
+
+    /* FIXME FT_UINT32 in specs */
+    { &hf_afp_session_token_len,
+      { "Len",         "afp.session_token_len",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "Session token length", HFILL }},
+
+    { &hf_afp_session_token_timestamp,
+      { "Time stamp",         "afp.session_token_timestamp",
+               FT_UINT32, BASE_HEX, NULL, 0x0,
+       "Session time stamp", HFILL }},
+
+    { &hf_afp_session_token,
+      { "Token",         "afp.session_token",
+               FT_BYTES, BASE_HEX, NULL, 0x0,
+       "Session token", HFILL }},
+
+    { &hf_afp_user_flag,
+      { "Flag",         "afp.user_flag",
+               FT_UINT8, BASE_HEX, VALS(user_flag_vals), 0x01,
+       "User Info flag", HFILL }},
+
+    { &hf_afp_user_ID,
+      { "User ID",         "afp.user_ID",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "User ID", HFILL }},
+
+    { &hf_afp_group_ID,
+      { "Group ID",         "afp.group_ID",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "Group ID", HFILL }},
+
+    { &hf_afp_user_bitmap,
+      { "Bitmap",         "afp.user_bitmap",
+               FT_UINT16, BASE_HEX, NULL, 0,
+       "User Info bitmap", HFILL }},
+
+    { &hf_afp_user_bitmap_UID,
+      { "User ID",         "afp.user_bitmap.UID",
+               FT_BOOLEAN, 16, NULL, 0x01,
+       "User ID", HFILL }},
+
+    { &hf_afp_user_bitmap_GID,
+      { "Primary group ID",         "afp.user_bitmap.GID",
+               FT_BOOLEAN, 16, NULL, 0x02,
+       "Primary group ID", HFILL }},
   };
 
   static gint *ett[] = {
-    &ett_afp,
+       &ett_afp,
+       &ett_afp_server_vol,
+       &ett_afp_vol_list,
+       &ett_afp_vol_flag,
        &ett_afp_vol_bitmap,
        &ett_afp_vol_attribute,
        &ett_afp_dir_bitmap,
        &ett_afp_file_bitmap,
+       &ett_afp_unix_privs,
        &ett_afp_enumerate,
        &ett_afp_enumerate_line,
        &ett_afp_access_mode,
@@ -3126,6 +4564,11 @@ proto_register_afp(void)
        &ett_afp_path_name,
        &ett_afp_lock_flags,
        &ett_afp_dir_ar,
+       &ett_afp_cat_search,
+       &ett_afp_cat_r_bitmap,
+       &ett_afp_cat_spec,
+       &ett_afp_vol_did,
+       &ett_afp_user_bitmap,
   };
 
   proto_afp = proto_register_protocol("AppleTalk Filing Protocol", "AFP", "afp");