From 925e3b0a201456c5bd64b43f22d24b537548ec40 Mon Sep 17 00:00:00 2001
From: Rob Swindell <rob@synchro.net>
Date: Sun, 4 Apr 2021 02:49:37 -0700
Subject: [PATCH] A poll() failure with EINTR does not mean a socket is closed.

This won't impact Synchronet as it has a separate signal handling
thread, but we still need to behave properly for processes that
don't.  I'm also saying that ENOMEM does not indicate a disconnection,
though it may be better to pretend it was disconnected...
---
 3rdp/build/Common.gmake                       |    6 +
 3rdp/win32.release/libarchive/bin/archive.dll |  Bin 0 -> 567808 bytes
 3rdp/win32.release/libarchive/bin/archive.lib |  Bin 0 -> 113722 bytes
 .../libarchive/include/archive.h              | 1204 ++++++++++++
 .../libarchive/include/archive_entry.h        |  721 ++++++++
 .../win32.release/libarchive/libarchive.props |   17 +
 3rdp/win32.release/zlib/bin/zlib1.dll         |  Bin 0 -> 75264 bytes
 3rdp/win32.release/zlib/include/zconf.h       |  332 ++++
 3rdp/win32.release/zlib/include/zlib.h        | 1357 ++++++++++++++
 ctrl/file.cnf                                 |  Bin 12424 -> 12424 bytes
 ctrl/text.dat                                 |   46 +-
 docs/newfilebase.txt                          |  244 +++
 exec/addfiles.js                              |  285 +++
 exec/archive.js                               |  121 ++
 exec/default.src                              |    2 +-
 exec/filelist.js                              |  142 ++
 exec/hashfile.js                              |   31 +
 exec/jsdocs.js                                |    4 +-
 exec/load/avatar_lib.js                       |    2 +
 exec/load/fidocfg.js                          |    4 +-
 exec/load/sbbslist_lib.js                     |    8 +-
 exec/load/text.js                             |   22 +-
 exec/pcboard.src                              |    4 +-
 exec/postfile.js                              |   57 +
 exec/rehashfiles.js                           |   42 +
 exec/sbbslist.js                              |   12 +-
 exec/simple.src                               |    2 +-
 exec/tickit.js                                |  122 +-
 exec/update.js                                |   26 +-
 exec/updatefiles.js                           |   25 +
 exec/wildcat.src                              |    2 +-
 src/hash/crc16.c                              |   41 +-
 src/hash/crc16.h                              |   30 +-
 src/hash/crc32.c                              |   40 +-
 src/hash/crc32.h                              |   46 +-
 src/hash/md5.c                                |   24 +-
 src/hash/md5.h                                |   17 +-
 src/hash/objects.mk                           |    4 +-
 src/hash/sha1.c                               |  311 ++++
 src/hash/sha1.h                               |   57 +
 src/sbbs3/GNUmakefile                         |   23 +-
 src/sbbs3/addfiles.c                          |  665 +++----
 src/sbbs3/addfiles.vcxproj                    |    5 +-
 src/sbbs3/allusers.c                          |   11 +-
 src/sbbs3/atcodes.cpp                         |   20 +-
 src/sbbs3/bat_xfer.cpp                        |  826 ++++-----
 src/sbbs3/chksmb.c                            |  134 +-
 src/sbbs3/con_out.cpp                         |   11 +-
 src/sbbs3/ctrl/AboutBoxFormUnit.dfm           |    2 +-
 src/sbbs3/ctrl/MainFormUnit.cpp               |   75 +-
 src/sbbs3/ctrl/sbbsctrl.bpr                   |    2 +-
 src/sbbs3/dat_rec.c                           |    4 +-
 src/sbbs3/dat_rec.h                           |   48 +-
 src/sbbs3/data.cpp                            |   36 -
 src/sbbs3/delfiles.c                          |  188 +-
 src/sbbs3/delfiles.vcxproj                    |    6 +
 src/sbbs3/download.cpp                        |  187 +-
 src/sbbs3/dupefind.c                          |  121 +-
 src/sbbs3/dupefind.vcxproj                    |    3 +
 src/sbbs3/email.cpp                           |    4 +-
 src/sbbs3/exec.cpp                            |    9 +-
 src/sbbs3/execfile.cpp                        |  176 +-
 src/sbbs3/execfunc.cpp                        |   41 +-
 src/sbbs3/execmisc.cpp                        |    4 +-
 src/sbbs3/file.cpp                            |  373 ++--
 src/sbbs3/filedat.c                           | 1626 ++++++++++-------
 src/sbbs3/filedat.h                           |   69 +-
 src/sbbs3/filelist.c                          |  265 ++-
 src/sbbs3/filelist.vcxproj                    |    6 +
 src/sbbs3/fixsmb.c                            |   52 +-
 src/sbbs3/ftpsrvr.c                           |  412 ++---
 src/sbbs3/ftpsrvr.h                           |    4 +-
 src/sbbs3/ftpsrvr.vcxproj                     |    1 -
 src/sbbs3/getmsg.cpp                          |   15 +-
 src/sbbs3/getstats.c                          |   20 +-
 src/sbbs3/js_archive.c                        |  674 +++++++
 src/sbbs3/js_bbs.cpp                          |   89 +-
 src/sbbs3/js_com.c                            |    8 +-
 src/sbbs3/js_console.cpp                      |    3 +
 src/sbbs3/js_file.c                           |   32 +-
 src/sbbs3/js_file_area.c                      |   42 +-
 src/sbbs3/js_filebase.c                       | 1619 ++++++++++++++++
 src/sbbs3/js_global.c                         |   54 +-
 src/sbbs3/js_internal.c                       |   14 +-
 src/sbbs3/js_msgbase.c                        |   32 +-
 src/sbbs3/js_socket.c                         |   26 +-
 src/sbbs3/js_user.c                           |    2 +-
 src/sbbs3/jsdoor.c                            |    4 +
 src/sbbs3/listfile.cpp                        | 1224 +++++--------
 src/sbbs3/load_cfg.c                          |   85 +-
 src/sbbs3/load_cfg.h                          |    5 +
 src/sbbs3/logfile.cpp                         |    2 +-
 src/sbbs3/logon.cpp                           |   47 +-
 src/sbbs3/logout.cpp                          |   59 +-
 src/sbbs3/mailsrvr.c                          |   26 +-
 src/sbbs3/mailsrvr.vcxproj                    |    1 -
 src/sbbs3/main.cpp                            |  170 +-
 src/sbbs3/makeuser.vcxproj                    |    2 +
 src/sbbs3/msg_id.c                            |    5 +-
 src/sbbs3/msgdate.c                           |    8 -
 src/sbbs3/msgdate.h                           |    3 +-
 src/sbbs3/netmail.cpp                         |   14 +-
 src/sbbs3/node.c                              |    2 +-
 src/sbbs3/nodedefs.h                          |    8 +-
 src/sbbs3/objects.mk                          |   21 +-
 src/sbbs3/pack_qwk.cpp                        |  157 +-
 src/sbbs3/pack_rep.cpp                        |   39 +-
 src/sbbs3/postmsg.cpp                         |   26 +-
 src/sbbs3/qwk.cpp                             |  146 +-
 src/sbbs3/qwknodes.c                          |   12 +-
 src/sbbs3/readmsgs.cpp                        |    2 +
 src/sbbs3/release.bat                         |    1 +
 src/sbbs3/sbbs.h                              |   99 +-
 src/sbbs3/sbbs.vcxproj                        |   14 +-
 src/sbbs3/sbbs3.sln                           |    6 +
 src/sbbs3/sbbs4defs.h                         |    3 +-
 src/sbbs3/sbbs_ini.c                          |    2 +
 src/sbbs3/sbbsdefs.h                          |   85 +-
 src/sbbs3/sbbsecho.c                          |  172 +-
 src/sbbs3/sbbsecho.vcxproj                    |    4 +-
 src/sbbs3/scandirs.cpp                        |    8 +-
 src/sbbs3/scfg/scfg.c                         |    3 +
 src/sbbs3/scfg/scfg.h                         |    2 +-
 src/sbbs3/scfg/scfg.vcxproj                   |    2 +
 src/sbbs3/scfg/scfgnet.c                      |   53 +-
 src/sbbs3/scfg/scfgsub.c                      |    4 +-
 src/sbbs3/scfg/scfgxfr1.c                     |  176 +-
 src/sbbs3/scfg/scfgxfr2.c                     |  165 +-
 src/sbbs3/scfgdefs.h                          |    2 +
 src/sbbs3/scfglib.h                           |    5 +
 src/sbbs3/scfglib1.c                          |   55 +-
 src/sbbs3/scfglib2.c                          |    5 +-
 src/sbbs3/scfgsave.c                          |   60 +-
 src/sbbs3/scfgsave.h                          |    3 -
 src/sbbs3/services.c                          |   11 +-
 src/sbbs3/services.vcxproj                    |    1 -
 src/sbbs3/sexyz.vcxproj                       |    4 +-
 src/sbbs3/slog.c                              |   12 +-
 src/sbbs3/smbactiv.c                          |    5 +-
 src/sbbs3/smbutil.c                           |  198 +-
 src/sbbs3/sortdir.cpp                         |  239 ---
 src/sbbs3/str.cpp                             |   13 +-
 src/sbbs3/str_util.c                          |   43 +-
 src/sbbs3/str_util.h                          |    2 +-
 src/sbbs3/targets.mk                          |   13 +-
 src/sbbs3/text.h                              |   22 +-
 src/sbbs3/text_defaults.c                     |   50 +-
 src/sbbs3/tmp_xfer.cpp                        |   45 +-
 src/sbbs3/uedit/uedit.c                       |    4 +-
 src/sbbs3/un_qwk.cpp                          |   24 +-
 src/sbbs3/un_rep.cpp                          |   43 +-
 src/sbbs3/unbaja.c                            |    6 +-
 src/sbbs3/upgrade_to_v319.c                   |  717 ++++++++
 src/sbbs3/upgrade_to_v319.vcxproj             |  114 ++
 src/sbbs3/upload.cpp                          |  435 ++---
 src/sbbs3/userdat.c                           |  109 +-
 src/sbbs3/userdat.h                           |   13 +-
 src/sbbs3/useredit.cpp                        |   30 +-
 src/sbbs3/v4upgrade.c                         |  336 ++--
 src/sbbs3/viewfile.cpp                        |   61 +-
 src/sbbs3/websrvr.c                           |   29 +-
 src/sbbs3/websrvr.vcxproj                     |    1 -
 src/sbbs3/writemsg.cpp                        |   18 +-
 src/sbbs3/xtrn.cpp                            |  238 +--
 src/sbbs3/xtrn_sec.cpp                        |    9 +-
 src/smblib/smbadd.c                           |   45 +-
 src/smblib/smballoc.c                         |   67 +-
 src/smblib/smbdefs.h                          |  214 ++-
 src/smblib/smbdump.c                          |    9 +-
 src/smblib/smbfile.c                          |  303 ++-
 src/smblib/smbhash.c                          |   96 +-
 src/smblib/smblib.c                           |  364 ++--
 src/smblib/smblib.h                           |  301 ++-
 src/smblib/smblib.vcxproj                     |    1 +
 src/smblib/smbstr.c                           |   26 +-
 src/xpdev/dirwrap.c                           |   30 +-
 src/xpdev/dirwrap.h                           |   21 +-
 src/xpdev/gen_defs.h                          |   31 +-
 src/xpdev/ini_file.c                          |    3 +
 src/xpdev/str_list.c                          |   82 +-
 src/xpdev/str_list.h                          |   23 +-
 src/xpdev/xpdatetime.c                        |   14 +
 src/xpdev/xpdatetime.h                        |    1 +
 text/menu/sysxfer.asc                         |    3 -
 text/menu/transfer.msg                        |    8 +-
 185 files changed, 14022 insertions(+), 6911 deletions(-)
 create mode 100644 3rdp/win32.release/libarchive/bin/archive.dll
 create mode 100644 3rdp/win32.release/libarchive/bin/archive.lib
 create mode 100644 3rdp/win32.release/libarchive/include/archive.h
 create mode 100644 3rdp/win32.release/libarchive/include/archive_entry.h
 create mode 100644 3rdp/win32.release/libarchive/libarchive.props
 create mode 100644 3rdp/win32.release/zlib/bin/zlib1.dll
 create mode 100644 3rdp/win32.release/zlib/include/zconf.h
 create mode 100644 3rdp/win32.release/zlib/include/zlib.h
 create mode 100644 docs/newfilebase.txt
 create mode 100755 exec/addfiles.js
 create mode 100755 exec/archive.js
 create mode 100755 exec/filelist.js
 create mode 100755 exec/hashfile.js
 create mode 100755 exec/postfile.js
 create mode 100755 exec/rehashfiles.js
 create mode 100755 exec/updatefiles.js
 create mode 100644 src/hash/sha1.c
 create mode 100644 src/hash/sha1.h
 create mode 100644 src/sbbs3/js_archive.c
 create mode 100644 src/sbbs3/js_filebase.c
 delete mode 100644 src/sbbs3/sortdir.cpp
 create mode 100644 src/sbbs3/upgrade_to_v319.c
 create mode 100644 src/sbbs3/upgrade_to_v319.vcxproj

diff --git a/3rdp/build/Common.gmake b/3rdp/build/Common.gmake
index c74fd26689..ce5b94aec4 100644
--- a/3rdp/build/Common.gmake
+++ b/3rdp/build/Common.gmake
@@ -138,3 +138,9 @@ ifdef CRYPTLIBDIR
  CRYPT_LDFLAGS += -L$(CRYPTLIBDIR)
 endif
 
+####################
+# libarchive stuff #
+####################
+ifeq ($(os),win32)
+ LDFLAGS += -L$(3RDP_ROOT)/win32.release/libarchive/bin
+endif
diff --git a/3rdp/win32.release/libarchive/bin/archive.dll b/3rdp/win32.release/libarchive/bin/archive.dll
new file mode 100644
index 0000000000000000000000000000000000000000..1650fba0460c4ddd531c41e41124f4f04e1a1129
GIT binary patch
literal 567808
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%0A4&=CK2%8
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

literal 0
HcmV?d00001

diff --git a/3rdp/win32.release/libarchive/bin/archive.lib b/3rdp/win32.release/libarchive/bin/archive.lib
new file mode 100644
index 0000000000000000000000000000000000000000..88c79c17d4e463be925cef6cf62c9eaf678b7d5a
GIT binary patch
literal 113722
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
NT~U>jnS}MKS^#(0mdF4A

literal 0
HcmV?d00001

diff --git a/3rdp/win32.release/libarchive/include/archive.h b/3rdp/win32.release/libarchive/include/archive.h
new file mode 100644
index 0000000000..52f4d78295
--- /dev/null
+++ b/3rdp/win32.release/libarchive/include/archive.h
@@ -0,0 +1,1204 @@
+/*-
+ * Copyright (c) 2003-2010 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $
+ */
+
+#ifndef ARCHIVE_H_INCLUDED
+#define	ARCHIVE_H_INCLUDED
+
+/*
+ * The version number is expressed as a single integer that makes it
+ * easy to compare versions at build time: for version a.b.c, the
+ * version number is printf("%d%03d%03d",a,b,c).  For example, if you
+ * know your application requires version 2.12.108 or later, you can
+ * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
+ */
+/* Note: Compiler will complain if this does not match archive_entry.h! */
+#define	ARCHIVE_VERSION_NUMBER 3005001
+
+#include <sys/stat.h>
+#include <stddef.h>  /* for wchar_t */
+#include <stdio.h> /* For FILE * */
+#include <time.h> /* For time_t */
+
+/*
+ * Note: archive.h is for use outside of libarchive; the configuration
+ * headers (config.h, archive_platform.h, etc.) are purely internal.
+ * Do NOT use HAVE_XXX configuration macros to control the behavior of
+ * this header!  If you must conditionalize, use predefined compiler and/or
+ * platform macros.
+ */
+#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560
+# include <stdint.h>
+#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS) && !defined(__osf__) && !defined(__CLANG_INTTYPES_H)
+# include <inttypes.h>
+#endif
+
+/* Get appropriate definitions of 64-bit integer */
+#if !defined(__LA_INT64_T_DEFINED)
+/* Older code relied on the __LA_INT64_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_INT64_T la_int64_t
+# endif
+#define __LA_INT64_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+typedef __int64 la_int64_t;
+# else
+# include <unistd.h>  /* ssize_t */
+#  if defined(_SCO_DS) || defined(__osf__)
+typedef long long la_int64_t;
+#  else
+typedef int64_t la_int64_t;
+#  endif
+# endif
+#endif
+
+/* The la_ssize_t should match the type used in 'struct stat' */
+#if !defined(__LA_SSIZE_T_DEFINED)
+/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_SSIZE_T la_ssize_t
+# endif
+#define __LA_SSIZE_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+#  if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
+typedef ssize_t la_ssize_t;
+#  elif defined(_WIN64)
+typedef __int64 la_ssize_t;
+#  else
+typedef long la_ssize_t;
+#  endif
+# else
+# include <unistd.h>  /* ssize_t */
+typedef ssize_t la_ssize_t;
+# endif
+#endif
+
+/* Large file support for Android */
+#ifdef __ANDROID__
+#include "android_lf.h"
+#endif
+
+/*
+ * On Windows, define LIBARCHIVE_STATIC if you're building or using a
+ * .lib.  The default here assumes you're building a DLL.  Only
+ * libarchive source should ever define __LIBARCHIVE_BUILD.
+ */
+#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)
+# ifdef __LIBARCHIVE_BUILD
+#  ifdef __GNUC__
+#   define __LA_DECL	__attribute__((dllexport)) extern
+#  else
+#   define __LA_DECL	__declspec(dllexport)
+#  endif
+# else
+#  ifdef __GNUC__
+#   define __LA_DECL
+#  else
+#   define __LA_DECL	__declspec(dllimport)
+#  endif
+# endif
+#else
+/* Static libraries or non-Windows needs no special declaration. */
+# define __LA_DECL
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__)
+#define	__LA_PRINTF(fmtarg, firstvararg) \
+	__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
+#else
+#define	__LA_PRINTF(fmtarg, firstvararg)	/* nothing */
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
+# define __LA_DEPRECATED __attribute__((deprecated))
+#else
+# define __LA_DEPRECATED
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The version number is provided as both a macro and a function.
+ * The macro identifies the installed header; the function identifies
+ * the library version (which may not be the same if you're using a
+ * dynamically-linked version of the library).  Of course, if the
+ * header and library are very different, you should expect some
+ * strangeness.  Don't do that.
+ */
+__LA_DECL int		archive_version_number(void);
+
+/*
+ * Textual name/version of the library, useful for version displays.
+ */
+#define	ARCHIVE_VERSION_ONLY_STRING "3.5.1"
+#define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
+__LA_DECL const char *	archive_version_string(void);
+
+/*
+ * Detailed textual name/version of the library and its dependencies.
+ * This has the form:
+ *    "libarchive x.y.z zlib/a.b.c liblzma/d.e.f ... etc ..."
+ * the list of libraries described here will vary depending on how
+ * libarchive was compiled.
+ */
+__LA_DECL const char *	archive_version_details(void);
+
+/*
+ * Returns NULL if libarchive was compiled without the associated library.
+ * Otherwise, returns the version number that libarchive was compiled
+ * against.
+ */
+__LA_DECL const char *  archive_zlib_version(void);
+__LA_DECL const char *  archive_liblzma_version(void);
+__LA_DECL const char *  archive_bzlib_version(void);
+__LA_DECL const char *  archive_liblz4_version(void);
+__LA_DECL const char *  archive_libzstd_version(void);
+
+/* Declare our basic types. */
+struct archive;
+struct archive_entry;
+
+/*
+ * Error codes: Use archive_errno() and archive_error_string()
+ * to retrieve details.  Unless specified otherwise, all functions
+ * that return 'int' use these codes.
+ */
+#define	ARCHIVE_EOF	  1	/* Found end of archive. */
+#define	ARCHIVE_OK	  0	/* Operation was successful. */
+#define	ARCHIVE_RETRY	(-10)	/* Retry might succeed. */
+#define	ARCHIVE_WARN	(-20)	/* Partial success. */
+/* For example, if write_header "fails", then you can't push data. */
+#define	ARCHIVE_FAILED	(-25)	/* Current operation cannot complete. */
+/* But if write_header is "fatal," then this archive is dead and useless. */
+#define	ARCHIVE_FATAL	(-30)	/* No more operations are possible. */
+
+/*
+ * As far as possible, archive_errno returns standard platform errno codes.
+ * Of course, the details vary by platform, so the actual definitions
+ * here are stored in "archive_platform.h".  The symbols are listed here
+ * for reference; as a rule, clients should not need to know the exact
+ * platform-dependent error code.
+ */
+/* Unrecognized or invalid file format. */
+/* #define	ARCHIVE_ERRNO_FILE_FORMAT */
+/* Illegal usage of the library. */
+/* #define	ARCHIVE_ERRNO_PROGRAMMER_ERROR */
+/* Unknown or unclassified error. */
+/* #define	ARCHIVE_ERRNO_MISC */
+
+/*
+ * Callbacks are invoked to automatically read/skip/write/open/close the
+ * archive. You can provide your own for complex tasks (like breaking
+ * archives across multiple tapes) or use standard ones built into the
+ * library.
+ */
+
+/* Returns pointer and size of next block of data from archive. */
+typedef la_ssize_t	archive_read_callback(struct archive *,
+			    void *_client_data, const void **_buffer);
+
+/* Skips at most request bytes from archive and returns the skipped amount.
+ * This may skip fewer bytes than requested; it may even skip zero bytes.
+ * If you do skip fewer bytes than requested, libarchive will invoke your
+ * read callback and discard data as necessary to make up the full skip.
+ */
+typedef la_int64_t	archive_skip_callback(struct archive *,
+			    void *_client_data, la_int64_t request);
+
+/* Seeks to specified location in the file and returns the position.
+ * Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h.
+ * Return ARCHIVE_FATAL if the seek fails for any reason.
+ */
+typedef la_int64_t	archive_seek_callback(struct archive *,
+    void *_client_data, la_int64_t offset, int whence);
+
+/* Returns size actually written, zero on EOF, -1 on error. */
+typedef la_ssize_t	archive_write_callback(struct archive *,
+			    void *_client_data,
+			    const void *_buffer, size_t _length);
+
+typedef int	archive_open_callback(struct archive *, void *_client_data);
+
+typedef int	archive_close_callback(struct archive *, void *_client_data);
+
+typedef int	archive_free_callback(struct archive *, void *_client_data);
+
+/* Switches from one client data object to the next/prev client data object.
+ * This is useful for reading from different data blocks such as a set of files
+ * that make up one large file.
+ */
+typedef int archive_switch_callback(struct archive *, void *_client_data1,
+			    void *_client_data2);
+
+/*
+ * Returns a passphrase used for encryption or decryption, NULL on nothing
+ * to do and give it up.
+ */
+typedef const char *archive_passphrase_callback(struct archive *,
+			    void *_client_data);
+
+/*
+ * Codes to identify various stream filters.
+ */
+#define	ARCHIVE_FILTER_NONE	0
+#define	ARCHIVE_FILTER_GZIP	1
+#define	ARCHIVE_FILTER_BZIP2	2
+#define	ARCHIVE_FILTER_COMPRESS	3
+#define	ARCHIVE_FILTER_PROGRAM	4
+#define	ARCHIVE_FILTER_LZMA	5
+#define	ARCHIVE_FILTER_XZ	6
+#define	ARCHIVE_FILTER_UU	7
+#define	ARCHIVE_FILTER_RPM	8
+#define	ARCHIVE_FILTER_LZIP	9
+#define	ARCHIVE_FILTER_LRZIP	10
+#define	ARCHIVE_FILTER_LZOP	11
+#define	ARCHIVE_FILTER_GRZIP	12
+#define	ARCHIVE_FILTER_LZ4	13
+#define	ARCHIVE_FILTER_ZSTD	14
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+#define	ARCHIVE_COMPRESSION_NONE	ARCHIVE_FILTER_NONE
+#define	ARCHIVE_COMPRESSION_GZIP	ARCHIVE_FILTER_GZIP
+#define	ARCHIVE_COMPRESSION_BZIP2	ARCHIVE_FILTER_BZIP2
+#define	ARCHIVE_COMPRESSION_COMPRESS	ARCHIVE_FILTER_COMPRESS
+#define	ARCHIVE_COMPRESSION_PROGRAM	ARCHIVE_FILTER_PROGRAM
+#define	ARCHIVE_COMPRESSION_LZMA	ARCHIVE_FILTER_LZMA
+#define	ARCHIVE_COMPRESSION_XZ		ARCHIVE_FILTER_XZ
+#define	ARCHIVE_COMPRESSION_UU		ARCHIVE_FILTER_UU
+#define	ARCHIVE_COMPRESSION_RPM		ARCHIVE_FILTER_RPM
+#define	ARCHIVE_COMPRESSION_LZIP	ARCHIVE_FILTER_LZIP
+#define	ARCHIVE_COMPRESSION_LRZIP	ARCHIVE_FILTER_LRZIP
+#endif
+
+/*
+ * Codes returned by archive_format.
+ *
+ * Top 16 bits identifies the format family (e.g., "tar"); lower
+ * 16 bits indicate the variant.  This is updated by read_next_header.
+ * Note that the lower 16 bits will often vary from entry to entry.
+ * In some cases, this variation occurs as libarchive learns more about
+ * the archive (for example, later entries might utilize extensions that
+ * weren't necessary earlier in the archive; in this case, libarchive
+ * will change the format code to indicate the extended format that
+ * was used).  In other cases, it's because different tools have
+ * modified the archive and so different parts of the archive
+ * actually have slightly different formats.  (Both tar and cpio store
+ * format codes in each entry, so it is quite possible for each
+ * entry to be in a different format.)
+ */
+#define	ARCHIVE_FORMAT_BASE_MASK		0xff0000
+#define	ARCHIVE_FORMAT_CPIO			0x10000
+#define	ARCHIVE_FORMAT_CPIO_POSIX		(ARCHIVE_FORMAT_CPIO | 1)
+#define	ARCHIVE_FORMAT_CPIO_BIN_LE		(ARCHIVE_FORMAT_CPIO | 2)
+#define	ARCHIVE_FORMAT_CPIO_BIN_BE		(ARCHIVE_FORMAT_CPIO | 3)
+#define	ARCHIVE_FORMAT_CPIO_SVR4_NOCRC		(ARCHIVE_FORMAT_CPIO | 4)
+#define	ARCHIVE_FORMAT_CPIO_SVR4_CRC		(ARCHIVE_FORMAT_CPIO | 5)
+#define	ARCHIVE_FORMAT_CPIO_AFIO_LARGE		(ARCHIVE_FORMAT_CPIO | 6)
+#define	ARCHIVE_FORMAT_SHAR			0x20000
+#define	ARCHIVE_FORMAT_SHAR_BASE		(ARCHIVE_FORMAT_SHAR | 1)
+#define	ARCHIVE_FORMAT_SHAR_DUMP		(ARCHIVE_FORMAT_SHAR | 2)
+#define	ARCHIVE_FORMAT_TAR			0x30000
+#define	ARCHIVE_FORMAT_TAR_USTAR		(ARCHIVE_FORMAT_TAR | 1)
+#define	ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE	(ARCHIVE_FORMAT_TAR | 2)
+#define	ARCHIVE_FORMAT_TAR_PAX_RESTRICTED	(ARCHIVE_FORMAT_TAR | 3)
+#define	ARCHIVE_FORMAT_TAR_GNUTAR		(ARCHIVE_FORMAT_TAR | 4)
+#define	ARCHIVE_FORMAT_ISO9660			0x40000
+#define	ARCHIVE_FORMAT_ISO9660_ROCKRIDGE	(ARCHIVE_FORMAT_ISO9660 | 1)
+#define	ARCHIVE_FORMAT_ZIP			0x50000
+#define	ARCHIVE_FORMAT_EMPTY			0x60000
+#define	ARCHIVE_FORMAT_AR			0x70000
+#define	ARCHIVE_FORMAT_AR_GNU			(ARCHIVE_FORMAT_AR | 1)
+#define	ARCHIVE_FORMAT_AR_BSD			(ARCHIVE_FORMAT_AR | 2)
+#define	ARCHIVE_FORMAT_MTREE			0x80000
+#define	ARCHIVE_FORMAT_RAW			0x90000
+#define	ARCHIVE_FORMAT_XAR			0xA0000
+#define	ARCHIVE_FORMAT_LHA			0xB0000
+#define	ARCHIVE_FORMAT_CAB			0xC0000
+#define	ARCHIVE_FORMAT_RAR			0xD0000
+#define	ARCHIVE_FORMAT_7ZIP			0xE0000
+#define	ARCHIVE_FORMAT_WARC			0xF0000
+#define	ARCHIVE_FORMAT_RAR_V5			0x100000
+
+/*
+ * Codes returned by archive_read_format_capabilities().
+ *
+ * This list can be extended with values between 0 and 0xffff.
+ * The original purpose of this list was to let different archive
+ * format readers expose their general capabilities in terms of
+ * encryption.
+ */
+#define ARCHIVE_READ_FORMAT_CAPS_NONE (0) /* no special capabilities */
+#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA (1<<0)  /* reader can detect encrypted data */
+#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA (1<<1)  /* reader can detect encryptable metadata (pathname, mtime, etc.) */
+
+/*
+ * Codes returned by archive_read_has_encrypted_entries().
+ *
+ * In case the archive does not support encryption detection at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader
+ * for some other reason (e.g. not enough bytes read) cannot say if
+ * there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW
+ * is returned.
+ */
+#define ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED -2
+#define ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW -1
+
+/*-
+ * Basic outline for reading an archive:
+ *   1) Ask archive_read_new for an archive reader object.
+ *   2) Update any global properties as appropriate.
+ *      In particular, you'll certainly want to call appropriate
+ *      archive_read_support_XXX functions.
+ *   3) Call archive_read_open_XXX to open the archive
+ *   4) Repeatedly call archive_read_next_header to get information about
+ *      successive archive entries.  Call archive_read_data to extract
+ *      data for entries of interest.
+ *   5) Call archive_read_free to end processing.
+ */
+__LA_DECL struct archive	*archive_read_new(void);
+
+/*
+ * The archive_read_support_XXX calls enable auto-detect for this
+ * archive handle.  They also link in the necessary support code.
+ * For example, if you don't want bzlib linked in, don't invoke
+ * support_compression_bzip2().  The "all" functions provide the
+ * obvious shorthand.
+ */
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+__LA_DECL int archive_read_support_compression_all(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_bzip2(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_compress(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_gzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_lzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_lzma(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_none(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_program(struct archive *,
+		     const char *command) __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_program_signature
+		(struct archive *, const char *,
+		 const void * /* match */, size_t) __LA_DEPRECATED;
+
+__LA_DECL int archive_read_support_compression_rpm(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_uu(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_xz(struct archive *)
+		__LA_DEPRECATED;
+#endif
+
+__LA_DECL int archive_read_support_filter_all(struct archive *);
+__LA_DECL int archive_read_support_filter_by_code(struct archive *, int);
+__LA_DECL int archive_read_support_filter_bzip2(struct archive *);
+__LA_DECL int archive_read_support_filter_compress(struct archive *);
+__LA_DECL int archive_read_support_filter_gzip(struct archive *);
+__LA_DECL int archive_read_support_filter_grzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lrzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lz4(struct archive *);
+__LA_DECL int archive_read_support_filter_lzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lzma(struct archive *);
+__LA_DECL int archive_read_support_filter_lzop(struct archive *);
+__LA_DECL int archive_read_support_filter_none(struct archive *);
+__LA_DECL int archive_read_support_filter_program(struct archive *,
+		     const char *command);
+__LA_DECL int archive_read_support_filter_program_signature
+		(struct archive *, const char * /* cmd */,
+				    const void * /* match */, size_t);
+__LA_DECL int archive_read_support_filter_rpm(struct archive *);
+__LA_DECL int archive_read_support_filter_uu(struct archive *);
+__LA_DECL int archive_read_support_filter_xz(struct archive *);
+__LA_DECL int archive_read_support_filter_zstd(struct archive *);
+
+__LA_DECL int archive_read_support_format_7zip(struct archive *);
+__LA_DECL int archive_read_support_format_all(struct archive *);
+__LA_DECL int archive_read_support_format_ar(struct archive *);
+__LA_DECL int archive_read_support_format_by_code(struct archive *, int);
+__LA_DECL int archive_read_support_format_cab(struct archive *);
+__LA_DECL int archive_read_support_format_cpio(struct archive *);
+__LA_DECL int archive_read_support_format_empty(struct archive *);
+__LA_DECL int archive_read_support_format_gnutar(struct archive *);
+__LA_DECL int archive_read_support_format_iso9660(struct archive *);
+__LA_DECL int archive_read_support_format_lha(struct archive *);
+__LA_DECL int archive_read_support_format_mtree(struct archive *);
+__LA_DECL int archive_read_support_format_rar(struct archive *);
+__LA_DECL int archive_read_support_format_rar5(struct archive *);
+__LA_DECL int archive_read_support_format_raw(struct archive *);
+__LA_DECL int archive_read_support_format_tar(struct archive *);
+__LA_DECL int archive_read_support_format_warc(struct archive *);
+__LA_DECL int archive_read_support_format_xar(struct archive *);
+/* archive_read_support_format_zip() enables both streamable and seekable
+ * zip readers. */
+__LA_DECL int archive_read_support_format_zip(struct archive *);
+/* Reads Zip archives as stream from beginning to end.  Doesn't
+ * correctly handle SFX ZIP files or ZIP archives that have been modified
+ * in-place. */
+__LA_DECL int archive_read_support_format_zip_streamable(struct archive *);
+/* Reads starting from central directory; requires seekable input. */
+__LA_DECL int archive_read_support_format_zip_seekable(struct archive *);
+
+/* Functions to manually set the format and filters to be used. This is
+ * useful to bypass the bidding process when the format and filters to use
+ * is known in advance.
+ */
+__LA_DECL int archive_read_set_format(struct archive *, int);
+__LA_DECL int archive_read_append_filter(struct archive *, int);
+__LA_DECL int archive_read_append_filter_program(struct archive *,
+    const char *);
+__LA_DECL int archive_read_append_filter_program_signature
+    (struct archive *, const char *, const void * /* match */, size_t);
+
+/* Set various callbacks. */
+__LA_DECL int archive_read_set_open_callback(struct archive *,
+    archive_open_callback *);
+__LA_DECL int archive_read_set_read_callback(struct archive *,
+    archive_read_callback *);
+__LA_DECL int archive_read_set_seek_callback(struct archive *,
+    archive_seek_callback *);
+__LA_DECL int archive_read_set_skip_callback(struct archive *,
+    archive_skip_callback *);
+__LA_DECL int archive_read_set_close_callback(struct archive *,
+    archive_close_callback *);
+/* Callback used to switch between one data object to the next */
+__LA_DECL int archive_read_set_switch_callback(struct archive *,
+    archive_switch_callback *);
+
+/* This sets the first data object. */
+__LA_DECL int archive_read_set_callback_data(struct archive *, void *);
+/* This sets data object at specified index */
+__LA_DECL int archive_read_set_callback_data2(struct archive *, void *,
+    unsigned int);
+/* This adds a data object at the specified index. */
+__LA_DECL int archive_read_add_callback_data(struct archive *, void *,
+    unsigned int);
+/* This appends a data object to the end of list */
+__LA_DECL int archive_read_append_callback_data(struct archive *, void *);
+/* This prepends a data object to the beginning of list */
+__LA_DECL int archive_read_prepend_callback_data(struct archive *, void *);
+
+/* Opening freezes the callbacks. */
+__LA_DECL int archive_read_open1(struct archive *);
+
+/* Convenience wrappers around the above. */
+__LA_DECL int archive_read_open(struct archive *, void *_client_data,
+		     archive_open_callback *, archive_read_callback *,
+		     archive_close_callback *);
+__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
+		     archive_open_callback *, archive_read_callback *,
+		     archive_skip_callback *, archive_close_callback *);
+
+/*
+ * A variety of shortcuts that invoke archive_read_open() with
+ * canned callbacks suitable for common situations.  The ones that
+ * accept a block size handle tape blocking correctly.
+ */
+/* Use this if you know the filename.  Note: NULL indicates stdin. */
+__LA_DECL int archive_read_open_filename(struct archive *,
+		     const char *_filename, size_t _block_size);
+/* Use this for reading multivolume files by filenames.
+ * NOTE: Must be NULL terminated. Sorting is NOT done. */
+__LA_DECL int archive_read_open_filenames(struct archive *,
+		     const char **_filenames, size_t _block_size);
+__LA_DECL int archive_read_open_filename_w(struct archive *,
+		     const wchar_t *_filename, size_t _block_size);
+/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
+__LA_DECL int archive_read_open_file(struct archive *,
+		     const char *_filename, size_t _block_size) __LA_DEPRECATED;
+/* Read an archive that's stored in memory. */
+__LA_DECL int archive_read_open_memory(struct archive *,
+		     const void * buff, size_t size);
+/* A more involved version that is only used for internal testing. */
+__LA_DECL int archive_read_open_memory2(struct archive *a, const void *buff,
+		     size_t size, size_t read_size);
+/* Read an archive that's already open, using the file descriptor. */
+__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
+		     size_t _block_size);
+/* Read an archive that's already open, using a FILE *. */
+/* Note: DO NOT use this with tape drives. */
+__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
+
+/* Parses and returns next entry header. */
+__LA_DECL int archive_read_next_header(struct archive *,
+		     struct archive_entry **);
+
+/* Parses and returns next entry header using the archive_entry passed in */
+__LA_DECL int archive_read_next_header2(struct archive *,
+		     struct archive_entry *);
+
+/*
+ * Retrieve the byte offset in UNCOMPRESSED data where last-read
+ * header started.
+ */
+__LA_DECL la_int64_t		 archive_read_header_position(struct archive *);
+
+/*
+ * Returns 1 if the archive contains at least one encrypted entry.
+ * If the archive format not support encryption at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.
+ * If for any other reason (e.g. not enough data read so far)
+ * we cannot say whether there are encrypted entries, then
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.
+ * In general, this function will return values below zero when the
+ * reader is uncertain or totally incapable of encryption support.
+ * When this function returns 0 you can be sure that the reader
+ * supports encryption detection but no encrypted entries have
+ * been found yet.
+ *
+ * NOTE: If the metadata/header of an archive is also encrypted, you
+ * cannot rely on the number of encrypted entries. That is why this
+ * function does not return the number of encrypted entries but#
+ * just shows that there are some.
+ */
+__LA_DECL int	archive_read_has_encrypted_entries(struct archive *);
+
+/*
+ * Returns a bitmask of capabilities that are supported by the archive format reader.
+ * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned.
+ */
+__LA_DECL int		 archive_read_format_capabilities(struct archive *);
+
+/* Read data from the body of an entry.  Similar to read(2). */
+__LA_DECL la_ssize_t		 archive_read_data(struct archive *,
+				    void *, size_t);
+
+/* Seek within the body of an entry.  Similar to lseek(2). */
+__LA_DECL la_int64_t archive_seek_data(struct archive *, la_int64_t, int);
+
+/*
+ * A zero-copy version of archive_read_data that also exposes the file offset
+ * of each returned block.  Note that the client has no way to specify
+ * the desired size of the block.  The API does guarantee that offsets will
+ * be strictly increasing and that returned blocks will not overlap.
+ */
+__LA_DECL int archive_read_data_block(struct archive *a,
+		    const void **buff, size_t *size, la_int64_t *offset);
+
+/*-
+ * Some convenience functions that are built on archive_read_data:
+ *  'skip': skips entire entry
+ *  'into_buffer': writes data into memory buffer that you provide
+ *  'into_fd': writes data to specified filedes
+ */
+__LA_DECL int archive_read_data_skip(struct archive *);
+__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
+
+/*
+ * Set read options.
+ */
+/* Apply option to the format only. */
+__LA_DECL int archive_read_set_format_option(struct archive *_a,
+			    const char *m, const char *o,
+			    const char *v);
+/* Apply option to the filter only. */
+__LA_DECL int archive_read_set_filter_option(struct archive *_a,
+			    const char *m, const char *o,
+			    const char *v);
+/* Apply option to both the format and the filter. */
+__LA_DECL int archive_read_set_option(struct archive *_a,
+			    const char *m, const char *o,
+			    const char *v);
+/* Apply option string to both the format and the filter. */
+__LA_DECL int archive_read_set_options(struct archive *_a,
+			    const char *opts);
+
+/*
+ * Add a decryption passphrase.
+ */
+__LA_DECL int archive_read_add_passphrase(struct archive *, const char *);
+__LA_DECL int archive_read_set_passphrase_callback(struct archive *,
+			    void *client_data, archive_passphrase_callback *);
+
+
+/*-
+ * Convenience function to recreate the current entry (whose header
+ * has just been read) on disk.
+ *
+ * This does quite a bit more than just copy data to disk. It also:
+ *  - Creates intermediate directories as required.
+ *  - Manages directory permissions:  non-writable directories will
+ *    be initially created with write permission enabled; when the
+ *    archive is closed, dir permissions are edited to the values specified
+ *    in the archive.
+ *  - Checks hardlinks:  hardlinks will not be extracted unless the
+ *    linked-to file was also extracted within the same session. (TODO)
+ */
+
+/* The "flags" argument selects optional behavior, 'OR' the flags you want. */
+
+/* Default: Do not try to set owner/group. */
+#define	ARCHIVE_EXTRACT_OWNER			(0x0001)
+/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */
+#define	ARCHIVE_EXTRACT_PERM			(0x0002)
+/* Default: Do not restore mtime/atime. */
+#define	ARCHIVE_EXTRACT_TIME			(0x0004)
+/* Default: Replace existing files. */
+#define	ARCHIVE_EXTRACT_NO_OVERWRITE 		(0x0008)
+/* Default: Try create first, unlink only if create fails with EEXIST. */
+#define	ARCHIVE_EXTRACT_UNLINK			(0x0010)
+/* Default: Do not restore ACLs. */
+#define	ARCHIVE_EXTRACT_ACL			(0x0020)
+/* Default: Do not restore fflags. */
+#define	ARCHIVE_EXTRACT_FFLAGS			(0x0040)
+/* Default: Do not restore xattrs. */
+#define	ARCHIVE_EXTRACT_XATTR 			(0x0080)
+/* Default: Do not try to guard against extracts redirected by symlinks. */
+/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */
+#define	ARCHIVE_EXTRACT_SECURE_SYMLINKS		(0x0100)
+/* Default: Do not reject entries with '..' as path elements. */
+#define	ARCHIVE_EXTRACT_SECURE_NODOTDOT		(0x0200)
+/* Default: Create parent directories as needed. */
+#define	ARCHIVE_EXTRACT_NO_AUTODIR		(0x0400)
+/* Default: Overwrite files, even if one on disk is newer. */
+#define	ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER	(0x0800)
+/* Detect blocks of 0 and write holes instead. */
+#define	ARCHIVE_EXTRACT_SPARSE			(0x1000)
+/* Default: Do not restore Mac extended metadata. */
+/* This has no effect except on Mac OS. */
+#define	ARCHIVE_EXTRACT_MAC_METADATA		(0x2000)
+/* Default: Use HFS+ compression if it was compressed. */
+/* This has no effect except on Mac OS v10.6 or later. */
+#define	ARCHIVE_EXTRACT_NO_HFS_COMPRESSION	(0x4000)
+/* Default: Do not use HFS+ compression if it was not compressed. */
+/* This has no effect except on Mac OS v10.6 or later. */
+#define	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED	(0x8000)
+/* Default: Do not reject entries with absolute paths */
+#define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000)
+/* Default: Do not clear no-change flags when unlinking object */
+#define	ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS	(0x20000)
+/* Default: Do not extract atomically (using rename) */
+#define	ARCHIVE_EXTRACT_SAFE_WRITES		(0x40000)
+
+__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
+		     int flags);
+__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
+		     struct archive * /* dest */);
+__LA_DECL void	 archive_read_extract_set_progress_callback(struct archive *,
+		     void (*_progress_func)(void *), void *_user_data);
+
+/* Record the dev/ino of a file that will not be written.  This is
+ * generally set to the dev/ino of the archive being read. */
+__LA_DECL void		archive_read_extract_set_skip_file(struct archive *,
+		     la_int64_t, la_int64_t);
+
+/* Close the file and release most resources. */
+__LA_DECL int		 archive_read_close(struct archive *);
+/* Release all resources and destroy the object. */
+/* Note that archive_read_free will call archive_read_close for you. */
+__LA_DECL int		 archive_read_free(struct archive *);
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Synonym for archive_read_free() for backwards compatibility. */
+__LA_DECL int		 archive_read_finish(struct archive *) __LA_DEPRECATED;
+#endif
+
+/*-
+ * To create an archive:
+ *   1) Ask archive_write_new for an archive writer object.
+ *   2) Set any global properties.  In particular, you should set
+ *      the compression and format to use.
+ *   3) Call archive_write_open to open the file (most people
+ *       will use archive_write_open_file or archive_write_open_fd,
+ *       which provide convenient canned I/O callbacks for you).
+ *   4) For each entry:
+ *      - construct an appropriate struct archive_entry structure
+ *      - archive_write_header to write the header
+ *      - archive_write_data to write the entry data
+ *   5) archive_write_close to close the output
+ *   6) archive_write_free to cleanup the writer and release resources
+ */
+__LA_DECL struct archive	*archive_write_new(void);
+__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
+		     int bytes_per_block);
+__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
+/* XXX This is badly misnamed; suggestions appreciated. XXX */
+__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
+		     int bytes_in_last_block);
+__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
+
+/* The dev/ino of a file that won't be archived.  This is used
+ * to avoid recursively adding an archive to itself. */
+__LA_DECL int archive_write_set_skip_file(struct archive *,
+    la_int64_t, la_int64_t);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+__LA_DECL int archive_write_set_compression_bzip2(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_compress(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_gzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_lzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_lzma(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_none(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_program(struct archive *,
+		     const char *cmd) __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_xz(struct archive *)
+		__LA_DEPRECATED;
+#endif
+
+/* A convenience function to set the filter based on the code. */
+__LA_DECL int archive_write_add_filter(struct archive *, int filter_code);
+__LA_DECL int archive_write_add_filter_by_name(struct archive *,
+		     const char *name);
+__LA_DECL int archive_write_add_filter_b64encode(struct archive *);
+__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
+__LA_DECL int archive_write_add_filter_compress(struct archive *);
+__LA_DECL int archive_write_add_filter_grzip(struct archive *);
+__LA_DECL int archive_write_add_filter_gzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lrzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lz4(struct archive *);
+__LA_DECL int archive_write_add_filter_lzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lzma(struct archive *);
+__LA_DECL int archive_write_add_filter_lzop(struct archive *);
+__LA_DECL int archive_write_add_filter_none(struct archive *);
+__LA_DECL int archive_write_add_filter_program(struct archive *,
+		     const char *cmd);
+__LA_DECL int archive_write_add_filter_uuencode(struct archive *);
+__LA_DECL int archive_write_add_filter_xz(struct archive *);
+__LA_DECL int archive_write_add_filter_zstd(struct archive *);
+
+
+/* A convenience function to set the format based on the code or name. */
+__LA_DECL int archive_write_set_format(struct archive *, int format_code);
+__LA_DECL int archive_write_set_format_by_name(struct archive *,
+		     const char *name);
+/* To minimize link pollution, use one or more of the following. */
+__LA_DECL int archive_write_set_format_7zip(struct archive *);
+__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
+__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
+__LA_DECL int archive_write_set_format_cpio(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
+__LA_DECL int archive_write_set_format_gnutar(struct archive *);
+__LA_DECL int archive_write_set_format_iso9660(struct archive *);
+__LA_DECL int archive_write_set_format_mtree(struct archive *);
+__LA_DECL int archive_write_set_format_mtree_classic(struct archive *);
+/* TODO: int archive_write_set_format_old_tar(struct archive *); */
+__LA_DECL int archive_write_set_format_pax(struct archive *);
+__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
+__LA_DECL int archive_write_set_format_raw(struct archive *);
+__LA_DECL int archive_write_set_format_shar(struct archive *);
+__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
+__LA_DECL int archive_write_set_format_ustar(struct archive *);
+__LA_DECL int archive_write_set_format_v7tar(struct archive *);
+__LA_DECL int archive_write_set_format_warc(struct archive *);
+__LA_DECL int archive_write_set_format_xar(struct archive *);
+__LA_DECL int archive_write_set_format_zip(struct archive *);
+__LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const char *filename);
+__LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext);
+__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
+__LA_DECL int archive_write_zip_set_compression_store(struct archive *);
+/* Deprecated; use archive_write_open2 instead */
+__LA_DECL int archive_write_open(struct archive *, void *,
+		     archive_open_callback *, archive_write_callback *,
+		     archive_close_callback *);
+__LA_DECL int archive_write_open2(struct archive *, void *,
+		     archive_open_callback *, archive_write_callback *,
+		     archive_close_callback *, archive_free_callback *);
+__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
+__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_filename_w(struct archive *,
+		     const wchar_t *_file);
+/* A deprecated synonym for archive_write_open_filename() */
+__LA_DECL int archive_write_open_file(struct archive *, const char *_file)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
+/* _buffSize is the size of the buffer, _used refers to a variable that
+ * will be updated after each write into the buffer. */
+__LA_DECL int archive_write_open_memory(struct archive *,
+			void *_buffer, size_t _buffSize, size_t *_used);
+
+/*
+ * Note that the library will truncate writes beyond the size provided
+ * to archive_write_header or pad if the provided data is short.
+ */
+__LA_DECL int archive_write_header(struct archive *,
+		     struct archive_entry *);
+__LA_DECL la_ssize_t	archive_write_data(struct archive *,
+			    const void *, size_t);
+
+/* This interface is currently only available for archive_write_disk handles.  */
+__LA_DECL la_ssize_t	 archive_write_data_block(struct archive *,
+				    const void *, size_t, la_int64_t);
+
+__LA_DECL int		 archive_write_finish_entry(struct archive *);
+__LA_DECL int		 archive_write_close(struct archive *);
+/* Marks the archive as FATAL so that a subsequent free() operation
+ * won't try to close() cleanly.  Provides a fast abort capability
+ * when the client discovers that things have gone wrong. */
+__LA_DECL int            archive_write_fail(struct archive *);
+/* This can fail if the archive wasn't already closed, in which case
+ * archive_write_free() will implicitly call archive_write_close(). */
+__LA_DECL int		 archive_write_free(struct archive *);
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Synonym for archive_write_free() for backwards compatibility. */
+__LA_DECL int		 archive_write_finish(struct archive *) __LA_DEPRECATED;
+#endif
+
+/*
+ * Set write options.
+ */
+/* Apply option to the format only. */
+__LA_DECL int archive_write_set_format_option(struct archive *_a,
+			    const char *m, const char *o,
+			    const char *v);
+/* Apply option to the filter only. */
+__LA_DECL int archive_write_set_filter_option(struct archive *_a,
+			    const char *m, const char *o,
+			    const char *v);
+/* Apply option to both the format and the filter. */
+__LA_DECL int archive_write_set_option(struct archive *_a,
+			    const char *m, const char *o,
+			    const char *v);
+/* Apply option string to both the format and the filter. */
+__LA_DECL int archive_write_set_options(struct archive *_a,
+			    const char *opts);
+
+/*
+ * Set a encryption passphrase.
+ */
+__LA_DECL int archive_write_set_passphrase(struct archive *_a, const char *p);
+__LA_DECL int archive_write_set_passphrase_callback(struct archive *,
+			    void *client_data, archive_passphrase_callback *);
+
+/*-
+ * ARCHIVE_WRITE_DISK API
+ *
+ * To create objects on disk:
+ *   1) Ask archive_write_disk_new for a new archive_write_disk object.
+ *   2) Set any global properties.  In particular, you probably
+ *      want to set the options.
+ *   3) For each entry:
+ *      - construct an appropriate struct archive_entry structure
+ *      - archive_write_header to create the file/dir/etc on disk
+ *      - archive_write_data to write the entry data
+ *   4) archive_write_free to cleanup the writer and release resources
+ *
+ * In particular, you can use this in conjunction with archive_read()
+ * to pull entries out of an archive and create them on disk.
+ */
+__LA_DECL struct archive	*archive_write_disk_new(void);
+/* This file will not be overwritten. */
+__LA_DECL int archive_write_disk_set_skip_file(struct archive *,
+    la_int64_t, la_int64_t);
+/* Set flags to control how the next item gets created.
+ * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */
+__LA_DECL int		 archive_write_disk_set_options(struct archive *,
+		     int flags);
+/*
+ * The lookup functions are given uname/uid (or gname/gid) pairs and
+ * return a uid (gid) suitable for this system.  These are used for
+ * restoring ownership and for setting ACLs.  The default functions
+ * are naive, they just return the uid/gid.  These are small, so reasonable
+ * for applications that don't need to preserve ownership; they
+ * are probably also appropriate for applications that are doing
+ * same-system backup and restore.
+ */
+/*
+ * The "standard" lookup functions use common system calls to lookup
+ * the uname/gname, falling back to the uid/gid if the names can't be
+ * found.  They cache lookups and are reasonably fast, but can be very
+ * large, so they are not used unless you ask for them.  In
+ * particular, these match the specifications of POSIX "pax" and old
+ * POSIX "tar".
+ */
+__LA_DECL int	 archive_write_disk_set_standard_lookup(struct archive *);
+/*
+ * If neither the default (naive) nor the standard (big) functions suit
+ * your needs, you can write your own and register them.  Be sure to
+ * include a cleanup function if you have allocated private data.
+ */
+__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
+    void * /* private_data */,
+    la_int64_t (*)(void *, const char *, la_int64_t),
+    void (* /* cleanup */)(void *));
+__LA_DECL int archive_write_disk_set_user_lookup(struct archive *,
+    void * /* private_data */,
+    la_int64_t (*)(void *, const char *, la_int64_t),
+    void (* /* cleanup */)(void *));
+__LA_DECL la_int64_t archive_write_disk_gid(struct archive *, const char *, la_int64_t);
+__LA_DECL la_int64_t archive_write_disk_uid(struct archive *, const char *, la_int64_t);
+
+/*
+ * ARCHIVE_READ_DISK API
+ *
+ * This is still evolving and somewhat experimental.
+ */
+__LA_DECL struct archive *archive_read_disk_new(void);
+/* The names for symlink modes here correspond to an old BSD
+ * command-line argument convention: -L, -P, -H */
+/* Follow all symlinks. */
+__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *);
+/* Follow no symlinks. */
+__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *);
+/* Follow symlink initially, then not. */
+__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *);
+/* TODO: Handle Linux stat32/stat64 ugliness. <sigh> */
+__LA_DECL int archive_read_disk_entry_from_file(struct archive *,
+    struct archive_entry *, int /* fd */, const struct stat *);
+/* Look up gname for gid or uname for uid. */
+/* Default implementations are very, very stupid. */
+__LA_DECL const char *archive_read_disk_gname(struct archive *, la_int64_t);
+__LA_DECL const char *archive_read_disk_uname(struct archive *, la_int64_t);
+/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the
+ * results for performance. */
+__LA_DECL int	archive_read_disk_set_standard_lookup(struct archive *);
+/* You can install your own lookups if you like. */
+__LA_DECL int	archive_read_disk_set_gname_lookup(struct archive *,
+    void * /* private_data */,
+    const char *(* /* lookup_fn */)(void *, la_int64_t),
+    void (* /* cleanup_fn */)(void *));
+__LA_DECL int	archive_read_disk_set_uname_lookup(struct archive *,
+    void * /* private_data */,
+    const char *(* /* lookup_fn */)(void *, la_int64_t),
+    void (* /* cleanup_fn */)(void *));
+/* Start traversal. */
+__LA_DECL int	archive_read_disk_open(struct archive *, const char *);
+__LA_DECL int	archive_read_disk_open_w(struct archive *, const wchar_t *);
+/*
+ * Request that current entry be visited.  If you invoke it on every
+ * directory, you'll get a physical traversal.  This is ignored if the
+ * current entry isn't a directory or a link to a directory.  So, if
+ * you invoke this on every returned path, you'll get a full logical
+ * traversal.
+ */
+__LA_DECL int	archive_read_disk_descend(struct archive *);
+__LA_DECL int	archive_read_disk_can_descend(struct archive *);
+__LA_DECL int	archive_read_disk_current_filesystem(struct archive *);
+__LA_DECL int	archive_read_disk_current_filesystem_is_synthetic(struct archive *);
+__LA_DECL int	archive_read_disk_current_filesystem_is_remote(struct archive *);
+/* Request that the access time of the entry visited by traversal be restored. */
+__LA_DECL int  archive_read_disk_set_atime_restored(struct archive *);
+/*
+ * Set behavior. The "flags" argument selects optional behavior.
+ */
+/* Request that the access time of the entry visited by traversal be restored.
+ * This is the same as archive_read_disk_set_atime_restored. */
+#define	ARCHIVE_READDISK_RESTORE_ATIME		(0x0001)
+/* Default: Do not skip an entry which has nodump flags. */
+#define	ARCHIVE_READDISK_HONOR_NODUMP		(0x0002)
+/* Default: Skip a mac resource fork file whose prefix is "._" because of
+ * using copyfile. */
+#define	ARCHIVE_READDISK_MAC_COPYFILE		(0x0004)
+/* Default: Traverse mount points. */
+#define	ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS	(0x0008)
+/* Default: Xattrs are read from disk. */
+#define	ARCHIVE_READDISK_NO_XATTR		(0x0010)
+/* Default: ACLs are read from disk. */
+#define	ARCHIVE_READDISK_NO_ACL			(0x0020)
+/* Default: File flags are read from disk. */
+#define	ARCHIVE_READDISK_NO_FFLAGS		(0x0040)
+
+__LA_DECL int  archive_read_disk_set_behavior(struct archive *,
+		    int flags);
+
+/*
+ * Set archive_match object that will be used in archive_read_disk to
+ * know whether an entry should be skipped. The callback function
+ * _excluded_func will be invoked when an entry is skipped by the result
+ * of archive_match.
+ */
+__LA_DECL int	archive_read_disk_set_matching(struct archive *,
+		    struct archive *_matching, void (*_excluded_func)
+		    (struct archive *, void *, struct archive_entry *),
+		    void *_client_data);
+__LA_DECL int	archive_read_disk_set_metadata_filter_callback(struct archive *,
+		    int (*_metadata_filter_func)(struct archive *, void *,
+		    	struct archive_entry *), void *_client_data);
+
+/* Simplified cleanup interface;
+ * This calls archive_read_free() or archive_write_free() as needed. */
+__LA_DECL int	archive_free(struct archive *);
+
+/*
+ * Accessor functions to read/set various information in
+ * the struct archive object:
+ */
+
+/* Number of filters in the current filter pipeline. */
+/* Filter #0 is the one closest to the format, -1 is a synonym for the
+ * last filter, which is always the pseudo-filter that wraps the
+ * client callbacks. */
+__LA_DECL int		 archive_filter_count(struct archive *);
+__LA_DECL la_int64_t	 archive_filter_bytes(struct archive *, int);
+__LA_DECL int		 archive_filter_code(struct archive *, int);
+__LA_DECL const char *	 archive_filter_name(struct archive *, int);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* These don't properly handle multiple filters, so are deprecated and
+ * will eventually be removed. */
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
+__LA_DECL la_int64_t	 archive_position_compressed(struct archive *)
+				__LA_DEPRECATED;
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
+__LA_DECL la_int64_t	 archive_position_uncompressed(struct archive *)
+				__LA_DEPRECATED;
+/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
+__LA_DECL const char	*archive_compression_name(struct archive *)
+				__LA_DEPRECATED;
+/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
+__LA_DECL int		 archive_compression(struct archive *)
+				__LA_DEPRECATED;
+#endif
+
+__LA_DECL int		 archive_errno(struct archive *);
+__LA_DECL const char	*archive_error_string(struct archive *);
+__LA_DECL const char	*archive_format_name(struct archive *);
+__LA_DECL int		 archive_format(struct archive *);
+__LA_DECL void		 archive_clear_error(struct archive *);
+__LA_DECL void		 archive_set_error(struct archive *, int _err,
+			    const char *fmt, ...) __LA_PRINTF(3, 4);
+__LA_DECL void		 archive_copy_error(struct archive *dest,
+			    struct archive *src);
+__LA_DECL int		 archive_file_count(struct archive *);
+
+/*
+ * ARCHIVE_MATCH API
+ */
+__LA_DECL struct archive *archive_match_new(void);
+__LA_DECL int	archive_match_free(struct archive *);
+
+/*
+ * Test if archive_entry is excluded.
+ * This is a convenience function. This is the same as calling all
+ * archive_match_path_excluded, archive_match_time_excluded
+ * and archive_match_owner_excluded.
+ */
+__LA_DECL int	archive_match_excluded(struct archive *,
+		    struct archive_entry *);
+
+/*
+ * Test if pathname is excluded. The conditions are set by following functions.
+ */
+__LA_DECL int	archive_match_path_excluded(struct archive *,
+		    struct archive_entry *);
+/* Control recursive inclusion of directory content when directory is included. Default on. */
+__LA_DECL int	archive_match_set_inclusion_recursion(struct archive *, int);
+/* Add exclusion pathname pattern. */
+__LA_DECL int	archive_match_exclude_pattern(struct archive *, const char *);
+__LA_DECL int	archive_match_exclude_pattern_w(struct archive *,
+		    const wchar_t *);
+/* Add exclusion pathname pattern from file. */
+__LA_DECL int	archive_match_exclude_pattern_from_file(struct archive *,
+		    const char *, int _nullSeparator);
+__LA_DECL int	archive_match_exclude_pattern_from_file_w(struct archive *,
+		    const wchar_t *, int _nullSeparator);
+/* Add inclusion pathname pattern. */
+__LA_DECL int	archive_match_include_pattern(struct archive *, const char *);
+__LA_DECL int	archive_match_include_pattern_w(struct archive *,
+		    const wchar_t *);
+/* Add inclusion pathname pattern from file. */
+__LA_DECL int	archive_match_include_pattern_from_file(struct archive *,
+		    const char *, int _nullSeparator);
+__LA_DECL int	archive_match_include_pattern_from_file_w(struct archive *,
+		    const wchar_t *, int _nullSeparator);
+/*
+ * How to get statistic information for inclusion patterns.
+ */
+/* Return the amount number of unmatched inclusion patterns. */
+__LA_DECL int	archive_match_path_unmatched_inclusions(struct archive *);
+/* Return the pattern of unmatched inclusion with ARCHIVE_OK.
+ * Return ARCHIVE_EOF if there is no inclusion pattern. */
+__LA_DECL int	archive_match_path_unmatched_inclusions_next(
+		    struct archive *, const char **);
+__LA_DECL int	archive_match_path_unmatched_inclusions_next_w(
+		    struct archive *, const wchar_t **);
+
+/*
+ * Test if a file is excluded by its time stamp.
+ * The conditions are set by following functions.
+ */
+__LA_DECL int	archive_match_time_excluded(struct archive *,
+		    struct archive_entry *);
+
+/*
+ * Flags to tell a matching type of time stamps. These are used for
+ * following functions.
+ */
+/* Time flag: mtime to be tested. */
+#define ARCHIVE_MATCH_MTIME	(0x0100)
+/* Time flag: ctime to be tested. */
+#define ARCHIVE_MATCH_CTIME	(0x0200)
+/* Comparison flag: Match the time if it is newer than. */
+#define ARCHIVE_MATCH_NEWER	(0x0001)
+/* Comparison flag: Match the time if it is older than. */
+#define ARCHIVE_MATCH_OLDER	(0x0002)
+/* Comparison flag: Match the time if it is equal to. */
+#define ARCHIVE_MATCH_EQUAL	(0x0010)
+/* Set inclusion time. */
+__LA_DECL int	archive_match_include_time(struct archive *, int _flag,
+		    time_t _sec, long _nsec);
+/* Set inclusion time by a date string. */
+__LA_DECL int	archive_match_include_date(struct archive *, int _flag,
+		    const char *_datestr);
+__LA_DECL int	archive_match_include_date_w(struct archive *, int _flag,
+		    const wchar_t *_datestr);
+/* Set inclusion time by a particular file. */
+__LA_DECL int	archive_match_include_file_time(struct archive *,
+		    int _flag, const char *_pathname);
+__LA_DECL int	archive_match_include_file_time_w(struct archive *,
+		    int _flag, const wchar_t *_pathname);
+/* Add exclusion entry. */
+__LA_DECL int	archive_match_exclude_entry(struct archive *,
+		    int _flag, struct archive_entry *);
+
+/*
+ * Test if a file is excluded by its uid ,gid, uname or gname.
+ * The conditions are set by following functions.
+ */
+__LA_DECL int	archive_match_owner_excluded(struct archive *,
+		    struct archive_entry *);
+/* Add inclusion uid, gid, uname and gname. */
+__LA_DECL int	archive_match_include_uid(struct archive *, la_int64_t);
+__LA_DECL int	archive_match_include_gid(struct archive *, la_int64_t);
+__LA_DECL int	archive_match_include_uname(struct archive *, const char *);
+__LA_DECL int	archive_match_include_uname_w(struct archive *,
+		    const wchar_t *);
+__LA_DECL int	archive_match_include_gname(struct archive *, const char *);
+__LA_DECL int	archive_match_include_gname_w(struct archive *,
+		    const wchar_t *);
+
+/* Utility functions */
+/* Convenience function to sort a NULL terminated list of strings */
+__LA_DECL int archive_utility_string_sort(char **);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* These are meaningless outside of this header. */
+#undef __LA_DECL
+
+#endif /* !ARCHIVE_H_INCLUDED */
diff --git a/3rdp/win32.release/libarchive/include/archive_entry.h b/3rdp/win32.release/libarchive/include/archive_entry.h
new file mode 100644
index 0000000000..c0e75bf9f1
--- /dev/null
+++ b/3rdp/win32.release/libarchive/include/archive_entry.h
@@ -0,0 +1,721 @@
+/*-
+ * Copyright (c) 2003-2008 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libarchive/archive_entry.h 201096 2009-12-28 02:41:27Z kientzle $
+ */
+
+#ifndef ARCHIVE_ENTRY_H_INCLUDED
+#define	ARCHIVE_ENTRY_H_INCLUDED
+
+/* Note: Compiler will complain if this does not match archive.h! */
+#define	ARCHIVE_VERSION_NUMBER 3005001
+
+/*
+ * Note: archive_entry.h is for use outside of libarchive; the
+ * configuration headers (config.h, archive_platform.h, etc.) are
+ * purely internal.  Do NOT use HAVE_XXX configuration macros to
+ * control the behavior of this header!  If you must conditionalize,
+ * use predefined compiler and/or platform macros.
+ */
+
+#include <sys/types.h>
+#include <stddef.h>  /* for wchar_t */
+#include <stdint.h>
+#include <time.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#endif
+
+/* Get a suitable 64-bit integer type. */
+#if !defined(__LA_INT64_T_DEFINED)
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_INT64_T la_int64_t
+# endif
+#define __LA_INT64_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+typedef __int64 la_int64_t;
+# else
+#include <unistd.h>
+#  if defined(_SCO_DS) || defined(__osf__)
+typedef long long la_int64_t;
+#  else
+typedef int64_t la_int64_t;
+#  endif
+# endif
+#endif
+
+/* The la_ssize_t should match the type used in 'struct stat' */
+#if !defined(__LA_SSIZE_T_DEFINED)
+/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_SSIZE_T la_ssize_t
+# endif
+#define __LA_SSIZE_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+#  if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
+typedef ssize_t la_ssize_t;
+#  elif defined(_WIN64)
+typedef __int64 la_ssize_t;
+#  else
+typedef long la_ssize_t;
+#  endif
+# else
+# include <unistd.h>  /* ssize_t */
+typedef ssize_t la_ssize_t;
+# endif
+#endif
+
+/* Get a suitable definition for mode_t */
+#if ARCHIVE_VERSION_NUMBER >= 3999000
+/* Switch to plain 'int' for libarchive 4.0.  It's less broken than 'mode_t' */
+# define	__LA_MODE_T	int
+#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
+# define	__LA_MODE_T	unsigned short
+#else
+# define	__LA_MODE_T	mode_t
+#endif
+
+/* Large file support for Android */
+#ifdef __ANDROID__
+#include "android_lf.h"
+#endif
+
+/*
+ * On Windows, define LIBARCHIVE_STATIC if you're building or using a
+ * .lib.  The default here assumes you're building a DLL.  Only
+ * libarchive source should ever define __LIBARCHIVE_BUILD.
+ */
+#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)
+# ifdef __LIBARCHIVE_BUILD
+#  ifdef __GNUC__
+#   define __LA_DECL	__attribute__((dllexport)) extern
+#  else
+#   define __LA_DECL	__declspec(dllexport)
+#  endif
+# else
+#  ifdef __GNUC__
+#   define __LA_DECL
+#  else
+#   define __LA_DECL	__declspec(dllimport)
+#  endif
+# endif
+#else
+/* Static libraries on all platforms and shared libraries on non-Windows. */
+# define __LA_DECL
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
+# define __LA_DEPRECATED __attribute__((deprecated))
+#else
+# define __LA_DEPRECATED
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Description of an archive entry.
+ *
+ * You can think of this as "struct stat" with some text fields added in.
+ *
+ * TODO: Add "comment", "charset", and possibly other entries that are
+ * supported by "pax interchange" format.  However, GNU, ustar, cpio,
+ * and other variants don't support these features, so they're not an
+ * excruciatingly high priority right now.
+ *
+ * TODO: "pax interchange" format allows essentially arbitrary
+ * key/value attributes to be attached to any entry.  Supporting
+ * such extensions may make this library useful for special
+ * applications (e.g., a package manager could attach special
+ * package-management attributes to each entry).
+ */
+struct archive;
+struct archive_entry;
+
+/*
+ * File-type constants.  These are returned from archive_entry_filetype()
+ * and passed to archive_entry_set_filetype().
+ *
+ * These values match S_XXX defines on every platform I've checked,
+ * including Windows, AIX, Linux, Solaris, and BSD.  They're
+ * (re)defined here because platforms generally don't define the ones
+ * they don't support.  For example, Windows doesn't define S_IFLNK or
+ * S_IFBLK.  Instead of having a mass of conditional logic and system
+ * checks to define any S_XXX values that aren't supported locally,
+ * I've just defined a new set of such constants so that
+ * libarchive-based applications can manipulate and identify archive
+ * entries properly even if the hosting platform can't store them on
+ * disk.
+ *
+ * These values are also used directly within some portable formats,
+ * such as cpio.  If you find a platform that varies from these, the
+ * correct solution is to leave these alone and translate from these
+ * portable values to platform-native values when entries are read from
+ * or written to disk.
+ */
+/*
+ * In libarchive 4.0, we can drop the casts here.
+ * They're needed to work around Borland C's broken mode_t.
+ */
+#define AE_IFMT		((__LA_MODE_T)0170000)
+#define AE_IFREG	((__LA_MODE_T)0100000)
+#define AE_IFLNK	((__LA_MODE_T)0120000)
+#define AE_IFSOCK	((__LA_MODE_T)0140000)
+#define AE_IFCHR	((__LA_MODE_T)0020000)
+#define AE_IFBLK	((__LA_MODE_T)0060000)
+#define AE_IFDIR	((__LA_MODE_T)0040000)
+#define AE_IFIFO	((__LA_MODE_T)0010000)
+
+/*
+ * Symlink types
+ */
+#define AE_SYMLINK_TYPE_UNDEFINED	0
+#define AE_SYMLINK_TYPE_FILE		1
+#define AE_SYMLINK_TYPE_DIRECTORY	2
+
+/*
+ * Basic object manipulation
+ */
+
+__LA_DECL struct archive_entry	*archive_entry_clear(struct archive_entry *);
+/* The 'clone' function does a deep copy; all of the strings are copied too. */
+__LA_DECL struct archive_entry	*archive_entry_clone(struct archive_entry *);
+__LA_DECL void			 archive_entry_free(struct archive_entry *);
+__LA_DECL struct archive_entry	*archive_entry_new(void);
+
+/*
+ * This form of archive_entry_new2() will pull character-set
+ * conversion information from the specified archive handle.  The
+ * older archive_entry_new(void) form is equivalent to calling
+ * archive_entry_new2(NULL) and will result in the use of an internal
+ * default character-set conversion.
+ */
+__LA_DECL struct archive_entry	*archive_entry_new2(struct archive *);
+
+/*
+ * Retrieve fields from an archive_entry.
+ *
+ * There are a number of implicit conversions among these fields.  For
+ * example, if a regular string field is set and you read the _w wide
+ * character field, the entry will implicitly convert narrow-to-wide
+ * using the current locale.  Similarly, dev values are automatically
+ * updated when you write devmajor or devminor and vice versa.
+ *
+ * In addition, fields can be "set" or "unset."  Unset string fields
+ * return NULL, non-string fields have _is_set() functions to test
+ * whether they've been set.  You can "unset" a string field by
+ * assigning NULL; non-string fields have _unset() functions to
+ * unset them.
+ *
+ * Note: There is one ambiguity in the above; string fields will
+ * also return NULL when implicit character set conversions fail.
+ * This is usually what you want.
+ */
+__LA_DECL time_t	 archive_entry_atime(struct archive_entry *);
+__LA_DECL long		 archive_entry_atime_nsec(struct archive_entry *);
+__LA_DECL int		 archive_entry_atime_is_set(struct archive_entry *);
+__LA_DECL time_t	 archive_entry_birthtime(struct archive_entry *);
+__LA_DECL long		 archive_entry_birthtime_nsec(struct archive_entry *);
+__LA_DECL int		 archive_entry_birthtime_is_set(struct archive_entry *);
+__LA_DECL time_t	 archive_entry_ctime(struct archive_entry *);
+__LA_DECL long		 archive_entry_ctime_nsec(struct archive_entry *);
+__LA_DECL int		 archive_entry_ctime_is_set(struct archive_entry *);
+__LA_DECL dev_t		 archive_entry_dev(struct archive_entry *);
+__LA_DECL int		 archive_entry_dev_is_set(struct archive_entry *);
+__LA_DECL dev_t		 archive_entry_devmajor(struct archive_entry *);
+__LA_DECL dev_t		 archive_entry_devminor(struct archive_entry *);
+__LA_DECL __LA_MODE_T	 archive_entry_filetype(struct archive_entry *);
+__LA_DECL void		 archive_entry_fflags(struct archive_entry *,
+			    unsigned long * /* set */,
+			    unsigned long * /* clear */);
+__LA_DECL const char	*archive_entry_fflags_text(struct archive_entry *);
+__LA_DECL la_int64_t	 archive_entry_gid(struct archive_entry *);
+__LA_DECL const char	*archive_entry_gname(struct archive_entry *);
+__LA_DECL const char	*archive_entry_gname_utf8(struct archive_entry *);
+__LA_DECL const wchar_t	*archive_entry_gname_w(struct archive_entry *);
+__LA_DECL const char	*archive_entry_hardlink(struct archive_entry *);
+__LA_DECL const char	*archive_entry_hardlink_utf8(struct archive_entry *);
+__LA_DECL const wchar_t	*archive_entry_hardlink_w(struct archive_entry *);
+__LA_DECL la_int64_t	 archive_entry_ino(struct archive_entry *);
+__LA_DECL la_int64_t	 archive_entry_ino64(struct archive_entry *);
+__LA_DECL int		 archive_entry_ino_is_set(struct archive_entry *);
+__LA_DECL __LA_MODE_T	 archive_entry_mode(struct archive_entry *);
+__LA_DECL time_t	 archive_entry_mtime(struct archive_entry *);
+__LA_DECL long		 archive_entry_mtime_nsec(struct archive_entry *);
+__LA_DECL int		 archive_entry_mtime_is_set(struct archive_entry *);
+__LA_DECL unsigned int	 archive_entry_nlink(struct archive_entry *);
+__LA_DECL const char	*archive_entry_pathname(struct archive_entry *);
+__LA_DECL const char	*archive_entry_pathname_utf8(struct archive_entry *);
+__LA_DECL const wchar_t	*archive_entry_pathname_w(struct archive_entry *);
+__LA_DECL __LA_MODE_T	 archive_entry_perm(struct archive_entry *);
+__LA_DECL dev_t		 archive_entry_rdev(struct archive_entry *);
+__LA_DECL dev_t		 archive_entry_rdevmajor(struct archive_entry *);
+__LA_DECL dev_t		 archive_entry_rdevminor(struct archive_entry *);
+__LA_DECL const char	*archive_entry_sourcepath(struct archive_entry *);
+__LA_DECL const wchar_t	*archive_entry_sourcepath_w(struct archive_entry *);
+__LA_DECL la_int64_t	 archive_entry_size(struct archive_entry *);
+__LA_DECL int		 archive_entry_size_is_set(struct archive_entry *);
+__LA_DECL const char	*archive_entry_strmode(struct archive_entry *);
+__LA_DECL const char	*archive_entry_symlink(struct archive_entry *);
+__LA_DECL const char	*archive_entry_symlink_utf8(struct archive_entry *);
+__LA_DECL int		 archive_entry_symlink_type(struct archive_entry *);
+__LA_DECL const wchar_t	*archive_entry_symlink_w(struct archive_entry *);
+__LA_DECL la_int64_t	 archive_entry_uid(struct archive_entry *);
+__LA_DECL const char	*archive_entry_uname(struct archive_entry *);
+__LA_DECL const char	*archive_entry_uname_utf8(struct archive_entry *);
+__LA_DECL const wchar_t	*archive_entry_uname_w(struct archive_entry *);
+__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *);
+__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *);
+__LA_DECL int archive_entry_is_encrypted(struct archive_entry *);
+
+/*
+ * Set fields in an archive_entry.
+ *
+ * Note: Before libarchive 2.4, there were 'set' and 'copy' versions
+ * of the string setters.  'copy' copied the actual string, 'set' just
+ * stored the pointer.  In libarchive 2.4 and later, strings are
+ * always copied.
+ */
+
+__LA_DECL void	archive_entry_set_atime(struct archive_entry *, time_t, long);
+__LA_DECL void  archive_entry_unset_atime(struct archive_entry *);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *);
+#endif
+__LA_DECL void	archive_entry_set_birthtime(struct archive_entry *, time_t, long);
+__LA_DECL void  archive_entry_unset_birthtime(struct archive_entry *);
+__LA_DECL void	archive_entry_set_ctime(struct archive_entry *, time_t, long);
+__LA_DECL void  archive_entry_unset_ctime(struct archive_entry *);
+__LA_DECL void	archive_entry_set_dev(struct archive_entry *, dev_t);
+__LA_DECL void	archive_entry_set_devmajor(struct archive_entry *, dev_t);
+__LA_DECL void	archive_entry_set_devminor(struct archive_entry *, dev_t);
+__LA_DECL void	archive_entry_set_filetype(struct archive_entry *, unsigned int);
+__LA_DECL void	archive_entry_set_fflags(struct archive_entry *,
+	    unsigned long /* set */, unsigned long /* clear */);
+/* Returns pointer to start of first invalid token, or NULL if none. */
+/* Note that all recognized tokens are processed, regardless. */
+__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,
+	    const char *);
+__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
+	    const wchar_t *);
+__LA_DECL void	archive_entry_set_gid(struct archive_entry *, la_int64_t);
+__LA_DECL void	archive_entry_set_gname(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_gname_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_gname(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int	archive_entry_update_gname_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_hardlink(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_hardlink_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_hardlink(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int	archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_ino(struct archive_entry *, la_int64_t);
+__LA_DECL void	archive_entry_set_ino64(struct archive_entry *, la_int64_t);
+__LA_DECL void	archive_entry_set_link(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_link_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_link(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int	archive_entry_update_link_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_mode(struct archive_entry *, __LA_MODE_T);
+__LA_DECL void	archive_entry_set_mtime(struct archive_entry *, time_t, long);
+__LA_DECL void  archive_entry_unset_mtime(struct archive_entry *);
+__LA_DECL void	archive_entry_set_nlink(struct archive_entry *, unsigned int);
+__LA_DECL void	archive_entry_set_pathname(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_pathname_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_pathname(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int	archive_entry_update_pathname_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);
+__LA_DECL void	archive_entry_set_rdev(struct archive_entry *, dev_t);
+__LA_DECL void	archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
+__LA_DECL void	archive_entry_set_rdevminor(struct archive_entry *, dev_t);
+__LA_DECL void	archive_entry_set_size(struct archive_entry *, la_int64_t);
+__LA_DECL void	archive_entry_unset_size(struct archive_entry *);
+__LA_DECL void	archive_entry_copy_sourcepath(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *);
+__LA_DECL void	archive_entry_set_symlink(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_symlink_type(struct archive_entry *, int);
+__LA_DECL void	archive_entry_set_symlink_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_symlink(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int	archive_entry_update_symlink_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_uid(struct archive_entry *, la_int64_t);
+__LA_DECL void	archive_entry_set_uname(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_uname_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_uname(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
+__LA_DECL int	archive_entry_update_uname_utf8(struct archive_entry *, const char *);
+__LA_DECL void	archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted);
+__LA_DECL void	archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted);
+/*
+ * Routines to bulk copy fields to/from a platform-native "struct
+ * stat."  Libarchive used to just store a struct stat inside of each
+ * archive_entry object, but this created issues when trying to
+ * manipulate archives on systems different than the ones they were
+ * created on.
+ *
+ * TODO: On Linux and other LFS systems, provide both stat32 and
+ * stat64 versions of these functions and all of the macro glue so
+ * that archive_entry_stat is magically defined to
+ * archive_entry_stat32 or archive_entry_stat64 as appropriate.
+ */
+__LA_DECL const struct stat	*archive_entry_stat(struct archive_entry *);
+__LA_DECL void	archive_entry_copy_stat(struct archive_entry *, const struct stat *);
+
+/*
+ * Storage for Mac OS-specific AppleDouble metadata information.
+ * Apple-format tar files store a separate binary blob containing
+ * encoded metadata with ACL, extended attributes, etc.
+ * This provides a place to store that blob.
+ */
+
+__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);
+__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
+
+/*
+ * Digest routine. This is used to query the raw hex digest for the
+ * given entry. The type of digest is provided as an argument.
+ */
+#define ARCHIVE_ENTRY_DIGEST_MD5              0x00000001
+#define ARCHIVE_ENTRY_DIGEST_RMD160           0x00000002
+#define ARCHIVE_ENTRY_DIGEST_SHA1             0x00000003
+#define ARCHIVE_ENTRY_DIGEST_SHA256           0x00000004
+#define ARCHIVE_ENTRY_DIGEST_SHA384           0x00000005
+#define ARCHIVE_ENTRY_DIGEST_SHA512           0x00000006
+
+__LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */);
+
+/*
+ * ACL routines.  This used to simply store and return text-format ACL
+ * strings, but that proved insufficient for a number of reasons:
+ *   = clients need control over uname/uid and gname/gid mappings
+ *   = there are many different ACL text formats
+ *   = would like to be able to read/convert archives containing ACLs
+ *     on platforms that lack ACL libraries
+ *
+ *  This last point, in particular, forces me to implement a reasonably
+ *  complete set of ACL support routines.
+ */
+
+/*
+ * Permission bits.
+ */
+#define	ARCHIVE_ENTRY_ACL_EXECUTE             0x00000001
+#define	ARCHIVE_ENTRY_ACL_WRITE               0x00000002
+#define	ARCHIVE_ENTRY_ACL_READ                0x00000004
+#define	ARCHIVE_ENTRY_ACL_READ_DATA           0x00000008
+#define	ARCHIVE_ENTRY_ACL_LIST_DIRECTORY      0x00000008
+#define	ARCHIVE_ENTRY_ACL_WRITE_DATA          0x00000010
+#define	ARCHIVE_ENTRY_ACL_ADD_FILE            0x00000010
+#define	ARCHIVE_ENTRY_ACL_APPEND_DATA         0x00000020
+#define	ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY    0x00000020
+#define	ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS    0x00000040
+#define	ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS   0x00000080
+#define	ARCHIVE_ENTRY_ACL_DELETE_CHILD        0x00000100
+#define	ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES     0x00000200
+#define	ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES    0x00000400
+#define	ARCHIVE_ENTRY_ACL_DELETE              0x00000800
+#define	ARCHIVE_ENTRY_ACL_READ_ACL            0x00001000
+#define	ARCHIVE_ENTRY_ACL_WRITE_ACL           0x00002000
+#define	ARCHIVE_ENTRY_ACL_WRITE_OWNER         0x00004000
+#define	ARCHIVE_ENTRY_ACL_SYNCHRONIZE         0x00008000
+
+#define	ARCHIVE_ENTRY_ACL_PERMS_POSIX1E			\
+	(ARCHIVE_ENTRY_ACL_EXECUTE			\
+	    | ARCHIVE_ENTRY_ACL_WRITE			\
+	    | ARCHIVE_ENTRY_ACL_READ)
+
+#define ARCHIVE_ENTRY_ACL_PERMS_NFS4			\
+	(ARCHIVE_ENTRY_ACL_EXECUTE			\
+	    | ARCHIVE_ENTRY_ACL_READ_DATA		\
+	    | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 		\
+	    | ARCHIVE_ENTRY_ACL_WRITE_DATA		\
+	    | ARCHIVE_ENTRY_ACL_ADD_FILE		\
+	    | ARCHIVE_ENTRY_ACL_APPEND_DATA		\
+	    | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY	\
+	    | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS	\
+	    | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS	\
+	    | ARCHIVE_ENTRY_ACL_DELETE_CHILD		\
+	    | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES		\
+	    | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES	\
+	    | ARCHIVE_ENTRY_ACL_DELETE			\
+	    | ARCHIVE_ENTRY_ACL_READ_ACL		\
+	    | ARCHIVE_ENTRY_ACL_WRITE_ACL		\
+	    | ARCHIVE_ENTRY_ACL_WRITE_OWNER		\
+	    | ARCHIVE_ENTRY_ACL_SYNCHRONIZE)
+
+/*
+ * Inheritance values (NFS4 ACLs only); included in permset.
+ */
+#define	ARCHIVE_ENTRY_ACL_ENTRY_INHERITED                   0x01000000
+#define	ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT                0x02000000
+#define	ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT           0x04000000
+#define	ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT        0x08000000
+#define	ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY                0x10000000
+#define	ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS           0x20000000
+#define	ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS               0x40000000
+
+#define	ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4			\
+	(ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT			\
+	    | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT		\
+	    | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT	\
+	    | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY		\
+	    | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS		\
+	    | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS		\
+	    | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED)
+
+/* We need to be able to specify combinations of these. */
+#define	ARCHIVE_ENTRY_ACL_TYPE_ACCESS	0x00000100  /* POSIX.1e only */
+#define	ARCHIVE_ENTRY_ACL_TYPE_DEFAULT	0x00000200  /* POSIX.1e only */
+#define	ARCHIVE_ENTRY_ACL_TYPE_ALLOW	0x00000400 /* NFS4 only */
+#define	ARCHIVE_ENTRY_ACL_TYPE_DENY	0x00000800 /* NFS4 only */
+#define	ARCHIVE_ENTRY_ACL_TYPE_AUDIT	0x00001000 /* NFS4 only */
+#define	ARCHIVE_ENTRY_ACL_TYPE_ALARM	0x00002000 /* NFS4 only */
+#define	ARCHIVE_ENTRY_ACL_TYPE_POSIX1E	(ARCHIVE_ENTRY_ACL_TYPE_ACCESS \
+	    | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
+#define	ARCHIVE_ENTRY_ACL_TYPE_NFS4	(ARCHIVE_ENTRY_ACL_TYPE_ALLOW \
+	    | ARCHIVE_ENTRY_ACL_TYPE_DENY \
+	    | ARCHIVE_ENTRY_ACL_TYPE_AUDIT \
+	    | ARCHIVE_ENTRY_ACL_TYPE_ALARM)
+
+/* Tag values mimic POSIX.1e */
+#define	ARCHIVE_ENTRY_ACL_USER		10001	/* Specified user. */
+#define	ARCHIVE_ENTRY_ACL_USER_OBJ 	10002	/* User who owns the file. */
+#define	ARCHIVE_ENTRY_ACL_GROUP		10003	/* Specified group. */
+#define	ARCHIVE_ENTRY_ACL_GROUP_OBJ	10004	/* Group who owns the file. */
+#define	ARCHIVE_ENTRY_ACL_MASK		10005	/* Modify group access (POSIX.1e only) */
+#define	ARCHIVE_ENTRY_ACL_OTHER		10006	/* Public (POSIX.1e only) */
+#define	ARCHIVE_ENTRY_ACL_EVERYONE	10107   /* Everyone (NFS4 only) */
+
+/*
+ * Set the ACL by clearing it and adding entries one at a time.
+ * Unlike the POSIX.1e ACL routines, you must specify the type
+ * (access/default) for each entry.  Internally, the ACL data is just
+ * a soup of entries.  API calls here allow you to retrieve just the
+ * entries of interest.  This design (which goes against the spirit of
+ * POSIX.1e) is useful for handling archive formats that combine
+ * default and access information in a single ACL list.
+ */
+__LA_DECL void	 archive_entry_acl_clear(struct archive_entry *);
+__LA_DECL int	 archive_entry_acl_add_entry(struct archive_entry *,
+	    int /* type */, int /* permset */, int /* tag */,
+	    int /* qual */, const char * /* name */);
+__LA_DECL int	 archive_entry_acl_add_entry_w(struct archive_entry *,
+	    int /* type */, int /* permset */, int /* tag */,
+	    int /* qual */, const wchar_t * /* name */);
+
+/*
+ * To retrieve the ACL, first "reset", then repeatedly ask for the
+ * "next" entry.  The want_type parameter allows you to request only
+ * certain types of entries.
+ */
+__LA_DECL int	 archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
+__LA_DECL int	 archive_entry_acl_next(struct archive_entry *, int /* want_type */,
+	    int * /* type */, int * /* permset */, int * /* tag */,
+	    int * /* qual */, const char ** /* name */);
+
+/*
+ * Construct a text-format ACL.  The flags argument is a bitmask that
+ * can include any of the following:
+ *
+ * Flags only for archive entries with POSIX.1e ACL:
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.
+ * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
+ *    default ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and
+ *    "mask" entries.
+ *
+ * Flags only for archive entries with NFSv4 ACL:
+ * ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for
+ *    unset permissions and flags in NFSv4 ACL permission and flag fields
+ *
+ * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL:
+ * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
+ *    each ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma
+ *    instead of newline.
+ */
+#define	ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID	0x00000001
+#define	ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT	0x00000002
+#define	ARCHIVE_ENTRY_ACL_STYLE_SOLARIS		0x00000004
+#define	ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA	0x00000008
+#define	ARCHIVE_ENTRY_ACL_STYLE_COMPACT		0x00000010
+
+__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *,
+	    la_ssize_t * /* len */, int /* flags */);
+__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *,
+	    la_ssize_t * /* len */, int /* flags */);
+__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *,
+	    const wchar_t * /* wtext */, int /* type */);
+__LA_DECL int archive_entry_acl_from_text(struct archive_entry *,
+	    const char * /* text */, int /* type */);
+
+/* Deprecated constants */
+#define	OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID		1024
+#define	OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT	2048
+
+/* Deprecated functions */
+__LA_DECL const wchar_t	*archive_entry_acl_text_w(struct archive_entry *,
+		    int /* flags */) __LA_DEPRECATED;
+__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
+		    int /* flags */) __LA_DEPRECATED;
+
+/* Return bitmask of ACL types in an archive entry */
+__LA_DECL int	 archive_entry_acl_types(struct archive_entry *);
+
+/* Return a count of entries matching 'want_type' */
+__LA_DECL int	 archive_entry_acl_count(struct archive_entry *, int /* want_type */);
+
+/* Return an opaque ACL object. */
+/* There's not yet anything clients can actually do with this... */
+struct archive_acl;
+__LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *);
+
+/*
+ * extended attributes
+ */
+
+__LA_DECL void	 archive_entry_xattr_clear(struct archive_entry *);
+__LA_DECL void	 archive_entry_xattr_add_entry(struct archive_entry *,
+	    const char * /* name */, const void * /* value */,
+	    size_t /* size */);
+
+/*
+ * To retrieve the xattr list, first "reset", then repeatedly ask for the
+ * "next" entry.
+ */
+
+__LA_DECL int	archive_entry_xattr_count(struct archive_entry *);
+__LA_DECL int	archive_entry_xattr_reset(struct archive_entry *);
+__LA_DECL int	archive_entry_xattr_next(struct archive_entry *,
+	    const char ** /* name */, const void ** /* value */, size_t *);
+
+/*
+ * sparse
+ */
+
+__LA_DECL void	 archive_entry_sparse_clear(struct archive_entry *);
+__LA_DECL void	 archive_entry_sparse_add_entry(struct archive_entry *,
+	    la_int64_t /* offset */, la_int64_t /* length */);
+
+/*
+ * To retrieve the xattr list, first "reset", then repeatedly ask for the
+ * "next" entry.
+ */
+
+__LA_DECL int	archive_entry_sparse_count(struct archive_entry *);
+__LA_DECL int	archive_entry_sparse_reset(struct archive_entry *);
+__LA_DECL int	archive_entry_sparse_next(struct archive_entry *,
+	    la_int64_t * /* offset */, la_int64_t * /* length */);
+
+/*
+ * Utility to match up hardlinks.
+ *
+ * The 'struct archive_entry_linkresolver' is a cache of archive entries
+ * for files with multiple links.  Here's how to use it:
+ *   1. Create a lookup object with archive_entry_linkresolver_new()
+ *   2. Tell it the archive format you're using.
+ *   3. Hand each archive_entry to archive_entry_linkify().
+ *      That function will return 0, 1, or 2 entries that should
+ *      be written.
+ *   4. Call archive_entry_linkify(resolver, NULL) until
+ *      no more entries are returned.
+ *   5. Call archive_entry_linkresolver_free(resolver) to free resources.
+ *
+ * The entries returned have their hardlink and size fields updated
+ * appropriately.  If an entry is passed in that does not refer to
+ * a file with multiple links, it is returned unchanged.  The intention
+ * is that you should be able to simply filter all entries through
+ * this machine.
+ *
+ * To make things more efficient, be sure that each entry has a valid
+ * nlinks value.  The hardlink cache uses this to track when all links
+ * have been found.  If the nlinks value is zero, it will keep every
+ * name in the cache indefinitely, which can use a lot of memory.
+ *
+ * Note that archive_entry_size() is reset to zero if the file
+ * body should not be written to the archive.  Pay attention!
+ */
+struct archive_entry_linkresolver;
+
+/*
+ * There are three different strategies for marking hardlinks.
+ * The descriptions below name them after the best-known
+ * formats that rely on each strategy:
+ *
+ * "Old cpio" is the simplest, it always returns any entry unmodified.
+ *    As far as I know, only cpio formats use this.  Old cpio archives
+ *    store every link with the full body; the onus is on the dearchiver
+ *    to detect and properly link the files as they are restored.
+ * "tar" is also pretty simple; it caches a copy the first time it sees
+ *    any link.  Subsequent appearances are modified to be hardlink
+ *    references to the first one without any body.  Used by all tar
+ *    formats, although the newest tar formats permit the "old cpio" strategy
+ *    as well.  This strategy is very simple for the dearchiver,
+ *    and reasonably straightforward for the archiver.
+ * "new cpio" is trickier.  It stores the body only with the last
+ *    occurrence.  The complication is that we might not
+ *    see every link to a particular file in a single session, so
+ *    there's no easy way to know when we've seen the last occurrence.
+ *    The solution here is to queue one link until we see the next.
+ *    At the end of the session, you can enumerate any remaining
+ *    entries by calling archive_entry_linkify(NULL) and store those
+ *    bodies.  If you have a file with three links l1, l2, and l3,
+ *    you'll get the following behavior if you see all three links:
+ *           linkify(l1) => NULL   (the resolver stores l1 internally)
+ *           linkify(l2) => l1     (resolver stores l2, you write l1)
+ *           linkify(l3) => l2, l3 (all links seen, you can write both).
+ *    If you only see l1 and l2, you'll get this behavior:
+ *           linkify(l1) => NULL
+ *           linkify(l2) => l1
+ *           linkify(NULL) => l2   (at end, you retrieve remaining links)
+ *    As the name suggests, this strategy is used by newer cpio variants.
+ *    It's noticeably more complex for the archiver, slightly more complex
+ *    for the dearchiver than the tar strategy, but makes it straightforward
+ *    to restore a file using any link by simply continuing to scan until
+ *    you see a link that is stored with a body.  In contrast, the tar
+ *    strategy requires you to rescan the archive from the beginning to
+ *    correctly extract an arbitrary link.
+ */
+
+__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);
+__LA_DECL void archive_entry_linkresolver_set_strategy(
+	struct archive_entry_linkresolver *, int /* format_code */);
+__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
+__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,
+    struct archive_entry **, struct archive_entry **);
+__LA_DECL struct archive_entry *archive_entry_partial_links(
+    struct archive_entry_linkresolver *res, unsigned int *links);
+#ifdef __cplusplus
+}
+#endif
+
+/* This is meaningless outside of this header. */
+#undef __LA_DECL
+
+#endif /* !ARCHIVE_ENTRY_H_INCLUDED */
diff --git a/3rdp/win32.release/libarchive/libarchive.props b/3rdp/win32.release/libarchive/libarchive.props
new file mode 100644
index 0000000000..7928e34137
--- /dev/null
+++ b/3rdp/win32.release/libarchive/libarchive.props
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_PropertySheetDisplayName>Archive Library</_PropertySheetDisplayName>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>$(MSBuildThisFileDirectory)/bin/archive.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup />
+</Project>
\ No newline at end of file
diff --git a/3rdp/win32.release/zlib/bin/zlib1.dll b/3rdp/win32.release/zlib/bin/zlib1.dll
new file mode 100644
index 0000000000000000000000000000000000000000..31996cd3e2e9c86188c25882a2d5671e926c0740
GIT binary patch
literal 75264
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%0A3pEVw|vj~$sAvg
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
UL<}ShbPQa;hrkZ@td7ln0N87dF8}}l

literal 0
HcmV?d00001

diff --git a/3rdp/win32.release/zlib/include/zconf.h b/3rdp/win32.release/zlib/include/zconf.h
new file mode 100644
index 0000000000..03a9431c8b
--- /dev/null
+++ b/3rdp/win32.release/zlib/include/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/3rdp/win32.release/zlib/include/zlib.h b/3rdp/win32.release/zlib/include/zlib.h
new file mode 100644
index 0000000000..022817927c
--- /dev/null
+++ b/3rdp/win32.release/zlib/include/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.3, July 18th, 2005
+
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+     This library can optionally read and write gzip streams in memory as well.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumualte before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  the value returned by deflateBound (see below). If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer). It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+   determines the window size. deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding. Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper. The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero),
+   no header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding). Filtered data consists mostly of small values with a somewhat
+   random distribution. In this case, the compression algorithm is tuned to
+   compress them better. The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+   parameter only affects the compression ratio but not the correctness of the
+   compressed output even if it is not set appropriately.  Z_FIXED prevents the
+   use of dynamic Huffman codes, allowing for a simpler decoder for special
+   applications.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front. In addition, the
+   current implementation of deflate will use at most the window size minus
+   262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit()
+   or deflateInit2().  This would be used to allocate an output buffer
+   for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+  is that this function is used to start off the deflate output with the
+  bits leftover from a previous deflate stream when appending to it.  As such,
+  this function can only be used for raw deflate, and must be used before the
+  first deflate() call after a deflateInit2() or deflateReset().  bits must be
+  less than or equal to 16, and that many of the least significant bits of
+  value will be inserted in the output.
+
+      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+      If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+      deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+  that this function is used to start inflating at a bit position in the
+  middle of a byte.  The provided bits will be used before any bytes are used
+  from next_in.  This function should only be used with raw inflate, and
+  should be used before the first inflate() call after inflateInit2() or
+  inflateReset().  bits must be less than or equal to 16, and that many of the
+  least significant bits of value will be inserted in the input.
+
+      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK can be used to
+   force inflate() to return immediately after header processing is complete
+   and before any actual data is decompressed.
+
+      The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.)  If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When
+   any of extra, name, or comment are not Z_NULL and the respective field is
+   not present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+      If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+      inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+   be allocated, or Z_VERSION_ERROR if the version of the library does not
+   match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free
+   the allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects
+   only the raw deflate stream to decompress.  This is different from the
+   normal behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format
+   error in the deflate stream (in which case strm->msg is set to indicate the
+   nature of the error), or Z_STREAM_ERROR if the stream was not properly
+   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
+   distinguished using strm->next_in which will be Z_NULL only if in() returned
+   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+   out() returning non-zero.  (in() will always be called before out(), so
+   strm->next_in is assured to be defined if out() returns non-zero.)  Note
+   that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least the value returned
+   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before
+   a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h", or 'R' for run-length encoding
+   as in "wb1R". (See the description of deflateInit2 for more information
+   about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file,
+                                   voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).  The number of
+   uncompressed bytes written is limited to 4095. The caller should assure that
+   this limit is not exceeded. If it is exceeded, then gzprintf() will return
+   return an error (0) with nothing written. In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzungetc OF((int c, gzFile file));
+/*
+      Push one character back onto the stream to be read again later.
+   Only one character of push-back is allowed.  gzungetc() returns the
+   character pushed, or -1 on failure.  gzungetc() will fail if a
+   character has been pushed but not read yet, or if c is -1. The pushed
+   character will be discarded if the stream is repositioned with gzseek()
+   or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                      z_off_t offset, int whence));
+/*
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns 1 if file is being read directly without decompression, otherwise
+   zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file. This is analogous to the
+   clearerr() function in stdio. This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+/*
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32. If buf is NULL, this function returns the required initial
+   value for the for the crc. Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+        ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/ctrl/file.cnf b/ctrl/file.cnf
index a829db1df6deec0997627d8fca1e5f46910de550..f8c9922e30d9c9f20ae71bc5e0484563c395598e 100644
GIT binary patch
delta 292
zcmeB3>`2_8E;La=fsuD|p^)rE1^&$?LYo+w&T>o?)Ss*%Ejm#_X>*^*Z8VXKVrU|h
zZ6*0OD@mS3RX4donuR5^Br|pLL>9%(4bo@^Pd+Rw1+ww5EV=}n0$74g0Zn4Ff)cvL
mJt`cVvsEsmTD*Cg8k)MzFE!9bbhOb$@^w)~6ee%bzX1S*rC9v{

delta 701
zcmeB3>`2_8E~NOM0N|ZmC?q>kfq!#}&?ZKvlN=KT^(QMxiz*P%_J4Da$X$}upBE!d
zy^tibdM!fkVPFU?$;`<t$xNL*kwtNHgEUFLnS4-IW}*WB<XN&(oA1ibAjxC5<&hmq
lIN;=zNK>DvLYn#|YNV-uu0fi5Ep5`&=jxKAe)0zW8vxxV3}FBO

diff --git a/ctrl/text.dat b/ctrl/text.dat
index 63906618a2..4424ebd097 100644
--- a/ctrl/text.dat
+++ b/ctrl/text.dat
@@ -96,7 +96,7 @@
 	" %4u\b\b\b\b\1h%s \1n\1c(\1h\1`?\1n\1c=Menu) (\1h%u\1n\1c of \1h%u\1n\1c): \1n\1~"
 "\r\nYou didn't post message #%d\r\n"                   072 YouDidntPostMsgN
 "\1?Delete message #%u '%s'"                          073 DeletePostQ
-"\1n\1b[\1h\1wI\1n\1b] \1hAutoLogon via IP address      "\     074 UserDefaultsAutoLogon
+"\1n\1b[\1h\1wI\1n\1b] \1hAutoLogon via IP address     "\     074 UserDefaultsAutoLogon
 	"\1n\1b: \1c%s\r\n"	 
 "\1n\r\n\1m%s sent to \1h%s #%u\r\n"                    075 MsgSentToUser
 "\1_\r\n\1y\1hText to search for: "                      076 SearchStringPrompt
@@ -201,8 +201,8 @@
 "Delete Guru file"                                      163 DeleteGuruLogQ
 "\1n\1g\7Telegram from \1n\1h%s\1n\1g on %s:\r\n\1h"    164 TelegramFmt
 "\r\n\r\nYou can't download.\r\n"                       165 R_Download
-"\r\n\1w\1hSearching all directories @ELLIPSIS@\r\n"      166 SearchingAllDirs
-"\1w\1hSearching all libraries @ELLIPSIS@\r\n"            167 SearchingAllLibs
+"\r\n\1w\1hSearching current library @ELLIPSIS@\r\n\1q"   166 SearchingAllDirs
+"\1w\1hSearching all libraries @ELLIPSIS@\r\n\1q"         167 SearchingAllLibs
 "\r\n\1w\1h%u Files Listed.\r\n"                          168 NFilesListed
 "\r\n\1w\1hEmpty directory.\r\n"                          169 EmptyDir
 "\r\n\1n\1cSearching for files "\                         170 NScanHdr
@@ -278,7 +278,7 @@
 "\r\n\7\1r\1h\1iBatch upload queue is full.\1n\r\n"         229 BatchUlQueueIsFull
 "\r\n\1n\1m\1h%s \1n\1madded to batch upload queue"\         230 FileAddedToUlQueue
 	"\1c - Files: \1h%u \1n\1c(\1h%u\1n\1c Max)\r\n"
-"\7\1_\1w\1hNode %2d: \1g%s\1n\1g sent you a file.\r\n"       231 UserToUserXferNodeMsg
+"Unused 231"                                               231 UserToUserXferNodeMsg
 "\1n\1?\1g\1h%s\1y: \1w~B\1yatch download, "\              232 FileInfoPrompt
 	"\1w~E\1yxtended info, "\
 	"\1w~V\1yiew file, "\
@@ -312,14 +312,14 @@
 "\1_\1y\1hCredit value     : \1n"                           257 EditCreditValue
 "\1_\1y\1hTimes downloaded : \1n"                           258 EditTimesDownloaded
 "\1_\1y\1hOpen count       : \1n"                           259 EditOpenCount
-"\1_\1y\1hAlternate Path   : \1n"                           260 EditAltPath
+"UNUSED260"                                                 260 Unused260
 "\r\n\1w\1hYou only have %s credits.\r\n"                 261 YouOnlyHaveNCredits
 "\r\nYou don't have enough credits.\r\n"                262 NotEnoughCredits
 "\r\n\1w\1hNot enough time left to transfer.\r\n"         263 NotEnoughTimeToDl
 "\r\nProtocol, ~Batch, ~Quit, or [~Next]: "             264 ProtocolBatchQuitOrNext
 "\r\nBulk Upload %s %s Directory\r\n"\                  265 BulkUpload
 	"(Enter '-' for description to skip file):\r\n"
-"\1_\1y\1h%s\1w%7uk\1b:"                                     266 BulkUploadDescPrompt
+"\1_\1y\1h%-12s\1w%7uk\1b:"                             266 BulkUploadDescPrompt
 "\r\n\1r\1h\1iNo files in batch queue.\1n"\                 267 NoFilesInBatchQueue
 	"\r\n\r\n\1mUse \1hD\1n\1m or \1hU\1n\1m to add files to the queue.\r\n"
 "\1_\r\n\1y\1hBatch: \1n"                                   268 BatchMenuPrompt
@@ -356,16 +356,14 @@
 "\r\nUploader: %s\r\nFilename: %s\r\n"                  294 TempFileInfo
 "\r\n%s bytes in %u files\r\n"                          295 TempDirTotal
 "\r\n%u files removed.\r\n"                             296 NFilesRemoved
-"\1r\1h\1iAll other nodes should NOT be in use "\          297 ResortWarning
-	"during resort/compression.\1n\r\n"
-"\1-\1c%-15.15s \1y\1h%-25.25s "                            298 ResortLineFmt
-"\1bEmpty\1n\r\n"                                         299 ResortEmptyDir
-"\1wSorting @ELLIPSIS@"                                   300 Sorting
-"\b\b\b\b\b\b\b\b\b\b\1bSorted    \1n\r\n"                301 Sorted
-"\b\b\b\b\b\b\b\b\b\b\1bCompressed %u slots "\           302 Compressed
-	"(%s bytes)\1n\r\n"
-"\1w\1h\r\n%s is already in the queue.\r\n"               303 FileAlreadyInQueue
-"\1w\1h\1/File is not online.\r\n"                       304 FileIsNotOnline
+"Tag this file"                                         297 TagFileQ
+"\1h\1yEnter (space-separated) Tags: "                  298 TagFilePrompt
+"UNUSED299"                                             299 Unused299
+"UNUSED300"                                             300 Unused300
+"UNUSED301"                                             301 Unused301
+"UNUSED302"                                             302 Unused302
+"\1w\1h\r\n%s is already in the queue.\r\n"             303 FileAlreadyInQueue
+"\1w\1h\1/File is not online.\r\n"                      304 FileIsNotOnline
 "\1n\r\n\1m\1h%s \1n\1madded to batch download queue -\r\n"\ 305 FileAddedToBatDlQueue
 	"\1cFiles: \1h%u\1n\1c (\1h%u\1n\1c Max)  Credits: \1h%s\1n\1c"\
 	"  Bytes: \1h%s\1n\1c  Time: \1h%s\r\n"
@@ -379,7 +377,7 @@
 "\1_\1h\1w%s was %sdownloaded by %s\r\n"\                  312 DownloadUserMsg
 	"\1n\1gYou were awarded %s credits.\r\n"
 "partially "                                            313 Partially
-"\r\n\1n\1gLibrary          :\1h (%u) %s"                  314 FiLib
+"\1l\1n\1gLibrary          :\1h (%u) %s"                  314 FiLib
 "\r\n\1n\1gDirectory        :\1h (%u) %s"                  315 FiDir
 "\r\n\1n\1gFilename         :\1h %s"                       316 FiFilename
 "\r\n\1n\1gFile size        :\1h %s (%s) bytes"            317 FiFileSize
@@ -391,9 +389,9 @@
 "\r\n\1n\1gLast downloaded  :\1h %s"                       323 FiDateDled
 "\r\n\1n\1gTimes downloaded :\1h %u"                       324 FiTimesDled
 "\r\n\1n\1gTime to download :\1h %s"                       325 FiTransferTime
-"\r\n\1n\1gAlternate Path   :\1h %s"                       326 FiAlternatePath
-"\r\n\1r\1h\1iInvalid Alternate Path Number: %u\1n"         327 InvalidAlternatePathN
-"\1_\1/\1w\1hFile is currently open by %d user%s.\r\n"    328 FileIsOpen
+"\r\n\1n\1gTags             :\1h %s"                       326 FiTags
+"UNUSED327"                                                327 Unused327
+"\r\n\1n\1gFile %-6.6s      :\1h %s"                       328 FiChecksum
 "\7\7\r\n\1h\1rH\1ba\1gp\1yp\1cy \1mB\1wi\1rr\1gt\1bh\1cd\1ma\1yy "\  329 HappyBirthday
 	"\1wt\1ro \1gy\1bo\1cu\r\n\7\7\1mH\1ya\1wp\1rp\1gy "\
 	"\1bB\1ci\1mr\1yt\1wh\1rd\1ga\1by \1ct\1mo \1yy\1wo\1ru\1g.\1b.\1c.\r\n\r\n"
@@ -430,10 +428,8 @@
 	"same time.\1n\r\n"
 "\7\1r\1h\1i%d critical errors have occurred. "\           359 CriticalErrors
 	"Type ;ERR at main menu.\1n\r\n"
-"\1_\1w\1hYou have %d User to User Transfer%s "\           360 UserXferForYou
-	"waiting for you\r\n"
-"\1_\1w\1hYou have sent %d unreceived User to "\           361 UnreceivedUserXfer
-	"User Transfer%s\r\n"
+"Unused360"                                                360 UserXferForYou
+"Unused361"                                                361 UnreceivedUserXfer
 "Read your mail now"                                    362 ReadYourMailNowQ
 "Sorry, the system is closed to new users.\r\n"         363 NoNewUsers
 "New User Password: "                                   364 NewUserPasswordPrompt
@@ -737,7 +733,7 @@
 "\r\n%u credits have been added to your account.\r\n"  592 CreditedAccount
 "\r\nANSI Capture is now %s\r\n"                        593 ANSICaptureIsNow
 "\1n\1m\r\nRetrieving \1h%s\1n\1m..."                        594 RetrievingFile
-"\1n\r\nAlternate upload path now: %s\r\n"               595 AltULPathIsNow
+"UNUSED595"                                             595 Unused595
 "\r\nPrivate"                                           596 PrivatePostQ
 "\r\n\1_\1y\1hPost to: "                                   597 PostTo
 "\r\nPrivate posts require a destination user "\        598 NoToUser
diff --git a/docs/newfilebase.txt b/docs/newfilebase.txt
new file mode 100644
index 0000000000..bd085fed90
--- /dev/null
+++ b/docs/newfilebase.txt
@@ -0,0 +1,244 @@
+_New FileBases_
+
+The new FileBase files are stored in the same database location as before
+(e.g. data/dirs/), but the file extensions are different:
+
+^ Purpose                  ^   Old    ^   New    ^
+| Index (e.g. filenames)   | code.ixb | code.sid |
+| Data (e.g. descriptions) | code.dat | code.shd |
+| Extended Descriptions    | code.exb | code.sdt |
+| Metadata                 | code.dab | code.ini |
+| Allocation Tables        | N/A      | code.sda and code.sha |
+
+If these new filebase file extensions look familiar to you, that's because
+we're using the Synchronet Message Base format/library (v3.0 now) for the
+underlying database. This means that the SMB tools you may be familiar with
+(e.g. CHKSMB, FIXSMB, SMBUTIL) also work on the new filebases.
+
+The conversion of the filebases to the new format should occur automatically
+when you run 'jsexec update' which in turn will execute the program
+'upgrade_to_v319' when appropriate (just one time). Once converted, you can
+delete the old files or leave them in place in case you need to revert back to
+Synchronet v3.18 for any reason. The old filebase files won't harm anything if
+left.
+
+The creation of each new filebase will automatically calculate and store the
+hashes of the contents of the actual files available for download. These
+hashes are useful for duplicate file detection and data integrity assurance.
+If you wish to opt-out of the file hashing (which consumes the majority of the
+time during the upgrade process), you can turn off file hashing in the
+per-directory Toggle Options in SCFG->File Areas. You would have to perform
+this opt-out for the directories of choice *before* you run 'jsexec update' /
+'upgrade_to_v319'. You should not normally need to run 'upgrade_to_v319'.
+
+_Long Filenames_
+
+While filenames stored in the filebases used to be limited to MS-DOS
+compatible 8.3 formatted names, longer filenames are now supported on all
+platforms. Additionally, some previously invalid filename characters (e.g.
+spaces) are now allowed and files without extensions (i.e. no '.' in their
+filename are now supported).
+
+Although Synchronet for Windows previously used Win32 API functions for short
+<-> long filename conversions in the Windows builds of Synchronet, resulting
+in the unfortunate Micros~1 shorted filenames stored and sometimes seen, that
+is no longer the case. Except for the %~ command-line specifier, those
+short/long filename conversion functions are no longer in use anywhere within
+Synchronet for Windows - it's native filenames through-out. The filebase
+conversion process (upgrade_to_v319 / 'jsexec update') on Windows will attempt
+to automatically resolve the native/long filenames and store those names and
+only those names in the new filebases.
+
+Note: abbreviated versions of long filenames are displayed in some situations
+to accommodate the limited width of a traditional BBS user terminal. An effort
+is made to always display the full file extension/suffix however
+(e.g. "longfilename.jpeg" may be *displayed* as "longfil.jpeg").
+
+Note: only 64 characters of each filename (always including any extension) are
+indexed for searches and duplicate checking, but the entire filename, up to
+64K characters in length, is stored intact in the filebase.
+
+Filenames with /extensions/ longer than 3 characters, e.g. ".jpeg", ".tar.gz",
+can be added to the filebases, but the configurable compressible, extractable,
+and viewable file types/extensions remain limited to 3 characters in SCFG.
+Similarly, a maximum length of 3 character archive "types" are stored per BBS
+user record (for each user's QWK packet format and temp archive preference).
+
+_Large Files_
+
+Files greater in size than 2GB or 4GB (depending) were previously a problem.
+Though there are still some 32-bit file length limitations (e.g. only files
+smaller than 4GB in size will be hashed), there is better and increasing
+support for larger files in general.
+
+Note: the ZMODEM transfer protocol as designed by Chuck Forsberg only supports
+files up to 4GB in size and in many cases, files greater than or equal to 2GB
+in size will prove difficult or impossible to transfer between some ZMODEM
+implementations. In general, it is recommended to use an alternate transfer
+protocol (e.g. YMODEM[-G], FTP, HTTP) for files >= 2GB in length.
+
+_Large Directories_
+
+Due to the new filebase design, directories with more than 10,000 files are
+now supported (though, not encouraged).
+
+_Descriptions_
+
+The file "summary" or single-line "short description" remains limited to 58
+characters in length for practical purposes. Though longer file summaries
+(up to 64KB) can be stored in the filebase, they are not recommended.
+
+Extended (multi-line) descriptions may now span more than the previous limit
+of 10 lines or 512 total characters. There is no technical limit to the length
+of extended file descriptions, though a limit of 1024 characters imported from
+description files embedded in archives (e.g. FILE_ID.DIZ) is being imposed. If
+you have a need for longer (than 1024 character) extended descriptions
+imported from embedded description files, please provide me with details.
+
+_Batches_
+
+File upload and download batch queues used to be maintained in memory (though
+they were written to disk files to be retained between user logons), they are
+now entirely maintained in disk files (data/user/*.upload and *.dnload in .ini
+file format). This means that custom batch management can now be performed
+easily by modules or non-Terminal Server scripts.
+
+_Hashes_
+
+Files are now hashed, by default, using multiple hashing algorithms (CRC16,
+CRC32, MD5, and SHA1) for duplicate file detection and for reporting to users
+(e.g. to insure data integrity). For a file to be considered a duplicate
+(i.e. and rejected for upload) it must have the same size and hash values as
+another file in a filebase already. Each directory is configurable as to
+whether or not to hash its files or use it for duplicate file detection
+(by name or hash).
+
+_Sorting_
+
+While the old filebases 
+The new filebases are indexed in the order in which the files are imported
+into the database. Sorting of the files for display purposes in the terminal
+and FTP servers is optional and configured by the sysop:
+ Name Ascending (case-insensitive)
+ Name Descending (case-insensitive)
+ Name Ascending (case-sensitive)
+ Name Descending (case-sensitive)
+ Date Ascending
+ Date Descending
+
+As a result, the "RESORT" file transfer operator command has been removed.
+
+_Tags_
+
+Individual files can now be tagged for easy searching/grouping. This feature
+will be utilized/enhanced more in the future.
+
+_JavaScript_
+
+The new "FileBase" class is used (similar to the existing MsgBase class) to
+open and access filebases from JavaScript modules. Using this class, the
+defaults methods of listing and transferring files can be replaced with
+custom modules.
+
+_TickIT_
+
+The new FileBase JS class is now used to import files directly from FidoNet
+-style .TIC files (via tickit.js) so no dependency or invocation of any
+external utilities (e.g. addfiles) is required.
+
+_Utilities_
+
+The native utilities ADDFILES, FILELIST, DELFILES, and DUPEFIND have been
+replaced with similarly named and purposed JavaScript utility scripts to be
+invoked with JSexec:
+- addfiles.js for importing lists of files into filebases
+- postfile.js for importing a single file into a filebase
+- filelist.js for generating file listings from filebases
+- delfiles.js for removing files from filebases
+- dupefind.js for discovering and reporting duplicate files in the filebases
+
+_Performance_
+
+Due to the nature and use of the new filebase API, file listings are much
+faster (e.g. large file listings from the Synchronet FTP server) as well as
+filename/pattern, description text, and duplicate-file searching.
+
+_FTP Server_
+
+Due to the removal of support for rendering FTP-downloaded content (e.g.
+HTML files) in modern web browsers, the FTP Server no longer supports dynamic
+HTML index file generation (e.g. 00index.html). Instead, we will focus on
+better support for filebase browsing and file transfers via HTTP and HTTPS in
+addition to the traditional FTP and FTPS uses. The dynamic generation of
+the ASCII file listings via FTP (e.g. 00index) is still supported by the FTP
+server, though now much faster than before.
+
+_libarchive_
+
+The libarchive library (http://libarchive.org/) has now been integrated into
+Synchronet (and exposed via the new "Archive" JavaScript class) and integrated
+into SBBSecho so that the creation, listing/viewing, and extraction of
+archived files can now be performed "in-process" without the invocation of or
+dependency on external programs (e.g. Info-Zip unzip or PKUNZIP).
+
+Formats fully supported:
+- zip
+- 7zip
+- gzipped-tar
+- bzipped-tar
+
+Formats supported for viewing and extraction only:
+- rar
+- lha/lzh
+- iso
+- xar
+- cab
+
+This means that for most BBSes, no "Compressible" or "Extractable" file types
+need to be configured in SCFG->File Options. Additionally, by setting
+"Archive Format" to "ZIP" for SCFG->Networks->QWK->Hubs, no "pack" or "unpack"
+command-line need be configured.
+
+For listing the contents of archives, the new archive.js utility script may be
+installed as a "Viewable File Type" handler for the commonly supported file
+extensions by running 'jsexec archive.js install'.
+
+_DIZ_
+
+Description files embedded in archives (e.g. FILE_ID.DIZ) are now supported
+more uniformly and seamlessly.
+
+_File Echoes_
+
+Each file transfer directory configured in SCFG->File Areas may now have an
+"Area Tag" explicitly set for FidoNet-style file distribution networks. If
+an Area Tag is not explicitly set, then the directory's short name is used
+(with spaces replaced with underscores) automatically. tickit.js now uses
+this new "area_tag" file_area.dir[] JS property for its "AutoAreas" feature.
+
+_User to User Files_
+
+The user to user file transfer feature has been removed. Send file attachments
+with email/netmail if you want to send files to users.
+
+_Opened Files_
+
+The "open" (reference) counter for files is now gone. If you want to remove
+a file from the filebase while a user has it in their batch download queue or
+is actively downloading it, nothing is preventing you from doing so.
+
+As a result, the "CLOSE" file transfer operator command has been removed.
+
+_Alternate File Paths_
+
+The support for "Alternate File Paths" has been removed. There are better
+modern operating/file system solutions to the original problem solved with
+this feature.
+
+As a result, the "ALTUL" file transfer operator command has been removed.
+
+_Bi-directional File Transfers_
+
+The protocol drivers that supported bi-directional file transfers (Bi-Modem,
+HS/Link) are now long unsupported DOS/OS2 programs with no equivalent in the
+modern world. Bye bye Bi-modem. :-(
\ No newline at end of file
diff --git a/exec/addfiles.js b/exec/addfiles.js
new file mode 100755
index 0000000000..35899a27ac
--- /dev/null
+++ b/exec/addfiles.js
@@ -0,0 +1,285 @@
+// Add files to a file base/area directory for SBBS v3.19+
+// Replaces functionality of the old ADDFILES program written in C
+
+require("sbbsdefs.js", 'LEN_FDESC');
+
+"use strict";
+
+const default_excludes = [
+	"FILES.BBS",
+	"FILE_ID.DIZ",
+	"DESCRIPT.ION",
+	"SFFILES.BBS"
+];
+
+if(argv.indexOf("-help") >= 0 || argv.indexOf("-?") >= 0) {
+	print("usage: [-options] [dir-code] [listfile]");
+	print("options:");
+	print("-all            add files in all libraries/directories (implies -auto)");
+	print("-lib=<name>     add files in all directories of specified library (implies -auto)");
+	print("-from=<name>    specify uploader's user name (may require quotes)");
+	print("-ex=<filename>  add to excluded filename list");
+	print("                (default: " + default_excludes.join(',') + ")");
+	print("-diz            always extract/use description in archive");
+	print("-update         update existing file entries (default is to skip them)");
+	print("-date[=fmt]     include today's date in description");
+	print("-fdate[=fmt]    include file's date in description");
+	print("-adate[=fmt]    include newest archived file date in description");
+	print("                (fmt = optional strftime date/time format string)");
+	print("-v              increase verbosity of output");
+	print("-debug          enable debug output");
+	exit(0);
+}
+
+function datestr(t)
+{
+	if(date_fmt)
+		return strftime(date_fmt, t);
+	return system.datestr(t);
+}
+
+function archive_date(file)
+{
+	try {
+		var list = Archive(file).list();
+	} catch(e) {
+		return file_date(file);
+	}
+	var t = 0;
+	for(var i = 0; i < list.length; i++)
+		t = Math.max(list[i].time, t);
+	return t;
+}
+
+var uploader;
+var listfile;
+var date_fmt;
+var options = {};
+var exclude = [];
+var dir_list = [];
+var verbosity = 0;
+for(var i = 0; i < argc; i++) {
+	var arg = argv[i];
+	if(arg[0] == '-') {
+		if(arg.indexOf("-ex=") == 0) {
+			exclude.push(arg.slice(4).toUpperCase());
+			continue;
+		}
+		if(arg.indexOf("-lib=") == 0) {
+			var lib = arg.slice(5);
+			if(!file_area.lib[lib]) {
+				alert("Library not found: " + lib);
+				exit(1);
+			}
+			for(var j = 0; j < file_area.lib[lib].dir_list.length; j++)
+				dir_list.push(file_area.lib[lib].dir_list[j].code);
+			options.auto = true;
+			continue;
+		}
+		if(arg.indexOf("-from=") == 0) {
+			uploader = arg.slice(6);
+			continue;
+		}
+		if(arg.indexOf("-date=") == 0) {
+			date_fmt = arg.slice(6);
+			options.date = true;
+			continue;
+		}
+		if(arg.indexOf("-fdate=") == 0) {
+			date_fmt = arg.slice(7);
+			options.fdate = true;
+			continue;
+		}
+		if(arg.indexOf("-adate=") == 0) {
+			date_fmt = arg.slice(7);
+			options.adate = true;
+			continue;
+		}
+		if(arg == '-' || arg == '-all') {
+			for(var dir in file_area.dir)
+				dir_list.push(dir);
+			options.auto = true;
+			continue;
+		}
+		if(arg[1] == 'v') {
+			var j = 1;
+			while(arg[j++] == 'v')
+				verbosity++;
+			continue;
+		}
+		options[arg.slice(1)] = true;
+	} else {
+		if(!dir_list.length)
+			dir_list.push(arg);
+		else
+			listfile = arg;
+	}
+}
+
+if(exclude.length < 1)
+	exclude = default_excludes;
+if(listfile)
+	exclude.push(listfile.toUpperCase());
+
+if(!dir_list.length) {
+	var code;
+	while(!file_area.dir[code] && !js.terminated) {
+		for(var d in file_area.dir)
+			print(d);
+		code = prompt("Directory code");
+	}
+	dir_list.push(code);
+}
+
+var added = 0;
+var updated = 0;
+for(var d = 0; d < dir_list.length; d++) {
+	
+	var code = dir_list[d];
+	var dir = file_area.dir[code];
+	if(!dir) {
+		alert("Directory '" + code + "' does not exist in configuration");
+		continue;
+	}
+	if(options.auto && (dir.settings & DIR_NOAUTO))
+		continue;
+	print("Adding files to " + dir.lib_name + " " + dir.name);
+	
+	var filebase = new FileBase(code);
+	if(!filebase.open("r")) {
+		alert("Failed to open: " + filebase.file);
+		continue;
+	}
+
+	var name_list = filebase.get_names();
+	// Convert to uppercase
+	for(var i = 0; i < name_list.length; i++) {
+		name_list[i] = name_list[i].toUpperCase();
+		if(options.debug)
+			print(name_list[i]);
+	}
+	var file_list = [];
+
+	if(listfile) {
+		var listpath = file_getcase(dir.path + listfile) || file_getcase(listfile);
+		var f = new File(listpath);
+		if(f.exists) {
+			print("Opening " + f.name);
+			if(!f.open('r')) {
+				alert("Error " + f.error + " (" + strerror(f.error) + ") opening " + f.name);
+				exit(1);
+			}
+			file_list = parse_file_list(f.readAll());
+			f.close();
+		} else {
+			alert(dir.path + file_getname(listfile) + " does not exist");
+		}
+	}
+	else {
+		var list = directory(dir.path + '*');
+		for(var i = 0; i < list.length; i++) {
+			if(!file_isdir(list[i]))
+				file_list.push({ name: file_getname(list[i]) });
+		}
+	}
+	
+	for(var i = 0; i < file_list.length; i++) {
+		var file = file_list[i];
+		file.from = uploader;
+		if(options.debug)
+			print(JSON.stringify(file, null, 4));
+		else if(verbosity)
+			printf("%s ", file.name);
+		if(exclude.indexOf(file.name.toUpperCase()) >= 0) {
+			if(verbosity)
+				print("excluded (ignored)");
+			continue;
+		}
+		file.extdesc = lfexpand(file.extdesc);
+		if(verbosity > 1)
+			print(JSON.stringify(file));
+		var exists = name_list.indexOf(filebase.get_name(file.name).toUpperCase()) >= 0;
+		if(exists && !options.update) {
+			if(verbosity)
+				print("already added");
+			continue;
+		}
+		var path = file_area.dir[code].path + file.name;
+		if(!file_exists(path)) {
+			alert("does not exist: " + path);
+			continue;
+		}
+		if(options.date)
+			file.desc = datestr(time()) + " " + file.desc;
+		else if(options.fdate)
+			file.desc = datestr(file_date(path)) + " " + file.desc;
+		else if(options.adate)
+			file.desc = datestr(archive_date(path)) + " " + file.desc;
+		file.cost = file_size(path);
+		if(exists) {
+			var hash = filebase.hash(file.name);
+			if(hash) {
+				file.size = hash.size;
+				file.crc16 = hash.crc16;
+				file.crc32 = hash.crc32;
+				file.md5 = hash.md5;
+				file.sha1 = hash.sha1;
+			}
+			if(!filebase.update(file.name, file, options.diz)) {
+				alert("Error " + filebase.last_error + " updating " + file.name);
+			} else {
+				print("Updated " + file.name);
+				updated++;
+			}
+		} else {
+			// Add file here:
+			if(!filebase.add(file, options.diz)) {
+				alert("Error " + filebase.last_error + " adding " + file.name);
+			} else {
+				print("Added " + file.name);
+				added++;
+			}
+		}
+	}
+	
+	filebase.close();
+}
+print(added + " files added");
+if(updated)
+	print(updated + " files updated");
+
+// Parse a FILES.BBS (or similar) file listing file
+// Note: file descriptions must begin with an alphabetic character
+function parse_file_list(lines)
+{
+	var file_list = [];
+	for(var i = 0; i < lines.length; i++) {
+		var line = lines[i];
+		var match = line.match(/(^[\w]+[\w\-\!\#\.]*)\W+[^A-Za-z]*(.*)/);
+//		print('fname line match: ' + JSON.stringify(match));
+		if(match && match.length > 1) {
+			var file = { name: match[1], desc: match[2] };
+			if(file.desc && file.desc.length > LEN_FDESC)
+				file.extdesc = word_wrap(file.desc, 45);
+			file_list.push(file);
+			continue;
+		}
+		match = line.match(/\W+\|\s+(.*)/);
+		if(!match) {
+			if(verbosity)
+				alert("Ignoring line: " + line);
+			continue;
+		}
+//		print('match: ' + JSON.stringify(match));
+		if(match && match.length > 1 && file_list.length) {
+			var file = file_list[file_list.length - 1];
+			if(!file.extdesc)
+				file.extdesc = file.desc + "\n";
+			file.extdesc += match[1] + "\n";
+			var combined = file.desc + " " + match[1].trim();
+			if(combined.length <= LEN_FDESC)
+				file.desc = combined;
+		}
+	}
+	return file_list;
+}
diff --git a/exec/archive.js b/exec/archive.js
new file mode 100755
index 0000000000..f924821b2d
--- /dev/null
+++ b/exec/archive.js
@@ -0,0 +1,121 @@
+// Deal with archive files using Synchronet v3.19 Archive class
+
+// Install "Viewable File Types" using 'jsexec archive.js install'
+
+"use strict";
+
+var cmd = argv.shift();
+var fname = argv.shift();
+var verbose = false;
+var i = argv.indexOf('-v');
+if(i >= 0) {
+	verbose = true;
+	argv.splice(i, 1);
+}
+switch(cmd) {
+	case 'list':
+		list(fname, verbose);
+		break;
+	case 'json':
+		writeln(JSON.stringify(Archive(fname).list(verbose, argv[0]), null, 4));
+		break;
+	case 'create':
+		print(Archive(fname).create(directory(argv[0])) + " files archived");
+		break;
+	case 'extract':
+		var a = Archive(fname);
+		print(a.extract.apply(a, argv) + " files extracted");
+		break;
+	case 'read':
+		print(Archive(fname).read(argv[0]));
+		break;
+	case 'type':
+		print(Archive(fname).type);
+		break;
+	case 'install':
+		install();
+		break;
+	default:
+		throw new Error("invalid command: " + cmd);
+}
+
+function list(filename, verbose)
+{
+	var list;
+	try {
+		 list = Archive(filename).list(verbose);
+	} catch(e) {
+		alert(file_getname(filename) + ": Unsupported archive format");
+		return;
+	}
+	
+	var dir_fmt = "\x01n%s";
+	var file_fmt = "\x01n \x01c\x01h%-*s \x01n\x01c%10lu  ";
+	if(verbose)
+		file_fmt += "\x01h%08lX  ";
+	file_fmt += "\x01h\x01w%s";
+	if(!js.global.console) {
+		dir_fmt = strip_ctrl(dir_fmt);
+		file_fmt = strip_ctrl(file_fmt);
+	}
+	var longest_name = 0;
+	for(var i = 0; i < list.length; i++) {
+		longest_name = Math.max(longest_name, file_getname(list[i].name).length);
+	}
+	var curpath;
+	for(var i = 0; i < list.length && !js.terminated && (!js.global.console || !console.aborted); i++) {
+		if(list[i].type != "file")
+			continue;
+		else {
+			var fname = file_getname(list[i].name);
+			var path = list[i].name.slice(0, -fname.length);
+			if(path != curpath)
+				writeln(format(dir_fmt, path ? path : "[root]"));
+			if(verbose)
+				writeln(format(file_fmt
+					,longest_name, fname, list[i].size, list[i].crc32
+					,system.timestr(list[i].time).slice(4)));
+			else
+				writeln(format(file_fmt
+					,longest_name, fname, list[i].size
+					,system.timestr(list[i].time).slice(4)));
+			curpath = path;
+		}
+	}
+}
+
+function install()
+{
+	var viewable_exts = [
+		'7z',
+		'exe',
+		'bz',
+		'gz',
+		'iso',
+		'lha',
+		'lzh',
+		'tbz',
+		'tgz',
+		'rar',
+		'xar',
+		'zip'
+	];
+	
+	var cnflib = load({}, "cnflib.js");
+	var file_cnf = cnflib.read("file.cnf");
+	if(!file_cnf) {
+		alert("Failed to read file.cnf");
+		exit(-1);
+	}
+	for(var e in viewable_exts) {
+		file_cnf.fview.push({
+			extension: viewable_exts[e],
+			cmd: '?archive list %f'
+			});
+	}
+	if(!cnflib.write("file.cnf", undefined, file_cnf)) {
+		alert("Failed to write file.cnf");
+		exit(-1);
+	}
+	exit(0);
+}	
diff --git a/exec/default.src b/exec/default.src
index c8774ea630..455c9f08b9 100644
--- a/exec/default.src
+++ b/exec/default.src
@@ -746,7 +746,7 @@ cmdkey J
 	end_cmd
 
 cmdkey L
-	setstr *.*
+	setstr *
 	file_list
 	end_cmd
 
diff --git a/exec/filelist.js b/exec/filelist.js
new file mode 100755
index 0000000000..a1b17607b5
--- /dev/null
+++ b/exec/filelist.js
@@ -0,0 +1,142 @@
+// List files in a Synchronet v3.19 file base directory
+
+"use strict";
+
+var options = { sort: false};
+var detail = -1;
+var dir_list = [];
+var filespec = "";
+var props = [];
+var fmt;
+for(var i = 0; i < argc; i++) {
+	var arg = argv[i];
+	if(arg[0] == '-') {
+		var opt = arg.slice(1);
+		if(opt[0] == 'v') {
+			var j = 0;
+			while(opt[j++] == 'v')
+				detail++;
+			continue;
+		}
+		if(opt.indexOf("p=") == 0) {
+			props.push(opt.slice(2));
+			continue;
+		}
+		if(opt == "json") {
+			fmt = "json";
+			continue;
+		}
+		if(opt == "arc") {
+			fmt = "arc";
+			continue;
+		}
+		if(opt.indexOf("fmt=") == 0) {
+			fmt = opt.slice(4);
+			continue;
+		}
+		if(opt == "all") {
+			for(var dir in file_area.dir)
+				dir_list.push(dir);
+			continue;
+		}
+		options[opt] = true;
+		continue;
+	}
+	if(file_area.dir[arg])
+		dir_list.push(arg);
+	else
+		filespec = arg;
+}
+if(props.length < 1)
+	props = ["name", "size", "from", "desc", "extdesc"];
+if(!fmt) {
+	fmt = "%-13s %10s  %-25s  %s";
+	if(detail > 1)
+		fmt += "\n%s";
+}
+
+var output = [];
+for(var i in dir_list) {
+	var dir_code = dir_list[i];
+	var dir = file_area.dir[dir_code];
+	if(!dir) {
+		alert("dir not found: " + dir_code);
+		continue;
+	}
+	if(options.hdr) {
+		var hdr = format("%-15s %-40s Files: %d", dir.lib_name, dir.description, dir.files);
+		output.push(hdr);
+		output.push(format("%.*s", hdr.length
+			, "-------------------------------------------------------------------------------"));
+	}
+	output = output.concat(listfiles(dir_code, filespec, detail, fmt, props));
+}
+//if(options.sort)
+//	output.sort();
+for(var i in output)
+	print(output[i]);
+
+function archive_contents(path, list)
+{
+	var output = [];
+	for(var i = 0; i < list.length; i++) {
+		var fname = path + list[i];
+		print(fname);
+		output.push(fname);
+		var contents;
+		try {
+			contents = Archive(fname).list();
+		} catch(e) {
+//			alert(e);
+			continue;
+		}
+		for(var j = 0; j < contents.length; j++)
+			output.push(contents[j].name + " " + contents[j].size);
+	}
+	return output;
+}
+
+function listfiles(dir_code, filespec, detail, fmt, props)
+{
+	var base = new FileBase(dir_code);
+	if(!base.open())
+		return base.last_error;
+	var output = [];
+	if(detail < 0) {
+		var list = base.get_names(filespec, options.sort);
+		if(fmt == 'json')
+			output = JSON.stringify(list, null, 4).split('\n');
+		else if(fmt == 'arc')
+			output = archive_contents(file_area.dir[dir_code].path, list);
+		else
+			output = list;
+	} else {
+		var list = base.get_list(filespec, detail, options.sort);
+		if(fmt == 'json')
+			output.push(JSON.stringify(list, null, 4));
+		else {
+			for(var i = 0; i < list.length; i ++)
+				output.push(list_file(list[i], fmt, props));
+		}
+	}
+	base.close();
+	return output;
+}
+
+function list_file(file, fmt, props)
+{
+	if(typeof file == 'string') {
+		print(file);
+		return;
+	}
+	if(fmt === undefined)
+		fmt = "%s";
+	var a = [fmt];
+	for(var i in props) {
+		if(file[props[i]] === undefined)
+			a.push('');
+		else
+			a.push(file[props[i]]);
+	}
+	return format.apply(this, a);
+}
diff --git a/exec/hashfile.js b/exec/hashfile.js
new file mode 100755
index 0000000000..02100b6d8f
--- /dev/null
+++ b/exec/hashfile.js
@@ -0,0 +1,31 @@
+"use strict";
+
+if(argv.indexOf("-help") >= 0 || argv.indexOf("-?") >= 0) {
+	print("usage: [dir-code] [file-name]");
+	exit(0);
+}
+
+var code = argv[0];
+
+while(!file_area.dir[code] && !js.terminated) {
+	for(var d in file_area.dir)
+		print(d);
+	code = prompt("Directory code");
+}
+
+var dir = file_area.dir[code];
+
+var filebase = new FileBase(code);
+if(!filebase.open()) {
+	alert("Failed to open: " + filebase.file);
+	exit(1);
+}
+
+print(JSON.stringify(filebase.hash(argv[1]), null, 4));
+
+print(filebase.last_error);
+/*
+
+var name_list = filebase.get_file_names();
+
+*/
\ No newline at end of file
diff --git a/exec/jsdocs.js b/exec/jsdocs.js
index 8418667fa0..9a42d2976d 100644
--- a/exec/jsdocs.js
+++ b/exec/jsdocs.js
@@ -3,8 +3,6 @@
 // This script generates HTML documentation of the Synchronet JavaScript object model
 // Requires a Debug build of the Synchronet executable(s)
 
-// $Id: jsdocs.js,v 1.40 2020/04/20 06:31:15 rswindell Exp $
-
 const table_tag = "<table border=1 width=100%>";
 
 const li_tag =	"<li onclick = 'this.className = (this.className == \"showList\") ? \"defaultStyles\" : \"showList\";'\n" +
@@ -320,7 +318,9 @@ if(js.global.msg_area != undefined)		document_object("msg_area"	,msg_area);
 if(js.global.file_area != undefined)	document_object("file_area"	,file_area);
 if(js.global.xtrn_area != undefined)	document_object("xtrn_area"	,xtrn_area);
 if(js.global.MsgBase != undefined)		document_object("MsgBase"	,new MsgBase(msg_area.grp_list[0].sub_list[0].code), "class");
+if(js.global.FileBase != undefined)		document_object("FileBase"	,new FileBase(file_area.lib_list[0].dir_list[0].code), "class");
 if(js.global.File != undefined)			document_object("File"		,new File(system.devnull), "class");
+if(js.global.Archive != undefined)		document_object("Archive"	,new Archive(system.devnull), "class");
 if(js.global.Queue != undefined)		document_object("Queue"		,new Queue(), "class");
 if(js.global.Socket != undefined) {
 	var sock=new Socket();
diff --git a/exec/load/avatar_lib.js b/exec/load/avatar_lib.js
index 02d8ee57b4..d110dcd497 100644
--- a/exec/load/avatar_lib.js
+++ b/exec/load/avatar_lib.js
@@ -195,6 +195,8 @@ function read_netuser(username, netaddr)
 function read(usernum, username, netaddr, bbsid)
 {
 	var usernum = parseInt(usernum, 10);
+	if(!usernum && !username)
+		return false;
 	var obj = cache_get(usernum >= 1 ? usernum : username, netaddr);
 	if(obj !== undefined)	// null and false are also valid cached avatar values
 		return obj;
diff --git a/exec/load/fidocfg.js b/exec/load/fidocfg.js
index 48fea276f4..5542abbf3b 100644
--- a/exec/load/fidocfg.js
+++ b/exec/load/fidocfg.js
@@ -82,9 +82,7 @@ function TickITCfg(fname) {
 		var dir = file_area.dir[code];
 		if(auto_areas.indexOf(dir.lib_name) < 0)
 			continue;
-		if(dir.name.indexOf(' ') >= 0) // Invalid areatag
-			continue;
-		this.acfg[dir.name.toLowerCase()] = { dir: code };
+		this.acfg[dir.area_tag.toLowerCase()] = { dir: code };
 	}
 	sects = tcfg.iniGetSections();
 	for (i=0; i<sects.length; i++) {
diff --git a/exec/load/sbbslist_lib.js b/exec/load/sbbslist_lib.js
index 2be83a4130..390cf8e37b 100644
--- a/exec/load/sbbslist_lib.js
+++ b/exec/load/sbbslist_lib.js
@@ -13,7 +13,7 @@ var sort_property = 'name';
 
 // These max lengths are derived from the bbs_t structure definition in xtrn/sbl/sbldefs.h:
 const max_len = {
-	name:				25,		/* Synchronet allows 40, I think this restricted by 25-char QWK msg subjs in sbldefs.h */
+	name:				40,		/* Synchronet allows 40, I think this restricted by 25-char QWK msg subjs in sbldefs.h */
 	phone_number:		25,		/* only the first 12 chars are backwards compatible with SBL v3 */
 	location:			30,
 	sysop_name:			25,
@@ -658,11 +658,11 @@ function new_system(name, nodes, stats)
 function check_entry(bbs)
 {
 	if(!bbs.name || !bbs.name.length || bbs.name.length > max_len.name) {
-		log("Problem with BBS name: " + bbs.name);
+		log(LOG_WARNING, "Problem with BBS name: " + bbs.name);
 		return false;
 	}
 	if(!bbs.service || !bbs.service.length) {
-		log(bbs.name + " has no services");
+		log(LOG_WARNING, bbs.name + " has no services");
 		return false;
 	}
 /** this is valid in SBL
@@ -672,7 +672,7 @@ function check_entry(bbs)
 	}
 **/
 	if(!bbs.entry || !bbs.entry.created || !bbs.entry.created.by) {
-		log(bbs.name + " has no entry.created.by property");
+		log(LOG_WARNING, bbs.name + " has no entry.created.by property");
 		return false;
 	}
 	return true;	// All is good
diff --git a/exec/load/text.js b/exec/load/text.js
index c88269c30e..b923fac29b 100644
--- a/exec/load/text.js
+++ b/exec/load/text.js
@@ -266,7 +266,7 @@ var EditUploader=256;
 var EditCreditValue=257;
 var EditTimesDownloaded=258;
 var EditOpenCount=259;
-var EditAltPath=260;
+var Unused260=260;
 var YouOnlyHaveNCredits=261;
 var NotEnoughCredits=262;
 var NotEnoughTimeToDl=263;
@@ -303,12 +303,12 @@ var TempFileNotCreatedYet=293;
 var TempFileInfo=294;
 var TempDirTotal=295;
 var NFilesRemoved=296;
-var ResortWarning=297;
-var ResortLineFmt=298;
-var ResortEmptyDir=299;
-var Sorting=300;
-var Sorted=301;
-var Compressed=302;
+var TagFileQ=297;
+var TagFilePrompt=298;
+var Unused299=299;
+var Unused300=300;
+var Unused301=301;
+var Unused302=302;
 var FileAlreadyInQueue=303;
 var FileIsNotOnline=304;
 var FileAddedToBatDlQueue=305;
@@ -332,9 +332,9 @@ var FiDateUled=322;
 var FiDateDled=323;
 var FiTimesDled=324;
 var FiTransferTime=325;
-var FiAlternatePath=326;
-var InvalidAlternatePathN=327;
-var FileIsOpen=328;
+var FiTags=326;
+var Unused327=327;
+var FiChecksum=328;
 var HappyBirthday=329;
 var TimeToChangePw=330;
 var NewPasswordQ=331;
@@ -601,7 +601,7 @@ var Convert100ktoNminQ=591;
 var CreditedAccount=592;
 var ANSICaptureIsNow=593;
 var RetrievingFile=594;
-var AltULPathIsNow=595;
+var Unused595=595;
 var PrivatePostQ=596;
 var PostTo=597;
 var NoToUser=598;
diff --git a/exec/pcboard.src b/exec/pcboard.src
index d360f3ed65..5bcc3448c9 100644
--- a/exec/pcboard.src
+++ b/exec/pcboard.src
@@ -46,7 +46,7 @@ cmdstr HELP
 cmdstr F
 	file_select_area
 	if_true
-		setstr "*.*"
+		setstr "*"
 		file_list
 		end_if
 	end_cmd
@@ -54,7 +54,7 @@ cmdstr F
 cmdstr EXT
 	file_select_area
 	if_true
-		setstr "*.*"
+		setstr "*"
 		file_list_extended
 		end_if
 	end_cmd
diff --git a/exec/postfile.js b/exec/postfile.js
new file mode 100755
index 0000000000..fafed63132
--- /dev/null
+++ b/exec/postfile.js
@@ -0,0 +1,57 @@
+"use strict";
+
+if(argv.indexOf("-help") >= 0 || argv.indexOf("-?") >= 0) {
+	print("usage: [dir-code] [file-name] [file-description] [uploader-name]");
+	exit(0);
+}
+
+var code = argv[0];
+var file = { name: argv[1], desc: argv[2], from: argv[3] };
+
+while(!file_area.dir[code] && !js.terminated) {
+	for(var d in file_area.dir)
+		print(d);
+	code = prompt("Directory code");
+}
+
+var dir = file_area.dir[code];
+
+var filebase = new FileBase(code);
+if(!filebase.open()) {
+	alert("Failed to open: " + filebase.file);
+	exit(1);
+}
+
+var name_list = filebase.get_names();
+
+while(!file_exists(dir.path + file.name) && !js.terminated) {
+	if(file.name)
+		alert(dir.path + file.name + " does not exist");
+	var list = directory(dir.path + '*');
+	for(var i = 0; i < list.length; i++) {
+		if(!file_isdir(list[i]) && name_list.indexOf(file_getname(list[i])) < 0)
+			print(file_getname(list[i]));
+	}
+	file.name = prompt("File name");
+}
+
+if(filebase.get(file.name)) {
+	alert("File '" + file.name + "' already added.");
+	exit(1);
+}
+
+while(!file.desc && !js.terminated) {
+	file.desc = prompt("Description");
+}
+
+while(!file.from && !js.terminated) {
+	file.from = prompt("Uploader");
+}
+
+print("Adding " + file.name + " to " + filebase.file);
+if(filebase.add(file))
+	print(format("File (%s) added successfully to: ", file.name) + code);
+else
+	alert("Error " + filebase.last_error + " adding file to: " + code);
+filebase.close();
+
diff --git a/exec/rehashfiles.js b/exec/rehashfiles.js
new file mode 100755
index 0000000000..19347183f6
--- /dev/null
+++ b/exec/rehashfiles.js
@@ -0,0 +1,42 @@
+"use strict";
+
+if(argv.indexOf("-help") >= 0 || argv.indexOf("-?") >= 0) {
+	print("usage: [dir-code] [file-name]");
+	exit(0);
+}
+
+var code = argv[0];
+
+while(!file_area.dir[code] && !js.terminated) {
+	for(var d in file_area.dir)
+		print(d);
+	code = prompt("Directory code");
+}
+
+var dir = file_area.dir[code];
+
+var filebase = new FileBase(code);
+if(!filebase.open()) {
+	alert("Failed to open: " + filebase.file);
+	exit(1);
+}
+
+var file_list = filebase.get_list();
+for(var i = 0; i < file_list.length; i++) {
+	var file = file_list[i];
+	print(JSON.stringify(file, null, 4));
+	var hash = filebase.hash(file.name);
+	if(hash == null) {
+		alert("hash is null");
+		break;
+	}
+	file.size = hash.size;
+	file.crc16 = hash.crc16;
+	file.crc32 = hash.crc32;
+	file.md5 = hash.md5;
+	file.sha1 = hash.sha1;
+	if(!filebase.update(file.name, file)) {
+		alert(filebase.status + " " + filebase.last_error);
+		break;
+	}
+}
diff --git a/exec/sbbslist.js b/exec/sbbslist.js
index 8ed1088639..7c107c5ea0 100644
--- a/exec/sbbslist.js
+++ b/exec/sbbslist.js
@@ -267,7 +267,7 @@ function import_entry(name, text)
         if(debug) print(match[1] + " = " + match[2]);
         switch(match[1].toLowerCase()) {
             case 'birth':
-		if(match[2] && match[2].length)
+				if(match[2] && match[2].length)
                 	bbs.first_online = date_from_str(match[2]);
                 break;
             case 'software':
@@ -432,17 +432,17 @@ function import_from_msgbase(list, msgbase, import_ptr, limit, all)
             if(!list[l].entry)
                 continue;
             if(!list[l].imported && hdr.from_net_type) {
-                print(msg_from + " attempted to update/over-write local entry: " + bbs_name);
+                alert(msg_from + " attempted to update/over-write local entry: " + bbs_name);
                 continue;
             }
 			entry = list[l].entry;
             if(entry.created.by.toLowerCase() != hdr.from.toLowerCase()
 				|| (entry.created.at && entry.created.at != hdr.from_net_addr)) {
-                print(msg_from  + " did not create entry: " 
+                alert(msg_from  + " did not create entry: "
 					+ bbs_name + " (" + entry.created.by + "@" + entry.created.at + " did)");
                 continue;
             }
-            print((sbl_remove ? "Removing" : "Updating") 
+            print((sbl_remove ? "Removing" : "Updating")
 				+ " existing entry: " + bbs_name + " (by " + entry.created.by + ")");
 			if(sbl_remove) {
 				if(!lib.remove(entry))
@@ -1606,7 +1606,7 @@ function view(list, current)
 		printf("\1n  ");
 		printf(fmt, "Name\1w", lib.max_len.name, lib.max_len.name, bbs.name);
 		if(bbs.first_online)
-			printf("\1n\1c since \1h%s", bbs.first_online.substring(0,10));
+			printf("\1n\1c est \1h%s", bbs.first_online.substring(0,10));
 		if(bbs.software) {
 			console.attributes = LIGHTGRAY;
 			right_justify(bbs.software);
@@ -2697,4 +2697,4 @@ function main()
 	return 0;
 }
 
-exit(main());
\ No newline at end of file
+exit(main());
diff --git a/exec/simple.src b/exec/simple.src
index 00a47bda77..442c136325 100644
--- a/exec/simple.src
+++ b/exec/simple.src
@@ -219,7 +219,7 @@ cmdstr F
 		if_false
 			end_cmd
 			end_if
-		setstr "*.*"
+		setstr "*"
 		file_list
 		end_cmd
 
diff --git a/exec/tickit.js b/exec/tickit.js
index 5be4986870..c3d84258e0 100644
--- a/exec/tickit.js
+++ b/exec/tickit.js
@@ -1,6 +1,5 @@
 /*
  * An intentionally simple TIC handler for Synchronet.
- * $Id: tickit.js,v 1.56 2020/05/16 20:11:37 rswindell Exp $
  *
  * How to set up... add a timed event:
  * Internal Code                   TICKIT
@@ -23,11 +22,13 @@
  * flag /sbbs/data/tickit.now *.tic *.TIC
  */
 
-load("sbbsdefs.js");
+require("sbbsdefs.js", 'LEN_FDESC');
 require("fidocfg.js", 'TickITCfg');
 require("fido.js", 'FIDO');
 
 var cfgfile;
+var force_replace = false;
+var use_diz_always = true;
 
 for (var i in argv) {
 	if(argv[i] == "-force-replace")
@@ -37,11 +38,13 @@ for (var i in argv) {
 }
 
 var tickit = new TickITCfg(cfgfile);
+if(tickit.gcfg.forcereplace === true)
+	force_replace = true;
 var sbbsecho = new SBBSEchoCfg(tickit.gcfg.echocfg);
-var files_bbs={};
-var force_replace = false;
+var file_list = {};
+var files_imported = 0;
 
-const REVISION = "$Revision: 1.56 $".split(' ')[1];
+const REVISION = "2.0";
 
 var tickitVersion = "TickIT "+REVISION;
 // emit tickitVersion to the log for general purposes - wk42
@@ -49,9 +52,6 @@ log(LOG_INFO, tickitVersion);
 // emit system.temp_dir to the log for debug purposes; mainly with which
 // temp directory is used when tickit.js is executed (event vs jsexec) - wk42
 log(LOG_DEBUG, "Using system.temp_dir = '"+system.temp_dir+"'");
-// also let's log the logs_dir so we know where it is for the addfiles
-// log if addfileslogcap is set in the ini... this is a manual setting - wk42
-log(LOG_DEBUG, "Using system.logs_dir = '"+system.logs_dir+"'");
 
 if (!String.prototype.repeat) {
   String.prototype.repeat = function(count) {
@@ -116,7 +116,6 @@ function process_tic(tic)
 	var handler;
 	var handler_arg;
 
-	log(LOG_INFO, "Processing...");
 	log(LOG_INFO, "Working with '"+tic.file+"' in '"+tic.area.toUpperCase()+"'.");
 
 	if (tickit.gcfg.path !== undefined)
@@ -144,9 +143,9 @@ function process_tic(tic)
 			handler = cfg.handler;
 			handler_arg = cfg.handlerarg;
 		}
-		if (cfg.forcereplace !== undefined) {
+		if (cfg.forcereplace === true) {
 			log(LOG_INFO, "ForceReplace enabled for area "+tic.area.toUpperCase()+".");
-			force_replace_area = cfg.forcereplace;
+			force_replace_area = true;
 		}
 	}
 
@@ -216,16 +215,11 @@ function process_tic(tic)
 	}
 
 	if (dir !== undefined) {
-		if (files_bbs[dir] === undefined)
-			files_bbs[dir] = '';
-
-		files_bbs[dir] += format("%-12s %10s ", tic.file, tic.size);
-		ld = tic.ldesc.split(/\r?\n/);
-		for (i=0; i<ld.length; i++) {
-			if (i)
-				files_bbs[dir] += " ".repeat(24);
-			files_bbs[dir] += ld[i]+"\r\n";
-		}
+		if (file_list[dir] === undefined)
+			file_list[dir] = [];
+		file = { name: tic.file, cost: tic.size, desc: tic.desc, extdesc: tic.ldesc };
+		file_list[dir].push(file);
+//		log(LOG_INFO, JSON.stringify(file));
 	}
 	log(LOG_INFO, "Deleting TIC file '"+tic.tic_filename+"'.");
 	file_remove(tic.tic_filename);
@@ -548,6 +542,11 @@ function parse_ticfile(fname)
 
 			if (key !== 'desc' && key !== 'ldesc')
 				key = key.replace(/^\s*/,'');
+			if (key == 'desc' && tic.desc) {
+				if (!tic.ldesc)
+					tic.ldesc = tic.desc;
+				key = 'ldesc';
+			}
 			switch(key) {
 				// These are not passed unmodified.
 				// Single value, single line...
@@ -564,7 +563,7 @@ function parse_ticfile(fname)
 				case 'path':
 					// log the path lines for informational purposes before we apply
 					// the circular path detection. - wk42
-					log(LOG_INFO, "Path "+val);
+					log(LOG_DEBUG, "Path "+val);
 					// Circular path detection...
 					for (i=0; i<system.fido_addr_list.length; i++) {
 						if (val === system.fido_addr_list[i]) {
@@ -582,7 +581,7 @@ function parse_ticfile(fname)
 					// we'll log this one for informational purposes and throw it
 					// away so we can create our own later in forward_tic() with our
 					// tickit.js revision line. - wk42
-					log(LOG_INFO, "Created "+val);
+					log(LOG_DEBUG, "Created "+val);
 					break;
 
 				// All the rest are passed through unmodified
@@ -597,6 +596,7 @@ function parse_ticfile(fname)
 				case 'magic':
 				case 'replaces':
 				case 'crc':
+				case 'desc':
 					outtic.push(line);
 					tic[key] = val;
 					break;
@@ -607,7 +607,6 @@ function parse_ticfile(fname)
 					break;
 
 				// Multi-line values
-				case 'desc':
 				case 'ldesc':
 					outtic.push(line);
 					if (tic[key] === undefined)
@@ -622,10 +621,11 @@ function parse_ticfile(fname)
 			}
 		}
 	}
-
-	if (tic.ldesc === undefined || tic.ldesc.length <= tic.desc.length)
-		tic.ldesc = tic.desc;
-
+	if (tic.desc !== undefined) {
+		if(tic.desc.length > LEN_FDESC && !tic.ldesc)
+			tic.ldesc = tic.desc.replace("  ", "\r\n");
+		tic.desc = format("%.*s", LEN_FDESC, tic.desc.trim());
+	}
 	f.close();
 	f = new File(dir+tic.file);
 	if (!f.exists) {
@@ -637,6 +637,7 @@ function parse_ticfile(fname)
 		log(LOG_WARNING, "File '"+f.name+"' length mismatch. File is "+f.length+", expected "+tic.size+".");
 		return false;
 	}
+	tic.size = f.length;
 	if (tic.crc !== undefined) {
 		// File needs to be open to calculate the CRC32.
 		if (!f.open("rb")) {
@@ -656,10 +657,10 @@ function parse_ticfile(fname)
 	else {
 		// there may or may not be @domain on the from line in the
 		// TIC file. look for both address forms. - wk42
-		log(LOG_INFO, "Verifying password for sender: "+tic.from);
+		log(LOG_DEBUG, "Verifying password for sender: "+tic.from);
 		if (!sbbsecho.match_ticpw(tic.from, tic.pw)) {
 			var alink = FIDO.parse_addr(tic.from).toString();
-			log(LOG_INFO, "Verifying password with domain this time: "+alink);
+			log(LOG_DEBUG, "Verifying password with domain this time: "+alink);
 			if (!sbbsecho.match_ticpw(alink, tic.pw)) {
 				// if we get here and there is no match, then we have
 				// defined the wrong password somewhere... - wk42
@@ -677,62 +678,53 @@ function parse_ticfile(fname)
 	return tic;
 }
 
+function import_file_list(dir, list, uploader)
+{
+	log(LOG_INFO, "Importing file list into: " + dir);
+	var fb = new FileBase(dir);
+	if(!fb.open())
+		return "Error " + fb.last_error + " opening filebase: " + dir;
+	for(var i = 0; i < list.length; i++) {
+		var file = list[i];
+		file.from = uploader;
+		log(LOG_INFO, "Adding file (" + file.name + ") to: " + dir);
+		if(!fb.add(file, use_diz_always)) {
+			fb.close();
+			return "Error " + fb.last_error + " adding file to: " + dir;
+		} else
+			files_imported++;
+	}
+	fb.close();
+	return true;
+}
+
 // need the tic for some more processing
 function import_files(tic)
 {
 	log(LOG_INFO, "Importing...");
 	var i;
 	var cmd;
-	var f=new File(system.temp_dir+"tickit-files.bbs");
 
-	for (i in files_bbs) {
+	for (i in file_list) {
 		if (file_area.dir[i] === undefined) {
 			log(LOG_ERROR, "Invalid directory "+i+" when importing!");
 			continue;
 		}
 
-		if (!f.open("wb")) {
-			log(LOG_ERROR, "Unable to create '"+f.name+"'.");
-			return false;
-		}
-		f.write(files_bbs[i]);
-		f.close();
-
 		// figure out the uploader name if there is an override in place
 		// globally or per area. - wk42
 		var uploader = "";
 		var cfg = tickit.acfg[tic.area.toLowerCase()];
 		if (cfg !== undefined && cfg.uploader !== undefined) {
 			uploader = cfg.uploader.toString();
-			log(LOG_INFO, "Using '"+tic.area.toUpperCase()+"' area uploader: "+uploader);
+			log(LOG_DEBUG, "Using '"+tic.area.toUpperCase()+"' area uploader: "+uploader);
 		} else if (tickit.gcfg.uploader !== undefined) {
 			uploader = tickit.gcfg.uploader.toString();
-			log(LOG_INFO, "Using global uploader: "+uploader);
-		}
-		cmd = system.exec_dir+"addfiles "+i;
-		if (uploader !== undefined && uploader !== "")
-			cmd += ' -x "' + uploader + '"';
-		cmd += " -zd +"+f.name+" 24 13";
-		if (tickit.gcfg.addfileslogcap) {
-			// catch addfiles output only if global AddFilesLogCap is
-			// enabled. this is so we can try to determine what causes
-			// addfiles to abort early and not import some files for
-			// some reason. we're going to write this to the
-			// system.logs_dir because system.temp_dir is cleaned
-			// regularly and indiscriminately - wk42
-			if (system.platform === 'Win32')
-				cmd += " 1>>" + system.logs_dir + "addfiles.log 2>&1";
-			else
-				cmd += " >>" + system.logs_dir + "addfiles.log 2>&1";
+			log(LOG_DEBUG, "Using global uploader: "+uploader);
 		}
-		log(LOG_INFO, "Executing: '"+cmd+"'.");
-		log(LOG_INFO, "addfiles returned: "+system.exec(cmd));
+		import_file_list(i, file_list[i], uploader);
 	}
-	// clear the files_bbs array since we're now importing the files one
-	// file at a time as they are processed. this is a quick hack to
-	// enable per area uploader names and i didn't take the time to try
-	// to refactor this properly. it works for now - wk42
-	files_bbs = {};
+	file_list = {};
 }
 
 function main() {
@@ -811,6 +803,8 @@ function main() {
 			}
 		}
 	}
+	if(files_imported > 0)
+		log(LOG_INFO, files_imported + " files imported successfully");
 }
 
 main();
diff --git a/exec/update.js b/exec/update.js
index 5c219aec19..da49be72b6 100644
--- a/exec/update.js
+++ b/exec/update.js
@@ -1,8 +1,6 @@
-/* $Id: update.js,v 1.10 2020/05/05 01:09:27 rswindell Exp $ */
+/* Synchronet v3.15+ update script (to be executed with jsexec) */
 
-/* Synchronet v3.15 update script (to be executed with jsexec) */
-
-const REVISION = "$Revision: 1.10 $".split(' ')[1];
+const REVISION = "2.0";
 
 var test = argv.indexOf("-test") >= 0;
 
@@ -150,7 +148,7 @@ function update_gfile_indexes()
 	return count;
 }
 
-printf("Synchronet update.js revision %u\n", REVISION);
+printf("Synchronet update.js revision %s\n", REVISION);
 printf("Updating exec directory: ");
 printf("%s\n", update_exec_dir() ? "Success" : "FAILURE");
 printf("Updating users ip_address field: ");
@@ -207,4 +205,20 @@ for(var i in src_files) {
 	print("Building " + bin);
 	if(!test)
 		system.exec(system.exec_dir + "baja " + src_files[i]);
-}
\ No newline at end of file
+}
+
+print("Checking for v3.19 file bases");
+var upgraded = true;
+for(var d in file_area.dir) {
+	upgraded = false;
+	dir_idx = directory(file_area.dir[d].data_dir + "*.sid");
+	if(dir_idx && dir_idx.length) {
+		upgraded = true;
+		break;
+	}
+}
+if(!upgraded) {
+	var cmdline = system.exec_dir + "upgrade_to_v319";
+	print("No v3.19 file bases found, running " + cmdline);
+	system.exec(cmdline);
+}
diff --git a/exec/updatefiles.js b/exec/updatefiles.js
new file mode 100755
index 0000000000..4eb370ec38
--- /dev/null
+++ b/exec/updatefiles.js
@@ -0,0 +1,25 @@
+if(argc < 1) {
+	alert("No directory code specfiied");
+	exit(0);
+}
+var fbase = new FileBase(argv[0]);
+if(!fbase.open()) {
+	alert("failed to open base");
+	exit(1);
+}
+var file_list = fbase.get_list(argv[1] || "*", FileBase.DETAIL.NORM);
+for(var i in file_list) {
+	var file = file_list[i];
+	var copy = JSON.parse(JSON.stringify(file));
+	for(var p in file) {
+		var str = prompt(p + " [" + file[p] + "]");
+		if(str)
+			file[p] = str;
+	}
+	if(JSON.stringify(copy) != JSON.stringify(file)) {
+		alert("changed");
+		print(fbase.update(copy.name, file));
+		print(fbase.status);
+		print(fbase.last_error);
+	}
+}
diff --git a/exec/wildcat.src b/exec/wildcat.src
index 9a9df8698c..80d1c0bc17 100644
--- a/exec/wildcat.src
+++ b/exec/wildcat.src
@@ -208,7 +208,7 @@ cmdkey Q
 	end_cmd
 
 cmdkey L
-	setstr "*.*"
+	setstr "*"
 	file_list
         end_cmd
 
diff --git a/src/hash/crc16.c b/src/hash/crc16.c
index 42f848d782..c95801d125 100644
--- a/src/hash/crc16.c
+++ b/src/hash/crc16.c
@@ -1,44 +1,28 @@
-/* crc16.c */
-
 /* CCITT 16-bit CRC table and calculation function */
 
-/* $Id: crc16.c,v 1.8 2018/07/24 01:12:53 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
  * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
  *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
+ * This library is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU Lesser General Public License		*
  * as published by the Free Software Foundation; either version 2			*
  * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
+ * See the GNU Lesser General Public License for more details: lgpl.txt or	*
+ * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include <string.h>	/* strlen */
 #include "crc16.h"
 
-CRCEXPORT uint16_t crc16tbl[] = {
+uint16_t crc16tbl[] = {
 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
@@ -73,16 +57,25 @@ CRCEXPORT uint16_t crc16tbl[] = {
 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
 };
 
-uint16_t CRCCALL crc16(const char* data, unsigned long len)
+uint16_t crc16(const char* data, size_t len)
 {
 	uint16_t crc = 0;
-	unsigned long l;
+	size_t l;
 
 	if(len==0 && data!=NULL)
 		len=strlen(data);
 	for(l=0;l<len;l++)
 		crc = ucrc16(data[l],crc);
  
-    return(crc);
+    return crc;
 }
 
+uint16_t icrc16(uint16_t crc, const char* data, size_t len)
+{
+	size_t l;
+
+	for(l=0; l<len; l++)
+		crc = ucrc16(data[l], crc);
+ 
+    return crc;
+}
diff --git a/src/hash/crc16.h b/src/hash/crc16.h
index 0093aa1d5d..bca8a90eb7 100644
--- a/src/hash/crc16.h
+++ b/src/hash/crc16.h
@@ -1,37 +1,21 @@
-/* crc16.h */
-
 /* CCITT 16-bit CRC table and calculation macro */
 
-/* $Id: crc16.h,v 1.7 2018/07/24 01:12:53 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
  * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
  *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
+ * This library is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU Lesser General Public License		*
  * as published by the Free Software Foundation; either version 2			*
  * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
+ * See the GNU Lesser General Public License for more details: lgpl.txt or	*
+ * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -39,15 +23,15 @@
 #define _CRC16_H_
 
 #include "gen_defs.h"
-#include "crc32.h"	/* CRCEXPORT/CRCCALL */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-CRCEXPORT extern uint16_t crc16tbl[];
+extern uint16_t crc16tbl[];
 
-CRCEXPORT uint16_t CRCCALL crc16(const char* data, unsigned long len);
+uint16_t crc16(const char* data, size_t len);
+uint16_t icrc16(uint16_t crc, const char* data, size_t len);
 
 #ifdef __cplusplus
 }
diff --git a/src/hash/crc32.c b/src/hash/crc32.c
index 42a7120543..2ad0843043 100644
--- a/src/hash/crc32.c
+++ b/src/hash/crc32.c
@@ -1,44 +1,28 @@
-/* crc32.c */
-
 /* IEEE 802.3 32-bit CRC table and convenience functions */
 
-/* $Id: crc32.c,v 1.12 2018/07/24 01:12:53 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
  * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
  *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
+ * This library is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU Lesser General Public License		*
  * as published by the Free Software Foundation; either version 2			*
  * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
+ * See the GNU Lesser General Public License for more details: lgpl.txt or	*
+ * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include <string.h>	/* strlen */
 #include "crc32.h"
 
-CRCEXPORT int32_t crc32tbl[]={	/* CRC polynomial 0xedb88320 */
+int32_t crc32tbl[]={	/* CRC polynomial 0xedb88320 */
 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
@@ -78,22 +62,22 @@ CRCEXPORT int32_t crc32tbl[]={	/* CRC polynomial 0xedb88320 */
 /* Pass len of 0 to auto-determine ASCIIZ string length						*/
 /* or non-zero for arbitrary binary data									*/
 /****************************************************************************/
-uint32_t CRCCALL crc32i(uint32_t crc, const char *buf, unsigned long len)
+uint32_t crc32i(uint32_t crc, const char *buf, size_t len)
 {
-	unsigned long l;
+	size_t l;
 
 	if(len==0 && buf!=NULL) 
 		len=strlen(buf);
 	for(l=0;l<len;l++)
 		crc=ucrc32(buf[l],crc);
-	return(~crc);
+	return ~crc;
 }
 
-uint32_t CRCCALL fcrc32(FILE* fp, unsigned long len)
+uint32_t fcrc32(FILE* fp, size_t len)
 {
 	int	ch;
 	uint32_t crc=0xffffffff;
-	unsigned long l;
+	size_t l;
 
 	rewind(fp);
 	for(l=0;(len==0 || l<len) && !feof(fp);l++) {
@@ -101,7 +85,5 @@ uint32_t CRCCALL fcrc32(FILE* fp, unsigned long len)
 			break;
 		crc=ucrc32(ch,crc);
 	}
-	return(~crc);
+	return ~crc;
 }
-
-
diff --git a/src/hash/crc32.h b/src/hash/crc32.h
index 9c6644db56..b7b7ba49f6 100644
--- a/src/hash/crc32.h
+++ b/src/hash/crc32.h
@@ -1,37 +1,21 @@
-/* crc32.h */
-
 /* 32-bit CRC table and calculation macro */
 
-/* $Id: crc32.h,v 1.18 2019/03/22 21:29:12 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
  * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
  *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
+ * This library is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU Lesser General Public License		*
  * as published by the Free Software Foundation; either version 2			*
  * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
+ * See the GNU Lesser General Public License for more details: lgpl.txt or	*
+ * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -41,30 +25,14 @@
 #include <stdio.h>	/* FILE */
 #include "gen_defs.h"	/* uint32_t */
 
-#if defined(_WIN32) && (defined(CRC_IMPORTS) || defined(CRC_EXPORTS))
-	#if defined(CRC_IMPORTS)
-		#define CRCEXPORT	__declspec(dllimport)
-	#else
-		#define CRCEXPORT	__declspec(dllexport)
-	#endif
-	#if defined(__BORLANDC__)
-		#define CRCCALL
-	#else
-		#define CRCCALL
-	#endif
-#else	/* !_WIN32 */
-	#define CRCEXPORT
-	#define CRCCALL
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-CRCEXPORT extern int32_t crc32tbl[];
+extern int32_t crc32tbl[];
 
-CRCEXPORT uint32_t CRCCALL crc32i(uint32_t crc, const char* buf, unsigned long len);
-CRCEXPORT uint32_t CRCCALL fcrc32(FILE* fp, unsigned long len);
+uint32_t crc32i(uint32_t crc, const char* buf, size_t);
+uint32_t fcrc32(FILE* fp, size_t);
 
 #ifdef __cplusplus
 }
diff --git a/src/hash/md5.c b/src/hash/md5.c
index 4359836fa9..107ce8a849 100644
--- a/src/hash/md5.c
+++ b/src/hash/md5.c
@@ -34,7 +34,7 @@ documentation and/or software.
 	#define LITTLE_ENDIAN	/* Little Endian by default */
 #endif
 
-void MD5CALL MD5_open(MD5 *md5)
+void MD5_open(MD5 *md5)
 {
   md5->count[0] = md5->count[1] = 0;
   /* Load magic initialization constants.*/
@@ -194,7 +194,7 @@ static void MD5Transform(uint32_t state[4], const BYTE block[64])
   memset(x, 0, sizeof(x));
 }
 
-void MD5CALL MD5_digest(MD5 *md5, const void *input, size_t inputLen)
+void MD5_digest(MD5 *md5, const void *input, size_t inputLen)
 {
   unsigned int i, index, partLen;
   /* Compute number of bytes mod 64 */
@@ -229,7 +229,7 @@ void MD5CALL MD5_digest(MD5 *md5, const void *input, size_t inputLen)
 #define ENCODE(p,n) (p)[0]=n,(p)[1]=n>>8,(p)[2]=n>>16,(p)[3]=n>>24
 #endif
 
-void MD5CALL MD5_close(MD5 *md5, BYTE digest[MD5_DIGEST_SIZE])
+void MD5_close(MD5 *md5, BYTE digest[MD5_DIGEST_SIZE])
 {
   BYTE bits[8];
   unsigned int index, padLen;
@@ -257,7 +257,7 @@ void MD5CALL MD5_close(MD5 *md5, BYTE digest[MD5_DIGEST_SIZE])
   memset(md5, 0, sizeof(MD5));
 }
 
-BYTE* MD5CALL MD5_calc(BYTE digest[MD5_DIGEST_SIZE], const void* buf, size_t len)
+BYTE* MD5_calc(BYTE digest[MD5_DIGEST_SIZE], const void* buf, size_t len)
 {
 	MD5 ctx;
 
@@ -270,20 +270,20 @@ BYTE* MD5CALL MD5_calc(BYTE digest[MD5_DIGEST_SIZE], const void* buf, size_t len
 
 /* conversion for 16 character binary md5 to hex */
 
-BYTE* MD5CALL MD5_hex(BYTE* to, const BYTE digest[MD5_DIGEST_SIZE])
+char* MD5_hex(char* to, const BYTE digest[MD5_DIGEST_SIZE])
 {
 	BYTE const* from = digest;
-    static char *hexdigits = "0123456789abcdef";
-    const BYTE *end = digest + MD5_DIGEST_SIZE;
-    char *d = (char *)to;
+	const char *hexdigits = "0123456789abcdef";
+	const BYTE *end = digest + MD5_DIGEST_SIZE;
+	char *d = to;
 
-    while (from < end) {
+	while (from < end) {
 		*d++ = hexdigits[(*from >> 4)];
 		*d++ = hexdigits[(*from & 0x0F)];
 		from++;
-    }
-    *d = '\0';
-    return to;
+	}
+	*d = '\0';
+	return to;
 }
 
 #ifdef MD5_TEST
diff --git a/src/hash/md5.h b/src/hash/md5.h
index 2274979df9..c23a4a1254 100644
--- a/src/hash/md5.h
+++ b/src/hash/md5.h
@@ -54,26 +54,19 @@ typedef struct
 	#else
 		#define MD5EXPORT	__declspec(dllexport)
 	#endif
-	#if defined(__BORLANDC__)
-		#define MD5CALL
-	#else
-		#define MD5CALL
-	#endif
 #else	/* !_WIN32 */
 	#define MD5EXPORT
-	#define MD5CALL
 #endif
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-MD5EXPORT void	MD5CALL MD5_open(MD5* ctx);
-MD5EXPORT void	MD5CALL MD5_digest(MD5* ctx, const void* buf, size_t len);
-MD5EXPORT void	MD5CALL MD5_close(MD5* ctx, BYTE digest[MD5_DIGEST_SIZE]);
-MD5EXPORT BYTE*	MD5CALL MD5_calc(BYTE digest[MD5_DIGEST_SIZE], const void* buf, size_t len);
-MD5EXPORT BYTE*	MD5CALL MD5_hex(BYTE* dest, const BYTE digest[MD5_DIGEST_SIZE]);
+MD5EXPORT void	MD5_open(MD5* ctx);
+MD5EXPORT void	MD5_digest(MD5* ctx, const void* buf, size_t len);
+MD5EXPORT void	MD5_close(MD5* ctx, BYTE digest[MD5_DIGEST_SIZE]);
+MD5EXPORT BYTE*	MD5_calc(BYTE digest[MD5_DIGEST_SIZE], const void* buf, size_t len);
+MD5EXPORT char*	MD5_hex(char* dest, const BYTE digest[MD5_DIGEST_SIZE]);
 
 #ifdef __cplusplus
 }
diff --git a/src/hash/objects.mk b/src/hash/objects.mk
index 4447d49073..e85ac9eb14 100644
--- a/src/hash/objects.mk
+++ b/src/hash/objects.mk
@@ -8,6 +8,6 @@
 
 OBJS	=	$(OBJODIR)$(DIRSEP)crc16$(OFILE) \
 		$(OBJODIR)$(DIRSEP)crc32$(OFILE) \
-		$(OBJODIR)$(DIRSEP)md5$(OFILE)
-
+		$(OBJODIR)$(DIRSEP)md5$(OFILE) \
+		$(OBJODIR)$(DIRSEP)sha1$(OFILE)
 
diff --git a/src/hash/sha1.c b/src/hash/sha1.c
new file mode 100644
index 0000000000..a9dc3a5e4c
--- /dev/null
+++ b/src/hash/sha1.c
@@ -0,0 +1,311 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#define SHA1HANDSOFF
+
+#include <stdio.h>
+#include <string.h>
+
+/* for uint32_t */
+#include <stdint.h>
+
+#include "sha1.h"
+
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+#define blk0(i) block->l[i]
+#else
+#error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(
+    uint32_t state[5],
+    const uint8_t buffer[64]
+)
+{
+    uint32_t a, b, c, d, e;
+
+    typedef union
+    {
+        uint8_t c[64];
+        uint32_t l[16];
+    } CHAR64LONG16;
+
+#ifdef SHA1HANDSOFF
+    CHAR64LONG16 block[1];      /* use array to appear as a pointer */
+
+    memcpy(block, buffer, 64);
+#else
+    /* The following had better never be used because it causes the
+     * pointer-to-const buffer to be cast into a pointer to non-const.
+     * And the result is written through.  I threw a "const" in, hoping
+     * this will cause a diagnostic.
+     */
+    CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer;
+#endif
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a, b, c, d, e, 0);
+    R0(e, a, b, c, d, 1);
+    R0(d, e, a, b, c, 2);
+    R0(c, d, e, a, b, 3);
+    R0(b, c, d, e, a, 4);
+    R0(a, b, c, d, e, 5);
+    R0(e, a, b, c, d, 6);
+    R0(d, e, a, b, c, 7);
+    R0(c, d, e, a, b, 8);
+    R0(b, c, d, e, a, 9);
+    R0(a, b, c, d, e, 10);
+    R0(e, a, b, c, d, 11);
+    R0(d, e, a, b, c, 12);
+    R0(c, d, e, a, b, 13);
+    R0(b, c, d, e, a, 14);
+    R0(a, b, c, d, e, 15);
+    R1(e, a, b, c, d, 16);
+    R1(d, e, a, b, c, 17);
+    R1(c, d, e, a, b, 18);
+    R1(b, c, d, e, a, 19);
+    R2(a, b, c, d, e, 20);
+    R2(e, a, b, c, d, 21);
+    R2(d, e, a, b, c, 22);
+    R2(c, d, e, a, b, 23);
+    R2(b, c, d, e, a, 24);
+    R2(a, b, c, d, e, 25);
+    R2(e, a, b, c, d, 26);
+    R2(d, e, a, b, c, 27);
+    R2(c, d, e, a, b, 28);
+    R2(b, c, d, e, a, 29);
+    R2(a, b, c, d, e, 30);
+    R2(e, a, b, c, d, 31);
+    R2(d, e, a, b, c, 32);
+    R2(c, d, e, a, b, 33);
+    R2(b, c, d, e, a, 34);
+    R2(a, b, c, d, e, 35);
+    R2(e, a, b, c, d, 36);
+    R2(d, e, a, b, c, 37);
+    R2(c, d, e, a, b, 38);
+    R2(b, c, d, e, a, 39);
+    R3(a, b, c, d, e, 40);
+    R3(e, a, b, c, d, 41);
+    R3(d, e, a, b, c, 42);
+    R3(c, d, e, a, b, 43);
+    R3(b, c, d, e, a, 44);
+    R3(a, b, c, d, e, 45);
+    R3(e, a, b, c, d, 46);
+    R3(d, e, a, b, c, 47);
+    R3(c, d, e, a, b, 48);
+    R3(b, c, d, e, a, 49);
+    R3(a, b, c, d, e, 50);
+    R3(e, a, b, c, d, 51);
+    R3(d, e, a, b, c, 52);
+    R3(c, d, e, a, b, 53);
+    R3(b, c, d, e, a, 54);
+    R3(a, b, c, d, e, 55);
+    R3(e, a, b, c, d, 56);
+    R3(d, e, a, b, c, 57);
+    R3(c, d, e, a, b, 58);
+    R3(b, c, d, e, a, 59);
+    R4(a, b, c, d, e, 60);
+    R4(e, a, b, c, d, 61);
+    R4(d, e, a, b, c, 62);
+    R4(c, d, e, a, b, 63);
+    R4(b, c, d, e, a, 64);
+    R4(a, b, c, d, e, 65);
+    R4(e, a, b, c, d, 66);
+    R4(d, e, a, b, c, 67);
+    R4(c, d, e, a, b, 68);
+    R4(b, c, d, e, a, 69);
+    R4(a, b, c, d, e, 70);
+    R4(e, a, b, c, d, 71);
+    R4(d, e, a, b, c, 72);
+    R4(c, d, e, a, b, 73);
+    R4(b, c, d, e, a, 74);
+    R4(a, b, c, d, e, 75);
+    R4(e, a, b, c, d, 76);
+    R4(d, e, a, b, c, 77);
+    R4(c, d, e, a, b, 78);
+    R4(b, c, d, e, a, 79);
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+    memset(block, '\0', sizeof(block));
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(
+    SHA1_CTX * context
+)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(
+    SHA1_CTX * context,
+    const void * buf,
+    size_t len
+)
+{
+    uint32_t i;
+    uint32_t j;
+    uint8_t* data = (uint8_t*)buf;
+
+    j = context->count[0];
+    if ((context->count[0] += len << 3) < j)
+        context->count[1]++;
+    context->count[1] += (len >> 29);
+    j = (j >> 3) & 63;
+    if ((j + len) > 63)
+    {
+        memcpy(&context->buffer[j], data, (i = 64 - j));
+        SHA1Transform(context->state, context->buffer);
+        for (; i + 63 < len; i += 64)
+        {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else
+        i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(
+    SHA1_CTX * context,
+    uint8_t digest[SHA1_DIGEST_SIZE]
+)
+{
+    unsigned i;
+
+    uint8_t finalcount[8];
+
+    uint8_t c;
+
+#if 0    /* untested "improvement" by DHR */
+    /* Convert context->count to a sequence of bytes
+     * in finalcount.  Second element first, but
+     * big-endian order within element.
+     * But we do it all backwards.
+     */
+    uint8_t *fcp = &finalcount[8];
+
+    for (i = 0; i < 2; i++)
+    {
+        uint32_t t = context->count[i];
+
+        int j;
+
+        for (j = 0; j < 4; t >>= 8, j++)
+            *--fcp = (uint8_t) t}
+#else
+    for (i = 0; i < 8; i++)
+    {
+        finalcount[i] = (uint8_t) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255);      /* Endian independent */
+    }
+#endif
+    c = 0200;
+    SHA1Update(context, &c, 1);
+    while ((context->count[0] & 504) != 448)
+    {
+        c = 0000;
+        SHA1Update(context, &c, 1);
+    }
+    SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+    for (i = 0; i < 20; i++)
+    {
+        digest[i] = (uint8_t)
+            ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
+    }
+    /* Wipe variables */
+    memset(context, '\0', sizeof(*context));
+    memset(&finalcount, '\0', sizeof(finalcount));
+}
+
+void SHA1_calc(
+    uint8_t *hash_out,
+    const void *data,
+    size_t len)
+{
+    SHA1_CTX ctx;
+    unsigned int ii;
+
+    SHA1Init(&ctx);
+    for (ii=0; ii<len; ii+=1)
+        SHA1Update(&ctx, (const char*)data + ii, 1);
+    SHA1Final(&ctx, hash_out);
+}
+
+/* conversion for 20 byte binary sha1 to hex */
+char* SHA1_hex(char* to, const uint8_t digest[SHA1_DIGEST_SIZE])
+{
+	uint8_t const* from = digest;
+	const char *hexdigits = "0123456789abcdef";
+	const uint8_t *end = digest + SHA1_DIGEST_SIZE;
+	char *d = to;
+
+	while (from < end) {
+		*d++ = hexdigits[(*from >> 4)];
+		*d++ = hexdigits[(*from & 0x0F)];
+		from++;
+	}
+	*d = '\0';
+	return to;
+}
diff --git a/src/hash/sha1.h b/src/hash/sha1.h
new file mode 100644
index 0000000000..852585ca2b
--- /dev/null
+++ b/src/hash/sha1.h
@@ -0,0 +1,57 @@
+#ifndef SHA1_H
+#define SHA1_H
+
+/*
+   SHA-1 in C
+   By Steve Reid <steve@edmweb.com>
+   100% Public Domain
+ */
+
+#include <stddef.h>		/* size_t */
+#include <gen_defs.h>	/* uint32_t */
+
+#define SHA1_DIGEST_SIZE 20
+
+typedef struct
+{
+    uint32_t state[5];
+    uint32_t count[2];
+    uint8_t buffer[64];
+} SHA1_CTX;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void SHA1Transform(
+    uint32_t state[5],
+    const uint8_t buffer[64]
+    );
+
+void SHA1Init(
+    SHA1_CTX * context
+    );
+
+void SHA1Update(
+    SHA1_CTX * context,
+    const void * data,
+    size_t len
+    );
+
+void SHA1Final(
+    SHA1_CTX * context,
+    uint8_t digest[SHA1_DIGEST_SIZE]
+    );
+
+void SHA1_calc(
+    uint8_t *hash_out,
+    const void *str,
+    size_t len);
+
+char* SHA1_hex(char* to, const uint8_t digest[SHA1_DIGEST_SIZE]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SHA1_H */
diff --git a/src/sbbs3/GNUmakefile b/src/sbbs3/GNUmakefile
index 5c149e77d7..d4bb30124e 100644
--- a/src/sbbs3/GNUmakefile
+++ b/src/sbbs3/GNUmakefile
@@ -20,6 +20,7 @@ UTIL_LDFLAGS	:=	$(LDFLAGS)
 UTIL_LDFLAGS	+=	$(SMBLIB_LDFLAGS) $(UIFC-MT_LDFLAGS) $(CIOLIB-MT_LDFLAGS) $(XPDEV_LDFLAGS) $(ENCODE_LDFLAGS)
 CONSOLE_LDFLAGS	+=	$(LDFLAGS) $(SMBLIB_LDFLAGS) $(XPDEV_LDFLAGS)
 UTIL_LIBS	+=	$(HASH_LIBS)
+FILE_LIBS	= -larchive
 
 ifndef bcc
  ifneq ($(os),sunos)
@@ -90,12 +91,12 @@ SHLIBOPTS	:=	-shared
 ifeq ($(os),darwin)
  MKSHLIB		:=	libtool -dynamic -framework System -lcc_dynamic
  MKSHPPLIB		:=	libtool -dynamic -framework System -lcc_dynamic -lstdc++
- SHLIBOPTS	:=	
+ SHLIBOPTS	:=
 else
  ifeq ($(os),sunos)
   MKSHLIB		:=	/usr/ccs/bin/ld -G
   MKSHPPLIB		:=	/usr/ccs/bin/ld -G
-  SHLIBOPTS	:=	
+  SHLIBOPTS	:=
  else
   MKSHLIB		:=	$(CC)
   MKSHPPLIB		:=	$(CXX)
@@ -122,7 +123,7 @@ $(SBBSMONO): $(MONO_OBJS) $(OBJS)
 # Synchronet BBS library Link Rule
 $(SBBS): $(JS_DEPS) $(CRYPT_DEPS) $(OBJS) $(LIBS) $(EXTRA_SBBS_DEPENDS) $(ENCODE_LIB) $(HASH_LIB) | $(LIBODIR)
 	@echo Linking $@
-	$(QUIET)$(MKSHPPLIB) $(LDFLAGS) -o $@ $(OBJS) $(SBBS_LIBS) $(SMBLIB_LIBS) $(LIBS) $(SHLIBOPTS) $(JS_LIBS) $(CRYPT_LIBS) $(ENCODE_LIBS) $(HASH_LIBS) $(XPDEV-MT_LIBS)
+	$(QUIET)$(MKSHPPLIB) $(LDFLAGS) -o $@ $(OBJS) $(SBBS_LIBS) $(SMBLIB_LIBS) $(LIBS) $(SHLIBOPTS) $(JS_LIBS) $(CRYPT_LIBS) $(ENCODE_LIBS) $(HASH_LIBS) $(XPDEV-MT_LIBS) $(FILE_LIBS)
 
 # FTP Server Link Rule
 $(FTPSRVR): $(MTOBJODIR)/ftpsrvr.o
@@ -182,7 +183,7 @@ $(SMBUTIL): $(SMBUTIL_OBJS)
 # SBBSecho (FidoNet Packet Tosser)
 $(SBBSECHO): $(SBBSECHO_OBJS)
 	@echo Linking $@
-	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(SBBSECHO_OBJS) $(SMBLIB_LIBS) $(XPDEV_LIBS) $(ENCODE_LIBS) $(HASH_LIBS)
+	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(SBBSECHO_OBJS) $(SMBLIB_LIBS) $(XPDEV_LIBS) $(ENCODE_LIBS) $(HASH_LIBS) $(FILE_LIBS)
 
 # SBBSecho Configuration Program
 $(ECHOCFG): $(ECHOCFG_OBJS) $(ENCODE_LIB)
@@ -192,12 +193,12 @@ $(ECHOCFG): $(ECHOCFG_OBJS) $(ENCODE_LIB)
 # ADDFILES
 $(ADDFILES): $(ADDFILES_OBJS)
 	@echo Linking $@
-	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(ADDFILES_OBJS) $(XPDEV_LIBS) $(SMBLIB_LIBS) $(ENCODE_LIBS) $(HASH_LIBS)
+	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(ADDFILES_OBJS) $(XPDEV_LIBS) $(SMBLIB_LIBS) $(ENCODE_LIBS) $(HASH_LIBS) $(FILE_LIBS)
 
 # FILELIST
 $(FILELIST): $(FILELIST_OBJS) $(ENCODE_LIB)
 	@echo Linking $@
-	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(FILELIST_OBJS) $(XPDEV_LIBS) $(ENCODE_LIBS)
+	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(FILELIST_OBJS) $(XPDEV_LIBS) $(SMBLIB_LIBS) $(ENCODE_LIBS) $(HASH_LIBS) $(FILE_LIBS)
 
 # MAKEUSER
 $(MAKEUSER): $(MAKEUSER_OBJS)
@@ -207,7 +208,7 @@ $(MAKEUSER): $(MAKEUSER_OBJS)
 # JSDOOR
 $(JSDOOR): $(JSDOOR_OBJS) $(XPDEV_LIB) $(ENCODE_LIB) $(HASH_LIB) | $(EXEODIR)
 	@echo Linking $@
-	$(QUIET)$(CXX) $(JS_CFLAGS) $(LDFLAGS) $(MT_LDFLAGS) -o $@ $(JSDOOR_OBJS) $(JS_LIBS) $(CRYPT_LIBS) $(UIFC-MT_LIBS) $(CIOLIB-MT_LIBS) $(SMBLIB_LIBS) $(ENCODE_LIBS) $(XPDEV-MT_LIBS) $(HASH_LIBS)
+	$(QUIET)$(CXX) $(JS_CFLAGS) $(LDFLAGS) $(MT_LDFLAGS) -o $@ $(JSDOOR_OBJS) $(JS_LIBS) $(CRYPT_LIBS) $(UIFC-MT_LIBS) $(CIOLIB-MT_LIBS) $(SMBLIB_LIBS) $(ENCODE_LIBS) $(XPDEV-MT_LIBS) $(HASH_LIBS) $(FILE_LIBS)
 
 # JSEXEC
 $(JSEXEC): $(JSEXEC_OBJS) $(SBBS)
@@ -247,12 +248,12 @@ $(ALLUSERS): $(ALLUSERS_OBJS) $(ENCODE_LIB)
 # DELFILES
 $(DELFILES): $(DELFILES_OBJS) $(ENCODE_LIB)
 	@echo Linking $@
-	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(DELFILES_OBJS) $(XPDEV_LIBS) $(ENCODE_LIBS)
+	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(DELFILES_OBJS) $(SMBLIB_LIBS) $(XPDEV_LIBS) $(ENCODE_LIBS) $(HASH_LIBS) $(FILE_LIBS)
 
 # DUPEFIND
 $(DUPEFIND): $(DUPEFIND_OBJS) $(ENCODE_LIB)
 	@echo Linking $@
-	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(DUPEFIND_OBJS) $(HASH_LIBS) $(XPDEV_LIBS) $(ENCODE_LIBS)
+	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(DUPEFIND_OBJS) $(SMBLIB_LIBS) $(HASH_LIBS) $(XPDEV_LIBS) $(ENCODE_LIBS)
 
 # SMBACTIV
 $(SMBACTIV): $(SMBACTIV_OBJS)
@@ -283,3 +284,7 @@ $(PKTDUMP): $(PKTDUMP_OBJS) $(OBJODIR) $(EXEODIR)
 $(FMSGDUMP): $(FMSGDUMP_OBJS) $(OBJODIR) $(EXEODIR)
 	@echo Linking $@
 	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(FMSGDUMP_OBJS)
+
+$(UPGRADE_TO_V319): $(UPGRADE_TO_V319_OBJS) $(OBJODIR) $(EXEODIR)
+	@echo Linking $@
+	$(QUIET)$(CC) $(CONSOLE_LDFLAGS) -o $@ $(UPGRADE_TO_V319_OBJS) $(SMBLIB_LIBS) $(XPDEV_LIBS) $(ENCODE_LIBS) $(HASH_LIBS) $(FILE_LIBS)
diff --git a/src/sbbs3/addfiles.c b/src/sbbs3/addfiles.c
index a79d406def..a6da5a368c 100644
--- a/src/sbbs3/addfiles.c
+++ b/src/sbbs3/addfiles.c
@@ -1,4 +1,4 @@
-/* Program to add files to a Synchronet file database */
+/* Add files to a Synchronet file database(s) */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -26,10 +26,14 @@
 #include "userdat.h"
 #include "filedat.h"
 #include "load_cfg.h"
+#include "smblib.h"
+#include "git_branch.h"
+#include "git_hash.h"
+
 #include <stdbool.h>
 #include <stdarg.h>
 
-#define ADDFILES_VER "3.05"
+#define ADDFILES_VER "3.19"
 
 scfg_t scfg;
 
@@ -74,103 +78,6 @@ int lprintf(int level, const char *fmat, ...)
 	return(chcount);
 }
 
-void prep_desc(char *str)
-{
-	char tmp[1024];
-	int i,j;
-
-	for(i=j=0;str[i] && j < sizeof(tmp)-1;i++) {
-		if(j && str[i]==' ' && tmp[j-1]==' ' && (mode&KEEP_SPACE))
-			tmp[j++]=str[i];
-		else if(j && str[i]<=' ' && str[i] > 0&& tmp[j-1]==' ')
-			continue;
-		else if(i && !IS_ALPHANUMERIC(str[i]) && str[i]==str[i-1])
-			continue;
-		else if(str[i]>=' ' || str[i]<0)
-			tmp[j++]=str[i];
-		else if(str[i]==TAB || (str[i]==CR && str[i+1]==LF))
-			tmp[j++]=' ';
-	}
-	tmp[j]=0;
-	strcpy(str,tmp);
-}
-
-/*****************************************************************************/
-/* Returns command line generated from instr with %c replacments             */
-/*****************************************************************************/
-char *mycmdstr(const char *instr, const char *fpath, const char *fspec, char *outstr)
-{
-    static char cmd[MAX_PATH+1];
-    char str[MAX_PATH+1];
-    int i,j,len;
-#ifdef _WIN32
-	char sfpath[MAX_PATH+1];
-#endif
-
-	len=strlen(instr);
-	for(i=j=0;i<len && j<128;i++) {
-		if(instr[i]=='%') {
-			i++;
-			cmd[j]=0;
-			switch(toupper(instr[i])) {
-				case 'F':   /* File path */
-					SAFECAT(cmd,fpath);
-					break;
-				case '~':	/* DOS-compatible (8.3) filename */
-#ifdef _WIN32
-					SAFECOPY(sfpath,fpath);
-					GetShortPathName(fpath,sfpath,sizeof(sfpath));
-					SAFECAT(cmd,sfpath);
-#else
-                    SAFECAT(cmd,fpath);
-#endif
-					break;
-				case 'G':   /* Temp directory */
-					SAFECAT(cmd,scfg.temp_dir);
-					break;
-                case 'J':
-                    SAFECAT(cmd,scfg.data_dir);
-                    break;
-                case 'K':
-                    SAFECAT(cmd,scfg.ctrl_dir);
-                    break;
-				case 'N':   /* Node Directory (same as SBBSNODE environment var) */
-					SAFECAT(cmd,scfg.node_dir);
-					break;
-				case 'S':   /* File Spec */
-					SAFECAT(cmd,fspec);
-					break;
-                case 'Z':
-                    SAFECAT(cmd,scfg.text_dir);
-                    break;
-				case '!':   /* EXEC Directory */
-					SAFECAT(cmd,scfg.exec_dir);
-					break;
-                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
-#ifndef __unix__
-                    SAFECAT(cmd,scfg.exec_dir);
-#endif
-                    break;
-				case '#':   /* Node number (same as SBBSNNUM environment var) */
-					sprintf(str,"%d",scfg.node_num);
-					SAFECAT(cmd,str);
-					break;
-				case '%':   /* %% for percent sign */
-					SAFECAT(cmd,"%");
-					break;
-				default:    /* unknown specification */
-					break;
-			}
-			j=strlen(cmd);
-		}
-		else
-			cmd[j++]=instr[i];
-	}
-	cmd[j]=0;
-
-	return(cmd);
-}
-
 /****************************************************************************/
 /* Updates dstst.dab file													*/
 /****************************************************************************/
@@ -197,62 +104,44 @@ void updatestats(ulong size)
 	close(file);
 }
 
-bool get_file_diz(file_t* f, const char* filepath, char* ext)
+bool reupload(smb_t* smb, file_t* f)
 {
-	int i,file;
-	char tmp[MAX_PATH+1];
-	char tmpext[513];
-
-	for(i=0;i<scfg.total_fextrs;i++)
-		if(!stricmp(scfg.fextr[i]->ext,f->name+9)
-			&& chk_ar(&scfg,scfg.fextr[i]->ar,/* user: */NULL, /* client: */NULL))
-			break;
-	// If we could not find an extractor which matches our requirements, use any
-	if(i >= scfg.total_fextrs) {
-		for(i=0;i<scfg.total_fextrs;i++)
-			if(!stricmp(scfg.fextr[i]->ext,f->name+9))
-				break;
-	}
-	if(i >= scfg.total_fextrs)
+	char path[MAX_PATH + 1];
+	if(!smb_renewfile(smb, f, SMB_SELFPACK, getfilepath(&scfg, f, path))) {
+		fprintf(stderr, "!Error renewing: %s\n", f->name);
 		return false;
-
-	SAFEPRINTF(tmp,"%sFILE_ID.DIZ",scfg.temp_dir);
-	removecase(tmp);
-	system(mycmdstr(scfg.fextr[i]->cmd,filepath,"FILE_ID.DIZ",NULL));
-	if(!fexistcase(tmp)) {
-		SAFEPRINTF(tmp,"%sDESC.SDI",scfg.temp_dir);
-		removecase(tmp);
-		system(mycmdstr(scfg.fextr[i]->cmd,filepath,"DESC.SDI",NULL));
-		fexistcase(tmp);
 	}
+	return true;
+}
+
 
-	if((file=nopen(tmp,O_RDONLY|O_BINARY)) == -1)
+bool get_file_diz(file_t* f, char* ext, size_t maxlen)
+{
+	char path[MAX_PATH + 1];
+	printf("Extracting DIZ from: %s\n", getfilepath(&scfg, f, path));
+	char diz_fpath[MAX_PATH + 1];
+	if(!extract_diz(&scfg, f, /* diz_fnames */NULL, diz_fpath, sizeof(diz_fpath))) {
+		printf("DIZ does not exist in: %s\n", getfilepath(&scfg, f, path));
 		return false;
+	}
+	printf("Parsing DIZ: %s\n", diz_fpath);
+	str_list_t lines = read_diz(diz_fpath, /* max_line_len: */80);
+	format_diz(lines, ext, maxlen, /* allow_ansi: */false);
+	strListFree(&lines);
+	remove(diz_fpath);
 
-	memset(ext,0,513);
-	read(file,ext,512);
-	for(i=512;i;i--)
-		if(ext[i-1]>' ' || ext[i-1]<0)
-			break;
-	ext[i]=0;
 	if(mode&ASCII_ONLY)
 		strip_exascii(ext, ext);
+
 	if(!(mode&KEEP_DESC)) {
-		sprintf(tmpext,"%.256s",ext);
-		prep_desc(tmpext);
-		for(i=0;tmpext[i];i++)
-			if(IS_ALPHA(tmpext[i]))
-				break;
-		sprintf(f->desc,"%.*s",LEN_FDESC,tmpext+i);
-		for(i=0;(f->desc[i]>=' ' || f->desc[i]<0) && i<LEN_FDESC;i++)
-			;
-		f->desc[i]=0; }
-	close(file);
-	f->misc|=FM_EXTDESC;
+		char* fdesc = strdup(ext);
+		smb_new_hfield_str(f, SMB_FILEDESC, prep_file_desc(fdesc, fdesc));
+		free(fdesc);
+	}
 	return true;
 }
 
-void addlist(char *inpath, file_t f, uint dskip, uint sskip)
+void addlist(char *inpath, uint dirnum, const char* uploader, uint dskip, uint sskip)
 {
 	char str[MAX_PATH+1];
 	char tmp[MAX_PATH+1];
@@ -263,53 +152,54 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 	char *p;
 	char ext[1024];
 	int i;
-	long l;
+	off_t l;
 	BOOL exist;
 	FILE *stream;
 	DIR*	dir;
 	DIRENT*	dirent;
+	smb_t smb;
+	file_t f;
 
+	int result = smb_open_dir(&scfg, &smb, dirnum);
+	if(result != SMB_SUCCESS) {
+		fprintf(stderr, "!Error %d (%s) opening %s\n", result, smb.last_error, smb.file);
+		return;
+	}
+	str_list_t fname_list = loadfilenames(&smb, ALLFILES, /* time: */0, FILE_SORT_NATURAL, /* count: */NULL);
 	if(mode&SEARCH_DIR) {
-		SAFECOPY(str,cur_altpath ? scfg.altpath[cur_altpath-1] : scfg.dir[f.dir]->path);
+		SAFECOPY(str,cur_altpath ? scfg.altpath[cur_altpath-1] : scfg.dir[dirnum]->path);
 		printf("Searching %s\n\n",str);
 		dir=opendir(str);
 
 		while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
-			sprintf(tmp,"%s%s"
-				,cur_altpath ? scfg.altpath[cur_altpath-1] : scfg.dir[f.dir]->path
+			sprintf(filepath, "%s%s"
+				,cur_altpath ? scfg.altpath[cur_altpath-1] : scfg.dir[dirnum]->path
 				,dirent->d_name);
-			if(isdir(tmp))
+			if(isdir(filepath))
 				continue;
-#ifdef _WIN32
-			GetShortPathName(tmp, filepath, sizeof(filepath));
-#else
-			SAFECOPY(filepath,tmp);
-#endif
-			f.misc=0;
-			f.desc[0]=0;
+			const char* fname = getfname(filepath);
+			printf("%s  ", fname);
+			if(strListFind(fname_list, fname, /* case-sensitive: */FALSE) && (mode&NO_UPDATE)) {
+				printf("already added.\n");
+				continue;
+			}
 			memset(ext, 0, sizeof(ext));
-			f.cdt=flength(filepath);
+			memset(&f, 0, sizeof(f));
+			char fdesc[LEN_FDESC + 1] = {0};
+			uint32_t cdt = (uint32_t)flength(filepath);
 			time_t file_timestamp = fdate(filepath);
-			padfname(getfname(filepath),f.name);
-			printf("%s  %10"PRIu32"  %s\n"
-				,f.name,f.cdt,unixtodstr(&scfg,(time32_t)file_timestamp,str));
-			exist=findfile(&scfg,f.dir,f.name);
+			printf("%10"PRIu32"  %s\n"
+				,cdt, unixtodstr(&scfg,(time32_t)file_timestamp,str));
+			exist = smb_findfile(&smb, fname, &f) == SMB_SUCCESS;
 			if(exist) {
 				if(mode&NO_UPDATE)
 					continue;
-				if(!getfileixb(&scfg,&f)) {
-					fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
-					continue;
-				}
-				if((mode&CHECK_DATE) && file_timestamp <= f.dateuled)
+				if((mode&CHECK_DATE) && file_timestamp <= f.idx.time)
 					continue;
 				if(mode&ULDATE_ONLY) {
-					f.dateuled=time32(NULL);
-					update_uldate(&scfg, &f);
-					continue;
-				}
-				if(f.misc & FM_EXTDESC)
-					getextdesc(&scfg, f.dir, f.datoffset, ext);
+					reupload(&smb, &f);
+					continue; 
+				} 
 			}
 
 			if(mode&TODAYS_DATE) {		/* put today's date in desc */
@@ -320,7 +210,7 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
 				} else
 					unixtodstr(&scfg, (time32_t)now, f.desc);
-				SAFECAT(f.desc,"  ");
+				SAFECAT(fdesc,"  ");
 			}
 			else if(mode&FILE_DATE) {		/* get the file date and put into desc */
 				if(datefmt) {
@@ -329,35 +219,45 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
 				} else
 					unixtodstr(&scfg,(time32_t)file_timestamp,f.desc);
-				SAFECAT(f.desc,"  ");
+				SAFECAT(fdesc,"  ");
 			}
 
-			if(mode&FILE_ID)
-				get_file_diz(&f, filepath, ext);
+			char* ext_desc = NULL;
+			if(mode&FILE_ID) {
+				if(get_file_diz(&f, ext, sizeof(ext))) {
+					ext_desc = ext;
+				}
+			}
 
-			f.dateuled=time32(NULL);
-			f.altpath=cur_altpath;
-			prep_desc(f.desc);
+			prep_file_desc(fdesc, fdesc);
 			if(mode&ASCII_ONLY)
-				strip_exascii(f.desc, f.desc);
+				strip_exascii(fdesc, fdesc);
+
+			smb_hfield_str(&f, SMB_FILENAME, fname);
+			smb_hfield_str(&f, SMB_FILEDESC, fdesc);
+			smb_hfield_str(&f, SENDER, uploader);
+			smb_hfield_bin(&f, SMB_COST, cdt);
+
+			truncsp(ext_desc);
 			if(exist) {
-				putfiledat(&scfg,&f);
+				result = smb_updatemsg(&smb, &f);
 				if(!(mode&NO_NEWDATE))
-					update_uldate(&scfg, &f);
+					reupload(&smb, &f);
 			}
 			else
-				addfiledat(&scfg,&f);
-			if(f.misc&FM_EXTDESC) {
-				truncsp(ext);
-				putextdesc(&scfg,f.dir,f.datoffset,ext);
-			}
+				result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, filepath);
+			smb_freefilemem(&f);
+			if(result != SMB_SUCCESS)
+				fprintf(stderr, "!Error %d (%s) adding file to %s", result, smb.last_error, smb.file);
 			if(mode&UL_STATS)
-				updatestats(f.cdt);
-			files++;
+				updatestats(cdt);
+			files++; 
 		}
 		if(dir!=NULL)
 			closedir(dir);
-		return;
+		smb_close(&smb);
+		strListFree(&fname_list);
+		return; 
 	}
 
 
@@ -367,22 +267,23 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 		fprintf(stderr,"Error %d (%s) opening %s\n"
 			,errno,strerror(errno),listpath);
 		sprintf(listpath,"%s%s",cur_altpath ? scfg.altpath[cur_altpath-1]
-				: scfg.dir[f.dir]->path,inpath);
+				: scfg.dir[dirnum]->path,inpath);
 		fexistcase(listpath);
 		if((stream=fopen(listpath,"r"))==NULL) {
 			printf("Can't open: %s\n"
 				   "        or: %s\n",inpath,listpath);
-			return;
-		}
+			smb_close(&smb);
+			strListFree(&fname_list);
+			return; 
+		} 
 	}
 
 	printf("Adding %s to %s %s\n\n"
-		,listpath,scfg.lib[scfg.dir[f.dir]->lib]->sname,scfg.dir[f.dir]->sname);
+		,listpath,scfg.lib[scfg.dir[dirnum]->lib]->sname,scfg.dir[dirnum]->sname);
 
 	fgets(nextline,255,stream);
 	do {
-		f.misc=0;
-		f.desc[0]=0;
+		char fdesc[LEN_FDESC + 1] = {0};
 		memset(ext, 0, sizeof(ext));
 		SAFECOPY(curline,nextline);
 		nextline[0]=0;
@@ -393,11 +294,6 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 		printf("%s\n",curline);
 		SAFECOPY(fname,curline);
 
-#if 0	/* Files without dots are valid on modern systems */
-		p=strchr(fname,'.');
-		if(!p || p==fname || p>fname+8)    /* no dot or invalid dot location */
-			continue;
-#endif
 		p=strchr(fname,' ');
 		if(p) *p=0;
 #if 0 // allow import of bare filename list
@@ -407,68 +303,37 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 		if(!IS_ALPHANUMERIC(*fname)) {	// filename doesn't begin with an alpha-numeric char?
 			continue;
 		}
-		SAFEPRINTF2(filepath,"%s%s",cur_altpath ? scfg.altpath[cur_altpath-1]
-			: scfg.dir[f.dir]->path,fname);
-
-#ifdef _WIN32
-		{
-			char shortpath[MAX_PATH+1];
-			GetShortPathName(filepath, shortpath, sizeof(shortpath));
-			SAFECOPY(fname, getfname(shortpath));
-		}
-#else
-		fexistcase(filepath);
-		SAFECOPY(fname, getfname(filepath));
-#endif
 
-		padfname(fname,f.name);
-		if(strcspn(f.name,"\\/|<>+[]:=\";,")!=strlen(f.name))
-			continue;
-
-		for(i=0;i<12;i++)
-			if(f.name[i]<' ' || (mode&ASCII_ONLY && (uchar)f.name[i]>0x7e))
-				break;
+		sprintf(filepath, "%s%s", cur_altpath ? scfg.altpath[cur_altpath-1]
+			: scfg.dir[dirnum]->path,fname);
 
-		if(i<12)					/* Ctrl chars or EX-ASCII in filename? */
+		if(strcspn(fname,"\\/|<>+[]:=\";,")!=strlen(fname)) {
+			fprintf(stderr, "!Illegal filename: %s\n", fname);
 			continue;
+		}
+
 		time_t file_timestamp = fdate(filepath);
-		exist=findfile(&scfg,f.dir,f.name);
+		exist = smb_findfile(&smb, fname, &f) == SMB_SUCCESS;
 		if(exist) {
 			if(mode&NO_UPDATE)
 				continue;
-			if(!getfileixb(&scfg,&f)) {
-				fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
-				continue;
-			}
-			if((mode&CHECK_DATE) && file_timestamp <= f.dateuled)
+			if((mode&CHECK_DATE) && file_timestamp <= f.idx.time)
 				continue;
 			if(mode&ULDATE_ONLY) {
-				f.dateuled=time32(NULL);
-				update_uldate(&scfg, &f);
-				continue;
-			}
-			if (f.misc & FM_EXTDESC)
-				getextdesc(&scfg, f.dir, f.datoffset, ext);
+				reupload(&smb, &f);
+				continue; 
+			} 
 		}
 
-		if(mode&TODAYS_DATE) {		/* put today's date in desc */
-			time_t now = time(NULL);
-			if(datefmt) {
-				struct tm tm = {0};
-				localtime_r(&now, &tm);
-				strftime(f.desc, sizeof(f.desc), datefmt, &tm);
-			} else
-				unixtodstr(&scfg, (time32_t)now, f.desc);
-			SAFECAT(f.desc,"  ");
+		if(mode&FILE_DATE) {		/* get the file date and put into desc */
+			unixtodstr(&scfg,(time32_t)file_timestamp, fdesc);
+			strcat(fdesc, "  "); 
 		}
-		else if(mode&FILE_DATE) {		/* get the file date and put into desc */
-			if(datefmt) {
-				struct tm tm = {0};
-				localtime_r(&file_timestamp, &tm);
-				strftime(f.desc, sizeof(f.desc), datefmt, &tm);
-			} else
-				unixtodstr(&scfg,(time32_t)file_timestamp,f.desc);
-			SAFECAT(f.desc,"  ");
+
+		if(mode&TODAYS_DATE) {		/* put today's date in desc */
+			l=time32(NULL);
+			unixtodstr(&scfg,(time32_t)l,fdesc);
+			strcat(fdesc, "  "); 
 		}
 
 		if(dskip && strlen(curline)>=dskip) p=curline+dskip;
@@ -478,21 +343,22 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 			SKIP_WHITESPACE(p);
 		}
 		SAFECOPY(tmp,p);
-		prep_desc(tmp);
-		sprintf(f.desc+strlen(f.desc),"%.*s",(int)(LEN_FDESC-strlen(f.desc)),tmp);
+		prep_file_desc(tmp, tmp);
+		sprintf(fdesc + strlen(fdesc), "%.*s", (int)(LEN_FDESC-strlen(fdesc)), tmp);
 
+		char* ext_desc = NULL;
 		if(nextline[0]==' ' || strlen(p)>LEN_FDESC) {	/* ext desc */
 			if(!(mode&NO_EXTEND)) {
 				memset(ext, 0, sizeof(ext));
-				f.misc|=FM_EXTDESC;
-				sprintf(ext,"%s\r\n",p);
+				sprintf(ext,"%s\r\n",p); 
+				ext_desc = ext;
 			}
 
 			if(nextline[0]==' ') {
 				SAFECOPY(str,nextline);				   /* tack on to end of desc */
 				p=str+dskip;
 				while(*p>0 && *p<=' ') p++;
-				i=LEN_FDESC-strlen(f.desc);
+				i=LEN_FDESC-strlen(fdesc);
 				if(i>1) {
 					p[i-1]=0;
 					truncsp(p);
@@ -509,8 +375,8 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 				truncsp(nextline);
 				printf("%s\n",nextline);
 				if(!(mode&NO_EXTEND)) {
-					f.misc|=FM_EXTDESC;
 					p=nextline+dskip;
+					ext_desc = ext;
 					while(*p==' ') p++;
 					SAFECAT(ext,p);
 					SAFECAT(ext,"\r\n");
@@ -520,7 +386,6 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 			}
 		}
 
-
 		l=flength(filepath);
 		if(l<0L) {
 			printf("%s not found.\n",filepath);
@@ -533,28 +398,31 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 		if(sskip) l=atol(fname+sskip);
 
 		if(mode&FILE_ID)
-			get_file_diz(&f, filepath, ext);
+			get_file_diz(&f, ext, sizeof(ext));
 
-		f.cdt=l;
-		f.dateuled=time32(NULL);
-		f.altpath=cur_altpath;
-		prep_desc(f.desc);
+		prep_file_desc(fdesc, fdesc);
 		if(mode&ASCII_ONLY)
-			strip_exascii(f.desc, f.desc);
+			strip_exascii(fdesc, fdesc);
+		memset(&f, 0, sizeof(f));
+		uint32_t cdt = (uint32_t)l;
+		smb_hfield_bin(&f, SMB_COST, cdt);
+		smb_hfield_str(&f, SMB_FILENAME, fname);
+		smb_hfield_str(&f, SMB_FILEDESC, fdesc);
+		smb_hfield_str(&f, SENDER, uploader);
 		if(exist) {
-			putfiledat(&scfg,&f);
+			result = smb_updatemsg(&smb, &f);
 			if(!(mode&NO_NEWDATE))
-				update_uldate(&scfg, &f);
+				reupload(&smb, &f);
 		}
 		else
-			addfiledat(&scfg,&f);
-		if(f.misc&FM_EXTDESC) {
-			truncsp(ext);
-			putextdesc(&scfg,f.dir,f.datoffset,ext);
-		}
+			result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, filepath);
+		smb_freefilemem(&f);
+		if(result != SMB_SUCCESS)
+			fprintf(stderr, "!ERROR %d (%s) writing to %s\n"
+				, result, smb.last_error, smb.file);
 
 		if(mode&UL_STATS)
-			updatestats(l);
+			updatestats((ulong)l);
 		files++;
 	} while(!feof(stream) && !ferror(stream));
 	fclose(stream);
@@ -562,44 +430,21 @@ void addlist(char *inpath, file_t f, uint dskip, uint sskip)
 		printf("\nDeleting %s\n",listpath);
 		remove(listpath);
 	}
-
+	smb_close(&smb);
+	strListFree(&fname_list);
 }
 
 void synclist(char *inpath, int dirnum)
 {
 	char	str[1024];
-	char	fname[MAX_PATH+1];
 	char	listpath[MAX_PATH+1];
-	uchar*	ixbbuf;
 	char*	p;
-	int		i,file,found;
-	long	l,m,length;
+	int		found;
+	long	l;
 	FILE*	stream;
-	file_t	f;
-
-	sprintf(str,"%s%s.ixb",scfg.dir[dirnum]->data_dir,scfg.dir[dirnum]->code);
-	if((file=nopen(str,O_RDONLY|O_BINARY))==-1) {
-		printf("ERR_OPEN %s\n",str);
-		return;
-	}
-	length=filelength(file);
-	if(length%F_IXBSIZE) {
-		close(file);
-		printf("ERR_LEN (%ld) of %s\n",length,str);
-		return;
-	}
-	if((ixbbuf=(uchar *)malloc(length))==NULL) {
-		close(file);
-		printf("ERR_ALLOC %s\n",str);
-		return;
-	}
-	if(read(file,ixbbuf,length)!=length) {
-		close(file);
-		free((char *)ixbbuf);
-		printf("ERR_READ %s\n",str);
-		return;
-	}
-	close(file);
+	file_t*	f;
+	file_t*	file_list;
+	smb_t	smb;
 
 	SAFECOPY(listpath,inpath);
 	if((stream=fopen(listpath,"r"))==NULL) {
@@ -612,18 +457,19 @@ void synclist(char *inpath, int dirnum)
 		}
 	}
 
+	int result = smb_open_dir(&scfg, &smb, dirnum);
+	if(result != SMB_SUCCESS) {
+		fprintf(stderr, "!Error %d (%s) opening %s\n", result, smb.last_error, smb.file);
+		return;
+	}
+	size_t file_count;
+	file_list = loadfiles(&smb, NULL, 0, /* extdesc: */FALSE, FILE_SORT_NATURAL, &file_count);
+
 	printf("\nSynchronizing %s with %s %s\n\n"
 		,listpath,scfg.lib[scfg.dir[dirnum]->lib]->sname,scfg.dir[dirnum]->sname);
 
-	for(l=0;l<length;l+=F_IXBSIZE) {
-		m=l;
-		for(i=0;i<12 && l<length;i++)
-			if(i==8)
-				str[i]=ixbbuf[m]>' ' ? '.' : ' ';
-			else
-				str[i]=ixbbuf[m++]; 	/* Turns FILENAMEEXT into FILENAME.EXT */
-		str[i]=0;
-		unpadfname(str,fname);
+	for(l = 0; l < (long)file_count; l++) {
+		f = &file_list[l];
 		rewind(stream);
 		found=0;
 		while(!found) {
@@ -632,34 +478,28 @@ void synclist(char *inpath, int dirnum)
 			truncsp(str);
 			p=strchr(str,' ');
 			if(p) *p=0;
-			if(!stricmp(str,fname))
-				found=1;
+			if(!stricmp(str, f->name))
+				found=1; 
 		}
 		if(found)
 			continue;
-		padfname(fname,f.name);
-		printf("%s not found in list - ",f.name);
-		f.dir=dirnum;
-		f.datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
-		if(!getfiledat(&scfg,&f)) {
-			fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
-			continue;
-		}
-		if(f.opencount) {
-			printf("currently OPEN by %u users\n",f.opencount);
-			continue;
+		printf("%s not found in list - ", f->name);
+		if(smb_removefile(&smb, f) != SMB_SUCCESS)
+			fprintf(stderr, "!ERROR (%s) removing file from database\n", smb.last_error);
+		else {
+			if(remove(getfilepath(&scfg, f, str)))
+				printf("Error removing %s\n",str);
+			removed++;
+			printf("Removed from database\n");
 		}
-		removefiledat(&scfg,&f);
-		if(remove(getfilepath(&scfg,&f,str)))
-			printf("Error removing %s\n",str);
-		removed++;
-		printf("Removed from database\n");
 	}
+	freefiles(file_list, file_count);
 
 	if(mode&DEL_LIST) {
 		printf("\nDeleting %s\n",listpath);
 		remove(listpath);
 	}
+	smb_close(&smb);
 	fclose(stream);
 }
 
@@ -698,24 +538,24 @@ char *usage="\nusage: addfiles code [.alt_path] [-opts] +list "
 int main(int argc, char **argv)
 {
 	char error[512];
-	char revision[16];
 	char str[MAX_PATH+1];
 	char tmp[MAX_PATH+1];
 	char *p;
-	char exist,listgiven=0,namegiven=0,ext[513]
+	char exist,listgiven=0,namegiven=0,ext[LEN_EXTDESC + 1]
 		,auto_name[MAX_PATH+1]="FILES.BBS";
 	int i,j;
 	uint desc_offset=0, size_offset=0;
 	long l;
+	smb_t	smb;
 	file_t	f;
+	uint dirnum = INVALID_DIR;
 
-	sscanf("$Revision: 1.63 $", "%*s %s", revision);
-
-	fprintf(stderr,"\nADDFILES v%s-%s (rev %s) - Adds Files to Synchronet "
+	fprintf(stderr,"\nADDFILES v%s-%s %s/%s - Adds Files to Synchronet "
 		"Filebase\n"
 		,ADDFILES_VER
 		,PLATFORM_DESC
-		,revision
+		,GIT_BRANCH
+		,GIT_HASH
 		);
 
 	if(argc<2) {
@@ -739,6 +579,7 @@ int main(int argc, char **argv)
 	}
 	SAFECOPY(scfg.temp_dir,"../temp");
 	prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
+	memset(&smb, 0, sizeof(smb));
 
 	if(argv[1][0]=='*' || argv[1][0]=='-') {
 		if(argv[1][1]=='?') {
@@ -761,18 +602,18 @@ int main(int argc, char **argv)
 
 		if(i>=scfg.total_dirs) {
 			printf("Directory code '%s' not found.\n",argv[1]);
-			exit(1);
-		}
+			exit(1); 
+		} 
+		dirnum = i;
 	}
 
-	memset(&f,0,sizeof(file_t));
-	f.dir=i;
-	SAFECOPY(f.uler,"-> ADDFILES <-");
+	memset(&f,0,sizeof(f));
+	const char* uploader = "-> ADDFILES <-";
 
 	for(j=2;j<argc;j++) {
 		if(argv[j][0]=='*')     /* set the uploader name (legacy) */
-			SAFECOPY(f.uler,argv[j]+1);
-		else
+			uploader = argv[j]+1;
+		else 
 			if(argv[j][0]=='-'
 			|| argv[j][0]=='/'
 			) {      /* options */
@@ -811,7 +652,7 @@ int main(int argc, char **argv)
 							puts(usage);
 							return(-1);
 						}
-						SAFECOPY(f.uler,argv[j]);
+						uploader = argv[j];
 						i=strlen(argv[j])-1;
 						break;
 					case 'Z':
@@ -869,18 +710,18 @@ int main(int argc, char **argv)
 				&& IS_DIGIT(argv[j+1][0])) { /* skip x characters before description */
 				if(argc > j+2
 					&& IS_DIGIT(argv[j+2][0])) { /* skip x characters before size */
-					addlist(argv[j]+1,f,atoi(argv[j+1]),atoi(argv[j+2]));
+					addlist(argv[j]+1, dirnum, uploader, atoi(argv[j+1]), atoi(argv[j+2]));
 					j+=2;
 				}
 				else {
-					addlist(argv[j]+1,f,atoi(argv[j+1]),0);
-					j++;
-				}
+					addlist(argv[j]+1, dirnum, uploader, atoi(argv[j+1]), 0);
+					j++; 
+				} 
 			}
 			else
-				addlist(argv[j]+1,f,0,0);
+				addlist(argv[j]+1, dirnum, uploader, 0, 0);
 			if(mode&SYNC_LIST)
-				synclist(argv[j]+1,f.dir);
+				synclist(argv[j]+1, dirnum); 
 		}
 		else if(argv[j][0]=='.') {      /* alternate file path */
 			cur_altpath=atoi(argv[j]+1);
@@ -891,86 +732,69 @@ int main(int argc, char **argv)
 		}
 		else {
 			namegiven=1;
-			padfname(argv[j],f.name);
-			f.desc[0]=0;
-			memset(ext, 0, sizeof(ext));
-#if 0
-			strupr(f.name);
-#endif
+			const char* fname = argv[j];
+			char fdesc[LEN_FDESC + 1] = {0};
+
 			if(j+1==argc) {
-				printf("%s no description given.\n",f.name);
-				SAFECOPY(f.desc, "no description given");
+				printf("%s no description given.\n",fname);
+				SAFECOPY(fdesc, "no description given");
 			}
+
 			sprintf(str,"%s%s",cur_altpath ? scfg.altpath[cur_altpath-1]
-				: scfg.dir[f.dir]->path,argv[j]);
-			if(mode&TODAYS_DATE) {
-				time_t now = time(NULL);
-				if(datefmt) {
-					struct tm tm = {0};
-					localtime_r(&now, &tm);
-					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
-				} else
-					SAFECOPY(f.desc, unixtodstr(&scfg, (time32_t)now, tmp));
-				SAFECAT(f.desc, "  ");
-			}
-			else if(mode&FILE_DATE) {
-				time_t file_timestamp = fdate(str);
-				if(datefmt) {
-					struct tm tm = {0};
-					localtime_r(&file_timestamp, &tm);
-					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
-				} else
-					SAFECOPY(f.desc, unixtodstr(&scfg,(time32_t)file_timestamp,tmp));
-				SAFECAT(f.desc, "  ");
-			}
-			if(j+1 < argc) {
-				j++;
-				SAFECAT(f.desc, argv[j]);
-			}
-			l=flength(str);
+				: scfg.dir[dirnum]->path, fname);
+			if(mode&FILE_DATE)
+				sprintf(fdesc, "%s  ", unixtodstr(&scfg,(time32_t)fdate(str),tmp));
+			if(mode&TODAYS_DATE)
+				sprintf(fdesc, "%s  ", unixtodstr(&scfg,time32(NULL),tmp));
+			sprintf(tmp, "%.*s", (int)(LEN_FDESC-strlen(fdesc)), argv[++j]);
+			SAFECOPY(fdesc, tmp);
+			l=(long)flength(str);
 			if(l==-1) {
 				printf("%s not found.\n",str);
 				continue;
 			}
-			exist=findfile(&scfg,f.dir,f.name);
+			if(SMB_IS_OPEN(&smb))
+				smb_close(&smb);
+
+			int result = smb_open_dir(&scfg, &smb, dirnum);
+			if(result != SMB_SUCCESS) {
+				fprintf(stderr, "!ERROR %d (%s) opening %s\n", result, smb.last_error, smb.file);
+				exit(EXIT_FAILURE);
+			}
+
+			exist = smb_findfile(&smb, fname, &f) == SMB_SUCCESS;
 			if(exist) {
 				if(mode&NO_UPDATE)
 					continue;
-				if(!getfileixb(&scfg,&f)) {
-					fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
-					continue;
-				}
-				if((mode&CHECK_DATE) && fdate(str) <= f.dateuled)
+				if((mode&CHECK_DATE) && fdate(str) <= f.idx.time)
 					continue;
 				if(mode&ULDATE_ONLY) {
-					f.dateuled=time32(NULL);
-					update_uldate(&scfg, &f);
-					continue;
-				}
-				if (f.misc & FM_EXTDESC)
-					getextdesc(&scfg, f.dir, f.datoffset, ext);
+					reupload(&smb, &f);
+					continue; 
+				} 
 			}
-			f.cdt=l;
-			f.dateuled=time32(NULL);
-			f.altpath=cur_altpath;
-			prep_desc(f.desc);
+			memset(&f, 0, sizeof(f));
+			prep_file_desc(fdesc, fdesc);
 			if(mode&ASCII_ONLY)
-				strip_exascii(f.desc, f.desc);
-			printf("%s %7"PRIu32" %s\n",f.name,f.cdt,f.desc);
-			if(mode&FILE_ID)
-				get_file_diz(&f, str, ext);
-
+				strip_exascii(fdesc, fdesc);
+			smb_hfield_str(&f, SMB_FILENAME, fname);
+			smb_hfield_str(&f, SMB_FILEDESC, fdesc);
+			smb_hfield_str(&f, SENDER, uploader);
+			uint32_t cdt = (uint32_t)l;
+			smb_hfield_bin(&f, SMB_COST, cdt);
+
+			printf("%s %7"PRIu64" %s\n",fname, (int64_t)l, fdesc);
+			char* ext_desc = NULL;
+			if(get_file_diz(&f, ext, sizeof(ext)))
+				ext_desc = ext;
 			if(exist) {
-				putfiledat(&scfg,&f);
 				if(!(mode&NO_NEWDATE))
-					update_uldate(&scfg, &f);
+					reupload(&smb, &f);
+				else
+					result = smb_updatemsg(&smb, &f);
 			}
 			else
-				addfiledat(&scfg,&f);
-
-			if(f.misc&FM_EXTDESC)
-				putextdesc(&scfg,f.dir,f.datoffset,ext);
-
+				result = smb_addfile(&smb, &f, SMB_SELFPACK, ext_desc, str);
 			if(mode&UL_STATS)
 				updatestats(l);
 			files++;
@@ -983,23 +807,23 @@ int main(int argc, char **argv)
 				continue;
 			if(scfg.dir[i]->misc&DIR_NOAUTO)
 				continue;
-			f.dir=i;
+			dirnum = i;
 			if(mode&SEARCH_DIR) {
-				addlist("",f,desc_offset,size_offset);
-				continue;
+				addlist("", dirnum, uploader, desc_offset, size_offset);
+				continue; 
 			}
-			sprintf(str,"%s%s.lst",scfg.dir[f.dir]->path,scfg.dir[f.dir]->code);
+			sprintf(str,"%s%s.lst",scfg.dir[dirnum]->path,scfg.dir[dirnum]->code);
 			if(fexistcase(str) && flength(str)>0L) {
 				printf("Auto-adding %s\n",str);
-				addlist(str,f,desc_offset,size_offset);
+				addlist(str, dirnum, uploader, desc_offset, size_offset);
 				if(mode&SYNC_LIST)
 					synclist(str,i);
 				continue;
 			}
-			SAFEPRINTF2(str,"%s%s",scfg.dir[f.dir]->path,auto_name);
+			SAFEPRINTF2(str,"%s%s",scfg.dir[dirnum]->path,auto_name);
 			if(fexistcase(str) && flength(str)>0L) {
 				printf("Auto-adding %s\n",str);
-				addlist(str,f,desc_offset,size_offset);
+				addlist(str, dirnum, uploader, desc_offset, size_offset);
 				if(mode&SYNC_LIST)
 					synclist(str,i);
 				continue;
@@ -1009,12 +833,11 @@ int main(int argc, char **argv)
 
 	else {
 		if(!listgiven && !namegiven) {
-			sprintf(str,"%s%s.lst",scfg.dir[f.dir]->path, scfg.dir[f.dir]->code);
+			sprintf(str,"%s%s.lst",scfg.dir[dirnum]->path, scfg.dir[dirnum]->code);
 			if(!fexistcase(str) || flength(str)<=0L)
-				SAFEPRINTF2(str,"%s%s",scfg.dir[f.dir]->path, auto_name);
-			addlist(str,f,desc_offset,size_offset);
+				SAFEPRINTF2(str,"%s%s",scfg.dir[dirnum]->path, auto_name);
 			if(mode&SYNC_LIST)
-				synclist(str,f.dir);
+				synclist(str, dirnum);
 		}
 	}
 
diff --git a/src/sbbs3/addfiles.vcxproj b/src/sbbs3/addfiles.vcxproj
index 941a6ebf50..8307ed9c89 100644
--- a/src/sbbs3/addfiles.vcxproj
+++ b/src/sbbs3/addfiles.vcxproj
@@ -38,6 +38,7 @@
     <Import Project="..\build\undeprecate.props" />
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -47,6 +48,7 @@
     <Import Project="..\build\undeprecate.props" />
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
@@ -96,6 +98,7 @@
       <TargetMachine>MachineX86</TargetMachine>
       <IgnoreSpecificDefaultLibraries>libcd.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+      <AdditionalDependencies>netapi32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <Bscmake>
       <SuppressStartupBanner>true</SuppressStartupBanner>
@@ -139,6 +142,7 @@
       <TargetMachine>MachineX86</TargetMachine>
       <IgnoreSpecificDefaultLibraries>libcd.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+      <AdditionalDependencies>netapi32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <Bscmake>
       <SuppressStartupBanner>true</SuppressStartupBanner>
@@ -183,7 +187,6 @@
     </ProjectReference>
     <ProjectReference Include="..\xpdev\xpdev.vcxproj">
       <Project>{7428a1e8-56b7-4868-9c0e-29d031689feb}</Project>
-      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
     </ProjectReference>
     <ProjectReference Include="load_cfg.vcxproj">
       <Project>{08fc395f-bc60-499d-9ce9-170ed718bb94}</Project>
diff --git a/src/sbbs3/allusers.c b/src/sbbs3/allusers.c
index 7ac0bdec2e..047741ae26 100644
--- a/src/sbbs3/allusers.c
+++ b/src/sbbs3/allusers.c
@@ -146,7 +146,8 @@ int main(int argc, char **argv)
 {
 	char	dir[128],str[128];
 	int 	i,j,file,set,sub,mod;
-	long	l,f,flags,flagoff,length,offset;
+	long	l,f,flags,flagoff,offset;
+	off_t	length;
 	FILE	*stream;
 
 	printf("\nALLUSERS v2.10 - Bulk User Editor for Synchronet User Database\n");
@@ -220,12 +221,12 @@ int main(int argc, char **argv)
 						exit(1); 
 					}
 					setvbuf(stream,NULL,_IOFBF,2048);
-					length=filelength(file);
+					length=(ulong)filelength(file);
 					printf("\n%s Flags %s Set #%d\n",sub ? "Removing":"Adding"
 						,sub ? "from":"to",set);
 					for(offset=0;offset<length;offset+=U_LEN) {
 						printf("%lu of %lu (%u modified)\r"
-							,(offset/U_LEN)+1,length/U_LEN,mod);
+							,(offset/U_LEN)+1,(ulong)(length/U_LEN),mod);
 						if(lockuser(stream,offset)) {
 							printf("Error locking offset %lu\n",offset);
 							continue; 
@@ -290,7 +291,7 @@ int main(int argc, char **argv)
 						,flagoff==U_REST ? "Restrictions":"Exemptions");
 					for(offset=0;offset<length;offset+=U_LEN) {
 						printf("%lu of %lu (%u modified)\r"
-							,(offset/U_LEN)+1,length/U_LEN,mod);
+							,(offset/U_LEN)+1,(ulong)(length/U_LEN),mod);
 						if(lockuser(stream,offset)) {
 							printf("Error locking offset %lu\n",offset);
 							continue; 
@@ -343,7 +344,7 @@ int main(int argc, char **argv)
 					printf("\nChanging Levels\n");
 					for(offset=0;offset<length;offset+=U_LEN) {
 						printf("%lu of %lu (%u modified)\r"
-							,(offset/U_LEN)+1,length/U_LEN,mod);
+							,(offset/U_LEN)+1,(ulong)(length/U_LEN),mod);
 						if(lockuser(stream,offset)) {
 							printf("Error locking offset %lu\n",offset);
 							continue; 
diff --git a/src/sbbs3/atcodes.cpp b/src/sbbs3/atcodes.cpp
index 28f8c44829..f258c80f87 100644
--- a/src/sbbs3/atcodes.cpp
+++ b/src/sbbs3/atcodes.cpp
@@ -1990,31 +1990,33 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, long* pmode, bool
 			return current_file->name;
 		if(strcmp(sp, "FILE_DESC") == 0)
 			return current_file->desc;
+		if(strcmp(sp, "FILE_TAGS") == 0)
+			return current_file->tags;
 		if(strcmp(sp, "FILE_UPLOADER") == 0)
-			return current_file->uler;
+			return current_file->from;
 		if(strcmp(sp, "FILE_SIZE") == 0) {
 			safe_snprintf(str, maxlen, "%ld", (long)current_file->size);
 			return str;
 		}
 		if(strcmp(sp, "FILE_CREDITS") == 0) {
-			safe_snprintf(str, maxlen, "%lu", (ulong)current_file->cdt);
+			safe_snprintf(str, maxlen, "%lu", (ulong)current_file->cost);
 			return str;
 		}
 		if(strcmp(sp, "FILE_TIME") == 0)
-			return timestr(current_file->date);
+			return timestr(current_file->time);
 		if(strcmp(sp, "FILE_TIME_ULED") == 0)
-			return timestr(current_file->dateuled);
+			return timestr(current_file->hdr.when_imported.time);
 		if(strcmp(sp, "FILE_TIME_DLED") == 0)
-			return timestr(current_file->datedled);
+			return timestr(current_file->hdr.last_downloaded);
 		if(strcmp(sp, "FILE_DATE") == 0)
-			return datestr(current_file->date);
+			return datestr(current_file->time);
 		if(strcmp(sp, "FILE_DATE_ULED") == 0)
-			return datestr(current_file->dateuled);
+			return datestr(current_file->hdr.when_imported.time);
 		if(strcmp(sp, "FILE_DATE_DLED") == 0)
-			return datestr(current_file->datedled);
+			return datestr(current_file->hdr.last_downloaded);
 
 		if(strcmp(sp, "FILE_TIMES_DLED") == 0) {
-			safe_snprintf(str, maxlen, "%d", current_file->timesdled);
+			safe_snprintf(str, maxlen, "%lu", (ulong)current_file->hdr.times_downloaded);
 			return str;
 		}
 	}
diff --git a/src/sbbs3/bat_xfer.cpp b/src/sbbs3/bat_xfer.cpp
index 7c75c2779c..518f87b3e7 100644
--- a/src/sbbs3/bat_xfer.cpp
+++ b/src/sbbs3/bat_xfer.cpp
@@ -1,9 +1,5 @@
-/* bat_xfer.cpp */
-
 /* Synchronet batch file transfer functions */
 
-/* $Id: bat_xfer.cpp,v 1.41 2020/05/13 23:56:08 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,25 +13,14 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include "sbbs.h"
+#include "filedat.h"
 
 /****************************************************************************/
 /* This is the batch menu section                                           */
@@ -46,19 +31,19 @@ void sbbs_t::batchmenu()
 	char 	tmp[512];
 	char	keys[32];
 	uint	i,n,xfrprot,xfrdir;
-    ulong	totalcdt,totalsize,totaltime;
+    int64_t	totalcdt,totalsize;
     time_t	start,end;
-    file_t	f;
+	str_list_t ini;
+	str_list_t filenames;
 
-	if(!batdn_total && !batup_total && cfg.upload_dir==INVALID_DIR) {
+	if(batdn_total() < 1 && batup_total() < 1 && cfg.upload_dir==INVALID_DIR) {
 		bputs(text[NoFilesInBatchQueue]);
 		return; 
 	}
 	if(useron.misc&(RIP|WIP|HTML) && !(useron.misc&EXPERT))
 		menu("batchxfer");
 	lncntr=0;
-	while(online && !done && (batdn_total || batup_total
-		|| cfg.upload_dir!=INVALID_DIR)) {
+	while(online && !done && (cfg.upload_dir!=INVALID_DIR || batdn_total() || batup_total())) {
 		if(!(useron.misc&(EXPERT|RIP|WIP|HTML))) {
 			sys_status&=~SS_ABORT;
 			if(lncntr) {
@@ -71,7 +56,7 @@ void sbbs_t::batchmenu()
 		}
 		ASYNC;
 		bputs(text[BatchMenuPrompt]);
-		SAFEPRINTF(keys,"BCDLRU?\r%c", text[YNQP][2]);
+		SAFEPRINTF(keys,"CDLRU?\r%c", text[YNQP][2]);
 		ch=(char)getkeys(keys,0);
 		if(ch>' ')
 			logch(ch,0);
@@ -85,125 +70,21 @@ void sbbs_t::batchmenu()
 				if(useron.misc&(EXPERT|RIP|WIP|HTML))
 					menu("batchxfr");
 				break;
-			case 'B':   /* Bi-directional transfers */
-				if(useron.rest&FLAG('D')) {
-					bputs(text[R_Download]);
-					break; 
-				}
-				if(useron.rest&FLAG('U')) {
-					bputs(text[R_Upload]);
-					break; 
-				}
-				if(!batdn_total) {
-					bputs(text[DownloadQueueIsEmpty]);
-					break; 
-				}
-				if(!batup_total && cfg.upload_dir==INVALID_DIR) {
-					bputs(text[UploadQueueIsEmpty]);
-					break; 
-				}
-				for(i=0,totalcdt=0;i<batdn_total;i++)
-					if(!is_download_free(&cfg,batdn_dir[i],&useron,&client))
-						totalcdt+=batdn_cdt[i];
-				if(totalcdt>useron.cdt+useron.freecdt) {
-					bprintf(text[YouOnlyHaveNCredits]
-						,ultoac(useron.cdt+useron.freecdt,tmp));
-					break; 
-				}
-				for(i=0,totalsize=totaltime=0;i<batdn_total;i++) {
-					totalsize+=batdn_size[i];
-					if(!(cfg.dir[batdn_dir[i]]->misc&DIR_TFREE) && cur_cps)
-						totaltime+=batdn_size[i]/(ulong)cur_cps; 
-				}
-				if(!(useron.exempt&FLAG('T')) && !SYSOP && totaltime>timeleft) {
-					bputs(text[NotEnoughTimeToDl]);
-					break; 
-				}
-				xfer_prot_menu(XFER_BIDIR);
-				SYNC;
-				mnemonics(text[ProtocolOrQuit]);
-				SAFEPRINTF(tmp2,"%c",text[YNQP][2]);
-				for(i=0;i<cfg.total_prots;i++)
-					if(cfg.prot[i]->bicmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
-						sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
-						SAFECAT(tmp2,tmp); 
-					}
-				ungetkey(useron.prot);
-				ch=(char)getkeys(tmp2,0);
-				if(ch==text[YNQP][2])
-					break;
-				for(i=0;i<cfg.total_prots;i++)
-					if(cfg.prot[i]->bicmd[0] && cfg.prot[i]->mnemonic==ch
-						&& chk_ar(cfg.prot[i]->ar,&useron,&client))
-						break;
-				if(i<cfg.total_prots) {
-					if(!create_batchdn_lst((cfg.prot[i]->misc&PROT_NATIVE) ? true:false))
-						break;
-					if(!create_batchup_lst())
-						break;
-					if(!create_bimodem_pth())
-						break;
-
-					xfrprot=i;
-					action=NODE_BXFR;
-					SYNC;
-					for(i=0;i<batdn_total;i++)
-						if(cfg.dir[batdn_dir[i]]->seqdev) {
-							lncntr=0;
-							unpadfname(batdn_name[i],tmp);
-							SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,tmp);
-							if(!fexistcase(tmp2)) {
-								seqwait(cfg.dir[batdn_dir[i]]->seqdev);
-								bprintf(text[RetrievingFile],tmp);
-								SAFEPRINTF2(str,"%s%s"
-									,batdn_alt[i]>0 && batdn_alt[i]<=cfg.altpaths
-									? cfg.altpath[batdn_alt[i]-1]
-									: cfg.dir[batdn_dir[i]]->path
-									,tmp);
-								mv(str,tmp2,1); /* copy the file to temp dir */
-								if(getnodedat(cfg.node_num,&thisnode,true)==0) {
-									thisnode.aux=0xff;
-									putnodedat(cfg.node_num,&thisnode);
-								}
-								CRLF; 
-							} 
-						}
-					SAFEPRINTF(str,"%sBATCHDN.LST",cfg.node_dir);
-					SAFEPRINTF(tmp2,"%sBATCHUP.LST",cfg.node_dir);
-					start=time(NULL);
-					protocol(cfg.prot[xfrprot],XFER_BIDIR,str,tmp2,true);
-					end=time(NULL);
-					for(i=0;i<batdn_total;i++)
-						if(cfg.dir[batdn_dir[i]]->seqdev) {
-							unpadfname(batdn_name[i],tmp);
-							SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,tmp);
-							remove(tmp2); 
-						}
-					batch_upload();
-					batch_download(xfrprot);
-					if(batdn_total)     /* files still in queue, not xfered */
-						notdownloaded(totalsize,start,end);
-					autohangup(); 
-				}
-				break;
 			case 'C':
-				if(batup_total) {
+				if(batup_total() < 1) {
+					bputs(text[UploadQueueIsEmpty]);
+				} else {
 					if(text[ClearUploadQueueQ][0]==0 || !noyes(text[ClearUploadQueueQ])) {
-						batup_total=0;
-						bputs(text[UploadQueueCleared]); 
+						if(clearbatul())
+							bputs(text[UploadQueueCleared]);
 					} 
 				}
-				if(batdn_total) {
+				if(batdn_total() <1 ) {
+					bputs(text[DownloadQueueIsEmpty]);
+				} else {
 					if(text[ClearDownloadQueueQ][0]==0 || !noyes(text[ClearDownloadQueueQ])) {
-						for(i=0;i<batdn_total;i++) {
-							f.dir=batdn_dir[i];
-							f.datoffset=batdn_offset[i];
-							f.size=batdn_size[i];
-							SAFECOPY(f.name,batdn_name[i]);
-							closefile(&f); 
-						}
-						batdn_total=0;
-						bputs(text[DownloadQueueCleared]); 
+						if(clearbatdl())
+							bputs(text[DownloadQueueCleared]); 
 					} 
 				}
 				break;
@@ -211,72 +92,68 @@ void sbbs_t::batchmenu()
 				start_batch_download();
 				break;
 			case 'L':
-				if(batup_total) {
+				ini = batch_list_read(&cfg, useron.number, XFER_BATCH_UPLOAD);
+				filenames = iniGetSectionList(ini, NULL);
+				if(strListCount(filenames)) {
 					bputs(text[UploadQueueLstHdr]);
-					for(i=0;i<batup_total;i++)
-						bprintf(text[UploadQueueLstFmt],i+1,batup_name[i]
-							,batup_desc[i]); 
-				}
-				if(batdn_total) {
+					for(size_t i = 0; filenames[i]; ++i) {
+						const char* filename = filenames[i];
+						char value[INI_MAX_VALUE_LEN];
+						bprintf(text[UploadQueueLstFmt]
+							,i+1, filename
+							,iniGetString(ini, filename, "desc", text[NoDescription], value));
+					}
+				} else
+					bputs(text[UploadQueueIsEmpty]);
+
+				iniFreeStringList(filenames);
+				iniFreeStringList(ini);
+
+				totalsize = 0;
+				totalcdt = 0;
+				ini = batch_list_read(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+				filenames = iniGetSectionList(ini, NULL);
+				if(strListCount(filenames)) {
 					bputs(text[DownloadQueueLstHdr]);
-					for(i=0,totalcdt=0,totalsize=0;i<batdn_total;i++) {
+					for(size_t i = 0; filenames[i]; ++i) {
+						const char* filename = filenames[i];
+						file_t f = {{}};
+						if(!batch_file_load(&cfg, ini, filename, &f))
+							continue;
+						getfilesize(&cfg, &f);
+						getfiletime(&cfg, &f);
 						bprintf(text[DownloadQueueLstFmt],i+1
-							,batdn_name[i],ultoac(batdn_cdt[i],tmp)
-							,ultoac(batdn_size[i],str)
+							,filename
+							,ultoac(f.cost, tmp)
+							,ultoac((ulong)f.size, str)
 							,cur_cps
-							? sectostr(batdn_size[i]/(ulong)cur_cps,tmp2)
-							: "??:??:??");
-						totalsize+=batdn_size[i];
-						totalcdt+=batdn_cdt[i]; 
+								? sectostr((uint)(f.size/(ulong)cur_cps),tmp2)
+								: "??:??:??"
+							,datestr(f.time)
+						);
+						totalsize += f.size;
+						totalcdt += f.cost;
+						smb_freemsgmem(&f);
 					}
 					bprintf(text[DownloadQueueTotals]
-						,ultoac(totalcdt,tmp),ultoac(totalsize,str),cur_cps
-						? sectostr(totalsize/(ulong)cur_cps,tmp2)
+						,ultoac((ulong)totalcdt,tmp),ultoac((ulong)totalsize,str),cur_cps
+						? sectostr((ulong)totalsize/(ulong)cur_cps,tmp2)
 						: "??:??:??"); 
-				}
-				break;  /* Questionable line ^^^, see note above function */
+				} else
+					bputs(text[DownloadQueueIsEmpty]);
+				iniFreeStringList(filenames);
+				iniFreeStringList(ini);
+				break;
 			case 'R':
-				if(batup_total) {
-					bprintf(text[RemoveWhichFromUlQueue],batup_total);
-					n=getnum(batup_total);
-					if((int)n>=1) {
-						n--;
-						batup_total--;
-						while(n<batup_total) {
-							batup_dir[n]=batup_dir[n+1];
-							batup_misc[n]=batup_misc[n+1];
-							batup_alt[n]=batup_alt[n+1];
-							strcpy(batup_name[n],batup_name[n+1]);
-							strcpy(batup_desc[n],batup_desc[n+1]);
-							n++; 
-						}
-						if(!batup_total)
-							bputs(text[UploadQueueCleared]); 
-					} 
+				if((n = batup_total()) > 0) {
+					bprintf(text[RemoveWhichFromUlQueue], n);
+					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
+						batch_file_remove(&cfg, useron.number, XFER_BATCH_UPLOAD, str);
 				}
-				if(batdn_total) {
-					bprintf(text[RemoveWhichFromDlQueue],batdn_total);
-					n=getnum(batdn_total);
-					if((int)n>=1) {
-						n--;
-						f.dir=batdn_dir[n];
-						SAFECOPY(f.name,batdn_name[n]);
-						f.datoffset=batdn_offset[n];
-						f.size=batdn_size[n];
-						closefile(&f);
-						batdn_total--;
-						while(n<batdn_total) {
-							strcpy(batdn_name[n],batdn_name[n+1]);
-							batdn_dir[n]=batdn_dir[n+1];
-							batdn_cdt[n]=batdn_cdt[n+1];
-							batdn_alt[n]=batdn_alt[n+1];
-							batdn_size[n]=batdn_size[n+1];
-							batdn_offset[n]=batdn_offset[n+1];
-							n++; 
-						}
-						if(!batdn_total)
-							bputs(text[DownloadQueueCleared]); 
-					} 
+				if((n = batdn_total()) > 0) {
+					bprintf(text[RemoveWhichFromDlQueue], n);
+					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
+						batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, str);
 				}
 				break;
 		   case 'U':
@@ -284,15 +161,13 @@ void sbbs_t::batchmenu()
 					bputs(text[R_Upload]);
 					break; 
 				}
-				if(!batup_total && cfg.upload_dir==INVALID_DIR) {
+				if(batup_total() < 1 && cfg.upload_dir==INVALID_DIR) {
 					bputs(text[UploadQueueIsEmpty]);
 					break; 
 				}
 				xfer_prot_menu(XFER_BATCH_UPLOAD);
 				if(!create_batchup_lst())
 					break;
-				if(!create_bimodem_pth())
-					break;
 				ASYNC;
 				mnemonics(text[ProtocolOrQuit]);
 				SAFEPRINTF(str,"%c",text[YNQP][2]);
@@ -311,10 +186,7 @@ void sbbs_t::batchmenu()
 				if(i<cfg.total_prots) {
 					SAFEPRINTF(str,"%sBATCHUP.LST",cfg.node_dir);
 					xfrprot=i;
-					if(batup_total)
-						xfrdir=batup_dir[0];
-					else
-						xfrdir=cfg.upload_dir;
+					xfrdir=cfg.upload_dir;
 					action=NODE_ULNG;
 					SYNC;
 					if(online==ON_REMOTE) {
@@ -342,41 +214,75 @@ BOOL sbbs_t::start_batch_download()
 {
 	char	ch;
 	char	tmp[32];
-	char	fname[64];
 	char	str[MAX_PATH+1];
 	char 	path[MAX_PATH+1];
-	char*	list;
-	size_t	list_len;
+	char	list[1024] = "";
 	int		error;
-    int		j;
     uint	i,xfrprot;
-    ulong	totalcdt,totalsize,totaltime;
     time_t	start,end,t;
 	struct	tm tm;
 
-	if(batdn_total==0) {
-		bputs(text[DownloadQueueIsEmpty]);
-		return(FALSE);
-	}
 	if(useron.rest&FLAG('D')) {     /* Download restriction */
 		bputs(text[R_Download]);
 		return(FALSE); 
 	}
-	for(i=0,totalcdt=0;i<batdn_total;i++)
-		if(is_download_free(&cfg,batdn_dir[i],&useron,&client))
-			totalcdt+=batdn_cdt[i];
-	if(totalcdt>useron.cdt+useron.freecdt) {
+
+	str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+
+	size_t file_count = iniGetSectionCount(ini, NULL);
+	if(file_count < 1) {
+		bputs(text[DownloadQueueIsEmpty]);
+		iniFreeStringList(ini);
+		return(FALSE);
+	}
+	str_list_t filenames = iniGetSectionList(ini, NULL);
+
+	if(file_count == 1) {	// Only one file in the queue? Perform a non-batch (e.g. XMODEM) download
+		file_t f = {{}};
+		BOOL result = FALSE;
+		if(batch_file_get(&cfg, ini, filenames[0], &f)) {
+			result = sendfile(&f, /* prot: */' ', /* autohang: */true);
+			if(result == TRUE)
+				batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, f.name);
+		}
+		iniFreeStringList(ini);
+		iniFreeStringList(filenames);
+		smb_freefilemem(&f);
+		return result;
+	}
+
+	int64_t totalcdt = 0;
+	for(size_t i=0; filenames[i] != NULL; ++i) {
+		file_t f = {{}};
+		if(batch_file_load(&cfg, ini, filenames[i], &f)) {
+			totalcdt += f.cost;
+			smb_freefilemem(&f);
+		}
+	}
+	if(totalcdt > (int64_t)(useron.cdt+useron.freecdt)) {
 		bprintf(text[YouOnlyHaveNCredits]
 			,ultoac(useron.cdt+useron.freecdt,tmp));
+		iniFreeStringList(ini);
+		iniFreeStringList(filenames);
 		return(FALSE); 
 	}
 
-	for(i=0,totalsize=totaltime=0;i<batdn_total;i++) {
-		totalsize+=batdn_size[i];
-		if(!(cfg.dir[batdn_dir[i]]->misc&DIR_TFREE) && cur_cps)
-			totaltime+=batdn_size[i]/(ulong)cur_cps; 
+	int64_t totalsize = 0;
+	int64_t totaltime = 0;
+	for(size_t i=0; filenames[i] != NULL; ++i) {
+		file_t f = {{}};
+		if(!batch_file_get(&cfg, ini, filenames[i], &f))
+			continue;
+		if(!(cfg.dir[f.dir]->misc&DIR_TFREE) && cur_cps)
+			totaltime += getfilesize(&cfg, &f) / (ulong)cur_cps;
+		SAFECAT(list, getfilepath(&cfg, &f, path));
+		SAFECAT(list, " ");
+		smb_freefilemem(&f);
 	}
-	if(!(useron.exempt&FLAG('T')) && !SYSOP && totaltime>timeleft) {
+	iniFreeStringList(ini);
+	iniFreeStringList(filenames);
+
+	if(!(useron.exempt&FLAG('T')) && !SYSOP && totaltime > (int64_t)timeleft) {
 		bputs(text[NotEnoughTimeToDl]);
 		return(FALSE); 
 	}
@@ -397,15 +303,11 @@ BOOL sbbs_t::start_batch_download()
 		if(cfg.prot[i]->batdlcmd[0] && cfg.prot[i]->mnemonic==ch
 			&& chk_ar(cfg.prot[i]->ar,&useron,&client))
 			break;
-	if(i>=cfg.total_prots)
-		return(FALSE);	/* no protocol selected */
-
-	if(!create_batchdn_lst((cfg.prot[i]->misc&PROT_NATIVE) ? true:false))
-		return(FALSE);
-	if(!create_bimodem_pth())
+	if(i>=cfg.total_prots || !create_batchdn_lst((cfg.prot[i]->misc&PROT_NATIVE) ? true:false)) {
 		return(FALSE);
-
+	}
 	xfrprot=i;
+#if 0 // NFB-TODO: Download events
 	list=NULL;
 	for(i=0;i<batdn_total;i++) {
 		curdirnum=batdn_dir[i]; 		/* for ARS */
@@ -417,9 +319,7 @@ BOOL sbbs_t::start_batch_download()
 				seqwait(cfg.dir[batdn_dir[i]]->seqdev);
 				bprintf(text[RetrievingFile],fname);
 				SAFEPRINTF2(str,"%s%s"
-					,batdn_alt[i]>0 && batdn_alt[i]<=cfg.altpaths
-					? cfg.altpath[batdn_alt[i]-1]
-					: cfg.dir[batdn_dir[i]]->path
+					,cfg.dir[batdn_dir[i]]->path
 					,fname);
 				mv(str,path,1); /* copy the file to temp dir */
 				if(getnodedat(cfg.node_num,&thisnode,true)==0) {
@@ -462,6 +362,7 @@ BOOL sbbs_t::start_batch_download()
 			CRLF; 
 		}
 	}
+#endif
 
 	SAFEPRINTF(str,"%sBATCHDN.LST",cfg.node_dir);
 	action=NODE_DLNG;
@@ -479,13 +380,11 @@ BOOL sbbs_t::start_batch_download()
 	end=time(NULL);
 	if(cfg.prot[xfrprot]->misc&PROT_DSZLOG || !error)
 		batch_download(xfrprot);
-	if(batdn_total)
-		notdownloaded(totalsize,start,end);
-	autohangup(); 
-	if(list!=NULL)
-		free(list);
+	if(batdn_total())
+		notdownloaded((ulong)totalsize,start,end);
+	autohangup();
 
-	return(TRUE);
+	return TRUE;
 }
 
 /****************************************************************************/
@@ -495,31 +394,45 @@ BOOL sbbs_t::start_batch_download()
 bool sbbs_t::create_batchdn_lst(bool native)
 {
 	char	path[MAX_PATH+1];
-	char	fname[MAX_PATH+1];
-	int		file;
-	uint	i;
 
-	SAFEPRINTF(path,"%sBATCHDN.LST",cfg.node_dir);
-	if((file=nopen(path,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
-		errormsg(WHERE,ERR_OPEN,path,O_WRONLY|O_CREAT|O_TRUNC);
-		return(false); 
+	SAFEPRINTF(path, "%sBATCHDN.LST", cfg.node_dir);
+	FILE* fp = fopen(path, "wb");
+	if(fp == NULL) {
+		errormsg(WHERE, ERR_OPEN, path);
+		return false;
 	}
-	for(i=0;i<batdn_total;i++) {
-		if(batdn_dir[i]>=cfg.total_dirs || cfg.dir[batdn_dir[i]]->seqdev)
-			SAFECOPY(path,cfg.temp_dir);
-		else
-			SAFECOPY(path,batdn_alt[i]>0 && batdn_alt[i]<=cfg.altpaths
-				? cfg.altpath[batdn_alt[i]-1] : cfg.dir[batdn_dir[i]]->path);
-
-		unpadfname(batdn_name[i],fname);
-		SAFECAT(path,fname);
-		if(native)
-			fexistcase(path);
-		SAFECAT(path,crlf);
-		write(file,path,strlen(path)); 
+	str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+	str_list_t filenames = iniGetSectionList(ini, /* prefix: */NULL);
+	for(size_t i = 0; filenames[i] != NULL; ++i) {
+		const char* filename = filenames[i];
+		file_t f = {};
+		f.dir = batch_file_dir(&cfg, ini, filename);
+		if(!loadfile(&cfg, f.dir, filename, &f, file_detail_index)) {
+			errormsg(WHERE, "loading file", filename, i);
+			batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
+			continue;
+		}
+		getfilepath(&cfg, &f, path);
+		if(!fexistcase(path)) {
+			bprintf(text[FileDoesNotExist], path);
+			batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
+		}
+		else {
+#ifdef _WIN32
+			if(!native) {
+				char tmp[MAX_PATH + 1];
+				GetShortPathName(path, tmp, sizeof(tmp));
+				SAFECOPY(path, tmp);
+			}
+#endif
+			fprintf(fp, "%s\r\n", path);
+		}
+		smb_freefilemem(&f);
 	}
-	close(file);
-	return(true);
+	fclose(fp);
+	iniFreeStringList(ini);
+	iniFreeStringList(filenames);
+	return true;
 }
 
 /****************************************************************************/
@@ -529,66 +442,28 @@ bool sbbs_t::create_batchdn_lst(bool native)
 /****************************************************************************/
 bool sbbs_t::create_batchup_lst()
 {
-    char	str[256];
-    int		file;
-	uint	i;
-
-	SAFEPRINTF(str,"%sBATCHUP.LST",cfg.node_dir);
-	if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
-		errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_TRUNC);
-		return(false); 
-	}
-	for(i=0;i<batup_total;i++) {
-		if(batup_dir[i]>=cfg.total_dirs)
-			SAFECOPY(str,cfg.temp_dir);
-		else
-			SAFECOPY(str,batup_alt[i]>0 && batup_alt[i]<=cfg.altpaths
-				? cfg.altpath[batup_alt[i]-1] : cfg.dir[batup_dir[i]]->path);
-		write(file,str,strlen(str));
-		unpadfname(batup_name[i],str);
-		strcat(str,crlf);
-		write(file,str,strlen(str)); 
-	}
-	close(file);
-	return(true);
-}
-
-/****************************************************************************/
-/* Creates the file BIMODEM.PTH in the node directory. Returns true if      */
-/* everything goes okay, false if not.                                      */
-/****************************************************************************/
-bool sbbs_t::create_bimodem_pth()
-{
-    char	str[256],tmp2[512];
-	char 	tmp[512];
-    int		file;
-	uint	i;
+    char	path[MAX_PATH + 1];
 
-	SAFEPRINTF(str,"%sBIMODEM.PTH",cfg.node_dir);  /* Create bimodem file */
-	if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
-		errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_TRUNC);
-		return(false); 
-	}
-	for(i=0;i<batup_total;i++) {
-		SAFEPRINTF2(str,"%s%s",batup_dir[i]>=cfg.total_dirs ? cfg.temp_dir
-			: batup_alt[i]>0 && batup_alt[i]<=cfg.altpaths
-			? cfg.altpath[batup_alt[i]-1] : cfg.dir[batup_dir[i]]->path
-			,unpadfname(batup_name[i],tmp));
-		SAFEPRINTF2(tmp2,"D       %-80.80s%-160.160s"
-			,unpadfname(batup_name[i],tmp),str);
-		write(file,tmp2,248); 
+	SAFEPRINTF(path,"%sBATCHUP.LST",cfg.node_dir);
+	FILE* fp = fopen(path, "wb");
+	if(fp == NULL) {
+		errormsg(WHERE, ERR_OPEN, path);
+		return false;
 	}
-	for(i=0;i<batdn_total;i++) {
-		SAFEPRINTF2(str,"%s%s"
-			,(batdn_dir[i]>=cfg.total_dirs || cfg.dir[batdn_dir[i]]->seqdev)
-			? cfg.temp_dir : batdn_alt[i]>0 && batdn_alt[i]<=cfg.altpaths
-				? cfg.altpath[batdn_alt[i]-1] : cfg.dir[batdn_dir[i]]->path
-				,unpadfname(batdn_name[i],tmp));
-		SAFEPRINTF(tmp2,"U       %-240.240s",str);
-		write(file,tmp2,248); 
+	str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_UPLOAD);
+	str_list_t filenames = iniGetSectionList(ini, /* prefix: */NULL);
+	for(size_t i = 0; filenames[i] != NULL; ++i) {
+		const char* filename = filenames[i];
+		file_t f = {{}};
+		if(!batch_file_get(&cfg, ini, filename, &f))
+			continue;
+		fprintf(fp, "%s%s\r\n", cfg.dir[f.dir]->path, filename);
+		smb_freemsgmem(&f);
 	}
-	close(file);
-	return(true);
+	fclose(fp);
+	iniFreeStringList(ini);
+	iniFreeStringList(filenames);
+	return true;
 }
 
 /****************************************************************************/
@@ -596,79 +471,74 @@ bool sbbs_t::create_bimodem_pth()
 /****************************************************************************/
 void sbbs_t::batch_upload()
 {
-    char	str1[MAX_PATH+1],str2[MAX_PATH+1];
-	char	path[MAX_PATH+1];
-	char 	tmp[MAX_PATH+1];
-	uint	i,j,x,y;
-    file_t	f;
-	DIR*	dir;
-	DIRENT*	dirent;
-
-	for(i=0;i<batup_total;) {
-		curdirnum=batup_dir[i]; 			/* for ARS */
-		lncntr=0;                               /* defeat pause */
-		unpadfname(batup_name[i],tmp);
-		SAFEPRINTF2(str1,"%s%s",cfg.temp_dir,tmp);
-		SAFEPRINTF2(str2,"%s%s",cfg.dir[batup_dir[i]]->path,tmp);
-		if(fexistcase(str1) && fexistcase(str2)) { /* file's in two places */
-			bprintf(text[FileAlreadyThere],batup_name[i]);
-			remove(str1);    /* this is the one received */
-			i++;
-			continue; 
-		}
-		if(fexist(str1))
-			mv(str1,str2,0);
-		SAFECOPY(f.name,batup_name[i]);
-		SAFECOPY(f.desc,batup_desc[i]);
-		f.dir=batup_dir[i];
-		f.misc=batup_misc[i];
-		f.altpath=batup_alt[i];
-		if(uploadfile(&f)) {
-			batup_total--;
-			for(j=i;j<batup_total;j++) {
-				batup_dir[j]=batup_dir[j+1];
-				batup_alt[j]=batup_alt[j+1];
-				batup_misc[j]=batup_misc[j+1];
-				strcpy(batup_name[j],batup_name[j+1]);
-				strcpy(batup_desc[j],batup_desc[j+1]); 
-			} 
+	char src[MAX_PATH + 1];
+	char dest[MAX_PATH + 1];
+
+	str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_UPLOAD);
+	str_list_t filenames = iniGetSectionList(ini, /* prefix: */NULL);
+	for(size_t i = 0; filenames[i] != NULL; ++i) {
+		const char* filename = filenames[i];
+		int dir = batch_file_dir(&cfg, ini, filename);
+		curdirnum = dir; /* for ARS */
+		lncntr = 0; /* defeat pause */
+
+		SAFEPRINTF2(src, "%s%s", cfg.temp_dir, filename);
+		SAFEPRINTF2(dest, "%s%s", cfg.dir[dir]->path, filename);
+		if(fexistcase(src) && fexistcase(dest)) { /* file's in two places */
+			bprintf(text[FileAlreadyThere], filename);
+			remove(src);    /* this is the one received */
+			continue;
 		}
-		else i++; 
+
+		if(fexist(src))
+			mv(src, dest, /* copy: */FALSE);
+
+		file_t f = {{}};
+		if(!batch_file_get(&cfg, ini, filename, &f))
+			continue;
+		if(uploadfile(&f))
+			batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
+		smb_freemsgmem(&f);
 	}
-	if(cfg.upload_dir==INVALID_DIR)
+	iniFreeStringList(filenames);
+	iniFreeStringList(ini);
+
+	if(cfg.upload_dir == INVALID_DIR) // no blind upload dir specified
 		return;
-	dir=opendir(cfg.temp_dir);
+
+	DIR* dir = opendir(cfg.temp_dir);
+	DIRENT* dirent;
 	while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
-		SAFEPRINTF2(tmp,"%s%s",cfg.temp_dir,dirent->d_name);
-		if(isdir(tmp))
+		SAFEPRINTF2(src, "%s%s", cfg.temp_dir,dirent->d_name);
+		if(isdir(src))
 			continue;
-		memset(&f,0,sizeof(file_t));
-		f.dir=cfg.upload_dir;
-		SAFEPRINTF2(path,"%s%s",cfg.dir[f.dir]->path,dirent->d_name);
-		if(fexistcase(path)) {
+		SAFEPRINTF2(dest, "%s%s", cfg.dir[cfg.upload_dir]->path, dirent->d_name);
+		if(fexistcase(dest)) {
 			bprintf(text[FileAlreadyOnline], dirent->d_name);
 			continue;
 		}
-		if(mv(tmp, path, /* copy: */false))
+		if(mv(src, dest, /* copy: */false))
 			continue;
 
-#ifdef _WIN32
-		GetShortPathName(path, tmp, sizeof(tmp));
-#endif
-		padfname(getfname(tmp),f.name);
-
+		bputs(text[SearchingForDupes]);
+		uint x,y;
 		for(x=0;x<usrlibs;x++) {
 			for(y=0;y<usrdirs[x];y++)
 				if(cfg.dir[usrdir[x][y]]->misc&DIR_DUPES
-					&& findfile(&cfg,usrdir[x][y],f.name))
+					&& findfile(&cfg,usrdir[x][y], dirent->d_name, NULL))
 					break;
 			if(y<usrdirs[x])
 				break; 
 		}
+		bputs(text[SearchedForDupes]);
 		if(x<usrlibs) {
-			bprintf(text[FileAlreadyOnline],f.name);
+			bprintf(text[FileAlreadyOnline], dirent->d_name);
 		} else {
-			uploadfile(&f); 
+			file_t f = {{}};
+			f.dir = cfg.upload_dir;
+			smb_hfield_str(&f, SMB_FILENAME, dirent->d_name);
+			uploadfile(&f);
+			smb_freefilemem(&f);
 		}
 	}
 	if(dir!=NULL)
@@ -681,33 +551,32 @@ void sbbs_t::batch_upload()
 /****************************************************************************/
 void sbbs_t::batch_download(int xfrprot)
 {
-    uint	i,j;
-    file_t	f;
+	FILE* fp = batch_list_open(&cfg, useron.number, XFER_BATCH_DOWNLOAD, /* create: */FALSE);
+	if(fp == NULL)
+		return;
+	str_list_t ini = iniReadFile(fp);
+	str_list_t filenames = iniGetSectionList(ini, /* prefix: */NULL);
 
-	for(i=0;i<batdn_total;) {
+	for(size_t i = 0; filenames[i] != NULL; ++i) {
+		char* filename = filenames[i];
 		lncntr=0;                               /* defeat pause */
-		f.dir=curdirnum=batdn_dir[i];
-		SAFECOPY(f.name,batdn_name[i]);
-		f.datoffset=batdn_offset[i];
-		f.size=batdn_size[i];
-		f.altpath=batdn_alt[i];
-		if(xfrprot==-1 || checkprotresult(cfg.prot[xfrprot],0,&f)) {
+		if(xfrprot==-1 || checkprotresult(cfg.prot[xfrprot], 0, filename)) {
+			file_t f = {{}};
+			if(!batch_file_load(&cfg, ini, filename, &f)) {
+				errormsg(WHERE, "loading file", filename, i);
+				continue;
+			}
+			iniRemoveSection(&ini, filename);
 			if(cfg.dir[f.dir]->misc&DIR_TFREE && cur_cps)
 				starttime+=f.size/(ulong)cur_cps;
-			downloadfile(&f);
-			closefile(&f);
-			batdn_total--;
-			for(j=i;j<batdn_total;j++) {
-				strcpy(batdn_name[j],batdn_name[j+1]);
-				batdn_dir[j]=batdn_dir[j+1];
-				batdn_cdt[j]=batdn_cdt[j+1];
-				batdn_alt[j]=batdn_alt[j+1];
-				batdn_size[j]=batdn_size[j+1];
-				batdn_offset[j]=batdn_offset[j+1]; 
-			} 
+			downloadedfile(&f);
+			smb_freefilemem(&f);
 		}
-		else i++; 
 	}
+	iniWriteFile(fp, ini);
+	iniCloseFile(fp);
+	iniFreeStringList(ini);
+	iniFreeStringList(filenames);
 }
 
 /****************************************************************************/
@@ -715,7 +584,8 @@ void sbbs_t::batch_download(int xfrprot)
 /****************************************************************************/
 void sbbs_t::batch_add_list(char *list)
 {
-    char	str[128];
+    char	str[1024];
+	char	path[MAX_PATH + 1];
 	int		file;
 	uint	i,j,k;
     FILE *	stream;
@@ -727,52 +597,31 @@ void sbbs_t::batch_add_list(char *list)
 			checkline();
 			if(!online)
 				break;
-			if(!fgets(str,127,stream))
+			if(!fgets(str, sizeof(str) - 1,stream))
 				break;
 			truncnl(str);
-			sprintf(f.name,"%.12s",str);
 			lncntr=0;
 			for(i=j=k=0;i<usrlibs;i++) {
 				for(j=0;j<usrdirs[i];j++,k++) {
 					outchar('.');
 					if(k && !(k%5))
 						bputs("\b\b\b\b\b     \b\b\b\b\b");
-					if(findfile(&cfg,usrdir[i][j],f.name))
-						break; 
+					if(loadfile(&cfg, usrdir[i][j], str, &f, file_detail_normal)) {
+						if(fexist(getfilepath(&cfg, &f, path)))
+							addtobatdl(&f);
+						else
+							bprintf(text[FileIsNotOnline],f.name);
+						smb_freefilemem(&f);
+						break;
+					}
 				}
 				if(j<usrdirs[i])
 					break; 
 			}
-			if(i<usrlibs) {
-				f.dir=usrdir[i][j];
-				getfileixb(&cfg,&f);
-				f.size=0;
-				getfiledat(&cfg,&f);
-				if(f.size==-1L)
-					bprintf(text[FileIsNotOnline],f.name);
-				else
-					addtobatdl(&f); 
-			} 
 		}
 		fclose(stream);
 		remove(list);
-		CRLF; 
-	}
-}
-/****************************************************************************/
-void sbbs_t::batch_create_list()
-{
-	char	str[MAX_PATH+1];
-	int		i;
-	FILE*	stream;
-
-	if(batdn_total) {
-		SAFEPRINTF2(str,"%sfile/%04u.dwn",cfg.data_dir,useron.number);
-		if((stream=fnopen(NULL,str,O_WRONLY|O_TRUNC|O_CREAT))!=NULL) {
-			for(i=0;i<(int)batdn_total;i++)
-				fprintf(stream,"%s\r\n",batdn_name[i]);
-			fclose(stream); 
-		} 
+		CRLF;
 	}
 }
 
@@ -784,68 +633,97 @@ bool sbbs_t::addtobatdl(file_t* f)
     char	str[256],tmp2[256];
 	char 	tmp[512];
     uint	i;
-	ulong	totalcdt, totalsize, totaltime;
+	uint64_t	totalcost, totalsize;
+	uint64_t	totaltime;
 
 	if(useron.rest&FLAG('D')) {
 		bputs(text[R_Download]);
-		return(false); 
-	}
-	for(i=0;i<batdn_total;i++) {
-		if(!strcmp(batdn_name[i],f->name) && f->dir==batdn_dir[i]) {
-			bprintf(text[FileAlreadyInQueue],f->name);
-			return(false); 
-		} 
-	}
-	if(f->size<=0 /* !fexist(str) */) {
-		bprintf(text[CantAddToQueue],f->name);
-		bprintf(text[FileIsNotOnline],f->name);
-		return(false); 
-	}
-	if(batdn_total>=cfg.max_batdn) {
-		bprintf(text[CantAddToQueue],f->name);
-		bputs(text[BatchDlQueueIsFull]);
-		return(false); 
-	}
-	for(i=0,totalcdt=0;i<batdn_total;i++)
-		if(!is_download_free(&cfg,batdn_dir[i],&useron,&client))
-			totalcdt+=batdn_cdt[i];
-	if(cfg.dir[f->dir]->misc&DIR_FREE) f->cdt=0L;
-	if(!is_download_free(&cfg,f->dir,&useron,&client))
-		totalcdt+=f->cdt;
-	if(totalcdt>useron.cdt+useron.freecdt) {
-		bprintf(text[CantAddToQueue],f->name);
-		bprintf(text[YouOnlyHaveNCredits],ultoac(useron.cdt+useron.freecdt,tmp));
-		return(false); 
+		return false;
 	}
 	if(!chk_ar(cfg.dir[f->dir]->dl_ar,&useron,&client)) {
 		bprintf(text[CantAddToQueue],f->name);
 		bputs(text[CantDownloadFromDir]);
-		return(false); 
+		return false;
 	}
-	for(i=0,totalsize=totaltime=0;i<batdn_total;i++) {
-		totalsize+=batdn_size[i];
-		if(!(cfg.dir[batdn_dir[i]]->misc&DIR_TFREE) && cur_cps)
-			totaltime+=batdn_size[i]/(ulong)cur_cps; 
+	if(getfilesize(&cfg, f) < 1) {
+		bprintf(text[CantAddToQueue], f->name);
+		bprintf(text[FileIsNotOnline], f->name);
+		return false;
 	}
-	totalsize+=f->size;
-	if(!(cfg.dir[f->dir]->misc&DIR_TFREE) && cur_cps)
-		totaltime+=f->size/(ulong)cur_cps;
-	if(!(useron.exempt&FLAG('T')) && totaltime>timeleft) {
-		bprintf(text[CantAddToQueue],f->name);
-		bputs(text[NotEnoughTimeToDl]);
-		return(false); 
+
+	str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+	if(iniSectionExists(ini, f->name)) {
+		bprintf(text[FileAlreadyInQueue], f->name);
+		iniFreeStringList(ini);
+		return false;
 	}
-	strcpy(batdn_name[batdn_total],f->name);
-	batdn_dir[batdn_total]=f->dir;
-	batdn_cdt[batdn_total]=f->cdt;
-	batdn_offset[batdn_total]=f->datoffset;
-	batdn_size[batdn_total]=f->size;
-	batdn_alt[batdn_total]=f->altpath;
-	batdn_total++;
-	openfile(f);
-	bprintf(text[FileAddedToBatDlQueue]
-		,f->name,batdn_total,cfg.max_batdn,ultoac(totalcdt,tmp)
-		,ultoac(totalsize,tmp2)
-		,sectostr(totalsize/(ulong)cur_cps,str));
-	return(true);
+
+	bool result = false;
+	str_list_t filenames = iniGetSectionList(ini, /* prefix: */NULL);
+	if(strListCount(filenames) >= cfg.max_batdn) {
+		bprintf(text[CantAddToQueue] ,f->name);
+		bputs(text[BatchDlQueueIsFull]);
+	} else {
+		totalcost = 0;
+		totaltime = 0;
+		totalsize = 0;
+		for(i=0; filenames[i] != NULL; ++i) {
+			const char* filename = filenames[i];
+			file_t bf = {{}};
+			if(!batch_file_load(&cfg, ini, filename, &bf))
+				continue;
+			totalcost += bf.cost;
+			totalsize += getfilesize(&cfg, &bf);
+			if(!(cfg.dir[bf.dir]->misc&DIR_TFREE) && cur_cps)
+				totaltime += bf.size/(ulong)cur_cps;
+			smb_freefilemem(&bf);
+		}
+		if(cfg.dir[f->dir]->misc&DIR_FREE)
+			f->cost=0L;
+		if(!is_download_free(&cfg,f->dir,&useron,&client))
+			totalcost += f->cost;
+		if(totalcost > useron.cdt+useron.freecdt) {
+			bprintf(text[CantAddToQueue],f->name);
+			bprintf(text[YouOnlyHaveNCredits],ultoac(useron.cdt+useron.freecdt,tmp));
+		} else {
+			totalsize += f->size;
+			if(!(cfg.dir[f->dir]->misc&DIR_TFREE) && cur_cps)
+				totaltime += f->size/(ulong)cur_cps;
+			if(!(useron.exempt&FLAG('T')) && totaltime > timeleft) {
+				bprintf(text[CantAddToQueue],f->name);
+				bputs(text[NotEnoughTimeToDl]);
+			} else {
+				if(batch_file_add(&cfg, useron.number, XFER_BATCH_DOWNLOAD, f)) {
+					bprintf(text[FileAddedToBatDlQueue]
+						,f->name, strListCount(filenames) + 1, cfg.max_batdn, ultoac((ulong)totalcost,tmp)
+						,ultoac((ulong)totalsize,tmp2)
+						,sectostr((ulong)totalsize/(ulong)cur_cps,str));
+					result = true;
+				}
+			}
+		}
+	}
+	iniFreeStringList(ini);
+	iniFreeStringList(filenames);
+	return result;
+}
+
+bool sbbs_t::clearbatdl(void)
+{
+	return batch_list_clear(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+}
+
+bool sbbs_t::clearbatul(void)
+{
+	return batch_list_clear(&cfg, useron.number, XFER_BATCH_UPLOAD);
+}
+
+size_t sbbs_t::batdn_total(void)
+{
+	return batch_file_count(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+}
+
+size_t sbbs_t::batup_total(void)
+{
+	return batch_file_count(&cfg, useron.number, XFER_BATCH_UPLOAD);
 }
diff --git a/src/sbbs3/chksmb.c b/src/sbbs3/chksmb.c
index f2ec6dca7c..cd289af702 100644
--- a/src/sbbs3/chksmb.c
+++ b/src/sbbs3/chksmb.c
@@ -1,8 +1,5 @@
 /* Synchronet message base (SMB) validity checker */
 
-/* $Id: chksmb.c,v 1.72 2020/04/04 20:36:38 rswindell Exp $ */
-// vi: tabstop=4
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -16,21 +13,9 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -41,6 +26,9 @@
 #include <time.h>		/* ctime */
 #include <ctype.h>		/* toupper */
 
+#include "git_branch.h"
+#include "git_hash.h"
+
 /* SMB-specific */
 #include "genwrap.h"
 #include "conwrap.h"	/* getch */
@@ -117,13 +105,21 @@ BOOL contains_ctrl_chars(char* str)
 
 void print_hash(hash_t* hash)
 {
+	char str[128];
+
 	printf("\t%-20s = %lu\n"		,"hash.number"	, (ulong)hash->number);
 	printf("\t%-20s = 0x%08lX\n"	,"hash.time"	, (ulong)hash->time);
 	printf("\t%-20s = %lu\n"		,"hash.length"	, (ulong)hash->length);
 	printf("\t%-20s = 0x%02X\n"		,"hash.source"	, (unsigned)hash->source);
 	printf("\t%-20s = 0x%02X\n"		,"hash.flags"	, (unsigned)hash->flags);
-	printf("\t%-20s = 0x%04hX\n"	,"hash.crc16"	, hash->crc16);
-	printf("\t%-20s = 0x%08X\n"		,"hash.crc32"	, hash->crc32);
+	if(hash->flags & SMB_HASH_CRC16)
+		printf("\t%-20s = 0x%04hX\n"	,"hash.crc16"	, hash->data.crc16);
+	if(hash->flags & SMB_HASH_CRC32)
+		printf("\t%-20s = 0x%08X\n"		,"hash.crc32"	, hash->data.crc32);
+	if(hash->flags & SMB_HASH_MD5)
+		printf("\t%-20s = %s\n"			,"hash.md5"		, MD5_hex(str, hash->data.md5));
+	if(hash->flags & SMB_HASH_SHA1)
+		printf("\t%-20s = %s\n"			,"hash.sha1"	, SHA1_hex(str, hash->data.sha1));
 }
 
 char *usage="\nusage: chksmb [-opts] <filespec.SHD>\n"
@@ -175,15 +171,13 @@ int main(int argc, char **argv)
 	smb_t		smb;
 	idxrec_t	idx;
 	idxrec_t*	idxrec = NULL;
+	fileidxrec_t* fidxrec = NULL;
 	smbmsg_t	msg;
 	hash_t**	hashes;
-	char		revision[16];
 	time_t		now=time(NULL);
 
-	sscanf("$Revision: 1.72 $", "%*s %s", revision);
-
-	fprintf(stderr,"\nCHKSMB v2.30-%s (rev %s) SMBLIB %s - Check Synchronet Message Base\n"
-		,PLATFORM_DESC,revision,smb_lib_ver());
+	fprintf(stderr,"\nCHKSMB v3.19-%s %s/%s SMBLIB %s - Check Synchronet Message Base\n"
+		,PLATFORM_DESC, GIT_BRANCH, GIT_HASH, smb_lib_ver());
 
 	if(argc<2) {
 		printf("%s",usage);
@@ -277,32 +271,34 @@ int main(int argc, char **argv)
 		continue;
 	}
 
+	size_t idxreclen = smb_idxreclen(&smb);
 	off_t sid_length = filelength(fileno(smb.sid_fp));
-	if(sid_length != smb.status.total_msgs * sizeof(idxrec_t)) {
-		printf("!Size of index file (%ld) is incorrect (expected: %ld)\n", sid_length, (long)(smb.status.total_msgs * sizeof(idxrec_t)));
+	if(sid_length != smb.status.total_msgs * idxreclen) {
+		printf("!Size of index file (%ld) is incorrect (expected: %ld)\n", (long)sid_length, (long)(smb.status.total_msgs * idxreclen));
 		smb_close(&smb);
 		errors++;
 		continue;
 	}
 
 	FREE_AND_NULL(idxrec);
-	if((idxrec = calloc(smb.status.total_msgs, sizeof(*idxrec))) == NULL) {
+	if((idxrec = calloc(smb.status.total_msgs, idxreclen)) == NULL) {
 		printf("!Error allocating %lu index record\n", (ulong)smb.status.total_msgs);
 		smb_close(&smb);
 		errors++;
 		continue;
 	}
-	if(fread(idxrec, sizeof(*idxrec), smb.status.total_msgs, smb.sid_fp) != smb.status.total_msgs) {
+	if(fread(idxrec, idxreclen, smb.status.total_msgs, smb.sid_fp) != smb.status.total_msgs) {
 		printf("!Error reading %lu index records\n", (ulong)smb.status.total_msgs);
 		smb_close(&smb);
 		errors++;
 		continue;
 	}
+	fidxrec = (fileidxrec_t*)idxrec;
 
 	off_t shd_hdrs = shd_length - smb.status.header_offset;
 
 	if(shd_hdrs && (shd_hdrs%SHD_BLOCK_LEN) != 0)
-		printf("!Size of msg header records in SHD file incorrect: %lu\n", shd_hdrs);
+		printf("!Size of msg header records in SHD file incorrect: %lu\n", (ulong)shd_hdrs);
 
 	if((i=smb_locksmbhdr(&smb))!=0) {
 		smb_close(&smb);
@@ -311,21 +307,21 @@ int main(int argc, char **argv)
 		continue;
 	}
 
-	if(((shd_hdrs/SHD_BLOCK_LEN)*sizeof(ulong)) != 0) {
-		if((number=malloc(((shd_hdrs/SHD_BLOCK_LEN)+2)*sizeof(ulong)))
+	if(((shd_hdrs/SHD_BLOCK_LEN)*sizeof(*number)) != 0){
+		if((number=malloc((size_t)(((shd_hdrs/SHD_BLOCK_LEN)+2))*sizeof(*number)))
 			==NULL) {
 			printf("Error allocating %lu bytes of memory\n"
-				,(shd_hdrs/SHD_BLOCK_LEN)*sizeof(ulong));
-			return(++errors);
-		}
+				,(ulong)((shd_hdrs/SHD_BLOCK_LEN)*sizeof(*number)));
+			return(++errors); 
+		} 
 	}
 	else
 		number=NULL;
 
 	off_t sdt_length = filelength(fileno(smb.sdt_fp));
 	if(sdt_length && (sdt_length % SDT_BLOCK_LEN) != 0)
-		printf("!Size of SDT file (%lu) not evenly divisble by block length (%u)\n"
-			,sdt_length, SDT_BLOCK_LEN);
+		printf("!Size of SDT file (%lu) not evenly divisible by block length (%u)\n"
+			,(ulong)sdt_length, SDT_BLOCK_LEN);
 
 	if(chkalloc && !(smb.status.attr&SMB_HYPERALLOC)) {
 		if((i=smb_open_ha(&smb))!=0) {
@@ -335,8 +331,8 @@ int main(int argc, char **argv)
 		if(filelength(fileno(smb.shd_fp)) != smb.status.header_offset
 			+ (filelength(fileno(smb.sha_fp)) * SHD_BLOCK_LEN))
 			printf("!Size of SHA file (%lu) does not match SHD file (%lu)\n"
-				,filelength(fileno(smb.sha_fp))
-				,filelength(fileno(smb.shd_fp)));
+				,(ulong)filelength(fileno(smb.sha_fp))
+				,(ulong)filelength(fileno(smb.shd_fp)));
 
 		if((i=smb_open_da(&smb))!=0) {
 			printf("smb_open_da returned %d: %s\n",i,smb.last_error);
@@ -344,8 +340,8 @@ int main(int argc, char **argv)
 		}
 		if((filelength(fileno(smb.sda_fp)))/sizeof(uint16_t) != filelength(fileno(smb.sdt_fp))/SDT_BLOCK_LEN)
 			printf("!Size of SDA file (%lu) does not match SDT file (%lu)\n"
-				,filelength(fileno(smb.sda_fp))
-				,filelength(fileno(smb.sdt_fp)));
+				,(ulong)filelength(fileno(smb.sda_fp))
+				,(ulong)filelength(fileno(smb.sdt_fp)));
 	}
 
 	headers=deleted=orphan=dupenumhdr=attr=zeronum=timeerr=lockerr=hdrerr=0;
@@ -402,15 +398,23 @@ int main(int argc, char **argv)
 		smb_unlockmsghdr(&smb,&msg);
 		size=smb_hdrblocks(smb_getmsghdrlen(&msg))*SHD_BLOCK_LEN;
 
-		SAFECOPY(from,msg.from);
+		if(msg.hdr.type == SMB_MSG_TYPE_FILE)
+			SAFECOPY(from, msg.subj);
+		else
+			SAFECOPY(from, msg.from);
 		truncsp(from);
 		strip_ctrl(from);
 		fprintf(stderr,"#%-5"PRIu32" (%06lX) %-25.25s ",msg.hdr.number,l,from);
 
 		for(n = 0; n < smb.status.total_msgs; n++) {
-			if(idxrec[n].number == msg.hdr.number)
+			idxrec_t* idx;
+			if(idxreclen == sizeof(*fidxrec))
+				idx = &fidxrec[n].idx;
+			else
+				idx = &idxrec[n];
+			if(idx->number == msg.hdr.number)
 				continue;
-			if(idxrec[n].offset > l && idxrec[n].offset < l + (smb_hdrblocks(msg.hdr.length) * SHD_BLOCK_LEN)) {
+			if(idx->offset > l && idx->offset < l + (smb_hdrblocks(msg.hdr.length) * SHD_BLOCK_LEN)) {
 				fprintf(stderr,"%sMessage header overlap\n", beep);
 				msgerr=TRUE;
 				if(extinfo)
@@ -440,7 +444,7 @@ int main(int argc, char **argv)
 			hdrlenerr++;
 		}
 
-		if(chk_msgids && msg.from_net.type == NET_NONE && msg.id == NULL) {
+		if(msg.hdr.type == SMB_MSG_TYPE_NORMAL && chk_msgids && msg.from_net.type == NET_NONE && msg.id == NULL) {
 			fprintf(stderr,"%sNo Message-ID\n",beep);
 			msgerr=TRUE;
 			if(extinfo)
@@ -479,7 +483,7 @@ int main(int argc, char **argv)
 			types++;
 		}
 
-		if(!(smb.status.attr&SMB_EMAIL) && chkhash) {
+		if(!(smb.status.attr&(SMB_EMAIL|SMB_NOHASH|SMB_FILE_DIRECTORY)) && chkhash) {
 			/* Look-up the message hashes */
 			hashes=smb_msghashes(&msg,(uchar*)body,SMB_HASH_SOURCE_DUPE);
 			if(hashes!=NULL
@@ -503,11 +507,13 @@ int main(int argc, char **argv)
 						printf("%-10s: %"PRIu32"\n",		"Length",	hashes[h]->length);
 						printf("%-10s: %x\n",		"Flags",	hashes[h]->flags);
 						if(hashes[h]->flags&SMB_HASH_CRC16)
-							printf("%-10s: %04x\n",	"CRC-16",	hashes[h]->crc16);
+							printf("%-10s: %04x\n",	"CRC-16",	hashes[h]->data.crc16);
 						if(hashes[h]->flags&SMB_HASH_CRC32)
-							printf("%-10s: %08"PRIx32"\n","CRC-32",	hashes[h]->crc32);
+							printf("%-10s: %08"PRIx32"\n","CRC-32",	hashes[h]->data.crc32);
 						if(hashes[h]->flags&SMB_HASH_MD5)
-							printf("%-10s: %s\n",	"MD5",		MD5_hex((BYTE*)str,hashes[h]->md5));
+							printf("%-10s: %s\n",	"MD5",		MD5_hex(str,hashes[h]->data.md5));
+						if(hashes[h]->flags&SMB_HASH_SHA1)
+							printf("%-10s: %s\n",	"SHA-1",	SHA1_hex(str,hashes[h]->data.md5));
 
 #endif
 					}
@@ -571,7 +577,7 @@ int main(int argc, char **argv)
 							"index import date/time\n");
 					timeerr++;
 				}
-				if(msg.hdr.type != SMB_MSG_TYPE_BALLOT
+				if((msg.hdr.type == SMB_MSG_TYPE_NORMAL || msg.hdr.type == SMB_MSG_TYPE_POLL)
 					&& msg.idx.subj!=smb_subject_crc(msg.subj)) {
 					fprintf(stderr,"%sSubject CRC mismatch\n",beep);
 					msgerr=TRUE;
@@ -581,7 +587,7 @@ int main(int argc, char **argv)
 							,smb_subject_crc(msg.subj),msg.idx.subj);
 					subjcrc++;
 				}
-				if(smb.status.attr&SMB_EMAIL
+				if(smb.status.attr & SMB_EMAIL
 					&& (msg.from_ext!=NULL || msg.idx.from)
 					&& (msg.from_ext==NULL || msg.idx.from!=atoi(msg.from_ext))) {
 					fprintf(stderr,"%sFrom extension mismatch\n",beep);
@@ -592,8 +598,8 @@ int main(int argc, char **argv)
 							,msg.from_ext,msg.idx.from);
 					fromcrc++;
 				}
-				if(!(smb.status.attr&SMB_EMAIL)
-					&& msg.hdr.type != SMB_MSG_TYPE_BALLOT
+				if(!(smb.status.attr & SMB_EMAIL)
+					&& (msg.hdr.type == SMB_MSG_TYPE_NORMAL || msg.hdr.type == SMB_MSG_TYPE_POLL)
 					&& msg.idx.from!=smb_name_crc(msg.from)) {
 					fprintf(stderr,"%sFrom CRC mismatch\n",beep);
 					msgerr=TRUE;
@@ -603,7 +609,7 @@ int main(int argc, char **argv)
 							,smb_name_crc(msg.from),msg.idx.from);
 					fromcrc++;
 				}
-				if(smb.status.attr&SMB_EMAIL
+				if(smb.status.attr & SMB_EMAIL
 					&& (msg.to_ext!=NULL || msg.idx.to)
 					&& (msg.to_ext==NULL || msg.idx.to!=atoi(msg.to_ext))) {
 					fprintf(stderr,"%sTo extension mismatch\n",beep);
@@ -614,8 +620,8 @@ int main(int argc, char **argv)
 							,msg.to_ext,msg.idx.to);
 					tocrc++;
 				}
-				if(!(smb.status.attr&SMB_EMAIL)
-					&& msg.hdr.type != SMB_MSG_TYPE_BALLOT
+				if(!(smb.status.attr & SMB_EMAIL)
+					&& (msg.hdr.type == SMB_MSG_TYPE_NORMAL || msg.hdr.type == SMB_MSG_TYPE_POLL)
 					&& msg.to_ext==NULL && msg.idx.to!=smb_name_crc(msg.to)) {
 					fprintf(stderr,"%sTo CRC mismatch\n",beep);
 					msgerr=TRUE;
@@ -807,7 +813,7 @@ int main(int argc, char **argv)
 		fprintf(stderr,"\r%79s\r100%%\n","");
 	}
 
-	total=filelength(fileno(smb.sid_fp))/sizeof(idxrec_t);
+	total=(ulong)filelength(fileno(smb.sid_fp))/smb_idxreclen(&smb);
 
 	dupenum=dupeoff=misnumbered=idxzeronum=idxnumerr=idxofferr=idxerr=delidx=0;
 
@@ -815,19 +821,19 @@ int main(int argc, char **argv)
 
 	fprintf(stderr,"\nChecking %s Index\n\n",smb.file);
 
-	if((offset=(ulong *)malloc(total*sizeof(ulong)))==NULL) {
-		printf("Error allocating %lu bytes of memory\n",total*sizeof(ulong));
-		return(++errors);
+	if((offset=malloc(total*sizeof(*offset)))==NULL) {
+		printf("Error allocating %lu bytes of memory\n",total*sizeof(*offset));
+		return(++errors); 
 	}
-	if((number=(ulong *)malloc(total*sizeof(ulong)))==NULL) {
-		printf("Error allocating %lu bytes of memory\n",total*sizeof(ulong));
-		return(++errors);
+	if((number=malloc(total*sizeof(*number)))==NULL) {
+		printf("Error allocating %lu bytes of memory\n",total*sizeof(*number));
+		return(++errors); 
 	}
-	fseek(smb.sid_fp,0L,SEEK_SET);
 
 	for(l=0;l<total;l++) {
+		fseek(smb.sid_fp, l * smb_idxreclen(&smb), SEEK_SET);
 		fprintf(stderr,"\r%2lu%%  %5lu ",l ? (long)(100.0/((float)total/l)) : 0,l);
-		if(!fread(&idx,sizeof(idxrec_t),1,smb.sid_fp))
+		if(!fread(&idx,sizeof(idx),1,smb.sid_fp))
 			break;
 		fprintf(stderr,"#%-5"PRIu32" (%06"PRIX32") 1st Pass ",idx.number,idx.offset);
 		if(idx.attr&MSG_DELETE) {
@@ -1042,11 +1048,11 @@ int main(int argc, char **argv)
 			,subjcrc);
 	if(fromcrc)
 		printf("%-35.35s (!): %lu\n"
-			,smb.status.attr&SMB_EMAIL ? INDXERR "From Ext" : INDXERR "From CRCs"
+			,smb.status.attr&(SMB_EMAIL|SMB_FILE_DIRECTORY) ? INDXERR "From Ext" : INDXERR "From CRCs"
 			,fromcrc);
 	if(tocrc)
 		printf("%-35.35s (!): %lu\n"
-			,smb.status.attr&SMB_EMAIL ? INDXERR "To Ext" : INDXERR "To CRCs"
+			,smb.status.attr&(SMB_EMAIL|SMB_FILE_DIRECTORY) ? INDXERR "To Ext" : INDXERR "To CRCs"
 			,tocrc);
 	if(intransit)
 		printf("%-35.35s (?): %lu\n"
diff --git a/src/sbbs3/con_out.cpp b/src/sbbs3/con_out.cpp
index 80fbac5d10..8f72f84f9c 100644
--- a/src/sbbs3/con_out.cpp
+++ b/src/sbbs3/con_out.cpp
@@ -1163,18 +1163,13 @@ void sbbs_t::ctrl_a(char x)
 			cursor_left();
 			break;
 		case '/':	/* Conditional new-line */
-			if(column > 0)
-				newline();
+			cond_newline();
 			break;
 		case '\\':	/* Conditional New-line / Continuation prefix (if cols < 80) */
-			if(column > 0 && cols < TERM_COLS_DEFAULT)
-				bputs(text[LongLineContinuationPrefix]);
+			cond_contline();
 			break;
 		case '?':	/* Conditional blank-line */
-			if(column > 0)
-				newline();
-			if(lastlinelen)
-				newline();
+			cond_blankline();
 			break;
 		case '[':   /* Carriage return */
 			carriage_return();
diff --git a/src/sbbs3/ctrl/AboutBoxFormUnit.dfm b/src/sbbs3/ctrl/AboutBoxFormUnit.dfm
index 6c7d2babba..2332f3c872 100644
--- a/src/sbbs3/ctrl/AboutBoxFormUnit.dfm
+++ b/src/sbbs3/ctrl/AboutBoxFormUnit.dfm
@@ -13373,7 +13373,7 @@ object AboutBoxForm: TAboutBoxForm
     Alignment = taRightJustify
     Anchors = [akLeft, akBottom]
     AutoSize = False
-    Caption = 'Copyright 2020  ::'
+    Caption = 'Copyright 2021  ::'
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
     Font.Height = -15
diff --git a/src/sbbs3/ctrl/MainFormUnit.cpp b/src/sbbs3/ctrl/MainFormUnit.cpp
index e0110b8762..a6adb78545 100644
--- a/src/sbbs3/ctrl/MainFormUnit.cpp
+++ b/src/sbbs3/ctrl/MainFormUnit.cpp
@@ -293,9 +293,6 @@ static int lputs(void* p, int level, const char *str)
 
 static void log_msg(TRichEdit* Log, log_msg_t* msg)
 {
-    while(MaxLogLen && Log->Lines->Count >= MaxLogLen)
-        Log->Lines->Delete(0);
-
     AnsiString Line=SystemTimeToDateTime(msg->time).FormatString(LOG_TIME_FMT)+"  ";
     Line+=AnsiString(msg->buf).Trim();
 	if(msg->repeated)
@@ -305,7 +302,13 @@ static void log_msg(TRichEdit* Log, log_msg_t* msg)
     Log->SelAttributes->Assign(
         MainForm->LogAttributes(msg->level, Log->Color, Log->Font));
 	Log->Lines->Add(Line);
-    SendMessage(Log->Handle, WM_VSCROLL, SB_BOTTOM, NULL);
+}
+
+static void logged_msgs(TRichEdit* Log)
+{
+    while(MaxLogLen && Log->Lines->Count >= MaxLogLen)
+        Log->Lines->Delete(0);
+	SendMessage(Log->Handle, WM_VSCROLL, SB_BOTTOM, NULL);
 }
 
 static void bbs_log_msg(log_msg_t* msg)
@@ -3393,60 +3396,86 @@ void __fastcall TMainForm::LogTimerTick(TObject *Sender)
 {
     log_msg_t   msg;
     log_msg_t*  pmsg;
+	ulong count;
+	const int max_lines = 1000;
 
     if(!TelnetPause->Checked) {
-        while(GetServerLogLine(bbs_log,NTSVC_NAME_BBS,&msg))
-            bbs_log_msg(&msg);
+		count = 0;
+        while(count < max_lines && GetServerLogLine(bbs_log,NTSVC_NAME_BBS,&msg))
+            bbs_log_msg(&msg), count++;
 
-        while(GetServerLogLine(event_log,NTSVC_NAME_EVENT,&msg))
-            event_log_msg(&msg);
-
-        while((pmsg=(log_msg_t*)listShiftNode(&bbs_log_list)) != NULL) {
+        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&bbs_log_list)) != NULL) {
             bbs_log_msg(pmsg);
             free(pmsg);
+			count++;
         }
+		if(count)
+			logged_msgs(TelnetForm->Log);
+
+		count = 0;
+        while(count < max_lines && GetServerLogLine(event_log,NTSVC_NAME_EVENT,&msg))
+            event_log_msg(&msg), count++;
 
-        while((pmsg=(log_msg_t*)listShiftNode(&event_log_list)) != NULL) {
+        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&event_log_list)) != NULL) {
             event_log_msg(pmsg);
             free(pmsg);
+			count++;
         }
+		if(count)
+			logged_msgs(EventsForm->Log);
     }
 
     if(!FtpPause->Checked) {
-        while(GetServerLogLine(ftp_log,NTSVC_NAME_FTP,&msg))
-            ftp_log_msg(&msg);
+		count = 0;
+        while(count < max_lines && GetServerLogLine(ftp_log,NTSVC_NAME_FTP,&msg))
+            ftp_log_msg(&msg), count++;
 
-        while((pmsg=(log_msg_t*)listShiftNode(&ftp_log_list)) != NULL) {
+        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&ftp_log_list)) != NULL) {
             ftp_log_msg(pmsg);
             free(pmsg);
+			count++;
         }
+		if(count)
+			logged_msgs(FtpForm->Log);
     }
     if(!MailPause->Checked) {
-        while(GetServerLogLine(mail_log,NTSVC_NAME_MAIL,&msg))
-            mail_log_msg(&msg);
+		count = 0;
+        while(count < max_lines && GetServerLogLine(mail_log,NTSVC_NAME_MAIL,&msg))
+            mail_log_msg(&msg), count++;
 
-        while((pmsg=(log_msg_t*)listShiftNode(&mail_log_list)) != NULL) {
+        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&mail_log_list)) != NULL) {
             mail_log_msg(pmsg);
             free(pmsg);
+			count++;
         }
+		if(count)
+			logged_msgs(MailForm->Log);
     }
     if(!WebPause->Checked) {
-        while(GetServerLogLine(web_log,NTSVC_NAME_WEB,&msg))
-            web_log_msg(&msg);
+		count = 0;
+        while(count < max_lines && GetServerLogLine(web_log,NTSVC_NAME_WEB,&msg))
+            web_log_msg(&msg), count++;
 
-        while((pmsg=(log_msg_t*)listShiftNode(&web_log_list)) != NULL) {
+        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&web_log_list)) != NULL) {
             web_log_msg(pmsg);
             free(pmsg);
+			count++;
         }
+		if(count)
+			logged_msgs(WebForm->Log);
     }
     if(!ServicesPause->Checked) {
-        while(GetServerLogLine(services_log,NTSVC_NAME_SERVICES,&msg))
-            services_log_msg(&msg);
+		count = 0;
+        while(count < max_lines && GetServerLogLine(services_log,NTSVC_NAME_SERVICES,&msg))
+            services_log_msg(&msg), count++;
 
-        while((pmsg=(log_msg_t*)listShiftNode(&services_log_list)) != NULL) {
+        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&services_log_list)) != NULL) {
             services_log_msg(pmsg);
             free(pmsg);
+			count++;
         }
+		if(count)
+			logged_msgs(ServicesForm->Log);
     }
 }
 //---------------------------------------------------------------------------
diff --git a/src/sbbs3/ctrl/sbbsctrl.bpr b/src/sbbs3/ctrl/sbbsctrl.bpr
index 05f779670b..46803f62b9 100644
--- a/src/sbbs3/ctrl/sbbsctrl.bpr
+++ b/src/sbbs3/ctrl/sbbsctrl.bpr
@@ -48,7 +48,7 @@
     <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
     <RELEASELIBPATH value="$(BCB)\lib\release"/>
     <LINKER value="ilink32"/>
-    <USERDEFINES value="SBBS;RINGBUF_SEM;RINGBUF_MUTEX;USE_CRYPTLIB;_DEBUG"/>
+    <USERDEFINES value="SBBS;RINGBUF_SEM;RINGBUF_MUTEX;RINGBUF_EVENT;USE_CRYPTLIB;_DEBUG"/>
     <SYSDEFINES value="NO_STRICT;_VIS_NOLIB"/>
     <MAINSOURCE value="sbbsctrl.cpp"/>
     <INCLUDEPATH value="..\;..;$(BCB)\Projects;..\..\xpdev;..\..\smblib;..\..\hash;$(BCB)\include;$(BCB)\include\vcl;..\..\..\3rdp\win32.release\cryptlib\include;..\..\comio"/>
diff --git a/src/sbbs3/dat_rec.c b/src/sbbs3/dat_rec.c
index c985970428..8b401a94cb 100644
--- a/src/sbbs3/dat_rec.c
+++ b/src/sbbs3/dat_rec.c
@@ -27,7 +27,7 @@
 /* Places into 'strout' CR or ETX terminated string starting at             */
 /* 'start' and ending at 'start'+'length' or terminator from 'strin'        */
 /****************************************************************************/
-int DLLCALL getrec(const char *strin,int start,int length,char *strout)
+int getrec(const char *strin,int start,int length,char *strout)
 {
     int i=0,stop;
 
@@ -45,7 +45,7 @@ int DLLCALL getrec(const char *strin,int start,int length,char *strout)
 /* Places into 'strout', 'strin' starting at 'start' and ending at          */
 /* 'start'+'length'                                                         */
 /****************************************************************************/
-void DLLCALL putrec(char *strout,int start,int length,char *strin)
+void putrec(char *strout,int start,int length, const char *strin)
 {
     int i=0,j;
 
diff --git a/src/sbbs3/dat_rec.h b/src/sbbs3/dat_rec.h
index b266c0bd04..032ae9fde4 100644
--- a/src/sbbs3/dat_rec.h
+++ b/src/sbbs3/dat_rec.h
@@ -1,9 +1,5 @@
-/* dat_rec.h */
-
 /* Synchronet text data access routines (exported) */
 
-/* $Id: dat_rec.h,v 1.5 2019/03/22 21:28:27 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,61 +13,23 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #ifndef _DAT_REC_H
 #define _DAT_REC_H
 
-#ifdef DLLEXPORT
-#undef DLLEXPORT
-#endif
-#ifdef DLLCALL
-#undef DLLCALL
-#endif
-
-#ifdef _WIN32
-	#ifdef __MINGW32__
-		#define DLLEXPORT
-		#define DLLCALL
-	#else
-		#ifdef SBBS_EXPORTS
-			#define DLLEXPORT __declspec(dllexport)
-		#else
-			#define DLLEXPORT __declspec(dllimport)
-		#endif
-		#ifdef __BORLANDC__
-			#define DLLCALL
-		#else
-			#define DLLCALL
-		#endif
-	#endif
-#else
-	#define DLLEXPORT
-	#define DLLCALL
-#endif
+#include "dllexport.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-DLLEXPORT int	DLLCALL getrec(const char *instr,int start,int length,char *outstr); /* Retrieve a record from a string */
-DLLEXPORT void	DLLCALL putrec(char *outstr,int start,int length,char *instr); /* Place a record into a string */
+DLLEXPORT int	getrec(const char *instr, int start, int length, char *outstr); /* Retrieve a record from a string */
+DLLEXPORT void	putrec(char *outstr, int start, int length, const char *instr); /* Place a record into a string */
 
 #ifdef __cplusplus
 }
diff --git a/src/sbbs3/data.cpp b/src/sbbs3/data.cpp
index cbc899fb12..59ad589622 100644
--- a/src/sbbs3/data.cpp
+++ b/src/sbbs3/data.cpp
@@ -97,42 +97,6 @@ uint sbbs_t::finduser(const char* instr, bool silent_failure)
 	return(0);
 }
 
-/****************************************************************************/
-/* Returns the number of user transfers in XFER.IXT for either a dest user  */
-/* source user, or filename.												*/
-/****************************************************************************/
-int sbbs_t::getuserxfers(int fromuser, int destuser, char *fname)
-{
-	char str[256];
-	int file,found=0;
-	FILE *stream;
-
-	SAFEPRINTF(str,"%sxfer.ixt",cfg.data_dir);
-	if(!fexist(str))
-		return(0);
-	if(!flength(str)) {
-		remove(str);
-		return(0); 
-	}
-	if((stream=fnopen(&file,str,O_RDONLY))==NULL) {
-		errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
-		return(0); 
-	}
-	while(!ferror(stream)) {
-		if(!fgets(str,81,stream))
-			break;
-		str[22]=0;
-		if(fname!=NULL && fname[0] && !strncmp(str+5,fname,12))
-				found++;
-		else if(fromuser && atoi(str+18)==fromuser)
-				found++;
-		else if(destuser && atoi(str)==destuser)
-				found++; 
-	}
-	fclose(stream);
-	return(found);
-}
-
 /****************************************************************************/
 /* Return date/time that the specified event should run next				*/
 /****************************************************************************/
diff --git a/src/sbbs3/delfiles.c b/src/sbbs3/delfiles.c
index a017ff8b2b..3104f93db2 100644
--- a/src/sbbs3/delfiles.c
+++ b/src/sbbs3/delfiles.c
@@ -23,10 +23,12 @@
 #include "load_cfg.h"
 #include "filedat.h"
 #include "nopen.h"
+#include "smblib.h"
 #include "str_util.h"
 #include <stdarg.h>
+#include <stdbool.h>
 
-#define DELFILES_VER "1.01"
+#define DELFILES_VER "3.19"
 
 char tmp[256];
 char *crlf="\r\n";
@@ -75,33 +77,45 @@ int lprintf(const char *fmat, ...)
 	return(chcount);
 }
 
+bool delfile(const char *filename)
+{
+	if(remove(filename) != 0) {
+		fprintf(stderr, "ERROR %u (%s) removing file %s\n"
+			,errno, strerror(errno), filename);
+		return false;
+	}
+	return true;
+}
+
 int main(int argc, char **argv)
 {
-	char str[256],fname[MAX_PATH+1],not[MAX_NOTS][9],nots=0,*p;
-	int i,j,dirnum,libnum,file;
-	ulong l,m;
+	char revision[16];
+	char str[256],not[MAX_NOTS][LEN_EXTCODE + 1],nots=0,*p;
+	char fpath[MAX_PATH+1];
+	int i,j,dirnum,libnum;
+	size_t fi;
 	long misc=0;
-	time_t now;
-	file_t workfile;
+	time_t now = time(NULL);
 	scfg_t cfg;
 	glob_t gl;
-	uchar *ixbbuf;
 
 	setvbuf(stdout,NULL,_IONBF,0);
 
-	fprintf(stderr,"\nDELFILES Version %s (%s) - Removes files from Synchronet "
-		"Filebase\n" ,DELFILES_VER, PLATFORM_DESC );
+	sscanf("$Revision: 1.54 $", "%*s %s", revision);
+
+	fprintf(stderr,"\nDELFILES Version %s-%s (rev %s) - Removes files from Synchronet "
+		"Filebase\n" ,DELFILES_VER, PLATFORM_DESC, revision);
 
 	if(argc<2) {
-		printf("\n   usage: DELFILES [dir_code] [switches]\n");
-		printf("\nswitches: -LIB name All directories of specified library\n");
-		printf("          -ALL      Search all directories\n");
-		printf("          -NOT code Exclude specific directory\n");
-		printf("          -OFF      Remove files that are offline "
+		printf("\n   usage: %s <dir_code or * for ALL> [switches]\n", argv[0]);
+		printf("\nswitches: -lib name All directories of specified library\n");
+		printf("          -all      Search all directories\n");
+		printf("          -not code Exclude specific directory\n");
+		printf("          -off      Remove files that are offline "
 			"(don't exist on disk)\n");
-		printf("          -NOL      Remove files with no link "
+		printf("          -nol      Remove files with no link "
 			"(don't exist in database)\n");
-		printf("          -RPT      Report findings only "
+		printf("          -rpt      Report findings only "
 			"(don't delete any files)\n");
 		return(0); 
 	}
@@ -162,7 +176,8 @@ int main(int argc, char **argv)
 				printf("\nDirectory internal code must follow /NOT parameter.\n");
 				return(1); 
 			}
-			sprintf(not[nots++],"%.8s",argv[i]); 
+			SAFECOPY(not[nots], argv[i]); 
+			nots++;
 		}
 		else if(!stricmp(argv[i]+1,"OFF"))
 			misc|=OFFLINE;
@@ -187,117 +202,88 @@ int main(int argc, char **argv)
 		if(!(misc&ALL) && i!=dirnum && cfg.dir[i]->lib!=libnum)
 			continue;
 		for(j=0;j<nots;j++)
-			if(!stricmp(not[j],cfg.dir[i]->code))
+			if(!stricmp(not[j], cfg.dir[i]->code))
 				break;
 		if(j<nots)
 			continue;
 
+		smb_t smb;
+		int result = smb_open_dir(&cfg, &smb, i);
+		if(result != SMB_SUCCESS) {
+			fprintf(stderr, "!ERROR %d (%s) opening %s\n", result, smb.last_error, smb.file);
+			continue;
+		}
+
 		if(misc&NO_LINK && cfg.dir[i]->misc&DIR_FCHK) {
-			strcpy(tmp,cfg.dir[i]->path);
-			SAFEPRINTF(str,"%s*.*",tmp);
-			printf("\nSearching %s for unlinked files\n",str);
-			if(!glob(str, GLOB_MARK, NULL, &gl)) {
+			printf("\nSearching %s for unlinked files\n", cfg.dir[i]->path);
+			sprintf(str, "%s%s", cfg.dir[i]->path, ALLFILES);
+			if(glob(str, GLOB_MARK, NULL, &gl) == 0) {
 				for(j=0; j<(int)gl.gl_pathc; j++) {
+					const char* fname = gl.gl_pathv[j];
 					/* emulate _A_NORMAL */
-					if(isdir(gl.gl_pathv[j]))
+					if(isdir(fname))
 						continue;
-					if(access(gl.gl_pathv[j], R_OK|W_OK))
+					if(access(fname, R_OK|W_OK))
 						continue;
-					padfname(gl.gl_pathv[j],str);
-					/* strupr(str); */
-					if(!findfile(&cfg, i,str)) {
-						sprintf(str,"%s%s",tmp,gl.gl_pathv[j]);
-						printf("Removing %s (not in database)\n",gl.gl_pathv[j]);
-						if(!(misc&REPORT) && remove(str))
-							printf("Error removing %s\n",str); 
-					} 
-				} 
+					if(!smb_findfile(&smb, getfname(fname), /* file: */NULL)) {
+						printf("Not in database: %s\n", fname);
+						if(!(misc&REPORT))
+							delfile(fname);
+					}
+				}
 			}
 			globfree(&gl);
 		}
 
-		if(!cfg.dir[i]->maxage && !(misc&OFFLINE))
+		if(!cfg.dir[i]->maxage && !(misc&OFFLINE)) {
+			smb_close(&smb);
 			continue;
+		}
 
-		printf("\nScanning %s %s\n",cfg.lib[cfg.dir[i]->lib]->sname,cfg.dir[i]->lname);
+		printf("\nScanning %s %s\n", cfg.lib[cfg.dir[i]->lib]->sname, cfg.dir[i]->lname);
 
-		sprintf(str,"%s%s.ixb",cfg.dir[i]->data_dir,cfg.dir[i]->code);
-		if((file=nopen(str,O_RDONLY|O_BINARY))==-1)
-			continue;
-		l=filelength(file);
-		if(!l) {
-			close(file);
-			continue; 
-		}
-		if((ixbbuf=malloc(l))==NULL) {
-			close(file);
-			printf("\7ERR_ALLOC %s %lu\n",str,l);
-			continue; 
-		}
-		if(read(file,ixbbuf,l)!=(int)l) {
-			close(file);
-			printf("\7ERR_READ %s %lu\n",str,l);
-			free((char *)ixbbuf);
-			continue; 
-		}
-		close(file);
+		size_t file_count;
+		file_t* file_list = loadfiles(&smb, NULL, 0, /* extdesc: */FALSE, FILE_SORT_NATURAL, &file_count);
 
-		m=0L;
-		now=time(NULL);
-		while(m<l) {
-			memset(&workfile,0,sizeof(file_t));
-			for(j=0;j<12 && m<l;j++)
-				if(j==8)
-					fname[j]='.';
-				else
-					fname[j]=ixbbuf[m++];
-			fname[j]=0;
-			strcpy(workfile.name,fname);
-			unpadfname(workfile.name,fname);
-			workfile.dir=i;
-			SAFEPRINTF2(str,"%s%s"
-				,workfile.altpath>0 && workfile.altpath<=cfg.altpaths
-					? cfg.altpath[workfile.altpath-1]
-				: cfg.dir[workfile.dir]->path,fname);
-			workfile.datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)
-				|((long)ixbbuf[m+2]<<16);
-			workfile.dateuled=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
-				|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24));
-			workfile.datedled=(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
-				|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24));
-			m+=11;
-			if(cfg.dir[i]->maxage && cfg.dir[i]->misc&DIR_SINCEDL && workfile.datedled
-				&& (now-workfile.datedled)/86400L>cfg.dir[i]->maxage) {
-					printf("Deleting %s (%ld days since last download)\n",fname
-						,(long)(now-workfile.datedled)/86400L);
-					getfiledat(&cfg, &workfile);
+		for(fi = 0; fi < file_count; fi++) {
+			file_t* f = &file_list[fi];
+			getfilepath(&cfg, f, fpath);
+			if(cfg.dir[i]->maxage && cfg.dir[i]->misc&DIR_SINCEDL && f->hdr.last_downloaded
+				&& (now - f->hdr.last_downloaded)/86400L > cfg.dir[i]->maxage) {
+					printf("Deleting %s (%ld days since last download)\n"
+						,f->name
+						,(long)(now - f->hdr.last_downloaded)/86400L);
 					if(!(misc&REPORT)) {
-						removefiledat(&cfg, &workfile);
-						if(remove(str))
-							printf("Error removing %s\n",str); 
+						if(smb_removefile(&smb, f) == SMB_SUCCESS)
+							delfile(fpath);
+						else
+							printf("ERROR (%s) removing file from database\n", smb.last_error);
 					} 
 			}
 			else if(cfg.dir[i]->maxage
-				&& !(workfile.datedled && cfg.dir[i]->misc&DIR_SINCEDL)
-				&& (now-workfile.dateuled)/86400L>cfg.dir[i]->maxage) {
-					printf("Deleting %s (uploaded %ld days ago)\n",fname
-						,(long)(now-workfile.dateuled)/86400L);
-					getfiledat(&cfg, &workfile);
+				&& !(f->hdr.last_downloaded && cfg.dir[i]->misc&DIR_SINCEDL)
+				&& (now - f->hdr.when_imported.time)/86400L > cfg.dir[i]->maxage) {
+					printf("Deleting %s (uploaded %ld days ago)\n"
+						,f->name
+						,(long)(now - f->hdr.when_imported.time)/86400L);
 					if(!(misc&REPORT)) {
-						removefiledat(&cfg, &workfile);
-						if(remove(str))
-							printf("Error removing %s\n",str); 
+						if(smb_removefile(&smb, f) == SMB_SUCCESS)
+							delfile(fpath);
+						else
+							printf("ERROR (%s) removing file from database\n", smb.last_error);
 					} 
 			}
-			else if(misc&OFFLINE && cfg.dir[i]->misc&DIR_FCHK && !fexist(str)) {
-					printf("Removing %s (doesn't exist)\n",fname);
-					getfiledat(&cfg, &workfile);
-					if(!(misc&REPORT))
-						removefiledat(&cfg, &workfile); 
+			else if(misc&OFFLINE && cfg.dir[i]->misc&DIR_FCHK && !fexist(fpath)) {
+					printf("Removing %s (doesn't exist)\n", f->name);
+					if(!(misc&REPORT)) {
+						if(smb_removefile(&smb, f) != SMB_SUCCESS)
+							printf("ERROR (%s) removing file from database\n", smb.last_error);
+					}
 			} 
 		}
+		freefiles(file_list, file_count);
 
-		free((char *)ixbbuf); 
+		smb_close(&smb);
 	}
 
 	return(0);
diff --git a/src/sbbs3/delfiles.vcxproj b/src/sbbs3/delfiles.vcxproj
index 5b201b9f58..af7f406281 100644
--- a/src/sbbs3/delfiles.vcxproj
+++ b/src/sbbs3/delfiles.vcxproj
@@ -38,6 +38,7 @@
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -48,6 +49,7 @@
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
@@ -160,8 +162,12 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="userdat.c" />
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\smblib\smblib.vcxproj">
+      <Project>{d674842b-2f41-42cb-9426-b3c4b0682574}</Project>
+    </ProjectReference>
     <ProjectReference Include="..\xpdev\xpdev.vcxproj">
       <Project>{7428a1e8-56b7-4868-9c0e-29d031689feb}</Project>
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
diff --git a/src/sbbs3/download.cpp b/src/sbbs3/download.cpp
index e4dad09a54..8590bba83f 100644
--- a/src/sbbs3/download.cpp
+++ b/src/sbbs3/download.cpp
@@ -21,129 +21,46 @@
 
 #include "sbbs.h"
 #include "telnet.h"
+#include "filedat.h"
 
 /****************************************************************************/
+/* Call this function *AFTER* a file has been successfully downloaded		*/
 /* Updates downloader, uploader and downloaded file data                    */
 /* Must have offset, dir and name fields filled prior to call.              */
 /****************************************************************************/
-void sbbs_t::downloadfile(file_t* f)
+void sbbs_t::downloadedfile(file_t* f)
 {
-    char		str[MAX_PATH+1],fname[13];
+    char		str[MAX_PATH+1];
 	char 		tmp[512];
-    int			i,file;
-	long		mod;
-	long		length;
-    ulong		l;
-	user_t		uploader;
-
-	getfiledat(&cfg,f); /* Get current data - right after download */
-	if((length=f->size)<0L)
-		length=0L;
-	if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
-		logon_dlb+=length;  /* Update 'this call' stats */
+	off_t		length;
+
+	length = getfilesize(&cfg, f);
+	if(length > 0 && !(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
+		logon_dlb += length;  /* Update 'this call' stats */
 		logon_dls++;
 	}
-	bprintf(text[FileNBytesSent],f->name,ultoac(length,tmp));
+	bprintf(text[FileNBytesSent],f->name,ultoac((ulong)length,tmp));
 	SAFEPRINTF3(str,"downloaded %s from %s %s"
 		,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname
 		,cfg.dir[f->dir]->sname);
 	logline("D-",str);
-	/****************************/
-	/* Update Downloader's Info */
-	/****************************/
-	user_downloaded(&cfg, &useron, 1, length);
-	if(!is_download_free(&cfg,f->dir,&useron,&client))
-		subtract_cdt(&cfg,&useron,f->cdt);
-	/**************************/
-	/* Update Uploader's Info */
-	/**************************/
-	i=matchuser(&cfg,f->uler,TRUE /*sysop_alias*/);
-	memset(&uploader, 0, sizeof(uploader));
-	uploader.number=i;
-	getuserdat(&cfg,&uploader);
-	if(i && i!=useron.number && uploader.firston<f->dateuled) {
-		l=f->cdt;
-		if(!(cfg.dir[f->dir]->misc&DIR_CDTDL))	/* Don't give credits on d/l */
-			l=0;
-		if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps) { /* Give min instead of cdt */
-			mod=((ulong)(l*(cfg.dir[f->dir]->dn_pct/100.0))/cur_cps)/60;
-			adjustuserrec(&cfg,i,U_MIN,10,mod);
-			SAFEPRINTF(tmp,"%lu minute",mod);
-		} else {
-			mod=(ulong)(l*(cfg.dir[f->dir]->dn_pct/100.0));
-			adjustuserrec(&cfg,i,U_CDT,10,mod);
-			ultoac(mod,tmp);
-		}
-		if(!(cfg.dir[f->dir]->misc&DIR_QUIET)) {
-			SAFEPRINTF4(str,text[DownloadUserMsg]
-				,!strcmp(cfg.dir[f->dir]->code,"TEMP") ? temp_file : f->name
-				,!strcmp(cfg.dir[f->dir]->code,"TEMP") ? text[Partially] : nulstr
-				,useron.alias,tmp);
-			putsmsg(&cfg,i,str);
-		}
-	}
-	/*******************/
-	/* Update IXB File */
-	/*******************/
-	f->datedled=time32(NULL);
-	SAFEPRINTF2(str,"%s%s.ixb",cfg.dir[f->dir]->data_dir,cfg.dir[f->dir]->code);
-	if((file=nopen(str,O_RDWR))==-1) {
-		errormsg(WHERE,ERR_OPEN,str,O_RDWR);
-		return;
-	}
-	length=(long)filelength(file);
-	if(length%F_IXBSIZE) {
-		close(file);
-		errormsg(WHERE,ERR_LEN,str,length);
-		return;
-	}
-	strcpy(fname,f->name);
-	for(i=8;i<12;i++)   /* Turn FILENAME.EXT into FILENAMEEXT */
-		fname[i]=fname[i+1];
-	for(l=0;l<(ulong)length;l+=F_IXBSIZE) {
-		read(file,str,F_IXBSIZE);      /* Look for the filename in the IXB file */
-		str[11]=0;
-		if(!stricmp(fname,str))
-			break;
-	}
-	if(l>=(ulong)length) {
-		close(file);
-		errormsg(WHERE,ERR_CHK,f->name,0);
-		return;
-	}
-	lseek(file,l+18,SEEK_SET);
-	write(file,&f->datedled,4);  /* Write the current time stamp for datedled */
-	close(file);
-	/*******************/
-	/* Update DAT File */
-	/*******************/
-	f->timesdled++;
-	putfiledat(&cfg,f);
-	/******************************************/
-	/* Update User to User index if necessary */
-	/******************************************/
-	if(f->dir==cfg.user_dir) {
-		rmuserxfers(&cfg,0,useron.number,f->name);
-		if(!getuserxfers(0,0,f->name)) { /* check if any ixt entries left */
-			remove(getfilepath(&cfg,f,str));
-			removefiledat(&cfg,f);
-		}
-	}
+
+	user_downloaded_file(&cfg, &useron, &client, f->dir, f->name, length);
 
 	user_event(EVENT_DOWNLOAD);
 }
 
 /****************************************************************************/
 /* This function is called when a file is unsuccessfully downloaded.        */
-/* It logs the tranfer time and checks for possible leech protocol use.     */
+/* It logs the transfer time and checks for possible leech protocol use.    */
 /****************************************************************************/
-void sbbs_t::notdownloaded(ulong size, time_t start, time_t end)
+void sbbs_t::notdownloaded(off_t size, time_t start, time_t end)
 {
     char	str[256],tmp2[256];
 	char 	tmp[512];
 
 	SAFEPRINTF2(str,"Estimated Time: %s  Transfer Time: %s"
-		,sectostr(cur_cps ? size/cur_cps : 0,tmp)
+		,sectostr(cur_cps ? (uint)(size/cur_cps) : 0,tmp)
 		,sectostr((uint)(end-start),tmp2));
 	logline(nulstr,str);
 	if(cfg.leech_pct && cur_cps                 /* leech detection */
@@ -166,8 +83,6 @@ const char* sbbs_t::protcmdline(prot_t* prot, enum XFER_TYPE type)
 			return(prot->batulcmd);
 		case XFER_BATCH_DOWNLOAD:
 			return(prot->batdlcmd);
-		case XFER_BIDIR:
-			return(prot->bicmd);
 	}
 
 	return("invalid transfer type");
@@ -177,7 +92,7 @@ const char* sbbs_t::protcmdline(prot_t* prot, enum XFER_TYPE type)
 /* Handles start and stop routines for transfer protocols                   */
 /****************************************************************************/
 int sbbs_t::protocol(prot_t* prot, enum XFER_TYPE type
-					 ,char *fpath, char *fspec, bool cd, bool autohangup)
+					 ,const char *fpath, const char *fspec, bool cd, bool autohangup)
 {
 	char	protlog[256],*p;
 	char*	cmdline;
@@ -226,8 +141,6 @@ int sbbs_t::protocol(prot_t* prot, enum XFER_TYPE type
 	request_telnet_opt(TELNET_WONT,TELNET_BINARY_TX);
 
 	sys_status&=~SS_FILEXFER;
-	if(online==ON_REMOTE)
-		rioctl(IOFB);
 
 	// Save DSZLOG to logfile
 	if((stream=fnopen(NULL,protlog,O_RDONLY))!=NULL) {
@@ -306,7 +219,7 @@ bool sbbs_t::checkdszlog(const char* fpath)
 
 	SAFEPRINTF(path,"%sPROTOCOL.LOG",cfg.node_dir);
 	if((fp=fopen(path,"r"))==NULL)
-		return(false);
+		return false;
 
 	SAFECOPY(rpath, fpath);
 	fexistcase(rpath);
@@ -355,40 +268,50 @@ bool sbbs_t::checkdszlog(const char* fpath)
 
 /****************************************************************************/
 /* Checks dsz compatible log file for errors in transfer                    */
-/* Returns 1 if the file in the struct file_t was successfuly transfered    */
+/* Returns 1 if the file in the struct file_t was successfully transfered   */
 /****************************************************************************/
-bool sbbs_t::checkprotresult(prot_t* prot, int error, file_t* f)
+bool sbbs_t::checkprotresult(prot_t* prot, int error, const char* fpath)
 {
-	char str[512];
-	char tmp[128];
 	bool success;
-	char fpath[MAX_PATH+1];
 
-	getfilepath(&cfg,f,fpath);
 	if(prot->misc&PROT_DSZLOG)
 		success=checkdszlog(fpath);
 	else
 		success=(error==0);
 
-	if(!success) {
-		bprintf(text[FileNotSent],f->name);
+	if(!success)
+		bprintf(text[FileNotSent], getfname(fpath));
+
+	return success;
+}
+
+bool sbbs_t::checkprotresult(prot_t* prot, int error, file_t* f)
+{
+	char str[512];
+	char tmp[128];
+	char fpath[MAX_PATH+1];
+
+	getfilepath(&cfg, f, fpath);
+	if(!checkprotresult(prot, error, fpath)) {
 		if(f->dir<cfg.total_dirs)
 			SAFEPRINTF4(str,"attempted to download %s (%s) from %s %s"
-				,f->name,ultoac(f->size,tmp)
+				,f->name,ultoac((ulong)f->size,tmp)
 				,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
 		else if(f->dir==cfg.total_dirs)
 			SAFECOPY(str,"attempted to download QWK packet");
-		else if(f->dir==cfg.total_dirs+1)
+		else if(f->dir == cfg.total_dirs + 1)
 			SAFEPRINTF(str,"attempted to download attached file: %s"
 				,f->name);
+		else
+			SAFEPRINTF2(str,"attempted to download file (%s) from unknown dir: %ld"
+				,f->name, (long)f->dir);
 		logline(LOG_NOTICE,"D!",str);
-		return(false);
+		return false; 
 	}
-	return(true);
+	return true;
 }
 
 
-
 /************************************************************************/
 /* Wait (for a limited period of time) for sequential dev to become 	*/
 /* available for file retrieval 										*/
@@ -453,7 +376,7 @@ bool sbbs_t::sendfile(char* fname, char prot, const char* desc, bool autohang)
 		ch=(char)getkeys(keys,0);
 
 		if(ch==text[YNQP][2] || sys_status&SS_ABORT)
-			return(false);
+			return false; 
 	}
 	for(i=0;i<cfg.total_prots;i++)
 		if(cfg.prot[i]->mnemonic==ch && chk_ar(cfg.prot[i]->ar,&useron,&client))
@@ -471,9 +394,9 @@ bool sbbs_t::sendfile(char* fname, char prot, const char* desc, bool autohang)
 		logon_dlb += length;	/* Update stats */
 		logon_dls++;
 		useron.dls = (ushort)adjustuserrec(&cfg, useron.number, U_DLS, 5, 1);
-		useron.dlb = adjustuserrec(&cfg,useron.number, U_DLB, 10, length);
+		useron.dlb = adjustuserrec(&cfg,useron.number, U_DLB, 10, (long)length);
 		char bytes[32];
-		ultoac(length, bytes);
+		ultoac((ulong)length, bytes);
 		bprintf(text[FileNBytesSent], getfname(fname), bytes);
 		char str[128];
 		SAFEPRINTF3(str, "downloaded %s: %s (%s bytes)"
@@ -488,3 +411,27 @@ bool sbbs_t::sendfile(char* fname, char prot, const char* desc, bool autohang)
 	}
 	return result;
 }
+
+// contains some copy/pasta from downloadedfile()
+bool sbbs_t::sendfile(file_t* f, char prot, bool autohang)
+{
+	char path[MAX_PATH + 1];
+	char str[256];
+
+	SAFEPRINTF2(str, "from %s %s"
+		,cfg.lib[cfg.dir[f->dir]->lib]->sname
+		,cfg.dir[f->dir]->sname);
+	bool result = sendfile(getfilepath(&cfg, f, path), prot, str, autohang);
+	if(result == true) {
+		if(cfg.dir[f->dir]->misc&DIR_TFREE && cur_cps)
+			starttime += f->size / (ulong)cur_cps;
+		off_t length = getfilesize(&cfg, f);
+		if(length > 0 && !(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
+			logon_dlb += length;  /* Update 'this call' stats */
+			logon_dls++;
+		}
+		user_downloaded_file(&cfg, &useron, &client, f->dir, f->name, length);
+		user_event(EVENT_DOWNLOAD);
+	}
+	return result;
+}
diff --git a/src/sbbs3/dupefind.c b/src/sbbs3/dupefind.c
index b2ec2b1990..f8d514e3ab 100644
--- a/src/sbbs3/dupefind.c
+++ b/src/sbbs3/dupefind.c
@@ -20,11 +20,12 @@
 #include "scfgdefs.h"
 #include "str_util.h"
 #include "load_cfg.h"
+#include "smblib.h"
 #include "nopen.h"
 #include "crc32.h"
 #include <stdarg.h>
 
-#define DUPEFIND_VER "1.02"
+#define DUPEFIND_VER "3.19"
 
 char* crlf="\r\n";
 
@@ -65,37 +66,38 @@ int lprintf(const char *fmat, ...)
 	return(chcount);
 }
 
-char *display_filename(scfg_t *cfg, ushort dir_num,ushort fil_off)
+char *display_filename(scfg_t *cfg, uint dirnum, uint32_t fil_off)
 {
 	static char str[256];
-	char fname[13];
-	int file;
-
-	sprintf(str,"%s%s.ixb",cfg->dir[dir_num]->data_dir,cfg->dir[dir_num]->code);
-	if((file=nopen(str,O_RDONLY))==-1)
-		return("UNKNOWN");
-	lseek(file,(long)(22*(fil_off-1)),SEEK_SET);
-	read(file,fname,11);
-	close(file);
-
-	sprintf(str,"%-8.8s.%c%c%c",fname,fname[8],fname[9],fname[10]);
-	return(str);
+	static smb_t smb;
+	if(smb_open_dir(cfg, &smb, dirnum) != SMB_SUCCESS)
+		return smb.last_error;
+	smb_fseek(smb.sid_fp, (fil_off - 1) * sizeof(fileidxrec_t), SEEK_SET);
+	fileidxrec_t idx;
+	if(smb_fread(&smb, &idx, sizeof(idx), smb.sid_fp) != sizeof(idx)) {
+		smb_close(&smb);
+		return smb.last_error;
+	}
+	smb_close(&smb);
+	SAFECOPY(str, idx.name);
+	return str;
 }
 
 int main(int argc,char **argv)
 {
-	char str[256],*ixbbuf,*p;
-	ulong **fcrc,*foundcrc,total_found=0L;
+	char str[256], *p;
+	uint32_t **fcrc,*foundcrc;
+	ulong total_found=0L;
 	ulong g;
-	ushort i,j,k,h,start_lib=0,end_lib=0,found=-1;
-	int file;
-    long l,m;
+	uint i,j,k,h,start_lib=0,end_lib=0,found=-1;
 	scfg_t cfg;
 
 	setvbuf(stdout,NULL,_IONBF,0);
 
-	fprintf(stderr,"\nDUPEFIND Version %s (%s) - Synchronet Duplicate File "
-		"Finder\n", DUPEFIND_VER, PLATFORM_DESC);
+	char revision[16];
+	sscanf("$Revision: 1.54 $", "%*s %s", revision);
+	fprintf(stderr,"\nDUPEFIND v%s-%s (rev %s) - Synchronet Duplicate File "
+		"Finder\n", DUPEFIND_VER, PLATFORM_DESC, revision);
 
     p = get_ctrl_dir(/* warn: */TRUE);
 
@@ -126,78 +128,73 @@ int main(int argc,char **argv)
 	if(argc>2)
         end_lib=atoi(argv[2])-1;
 
-	if((fcrc=(ulong **)malloc(cfg.total_dirs*sizeof(ulong *)))==NULL) {
+	if((fcrc = malloc(cfg.total_dirs*sizeof(uint32_t *)))==NULL) {
 		printf("Not enough memory for CRCs.\r\n");
 		return(1); 
 	}
+	memset(fcrc, 0, cfg.total_dirs*sizeof(uint32_t *));
 
 	for(i=0;i<cfg.total_dirs;i++) {
-		fprintf(stderr,"Reading directory index %u of %u\r",i+1,cfg.total_dirs);
-        sprintf(str,"%s%s.ixb",cfg.dir[i]->data_dir,cfg.dir[i]->code);
-		if((file=nopen(str,O_RDONLY|O_BINARY))==-1) {
-			fcrc[i]=(ulong *)malloc(1*sizeof(ulong));
-            fcrc[i][0]=0;
-			continue; 
+		if(cfg.dir[i]->lib < start_lib || cfg.dir[i]->lib > end_lib)
+			continue;
+		printf("Reading directory %u of %u\r",i+1,cfg.total_dirs);
+		smb_t smb;
+		int result = smb_open_dir(&cfg, &smb, i);
+		if(result != SMB_SUCCESS) {
+			fprintf(stderr, "!ERROR %d (%s) opening %s\n"
+				,result, smb.last_error, smb.file);
+			continue;
 		}
-        l=filelength(file);
-		if(!l || (cfg.dir[i]->lib<start_lib || cfg.dir[i]->lib>end_lib)) {
-            close(file);
-			fcrc[i]=(ulong *)malloc(1*sizeof(ulong));
-			fcrc[i][0]=0;
-            continue; 
+		if(smb.status.total_files < 1) {
+			smb_close(&smb);
+			continue;
 		}
-		if((fcrc[i]=(ulong *)malloc((l/22+2)*sizeof(ulong)))==NULL) {
+		if((fcrc[i] = malloc(smb.status.total_files * sizeof(uint32_t)))==NULL) {
             printf("Not enough memory for CRCs.\r\n");
             return(1); 
 		}
-		fcrc[i][0]=(ulong)(l/22);
-        if((ixbbuf=(char *)malloc(l))==NULL) {
-            close(file);
-            printf("\7Error allocating memory for index %s.\r\n",str);
-            continue; 
+		j=0;
+		fcrc[i][j++] = smb.status.total_files;
+		rewind(smb.sid_fp);
+		while(!feof(smb.sid_fp)) {
+			fileidxrec_t idx;
+			if(smb_fread(&smb, &idx, sizeof(idx), smb.sid_fp) != sizeof(idx))
+				break;
+			char filename[sizeof(idx.name) + 1];
+			SAFECOPY(filename, idx.name);
+			fcrc[i][j++]=crc32(filename, 0);
 		}
-        if(read(file,ixbbuf,l)!=l) {
-            close(file);
-            printf("\7Error reading %s.\r\n",str);
-			free(ixbbuf);
-            continue; 
-		}
-        close(file);
-		j=1;
-		m=0L;
-		while(m<l) {
-			sprintf(str,"%-11.11s",(ixbbuf+m));
-			strupr(str);
-			fcrc[i][j++]=crc32(str,0);
-			m+=22; 
-		}
-		free(ixbbuf); 
+		smb_close(&smb);
 	}
 	lputs("\n");
 
-	foundcrc=0L;
+	foundcrc = NULL;
 	for(i=0;i<cfg.total_dirs;i++) {
 		if(cfg.dir[i]->lib<start_lib || cfg.dir[i]->lib>end_lib)
 			continue;
 		lprintf("Scanning %s %s\n",cfg.lib[cfg.dir[i]->lib]->sname,cfg.dir[i]->sname);
+		if(fcrc[i] == NULL)
+			continue;
 		for(k=1;k<fcrc[i][0];k++) {
 			for(j=i+1;j<cfg.total_dirs;j++) {
 				if(cfg.dir[j]->lib<start_lib || cfg.dir[j]->lib>end_lib)
 					continue;
+				if(fcrc[j] == NULL)
+					continue;
 				for(h=1;h<fcrc[j][0];h++) {
 					if(fcrc[i][k]==fcrc[j][h]) {
 						if(found!=k) {
 							found=k;
 							for(g=0;g<total_found;g++) {
 								if(foundcrc[g]==fcrc[i][k])
-									g=total_found+1; 
+									break; 
 							}
 							if(g==total_found) {
 								++total_found;
-								if((foundcrc=(ulong *)realloc(foundcrc
-									,total_found*sizeof(ulong)))==NULL) {
-								printf("Out of memory reallocating\r\n");
-								return(1); 
+								if((foundcrc = realloc(foundcrc
+									,total_found*sizeof(uint32_t)))==NULL) {
+									printf("Out of memory reallocating\r\n");
+									return(1); 
 								} 
 							}
 							else
diff --git a/src/sbbs3/dupefind.vcxproj b/src/sbbs3/dupefind.vcxproj
index daa7e3d2c0..3a1846d25e 100644
--- a/src/sbbs3/dupefind.vcxproj
+++ b/src/sbbs3/dupefind.vcxproj
@@ -38,6 +38,7 @@
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -48,6 +49,7 @@
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
@@ -160,6 +162,7 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="userdat.c" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\smblib\smblib.vcxproj">
diff --git a/src/sbbs3/email.cpp b/src/sbbs3/email.cpp
index 1a0245dc08..77cca6f921 100644
--- a/src/sbbs3/email.cpp
+++ b/src/sbbs3/email.cpp
@@ -40,7 +40,7 @@ bool sbbs_t::email(int usernumber, const char *top, const char *subj, long mode,
 	int 		i,j,x,file;
 	long		l;
 	long		length;
-	ulong		offset;
+	off_t		offset;
 	uint32_t	crc=0xffffffffUL;
 	FILE*		instream;
 	node_t		node;
@@ -271,7 +271,7 @@ bool sbbs_t::email(int usernumber, const char *top, const char *subj, long mode,
 		} 
 	}
 
-	msg.hdr.offset=offset;
+	msg.hdr.offset=(uint32_t)offset;
 
 	username(&cfg,usernumber,str);
 	smb_hfield_str(&msg,RECIPIENT,str);
diff --git a/src/sbbs3/exec.cpp b/src/sbbs3/exec.cpp
index 7900c368f3..cd9e0e5a59 100644
--- a/src/sbbs3/exec.cpp
+++ b/src/sbbs3/exec.cpp
@@ -1,4 +1,4 @@
-/* Synchronet command shell/module interpretter */
+/* Synchronet command shell/module interpreter */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -802,7 +802,7 @@ long sbbs_t::exec_bin(const char *cmdline, csi_t *csi, const char* startup_dir)
 
 	memcpy(&bin,csi,sizeof(csi_t));
 	clearvars(&bin);
-	bin.length = filelength(file);
+	bin.length = (long)filelength(file);
 	if(bin.length < 1) {
 		close(file);
 		errormsg(WHERE, ERR_LEN, str, bin.length);
@@ -1157,7 +1157,8 @@ void sbbs_t::skipto(csi_t *csi, uchar inst)
 
 int sbbs_t::exec(csi_t *csi)
 {
-	char	str[256],*path;
+	char	str[256];
+	const char* path;
 	char 	tmp[512];
 	uchar	buf[1025],ch;
 	int 	i,j,file;
@@ -1227,7 +1228,7 @@ int sbbs_t::exec(csi_t *csi)
 							}
 							else if(text[i][0]==0) {
 								free(text[i]);
-								text[i]=nulstr; 
+								text[i]=(char*)nulstr; 
 							} 
 						}
 						if(i<TOTAL_TEXT) {
diff --git a/src/sbbs3/execfile.cpp b/src/sbbs3/execfile.cpp
index a27f220ea6..dae7a9c871 100644
--- a/src/sbbs3/execfile.cpp
+++ b/src/sbbs3/execfile.cpp
@@ -1,9 +1,5 @@
-/* execfile.cpp */
-
 /* Synchronet file transfer-related command shell/module routines */
 
-/* $Id: execfile.cpp,v 1.18 2020/05/24 08:11:45 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,26 +13,15 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include "sbbs.h"
 #include "cmdshell.h"
+#include "filedat.h"
 
 int sbbs_t::exec_file(csi_t *csi)
 {
@@ -319,43 +304,37 @@ int sbbs_t::exec_file(csi_t *csi)
 				bputs(text[R_Download]);
 				return(0); 
 			}
-			padfname(csi->str,str);
-			strupr(str);
-			if(!listfileinfo(usrdir[curlib][curdir[curlib]],str,FI_DOWNLOAD)) {
+			if(!listfileinfo(usrdir[curlib][curdir[curlib]], csi->str, FI_DOWNLOAD)
+				&& strcmp(csi->str, ALLFILES) != 0) {
 				bputs(text[SearchingAllDirs]);
-				for(i=0;i<usrdirs[curlib];i++)
+				for(i=0;i<usrdirs[curlib];i++) {
+					if(msgabort())
+						return 0;
 					if(i!=curdir[curlib] &&
-						(s=listfileinfo(usrdir[curlib][i],str,FI_DOWNLOAD))!=0)
-						if(s==-1 || (!strchr(str,'?') && !strchr(str,'*')))
+						(s=listfileinfo(usrdir[curlib][i],csi->str,FI_DOWNLOAD))!=0)
+						if(s==-1 || (!strchr(csi->str,'?') && !strchr(csi->str,'*')))
 							return(0);
+				}
 				bputs(text[SearchingAllLibs]);
 				for(i=0;i<usrlibs;i++) {
 					if(i==curlib) continue;
-					for(j=0;j<usrdirs[i];j++)
-						if((s=listfileinfo(usrdir[i][j],str,FI_DOWNLOAD))!=0)
-							if(s==-1 || (!strchr(str,'?') && !strchr(str,'*')))
-								return(0); 
+					for(j=0;j<usrdirs[i];j++) {
+						if(msgabort())
+							return 0;
+						if((s=listfileinfo(usrdir[i][j],csi->str,FI_DOWNLOAD))!=0)
+							if(s==-1 || (!strchr(csi->str,'?') && !strchr(csi->str,'*')))
+								return(0);
+					}
 				} 
 			}
 			return(0);
 		case CS_FILE_DOWNLOAD_USER: /* Download from user dir */
 			csi->logic=LOGIC_FALSE;
-			if(cfg.user_dir==INVALID_DIR) {
-				bputs(text[NoUserDir]);
-				return(0); 
-			}
-			if(useron.rest&FLAG('D')) {
-				bputs(text[R_Download]);
-				return(0); 
-			}
-			CRLF;
-			if(!listfileinfo(cfg.user_dir,nulstr,FI_USERXFER))
-				bputs(text[NoFilesForYou]);
-			else
-				csi->logic=LOGIC_TRUE;
+			bputs(text[NoUserDir]);
 			return(0);
 		case CS_FILE_DOWNLOAD_BATCH:
-			if(batdn_total && (text[DownloadBatchQ][0]==0 || yesno(text[DownloadBatchQ]))) {
+			if(batdn_total() > 0
+				&& (text[DownloadBatchQ][0]==0 || yesno(text[DownloadBatchQ]))) {
 				start_batch_download();
 				csi->logic=LOGIC_TRUE; 
 			}
@@ -369,50 +348,36 @@ int sbbs_t::exec_file(csi_t *csi)
 			csi->logic=LOGIC_FALSE;
 			if(!csi->str[0])
 				return(0);
-			padfname(csi->str,f.name);
 			for(x=y=0;x<usrlibs;x++) {
-				for(y=0;y<usrdirs[x];y++)
-					if(findfile(&cfg,usrdir[x][y],f.name))
-						break;
-				if(y<usrdirs[x])
-					break; 
+				for(y=0;y<usrdirs[x];y++) {
+					if(msgabort())
+						return 0;
+					if(loadfile(&cfg, usrdir[x][y], csi->str, &f, file_detail_normal)) {
+						addtobatdl(&f);
+						smb_freefilemem(&f);
+						csi->logic=LOGIC_TRUE;
+						return 0;
+					}
+				}
 			}
-			if(x>=usrlibs)
-				return(0);
-			f.dir=usrdir[x][y];
-			getfileixb(&cfg,&f);
-			f.size=0;
-			getfiledat(&cfg,&f);
-			addtobatdl(&f);
-			csi->logic=LOGIC_TRUE;
 			return(0);
+
 		case CS_FILE_BATCH_CLEAR:
-			if(!batdn_total) {
-				csi->logic=LOGIC_FALSE;
-				return(0); 
-			}
-			csi->logic=LOGIC_TRUE;
-			for(i=0;i<batdn_total;i++) {
-				f.dir=batdn_dir[i];
-				f.datoffset=batdn_offset[i];
-				f.size=batdn_size[i];
-				strcpy(f.name,batdn_name[i]);
-				closefile(&f); 
-			}
-			batdn_total=0;
-			return(0);
+			csi->logic = clearbatdl() ? LOGIC_TRUE : LOGIC_FALSE;
+			return 0; 
 
 		case CS_FILE_VIEW:
 			if(!usrlibs) return(0);
-			padfname(csi->str,str);
-			strupr(str);
 			csi->logic=LOGIC_TRUE;
-			if(listfiles(usrdir[curlib][curdir[curlib]],str,0,FL_VIEW))
+			if(listfiles(usrdir[curlib][curdir[curlib]], csi->str, 0, FL_VIEW)
+				|| strcmp(csi->str, ALLFILES) == 0)
 				return(0);
 			bputs(text[SearchingAllDirs]);
 			for(i=0;i<usrdirs[curlib];i++) {
+				if(msgabort())
+					return 0;
 				if(i==curdir[curlib]) continue;
-				if(listfiles(usrdir[curlib][i],str,0,FL_VIEW))
+				if(listfiles(usrdir[curlib][i],csi->str,0,FL_VIEW))
 					break; 
 			}
 			if(i<usrdirs[curlib])
@@ -420,9 +385,12 @@ int sbbs_t::exec_file(csi_t *csi)
 			bputs(text[SearchingAllLibs]);
 			for(i=0;i<usrlibs;i++) {
 				if(i==curlib) continue;
-				for(j=0;j<usrdirs[i];j++)
-					if(listfiles(usrdir[i][j],str,0,FL_VIEW))
-						return(0); 
+				for(j=0;j<usrdirs[i];j++) {
+					if(msgabort())
+						return 0;
+					if(listfiles(usrdir[i][j],csi->str,0,FL_VIEW))
+						return(0);
+				}
 			}
 			csi->logic=LOGIC_FALSE;
 			bputs(text[FileNotFound]);
@@ -434,9 +402,7 @@ int sbbs_t::exec_file(csi_t *csi)
 				bputs(text[EmptyDir]);
 				return(0); 
 			}
-			padfname(csi->str,str);
-			strupr(str);
-			s=listfiles(usrdir[curlib][curdir[curlib]],str,0,0);
+			s=listfiles(usrdir[curlib][curdir[curlib]], csi->str, 0, 0);
 			if(s>1) {
 				bprintf(text[NFilesListed],s); 
 			}
@@ -444,22 +410,27 @@ int sbbs_t::exec_file(csi_t *csi)
 			return(0);
 		case CS_FILE_LIST_EXTENDED: /* Extended Information on files */
 			if(!usrlibs) return(0);
-			padfname(csi->str,str);
-			strupr(str);
-			if(!listfileinfo(usrdir[curlib][curdir[curlib]],str,FI_INFO)) {
+			if(!listfileinfo(usrdir[curlib][curdir[curlib]], csi->str, FI_INFO)
+				&& strcmp(csi->str, ALLFILES) != 0) {
 				bputs(text[SearchingAllDirs]);
-				for(i=0;i<usrdirs[curlib];i++)
+				for(i=0;i<usrdirs[curlib];i++) {
+					if(msgabort())
+						return 0;
 					if(i!=curdir[curlib] && (s=listfileinfo(usrdir[curlib][i]
-						,str,FI_INFO))!=0)
-						if(s==-1 || (!strchr(str,'?') && !strchr(str,'*')))
+						,csi->str,FI_INFO))!=0)
+						if(s==-1 || (!strchr(csi->str,'?') && !strchr(csi->str,'*')))
 							return(0);
+				}
 				bputs(text[SearchingAllLibs]);
 				for(i=0;i<usrlibs;i++) {
 					if(i==curlib) continue;
-					for(j=0;j<usrdirs[i];j++)
-						if((s=listfileinfo(usrdir[i][j],str,FI_INFO))!=0)
-							if(s==-1 || (!strchr(str,'?') && !strchr(str,'*')))
-								return(0); 
+					for(j=0;j<usrdirs[i];j++) {
+						if(msgabort())
+							return 0;
+						if((s=listfileinfo(usrdir[i][j],csi->str,FI_INFO))!=0)
+							if(s==-1 || (!strchr(csi->str,'?') && !strchr(csi->str,'*')))
+								return(0);
+					}
 				} 
 			}
 			return(0);
@@ -496,27 +467,32 @@ int sbbs_t::exec_file(csi_t *csi)
 				bputs(text[R_RemoveFiles]);
 				return(0); 
 			}
-			padfname(csi->str,str);
-			strupr(str);
-			if(!listfileinfo(usrdir[curlib][curdir[curlib]],str,FI_REMOVE)) {
+			if(!listfileinfo(usrdir[curlib][curdir[curlib]], csi->str, FI_REMOVE)
+				&& strcmp(csi->str, ALLFILES) != 0) {
 				if(cfg.user_dir!=INVALID_DIR
 					&& cfg.user_dir!=usrdir[curlib][curdir[curlib]])
-					if((s=listfileinfo(cfg.user_dir,str,FI_REMOVE))!=0)
-						if(s==-1 || (!strchr(str,'?') && !strchr(str,'*')))
+					if((s=listfileinfo(cfg.user_dir,csi->str,FI_REMOVE))!=0)
+						if(s==-1 || (!strchr(csi->str,'?') && !strchr(csi->str,'*')))
 							return(0);
 				bputs(text[SearchingAllDirs]);
-				for(i=0;i<usrdirs[curlib];i++)
+				for(i=0;i<usrdirs[curlib];i++) {
+					if(msgabort())
+						return 0;
 					if(i!=curdir[curlib] && i!=cfg.user_dir
-						&& (s=listfileinfo(usrdir[curlib][i],str,FI_REMOVE))!=0)
-						if(s==-1 || (!strchr(str,'?') && !strchr(str,'*')))
+						&& (s=listfileinfo(usrdir[curlib][i],csi->str,FI_REMOVE))!=0)
+						if(s==-1 || (!strchr(csi->str,'?') && !strchr(csi->str,'*')))
 							return(0);
+				}
 				bputs(text[SearchingAllLibs]);
 				for(i=0;i<usrlibs;i++) {
 					if(i==curlib || i==cfg.user_dir) continue;
-					for(j=0;j<usrdirs[i]; j++)
-						if((s=listfileinfo(usrdir[i][j],str,FI_REMOVE))!=0)
-							if(s==-1 || (!strchr(str,'?') && !strchr(str,'*')))
-								return(0); 
+					for(j=0;j<usrdirs[i]; j++) {
+						if(msgabort())
+							return 0;
+						if((s=listfileinfo(usrdir[i][j],csi->str,FI_REMOVE))!=0)
+							if(s==-1 || (!strchr(csi->str,'?') && !strchr(csi->str,'*')))
+								return(0);
+					}
 				} 
 			}
 			return(0);
diff --git a/src/sbbs3/execfunc.cpp b/src/sbbs3/execfunc.cpp
index 3eedc2cf2a..28566807b5 100644
--- a/src/sbbs3/execfunc.cpp
+++ b/src/sbbs3/execfunc.cpp
@@ -25,7 +25,6 @@
 int sbbs_t::exec_function(csi_t *csi)
 {
 	char	str[256];
-	char 	tmp[512];
 	uchar*	p;
 	int		s;
 	uint 	i,j,k;
@@ -302,38 +301,11 @@ int sbbs_t::exec_function(csi_t *csi)
 			}
 			return(0);
 		case CS_FILE_SET_ALT_PATH:
-			altul=atoi(csi->str);
-			if(altul>cfg.altpaths)
-				altul=0;
-			bprintf(text[AltULPathIsNow],altul ? cfg.altpath[altul-1] : text[OFF]);
+			bprintf("Alternate Upload Paths are Unsupported\r\n");
 			return(0);
 		case CS_FILE_RESORT_DIRECTORY:
-			for(i=1;i<=cfg.sys_nodes;i++)
-				if(i!=cfg.node_num) {
-					getnodedat(i,&node,0);
-					if(node.status==NODE_INUSE
-						|| node.status==NODE_QUIET)
-						break; 
-				}
-
-			if(i<=cfg.sys_nodes) {
-				bputs(text[ResortWarning]);
-				return(0); 
-			}
-
-			if(!stricmp(csi->str,"ALL")) {     /* all libraries */
-				for(i=0;i<usrlibs;i++)
-					for(j=0;j<usrdirs[i];j++)
-						resort(usrdir[i][j]);
-				return(0); 
-			}
-			if(!stricmp(csi->str,"LIB")) {     /* current library */
-				for(i=0;i<usrdirs[curlib];i++)
-					resort(usrdir[curlib][i]);
-				return(0); 
-			}
-			resort(usrdir[curlib][curdir[curlib]]);
-			return(0);
+			lprintf(LOG_WARNING, "deprecated function: RESORT_DIRECTORY");
+			return 0;
 
 		case CS_FILE_GET:
 			if(!fexist(csi->str)) {
@@ -387,9 +359,8 @@ int sbbs_t::exec_function(csi_t *csi)
 		case CS_FILE_FIND_OFFLINE:
 		case CS_FILE_FIND_OLD_UPLOADS:
 			if(!usrlibs) return(0);
-			if(!getfilespec(tmp))
+			if(!getfilespec(str))
 				return(0);
-			padfname(tmp,str);
 			k=0;
 			bputs("\r\nSearching ");
 			if(!stricmp(csi->str,"ALL"))
@@ -412,8 +383,8 @@ int sbbs_t::exec_function(csi_t *csi)
 				bputs("not online...\r\n"); 
 			}
 			else {
-				l=FI_CLOSE;
-				bputs("currently open...\r\n"); 
+				// e.g. FI_CLOSE;
+				return 0;
 			}
 			if(!stricmp(csi->str,"ALL")) {
 				for(i=0;i<usrlibs;i++)
diff --git a/src/sbbs3/execmisc.cpp b/src/sbbs3/execmisc.cpp
index 97ce59e1d5..d19f8a1987 100644
--- a/src/sbbs3/execmisc.cpp
+++ b/src/sbbs3/execmisc.cpp
@@ -48,7 +48,7 @@ static char* format_string(sbbs_t* sbbs, csi_t* csi)
 	return xp_asprintf_end(fmt, NULL);
 }
 
-int sbbs_t::exec_misc(csi_t* csi, char *path)
+int sbbs_t::exec_misc(csi_t* csi, const char *path)
 {
 	char	str[512],tmp[512],buf[1025],ch,op,*p,**pp,**pp1,**pp2;
 	ushort	w;
@@ -1576,7 +1576,7 @@ int sbbs_t::exec_misc(csi_t* csi, char *path)
 				free(text[i]);
 			j=strlen(cmdstr((char *)csi->ip,path,csi->str,buf));
 			if(!j)
-				text[i]=nulstr;
+				text[i]=(char*)nulstr;
 			else
 				text[i]=(char *)malloc(j+1);
 			if(!text[i]) {
diff --git a/src/sbbs3/file.cpp b/src/sbbs3/file.cpp
index 6ebc3a64a7..725478e634 100644
--- a/src/sbbs3/file.cpp
+++ b/src/sbbs3/file.cpp
@@ -1,4 +1,4 @@
-/* Synchronet file transfer-related functions */
+/* Synchronet file transfer-related sbbs_t class methods */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -20,220 +20,89 @@
  ****************************************************************************/
 
 #include "sbbs.h"
+#include "filedat.h"
 
 /****************************************************************************/
 /* Prints all information of file in file_t structure 'f'					*/
 /****************************************************************************/
-void sbbs_t::fileinfo(file_t* f)
+void sbbs_t::showfileinfo(file_t* f, bool show_extdesc)
 {
-	char	ext[513];
 	char 	tmp[512];
 	char	tmp2[64];
 	char	path[MAX_PATH+1];
-	char	fname[MAX_PATH+1];
-	char*	real_fname;
-	uint	i,j;
 
 	current_file = f;
-	for(i=0;i<usrlibs;i++)
-		if(usrlib[i]==cfg.dir[f->dir]->lib)
-			break;
-	for(j=0;j<usrdirs[i];j++)
-		if(usrdir[i][j]==f->dir)
-			break;
+	getfilepath(&cfg, f, path);
+	bprintf(P_TRUNCATE, text[FiLib], getusrlib(f->dir), cfg.lib[cfg.dir[f->dir]->lib]->lname);
+	bprintf(P_TRUNCATE, text[FiDir], getusrdir(f->dir), cfg.dir[f->dir]->lname);
+	bprintf(P_TRUNCATE, text[FiFilename],f->name);
 
-	getfilepath(&cfg,f,path);
-	real_fname = getfname(path);
-	unpadfname(f->name, fname);
-	bprintf(text[FiLib],i+1,cfg.lib[cfg.dir[f->dir]->lib]->lname);
-	bprintf(text[FiDir],j+1,cfg.dir[f->dir]->lname);
-	bprintf(text[FiFilename],fname);
-	if(strcmp(real_fname, fname) && strcmp(f->desc, real_fname))	/* Different "actual" filename */
-		bprintf(text[FiFilename], real_fname);
-
-	if(f->size!=-1L)
-		bprintf(text[FiFileSize],ultoac(f->size,tmp)
+	if(getfilesize(&cfg, f) >= 0)
+		bprintf(P_TRUNCATE, text[FiFileSize], ultoac((ulong)f->size,tmp)
 			, byte_estimate_to_str(f->size, tmp2, sizeof(tmp2), /* units: */1024, /* precision: */1));
-	bprintf(text[FiCredits]
-		,(cfg.dir[f->dir]->misc&DIR_FREE || !f->cdt) ? "FREE" : ultoac(f->cdt,tmp));
-	bprintf(text[FiDescription],f->desc);
-	bprintf(text[FiUploadedBy],f->misc&FM_ANON ? text[UNKNOWN_USER] : f->uler);
-	if(f->date)
-		bprintf(text[FiFileDate],timestr(f->date));
-	bprintf(text[FiDateUled],timestr(f->dateuled));
-	bprintf(text[FiDateDled],f->datedled ? timestr(f->datedled) : "Never");
-	bprintf(text[FiTimesDled],f->timesdled);
-	if(f->size>0 && f->timetodl>0)
-		bprintf(text[FiTransferTime],sectostr(f->timetodl,tmp));
-	if(f->altpath) {
-		if(f->altpath<=cfg.altpaths) {
-			if(SYSOP)
-				bprintf(text[FiAlternatePath],cfg.altpath[f->altpath-1]); 
+
+	bprintf(P_TRUNCATE, text[FiCredits]
+		,(cfg.dir[f->dir]->misc&DIR_FREE || !f->cost) ? "FREE" : ultoac((ulong)f->cost,tmp));
+	if(getfilesize(&cfg, f) > 0 &&  f->size == f->file_idx.idx.size) {
+#if 0 // I don't think anyone cares about the CRC-16 checksum value of a file
+		if(f->file_idx.hash.flags & SMB_HASH_CRC16) {
+			SAFEPRINTF(tmp, "%04x", f->file_idx.hash.data.crc16);
+			bprintf(P_TRUNCATE, text[FiChecksum], "CRC-16", tmp);
+		}
+#endif
+		if(f->file_idx.hash.flags & SMB_HASH_CRC32) {
+			SAFEPRINTF(tmp, "%08x", f->file_idx.hash.data.crc32);
+			bprintf(P_TRUNCATE, text[FiChecksum], "CRC-32", tmp);
 		}
-		else
-			bprintf(text[InvalidAlternatePathN],f->altpath); 
+		if(f->file_idx.hash.flags & SMB_HASH_MD5)
+			bprintf(P_TRUNCATE, text[FiChecksum], "MD5", MD5_hex(tmp, f->file_idx.hash.data.md5));
+		if(f->file_idx.hash.flags & SMB_HASH_SHA1)
+			bprintf(P_TRUNCATE, text[FiChecksum], "SHA-1", SHA1_hex(tmp, f->file_idx.hash.data.sha1));
 	}
-	bputs(text[FileHdrDescSeparator]);
-	if(f->misc&FM_EXTDESC) {
-		getextdesc(&cfg,f->dir,f->datoffset,ext);
-		putmsg(ext,P_NOATCODES);
-		CRLF; 
+	if(f->desc && f->desc[0])
+		bprintf(P_TRUNCATE, text[FiDescription],f->desc);
+	if(f->tags && f->tags[0])
+		bprintf(P_TRUNCATE, text[FiTags], f->tags);
+	char* p = f->hdr.attr&MSG_ANONYMOUS ? text[UNKNOWN_USER] : f->from;
+	if(p != NULL && *p != '\0')
+		bprintf(P_TRUNCATE, text[FiUploadedBy], p);
+	bprintf(P_TRUNCATE, text[FiDateUled],timestr(f->hdr.when_imported.time));
+	if(getfiletime(&cfg, f) > 0)
+		bprintf(P_TRUNCATE, text[FiFileDate],timestr(f->time));
+	bprintf(P_TRUNCATE, text[FiDateDled],f->hdr.last_downloaded ? timestr(f->hdr.last_downloaded) : "Never");
+	bprintf(P_TRUNCATE, text[FiTimesDled],f->hdr.times_downloaded);
+	ulong timetodl = gettimetodl(&cfg, f, cur_cps);
+	if(timetodl > 0)
+		bprintf(text[FiTransferTime],sectostr(timetodl,tmp));
+	bputs(P_TRUNCATE, text[FileHdrDescSeparator]);
+	if(show_extdesc && f->extdesc != NULL && *f->extdesc) {
+		char* p = f->extdesc;
+		SKIP_CRLF(p);
+		truncsp(p);
+		long p_mode = P_NOATCODES;
+		if(!(console&CON_RAW_IN))
+			p_mode |= P_WORDWRAP;
+		putmsg(p, p_mode);
+		newline();
 	}
-	if(f->size==-1L) {
+	if(f->size == -1) {
 		bprintf(text[FileIsNotOnline],f->name);
 		if(SYSOP)
 			bprintf("%s\r\n",path);
 	}
-	if(f->opencount)
-		bprintf(text[FileIsOpen],f->opencount,f->opencount>1 ? "s" : nulstr);
 	current_file = NULL;
 }
 
-
-/****************************************************************************/
-/* Increments the opencount on the file data 'f' and adds the transaction 	*/
-/* to the backout.dab														*/
-/****************************************************************************/
-void sbbs_t::openfile(file_t* f)
-{
-	char str1[256],str2[4],str3[4],ch;
-	int file;
-
-	/************************************/
-	/* Increment open count in dat file */
-	/************************************/
-	sprintf(str1,"%s%s.dat",cfg.dir[f->dir]->data_dir,cfg.dir[f->dir]->code);
-	if((file=nopen(str1,O_RDWR))==-1) {
-		errormsg(WHERE,ERR_OPEN,str1,O_RDWR);
-		return; 
-	}
-	(void)lseek(file,f->datoffset+F_OPENCOUNT,SEEK_SET);
-	if(read(file,str2,3)!=3) {
-		close(file);
-		errormsg(WHERE,ERR_READ,str1,3);
-		return; 
-	}
-	str2[3]=0;
-	ultoa(atoi(str2)+1,str3,10);
-	putrec(str2,0,3,str3);
-	(void)lseek(file,f->datoffset+F_OPENCOUNT,SEEK_SET);
-	if(write(file,str2,3)!=3) {
-		close(file);
-		errormsg(WHERE,ERR_WRITE,str1,3);
-		return; 
-	}
-	close(file);
-	/**********************************/
-	/* Add transaction to BACKOUT.DAB */
-	/**********************************/
-	sprintf(str1,"%sbackout.dab",cfg.node_dir);
-	if((file=nopen(str1,O_WRONLY|O_APPEND|O_CREAT))==-1) {
-		errormsg(WHERE,ERR_OPEN,str1,O_WRONLY|O_APPEND|O_CREAT);
-		return; 
-	}
-	ch=BO_OPENFILE;
-	write(file,&ch,1);				/* backout type */
-	write(file,cfg.dir[f->dir]->code,8); /* directory code */
-	write(file,&f->datoffset,4);		/* offset into .dat file */
-	write(file,&ch,BO_LEN-(1+8+4)); /* pad it */
-	close(file);
-}
-
-/****************************************************************************/
-/* Decrements the opencount on the file data 'f' and removes the backout  	*/
-/* from the backout.dab														*/
-/****************************************************************************/
-void sbbs_t::closefile(file_t* f)
-{
-	char	str1[256],str2[4],str3[4],ch,*buf;
-	int		file;
-	long	length,l,offset;
-
-	/************************************/
-	/* Decrement open count in dat file */
-	/************************************/
-	sprintf(str1,"%s%s.dat",cfg.dir[f->dir]->data_dir,cfg.dir[f->dir]->code);
-	if((file=nopen(str1,O_RDWR))==-1) {
-		errormsg(WHERE,ERR_OPEN,str1,O_RDWR);
-		return; 
-	}
-	(void)lseek(file,f->datoffset+F_OPENCOUNT,SEEK_SET);
-	if(read(file,str2,3)!=3) {
-		close(file);
-		errormsg(WHERE,ERR_READ,str1,3);
-		return; 
-	}
-	str2[3]=0;
-	ch=atoi(str2);
-	if(ch) ch--;
-	ultoa(ch,str3,10);
-	putrec(str2,0,3,str3);
-	(void)lseek(file,f->datoffset+F_OPENCOUNT,SEEK_SET);
-	if(write(file,str2,3)!=3) {
-		close(file);
-		errormsg(WHERE,ERR_WRITE,str1,3);
-		return; 
-	}
-	close(file);
-	/*****************************************/
-	/* Removing transaction from BACKOUT.DAB */
-	/*****************************************/
-	sprintf(str1,"%sbackout.dab",cfg.node_dir);
-	if(flength(str1)<1L)	/* file is not there or empty */
-		return;
-	if((file=nopen(str1,O_RDONLY))==-1) {
-		errormsg(WHERE,ERR_OPEN,str1,O_RDONLY);
-		return; 
-	}
-	length=(long)filelength(file);
-	if((buf=(char *)malloc(length))==NULL) {
-		close(file);
-		errormsg(WHERE,ERR_ALLOC,str1,length);
-		return; 
-	}
-	if(read(file,buf,length)!=length) {
-		close(file);
-		free(buf);
-		errormsg(WHERE,ERR_READ,str1,length);
-		return; 
-	}
-	close(file);
-	if((file=nopen(str1,O_WRONLY|O_TRUNC))==-1) {
-		free(buf);
-		errormsg(WHERE,ERR_OPEN,str1,O_WRONLY|O_TRUNC);
-		return; 
-	}
-	ch=0;								/* 'ch' is a 'file already removed' flag */
-	for(l=0;l<length;l+=BO_LEN) {       /* in case file is in backout.dab > 1 */
-		if(!ch && buf[l]==BO_OPENFILE) {
-			memcpy(str1,buf+l+1,8);
-			str1[8]=0;
-			memcpy(&offset,buf+l+9,4);
-			if(!stricmp(str1,cfg.dir[f->dir]->code) && offset==f->datoffset) {
-				ch=1;
-				continue; 
-			}
-		}
-		write(file,buf+l,BO_LEN); 
-	}
-	free(buf);
-	close(file);
-}
-
 /****************************************************************************/
-/* Prompts user for file specification. <CR> is *.* and .* is assumed.      */
+/* Prompts user for file specification. <CR> is *							*/
 /* Returns padded file specification.                                       */
 /* Returns NULL if input was aborted.                                       */
 /****************************************************************************/
 char * sbbs_t::getfilespec(char *str)
 {
 	bputs(text[FileSpecStarDotStar]);
-	if(!getstr(str,64,K_NONE))
-		strcpy(str,ALLFILES);
-#if 0
-	else if(!strchr(str,'.') && strlen(str)<=8)
-		strcat(str,".*");
-#endif
+	if(!getstr(str, MAX_FILENAME_LEN, K_NONE))
+		strcpy(str, ALLFILES);
 	if(sys_status&SS_ABORT)
 		return(0);
 	return(str);
@@ -244,19 +113,7 @@ char * sbbs_t::getfilespec(char *str)
 /****************************************************************************/
 extern "C" BOOL filematch(const char *filename, const char *filespec)
 {
-    char c;
-
-	for(c=0;c<8;c++) /* Handle Name */
-		if(filespec[c]=='*') break;
-		else if(filespec[c]=='?') continue;
-		else if(toupper(filename[c])!=toupper(filespec[c])) return(FALSE);
-	if(filespec[8]==' ')	/* no extension specified */
-		return(TRUE);
-	for(c=9;c<12;c++)
-		if(filespec[c]=='*') break;
-		else if(filespec[c]=='?') continue;
-		else if(toupper(filename[c])!=toupper(filespec[c])) return(FALSE);
-	return(TRUE);
+	return wildmatchi(filename, filespec, /* path: */FALSE);
 }
 
 /*****************************************************************************/
@@ -267,17 +124,12 @@ bool sbbs_t::checkfname(char *fname)
     int		c=0,d;
 
 	if(fname[0]=='-'
-		|| strcspn(fname,ILLEGAL_FILENAME_CHARS)!=strlen(fname)) {
+		|| strcspn(fname,ILLEGAL_FILENAME_CHARS)!=strlen(fname)
+		|| strstr(fname, "..") != NULL) {
 		lprintf(LOG_WARNING,"Suspicious filename attempt: '%s'",fname);
 		hacklog((char *)"Filename", fname);
 		return(false); 
 	}
-	if(strstr(fname,".."))
-		return(false);
-#if 0	/* long file name support */
-	if(strcspn(fname,".")>8)
-		return(false);
-#endif
 	d=strlen(fname);
 	while(c<d) {
 		if(fname[c]<=' ' || fname[c]&0x80)
@@ -294,3 +146,112 @@ long sbbs_t::delfiles(const char *inpath, const char *spec, size_t keep)
 		errormsg(WHERE, ERR_REMOVE, inpath, result, spec);
 	return result;
 }
+
+/****************************************************************************/
+/* Remove credits or minutes and adjust statistics of uploader of file 'f'	*/
+/****************************************************************************/
+bool sbbs_t::removefcdt(file_t* f)
+{
+	char	str[128];
+	char 	tmp[512];
+	int		u;
+	long	cdt;
+
+	if((u=matchuser(&cfg,f->from,TRUE /*sysop_alias*/))==0) {
+	   bputs(text[UnknownUser]);
+	   return(false); 
+	}
+	cdt=0L;
+	if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps) {
+		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
+			cdt=((ulong)(f->cost*(cfg.dir[f->dir]->up_pct/100.0))/cur_cps)/60;
+		if(cfg.dir[f->dir]->misc&DIR_CDTDL
+			&& f->hdr.times_downloaded)  /* all downloads */
+			cdt+=((ulong)((long)f->hdr.times_downloaded
+				*f->cost*(cfg.dir[f->dir]->dn_pct/100.0))/cur_cps)/60;
+		if(cdt) {
+			adjustuserrec(&cfg,u,U_MIN,10,-cdt);
+			sprintf(str,"%lu minute",cdt);
+			sprintf(tmp,text[FileRemovedUserMsg]
+				,f->name,cdt ? str : text[No]);
+			putsmsg(&cfg,u,tmp);
+		}
+	}
+	else {
+		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
+			cdt=(ulong)(f->cost*(cfg.dir[f->dir]->up_pct/100.0));
+		if(cfg.dir[f->dir]->misc&DIR_CDTDL
+			&& f->hdr.times_downloaded)  /* all downloads */
+			cdt+=(ulong)((long)f->hdr.times_downloaded
+				*f->cost*(cfg.dir[f->dir]->dn_pct/100.0));
+		if(dir_op(f->dir)) {
+			ultoa(cdt, str, 10);
+			bputs(text[CreditsToRemove]);
+			getstr(str, 10, K_NUMBER|K_LINE|K_EDIT|K_AUTODEL);
+			if(sys_status&SS_ABORT)
+				return false;
+			cdt = atol(str); 
+		}
+		if(cdt) {
+			adjustuserrec(&cfg,u,U_CDT,10,-cdt);
+			sprintf(tmp,text[FileRemovedUserMsg]
+				,f->name,cdt ? ultoac(cdt,str) : text[No]);
+			putsmsg(&cfg,u,tmp);
+		}
+	}
+
+	adjustuserrec(&cfg,u,U_ULB,10,(long)-f->size);
+	adjustuserrec(&cfg,u,U_ULS,5,-1);
+	return(true);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+bool sbbs_t::removefile(smb_t* smb, file_t* f)
+{
+	char str[256];
+	int result;
+
+	if((result = smb_removefile(smb ,f)) == SMB_SUCCESS) {
+		SAFEPRINTF4(str,"%s removed %s from %s %s"
+			,useron.alias
+			,f->name
+			,cfg.lib[cfg.dir[smb->dirnum]->lib]->sname,cfg.dir[smb->dirnum]->sname);
+		logline("U-",str);
+		return true;
+	}
+	errormsg(WHERE, ERR_REMOVE, f->name, result, smb->last_error);
+	return false;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+bool sbbs_t::movefile(smb_t* smb, file_t* f, int newdir)
+{
+	if(findfile(&cfg, newdir, f->name, NULL)) {
+		bprintf(text[FileAlreadyThere], f->name);
+		return false; 
+	}
+
+	if(!addfile(&cfg, newdir, f, f->extdesc))
+		return false;
+	removefile(smb, f);
+	bprintf(text[MovedFile],f->name
+		,cfg.lib[cfg.dir[newdir]->lib]->sname,cfg.dir[newdir]->sname);
+	char str[MAX_PATH+1];
+	SAFEPRINTF4(str, "%s moved %s to %s %s",f->name
+		,useron.alias
+		,cfg.lib[cfg.dir[newdir]->lib]->sname
+		,cfg.dir[newdir]->sname);
+	logline(nulstr,str);
+
+	/* move actual file */
+	char oldpath[MAX_PATH + 1];
+	getfilepath(&cfg, f, oldpath);
+	f->dir = newdir;
+	char newpath[MAX_PATH + 1];
+	getfilepath(&cfg, f, newpath);
+	mv(oldpath, newpath, /* copy */false); 
+	
+	return true;
+}
diff --git a/src/sbbs3/filedat.c b/src/sbbs3/filedat.c
index 11f8e7625e..1007b5b2e0 100644
--- a/src/sbbs3/filedat.c
+++ b/src/sbbs3/filedat.c
@@ -20,711 +20,1095 @@
  ****************************************************************************/
 
 #include "filedat.h"
+#include "userdat.h"
 #include "dat_rec.h"
 #include "datewrap.h"	// time32()
 #include "str_util.h"
 #include "nopen.h"
+#include "smblib.h"
+#include "load_cfg.h"	// smb_open_dir()
+#include "scfglib.h"
 
-static char* crlf = "\r\n";
+/* libarchive: */
+#include <archive.h>
+#include <archive_entry.h>
 
+ /****************************************************************************/
 /****************************************************************************/
-/* Gets filedata from dircode.DAT file										*/
-/* Need fields .name ,.dir and .offset to get other info    				*/
-/* Does not fill .dateuled or .datedled fields.                             */
-/****************************************************************************/
-BOOL DLLCALL getfiledat(scfg_t* cfg, file_t* f)
+bool findfile(scfg_t* cfg, uint dirnum, const char *filename, file_t* file)
 {
-	char buf[F_LEN+1],str[MAX_PATH+1];
-	int file;
-	long length;
+	smb_t smb;
 
-	SAFEPRINTF2(str,"%s%s.dat",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_RDONLY|O_BINARY,SH_DENYWR))==-1) {
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	if(f->datoffset>length) {
-		close(file);
-		return(FALSE); 
-	}
-	if(length%F_LEN) {
-		close(file);
-		return(FALSE); 
-	}
-	lseek(file,f->datoffset,SEEK_SET);
-	if(read(file,buf,F_LEN)!=F_LEN) {
-		close(file);
-		return(FALSE); 
-	}
-	close(file);
-	getrec(buf,F_ALTPATH,2,str);
-	f->altpath=hptoi(str);
-	getrec(buf,F_CDT,LEN_FCDT,str);
-	f->cdt=atol(str);
+	if(cfg == NULL || filename == NULL)
+		return false;
 
-	if(f->size == 0) {					// only read disk if f->size == 0
-		struct stat st;
-		getfilepath(cfg,f,str);
-		if(stat(str, &st) == 0) {
-			f->size = st.st_size;
-			f->date = (time32_t)st.st_mtime;
-		} else
-			f->size = -1;	// indicates file does not exist
-	}
-#if 0
-	if((f->size>0L) && cur_cps)
-		f->timetodl=(ushort)(f->size/(ulong)cur_cps);
-	else
-#endif
-		f->timetodl=0;
+	if(!smb_init_dir(cfg, &smb, dirnum))
+		return false;
+	if(smb_open_index(&smb) != SMB_SUCCESS)
+		return false;
+	int result = smb_findfile(&smb, filename, file);
+	smb_close(&smb);
+	return result == SMB_SUCCESS;
+}
 
-	getrec(buf,F_DESC,LEN_FDESC,f->desc);
-	getrec(buf,F_ULER,LEN_ALIAS,f->uler);
-	getrec(buf,F_TIMESDLED,5,str);
-	f->timesdled=atoi(str);
-	getrec(buf,F_OPENCOUNT,3,str);
-	f->opencount=atoi(str);
-	if(buf[F_MISC]!=ETX)
-		f->misc=buf[F_MISC]-' ';
-	else
-		f->misc=0;
-	return(TRUE);
+// This function may be called without opening the file base (for fast new-scans)
+time_t newfiletime(smb_t* smb)
+{
+	char str[MAX_PATH + 1];
+	SAFEPRINTF(str, "%s.sid", smb->file);
+	return fdate(str);
 }
 
-/****************************************************************************/
-/* Puts filedata into DIR_code.DAT file                                     */
-/* Called from removefiles                                                  */
-/****************************************************************************/
-BOOL DLLCALL putfiledat(scfg_t* cfg, file_t* f)
-{
-    char buf[F_LEN+1],str[MAX_PATH+1],tmp[128];
-    int file;
-    long length;
-
-	putrec(buf,F_CDT,LEN_FCDT,ultoa(f->cdt,tmp,10));
-	putrec(buf,F_DESC,LEN_FDESC,f->desc);
-	putrec(buf,F_DESC+LEN_FDESC,2,crlf);
-	putrec(buf,F_ULER,LEN_ALIAS+5,f->uler);
-	putrec(buf,F_ULER+LEN_ALIAS+5,2,crlf);
-	putrec(buf,F_TIMESDLED,5,ultoa(f->timesdled,tmp,10));
-	putrec(buf,F_TIMESDLED+5,2,crlf);
-	putrec(buf,F_OPENCOUNT,3,ultoa(f->opencount,tmp,10));
-	putrec(buf,F_OPENCOUNT+3,2,crlf);
-	buf[F_MISC]=(char)f->misc+' ';
-	putrec(buf,F_ALTPATH,2,hexplus(f->altpath,tmp));
-	putrec(buf,F_ALTPATH+2,2,crlf);
-	SAFEPRINTF2(str,"%s%s.dat",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_WRONLY|O_BINARY,SH_DENYRW))==-1) {
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	if(length%F_LEN) {
-		close(file);
-		return(FALSE); 
-	}
-	if(f->datoffset>length) {
-		close(file);
-		return(FALSE); 
-	}
-	lseek(file,f->datoffset,SEEK_SET);
-	if(write(file,buf,F_LEN)!=F_LEN) {
-		close(file);
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	close(file);
-	if(length%F_LEN) {
-		return(FALSE);
+time_t dir_newfiletime(scfg_t* cfg, uint dirnum)
+{
+	smb_t smb;
+
+	if(!smb_init_dir(cfg, &smb, dirnum))
+		return -1;
+	return newfiletime(&smb);
+}
+
+// This function may be called without opening the file base (for fast new-scans)
+bool newfiles(smb_t* smb, time_t t)
+{
+	return newfiletime(smb) > t;
+}
+
+// This function *must* be called with file base closed
+bool update_newfiletime(smb_t* smb, time_t t)
+{
+	char path[MAX_PATH + 1];
+	SAFEPRINTF(path, "%s.sid", smb->file);
+	return setfdate(path, t) == 0;
+}
+
+time_t lastfiletime(smb_t* smb)
+{
+	idxrec_t idx;
+	if(smb_getlastidx(smb, &idx) != SMB_SUCCESS)
+		return (time_t)-1;
+	return idx.time;
+}
+
+static int filename_compare_a(const void *arg1, const void *arg2)
+{
+   return stricmp(*(char**) arg1, *(char**) arg2);
+}
+
+static int filename_compare_d(const void *arg1, const void *arg2)
+{
+   return stricmp(*(char**) arg2, *(char**) arg1);
+}
+
+static int filename_compare_ac(const void *arg1, const void *arg2)
+{
+   return strcmp(*(char**) arg1, *(char**) arg2);
+}
+
+static int filename_compare_dc(const void *arg1, const void *arg2)
+{
+   return strcmp(*(char**) arg2, *(char**) arg1);
+}
+
+// Note: does not support sorting by date
+void sortfilenames(str_list_t filelist, size_t count, enum file_sort order)
+{
+	switch(order) {
+		case FILE_SORT_NAME_A:
+			qsort(filelist, count, sizeof(*filelist), filename_compare_a);
+			break;
+		case FILE_SORT_NAME_D:
+			qsort(filelist, count, sizeof(*filelist), filename_compare_d);
+			break;
+		case FILE_SORT_NAME_AC:
+			qsort(filelist, count, sizeof(*filelist), filename_compare_ac);
+			break;
+		case FILE_SORT_NAME_DC:
+			qsort(filelist, count, sizeof(*filelist), filename_compare_dc);
+			break;
+		default:
+			break;
 	}
-	return(TRUE);
 }
 
-/****************************************************************************/
-/* Adds the data for struct filedat to the directory's data base.           */
-/* changes the .datoffset field only                                        */
-/* returns 1 if added successfully, 0 if not.								*/
-/****************************************************************************/
-BOOL DLLCALL addfiledat(scfg_t* cfg, file_t* f)
-{
-	char	str[MAX_PATH+1],fname[13],c,fdat[F_LEN+1];
-	char	tmp[128];
-	uchar	*ixbbuf,idx[3];
-    int		i,file;
-	long	l,length;
-	time_t	uldate;
-
-	/************************/
-	/* Add data to DAT File */
-	/************************/
-	SAFEPRINTF2(str,"%s%s.dat",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_RDWR|O_BINARY|O_CREAT,SH_DENYRW,DEFFILEMODE))==-1) {
-		return(FALSE); 
+// Return an optionally-sorted dynamically-allocated string list of filenames added since date/time (t)
+// Note: does not support sorting by date (exception: natural sort order of date-ascending)
+str_list_t loadfilenames(smb_t* smb, const char* filespec, time_t t, enum file_sort order, size_t* count)
+{
+	size_t count_;
+
+	if(count == NULL)
+		count = &count_;
+
+	*count = 0;
+
+	long start = 0;	
+	if(t > 0) {
+		idxrec_t idx;
+		start = smb_getmsgidx_by_time(smb, &idx, t);
+		if(start < 0)
+			return NULL;
 	}
-	length=(long)filelength(file);
-	if(length==0L)
-		l=0L;
-	else {
-		if(length%F_LEN) {
-			close(file);
-			return(FALSE); 
-		}
-		for(l=0;l<length;l+=F_LEN) {    /* Find empty slot */
-			lseek(file,l,SEEK_SET);
-			read(file,&c,1);
-			if(c==ETX) break; 
+
+	char** file_list = calloc(smb->status.total_files + 1, sizeof(char*));
+	if(file_list == NULL)
+		return NULL;
+
+	fseek(smb->sid_fp, start * sizeof(fileidxrec_t), SEEK_SET);
+	while(!feof(smb->sid_fp)) {
+		fileidxrec_t fidx;
+
+		if(smb_fread(smb, &fidx, sizeof(fidx), smb->sid_fp) != sizeof(fidx))
+			break;
+
+		if(fidx.idx.number == 0)	/* invalid message number, ignore */
+			continue;
+
+		TERMINATE(fidx.name);
+
+		if(filespec != NULL && *filespec != '\0') {
+			if(!wildmatch(fidx.name, filespec, /* path: */false, /* case-sensitive: */false))
+				continue;
 		}
-		if(l/F_LEN>=MAX_FILES) {
-			close(file);
-			return(FALSE); 
-		} 
-	}
-	putrec(fdat,F_CDT,LEN_FCDT,ultoa(f->cdt,tmp,10));
-	putrec(fdat,F_DESC,LEN_FDESC,f->desc);
-	putrec(fdat,F_DESC+LEN_FDESC,2,crlf);
-	putrec(fdat,F_ULER,LEN_ALIAS+5,f->uler);
-	putrec(fdat,F_ULER+LEN_ALIAS+5,2,crlf);
-	putrec(fdat,F_TIMESDLED,5,ultoa(f->timesdled,tmp,10));
-	putrec(fdat,F_TIMESDLED+5,2,crlf);
-	putrec(fdat,F_OPENCOUNT,3,ultoa(f->opencount,tmp,10));
-	putrec(fdat,F_OPENCOUNT+3,2,crlf);
-	fdat[F_MISC]=(char)f->misc+' ';
-	putrec(fdat,F_ALTPATH,2,hexplus(f->altpath,tmp));
-	putrec(fdat,F_ALTPATH+2,2,crlf);
-	f->datoffset=l;
-	idx[0]=(uchar)(l&0xff);          /* Get offset within DAT file for IXB file */
-	idx[1]=(uchar)((l>>8)&0xff);
-	idx[2]=(uchar)((l>>16)&0xff);
-	lseek(file,l,SEEK_SET);
-	if(write(file,fdat,F_LEN)!=F_LEN) {
-		close(file);
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	close(file);
-	if(length%F_LEN) {
-		return(FALSE);
+		file_list[*count] = strdup(fidx.name);
+		(*count)++;
 	}
+	if(order != FILE_SORT_NATURAL)
+		sortfilenames(file_list, *count, order);
 
-	/*******************************************/
-	/* Update last upload date/time stamp file */
-	/*******************************************/
-	SAFEPRINTF2(str,"%s%s.dab",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_WRONLY|O_CREAT|O_BINARY,SH_DENYRW,DEFFILEMODE))!=-1) {
-		time32_t now=time32(NULL);
-		/* TODO: LE required */
-		write(file,&now,sizeof(time32_t));
-		close(file); 
-	}
+	return file_list;
+}
 
-	/************************/
-	/* Add data to IXB File */
-	/************************/
-	SAFECOPY(fname,f->name);
-	for(i=8;i<12;i++)   /* Turn FILENAME.EXT into FILENAMEEXT */
-		fname[i]=fname[i+1];
-	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,DEFFILEMODE))==-1) {
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	if(length) {    /* IXB file isn't empty */
-		if(length%F_IXBSIZE) {
-			close(file);
-			return(FALSE); 
-		}
-		if((ixbbuf=(uchar *)malloc(length))==NULL) {
-			close(file);
-			return(FALSE); 
-		}
-		if(read(file,ixbbuf,length)!=length) {
-			close(file);
-			free(ixbbuf);
-			return(FALSE); 
-		}
-	/************************************************/
-	/* Sort by Name or Date, Assending or Decending */
-	/************************************************/
-		if(cfg->dir[f->dir]->sort==SORT_NAME_A || cfg->dir[f->dir]->sort==SORT_NAME_D) {
-			for(l=0;l<length;l+=F_IXBSIZE) {
-				for(i=0;i<12 && toupper(fname[i])==toupper(ixbbuf[l+i]);i++);
-				if(i==12) {     /* file already in directory index */
-					close(file);
-					free(ixbbuf);
-					return(FALSE); 
-				}
-				if(cfg->dir[f->dir]->sort==SORT_NAME_A 
-					&& toupper(fname[i])<toupper(ixbbuf[l+i]))
-					break;
-				if(cfg->dir[f->dir]->sort==SORT_NAME_D 
-					&& toupper(fname[i])>toupper(ixbbuf[l+i]))
-					break; 
-			} 
-		}
-		else {  /* sort by date */
-			for(l=0;l<length;l+=F_IXBSIZE) {
-				uldate=(ixbbuf[l+14]|((long)ixbbuf[l+15]<<8)
-					|((long)ixbbuf[l+16]<<16)|((long)ixbbuf[l+17]<<24));
-				if(cfg->dir[f->dir]->sort==SORT_DATE_A && f->dateuled<uldate)
-					break;
-				if(cfg->dir[f->dir]->sort==SORT_DATE_D && f->dateuled>uldate)
-					break; 
-			} 
-		}
-		lseek(file,l,SEEK_SET);
-		if(write(file,fname,11)!=11) {  /* Write filename to IXB file */
-			close(file);
-			free(ixbbuf);
-			return(FALSE); 
-		}
-		if(write(file,idx,3)!=3) {  /* Write DAT offset into IXB file */
-			close(file);
-			free(ixbbuf);
-			return(FALSE); 
-		}
-		write(file,&f->dateuled,4);
-		write(file,&f->datedled,4);              /* Write 0 for datedled */
-		if(write(file,&ixbbuf[l],length-l)!=length-l) { /* Write rest of IXB */
-			close(file);
-			free(ixbbuf);
-			return(FALSE); 
-		}
-		free(ixbbuf); 
+// Load and optionally-sort files from an open filebase into a dynamically-allocated list of "objects"
+file_t* loadfiles(smb_t* smb, const char* filespec, time_t t, enum file_detail detail, enum file_sort order, size_t* count)
+{
+	*count = 0;
+
+	long start = 0;	
+	if(t) {
+		idxrec_t idx;
+		start = smb_getmsgidx_by_time(smb, &idx, t);
+		if(start < 0)
+			return NULL;
 	}
-	else {              /* IXB file is empty... No files */
-		if(write(file,fname,11)!=11) {  /* Write filename it IXB file */
-			close(file);
-			return(FALSE); 
-		}
-		if(write(file,idx,3)!=3) {  /* Write DAT offset into IXB file */
-			close(file);
-			return(FALSE); 
+
+	file_t* file_list = calloc(smb->status.total_files, sizeof(file_t));
+	if(file_list == NULL)
+		return NULL;
+
+	fseek(smb->sid_fp, start * sizeof(fileidxrec_t), SEEK_SET);
+	long offset = start;
+	while(!feof(smb->sid_fp)) {
+		file_t* f = &file_list[*count];
+
+		if(smb_fread(smb, &f->file_idx, sizeof(f->file_idx), smb->sid_fp) != sizeof(f->file_idx))
+			break;
+
+		f->idx_offset = offset++;
+
+		if(f->idx.number == 0)	/* invalid message number, ignore */
+			continue;
+
+		TERMINATE(f->file_idx.name);
+
+		if(filespec != NULL && *filespec != '\0') {
+			if(!wildmatch(f->file_idx.name, filespec, /* path: */false, /* case-sensitive: */false))
+				continue;
 		}
-		write(file,&f->dateuled,4);
-		write(file,&f->datedled,4); 
+		int result = smb_getfile(smb, f, detail);
+		if(result != SMB_SUCCESS)
+			break;
+		(*count)++;
 	}
-	length=(long)filelength(file);
-	close(file);
-	return(TRUE);
+	if(order != FILE_SORT_NATURAL)
+		sortfiles(file_list, *count, order);
+
+	return file_list;
 }
 
-/****************************************************************************/
-/* Gets file data from dircode.ixb file										*/
-/* Need fields .name and .dir filled.                                       */
-/* only fills .offset, .dateuled, and .datedled                             */
-/****************************************************************************/
-BOOL DLLCALL getfileixb(scfg_t* cfg, file_t* f)
+static int file_compare_name_a(const void* v1, const void* v2)
 {
-	char			str[MAX_PATH+1],fname[13];
-	uchar *	ixbbuf;
-	int				file;
-	long			l,length;
+	file_t* f1 = (file_t*)v1;
+	file_t* f2 = (file_t*)v2;
 
-	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_RDONLY|O_BINARY,SH_DENYWR))==-1) {
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	if(length%F_IXBSIZE) {
-		close(file);
-		return(FALSE); 
-	}
-	if((ixbbuf=(uchar *)malloc(length))==NULL) {
-		close(file);
-		return(FALSE); 
-	}
-	if(read(file,ixbbuf,length)!=length) {
-		close(file);
-		free(ixbbuf);
-		return(FALSE); 
-	}
-	close(file);
-	SAFECOPY(fname,f->name);
-	for(l=8;l<12;l++)	/* Turn FILENAME.EXT into FILENAMEEXT */
-		fname[l]=fname[l+1];
-	for(l=0;l<length;l+=F_IXBSIZE) {
-		SAFEPRINTF(str,"%11.11s",ixbbuf+l);
-		if(!stricmp(str,fname))
-			break; 
-	}
-	if(l>=length) {
-		free(ixbbuf);
-		return(FALSE); 
-	}
-	l+=11;
-	f->datoffset=ixbbuf[l]|((long)ixbbuf[l+1]<<8)|((long)ixbbuf[l+2]<<16);
-	f->dateuled=ixbbuf[l+3]|((long)ixbbuf[l+4]<<8)
-		|((long)ixbbuf[l+5]<<16)|((long)ixbbuf[l+6]<<24);
-	f->datedled=ixbbuf[l+7]|((long)ixbbuf[l+8]<<8)
-		|((long)ixbbuf[l+9]<<16)|((long)ixbbuf[l+10]<<24);
-	free(ixbbuf);
-	return(TRUE);
+	return stricmp(f1->name, f2->name);
 }
 
-/****************************************************************************/
-/* Updates the datedled and dateuled index record fields for a file			*/
-/****************************************************************************/
-BOOL DLLCALL putfileixb(scfg_t* cfg, file_t* f)
+static int file_compare_name_ac(const void* v1, const void* v2)
 {
-	char	str[MAX_PATH+1],fname[13];
-	uchar*	ixbbuf;
-	int		file;
-	long	l,length;
+	file_t* f1 = (file_t*)v1;
+	file_t* f2 = (file_t*)v2;
 
-	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_RDWR|O_BINARY,SH_DENYRW))==-1) {
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	if(length%F_IXBSIZE) {
-		close(file);
-		return(FALSE); 
-	}
-	if((ixbbuf=(uchar *)malloc(length))==NULL) {
-		close(file);
-		return(FALSE); 
-	}
-	if(read(file,ixbbuf,length)!=length) {
-		close(file);
-		free(ixbbuf);
-		return(FALSE); 
-	}
-	SAFECOPY(fname,f->name);
-	for(l=8;l<12;l++)	/* Turn FILENAME.EXT into FILENAMEEXT */
-		fname[l]=fname[l+1];
-	for(l=0;l<length;l+=F_IXBSIZE) {
-		SAFEPRINTF(str,"%11.11s",ixbbuf+l);
-		if(!stricmp(str,fname))
+	return strcmp(f1->name, f2->name);
+}
+
+static int file_compare_name_d(const void* v1, const void* v2)
+{
+	file_t* f1 = (file_t*)v1;
+	file_t* f2 = (file_t*)v2;
+
+	return stricmp(f2->name, f1->name);
+}
+
+static int file_compare_name_dc(const void* v1, const void* v2)
+{
+	file_t* f1 = (file_t*)v1;
+	file_t* f2 = (file_t*)v2;
+
+	return strcmp(f2->name, f1->name);
+}
+
+static int file_compare_date_a(const void* v1, const void* v2)
+{
+	file_t* f1 = (file_t*)v1;
+	file_t* f2 = (file_t*)v2;
+
+	return f1->hdr.when_imported.time - f2->hdr.when_imported.time;
+}
+
+static int file_compare_date_d(const void* v1, const void* v2)
+{
+	file_t* f1 = (file_t*)v1;
+	file_t* f2 = (file_t*)v2;
+
+	return f2->hdr.when_imported.time - f1->hdr.when_imported.time;
+}
+
+void sortfiles(file_t* filelist, size_t count, enum file_sort order)
+{
+	switch(order) {
+		case FILE_SORT_NAME_A:
+			qsort(filelist, count, sizeof(*filelist), file_compare_name_a);
+			break;
+		case FILE_SORT_NAME_D:
+			qsort(filelist, count, sizeof(*filelist), file_compare_name_d);
+			break;
+		case FILE_SORT_NAME_AC:
+			qsort(filelist, count, sizeof(*filelist), file_compare_name_ac);
+			break;
+		case FILE_SORT_NAME_DC:
+			qsort(filelist, count, sizeof(*filelist), file_compare_name_dc);
+			break;
+		case FILE_SORT_DATE_A:
+			qsort(filelist, count, sizeof(*filelist), file_compare_date_a);
+			break;
+		case FILE_SORT_DATE_D:
+			qsort(filelist, count, sizeof(*filelist), file_compare_date_d);
 			break; 
 	}
-	free(ixbbuf);
+}
 
-	if(l>=length) {
-		close(file);
-		return(FALSE); 
-	}
-	
-	lseek(file,l+11+3,SEEK_SET);
+void freefiles(file_t* filelist, size_t count)
+{
+	for(size_t i = 0; i < count; i++)
+		smb_freefilemem(&filelist[i]);
+	free(filelist);
+}
 
-	write(file,&f->dateuled,4);
-	write(file,&f->datedled,4);
+bool loadfile(scfg_t* cfg, uint dirnum, const char* filename, file_t* file, enum file_detail detail)
+{
+	smb_t smb;
 
-	close(file);
+	if(smb_open_dir(cfg, &smb, dirnum) != SMB_SUCCESS)
+		return false;
 
-	return(TRUE);
+	int result = smb_loadfile(&smb, filename, file, detail);
+	smb_close(&smb);
+	if(cfg->dir[dirnum]->misc & DIR_FREE)
+		file->cost = 0;
+	return result == SMB_SUCCESS;
 }
 
+char* batch_list_name(scfg_t* cfg, uint usernumber, enum XFER_TYPE type, char* fname, size_t size)
+{
+	safe_snprintf(fname, size, "%suser/%04u.%sload", cfg->data_dir, usernumber
+		,(type == XFER_UPLOAD || type == XFER_BATCH_UPLOAD) ? "up" : "dn");
+	return fname;
+}
 
-/****************************************************************************/
-/* Removes DAT and IXB entries for the file in the struct 'f'               */
-/****************************************************************************/
-BOOL DLLCALL removefiledat(scfg_t* cfg, file_t* f)
-{
-	char	c,str[MAX_PATH+1],ixbname[12],*ixbbuf,fname[13];
-    int		i,file;
-	long	l,length;
-
-	SAFECOPY(fname,f->name);
-	for(i=8;i<12;i++)   /* Turn FILENAME.EXT into FILENAMEEXT */
-		fname[i]=fname[i+1];
-	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_RDONLY|O_BINARY,SH_DENYWR))==-1) {
-		return(FALSE); 
-	}
-	length=(long)filelength(file);
-	if(!length) {
-		close(file);
-		return(FALSE); 
-	}
-	if((ixbbuf=(char *)malloc(length))==0) {
-		close(file);
-		return(FALSE); 
-	}
-	if(read(file,ixbbuf,length)!=length) {
-		close(file);
-		free(ixbbuf);
-		return(FALSE); 
-	}
-	close(file);
-	if((file=sopen(str,O_WRONLY|O_TRUNC|O_BINARY,SH_DENYRW))==-1) {
-		free(ixbbuf);
-		return(FALSE); 
-	}
-	for(l=0;l<length;l+=F_IXBSIZE) {
-		for(i=0;i<11;i++)
-			ixbname[i]=ixbbuf[l+i];
-		ixbname[i]=0;
-		if(stricmp(ixbname,fname))
-			if(write(file,&ixbbuf[l],F_IXBSIZE)!=F_IXBSIZE) {
-				close(file);
-				free(ixbbuf);
-				return(FALSE); 
-		} 
-	}
-	free(ixbbuf);
-	close(file);
-	SAFEPRINTF2(str,"%s%s.dat",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=sopen(str,O_WRONLY|O_BINARY,SH_DENYRW))==-1) {
-		return(FALSE); 
-	}
-	lseek(file,f->datoffset,SEEK_SET);
-	c=ETX;          /* If first char of record is ETX, record is unused */
-	if(write(file,&c,1)!=1) { /* So write a D_T on the first byte of the record */
-		close(file);
-		return(FALSE); 
+FILE* batch_list_open(scfg_t* cfg, uint usernumber, enum XFER_TYPE type, bool create)
+{
+	char path[MAX_PATH + 1];
+	return iniOpenFile(batch_list_name(cfg, usernumber, type, path, sizeof(path)), create);
+}
+
+str_list_t batch_list_read(scfg_t* cfg, uint usernumber, enum XFER_TYPE type)
+{
+	FILE* fp = batch_list_open(cfg, usernumber, type, /* create: */false);
+	if(fp == NULL)
+		return NULL;
+	str_list_t ini = iniReadFile(fp);
+	iniCloseFile(fp);
+	return ini;
+}
+
+bool batch_list_write(scfg_t* cfg, uint usernumber, enum XFER_TYPE type, str_list_t list)
+{
+	FILE* fp = batch_list_open(cfg, usernumber, type, /* create: */true);
+	if(fp == NULL)
+		return false;
+	bool result = iniWriteFile(fp, list);
+	iniCloseFile(fp);
+	return result;
+}
+
+bool batch_list_clear(scfg_t* cfg, uint usernumber, enum XFER_TYPE type)
+{
+	char path[MAX_PATH + 1];
+	return remove(batch_list_name(cfg, usernumber, type, path, sizeof(path))) == 0;
+}
+
+size_t batch_file_count(scfg_t* cfg, uint usernumber, enum XFER_TYPE type)
+{
+	FILE* fp = batch_list_open(cfg, usernumber, type, /* create: */false);
+	if(fp == NULL)
+		return 0;
+	size_t result = iniReadSectionCount(fp, /* prefix: */NULL);
+	iniCloseFile(fp);
+	return result;
+}
+
+bool batch_file_remove(scfg_t* cfg, uint usernumber, enum XFER_TYPE type, const char* filename)
+{
+	FILE* fp = batch_list_open(cfg, usernumber, type, /* create: */false);
+	if(fp == NULL)
+		return false;
+	str_list_t ini = iniReadFile(fp);
+	bool result = iniRemoveSection(&ini, filename);
+	iniWriteFile(fp, ini);
+	iniCloseFile(fp);
+	iniFreeStringList(ini);
+	return result;
+}
+
+bool batch_file_exists(scfg_t* cfg, uint usernumber, enum XFER_TYPE type, const char* filename)
+{
+	FILE* fp = batch_list_open(cfg, usernumber, type, /* create: */false);
+	if(fp == NULL)
+		return false;
+	str_list_t ini = iniReadFile(fp);
+	bool result = iniSectionExists(ini, filename);
+	iniCloseFile(fp);
+	iniFreeStringList(ini);
+	return result;
+}
+
+bool batch_file_add(scfg_t* cfg, uint usernumber, enum XFER_TYPE type, file_t* f)
+{
+	FILE* fp = batch_list_open(cfg, usernumber, type, /* create: */true);
+	if(fp == NULL)
+		return false;
+	fseek(fp, 0, SEEK_END);
+	fprintf(fp, "\n[%s]\n", f->name);
+	if(f->dir >= 0 && f->dir < cfg->total_dirs)
+		fprintf(fp, "dir=%s\n", cfg->dir[f->dir]->code);
+	if(f->desc != NULL)
+		fprintf(fp, "desc=%s\n", f->desc);
+	if(f->tags != NULL)
+		fprintf(fp, "tags=%s\n", f->tags);
+	fclose(fp);
+	return true;
+}
+
+bool batch_file_get(scfg_t* cfg, str_list_t ini, const char* filename, file_t* f)
+{
+	char* p;
+	char value[INI_MAX_VALUE_LEN + 1];
+
+	if(!iniSectionExists(ini, filename))
+		return false;
+	f->dir = batch_file_dir(cfg, ini, filename);
+	if(f->dir < 0 || f->dir >= cfg->total_dirs)
+		return false;
+	smb_hfield_str(f, SMB_FILENAME, filename);
+	if((p = iniGetString(ini, filename, "desc", NULL, value)) != NULL)
+		smb_hfield_str(f, SMB_FILEDESC, p);
+	if((p = iniGetString(ini, filename, "tags", NULL, value)) != NULL)
+		smb_hfield_str(f, SMB_TAGS, p);
+	return true;
+}
+
+int batch_file_dir(scfg_t* cfg, str_list_t ini, const char* filename)
+{
+	char value[INI_MAX_VALUE_LEN + 1];
+	return getdirnum(cfg, iniGetString(ini, filename, "dir", NULL, value));
+}
+
+bool batch_file_load(scfg_t* cfg, str_list_t ini, const char* filename, file_t* f)
+{
+	if(!iniSectionExists(ini, filename))
+		return false;
+	f->dir = batch_file_dir(cfg, ini, filename);
+	if(f->dir < 0)
+		return false;
+	return loadfile(cfg, f->dir, filename, f, file_detail_normal);
+}
+
+bool updatefile(scfg_t* cfg, file_t* file)
+{
+	smb_t smb;
+
+	if(smb_open_dir(cfg, &smb, file->dir) != SMB_SUCCESS)
+		return false;
+
+	int result = smb_updatemsg(&smb, file) == SMB_SUCCESS;
+	smb_close(&smb);
+	return result == SMB_SUCCESS;
+}
+
+bool removefile(scfg_t* cfg, uint dirnum, const char* filename)
+{
+	smb_t smb;
+
+	if(smb_open_dir(cfg, &smb, dirnum) != SMB_SUCCESS)
+		return false;
+
+	int result;
+	file_t file;
+	if((result = smb_loadfile(&smb, filename, &file, file_detail_normal)) == SMB_SUCCESS) {
+		result = smb_removefile(&smb, &file);
+		smb_freefilemem(&file);
 	}
-	close(file);
-	if(f->dir==cfg->user_dir)  /* remove file from index */
-		rmuserxfers(cfg,0,0,f->name);
-	return(TRUE);
+	smb_close(&smb);
+	return result == SMB_SUCCESS;
 }
 
 /****************************************************************************/
-/* Checks  directory data file for 'filename' (must be padded). If found,   */
-/* it returns the 1, else returns 0.                                        */
-/* Called from upload and bulkupload                                        */
+/* Returns full (case-corrected) path to specified file						*/
+/* 'path' should be MAX_PATH + 1 chars in size								*/
+/* If the directory is configured to allow file-checking and the file does	*/
+/* not exist, the size element is set to -1.								*/
 /****************************************************************************/
-BOOL DLLCALL findfile(scfg_t* cfg, uint dirnum, char *filename)
-{
-	char str[MAX_PATH+1],fname[13],*ixbbuf;
-    int i,file;
-    long length,l;
-
-	SAFECOPY(fname,filename);
-	strupr(fname);
-	for(i=8;i<12;i++)   /* Turn FILENAME.EXT into FILENAMEEXT */
-		fname[i]=fname[i+1];
-	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[dirnum]->data_dir,cfg->dir[dirnum]->code);
-	if((file=sopen(str,O_RDONLY|O_BINARY,SH_DENYWR))==-1) return(FALSE);
-	length=(long)filelength(file);
-	if(!length) {
-		close(file);
-		return(FALSE); 
+char* getfilepath(scfg_t* cfg, file_t* f, char* path)
+{
+	bool fchk = true;
+	const char* name = f->name == NULL ? f->file_idx.name : f->name;
+	if(f->dir >= cfg->total_dirs)
+		safe_snprintf(path, MAX_PATH, "%s%s", cfg->temp_dir, name);
+	else {
+		safe_snprintf(path, MAX_PATH, "%s%s", cfg->dir[f->dir]->path, name);
+		fchk = (cfg->dir[f->dir]->misc & DIR_FCHK) != 0;
 	}
-	if((ixbbuf=(char *)malloc(length))==NULL) {
-		close(file);
-		return(FALSE); 
+	if(f->size == 0 && fchk && !fexistcase(path))
+		f->size = -1;
+	return path;
+}
+
+off_t getfilesize(scfg_t* cfg, file_t* f)
+{
+	char fpath[MAX_PATH + 1];
+	if(f->size > 0)
+		return f->size;
+	f->size = flength(getfilepath(cfg, f, fpath));
+	return f->size;
+}
+
+time_t getfiletime(scfg_t* cfg, file_t* f)
+{
+	char fpath[MAX_PATH + 1];
+	if(f->time > 0)
+		return f->time;
+	f->time = fdate(getfilepath(cfg, f, fpath));
+	return f->time;
+}
+
+ulong gettimetodl(scfg_t* cfg, file_t* f, uint rate_cps)
+{
+	if(getfilesize(cfg, f) < 1)
+		return 0;
+	if(f->size <= (off_t)rate_cps)
+		return 1;
+	return (ulong)(f->size / rate_cps);
+}
+
+bool hashfile(scfg_t* cfg, file_t* f)
+{
+	bool result = false;
+	smb_t smb;
+
+	if(cfg->dir[f->dir]->misc & DIR_NOHASH)
+		return false;
+
+	if(smb_open_dir(cfg, &smb, f->dir) != SMB_SUCCESS)
+		return false;
+
+	if(!(smb.status.attr & SMB_NOHASH)) {
+		char fpath[MAX_PATH + 1];
+		getfilepath(cfg, f, fpath);
+		if((f->file_idx.hash.flags = smb_hashfile(fpath, getfilesize(cfg, f), &f->file_idx.hash.data)) != 0)
+			result = true;
+	}
+	smb_close(&smb);
+	return result;
+}
+
+bool addfile(scfg_t* cfg, uint dirnum, file_t* f, const char* extdesc)
+{
+	char fpath[MAX_PATH + 1];
+	smb_t smb;
+
+	if(smb_open_dir(cfg, &smb, dirnum) != SMB_SUCCESS)
+		return false;
+
+	getfilepath(cfg, f, fpath);
+	int result = smb_addfile(&smb, f, SMB_SELFPACK, extdesc, fpath);
+	smb_close(&smb);
+	return result == SMB_SUCCESS;
+}
+
+/* 'size' does not include the NUL-terminator */
+char* format_filename(const char* fname, char* buf, size_t size, bool pad)
+{
+	size_t fnlen = strlen(fname);
+	char* ext = getfext(fname);
+	if(ext != NULL) {
+		size_t extlen = strlen(ext);
+		if(extlen >= size)
+			safe_snprintf(buf, size + 1, "%s", fname);
+		else {
+			fnlen -= extlen;
+			if(fnlen > size - extlen)
+				fnlen = size - extlen;
+			safe_snprintf(buf, size + 1, "%-*.*s%s", (int)(pad ? (size - extlen) : 0), (int)fnlen, fname, ext);
+		}
+	} else	/* no extension */
+		snprintf(buf, size + 1, "%s", fname);
+	return buf;
+}
+
+int archive_type(const char* archive, char* str, size_t size)
+{
+	int result;
+	struct archive *ar;
+	struct archive_entry *entry;
+
+	if((ar = archive_read_new()) == NULL) {
+		safe_snprintf(str, size, "archive_read_new returned NULL");
+		return -1;
 	}
-	if(read(file,ixbbuf,length)!=length) {
-		close(file);
-		free(ixbbuf);
-		return(FALSE); 
+	archive_read_support_filter_all(ar);
+	archive_read_support_format_all(ar);
+	if((result = archive_read_open_filename(ar, archive, 10240)) != ARCHIVE_OK) {
+		safe_snprintf(str, size, "archive_read_open_filename returned %d: %s"
+			,result, archive_error_string(ar));
+		archive_read_free(ar);
+		return result;
 	}
-	close(file);
-	for(l=0;l<length;l+=F_IXBSIZE) {
-		for(i=0;i<11;i++)
-			if(toupper(fname[i])!=toupper(ixbbuf[l+i])) break;
-		if(i==11) break; 
+	result = archive_filter_code(ar, 0);
+	if(result >= 0) {
+		int comp = result;
+		result = archive_read_next_header(ar, &entry);
+		if(result != ARCHIVE_OK)
+			safe_snprintf(str, size, "archive_read_next_header returned %d: %s"
+				,result, archive_error_string(ar));
+		else {
+			result = archive_format(ar);
+			if(comp > 0)
+				safe_snprintf(str, size, "%s/%s", archive_filter_name(ar, 0), archive_format_name(ar));
+			else
+				safe_snprintf(str, size, "%s", archive_format_name(ar));
+		}
 	}
-	free(ixbbuf);
-	if(l!=length)
-		return(TRUE);
-	return(FALSE);
+	archive_read_free(ar);
+	return result;
 }
 
-/****************************************************************************/
-/* Turns FILE.EXT into FILE    .EXT                                         */
-/****************************************************************************/
-char* DLLCALL padfname(const char *filename, char *str)
-{
-    int c,d;
-
-	for(c=0;c<8;c++)
-		if(filename[c]=='.' || !filename[c]) break;
-		else str[c]=filename[c];
-	d=c;
-	if(filename[c]=='.') c++;
-	while(d<8)
-		str[d++]=' ';
-	if(filename[c]>' ')	/* Change "FILE" to "FILE        " */
-		str[d++]='.';	/* (don't add a dot if there's no extension) */
-	else
-		str[d++]=' ';
-	while(d<12)
-		if(!filename[c]) break;
-		else str[d++]=filename[c++];
-	while(d<12)
-		str[d++]=' ';
-	str[d]=0;
-	return(str);
+str_list_t directory(const char* path)
+{
+	int			flags = GLOB_MARK;
+	glob_t		g;
+
+	if(glob(path, flags, NULL, &g) != 0)
+		return NULL;
+	str_list_t list = strListInit();
+	for(size_t i = 0; i < g.gl_pathc; i++) {
+		strListPush(&list, g.gl_pathv[i]);
+	}
+	globfree(&g);
+	return list;
 }
 
-/****************************************************************************/
-/* Turns FILE    .EXT into FILE.EXT                                         */
-/****************************************************************************/
-char* DLLCALL unpadfname(const char *filename, char *str)
+const char* supported_archive_formats[] = { "zip", "7z", "tgz", "tbz", NULL };
+// Returns negative on error
+long create_archive(const char* archive, const char* format
+	,bool with_path, str_list_t file_list, char* error, size_t maxerrlen)
 {
-    int c,d;
+	int result;
+	struct archive *ar;
 
-	for(c=0,d=0;filename[c];c++)
-		if(filename[c]!=' ') str[d++]=filename[c];
-	str[d]=0;
-	return(str);
-}
+	if(file_list == NULL || *file_list == NULL)
+		return 0;
 
-/****************************************************************************/
-/* Removes any files in the user transfer index (XFER.IXT) that match the   */
-/* specifications of dest, or source user, or filename or any combination.  */
-/****************************************************************************/
-BOOL DLLCALL rmuserxfers(scfg_t* cfg, int fromuser, int destuser, char *fname)
-{
-    char str[MAX_PATH+1],*ixtbuf;
-    int file;
-    long l,length;
-
-	SAFEPRINTF(str,"%sxfer.ixt", cfg->data_dir);
-	if(!fexist(str))
-		return(FALSE);
-	if(!flength(str)) {
-		remove(str);
-		return(FALSE); 
+	if((ar = archive_write_new()) == NULL) {
+		safe_snprintf(error, maxerrlen, "archive_write_new returned NULL");
+		return -1;
 	}
-	if((file=sopen(str,O_RDONLY|O_BINARY,SH_DENYWR))==-1) {
-		return(FALSE); 
+	if(stricmp(format, "tgz") == 0) {
+		archive_write_add_filter_gzip(ar);
+		archive_write_set_format_pax_restricted(ar);
+	} else if(stricmp(format, "tbz") == 0) {
+		archive_write_add_filter_bzip2(ar);
+		archive_write_set_format_pax_restricted(ar);
+	} else if(stricmp(format, "zip") == 0) {
+		archive_write_set_format_zip(ar);
+	} else if(stricmp(format, "7z") == 0) {
+		archive_write_set_format_7zip(ar);
+	} else {
+		safe_snprintf(error, maxerrlen, "unsupported format: %s", format);
+		return -2;
 	}
-	length=(long)filelength(file);
-	if((ixtbuf=(char *)malloc(length))==NULL) {
-		close(file);
-		return(FALSE); 
+	if((result = archive_write_open_filename(ar, archive)) != ARCHIVE_OK) {
+		safe_snprintf(error, maxerrlen, "archive_write_open_filename(%s) returned %d: %s"
+			,archive, result, archive_error_string(ar));
+		archive_write_free(ar);
+		return result;
 	}
-	if(read(file,ixtbuf,length)!=length) {
-		close(file);
-		free(ixtbuf);
-		return(FALSE); 
+	ulong file_count = 0;
+	for(;file_list[file_count] != NULL; file_count++) {
+		struct archive_entry* entry;
+		struct stat st;
+		const char* filename = file_list[file_count];
+		FILE* fp = fopen(filename, "rb");
+		if(fp == NULL) {
+			safe_snprintf(error, maxerrlen, "%d opening %s", errno, filename);
+			break;
+		}
+		fstat(fileno(fp), &st);
+		if((entry = archive_entry_new()) == NULL) {
+			safe_snprintf(error, maxerrlen, "archive_entry_new returned NULL");
+			fclose(fp);
+			break;
+		}
+		if(with_path)
+			archive_entry_set_pathname(entry, filename);
+		else
+			archive_entry_set_pathname(entry, getfname(filename));
+		archive_entry_set_size(entry, st.st_size);
+		archive_entry_set_mtime(entry, st.st_mtime, 0);
+		archive_entry_set_filetype(entry, AE_IFREG);
+		archive_entry_set_perm(entry, 0644);
+		if((result = archive_write_header(ar, entry)) != ARCHIVE_OK)
+			safe_snprintf(error, maxerrlen, "archive_write_header returned %d", result);
+		else while(!feof(fp)) {
+			char buf[256 * 1024];
+			size_t len = fread(buf, 1, sizeof(buf), fp);
+			if((result = archive_write_data(ar, buf, len)) != len) {
+				safe_snprintf(error, maxerrlen, "archive_write_data returned %d instead of %d", result, (int)len);
+				break;
+			} else
+				result = ARCHIVE_OK;
+		}
+		fclose(fp);
+		archive_entry_free(entry);
+		if(result != ARCHIVE_OK)
+			break;
 	}
-	close(file);
-	if((file=sopen(str,O_WRONLY|O_TRUNC|O_BINARY,SH_DENYRW))==-1) {
-		free(ixtbuf);
-		return(FALSE); 
+	archive_write_close(ar);
+	archive_write_free(ar);
+	if(file_list[file_count] != NULL)
+		return result < 0 ? result : -1;
+	return file_count;
+}
+
+long extract_files_from_archive(const char* archive, const char* outdir, const char* allowed_filename_chars
+	,bool with_path, long max_files, str_list_t file_list, char* error, size_t maxerrlen)
+{
+	int result;
+	struct archive *ar;
+	struct archive_entry *entry;
+	long extracted = 0;
+	char fpath[MAX_PATH + 1];
+
+	if(error != NULL && maxerrlen >= 1)
+		*error = '\0';
+	if((ar = archive_read_new()) == NULL) {
+		safe_snprintf(error, maxerrlen, "archive_read_new returned NULL");
+		return -1;
 	}
-	for(l=0;l<length;l+=24) {
-		if(fname!=NULL && fname[0]) {               /* fname specified */
-			if(!strncmp(ixtbuf+l+5,fname,12)) {     /* this is the file */
-				if(destuser && fromuser) {          /* both dest and from user */
-					if(atoi(ixtbuf+l)==destuser && atoi(ixtbuf+l+18)==fromuser)
-						continue;                   /* both match */
-				}
-				else if(fromuser) {                 /* from user */
-					if(atoi(ixtbuf+l+18)==fromuser) /* matches */
-						continue; 
-				}
-				else if(destuser) {                 /* dest user */
-					if(atoi(ixtbuf+l)==destuser)    /* matches */
-						continue; 
-				}
-				else continue;		                /* no users, so match */
-			}
-		}
-		else if(destuser && fromuser) {
-			if(atoi(ixtbuf+l+18)==fromuser && atoi(ixtbuf+l)==destuser)
-				continue; 
+	archive_read_support_filter_all(ar);
+	archive_read_support_format_all(ar);
+	if((result = archive_read_open_filename(ar, archive, 10240)) != ARCHIVE_OK) {
+		safe_snprintf(error, maxerrlen, "archive_read_open_filename returned %d: %s"
+			,result, archive_error_string(ar));
+		archive_read_free(ar);
+		return result >= 0 ? -1 : result;
+	}
+	while(1) {
+		result = archive_read_next_header(ar, &entry);
+		if(result != ARCHIVE_OK) {
+			if(result != ARCHIVE_EOF)
+				safe_snprintf(error, maxerrlen, "archive_read_next_header returned %d: %s"
+					,result, archive_error_string(ar));
+			break;
 		}
-		else if(destuser && atoi(ixtbuf+l)==destuser)
+		const char* pathname = archive_entry_pathname(entry);
+		if(pathname == NULL)
 			continue;
-		else if(fromuser && atoi(ixtbuf+l+18)==fromuser)
+		int filetype = archive_entry_filetype(entry);
+		if(filetype == AE_IFDIR) {
+			if(!with_path)
+				continue;
+			if(strstr(pathname, "..") != NULL) {
+				safe_snprintf(error, maxerrlen, "Illegal double-dots in path '%s'", pathname);
+				break;
+			}
+			SAFECOPY(fpath, outdir);
+			backslash(fpath);
+			SAFECAT(fpath, pathname);
+			if(mkpath(fpath) != 0) {
+				char err[256];
+				safe_snprintf(error, maxerrlen, "%d (%s) creating path '%s'", errno, safe_strerror(errno, err, sizeof(err)), fpath);
+				break;
+			}
 			continue;
-		write(file,ixtbuf+l,24); 
-	}
-	close(file);
-	free(ixtbuf);
+		}
+		if(filetype != AE_IFREG)
+			continue;
+		char* filename = getfname(pathname);
+		if(allowed_filename_chars != NULL
+			&& *allowed_filename_chars != '\0'
+			&& strspn(filename, allowed_filename_chars) != strlen(filename)) {
+			safe_snprintf(error, maxerrlen, "disallowed filename '%s'", pathname);
+			break;
+		}
+		if(!with_path)
+			pathname = filename;
+		if(file_list != NULL) {
+			int i;
+			for (i = 0; file_list[i] != NULL; i++)
+				if(wildmatch(pathname, file_list[i], with_path, /* case-sensitive: */false))
+					break;
+			if(file_list[i] == NULL)
+				continue;
+		}
+		SAFECOPY(fpath, outdir);
+		backslash(fpath);
+		SAFECAT(fpath, pathname);
+		FILE* fp = fopen(fpath, "wb");
+		if(fp == NULL) {
+			char err[256];
+			safe_snprintf(error, maxerrlen, "%d (%s) opening/creating '%s'", errno, safe_strerror(errno, err, sizeof(err)), fpath);
+			break;
+		}
+
+		const void *buff;
+		size_t size;
+		la_int64_t offset;
 
-	return(TRUE);
+		for(;;) {
+			result = archive_read_data_block(ar, &buff, &size, &offset);
+			if(result == ARCHIVE_EOF) {
+				extracted++;
+				break;
+			}
+			if(result < ARCHIVE_OK) {
+				safe_snprintf(error, maxerrlen, "archive_read_data_block returned %d: %s"
+					,result, archive_error_string(ar));
+				break;
+			}
+			if(fwrite(buff, 1, size, fp) != size)
+				break;
+		}
+		fclose(fp);
+		if(result != ARCHIVE_EOF)
+			(void)remove(fpath);
+		if(max_files && extracted >= max_files) {
+			safe_snprintf(error, maxerrlen, "maximum number of files (%lu) extracted", max_files);
+			break;
+		}
+	}
+	archive_read_free(ar);
+	return extracted;
 }
 
-void DLLCALL getextdesc(scfg_t* cfg, uint dirnum, ulong datoffset, char *ext)
+bool extract_diz(scfg_t* cfg, file_t* f, str_list_t diz_fnames, char* path, size_t maxlen)
 {
-	char str[MAX_PATH+1];
-	int file;
+	int i;
+	char archive[MAX_PATH + 1];
+	char* default_diz_fnames[] = { "FILE_ID.DIZ", "DESC.SDI", NULL };
+
+	getfilepath(cfg, f, archive);
+	if(diz_fnames == NULL)
+		diz_fnames = default_diz_fnames;
+
+	if(!fexistcase(archive))
+		return false;
+
+	for(i = 0; diz_fnames[i] != NULL; i++) {
+		safe_snprintf(path, maxlen, "%s%s", cfg->temp_dir, diz_fnames[i]); // no slash
+		removecase(path);
+		if(fexistcase(path))	// failed to delete?
+			return false;
+	}
+
+	if(extract_files_from_archive(archive
+		,/* outdir: */cfg->temp_dir
+		,/* allowed_filename_chars: */NULL /* any */
+		,/* with_path: */false
+		,/* max_files: */strListCount(diz_fnames)
+		,/* file_list: */diz_fnames
+		,/* error: */NULL, 0) >= 0) {
+		for(i = 0; diz_fnames[i] != NULL; i++) {
+			safe_snprintf(path, maxlen, "%s%s", cfg->temp_dir, diz_fnames[i]); // no slash
+			if(fexistcase(path))
+				return true;
+		}
+		return false;
+	}
+
+	char* fext = getfext(f->name);
 
-	memset(ext,0,F_EXBSIZE+1);
-	SAFEPRINTF2(str,"%s%s.exb",cfg->dir[dirnum]->data_dir,cfg->dir[dirnum]->code);
-	if((file=nopen(str,O_RDONLY))==-1)
-		return;
-	lseek(file,(datoffset/F_LEN)*F_EXBSIZE,SEEK_SET);
-	read(file,ext,F_EXBSIZE);
-	close(file);
+	if(fext == NULL)
+		return false;
+
+	for(i = 0; i < cfg->total_fextrs; i++)
+		if(stricmp(cfg->fextr[i]->ext, fext + 1) == 0 && chk_ar(cfg, cfg->fextr[i]->ar, /* user: */NULL, /* client: */NULL))
+			break;
+	if(i >= cfg->total_fextrs)
+		return false;
+
+	fextr_t* fextr = cfg->fextr[i];
+	char cmd[512];
+	for(i = 0; diz_fnames[i] != NULL; i++) {
+		safe_snprintf(path, maxlen, "%s%s", cfg->temp_dir, diz_fnames[i]);
+		system(cmdstr(cfg, /* user: */NULL, fextr->cmd, archive, diz_fnames[i], cmd, sizeof(cmd)));
+		if(fexistcase(path))
+			return true;
+	}
+	return false;
 }
 
-void DLLCALL putextdesc(scfg_t* cfg, uint dirnum, ulong datoffset, char *ext)
+str_list_t read_diz(const char* path, size_t max_line_len)
 {
-	char str[MAX_PATH+1],nulbuf[F_EXBSIZE];
-	int file;
+	FILE* fp = fopen(path, "r");
+	if(fp == NULL)
+		return NULL;
 
-	strip_ansi(ext);
-	strip_invalid_attr(ext);	/* eliminate bogus ctrl-a codes */
-	memset(nulbuf,0,sizeof(nulbuf));
-	SAFEPRINTF2(str,"%s%s.exb",cfg->dir[dirnum]->data_dir,cfg->dir[dirnum]->code);
-	if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
-		return;
-	lseek(file,0L,SEEK_END);
-	while(filelength(file)<(long)(datoffset/F_LEN)*F_EXBSIZE)
-		write(file,nulbuf,sizeof(nulbuf));
-	lseek(file,(datoffset/F_LEN)*F_EXBSIZE,SEEK_SET);
-	write(file,ext,F_EXBSIZE);
-	close(file);
+	str_list_t lines = strListReadFile(fp, NULL, max_line_len);
+	fclose(fp);
+	return lines;
 }
 
-/****************************************************************************/
-/* Update the upload date for the file 'f'                                  */
-/****************************************************************************/
-int DLLCALL update_uldate(scfg_t* cfg, file_t* f)
-{
-	char str[MAX_PATH+1],fname[13];
-	int i,file;
-	long l,length;
-
-	/*******************/
-	/* Update IXB File */
-	/*******************/
-	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=nopen(str,O_RDWR))==-1)
-		return(errno); 
-	length=(long)filelength(file);
-	if(length%F_IXBSIZE) {
-		close(file);
-		return(-1); 
-	}
-	SAFECOPY(fname,f->name);
-	for(i=8;i<12;i++)   /* Turn FILENAME.EXT into FILENAMEEXT */
-		fname[i]=fname[i+1];
-	for(l=0;l<length;l+=F_IXBSIZE) {
-		read(file,str,F_IXBSIZE);      /* Look for the filename in the IXB file */
-		str[11]=0;
-		if(!stricmp(fname,str)) break; 
+char* format_diz(str_list_t lines, char* str, size_t maxlen, bool allow_ansi)
+{
+	if(lines == NULL) {
+		*str = '\0';
+		return NULL;
 	}
-	if(l>=length) {
-		close(file);
-		return(-2); 
+	strListTruncateTrailingWhitespaces(lines);
+	if(!allow_ansi) {
+		for(size_t i = 0; lines[i] != NULL; i++) {
+			strip_ansi(lines[i]);
+			strip_ctrl(lines[i], lines[i]);
+		}
 	}
-	lseek(file,l+14,SEEK_SET);
-	write(file,&f->dateuled,4);
-	close(file);
+	strListFastDeleteBlanks(lines);
+	return strListCombine(lines, str, maxlen, "\r\n");
+}
 
-	/*******************************************/
-	/* Update last upload date/time stamp file */
-	/*******************************************/
-	SAFEPRINTF2(str,"%s%s.dab",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
-	if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
-		return(errno);
+// Take a verbose extended description (e.g. FILE_ID.DIZ)
+// and convert to suitable short description
+char* prep_file_desc(const char *src, char* dest)
+{
+	int out;
+
+	FIND_ALPHANUMERIC(src);
+	for(out = 0; *src != '\0' && out < LEN_FDESC; src++) {
+		if(IS_WHITESPACE(*src) && out && IS_WHITESPACE(dest[out - 1]))
+			continue;
+		if(!IS_ALPHANUMERIC(*src) && out && *src == dest[out - 1])
+			continue;
+		if(*src == '\n') {
+			if(out && !IS_WHITESPACE(dest[out - 1]))
+				dest[out++] = ' ';
+			continue;
+		}
+		if(IS_CONTROL(*src))
+			continue;
+		dest[out++] = *src;
+	}
+	dest[out] = '\0';
+	return dest;
+}
 
-	write(file,&f->dateuled,4);
-	close(file); 
-	return(0);
+static const char* quoted_string(const char* str, char* buf, size_t maxlen)
+{
+	if(strchr(str,' ')==NULL)
+		return(str);
+	safe_snprintf(buf,maxlen,"\"%s\"",str);
+	return(buf);
 }
 
+#define QUOTED_STRING(ch, str, buf, maxlen) \
+	((IS_ALPHA(ch) && IS_UPPERCASE(ch)) ? str : quoted_string(str,buf,maxlen))
+
 /****************************************************************************/
-/* Returns full (case-corrected) path to specified file						*/
+/* Returns command line generated from instr with %c replacements           */
+/* This is the C-exported version of sbbs_t::cmdstr()						*/
 /****************************************************************************/
-char* DLLCALL getfilepath(scfg_t* cfg, file_t* f, char* path)
+char* cmdstr(scfg_t* cfg, user_t* user, const char* instr, const char* fpath
+						,const char* fspec, char* cmd, size_t maxlen)
 {
-	char	fname[MAX_PATH+1];
+	char	str[MAX_PATH+1];
+    int		i,j,len;
+
+	len=strlen(instr);
+	for(i=j=0; i < len && j < (int)maxlen; i++) {
+        if(instr[i]=='%') {
+            i++;
+            cmd[j]=0;
+			int avail = maxlen - j;
+			char ch=instr[i];
+			if(IS_ALPHA(ch))
+				ch=toupper(ch);
+            switch(ch) {
+                case 'A':   /* User alias */
+					if(user!=NULL)
+						strncat(cmd,QUOTED_STRING(instr[i],user->alias,str,sizeof(str)), avail);
+                    break;
+                case 'B':   /* Baud (DTE) Rate */
+                    break;
+                case 'C':   /* Connect Description */
+					if(user!=NULL)
+						strncat(cmd,user->modem, avail);
+                    break;
+                case 'D':   /* Connect (DCE) Rate */
+                    break;
+                case 'E':   /* Estimated Rate */
+                    break;
+                case 'F':   /* File path */
+                    strncat(cmd,QUOTED_STRING(instr[i],fpath,str,sizeof(str)), avail);
+                    break;
+                case 'G':   /* Temp directory */
+                    strncat(cmd,cfg->temp_dir, avail);
+                    break;
+                case 'H':   /* Port Handle or Hardware Flow Control */
+                    break;
+                case 'I':   /* IP address */
+					if(user!=NULL)
+						strncat(cmd,user->note, avail);
+                    break;
+                case 'J':
+                    strncat(cmd,cfg->data_dir, avail);
+                    break;
+                case 'K':
+                    strncat(cmd,cfg->ctrl_dir, avail);
+                    break;
+                case 'L':   /* Lines per message */
+					if(user!=NULL)
+						strncat(cmd,ultoa(cfg->level_linespermsg[user->level],str,10), avail);
+                    break;
+                case 'M':   /* Minutes (credits) for user */
+					if(user!=NULL)
+						strncat(cmd,ultoa(user->min,str,10), avail);
+                    break;
+                case 'N':   /* Node Directory (same as SBBSNODE environment var) */
+                    strncat(cmd,cfg->node_dir, avail);
+                    break;
+                case 'O':   /* SysOp */
+                    strncat(cmd,QUOTED_STRING(instr[i],cfg->sys_op,str,sizeof(str)), avail);
+                    break;
+                case 'P':   /* Client protocol */
+                    break;
+                case 'Q':   /* QWK ID */
+                    strncat(cmd,cfg->sys_id, avail);
+                    break;
+                case 'R':   /* Rows */
+					if(user!=NULL)
+						strncat(cmd,ultoa(user->rows,str,10), avail);
+                    break;
+                case 'S':   /* File Spec */
+                    strncat(cmd, fspec, avail);
+                    break;
+                case 'T':   /* Time left in seconds */
+                    break;
+                case 'U':   /* UART I/O Address (in hex) */
+                    strncat(cmd,ultoa(cfg->com_base,str,16), avail);
+                    break;
+                case 'V':   /* Synchronet Version */
+                    sprintf(str,"%s%c",VERSION,REVISION);
+					strncat(cmd,str, avail);
+                    break;
+                case 'W':   /* Columns/width */
+                    break;
+                case 'X':
+					if(user!=NULL)
+						strncat(cmd,cfg->shell[user->shell]->code, avail);
+                    break;
+                case '&':   /* Address of msr */
+                    break;
+                case 'Y':
+                    break;
+                case 'Z':
+                    strncat(cmd,cfg->text_dir, avail);
+                    break;
+				case '~':	/* DOS-compatible (8.3) filename */
+				{
+#ifdef _WIN32
+					char sfpath[MAX_PATH+1];
+					SAFECOPY(sfpath,fpath);
+					GetShortPathName(fpath,sfpath,sizeof(sfpath));
+					strncat(cmd,sfpath, avail);
+#else
+                    strncat(cmd,QUOTED_STRING(instr[i],fpath,str,sizeof(str)), avail);
+#endif
+					break;
+				}
+                case '!':   /* EXEC Directory */
+                    strncat(cmd,cfg->exec_dir, avail);
+                    break;
+                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
+#ifndef __unix__
+                    strncat(cmd,cfg->exec_dir, avail);
+#endif
+                    break;
+
+                case '#':   /* Node number (same as SBBSNNUM environment var) */
+                    sprintf(str,"%d",cfg->node_num);
+                    strncat(cmd,str, avail);
+                    break;
+                case '*':
+                    sprintf(str,"%03d",cfg->node_num);
+                    strncat(cmd,str, avail);
+                    break;
+                case '$':   /* Credits */
+					if(user!=NULL)
+						strncat(cmd,ultoa(user->cdt+user->freecdt,str,10), avail);
+                    break;
+                case '%':   /* %% for percent sign */
+                    strncat(cmd,"%", avail);
+                    break;
+				case '.':	/* .exe for DOS/OS2/Win32, blank for Unix */
+#ifndef __unix__
+					strncat(cmd,".exe", avail);
+#endif
+					break;
+				case '?':	/* Platform */
+#ifdef __OS2__
+					strcpy(str,"OS2");
+#else
+					strcpy(str,PLATFORM_DESC);
+#endif
+					strlwr(str);
+					strncat(cmd,str, avail);
+					break;
+				case '^':	/* Architecture */
+					strncat(cmd, ARCHITECTURE_DESC, avail);
+					break;
+                default:    /* unknown specification */
+                    if(IS_DIGIT(instr[i]) && user!=NULL) {
+                        sprintf(str,"%0*d",instr[i]&0xf,user->number);
+                        strncat(cmd,str, avail);
+					}
+                    break;
+			}
+            j=strlen(cmd);
+		}
+        else
+            cmd[j++]=instr[i];
+	}
+    cmd[j]=0;
 
-	unpadfname(f->name,fname);
-	if(f->dir>=cfg->total_dirs)
-		safe_snprintf(path,MAX_PATH,"%s%s",cfg->temp_dir,fname);
-	else
-		safe_snprintf(path,MAX_PATH,"%s%s",f->altpath>0 && f->altpath<=cfg->altpaths 
-			? cfg->altpath[f->altpath-1] : cfg->dir[f->dir]->path
-			,fname);
-	fexistcase(path);
-	return(path);
+    return(cmd);
 }
+
diff --git a/src/sbbs3/filedat.h b/src/sbbs3/filedat.h
index 67f3d3e837..277d9ad56c 100644
--- a/src/sbbs3/filedat.h
+++ b/src/sbbs3/filedat.h
@@ -1,4 +1,4 @@
-/* Synchronet Filebase Access functions */
+/* Synchronet FileBase Access functions */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -24,29 +24,66 @@
 
 #include "scfgdefs.h"	// scfg_t
 #include "dllexport.h"
+#include "smblib.h"
+
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-DLLEXPORT BOOL		getfileixb(scfg_t* cfg, file_t* f);
-DLLEXPORT BOOL		putfileixb(scfg_t* cfg, file_t* f);
-DLLEXPORT BOOL		getfiledat(scfg_t* cfg, file_t* f);
-DLLEXPORT BOOL		putfiledat(scfg_t* cfg, file_t* f);
-DLLEXPORT void		putextdesc(scfg_t* cfg, uint dirnum, ulong datoffset, char *ext);
-DLLEXPORT void		getextdesc(scfg_t* cfg, uint dirnum, ulong datoffset, char *ext);
-DLLEXPORT char*		getfilepath(scfg_t* cfg, file_t* f, char* path);
+DLLEXPORT bool			newfiles(smb_t*, time_t);
+DLLEXPORT time_t		newfiletime(smb_t*);
+DLLEXPORT bool			update_newfiletime(smb_t*, time_t);
+DLLEXPORT time_t		dir_newfiletime(scfg_t*, uint dirnum);
+DLLEXPORT time_t		lastfiletime(smb_t*); // Reads the last index record
+
+DLLEXPORT bool			findfile(scfg_t* cfg, uint dirnum, const char *filename, file_t*);
+DLLEXPORT bool			loadfile(scfg_t*, uint dirnum, const char* filename, file_t*, enum file_detail);
+DLLEXPORT file_t*	loadfiles(smb_t*, const char* filespec, time_t, enum file_detail, enum file_sort, size_t* count);
+DLLEXPORT void			sortfiles(file_t*, size_t count, enum file_sort);
+DLLEXPORT void			freefiles(file_t*, size_t count);
+DLLEXPORT str_list_t	loadfilenames(smb_t*, const char* filespec, time_t t, enum file_sort, size_t* count);
+DLLEXPORT void			sortfilenames(str_list_t, size_t count, enum file_sort);
+DLLEXPORT bool			updatefile(scfg_t*, file_t*);
+DLLEXPORT char*			getfilepath(scfg_t*, file_t*, char* path);
+DLLEXPORT off_t			getfilesize(scfg_t*, file_t*);
+DLLEXPORT time_t		getfiletime(scfg_t*, file_t*);
+DLLEXPORT ulong			gettimetodl(scfg_t*, file_t*, uint rate_cps);
+DLLEXPORT bool			hashfile(scfg_t*, file_t*);
+DLLEXPORT bool			addfile(scfg_t*, uint dirnum, file_t*, const char* extdesc);
+DLLEXPORT bool			removefile(scfg_t*, uint dirnum, const char* filename);
+DLLEXPORT char*			format_filename(const char* fname, char* buf, size_t, bool pad);
+DLLEXPORT bool			extract_diz(scfg_t*, file_t*, str_list_t diz_fname, char* path, size_t);
+DLLEXPORT str_list_t	read_diz(const char* path, size_t max_line_len);
+DLLEXPORT char*			format_diz(str_list_t lines, char*, size_t maxlen, bool allow_ansi);
+DLLEXPORT char*			prep_file_desc(const char *src, char* dst);
+
+DLLEXPORT str_list_t	directory(const char* path);
+DLLEXPORT long			create_archive(const char* archive, const char* format
+						               ,bool with_path, str_list_t file_list, char* error, size_t maxerrlen);
+DLLEXPORT char*			cmdstr(scfg_t*, user_t*, const char* instr, const char* fpath, const char* fspec, char* cmd, size_t);
+DLLEXPORT long			extract_files_from_archive(const char* archive, const char* outdir, const char* allowed_filename_chars
+						                           ,bool with_path, long max_files, str_list_t file_list, char* error, size_t);
+DLLEXPORT int			archive_type(const char* archive, char* str, size_t size);
+extern const char*		supported_archive_formats[];
 
-DLLEXPORT BOOL		removefiledat(scfg_t* cfg, file_t* f);
-DLLEXPORT BOOL		addfiledat(scfg_t* cfg, file_t* f);
-DLLEXPORT BOOL		findfile(scfg_t* cfg, uint dirnum, char *filename);
-DLLEXPORT char *	padfname(const char *filename, char *str);
-DLLEXPORT char *	unpadfname(const char *filename, char *str);
-DLLEXPORT BOOL		rmuserxfers(scfg_t* cfg, int fromuser, int destuser, char *fname);
+/* Batch file transfer queues */
+DLLEXPORT char*			batch_list_name(scfg_t* , uint usernumber, enum XFER_TYPE, char* fname, size_t);
+DLLEXPORT FILE*			batch_list_open(scfg_t* , uint usernumber, enum XFER_TYPE, bool create);
+DLLEXPORT str_list_t	batch_list_read(scfg_t* , uint usernumber, enum XFER_TYPE);
+DLLEXPORT bool			batch_list_write(scfg_t*, uint usernumber, enum XFER_TYPE, str_list_t list);
+DLLEXPORT bool			batch_list_clear(scfg_t*, uint usernumber, enum XFER_TYPE);
 
-DLLEXPORT int		update_uldate(scfg_t* cfg, file_t* f);
+DLLEXPORT bool			batch_file_add(scfg_t*, uint usernumber, enum XFER_TYPE, file_t*);
+DLLEXPORT bool			batch_file_exists(scfg_t*, uint usernumber, enum XFER_TYPE, const char* filename);
+DLLEXPORT bool			batch_file_remove(scfg_t*, uint usernumber, enum XFER_TYPE, const char* filename);
+DLLEXPORT size_t		batch_file_count(scfg_t*, uint usernumber, enum XFER_TYPE);
+DLLEXPORT bool			batch_file_get(scfg_t*, str_list_t, const char* filename, file_t*);
+DLLEXPORT int			batch_file_dir(scfg_t*, str_list_t, const char* filename);
+DLLEXPORT bool			batch_file_load(scfg_t*, str_list_t, const char* filename, file_t*);
 
 #ifdef __cplusplus
 }
 #endif
-#endif /* Don't add anything after this line */
\ No newline at end of file
+#endif /* Don't add anything after this line */
diff --git a/src/sbbs3/filelist.c b/src/sbbs3/filelist.c
index 8d307e25e9..0a532fc4cd 100644
--- a/src/sbbs3/filelist.c
+++ b/src/sbbs3/filelist.c
@@ -28,9 +28,10 @@
 #include "nopen.h"
 #include "filedat.h"
 #include "dat_rec.h"
+#include "smblib.h"
 #include <stdarg.h>
 
-#define FILELIST_VER "3.15"
+#define FILELIST_VER "3.19"
 
 #define MAX_NOTS 25
 
@@ -67,11 +68,33 @@ void stripctrlz(char *str)
 	strcpy(str,tmp);
 }
 
+char* byteStr(unsigned long value)
+{
+	static char tmp[128];
+
+	if(value>=(1024*1024*1024))
+		sprintf(tmp, "%5.1fG", value/(1024.0*1024.0*1024.0));
+	else if(value>=(1024*1024))
+		sprintf(tmp, "%5.1fM", value/(1024.0*1024.0));
+	else if(value>=1024)
+		sprintf(tmp, "%5.1fK", value/1024.0); 
+	else
+		sprintf(tmp, "%5luB", value);
+	return tmp;
+}
+
+void fprint_extdesc(FILE* fp, char* ext_desc, int desc_off)
+{
+	for(char* line = strtok(ext_desc, "\n"); line != NULL; line = strtok(NULL, "\n")) {
+		truncsp(line);
+		fprintf(fp, "\n%*s %s", desc_off, "", line);
+	}
+}
 
 #define ALL 	(1L<<0)
 #define PAD 	(1L<<1)
 #define HDR 	(1L<<2)
-#define CDT_	(1L<<3)
+#define CREDITS	(1L<<3)
 #define EXT 	(1L<<4)
 #define ULN 	(1L<<5)
 #define ULD 	(1L<<6)
@@ -93,14 +116,13 @@ int main(int argc, char **argv)
 {
 	char	revision[16];
 	char	error[512];
-	char	str[256],fname[256],ext,not[MAX_NOTS][9];
-	uchar	*datbuf,*ixbbuf;
-	int 	i,j,file,dirnum,libnum,desc_off,lines,nots=0
-			,omode=O_WRONLY|O_CREAT|O_TRUNC;
-	ulong	l,m,n,cdt,misc=0,total_cdt=0,total_files=0,dir_files,datbuflen;
-	time32_t uld,dld,now;
+	char	*p,str[256],fname[256],ext,not[MAX_NOTS][9];
+	int 	i,j,dirnum,libnum,desc_off,lines,nots=0;
+	char*	omode="w";
+	char*	pattern=NULL;
+	ulong	m,cdt,misc=0,total_cdt=0,total_files=0,dir_files;
 	long	max_age=0;
-	FILE	*in,*out=NULL;
+	FILE*	out=NULL;
 
 	sscanf("$Revision: 1.22 $", "%*s %s", revision);
 
@@ -122,14 +144,15 @@ int main(int argc, char **argv)
 		printf("switches: -lib name All directories of specified library\n");
 		printf("          -not code Exclude specific directory\n");
 		printf("          -new days Include only new files in listing (days since upload)\n");
-		printf("          -cat      Concatenate to existing outfile\n");
+		printf("          -inc pattern Only list files matching 'pattern'\n");
+		printf("          -cat      Concatenate to existing 'outfile'\n");
 		printf("          -pad      Pad filename with spaces\n");
 		printf("          -hdr      Include directory headers\n");
 		printf("          -cdt      Include credit value\n");
 		printf("          -tot      Include credit totals\n");
 		printf("          -uln      Include uploader's name\n");
 		printf("          -uld      Include upload date\n");
-		printf("          -dfd      Include DOS file date\n");
+		printf("          -dfd      Include current file date\n");
 		printf("          -dld      Include download date\n");
 		printf("          -dls      Include total downloads\n");
 		printf("          -nod      Exclude normal descriptions\n");
@@ -143,7 +166,12 @@ int main(int argc, char **argv)
 		exit(0); 
 	}
 
-	now=time32(NULL);
+	p=getenv("SBBSCTRL");
+	if(p==NULL) {
+		printf("\nSBBSCTRL environment variable not set.\n");
+		printf("\nExample: SET SBBSCTRL=/sbbs/ctrl\n");
+		exit(1);
+	}
 
 	memset(&scfg,0,sizeof(scfg));
 	scfg.size=sizeof(scfg);
@@ -227,14 +255,22 @@ int main(int argc, char **argv)
 			}
 			max_age=strtol(argv[i],NULL,0);
 		}
+		else if(!stricmp(argv[i],"-inc")) {
+			i++;
+			if(i>=argc) {
+				printf("\nFilename pattern must follow -inc parameter.\n");
+				exit(1); 
+			}
+			pattern = argv[i];
+		}
 		else if(!stricmp(argv[i],"-pad"))
 			misc|=PAD;
 		else if(!stricmp(argv[i],"-cat"))
-			omode=O_WRONLY|O_CREAT|O_APPEND;
+			omode="a";
 		else if(!stricmp(argv[i],"-hdr"))
 			misc|=HDR;
 		else if(!stricmp(argv[i],"-cdt"))
-			misc|=CDT_;
+			misc|=CREDITS;
 		else if(!stricmp(argv[i],"-tot"))
 			misc|=TOT;
 		else if(!stricmp(argv[i],"-ext"))
@@ -260,18 +296,17 @@ int main(int argc, char **argv)
 		else if(!stricmp(argv[i],"--"))
 			misc|=MINUS;
 		else if(!stricmp(argv[i],"-*"))
-			misc|=(HDR|PAD|CDT_|PLUS|MINUS);
+			misc|=(HDR|PAD|CREDITS|PLUS|MINUS);
 
 		else if(i!=1) {
 			if(argv[i][0]=='*' || strcmp(argv[i],"-")==0) {
 				misc|=AUTO;
 				continue; 
 			}
-			if((j=nopen(argv[i],omode))==-1) {
-				printf("\nError opening/creating %s for output.\n",argv[i]);
+			if((out=fopen(argv[i], omode)) == NULL) {
+				perror(argv[i]);
 				exit(1); 
 			}
-			out=fdopen(j,"wb"); 
 		} 
 	}
 
@@ -293,119 +328,79 @@ int main(int argc, char **argv)
 		if(misc&AUTO && scfg.dir[i]->seqdev) 	/* CD-ROM */
 			continue;
 		printf("\n%-*s %s",LEN_GSNAME,scfg.lib[scfg.dir[i]->lib]->sname,scfg.dir[i]->lname);
-		sprintf(str,"%s%s.ixb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
-		if((file=nopen(str,O_RDONLY))==-1)
+
+		smb_t smb;
+		int result = smb_open_dir(&scfg, &smb, i);
+		if(result != SMB_SUCCESS) {
+			fprintf(stderr, "!ERROR %d (%s) opening file base: %s\n", result, smb.last_error, scfg.dir[i]->code);
 			continue;
-		l=filelength(file);
+		}
+		time_t t = 0;
+		if(max_age)
+			t = time(NULL) - (max_age * 24 * 60 * 60);
+		ulong file_count;
+		file_t* file_list = loadfiles(&smb
+			,/* filespec: */pattern, /* time: */t, /* extdesc: */TRUE, scfg.dir[i]->sort, &file_count);
+
 		if(misc&AUTO) {
 			sprintf(str,"%sFILES.BBS",scfg.dir[i]->path);
-			if((j=nopen(str,omode))==-1) {
-				printf("\nError opening/creating %s for output.\n",str);
+			if((out=fopen(str, omode)) == NULL) {
+				perror(str);
 				exit(1); 
 			}
-			out=fdopen(j,"wb"); 
 		}
 		if(misc&HDR) {
 			sprintf(fname,"%-*s      %-*s       Files: %4lu"
 				,LEN_GSNAME,scfg.lib[scfg.dir[i]->lib]->sname
-				,LEN_SLNAME,scfg.dir[i]->lname,l/F_IXBSIZE);
-			fprintf(out,"%s\r\n",fname);
+				,LEN_SLNAME,scfg.dir[i]->lname, (ulong)smb.status.total_files);
+			fprintf(out,"%s\n",fname);
 			memset(fname,'-',strlen(fname));
-			fprintf(out,"%s\r\n",fname); 
+			fprintf(out,"%s\n",fname); 
 		}
-		if(!l) {
-			close(file);
+		if(!smb.status.total_files) {
 			if(misc&AUTO) fclose(out);
 			continue; 
 		}
-		if((ixbbuf=(uchar *)malloc(l))==NULL) {
-			close(file);
-			if(misc&AUTO) fclose(out);
-			printf("\7ERR_ALLOC %s %lu\n",str,l);
-			continue; 
+		int longest_filename = 12;
+		for(m = 0; m < file_count; m++) {
+			int fnamelen = strlen(file_list[m].name);
+			if(fnamelen > longest_filename)
+				longest_filename = fnamelen;
 		}
-		if(read(file,ixbbuf,l)!=(int)l) {
-			close(file);
-			if(misc&AUTO) fclose(out);
-			printf("\7ERR_READ %s %lu\n",str,l);
-			free((char *)ixbbuf);
-			continue; 
-		}
-		close(file);
-		sprintf(str,"%s%s.dat",scfg.dir[i]->data_dir,scfg.dir[i]->code);
-		if((file=nopen(str,O_RDONLY))==-1) {
-			printf("\7ERR_OPEN %s %u\n",str,O_RDONLY);
-			free((char *)ixbbuf);
-			if(misc&AUTO) fclose(out);
-			continue; 
-		}
-		datbuflen=filelength(file);
-		if((datbuf=malloc(datbuflen))==NULL) {
-			close(file);
-			printf("\7ERR_ALLOC %s %lu\n",str,datbuflen);
-			free((char *)ixbbuf);
-			if(misc&AUTO) fclose(out);
-			continue; 
-		}
-		if(read(file,datbuf,datbuflen)!=(int)datbuflen) {
-			close(file);
-			printf("\7ERR_READ %s %lu\n",str,datbuflen);
-			free((char *)datbuf);
-			free((char *)ixbbuf);
-			if(misc&AUTO) fclose(out);
-			continue; 
-		}
-		close(file);
-		m=0L;
-		while(m<l && !ferror(out)) {
-			for(j=0;j<12 && m<l;j++)
-				if(j==8)
-					str[j]=ixbbuf[m]>' ' ? '.' : ' ';
-				else
-					str[j]=ixbbuf[m++]; /* Turns FILENAMEEXT into FILENAME.EXT */
-			str[j]=0;
-			unpadfname(str,fname);
-			n=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
-			uld=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
-				|((long)ixbbuf[m+6]<<24));
-			dld=(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)|((long)ixbbuf[m+9]<<16)
-				|((long)ixbbuf[m+10]<<24));
-			m+=11;
-
-			if(n>=datbuflen 							/* index out of bounds */
-				|| datbuf[n+F_DESC+LEN_FDESC]!=CR) {	/* corrupted data */
-				fprintf(stderr,"\n\7%s%s is corrupted!\n"
-					,scfg.dir[i]->data_dir,scfg.dir[i]->code);
-				exit(-1); 
-			}
-			
-			if(max_age && ((now - uld) / (24*60*60) > max_age))
-				continue;
-
-			fprintf(out,"%-12.12s",misc&PAD ? str : fname);
+		for(m = 0; m < file_count && !ferror(out); m++) {
+			file_t file = file_list[m];
+
+			if(misc&PAD) {
+				char* ext = getfext(file.name);
+				if(ext == NULL)
+					ext="";
+				fprintf(out,"%-*.*s%s"
+					, (int)(longest_filename - strlen(ext))
+					, (int)(strlen(file.name) - strlen(ext))
+					, file.name, ext);
+			} else
+				fprintf(out,"%-*s", longest_filename, file.name);
 
 			total_files++;
 			dir_files++;
 
-			if(misc&PLUS && datbuf[n+F_MISC]!=ETX
-				&& (datbuf[n+F_MISC]-' ')&FM_EXTDESC)
+			if(misc&PLUS && file.extdesc != NULL && file.extdesc[0])
 				fputc('+',out);
 			else
 				fputc(' ',out);
 
-			desc_off=12;
-			if(misc&(CDT_|TOT)) {
-				getrec((char *)&datbuf[n],F_CDT,LEN_FCDT,str);
-				cdt=atol(str);
+			desc_off = longest_filename;
+			if(misc&(CREDITS|TOT)) {
+				cdt=file.cost;
 				total_cdt+=cdt;
-				if(misc&CDT_) {
-					fprintf(out,"%7lu",cdt);
-					desc_off+=7; 
+				if(misc&CREDITS) {
+//					fprintf(out,"%7lu",cdt);
+					desc_off += fprintf(out, "%7s", byteStr(cdt));
 				} 
 			}
 
 			if(misc&MINUS) {
-				SAFEPRINTF2(str,"%s%s",scfg.dir[i]->path,fname);
+				sprintf(str,"%s%s",scfg.dir[i]->path,file.name);
 				if(!fexistcase(str))
 					fputc('-',out);
 				else
@@ -416,88 +411,56 @@ int main(int argc, char **argv)
 			desc_off++;
 
 			if(misc&DFD) {
-				SAFEPRINTF2(str,"%s%s",scfg.dir[i]->path,fname);
-				fprintf(out,"%s ",unixtodstr(&scfg,(time32_t)fdate(str),str));
-				desc_off+=9; 
+				// TODO: Fix to support alt-file-paths:
+				sprintf(str,"%s%s",scfg.dir[i]->path,file.name);
+				desc_off += fprintf(out,"%s ",unixtodstr(&scfg,(time32_t)fdate(str),str));
 			}
 
 			if(misc&ULD) {
-				fprintf(out,"%s ",unixtodstr(&scfg,uld,str));
-				desc_off+=9; 
+				desc_off += fprintf(out,"%s ",unixtodstr(&scfg,file.hdr.when_imported.time,str));
 			}
 
 			if(misc&ULN) {
-				getrec((char *)&datbuf[n],F_ULER,25,str);
-				fprintf(out,"%-25s ",str);
-				desc_off+=26; 
+				desc_off += fprintf(out,"%-25s ",file.from);
 			}
 
 			if(misc&DLD) {
-				fprintf(out,"%s ",unixtodstr(&scfg,dld,str));
-				desc_off+=9; 
+				desc_off += fprintf(out,"%s ",unixtodstr(&scfg,file.hdr.last_downloaded,str));
 			}
 
 			if(misc&DLS) {
-				getrec((char *)&datbuf[n],F_TIMESDLED,5,str);
-				j=atoi(str);
-				fprintf(out,"%5u ",j);
-				desc_off+=6; 
+				desc_off += fprintf(out,"%5u ",file.hdr.times_downloaded);
 			}
 
-			if(datbuf[n+F_MISC]!=ETX && (datbuf[n+F_MISC]-' ')&FM_EXTDESC)
+			if(file.extdesc != NULL && file.extdesc[0])
 				ext=1;	/* extended description exists */
 			else
 				ext=0;	/* it doesn't */
 
 			if(!(misc&NOD) && !(misc&NOE && ext)) {
-				getrec((char *)&datbuf[n],F_DESC,LEN_FDESC,str);
-				fprintf(out,"%s",str); 
+				fprintf(out,"%s",file.desc); 
 			}
 
 			if(misc&EXT && ext) {							/* Print ext desc */
 
-				sprintf(str,"%s%s.exb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
-				if(!fexist(str))
-					continue;
-				if((j=nopen(str,O_RDONLY))==-1) {
-					printf("\7ERR_OPEN %s %u\n",str,O_RDONLY);
-					continue; 
-				}
-				if((in=fdopen(j,"rb"))==NULL) {
-					close(j);
-					continue; 
-				}
-				fseek(in,(n/F_LEN)*512L,SEEK_SET);
 				lines=0;
 				if(!(misc&NOE)) {
-					fprintf(out,"\r\n");
-					lines++; 
-				}
-				while(!feof(in) && !ferror(in)
-					&& ftell(in)<(long)((n/F_LEN)+1)*512L) {
-					if(!fgets(str,128,in) || !str[0])
-						break;
-					stripctrlz(str);
-					if(lines) {
-						if(misc&JST)
-							fprintf(out,"%*s",desc_off,"");
-						fputc(' ',out);				/* indent one character */ }
-					fprintf(out,"%s",str);
+					truncsp((char*)file.extdesc);
+					fprint_extdesc(out, file.extdesc, (misc&JST) ? desc_off : 0);
 					lines++; 
 				}
-				fclose(in); 
 			}
-			fprintf(out,"\r\n"); 
+			fprintf(out,"\n"); 
 		}
-		free((char *)datbuf);
-		free((char *)ixbbuf);
+		smb_close(&smb);
 		if(dir_files)
-			fprintf(out,"\r\n"); /* blank line at end of dir */
+			fprintf(out,"\n"); /* blank line at end of dir */
 		if(misc&AUTO) fclose(out); 
+		freefiles(file_list, file_count);
 	}
 
 	if(misc&TOT && !(misc&AUTO))
-		fprintf(out,"TOTALS\n------\n%lu credits/bytes in %lu files.\r\n"
+		fprintf(out,"TOTALS\n------\n%lu credits/bytes in %lu files.\n"
 			,total_cdt,total_files);
 	printf("\nDone.\n");
 	return(0);
diff --git a/src/sbbs3/filelist.vcxproj b/src/sbbs3/filelist.vcxproj
index 4b662e6cc4..84aa43f941 100644
--- a/src/sbbs3/filelist.vcxproj
+++ b/src/sbbs3/filelist.vcxproj
@@ -38,6 +38,7 @@
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -48,6 +49,7 @@
     <Import Project="..\build\target_ia32.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
@@ -168,8 +170,12 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="userdat.c" />
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\smblib\smblib.vcxproj">
+      <Project>{d674842b-2f41-42cb-9426-b3c4b0682574}</Project>
+    </ProjectReference>
     <ProjectReference Include="..\xpdev\xpdev.vcxproj">
       <Project>{7428a1e8-56b7-4868-9c0e-29d031689feb}</Project>
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
diff --git a/src/sbbs3/fixsmb.c b/src/sbbs3/fixsmb.c
index 343d57ff49..3a2e6cfceb 100644
--- a/src/sbbs3/fixsmb.c
+++ b/src/sbbs3/fixsmb.c
@@ -1,8 +1,5 @@
 /* Synchronet message base (SMB) index re-generator */
 
-/* $Id: fixsmb.c,v 1.46 2018/04/30 06:05:12 rswindell Exp $ */
-// vi: tabstop=4
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -16,21 +13,9 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -44,6 +29,8 @@
 #include "genwrap.h"	/* PLATFORM_DESC */
 #include "str_list.h"	/* strList API */
 #include "crc16.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 smb_t	smb;
 BOOL	renumber=FALSE;
@@ -60,22 +47,23 @@ int compare_index(const idxrec_t* idx1, const idxrec_t* idx2)
 void sort_index(smb_t* smb)
 {
 	ulong		l;
-	idxrec_t*	idx;
+	uint8_t*	idxbuf;
+	size_t		idxreclen = smb_idxreclen(smb);
 
 	printf("Sorting index... ");
-	if((idx=malloc(sizeof(idxrec_t)*smb->status.total_msgs))==NULL) {
+	if((idxbuf = malloc(idxreclen * smb->status.total_msgs))==NULL) {
 		perror("malloc");
 		return;
 	}
 
 	rewind(smb->sid_fp);
 	for(l=0;l<smb->status.total_msgs;l++)
-		if(fread(&idx[l],sizeof(idxrec_t),1,smb->sid_fp)<1) {
+		if(smb_fread(smb, idxbuf + (l * idxreclen), idxreclen, smb->sid_fp) != idxreclen) {
 			perror("reading index");
 			break;
 		}
 
-	qsort(idx,l,sizeof(idxrec_t)
+	qsort(idxbuf, l, idxreclen
 		,(int(*)(const void*, const void*))compare_index);
 
 	rewind(smb->sid_fp);
@@ -83,13 +71,13 @@ void sort_index(smb_t* smb)
 
 	printf("\nRe-writing index... \n");
 	smb->status.total_msgs=l;
-	for(l=0;l<smb->status.total_msgs;l++)
-		if(fwrite(&idx[l],sizeof(idxrec_t),1,smb->sid_fp)<1) {
+	for(l=0;l<smb->status.total_msgs;l++) {
+		if(smb_fwrite(smb, idxbuf + (l * idxreclen), idxreclen, smb->sid_fp) != idxreclen) {
 			perror("writing index");
 			break;
 		}
-
-	free(idx);
+	}
+	free(idxbuf);
 	printf("\n");
 }
 
@@ -110,7 +98,8 @@ int fixsmb(char* sub)
 	char*		text;
 	char		c;
 	int 		i,w;
-	ulong		l,length,size,n;
+	ulong		l,size,n;
+	off_t		length;
 	smbmsg_t	msg;
 	uint32_t*	numbers = NULL;
 	long		total = 0;
@@ -205,11 +194,12 @@ int fixsmb(char* sub)
 	} else
 		length=filelength(fileno(smb.shd_fp));
 
-	n=0;	/* messsage offset */
+	n=0;	/* message offset */
 	for(l=smb.status.header_offset;l<length;l+=size) {
 		size=SHD_BLOCK_LEN;
 		printf("\r%2lu%%  ",(long)(100.0/((float)length/l)));
 		fflush(stdout);
+		ZERO_VAR(msg);
 		msg.idx.offset=l;
 		if((i=smb_lockmsghdr(&smb,&msg))!=0) {
 			printf("\n(%06lX) smb_lockmsghdr returned %d:\n%s\n",l,i,smb.last_error);
@@ -222,7 +212,8 @@ int fixsmb(char* sub)
 			continue;
 		}
 		size=smb_hdrblocks(smb_getmsghdrlen(&msg))*SHD_BLOCK_LEN;
-		printf("#%-5"PRIu32" (%06lX) %-25.25s ",msg.hdr.number,l,msg.from);
+		printf("#%-5"PRIu32" (%06lX) %-25.25s ",msg.hdr.number,l
+			,msg.hdr.type == SMB_MSG_TYPE_FILE ? msg.subj : msg.from);
 
 		dupe_msgnum = FALSE;
 		for(i=0; i<total && !dupe_msgnum; i++)
@@ -267,7 +258,7 @@ int fixsmb(char* sub)
 		else if(msg.hdr.number==0)
 			printf("Not indexing invalid message number (0)!\n");
 		else {
-			msg.offset=n;
+			msg.idx_offset=n;
 			if(renumber)
 				msg.hdr.number=n+1;
 			if(msg.hdr.number > highest)
@@ -327,15 +318,12 @@ int fixsmb(char* sub)
 
 int main(int argc, char **argv)
 {
-	char		revision[16];
 	int 		i;
 	str_list_t	list;
 	int			retval = EXIT_SUCCESS;
 
-	sscanf("$Revision: 1.46 $", "%*s %s", revision);
-
-	printf("\nFIXSMB v2.10-%s (rev %s) SMBLIB %s - Rebuild Synchronet Message Base\n\n"
-		,PLATFORM_DESC,revision,smb_lib_ver());
+	printf("\nFIXSMB v3.19-%s %s/%s SMBLIB %s - Rebuild Synchronet Message Base\n\n"
+		,PLATFORM_DESC, GIT_BRANCH, GIT_HASH, smb_lib_ver());
 
 	list=strListInit();
 
diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index 5ae915ec54..e009f2d936 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -35,13 +35,15 @@
 #include "sbbs.h"
 #include "text.h"			/* TOTAL_TEXT */
 #include "ftpsrvr.h"
+#include "filedat.h"
 #include "telnet.h"
 #include "multisock.h"
 #include "ssl.h"
 #include "cryptlib.h"
 #include "xpprintf.h"		// vasprintf
 #include "md5.h"
-#include "ver.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 /* Constants */
 
@@ -597,7 +599,6 @@ typedef struct {
 static void send_thread(void* arg)
 {
 	char		buf[8192];
-	char		fname[MAX_PATH+1];
 	char		str[256];
 	char		tmp[128];
 	char		username[128];
@@ -633,11 +634,15 @@ static void send_thread(void* arg)
 	length=flength(xfer.filename);
 
 	if(length < 1) {
-		lprintf(LOG_WARNING, "%04d <%s> !DATA cannot send file (%s) with size of %"PRIdOFF" bytes"
-			,xfer.ctrl_sock, xfer.user->alias, xfer.filename, length);
-		sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"450 Invalid file size: %"PRIdOFF, length);
-		if(xfer.tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
-			(void)ftp_remove(xfer.ctrl_sock, __LINE__, xfer.filename, xfer.user->alias);
+		if(xfer.tmpfile) {
+			if(!(startup->options&FTP_OPT_KEEP_TEMP_FILES))
+				ftp_remove(xfer.ctrl_sock, __LINE__, xfer.filename, xfer.user->alias);
+			sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"450 No files");
+		} else {
+			lprintf(LOG_WARNING, "%04d <%s> !DATA cannot send file (%s) with size of %"PRIdOFF" bytes"
+				,xfer.ctrl_sock, xfer.user->alias, xfer.filename, length);
+			sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"450 Invalid file size: %"PRIdOFF, length);
+		}
 		ftp_close_socket(xfer.data_sock,xfer.data_sess,__LINE__);
 		*xfer.inprogress=FALSE;
 		thread_down();
@@ -668,7 +673,7 @@ static void send_thread(void* arg)
 		lprintf(LOG_DEBUG,"%04d <%s> DATA socket %d sending %s from offset %"PRIdOFF
 			,xfer.ctrl_sock, xfer.user->alias, *xfer.data_sock,xfer.filename,xfer.filepos);
 
-	(void)fseek(fp,xfer.filepos,SEEK_SET);
+	fseeko(fp,xfer.filepos,SEEK_SET);
 	last_report=start=time(NULL);
 	while((xfer.filepos+total)<length) {
 
@@ -705,7 +710,7 @@ static void send_thread(void* arg)
 		if (!socket_writable(*xfer.data_sock, 1000))
 			continue;
 
-		(void)fseek(fp,xfer.filepos+total,SEEK_SET);
+		fseeko(fp,xfer.filepos+total,SEEK_SET);
 		rd=fread(buf,sizeof(char),sizeof(buf),fp);
 		if(rd<1) /* EOF or READ error */
 			break;
@@ -781,7 +786,7 @@ static void send_thread(void* arg)
 	
 	if(!error) {
 		dur=(long)(time(NULL)-start);
-		cps=dur ? total/dur : total*2;
+		cps=(ulong)(dur ? total/dur : total*2);
 		lprintf(LOG_INFO,"%04d <%s> DATA Transfer successful: %"PRIdOFF" bytes sent in %lu seconds (%lu cps)"
 			,xfer.ctrl_sock
 			,xfer.user->alias
@@ -790,34 +795,29 @@ static void send_thread(void* arg)
 
 		if(xfer.dir>=0) {
 			memset(&f,0,sizeof(f));
-#ifdef _WIN32
-			GetShortPathName(xfer.filename,fname,sizeof(fname));
-#else
-			SAFECOPY(fname,xfer.filename);
-#endif
-			padfname(getfname(fname),f.name);
-			f.dir=xfer.dir;
-			f.size=total;
-			if(getfileixb(&scfg,&f)==TRUE && getfiledat(&scfg,&f)==TRUE) {
-				f.timesdled++;
-				putfiledat(&scfg,&f);
-				f.datedled=time32(NULL);
-				putfileixb(&scfg,&f);
+			if(loadfile(&scfg, xfer.dir, xfer.filename, &f, file_detail_normal) == TRUE) {
+				f.hdr.times_downloaded++;
+				f.hdr.last_downloaded = time32(NULL);
+				updatefile(&scfg, &f);
 
 				lprintf(LOG_INFO,"%04d <%s> DATA downloaded: %s (%u times total)"
 					,xfer.ctrl_sock
 					,xfer.user->alias
 					,xfer.filename
-					,f.timesdled);
+					,f.hdr.times_downloaded);
 				/**************************/
 				/* Update Uploader's Info */
 				/**************************/
-				uploader.number=matchuser(&scfg,f.uler,TRUE /*sysop_alias*/);
+				uploader.number = 0;
+				if(f.from_ext != NULL)
+					uploader.number = atoi(f.from_ext);
+				if(uploader.number == 0)
+					uploader.number=matchuser(&scfg, f.from, TRUE /*sysop_alias*/);
 				if(uploader.number
 					&& uploader.number!=xfer.user->number 
 					&& getuserdat(&scfg,&uploader)==0
-					&& uploader.firston<f.dateuled) {
-					l=f.cdt;
+					&& uploader.firston < (time_t)f.hdr.when_imported.time) {
+					l=f.cost;
 					if(!(scfg.dir[f.dir]->misc&DIR_CDTDL))	/* Don't give credits on d/l */
 						l=0;
 					if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps) { /* Give min instead of cdt */
@@ -847,7 +847,7 @@ static void send_thread(void* arg)
 				}
 			}
 			if(!xfer.tmpfile && !xfer.delfile && !(scfg.dir[f.dir]->misc&DIR_NOSTAT))
-				inc_sys_download_stats(&scfg, 1, total);
+				inc_sys_download_stats(&scfg, 1, (ulong)total);
 		}	
 
 		if(xfer.credits) {
@@ -876,17 +876,11 @@ static void send_thread(void* arg)
 
 static void receive_thread(void* arg)
 {
-	char*		p;
 	char		str[128];
 	char		buf[8192];
-	char		ext[F_EXBSIZE+1];
-	char		desc[F_EXBSIZE+1];
-	char		cmd[MAX_PATH*2];
+	char		extdesc[LEN_EXTDESC + 1] = "";
 	char		tmp[MAX_PATH+1];
-	char		fname[MAX_PATH+1];
-	int			i;
 	int			rd;
-	int			file;
 	off_t		total=0;
 	off_t		last_total=0;
 	ulong		dur;
@@ -894,7 +888,7 @@ static void receive_thread(void* arg)
 	BOOL		error=FALSE;
 	BOOL		filedat;
 	FILE*		fp;
-	file_t		f;
+	file_t	f;
 	xfer_t		xfer;
 	time_t		now;
 	time_t		start;
@@ -929,7 +923,7 @@ static void receive_thread(void* arg)
 		lprintf(LOG_DEBUG,"%04d <%s> DATA socket %d receiving %s from offset %"PRIdOFF
 			,xfer.ctrl_sock,xfer.user->alias, *xfer.data_sock,xfer.filename,xfer.filepos);
 
-	(void)fseek(fp,xfer.filepos,SEEK_SET);
+	fseeko(fp,xfer.filepos,SEEK_SET);
 	last_report=start=time(NULL);
 	while(1) {
 
@@ -1051,7 +1045,7 @@ static void receive_thread(void* arg)
 			(void)ftp_remove(xfer.ctrl_sock, __LINE__, xfer.filename, xfer.user->alias);
 	} else {
 		dur=(long)(time(NULL)-start);
-		cps=dur ? total/dur : total*2;
+		cps=(ulong)(dur ? total/dur : total*2);
 		lprintf(LOG_INFO,"%04d <%s> DATA Transfer successful: %"PRIdOFF" bytes received in %lu seconds (%lu cps)"
 			,xfer.ctrl_sock
 			,xfer.user->alias
@@ -1059,91 +1053,51 @@ static void receive_thread(void* arg)
 
 		if(xfer.dir>=0) {
 			memset(&f,0,sizeof(f));
-#ifdef _WIN32
-			GetShortPathName(xfer.filename,fname,sizeof(fname));
-#else
-			SAFECOPY(fname,xfer.filename);
-#endif
-			padfname(getfname(fname),f.name);
-			f.dir=xfer.dir;
-			filedat=getfileixb(&scfg,&f);
+			smb_hfield_str(&f, SMB_FILENAME, getfname(xfer.filename));
+			smb_hfield_str(&f, SENDER, xfer.user->alias);
+
+			filedat=findfile(&scfg, xfer.dir, f.name, NULL);
 			if(scfg.dir[f.dir]->misc&DIR_AONLY)  /* Forced anonymous */
-				f.misc|=FM_ANON;
-			f.cdt=flength(xfer.filename);
-			f.dateuled=time32(NULL);
+				f.hdr.attr |= MSG_ANONYMOUS;
+			off_t cdt = flength(xfer.filename);
+			smb_hfield_bin(&f, SMB_COST, cdt);
 
+			char fdesc[LEN_FDESC + 1] = "";
 			/* Description specified with DESC command? */
-			if(xfer.desc!=NULL && *xfer.desc!=0)	
-				SAFECOPY(f.desc,xfer.desc);
+			if(xfer.desc != NULL)	
+				SAFECOPY(fdesc, xfer.desc);
 
 			/* Necessary for DIR and LIB ARS keyword support in subsequent chk_ar()'s */
 			SAFECOPY(xfer.user->curdir, scfg.dir[f.dir]->code);
 
 			/* FILE_ID.DIZ support */
-			p=strrchr(f.name,'.');
-			if(p!=NULL && scfg.dir[f.dir]->misc&DIR_DIZ) {
-				for(i=0;i<scfg.total_fextrs;i++)
-					if(!stricmp(scfg.fextr[i]->ext,p+1) 
-						&& chk_ar(&scfg,scfg.fextr[i]->ar,xfer.user,xfer.client))
-						break;
-				if(i<scfg.total_fextrs) {
-					sprintf(tmp,"%sFILE_ID.DIZ",scfg.temp_dir);
-					if(fexistcase(tmp))
-						(void)ftp_remove(xfer.ctrl_sock, __LINE__, tmp, xfer.user->alias);
-					cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"FILE_ID.DIZ",cmd);
-					lprintf(LOG_DEBUG,"%04d <%s> DATA Extracting DIZ: %s",xfer.ctrl_sock, xfer.user->alias,cmd);
-					system(cmd);
-					if(!fexistcase(tmp)) {
-						sprintf(tmp,"%sDESC.SDI",scfg.temp_dir);
-						if(fexistcase(tmp))
-							(void)ftp_remove(xfer.ctrl_sock, __LINE__, tmp, xfer.user->alias);
-						cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"DESC.SDI",cmd);
-						lprintf(LOG_DEBUG,"%04d <%s> DATA Extracting DIZ: %s",xfer.ctrl_sock, xfer.user->alias,cmd);
-						system(cmd); 
-						fexistcase(tmp);	/* fixes filename case */
+			if(scfg.dir[f.dir]->misc&DIR_DIZ) {
+				lprintf(LOG_DEBUG,"%04d <%s> DATA Extracting DIZ from: %s",xfer.ctrl_sock, xfer.user->alias,xfer.filename);
+				if(extract_diz(&scfg, &f, /* diz_fnames */NULL, tmp, sizeof(tmp))) {
+					lprintf(LOG_DEBUG,"%04d <%s> DATA Parsing DIZ: %s",xfer.ctrl_sock, xfer.user->alias,tmp);
+					str_list_t lines = read_diz(tmp, /* max_line_len: */80);
+					format_diz(lines, extdesc, sizeof(extdesc), /* allow_ansi: */false);
+					strListFree(&lines);
+					if(!fdesc[0]) {						/* use for normal description */
+						prep_file_desc(extdesc, fdesc);	/* strip control chars and dupe chars */
 					}
-					if((file=nopen(tmp,O_RDONLY))!=-1) {
-						lprintf(LOG_DEBUG,"%04d <%s> DATA Parsing DIZ: %s",xfer.ctrl_sock, xfer.user->alias,tmp);
-						memset(ext,0,sizeof(ext));
-						read(file,ext,sizeof(ext)-1);
-						for(i=sizeof(ext)-1;i;i--)	/* trim trailing spaces */
-							if(ext[i-1]>' ')
-								break;
-						ext[i]=0;
-						if(!f.desc[0]) {			/* use for normal description */
-							SAFECOPY(desc,ext);
-							strip_exascii(desc, desc);	/* strip extended ASCII chars */
-							prep_file_desc(desc, desc);	/* strip control chars and dupe chars */
-							for(i=0;desc[i];i++)	/* find appropriate first char */
-								if(IS_ALPHANUMERIC(desc[i]))
-									break;
-							SAFECOPY(f.desc,desc+i); 
-						}
-						close(file);
-						(void)ftp_remove(xfer.ctrl_sock, __LINE__, tmp, xfer.user->alias);
-						f.misc|=FM_EXTDESC; 
-					} else
-						lprintf(LOG_DEBUG,"%04d <%s> DATA DIZ Does not exist: %s",xfer.ctrl_sock, xfer.user->alias,tmp);
-				} 
+					ftp_remove(xfer.ctrl_sock, __LINE__, tmp, xfer.user->alias);
+				} else
+					lprintf(LOG_DEBUG,"%04d <%s> DATA DIZ does not exist in: %s",xfer.ctrl_sock, xfer.user->alias ,xfer.filename);
 			} /* FILE_ID.DIZ support */
 
-			if(f.desc[0]==0) 	/* no description given, use (long) filename */
-				SAFECOPY(f.desc,getfname(xfer.filename));
-
-			SAFECOPY(f.uler,xfer.user->alias);	/* exception here, Aug-27-2002 */
+			smb_hfield_str(&f, SMB_FILEDESC, fdesc);
 			if(filedat) {
-				if(!putfiledat(&scfg,&f))
+				if(!updatefile(&scfg, &f))
 					lprintf(LOG_ERR,"%04d <%s> !DATA ERROR updating file (%s) in database"
-						,xfer.ctrl_sock, xfer.user->alias,f.name);
+						,xfer.ctrl_sock, xfer.user->alias, f.name);
 				/* need to update the index here */
 			} else {
-				if(!addfiledat(&scfg,&f))
+				if(!addfile(&scfg, xfer.dir, &f, extdesc))
 					lprintf(LOG_ERR,"%04d <%s> !DATA ERROR adding file (%s) to database"
-						,xfer.ctrl_sock, xfer.user->alias,f.name);
+						,xfer.ctrl_sock, xfer.user->alias, f.name);
 			}
-
-			if(f.misc&FM_EXTDESC)
-				putextdesc(&scfg,f.dir,f.datoffset,ext);
+			smb_freefilemem(&f);
 
 			if(scfg.dir[f.dir]->upload_sem[0])
 				ftouch(scfg.dir[f.dir]->upload_sem);
@@ -1157,10 +1111,10 @@ static void receive_thread(void* arg)
 						,((ulong)(total*(scfg.dir[f.dir]->up_pct/100.0))/cps)/60);
 				else
 					xfer.user->cdt=adjustuserrec(&scfg,xfer.user->number,U_CDT,10
-						,(ulong)(f.cdt*(scfg.dir[f.dir]->up_pct/100.0))); 
+						,(ulong)(cdt*(scfg.dir[f.dir]->up_pct/100.0))); 
 			}
 			if(!(scfg.dir[f.dir]->misc&DIR_NOSTAT))
-				inc_sys_upload_stats(&scfg, 1, total);
+				inc_sys_upload_stats(&scfg, 1, (ulong)total);
 		}
 		/* Send ACK */
 		sockprintf(xfer.ctrl_sock,sess,"226 Upload complete (%lu cps).",cps);
@@ -1463,6 +1417,10 @@ char* dotname(char* in, char* out)
 	char	ch;
 	int		i;
 
+	if(in == NULL) {
+		strcpy(out, "(null)");
+		return out;
+	}
 	if(strchr(in,'.')==NULL)
 		ch='.';
 	else
@@ -1847,7 +1805,7 @@ static char *get_unique(const char *path, char *uniq)
 		return NULL;
 
 	MD5_calc(digest, path, strlen(path));
-	MD5_hex((BYTE*)uniq, digest);
+	MD5_hex(uniq, digest);
 	return uniq;
 }
 
@@ -1942,7 +1900,7 @@ static BOOL write_local_mlsx(FILE *fp, SOCKET sock, CRYPT_SESSION sess, unsigned
 	*p=0;
 	if (is_file)
 		full_path = FALSE;
-	return send_mlsx_entry(fp, sock, sess, feats, type, permstr, (uint64_t)st.st_size, st.st_mtime, NULL, NULL, 0, full_path ? path : getfname(path));
+	return send_mlsx_entry(fp, sock, sess, feats, type, permstr, (uint64_t)st.st_size, st.st_mtime, NULL, NULL, st.st_ctime, full_path ? path : getfname(path));
 }
 
 /*
@@ -2037,11 +1995,8 @@ static BOOL can_append(lib_t *lib, dir_t *dir, user_t *user, client_t *client, f
 		if(!chk_ar(&scfg,dir->ul_ar,user,client))
 			return FALSE;
 	}
-	if(!getfileixb(&scfg,file) || !getfiledat(&scfg,file))
-		return FALSE;
-	if (stricmp(file->uler,user->alias))
+	if (file->from == NULL || stricmp(file->from, user->alias) != 0)
 		return FALSE;
-	// Check credits?
 	return TRUE;
 }
 
@@ -2057,8 +2012,6 @@ static BOOL can_delete(lib_t *lib, dir_t *dir, user_t *user, client_t *client, f
 		return FALSE;
 	if (!(user->exempt&FLAG('R')))
 		return FALSE;
-	if(!getfileixb(&scfg,file) && !(startup->options&FTP_OPT_DIR_FILES) && !(dir->misc&DIR_FILES))
-		return FALSE;
 	return TRUE;
 }
 
@@ -2072,8 +2025,6 @@ static BOOL can_download(lib_t *lib, dir_t *dir, user_t *user, client_t *client,
 		return FALSE;
 	if (!chk_ar(&scfg,dir->dl_ar,user,client))
 		return FALSE;
-	if(!getfileixb(&scfg,file) && !(startup->options&FTP_OPT_DIR_FILES) && !(dir->misc&DIR_FILES))
-		return FALSE;
 	// TODO: Verify credits
 	return TRUE;
 }
@@ -2103,10 +2054,10 @@ static void get_owner_name(file_t *file, char *namestr)
 	char *p;
 
 	if (file) {
-		if (file->misc & FM_ANON)
+		if (file->hdr.attr & MSG_ANONYMOUS)
 			strcpy(namestr, ANONYMOUS);
 		else
-			strcpy(namestr, file->uler);
+			strcpy(namestr, file->from);
 	}
 	else
 		strcpy(namestr, scfg.sys_id);
@@ -2223,8 +2174,6 @@ static void ctrl_thread(void* arg)
 	time_t		lastactive;
 	time_t		file_date;
 	off_t		file_size;
-	file_t		f;
-	glob_t		g;
 	node_t		node;
 	client_t	client;
 	struct tm	tm;
@@ -3231,6 +3180,7 @@ static void ctrl_thread(void* arg)
 					}
 					else {
 						time_t start = time(NULL);
+						glob_t g;
 						glob(path, GLOB_MARK, NULL, &g);
 						for(i=0;i<(int)g.gl_pathc;i++) {
 							char fpath[MAX_PATH + 1];
@@ -3289,6 +3239,7 @@ static void ctrl_thread(void* arg)
 					memset(&cur_tm,0,sizeof(cur_tm));
 			
 				time_t start = time(NULL);
+				glob_t g;
 				glob(path, GLOB_MARK, NULL, &g);
 				for(i=0;i<(int)g.gl_pathc;i++) {
 					char fpath[MAX_PATH + 1];
@@ -3299,14 +3250,12 @@ static void ctrl_thread(void* arg)
 						struct stat st;
 						if(stat(fpath, &st) != 0)
 							continue;
-						f.size = st.st_size;
-						t = st.st_mtime;
-						if(localtime_r(&t,&tm)==NULL)
+						if(localtime_r(&st.st_mtime,&tm)==NULL)
 							memset(&tm,0,sizeof(tm));
-						fprintf(fp,"%crw-r--r--   1 %-8s local %9"PRId32" %s %2d "
+						fprintf(fp,"%crw-r--r--   1 %-8s local %9"PRId64" %s %2d "
 							,*lastchar(g.gl_pathv[i]) == '/' ? 'd':'-'
 							,scfg.sys_id
-							,f.size
+							,(int64_t)st.st_size
 							,ftp_mon[tm.tm_mon],tm.tm_mday);
 						if(tm.tm_year==cur_tm.tm_year)
 							fprintf(fp,"%02d:%02d %s\r\n"
@@ -3774,51 +3723,45 @@ static void ctrl_thread(void* arg)
 						get_unique(aliaspath, uniq);
 						send_mlsx_entry(fp, sock, sess, mlsx_feats, "cdir", permstr, UINT64_MAX, 0, str, NULL, 0, aliaspath);
 					}
-
+					smb_t smb;
+					if((result = smb_open_dir(&scfg, &smb, dir)) != SMB_SUCCESS) {
+						lprintf(LOG_ERR, "ERROR %d (%s) opening %s", result, smb.last_error, smb.file);
+						continue;
+					}
 					time_t start = time(NULL);
-					SAFEPRINTF2(path,"%s%s",scfg.dir[dir]->path,"*");
-					glob(path, GLOB_MARK, NULL, &g);
-					for(i=0;i<(int)g.gl_pathc;i++) {
-						if(*lastchar(g.gl_pathv[i]) == '/')	/* is directory */
-							continue;
-#ifdef _WIN32
-						GetShortPathName(g.gl_pathv[i], str, sizeof(str));
-#else
-						SAFECOPY(str,g.gl_pathv[i]);
-#endif
-						padfname(getfname(str),f.name);
-						f.dateuled = 0;
-						f.dir=dir;
-						if((filedat=getfileixb(&scfg,&f))==FALSE
-							&& !(startup->options&FTP_OPT_DIR_FILES)
-							&& !(scfg.dir[dir]->misc&DIR_FILES))
-							continue;
-						if (cmd[3] != 'D' && strcmp(getfname(g.gl_pathv[i]), mls_fname) != 0)
+					size_t file_count = 0;
+					file_t* file_list = loadfiles(&smb
+						,/* filespec */NULL, /* time: */0, file_detail_normal, scfg.dir[dir]->sort, &file_count);
+					for(size_t i = 0; i < file_count; i++) {
+						file_t* f = &file_list[i];
+						if (cmd[3] != 'D' && strcmp(f->name, mls_fname) != 0)
 							continue;
 						if (cmd[3] == 'T')
 							sockprintf(sock,sess, "250- Listing %s", p);
-						get_fileperm(scfg.lib[lib], scfg.dir[dir], &user, &client, &f, permstr);
-						get_owner_name(&f, str);
-						SAFEPRINTF3(aliaspath, "/%s/%s/%s", scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix, getfname(g.gl_pathv[i]));
+						get_fileperm(scfg.lib[lib], scfg.dir[dir], &user, &client, f, permstr);
+						get_owner_name(f, str);
+						SAFEPRINTF3(aliaspath, "/%s/%s/%s", scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix, f->name);
 						get_unique(aliaspath, uniq);
-						f.size = f.cdt;
-						f.date = f.dateuled;
-						if(!filedat || (scfg.dir[dir]->misc&DIR_FCHK)) {
+						f->size = f->cost;
+						f->time = f->hdr.when_imported.time;
+						if(scfg.dir[dir]->misc&DIR_FCHK) {
 							struct stat st;
-							if(stat(g.gl_pathv[i], &st) != 0)
+							if(stat(getfilepath(&scfg, f, path), &st) != 0)
 								continue;
-							f.size = st.st_size;
-							f.date = (time32_t)st.st_mtime;
+							f->size = st.st_size;
+							f->time = st.st_mtime;
+							f->hdr.when_imported.time = (uint32_t)st.st_ctime;
 						}
-						send_mlsx_entry(fp, sock, sess, mlsx_feats, "file", permstr, f.size, f.date, str, uniq, f.dateuled, cmd[3] == 'T' ? mls_path : getfname(g.gl_pathv[i]));
+						send_mlsx_entry(fp, sock, sess, mlsx_feats, "file", permstr, f->size, f->time, str, uniq, f->hdr.when_imported.time, cmd[3] == 'T' ? mls_path : f->name);
 						l++;
 					}
 					if (cmd[3] == 'D') {
 						lprintf(LOG_INFO, "%04d <%s> %s listing (%ld bytes) of /%s/%s (%lu files) created in %ld seconds"
 						    ,sock, user.alias, cmd, ftell(fp), scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix
-						    ,(ulong)g.gl_pathc, (long)time(NULL) - start);
+						    ,(ulong)file_count, (long)time(NULL) - start);
 					}
-					globfree(&g);
+					freefiles(file_list, file_count);
+					smb_close(&smb);
 				} else 
 					lprintf(LOG_INFO,"%04d <%s> %s listing: /%s/%s directory in %s mode (empty - no access)"
 						,sock, user.alias, cmd, scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix, mode);
@@ -3913,7 +3856,7 @@ static void ctrl_thread(void* arg)
 						if(detail) {
 							if(fexistcase(qwkfile)) {
 								t=fdate(qwkfile);
-								l=flength(qwkfile);
+								l=(ulong)flength(qwkfile);
 							} else {
 								t=time(NULL);
 								l=10240;
@@ -4067,65 +4010,55 @@ static void ctrl_thread(void* arg)
 					,sock, user.alias, detail ? "detailed ":""
 					,scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix, mode);
 
+				smb_t smb;
+				if((result = smb_open_dir(&scfg, &smb, dir)) != SMB_SUCCESS) {
+					lprintf(LOG_ERR, "ERROR %d (%s) opening %s", result, smb.last_error, smb.file);
+					continue;
+				}
 				time_t start = time(NULL);
-				SAFEPRINTF2(path,"%s%s",scfg.dir[dir]->path,filespec);
-				glob(path, GLOB_MARK, NULL, &g);
-				for(i=0;i<(int)g.gl_pathc;i++) {
-					if(*lastchar(g.gl_pathv[i]) == '/')	/* is directory */
-						continue;
-#ifdef _WIN32
-					GetShortPathName(g.gl_pathv[i], str, sizeof(str));
-#else
-					SAFECOPY(str,g.gl_pathv[i]);
-#endif
-					padfname(getfname(str),f.name);
-					f.dir=dir;
-					if((filedat=getfileixb(&scfg,&f))==FALSE
-						&& !(startup->options&FTP_OPT_DIR_FILES)
-						&& !(scfg.dir[dir]->misc&DIR_FILES))
-						continue;
+				size_t file_count = 0;
+				file_t* file_list = loadfiles(&smb
+					,filespec, /* time: */0, file_detail_normal, scfg.dir[dir]->sort, &file_count);
+				for(size_t i = 0; i < file_count; i++) {
+					file_t* f = &file_list[i];
 					if(detail) {
-						if(filedat && !getfiledat(&scfg,&f))
-							continue;
-						f.size = f.cdt;
-						t = f.dateuled;
-						if(!filedat || (scfg.dir[dir]->misc&DIR_FCHK)) {
+						f->size = f->cost;
+						t = f->hdr.when_imported.time;
+						if(scfg.dir[dir]->misc&DIR_FCHK) {
 							struct stat st;
-							if(stat(g.gl_pathv[i], &st) != 0)
+							if(stat(getfilepath(&scfg, f, path), &st) != 0)
 								continue;
-							f.size = st.st_size;
+							f->size = st.st_size;
 							t = st.st_mtime;
 						}
 						if(localtime_r(&t,&tm)==NULL)
 							memset(&tm,0,sizeof(tm));
-						if(filedat) {
-							if(f.misc&FM_ANON)
-								SAFECOPY(str,ANONYMOUS);
-							else
-								dotname(f.uler,str);
-						} else
-							SAFECOPY(str,scfg.sys_id);
-						fprintf(fp,"-r--r--r--   1 %-*s %-8s %9"PRId32" %s %2d "
+						if(f->hdr.attr & MSG_ANONYMOUS)
+							SAFECOPY(str,ANONYMOUS);
+						else
+							dotname(f->from,str);
+						fprintf(fp,"-r--r--r--   1 %-*s %-8s %9"PRId64" %s %2d "
 							,NAME_LEN
 							,str
 							,scfg.dir[dir]->code_suffix
-							,f.size
+							,(int64_t)f->size
 							,ftp_mon[tm.tm_mon],tm.tm_mday);
 						if(tm.tm_year==cur_tm.tm_year)
 							fprintf(fp,"%02d:%02d %s\r\n"
 								,tm.tm_hour,tm.tm_min
-								,getfname(g.gl_pathv[i]));
+								,f->name);
 						else
 							fprintf(fp,"%5d %s\r\n"
 								,1900+tm.tm_year
-								,getfname(g.gl_pathv[i]));
+								,f->name);
 					} else
-						fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i]));
+						fprintf(fp,"%s\r\n", f->name);
 				}
 				lprintf(LOG_INFO, "%04d <%s> %slisting (%ld bytes) of /%s/%s (%lu files) created in %ld seconds"
 					,sock, user.alias, detail ? "detailed ":"", ftell(fp), scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix
-					,(ulong)g.gl_pathc, (long)time(NULL) - start);
-				globfree(&g);
+					,(ulong)file_count, (long)time(NULL) - start);
+				freefiles(file_list, file_count);
+				smb_close(&smb);
 			} else
 				lprintf(LOG_INFO,"%04d <%s> %slisting: /%s/%s directory in %s mode (empty - no access)"
 					,sock, user.alias, detail ? "detailed ":"", scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix, mode);
@@ -4366,34 +4299,25 @@ static void ctrl_thread(void* arg)
 								,INDEX_FNAME_LEN,scfg.dir[i]->code_suffix,scfg.dir[i]->lname);
 						}
 					} else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user,&client)){
-						sprintf(cmd,"%s*",scfg.dir[dir]->path);
+						smb_t smb;
+						if((result = smb_open_dir(&scfg, &smb, dir)) != SMB_SUCCESS) {
+							lprintf(LOG_ERR, "ERROR %d (%s) opening %s", result, smb.last_error, smb.file);
+							continue;
+						}
 						time_t start = time(NULL);
-						glob(cmd, GLOB_MARK, NULL, &g);
-						for(i=0;i<(int)g.gl_pathc;i++) {
-							if(*lastchar(g.gl_pathv[i]) == '/')	/* is directory */
-								continue;
-	#ifdef _WIN32
-							GetShortPathName(g.gl_pathv[i], str, sizeof(str));
-	#else
-							SAFECOPY(str,g.gl_pathv[i]);
-	#endif
-							memset(&f, 0, sizeof(f));
-							padfname(getfname(str),f.name);
-							f.dir=dir;
-							if((filedat=getfileixb(&scfg,&f))==FALSE
-								&& !(startup->options&FTP_OPT_DIR_FILES)
-								&& !(scfg.dir[dir]->misc&DIR_FILES))
-								continue;
-							f.size = -1;	// Not used, don't query
-							if(filedat && !getfiledat(&scfg,&f))
-								continue;
+						size_t file_count = 0;
+						file_t* file_list = loadfiles(&smb
+							,/* filespec */NULL, /* time: */0, file_detail_normal, scfg.dir[dir]->sort, &file_count);
+						for(size_t i = 0; i < file_count; i++) {
+							file_t* f = &file_list[i];
 							fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN
-								,getfname(g.gl_pathv[i]),f.desc);
+								,f->name, f->desc);
 						}
 						lprintf(LOG_INFO, "%04d <%s> index (%ld bytes) of /%s/%s (%lu files) created in %ld seconds"
 							,sock, user.alias, ftell(fp), scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix
-							,(ulong)g.gl_pathc, (long)time(NULL) - start);
-						globfree(&g);
+							,(ulong)file_count, (long)time(NULL) - start);
+						freefiles(file_list, file_count);
+						smb_close(&smb);
 					}
 					fclose(fp);
 				}
@@ -4430,17 +4354,8 @@ static void ctrl_thread(void* arg)
 					continue;
 				}
 				SAFEPRINTF2(fname,"%s%s",scfg.dir[dir]->path,p);
-#ifdef _WIN32
-				GetShortPathName(fname, str, sizeof(str));
-#else
-				SAFECOPY(str,fname);
-#endif
-				padfname(getfname(str),f.name);
-				f.dir=dir;
-				f.cdt=0;
-				f.size=-1;
-				filedat=getfileixb(&scfg,&f);
-				if(!filedat && !(startup->options&FTP_OPT_DIR_FILES) && !(scfg.dir[dir]->misc&DIR_FILES)) {
+				filedat=findfile(&scfg, dir, p, NULL);
+				if(!filedat) {
 					sockprintf(sock,sess,"550 File not found: %s",p);
 					lprintf(LOG_WARNING,"%04d <%s> file (%s%s) not in database for %.4s command"
 						,sock,user.alias,genvpath(lib,dir,str),p,cmd);
@@ -4451,20 +4366,23 @@ static void ctrl_thread(void* arg)
 				/* Verify credits */
 				if(!getsize && !getdate && !delecmd
 					&& !is_download_free(&scfg,dir,&user,&client)) {
+					file_t f;
 					if(filedat)
-						getfiledat(&scfg,&f);
+						loadfile(&scfg, dir, p, &f, file_detail_normal);
 					else
-						f.cdt=flength(fname);
-					if(f.cdt>(user.cdt+user.freecdt)) {
+						f.cost=(uint32_t)flength(fname);
+					if(f.cost>(user.cdt+user.freecdt)) {
 						lprintf(LOG_WARNING,"%04d <%s> has insufficient credit to download /%s/%s/%s (%lu credits)"
 							,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname
 							,scfg.dir[dir]->code_suffix
 							,p
-							,(ulong)f.cdt);
-						sockprintf(sock,sess,"550 Insufficient credit (%lu required).", (ulong)f.cdt);
+							,(ulong)f.cost);
+						sockprintf(sock,sess,"550 Insufficient credit (%lu required).", (ulong)f.cost);
 						filepos=0;
+						smb_freefilemem(&f);
 						continue;
 					}
+					smb_freefilemem(&f);
 				}
 
 				if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)) {
@@ -4504,7 +4422,7 @@ static void ctrl_thread(void* arg)
 				} else {
 					lprintf(LOG_NOTICE,"%04d <%s> deleted %s",sock,user.alias,fname);
 					if(filedat) 
-						removefiledat(&scfg,&f);
+						removefile(&scfg, dir, getfname(fname));
 					sockprintf(sock,sess,"250 %s deleted.",fname);
 				}
 			} else if(success) {
@@ -4659,16 +4577,8 @@ static void ctrl_thread(void* arg)
 					continue;
 				}
 				if(append || filepos) {	/* RESUME */
-#ifdef _WIN32
-					GetShortPathName(fname, str, sizeof(str));
-#else
-					SAFECOPY(str,fname);
-#endif
-					padfname(getfname(str),f.name);
-					f.dir=dir;
-					f.cdt=0;
-					f.size=-1;
-					if(!getfileixb(&scfg,&f) || !getfiledat(&scfg,&f)) {
+					file_t f;
+					if(!loadfile(&scfg, dir, p, &f, file_detail_normal)) {
 						if(filepos) {
 							lprintf(LOG_WARNING,"%04d <%s> file (%s) not in database for %.4s command"
 								,sock,user.alias,fname,cmd);
@@ -4678,12 +4588,14 @@ static void ctrl_thread(void* arg)
 						append=FALSE;
 					}
 					/* Verify user is original uploader */
-					if((append || filepos) && stricmp(f.uler,user.alias)) {
+					if((append || filepos) && stricmp(f.from, user.alias)) {
 						lprintf(LOG_WARNING,"%04d <%s> !cannot resume upload of %s, uploaded by %s"
-							,sock,user.alias,fname,f.uler);
+							,sock,user.alias,fname,f.from);
 						sockprintf(sock,sess,"553 Insufficient access (can't resume upload from different user).");
+						smb_freefilemem(&f);
 						continue;
 					}
+					smb_freefilemem(&f);
 				}
 				lprintf(LOG_INFO,"%04d <%s> uploading: %s to %s (%s) in %s mode"
 					,sock,user.alias
@@ -4990,7 +4902,7 @@ const char* DLLCALL ftp_ver(void)
 #else
 		,""
 #endif
-		,git_branch, git_hash
+		,GIT_BRANCH, GIT_HASH
 		,__DATE__, __TIME__, compiler);
 
 	return(ver);
@@ -5072,7 +4984,7 @@ void DLLCALL ftp_server(void* arg)
 
 		DESCRIBE_COMPILER(compiler);
 
-		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", git_branch, git_hash, __DATE__, __TIME__, compiler);
+		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, compiler);
 
 		sbbs_srand();	/* Seed random number generator */
 
diff --git a/src/sbbs3/ftpsrvr.h b/src/sbbs3/ftpsrvr.h
index 028e57dc7f..acf8c11b69 100644
--- a/src/sbbs3/ftpsrvr.h
+++ b/src/sbbs3/ftpsrvr.h
@@ -43,8 +43,8 @@ typedef struct {
 	WORD	pasv_port_low;
 	WORD	pasv_port_high;
     DWORD	options;			/* See FTP_OPT definitions */
-	uint64_t	min_fsize;		/* Minimum file size accepted for upload */
-	uint64_t	max_fsize;		/* Maximum file size accepted for upload (0=unlimited) */
+	int64_t	min_fsize;			/* Minimum file size accepted for upload */
+	int64_t	max_fsize;			/* Maximum file size accepted for upload (0=unlimited) */
 
 	void*	cbdata;				/* Private data passed to callbacks */ 
 
diff --git a/src/sbbs3/ftpsrvr.vcxproj b/src/sbbs3/ftpsrvr.vcxproj
index 7bcbbde891..84539c12fd 100644
--- a/src/sbbs3/ftpsrvr.vcxproj
+++ b/src/sbbs3/ftpsrvr.vcxproj
@@ -176,7 +176,6 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
-    <ClCompile Include="ver.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\xpdev\xpdev_mt.vcxproj">
diff --git a/src/sbbs3/getmsg.cpp b/src/sbbs3/getmsg.cpp
index 7b59ce3f11..ae7c707c70 100644
--- a/src/sbbs3/getmsg.cpp
+++ b/src/sbbs3/getmsg.cpp
@@ -403,10 +403,7 @@ void sbbs_t::download_msg_attachments(smb_t* smb, smbmsg_t* msg, bool del)
 			p=strchr(tp,' ');
 			if(p) *p=0;
 			tp=getfname(tp);
-			file_t	fd;
-			fd.dir=cfg.total_dirs+1;			/* temp dir for file attachments */
 			if(strcspn(tp, ILLEGAL_FILENAME_CHARS) == strlen(tp)) {
-				padfname(tp,fd.name);
 				SAFEPRINTF3(fpath,"%sfile/%04u.in/%s"  /* path is path/fname */
 					,cfg.data_dir, msg->idx.to, tp);
 				if(!fexistcase(fpath) && msg->idx.from)
@@ -441,7 +438,7 @@ void sbbs_t::download_msg_attachments(smb_t* smb, smbmsg_t* msg, bool del)
 									break;
 							if(i<cfg.total_prots) {
 								int error = protocol(cfg.prot[i], XFER_DOWNLOAD, fpath, nulstr, false);
-								if(checkprotresult(cfg.prot[i],error,&fd)) {
+								if(checkprotresult(cfg.prot[i],error,fpath)) {
 									if(del)
 										(void)remove(fpath);
 									logon_dlb+=length;	/* Update stats */
@@ -451,10 +448,10 @@ void sbbs_t::download_msg_attachments(smb_t* smb, smbmsg_t* msg, bool del)
 									useron.dlb=adjustuserrec(&cfg,useron.number
 										,U_DLB,10,length);
 									bprintf(text[FileNBytesSent]
-										,fd.name,ultoac(length,tmp));
+										,getfname(fpath),ultoac(length,tmp));
 									SAFEPRINTF(str
 										,"downloaded attached file: %s"
-										,fd.name);
+										,getfname(fpath));
 									logline("D-",str);
 								}
 								autohangup();
@@ -569,7 +566,7 @@ time_t sbbs_t::getmsgtime(uint subnum, ulong ptr)
 		smb_close(&smb);
 		return(0);
 	}
-	msg.offset=0;
+	msg.idx_offset=0;
 	msg.hdr.number=0;
 	if(smb_getmsgidx(&smb,&msg)) {				/* Get first message index */
 		smb_close(&smb);
@@ -597,13 +594,13 @@ time_t sbbs_t::getmsgtime(uint subnum, ulong ptr)
 	}
 
 	if(ptr-msg.idx.number < lastidx.number-ptr) {
-		msg.offset=0;
+		msg.idx_offset=0;
 		msg.idx.number=0;
 		while(msg.idx.number<ptr) {
 			msg.hdr.number=0;
 			if(smb_getmsgidx(&smb,&msg) || msg.idx.number>=ptr)
 				break;
-			msg.offset++;
+			msg.idx_offset++;
 		}
 		smb_close(&smb);
 		return(msg.idx.time);
diff --git a/src/sbbs3/getstats.c b/src/sbbs3/getstats.c
index 8de3c082e2..de5aa52c60 100644
--- a/src/sbbs3/getstats.c
+++ b/src/sbbs3/getstats.c
@@ -48,16 +48,16 @@ BOOL DLLCALL getstats(scfg_t* cfg, char node, stats_t* stats)
 /****************************************************************************/
 long DLLCALL getfiles(scfg_t* cfg, uint dirnum)
 {
-	char str[256];
-	long l;
+	char path[MAX_PATH + 1];
+	off_t l;
 
-	if(dirnum>=cfg->total_dirs)	/* out of range */
-		return(0);
-	sprintf(str,"%s%s.ixb",cfg->dir[dirnum]->data_dir, cfg->dir[dirnum]->code);
-	l=(long)flength(str);
-	if(l>0L)
-		return(l/F_IXBSIZE);
-	return(0);
+	if(dirnum >= cfg->total_dirs)	/* out of range */
+		return 0;
+	SAFEPRINTF2(path, "%s%s.sid", cfg->dir[dirnum]->data_dir, cfg->dir[dirnum]->code);
+	l = flength(path);
+	if(l <= 0)
+		return 0;
+	return (long)(l / sizeof(fileidxrec_t));
 }
 
 /****************************************************************************/
@@ -73,7 +73,7 @@ ulong DLLCALL getposts(scfg_t* cfg, uint subnum)
 		l = flength(path);
 		if(l < sizeof(idxrec_t))
 			return 0;
-		return l / sizeof(idxrec_t);
+		return (ulong)(l / sizeof(idxrec_t));
 	}
 	smb_t smb = {{0}};
 	SAFEPRINTF2(smb.file, "%s%s", cfg->sub[subnum]->data_dir, cfg->sub[subnum]->code);
diff --git a/src/sbbs3/js_archive.c b/src/sbbs3/js_archive.c
new file mode 100644
index 0000000000..459b09713a
--- /dev/null
+++ b/src/sbbs3/js_archive.c
@@ -0,0 +1,674 @@
+/* Synchronet JavaScript "Archive" Object */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
+ *																			*
+ * This program is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU General Public License				*
+ * as published by the Free Software Foundation; either version 2			*
+ * of the License, or (at your option) any later version.					*
+ * See the GNU General Public License for more details: gpl.txt or			*
+ * http://www.fsf.org/copyleft/gpl.html										*
+ *																			*
+ * For Synchronet coding style and modification guidelines, see				*
+ * http://www.synchro.net/source.html										*
+ *																			*
+ * Note: If this box doesn't appear square, then you need to fix your tabs.	*
+ ****************************************************************************/
+
+#include "sbbs.h"
+#include "js_request.h"
+#include "filedat.h"
+
+/* libarchive: */
+#include <archive.h>
+#include <archive_entry.h>
+
+#include <stdbool.h>
+
+JSClass js_archive_class;
+
+static JSBool
+js_create(JSContext *cx, uintN argc, jsval *arglist)
+{
+	jsval *argv = JS_ARGV(cx, arglist);
+	JSObject *obj = JS_THIS_OBJECT(cx, arglist);
+	char		format[32] = "";
+	str_list_t	file_list = NULL;
+	char		path[MAX_PATH + 1];
+	bool		with_path = false;
+	char		error[256] = "";
+	jsval		val;
+	jsrefcount	rc;
+	const char* filename;
+
+	if((filename = js_GetClassPrivate(cx, obj, &js_archive_class)) == NULL)
+		return JS_FALSE;
+
+	if(!js_argc(cx, argc, 1))
+		return JS_FALSE;
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn])) {
+		JSString* js_str = JS_ValueToString(cx, argv[argn]);
+		if(js_str == NULL) {
+			JS_ReportError(cx, "string conversion error");
+			return JS_FALSE;
+		}
+		JSSTRING_TO_STRBUF(cx, js_str, format, sizeof(format), NULL);
+		argn++;
+	}
+	if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
+		with_path = JSVAL_TO_BOOLEAN(argv[argn]);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_OBJECT(argv[argn])) {
+		JSObject* array = JSVAL_TO_OBJECT(argv[argn]);
+		if(!JS_IsArrayObject(cx, array)) {
+			JS_ReportError(cx, "invalid array object");
+			return JS_FALSE;
+		}
+		file_list = strListInit();
+		for(jsint i = 0;; i++)  {
+			if(!JS_GetElement(cx, array, i, &val))
+				break;
+			if(!JSVAL_IS_STRING(val))
+				break;
+			JSVALUE_TO_STRBUF(cx, val, path, sizeof(path), NULL);
+			strListPush(&file_list, path);
+		}
+		argn++;
+	}
+
+	char* fext;
+	if(*format == '\0' && (fext = getfext(filename)) != NULL)
+		SAFECOPY(format,  fext + 1);
+	if(*format == '\0')
+		SAFECOPY(format, "zip");
+	rc = JS_SUSPENDREQUEST(cx);
+	long file_count = create_archive(filename, format, with_path, file_list, error, sizeof(error));
+	strListFree(&file_list);
+	JS_RESUMEREQUEST(cx, rc);
+	if(file_count < 0) {
+		JS_ReportError(cx, error);
+		return JS_FALSE;
+	}
+	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(file_count));
+	return JS_TRUE;
+}
+
+static JSBool
+js_extract(JSContext *cx, uintN argc, jsval *arglist)
+{
+	jsval *argv = JS_ARGV(cx, arglist);
+	JSObject *obj = JS_THIS_OBJECT(cx, arglist);
+	char*		outdir = NULL;
+	char*		allowed_filename_chars = SAFEST_FILENAME_CHARS;
+	str_list_t	file_list = NULL;
+	bool		with_path = false;
+	int32		max_files = 0;
+	char		error[256] = "";
+	jsrefcount	rc;
+	const char* filename;
+	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
+
+	if((filename = js_GetClassPrivate(cx, obj, &js_archive_class)) == NULL)
+		return JS_FALSE;
+
+ 	if(!js_argc(cx, argc, 1))
+		return JS_FALSE;
+
+	if(JSVAL_NULL_OR_VOID(argv[0]))
+		JS_ReportError(cx, "Invalid output directory specified (null or undefined)");
+	else
+		JSVALUE_TO_MSTRING(cx, argv[0], outdir, NULL);
+	if(JS_IsExceptionPending(cx)) {
+		free(outdir);
+		return JS_FALSE;
+	}
+	uintN argn = 1;
+	if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
+		with_path = JSVAL_TO_BOOLEAN(argv[argn]);
+		if(with_path)
+			allowed_filename_chars = NULL;	// We trust this archive
+		argn++;
+	}
+	if(argc > argn && JSVAL_IS_NUMBER(argv[argn])) {
+		if(!JS_ValueToInt32(cx, argv[argn], &max_files)) {
+			free(outdir);
+			strListFree(&file_list);
+			return JS_FALSE;
+		}
+		argn++;
+	}
+	for(; argn < argc; argn++) {
+		if(JSVAL_IS_STRING(argv[argn])) {
+			char path[MAX_PATH + 1];
+			JSVALUE_TO_STRBUF(cx, argv[argn], path, sizeof(path), NULL);
+			strListPush(&file_list, path);
+		}
+	}
+
+	rc = JS_SUSPENDREQUEST(cx);
+	long extracted = extract_files_from_archive(filename, outdir, allowed_filename_chars
+		,with_path, (ulong)max_files, file_list, error, sizeof(error));
+	strListFree(&file_list);
+	free(outdir);
+	JS_RESUMEREQUEST(cx, rc);
+	if(*error != '\0') {
+		if(extracted >= 0)
+			JS_ReportError(cx, "%s (after extracting %ld items successfully)", error, extracted);
+		else
+			JS_ReportError(cx, "%s", error);
+		return JS_FALSE;
+	}
+	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(extracted));
+	return JS_TRUE;
+}
+
+/* getter */
+static JSBool
+js_archive_type(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+	char		type[256] = "";
+	jsrefcount	rc;
+	const char* filename;
+
+	if((filename = js_GetClassPrivate(cx, obj, &js_archive_class)) == NULL)
+		return JS_FALSE;
+
+	rc = JS_SUSPENDREQUEST(cx);
+	int result = archive_type(filename, type, sizeof(type));
+	JS_RESUMEREQUEST(cx, rc);
+	if(result >= 0) {
+		JSString* js_str = JS_NewStringCopyZ(cx, type);
+		*vp = STRING_TO_JSVAL(js_str);
+	} else
+		*vp = JSVAL_NULL;
+	return JS_TRUE;
+}
+
+// TODO: consider making 'path' and 'case-sensitive' arguments to wildmatch() configurable via method arguments
+static JSBool
+js_list(JSContext *cx, uintN argc, jsval *arglist)
+{
+	jsval *argv = JS_ARGV(cx, arglist);
+	JSObject *obj = JS_THIS_OBJECT(cx, arglist);
+	jsval val;
+	jsrefcount	rc;
+	JSObject* array;
+	JSString* js_str;
+	struct archive *ar;
+	struct archive_entry *entry;
+	bool hash = false;
+	int	result;
+	const char* filename;
+	char pattern[MAX_PATH + 1] = "";
+
+	if((filename = js_GetClassPrivate(cx, obj, &js_archive_class)) == NULL)
+		return JS_FALSE;
+
+	uintN argn = 0;
+	if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
+		hash = JSVAL_TO_BOOLEAN(argv[argn]);
+		argn++;
+	}
+	if(argc > argn && JSVAL_IS_STRING(argv[argn])) {
+		JSString* js_str = JS_ValueToString(cx, argv[argn]);
+		if(js_str == NULL) {
+			JS_ReportError(cx, "string conversion error");
+			return JS_FALSE;
+		}
+		JSSTRING_TO_STRBUF(cx, js_str, pattern, sizeof(pattern), NULL);
+		argn++;
+	}
+
+	if((ar = archive_read_new()) == NULL) {
+		JS_ReportError(cx, "archive_read_new() returned NULL");
+		return JS_FALSE;
+	}
+	archive_read_support_filter_all(ar);
+	archive_read_support_format_all(ar);
+	if((result = archive_read_open_filename(ar, filename, 10240)) != ARCHIVE_OK) {
+		JS_ReportError(cx, "archive_read_open_filename() returned %d: %s"
+			,result, archive_error_string(ar));
+		archive_read_free(ar);
+		return JS_FALSE;
+	}
+
+    if((array = JS_NewArrayObject(cx, 0, NULL))==NULL) {
+		JS_ReportError(cx, "JS_NewArrayObject() returned NULL");
+		archive_read_free(ar);
+		return JS_FALSE;
+	}
+
+	JSBool retval = JS_TRUE;
+	rc = JS_SUSPENDREQUEST(cx);
+	jsint len = 0;
+	while(1) {
+		result = archive_read_next_header(ar, &entry);
+		if(result != ARCHIVE_OK) {
+			if(result != ARCHIVE_EOF) {
+				JS_ReportError(cx, "archive_read_next_header() returned %d: %s"
+					,result, archive_error_string(ar));
+				retval = JS_FALSE;
+			}
+			break;
+		}
+
+		const char* p = archive_entry_pathname(entry);
+		if(p == NULL)
+			continue;
+
+		if(*pattern && !wildmatch(p, pattern, /* path: */false, /* case-sensitive: */false))
+			continue;
+
+		const char* type;
+		switch(archive_entry_filetype(entry)) {
+			case AE_IFREG:
+				type = "file";
+				break;
+			case AE_IFLNK:
+				type = "link";
+				break;
+			case AE_IFDIR:
+				type = "directory";
+				break;
+			default:
+				continue;
+		}
+
+		JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
+		if(obj == NULL)
+			break;
+
+		js_str = JS_NewStringCopyZ(cx, type);
+		if(js_str == NULL)
+			break;
+		val = STRING_TO_JSVAL(js_str);
+		JS_SetProperty(cx, obj, "type", &val);
+
+		js_str = JS_NewStringCopyZ(cx, p);
+		if(js_str == NULL)
+			break;
+		val = STRING_TO_JSVAL(js_str);
+		JS_SetProperty(cx, obj, "name", &val);
+
+		if((p = archive_entry_sourcepath(entry)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "path", &val);
+		}
+
+		if((p = archive_entry_symlink(entry)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "symlink", &val);
+
+//			val = INT_TO_JSVAL(archive_entry_symlink_type(entry));
+//			JS_SetProperty(cx, obj, "symlink_type", &val);
+		}
+
+		if((p = archive_entry_hardlink(entry)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "hardlink", &val);
+		}
+
+		val = DOUBLE_TO_JSVAL((jsdouble)archive_entry_size(entry));
+		JS_SetProperty(cx, obj, "size", &val);
+
+		val = DOUBLE_TO_JSVAL((jsdouble)archive_entry_mtime(entry));
+		JS_SetProperty(cx, obj, "time", &val);
+
+		val = INT_TO_JSVAL(archive_entry_mode(entry));
+		JS_SetProperty(cx, obj, "mode", &val);
+
+		if((p = archive_entry_uname(entry)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "user", &val);
+		}
+
+		if((p = archive_entry_gname(entry)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "group", &val);
+		}
+
+		if((p = archive_format_name(ar)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "format", &val);
+		}
+
+		if((p = archive_filter_name(ar, 0)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "compression", &val);
+		}
+
+		if((p = archive_entry_fflags_text(entry)) != NULL) {
+			js_str = JS_NewStringCopyZ(cx, p);
+			if(js_str == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			JS_SetProperty(cx, obj, "fflags", &val);
+		}
+
+		if(hash && archive_entry_filetype(entry) == AE_IFREG) {
+			MD5 md5_ctx;
+			SHA1_CTX sha1_ctx;
+			uint8_t md5[MD5_DIGEST_SIZE];
+			uint8_t sha1[SHA1_DIGEST_SIZE];
+			uint16_t crc16 = 0;
+			uint32_t crc32 = 0;
+
+			MD5_open(&md5_ctx);
+			SHA1Init(&sha1_ctx);
+
+			const void *buff;
+			size_t size;
+			la_int64_t offset;
+
+			for(;;) {
+				result = archive_read_data_block(ar, &buff, &size, &offset);
+				if(result != ARCHIVE_OK)
+					break;
+				crc32 = crc32i(~crc32, buff, size);
+				crc16 = icrc16(crc16, buff, size);
+				MD5_digest(&md5_ctx, buff, size);
+				SHA1Update(&sha1_ctx, buff, size);
+			}
+			MD5_close(&md5_ctx, md5);
+			SHA1Final(&sha1_ctx, sha1);
+			val = UINT_TO_JSVAL(crc16);
+			if(!JS_SetProperty(cx, obj, "crc16", &val))
+				break;
+			val = UINT_TO_JSVAL(crc32);
+			if(!JS_SetProperty(cx, obj, "crc32", &val))
+				break;
+			char hex[128];
+			if((js_str = JS_NewStringCopyZ(cx, MD5_hex(hex, md5))) == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			if(!JS_SetProperty(cx, obj, "md5", &val))
+				break;
+			if((js_str = JS_NewStringCopyZ(cx, SHA1_hex(hex, sha1))) == NULL)
+				break;
+			val = STRING_TO_JSVAL(js_str);
+			if(!JS_SetProperty(cx, obj, "sha1", &val))
+				break;
+		}
+
+		val = OBJECT_TO_JSVAL(obj);
+        if(!JS_SetElement(cx, array, len++, &val))
+			break;
+	}
+	archive_read_free(ar);
+	JS_RESUMEREQUEST(cx, rc);
+	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
+
+	return retval;
+}
+
+static JSBool
+js_read(JSContext *cx, uintN argc, jsval *arglist)
+{
+	jsval *argv = JS_ARGV(cx, arglist);
+	JSObject *obj = JS_THIS_OBJECT(cx, arglist);
+	jsrefcount	rc;
+	struct archive *ar;
+	struct archive_entry *entry;
+	int	result;
+	const char* filename;
+	char pattern[MAX_PATH + 1] = "";
+
+	if((filename = js_GetClassPrivate(cx, obj, &js_archive_class)) == NULL)
+		return JS_FALSE;
+
+ 	if(!js_argc(cx, argc, 1))
+		return JS_FALSE;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+
+	uintN argn = 0;
+	if(argc > argn && JSVAL_IS_STRING(argv[argn])) {
+		JSString* js_str = JS_ValueToString(cx, argv[argn]);
+		if(js_str == NULL) {
+			JS_ReportError(cx, "string conversion error");
+			return JS_FALSE;
+		}
+		JSSTRING_TO_STRBUF(cx, js_str, pattern, sizeof(pattern), NULL);
+		argn++;
+	}
+
+	if((ar = archive_read_new()) == NULL) {
+		JS_ReportError(cx, "archive_read_new() returned NULL");
+		return JS_FALSE;
+	}
+	archive_read_support_filter_all(ar);
+	archive_read_support_format_all(ar);
+	if((result = archive_read_open_filename(ar, filename, 10240)) != ARCHIVE_OK) {
+		JS_ReportError(cx, "archive_read_open_filename() returned %d: %s"
+			,result, archive_error_string(ar));
+		archive_read_free(ar);
+		return JS_FALSE;
+	}
+
+	JSBool retval = JS_TRUE;
+	rc = JS_SUSPENDREQUEST(cx);
+	while(1) {
+		result = archive_read_next_header(ar, &entry);
+		if(result != ARCHIVE_OK) {
+			if(result != ARCHIVE_EOF) {
+				JS_ReportError(cx, "archive_read_next_header() returned %d: %s"
+					,result, archive_error_string(ar));
+				retval = JS_FALSE;
+			}
+			break;
+		}
+
+		if(archive_entry_filetype(entry) != AE_IFREG)
+			continue;
+
+		const char* pathname = archive_entry_pathname(entry);
+		if(pathname == NULL)
+			continue;
+
+		if(stricmp(pathname, pattern) != 0)
+			continue;
+
+		char* p = NULL;
+		size_t total = 0;
+		const void *buff;
+		size_t size;
+		la_int64_t offset;
+
+		for(;;) {
+			result = archive_read_data_block(ar, &buff, &size, &offset);
+			if(result != ARCHIVE_OK)
+				break;
+			char* np = realloc(p, total + size);
+			if(np == NULL)
+				break;
+			p = np;
+			memcpy(p + total, buff, size);
+			total += size;
+		}
+		JSString* js_str = JS_NewStringCopyN(cx, p, total);
+		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
+		free(p);
+		break;
+	}
+	archive_read_free(ar);
+	JS_RESUMEREQUEST(cx, rc);
+
+	return retval;
+}
+
+static jsSyncMethodSpec js_archive_functions[] = {
+	{ "create",		js_create,		1,	JSTYPE_NUMBER
+		,JSDOCSTR("[string format] [,boolean with_path = false] [,array file_list]")
+		,JSDOCSTR("create an archive of the specified format, returns the number of files archived, will throw exception upon error")
+		,31900
+	},
+	{ "read",		js_read,		1,	JSTYPE_STRING
+		,JSDOCSTR("string path/filename")
+		,JSDOCSTR("read and return the contents of the specified archived text file")
+		,31900
+	},
+	{ "extract",	js_extract,		1,	JSTYPE_NUMBER
+		,JSDOCSTR("output_directory [,boolean with_path = false] [,number max_files = 0] [,string file/pattern [...]]")
+		,JSDOCSTR("extract files from an archive to specified output directory, returns the number of files extracted, will throw exception upon error")
+		,31900
+	},
+	{ "list",		js_list,		1,	JSTYPE_ARRAY
+		,JSDOCSTR("[,boolean hash = false] [,string file/pattern]")
+		,JSDOCSTR("get list of archive contents as an array of objects<br>"
+			"archived object properties:<br>"
+			"<ul>"
+			"<li>string <tt>type</tt> - item type: 'file', 'link', or 'directory'"
+			"<li>string <tt>name</tt> - item path/name"
+			"<li>string <tt>path</tt> - source path"
+			"<li>string <tt>symlink</tt>"
+			"<li>string <tt>hardlink</tt>"
+			"<li>number <tt>size</tt> - item size in bytes"
+			"<li>number <tt>time</tt> - modification date/time in time_t format"
+			"<li>number <tt>mode</tt> - permissions/mode flags"
+			"<li>string <tt>user</tt> - owner name"
+			"<li>string <tt>group</tt> - owner group"
+			"<li>string <tt>format</tt> - archive format"
+			"<li>string <tt>compression</tt> - compression method"
+			"<li>string <tt>fflags</tt>"
+			"<li>number <tt>crc16</tt> - 16-bit CRC, when hash is true and type is file"
+			"<li>number <tt>crc32</tt> - 32-bit CRC, when hash is true and type is file"
+			"<li>string <tt>md5</tt> - hexadecimal MD-5 sum, when hash is true and type is file"
+			"<li>string <tt>sha1</tt> - hexadecimal SHA-1 sum, when hash is true and type is file"
+			"</ul>"
+			"when <tt>hash</tt> is <tt>true</tt>, calculates and returns hash/digest values of files in stored archive")
+		,31900
+	},
+	{0}
+};
+
+#ifdef BUILD_JSDOCS
+static char* archive_prop_desc[] = {
+
+	 "format/compression type of archive file - <small>READ ONLY</small>"
+	,NULL
+};
+#endif
+
+static JSBool
+js_archive_constructor(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject *obj = JS_THIS_OBJECT(cx, arglist);
+	jsval *argv = JS_ARGV(cx, arglist);
+	JSString* str;
+	char* filename;
+
+	obj = JS_NewObject(cx, &js_archive_class, NULL, NULL);
+	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj));
+	if(argc < 1 || (str = JS_ValueToString(cx, argv[0]))==NULL) {
+		JS_ReportError(cx, "No filename specified");
+		return JS_FALSE;
+	}
+
+	JSSTRING_TO_MSTRING(cx, str, filename, NULL);
+
+	if(!JS_SetPrivate(cx, obj, filename)) {
+		JS_ReportError(cx, "JS_SetPrivate failed");
+		return JS_FALSE;
+	}
+
+	if(!JS_DefineProperty(cx, obj, "type", JSVAL_VOID, js_archive_type, NULL, JSPROP_ENUMERATE|JSPROP_READONLY)) {
+		JS_ReportError(cx, "JS_DefineProperty failed");
+		return JS_FALSE;
+	}
+
+#ifdef BUILD_JSDOCS
+	js_DescribeSyncObject(cx,obj,"Class used for opening, creating, reading, or writing archive files on the local file system<p>"
+		,31900
+		);
+	js_DescribeSyncConstructor(cx,obj,"To create a new Archive object: <tt>var a = new Archive(<i>filename</i>)</tt>");
+	js_CreateArrayOfStrings(cx, obj, "_property_desc_list", archive_prop_desc, JSPROP_READONLY);
+#endif
+
+	return JS_TRUE;
+}
+
+static void js_finalize_archive(JSContext *cx, JSObject *obj)
+{
+	void* p;
+
+	if((p = JS_GetPrivate(cx, obj)) == NULL)
+		return;
+	free(p);
+	JS_SetPrivate(cx, obj, NULL);
+}
+
+static JSBool js_archive_resolve(JSContext *cx, JSObject *obj, jsid id)
+{
+	char*			name=NULL;
+	JSBool			ret;
+
+	if(id != JSID_VOID && id != JSID_EMPTY) {
+		jsval idval;
+
+		JS_IdToValue(cx, id, &idval);
+		if(JSVAL_IS_STRING(idval))
+			JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL);
+	}
+
+	ret=js_SyncResolve(cx, obj, name, NULL, js_archive_functions, NULL, 0);
+	if(name)
+		free(name);
+	return ret;
+}
+
+static JSBool js_archive_enumerate(JSContext *cx, JSObject *obj)
+{
+	return js_archive_resolve(cx, obj, JSID_VOID);
+}
+
+JSClass js_archive_class = {
+     "Archive"				/* name			*/
+    ,JSCLASS_HAS_PRIVATE	/* flags		*/
+	,JS_PropertyStub		/* addProperty	*/
+	,JS_PropertyStub		/* delProperty	*/
+	,JS_PropertyStub		/* getProperty	*/
+	,JS_StrictPropertyStub	/* setProperty	*/
+	,js_archive_enumerate	/* enumerate	*/
+	,js_archive_resolve		/* resolve		*/
+	,JS_ConvertStub			/* convert		*/
+	,js_finalize_archive	/* finalize		*/
+};
+
+JSObject* js_CreateArchiveClass(JSContext* cx, JSObject* parent)
+{
+	return JS_InitClass(cx, parent, NULL
+		,&js_archive_class
+		,js_archive_constructor
+		,1		/* number of constructor args */
+		,NULL	/* props, set in constructor */
+		,NULL	/* funcs, set in constructor */
+		,NULL, NULL);
+}
diff --git a/src/sbbs3/js_bbs.cpp b/src/sbbs3/js_bbs.cpp
index df4b0aa5ee..466dacb5af 100644
--- a/src/sbbs3/js_bbs.cpp
+++ b/src/sbbs3/js_bbs.cpp
@@ -79,8 +79,6 @@ enum {
 	,BBS_PROP_RLOGIN_TERM
 	,BBS_PROP_CLIENT_NAME
 
-	,BBS_PROP_ALTUL
-
 	,BBS_PROP_ERRORLEVEL		/* READ ONLY */
 
 	/* READ ONLY */
@@ -205,8 +203,6 @@ enum {
 	,"terminal specified during RLogin negotiation"
 	,"client name"
 
-	,"current alternate upload path number"
-
 	,"error level returned from last executed external program"
 
 	/* READ ONLY */
@@ -374,16 +370,16 @@ static JSBool js_bbs_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			break;
 
 		case BBS_PROP_LOGON_ULB:
-			val=sbbs->logon_ulb;
+			val=(uint32_t)sbbs->logon_ulb;	// TODO: fix for > 4GB!
 			break;
 		case BBS_PROP_LOGON_DLB:
-			val=sbbs->logon_dlb;
+			val=(uint32_t)sbbs->logon_dlb;	// TODO: fix for > 4GB!
 			break;
 		case BBS_PROP_LOGON_ULS:
-			val=sbbs->logon_uls;
+			val=(uint32_t)sbbs->logon_uls;	// TODO: fix for > 4GB!
 			break;
 		case BBS_PROP_LOGON_DLS:
-			val=sbbs->logon_dls;
+			val=(uint32_t)sbbs->logon_dls;	// TODO: fix for > 4GB!
 			break;
 		case BBS_PROP_LOGON_POSTS:
 			val=sbbs->logon_posts;
@@ -455,10 +451,6 @@ static JSBool js_bbs_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			p=sbbs->client_name;
 			break;
 
-		case BBS_PROP_ALTUL:
-			val=sbbs->altul;
-			break;
-
 		case BBS_PROP_ERRORLEVEL:
 			val=sbbs->errorlevel;
 			break;
@@ -638,7 +630,7 @@ static JSBool js_bbs_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			break;
 		case BBS_PROP_MSG_OFFSET:
 			if(sbbs->current_msg!=NULL)
-				val=sbbs->current_msg->offset;
+				val=sbbs->current_msg->idx_offset;
 			break;
 		case BBS_PROP_MSG_NUMBER:
 			if(sbbs->current_msg!=NULL)
@@ -705,43 +697,43 @@ static JSBool js_bbs_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			if(sbbs->current_file==NULL)
 				p=nulstr;
 			else
-				p=sbbs->current_file->uler;
+				p=sbbs->current_file->from;
 			break;
 		case BBS_PROP_FILE_DATE:
 			if(sbbs->current_file==NULL)
 				p=nulstr;
 			else
-				val=sbbs->current_file->date;
+				val=(uint32)sbbs->current_file->time;
 			break;
 		case BBS_PROP_FILE_DATE_ULED:
 			if(sbbs->current_file==NULL)
 				p=nulstr;
 			else
-				val=sbbs->current_file->dateuled;
+				val=sbbs->current_file->hdr.when_imported.time;
 			break;
 		case BBS_PROP_FILE_DATE_DLED:
 			if(sbbs->current_file==NULL)
 				p=nulstr;
 			else
-				val=sbbs->current_file->datedled;
+				val=sbbs->current_file->hdr.last_downloaded;
 			break;
 		case BBS_PROP_FILE_TIMES_DLED:
 			if(sbbs->current_file==NULL)
 				p=nulstr;
 			else
-				val=sbbs->current_file->timesdled;
+				val=sbbs->current_file->hdr.times_downloaded;
 			break;
 		case BBS_PROP_FILE_SIZE:
 			if(sbbs->current_file==NULL)
 				p=nulstr;
-			else
-				val=sbbs->current_file->size;
+			else // TODO: fix for 64-bit file sizes
+				val=(uint32)sbbs->current_file->size;
 			break;
 		case BBS_PROP_FILE_CREDITS:
 			if(sbbs->current_file==NULL)
 				p=nulstr;
 			else
-				val=sbbs->current_file->cdt;
+				val=sbbs->current_file->cost;
 			break;
 		case BBS_PROP_FILE_DIR:
 			if(sbbs->current_file==NULL)
@@ -753,14 +745,14 @@ static JSBool js_bbs_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			if(sbbs->current_file==NULL)
 				p=nulstr;
 			else
-				val=sbbs->current_file->misc;
+				val=sbbs->current_file->hdr.attr;
 			break;
 
 		case BBS_PROP_BATCH_UPLOAD_TOTAL:
-			val=sbbs->batup_total;
+			val = sbbs->batup_total();
 			break;
 		case BBS_PROP_BATCH_DNLOAD_TOTAL:
-			val=sbbs->batdn_total;
+			val = sbbs->batdn_total();
 			break;
 
 		case BBS_PROP_COMMAND_STR:
@@ -954,11 +946,6 @@ static JSBool js_bbs_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, j
 				SAFECOPY(sbbs->client_name,p);
 			break;
 
-		case BBS_PROP_ALTUL:
-			if(val<sbbs->cfg.altpaths)
-				sbbs->altul=(ushort)val;
-			break;
-
 		case BBS_PROP_COMMAND_STR:
 			if(p != NULL)
 				sprintf(sbbs->main_csi.str, "%.*s", 1024, p);
@@ -1036,7 +1023,6 @@ static jsSyncPropertySpec js_bbs_properties[] = {
 	{	"rlogin_password"	,BBS_PROP_RLOGIN_PASS	,JSPROP_ENUMERATE	,315},
 	{	"rlogin_terminal"	,BBS_PROP_RLOGIN_TERM	,JSPROP_ENUMERATE	,316},
 	{	"client_name"		,BBS_PROP_CLIENT_NAME	,JSPROP_ENUMERATE	,310},
-	{	"alt_ul_dir"		,BBS_PROP_ALTUL			,JSPROP_ENUMERATE	,310},
 	{	"errorlevel"		,BBS_PROP_ERRORLEVEL	,PROP_READONLY		,312},
 
 	{	"smb_group"			,BBS_PROP_SMB_GROUP			,PROP_READONLY	,310},
@@ -1512,7 +1498,7 @@ js_replace_text(JSContext *cx, uintN argc, jsval *arglist)
 
 	len=strlen(p);
 	if(!len) {
-		sbbs->text[i]=nulstr;
+		sbbs->text[i]=(char*)nulstr;
 		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
 		free(p);
 	} else {
@@ -1614,7 +1600,7 @@ js_load_text(JSContext *cx, uintN argc, jsval *arglist)
 		}
 		else if(sbbs->text[i][0]==0) {
 			free(sbbs->text[i]);
-			sbbs->text[i]=nulstr;
+			sbbs->text[i]=(char*)nulstr;
 		}
 	}
 	if(i<TOTAL_TEXT)
@@ -2883,34 +2869,6 @@ js_bulkupload(JSContext *cx, uintN argc, jsval *arglist)
 	return(JS_TRUE);
 }
 
-static JSBool
-js_resort_dir(JSContext *cx, uintN argc, jsval *arglist)
-{
-	jsval *argv=JS_ARGV(cx, arglist);
-	uint		dirnum=0;
-	sbbs_t*		sbbs;
-	jsrefcount	rc;
-
-	if((sbbs=js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist)))==NULL)
-		return(JS_FALSE);
-
-	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
-
-	dirnum=get_dirnum(cx,sbbs,argv[0], argc == 0);
-
-	if(dirnum>=sbbs->cfg.total_dirs) {
-		JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
-		return(JS_TRUE);
-	}
-
-	rc=JS_SUSPENDREQUEST(cx);
-	sbbs->resort(dirnum);
-	JS_RESUMEREQUEST(cx, rc);
-
-	JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
-	return(JS_TRUE);
-}
-
 static JSBool
 js_telnet_gate(JSContext *cx, uintN argc, jsval *arglist)
 {
@@ -3480,7 +3438,6 @@ js_listfiles(JSContext *cx, uintN argc, jsval *arglist)
 	const char	*def=ALLFILES;
 	char*		afspec=NULL;
 	char*		fspec=(char *)def;
-	char		buf[MAX_PATH+1];
 	uint		dirnum;
     JSString*	js_str;
 	sbbs_t*		sbbs;
@@ -3518,9 +3475,6 @@ js_listfiles(JSContext *cx, uintN argc, jsval *arglist)
 	}
 
 	rc=JS_SUSPENDREQUEST(cx);
-	if(!(mode&(FL_FINDDESC|FL_EXFIND)))
-		fspec=padfname(fspec,buf);
-
 	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->listfiles(dirnum,fspec,0 /* tofile */,mode)));
 	if(afspec)
 		free(afspec);
@@ -3536,7 +3490,6 @@ js_listfileinfo(JSContext *cx, uintN argc, jsval *arglist)
 	uint32		mode=FI_INFO;
 	const char	*def=ALLFILES;
 	char*		fspec=(char *)def;
-	char		buf[MAX_PATH+1];
 	uint		dirnum;
     JSString*	js_str;
 	sbbs_t*		sbbs;
@@ -3573,7 +3526,7 @@ js_listfileinfo(JSContext *cx, uintN argc, jsval *arglist)
 	}
 
 	rc=JS_SUSPENDREQUEST(cx);
-	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->listfileinfo(dirnum,padfname(fspec,buf),mode)));
+	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->listfileinfo(dirnum, fspec, mode)));
 	if(fspec != def)
 		free(fspec);
 	JS_RESUMEREQUEST(cx, rc);
@@ -4464,10 +4417,6 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 		"specified by number or internal code")
 	,310
 	},
-	{"resort_dir",		js_resort_dir,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("[directory=<i>current</i>]")
-	,JSDOCSTR("re-sort the file directory specified by number or internal code)")
-	,310
-	},
 	{"list_files",		js_listfiles,		1,	JSTYPE_NUMBER,	JSDOCSTR("[directory=<i>current</i>] [,filespec=<tt>\"*.*\"</tt> or search_string] [,mode=<tt>FL_NONE</tt>]")
 	,JSDOCSTR("list files in the specified file directory, "
 		"optionally specifying a file specification (wildcards) or a description search string, "
diff --git a/src/sbbs3/js_com.c b/src/sbbs3/js_com.c
index c38f94f94d..43fcc93935 100644
--- a/src/sbbs3/js_com.c
+++ b/src/sbbs3/js_com.c
@@ -191,7 +191,7 @@ js_sendfile(JSContext *cx, uintN argc, jsval *arglist)
 {
 	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
 	jsval *argv=JS_ARGV(cx, arglist);
-	long		len;
+	off_t		len;
 	int			file;
 	char*		fname = NULL;
 	private_t*	p;
@@ -225,18 +225,18 @@ js_sendfile(JSContext *cx, uintN argc, jsval *arglist)
 
 	free(fname);
 	len=filelength(file);
-	if((buf=malloc(len))==NULL) {
+	if((buf=malloc((size_t)len))==NULL) {
 		close(file);
 		return(JS_TRUE);
 	}
-	if(read(file,buf,len)!=len) {
+	if(read(file,buf,(uint)len)!=len) {
 		free(buf);
 		close(file);
 		return(JS_TRUE);
 	}
 	close(file);
 
-	if(comWriteBuf(p->com,(uint8_t *)buf,len)==len) {
+	if(comWriteBuf(p->com,(uint8_t *)buf,(size_t)len)==len) {
 		dbprintf(FALSE, p, "sent %u bytes",len);
 		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
 	} else {
diff --git a/src/sbbs3/js_console.cpp b/src/sbbs3/js_console.cpp
index 4c21a940af..8e691b08f3 100644
--- a/src/sbbs3/js_console.cpp
+++ b/src/sbbs3/js_console.cpp
@@ -2211,6 +2211,9 @@ js_clear_console_event(JSContext *cx, uintN argc, jsval *arglist, BOOL once)
 	size_t slen;
 	sbbs_t *sbbs;
 
+	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
+		return(JS_FALSE);
+
 	if (argc != 2) {
 		JS_ReportError(cx, "console.clearOn() and console.clearOnce() require exactly two parameters");
 		return JS_FALSE;
diff --git a/src/sbbs3/js_file.c b/src/sbbs3/js_file.c
index fe05c04747..a52b1f03c2 100644
--- a/src/sbbs3/js_file.c
+++ b/src/sbbs3/js_file.c
@@ -410,7 +410,7 @@ js_raw_read(JSContext *cx, uintN argc, jsval *arglist)
 	fd = fileno(p->fp);
 	lseek(fd, pos, SEEK_SET);
 	len = read(fileno(p->fp),buf,len);
-	fseek(p->fp, pos + (len >= 0 ? len : 0), SEEK_SET);
+	fseeko(p->fp, pos + (len >= 0 ? len : 0), SEEK_SET);
 	dbprintf(FALSE, p, "read %u raw bytes",len);
 	if(len<0)
 		len=0;
@@ -2294,6 +2294,8 @@ enum {
 	,FILE_PROP_CRC32
 	,FILE_PROP_MD5_HEX
 	,FILE_PROP_MD5_B64
+	,FILE_PROP_SHA1_HEX
+	,FILE_PROP_SHA1_B64
 	/* ini style */
 	,FILE_INI_KEY_LEN
 	,FILE_INI_KEY_PREFIX
@@ -2441,8 +2443,9 @@ static JSBool js_file_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 	ushort		c16=0;
 	uint32		c32=~0;
 	MD5			md5_ctx;
+	SHA1_CTX	sha1_ctx;
 	BYTE		block[4096];
-	BYTE		digest[MD5_DIGEST_SIZE];
+	BYTE		digest[SHA1_DIGEST_SIZE];
     jsint       tiny;
 	JSString*	js_str=NULL;
 	private_t*	p;
@@ -2561,6 +2564,8 @@ static JSBool js_file_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			/* fall-through */
 		case FILE_PROP_MD5_HEX:
 		case FILE_PROP_MD5_B64:
+		case FILE_PROP_SHA1_HEX:
+		case FILE_PROP_SHA1_B64:
 			*vp = JSVAL_VOID;
 			if(p->fp==NULL)
 				break;
@@ -2574,6 +2579,10 @@ static JSBool js_file_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 				case FILE_PROP_MD5_B64:
 					MD5_open(&md5_ctx);
 					break;
+				case FILE_PROP_SHA1_HEX:
+				case FILE_PROP_SHA1_B64:
+					SHA1Init(&sha1_ctx);
+					break;
 			}
 
 			/* calculate */
@@ -2597,6 +2606,10 @@ static JSBool js_file_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 					case FILE_PROP_MD5_B64:
 						MD5_digest(&md5_ctx,block,rd);
 						break;
+					case FILE_PROP_SHA1_HEX:
+					case FILE_PROP_SHA1_B64:
+						SHA1Update(&sha1_ctx,block,rd);
+						break;
 					}
 			}
 			JS_RESUMEREQUEST(cx, rc);
@@ -2616,14 +2629,23 @@ static JSBool js_file_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 				case FILE_PROP_MD5_B64:
 					MD5_close(&md5_ctx,digest);
 					if(tiny==FILE_PROP_MD5_HEX)
-						MD5_hex((BYTE*)str,digest);
+						MD5_hex(str,digest);
+					else
+						b64_encode(str,sizeof(str)-1,(char *)digest,sizeof(digest));
+					js_str=JS_NewStringCopyZ(cx, str);
+					break;
+				case FILE_PROP_SHA1_HEX:
+				case FILE_PROP_SHA1_B64:
+					SHA1Final(&sha1_ctx,digest);
+					if(tiny==FILE_PROP_SHA1_HEX)
+						SHA1_hex(str,digest);
 					else
 						b64_encode(str,sizeof(str)-1,(char *)digest,sizeof(digest));
 					js_str=JS_NewStringCopyZ(cx, str);
 					break;
 			}
 			rc=JS_SUSPENDREQUEST(cx);
-			fseek(p->fp,offset,SEEK_SET);	/* restore saved file position */
+			fseeko(p->fp,offset,SEEK_SET);	/* restore saved file position */
 			JS_RESUMEREQUEST(cx, rc);
 			if(js_str!=NULL)
 				*vp = STRING_TO_JSVAL(js_str);
@@ -2696,6 +2718,8 @@ static jsSyncPropertySpec js_file_properties[] = {
 	{	"chksum"			,FILE_PROP_CHKSUM		,FILE_PROP_FLAGS,	311},
 	{	"md5_hex"			,FILE_PROP_MD5_HEX		,FILE_PROP_FLAGS,	311},
 	{	"md5_base64"		,FILE_PROP_MD5_B64		,FILE_PROP_FLAGS,	311},
+	{	"sha1_hex"			,FILE_PROP_SHA1_HEX		,FILE_PROP_FLAGS,	31900},
+	{	"sha1_base64"		,FILE_PROP_SHA1_B64		,FILE_PROP_FLAGS,	31900},
 	/* ini style elements */
 	{	"ini_key_len"				,FILE_INI_KEY_LEN				,JSPROP_ENUMERATE,	317},
 	{	"ini_key_prefix"			,FILE_INI_KEY_PREFIX			,JSPROP_ENUMERATE,	317},
diff --git a/src/sbbs3/js_file_area.c b/src/sbbs3/js_file_area.c
index 30a9f9db78..962b72feb6 100644
--- a/src/sbbs3/js_file_area.c
+++ b/src/sbbs3/js_file_area.c
@@ -18,6 +18,7 @@
  ****************************************************************************/
 
 #include "sbbs.h"
+#include "filedat.h"
 
 #ifdef JAVASCRIPT
 
@@ -26,7 +27,6 @@
 static char* file_area_prop_desc[] = {
 	 "minimum amount of available disk space (in kilobytes) required for user uploads to be allowed"
 	,"file area settings (bitfield) - see <tt>FM_*</tt> in <tt>sbbsdefs.js</tt> for details"
-	,"array of alternative file paths.  NOTE: this array is zero-based, but alt path fields are one-based."
 	,NULL
 };
 
@@ -52,6 +52,7 @@ static char* dir_prop_desc[] = {
 	,"directory internal code"
 	,"directory name"
 	,"directory description"
+	,"directory area tag for file echoes <i>(introduced in v3.19)</i>"
 	,"directory file storage location"
 	,"directory access requirements"
 	,"directory upload requirements"
@@ -63,13 +64,14 @@ static char* dir_prop_desc[] = {
 	,"directory data storage location"
 	,"toggle options (bitfield)"
 	,"sequential (slow storage) device number"
-	,"sort order (see <tt>SORT_*</tt> in <tt>sbbsdefs.js</tt> for valid values)"
+	,"sort order (see <tt>FileBase.SORT</tt> for valid values)"
 	,"configured maximum number of files"
 	,"configured maximum age (in days) of files before expiration"
 	,"percent of file size awarded uploader in credits upon file upload"
 	,"percent of file size awarded uploader in credits upon subsequent downloads"
 	,"directory link (for HTML index)"
 	,"number of files currently in this directory <i>(introduced in v3.18c)</i>"
+	,"timestamp of file base index of this directory <i>(introduced in v3.19)</i>"
 	,"user has sufficient access to view this directory (e.g. list files) <i>(introduced in v3.18)</i>"
 	,"user has sufficient access to upload files to this directory"
 	,"user has sufficient access to download files from this directory"
@@ -108,6 +110,7 @@ js_file_area_finalize(JSContext *cx, JSObject *obj)
 /***************************************/
 enum {
 	 DIR_PROP_FILES
+	,DIR_PROP_UPDATE_TIME
 	,DIR_PROP_CAN_ACCESS
 	,DIR_PROP_CAN_UPLOAD
 	,DIR_PROP_CAN_DOWNLOAD
@@ -119,6 +122,7 @@ static struct JSPropertySpec js_dir_properties[] = {
 /*		 name				,tinyid		,flags	*/
 
 	{	"files"			,DIR_PROP_FILES			,JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY },
+	{	"update_time"	,DIR_PROP_UPDATE_TIME	,JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY },
 	{	"can_access"	,DIR_PROP_CAN_ACCESS	,JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY },
 	{	"can_upload"	,DIR_PROP_CAN_UPLOAD	,JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY },
 	{	"can_download"	,DIR_PROP_CAN_DOWNLOAD	,JSPROP_ENUMERATE|JSPROP_SHARED|JSPROP_READONLY },
@@ -143,6 +147,9 @@ static JSBool js_dir_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 		case DIR_PROP_FILES:
 			*vp = UINT_TO_JSVAL(getfiles(p->cfg, p->dirnum));
 			break;
+		case DIR_PROP_UPDATE_TIME:
+			*vp = UINT_TO_JSVAL((uint32_t)dir_newfiletime(p->cfg, p->dirnum));
+			break;
 		case DIR_PROP_CAN_ACCESS:
 			*vp = BOOLEAN_TO_JSVAL(p->user == NULL || can_user_access_dir(p->cfg, p->dirnum, p->user, p->client));
 			break;
@@ -177,12 +184,12 @@ static JSClass js_dir_class = {
 
 JSBool DLLCALL js_file_area_resolve(JSContext* cx, JSObject* areaobj, jsid id)
 {
+	char		str[128];
 	char		vpath[MAX_PATH+1];
 	JSObject*	alllibs;
 	JSObject*	alldirs;
 	JSObject*	libobj;
 	JSObject*	dirobj;
-	JSObject*	alt_list;
 	JSObject*	lib_list;
 	JSObject*	dir_list;
 	JSString*	js_str;
@@ -223,29 +230,6 @@ JSBool DLLCALL js_file_area_resolve(JSContext* cx, JSObject* areaobj, jsid id)
 			return(JS_TRUE);
 	}
 
-	if(name==NULL || strcmp(name, "alt_paths")==0) {
-		if(name)
-			free(name);
-		/* file_area.alt_paths[] */
-		if((alt_list=JS_NewArrayObject(cx, 0, NULL))==NULL) 
-			return JS_FALSE;
-
-		val=OBJECT_TO_JSVAL(alt_list);
-		if(!JS_SetProperty(cx, areaobj, "alt_paths", &val)) 
-			return JS_FALSE;
-
-		for (l=0; l<p->cfg->altpaths; l++) {
-			if((js_str=JS_NewStringCopyZ(cx, p->cfg->altpath[l]))==NULL)
-				return JS_FALSE;
-			val=STRING_TO_JSVAL(js_str);
-
-			if(!JS_SetElement(cx, alt_list, l, &val))
-				return JS_FALSE;
-		}
-		if(name)
-			return(JS_TRUE);
-	}
-
 #ifdef BUILD_JSDOCS
 	js_CreateArrayOfStrings(cx, areaobj, "_property_desc_list", file_area_prop_desc, JSPROP_READONLY);
 #endif
@@ -445,6 +429,12 @@ JSBool DLLCALL js_file_area_resolve(JSContext* cx, JSObject* areaobj, jsid id)
 				if(!JS_SetProperty(cx, dirobj, "description", &val))
 					return JS_FALSE;
 
+				if((js_str=JS_NewStringCopyZ(cx, dir_area_tag(p->cfg, p->cfg->dir[d], str, sizeof(str))))==NULL)
+					return JS_FALSE;
+				val=STRING_TO_JSVAL(js_str);
+				if(!JS_SetProperty(cx, dirobj, "area_tag", &val))
+					return JS_FALSE;
+
 				if((js_str=JS_NewStringCopyZ(cx, p->cfg->dir[d]->path))==NULL)
 					return JS_FALSE;
 				val=STRING_TO_JSVAL(js_str);
diff --git a/src/sbbs3/js_filebase.c b/src/sbbs3/js_filebase.c
new file mode 100644
index 0000000000..475a58a95d
--- /dev/null
+++ b/src/sbbs3/js_filebase.c
@@ -0,0 +1,1619 @@
+/* Synchronet JavaScript "FileBase" Object */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
+ *																			*
+ * This program is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU General Public License				*
+ * as published by the Free Software Foundation; either version 2			*
+ * of the License, or (at your option) any later version.					*
+ * See the GNU General Public License for more details: gpl.txt or			*
+ * http://www.fsf.org/copyleft/gpl.html										*
+ *																			*
+ * For Synchronet coding style and modification guidelines, see				*
+ * http://www.synchro.net/source.html										*
+ *																			*
+ * Note: If this box doesn't appear square, then you need to fix your tabs.	*
+ ****************************************************************************/
+
+#include "sbbs.h"
+#include "filedat.h"
+#include "js_request.h"
+#include <stdbool.h>
+
+typedef struct
+{
+	smb_t	smb;
+	int		smb_result;
+
+} private_t;
+
+/* Destructor */
+
+static void js_finalize_filebase(JSContext *cx, JSObject *obj)
+{
+	private_t* p;
+
+	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL)
+		return;
+
+	if(SMB_IS_OPEN(&(p->smb)))
+		smb_close(&(p->smb));
+
+	free(p);
+
+	JS_SetPrivate(cx, obj, NULL);
+}
+
+/* Methods */
+
+extern JSClass js_filebase_class;
+
+static JSBool
+js_open(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject* obj = JS_THIS_OBJECT(cx, arglist);
+	private_t* p;
+	jsrefcount	rc;
+	scfg_t*		scfg;
+
+	scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL) {
+		return JS_FALSE;
+	}
+
+	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
+
+	if(p->smb.dirnum==INVALID_DIR
+		&& strchr(p->smb.file,'/')==NULL
+		&& strchr(p->smb.file,'\\')==NULL) {
+		JS_ReportError(cx,"Unrecognized filebase code: %s",p->smb.file);
+		return JS_TRUE;
+	}
+
+	rc=JS_SUSPENDREQUEST(cx);
+	if((p->smb_result = smb_open_dir(scfg, &(p->smb), p->smb.dirnum)) != SMB_SUCCESS) {
+		JS_RESUMEREQUEST(cx, rc);
+		return JS_TRUE;
+	}
+	JS_RESUMEREQUEST(cx, rc);
+
+	JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
+	return JS_TRUE;
+}
+
+static JSBool
+js_close(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject* obj = JS_THIS_OBJECT(cx, arglist);
+	private_t* p;
+	jsrefcount	rc;
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL) {
+		return JS_FALSE;
+	}
+
+	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
+
+	rc=JS_SUSPENDREQUEST(cx);
+	smb_close(&(p->smb));
+	JS_RESUMEREQUEST(cx, rc);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_dump_file(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		filename = NULL;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	uintN argn = 0;
+	if(argn < argc)	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filename, NULL);
+		HANDLE_PENDING(cx, filename);
+		argn++;
+	}
+	if(filename == NULL)
+		return JS_FALSE;
+
+	file_t file;
+	if((p->smb_result = smb_loadfile(&p->smb, filename, &file, file_detail_normal)) == SMB_SUCCESS) {
+		str_list_t list = smb_msghdr_str_list(&file);
+		if(list != NULL) {
+			JSObject* array;
+			if((array = JS_NewArrayObject(cx, 0, NULL)) == NULL) {
+				free(filename);
+				JS_ReportError(cx, "JS_NewArrayObject failure");
+				return JS_FALSE;
+			}
+			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
+			for(int i = 0; list[i] != NULL; i++) {
+				JSString* js_str = JS_NewStringCopyZ(cx, list[i]);
+				if(js_str == NULL)
+					break;
+				JS_DefineElement(cx, array, i, STRING_TO_JSVAL(js_str), NULL, NULL, JSPROP_ENUMERATE);
+			}
+			strListFree(&list);
+		}
+	}
+	smb_freefilemem(&file);
+	free(filename);
+	return JS_TRUE;
+}
+
+static bool
+set_file_properties(JSContext *cx, JSObject* obj, file_t* f, enum file_detail detail)
+{
+	jsval		val;
+	JSString*	js_str;
+	const uintN flags = JSPROP_ENUMERATE;
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+	if(f->name == NULL
+		|| (js_str = JS_NewStringCopyZ(cx, f->name)) == NULL
+		|| !JS_DefineProperty(cx, obj, "name", STRING_TO_JSVAL(js_str), NULL, NULL, flags))
+		return false;
+
+	if(f->from != NULL
+		&& ((js_str = JS_NewStringCopyZ(cx, f->from)) == NULL
+			|| !JS_DefineProperty(cx, obj, "from", STRING_TO_JSVAL(js_str), NULL, NULL, flags)))
+		return false;
+
+	val = BOOLEAN_TO_JSVAL(f->idx.attr & FILE_ANONYMOUS);
+	if((val == JSVAL_TRUE || detail > file_detail_extdesc)
+		&& !JS_DefineProperty(cx, obj, "anon", val, NULL, NULL, flags))
+		return false;
+
+	if(f->desc != NULL
+		&& ((js_str = JS_NewStringCopyZ(cx, f->desc)) == NULL
+			|| !JS_DefineProperty(cx, obj, "desc", STRING_TO_JSVAL(js_str), NULL, NULL, flags)))
+		return false;
+
+	if(f->extdesc != NULL && *f->extdesc != '\0'
+		&& ((js_str = JS_NewStringCopyZ(cx, f->extdesc)) == NULL
+			|| !JS_DefineProperty(cx, obj, "extdesc", STRING_TO_JSVAL(js_str), NULL, NULL, flags)))
+		return false;
+
+	if(f->cost > 0 || detail > file_detail_extdesc) {
+		val = UINT_TO_JSVAL(f->cost);
+		if(!JS_DefineProperty(cx, obj, "cost", val, NULL, NULL, flags))
+			return false;
+	}
+	val = UINT_TO_JSVAL(f->idx.size);
+	if(!JS_DefineProperty(cx, obj, "size", val, NULL, NULL, flags))
+		return false;
+
+	val = UINT_TO_JSVAL(f->hdr.when_written.time);
+	if(!JS_DefineProperty(cx, obj, "time", val, NULL, NULL, flags))
+		return false;
+	if(f->hdr.when_imported.time > 0 || detail > file_detail_extdesc) {
+		val = UINT_TO_JSVAL(f->hdr.when_imported.time);
+		if(!JS_DefineProperty(cx, obj, "added", val, NULL, NULL, flags))
+			return false;
+	}
+	if(f->hdr.last_downloaded > 0 || detail > file_detail_extdesc) {
+		val = UINT_TO_JSVAL(f->hdr.last_downloaded);
+		if(!JS_DefineProperty(cx, obj, "last_downloaded", val, NULL, NULL, flags))
+			return false;
+	}
+	if(f->hdr.times_downloaded > 0 || detail > file_detail_extdesc) {
+		val = UINT_TO_JSVAL(f->hdr.times_downloaded);
+		if(!JS_DefineProperty(cx, obj, "times_downloaded", val, NULL, NULL, flags))
+			return false;
+	}
+	if(f->file_idx.hash.flags & SMB_HASH_CRC16) {
+		val = UINT_TO_JSVAL(f->file_idx.hash.data.crc16);
+		if(!JS_DefineProperty(cx, obj, "crc16", val, NULL, NULL, flags))
+			return false;
+	}
+	if(f->file_idx.hash.flags & SMB_HASH_CRC32) {
+		val = UINT_TO_JSVAL(f->file_idx.hash.data.crc32);
+		if(!JS_DefineProperty(cx, obj, "crc32", val, NULL, NULL, flags))
+			return false;
+	}
+	if(f->file_idx.hash.flags & SMB_HASH_MD5) {
+		char hex[128];
+		if((js_str = JS_NewStringCopyZ(cx, MD5_hex(hex, f->file_idx.hash.data.md5))) == NULL
+			|| !JS_DefineProperty(cx, obj, "md5", STRING_TO_JSVAL(js_str), NULL, NULL, flags))
+			return false;
+	}
+	if(f->file_idx.hash.flags & SMB_HASH_SHA1) {
+		char hex[128];
+		if((js_str = JS_NewStringCopyZ(cx, SHA1_hex(hex, f->file_idx.hash.data.sha1))) == NULL
+			|| !JS_DefineProperty(cx, obj, "sha1", STRING_TO_JSVAL(js_str), NULL, NULL, flags))
+			return false;
+	}
+	if(f->tags != NULL
+		&& ((js_str = JS_NewStringCopyZ(cx, f->tags)) == NULL
+			|| !JS_DefineProperty(cx, obj, "tags", STRING_TO_JSVAL(js_str), NULL, NULL, flags)))
+		return false;
+
+	return true;
+}
+
+static BOOL
+parse_file_index_properties(JSContext *cx, JSObject* obj, fileidxrec_t* idx)
+{
+	char*		cp = NULL;
+	size_t		cp_sz = 0;
+	jsval		val;
+	const char* prop_name;
+
+	if(JS_GetProperty(cx, obj, prop_name = "name", &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JSVALUE_TO_RASTRING(cx, val, cp, &cp_sz, NULL);
+		HANDLE_PENDING(cx, cp);
+		if(cp==NULL) {
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return FALSE;
+		}
+		SAFECOPY(idx->name, cp);
+	}
+	if(JS_GetProperty(cx, obj, prop_name = "size", &val) && !JSVAL_NULL_OR_VOID(val)) {
+		if(!JS_ValueToECMAUint32(cx, val, &idx->idx.size)) {
+			JS_ReportError(cx, "Error converting adding '%s' property to Uint32", prop_name);
+			return FALSE;
+		}
+	}
+	if(JS_GetProperty(cx, obj, prop_name = "crc16", &val) && !JSVAL_NULL_OR_VOID(val)) {
+		idx->hash.data.crc16 = JSVAL_TO_INT(val);
+		idx->hash.flags |= SMB_HASH_CRC16;
+	}
+	if(JS_GetProperty(cx, obj, prop_name = "crc32", &val) && !JSVAL_NULL_OR_VOID(val)) {
+		if(!JS_ValueToECMAUint32(cx, val, &idx->hash.data.crc32)) {
+			JS_ReportError(cx, "Error converting adding '%s' property to Uint32", prop_name);
+			return FALSE;
+		}
+		idx->hash.flags |= SMB_HASH_CRC32;
+	}
+	if(JS_GetProperty(cx, obj, prop_name = "md5", &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JSVALUE_TO_RASTRING(cx, val, cp, &cp_sz, NULL);
+		HANDLE_PENDING(cx, cp);
+		if(cp==NULL || strlen(cp) != MD5_DIGEST_SIZE * 2) {
+			free(cp);
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return FALSE;
+		}
+		for(int i = 0; i < MD5_DIGEST_SIZE * 2; i += 2) {
+			idx->hash.data.md5[i/2] = HEX_CHAR_TO_INT(*(cp + i)) * 16;
+			idx->hash.data.md5[i/2] += HEX_CHAR_TO_INT(*(cp + i + 1));
+		}
+		idx->hash.flags |= SMB_HASH_MD5;
+	}
+	if(JS_GetProperty(cx, obj, prop_name = "sha1", &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JSVALUE_TO_RASTRING(cx, val, cp, &cp_sz, NULL);
+		HANDLE_PENDING(cx, cp);
+		if(cp==NULL || strlen(cp) != SHA1_DIGEST_SIZE * 2) {
+			free(cp);
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return FALSE;
+		}
+		for(int i = 0; i < SHA1_DIGEST_SIZE * 2; i += 2) {
+			idx->hash.data.sha1[i/2] = HEX_CHAR_TO_INT(*(cp + i)) * 16;
+			idx->hash.data.sha1[i/2] += HEX_CHAR_TO_INT(*(cp + i + 1));
+		}
+		idx->hash.flags |= SMB_HASH_SHA1;
+	}
+	free(cp);
+	return TRUE;
+}
+
+static int
+parse_file_properties(JSContext *cx, JSObject* obj, file_t* file, char** extdesc)
+{
+	char*		cp = NULL;
+	size_t		cp_sz = 0;
+	jsval		val;
+	int result = SMB_ERR_NOT_FOUND;
+
+	const char* prop_name = "name";
+	if(JS_GetProperty(cx, obj, prop_name, &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JSVALUE_TO_RASTRING(cx, val, cp, &cp_sz, NULL);
+		HANDLE_PENDING(cx, cp);
+		if(cp==NULL) {
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return SMB_FAILURE;
+		}
+		if((result = smb_new_hfield_str(file, SMB_FILENAME, cp)) != SMB_SUCCESS) {
+			free(cp);
+			JS_ReportError(cx, "Error %d adding '%s' property to file object", result, prop_name);
+			return result;
+		}
+	}
+
+	prop_name = "from";
+	if(JS_GetProperty(cx, obj, prop_name, &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JSVALUE_TO_RASTRING(cx, val, cp, &cp_sz, NULL);
+		HANDLE_PENDING(cx, cp);
+		if(cp==NULL) {
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return SMB_FAILURE;
+		}
+		if((result = smb_new_hfield_str(file, SMB_FILEUPLOADER, cp)) != SMB_SUCCESS) {
+			free(cp);
+			JS_ReportError(cx, "Error %d adding '%s' property to file object", result, prop_name);
+			return result;
+		}
+	}
+
+	prop_name = "desc";
+	if(JS_GetProperty(cx, obj, prop_name, &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JSVALUE_TO_RASTRING(cx, val, cp, &cp_sz, NULL);
+		HANDLE_PENDING(cx, cp);
+		if(cp==NULL) {
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return SMB_FAILURE;
+		}
+		if((result = smb_new_hfield_str(file, SMB_FILEDESC, cp)) != SMB_SUCCESS) {
+			free(cp);
+			JS_ReportError(cx, "Error %d adding '%s' property to file object", result, prop_name);
+			return result;
+		}
+	}
+	prop_name = "extdesc";
+	if(extdesc != NULL && JS_GetProperty(cx, obj, prop_name, &val) && !JSVAL_NULL_OR_VOID(val)) {
+		FREE_AND_NULL(*extdesc);
+		JSVALUE_TO_MSTRING(cx, val, *extdesc, NULL);
+		HANDLE_PENDING(cx, *extdesc);
+		if(*extdesc == NULL) {
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return SMB_ERR_MEM;
+		}
+		truncsp(*extdesc);
+	}
+	prop_name = "tags";
+	if(JS_GetProperty(cx, obj, prop_name, &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JSVALUE_TO_RASTRING(cx, val, cp, &cp_sz, NULL);
+		HANDLE_PENDING(cx, cp);
+		if(cp==NULL) {
+			JS_ReportError(cx, "Invalid '%s' string in file object", prop_name);
+			return SMB_FAILURE;
+		}
+		if((result = smb_new_hfield_str(file, SMB_TAGS, cp)) != SMB_SUCCESS) {
+			free(cp);
+			JS_ReportError(cx, "Error %d adding '%s' property to file object", result, prop_name);
+			return result;
+		}
+	}
+	prop_name = "cost";
+	if(JS_GetProperty(cx, obj, prop_name, &val) && !JSVAL_NULL_OR_VOID(val)) {
+		uint32_t cost = 0;
+		if(!JS_ValueToECMAUint32(cx, val, &cost)) {
+			JS_ReportError(cx, "Error converting adding '%s' property to Uint32", prop_name);
+			return SMB_FAILURE;
+		}
+		if((result = smb_new_hfield(file, SMB_COST, sizeof(cost), &cost)) != SMB_SUCCESS) {
+			free(cp);
+			JS_ReportError(cx, "Error %d adding '%s' property to file object", result, prop_name);
+			return result;
+		}
+	}
+
+	if(JS_GetProperty(cx, obj, "anon", &val) && val == JSVAL_TRUE)
+		file->hdr.attr |= FILE_ANONYMOUS;
+
+	if(!parse_file_index_properties(cx, obj, &file->file_idx))
+		result = SMB_FAILURE;
+
+	free(cp);
+	return result;
+}
+
+static JSBool
+js_hash_file(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char		path[MAX_PATH + 1];
+	char*		filename = NULL;
+	enum file_detail detail = file_detail_normal;
+	jsrefcount	rc;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	file_t file;
+	ZERO_VAR(file);
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn]))	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filename, NULL);
+		HANDLE_PENDING(cx, filename);
+		argn++;
+	}
+	if(filename == NULL) {
+		JS_ReportError(cx, "No filename argument");
+		return JS_TRUE;
+	}
+	rc=JS_SUSPENDREQUEST(cx);
+	if(getfname(filename) != filename)
+		SAFECOPY(path, filename);
+	else {
+		file.name = filename;
+		// read index record, if it exists (for altpath)
+		smb_findfile(&p->smb, filename, &file);
+		getfilepath(scfg, &file, path);
+	}
+	off_t size = flength(path);
+	if(size == -1)
+		JS_ReportError(cx, "File does not exist: %s", path);
+	else {
+		file.idx.size = (uint32_t)size;
+		if((p->smb_result = smb_hashfile(path, size, &file.file_idx.hash.data)) > 0) {
+			file.file_idx.hash.flags = p->smb_result;
+			file.hdr.when_written.time = (uint32_t)fdate(path);
+			JSObject* fobj;
+			if((fobj = JS_NewObject(cx, NULL, NULL, obj)) == NULL)
+				JS_ReportError(cx, "object allocation failure, line %d", __LINE__);
+			else {
+				set_file_properties(cx, fobj, &file, detail);
+				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(fobj));
+			}
+		}
+	}
+	JS_RESUMEREQUEST(cx, rc);
+	free(filename);
+	smb_freefilemem(&file);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_get_file(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		filename = NULL;
+	enum file_detail detail = file_detail_normal;
+	jsrefcount	rc;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	file_t file;
+	ZERO_VAR(file);
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn]))	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filename, NULL);
+		HANDLE_PENDING(cx, filename);
+		if(filename == NULL)
+			return JS_FALSE;
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_OBJECT(argv[argn])) {
+		if(!parse_file_index_properties(cx, JSVAL_TO_OBJECT(argv[argn]), &file.file_idx))
+			return JS_TRUE;
+		free(filename);
+		filename = strdup(file.file_idx.name);
+		argn++;
+	}
+	else if(filename == NULL)
+		return JS_TRUE;
+	if(argn < argc && JSVAL_IS_NUMBER(argv[argn])) {
+		detail = JSVAL_TO_INT(argv[argn]);
+		argn++;
+	}
+	rc=JS_SUSPENDREQUEST(cx);
+	if((p->smb_result = smb_findfile(&p->smb, filename, &file)) == SMB_SUCCESS
+		&& (p->smb_result = smb_getfile(&p->smb, &file, detail)) == SMB_SUCCESS) {
+		JSObject* fobj;
+		if((fobj = JS_NewObject(cx, NULL, NULL, obj)) == NULL)
+			JS_ReportError(cx, "object allocation failure, line %d", __LINE__);
+		else {
+			set_file_properties(cx, fobj, &file, detail);
+		    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(fobj));
+		}
+	}
+	JS_RESUMEREQUEST(cx, rc);
+	free(filename);
+	smb_freefilemem(&file);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_get_file_list(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	time_t		t = 0;
+	char*		filespec = NULL;
+	enum file_detail detail = file_detail_normal;
+	enum file_sort sort = FILE_SORT_NAME_A;
+	jsrefcount	rc;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	if(p->smb.dirnum != INVALID_DIR)
+		sort = scfg->dir[p->smb.dirnum]->sort;
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn]))	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filespec, NULL);
+		HANDLE_PENDING(cx, filespec);
+		if(filespec == NULL)
+			return JS_FALSE;
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_NUMBER(argv[argn])) {
+		detail = JSVAL_TO_INT(argv[argn]);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_NUMBER(argv[argn]))	{
+		t = JSVAL_TO_INT(argv[argn]);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_BOOLEAN(argv[argn])) {
+		if(argv[argn++] == JSVAL_FALSE)
+			sort = FILE_SORT_NATURAL;
+		else if(argn < argc && JSVAL_IS_NUMBER(argv[argn])) {
+			sort = JSVAL_TO_INT(argv[argn]);
+			argn++;
+		}
+	}
+
+	rc=JS_SUSPENDREQUEST(cx);
+	JSObject* array;
+    if((array = JS_NewArrayObject(cx, 0, NULL)) == NULL) {
+		free(filespec);
+		JS_RESUMEREQUEST(cx, rc);
+		JS_ReportError(cx, "JS_NewArrayObject failure");
+		return JS_FALSE;
+	}
+
+	size_t file_count;
+	file_t* file_list = loadfiles(&p->smb, filespec, t, detail, sort, &file_count);
+	if(file_list != NULL) {
+		for(size_t i = 0; i < file_count; i++) {
+			JSObject* fobj;
+			if((fobj = JS_NewObject(cx, NULL, NULL, array)) == NULL) {
+				JS_ReportError(cx, "object allocation failure, line %d", __LINE__);
+				break;
+			}
+			set_file_properties(cx, fobj, &file_list[i], detail);
+			JS_DefineElement(cx, array, i, OBJECT_TO_JSVAL(fobj), NULL, NULL, JSPROP_ENUMERATE);
+		}
+		freefiles(file_list, file_count);
+	}
+    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
+	JS_RESUMEREQUEST(cx, rc);
+	free(filespec);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_get_file_names(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	time_t		t = 0;
+	char*		filespec = NULL;
+	enum file_sort sort = FILE_SORT_NAME_A;
+	jsrefcount	rc;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	if(p->smb.dirnum != INVALID_DIR)
+		sort = scfg->dir[p->smb.dirnum]->sort;
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn]))	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filespec, NULL);
+		HANDLE_PENDING(cx, filespec);
+		if(filespec == NULL)
+			return JS_FALSE;
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_NUMBER(argv[argn]))	{
+		t = JSVAL_TO_INT(argv[argn]);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_BOOLEAN(argv[argn])) {
+		if(argv[argn++] == JSVAL_FALSE)
+			sort = FILE_SORT_NATURAL;
+		else if(argn < argc && JSVAL_IS_NUMBER(argv[argn])) {
+			sort = JSVAL_TO_INT(argv[argn]);
+			argn++;
+		}
+	}
+
+	rc=JS_SUSPENDREQUEST(cx);
+	JSObject* array;
+    if((array = JS_NewArrayObject(cx, 0, NULL)) == NULL) {
+		free(filespec);
+		JS_RESUMEREQUEST(cx, rc);
+		JS_ReportError(cx, "JS_NewArrayObject failure");
+		return JS_FALSE;
+	}
+
+	str_list_t file_list = loadfilenames(&p->smb, filespec, t, sort, NULL);
+	if(file_list != NULL) {
+		for(size_t i = 0; file_list[i] != NULL; i++) {
+			JSString* js_str;
+			if((js_str = JS_NewStringCopyZ(cx, file_list[i]))==NULL)
+				return JS_FALSE;
+			JS_DefineElement(cx, array, i, STRING_TO_JSVAL(js_str), NULL, NULL, JSPROP_ENUMERATE);
+		}
+		strListFree(&file_list);
+	}
+    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
+	JS_RESUMEREQUEST(cx, rc);
+	free(filespec);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_get_file_name(JSContext *cx, uintN argc, jsval *arglist)
+{
+	jsval*		argv = JS_ARGV(cx, arglist);
+	char*		filepath = NULL;
+	char		filename[SMB_FILEIDX_NAMELEN + 1] = "";
+
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+
+ 	if(!js_argc(cx, argc, 1))
+		return JS_FALSE;
+
+	uintN argn = 0;
+	JSVALUE_TO_MSTRING(cx, argv[argn], filepath, NULL);
+	HANDLE_PENDING(cx, filepath);
+	JSString* js_str;
+	if((js_str = JS_NewStringCopyZ(cx, smb_fileidxname(getfname(filepath), filename, sizeof(filename)))) != NULL)
+		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_get_file_path(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		filename = NULL;
+	jsrefcount	rc;
+	file_t file;
+
+	ZERO_VAR(file);
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn]))	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filename, NULL);
+		HANDLE_PENDING(cx, filename);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_OBJECT(argv[argn])) {
+		if(!parse_file_index_properties(cx, JSVAL_TO_OBJECT(argv[argn]), &file.file_idx))
+			return JS_TRUE;
+		free(filename);
+		filename = strdup(file.file_idx.name);
+		argn++;
+	}
+	else if(filename == NULL)
+		return JS_TRUE;
+
+	rc=JS_SUSPENDREQUEST(cx);
+	if((p->smb_result = smb_loadfile(&p->smb, filename, &file, file_detail_index)) == SMB_SUCCESS) {
+		char path[MAX_PATH + 1];
+		JSString* js_str;
+		if((js_str = JS_NewStringCopyZ(cx, getfilepath(scfg, &file, path))) != NULL)
+			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
+		smb_freefilemem(&file);
+	}
+	JS_RESUMEREQUEST(cx, rc);
+	free(filename);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_get_file_size(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		filename = NULL;
+	jsrefcount	rc;
+	file_t	file;
+
+	ZERO_VAR(file);
+	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn]))	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filename, NULL);
+		HANDLE_PENDING(cx, filename);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_OBJECT(argv[argn])) {
+		if(!parse_file_index_properties(cx, JSVAL_TO_OBJECT(argv[argn]), &file.file_idx))
+			return JS_TRUE;
+		free(filename);
+		filename = strdup(file.file_idx.name);
+		argn++;
+	}
+	else if(filename == NULL)
+		return JS_TRUE;
+
+	rc=JS_SUSPENDREQUEST(cx);
+	if((p->smb_result = smb_loadfile(&p->smb, filename, &file, file_detail_index)) == SMB_SUCCESS) {
+		char path[MAX_PATH + 1];
+		getfilepath(scfg, &file, path);
+	    JS_SET_RVAL(cx, arglist, DOUBLE_TO_JSVAL((jsdouble)getfilesize(scfg, &file)));
+		smb_freefilemem(&file);
+	}
+	JS_RESUMEREQUEST(cx, rc);
+	free(filename);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_get_file_time(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		filename = NULL;
+	jsrefcount	rc;
+	file_t file;
+
+	ZERO_VAR(file);
+	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_STRING(argv[argn]))	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], filename, NULL);
+		HANDLE_PENDING(cx, filename);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_OBJECT(argv[argn])) {
+		if(!parse_file_index_properties(cx, JSVAL_TO_OBJECT(argv[argn]), &file.file_idx))
+			return JS_TRUE;
+		free(filename);
+		filename = strdup(file.file_idx.name);
+		argn++;
+	}
+	else if(filename == NULL)
+		return JS_TRUE;
+
+	rc=JS_SUSPENDREQUEST(cx);
+	if((p->smb_result = smb_loadfile(&p->smb, filename, &file, file_detail_index)) == SMB_SUCCESS) {
+		char path[MAX_PATH + 1];
+		getfilepath(scfg, &file, path);
+	    JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL((uint32)getfiletime(scfg, &file)));
+		smb_freefilemem(&file);
+	}
+	JS_RESUMEREQUEST(cx, rc);
+	free(filename);
+
+	return JS_TRUE;
+}
+
+static void get_diz(scfg_t* scfg, file_t* file, char** extdesc)
+{
+	char diz_fpath[MAX_PATH + 1];
+	if(extract_diz(scfg, file, /* diz_fnames: */NULL, diz_fpath, sizeof(diz_fpath))) {
+		char extbuf[LEN_EXTDESC + 1] = "";
+		str_list_t lines = read_diz(diz_fpath, /* max_line_len: */80);
+		if(lines != NULL) {
+			format_diz(lines, extbuf, sizeof(extbuf), /* allow_ansi: */false);
+			strListFree(&lines);
+			free(*extdesc);
+			*extdesc = strdup(extbuf);
+			if(file->desc == NULL)
+				smb_new_hfield_str(file, SMB_FILEDESC, prep_file_desc(extbuf, extbuf));
+		}
+		(void)remove(diz_fpath);
+	}
+}
+
+static JSBool
+js_add_file(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		extdesc = NULL;
+	file_t	file;
+	bool		use_diz_always = false;
+	jsrefcount	rc;
+
+	ZERO_VAR(file);
+	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	uintN argn = 0;
+	if(argn < argc && JSVAL_IS_OBJECT(argv[argn])) {
+		p->smb_result = parse_file_properties(cx, JSVAL_TO_OBJECT(argv[argn]), &file, &extdesc);
+		if(p->smb_result != SMB_SUCCESS)
+			return JS_TRUE;
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_BOOLEAN(argv[argn])) {
+		use_diz_always = JSVAL_TO_BOOLEAN(argv[argn]);
+		argn++;
+	}
+
+	file.dir = p->smb.dirnum;
+	rc=JS_SUSPENDREQUEST(cx);
+	if(file.name != NULL) {
+		if((extdesc == NULL	|| use_diz_always == true)
+			&& file.dir < scfg->total_dirs
+			&& (scfg->dir[file.dir]->misc & DIR_DIZ)) {
+			get_diz(scfg, &file, &extdesc);
+		}
+		char fpath[MAX_PATH + 1];
+		getfilepath(scfg, &file, fpath);
+		p->smb_result = smb_addfile(&p->smb, &file, SMB_SELFPACK, extdesc, fpath);
+		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(p->smb_result == SMB_SUCCESS));
+	}
+	JS_RESUMEREQUEST(cx, rc);
+	smb_freefilemem(&file);
+	free(extdesc);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_update_file(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	file_t	file;
+	char*		filename = NULL;
+	JSObject*	fileobj = NULL;
+	bool		use_diz_always = false;
+	jsrefcount	rc;
+
+	ZERO_VAR(file);
+	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	uintN argn = 0;
+	if(argn < argc) {
+		JSVALUE_TO_MSTRING(cx, argv[argn], filename, NULL);
+		HANDLE_PENDING(cx, filename);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_OBJECT(argv[argn])) {
+		fileobj = JSVAL_TO_OBJECT(argv[argn]);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_BOOLEAN(argv[argn])) {
+		use_diz_always = JSVAL_TO_BOOLEAN(argv[argn]);
+		argn++;
+	}
+
+	JSBool result = JS_TRUE;
+	char* extdesc = NULL;
+	rc=JS_SUSPENDREQUEST(cx);
+	if(filename != NULL && fileobj != NULL
+		&& (p->smb_result = smb_loadfile(&p->smb, filename, &file, file_detail_extdesc)) == SMB_SUCCESS) {
+		p->smb_result = parse_file_properties(cx, fileobj, &file, &extdesc);
+		if((extdesc == NULL	|| use_diz_always == true)
+			&& file.dir < scfg->total_dirs
+			&& (scfg->dir[file.dir]->misc & DIR_DIZ)) {
+			get_diz(scfg, &file, &extdesc);
+		}
+		if(p->smb_result == SMB_SUCCESS) {
+			char orgfname[MAX_PATH + 1];
+			char newfname[MAX_PATH + 1];
+			getfilepath(scfg, &file, newfname);
+			SAFECOPY(orgfname, newfname);
+			*getfname(orgfname) = '\0';
+			SAFECAT(orgfname, filename);
+			if(strcmp(orgfname, newfname) != 0 && fexistcase(orgfname) && rename(orgfname, newfname) != 0) {
+				JS_ReportError(cx, "%d renaming '%s' to '%s'", errno, orgfname, newfname);
+				result = JS_FALSE;
+				p->smb_result = SMB_ERR_RENAME;
+			} else {
+				if(file.extdesc != NULL)
+					truncsp(file.extdesc);
+				if(strcmp(extdesc ? extdesc : "", file.extdesc ? file.extdesc : "") == 0)
+					p->smb_result = smb_putfile(&p->smb, &file);
+				else {
+					if((p->smb_result = smb_removefile(&p->smb, &file)) == SMB_SUCCESS)
+						p->smb_result = smb_addfile(&p->smb, &file, SMB_SELFPACK, extdesc, newfname);
+				}
+			}
+		}
+		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(p->smb_result == SMB_SUCCESS));
+	}
+	JS_RESUMEREQUEST(cx, rc);
+	smb_freefilemem(&file);
+	free(filename);
+	free(extdesc);
+
+	return result;
+}
+
+static JSBool
+js_renew_file(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		fname = NULL;
+	jsrefcount	rc;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	uintN argn = 0;
+	if(argn < argc) {
+		JSVALUE_TO_MSTRING(cx, argv[argn], fname, NULL);
+		HANDLE_PENDING(cx, fname);
+		argn++;
+	}
+	if(fname == NULL)
+		return JS_TRUE;
+
+	rc=JS_SUSPENDREQUEST(cx);
+	file_t file;
+	if((p->smb_result = smb_loadfile(&p->smb, fname, &file, file_detail_index)) == SMB_SUCCESS) {
+		char path[MAX_PATH + 1];
+		p->smb_result = smb_renewfile(&p->smb, &file, SMB_SELFPACK, getfilepath(scfg, &file, path));
+		smb_freefilemem(&file);
+	}
+	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(p->smb_result == SMB_SUCCESS));
+	JS_RESUMEREQUEST(cx, rc);
+	free(fname);
+
+	return JS_TRUE;
+}
+
+static JSBool
+js_remove_file(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj = JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv = JS_ARGV(cx, arglist);
+	private_t*	p;
+	char*		fname = NULL;
+	bool		delfile = false;
+	jsrefcount	rc;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
+
+	scfg_t* scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+	if(scfg == NULL) {
+		JS_ReportError(cx, "JS_GetRuntimePrivate returned NULL");
+		return JS_FALSE;
+	}
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL)
+		return JS_FALSE;
+
+	if(!SMB_IS_OPEN(&(p->smb))) {
+		JS_ReportError(cx, "FileBase is not open");
+		return JS_FALSE;
+	}
+
+	uintN argn = 0;
+	if(argn < argc)	{
+		JSVALUE_TO_MSTRING(cx, argv[argn], fname, NULL);
+		HANDLE_PENDING(cx, fname);
+		argn++;
+	}
+	if(argn < argc && JSVAL_IS_BOOLEAN(argv[argn])) {
+		delfile = JSVAL_TO_BOOLEAN(argv[argn]);
+		argn++;
+	}
+	if(fname == NULL)
+		return JS_TRUE;
+
+	JSBool result = JS_TRUE;
+	rc=JS_SUSPENDREQUEST(cx);
+	file_t file;
+	if((p->smb_result = smb_loadfile(&p->smb, fname, &file, file_detail_index)) == SMB_SUCCESS) {
+		char path[MAX_PATH + 1];
+		if(delfile && remove(getfilepath(scfg, &file, path)) != 0) {
+			JS_ReportError(cx, "%d removing '%s'", errno, path);
+			p->smb_result = SMB_ERR_DELETE;
+			result = JS_FALSE;
+		} else
+			p->smb_result = smb_removefile(&p->smb, &file);
+		smb_freefilemem(&file);
+	}
+	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(p->smb_result == SMB_SUCCESS));
+	JS_RESUMEREQUEST(cx, rc);
+	free(fname);
+
+	return result;
+}
+
+/* FileBase Object Properties */
+enum {
+	 FB_PROP_LAST_ERROR
+	,FB_PROP_FILE
+	,FB_PROP_DEBUG
+	,FB_PROP_RETRY_TIME
+	,FB_PROP_RETRY_DELAY
+	,FB_PROP_FIRST_FILE		/* first file number */
+	,FB_PROP_LAST_FILE		/* last file number */
+	,FB_PROP_LAST_FILE_TIME	/* last file index time */
+	,FB_PROP_FILES 			/* total files */
+	,FB_PROP_UPDATE_TIME
+    ,FB_PROP_MAX_FILES		/* Maximum number of file to keep in dir */
+    ,FB_PROP_MAX_AGE		/* Maximum age of file to keep in dir (in days) */
+	,FB_PROP_ATTR			/* Attributes for this file base (SMB_HYPER,etc) */
+	,FB_PROP_DIRNUM			/* Directory number */
+	,FB_PROP_IS_OPEN
+	,FB_PROP_STATUS			/* Last SMBLIB returned status value (e.g. retval) */
+};
+
+static JSBool js_filebase_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
+{
+	time32_t t;
+	jsval idval;
+    jsint       tiny;
+	private_t*	p;
+
+	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_filebase_class))==NULL) {
+		return JS_FALSE;
+	}
+
+    JS_IdToValue(cx, id, &idval);
+    tiny = JSVAL_TO_INT(idval);
+
+	switch(tiny) {
+		case FB_PROP_RETRY_TIME:
+			if(!JS_ValueToInt32(cx,*vp,(int32*)&(p->smb).retry_time))
+				return JS_FALSE;
+			break;
+		case FB_PROP_RETRY_DELAY:
+			if(!JS_ValueToInt32(cx,*vp,(int32*)&(p->smb).retry_delay))
+				return JS_FALSE;
+			break;
+		case FB_PROP_UPDATE_TIME:
+			if(!JS_ValueToInt32(cx, *vp, (int32*)&t))
+				return JS_FALSE;
+			update_newfiletime(&(p->smb), t);
+			break;
+	}
+
+	return JS_TRUE;
+}
+
+static JSBool js_filebase_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+	jsval idval;
+	char*		s=NULL;
+	JSString*	js_str;
+    jsint       tiny;
+	idxrec_t	idx;
+	private_t*	p;
+	jsrefcount	rc;
+
+	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL)
+		return JS_FALSE;
+
+    JS_IdToValue(cx, id, &idval);
+    tiny = JSVAL_TO_INT(idval);
+
+	switch(tiny) {
+		case FB_PROP_FILE:
+			s=p->smb.file;
+			break;
+		case FB_PROP_LAST_ERROR:
+			s=p->smb.last_error;
+			break;
+		case FB_PROP_STATUS:
+			*vp = INT_TO_JSVAL(p->smb_result);
+			break;
+		case FB_PROP_RETRY_TIME:
+			*vp = INT_TO_JSVAL(p->smb.retry_time);
+			break;
+		case FB_PROP_RETRY_DELAY:
+			*vp = INT_TO_JSVAL(p->smb.retry_delay);
+			break;
+		case FB_PROP_FIRST_FILE:
+			rc=JS_SUSPENDREQUEST(cx);
+			memset(&idx,0,sizeof(idx));
+			smb_getfirstidx(&(p->smb),&idx);
+			JS_RESUMEREQUEST(cx, rc);
+			*vp=UINT_TO_JSVAL(idx.number);
+			break;
+		case FB_PROP_LAST_FILE:
+			rc=JS_SUSPENDREQUEST(cx);
+			smb_getstatus(&(p->smb));
+			JS_RESUMEREQUEST(cx, rc);
+			*vp=UINT_TO_JSVAL(p->smb.status.last_file);
+			break;
+		case FB_PROP_LAST_FILE_TIME:
+			rc=JS_SUSPENDREQUEST(cx);
+			*vp = UINT_TO_JSVAL((uint32_t)lastfiletime(&p->smb));
+			JS_RESUMEREQUEST(cx, rc);
+			break;
+		case FB_PROP_FILES:
+			rc=JS_SUSPENDREQUEST(cx);
+			smb_getstatus(&(p->smb));
+			JS_RESUMEREQUEST(cx, rc);
+			*vp=UINT_TO_JSVAL(p->smb.status.total_files);
+			break;
+		case FB_PROP_UPDATE_TIME:
+			*vp = UINT_TO_JSVAL((uint32_t)newfiletime(&p->smb));
+			break;
+		case FB_PROP_MAX_FILES:
+			*vp=UINT_TO_JSVAL(p->smb.status.max_files);
+			break;
+		case FB_PROP_MAX_AGE:
+			*vp=UINT_TO_JSVAL(p->smb.status.max_age);
+			break;
+		case FB_PROP_ATTR:
+			*vp=UINT_TO_JSVAL(p->smb.status.attr);
+			break;
+		case FB_PROP_DIRNUM:
+			*vp = INT_TO_JSVAL(p->smb.dirnum);
+			break;
+		case FB_PROP_IS_OPEN:
+			*vp = BOOLEAN_TO_JSVAL(SMB_IS_OPEN(&(p->smb)));
+			break;
+	}
+
+	if(s!=NULL) {
+		if((js_str=JS_NewStringCopyZ(cx, s))==NULL)
+			return JS_FALSE;
+		*vp = STRING_TO_JSVAL(js_str);
+	}
+
+	return JS_TRUE;
+}
+
+#define FB_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY
+
+static jsSyncPropertySpec js_filebase_properties[] = {
+/*		 name				,tinyid					,flags,				ver	*/
+
+	{	"error"				,FB_PROP_LAST_ERROR		,FB_PROP_FLAGS,		31900 },
+	{	"last_error"		,FB_PROP_LAST_ERROR		,JSPROP_READONLY,	31900 },	/* alias */
+	{	"status"			,FB_PROP_STATUS			,FB_PROP_FLAGS,		31900 },
+	{	"file"				,FB_PROP_FILE			,FB_PROP_FLAGS,		31900 },
+	{	"debug"				,FB_PROP_DEBUG			,0,					31900 },
+	{	"retry_time"		,FB_PROP_RETRY_TIME		,JSPROP_ENUMERATE,	31900 },
+	{	"retry_delay"		,FB_PROP_RETRY_DELAY	,JSPROP_ENUMERATE,	31900 },
+	{	"first_file"		,FB_PROP_FIRST_FILE		,FB_PROP_FLAGS,		31900 },
+	{	"last_file"			,FB_PROP_LAST_FILE		,FB_PROP_FLAGS,		31900 },
+	{	"last_file_time"	,FB_PROP_LAST_FILE_TIME	,FB_PROP_FLAGS,		31900 },
+	{	"files"				,FB_PROP_FILES			,FB_PROP_FLAGS,		31900 },
+	{	"update_time"		,FB_PROP_UPDATE_TIME	,JSPROP_ENUMERATE,	31900 },
+	{	"max_files"			,FB_PROP_MAX_FILES  	,FB_PROP_FLAGS,		31900 },
+	{	"max_age"			,FB_PROP_MAX_AGE   		,FB_PROP_FLAGS,		31900 },
+	{	"attributes"		,FB_PROP_ATTR			,FB_PROP_FLAGS,		31900 },
+	{	"dirnum"			,FB_PROP_DIRNUM			,FB_PROP_FLAGS,		31900 },
+	{	"is_open"			,FB_PROP_IS_OPEN		,FB_PROP_FLAGS,		31900 },
+	{0}
+};
+
+#ifdef BUILD_JSDOCS
+static char* filebase_prop_desc[] = {
+
+	 "last occurred file base error - <small>READ ONLY</small>"
+	,"return value of last <i>SMB Library</i> function call - <small>READ ONLY</small>"
+	,"base path and filename of file base - <small>READ ONLY</small>"
+	,"file base open/lock retry timeout (in seconds)"
+	,"delay between file base open/lock retries (in milliseconds)"
+	,"first file number - <small>READ ONLY</small>"
+	,"last file number - <small>READ ONLY</small>"
+	,"timestamp of last file - <small>READ ONLY</small>"
+	,"total number of files - <small>READ ONLY</small>"
+	,"timestamp of file base index (only writable when file base is closed)"
+	,"maximum number of files before expiration - <small>READ ONLY</small>"
+	,"maximum age (in days) of files to store - <small>READ ONLY</small>"
+	,"file base attributes - <small>READ ONLY</small>"
+	,"directory number (0-based, -1 if invalid) - <small>READ ONLY</small>"
+	,"<i>true</i> if the file base has been opened successfully - <small>READ ONLY</small>"
+	,NULL
+};
+#endif
+
+static jsSyncMethodSpec js_filebase_functions[] = {
+	{"open",			js_open,			0, JSTYPE_BOOLEAN
+		,JSDOCSTR("")
+		,JSDOCSTR("open file base")
+		,31900
+	},
+	{"close",			js_close,			0, JSTYPE_BOOLEAN
+		,JSDOCSTR("")
+		,JSDOCSTR("close file base (if open)")
+		,31900
+	},
+	{"get",				js_get_file,		2, JSTYPE_OBJECT
+		,JSDOCSTR("filename or file-meta-object [,detail=FileBase.DETAIL.NORM]")
+		,JSDOCSTR("get a file metadata object")
+		,31900
+	},
+	{"get_list",		js_get_file_list,	4, JSTYPE_ARRAY
+		,JSDOCSTR("[filespec] [,detail=FileBase.DETAIL.NORM] [,since-time=0] [,sort=true [,order]]")
+		,JSDOCSTR("get a list (array) of file metadata objects"
+			", the default sort order is the sysop-configured order or <tt>FileBase.SORT.NAME_AI</tt>"
+			)
+		,31900
+	},
+	{"get_name",		js_get_file_name,	1, JSTYPE_STRING
+		,JSDOCSTR("path/filename")
+		,JSDOCSTR("returns index-formatted (e.g. shortened) version of filename without path (file base does not have to be open)")
+		,31900
+	},
+	{"get_names",		js_get_file_names,	3, JSTYPE_ARRAY
+		,JSDOCSTR("[filespec] [,since-time=0] [,sort=true [,order]]")
+		,JSDOCSTR("get a list of index-formatted (e.g. shortened) filenames (strings) from file base index"
+			", the default sort order is the sysop-configured order or <tt>FileBase.SORT.NAME_A</tt>")
+		,31900
+	},
+	{"get_path",		js_get_file_path,	1, JSTYPE_STRING
+		,JSDOCSTR("filename")
+		,JSDOCSTR("get the full path to the local file")
+		,31900
+	},
+	{"get_size",		js_get_file_size,	1, JSTYPE_NUMBER
+		,JSDOCSTR("filename")
+		,JSDOCSTR("get the size of the local file, in bytes, or -1 if it does not exist")
+		,31900
+	},
+	{"get_time",		js_get_file_time,	1, JSTYPE_NUMBER
+		,JSDOCSTR("filename")
+		,JSDOCSTR("get the modification date/time stamp of the local file")
+		,31900
+	},
+	{"add",				js_add_file,		1, JSTYPE_BOOLEAN
+		,JSDOCSTR("file-meta-object [,use_diz_always=false]")
+		,JSDOCSTR("add a file to the file base")
+		,31900
+	},
+	{"remove",			js_remove_file,		2, JSTYPE_BOOLEAN
+		,JSDOCSTR("filename [,delete=false]")
+		,JSDOCSTR("remove an existing file from the file base and optionally delete file"
+				", may throw exception on errors (e.g. file remove failure)")
+		,31900
+	},
+	{"update",			js_update_file,		3, JSTYPE_BOOLEAN
+		,JSDOCSTR("filename, file-meta-object [,use_diz_always=false]")
+		,JSDOCSTR("update an existing file in the file base"
+				", may throw exception on errors (e.g. file rename failure)")
+		,31900
+	},
+	{"renew",			js_renew_file,		1, JSTYPE_BOOLEAN
+		,JSDOCSTR("filename")
+		,JSDOCSTR("remove and re-add (as new) an existing file in the file base")
+		,31900
+	},
+	{"hash",			js_hash_file,		1, JSTYPE_OBJECT
+		,JSDOCSTR("filename_or_fullpath")
+		,JSDOCSTR("calculate hashes of a file's contents (file base does not have to be open)")
+		,31900
+	},
+	{"dump",			js_dump_file,		1, JSTYPE_ARRAY
+		,JSDOCSTR("filename")
+		,JSDOCSTR("dump file metadata to an array of strings for diagnostic uses")
+		,31900
+	},
+	{0}
+};
+
+static JSBool js_filebase_resolve(JSContext *cx, JSObject *obj, jsid id)
+{
+	char*			name=NULL;
+	JSBool			ret;
+
+	if(id != JSID_VOID && id != JSID_EMPTY) {
+		jsval idval;
+
+		JS_IdToValue(cx, id, &idval);
+		if(JSVAL_IS_STRING(idval)) {
+			JSVALUE_TO_MSTRING(cx, idval, name, NULL);
+			HANDLE_PENDING(cx, name);
+		}
+	}
+
+	ret=js_SyncResolve(cx, obj, name, js_filebase_properties, js_filebase_functions, NULL, 0);
+	if(name)
+		free(name);
+	return ret;
+}
+
+static JSBool js_filebase_enumerate(JSContext *cx, JSObject *obj)
+{
+	return(js_filebase_resolve(cx, obj, JSID_VOID));
+}
+
+JSClass js_filebase_class = {
+     "FileBase"				/* name			*/
+    ,JSCLASS_HAS_PRIVATE	/* flags		*/
+	,JS_PropertyStub		/* addProperty	*/
+	,JS_PropertyStub		/* delProperty	*/
+	,js_filebase_get		/* getProperty	*/
+	,js_filebase_set		/* setProperty	*/
+	,js_filebase_enumerate	/* enumerate	*/
+	,js_filebase_resolve	/* resolve		*/
+	,JS_ConvertStub			/* convert		*/
+	,js_finalize_filebase	/* finalize		*/
+};
+
+/* FileBase Constructor (open file base) */
+static JSBool
+js_filebase_constructor(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject *		obj;
+	jsval *			argv=JS_ARGV(cx, arglist);
+	char*			base = NULL;
+	private_t*		p;
+	scfg_t*			scfg;
+
+	scfg=JS_GetRuntimePrivate(JS_GetRuntime(cx));
+
+	obj=JS_NewObject(cx, &js_filebase_class, NULL, NULL);
+	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj));
+	if((p=(private_t*)malloc(sizeof(private_t)))==NULL) {
+		JS_ReportError(cx,"malloc failed");
+		return JS_FALSE;
+	}
+
+	memset(p,0,sizeof(private_t));
+	p->smb.retry_time=scfg->smb_retry_time;
+
+	JSSTRING_TO_MSTRING(cx, JS_ValueToString(cx, argv[0]), base, NULL);
+	if(JS_IsExceptionPending(cx)) {
+		if(base != NULL)
+			free(base);
+		free(p);
+		return JS_FALSE;
+	}
+	if(base==NULL) {
+		JS_ReportError(cx, "Invalid base parameter");
+		free(p);
+		return JS_FALSE;
+	}
+
+	if(!JS_SetPrivate(cx, obj, p)) {
+		JS_ReportError(cx,"JS_SetPrivate failed");
+		free(p);
+		free(base);
+		return JS_FALSE;
+	}
+
+#ifdef BUILD_JSDOCS
+	js_DescribeSyncObject(cx,obj,"Class used for accessing file databases", 31900);
+	js_DescribeSyncConstructor(cx,obj,"To create a new FileBase object: "
+		"<tt>var filebase = new FileBase('<i>code</i>')</tt><br>"
+		"where <i>code</i> is a directory internal code."
+		);
+	js_CreateArrayOfStrings(cx, obj, "_property_desc_list", filebase_prop_desc, JSPROP_READONLY);
+#endif
+
+	p->smb.dirnum = getdirnum(scfg, base);
+	if(p->smb.dirnum >= 0 && p->smb.dirnum < scfg->total_dirs) {
+		safe_snprintf(p->smb.file, sizeof(p->smb.file), "%s%s"
+			,scfg->dir[p->smb.dirnum]->data_dir, scfg->dir[p->smb.dirnum]->code);
+	} else { /* unknown code */
+		SAFECOPY(p->smb.file, base);
+	}
+
+	free(base);
+	return JS_TRUE;
+}
+
+#ifdef BUILD_JSDOCS
+static char* filebase_detail_prop_desc[] = {
+	 "Include indexed-filenames only",
+	 "Normal level of file detail (e.g. full filenames, minimal meta data)",
+	 "Normal level of file detail plus extended descriptions",
+	 "Maximum file detail, include undefined/null property values",
+	 NULL
+};
+
+static char* filebase_sort_prop_desc[] = {
+	"Natural sort order (same as DATE_A)",
+	"Filename ascending, case insensitive sort order",
+	"Filename descending, case insensitive sort order",
+	"Filename ascending, case sensitive sort order",
+	"Filename descending, case sensitive sort order",
+	"Import date/time ascending sort order",
+	"Import date/time descending sort order",
+	NULL
+};
+#endif
+
+JSObject* DLLCALL js_CreateFileBaseClass(JSContext* cx, JSObject* parent, scfg_t* cfg)
+{
+	JSObject*	obj;
+	JSObject*	constructor;
+	jsval		val;
+
+	obj = JS_InitClass(cx, parent, NULL
+		,&js_filebase_class
+		,js_filebase_constructor
+		,1	/* number of constructor args */
+		,NULL
+		,NULL
+		,NULL, NULL);
+
+	if(JS_GetProperty(cx, parent, js_filebase_class.name, &val) && !JSVAL_NULL_OR_VOID(val)) {
+		JS_ValueToObject(cx, val, &constructor);
+		JSObject* detail = JS_DefineObject(cx, constructor, "DETAIL", NULL, NULL, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+		if(detail != NULL) {
+			JS_DefineProperty(cx, detail, "MIN", INT_TO_JSVAL(file_detail_index), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, detail, "NORM", INT_TO_JSVAL(file_detail_normal), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, detail, "EXTENDED", INT_TO_JSVAL(file_detail_extdesc), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, detail, "MAX", INT_TO_JSVAL(file_detail_extdesc + 1), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+#ifdef BUILD_JSDOCS
+			js_DescribeSyncObject(cx, detail, "Detail level numeric constants", 0);
+			js_CreateArrayOfStrings(cx, detail, "_property_desc_list", filebase_detail_prop_desc, JSPROP_READONLY);
+#endif
+		}
+		JSObject* sort = JS_DefineObject(cx, constructor, "SORT", NULL, NULL, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+		if(sort != NULL) {
+			JS_DefineProperty(cx, sort, "NATURAL", INT_TO_JSVAL(FILE_SORT_NATURAL), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, sort, "NAME_AI", INT_TO_JSVAL(FILE_SORT_NAME_A), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, sort, "NAME_DI", INT_TO_JSVAL(FILE_SORT_NAME_D), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, sort, "NAME_AS", INT_TO_JSVAL(FILE_SORT_NAME_AC), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, sort, "NAME_DS", INT_TO_JSVAL(FILE_SORT_NAME_DC), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, sort, "DATE_A", INT_TO_JSVAL(FILE_SORT_DATE_A), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+			JS_DefineProperty(cx, sort, "DATE_D", INT_TO_JSVAL(FILE_SORT_DATE_D), NULL, NULL
+				, JSPROP_PERMANENT|JSPROP_ENUMERATE|JSPROP_READONLY);
+#ifdef BUILD_JSDOCS
+			js_DescribeSyncObject(cx, sort, "Sort order numeric constants", 0);
+			js_CreateArrayOfStrings(cx, sort, "_property_desc_list", filebase_sort_prop_desc, JSPROP_READONLY);
+#endif
+		}
+	}
+	return obj;
+}
diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c
index 32ac501e28..c48311f123 100644
--- a/src/sbbs3/js_global.c
+++ b/src/sbbs3/js_global.c
@@ -2629,7 +2629,50 @@ js_md5_calc(JSContext* cx, uintN argc, jsval* arglist)
 	free(inbuf);
 
 	if(hex)
-		MD5_hex((BYTE*)outbuf,digest);
+		MD5_hex(outbuf,digest);
+	else
+		b64_encode(outbuf,sizeof(outbuf),(char*)digest,sizeof(digest));
+	JS_RESUMEREQUEST(cx, rc);
+
+	js_str = JS_NewStringCopyZ(cx, outbuf);
+	if(js_str==NULL)
+		return(JS_FALSE);
+
+	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
+	return(JS_TRUE);
+}
+
+static JSBool
+js_sha1_calc(JSContext* cx, uintN argc, jsval* arglist)
+{
+	jsval *argv=JS_ARGV(cx, arglist);
+	BYTE		digest[SHA1_DIGEST_SIZE];
+	JSBool		hex=JS_FALSE;
+	size_t		inbuf_len;
+	char*		inbuf = NULL;
+	char		outbuf[64];
+	JSString*	js_str;
+	jsrefcount	rc;
+
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+
+	if(argc==0 || JSVAL_NULL_OR_VOID(argv[0]))
+		return(JS_TRUE);
+
+	JSVALUE_TO_MSTRING(cx, argv[0], inbuf, &inbuf_len);
+	HANDLE_PENDING(cx, inbuf);
+	if(inbuf==NULL)
+		return(JS_TRUE);
+
+	if(argc>1 && JSVAL_IS_BOOLEAN(argv[1]))
+		hex=JSVAL_TO_BOOLEAN(argv[1]);
+
+	rc=JS_SUSPENDREQUEST(cx);
+	SHA1_calc(digest,inbuf,inbuf_len);
+	free(inbuf);
+
+	if(hex)
+		SHA1_hex(outbuf,digest);
 	else
 		b64_encode(outbuf,sizeof(outbuf),(char*)digest,sizeof(digest));
 	JS_RESUMEREQUEST(cx, rc);
@@ -3603,10 +3646,7 @@ js_wildmatch(JSContext *cx, uintN argc, jsval *arglist)
 		JS_ValueToBoolean(cx, argv[argn++], &path);
 	
 	rc=JS_SUSPENDREQUEST(cx);
-	if(case_sensitive)
-		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(wildmatch(fname, spec, path)));
-	else
-		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(wildmatchi(fname, spec, path)));
+	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(wildmatch(fname, spec, path, case_sensitive)));
 	free(fname);
 	if(spec != spec_def)
 		free(spec);
@@ -5027,6 +5067,10 @@ static jsSyncMethodSpec js_global_functions[] = {
 	,JSDOCSTR("calculate and return 128-bit MD5 digest of text string, result encoded in base64 (default) or hexadecimal")
 	,311
 	},
+	{"sha1_calc",		js_sha1_calc,		1,	JSTYPE_STRING,	JSDOCSTR("text [,hex=false]")
+	,JSDOCSTR("calculate and return 160-bit SHA-1 digest of text string, result encoded in base64 (default) or hexadecimal")
+	,31900
+	},
 	{"gethostbyname",	js_resolve_ip,		1,	JSTYPE_ALIAS },
 	{"resolve_ip",		js_resolve_ip,		1,	JSTYPE_STRING,	JSDOCSTR("hostname [,array=<tt>false</tt>]")
 	,JSDOCSTR("resolve IP address of specified hostname (AKA gethostbyname).  If <i>array</i> is true (added in 3.17), will return "
diff --git a/src/sbbs3/js_internal.c b/src/sbbs3/js_internal.c
index bb10abb702..82f51628ca 100644
--- a/src/sbbs3/js_internal.c
+++ b/src/sbbs3/js_internal.c
@@ -713,7 +713,7 @@ js_setTimeout(JSContext *cx, uintN argc, jsval *arglist)
 	js_callback_t*	cb;
 	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
 	JSFunction *ecb;
-	uint64_t now = xp_timer() * 1000;
+	uint64_t now = (uint64_t)(xp_timer() * 1000);
 	jsdouble timeout;
 
 	if((cb=(js_callback_t*)JS_GetPrivate(cx,obj))==NULL)
@@ -752,7 +752,7 @@ js_setTimeout(JSContext *cx, uintN argc, jsval *arglist)
 	ev->cx = obj;
 	JS_AddObjectRoot(cx, &ev->cx);
 	ev->cb = ecb;
-	ev->data.timeout.end = now + timeout;
+	ev->data.timeout.end = (uint64_t)(now + timeout);
 	ev->id = cb->next_eid++;
 	cb->events = ev;
 
@@ -831,7 +831,7 @@ js_setInterval(JSContext *cx, uintN argc, jsval *arglist)
 	js_callback_t*	cb;
 	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
 	JSFunction *ecb;
-	uint64_t now = xp_timer() * 1000;
+	uint64_t now = (uint64_t)(xp_timer() * 1000);
 	jsdouble period;
 
 	if((cb=(js_callback_t*)JS_GetPrivate(cx,obj))==NULL)
@@ -871,7 +871,7 @@ js_setInterval(JSContext *cx, uintN argc, jsval *arglist)
 	JS_AddObjectRoot(cx, &ev->cx);
 	ev->cb = ecb;
 	ev->data.interval.last = now;
-	ev->data.interval.period = period;
+	ev->data.interval.period =(uint64_t)period;
 	ev->id = cb->next_eid++;
 	cb->events = ev;
 
@@ -1090,7 +1090,7 @@ js_handle_events(JSContext *cx, js_callback_t *cb, volatile int *terminated)
 
 	while (cb->keepGoing && !JS_IsExceptionPending(cx) && cb->events && !*terminated) {
 		timeout = -1;	// Infinity by default...
-		now = xp_timer() * 1000;
+		now = (uint64_t)(xp_timer() * 1000);
 		ev = NULL;
 		tev = NULL;
 		cev = NULL;
@@ -1170,7 +1170,7 @@ js_handle_events(JSContext *cx, js_callback_t *cb, volatile int *terminated)
 						tev = ev;
 					}
 					else {
-						i = ev->data.interval.last + ev->data.interval.period - now;
+						i = (int)(ev->data.interval.last + ev->data.interval.period - now);
 						if (timeout == -1 || i < timeout) {
 							timeout = i;
 							tev = ev;
@@ -1184,7 +1184,7 @@ js_handle_events(JSContext *cx, js_callback_t *cb, volatile int *terminated)
 						tev = ev;
 					}
 					else {
-						i = ev->data.timeout.end - now;
+						i = (int)(ev->data.timeout.end - now);
 						if (timeout == -1 || i < timeout) {
 							timeout = i;
 							tev = ev;
diff --git a/src/sbbs3/js_msgbase.c b/src/sbbs3/js_msgbase.c
index 6780203935..0febc40e85 100644
--- a/src/sbbs3/js_msgbase.c
+++ b/src/sbbs3/js_msgbase.c
@@ -1042,7 +1042,7 @@ static BOOL msg_offset_by_id(private_t* p, char* id, int32_t* offset)
 	if((p->smb_result = smb_getmsgidx_by_msgid(&(p->smb),&msg,id))!=SMB_SUCCESS)
 		return(FALSE);
 
-	*offset = msg.offset;
+	*offset = msg.idx_offset;
 	return(TRUE);
 }
 
@@ -1135,7 +1135,7 @@ js_get_msg_index(JSContext *cx, uintN argc, jsval *arglist)
 			include_votes = JSVAL_TO_BOOLEAN(argv[n]);
 		else if(JSVAL_IS_NUMBER(argv[n])) {
 			if(by_offset) {							/* Get by offset */
-				if(!JS_ValueToInt32(cx, argv[n], (int32*)&msg.offset))
+				if(!JS_ValueToInt32(cx, argv[n], (int32*)&msg.idx_offset))
 					return JS_FALSE;
 			}
 			else {									/* Get by number */
@@ -1167,7 +1167,7 @@ js_get_msg_index(JSContext *cx, uintN argc, jsval *arglist)
 	if((idxobj=JS_NewObject(cx,NULL,proto,obj))==NULL)
 		return JS_TRUE;
 
-	set_msg_idx_properties(cx, idxobj, &msg.idx, msg.offset);
+	set_msg_idx_properties(cx, idxobj, &msg.idx, msg.idx_offset);
 
 	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(idxobj));
 
@@ -1209,7 +1209,7 @@ js_get_index(JSContext *cx, uintN argc, jsval *arglist)
 	}
     JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
 
-	uint32_t total_msgs = index_length / sizeof(*idx);
+	uint32_t total_msgs = (uint32_t)(index_length / sizeof(*idx));
 	if(total_msgs > priv->smb.status.total_msgs)
 		total_msgs = priv->smb.status.total_msgs;
 	if(total_msgs < 1) {
@@ -1381,7 +1381,7 @@ static JSBool js_get_msg_header_resolve(JSContext *cx, JSObject *obj, jsid id)
 	}
 
 	LAZY_UINTEGER("number", p->msg.hdr.number, JSPROP_ENUMERATE);
-	LAZY_UINTEGER("offset", p->msg.offset, JSPROP_ENUMERATE);
+	LAZY_UINTEGER("offset", p->msg.idx_offset, JSPROP_ENUMERATE);
 	LAZY_STRING_TRUNCSP("to",p->msg.to, JSPROP_ENUMERATE);
 	LAZY_STRING_TRUNCSP("from",p->msg.from, JSPROP_ENUMERATE);
 	LAZY_STRING_TRUNCSP("subject",p->msg.subj, JSPROP_ENUMERATE);
@@ -1740,7 +1740,7 @@ js_get_msg_header(JSContext *cx, uintN argc, jsval *arglist)
 	/* Now parse message offset/id and get message */
 	if(n < argc && JSVAL_IS_NUMBER(argv[n])) {
 		if(by_offset) {							/* Get by offset */
-			if(!JS_ValueToInt32(cx,argv[n++],(int32*)&(p->msg).offset)) {
+			if(!JS_ValueToInt32(cx,argv[n++],(int32*)&(p->msg).idx_offset)) {
 				free(p);
 				return JS_FALSE;
 			}
@@ -1884,7 +1884,7 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
 	}
     JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(retobj));
 
-	uint32_t total_msgs = index_length / sizeof(*idx);
+	uint32_t total_msgs = (uint32_t)(index_length / sizeof(*idx));
 	if(total_msgs > priv->smb.status.total_msgs)
 		total_msgs = priv->smb.status.total_msgs;
 	if(total_msgs < 1) {
@@ -2103,7 +2103,7 @@ js_put_msg_header(JSContext *cx, uintN argc, jsval *arglist)
 			by_offset=JSVAL_TO_BOOLEAN(argv[n]);
 		else if(JSVAL_IS_NUMBER(argv[n])) {
 			if(by_offset) {							/* Get by offset */
-				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.offset))
+				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.idx_offset))
 					return JS_FALSE;
 			}
 			else {									/* Get by number */
@@ -2116,7 +2116,7 @@ js_put_msg_header(JSContext *cx, uintN argc, jsval *arglist)
 			rc=JS_SUSPENDREQUEST(cx);
 			if(!msg_offset_by_id(p
 					,cstr
-					,&msg.offset)) {
+					,&msg.idx_offset)) {
 				free(cstr);
 				JS_RESUMEREQUEST(cx, rc);
 				return JS_TRUE;	/* ID not found */
@@ -2139,7 +2139,7 @@ js_put_msg_header(JSContext *cx, uintN argc, jsval *arglist)
 			JS_ReportError(cx, "Message header has 'expanded fields'");
 			return JS_FALSE;
 		}
-		msg.offset = mp->msg.offset;
+		msg.idx_offset = mp->msg.idx_offset;
 	}
 
 	rc=JS_SUSPENDREQUEST(cx);
@@ -2214,7 +2214,7 @@ js_remove_msg(JSContext *cx, uintN argc, jsval *arglist)
 			by_offset=JSVAL_TO_BOOLEAN(argv[n]);
 		else if(JSVAL_IS_NUMBER(argv[n])) {
 			if(by_offset) {							/* Get by offset */
-				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.offset))
+				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.idx_offset))
 					return JS_FALSE;
 			}
 			else {									/* Get by number */
@@ -2232,7 +2232,7 @@ js_remove_msg(JSContext *cx, uintN argc, jsval *arglist)
 			rc=JS_SUSPENDREQUEST(cx);
 			if(!msg_offset_by_id(p
 					,cstr
-					,&msg.offset)) {
+					,&msg.idx_offset)) {
 				free(cstr);
 				JS_RESUMEREQUEST(cx, rc);
 				return JS_TRUE;	/* ID not found */
@@ -2356,7 +2356,7 @@ js_get_msg_body(JSContext *cx, uintN argc, jsval *arglist)
 			by_offset=JSVAL_TO_BOOLEAN(argv[n]);
 		else if(JSVAL_IS_NUMBER(argv[n])) {
 			if(by_offset) {							/* Get by offset */
-				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.offset))
+				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.idx_offset))
 					return JS_FALSE;
 			}
 			else {									/* Get by number */
@@ -2372,7 +2372,7 @@ js_get_msg_body(JSContext *cx, uintN argc, jsval *arglist)
 			rc=JS_SUSPENDREQUEST(cx);
 			if(!msg_offset_by_id(p
 					,cstr
-					,&msg.offset)) {
+					,&msg.idx_offset)) {
 				free(cstr);
 				JS_RESUMEREQUEST(cx, rc);
 				return JS_TRUE;	/* ID not found */
@@ -2470,7 +2470,7 @@ js_get_msg_tail(JSContext *cx, uintN argc, jsval *arglist)
 			by_offset=JSVAL_TO_BOOLEAN(argv[n]);
 		else if(JSVAL_IS_NUMBER(argv[n])) {
 			if(by_offset) {							/* Get by offset */
-				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.offset))
+				if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.idx_offset))
 					return JS_FALSE;
 			}
 			else {									/* Get by number */
@@ -2486,7 +2486,7 @@ js_get_msg_tail(JSContext *cx, uintN argc, jsval *arglist)
 			rc=JS_SUSPENDREQUEST(cx);
 			if(!msg_offset_by_id(p
 					,cstr
-					,&msg.offset)) {
+					,&msg.idx_offset)) {
 				free(cstr);
 				JS_RESUMEREQUEST(cx, rc);
 				return JS_TRUE;	/* ID not found */
diff --git a/src/sbbs3/js_socket.c b/src/sbbs3/js_socket.c
index f7006061a8..f0156521f5 100644
--- a/src/sbbs3/js_socket.c
+++ b/src/sbbs3/js_socket.c
@@ -379,7 +379,7 @@ static int js_socket_sendfilesocket(js_socket_private_t *p, int file, off_t *off
 	int			i;
 
 	if(p->session==-1)
-		return sendfilesocket(p->sock, file, offset, count);
+		return (int)sendfilesocket(p->sock, file, offset, count);
 
 	len=filelength(file);
 
@@ -516,7 +516,7 @@ static ushort js_port(JSContext* cx, jsval val, int type)
 	return(0);
 }
 
-SOCKET DLLCALL js_socket(JSContext *cx, jsval val)
+SOCKET js_socket(JSContext *cx, jsval val)
 {
 	void*		vp;
 	JSClass*	cl;
@@ -536,7 +536,7 @@ SOCKET DLLCALL js_socket(JSContext *cx, jsval val)
 }
 
 #ifdef PREFER_POLL
-size_t DLLCALL js_socket_numsocks(JSContext *cx, jsval val)
+size_t js_socket_numsocks(JSContext *cx, jsval val)
 {
 	js_socket_private_t	*p;
 	JSClass*	cl;
@@ -571,7 +571,7 @@ size_t DLLCALL js_socket_numsocks(JSContext *cx, jsval val)
 	return ret;
 }
 
-size_t DLLCALL js_socket_add(JSContext *cx, jsval val, struct pollfd *fds, short events)
+size_t js_socket_add(JSContext *cx, jsval val, struct pollfd *fds, short events)
 {
 	js_socket_private_t	*p;
 	JSClass*	cl;
@@ -612,7 +612,7 @@ size_t DLLCALL js_socket_add(JSContext *cx, jsval val, struct pollfd *fds, short
 	return ret;
 }
 #else
-SOCKET DLLCALL js_socket_add(JSContext *cx, jsval val, fd_set *fds)
+SOCKET js_socket_add(JSContext *cx, jsval val, fd_set *fds)
 {
 	js_socket_private_t	*p;
 	JSClass*	cl;
@@ -648,7 +648,7 @@ SOCKET DLLCALL js_socket_add(JSContext *cx, jsval val, fd_set *fds)
 	return sock;
 }
 
-BOOL DLLCALL  js_socket_isset(JSContext *cx, jsval val, fd_set *fds)
+BOOL  js_socket_isset(JSContext *cx, jsval val, fd_set *fds)
 {
 	js_socket_private_t	*p;
 	JSClass*	cl;
@@ -685,7 +685,7 @@ BOOL DLLCALL  js_socket_isset(JSContext *cx, jsval val, fd_set *fds)
 	return FALSE;
 }
 
-void DLLCALL js_timeval(JSContext* cx, jsval val, struct timeval* tv)
+void js_timeval(JSContext* cx, jsval val, struct timeval* tv)
 {
 	jsdouble jsd;
 
@@ -700,7 +700,7 @@ void DLLCALL js_timeval(JSContext* cx, jsval val, struct timeval* tv)
 }
 #endif
 
-int DLLCALL js_polltimeout(JSContext* cx, jsval val)
+int js_polltimeout(JSContext* cx, jsval val)
 {
 	jsdouble jsd;
 
@@ -709,7 +709,7 @@ int DLLCALL js_polltimeout(JSContext* cx, jsval val)
 
 	if(JSVAL_IS_DOUBLE(val)) {
 		if(JS_ValueToNumber(cx,val,&jsd))
-			return jsd * 1000;
+			return (int)(jsd * 1000);
 	}
 
 	return 0;
@@ -2795,7 +2795,7 @@ static BOOL js_DefineSocketOptionsArray(JSContext *cx, JSObject *obj, int type)
 
 /* Socket Constructor (creates socket descriptor) */
 
-JSObject* DLLCALL js_CreateSocketObjectWithoutParent(JSContext* cx, SOCKET sock, CRYPT_CONTEXT session)
+JSObject* js_CreateSocketObjectWithoutParent(JSContext* cx, SOCKET sock, CRYPT_CONTEXT session)
 {
 	JSObject*	obj;
 	js_socket_private_t*	p;
@@ -3513,7 +3513,7 @@ js_socket_constructor(JSContext *cx, uintN argc, jsval *arglist)
 	return(JS_TRUE);
 }
 
-JSObject* DLLCALL js_CreateSocketClass(JSContext* cx, JSObject* parent)
+JSObject* js_CreateSocketClass(JSContext* cx, JSObject* parent)
 {
 	JSObject*	sockobj;
 	JSObject*	sockproto;
@@ -3563,7 +3563,7 @@ JSObject* DLLCALL js_CreateSocketClass(JSContext* cx, JSObject* parent)
 	return(sockobj);
 }
 
-JSObject* DLLCALL js_CreateSocketObject(JSContext* cx, JSObject* parent, char *name, SOCKET sock, CRYPT_CONTEXT session)
+JSObject* js_CreateSocketObject(JSContext* cx, JSObject* parent, char *name, SOCKET sock, CRYPT_CONTEXT session)
 {
 	JSObject*	obj;
 
@@ -3575,7 +3575,7 @@ JSObject* DLLCALL js_CreateSocketObject(JSContext* cx, JSObject* parent, char *n
 	return(obj);
 }
 
-JSObject* DLLCALL js_CreateSocketObjectFromSet(JSContext* cx, JSObject* parent, char *name, struct xpms_set *set)
+JSObject* js_CreateSocketObjectFromSet(JSContext* cx, JSObject* parent, char *name, struct xpms_set *set)
 {
 	JSObject*	obj;
 	js_socket_private_t*	p;
diff --git a/src/sbbs3/js_user.c b/src/sbbs3/js_user.c
index 39900e7d84..1d120b8b4c 100644
--- a/src/sbbs3/js_user.c
+++ b/src/sbbs3/js_user.c
@@ -1334,7 +1334,7 @@ static jsSyncMethodSpec js_user_functions[] = {
 	{"get_time_left",	js_get_time_left,	1,	JSTYPE_NUMBER,	JSDOCSTR("start_time")
 	,JSDOCSTR("Returns the user's available remaining time online, in seconds,<br>"
 	"based on the passed <i>start_time</i> value (in time_t format)<br>"
-	"Note: this method does not account for pending forced timed events"
+	"Note: this method does not account for pending forced timed events<br>"
 	"Note: for the pre-defined user object on the BBS, you almost certainly want bbs.get_time_left() instead.")
 	,31401
 	},
diff --git a/src/sbbs3/jsdoor.c b/src/sbbs3/jsdoor.c
index d709c5514a..c07a0902d6 100644
--- a/src/sbbs3/jsdoor.c
+++ b/src/sbbs3/jsdoor.c
@@ -284,6 +284,10 @@ BOOL DLLCALL js_CreateCommonObjects(JSContext* js_cx
 		if(js_CreateFileClass(js_cx, *glob)==NULL)
 			break;
 
+		/* Archive Class */
+		if(js_CreateArchiveClass(js_cx, *glob)==NULL)
+			break;
+
 		/* COM Class */
 		if(js_CreateCOMClass(js_cx, *glob)==NULL)
 			break;
diff --git a/src/sbbs3/listfile.cpp b/src/sbbs3/listfile.cpp
index 58923be8ea..79117cf7a3 100644
--- a/src/sbbs3/listfile.cpp
+++ b/src/sbbs3/listfile.cpp
@@ -1,9 +1,5 @@
-/* listfile.cpp */
-
 /* Synchronet file database listing functions */
 
-/* $Id: listfile.cpp,v 1.66 2020/05/11 08:57:18 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,102 +13,62 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include "sbbs.h"
+#include "filedat.h"
 
 #define BF_MAX	26	/* Batch Flag max: A-Z */	
 
 int extdesclines(char *str);
 
 /*****************************************************************************/
-/* List files in directory 'dir' that match 'filespec'. Filespec must be 	 */
-/* padded. ex: FILE*   .EXT, not FILE*.EXT. 'mode' determines other critiria */
+/* List files in directory 'dir' that match 'filespec'.						 */
+/* 'mode' determines other criteria											 */
 /* the files must meet before they'll be listed. 'mode' bit FL_NOHDR doesn't */
 /* list the directory header.                                                */
 /* Returns -1 if the listing was aborted, otherwise total files listed		 */
 /*****************************************************************************/
-int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
+int sbbs_t::listfiles(uint dirnum, const char *filespec, FILE* tofile, long mode)
 {
-	char	str[256],hdr[256],letter='A',*p,*datbuf,ext[513];
-	char 	tmp[512];
-	uchar*	ixbbuf;
+	char	hdr[256],letter='A',*p;
 	uchar	flagprompt=0;
 	int		c, d;
 	uint	i,j;
-	int		file,found=0,lastbat=0,disp;
-	long	m=0,n,anchor=0,next,datbuflen;
-	int32_t	l;
+	int		found=0,lastbat=0,disp;
+	size_t	m=0;
+	long	anchor=0,next;
+	file_t* bf[BF_MAX];	/* bf is batch flagged files */
+	smb_t	smb;
 	ulong	file_row[26];
-	file_t	f,bf[26];	/* bf is batch flagged files */
 
+	if(!smb_init_dir(&cfg, &smb, dirnum))
+		return 0;
 	if(mode&FL_ULTIME) {
-		last_ns_time=now;
-		sprintf(str,"%s%s.dab",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-		if((file=nopen(str,O_RDONLY))!=-1) {
-			read(file,&l,4);
-			close(file);
-			if(ns_time>(time_t)l)
-				return(0); 
-		}
-	}
-	sprintf(str,"%s%s.ixb",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-	if((file=nopen(str,O_RDONLY))==-1)
-		return(0);
-	l=(long)filelength(file);
-	if(!l) {
-		close(file);
-		return(0); 
-	}
-	if((ixbbuf=(uchar *)malloc(l))==NULL) {
-		close(file);
-		errormsg(WHERE,ERR_ALLOC,str,l);
-		return(0); 
-	}
-	if(lread(file,ixbbuf,l)!=l) {
-		close(file);
-		errormsg(WHERE,ERR_READ,str,l);
-		free((char *)ixbbuf);
-		return(0); 
-	}
-	close(file);
-	sprintf(str,"%s%s.dat",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-	if((file=nopen(str,O_RDONLY))==-1) {
-		errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
-		free((char *)ixbbuf);
-		return(0); 
+		last_ns_time = now;
+		if(!newfiles(&smb, ns_time))	// this is fast
+			return 0;
 	}
-	datbuflen=(long)filelength(file);
-	if((datbuf=(char *)malloc(datbuflen))==NULL) {
-		close(file);
-		errormsg(WHERE,ERR_ALLOC,str,datbuflen);
-		free((char *)ixbbuf);
-		return(0); 
-	}
-	if(lread(file,datbuf,datbuflen)!=datbuflen) {
-		close(file);
-		errormsg(WHERE,ERR_READ,str,datbuflen);
-		free((char *)datbuf);
-		free((char *)ixbbuf);
-		return(0); 
+	if(smb_open_dir(&cfg, &smb, dirnum) != SMB_SUCCESS)
+		return 0;
+
+	size_t file_count = 0;
+	file_t* file_list = loadfiles(&smb
+		, (mode&(FL_FINDDESC|FL_EXFIND)) ? NULL : filespec
+		, (mode&FL_ULTIME) ? ns_time : 0
+		, file_detail_extdesc
+		, (enum file_sort)cfg.dir[dirnum]->sort
+		, &file_count);
+	if(file_list == NULL || file_count < 1) {
+		smb_close(&smb);
+		free(file_list);
+		return 0;
 	}
-	close(file);
+
 	if(!tofile) {
 		action=NODE_LFIL;
 		getnodedat(cfg.node_num,&thisnode,0);
@@ -124,34 +80,35 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 		} 
 	}
 
-	while(online && found<MAX_FILES) {
+	m = 0; // current file index
+	file_t* f;
+	while(online) {
 		if(found<0)
 			found=0;
-		if(m>=l || flagprompt) {		  /* End of list */
+		if(m>=file_count || flagprompt) {		  /* End of list */
 			if(useron.misc&BATCHFLAG && !tofile && found && found!=lastbat
 				&& !(mode&(FL_EXFIND|FL_VIEW))) {
 				flagprompt=0;
 				lncntr=0;
-				if((i=batchflagprompt(dirnum,bf,file_row,letter-'A',l/F_IXBSIZE))==2) {
+				if((i=batchflagprompt(&smb, bf, file_row, letter-'A', file_count))==2) {
 					m=anchor;
 					found-=letter-'A';
 					letter='A'; 
 				}
 				else if(i==3) {
-					if((long)anchor-((letter-'A')*F_IXBSIZE)<0) {
+					if((long)anchor-(letter-'A')<0) {
 						m=0;
 						found=0; 
 					}
 					else {
-						m=anchor-((letter-'A')*F_IXBSIZE);
+						m=anchor-(letter-'A');
 						found-=letter-'A'; 
 					}
 					letter='A'; 
 				}
 				else if((int)i==-1) {
-					free((char *)ixbbuf);
-					free((char *)datbuf);
-					return(-1); 
+					found = -1;
+					break;
 				}
 				else
 					break;
@@ -161,6 +118,8 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 			else
 				break; 
 		}
+		if(m < file_count)
+			f = &file_list[m];
 
 		if(letter>'Z')
 			letter='A';
@@ -168,60 +127,47 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 			anchor=m;
 
 		if(msgabort()) {		 /* used to be !tofile && msgabort() */
-			free((char *)ixbbuf);
-			free((char *)datbuf);
-			return(-1); 
+			found = -1;
+			break;
 		}
-		for(j=0;j<12 && m<l;j++)
-			if(j==8)
-				str[j]=ixbbuf[m]>' ' ? '.' : ' ';
-			else
-				str[j]=ixbbuf[m++];		/* Turns FILENAMEEXT into FILENAME.EXT */
-		str[j]=0;
+#if 0 /* unnecessary? */
 		if(!(mode&(FL_FINDDESC|FL_EXFIND)) && filespec[0]
 			&& !filematch(str,filespec)) {
 			m+=11;
 			continue; 
 		}
-		n=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
-		if(n>=datbuflen) {	/* out of bounds */
-			m+=11;
-			continue; 
-		}
+#endif
 		if(mode&(FL_FINDDESC|FL_EXFIND)) {
-			getrec((char *)&datbuf[n],F_DESC,LEN_FDESC,tmp);
-			strupr(tmp);
-			p=strstr(tmp,filespec);
+			p = (f->desc == NULL) ? NULL : strcasestr(f->desc, filespec);
 			if(!(mode&FL_EXFIND) && p==NULL) {
-				m+=11;
+				m++;
 				continue; 
 			}
-			getrec((char *)&datbuf[n],F_MISC,1,tmp);
-			j=tmp[0];  /* misc bits */
-			if(j) j-=' ';
-			if(mode&FL_EXFIND && j&FM_EXTDESC) { /* search extended description */
-				getextdesc(&cfg,dirnum,n,ext);
-				strupr(ext);
-				if(!strstr(ext,filespec) && !p) {	/* not in description or */
-					m+=11;						 /* extended description */
+			if(mode&FL_EXFIND && f->extdesc != NULL) { /* search extended description */
+				if(!strcasestr((char*)f->extdesc, filespec) && p == NULL) {	/* not in description or */
+					m++;											 /* extended description */
 					continue; 
 				}
 			}
-			else if(!p) {			 /* no extended description and not in desc */
-				m+=11;
-				continue; } 
+			else if(p == NULL) {			 /* no extended description and not in desc */
+				m++;
+				continue; 
+			} 
 		}
+/** necessary?
 		if(mode&FL_ULTIME) {
 			if(ns_time>(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
 				|((long)ixbbuf[m+6]<<24))) {
 				m+=11;
-				continue; } 
+				continue; 
+			}
 		}
+**/
 		if(useron.misc&BATCHFLAG && letter=='A' && found && !tofile
 			&& !(mode&(FL_EXFIND|FL_VIEW))
 			&& (!mode || !(useron.misc&EXPERT)))
 			bputs(text[FileListBatchCommands]);
-		m+=11;
+		m++;
 		if(!found && !(mode&(FL_EXFIND|FL_VIEW))) {
 			for(i=0;i<usrlibs;i++)
 				if(usrlib[i]==cfg.dir[dirnum]->lib)
@@ -244,61 +190,54 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 							: strlen(cfg.dir[dirnum]->lname)+17;
 						if(i>8 || j>8) d++;
 						attr(cfg.color[clr_filelsthdrbox]);
-						bputs("��");            /* use to start with \r\n */
+						bputs("\xc9\xcd");            /* use to start with \r\n */
 						for(c=0;c<d;c++)
-							outchar('�');
-						bputs("�\r\n� ");
+							outchar('\xcd');
+						bputs("\xbb\r\n\xba ");
 						sprintf(hdr,text[BoxHdrLib],i+1,cfg.lib[usrlib[i]]->lname);
 						bputs(hdr);
 						for(c=bstrlen(hdr);c<d;c++)
 							outchar(' ');
 						attr(cfg.color[clr_filelsthdrbox]);
-						bputs("�\r\n� ");
+						bputs("\xba\r\n\xba ");
 						sprintf(hdr,text[BoxHdrDir],j+1,cfg.dir[dirnum]->lname);
 						bputs(hdr);
 						for(c=bstrlen(hdr);c<d;c++)
 							outchar(' ');
 						attr(cfg.color[clr_filelsthdrbox]);
-						bputs("�\r\n� ");
-						sprintf(hdr,text[BoxHdrFiles],l/F_IXBSIZE);
+						bputs("\xba\r\n\xba ");
+						sprintf(hdr,text[BoxHdrFiles], file_count);
 						bputs(hdr);
 						for(c=bstrlen(hdr);c<d;c++)
 							outchar(' ');
 						attr(cfg.color[clr_filelsthdrbox]);
-						bputs("�\r\n��");
+						bputs("\xba\r\n\xc8\xcd");
 						for(c=0;c<d;c++)
-							outchar('�');
-						bputs("�\r\n"); 
+							outchar('\xcd');
+						bputs("\xbc\r\n"); 
 					}
 				}
 			}
 			else {					/* short header */
 				if(tofile) {
-					sprintf(hdr,"(%u) %s ",i+1,cfg.lib[usrlib[i]]->sname);
-					write(tofile,crlf,2);
-					write(tofile,hdr,strlen(hdr)); 
+					c = fprintf(tofile,"\r\n(%u) %s ",i+1,cfg.lib[usrlib[i]]->sname) - 2;
 				}
 				else {
 					sprintf(hdr,text[ShortHdrLib],i+1,cfg.lib[usrlib[i]]->sname);
 					bputs("\r\1>\r\n");
 					bputs(hdr); 
+					c=bstrlen(hdr);
 				}
-				c=bstrlen(hdr);
 				if(tofile) {
-					sprintf(hdr,"(%u) %s",j+1,cfg.dir[dirnum]->lname);
-					write(tofile,hdr,strlen(hdr)); 
+					c += fprintf(tofile,"(%u) %s",j+1,cfg.dir[dirnum]->lname);
 				}
 				else {
 					sprintf(hdr,text[ShortHdrDir],j+1,cfg.dir[dirnum]->lname);
 					bputs(hdr); 
+					c+=bstrlen(hdr);
 				}
-				c+=bstrlen(hdr);
 				if(tofile) {
-					write(tofile,crlf,2);
-					sprintf(hdr,"%*s",c,nulstr);
-					memset(hdr,0xC4,c);
-					strcat(hdr,crlf);
-					write(tofile,hdr,strlen(hdr)); 
+					fprintf(tofile,"\r\n%.*s\r\n", c, "----------------------------------------------------------------");
 				}
 				else {
 					CRLF;
@@ -313,42 +252,22 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 		next=m;
 		disp=1;
 		if(mode&(FL_EXFIND|FL_VIEW)) {
-			f.dir=dirnum;
-			strcpy(f.name,str);
-			m-=11;
-			f.datoffset=n;
-			f.dateuled=ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
-				|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24);
-			f.datedled=ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
-				|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24);
-			m+=11;
-			f.size=0;
-			getfiledat(&cfg,&f);
 			if(!found)
 				bputs("\r\1>");
-			if(mode&FL_EXFIND) {
-				if(!viewfile(&f,1)) {
-					free((char *)ixbbuf);
-					free((char *)datbuf);
-					return(-1); } 
+			if(!viewfile(f, INT_TO_BOOL(mode&FL_EXFIND))) {
+				found = -1;
+				break;
 			}
-			else {
-				if(!viewfile(&f,0)) {
-					free((char *)ixbbuf);
-					free((char *)datbuf);
-					return(-1); 
-				} 
-			} 
+			CRLF;
 		}
-
 		else if(tofile)
-			listfiletofile(str,&datbuf[n],dirnum,tofile);
+			listfiletofile(f, tofile);
 		else if(mode&FL_FINDDESC)
-			disp=listfile(str,&datbuf[n],dirnum,filespec,letter,n);
+			disp=listfile(f, dirnum, filespec, letter);
 		else
-			disp=listfile(str,&datbuf[n],dirnum,nulstr,letter,n);
+			disp=listfile(f, dirnum, nulstr, letter);
 		if(!disp && letter>'A') {
-			next=m-F_IXBSIZE;
+			next=m-1;
 			letter--; 
 		}
 		else {
@@ -356,24 +275,17 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 			found++; 
 		}
 		if(sys_status&SS_ABORT) {
-			free((char *)ixbbuf);
-			free((char *)datbuf);
-			return(-1); 
+			found = -1;
+			break;
 		}
 		if(mode&(FL_EXFIND|FL_VIEW))
 			continue;
 		if(useron.misc&BATCHFLAG && !tofile) {
 			if(disp) {
-				strcpy(bf[letter-'A'].name,str);
-				m-=11;
-				bf[letter-'A'].datoffset=n;
-				bf[letter-'A'].dateuled=ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
-					|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24);
-				bf[letter-'A'].datedled=ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
-					|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24);
+				bf[letter-'A'] = f;
 				file_row[letter-'A'] = currow;
 			}
-			m+=11;
+			m++;
 			if(flagprompt || letter=='Z' || !disp ||
 				(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?')
 				&& !(mode&FL_FINDDESC))
@@ -382,31 +294,31 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 				flagprompt=0;
 				lncntr=0;
 				lastbat=found;
-				if((int)(i=batchflagprompt(dirnum,bf,file_row,letter-'A'+1,l/F_IXBSIZE))<1) {
-					free((char *)ixbbuf);
-					free((char *)datbuf);
+				if((int)(i=batchflagprompt(&smb, bf, file_row, letter-'A'+1, file_count))<1) {
 					if((int)i==-1)
-						return(-1);
-					else
-						return(found); 
+						found = -1;
+					break;
 				}
 				if(i==2) {
 					next=anchor;
 					found-=(letter-'A')+1; 
 				}
 				else if(i==3) {
-					if((long)anchor-((letter-'A'+1)*F_IXBSIZE)<0) {
+					if((long)anchor-((letter-'A'+1))<0) {
 						next=0;
 						found=0; 
 					}
 					else {
-						next=anchor-((letter-'A'+1)*F_IXBSIZE);
-						found-=letter-'A'+1; } 
+						next=anchor-((letter-'A'+1));
+						found-=letter-'A'+1; 
+					} 
 				}
 				getnodedat(cfg.node_num,&thisnode,0);
 				nodesync();
-				letter='A';	}
-			else letter++; 
+				letter='A';	
+			}
+			else
+				letter++; 
 		}
 		if(useron.misc&BATCHFLAG && !tofile
 			&& lncntr>=rows-2) {
@@ -419,250 +331,133 @@ int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
 			break; 
 	}
 
-	free((char *)ixbbuf);
-	free((char *)datbuf);
-	return(found);
+	freefiles(file_list, file_count);
+	smb_close(&smb);
+	return found;
 }
 
 /****************************************************************************/
 /* Prints one file's information on a single line                           */
 /* Return 1 if displayed, 0 otherwise										*/
 /****************************************************************************/
-bool sbbs_t::listfile(const char *fname, const char *buf, uint dirnum
-	, const char *search, const char letter, ulong datoffset)
+bool sbbs_t::listfile(file_t* f, uint dirnum, const char *search, const char letter)
 {
-	char	str[256],ext[513]="",*ptr,*cr,*lf,exist=1;
+	char	*ptr,*cr,*lf;
+	bool	exist = true;
+	char*	ext=NULL;
 	char	path[MAX_PATH+1];
-	char 	tmp[512];
-    uchar	alt;
     int		i,j;
-    ulong	cdt;
-	off_t	size;
+    off_t	cdt;
 	int		size_attr=clr_filecdt;
 
-	if(buf[F_MISC]!=ETX && (buf[F_MISC]-' ')&FM_EXTDESC && useron.misc&EXTDESC) {
-		getextdesc(&cfg,dirnum,datoffset,ext);
-		if(useron.misc&BATCHFLAG && lncntr+extdesclines(ext)>=rows-2 && letter!='A')
-			return(false); 
+	if(f->extdesc != NULL && *f->extdesc && (useron.misc&EXTDESC)) {
+		ext = f->extdesc;
+		if((useron.misc&BATCHFLAG) && lncntr+extdesclines(ext)>=rows-2 && letter!='A')
+			return false;
 	}
 
 	attr(cfg.color[clr_filename]);
-	bputs(fname);
-
-	getrec(buf,F_ALTPATH,2,str);
-	alt=(uchar)ahtoul(str);
-	sprintf(path,"%s%s",alt>0 && alt<=cfg.altpaths ? cfg.altpath[alt-1]:cfg.dir[dirnum]->path
-		,unpadfname(fname,tmp));
+	char fname[13];	/* This is one of the only 8.3 filename formats left! (used for display purposes only) */
+	bprintf("%-*s", (int)sizeof(fname)-1, format_filename(f->name, fname, sizeof(fname)-1, /* pad: */TRUE));
+	getfilepath(&cfg, f, path);
 
-	if(buf[F_MISC]!=ETX && (buf[F_MISC]-' ')&FM_EXTDESC) {
-		if(!(useron.misc&EXTDESC))
-			outchar('+');
-		else
-			outchar(' '); 
-	}
+	if(f->extdesc != NULL && *f->extdesc && !(useron.misc&EXTDESC))
+		outchar('+');
 	else
-		outchar(' ');
+		outchar(' '); 
 	if(useron.misc&BATCHFLAG) {
 		attr(cfg.color[clr_filedesc]);
 		bprintf("%c",letter); 
 	}
-	getrec(buf,F_CDT,LEN_FCDT,str);
-	cdt=atol(str);
-	if(cfg.dir[dirnum]->misc&DIR_FCHK) {
-		if(!fexistcase(path)) {
-			exist=0;
-			size_attr = clr_err; 
-		}
-		else if((cfg.dir[dirnum]->misc&DIR_FREE) && (size=flength(path)) >= 0)
-			cdt = size;
+	cdt = f->cost;
+	if(f->size == -1) {
+		exist = false;
+		size_attr = clr_err; 
 	}
+	else if((cfg.dir[dirnum]->misc & (DIR_FREE | DIR_FCHK)) == (DIR_FREE | DIR_FCHK))
+		cdt = getfilesize(&cfg, f);
+	char bytes[32];
+	unsigned units = 1;
+	do {
+		byte_estimate_to_str(cdt, bytes, sizeof(bytes), units, /* precision: */1);
+		units *= 1024;
+	} while(strlen(bytes) > 6 && units < 1024 * 1024 * 1024);
 	attr(cfg.color[size_attr]);
 	if(useron.misc&BATCHFLAG) {
 		if(!cdt && !(cfg.dir[dirnum]->misc&DIR_FREE)) {
 			attr(curatr^(HIGH|BLINK));
 			bputs("  FREE"); 
 		}
-		else if(cdt>=(1024*1024*1024))
-			bprintf("%5.1fG",cdt/(1024.0*1024.0*1024.0));
-		else if(cdt>=(1024*1024))
-			bprintf("%5.1fM",cdt/(1024.0*1024.0));
-		else if(cdt>=1024)
-			bprintf("%5.1fK",cdt/1024.0); 
-		else
-			bprintf("%5luB", cdt);
+		else 
+			bprintf("%6s", bytes);
 	}
 	else {
 		if(!cdt && !(cfg.dir[dirnum]->misc&DIR_FREE)) {  /* FREE file */
 			attr(curatr^(HIGH|BLINK));
 			bputs("   FREE"); 
 		}
-		else if(cdt>=(1024*1024*1024))
-			bprintf("%6.1fG",cdt/(1024.0*1024.0*1024.0));
-		else if(cdt>=(1024*1024))
-			bprintf("%6.1fM",cdt/(1024.0*1024.0));
-		else if(cdt>=1024)
-			bprintf("%6.1fK",cdt/1024.0); 
-		else
-			bprintf("%6luB", cdt);
+		else 
+			bprintf("%7s", bytes);
 	}
 	if(exist)
 		outchar(' ');
 	else
 		outchar('-');
-	getrec(buf,F_DESC,LEN_FDESC,str);
 	attr(cfg.color[clr_filedesc]);
 
-#ifdef _WIN32
- 
-	if(exist && !(cfg.file_misc&FM_NO_LFN)) {
-		fexistcase(path);	/* Get real (long?) filename */
-		ptr=getfname(path);
-		if(stricmp(ptr,tmp) && stricmp(ptr,str))
-			bprintf("%.*s\r\n%21s",LEN_FDESC,ptr,"");
-	}
-
-#endif
-
-	if(!ext[0]) {
-		if(search[0]) { /* high-light string in string */
-			strcpy(tmp,str);
-			strupr(tmp);
-			ptr=strstr(tmp,search);
-			i=strlen(search);
-			j=ptr-tmp;
-			bprintf("%.*s",j,str);
-			attr(cfg.color[clr_filedesc]^HIGH);
-			bprintf("%.*s",i,str+j);
-			attr(cfg.color[clr_filedesc]);
-			bprintf("%.*s",(int)(strlen(str)-(j+i)),str+j+i); 
+	if(ext == NULL) {
+		char* fdesc = f->desc;
+		SKIP_WHITESPACE(fdesc);
+		if(fdesc == NULL || *fdesc == '\0')
+			bputs(P_TRUNCATE, f->name);
+		else if(search[0]) { /* high-light string in string */
+			ptr = strcasestr(fdesc, search);
+			if(ptr != NULL) {
+				i=strlen(search);
+				j=ptr - fdesc;
+				bprintf("%.*s",j,fdesc);
+				attr(cfg.color[clr_filedesc]^HIGH);
+				bprintf("%.*s",i,fdesc+j);
+				attr(cfg.color[clr_filedesc]);
+				bprintf("%.*s",(int)strlen(fdesc)-(j+i),fdesc+j+i);
+			}
+		}
+		else {
+			bputs(P_TRUNCATE, fdesc);
 		}
-		else
-			bputs(str);
 		CRLF; 
-	}
-	ptr=ext;
-	while(*ptr && ptr<ext+512 && !msgabort()) {
-		cr=strchr(ptr,CR);
-		lf=strchr(ptr,LF);
-		if(lf && (lf<cr || !cr)) cr=lf;
-		if(cr>ptr+LEN_FDESC)
-			cr=ptr+LEN_FDESC;
-		else if(cr)
-			*cr=0;
-		sprintf(str,"%.*s\r\n",LEN_FDESC,ptr);
-		putmsg(str,P_NOATCODES|P_SAVEATR);
-		if(!cr) {
-			if(strlen(ptr)>LEN_FDESC)
+	} else {
+		char* ext_desc = strdup((char*)ext);
+		truncsp(ext_desc);
+		ptr=(char*)ext_desc;
+		SKIP_CRLF(ptr);
+		while(ptr && *ptr && !msgabort()) {
+			cr=strchr(ptr,CR);
+			lf=strchr(ptr,LF);
+			if(lf && (lf<cr || !cr)) cr=lf;
+			if(cr>ptr+LEN_FDESC)
 				cr=ptr+LEN_FDESC;
-			else
-				break; 
+			else if(cr)
+				*cr=0;
+			char str[256];
+			sprintf(str,"%.*s\r\n",LEN_FDESC,ptr);
+			putmsg(str,P_NOATCODES|P_SAVEATR);
+			if(!cr) {
+				if(strlen(ptr)>LEN_FDESC)
+					cr=ptr+LEN_FDESC;
+				else
+					break; 
+			}
+			if(!(*(cr+1)) || !(*(cr+2)))
+				break;
+			bprintf("%21s",nulstr);
+			ptr=cr;
+			if(!(*ptr)) ptr++;
+			while(*ptr==LF || *ptr==CR) ptr++; 
 		}
-		if(!(*(cr+1)) || !(*(cr+2)))
-			break;
-		bprintf("%21s",nulstr);
-		ptr=cr;
-		if(!(*ptr)) ptr++;
-		while(*ptr==LF || *ptr==CR) ptr++; 
-	}
-	return(true);
-}
-
-/****************************************************************************/
-/* Remove credits from uploader of file 'f'                                 */
-/****************************************************************************/
-bool sbbs_t::removefcdt(file_t* f)
-{
-	char	str[128];
-	char 	tmp[512];
-	int		u;
-	long	cdt;
-
-	if((u=matchuser(&cfg,f->uler,TRUE /*sysop_alias*/))==0) {
-	   bputs(text[UnknownUser]);
-	   return(false); 
-	}
-	cdt=0L;
-	if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps) {
-		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
-			cdt=((ulong)(f->cdt*(cfg.dir[f->dir]->up_pct/100.0))/cur_cps)/60;
-		if(cfg.dir[f->dir]->misc&DIR_CDTDL
-			&& f->timesdled)  /* all downloads */
-			cdt+=((ulong)((long)f->timesdled
-				*f->cdt*(cfg.dir[f->dir]->dn_pct/100.0))/cur_cps)/60;
-		adjustuserrec(&cfg,u,U_MIN,10,-cdt);
-		sprintf(str,"%lu minute",cdt);
-		sprintf(tmp,text[FileRemovedUserMsg]
-			,f->name,cdt ? str : text[No]);
-		putsmsg(&cfg,u,tmp); 
-	}
-	else {
-		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
-			cdt=(ulong)(f->cdt*(cfg.dir[f->dir]->up_pct/100.0));
-		if(cfg.dir[f->dir]->misc&DIR_CDTDL
-			&& f->timesdled)  /* all downloads */
-			cdt+=(ulong)((long)f->timesdled
-				*f->cdt*(cfg.dir[f->dir]->dn_pct/100.0));
-		adjustuserrec(&cfg,u,U_CDT,10,-cdt);
-		sprintf(tmp,text[FileRemovedUserMsg]
-			,f->name,cdt ? ultoac(cdt,str) : text[No]);
-		putsmsg(&cfg,u,tmp); 
-	}
-
-	adjustuserrec(&cfg,u,U_ULB,10,-f->size);
-	adjustuserrec(&cfg,u,U_ULS,5,-1);
-	return(true);
-}
-
-bool sbbs_t::removefile(file_t* f)
-{
-	char str[256];
-
-	if(removefiledat(&cfg,f)) {
-		SAFEPRINTF3(str,"removed %s from %s %s"
-			,f->name
-			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
-		logline("U-",str);
-		return(true);
-	}
-	SAFEPRINTF2(str,"%s %s",cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
-	errormsg(WHERE, ERR_REMOVE, f->name, 0, str);
-	return(false);
-}
-
-/****************************************************************************/
-/* Move file 'f' from f.dir to newdir                                       */
-/****************************************************************************/
-bool sbbs_t::movefile(file_t* f, int newdir)
-{
-	char str[MAX_PATH+1],path[MAX_PATH+1],fname[128],ext[1024];
-	int olddir=f->dir;
-
-	if(findfile(&cfg,newdir,f->name)) {
-		bprintf(text[FileAlreadyThere],f->name);
-		return(false); 
+		free(ext_desc);
 	}
-	getextdesc(&cfg,olddir,f->datoffset,ext);
-	if(cfg.dir[olddir]->misc&DIR_MOVENEW)
-		f->dateuled=time32(NULL);
-	unpadfname(f->name,fname);
-	removefiledat(&cfg,f);
-	f->dir=newdir;
-	addfiledat(&cfg,f);
-	bprintf(text[MovedFile],f->name
-		,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
-	sprintf(str,"moved %s to %s %s",f->name
-		,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
-	logline(nulstr,str);
-	if(!f->altpath) {	/* move actual file */
-		sprintf(str,"%s%s",cfg.dir[olddir]->path,fname);
-		if(fexistcase(str)) {
-			sprintf(path,"%s%s",cfg.dir[f->dir]->path,getfname(str));
-			mv(str,path,0); 
-		} 
-	}
-	if(f->misc&FM_EXTDESC)
-		putextdesc(&cfg,f->dir,f->datoffset,ext);
-	return(true);
+	return true;
 }
 
 /****************************************************************************/
@@ -670,29 +465,28 @@ bool sbbs_t::movefile(file_t* f, int newdir)
 /* Returns -1 if 'Q' or Ctrl-C, 0 if skip, 1 if [Enter], 2 otherwise        */
 /* or 3, backwards. 														*/
 /****************************************************************************/
-int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
+int sbbs_t::batchflagprompt(smb_t* smb, file_t** bf, ulong* row, uint total
 							,long totalfiles)
 {
-	char	ch,str[256],fname[128],*p,remcdt=0,remfile=0;
+	char	ch,str[256],*p,remcdt=0,remfile=0;
 	int		c, d;
-	char 	tmp[512];
+	char 	path[MAX_PATH + 1];
 	uint	i,j,ml=0,md=0,udir,ulib;
-	file_t	f;
 
 	for(ulib=0;ulib<usrlibs;ulib++)
-		if(usrlib[ulib]==cfg.dir[dirnum]->lib)
+		if(usrlib[ulib]==cfg.dir[smb->dirnum]->lib)
 			break;
 	for(udir=0;udir<usrdirs[ulib];udir++)
-		if(usrdir[ulib][udir]==dirnum)
+		if(usrdir[ulib][udir]==smb->dirnum)
 			break;
 
 	CRLF;
 	while(online) {
 		bprintf(text[BatchFlagPrompt]
 			,ulib+1
-			,cfg.lib[cfg.dir[dirnum]->lib]->sname
+			,cfg.lib[cfg.dir[smb->dirnum]->lib]->sname
 			,udir+1
-			,cfg.dir[dirnum]->sname
+			,cfg.dir[smb->dirnum]->sname
 			,total, totalfiles);
 		ch=getkey(K_UPPER);
 		clearline();
@@ -714,12 +508,7 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 				return(2); 
 			}
 			if(total==1) {
-				f.dir=dirnum;
-				strcpy(f.name,bf[0].name);
-				f.datoffset=bf[0].datoffset;
-				f.size=0;
-				getfiledat(&cfg,&f);
-				addtobatdl(&f);
+				addtobatdl(bf[0]);
 				if(ch=='D')
 					start_batch_download();
 				CRLF;
@@ -730,49 +519,40 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 			for(i=0; i < total; i++)
 				add_hotspot((char)('A' + i), /* hungry: */true, -1, -1, row[i]);
 			bputs(text[BatchDlFlags]);
-			d=getstr(str,BF_MAX,K_UPPER|K_LOWPRIO|K_NOCRLF);
+			d=getstr(str, BF_MAX, K_NOCRLF);
 			clear_hotspots();
 			mouse_hotspots = saved_hotspots;
 			lncntr=0;
 			if(sys_status&SS_ABORT)
 				return(-1);
-			if(d) { 	/* d is string length */
+			if(d > 0) { 	/* d is string length */
+				strupr(str);
 				CRLF;
 				lncntr=0;
 				for(c=0;c<d;c++) {
-					if(batdn_total>=cfg.max_batdn) {
+					if(batdn_total() >= cfg.max_batdn) {
 						bprintf(text[BatchDlQueueIsFull],str+c);
 						break; 
 					}
 					if(str[c]=='*' || strchr(str+c,'.')) {     /* filename or spec given */
-						f.dir=dirnum;
+//						f.dir=dirnum;
 						p=strchr(str+c,' ');
 						if(!p) p=strchr(str+c,',');
 						if(p) *p=0;
 						for(i=0;i<total;i++) {
-							if(batdn_total>=cfg.max_batdn) {
+							if(batdn_total() >= cfg.max_batdn) {
 								bprintf(text[BatchDlQueueIsFull],str+c);
 								break; 
 							}
-							padfname(str+c,tmp);
-							if(filematch(bf[i].name,tmp)) {
-								strcpy(f.name,bf[i].name);
-								f.datoffset=bf[i].datoffset;
-								f.size=0;
-								getfiledat(&cfg,&f);
-								addtobatdl(&f); 
+							if(filematch(bf[i]->name, str+c)) {
+								addtobatdl(bf[i]); 
 							} 
 						} 
 					}
 					if(strchr(str+c,'.'))
 						c+=strlen(str+c);
 					else if(str[c]<'A'+(char)total && str[c]>='A') {
-						f.dir=dirnum;
-						strcpy(f.name,bf[str[c]-'A'].name);
-						f.datoffset=bf[str[c]-'A'].datoffset;
-						f.size=0;
-						getfiledat(&cfg,&f);
-						addtobatdl(&f);
+						addtobatdl(bf[str[c]-'A']);
 					} 
 				}
 				if(ch=='D')
@@ -786,14 +566,7 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 
 		if(ch=='E' || ch=='V') {    /* Extended Info */
 			if(total==1) {
-				f.dir=dirnum;
-				strcpy(f.name,bf[0].name);
-				f.datoffset=bf[0].datoffset;
-				f.dateuled=bf[0].dateuled;
-				f.datedled=bf[0].datedled;
-				f.size=0;
-				getfiledat(&cfg,&f);
-				if(!viewfile(&f,ch=='E'))
+				if(!viewfile(bf[0], ch=='E'))
 					return(-1);
 				return(2); 
 			}
@@ -802,31 +575,25 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 			for(i=0; i < total; i++)
 				add_hotspot((char)('A' + i), /* hungry: */true, -1, -1, row[i]);
 			bputs(text[BatchDlFlags]);
-			d=getstr(str,BF_MAX,K_UPPER|K_LOWPRIO|K_NOCRLF);
+			d=getstr(str, BF_MAX, K_NOCRLF);
 			clear_hotspots();
 			mouse_hotspots = saved_hotspots;
 			lncntr=0;
 			if(sys_status&SS_ABORT)
 				return(-1);
-			if(d) { 	/* d is string length */
+			if(d > 0) { 	/* d is string length */
+				strupr(str);
 				CRLF;
 				lncntr=0;
 				for(c=0;c<d;c++) {
 					if(str[c]=='*' || strchr(str+c,'.')) {     /* filename or spec given */
-						f.dir=dirnum;
+//						f.dir=dirnum;
 						p=strchr(str+c,' ');
 						if(!p) p=strchr(str+c,',');
 						if(p) *p=0;
 						for(i=0;i<total;i++) {
-							padfname(str+c,tmp);
-							if(filematch(bf[i].name,tmp)) {
-								strcpy(f.name,bf[i].name);
-								f.datoffset=bf[i].datoffset;
-								f.dateuled=bf[i].dateuled;
-								f.datedled=bf[i].datedled;
-								f.size=0;
-								getfiledat(&cfg,&f);
-								if(!viewfile(&f,ch=='E'))
+							if(filematch(bf[i]->name, str+c)) {
+								if(!viewfile(bf[i], ch=='E'))
 									return(-1); 
 							} 
 						} 
@@ -834,16 +601,11 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 					if(strchr(str+c,'.'))
 						c+=strlen(str+c);
 					else if(str[c]<'A'+(char)total && str[c]>='A') {
-						f.dir=dirnum;
-						strcpy(f.name,bf[str[c]-'A'].name);
-						f.datoffset=bf[str[c]-'A'].datoffset;
-						f.dateuled=bf[str[c]-'A'].dateuled;
-						f.datedled=bf[str[c]-'A'].datedled;
-						f.size=0;
-						getfiledat(&cfg,&f);
-						if(!viewfile(&f,ch=='E'))
-							return(-1); } 
+						if(!viewfile(bf[str[c]-'A'], ch=='E'))
+							return(-1); 
+					} 
 				}
+				cond_newline();
 				return(2); 
 			}
 			clearline();
@@ -852,7 +614,7 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 
 		if((ch=='R' || ch=='M')     /* Delete or Move */
 			&& !(useron.rest&FLAG('R'))
-			&& (dir_op(dirnum) || useron.exempt&FLAG('R'))) {
+			&& (dir_op(smb->dirnum) || useron.exempt&FLAG('R'))) {
 			if(total==1) {
 				strcpy(str,"A");
 				d=1; 
@@ -863,33 +625,37 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 				for(i=0; i < total; i++)
 					add_hotspot((char)('A' + i), /* hungry: */true, -1, -1, row[i]);
 				bputs(text[BatchDlFlags]);
-				d=getstr(str,BF_MAX,K_UPPER|K_LOWPRIO|K_NOCRLF);
+				d=getstr(str, BF_MAX, K_NOCRLF);
 				clear_hotspots();
 				mouse_hotspots = saved_hotspots;
 			}
 			lncntr=0;
 			if(sys_status&SS_ABORT)
 				return(-1);
-			if(d) { 	/* d is string length */
-				CRLF;
+			if(d > 0) { 	/* d is string length */
+				strupr(str);
+				if(total > 1)
+					newline();
 				if(ch=='R') {
 					if(noyes(text[RemoveFileQ]))
 						return(2);
-					remcdt=remfile=1;
-					if(dir_op(dirnum)) {
+					remcdt = TRUE;
+					remfile = TRUE;
+					if(dir_op(smb->dirnum)) {
 						remcdt=!noyes(text[RemoveCreditsQ]);
-						remfile=!noyes(text[DeleteFileQ]); } 
+						remfile=!noyes(text[DeleteFileQ]);
+					}
 				}
 				else if(ch=='M') {
 					CRLF;
 					for(i=0;i<usrlibs;i++)
 						bprintf(text[MoveToLibLstFmt],i+1,cfg.lib[usrlib[i]]->lname);
 					SYNC;
-					bprintf(text[MoveToLibPrompt],cfg.dir[dirnum]->lib+1);
+					bprintf(text[MoveToLibPrompt],cfg.dir[smb->dirnum]->lib+1);
 					if((int)(ml=getnum(usrlibs))==-1)
 						return(2);
 					if(!ml)
-						ml=cfg.dir[dirnum]->lib;
+						ml=cfg.dir[smb->dirnum]->lib;
 					else
 						ml--;
 					CRLF;
@@ -908,66 +674,44 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 				lncntr=0;
 				for(c=0;c<d;c++) {
 					if(str[c]=='*' || strchr(str+c,'.')) {     /* filename or spec given */
-						f.dir=dirnum;
+//						f.dir=dirnum;
 						p=strchr(str+c,' ');
 						if(!p) p=strchr(str+c,',');
 						if(p) *p=0;
 						for(i=0;i<total;i++) {
-							padfname(str+c,tmp);
-							if(filematch(bf[i].name,tmp)) {
-								strcpy(f.name,bf[i].name);
-								unpadfname(f.name,fname);
-								f.datoffset=bf[i].datoffset;
-								f.dateuled=bf[i].dateuled;
-								f.datedled=bf[i].datedled;
-								f.size=0;
-								getfiledat(&cfg,&f);
-								if(f.opencount) {
-									bprintf(text[FileIsOpen]
-										,f.opencount,f.opencount>1 ? "s":nulstr);
-									continue; 
-								}
+							if(filematch(bf[i]->name, str+c)) {
 								if(ch=='R') {
-									removefile(&f);
-									if(remfile) {
-										sprintf(tmp,"%s%s",cfg.dir[f.dir]->path,fname);
-										remove(tmp); 
+									if(removefile(smb, bf[i])) {
+										if(remfile) {
+											if(remove(getfilepath(&cfg, bf[i], path)) != 0)
+												errormsg(WHERE, ERR_REMOVE, path);
+										}
+										if(remcdt)
+											removefcdt(bf[i]);
 									}
-									if(remcdt)
-										removefcdt(&f); 
 								}
 								else if(ch=='M')
-									movefile(&f,usrdir[ml][md]); 
+									movefile(smb, bf[i], usrdir[ml][md]); 
 							} 
 						} 
 					}
 					if(strchr(str+c,'.'))
 						c+=strlen(str+c);
 					else if(str[c]<'A'+(char)total && str[c]>='A') {
-						f.dir=dirnum;
-						strcpy(f.name,bf[str[c]-'A'].name);
-						unpadfname(f.name,fname);
-						f.datoffset=bf[str[c]-'A'].datoffset;
-						f.dateuled=bf[str[c]-'A'].dateuled;
-						f.datedled=bf[str[c]-'A'].datedled;
-						f.size=0;
-						getfiledat(&cfg,&f);
-						if(f.opencount) {
-							bprintf(text[FileIsOpen]
-								,f.opencount,f.opencount>1 ? "s":nulstr);
-							continue; 
-						}
+						file_t* f = bf[str[c]-'A'];
 						if(ch=='R') {
-							removefile(&f);
-							if(remfile) {
-								sprintf(tmp,"%s%s",cfg.dir[f.dir]->path,fname);
-								remove(tmp); 
+							if(removefile(smb, f)) {
+								if(remfile) {
+									if(remove(getfilepath(&cfg, f, path)) != 0 && fexist(path))
+										errormsg(WHERE, ERR_REMOVE, path);
+								}
+								if(remcdt)
+									removefcdt(f);
 							}
-							if(remcdt)
-								removefcdt(&f); 
 						}
 						else if(ch=='M')
-							movefile(&f,usrdir[ml][md]); } 
+							movefile(smb, f, usrdir[ml][md]); 
+					} 
 				}
 				return(2); 
 			}
@@ -986,79 +730,40 @@ int sbbs_t::batchflagprompt(uint dirnum, file_t* bf, ulong* row, uint total
 /* action depending on 'mode.'                                              */
 /* Returns number of files matching filespec that were found                */
 /****************************************************************************/
-int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
+int sbbs_t::listfileinfo(uint dirnum, const char *filespec, long mode)
 {
-	char	str[258],path[258],dirpath[256],done=0,ch,fname[13],ext[513];
+	char	str[MAX_PATH + 1],path[MAX_PATH + 1],dirpath[MAX_PATH + 1],done=0,ch;
 	char 	tmp[512];
-	uchar	*ixbbuf,*usrxfrbuf=NULL,*p;
-	int		file;
 	int		error;
 	int		found=0;
     uint	i,j;
-	long	usrxfrlen=0;
-    long	m,l;
-	long	usrcdt;
+    size_t	m;
     time_t	start,end,t;
-    file_t	f;
+    file_t*	f;
 	struct	tm tm;
+	smb_t	smb;
 
-	sprintf(str,"%sxfer.ixt",cfg.data_dir);
-	if(mode==FI_USERXFER) {
-		if(flength(str)<1L)
-			return(0);
-		if((file=nopen(str,O_RDONLY))==-1) {
-			errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
-			return(0); 
-		}
-		usrxfrlen=(long)filelength(file);
-		if((usrxfrbuf=(uchar *)malloc(usrxfrlen))==NULL) {
-			close(file);
-			errormsg(WHERE,ERR_ALLOC,str,usrxfrlen);
-			return(0); 
-		}
-		if(read(file,usrxfrbuf,usrxfrlen)!=usrxfrlen) {
-			close(file);
-			free(usrxfrbuf);
-			errormsg(WHERE,ERR_READ,str,usrxfrlen);
-			return(0); 
-		}
-		close(file); 
-	}
-	sprintf(str,"%s%s.ixb",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-	if((file=nopen(str,O_RDONLY))==-1)
-		return(0);
-	l=(long)filelength(file);
-	if(!l) {
-		FREE_AND_NULL(usrxfrbuf);
-		close(file);
-		return(0); 
-	}
-	if((ixbbuf=(uchar *)malloc(l))==NULL) {
-		close(file);
-		FREE_AND_NULL(usrxfrbuf);
-		errormsg(WHERE,ERR_ALLOC,str,l);
-		return(0); 
-	}
-	if(lread(file,ixbbuf,l)!=l) {
-		close(file);
-		errormsg(WHERE,ERR_READ,str,l);
-		free((char *)ixbbuf);
-		if(usrxfrbuf)
-			free(usrxfrbuf);
-		return(0); 
-	}
-	close(file);
-	sprintf(str,"%s%s.dat",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-	if((file=nopen(str,O_RDONLY))==-1) {
-		errormsg(WHERE,ERR_READ,str,O_RDONLY);
-		free((char *)ixbbuf);
-		if(usrxfrbuf)
-			free(usrxfrbuf);
-		return(0); 
+	if(!smb_init_dir(&cfg, &smb, dirnum))
+		return 0;
+	if(smb_open_dir(&cfg, &smb, dirnum) != SMB_SUCCESS)
+		return 0;
+
+	size_t file_count = 0;
+	file_t* file_list = loadfiles(&smb
+		, filespec
+		, /* time_t */0
+		, file_detail_extdesc
+		, (enum file_sort)cfg.dir[dirnum]->sort
+		, &file_count);
+	if(file_list == NULL || file_count < 1) {
+		smb_close(&smb);
+		free(file_list);
+		return 0;
 	}
-	close(file);
+
 	m=0;
-	while(online && !done && m<l) {
+	while(online && !done && m < file_count) {
+		f = &file_list[m];
 		if(mode==FI_REMOVE && dir_op(dirnum))
 			action=NODE_SYSP;
 		else action=NODE_LFIL;
@@ -1066,167 +771,140 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 			found=-1;
 			break; 
 		}
-		for(i=0;i<12 && m<l;i++)
-			if(i==8)
-				str[i]=ixbbuf[m]>' ' ? '.' : ' ';
-			else
-				str[i]=ixbbuf[m++];     /* Turns FILENAMEEXT into FILENAME.EXT */
-		str[i]=0;
-		unpadfname(str,fname);
-		if(filespec[0] && !filematch(str,filespec)) {
-			m+=11;
-			continue; 
-		}
-		f.datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
-		f.dateuled=ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
-			|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24);
-		f.datedled=ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
-			|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24);
-		m+=11;
-		if(mode==FI_OLD && f.datedled>ns_time)
+		m++;
+		if(mode==FI_OLD && f->hdr.last_downloaded > ns_time)
 			continue;
-		if((mode==FI_OLDUL || mode==FI_OLD) && f.dateuled>ns_time)
+		if((mode==FI_OLDUL || mode==FI_OLD) && f->hdr.when_written.time > ns_time)
 			continue;
-		f.dir=curdirnum=dirnum;
-		strcpy(f.name,str);
-		f.size=0;
-		getfiledat(&cfg,&f);
-		if(mode==FI_OFFLINE && f.size>=0)
+		curdirnum = dirnum;
+		if(mode==FI_OFFLINE && getfilesize(&cfg, f) >= 0)
 			continue;
-		if(f.altpath>0 && f.altpath<=cfg.altpaths)
-			strcpy(dirpath,cfg.altpath[f.altpath-1]);
-		else
-			strcpy(dirpath,cfg.dir[f.dir]->path);
-		if(mode==FI_CLOSE && !f.opencount)
-			continue;
-		if(mode==FI_USERXFER) {
-			for(p=usrxfrbuf;p<usrxfrbuf+usrxfrlen;p+=24) {
-				sprintf(str,"%17.17s",p);   /* %4.4u %12.12s */
-				if(!strcmp(str+5,f.name) && useron.number==atoi(str))
-					break; 
-			}
-			if(p>=usrxfrbuf+usrxfrlen) /* file wasn't found */
-				continue; 
-		}
-		if((mode==FI_REMOVE) && (!dir_op(dirnum) && stricmp(f.uler
+		SAFECOPY(dirpath, cfg.dir[f->dir]->path);
+		if((mode==FI_REMOVE) && (!dir_op(dirnum) && stricmp(f->from
 			,useron.alias) && !(useron.exempt&FLAG('R'))))
 			continue;
 		found++;
 		if(mode==FI_INFO) {
-			if(!viewfile(&f,1)) {
-				done=1;
-				found=-1; } 
+			switch(viewfile(f, true)) {
+				case 0:
+					done=1;
+					found=-1;
+					break;
+				case -2:
+					m--;
+					if(m)
+						m--;
+					break;
+			} 
 		}
-		else
-			fileinfo(&f);
-		if(mode==FI_CLOSE) {
-			if(!noyes(text[CloseFileRecordQ])) {
-				f.opencount=0;
-				putfiledat(&cfg,&f); } 
+		else {
+			showfileinfo(f, /* show_extdesc: */mode != FI_DOWNLOAD);
+//			newline();
 		}
-		else if(mode==FI_REMOVE || mode==FI_OLD || mode==FI_OLDUL
+		if(mode==FI_REMOVE || mode==FI_OLD || mode==FI_OLDUL
 			|| mode==FI_OFFLINE) {
 			SYNC;
-			CRLF;
-			if(f.opencount) {
-				mnemonics(text[QuitOrNext]);
-				strcpy(str,"QN\r"); 
-			}
-			else if(dir_op(dirnum)) {
+//			CRLF;
+			SAFECOPY(str, "VEQRNP\b-\r");
+			if(dir_op(dirnum)) {
 				mnemonics(text[SysopRemoveFilePrompt]);
-				strcpy(str,"VEFMCQRN\r"); 
+				SAFECAT(str,"FMC");
 			}
 			else if(useron.exempt&FLAG('R')) {
 				mnemonics(text[RExemptRemoveFilePrompt]);
-				strcpy(str,"VEMQRN\r"); 
+				SAFECAT(str,"M");
 			}
-			else {
+			else
 				mnemonics(text[UserRemoveFilePrompt]);
-				strcpy(str,"VEQRN\r"); 
-			}
 			switch(getkeys(str,0)) {
 				case 'V':
-					viewfilecontents(&f);
+					viewfilecontents(f);
 					CRLF;
 					ASYNC;
 					pause();
-					m-=F_IXBSIZE;
+					m--;
 					continue;
 				case 'E':   /* edit file information */
 					if(dir_op(dirnum)) {
 						bputs(text[EditFilename]);
-						strcpy(str,fname);
-						if(!getstr(str,12,K_EDIT|K_AUTODEL))
+						SAFECOPY(str, f->name);
+						if(!getstr(str, MAX_FILENAME_LEN, K_EDIT|K_AUTODEL))
 							break;
-						if(strcmp(str,fname)) { /* rename */
-							padfname(str,path);
-							if(stricmp(str,fname)
-								&& findfile(&cfg,f.dir,path))
+						if(strcmp(str,f->name) != 0) { /* rename */
+							if(stricmp(str,f->name)
+								&& findfile(&cfg, f->dir, path, NULL))
 								bprintf(text[FileAlreadyThere],path);
 							else {
-								SAFEPRINTF2(path,"%s%s",dirpath,fname);
+								SAFEPRINTF2(path,"%s%s",dirpath,f->name);
 								SAFEPRINTF2(tmp,"%s%s",dirpath,str);
 								if(fexistcase(path) && rename(path,tmp))
 									bprintf(text[CouldntRenameFile],path,tmp);
 								else {
 									bprintf(text[FileRenamed],path,tmp);
-									strcpy(fname,str);
-									removefiledat(&cfg,&f);
-									strcpy(f.name,padfname(str,tmp));
-									addfiledat(&cfg,&f); 
+									smb_new_hfield_str(f, SMB_FILENAME, str);
+									updatefile(&cfg, f);
 								} 
 							} 
 						} 
 					}
+					// Description
 					bputs(text[EditDescription]);
-					getstr(f.desc,LEN_FDESC,K_LINE|K_EDIT|K_AUTODEL);
+					char fdesc[LEN_FDESC + 1];
+					SAFECOPY(fdesc, f->desc);
+					getstr(fdesc, sizeof(fdesc)-1, K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
 					if(sys_status&SS_ABORT)
 						break;
-					if(f.misc&FM_EXTDESC) {
+					if(strcmp(fdesc, f->desc))
+						smb_new_hfield_str(f, SMB_FILEDESC, fdesc);
+
+					// Tags
+					if((cfg.dir[dirnum]->misc & DIR_FILETAGS) || dir_op(dirnum)) {
+						char tags[64] = "";
+						bputs(text[TagFilePrompt]);
+						if(f->tags != NULL)
+							SAFECOPY(tags, f->tags);
+						getstr(tags, sizeof(tags)-1, K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
+						if(sys_status&SS_ABORT)
+							break;
+						if((f->tags == NULL && *tags != '\0') || (f->tags != NULL && strcmp(tags, f->tags)))
+							smb_new_hfield_str(f, SMB_TAGS, tags);
+					}
+					// Extended Description
+					if(f->extdesc != NULL && *f->extdesc) {
 						if(!noyes(text[DeleteExtDescriptionQ])) {
-							f.misc&=~FM_EXTDESC; }
+							// TODO
+						} 
 					}
 					if(!dir_op(dirnum)) {
-						putfiledat(&cfg,&f);
+						updatefile(&cfg, f);
 						break; 
 					}
+					char uploader[LEN_ALIAS + 1];
+					SAFECOPY(uploader, f->from);
 					bputs(text[EditUploader]);
-					if(!getstr(f.uler,LEN_ALIAS,K_EDIT|K_AUTODEL))
+					if(!getstr(uploader, sizeof(uploader), K_EDIT|K_AUTODEL))
 						break;
-					ultoa(f.cdt,str,10);
+					smb_new_hfield_str(f, SMB_FILEUPLOADER, uploader);
+					ultoa(f->cost,str,10);
 					bputs(text[EditCreditValue]);
 					getstr(str,10,K_NUMBER|K_EDIT|K_AUTODEL);
 					if(sys_status&SS_ABORT)
 						break;
-					f.cdt=atol(str);
-					ultoa(f.timesdled,str,10);
+					f->cost = atol(str);
+					smb_new_hfield(f, SMB_COST, sizeof(f->cost), &f->cost);
+					ultoa(f->hdr.times_downloaded,str,10);
 					bputs(text[EditTimesDownloaded]);
 					getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL);
 					if(sys_status&SS_ABORT)
 						break;
-					f.timesdled=atoi(str);
-					if(f.opencount) {
-						ultoa(f.opencount,str,10);
-						bputs(text[EditOpenCount]);
-						getstr(str,3,K_NUMBER|K_EDIT|K_AUTODEL);
-						f.opencount=atoi(str); 
-					}
-					if(cfg.altpaths || f.altpath) {
-						ultoa(f.altpath,str,10);
-						bputs(text[EditAltPath]);
-						getstr(str,3,K_NUMBER|K_EDIT|K_AUTODEL);
-						f.altpath=atoi(str);
-						if(f.altpath>cfg.altpaths)
-							f.altpath=0; 
-					}
+					f->hdr.times_downloaded=atoi(str);
 					if(sys_status&SS_ABORT)
 						break;
-					putfiledat(&cfg,&f);
-					inputnstime32(&f.dateuled);
-					update_uldate(&cfg, &f);
+					inputnstime32((time32_t*)&f->hdr.when_imported.time);
+					updatefile(&cfg, f);
 					break;
 				case 'F':   /* delete file only */
-					SAFEPRINTF2(str,"%s%s",dirpath,fname);
+					SAFEPRINTF2(str,"%s%s",dirpath,f->name);
 					if(!fexistcase(str))
 						bprintf(text[FileDoesNotExist],str);
 					else {
@@ -1234,9 +912,8 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 							if(remove(str))
 								bprintf(text[CouldntRemoveFile],str);
 							else {
-								sprintf(tmp,"deleted %s"
-									,str);
-								logline(nulstr,tmp); 
+								SAFEPRINTF(tmp, "deleted %s", str);
+								logline(nulstr, tmp); 
 							} 
 						} 
 					}
@@ -1244,69 +921,40 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 				case 'R':   /* remove file from database */
 					if(noyes(text[RemoveFileQ]))
 						break;
-					removefile(&f);
-					SAFEPRINTF2(str,"%s%s",dirpath,fname);
-					if(fexistcase(str)) {
-						if(dir_op(dirnum)) {
-							if(!noyes(text[DeleteFileQ])) {
-								if(remove(str))
-									bprintf(text[CouldntRemoveFile],str);
-								else {
-									sprintf(tmp,"deleted %s"
-										,str);
-									logline(nulstr,tmp); 
+					if(removefile(&smb, f)) {
+						getfilepath(&cfg, f, path);
+						if(fexistcase(path)) {
+							if(dir_op(dirnum)) {
+								if(!noyes(text[DeleteFileQ])) {
+									if(remove(path) != 0)
+										errormsg(WHERE, ERR_REMOVE, path);
+									else {
+										SAFEPRINTF(tmp, "deleted %s", path);
+										logline(nulstr,path); 
+									} 
 								} 
-							} 
+							}
+							else if(remove(str))    /* always remove if not sysop */
+								bprintf(text[CouldntRemoveFile],str);
 						}
-						else if(remove(str))    /* always remove if not sysop */
-							bprintf(text[CouldntRemoveFile],str); 
 					}
 					if(dir_op(dirnum) || useron.exempt&FLAG('R')) {
-						i=cfg.lib[cfg.dir[f.dir]->lib]->offline_dir;
+						i=cfg.lib[cfg.dir[f->dir]->lib]->offline_dir;
 						if(i!=dirnum && i!=INVALID_DIR
-							&& !findfile(&cfg,i,f.name)) {
+							&& !findfile(&cfg, i, f->name, NULL)) {
 							sprintf(str,text[AddToOfflineDirQ]
-								,fname,cfg.lib[cfg.dir[i]->lib]->sname,cfg.dir[i]->sname);
+								,f->name,cfg.lib[cfg.dir[i]->lib]->sname,cfg.dir[i]->sname);
 							if(yesno(str)) {
-								getextdesc(&cfg,f.dir,f.datoffset,ext);
-								f.dir=i;
-								addfiledat(&cfg,&f);
-								if(f.misc&FM_EXTDESC)
-									putextdesc(&cfg,f.dir,f.datoffset,ext); 
+								addfile(&cfg, i, f, f->extdesc);
 							} 
 						} 
 					}
-					if(dir_op(dirnum) || stricmp(f.uler,useron.alias)) {
+					if(dir_op(dirnum) || stricmp(f->from, useron.alias)) {
 						if(noyes(text[RemoveCreditsQ]))
 	/* Fall through */      break; 
 					}
 				case 'C':   /* remove credits only */
-					if((i=matchuser(&cfg,f.uler,TRUE /*sysop_alias*/))==0) {
-						bputs(text[UnknownUser]);
-						break; 
-					}
-					if(dir_op(dirnum)) {
-						usrcdt=(ulong)(f.cdt*(cfg.dir[f.dir]->up_pct/100.0));
-						if(f.timesdled)     /* all downloads */
-							usrcdt+=(ulong)((long)f.timesdled
-								*f.cdt*(cfg.dir[f.dir]->dn_pct/100.0));
-						ultoa(usrcdt,str,10);
-						bputs(text[CreditsToRemove]);
-						getstr(str,10,K_NUMBER|K_LINE|K_EDIT|K_AUTODEL);
-						f.cdt=atol(str); 
-					}
-					usrcdt=adjustuserrec(&cfg,i,U_CDT,10,-(long)f.cdt);
-					if(i==useron.number)
-						useron.cdt=usrcdt;
-					sprintf(str,text[FileRemovedUserMsg]
-						,f.name,f.cdt ? ultoac(f.cdt,tmp) : text[No]);
-					putsmsg(&cfg,i,str);
-					usrcdt=adjustuserrec(&cfg,i,U_ULB,10,-f.size);
-					if(i==useron.number)
-						useron.ulb=usrcdt;
-					usrcdt=adjustuserrec(&cfg,i,U_ULS,5,-1);
-					if(i==useron.number)
-						useron.uls=(ushort)usrcdt;
+					removefcdt(f);
 					break;
 				case 'M':   /* move the file to another dir */
 					CRLF;
@@ -1332,16 +980,24 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 						j=usrdirs[i]-1;
 					else j--;
 					CRLF;
-					movefile(&f,usrdir[i][j]);
+					movefile(&smb, f, usrdir[i][j]);
+					break;
+				case 'P':	/* previous */
+				case '-':
+				case '\b':
+					m--;
+					if(m)
+						m--;
 					break;
 				case 'Q':   /* quit */
 					found=-1;
 					done=1;
-					break; } 
+					break; 
+			} 
 		}
-		else if(mode==FI_DOWNLOAD || mode==FI_USERXFER) {
-			SAFEPRINTF2(path,"%s%s",dirpath,fname);
-			if(f.size<1L) { /* getfiledat will set this to -1 if non-existant */
+		else if(mode==FI_DOWNLOAD) {
+			getfilepath(&cfg, f, path);
+			if(getfilesize(&cfg, f) < 1L) { /* getfilesize will set this to -1 if non-existant */
 				SYNC;       /* and 0 byte files shouldn't be d/led */
 				mnemonics(text[QuitOrNext]);
 				if(getkeys("\rQ",0)=='Q') {
@@ -1350,8 +1006,8 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 				}
 				continue; 
 			}
-			if(!is_download_free(&cfg,f.dir,&useron,&client)
-				&& f.cdt>(useron.cdt+useron.freecdt)) {
+			if(!is_download_free(&cfg,f->dir,&useron,&client)
+				&& f->cost>(useron.cdt+useron.freecdt)) {
 				SYNC;
 				bprintf(text[YouOnlyHaveNCredits]
 					,ultoac(useron.cdt+useron.freecdt,tmp));
@@ -1362,7 +1018,7 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 				}
 				continue; 
 			}
-			if(!chk_ar(cfg.dir[f.dir]->dl_ar,&useron,&client)) {
+			if(!chk_ar(cfg.dir[f->dir]->dl_ar,&useron,&client)) {
 				SYNC;
 				bputs(text[CantDownloadFromDir]);
 				mnemonics(text[QuitOrNext]);
@@ -1372,7 +1028,8 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 				}
 				continue; 
 			}
-			if(!(cfg.dir[f.dir]->misc&DIR_TFREE) && f.timetodl>timeleft && !dir_op(dirnum)
+
+			if(!(cfg.dir[f->dir]->misc&DIR_TFREE) && gettimetodl(&cfg, f, cur_cps) > timeleft && !dir_op(dirnum)
 				&& !(useron.exempt&FLAG('T'))) {
 				SYNC;
 				bputs(text[NotEnoughTimeToDl]);
@@ -1384,15 +1041,13 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 				continue; 
 			}
 			xfer_prot_menu(XFER_DOWNLOAD);
-			openfile(&f);
 			SYNC;
 			mnemonics(text[ProtocolBatchQuitOrNext]);
 			sprintf(str,"B%cN\r",text[YNQP][2]);
 			for(i=0;i<cfg.total_prots;i++)
 				if(cfg.prot[i]->dlcmd[0]
 					&& chk_ar(cfg.prot[i]->ar,&useron,&client)) {
-					sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
-					strcat(str,tmp); 
+					sprintf(str + strlen(str), "%c", cfg.prot[i]->mnemonic);
 				}
 	//		  ungetkey(useron.prot);
 			ch=(char)getkeys(str,0);
@@ -1401,9 +1056,9 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 				done=1; 
 			}
 			else if(ch=='B') {
-				if(!addtobatdl(&f)) {
-					closefile(&f);
-					break; } 
+				if(!addtobatdl(f)) {
+					break; 
+				} 
 			}
 			else if(ch!=CR && ch!='N') {
 				for(i=0;i<cfg.total_prots;i++)
@@ -1411,97 +1066,68 @@ int sbbs_t::listfileinfo(uint dirnum, char *filespec, long mode)
 						&& chk_ar(cfg.prot[i]->ar,&useron,&client))
 						break;
 				if(i<cfg.total_prots) {
-					{
-						delfiles(cfg.temp_dir,ALLFILES);
-						if(cfg.dir[f.dir]->seqdev) {
-							lncntr=0;
-							seqwait(cfg.dir[f.dir]->seqdev);
-							bprintf(text[RetrievingFile],fname);
-							SAFEPRINTF2(str,"%s%s",dirpath,fname);
-							SAFEPRINTF2(path,"%s%s",cfg.temp_dir,fname);
-							mv(str,path,1); /* copy the file to temp dir */
-							if(getnodedat(cfg.node_num,&thisnode,true)==0) {
-								thisnode.aux=0xf0;
-								putnodedat(cfg.node_num,&thisnode);
-							}
-							CRLF; 
+					delfiles(cfg.temp_dir,ALLFILES);
+					if(cfg.dir[f->dir]->seqdev) {
+						lncntr=0;
+						seqwait(cfg.dir[f->dir]->seqdev);
+						bprintf(text[RetrievingFile],f->name);
+						getfilepath(&cfg, f, str);
+						SAFEPRINTF2(path,"%s%s",cfg.temp_dir,f->name);
+						mv(str,path,1); /* copy the file to temp dir */
+						if(getnodedat(cfg.node_num,&thisnode,true)==0) {
+							thisnode.aux=0xf0;
+							putnodedat(cfg.node_num,&thisnode);
 						}
-						for(j=0;j<cfg.total_dlevents;j++)
-							if(!stricmp(cfg.dlevent[j]->ext,f.name+9)
+						CRLF; 
+					}
+					const char* file_ext = getfext(f->name);
+					if(file_ext != NULL) {
+						for(j=0; j<cfg.total_dlevents; j++) {
+							if(!stricmp(cfg.dlevent[j]->ext, file_ext + 1)
 								&& chk_ar(cfg.dlevent[j]->ar,&useron,&client)) {
 								bputs(cfg.dlevent[j]->workstr);
 								external(cmdstr(cfg.dlevent[j]->cmd,path,nulstr,NULL)
 									,EX_OUTL);
 								CRLF; 
 							}
-						getnodedat(cfg.node_num,&thisnode,1);
-						action=NODE_DLNG;
-						t=now+f.timetodl;
-						localtime_r(&t,&tm);
-						thisnode.aux=(tm.tm_hour*60)+tm.tm_min;
-						putnodedat(cfg.node_num,&thisnode); /* calculate ETA */
-						start=time(NULL);
-						error=protocol(cfg.prot[i],XFER_DOWNLOAD,path,nulstr,false);
-						end=time(NULL);
-						if(cfg.dir[f.dir]->misc&DIR_TFREE)
-							starttime+=end-start;
-						if(checkprotresult(cfg.prot[i],error,&f))
-							downloadfile(&f);
-						else
-							notdownloaded(f.size,start,end); 
-						delfiles(cfg.temp_dir,ALLFILES);
-						autohangup(); 
-					} 
+						}
+					}
+					getnodedat(cfg.node_num,&thisnode,1);
+					action=NODE_DLNG;
+					t=now + gettimetodl(&cfg, f, cur_cps);
+					localtime_r(&t,&tm);
+					thisnode.aux=(tm.tm_hour*60)+tm.tm_min;
+					putnodedat(cfg.node_num,&thisnode); /* calculate ETA */
+					start=time(NULL);
+					error=protocol(cfg.prot[i],XFER_DOWNLOAD,path,nulstr,false);
+					end=time(NULL);
+					if(cfg.dir[f->dir]->misc&DIR_TFREE)
+						starttime+=end-start;
+					if(checkprotresult(cfg.prot[i],error, f))
+						downloadedfile(f);
+					else
+						notdownloaded(f->size, start, end); 
+					delfiles(cfg.temp_dir,ALLFILES);
+					autohangup(); 
 				} 
-			}
-			closefile(&f); 
+			} 
 		}
 		if(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?')) 
 			break; 
 	}
-	free((char *)ixbbuf);
-	if(usrxfrbuf)
-		free(usrxfrbuf);
+	freefiles(file_list, file_count);
+	smb_close(&smb);
 	return(found);
 }
 
 /****************************************************************************/
-/* Prints one file's information on a single line to a file 'file'          */
+/* Prints one file's information on a single line to a file stream 'fp'		*/
 /****************************************************************************/
-void sbbs_t::listfiletofile(char *fname, char *buf, uint dirnum, int file)
+void sbbs_t::listfiletofile(file_t* f, FILE* fp)
 {
-    char	str[256];
-	char 	tmp[512];
-    uchar	alt;
-    ulong	cdt;
-	bool	exist=true;
-
-	strcpy(str,fname);
-	if(buf[F_MISC]!=ETX && (buf[F_MISC]-' ')&FM_EXTDESC)
-		strcat(str,"+");
-	else
-		strcat(str," ");
-	write(file,str,13);
-	getrec((char *)buf,F_ALTPATH,2,str);
-	alt=(uchar)ahtoul(str);
-	sprintf(str,"%s%s",alt>0 && alt<=cfg.altpaths ? cfg.altpath[alt-1]
-		: cfg.dir[dirnum]->path,unpadfname(fname,tmp));
-	if(cfg.dir[dirnum]->misc&DIR_FCHK && !fexistcase(str))
-		exist=false;
-	getrec((char *)buf,F_CDT,LEN_FCDT,str);
-	cdt=atol(str);
-	if(!cdt)
-		strcpy(str,"   FREE");
-	else
-		sprintf(str,"%7lu",cdt);
-	if(exist)
-		strcat(str," ");
-	else
-		strcat(str,"-");
-	write(file,str,8);
-	getrec((char *)buf,F_DESC,LEN_FDESC,str);
-	write(file,str,strlen(str));
-	write(file,crlf,2);
+	char fname[13];	/* This is one of the only 8.3 filename formats left! (used for display purposes only) */
+	fprintf(fp, "%-*s %10lu %s\r\n", (int)sizeof(fname)-1, format_filename(f->name, fname, sizeof(fname)-1, /* pad: */TRUE)
+		,(ulong)getfilesize(&cfg, f), f->desc);
 }
 
 int extdesclines(char *str)
diff --git a/src/sbbs3/load_cfg.c b/src/sbbs3/load_cfg.c
index 815d0b7f8e..a25fe5989d 100644
--- a/src/sbbs3/load_cfg.c
+++ b/src/sbbs3/load_cfg.c
@@ -176,9 +176,6 @@ void prep_cfg(scfg_t* cfg)
 	for(i=0;i<cfg->total_libs;i++) {
 		if(cfg->lib[i]->parent_path[0])
 			prep_dir(cfg->ctrl_dir, cfg->lib[i]->parent_path, sizeof(cfg->lib[i]->parent_path));
-	}
-
-	for(i=0;i<cfg->total_libs;i++) {
 		if((cfg->lib[i]->misc&LIB_DIRS) == 0 || cfg->lib[i]->parent_path[0] == 0)
 			continue;
 		char path[MAX_PATH+1];
@@ -495,3 +492,85 @@ ushort DLLCALL sys_timezone(scfg_t* cfg)
 
 	return(cfg->sys_timezone);
 }
+
+
+int DLLCALL smb_storage_mode(scfg_t* cfg, smb_t* smb)
+{
+	if(smb == NULL || smb->subnum == INVALID_SUB || (smb->status.attr&SMB_EMAIL))
+		return (cfg->sys_misc&SM_FASTMAIL) ? SMB_FASTALLOC : SMB_SELFPACK;
+	if(smb->subnum >= cfg->total_subs)
+		return (smb->status.attr&SMB_HYPERALLOC) ? SMB_HYPERALLOC : SMB_FASTALLOC;
+	if(cfg->sub[smb->subnum]->misc&SUB_HYPER) {
+		smb->status.attr |= SMB_HYPERALLOC;
+		return SMB_HYPERALLOC;
+	}
+	if(cfg->sub[smb->subnum]->misc&SUB_FAST)
+		return SMB_FASTALLOC;
+	return SMB_SELFPACK;
+}
+
+/* Open Synchronet Message Base and create, if necessary (e.g. first time opened) */
+/* If return value is not SMB_SUCCESS, sub-board is not left open */
+int DLLCALL smb_open_sub(scfg_t* cfg, smb_t* smb, unsigned int subnum)
+{
+	int retval;
+	smbstatus_t smb_status = {0};
+
+	if(subnum != INVALID_SUB && subnum >= cfg->total_subs)
+		return SMB_FAILURE;
+	memset(smb, 0, sizeof(smb_t));
+	if(subnum == INVALID_SUB) {
+		SAFEPRINTF(smb->file, "%smail", cfg->data_dir);
+		smb_status.max_crcs	= cfg->mail_maxcrcs;
+		smb_status.max_msgs	= 0;
+		smb_status.max_age	= cfg->mail_maxage;
+		smb_status.attr		= SMB_EMAIL;
+	} else {
+		SAFEPRINTF2(smb->file, "%s%s", cfg->sub[subnum]->data_dir, cfg->sub[subnum]->code);
+		smb_status.max_crcs	= cfg->sub[subnum]->maxcrcs;
+		smb_status.max_msgs	= cfg->sub[subnum]->maxmsgs;
+		smb_status.max_age	= cfg->sub[subnum]->maxage;
+		smb_status.attr		= cfg->sub[subnum]->misc&SUB_HYPER ? SMB_HYPERALLOC :0;
+	}
+	smb->retry_time = cfg->smb_retry_time;
+	if((retval = smb_open(smb)) == SMB_SUCCESS) {
+		if(smb_fgetlength(smb->shd_fp) < sizeof(smbhdr_t) + sizeof(smb->status)) {
+			smb->status = smb_status;
+			if((retval = smb_create(smb)) != SMB_SUCCESS)
+				smb_close(smb);
+		}
+		if(retval == SMB_SUCCESS)
+			smb->subnum = subnum;
+	}
+	return retval;
+}
+
+BOOL DLLCALL smb_init_dir(scfg_t* cfg, smb_t* smb, unsigned int dirnum)
+{
+	if(dirnum >= cfg->total_dirs)
+		return FALSE;
+	memset(smb, 0, sizeof(smb_t));
+	SAFEPRINTF2(smb->file, "%s%s", cfg->dir[dirnum]->data_dir, cfg->dir[dirnum]->code);
+	smb->retry_time = cfg->smb_retry_time;
+	return TRUE;
+}
+
+int DLLCALL smb_open_dir(scfg_t* cfg, smb_t* smb, unsigned int dirnum)
+{
+	int retval;
+
+	if(!smb_init_dir(cfg, smb, dirnum))
+		return SMB_FAILURE;
+	if((retval = smb_open(smb)) != SMB_SUCCESS)
+		return retval;
+	smb->dirnum = dirnum;
+	if(filelength(fileno(smb->shd_fp)) < 1) {
+		smb->status.max_files	= cfg->dir[dirnum]->maxfiles;
+		smb->status.max_age		= cfg->dir[dirnum]->maxage;
+		smb->status.attr		= SMB_FILE_DIRECTORY;
+		if(cfg->dir[dirnum]->misc & DIR_NOHASH)
+			smb->status.attr |= SMB_NOHASH;
+		smb_create(smb);
+	}
+	return SMB_SUCCESS;
+}
diff --git a/src/sbbs3/load_cfg.h b/src/sbbs3/load_cfg.h
index 2523d282e2..63e256a123 100644
--- a/src/sbbs3/load_cfg.h
+++ b/src/sbbs3/load_cfg.h
@@ -23,6 +23,7 @@
 #define _LOAD_CFG_H_
 
 #include "scfgdefs.h"	// scfg_t
+#include "smblib.h"
 #include "dllexport.h"
 
 #ifdef __cplusplus
@@ -36,6 +37,10 @@ DLLEXPORT ushort	sys_timezone(scfg_t* cfg);
 DLLEXPORT char *	prep_dir(const char* base, char* dir, size_t buflen);
 DLLEXPORT char *	prep_code(char *str, const char* prefix);
 DLLEXPORT int 		md(const char *path);
+DLLEXPORT int		smb_storage_mode(scfg_t*, smb_t*);
+DLLEXPORT int		smb_open_sub(scfg_t*, smb_t*, unsigned int subnum);
+DLLEXPORT BOOL		smb_init_dir(scfg_t*, smb_t*, unsigned int dirnum);
+DLLEXPORT int		smb_open_dir(scfg_t*, smb_t*, unsigned int dirnum);
 
 #ifdef __cplusplus
 }
diff --git a/src/sbbs3/logfile.cpp b/src/sbbs3/logfile.cpp
index b4d92520aa..a81dd245d7 100644
--- a/src/sbbs3/logfile.cpp
+++ b/src/sbbs3/logfile.cpp
@@ -142,7 +142,7 @@ void sbbs_t::logentry(const char *code, const char *entry)
 /****************************************************************************/
 /* Writes 'str' verbatim into node.log 										*/
 /****************************************************************************/
-void sbbs_t::log(char *str)
+void sbbs_t::log(const char *str)
 {
 	if(logfile_fp==NULL || online==ON_LOCAL) return;
 	if(logcol>=78 || (78-logcol)<strlen(str)) {
diff --git a/src/sbbs3/logon.cpp b/src/sbbs3/logon.cpp
index dfd0504445..e36827d651 100644
--- a/src/sbbs3/logon.cpp
+++ b/src/sbbs3/logon.cpp
@@ -21,6 +21,7 @@
 
 #include "sbbs.h"
 #include "cmdshell.h"
+#include "filedat.h"
 
 extern "C" void client_on(SOCKET sock, client_t* client, BOOL update);
 
@@ -217,8 +218,46 @@ bool sbbs_t::logon()
 	useron.ltoday++;
 
 	gettimeleft();
-	safe_snprintf(str, sizeof(str), "%sfile/%04u.dwn",cfg.data_dir,useron.number);
-	batch_add_list(str);
+
+	/* Inform the user of what's in their batch upload queue */
+	{
+		str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_UPLOAD);
+		str_list_t filenames = iniGetSectionList(ini, NULL);
+		for(size_t i = 0; filenames[i] != NULL; i++) {
+			const char* filename = filenames[i];
+			file_t f = {{}};
+			if(batch_file_get(&cfg, ini, filename, &f)) {
+				bprintf(text[FileAddedToUlQueue], f.name, i + 1, cfg.max_batup);
+				smb_freefilemem(&f);
+			} else
+				batch_file_remove(&cfg, useron.number, XFER_BATCH_UPLOAD, filename);
+		}
+		iniFreeStringList(ini);
+		iniFreeStringList(filenames);
+	}
+
+	/* Inform the user of what's in their batch download queue */
+	{
+		str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+		str_list_t filenames = iniGetSectionList(ini, NULL);
+		for(size_t i = 0; filenames[i] != NULL; i++) {
+			const char* filename = filenames[i];
+			file_t f = {{}};
+			if(batch_file_load(&cfg, ini, filename, &f)) {
+				char tmp2[256];
+				getfilesize(&cfg, &f);
+				bprintf(text[FileAddedToBatDlQueue]
+					,f.name, i + 1, cfg.max_batdn
+					,ultoac((ulong)f.cost,tmp)
+					,ultoac((ulong)f.size,tmp2)
+					,sectostr((ulong)f.size / (ulong)cur_cps,str));
+				smb_freefilemem(&f);
+			} else
+				batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
+		}
+		iniFreeStringList(ini);
+		iniFreeStringList(filenames);
+	}
 	if(!(sys_status&SS_QWKLOGON)) { 	 /* QWK Nodes don't go through this */
 
 		if(cfg.sys_pwdays && useron.pass[0]
@@ -511,10 +550,6 @@ bool sbbs_t::logon()
 
 	if(criterrs && SYSOP)
 		bprintf(text[CriticalErrors],criterrs);
-	if((i=getuserxfers(0,useron.number,0))!=0)
-		bprintf(text[UserXferForYou],i,i>1 ? "s" : nulstr); 
-	if((i=getuserxfers(useron.number,0,0))!=0)
-		bprintf(text[UnreceivedUserXfer],i,i>1 ? "s" : nulstr);
 	SYNC;
 	sys_status&=~SS_PAUSEON;	/* Turn off the pause override flag */
 	if(online==ON_REMOTE)
diff --git a/src/sbbs3/logout.cpp b/src/sbbs3/logout.cpp
index 0d3003febf..01861f0909 100644
--- a/src/sbbs3/logout.cpp
+++ b/src/sbbs3/logout.cpp
@@ -57,11 +57,9 @@ void sbbs_t::logout()
 
 	if(useron.rest&FLAG('G')) {
 		putuserrec(&cfg,useron.number,U_NAME,LEN_NAME,nulstr);		
-		batdn_total=0; 
+		clearbatdl();
 	}
 
-	batch_create_list();
-
 	if(sys_status&SS_USERON && thisnode.status!=NODE_QUIET && !(useron.rest&FLAG('Q')))
 		for(i=1;i<=cfg.sys_nodes;i++)
 			if(i!=cfg.node_num) {
@@ -86,7 +84,6 @@ void sbbs_t::logout()
 		lprintf(LOG_DEBUG, "executing logout module: %s", cfg.logout_mod);
 		exec_bin(cfg.logout_mod,&main_csi);
 	}
-	backout();
 	SAFEPRINTF2(path,"%smsgs/%4.4u.msg",cfg.data_dir,useron.number);
 	if(fexistcase(path) && !flength(path))		/* remove any 0 byte message files */
 		remove(path);
@@ -154,60 +151,6 @@ void sbbs_t::logout()
 	lprintf(LOG_DEBUG, "logout completed");
 }
 
-/****************************************************************************/
-/* Backout of transactions and statuses for this node 						*/
-/****************************************************************************/
-void sbbs_t::backout()
-{
-	char path[MAX_PATH+1],code[128],*buf;
-	int i,file;
-	long length,l;
-	file_t f;
-
-	SAFEPRINTF(path,"%sbackout.dab",cfg.node_dir);
-	if(flength(path)<1L) {
-		remove(path);
-		return; 
-	}
-	if((file=nopen(path,O_RDONLY))==-1) {
-		errormsg(WHERE,ERR_OPEN,path,O_RDONLY);
-		return; 
-	}
-	length=(long)filelength(file);
-	if((buf=(char *)malloc(length))==NULL) {
-		close(file);
-		errormsg(WHERE,ERR_ALLOC,path,length);
-		return; 
-	}
-	if(read(file,buf,length)!=length) {
-		close(file);
-		free(buf);
-		errormsg(WHERE,ERR_READ,path,length);
-		return; 
-	}
-	close(file);
-	for(l=0;l<length;l+=BO_LEN) {
-		switch(buf[l]) {
-			case BO_OPENFILE:	/* file left open */
-				memcpy(code,buf+l+1,8);
-				code[8]=0;
-				for(i=0;i<cfg.total_dirs;i++)			/* search by code */
-					if(!stricmp(cfg.dir[i]->code,code))
-						break;
-				if(i<cfg.total_dirs) {		/* found internal code */
-					f.dir=i;
-					memcpy(&f.datoffset,buf+l+9,4);
-					closefile(&f); 
-				}
-				break;
-			default:
-				errormsg(WHERE,ERR_CHK,path,buf[l]); 
-		} 
-	}
-	free(buf);
-	remove(path);	/* always remove the backout file */
-}
-
 /****************************************************************************/
 /* Detailed usage stats for each logon                                      */
 /****************************************************************************/
diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c
index 17295323c8..3e28e00cc7 100644
--- a/src/sbbs3/mailsrvr.c
+++ b/src/sbbs3/mailsrvr.c
@@ -45,7 +45,8 @@
 #include "multisock.h"
 #include "ssl.h"
 #include "cryptlib.h"
-#include "ver.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 /* Constants */
 static const char*	server_name="Synchronet Mail Server";
@@ -1296,7 +1297,7 @@ static void pop3_thread(void* arg)
 			strlwr(user.pass);	/* this is case-sensitive, so convert to lowercase */
 			strcat(challenge,user.pass);
 			MD5_calc(digest,challenge,strlen(challenge));
-			MD5_hex((BYTE*)str,digest);
+			MD5_hex(str,digest);
 			if(strcmp(str,response)) {
 				lprintf(LOG_NOTICE,"%04d %s [%s] !FAILED APOP authentication: %s"
 					,socket, client.protocol, host_ip, username);
@@ -2837,7 +2838,7 @@ static void smtp_thread(void* arg)
 	ulong		lines=0;
 	ulong		hdr_lines=0;
 	ulong		hdr_len=0;
-	ulong		length;
+	off_t		length;
 	ulong		badcmds=0;
 	ulong		login_attempts;
 	ulong		waiting;
@@ -3252,14 +3253,14 @@ static void smtp_thread(void* arg)
 					else
 						safe_snprintf(str,sizeof(str),"%s%s%s",head,sender_addr,tail);
 
-					if((telegram_buf=(char*)malloc(length+strlen(str)+1))==NULL) {
+					if((telegram_buf=(char*)malloc((size_t)(length+strlen(str)+1)))==NULL) {
 						lprintf(LOG_CRIT,"%04d %s %s !ERROR allocating %lu bytes of memory for telegram from %s"
 							,socket, client.protocol, client_id, length+strlen(str)+1,sender_addr);
 						sockprintf(socket,client.protocol,session, insuf_stor);
 						continue; 
 					}
 					strcpy(telegram_buf,str);	/* can't use SAFECOPY here */
-					if(fread(telegram_buf+strlen(str),1,length,msgtxt)!=length) {
+					if(fread(telegram_buf+strlen(str),1,(size_t)length,msgtxt)!=length) {
 						lprintf(LOG_ERR,"%04d %s %s !ERROR reading %lu bytes from telegram file"
 							,socket, client.protocol, client_id, length);
 						sockprintf(socket,client.protocol,session, insuf_stor);
@@ -3689,14 +3690,14 @@ static void smtp_thread(void* arg)
 					continue;
 				}
 
-				if((msgbuf=(char*)malloc(length+1))==NULL) {
+				if((msgbuf=(char*)malloc((size_t)(length+1)))==NULL) {
 					lprintf(LOG_CRIT,"%04d %s %s !ERROR allocating %lu bytes of memory"
 						,socket, client.protocol, client_id, length+1);
 					sockprintf(socket,client.protocol,session, insuf_stor);
 					subnum=INVALID_SUB;
 					continue;
 				}
-				fread(msgbuf,length,1,msgtxt);
+				fread(msgbuf,(size_t)length,1,msgtxt);
 				msgbuf[length]=0;	/* ASCIIZ */
 
 				/* Do external JavaScript processing here? */
@@ -3757,7 +3758,7 @@ static void smtp_thread(void* arg)
 						for(i=0;hashes[i];i++)
 							lprintf(LOG_DEBUG,"%04d %s %s Message %s crc32=%x flags=%x length=%u"
 								,socket, client.protocol, client_id, smb_hashsourcetype(hashes[i]->source)
-								,hashes[i]->crc32, hashes[i]->flags, hashes[i]->length);
+								,hashes[i]->data.crc32, hashes[i]->flags, hashes[i]->length);
 
 						lprintf(LOG_DEBUG, "%04d %s %s Searching SPAM database for a match", socket, client.protocol, client_id);
 						if((i=smb_findhash(&spam, hashes, &found, sources, /* Mark: */TRUE))==SMB_SUCCESS) {
@@ -4270,7 +4271,7 @@ static void smtp_thread(void* arg)
 				md5_data[i]=secret[i]^0x5c;	/* opad */
 			memcpy(md5_data+i,digest,sizeof(digest));
 			MD5_calc(digest,md5_data,sizeof(secret)+sizeof(digest));
-			MD5_hex((BYTE*)str,digest);
+			MD5_hex(str,digest);
 			if(strcmp(p,str)) {
 				lprintf(LOG_WARNING,"%04d SMTP %s !%s FAILED CRAM-MD5 authentication"
 					,socket, client_id, relay_user.alias);
@@ -5721,8 +5722,7 @@ static void sendmail_thread(void* arg)
 								md5_data[i]=secret[i]^0x5c;	/* opad */
 							memcpy(md5_data+i,digest,sizeof(digest));
 							MD5_calc(digest,md5_data,sizeof(secret)+sizeof(digest));
-							
-							safe_snprintf(buf,sizeof(buf),"%s %s",startup->relay_user,MD5_hex((BYTE*)str,digest));
+							safe_snprintf(buf,sizeof(buf),"%s %s",startup->relay_user,MD5_hex(str,digest));
 							b64_encode(p=resp,sizeof(resp),buf,strlen(buf));
 							break;
 						default:
@@ -5956,7 +5956,7 @@ const char* DLLCALL mail_ver(void)
 #else
 		,""
 #endif
-		,git_branch, git_hash
+		,GIT_BRANCH, GIT_HASH
 		,__DATE__, __TIME__, compiler
 		);
 
@@ -6061,7 +6061,7 @@ void DLLCALL mail_server(void* arg)
 
 		DESCRIBE_COMPILER(compiler);
 
-		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", git_branch, git_hash, __DATE__, __TIME__, compiler);
+		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, compiler);
 
 		sbbs_srand();
 
diff --git a/src/sbbs3/mailsrvr.vcxproj b/src/sbbs3/mailsrvr.vcxproj
index 76235c4c64..c4de8b7065 100644
--- a/src/sbbs3/mailsrvr.vcxproj
+++ b/src/sbbs3/mailsrvr.vcxproj
@@ -191,7 +191,6 @@
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <ClCompile Include="nopen.c" />
-    <ClCompile Include="ver.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\xpdev\xpdev_mt.vcxproj">
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index ed2d051a45..fec739c8fc 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -105,6 +105,12 @@ static	link_list_t current_connections;
 int	thread_suid_broken=TRUE;			/* NPTL is no longer broken */
 #endif
 
+/* convenient space-saving global variables */
+extern "C" {
+const char* crlf="\r\n";
+const char* nulstr="";
+};
+
 #define GCES(status, node, sess, action) do {                          \
 	char *GCES_estr;                                                    \
 	int GCES_level;                                                      \
@@ -429,6 +435,10 @@ void* DLLCALL js_GetClassPrivate(JSContext *cx, JSObject *obj, JSClass* cls)
 {
 	void *ret = JS_GetInstancePrivate(cx, obj, cls, NULL);
 
+	/*
+	 * NOTE: Any changes here should also be added to the same function in jsdoor.c
+	 *       (ie: anything not Synchronet specific).
+	 */
 	if(ret == NULL)
 		JS_ReportError(cx, "'%s' instance: No Private Data or Class Mismatch"
 			, cls == NULL ? "???" : cls->name);
@@ -692,6 +702,10 @@ DLLCALL js_DefineSyncProperties(JSContext *cx, JSObject *obj, jsSyncPropertySpec
 {
 	uint i;
 
+	/*
+	 * NOTE: Any changes here should also be added to the same function in jsdoor.c
+	 *       (ie: anything not Synchronet specific).
+	 */
 	for(i=0;props[i].name;i++) {
 		if (props[i].tinyid < 256 && props[i].tinyid > -129) {
 			if(!JS_DefinePropertyWithTinyId(cx, obj,
@@ -713,6 +727,10 @@ DLLCALL js_DefineSyncMethods(JSContext* cx, JSObject* obj, jsSyncMethodSpec *fun
 {
 	uint i;
 
+	/*
+	 * NOTE: Any changes here should also be added to the same function in jsdoor.c
+	 *       (ie: anything not Synchronet specific).
+	 */
 	for(i=0;funcs[i].name;i++)
 		if(!JS_DefineFunction(cx, obj, funcs[i].name, funcs[i].call, funcs[i].nargs, 0))
 			return(JS_FALSE);
@@ -725,6 +743,10 @@ DLLCALL js_SyncResolve(JSContext* cx, JSObject* obj, char *name, jsSyncPropertyS
 	uint i;
 	jsval	val;
 
+	/*
+	 * NOTE: Any changes here should also be added to the same function in jsdoor.c
+	 *       (ie: anything not Synchronet specific).
+	 */
 	if(props) {
 		for(i=0;props[i].name;i++) {
 			if(name==NULL || strcmp(name, props[i].name)==0) {
@@ -1410,10 +1432,16 @@ extern "C" BOOL DLLCALL js_CreateCommonObjects(JSContext* js_cx
 		node_cfg=cfg;
 
 	/* Global Object */
-	if(!js_CreateGlobalObject(js_cx, cfg, methods, js_startup, glob))
+	if(!js_CreateGlobalObject(js_cx, node_cfg, methods, js_startup, glob))
 		return(FALSE);
 
 	do {
+		/*
+		 * NOTE: Where applicable, anything added here should also be added to
+		 *       the same function in jsdoor.c (ie: anything not Synchronet
+		 *       specific).
+		 */
+
 		/* System Object */
 		if(js_CreateSystemObject(js_cx, *glob, node_cfg, uptime, host_name, socklib_desc)==NULL)
 			break;
@@ -1445,10 +1473,18 @@ extern "C" BOOL DLLCALL js_CreateCommonObjects(JSContext* js_cx
 		if(js_CreateMsgBaseClass(js_cx, *glob, cfg)==NULL)
 			break;
 
+		/* FileBase Class */
+		if(js_CreateFileBaseClass(js_cx, *glob, node_cfg)==NULL)
+			break;
+
 		/* File Class */
 		if(js_CreateFileClass(js_cx, *glob)==NULL)
 			break;
 
+		/* Archive Class */
+		if(js_CreateArchiveClass(js_cx, *glob)==NULL)
+			break;
+
 		/* User class */
 		if(js_CreateUserClass(js_cx, *glob, cfg)==NULL)
 			break;
@@ -2609,8 +2645,6 @@ void event_thread(void* arg)
 					sbbs->getusrsubs();
 					bool success = sbbs->unpack_rep(g.gl_pathv[i]);
 					sbbs->delfiles(sbbs->cfg.temp_dir,ALLFILES);		/* clean-up temp_dir after unpacking */
-					sbbs->batch_create_list();	/* FREQs? */
-					sbbs->batdn_total=0;
 					sbbs->online=FALSE;
 					sbbs->console&=~CON_L_ECHO;
 
@@ -2664,11 +2698,8 @@ void event_thread(void* arg)
 					sbbs->console|=CON_L_ECHO;
 					sbbs->getmsgptrs();
 					sbbs->getusrsubs();
-					sbbs->batdn_total=0;
 
 					sbbs->last_ns_time=sbbs->ns_time=sbbs->useron.ns_time;
-					SAFEPRINTF2(bat_list,"%sfile/%04u.dwn",sbbs->cfg.data_dir,sbbs->useron.number);
-					sbbs->batch_add_list(bat_list);
 
 					SAFEPRINTF3(str,"%sfile%c%04u.qwk"
 						,sbbs->cfg.data_dir,PATH_DELIM,sbbs->useron.number);
@@ -2723,7 +2754,6 @@ void event_thread(void* arg)
 						sbbs->console|=CON_L_ECHO;
 						sbbs->getmsgptrs();
 						sbbs->getusrsubs();
-						sbbs->batdn_total=0;
 						SAFEPRINTF3(str,"%sfile%c%04u.qwk"
 							,sbbs->cfg.data_dir,PATH_DELIM,sbbs->useron.number);
 						if(sbbs->pack_qwk(str,&l,true /* pre-pack */)) {
@@ -2878,7 +2908,7 @@ void event_thread(void* arg)
 					|| (sbbs->cfg.qhub[i]->time
 						&& (now_tm.tm_hour*60)+now_tm.tm_min>=sbbs->cfg.qhub[i]->time
 						&& (now_tm.tm_mday!=tm.tm_mday || now_tm.tm_mon!=tm.tm_mon)))
-					&& sbbs->cfg.qhub[i]->days&(1<<now_tm.tm_wday))) {
+							&& sbbs->cfg.qhub[i]->days&(1<<now_tm.tm_wday))) {
 				SAFEPRINTF2(str,"%sqnet/%s.now"
 					,sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id);
 				if(fexistcase(str)) {
@@ -3418,19 +3448,6 @@ sbbs_t::sbbs_t(ushort node_num, union xp_sockaddr *addr, size_t addr_len, const
 	usrdir=NULL;
 	usrlib_total=0;
 
-	batup_desc=NULL;
-	batup_name=NULL;
-	batup_misc=NULL;
-	batup_dir=NULL;
-	batup_alt=NULL;
-
-	batdn_name=NULL;
-	batdn_dir=NULL;
-	batdn_offset=NULL;
-	batdn_size=NULL;
-	batdn_alt=NULL;
-	batdn_cdt=NULL;
-
 	/* used by update_qwkroute(): */
 	qwknode=NULL;
 	total_qwknodes=0;
@@ -3454,7 +3471,6 @@ sbbs_t::sbbs_t(ushort node_num, union xp_sockaddr *addr, size_t addr_len, const
     usrgrps = 0;
     usrlibs = 0;
     comspec = 0;
-    altul = 0;
     noaccess_str = 0;
     noaccess_val = 0;
     cur_output_rate = output_rate_unlimited;
@@ -3607,9 +3623,6 @@ bool sbbs_t::init()
 		putnodedat(cfg.node_num,&thisnode);
 	}
 
-/** Put in if(cfg.node_num) ? (not needed for server and event threads) */
-	backout();
-
 	/* Reset COMMAND SHELL */
 
 	main_csi.str=(char *)malloc(1024);
@@ -3704,73 +3717,6 @@ bool sbbs_t::init()
 			}
 	}
 
-	if(cfg.max_batup) {
-
-		if((batup_desc=(char **)malloc(sizeof(char *)*cfg.max_batup))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batup_desc", sizeof(char *)*cfg.max_batup);
-			return(false);
-		}
-		if((batup_name=(char **)malloc(sizeof(char *)*cfg.max_batup))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batup_name", sizeof(char *)*cfg.max_batup);
-			return(false);
-		}
-		if((batup_misc=(long *)malloc(sizeof(long)*cfg.max_batup))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batup_misc", sizeof(char *)*cfg.max_batup);
-			return(false);
-		}
-		if((batup_dir=(uint *)malloc(sizeof(uint)*cfg.max_batup))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batup_dir", sizeof(char *)*cfg.max_batup);
-			return(false);
-		}
-		if((batup_alt=(ushort *)malloc(sizeof(ushort)*cfg.max_batup))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batup_alt", sizeof(char *)*cfg.max_batup);
-			return(false);
-		}
-		for(i=0;i<cfg.max_batup;i++) {
-			if((batup_desc[i]=(char *)malloc(LEN_FDESC+1))==NULL) {
-				errormsg(WHERE, ERR_ALLOC, "batup_desc[x]", LEN_FDESC+1);
-				return(false);
-			}
-			if((batup_name[i]=(char *)malloc(13))==NULL) {
-				errormsg(WHERE, ERR_ALLOC, "batup_name[x]", 13);
-				return(false);
-			}
-		}
-	}
-
-	if(cfg.max_batdn) {
-
-		if((batdn_name=(char **)malloc(sizeof(char *)*cfg.max_batdn))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batdn_name", sizeof(char *)*cfg.max_batdn);
-			return(false);
-		}
-		if((batdn_dir=(uint *)malloc(sizeof(uint)*cfg.max_batdn))==NULL)  {
-			errormsg(WHERE, ERR_ALLOC, "batdn_dir", sizeof(uint)*cfg.max_batdn);
-			return(false);
-		}
-		if((batdn_offset=(long *)malloc(sizeof(long)*cfg.max_batdn))==NULL)  {
-			errormsg(WHERE, ERR_ALLOC, "batdn_offset", sizeof(long)*cfg.max_batdn);
-			return(false);
-		}
-		if((batdn_size=(ulong *)malloc(sizeof(ulong)*cfg.max_batdn))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batdn_size", sizeof(ulong)*cfg.max_batdn);
-			return(false);
-		}
-		if((batdn_cdt=(ulong *)malloc(sizeof(ulong)*cfg.max_batdn))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batdn_cdt", sizeof(long)*cfg.max_batdn);
-			return(false);
-		}
-		if((batdn_alt=(ushort *)malloc(sizeof(ushort)*cfg.max_batdn))==NULL) {
-			errormsg(WHERE, ERR_ALLOC, "batdn_alt", sizeof(ushort)*cfg.max_batdn);
-			return(false);
-		}
-		for(i=0;i<cfg.max_batdn;i++)
-			if((batdn_name[i]=(char *)malloc(13))==NULL) {
-				errormsg(WHERE, ERR_ALLOC, "batdn_name[x]", 13);
-				return(false);
-			}
-	}
-
 #ifdef USE_CRYPTLIB
 	pthread_mutex_init(&ssh_mutex,NULL);
 	ssh_mutex_created = true;
@@ -3882,29 +3828,6 @@ sbbs_t::~sbbs_t()
 	FREE_AND_NULL(usrdirs);
 	FREE_AND_NULL(usrdir);
 
-	/* Batch upload vars */
-	for(i=0;i<cfg.max_batup && batup_desc!=NULL && batup_name!=NULL;i++) {
-		FREE_AND_NULL(batup_desc[i]);
-		FREE_AND_NULL(batup_name[i]);
-	}
-
-	FREE_AND_NULL(batup_desc);
-	FREE_AND_NULL(batup_name);
-	FREE_AND_NULL(batup_misc);
-	FREE_AND_NULL(batup_dir);
-	FREE_AND_NULL(batup_alt);
-
-	/* Batch download vars */
-	for(i=0;i<cfg.max_batdn && batdn_name!=NULL;i++)
-		FREE_AND_NULL(batdn_name[i]);
-
-	FREE_AND_NULL(batdn_name);
-	FREE_AND_NULL(batdn_dir);
-	FREE_AND_NULL(batdn_offset);
-	FREE_AND_NULL(batdn_size);
-	FREE_AND_NULL(batdn_cdt);
-	FREE_AND_NULL(batdn_alt);
-
 	listFree(&savedlines);
 	listFree(&smb_list);
 	listFree(&mouse_hotspots);
@@ -4238,12 +4161,10 @@ void sbbs_t::reset_logon_vars(void)
     autoterm=0;
 	cterm_version = 0;
     lbuflen=0;
-    altul=0;
     timeleft_warn=0;
 	keybufbot=keybuftop=0;
     logon_uls=logon_ulb=logon_dls=logon_dlb=0;
     logon_posts=logon_emails=logon_fbacks=0;
-    batdn_total=batup_total=0;
     usrgrps=usrlibs=0;
     curgrp=curlib=0;
 	for(i=0;i<cfg.total_libs;i++)
@@ -4357,10 +4278,9 @@ void sbbs_t::logoffstats()
 			stats.ttoday+=(uint32_t)(now-logontime)/60;
 			stats.ptoday+=logon_posts;
 		}
-		stats.uls+=logon_uls;
-		stats.ulb+=logon_ulb;
-		stats.dls+=logon_dls;
-		stats.dlb+=logon_dlb;
+		stats.uls+=(uint32_t)logon_uls;
+		stats.ulb+=(uint32_t)logon_ulb;
+		// logon_dls and logons_dlb are now handled in user_downloaded_file()
 		stats.etoday+=logon_emails;
 		stats.ftoday+=logon_fbacks;
 
@@ -4965,14 +4885,6 @@ void DLLCALL bbs_thread(void* arg)
 
 	status("Initializing");
 
-	/* Defeat the lameo hex0rs - the name and copyright must remain intact */
-	if(crc32(COPYRIGHT_NOTICE,0)!=COPYRIGHT_CRC
-		|| crc32(VERSION_NOTICE,10)!=SYNCHRONET_CRC) {
-		lprintf(LOG_CRIT,"!CORRUPTED LIBRARY FILE");
-		cleanup(1);
-		return;
-	}
-
 	memset(text, 0, sizeof(text));
     memset(&scfg, 0, sizeof(scfg));
 
diff --git a/src/sbbs3/makeuser.vcxproj b/src/sbbs3/makeuser.vcxproj
index 8588ea262e..551490ad33 100644
--- a/src/sbbs3/makeuser.vcxproj
+++ b/src/sbbs3/makeuser.vcxproj
@@ -94,6 +94,7 @@
       </DataExecutionPrevention>
       <TargetMachine>MachineX86</TargetMachine>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+      <AdditionalDependencies>netapi32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <Bscmake>
       <SuppressStartupBanner>true</SuppressStartupBanner>
@@ -137,6 +138,7 @@
       </DataExecutionPrevention>
       <TargetMachine>MachineX86</TargetMachine>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+      <AdditionalDependencies>netapi32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <Bscmake>
       <SuppressStartupBanner>true</SuppressStartupBanner>
diff --git a/src/sbbs3/msg_id.c b/src/sbbs3/msg_id.c
index cfde952467..471f9fd992 100644
--- a/src/sbbs3/msg_id.c
+++ b/src/sbbs3/msg_id.c
@@ -21,7 +21,8 @@
 
 #include "msg_id.h"
 #include "smblib.h"
-#include "ver.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 static ulong msg_number(smbmsg_t* msg)
 {
@@ -244,7 +245,7 @@ char* DLLCALL msg_program_id(char* pid, size_t maxlen)
 	DESCRIBE_COMPILER(compiler);
 	snprintf(pid, maxlen, "%.10s %s%c-%s %s/%s %s %s"
 		,VERSION_NOTICE,VERSION,REVISION,PLATFORM_DESC
-		,git_branch, git_hash
+		,GIT_BRANCH, GIT_HASH
 		,__DATE__,compiler);
 	return pid;
 }
diff --git a/src/sbbs3/msgdate.c b/src/sbbs3/msgdate.c
index d2ce643933..a09e71d9f8 100644
--- a/src/sbbs3/msgdate.c
+++ b/src/sbbs3/msgdate.c
@@ -161,11 +161,3 @@ when_t DLLCALL rfc822date(char* date)
 
 	return(when);
 }
-
-BOOL DLLCALL newmsgs(smb_t* smb, time_t t)
-{
-	char index_fname[MAX_PATH + 1];
-
-	SAFEPRINTF(index_fname, "%s.sid", smb->file);
-	return fdate(index_fname) >= t;
-}
diff --git a/src/sbbs3/msgdate.h b/src/sbbs3/msgdate.h
index 5df0564ff4..70d2ff6b49 100644
--- a/src/sbbs3/msgdate.h
+++ b/src/sbbs3/msgdate.h
@@ -33,9 +33,8 @@ extern "C" {
 
 DLLEXPORT when_t	rfc822date(char* p);
 DLLEXPORT char *	msgdate(when_t when, char* buf);
-DLLEXPORT BOOL		newmsgs(smb_t*, time_t);
 
 #ifdef __cplusplus
 }
 #endif
-#endif /* Don't add anything after this line */
\ No newline at end of file
+#endif /* Don't add anything after this line */
diff --git a/src/sbbs3/netmail.cpp b/src/sbbs3/netmail.cpp
index 248dbc0378..733465d5d1 100644
--- a/src/sbbs3/netmail.cpp
+++ b/src/sbbs3/netmail.cpp
@@ -367,7 +367,8 @@ void sbbs_t::qwktonetmail(FILE *rep, char *block, char *into, uchar fromhub)
 	int 	i,fido,inet=0,qnet=0;
 	uint16_t net;
 	uint16_t xlat;
-	long	l,offset,length,m,n;
+	long	l,length,m,n;
+	off_t offset;
 	faddr_t fidoaddr;
     fmsghdr_t hdr;
 	smbmsg_t msg;
@@ -709,7 +710,7 @@ void sbbs_t::qwktonetmail(FILE *rep, char *block, char *into, uchar fromhub)
 			smb_fputc(ch,smb.sdt_fp);
 		smb_fflush(smb.sdt_fp);
 
-		msg.hdr.offset=offset;
+		msg.hdr.offset=(uint32_t)offset;
 
 		smb_dfield(&msg,TEXT_BODY,length);
 
@@ -1099,7 +1100,7 @@ bool sbbs_t::inetmail(const char *into, const char *subj, long mode, smb_t* resm
 		errormsg(WHERE,ERR_OPEN,msgpath,O_RDONLY|O_BINARY);
 		return(false); 
 	}
-	off_t length = filelength(file);
+	long length = (long)filelength(file);
 	if(length < 1) {
 		strListFree(&rcpt_list);
 		fclose(instream);
@@ -1263,7 +1264,8 @@ bool sbbs_t::qnetmail(const char *into, const char *subj, long mode, smb_t* resm
 	const char*	charset=NULL;
 	ushort	xlat=XLAT_NONE,net=NET_QWK,touser;
 	int 	i,j,x,file;
-	ulong	length,offset;
+	ulong	length;
+	off_t offset;
 	FILE	*instream;
 	smbmsg_t msg;
 
@@ -1384,7 +1386,7 @@ bool sbbs_t::qnetmail(const char *into, const char *subj, long mode, smb_t* resm
 	}
 
 	setvbuf(instream,NULL,_IOFBF,2*1024);
-	fseek(smb.sdt_fp,offset,SEEK_SET);
+	fseeko(smb.sdt_fp,offset,SEEK_SET);
 	xlat=XLAT_NONE;
 	fwrite(&xlat,2,1,smb.sdt_fp);
 	x=SDT_BLOCK_LEN-2;				/* Don't read/write more than 255 */
@@ -1408,7 +1410,7 @@ bool sbbs_t::qnetmail(const char *into, const char *subj, long mode, smb_t* resm
 	msg.hdr.when_written.time=msg.hdr.when_imported.time=time32(NULL);
 	msg.hdr.when_written.zone=msg.hdr.when_imported.zone=sys_timezone(&cfg);
 
-	msg.hdr.offset=offset;
+	msg.hdr.offset=(uint32_t)offset;
 
 	net=NET_QWK;
 	smb_hfield_str(&msg,RECIPIENT,to);
diff --git a/src/sbbs3/node.c b/src/sbbs3/node.c
index e23fd52e8c..5de4ef2cd1 100644
--- a/src/sbbs3/node.c
+++ b/src/sbbs3/node.c
@@ -517,7 +517,7 @@ int main(int argc, char **argv)
 	sprintf(str,"%snode.exb",ctrl_dir);
 	nodeexb=sopen(str,O_RDWR|O_BINARY,SH_DENYNO);
 
-	sys_nodes=filelength(nodefile)/sizeof(node_t);
+	sys_nodes=(int)(filelength(nodefile)/sizeof(node_t));
 	if(!sys_nodes) {
 		printf("%s reflects 0 nodes!\n",str);
 		exit(1); }
diff --git a/src/sbbs3/nodedefs.h b/src/sbbs3/nodedefs.h
index 7e3a829252..31b7c97f21 100644
--- a/src/sbbs3/nodedefs.h
+++ b/src/sbbs3/nodedefs.h
@@ -108,13 +108,11 @@ enum node_action {                  /* Node Action */
 	,NODE_LAST_ACTION				/* Must be last */
     };
 
-#if defined(_WIN32) || defined(__BORLANDC__)	/* necessary for compatibility with SBBS v2 */
-	#pragma pack(push,1)
-#endif
+#pragma pack(push,1)
 
 #define SIZEOF_NODE_T 15			/* Must == sizeof(node_t) */
 
-typedef struct _PACK {					/* Node information kept in node.dab */
+typedef struct {					/* Node information kept in node.dab */
 	uchar		status,                 /* Current Status of Node (enum node_status) */
 				errors,                 /* Number of Critical Errors */
 				action;                 /* Action User is doing on Node (enum node_action) */
@@ -130,8 +128,6 @@ typedef struct _PACK {					/* Node information kept in node.dab */
     uint32_t   extaux;					/* Extended aux dword for node */
 	} node_t;
 
-#if defined(_WIN32) || defined(__BORLANDC__)
 #pragma pack(pop)		/* original packing */
-#endif
 
 #endif /* Don't add anything after this line */
diff --git a/src/sbbs3/objects.mk b/src/sbbs3/objects.mk
index e88c6d7434..1599921131 100644
--- a/src/sbbs3/objects.mk
+++ b/src/sbbs3/objects.mk
@@ -41,6 +41,7 @@ OBJS	=	$(MTOBJODIR)$(DIRSEP)ansiterm$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)inkey$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)ident$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)jsdebug$(OFILE)\
+			$(MTOBJODIR)$(DIRSEP)js_archive$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_bbs$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_client$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_com$(OFILE)\
@@ -54,6 +55,7 @@ OBJS	=	$(MTOBJODIR)$(DIRSEP)ansiterm$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)js_internal$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_msg_area$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_msgbase$(OFILE)\
+			$(MTOBJODIR)$(DIRSEP)js_filebase$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_queue$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_request$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)js_rtpool$(OFILE)\
@@ -95,7 +97,6 @@ OBJS	=	$(MTOBJODIR)$(DIRSEP)ansiterm$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)scfglib2$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)scfgsave$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)sockopts$(OFILE)\
-			$(MTOBJODIR)$(DIRSEP)sortdir$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)str$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)str_util$(OFILE)\
 			$(MTOBJODIR)$(DIRSEP)telgate$(OFILE)\
@@ -174,7 +175,6 @@ SMBUTIL_OBJS = \
 
 SBBSECHO_OBJS = \
 			$(OBJODIR)$(DIRSEP)sbbsecho$(OFILE) \
-			$(OBJODIR)$(DIRSEP)ver$(OFILE) \
 			$(OBJODIR)$(DIRSEP)ars$(OFILE) \
 			$(OBJODIR)$(DIRSEP)date_str$(OFILE) \
 			$(OBJODIR)$(DIRSEP)load_cfg$(OFILE) \
@@ -184,6 +184,7 @@ SBBSECHO_OBJS = \
 			$(OBJODIR)$(DIRSEP)nopen$(OFILE) \
 			$(OBJODIR)$(DIRSEP)str_util$(OFILE) \
 			$(OBJODIR)$(DIRSEP)dat_rec$(OFILE) \
+			$(OBJODIR)$(DIRSEP)filedat$(OFILE) \
 			$(OBJODIR)$(DIRSEP)userdat$(OFILE) \
 			$(OBJODIR)$(DIRSEP)rechocfg$(OFILE) \
 			$(OBJODIR)$(DIRSEP)msg_id$(OFILE) \
@@ -222,7 +223,8 @@ FILELIST_OBJS = \
 			$(OBJODIR)$(DIRSEP)nopen$(OFILE) \
 			$(OBJODIR)$(DIRSEP)str_util$(OFILE) \
 			$(OBJODIR)$(DIRSEP)dat_rec$(OFILE) \
-			$(OBJODIR)$(DIRSEP)filedat$(OFILE)
+			$(OBJODIR)$(DIRSEP)filedat$(OFILE) \
+			$(OBJODIR)$(DIRSEP)userdat$(OFILE)
 
 MAKEUSER_OBJS = \
 			$(OBJODIR)$(DIRSEP)makeuser$(OFILE) \
@@ -248,6 +250,7 @@ JSDOOR_OBJS = \
 			$(MTOBJODIR)$(DIRSEP)dat_rec$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)jsdoor$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)jsdebug$(OFILE) \
+			$(MTOBJODIR)$(DIRSEP)js_archive$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)js_uifc$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)js_conio$(OFILE) \
 			$(MTOBJODIR)$(DIRSEP)js_request$(OFILE) \
@@ -317,6 +320,7 @@ DELFILES_OBJS = \
 			$(OBJODIR)$(DIRSEP)ars$(OFILE) \
 			$(OBJODIR)$(DIRSEP)nopen$(OFILE) \
 			$(OBJODIR)$(DIRSEP)filedat$(OFILE) \
+			$(OBJODIR)$(DIRSEP)userdat$(OFILE) \
 			$(OBJODIR)$(DIRSEP)dat_rec$(OFILE)
 
 DUPEFIND_OBJS = \
@@ -353,3 +357,14 @@ PKTDUMP_OBJS =		$(OBJODIR)$(DIRSEP)pktdump$(OFILE)
 
 FMSGDUMP_OBJS = 	$(OBJODIR)$(DIRSEP)fmsgdump$(OFILE)
 
+UPGRADE_TO_V319_OBJS =	$(OBJODIR)$(DIRSEP)upgrade_to_v319$(OFILE) \
+			$(OBJODIR)$(DIRSEP)filedat$(OFILE) \
+			$(OBJODIR)$(DIRSEP)userdat$(OFILE) \
+			$(OBJODIR)$(DIRSEP)dat_rec$(OFILE) \
+			$(OBJODIR)$(DIRSEP)load_cfg$(OFILE) \
+			$(OBJODIR)$(DIRSEP)scfglib1$(OFILE) \
+			$(OBJODIR)$(DIRSEP)scfglib2$(OFILE) \
+			$(OBJODIR)$(DIRSEP)str_util$(OFILE) \
+			$(OBJODIR)$(DIRSEP)ars$(OFILE) \
+			$(OBJODIR)$(DIRSEP)nopen$(OFILE)
+
diff --git a/src/sbbs3/pack_qwk.cpp b/src/sbbs3/pack_qwk.cpp
index 6c3371a1c1..80975d8188 100644
--- a/src/sbbs3/pack_qwk.cpp
+++ b/src/sbbs3/pack_qwk.cpp
@@ -21,6 +21,7 @@
 
 #include "sbbs.h"
 #include "qwk.h"
+#include "filedat.h"
 
 /****************************************************************************/
 /* Creates QWK packet, returning 1 if successful, 0 if not. 				*/
@@ -28,7 +29,9 @@
 bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 {
 	char	str[MAX_PATH+1],ch;
-	char 	tmp[MAX_PATH+1],tmp2[MAX_PATH+1];
+	char 	tmp[MAX_PATH+1];
+	char	path[MAX_PATH+1];
+	char	error[256];
 	char*	fname;
 	int 	mode;
 	uint	i,j,k,conf;
@@ -36,8 +39,7 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 	uint32_t posts;
 	uint32_t mailmsgs=0;
 	uint32_t u;
-	ulong	totalcdt,totaltime
-			,files,submsgs,msgs,netfiles=0,preqwk=0;
+	ulong	files,submsgs,msgs,netfiles=0,preqwk=0;
 	uint32_t	lastmsg;
 	ulong	subs_scanned=0;
 	float	f;	/* Sparky is responsible */
@@ -67,17 +69,31 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 	delfiles(cfg.temp_dir,ALLFILES);
 	SAFEPRINTF2(str,"%sfile/%04u.qwk",cfg.data_dir,useron.number);
 	if(fexistcase(str)) {
-		for(k=0;k<cfg.total_fextrs;k++)
-			if(!stricmp(cfg.fextr[k]->ext,useron.tmpext)
-				&& chk_ar(cfg.fextr[k]->ar,&useron,&client))
-				break;
-		if(k>=cfg.total_fextrs)
-			k=0;
-		p=cmdstr(cfg.fextr[k]->cmd,str,ALLFILES,NULL);
-		if((i=external(p,ex))==0)
-			preqwk=1; 
-		else 
-			errormsg(WHERE,ERR_EXEC,p,i);
+		long file_count = extract_files_from_archive(str
+			,/* outdir: */cfg.temp_dir
+			,/* allowed_filename_chars: */NULL /* any */
+			,/* with_path: */false
+			,/* max_files: */0 /* unlimited */
+			,/* file_list: */NULL /* all files */
+			,error, sizeof(error));
+		if(file_count > 0) {
+			lprintf(LOG_DEBUG, "libarchive extracted %lu files from %s", file_count, str);
+			preqwk = TRUE;
+		} else {
+			if(*error)
+				lprintf(LOG_NOTICE, "libarchive error (%s) extracting %s", error, str);
+			for(k=0;k<cfg.total_fextrs;k++)
+				if(!stricmp(cfg.fextr[k]->ext,useron.tmpext)
+					&& chk_ar(cfg.fextr[k]->ar,&useron,&client))
+					break;
+			if(k>=cfg.total_fextrs)
+				k=0;
+			p=cmdstr(cfg.fextr[k]->cmd,str,ALLFILES,NULL);
+			if((i=external(p,ex))==0)
+				preqwk=1; 
+			else 
+				errormsg(WHERE,ERR_EXEC,p,i);
+		}
 	}
 
 	if(useron.qwk&QWK_EXPCTLA)
@@ -616,11 +632,11 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 			SAFEPRINTF3(str,"%sqnet/%s.out/%s",cfg.data_dir,id,dirent->d_name);
 			if(isdir(str))
 				continue;
-			SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,dirent->d_name);
+			SAFEPRINTF2(path,"%s%s",cfg.temp_dir,dirent->d_name);
 			lncntr=0;	/* Defeat pause */
 			lprintf(LOG_INFO,"Including %s in packet",str);
 			bprintf(text[RetrievingFile],str);
-			if(!mv(str,tmp2,/* copy: */TRUE))
+			if(!mv(str,path,/* copy: */TRUE))
 				netfiles++;
 		}
 		if(dir!=NULL)
@@ -628,47 +644,40 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 		if(netfiles)
 			CRLF; 
 	}
-
-	if(batdn_total) {
-		for(i=0,totalcdt=0;i<batdn_total;i++)
-			if(!is_download_free(&cfg,batdn_dir[i],&useron,&client))
-				totalcdt+=batdn_cdt[i];
-		if(totalcdt>useron.cdt+useron.freecdt) {
-			bprintf(text[YouOnlyHaveNCredits]
-				,ultoac(useron.cdt+useron.freecdt,tmp)); 
-		}
-		else {
-			for(i=0,totaltime=0;i<batdn_total;i++) {
-				if(!(cfg.dir[batdn_dir[i]]->misc&DIR_TFREE) && cur_cps)
-					totaltime+=batdn_size[i]/(ulong)cur_cps; 
+	{
+		int64_t totalcdt = 0;
+		str_list_t ini = batch_list_read(&cfg, useron.number, XFER_BATCH_DOWNLOAD);
+		str_list_t filenames = iniGetSectionList(ini, NULL);
+		for(size_t i = 0; filenames[i] != NULL; i++) {
+			const char* filename = filenames[i];
+			file_t f = {{}};
+			if(!batch_file_load(&cfg, ini, filename, &f))
+				continue;
+			if(!is_download_free(&cfg, f.dir, &useron, &client)) {
+				if(totalcdt + f.cost > (int64_t)(useron.cdt+useron.freecdt)) {
+					bprintf(text[YouOnlyHaveNCredits]
+						,ultoac(useron.cdt+useron.freecdt,tmp));
+					batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
+					continue;
+				}
+				totalcdt += f.cost;
 			}
-			if(!(useron.exempt&FLAG('T')) && !SYSOP && totaltime>timeleft)
-				bputs(text[NotEnoughTimeToDl]);
-			else {
-				for(i=0;i<batdn_total;i++) {
-					lncntr=0;
-					unpadfname(batdn_name[i],tmp);
-					SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,tmp);
-					if(!fexistcase(tmp2)) {
-						seqwait(cfg.dir[batdn_dir[i]]->seqdev);
-						bprintf(text[RetrievingFile],tmp);
-						SAFEPRINTF2(str,"%s%s"
-							,batdn_alt[i]>0 && batdn_alt[i]<=cfg.altpaths
-							? cfg.altpath[batdn_alt[i]-1]
-							: cfg.dir[batdn_dir[i]]->path
-							,tmp);
-						mv(str,tmp2,/* copy: */TRUE); /* copy the file to temp dir */
-						getnodedat(cfg.node_num,&thisnode,/* copy: */TRUE);
-						thisnode.aux=0xfe;
-						putnodedat(cfg.node_num,&thisnode);
-						CRLF; 
-					} 
-				} 
-			} 
-		} 
+			lncntr=0;
+			SAFEPRINTF2(tmp, "%s%s", cfg.temp_dir, filename);
+			if(!fexistcase(tmp)) {
+				seqwait(cfg.dir[f.dir]->seqdev);
+				getfilepath(&cfg, &f, path);
+				bprintf(text[RetrievingFile], path);
+				if(mv(path, tmp,/* copy: */TRUE) != 0) /* copy the file to temp dir */
+					batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
+				CRLF;
+			}
+		}
+		iniFreeStringList(ini);
+		iniFreeStringList(filenames);
 	}
 
-	if(!(*msgcnt) && !mailmsgs && !files && !netfiles && !batdn_total && !voting_data
+	if(!(*msgcnt) && !mailmsgs && !files && !netfiles && !batdn_total() && !voting_data
 		&& (prepack || !preqwk)) {
 		if(online == ON_REMOTE)
 			bputs(text[QWKNoNewMessages]);
@@ -681,28 +690,28 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 		/***********************/
 		SAFEPRINTF(str,"%sQWK/HELLO",cfg.text_dir);
 		if(fexistcase(str)) {
-			SAFEPRINTF(tmp2,"%sHELLO",cfg.temp_dir);
-			mv(str,tmp2,/* copy: */TRUE); 
+			SAFEPRINTF(path,"%sHELLO",cfg.temp_dir);
+			mv(str,path,/* copy: */TRUE); 
 		}
 		SAFEPRINTF(str,"%sQWK/BBSNEWS",cfg.text_dir);
 		if(fexistcase(str)) {
-			SAFEPRINTF(tmp2,"%sBBSNEWS",cfg.temp_dir);
-			mv(str,tmp2,/* copy: */TRUE); 
+			SAFEPRINTF(path,"%sBBSNEWS",cfg.temp_dir);
+			mv(str,path,/* copy: */TRUE); 
 		}
 		SAFEPRINTF(str,"%sQWK/GOODBYE",cfg.text_dir);
 		if(fexistcase(str)) {
-			SAFEPRINTF(tmp2,"%sGOODBYE",cfg.temp_dir);
-			mv(str,tmp2,/* copy: */TRUE); 
+			SAFEPRINTF(path,"%sGOODBYE",cfg.temp_dir);
+			mv(str,path,/* copy: */TRUE); 
 		}
 		SAFEPRINTF(str,"%sQWK/BLT-*",cfg.text_dir);
 		glob(str,0,NULL,&g);
 		for(i=0;i<(uint)g.gl_pathc;i++) { 			/* Copy BLT-*.* files */
 			fname=getfname(g.gl_pathv[i]);
-			padfname(fname,str);
-			if(IS_DIGIT(str[4]) && IS_DIGIT(str[9])) {
+			char* fext = getfext(fname);
+			if(IS_DIGIT(str[4]) && fext != NULL && IS_DIGIT(*(fext + 1))) {
 				SAFEPRINTF2(str,"%sQWK/%s",cfg.text_dir,fname);
-				SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,fname);
-				mv(str,tmp2,/* copy: */TRUE); 
+				SAFEPRINTF2(path,"%s%s",cfg.temp_dir,fname);
+				mv(str,path,/* copy: */TRUE); 
 			}
 		}
 		globfree(&g);
@@ -718,15 +727,21 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 	/*******************/
 	/* Compress Packet */
 	/*******************/
-	SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,ALLFILES);
-	i=external(cmdstr(temp_cmd(),packet,tmp2,NULL)
-		,ex|EX_WILDCARD);
+	SAFEPRINTF2(path,"%s%s",cfg.temp_dir,ALLFILES);
+	if(strListFind((str_list_t)supported_archive_formats, useron.tmpext, /* case_sensitive */FALSE) >= 0) {
+		str_list_t file_list = directory(path);
+		long file_count = create_archive(packet, useron.tmpext, /* with_path: */false, file_list, error, sizeof(error));
+		strListFree(&file_list);
+		if(file_count < 0)
+			lprintf(LOG_ERR, "libarchive error (%s) creating %s", error, packet);
+		else
+			lprintf(LOG_INFO, "libarchive created %s from %ld files", packet, file_count);
+	} else {
+		if((i = external(cmdstr(temp_cmd(),packet,path,NULL), ex|EX_WILDCARD)) != 0)
+			errormsg(WHERE,ERR_EXEC,cmdstr(temp_cmd(),packet,path,NULL),i);
+	}
 	if(!fexist(packet)) {
 		bputs(text[QWKCompressionFailed]);
-		if(i)
-			errormsg(WHERE,ERR_EXEC,cmdstr(temp_cmd(),packet,tmp2,NULL),i);
-		else
-			lprintf(LOG_ERR, "Couldn't compress QWK packet");
 		return(false); 
 	}
 
diff --git a/src/sbbs3/pack_rep.cpp b/src/sbbs3/pack_rep.cpp
index 86b3e5297d..190bba9ebb 100644
--- a/src/sbbs3/pack_rep.cpp
+++ b/src/sbbs3/pack_rep.cpp
@@ -21,6 +21,7 @@
 
 #include "sbbs.h"
 #include "qwk.h"
+#include "filedat.h"
 
 /****************************************************************************/
 /* Creates an REP packet for upload to QWK hub 'hubnum'.                    */
@@ -32,6 +33,7 @@ bool sbbs_t::pack_rep(uint hubnum)
 	char 		tmp[MAX_PATH+1],tmp2[MAX_PATH+1];
 	char		hubid_upper[LEN_QWKID+1];
 	char		hubid_lower[LEN_QWKID+1];
+	char		error[256];
 	int 		mode;
 	const char* fmode;
 	uint		i,j,k;
@@ -61,7 +63,21 @@ bool sbbs_t::pack_rep(uint hubnum)
 	SAFEPRINTF2(str,"%s%s.REP",cfg.data_dir,hubid_upper);
 	if(fexistcase(str)) {
 		lprintf(LOG_INFO,"Updating %s", str);
-		external(cmdstr(cfg.qhub[hubnum]->unpack,str,ALLFILES,NULL),EX_OFFLINE);
+		long file_count = extract_files_from_archive(str
+			,/* outdir: */cfg.temp_dir
+			,/* allowed_filename_chars: */NULL /* any */
+			,/* with_path: */false
+			,/* max_files: */0 /* unlimited */
+			,/* file_list: */NULL /* all files */
+			,error, sizeof(error));
+		if(file_count > 0) {
+			lprintf(LOG_DEBUG, "libarchive extracted %lu files from %s", file_count, str);
+		} else {
+			if(*error)
+				lprintf(LOG_NOTICE, "libarchive error (%s) extracting %s", error, str);
+			if(*cfg.qhub[hubnum]->unpack)
+				external(cmdstr(cfg.qhub[hubnum]->unpack,str,ALLFILES,NULL),EX_OFFLINE);
+		}
 	} else
 		lprintf(LOG_INFO,"Creating %s", str);
 	/*************************************************/
@@ -268,14 +284,23 @@ bool sbbs_t::pack_rep(uint hubnum)
 	/*******************/
 	SAFEPRINTF2(str,"%s%s.REP",cfg.data_dir,hubid_upper);
 	SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,ALLFILES);
-	i=external(cmdstr(cfg.qhub[hubnum]->pack,str,tmp2,NULL)
-		,EX_OFFLINE|EX_WILDCARD);
-	if(!fexistcase(str)) {
-		lprintf(LOG_WARNING,"%s",remove_ctrl_a(text[QWKCompressionFailed],tmp));
+	if(strListFind((str_list_t)supported_archive_formats, cfg.qhub[hubnum]->fmt, /* case_sensitive */FALSE) >= 0) {
+		str_list_t file_list = directory(tmp2);
+		long file_count = create_archive(str, cfg.qhub[hubnum]->fmt, /* with_path: */false, file_list, error, sizeof(error));
+		strListFree(&file_list);
+		if(file_count < 0)
+			lprintf(LOG_ERR, "libarchive error %ld (%s) creating %s", file_count, error, str);
+		else
+			lprintf(LOG_INFO, "libarchive created %s from %ld files", str, file_count);
+	} else {
+		i=external(cmdstr(cfg.qhub[hubnum]->pack,str,tmp2,NULL)
+			,EX_OFFLINE|EX_WILDCARD);
 		if(i)
 			errormsg(WHERE,ERR_EXEC,cmdstr(cfg.qhub[hubnum]->pack,str,tmp2,NULL),i);
-		else
-			lprintf(LOG_ERR, "Couldn't compress REP packet");
+	}
+	if(!fexistcase(str)) {
+		lprintf(LOG_WARNING,"%s",remove_ctrl_a(text[QWKCompressionFailed],tmp));
+		lprintf(LOG_ERR, "Couldn't compress REP packet");
 		return(false); 
 	}
 	SAFEPRINTF2(str,"%sqnet/%s.out/",cfg.data_dir,hubid_lower);
diff --git a/src/sbbs3/postmsg.cpp b/src/sbbs3/postmsg.cpp
index a370c45c49..05a34a4f79 100644
--- a/src/sbbs3/postmsg.cpp
+++ b/src/sbbs3/postmsg.cpp
@@ -1,7 +1,4 @@
 /* Synchronet user create/post public message routine */
-// vi: tabstop=4
-
-/* $Id: postmsg.cpp,v 1.135 2020/08/15 21:58:14 rswindell Exp $ */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -16,26 +13,15 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include "sbbs.h"
 #include "utf8.h"
+#include "filedat.h"
 
 int msgbase_open(scfg_t* cfg, smb_t* smb, unsigned int subnum, int* storage, long* dupechk_hashes, uint16_t* xlat)
 {
@@ -378,9 +364,9 @@ extern "C" void DLLCALL signal_sub_sem(scfg_t* cfg, uint subnum)
 
 	/* signal semaphore files */
 	if(cfg->sub[subnum]->misc&SUB_FIDO && cfg->echomail_sem[0])		
-		ftouch(cmdstr(cfg,NULL,cfg->echomail_sem,nulstr,nulstr,str));
+		ftouch(cmdstr(cfg,NULL,cfg->echomail_sem,nulstr,nulstr,str,sizeof(str)));
 	if(cfg->sub[subnum]->post_sem[0]) 
-		ftouch(cmdstr(cfg,NULL,cfg->sub[subnum]->post_sem,nulstr,nulstr,str));
+		ftouch(cmdstr(cfg,NULL,cfg->sub[subnum]->post_sem,nulstr,nulstr,str,sizeof(str)));
 }
 
 extern "C" int DLLCALL msg_client_hfields(smbmsg_t* msg, client_t* client)
@@ -507,8 +493,10 @@ extern "C" int DLLCALL savemsg(scfg_t* cfg, smb_t* smb, smbmsg_t* msg, client_t*
 	if((i=smb_addmsg(smb,msg,smb_storage_mode(cfg, smb),dupechk_hashes,xlat,(uchar*)msgbuf, findsig(msgbuf)))==SMB_SUCCESS
 		&& msg->to!=NULL	/* no recipient means no header created at this stage */) {
 		if(smb->subnum == INVALID_SUB) {
-			if(msg->to_net.type == NET_FIDO && cfg->netmail_sem[0])
-				ftouch(cmdstr(cfg,NULL,cfg->netmail_sem,nulstr,nulstr,NULL));
+			if(msg->to_net.type == NET_FIDO && cfg->netmail_sem[0]) {
+				char tmp[MAX_PATH + 1];
+				ftouch(cmdstr(cfg,NULL,cfg->netmail_sem,nulstr,nulstr,tmp, sizeof(tmp)));
+			}
 		} else
 			signal_sub_sem(cfg,smb->subnum);
 
diff --git a/src/sbbs3/qwk.cpp b/src/sbbs3/qwk.cpp
index 32a6013e97..ff39c49ab8 100644
--- a/src/sbbs3/qwk.cpp
+++ b/src/sbbs3/qwk.cpp
@@ -21,6 +21,7 @@
 
 #include "sbbs.h"
 #include "qwk.h"
+#include "filedat.h"
 
 /****************************************************************************/
 /* Converts a long to an msbin real number. required for QWK NDX file		*/
@@ -374,28 +375,21 @@ void sbbs_t::qwk_success(ulong msgcnt, char bi, char prepack)
 /****************************************************************************/
 void sbbs_t::qwk_sec()
 {
-	char	str[256],tmp2[256],ch,bi=0;
+	char	str[256],tmp2[256],ch;
 	char 	tmp[512];
 	int		error;
 	int 	s;
-	uint	i,k;
-	ulong	l;
+	uint	i;
 	ulong	msgcnt;
 	ulong	*sav_ptr;
-	file_t	fd;
 
-	memset(&fd,0,sizeof(fd));
 	getusrdirs();
-	fd.dir=cfg.total_dirs;
 	if((sav_ptr=(ulong *)malloc(sizeof(ulong)*cfg.total_subs))==NULL) {
 		errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(ulong)*cfg.total_subs);
 		return;
 	}
 	for(i=0;i<cfg.total_subs;i++)
 		sav_ptr[i]=subscan[i].ptr;
-	for(i=0;i<cfg.total_prots;i++)
-		if(cfg.prot[i]->bicmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client))
-			bi++;				/* number of bidirectional protocols configured */
 	if(useron.rest&FLAG('Q'))
 		getusrsubs();
 	delfiles(cfg.temp_dir,ALLFILES);
@@ -407,8 +401,6 @@ void sbbs_t::qwk_sec()
 		ASYNC;
 		bputs(text[QWKPrompt]);
 		sprintf(str,"?UDCSP\r%c",text[YNQP][2]);
-		if(bi)
-			strcat(str,"B");
 		ch=(char)getkeys(str,0);
 		if(ch>' ')
 			logch(ch,0);
@@ -506,14 +498,23 @@ void sbbs_t::qwk_sec()
 							useron.qwk&=~(QWK_EXPCTLA|QWK_RETCTLA);
 						break;
 					case 'T':
-						for(i=0;i<cfg.total_fcomps;i++)
-							uselect(1,i,text[ArchiveTypeHeading],cfg.fcomp[i]->ext,cfg.fcomp[i]->ar);
+					{
+						str_list_t ext_list = strListDup((str_list_t)supported_archive_formats);
+						for(i=0; i < cfg.total_fcomps; i++) {
+							if(strListFind(ext_list, cfg.fcomp[i]->ext, /* case-sensitive */FALSE) < 0
+								&& chk_ar(cfg.fcomp[i]->ar, &useron, &client))
+								strListPush(&ext_list, cfg.fcomp[i]->ext);
+						}
+						for(i=0; ext_list[i] != NULL; i++)
+							uselect(1, i, text[ArchiveTypeHeading], ext_list[i], NULL);
 						s=uselect(0,0,0,0,0);
 						if(s>=0) {
-							strcpy(useron.tmpext,cfg.fcomp[s]->ext);
+							SAFECOPY(useron.tmpext, ext_list[s]);
 							putuserrec(&cfg,useron.number,U_TMPEXT,3,useron.tmpext);
 						}
+						strListFree(&ext_list);
 						break;
+					}
 					case 'E':
 						if(!(useron.qwk&(QWK_EMAIL|QWK_ALLMAIL)))
 							useron.qwk|=QWK_EMAIL;
@@ -571,82 +572,7 @@ void sbbs_t::qwk_sec()
 			continue;
 		}
 
-
-		if(ch=='B') {   /* Bidirectional QWK and REP packet transfer */
-			sprintf(str,"%s%s.qwk",cfg.temp_dir,cfg.sys_id);
-			if(!fexistcase(str) && !pack_qwk(str,&msgcnt,0)) {
-				for(i=0;i<cfg.total_subs;i++)
-					subscan[i].ptr=sav_ptr[i];
-				remove(str);
-				last_ns_time=ns_time;
-				continue;
-			}
-			bprintf(text[UploadingREP],cfg.sys_id);
-			xfer_prot_menu(XFER_BIDIR);
-			mnemonics(text[ProtocolOrQuit]);
-			sprintf(tmp2,"%c",text[YNQP][2]);
-			for(i=0;i<cfg.total_prots;i++)
-				if(cfg.prot[i]->bicmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
-					sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
-					strcat(tmp2,tmp);
-				}
-			ch=(char)getkeys(tmp2,0);
-			if(ch==text[YNQP][2] || sys_status&SS_ABORT || !online) {
-				for(i=0;i<cfg.total_subs;i++)
-					subscan[i].ptr=sav_ptr[i];	/* re-load saved pointers */
-				last_ns_time=ns_time;
-				continue;
-			}
-			for(i=0;i<cfg.total_prots;i++)
-				if(cfg.prot[i]->bicmd[0] && cfg.prot[i]->mnemonic==ch
-					&& chk_ar(cfg.prot[i]->ar,&useron,&client))
-					break;
-			if(i<cfg.total_prots) {
-				batup_total=1;
-				batup_dir[0]=cfg.total_dirs;
-				sprintf(batup_name[0],"%s.rep",cfg.sys_id);
-				batdn_total=1;
-				batdn_dir[0]=cfg.total_dirs;
-				sprintf(batdn_name[0],"%s.qwk",cfg.sys_id);
-				if(!create_batchdn_lst((cfg.prot[i]->misc&PROT_NATIVE) ? true:false)
-					|| !create_batchup_lst()
-					|| !create_bimodem_pth()) {
-					batup_total=batdn_total=0;
-					continue;
-				}
-				sprintf(str,"%s%s.qwk",cfg.temp_dir,cfg.sys_id);
-				sprintf(tmp2,"%s.qwk",cfg.sys_id);
-				padfname(tmp2,fd.name);
-				sprintf(str,"%sBATCHDN.LST",cfg.node_dir);
-				sprintf(tmp2,"%sBATCHUP.LST",cfg.node_dir);
-				error=protocol(cfg.prot[i],XFER_BIDIR,str,tmp2,true);
-				batdn_total=batup_total=0;
-				if(!checkprotresult(cfg.prot[i],error,&fd)) {
-					last_ns_time=ns_time;
-					for(i=0;i<cfg.total_subs;i++)
-						subscan[i].ptr=sav_ptr[i]; /* re-load saved pointers */
-				}
-				else {
-					qwk_success(msgcnt,1,0);
-					for(i=0;i<cfg.total_subs;i++)
-						sav_ptr[i]=subscan[i].ptr;
-				}
-				sprintf(str,"%s%s.qwk",cfg.temp_dir,cfg.sys_id);
-				if(fexistcase(str))
-					remove(str);
-				unpack_rep();
-				delfiles(cfg.temp_dir,ALLFILES);
-				//autohangup();
-				}
-			else {
-				last_ns_time=ns_time;
-				for(i=0;i<cfg.total_subs;i++)
-					subscan[i].ptr=sav_ptr[i];
-			}
-
-		}
-
-		else if(ch=='D') {   /* Download QWK Packet of new messages */
+		if(ch=='D') {   /* Download QWK Packet of new messages */
 			sprintf(str,"%s%s.qwk",cfg.temp_dir,cfg.sys_id);
 			if(!fexistcase(str) && !pack_qwk(str,&msgcnt,0)) {
 				for(i=0;i<cfg.total_subs;i++)
@@ -656,12 +582,13 @@ void sbbs_t::qwk_sec()
 				continue;
 			}
 
-			l=(long)flength(str);
-			bprintf(text[FiFilename],getfname(str));
-			bprintf(text[FiFileSize],ultoac(l,tmp)
+			off_t l=flength(str);
+			bprintf(text[FiFilename], getfname(str));
+			bprintf(text[FiFileSize], ultoac((ulong)l,tmp)
 				, byte_estimate_to_str(l, tmp2, sizeof(tmp), /* units: */1024, /* precision: */1));
+
 			if(l>0L && cur_cps)
-				i=l/(ulong)cur_cps;
+				i=(uint)(l/(ulong)cur_cps);
 			else
 				i=0;
 			bprintf(text[FiTransferTime],sectostr(i,tmp));
@@ -696,9 +623,8 @@ void sbbs_t::qwk_sec()
 			if(i<cfg.total_prots) {
 				sprintf(str,"%s%s.qwk",cfg.temp_dir,cfg.sys_id);
 				sprintf(tmp2,"%s.qwk",cfg.sys_id);
-				padfname(tmp2,fd.name);
 				error=protocol(cfg.prot[i],XFER_DOWNLOAD,str,nulstr,false);
-				if(!checkprotresult(cfg.prot[i],error,&fd)) {
+				if(!checkprotresult(cfg.prot[i], error, tmp2)) {
 					last_ns_time=ns_time;
 					for(i=0;i<cfg.total_subs;i++)
 						subscan[i].ptr=sav_ptr[i]; /* re-load saved pointers */
@@ -726,15 +652,6 @@ void sbbs_t::qwk_sec()
 
 			delfiles(cfg.temp_dir,ALLFILES);
 			bprintf(text[UploadingREP],cfg.sys_id);
-			for(k=0;k<cfg.total_fextrs;k++)
-				if(!stricmp(cfg.fextr[k]->ext,useron.tmpext)
-					&& chk_ar(cfg.fextr[k]->ar,&useron,&client))
-					break;
-			if(k>=cfg.total_fextrs) {
-				bputs(text[QWKExtractionFailed]);
-				lprintf(LOG_ERR, "Couldn't extract REP packet - configuration error");
-				continue;
-			}
 
 			/******************/
 			/* Receive Packet */
@@ -802,7 +719,7 @@ void sbbs_t::qwkcfgline(char *buf,uint subnum)
 	uint 	x,y;
 	long	l;
 	ulong	qwk=useron.qwk;
-	file_t	f;
+	file_t f = {{}};
 
 	sprintf(str,"%-25.25s",buf);	/* Note: must be space-padded, left justified */
 	strupr(str);
@@ -968,29 +885,26 @@ void sbbs_t::qwkcfgline(char *buf,uint subnum)
 	}
 
 	else if(!strncmp(str,"FREQ ",5)) {                  /* file request */
-		padfname(str+5,f.name);
+		const char* fname = str + 5;
+		SKIP_WHITESPACE(fname);
 		for(x=y=0;x<usrlibs;x++) {
 			for(y=0;y<usrdirs[x];y++)
-				if(findfile(&cfg,usrdir[x][y],f.name))
+				if(loadfile(&cfg, usrdir[x][y], fname, &f, file_detail_normal))
 					break;
 			if(y<usrdirs[x])
 				break;
 		}
 		if(x>=usrlibs) {
-			bprintf("\r\n%s",f.name);
+			bprintf("\r\n%s",fname);
 			bputs(text[FileNotFound]);
 		}
 		else {
-			f.dir=usrdir[x][y];
-			getfileixb(&cfg,&f);
-			f.size=0;
-			getfiledat(&cfg,&f);
-			if(f.size==-1L)
-				bprintf(text[FileIsNotOnline],f.name);
+			if(getfilesize(&cfg, &f) < 0)
+				bprintf(text[FileIsNotOnline], f.name);
 			else
 				addtobatdl(&f);
 		}
-
+		smb_freefilemem(&f);
 	}
 
 	else {
diff --git a/src/sbbs3/qwknodes.c b/src/sbbs3/qwknodes.c
index ca13d0407f..0133094c26 100644
--- a/src/sbbs3/qwknodes.c
+++ b/src/sbbs3/qwknodes.c
@@ -275,18 +275,18 @@ int main(int argc, char **argv)
 			continue; 
 		}
 		smb_unlocksmbhdr(&smb);
-		msg.offset=smb.status.total_msgs;
-		if(!msg.offset) {
+		msg.idx_offset=smb.status.total_msgs;
+		if(!msg.idx_offset) {
 			smb_close(&smb);
 			printf("Empty.\n");
 			continue; 
 		}
-		while(!kbhit() && !ferror(smb.sid_fp) && msg.offset) {
-			msg.offset--;
-			fseek(smb.sid_fp,msg.offset*sizeof(idxrec_t),SEEK_SET);
+		while(!kbhit() && !ferror(smb.sid_fp) && msg.idx_offset) {
+			msg.idx_offset--;
+			fseek(smb.sid_fp,msg.idx_offset*sizeof(idxrec_t),SEEK_SET);
 			if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
 				break;
-			fprintf(stderr,"%-5u\r",msg.offset+1);
+			fprintf(stderr,"%-5u\r",msg.idx_offset+1);
 			if(msg.idx.to==smm || msg.idx.to==sbl)
 				continue;
 			if(max_age && now-msg.idx.time>((time_t)max_age*24UL*60UL*60UL))
diff --git a/src/sbbs3/readmsgs.cpp b/src/sbbs3/readmsgs.cpp
index 8f3572361e..0e6793e45a 100644
--- a/src/sbbs3/readmsgs.cpp
+++ b/src/sbbs3/readmsgs.cpp
@@ -474,6 +474,7 @@ int sbbs_t::scanposts(uint subnum, long mode, const char *find)
 		for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
 			if(subscan[subnum].ptr<post[smb.curmsg].idx.number)
 				break;
+		lncntr = 0;
 		bprintf(text[NScanStatusFmt]
 			,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,smb.msgs-smb.curmsg,msgs);
 		if(!smb.msgs) {		  /* no messages at all */
@@ -494,6 +495,7 @@ int sbbs_t::scanposts(uint subnum, long mode, const char *find)
 	}
 	else {
 		cleartoeol();
+		lncntr = 0;
 		if(mode&SCAN_TOYOU)
 			bprintf(text[NScanStatusFmt]
 			   ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->lname,smb.msgs,msgs);
diff --git a/src/sbbs3/release.bat b/src/sbbs3/release.bat
index 928d02cb89..e69ac8c0d5 100644
--- a/src/sbbs3/release.bat
+++ b/src/sbbs3/release.bat
@@ -1,2 +1,3 @@
 @echo off
+call gitinfo.bat
 call build.bat "/p:Configuration=Release" %*
\ No newline at end of file
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index baf519f70c..0fa8fb3938 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -291,7 +291,6 @@ extern int	thread_suid_broken;			/* NPTL is no longer broken */
 #include "str_util.h"
 #include "date_str.h"
 #include "load_cfg.h"
-#include "filedat.h"
 #include "getstats.h"
 #include "msgdate.h"
 #include "getmail.h"
@@ -433,6 +432,7 @@ public:
 
     RingBuf	inbuf;
     RingBuf	outbuf;
+	bool	WaitForOutbufEmpty(int timeout) { return WaitForEvent(outbuf.empty_event, timeout) == WAIT_OBJECT_0; }
 	HANDLE	input_thread;
 	pthread_mutex_t	input_thread_mutex;
 	bool	input_thread_mutex_created;
@@ -515,23 +515,8 @@ public:
 	int 	nodefile;		/* File handle for node.dab */
 	pthread_mutex_t	nodefile_mutex;
 	int		node_ext;		/* File handle for node.exb */
-
-							/* Batch download queue */
-	char 	**batdn_name;	/* Filenames */
-	ushort	*batdn_alt; 	/* Alternate path */
-	uint 	*batdn_dir, 	/* Directory for each file */
-			 batdn_total;	/* Total files */
-	long 	*batdn_offset;	/* Offset for data */
-	ulong	*batdn_size;	/* Size of file in bytes */
-	ulong	*batdn_cdt; 	/* Credit value of file */
-
-							/* Batch upload queue */
-	char 	**batup_desc,	/* Description for each file */
-			**batup_name;	/* Filenames */
-	long	*batup_misc;	/* Miscellaneous bits */
-	ushort	*batup_alt; 	/* Alternate path */
-	uint 	*batup_dir, 	/* Directory for each file */
-			batup_total;	/* Total files */
+	size_t	batup_total();
+	size_t	batdn_total();
 
 	/*********************************/
 	/* Color Configuration Variables */
@@ -584,14 +569,14 @@ public:
 	long 	sys_status; 	/* System Status */
 	subscan_t	*subscan;	/* User sub configuration/scan info */
 
-	ulong	logon_ulb,		/* Upload Bytes This Call */
+	int64_t	logon_ulb,		/* Upload Bytes This Call */
 			logon_dlb,		/* Download Bytes This Call */
 			logon_uls,		/* Uploads This Call */
-			logon_dls,		/* Downloads This Call */
-			logon_posts,	/* Posts This Call */
+			logon_dls;		/* Downloads This Call */
+	ulong	logon_posts,	/* Posts This Call */
 			logon_emails,	/* Emails This Call */
 			logon_fbacks;	/* Feedbacks This Call */
-	uchar	logon_ml;		/* ML of the user upon logon */
+	uchar	logon_ml;		/* Security level of the user upon logon */
 
 	uint 	main_cmds;		/* Number of Main Commands this call */
 	uint 	xfer_cmds;		/* Number of Xfer Commands this call */
@@ -622,7 +607,6 @@ public:
 	ulong 	timeleft;		/* Number of seconds user has left online */
 
 	char 	*comspec;		/* Pointer to environment variable COMSPEC */
-	ushort	altul;			/* Upload to alternate path flag */
 	char 	cid[LEN_CID+1]; /* Caller ID (IP Address) of current caller */
 	char 	*noaccess_str;	/* Why access was denied via ARS */
 	long 	noaccess_val;	/* Value of parameter not met in ARS */
@@ -634,7 +618,7 @@ public:
 	const char*	current_msg_subj;
 	const char*	current_msg_from;
 	const char*	current_msg_to;
-	file_t*		current_file;
+	file_t*	current_file;	
 
 			/* Global command shell variables */
 	uint	global_str_vars;
@@ -668,7 +652,7 @@ public:
 			/* Command Shell Methods */
 	int		exec(csi_t *csi);
 	int		exec_function(csi_t *csi);
-	int		exec_misc(csi_t *csi, char *path);
+	int		exec_misc(csi_t *csi, const char *path);
 	int		exec_net(csi_t *csi);
 	int		exec_msg(csi_t *csi);
 	int		exec_file(csi_t *csi);
@@ -704,7 +688,6 @@ public:
 	int 	sub_op(uint subnum);
 
 	int		dir_op(uint dirnum);
-	int		getuserxfers(int fromuser, int destuser, char *fname);
 
 	void	getmsgptrs(void);
 	void	putmsgptrs(void);
@@ -808,7 +791,9 @@ public:
 	/* con_out.cpp */
 	size_t	bstrlen(const char *str, long mode = 0);
 	int		bputs(const char *str, long mode = 0);	/* BBS puts function */
+	int		bputs(long mode, const char* str) { return bputs(str, mode); }
 	int		rputs(const char *str, size_t len=0);	/* BBS raw puts function */
+	int		rputs(long mode, const char* str) { return rputs(str, mode); }
 	int		bprintf(const char *fmt, ...)			/* BBS printf function */
 #if defined(__GNUC__)   // Catch printf-format errors
     __attribute__ ((format (printf, 2, 3)));		// 1 is 'this'
@@ -851,6 +836,9 @@ public:
 	void	carriage_return(int count=1);
 	void	line_feed(int count=1);
 	void	newline(int count=1);
+	void	cond_newline() { if(column > 0) newline(); }
+	void	cond_blankline() { if(column > 0) newline(); if(lastlinelen) newline(); }
+	void	cond_contline() { if(column > 0 && cols < TERM_COLS_DEFAULT) bputs(text[LongLineContinuationPrefix]); }
 	long	term_supports(long cmp_flags=0);
 	const char* term_type(long term_supports = -1);
 	const char* term_charset(long term_supports = -1);
@@ -971,7 +959,6 @@ public:
 
 	/* logout.cpp */
 	void	logout(void);
-	void	backout(void);
 
 	/* newuser.cpp */
 	BOOL	newuser(void);					/* Get new user							*/
@@ -1036,44 +1023,43 @@ public:
 	bool	bulkupload(uint dirnum);
 
 	/* download.cpp */
-	void	downloadfile(file_t* f);
-	void	notdownloaded(ulong size, time_t start, time_t end);
-	int		protocol(prot_t* prot, enum XFER_TYPE, char *fpath, char *fspec, bool cd, bool autohangup=true);
+	void	downloadedfile(file_t* f);
+	void	notdownloaded(off_t size, time_t start, time_t end);
+	int		protocol(prot_t* prot, enum XFER_TYPE, const char *fpath, const char *fspec, bool cd, bool autohangup=true);
 	const char*	protcmdline(prot_t* prot, enum XFER_TYPE type);
 	void	seqwait(uint devnum);
 	void	autohangup(void);
 	bool	checkdszlog(const char*);
+	bool	checkprotresult(prot_t*, int error, const char* fpath);
 	bool	checkprotresult(prot_t*, int error, file_t*);
+	bool	sendfile(file_t*, char prot, bool autohang);
 	bool	sendfile(char* fname, char prot=0, const char* description = NULL, bool autohang=true);
 	bool	recvfile(char* fname, char prot=0, bool autohang=true);
 
 	/* file.cpp */
-	void	fileinfo(file_t* f);
-	void	openfile(file_t* f);
-	void	closefile(file_t* f);
-	bool	removefcdt(file_t* f);
-	bool	removefile(file_t* f);
-	bool	movefile(file_t* f, int newdir);
+	void	showfileinfo(file_t*, bool show_extdesc = true);
+	bool	removefcdt(file_t*);
+	bool	removefile(smb_t*, file_t*);
+	bool	movefile(smb_t*, file_t*, int newdir);
 	char *	getfilespec(char *str);
 	bool	checkfname(char *fname);
-	bool	addtobatdl(file_t* f);
+	bool	addtobatdl(file_t*);
+	bool	clearbatdl(void);
+	bool	clearbatul(void);
 	long	delfiles(const char *inpath, const char *spec, size_t keep = 0);
 
 	/* listfile.cpp */
-	bool	listfile(const char *fname, const char *buf, uint dirnum
-				,const char *search, const char letter, ulong datoffset);
-	int		listfiles(uint dirnum, const char *filespec, int tofile, long mode);
-	int		listfileinfo(uint dirnum, char *filespec, long mode);
-	void	listfiletofile(char *fname, char *buf, uint dirnum, int file);
-	int		batchflagprompt(uint dirnum, file_t bf[], ulong row[], uint total, long totalfiles);
+	bool	listfile(file_t*, uint dirnum, const char *search, const char letter);
+	int		listfiles(uint dirnum, const char *filespec, FILE* tofile, long mode);
+	int		listfileinfo(uint dirnum, const char *filespec, long mode);
+	void	listfiletofile(file_t*, FILE*);
+	int		batchflagprompt(smb_t*, file_t* bf[], ulong row[], uint total, long totalfiles);
 
 	/* bat_xfer.cpp */
 	void	batchmenu(void);
-	void	batch_create_list(void);
 	void	batch_add_list(char *list);
 	bool	create_batchup_lst(void);
 	bool	create_batchdn_lst(bool native);
-	bool	create_bimodem_pth(void);
 	void	batch_upload(void);
 	void	batch_download(int xfrprot);
 	BOOL	start_batch_download(void);
@@ -1081,17 +1067,14 @@ public:
 	/* tmp_xfer.cpp */
 	void	temp_xfer(void);
 	void	extract(uint dirnum);
-	char *	temp_cmd(void);					/* Returns temp file command line */
+	const char*	temp_cmd(void);					/* Returns temp file command line */
 	ulong	create_filelist(const char *name, long mode);
 
 	/* viewfile.cpp */
-	int		viewfile(file_t* f, int ext);
+	int		viewfile(file_t* f, bool extdesc);
 	void	viewfiles(uint dirnum, char *fspec);
 	void	viewfilecontents(file_t* f);
 
-	/* sortdir.cpp */
-	void	resort(uint dirnum);
-
 	/* xtrn.cpp */
 	int		external(const char* cmdline, long mode, const char* startup_dir=NULL);
 	long	xtrn_mode;
@@ -1108,14 +1091,14 @@ public:
 
 	/* logfile.cpp */
 	void	logentry(const char *code,const char *entry);
-	void	log(char *str);				/* Writes 'str' to node log */
+	void	log(const char *str);				/* Writes 'str' to node log */
 	void	logch(char ch, bool comma);	/* Writes 'ch' to node log */
 	void	logline(const char *code,const char *str); /* Writes 'str' on it's own line in log (LOG_INFO level) */
 	void	logline(int level, const char *code,const char *str);
 	void	logofflist(void);              /* List of users logon activity */
 	bool	errormsg_inside;
 	void	errormsg(int line, const char* function, const char *source, const char* action, const char *object
-				,long access, const char *extinfo=NULL);
+				,long access=0, const char *extinfo=NULL);
 	BOOL	hacklog(char* prot, char* text);
 
 	/* qwk.cpp */
@@ -1233,6 +1216,8 @@ extern "C" {
 	DLLEXPORT char*		DLLCALL ansi_attr(int attr, int curattr, char* str, BOOL color);
 
 	/* main.cpp */
+	extern const char* nulstr;
+	extern const char* crlf;
 	DLLEXPORT int		DLLCALL sbbs_random(int);
 	DLLEXPORT void		DLLCALL sbbs_srand(void);
 
@@ -1261,10 +1246,6 @@ extern "C" {
 	DLLEXPORT int		DLLCALL set_socket_options(scfg_t* cfg, SOCKET sock, const char* section
 		,char* error, size_t errlen);
 
-	/* xtrn.cpp */
-	DLLEXPORT char*		DLLCALL cmdstr(scfg_t* cfg, user_t* user, const char* instr
-									,const char* fpath, const char* fspec, char* cmd);
-
 	/* qwk.cpp */
 	DLLEXPORT int		qwk_route(scfg_t*, const char *inaddr, char *fulladdr, size_t maxlen);
 
@@ -1421,6 +1402,9 @@ extern "C" {
 	DLLEXPORT BOOL		DLLCALL js_ParseMsgHeaderObject(JSContext* cx, JSObject* hdrobj, smbmsg_t*);
 	DLLEXPORT BOOL		DLLCALL js_GetMsgHeaderObjectPrivates(JSContext* cx, JSObject* hdrobj, smb_t**, smbmsg_t**, post_t**);
 
+	/* js_filebase.c */
+	DLLEXPORT JSObject* DLLCALL js_CreateFileBaseClass(JSContext*, JSObject* parent, scfg_t*);
+
 	/* js_socket.c */
 	DLLEXPORT JSObject* DLLCALL js_CreateSocketClass(JSContext* cx, JSObject* parent);
 #ifdef USE_CRYPTLIB
@@ -1451,6 +1435,9 @@ extern "C" {
 	DLLEXPORT JSObject* DLLCALL js_CreateFileClass(JSContext* cx, JSObject* parent);
 	DLLEXPORT JSObject* DLLCALL js_CreateFileObject(JSContext* cx, JSObject* parent, char *name, int fd, const char* mode);
 
+	/* js_archive.c */
+	DLLEXPORT JSObject* DLLCALL js_CreateArchiveClass(JSContext* cx, JSObject* parent);
+
 	/* js_sprintf.c */
 	DLLEXPORT char*		DLLCALL js_sprintf(JSContext* cx, uint argn, unsigned argc, jsval *argv);
 	DLLEXPORT void		DLLCALL js_sprintf_free(char *);
diff --git a/src/sbbs3/sbbs.vcxproj b/src/sbbs3/sbbs.vcxproj
index d71e501bee..53cc67719c 100644
--- a/src/sbbs3/sbbs.vcxproj
+++ b/src/sbbs3/sbbs.vcxproj
@@ -42,6 +42,7 @@
     <Import Project="..\xpdev\xpdev_mt.props" />
     <Import Project="..\encode\encode.props" />
     <Import Project="..\hash\hash.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -56,6 +57,7 @@
     <Import Project="..\xpdev\xpdev_mt.props" />
     <Import Project="..\encode\encode.props" />
     <Import Project="..\hash\hash.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
@@ -80,7 +82,7 @@
     <ClCompile>
       <Optimization>Disabled</Optimization>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;_USRDLL;SBBS;SBBS_EXPORTS;SMB_EXPORTS;RINGBUF_SEM;RINGBUF_MUTEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;_USRDLL;SBBS;SBBS_EXPORTS;SMB_EXPORTS;RINGBUF_SEM;RINGBUF_EVENT;RINGBUF_MUTEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <PrecompiledHeaderOutputFile>.\msvc.win32.debug\sbbs/sbbs.pch</PrecompiledHeaderOutputFile>
@@ -132,7 +134,7 @@
       <Optimization>MaxSpeed</Optimization>
       <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_USRDLL;SBBS;SBBS_EXPORTS;SMB_EXPORTS;RINGBUF_SEM;RINGBUF_MUTEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_USRDLL;SBBS;SBBS_EXPORTS;SMB_EXPORTS;RINGBUF_SEM;RINGBUF_EVENT;RINGBUF_MUTEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <FunctionLevelLinking>true</FunctionLevelLinking>
@@ -374,6 +376,7 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="js_archive.c" />
     <ClCompile Include="js_bbs.cpp">
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -402,6 +405,7 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="js_filebase.c" />
     <ClCompile Include="js_file_area.c">
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -678,12 +682,6 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
-    <ClCompile Include="sortdir.cpp">
-      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
-    </ClCompile>
     <ClCompile Include="ssl.c" />
     <ClCompile Include="str.cpp">
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
diff --git a/src/sbbs3/sbbs3.sln b/src/sbbs3/sbbs3.sln
index 7bd8bc1c62..43e18aa81e 100644
--- a/src/sbbs3/sbbs3.sln
+++ b/src/sbbs3/sbbs3.sln
@@ -84,6 +84,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pktdump", "pktdump.vcxproj"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmsgdump", "fmsgdump.vcxproj", "{E5F4F589-8238-4AE6-8E6D-40AB6D771E1C}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upgrade_to_v319", "upgrade_to_v319.vcxproj", "{B84CB739-8425-4612-BDEF-B292BEAE858F}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -246,6 +248,10 @@ Global
 		{E5F4F589-8238-4AE6-8E6D-40AB6D771E1C}.Debug|Win32.Build.0 = Debug|Win32
 		{E5F4F589-8238-4AE6-8E6D-40AB6D771E1C}.Release|Win32.ActiveCfg = Release|Win32
 		{E5F4F589-8238-4AE6-8E6D-40AB6D771E1C}.Release|Win32.Build.0 = Release|Win32
+		{B84CB739-8425-4612-BDEF-B292BEAE858F}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B84CB739-8425-4612-BDEF-B292BEAE858F}.Debug|Win32.Build.0 = Debug|Win32
+		{B84CB739-8425-4612-BDEF-B292BEAE858F}.Release|Win32.ActiveCfg = Release|Win32
+		{B84CB739-8425-4612-BDEF-B292BEAE858F}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/src/sbbs3/sbbs4defs.h b/src/sbbs3/sbbs4defs.h
index 0b84839741..b73b0641e4 100644
--- a/src/sbbs3/sbbs4defs.h
+++ b/src/sbbs3/sbbs4defs.h
@@ -45,6 +45,7 @@ char* user_dat_columns[] = {
 	 "Alias"
 	,"Name"
 	,"Handle"
+	,"Note"
 	,"IpAddress"
 	,"Hostname"
 	,"Comment"
@@ -55,7 +56,7 @@ char* user_dat_columns[] = {
 	,"Netmail"
 	,"Address"
 	,"Location"
-	,"Zip Code"
+	,"ZipCode"
 	,"Password"
 	,"PhoneNumber"
 	,"BirthDate"
diff --git a/src/sbbs3/sbbs_ini.c b/src/sbbs3/sbbs_ini.c
index 760cacd753..ab3d89f460 100644
--- a/src/sbbs3/sbbs_ini.c
+++ b/src/sbbs3/sbbs_ini.c
@@ -255,9 +255,11 @@ void sbbs_read_ini(
 {
 	const char*	section;
 	const char* default_term_ansi;
+#if defined(__linux__) || defined(__FreeBSD__)
 	const char*	default_dosemu_path;
 #if defined(__linux__)
 	const char*	default_dosemuconf_path;
+#endif
 #endif
 	char		value[INI_MAX_VALUE_LEN];
 	str_list_t	list;
diff --git a/src/sbbs3/sbbsdefs.h b/src/sbbs3/sbbsdefs.h
index be1fb144f6..096d7ff1bd 100644
--- a/src/sbbs3/sbbsdefs.h
+++ b/src/sbbs3/sbbsdefs.h
@@ -34,16 +34,14 @@
 /* Constants */
 /*************/
 
-#define VERSION 	"3.18"  /* Version: Major.minor  */
-#define REVISION	'c'     /* Revision: lowercase letter */
-#define VERSION_NUM	(31800	 + (tolower(REVISION)-'a'))
-#define VERSION_HEX	(0x31800 + (tolower(REVISION)-'a'))
+#define VERSION 	"3.19"  /* Version: Major.minor  */
+#define REVISION	'a'     /* Revision: lowercase letter */
+#define VERSION_NUM	(31900	 + (tolower(REVISION)-'a'))
+#define VERSION_HEX	(0x31900 + (tolower(REVISION)-'a'))
 
 #define VERSION_NOTICE		"Synchronet BBS for " PLATFORM_DESC\
 								"  Version " VERSION
-#define SYNCHRONET_CRC		0x9BCDD162
-#define COPYRIGHT_NOTICE	"Copyright 2020 Rob Swindell"
-#define COPYRIGHT_CRC		0xB12E96E6
+#define COPYRIGHT_NOTICE	"Copyright 2021 Rob Swindell"
 
 #define SBBSCTRL_DEFAULT	"/sbbs/ctrl"
 
@@ -51,7 +49,9 @@
 
 #define FNOPEN_BUF_SIZE		(2*1024)
 
+#define MAX_FILENAME_LEN		64
 #define ILLEGAL_FILENAME_CHARS	"\\/|<>:\";,%"
+#define SAFEST_FILENAME_CHARS	"-._0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
 
 #define BIND_FAILURE_HELP	"!Another application or service may be using this port"
 #define UNKNOWN_LOAD_ERROR	"Unknown load error - Library mismatch?"
@@ -86,9 +86,6 @@
 #define MAX_DIRS		65534
 #define MAX_XTRNS		65534
 
-#define MAX_FILES	  10000 /* Maximum number of files per dir			*/
-#define MAX_USERXFER	500 /* Maximum number of dest. users of usrxfer */
-
 #define MAX_TEXTDAT_ITEM_LEN	2000
 
 
@@ -261,10 +258,8 @@
 #define DIR_NOSTAT		(1<<19)		/* Do not include transfers in system stats */
 #define DIR_FILES		(1<<20)		/* List/access files not in database */
 #define DIR_TEMPLATE	(1<<21)		/* Use this dir as template for new dirs (in this lib) */
-
-                                    /* Bit values for file_t.misc */
-#define FM_EXTDESC  (1<<0)          /* Extended description exists */
-#define FM_ANON 	(1<<1)			/* Anonymous upload */
+#define DIR_NOHASH		(1<<22)		/* Don't auto calculate/store file content hashes */
+#define DIR_FILETAGS	(1<<23)		/* Allow files to have user-specified tags */
 
 									/* Bit values for cfg.file_misc				*/
 #define FM_NO_LFN	(1<<0)			/* No long filenames in listings			*/
@@ -293,12 +288,15 @@
 #define ERR_IOCTL	"sending IOCTL"	/* IOCTL error */
 #define ERR_SEEK	"seeking"		/* SEEKing error */
 
-enum {                              /* Values for dir[x].sort */
-     SORT_NAME_A                    /* Sort by filename, ascending */
-    ,SORT_NAME_D                    /* Sort by filename, descending */
-    ,SORT_DATE_A                    /* Sort by upload date, ascending */
-    ,SORT_DATE_D                    /* Sort by upload date, descending */
-    };
+enum file_sort {                    /* Values for dir[x].sort */
+     FILE_SORT_NAME_A   = 0	        /* Sort by filename, ascending (case-insensitive) */
+    ,FILE_SORT_NAME_D   = 1         /* Sort by filename, descending (case-insensitive) */
+	,FILE_SORT_NAME_AC  = 4			/* Sort by filename, ascending (case-sensitive) */
+	,FILE_SORT_NAME_DC  = 5         /* Sort by filename, descending (case-sensitive) */
+    ,FILE_SORT_DATE_A   = 2         /* Sort by upload date, ascending */
+    ,FILE_SORT_DATE_D   = 3         /* Sort by upload date, descending */
+	,FILE_SORT_NATURAL  = FILE_SORT_DATE_A
+};
 
 /* Values for grp[x].sort */
 enum area_sort {
@@ -508,7 +506,7 @@ typedef enum {						/* Values for xtrn_t.event				*/
 #define LEN_ZIPCODE 	10	/* Zip/Postal code								*/
 #define LEN_MODEM		 8	/* User modem type description					*/
 #define LEN_FDESC		58	/* File description 							*/
-#define LEN_FCDT		 9	/* 9 digits for file credit values				*/
+#define LEN_EXTDESC		1024 /* extended file description */
 #define LEN_TITLE		70	/* Message title								*/
 #define LEN_MAIN_CMD	28	/* Unused Storage in user.dat					*/
 #define LEN_COLS		3
@@ -602,23 +600,6 @@ typedef enum {						/* Values for xtrn_t.event				*/
 #define U_UNUSED	U_CURDIR+16
 #define U_LEN		(U_UNUSED+4+2)
 
-/****************************************************************************/
-/* Offsets into DIR .DAT file for different fields for each file 			*/
-/****************************************************************************/
-#define F_CDT		0				/* Offset in DIR#.DAT file for cdts		*/
-#define F_DESC		(F_CDT+LEN_FCDT)/* Description							*/
-#define F_ULER		(F_DESC+LEN_FDESC+2)   /* Uploader						*/
-#define F_TIMESDLED (F_ULER+30+2) 	/* Number of times downloaded 			*/
-#define F_OPENCOUNT	(F_TIMESDLED+5+2)
-#define F_MISC		(F_OPENCOUNT+3+2)
-#define F_ALTPATH	(F_MISC+1)		/* Two hex digit alternate path */
-#define F_LEN		(F_ALTPATH+2+2) /* Total length of all fdat in file		*/
-
-#define F_IXBSIZE	22				/* Length of each index entry			*/
-
-#define F_EXBSIZE	512				/* Length of each ext-desc entry		*/
-
-
 #define SIF_MAXBUF  0x7000			/* Maximum buffer size of SIF data		*/
 
 /* NOTE: Do not change the values of the following block of defines!		*/
@@ -881,8 +862,6 @@ enum {							/* Values for 'mode' in listfileinfo        */
 	,FI_OLD              		/* Search/Remove files not downloaded since */
 	,FI_OLDUL	 				/* Search/Remove files uploaded before      */
 	,FI_OFFLINE   				/* Search/Remove files not online			*/
-	,FI_USERXFER  				/* User Xfer Download                       */
-	,FI_CLOSE 	  				/* Close any open records					*/
 	};
 
 enum XFER_TYPE {				/* Values for type in xfer_prot_select()	*/
@@ -890,7 +869,6 @@ enum XFER_TYPE {				/* Values for type in xfer_prot_select()	*/
 	,XFER_DOWNLOAD
 	,XFER_BATCH_UPLOAD
 	,XFER_BATCH_DOWNLOAD
-	,XFER_BIDIR
 };
 
 #define L_LOGON     1			/* Logon List maintenance                   */
@@ -918,11 +896,6 @@ enum {							/* Values of mode for userlist function     */
 	,UL_DIR						/* List all users with access to curdir 	*/
 	};
 
-
-#define BO_LEN		16			/* backout.dab record length				*/
-
-#define BO_OPENFILE 0			/* Backout types */
-
 /**********/
 /* Macros */
 /**********/
@@ -1060,25 +1033,6 @@ typedef struct {						/* Users information */
 
 } user_t;
 
-typedef struct {						/* File (transfers) Data */
-	char    name[13],					/* Name of file FILENAME.EXT */
-			desc[LEN_FDESC+1],			/* Uploader's Description */
-			uler[LEN_ALIAS+1];			/* User who uploaded */
-	uchar	opencount;					/* Times record is currently open */
-	time32_t  date,						/* File date/time */
-			dateuled,					/* Date/Time (Unix) Uploaded */
-			datedled;					/* Date/Time (Unix) Last downloaded */
-	uint16_t	dir,						/* Directory file is in */
-			altpath,
-			timesdled,					/* Total times downloaded */
-			timetodl;					/* How long transfer time */
-	int32_t	datoffset,					/* Offset into .DAT file */
-			size,						/* Size of file */
-			misc;						/* Miscellaneous bits */
-	uint32_t	cdt;						/* Credit value for this file */
-
-} file_t;
-
 typedef struct {
 	idxrec_t	idx;					/* defined in smbdefs.h */
 	uint32_t	num;					/* 1-based offset */
@@ -1093,6 +1047,7 @@ typedef struct {
 } post_t;
 typedef idxrec_t mail_t;				/* defined in smbdefs.h */
 typedef fidoaddr_t faddr_t;				/* defined in smbdefs.h */
+typedef smbfile_t file_t;				/* defined in smbdefs.h */
 
 typedef struct {						/* System/Node Statistics */
 	uint32_t	logons,						/* Total Logons on System */
diff --git a/src/sbbs3/sbbsecho.c b/src/sbbs3/sbbsecho.c
index 9cf5b05c44..80c340f51a 100644
--- a/src/sbbs3/sbbsecho.c
+++ b/src/sbbs3/sbbsecho.c
@@ -50,10 +50,12 @@
 #include "nopen.h"
 #include "crc32.h"
 #include "userdat.h"
+#include "filedat.h"
 #include "msg_id.h"
 #include "scfgsave.h"
 #include "getmail.h"
-#include "ver.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 #define MAX_OPEN_SMBS	10
 
@@ -117,7 +119,7 @@ const char* sbbsecho_pid(void)
 	static char str[256];
 
 	sprintf(str, "SBBSecho %u.%02u-%s %s/%s %s %s"
-		,SBBSECHO_VERSION_MAJOR,SBBSECHO_VERSION_MINOR,PLATFORM_DESC,git_branch,git_hash,__DATE__,compiler);
+		,SBBSECHO_VERSION_MAJOR,SBBSECHO_VERSION_MINOR,PLATFORM_DESC,GIT_BRANCH,GIT_HASH,__DATE__,compiler);
 
 	return str;
 }
@@ -206,7 +208,7 @@ int fwrite_via_control_line(FILE* fp, fidoaddr_t* addr)
 		,tm->tm_hour
 		,tm->tm_min
 		,tm->tm_sec
-		,SBBSECHO_VERSION_MAJOR,SBBSECHO_VERSION_MINOR,PLATFORM_DESC,git_branch,git_hash);
+		,SBBSECHO_VERSION_MAJOR,SBBSECHO_VERSION_MINOR,PLATFORM_DESC,GIT_BRANCH,GIT_HASH);
 }
 
 int fwrite_intl_control_line(FILE* fp, fmsghdr_t* hdr)
@@ -555,121 +557,6 @@ bool delfile(const char *filename, int line)
 	return true;
 }
 
-/*****************************************************************************/
-/* Returns command line generated from instr with %c replacments             */
-/*****************************************************************************/
-char *mycmdstr(scfg_t* cfg, const char *instr, const char *fpath, const char *fspec)
-{
-    static char cmd[MAX_PATH+1];
-    char str[256],str2[128];
-    int i,j,len;
-
-	len=strlen(instr);
-	for(i=j=0;i<len && j<128;i++) {
-		if(instr[i]=='%') {
-			i++;
-			cmd[j]=0;
-			switch(toupper(instr[i])) {
-				case 'F':   /* File path */
-					SAFECAT(cmd,fpath);
-					break;
-				case 'G':   /* Temp directory */
-					if(cfg->temp_dir[0]!='\\'
-						&& cfg->temp_dir[0]!='/'
-						&& cfg->temp_dir[1]!=':') {
-						SAFECOPY(str,cfg->node_dir);
-						SAFECAT(str,cfg->temp_dir);
-						if(FULLPATH(str2,str,40))
-							strcpy(str,str2);
-						backslash(str);
-						SAFECAT(cmd,str);}
-					else
-						SAFECAT(cmd,cfg->temp_dir);
-					break;
-				case 'J':
-					if(cfg->data_dir[0]!='\\'
-						&& cfg->data_dir[0]!='/'
-						&& cfg->data_dir[1]!=':') {
-						SAFECOPY(str,cfg->node_dir);
-						SAFECAT(str,cfg->data_dir);
-						if(FULLPATH(str2,str,40))
-							SAFECOPY(str,str2);
-						backslash(str);
-						SAFECAT(cmd,str);
-					}
-					else
-						SAFECAT(cmd,cfg->data_dir);
-					break;
-				case 'K':
-					if(cfg->ctrl_dir[0]!='\\'
-						&& cfg->ctrl_dir[0]!='/'
-						&& cfg->ctrl_dir[1]!=':') {
-						SAFECOPY(str,cfg->node_dir);
-						SAFECAT(str,cfg->ctrl_dir);
-						if(FULLPATH(str2,str,40))
-							SAFECOPY(str,str2);
-						backslash(str);
-						SAFECAT(cmd,str);
-					}
-					else
-						SAFECAT(cmd,cfg->ctrl_dir);
-					break;
-				case 'N':   /* Node Directory (same as SBBSNODE environment var) */
-					SAFECAT(cmd,cfg->node_dir);
-					break;
-				case 'O':   /* SysOp */
-					SAFECAT(cmd,cfg->sys_op);
-					break;
-				case 'Q':   /* QWK ID */
-					SAFECAT(cmd,cfg->sys_id);
-					break;
-				case 'S':   /* File Spec */
-					SAFECAT(cmd,fspec);
-					break;
-				case '!':   /* EXEC Directory */
-					SAFECAT(cmd,cfg->exec_dir);
-					break;
-                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
-#ifndef __unix__
-                    SAFECAT(cmd,cfg->exec_dir);
-#endif
-                    break;
-				case '#':   /* Node number (same as SBBSNNUM environment var) */
-					sprintf(str,"%d",cfg->node_num);
-					SAFECAT(cmd,str);
-					break;
-				case '*':
-					sprintf(str,"%03d",cfg->node_num);
-					SAFECAT(cmd,str);
-					break;
-				case '%':   /* %% for percent sign */
-					SAFECAT(cmd,"%");
-					break;
-				case '.':	/* .exe for DOS/OS2/Win32, blank for Unix */
-#ifndef __unix__
-					SAFECAT(cmd,".exe");
-#endif
-					break;
-				case '?':	/* Platform */
-					SAFECOPY(str,PLATFORM_DESC);
-					strlwr(str);
-					SAFECAT(cmd,str);
-					break;
-				default:    /* unknown specification */
-					lprintf(LOG_ERR,"ERROR Checking Command Line '%s'",instr);
-					bail(1);
-					break;
-			}
-			j=strlen(cmd);
-		}
-		else
-			cmd[j++]=instr[i];
-}
-	cmd[j]=0;
-
-	return(cmd);
-}
-
 /****************************************************************************/
 /* Runs an external program directly using system()							*/
 /****************************************************************************/
@@ -2373,9 +2260,21 @@ char* process_areafix(fidoaddr_t addr, char* inbuf, const char* password, const
 int unpack(const char *infile, const char* outdir)
 {
 	FILE *stream;
-	char str[256],tmp[128];
+	char str[256],tmp[512];
+	char error[256];
 	int ch,file;
 	unsigned u,j;
+	long file_count;
+
+	file_count = extract_files_from_archive(infile, outdir
+		,/* allowed_filename_chars: */SAFEST_FILENAME_CHARS, /* with_path */false
+		,/* max_files: */0, /* file_list = ALL */NULL, error, sizeof(error));
+	if(file_count > 0) {
+		lprintf(LOG_DEBUG, "libarchive extracted %lu files from %s", file_count, infile);
+		return 0;
+	}
+	if(*error)
+		lprintf(LOG_NOTICE, "libarchive error (%s) extracting %s", error, infile);
 
 	if((stream=fnopen(&file,infile,O_RDONLY))==NULL) {
 		lprintf(LOG_ERR,"ERROR %u (%s) opening archive: %s",errno,strerror(errno),infile);
@@ -2405,7 +2304,7 @@ int unpack(const char *infile, const char* outdir)
 		return(1);
 	}
 
-	return execute(mycmdstr(&scfg,cfg.arcdef[u].unpack,infile, outdir));
+	return execute(cmdstr(&scfg, /* user: */NULL, cfg.arcdef[u].unpack,infile, outdir, tmp, sizeof(tmp)));
 }
 
 /******************************************************************************
@@ -2417,6 +2316,7 @@ int pack(const char *srcfile, const char *destfile, fidoaddr_t dest)
 {
 	nodecfg_t*	nodecfg;
 	arcdef_t*	archive;
+	char tmp[512];
 
 	if(!cfg.arcdefs) {
 		lprintf(LOG_DEBUG, "ERROR: pack() called with no archive types configured!");
@@ -2429,7 +2329,13 @@ int pack(const char *srcfile, const char *destfile, fidoaddr_t dest)
 
 	lprintf(LOG_DEBUG,"Packing packet (%s) into bundle (%s) for %s using %s"
 		,srcfile, destfile, smb_faddrtoa(&dest, NULL), archive->name);
-	return execute(mycmdstr(&scfg, archive->pack, destfile, srcfile));
+	if(strListFind((str_list_t)supported_archive_formats, archive->name, /* case_sensitive */FALSE) >= 0) {
+		const char* file_list[] = { srcfile, NULL };
+		if(create_archive(destfile, archive->name, /* with_path: */false, (str_list_t)file_list, tmp, sizeof(tmp)) == 1)
+			return 0;
+		lprintf(LOG_ERR, "libarchive error (%s) creating %s", tmp, destfile);
+	}
+	return execute(cmdstr(&scfg, /* user: */NULL, archive->pack, destfile, srcfile, tmp, sizeof(tmp)));
 }
 
 /* Reads a single FTS-1 stored message header from the specified file stream and terminates C-strings */
@@ -2824,7 +2730,8 @@ int mv(const char *insrc, const char *indest, bool copy)
 	char src[MAX_PATH+1];
 	char dest[MAX_PATH+1];
 	int  ind,outd;
-	long length,chunk=4096,l;
+	off_t length;
+	long chunk=4096,l;
     FILE *inp,*outp;
 
 	SAFECOPY(src, insrc);
@@ -2881,7 +2788,7 @@ int mv(const char *insrc, const char *indest, bool copy)
 	int result = 0;
 	while(l<length) {
 		if(l+chunk>length)
-			chunk=length-l;
+			chunk=(long)(length-l);
 		if(fread(buf,1,chunk,inp) != chunk) {
 			result = -2;
 			break;
@@ -2932,7 +2839,7 @@ long getlastmsg(uint subnum, uint32_t *ptr, /* unused: */time_t *t)
 ulong loadmsgs(smb_t* smb, post_t** post, ulong ptr)
 {
 	int i;
-	long l,total;
+	ulong l,total;
 	idxrec_t idx;
 
 	if((i=smb_locksmbhdr(smb))!=SMB_SUCCESS) {
@@ -2941,14 +2848,14 @@ ulong loadmsgs(smb_t* smb, post_t** post, ulong ptr)
 	}
 
 	/* total msgs in sub */
-	total=filelength(fileno(smb->sid_fp))/sizeof(idxrec_t);
+	total=(ulong)filelength(fileno(smb->sid_fp))/sizeof(idxrec_t);
 
 	if(!total) {			/* empty */
 		smb_unlocksmbhdr(smb);
 		return(0);
 	}
 
-	if(((*post)=(post_t*)malloc(sizeof(post_t)*total))    /* alloc for max */
+	if(((*post)=(post_t*)malloc((size_t)(sizeof(post_t)*total)))    /* alloc for max */
 		==NULL) {
 		smb_unlocksmbhdr(smb);
 		lprintf(LOG_ERR,"ERROR line %d allocating %lu bytes for %s",__LINE__
@@ -3276,6 +3183,7 @@ int fmsgtosmsg(char* fbuf, fmsghdr_t* hdr, uint usernumber, uint subnum)
 {
 	uchar	ch,stail[MAX_TAILLEN+1],*sbody;
 	char	msg_id[256],str[128],*p;
+	char	cmd[512];
 	bool	done,cr;
 	int 	i;
 	ushort	xlat=XLAT_NONE,net;
@@ -3652,7 +3560,7 @@ int fmsgtosmsg(char* fbuf, fmsghdr_t* hdr, uint usernumber, uint subnum)
 	i=smb_addmsg(smbfile, &msg, smb_storage_mode(&scfg, smbfile), dupechk_hashes, xlat, sbody, stail);
 	if(i == SMB_SUCCESS) {
 		if(subnum != INVALID_SUB && scfg.sub[subnum]->post_sem[0])
-			ftouch(mycmdstr(&scfg, scfg.sub[subnum]->post_sem, "", ""));
+			ftouch(cmdstr(&scfg, /* user: */NULL, scfg.sub[subnum]->post_sem, "", "", cmd, sizeof(cmd)));
 	} else {
 		lprintf(LOG_ERR,"ERROR %d (%s) line %d adding message to %s"
 			,i, smbfile->last_error, __LINE__, subnum==INVALID_SUB ? "mail":scfg.sub[subnum]->code);
@@ -5281,7 +5189,7 @@ int export_netmail(void)
 
 	memset(&msg, 0, sizeof(msg));
 	rewind(email->sid_fp);
-	for(;!feof(email->sid_fp);msg.offset++) {
+	for(;!feof(email->sid_fp);msg.idx_offset++) {
 
 		smb_freemsgmem(&msg);
 		if(fread(&msg.idx, sizeof(msg.idx), 1, email->sid_fp) != 1)
@@ -5360,7 +5268,7 @@ int export_netmail(void)
 			if((i = smb_updatemsg(email, &msg)) != SMB_SUCCESS)
 				lprintf(LOG_ERR,"!ERROR %d (%s) line %d deleting mail msg #%u"
 					,i, email->last_error, __LINE__, msg.hdr.number);
-			(void)fseek(email->sid_fp, (msg.offset+1)*sizeof(msg.idx), SEEK_SET);
+			(void)fseek(email->sid_fp, (msg.idx_offset+1)*sizeof(msg.idx), SEEK_SET);
 		} else {
 			if((i = smb_putmsghdr(email, &msg)) != SMB_SUCCESS)
 				lprintf(LOG_ERR,"!ERROR %d (%s) line %d updating msg header for mail msg #%u"
@@ -5647,7 +5555,7 @@ void find_stray_packets(void)
 	FILE*	fp;
 	size_t	f;
 	glob_t	g;
-	long	flen;
+	off_t	flen;
 	uint16_t	terminator;
 	fidoaddr_t	pkt_orig;
 	fidoaddr_t	pkt_dest;
@@ -5683,7 +5591,7 @@ void find_stray_packets(void)
 			continue;
 		}
 		terminator = ~FIDO_PACKET_TERMINATOR;
-		(void)fseek(fp, flen-sizeof(terminator), SEEK_SET);
+		(void)fseek(fp, (long)(flen-sizeof(terminator)), SEEK_SET);
 		if(fread(&terminator, sizeof(terminator), 1, fp) != 1)
 			lprintf(LOG_WARNING, "Failure reading last byte from %s", packet);
 		fclose(fp);
@@ -6180,7 +6088,7 @@ int main(int argc, char **argv)
 	printf("\nSBBSecho v%u.%02u-%s (%s/%s) - Synchronet FidoNet EchoMail Tosser\n"
 		,SBBSECHO_VERSION_MAJOR, SBBSECHO_VERSION_MINOR
 		,PLATFORM_DESC
-		,git_branch, git_hash
+		,GIT_BRANCH, GIT_HASH
 		);
 
 	cmdline[0]=0;
diff --git a/src/sbbs3/sbbsecho.vcxproj b/src/sbbs3/sbbsecho.vcxproj
index d78e6e0ad9..179567e9b4 100644
--- a/src/sbbs3/sbbsecho.vcxproj
+++ b/src/sbbs3/sbbsecho.vcxproj
@@ -38,6 +38,7 @@
     <Import Project="..\build\undeprecate.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -48,6 +49,7 @@
     <Import Project="..\build\undeprecate.props" />
     <Import Project="..\hash\hash.props" />
     <Import Project="..\encode\encode.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
@@ -161,6 +163,7 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="filedat.c" />
     <ClCompile Include="getmail.c" />
     <ClCompile Include="msg_id.c">
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -187,7 +190,6 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
-    <ClCompile Include="ver.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\smblib\smblib.vcxproj">
diff --git a/src/sbbs3/scandirs.cpp b/src/sbbs3/scandirs.cpp
index 9fd93a675c..4c7ecea316 100644
--- a/src/sbbs3/scandirs.cpp
+++ b/src/sbbs3/scandirs.cpp
@@ -27,7 +27,6 @@
 void sbbs_t::scandirs(long mode)
 {
 	char	ch,str[256]="";
-	char 	tmp[512];
 	int		s;
 	uint	i,k;
 
@@ -43,9 +42,8 @@ void sbbs_t::scandirs(long mode)
 			bprintf(text[NScanHdr],timestr(ns_time));
 		}
 		else if(mode==FL_NO_HDR) {		/* Search for a string */
-			if(!getfilespec(tmp))
+			if(!getfilespec(str))
 				return;
-			padfname(tmp,str); 
 		}
 		else if(mode==FL_FINDDESC) {	/* Find text in description */
 			if(text[SearchExtendedQ][0] && !noyes(text[SearchExtendedQ]))
@@ -101,7 +99,6 @@ void sbbs_t::scandirs(long mode)
 void sbbs_t::scanalldirs(long mode)
 {
 	char	str[256]="";
-	char 	tmp[512];
 	int		s;
 	uint	i,j,k,d;
 
@@ -111,9 +108,8 @@ void sbbs_t::scanalldirs(long mode)
 		bprintf(text[NScanHdr],timestr(ns_time));
 	}
 	else if(mode==FL_NO_HDR) {		/* Search for a string */
-		if(!getfilespec(tmp))
+		if(!getfilespec(str))
 			return;
-		padfname(tmp,str); 
 	}
 	else if(mode==FL_FINDDESC) {	/* Find text in description */
 		if(text[SearchExtendedQ][0] && !noyes(text[SearchExtendedQ]))
diff --git a/src/sbbs3/scfg/scfg.c b/src/sbbs3/scfg/scfg.c
index cc83f3cdc0..0ee5b9cdec 100644
--- a/src/sbbs3/scfg/scfg.c
+++ b/src/sbbs3/scfg/scfg.c
@@ -45,6 +45,9 @@ char error[256];
 int  backup_level=5;
 char* area_sort_desc[] = { "Index Position", "Long Name", "Short Name", "Internal Code", NULL };
 
+/* convenient space-saving global constants */
+const char* nulstr="";
+
 char *invalid_code=
 	"`Invalid Internal Code:`\n\n"
 	"Internal codes can be up to eight characters in length and can only\n"
diff --git a/src/sbbs3/scfg/scfg.h b/src/sbbs3/scfg/scfg.h
index f2e04f2b10..bfbd9d0dd3 100644
--- a/src/sbbs3/scfg/scfg.h
+++ b/src/sbbs3/scfg/scfg.h
@@ -100,7 +100,7 @@ extern char item;
 extern char **opt;
 extern char tmp[256];
 extern char error[256];
-extern char *nulstr;
+extern const char *nulstr;
 extern char *invalid_code,*num_flags;
 extern int	backup_level;
 extern BOOL new_install;
diff --git a/src/sbbs3/scfg/scfg.vcxproj b/src/sbbs3/scfg/scfg.vcxproj
index 04cce09ac0..84c7072cbb 100644
--- a/src/sbbs3/scfg/scfg.vcxproj
+++ b/src/sbbs3/scfg/scfg.vcxproj
@@ -41,6 +41,7 @@
     <Import Project="..\..\hash\hash.props" />
     <Import Project="..\..\encode\encode.props" />
     <Import Project="..\..\..\3rdp\win32.release\cryptlib\cryptlib.props" />
+    <Import Project="..\..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -54,6 +55,7 @@
     <Import Project="..\..\hash\hash.props" />
     <Import Project="..\..\encode\encode.props" />
     <Import Project="..\..\..\3rdp\win32.release\cryptlib\cryptlib.props" />
+    <Import Project="..\..\..\3rdp\win32.release\libarchive\libarchive.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
diff --git a/src/sbbs3/scfg/scfgnet.c b/src/sbbs3/scfg/scfgnet.c
index f88d02e874..360a8a3261 100644
--- a/src/sbbs3/scfg/scfgnet.c
+++ b/src/sbbs3/scfg/scfgnet.c
@@ -193,7 +193,7 @@ void net_cfg()
 							"networked sub-boards. This default can be overridden on a per sub-board\n"
 							"basis with the sub-board configuration `Network Options...`.\n"
 						;
-						uifc.input(WIN_MID|WIN_SAV,0,0,nulstr
+						uifc.input(WIN_MID|WIN_SAV,0,0,""
 							,cfg.qnet_tagline,sizeof(cfg.qnet_tagline)-1,K_MSG|K_EDIT);
 						break;
 					case 0:
@@ -238,8 +238,7 @@ void net_cfg()
 								if(!new_qhub(i))
 									continue;
 								SAFECOPY(cfg.qhub[i]->id,str);
-								SAFECOPY(cfg.qhub[i]->pack,"%@zip -jD %f %s");
-								SAFECOPY(cfg.qhub[i]->unpack,"%@unzip -Coj %f %s -d %g");
+								SAFECOPY(cfg.qhub[i]->fmt, "ZIP");
 								SAFECOPY(cfg.qhub[i]->call,"*qnet-ftp %s hub.address YOURPASS");
 								cfg.qhub[i]->node = NODE_ANY;
 								cfg.qhub[i]->days=0x7f; /* all days */
@@ -824,6 +823,7 @@ void qhub_edit(int num)
 	while(!done) {
 		i=0;
 		sprintf(opt[i++],"%-27.27s%s","Hub System ID",cfg.qhub[num]->id);
+		sprintf(opt[i++],"%-27.27s%s","Archive Format",cfg.qhub[num]->fmt);
 		sprintf(opt[i++],"%-27.27s%s","Pack Command Line",cfg.qhub[num]->pack);
 		sprintf(opt[i++],"%-27.27s%s","Unpack Command Line",cfg.qhub[num]->unpack);
 		sprintf(opt[i++],"%-27.27s%s","Call-out Command Line",cfg.qhub[num]->call);
@@ -859,8 +859,13 @@ void qhub_edit(int num)
 			"\n"
 			"The `Hub System ID` must match the QWK System ID of this network hub.\n"
 			"\n"
+			"The `Archive Format` should be set to an archive/compression format\n"
+			"that the hub will expect your REP packets to be submitted with\n"
+			"(typically, ZIP).\n"
+			"\n"
 			"The `Pack` and `Unpack Command Lines` are used for creating and extracting\n"
-			"REP (reply) and QWK message packets (files, usually in PKZIP format).\n"
+			"REP (reply) and QWK message packets using an external archive utility\n"
+			"(these command-lines are optional).\n"
 			"\n"
 			"The `Call-out Command Line` is executed when your system attempts a packet\n"
 			"exchange with the QWKnet hub (e.g. executes a script).\n"
@@ -904,7 +909,7 @@ void qhub_edit(int num)
 			case -1:
 				done=1;
 				break;
-			case 0:
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`QWK Network Hub System ID:`\n"
 					"\n"
@@ -916,7 +921,17 @@ void qhub_edit(int num)
 					,cfg.qhub[num]->id,LEN_QWKID,K_UPPER|K_EDIT))
 					strcpy(cfg.qhub[num]->id,str);
 				break;
-			case 1:
+			case __COUNTER__:
+				uifc.helpbuf=
+					"`REP Packet Archive Format:`\n"
+					"\n"
+					"This is the archive format used for REP packets created for this QWK\n"
+					"network hub (typically, this would be `ZIP`).\n"
+				;
+				uifc.input(WIN_MID|WIN_SAV,0,0,"REP Packet Archive Format"
+					,cfg.qhub[num]->fmt,sizeof(cfg.qhub[num]->fmt)-1,K_EDIT|K_UPPER);
+				break;
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`REP Packet Creation Command:`\n"
 					"\n"
@@ -928,7 +943,7 @@ void qhub_edit(int num)
 				uifc.input(WIN_MID|WIN_SAV,0,0,""
 					,cfg.qhub[num]->pack,sizeof(cfg.qhub[num]->pack)-1,K_EDIT);
 				break;
-			case 2:
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`QWK Packet Extraction Command:`\n"
 					"\n"
@@ -940,7 +955,7 @@ void qhub_edit(int num)
 				uifc.input(WIN_MID|WIN_SAV,0,0,""
 					,cfg.qhub[num]->unpack,sizeof(cfg.qhub[num]->unpack)-1,K_EDIT);
 				break;
-			case 3:
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`QWK Network Hub Call-out Command Line:`\n"
 					"\n"
@@ -952,7 +967,7 @@ void qhub_edit(int num)
 				uifc.input(WIN_MID|WIN_SAV,0,0,""
 					,cfg.qhub[num]->call,sizeof(cfg.qhub[num]->call)-1,K_EDIT);
 				break;
-			case 4:
+			case __COUNTER__:
 				if(cfg.qhub[num]->node == NODE_ANY)
 					SAFECOPY(str, "Any");
 				else
@@ -971,7 +986,7 @@ void qhub_edit(int num)
 						cfg.qhub[num]->node = NODE_ANY;
 				}
 				break;
-			case 5:
+			case __COUNTER__:
 				j=0;
 				while(1) {
 					for(i=0;i<7;i++)
@@ -992,7 +1007,7 @@ void qhub_edit(int num)
 					uifc.changes=1; 
 				}
 				break;
-			case 6:
+			case __COUNTER__:
 				i=1;
 				uifc.helpbuf=
 					"`Perform Call-out at a Specific Time:`\n"
@@ -1046,27 +1061,27 @@ void qhub_edit(int num)
 					} 
 				}
 				break;
-			case 7:
+			case __COUNTER__:
 				cfg.qhub[num]->misc^=QHUB_NOKLUDGES;
 				uifc.changes=1;
 				break;
-			case 8:
+			case __COUNTER__:
 				cfg.qhub[num]->misc^=QHUB_NOVOTING;
 				uifc.changes=1;
 				break;
-			case 9:
+			case __COUNTER__:
 				cfg.qhub[num]->misc^=QHUB_NOHEADERS;
 				uifc.changes=1;
 				break;
-			case 10:
+			case __COUNTER__:
 				cfg.qhub[num]->misc^=QHUB_UTF8;
 				uifc.changes=1;
 				break;
-			case 11:
+			case __COUNTER__:
 				cfg.qhub[num]->misc^=QHUB_EXT;
 				uifc.changes=1;
 				break;
-			case 12:
+			case __COUNTER__:
 				i = cfg.qhub[num]->misc&QHUB_CTRL_A;
 				i++;
 				if(i == QHUB_CTRL_A) i = 0;
@@ -1074,10 +1089,10 @@ void qhub_edit(int num)
 				cfg.qhub[num]->misc |= i;
 				uifc.changes=1;
 				break;
-			case 13:
+			case __COUNTER__:
 				import_qwk_conferences(num);
 				break;
-			case 14:
+			case __COUNTER__:
 				qhub_sub_edit(num);
 				break; 
 		} 
diff --git a/src/sbbs3/scfg/scfgsub.c b/src/sbbs3/scfg/scfgsub.c
index 540c13bad2..457dfbe546 100644
--- a/src/sbbs3/scfg/scfgsub.c
+++ b/src/sbbs3/scfg/scfgsub.c
@@ -1305,7 +1305,7 @@ void sub_cfg(uint grpnum)
 									"tagline in the `Networks` configuration, you should enter that tagline\n"
 									"here. If this option is left blank, the default tagline is used.\n"
 								;
-								uifc.input(WIN_MID|WIN_SAV,0,0,nulstr,cfg.sub[i]->tagline
+								uifc.input(WIN_MID|WIN_SAV,0,0,"",cfg.sub[i]->tagline
 									,sizeof(cfg.sub[i]->tagline)-1,K_MSG|K_EDIT);
 								break;
 							case 5:
@@ -1390,7 +1390,7 @@ void sub_cfg(uint grpnum)
 									"\n"
 									"If this option is blank, the default origin line is used.\n"
 								;
-								uifc.input(WIN_MID|WIN_SAV,0,0,nulstr,cfg.sub[i]->origline
+								uifc.input(WIN_MID|WIN_SAV,0,0,"",cfg.sub[i]->origline
 									,sizeof(cfg.sub[i]->origline)-1,K_EDIT);
 								break;
 						} 
diff --git a/src/sbbs3/scfg/scfgxfr1.c b/src/sbbs3/scfg/scfgxfr1.c
index 60747c3b92..098c8d7fbe 100644
--- a/src/sbbs3/scfg/scfgxfr1.c
+++ b/src/sbbs3/scfg/scfgxfr1.c
@@ -42,15 +42,12 @@ void xfer_opts()
 	static int dlevent_dflt;
 	static int dlevent_bar;
 	static int dlevent_opt;
-	static int altpath_dflt;
-	static int altpath_bar;
 	static fextr_t savfextr;
 	static fview_t savfview;
 	static ftest_t savftest;
 	static fcomp_t savfcomp;
 	static prot_t savprot;
 	static dlevent_t savdlevent;
-	static char savaltpath[LEN_DIR+1];
 
 	while(1) {
 		i=0;
@@ -60,8 +57,6 @@ void xfer_opts()
 			,cfg.max_batup);
 		sprintf(opt[i++],"%-33.33s%u","Max Files in Batch DL Queue"
 			,cfg.max_batdn);
-		sprintf(opt[i++],"%-33.33s%u","Max Users in User Transfers"
-			,cfg.max_userxfer);
 		sprintf(opt[i++],"%-33.33s%u%%","Default Credit on Upload"
 			,cfg.cdt_up_pct);
 		sprintf(opt[i++],"%-33.33s%u%%","Default Credit on Download"
@@ -71,16 +66,13 @@ void xfer_opts()
 				,cfg.leech_pct,cfg.leech_sec);
 		else
 			strcpy(str,"Disabled");
-		sprintf(opt[i++],"%-33.33s%s","Long Filenames in Listings"
-			,cfg.file_misc&FM_NO_LFN ? "No":"Yes");
 		sprintf(opt[i++],"%-33.33s%s","Leech Protocol Detection",str);
 		strcpy(opt[i++],"Viewable Files...");
 		strcpy(opt[i++],"Testable Files...");
 		strcpy(opt[i++],"Download Events...");
 		strcpy(opt[i++],"Extractable Files...");
-		strcpy(opt[i++],"Compressable Files...");
+		strcpy(opt[i++],"Compressible Files...");
 		strcpy(opt[i++],"Transfer Protocols...");
-		strcpy(opt[i++],"Alternate File Paths...");
 		opt[i][0]=0;
 		uifc.helpbuf=
 			"`File Transfer Configuration:`\n"
@@ -99,7 +91,7 @@ void xfer_opts()
 					refresh_cfg(&cfg);
 				}
 				return;
-			case 0:
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`Minimum Kilobytes Free Disk Space to Allow Uploads:`\n"
 					"\n"
@@ -111,7 +103,7 @@ void xfer_opts()
 					,ultoa(cfg.min_dspace,tmp,10),5,K_EDIT|K_NUMBER);
 				cfg.min_dspace=atoi(tmp);
 				break;
-			case 1:
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`Maximum Files in Batch Upload Queue:`\n"
 					"\n"
@@ -122,7 +114,7 @@ void xfer_opts()
 					,ultoa(cfg.max_batup,tmp,10),5,K_EDIT|K_NUMBER);
 				cfg.max_batup=atoi(tmp);
 				break;
-			case 2:
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`Maximum Files in Batch Download Queue:`\n"
 					"\n"
@@ -133,19 +125,7 @@ void xfer_opts()
 					,ultoa(cfg.max_batdn,tmp,10),5,K_EDIT|K_NUMBER);
 				cfg.max_batdn=atoi(tmp);
 				break;
-			case 3:
-				uifc.helpbuf=
-					"`Maximum Destination Users in User to User Transfer:`\n"
-					"\n"
-					"This is the maximum number of users allowed in the destination user list\n"
-					"of a user to user upload.\n"
-				;
-				uifc.input(WIN_MID,0,0
-					,"Maximum Destination Users in User to User Transfers"
-					,ultoa(cfg.max_userxfer,tmp,10),5,K_EDIT|K_NUMBER);
-				cfg.max_userxfer=atoi(tmp);
-				break;
-			case 4:
+			case __COUNTER__:
 	uifc.helpbuf=
 		"`Default Percentage of Credits to Credit Uploader on Upload:`\n"
 		"\n"
@@ -157,7 +137,7 @@ void xfer_opts()
 					,ultoa(cfg.cdt_up_pct,tmp,10),4,K_EDIT|K_NUMBER);
 				cfg.cdt_up_pct=atoi(tmp);
 				break;
-			case 5:
+			case __COUNTER__:
 	uifc.helpbuf=
 		"`Default Percentage of Credits to Credit Uploader on Download:`\n"
 		"\n"
@@ -169,27 +149,8 @@ void xfer_opts()
 					,ultoa(cfg.cdt_dn_pct,tmp,10),4,K_EDIT|K_NUMBER);
 				cfg.cdt_dn_pct=atoi(tmp);
 				break;
-			case 6:
-				i=0;
-				uifc.helpbuf=
-					"`Long Filenames in File Listings:`\n"
-					"\n"
-					"If you want long filenames to be displayed in the BBS file listings, set\n"
-					"this option to `Yes`. Note: This feature requires Windows 98, Windows 2000\n"
-					"or later.\n"
-				;
-				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
-					,"Long Filenames in Listings (Win98/Win2K)",uifcYesNoOpts);
-				if(!i && cfg.file_misc&FM_NO_LFN) {
-					cfg.file_misc&=~FM_NO_LFN;
-					uifc.changes=1;
-				} else if(i==1 && !(cfg.file_misc&FM_NO_LFN)) {
-					cfg.file_misc|=FM_NO_LFN;
-					uifc.changes=1;
-				}
-				break;
 
-			case 7:
+			case __COUNTER__:
 				uifc.helpbuf=
 					"`Leech Protocol Detection Percentage:`\n"
 					"\n"
@@ -219,7 +180,7 @@ void xfer_opts()
 					,ultoa(cfg.leech_sec,tmp,10),3,K_EDIT|K_NUMBER);
 				cfg.leech_sec=atoi(tmp);
 				break;
-			case 8: 	/* Viewable file types */
+			case __COUNTER__: 	/* Viewable file types */
 				while(1) {
 					for(i=0;i<cfg.total_fviews && i<MAX_OPTS;i++)
 						sprintf(opt[i],"%-3.3s  %-40s",cfg.fview[i]->ext,cfg.fview[i]->cmd);
@@ -337,7 +298,7 @@ void xfer_opts()
 					} 
 				}
 				break;
-			case 9:    /* Testable file types */
+			case __COUNTER__:    /* Testable file types */
 				while(1) {
 					for(i=0;i<cfg.total_ftests && i<MAX_OPTS;i++)
 						sprintf(opt[i],"%-3.3s  %-40s",cfg.ftest[i]->ext,cfg.ftest[i]->cmd);
@@ -472,7 +433,7 @@ void xfer_opts()
 					} 
 				}
 				break;
-			case 10:    /* Download Events */
+			case __COUNTER__:    /* Download Events */
 				while(1) {
 					for(i=0;i<cfg.total_dlevents && i<MAX_OPTS;i++)
 						sprintf(opt[i],"%-3.3s  %-40s",cfg.dlevent[i]->ext,cfg.dlevent[i]->cmd);
@@ -606,7 +567,7 @@ void xfer_opts()
 					} 
 				}
 				break;
-			case 11:	 /* Extractable file types */
+			case __COUNTER__:	 /* Extractable file types */
 				while(1) {
 					for(i=0;i<cfg.total_fextrs && i<MAX_OPTS;i++)
 						sprintf(opt[i],"%-3.3s  %-40s"
@@ -727,7 +688,7 @@ void xfer_opts()
 					} 
 				}
 				break;
-			case 12:	 /* Compressable file types */
+			case __COUNTER__:	 /* Compressible file types */
 				while(1) {
 					for(i=0;i<cfg.total_fcomps && i<MAX_OPTS;i++)
 						sprintf(opt[i],"%-3.3s  %-40s",cfg.fcomp[i]->ext,cfg.fcomp[i]->cmd);
@@ -740,13 +701,13 @@ void xfer_opts()
 					if(savfcomp.cmd[0])
 						i|=WIN_PASTE;
 					uifc.helpbuf=
-						"`Compressable File Types:`\n"
+						"`Compressible File Types:`\n"
 						"\n"
 						"This is a list of compression methods available for different file types.\n"
 						"These will be used for items such as creating QWK packets, temporary\n"
 						"files from the transfer section, and more.\n"
 					;
-					i=uifc.list(i,0,0,50,&fcomp_dflt,&fcomp_bar,"Compressable File Types",opt);
+					i=uifc.list(i,0,0,50,&fcomp_dflt,&fcomp_bar,"Compressible File Types",opt);
 					if(i==-1)
 						break;
 					int msk = i & MSK_ON;
@@ -821,13 +782,13 @@ void xfer_opts()
 							,cfg.fcomp[i]->arstr);
 						opt[j][0]=0;
 						switch(uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,0,&fcomp_opt,0
-							,"Compressable File Type",opt)) {
+							,"Compressible File Type",opt)) {
 							case -1:
 								done=1;
 								break;
 							case 0:
 								uifc.input(WIN_MID|WIN_SAV,0,0
-									,"Compressable File Type Extension"
+									,"Compressible File Type Extension"
 									,cfg.fcomp[i]->ext,sizeof(cfg.fcomp[i]->ext)-1,K_EDIT);
 								break;
 							case 1:
@@ -837,7 +798,7 @@ void xfer_opts()
 									,cfg.fcomp[i]->cmd,sizeof(cfg.fcomp[i]->cmd)-1,K_EDIT);
 								break;
 							case 2:
-								sprintf(str,"Compressable File Type %s"
+								sprintf(str,"Compressible File Type %s"
 									,cfg.fcomp[i]->ext);
 								getar(str,cfg.fcomp[i]->arstr);
 								break; 
@@ -845,7 +806,7 @@ void xfer_opts()
 					} 
 				}
 				break;
-			case 13:	/* Transfer protocols */
+			case __COUNTER__:	/* Transfer protocols */
 				while(1) {
 					for(i=0;i<cfg.total_prots && i<MAX_OPTS;i++)
 						sprintf(opt[i],"%c  %s"
@@ -865,8 +826,8 @@ void xfer_opts()
 						"files either to or from a remote user. For each protocol, you can\n"
 						"specify the mnemonic (hot-key) to use to specify that protocol, the\n"
 						"command line to use for uploads, downloads, batch uploads, batch\n"
-						"downloads, bi-directional file transfers, support of DSZLOG, and (for\n"
-						"*nix only) if it uses socket I/O or the more common stdio.\n"
+						"downloads, support of DSZLOG, and (for *nix only) if it uses socket\n"
+						"I/O or the more common stdio.\n"
 						"\n"
 						"If the protocol doesn't support a certain method of transfer, or you\n"
 						"don't wish it to be available for a certain method of transfer, leave\n"
@@ -951,8 +912,6 @@ void xfer_opts()
 							,cfg.prot[i]->batulcmd);
 						sprintf(opt[j++],"%-30.30s%-40s","Batch Download Command Line"
 							,cfg.prot[i]->batdlcmd);
-						sprintf(opt[j++],"%-30.30s%-40s","Bi-dir Command Line"
-							,cfg.prot[i]->bicmd);
 						sprintf(opt[j++],"%-30.30s%s",   "Native Executable/Script"
 							,cfg.prot[i]->misc&PROT_NATIVE ? "Yes" : "No");
 						sprintf(opt[j++],"%-30.30s%s",	 "Supports DSZLOG"
@@ -1008,12 +967,6 @@ void xfer_opts()
 									,cfg.prot[i]->batdlcmd,sizeof(cfg.prot[i]->batdlcmd)-1,K_EDIT);
 								break;
 							case 7:
-								uifc.helpbuf = SCFG_CMDLINE_PREFIX_HELP SCFG_CMDLINE_SPEC_HELP;
-								uifc.input(WIN_MID|WIN_SAV,0,0
-									,"Command"
-									,cfg.prot[i]->bicmd,sizeof(cfg.prot[i]->bicmd)-1,K_EDIT);
-								break;
-							case 8:
 								l=cfg.prot[i]->misc&PROT_NATIVE ? 0:1;
 								l=uifc.list(WIN_MID|WIN_SAV,0,0,0,&l,0
 									,"Native Executable/Script",uifcYesNoOpts);
@@ -1023,7 +976,7 @@ void xfer_opts()
 									uifc.changes=1; 
 								}
 								break; 
-							case 9:
+							case 8:
 								l=cfg.prot[i]->misc&PROT_DSZLOG ? 0:1;
 								l=uifc.list(WIN_MID|WIN_SAV,0,0,0,&l,0
 									,"Uses DSZLOG",uifcYesNoOpts);
@@ -1033,7 +986,7 @@ void xfer_opts()
 									uifc.changes=1; 
 								}
 								break; 
-							case 10:
+							case 9:
 								l=cfg.prot[i]->misc&PROT_SOCKET ? 0:1l;
 								l=uifc.list(WIN_MID|WIN_SAV,0,0,0,&l,0
 									,"Uses Socket I/O",uifcYesNoOpts);
@@ -1047,91 +1000,6 @@ void xfer_opts()
 					} 
 				}
 				break;
-			case 14:	/* Alternate file paths */
-				while(1) {
-					for(i=0;i<cfg.altpaths;i++)
-						sprintf(opt[i],"%3d: %-40s",i+1,cfg.altpath[i]);
-					opt[i][0]=0;
-					i=WIN_ACT|WIN_SAV;	/* save cause size can change */
-					if((int)cfg.altpaths<MAX_OPTS)
-						i|=WIN_INS|WIN_XTR;
-					if(cfg.altpaths)
-						i|=WIN_DEL|WIN_COPY|WIN_CUT;
-					if(savaltpath[0])
-						i|=WIN_PASTE;
-					uifc.helpbuf=
-						"`Alternate File Paths:`\n"
-						"\n"
-						"This option allows the sysop to add and configure alternate file paths\n"
-						"for files stored on drives and directories other than the configured\n"
-						"`File Transfer Path` of a file directory. This option is useful for sysops\n"
-						"that have file directories where they wish to have files listed from\n"
-						"multiple locations (CD-ROMs or hard disks).\n"
-					;
-					i=uifc.list(i,0,0,50,&altpath_dflt,&altpath_bar,"Alternate File Paths",opt);
-					if(i==-1)
-						break;
-					int msk = i & MSK_ON;
-					i &= MSK_OFF;
-					if(msk == MSK_DEL || msk == MSK_CUT) {
-						if(msk == MSK_CUT)
-							SAFECOPY(savaltpath, cfg.altpath[i]);
-						free(cfg.altpath[i]);
-						cfg.altpaths--;
-						while(i<cfg.altpaths) {
-							cfg.altpath[i]=cfg.altpath[i+1];
-							i++; 
-						}
-						uifc.changes=1;
-						continue; 
-					}
-					if(msk == MSK_INS) {
-						if((cfg.altpath=(char **)realloc(cfg.altpath
-							,sizeof(char *)*(cfg.altpaths+1)))==NULL) {
-							errormsg(WHERE,ERR_ALLOC,nulstr,cfg.altpaths+1);
-							cfg.altpaths=0;
-							bail(1);
-							continue; 
-						}
-						if(!cfg.altpaths) {
-							if((cfg.altpath[0]=(char *)malloc(LEN_DIR+1))==NULL) {
-								errormsg(WHERE,ERR_ALLOC,nulstr,LEN_DIR+1);
-								continue; 
-							}
-							memset(cfg.altpath[0],0,LEN_DIR+1); 
-						}
-						else {
-							for(j=cfg.altpaths;j>i;j--)
-								cfg.altpath[j]=cfg.altpath[j-1];
-							if((cfg.altpath[i]=(char *)malloc(LEN_DIR+1))==NULL) {
-								errormsg(WHERE,ERR_ALLOC,nulstr,LEN_DIR+1);
-								continue; 
-							}
-							if(i>=cfg.altpaths)
-								j=i-1;
-							else
-								j=i+1;
-							memcpy(cfg.altpath[i],cfg.altpath[j],LEN_DIR+1); 
-						}
-						cfg.altpaths++;
-						uifc.changes=1;
-						continue; 
-					}
-					if(msk == MSK_COPY) {
-						SAFECOPY(savaltpath,cfg.altpath[i]);
-						continue; 
-					}
-					if(msk == MSK_PASTE) {
-						memcpy(cfg.altpath[i],savaltpath,LEN_DIR+1);
-						uifc.changes=1;
-						continue; 
-					}
-					if (msk != 0)
-						continue;
-					sprintf(str,"Path %d",i+1);
-					uifc.input(WIN_MID|WIN_SAV,0,0,str,cfg.altpath[i],LEN_DIR,K_EDIT); 
-				}
-				break; 
 		} 
 	}
 }
diff --git a/src/sbbs3/scfg/scfgxfr2.c b/src/sbbs3/scfg/scfgxfr2.c
index 380df89069..40bb5d5714 100644
--- a/src/sbbs3/scfg/scfgxfr2.c
+++ b/src/sbbs3/scfg/scfgxfr2.c
@@ -23,6 +23,16 @@
 #define DEFAULT_DIR_OPTIONS (DIR_FCHK|DIR_MULT|DIR_DUPES|DIR_CDTUL|DIR_CDTDL|DIR_DIZ)
 #define CUT_LIBNUM	USHRT_MAX
 
+char* file_sort_desc[] = {
+	"Name Ascending (case-insensitive)",
+	"Name Descending (case-insensitive)",
+	"Date Ascending",
+	"Date Descending",
+	"Name Ascending (case-sensitive)",
+	"Name Descending (case-sensitive)",
+	NULL
+};
+
 static bool new_dir(unsigned new_dirnum, unsigned libnum)
 {
 	dir_t* new_directory = malloc(sizeof(dir_t));
@@ -32,7 +42,6 @@ static bool new_dir(unsigned new_dirnum, unsigned libnum)
 	}
 	memset(new_directory, 0, sizeof(*new_directory));
 	new_directory->lib = libnum;
-	new_directory->maxfiles = MAX_FILES;
 	new_directory->misc = DEFAULT_DIR_OPTIONS;
 	new_directory->up_pct = cfg.cdt_up_pct;
 	new_directory->dn_pct = cfg.cdt_dn_pct;
@@ -603,8 +612,9 @@ void xfer_cfg()
 							continue;
 						ported++;
 						if(k==1) {
-							fprintf(stream,"Area %-8s  0     !      %s\n"
-								,cfg.dir[j]->code_suffix,cfg.dir[j]->lname);
+							fprintf(stream,"Area %-*s  0     !      %s\n"
+								,FIDO_AREATAG_LEN
+								,dir_area_tag(&cfg, cfg.dir[j], str, sizeof(str)) ,cfg.dir[j]->lname);
 							continue;
 						}
 						fprintf(stream,"%s\n%s\n%s\n%s\n%s\n%s\n"
@@ -711,7 +721,6 @@ void xfer_cfg()
 							continue;
 						memset(&tmpdir,0,sizeof(dir_t));
 						tmpdir.misc=DEFAULT_DIR_OPTIONS;
-						tmpdir.maxfiles=MAX_FILES;
 						tmpdir.up_pct=cfg.cdt_up_pct;
 						tmpdir.dn_pct=cfg.cdt_dn_pct; 
 
@@ -761,8 +770,9 @@ void xfer_cfg()
 							while(*p && *p<=' ') p++;	/* Skip space */
 							while(*p>' ') p++;			/* Skip flags */
 							while(*p && *p<=' ') p++;	/* Skip space */
-							SAFECOPY(tmpdir.sname,tmp_code); 
-							SAFECOPY(tmpdir.lname,p); 
+							SAFECOPY(tmpdir.sname,tmp_code);
+							SAFECOPY(tmpdir.area_tag,tmp_code);
+							SAFECOPY(tmpdir.lname,p);
 							ported++;
 						}
 						else {
@@ -898,7 +908,6 @@ void xfer_cfg()
 							SAFECOPY(cfg.dir[j]->sname,tmpdir.sname);
 							SAFECOPY(cfg.dir[j]->lname,tmpdir.lname);
 							if(j==cfg.total_dirs) {
-								cfg.dir[j]->maxfiles=MAX_FILES;
 								cfg.dir[j]->up_pct=cfg.cdt_up_pct;
 								cfg.dir[j]->dn_pct=cfg.cdt_dn_pct; 
 							}
@@ -1132,6 +1141,7 @@ void dir_cfg(uint libnum)
 			sprintf(opt[n++],"%-27.27s%s","Short Name",cfg.dir[i]->sname);
 			sprintf(opt[n++],"%-27.27s%s%s","Internal Code"
 				,cfg.lib[cfg.dir[i]->lib]->code_prefix, cfg.dir[i]->code_suffix);
+			sprintf(opt[n++],"%-27.27s%s","Area Tag",cfg.dir[i]->area_tag);
 			sprintf(opt[n++],"%-27.27s%s","Access Requirements"
 				,cfg.dir[i]->arstr);
 			sprintf(opt[n++],"%-27.27s%s","Upload Requirements"
@@ -1162,8 +1172,12 @@ void dir_cfg(uint libnum)
 				SAFEPRINTF(str, "[%s]", path);
 			sprintf(opt[n++],"%-27.27s%s","Transfer File Path"
 				,str);
-			sprintf(opt[n++],"%-27.27s%u","Maximum Number of Files"
-				,cfg.dir[i]->maxfiles);
+			if(cfg.dir[i]->maxfiles)
+				sprintf(str, "%u", cfg.dir[i]->maxfiles);
+			else
+				SAFECOPY(str, "Unlimited");
+			sprintf(opt[n++],"%-27.27s%s","Maximum Number of Files"
+				,str);
 			if(cfg.dir[i]->maxage)
 				sprintf(str,"Enabled (%u days old)",cfg.dir[i]->maxage);
 			else
@@ -1216,48 +1230,49 @@ void dir_cfg(uint libnum)
 					}
 					break;
 				case 3:
+					uifc.helpbuf="FidoNet Area Tag!";
+					SAFECOPY(str, cfg.dir[i]->area_tag);
+					if(uifc.input(WIN_L2R|WIN_SAV,0,17,"FidoNet File Echo Area Tag"
+						,str, FIDO_AREATAG_LEN, K_EDIT | K_UPPER) > 0)
+						SAFECOPY(cfg.dir[i]->area_tag, str);
+					break;
+				case 4:
 					sprintf(str,"%s Access",cfg.dir[i]->sname);
 					getar(str,cfg.dir[i]->arstr);
 					break;
-				case 4:
+				case 5:
 					sprintf(str,"%s Upload",cfg.dir[i]->sname);
 					getar(str,cfg.dir[i]->ul_arstr);
 					break;
-				case 5:
+				case 6:
 					sprintf(str,"%s Download",cfg.dir[i]->sname);
 					getar(str,cfg.dir[i]->dl_arstr);
 					break;
-				case 6:
+				case 7:
 					sprintf(str,"%s Operator",cfg.dir[i]->sname);
 					getar(str,cfg.dir[i]->op_arstr);
 					break;
-				case 7:
+				case 8:
 					sprintf(str,"%s Exemption",cfg.dir[i]->sname);
 					getar(str,cfg.dir[i]->ex_arstr);
 					break;
-				case 8:
+				case 9:
 					uifc.helpbuf = dir_transfer_path_help;
 					uifc.input(WIN_L2R|WIN_SAV,0,17,"Transfer File Path"
 						,cfg.dir[i]->path,sizeof(cfg.dir[i]->path)-1,K_EDIT);
 					break;
-				case 9:
+				case 10:
 					uifc.helpbuf=
 						"`Maximum Number of Files:`\n"
 						"\n"
 						"This value is the maximum number of files allowed in this directory.\n"
 					;
 					sprintf(str,"%u",cfg.dir[i]->maxfiles);
-					uifc.input(WIN_L2R|WIN_SAV,0,17,"Maximum Number of Files"
+					uifc.input(WIN_L2R|WIN_SAV,0,17,"Maximum Number of Files (0=Unlimited)"
 						,str,5,K_EDIT|K_NUMBER);
-					n=atoi(str);
-					if(n>MAX_FILES) {
-						sprintf(str,"Maximum Files is %u",MAX_FILES);
-						uifc.msg(str);
-					}
-					else
-						cfg.dir[i]->maxfiles=n;
+					cfg.dir[i]->maxfiles=atoi(str);
 					break;
-				case 10:
+				case 11:
 					sprintf(str,"%u",cfg.dir[i]->maxage);
 					uifc.helpbuf=
 						"`Maximum Age of Files:`\n"
@@ -1273,7 +1288,7 @@ void dir_cfg(uint libnum)
 						,str,5,K_EDIT|K_NUMBER);
 					cfg.dir[i]->maxage=atoi(str);
 					break;
-				case 11:
+				case 12:
 	uifc.helpbuf=
 		"`Percentage of Credits to Credit Uploader on Upload:`\n"
 		"\n"
@@ -1289,7 +1304,7 @@ void dir_cfg(uint libnum)
 						,ultoa(cfg.dir[i]->up_pct,tmp,10),4,K_EDIT|K_NUMBER);
 					cfg.dir[i]->up_pct=atoi(tmp);
 					break;
-				case 12:
+				case 13:
 	uifc.helpbuf=
 		"`Percentage of Credits to Credit Uploader on Download:`\n"
 		"\n"
@@ -1306,7 +1321,7 @@ void dir_cfg(uint libnum)
 						,ultoa(cfg.dir[i]->dn_pct,tmp,10),4,K_EDIT|K_NUMBER);
 					cfg.dir[i]->dn_pct=atoi(tmp);
 					break;
-				case 13:
+				case 14:
 					while(1) {
 						n=0;
 						sprintf(opt[n++],"%-30.30s%s","Check for File Existence"
@@ -1355,10 +1370,12 @@ void dir_cfg(uint libnum)
 							,cfg.dir[i]->misc&DIR_MOVENEW ? "Yes":"No");
 						sprintf(opt[n++],"%-30.30s%s","Include Transfers In Stats"
 							,cfg.dir[i]->misc&DIR_NOSTAT ? "No":"Yes");
-						sprintf(opt[n++],"%-30.30s%s","Access Files not in Database"
-							,cfg.dir[i]->misc&DIR_FILES ? "Yes":"No");
+						sprintf(opt[n++],"%-30.30s%s","Calculate/Store Hash of Files"
+							,cfg.dir[i]->misc&DIR_NOHASH ? "No":"Yes");
 						sprintf(opt[n++],"%-30.30s%s","Template for New Directories"
 							,cfg.dir[i]->misc&DIR_TEMPLATE ? "Yes" : "No");
+						sprintf(opt[n++],"%-30.30s%s","Allow File Tagging"
+							,cfg.dir[i]->misc&DIR_FILETAGS ? "Yes" : "No");
 						opt[n][0]=0;
 						uifc.helpbuf=
 							"`Directory Toggle Options:`\n"
@@ -1799,22 +1816,25 @@ void dir_cfg(uint libnum)
 								}
 								break;
 							case 20:
-								n=cfg.dir[i]->misc&DIR_FILES ? 0:1;
+								n=cfg.dir[i]->misc&DIR_NOHASH ? 1:0;
 								uifc.helpbuf=
-									"`Allow Access to Files Not in Database:`\n"
+									"`Calculate/Store Hashes of Files:`\n"
 									"\n"
-									"If this option is set to ~Yes~, then all files in this directory's\n"
-									"`Transfer File Path` will be visible/downloadable by users with access to\n"
-									"this directory.\n"
+									"Set to ~Yes~ to calculate and store the hashes of file contents when\n"
+									"adding files to this file base.\n"
+									"\n"
+									"The hashes (CRC-16, CRC-32, MD5, and SHA-1) are useful for detecting\n"
+									"duplicate files (i.e. and rejecting them) as well as allowing the\n"
+									"confirmation of data integrity for the downloaders of files."
 								;
 								n=uifc.list(WIN_MID|WIN_SAV,0,0,0,&n,0
-									,"Allow Access to Files Not in Database"
+									,"Calculate/Store Hashes of Files"
 									,uifcYesNoOpts);
-								if(n==0 && !(cfg.dir[i]->misc&DIR_FILES)) {
-									cfg.dir[i]->misc|=DIR_FILES;
+								if(n==0 && cfg.dir[i]->misc&DIR_NOHASH) {
+									cfg.dir[i]->misc &= ~DIR_NOHASH;
 									uifc.changes=1; 
-								} else if(n==1 && cfg.dir[i]->misc&DIR_FILES){
-									cfg.dir[i]->misc&=~DIR_FILES;
+								} else if(n==1 && !(cfg.dir[i]->misc&DIR_NOHASH)){
+									cfg.dir[i]->misc |= DIR_NOHASH;
 									uifc.changes=1; 
 								}
 								break;
@@ -1844,10 +1864,30 @@ void dir_cfg(uint libnum)
 									cfg.dir[i]->misc&=~DIR_TEMPLATE; 
 								}
 								break;
+							case 22:
+								n=(cfg.dir[i]->misc&DIR_FILETAGS) ? 0:1;
+								uifc.helpbuf=
+									"`Allow Addition of Tags to Files:`\n"
+									"\n"
+								;
+								n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
+									,"Allow Addition of Tags to Files",uifcYesNoOpts);
+								if(n==-1)
+									break;
+								if(!n && !(cfg.dir[i]->misc & DIR_FILETAGS)) {
+									uifc.changes = TRUE;
+									cfg.dir[i]->misc |= DIR_FILETAGS;
+									break; 
+								}
+								if(n==1 && (cfg.dir[i]->misc&DIR_FILETAGS)) {
+									uifc.changes = TRUE;
+									cfg.dir[i]->misc &= ~DIR_FILETAGS; 
+								}
+								break;
 						} 
 					}
 					break;
-			case 14:
+			case 15:
 				while(1) {
 					n=0;
 					sprintf(opt[n++],"%-27.27s%s","Extensions Allowed"
@@ -1861,10 +1901,7 @@ void dir_cfg(uint libnum)
 					sprintf(opt[n++],"%-27.27s%s","Upload Semaphore File"
 						,cfg.dir[i]->upload_sem);
 					sprintf(opt[n++],"%-27.27s%s","Sort Value and Direction"
-						, cfg.dir[i]->sort==SORT_NAME_A ? "Name Ascending"
-						: cfg.dir[i]->sort==SORT_NAME_D ? "Name Descending"
-						: cfg.dir[i]->sort==SORT_DATE_A ? "Date Ascending"
-						: "Date Descending");
+						,file_sort_desc[cfg.dir[i]->sort]);
 					sprintf(opt[n++],"%-27.27sNow %u / Was %u","Directory Index", i, cfg.dir[i]->dirnum);
 					opt[n][0]=0;
 					uifc.helpbuf=
@@ -1872,7 +1909,7 @@ void dir_cfg(uint libnum)
 						"\n"
 						"This is the advanced options menu for the selected file directory.\n"
 					;
-						n=uifc.list(WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT,3,4,60,&adv_dflt,0
+						n=uifc.list(WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT,3,4,65,&adv_dflt,0
 							,"Advanced Options",opt);
 						if(n==-1)
 							break;
@@ -1914,38 +1951,22 @@ void dir_cfg(uint libnum)
 									,cfg.dir[i]->upload_sem,sizeof(cfg.dir[i]->upload_sem)-1,K_EDIT);
 								break;
 							case 3:
-								n=0;
-								strcpy(opt[0],"Name Ascending");
-								strcpy(opt[1],"Name Descending");
-								strcpy(opt[2],"Date Ascending");
-								strcpy(opt[3],"Date Descending");
-								opt[4][0]=0;
+								n = cfg.dir[i]->sort;
 								uifc.helpbuf=
 									"`Sort Value and Direction:`\n"
 									"\n"
-									"This option allows you to determine the sort value and direction. Files\n"
-									"that are uploaded are automatically sorted by filename or upload date,\n"
-									"ascending or descending. If you change the sort value or direction after\n"
-									"a directory already has files in it, use the sysop transfer menu `;RESORT`\n"
-									"command to resort the directory with the new sort parameters.\n"
+									"This option allows you to determine the sort value and direction for\n"
+									"the display of file listings.\n"
+									"\n"
+									"The dates available for sorting are the file import/upload date/time.\n"
+									"\n"
+									"The natural (and thus fastest) sort order is `Date Ascending`."
 								;
 								n=uifc.list(WIN_MID|WIN_SAV,0,0,0,&n,0
-									,"Sort Value and Direction",opt);
-								if(n==0 && cfg.dir[i]->sort!=SORT_NAME_A) {
-									cfg.dir[i]->sort=SORT_NAME_A;
-									uifc.changes=1;
-								}
-								else if(n==1 && cfg.dir[i]->sort!=SORT_NAME_D) {
-									cfg.dir[i]->sort=SORT_NAME_D;
-									uifc.changes=1;
-								}
-								else if(n==2 && cfg.dir[i]->sort!=SORT_DATE_A) {
-									cfg.dir[i]->sort=SORT_DATE_A;
-									uifc.changes=1;
-								}
-								else if(n==3 && cfg.dir[i]->sort!=SORT_DATE_D) {
-									cfg.dir[i]->sort=SORT_DATE_D;
-									uifc.changes=1;
+									,"Sort Value and Direction", file_sort_desc);
+								if(n >= 0 && cfg.dir[i]->sort != n) {
+									cfg.dir[i]->sort = n;
+									uifc.changes = TRUE;
 								}
 								break; 
 							case 4:
diff --git a/src/sbbs3/scfgdefs.h b/src/sbbs3/scfgdefs.h
index a23caa4eae..6ebf654d04 100644
--- a/src/sbbs3/scfgdefs.h
+++ b/src/sbbs3/scfgdefs.h
@@ -72,6 +72,7 @@ typedef struct {							/* Message group info */
 typedef struct {							/* Transfer Directory Info */
 	char		code[LEN_EXTCODE+1];		/* Internal code (with optional lib prefix) */
 	char		code_suffix[LEN_CODE+1];	/* Eight character code suffix */
+	char		area_tag[FIDO_AREATAG_LEN+1];
 	char		lname[LEN_SLNAME+1],		/* Long name - used for listing */
 				sname[LEN_SSNAME+1],		/* Short name - used for prompts */
 				arstr[LEN_ARSTR+1],			/* Access Requirements */
@@ -311,6 +312,7 @@ typedef struct {							/* QWK Network Hub */
 				call[LEN_CMD+1],			/* Call-out command line to execute */
 				pack[LEN_CMD+1],			/* Packing command line */
 				unpack[LEN_CMD+1];			/* Unpacking command line */
+	char		fmt[4]; 					/* Archive format */
 	uint16_t	time,						/* Time to call-out */
 				node,						/* Node to do the call-out */
 				freq,						/* Frequency of call-outs */
diff --git a/src/sbbs3/scfglib.h b/src/sbbs3/scfglib.h
index 3353552d37..0848464da0 100644
--- a/src/sbbs3/scfglib.h
+++ b/src/sbbs3/scfglib.h
@@ -61,6 +61,11 @@ long	aftol(char *str);              /* Converts flag string to long */
 char*	ltoaf(long l, char *str);     /* Converts long to flag string */
 uint	attrstr(char *str);		/* Convert ATTR string into attribute int */
 
+int		getdirnum(scfg_t*, const char* code);
+int		getlibnum(scfg_t*, const char* code);
+int		getsubnum(scfg_t*, const char* code);
+int		getgrpnum(scfg_t*, const char* code);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/sbbs3/scfglib1.c b/src/sbbs3/scfglib1.c
index 966dbf9087..f274307026 100644
--- a/src/sbbs3/scfglib1.c
+++ b/src/sbbs3/scfglib1.c
@@ -625,7 +625,8 @@ BOOL read_msgs_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
 			}
 		}
 		get_int(cfg->qhub[i]->misc, instream);
-		for(j=0;j<30;j++)
+		get_str(cfg->qhub[i]->fmt,instream);
+		for(j=0;j<28;j++)
 			get_int(n,instream);
 	}
 
@@ -812,3 +813,55 @@ void make_data_dirs(scfg_t* cfg)
 	}
 #endif
 }
+
+int getdirnum(scfg_t* cfg, const char* code)
+{
+	size_t i;
+
+	if(code == NULL || *code == '\0')
+		return -1;
+
+	for(i=0;i<cfg->total_dirs;i++)
+		if(stricmp(cfg->dir[i]->code,code)==0)
+			return(i);
+	return(-1);
+}
+
+int getlibnum(scfg_t* cfg, const char* code)
+{
+	size_t i;
+
+	if(code == NULL || *code == '\0')
+		return -1;
+
+	for(i=0;i<cfg->total_dirs;i++)
+		if(stricmp(cfg->dir[i]->code,code)==0)
+			return(cfg->dir[i]->lib);
+	return(-1);
+}
+
+int getsubnum(scfg_t* cfg, const char* code)
+{
+	size_t i;
+
+	if(code == NULL || *code == '\0')
+		return -1;
+
+	for(i=0;i<cfg->total_subs;i++)
+		if(stricmp(cfg->sub[i]->code,code)==0)
+			return(i);
+	return(-1);
+}
+
+int getgrpnum(scfg_t* cfg, const char* code)
+{
+	size_t i;
+
+	if(code == NULL || *code == '\0')
+		return -1;
+
+	for(i=0;i<cfg->total_subs;i++)
+		if(stricmp(cfg->sub[i]->code,code)==0)
+			return(cfg->sub[i]->grp);
+	return(-1);
+}
diff --git a/src/sbbs3/scfglib2.c b/src/sbbs3/scfglib2.c
index a6f9fc6c4a..ccba11fcf6 100644
--- a/src/sbbs3/scfglib2.c
+++ b/src/sbbs3/scfglib2.c
@@ -361,8 +361,6 @@ BOOL read_file_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
 		get_str(cfg->dir[i]->upload_sem,instream);
 
 		get_int(cfg->dir[i]->maxfiles,instream);
-		if(cfg->dir[i]->maxfiles>MAX_FILES)
-			cfg->dir[i]->maxfiles=MAX_FILES;
 		get_str(cfg->dir[i]->exts,instream);
 		get_int(cfg->dir[i]->misc,instream);
 		get_int(cfg->dir[i]->seqdev,instream);
@@ -373,8 +371,9 @@ BOOL read_file_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
 		get_int(cfg->dir[i]->maxage,instream);
 		get_int(cfg->dir[i]->up_pct,instream);
 		get_int(cfg->dir[i]->dn_pct,instream);
+		get_str(cfg->dir[i]->area_tag,instream);
 		get_int(c,instream);
-		for(j=0;j<24;j++)
+		for(j=0;j<6;j++)
 			get_int(n,instream); 
 	}
 
diff --git a/src/sbbs3/scfgsave.c b/src/sbbs3/scfgsave.c
index cbf258496d..5be3129b0d 100644
--- a/src/sbbs3/scfgsave.c
+++ b/src/sbbs3/scfgsave.c
@@ -540,8 +540,9 @@ BOOL DLLCALL write_msgs_cfg(scfg_t* cfg, int backup_level)
 			put_int(cfg->qhub[i]->mode[j],stream); 
 		}
 		put_int(cfg->qhub[i]->misc, stream);
+		put_str(cfg->qhub[i]->fmt,stream);
 		n=0;
-		for(j=0;j<30;j++)
+		for(j=0;j<28;j++)
 			put_int(n,stream); 
 	}
 	n=0;
@@ -835,13 +836,11 @@ BOOL DLLCALL write_file_cfg(scfg_t* cfg, int backup_level)
 				put_int(cfg->dir[i]->maxage, stream);
 				put_int(cfg->dir[i]->up_pct, stream);
 				put_int(cfg->dir[i]->dn_pct, stream);
+				put_str(cfg->dir[i]->area_tag, stream);
 				c = 0;
 				put_int(c, stream);
-				n = 0;
-				for (k = 0; k < 8; k++)
-					put_int(n, stream);
 				n = 0xffff;
-				for (k = 0; k < 16; k++)
+				for (k = 0; k < 6; k++)
 					put_int(n, stream);
 			}
 		}
@@ -1092,54 +1091,3 @@ void DLLCALL refresh_cfg(scfg_t* cfg)
 
 	SAFEPRINTF(str,"%srecycle",cfg->ctrl_dir);		ftouch(str);
 }
-
-int DLLCALL smb_storage_mode(scfg_t* cfg, smb_t* smb)
-{
-	if(smb == NULL || smb->subnum == INVALID_SUB || (smb->status.attr&SMB_EMAIL))
-		return (cfg->sys_misc&SM_FASTMAIL) ? SMB_FASTALLOC : SMB_SELFPACK;
-	if(smb->subnum >= cfg->total_subs)
-		return (smb->status.attr&SMB_HYPERALLOC) ? SMB_HYPERALLOC : SMB_FASTALLOC;
-	if(cfg->sub[smb->subnum]->misc&SUB_HYPER) {
-		smb->status.attr |= SMB_HYPERALLOC;
-		return SMB_HYPERALLOC;
-	}
-	if(cfg->sub[smb->subnum]->misc&SUB_FAST)
-		return SMB_FASTALLOC;
-	return SMB_SELFPACK;
-}
-
-/* Open Synchronet Message Base and create, if necessary (e.g. first time opened) */
-/* If return value is not SMB_SUCCESS, sub-board is not left open */
-int DLLCALL smb_open_sub(scfg_t* cfg, smb_t* smb, unsigned int subnum)
-{
-	int retval;
-	smbstatus_t smb_status = {0};
-
-	if(subnum != INVALID_SUB && subnum >= cfg->total_subs)
-		return SMB_FAILURE;
-	memset(smb, 0, sizeof(smb_t));
-	if(subnum == INVALID_SUB) {
-		SAFEPRINTF(smb->file, "%smail", cfg->data_dir);
-		smb_status.max_crcs	= cfg->mail_maxcrcs;
-		smb_status.max_msgs	= 0;
-		smb_status.max_age	= cfg->mail_maxage;
-		smb_status.attr		= SMB_EMAIL;
-	} else {
-		SAFEPRINTF2(smb->file, "%s%s", cfg->sub[subnum]->data_dir, cfg->sub[subnum]->code);
-		smb_status.max_crcs	= cfg->sub[subnum]->maxcrcs;
-		smb_status.max_msgs	= cfg->sub[subnum]->maxmsgs;
-		smb_status.max_age	= cfg->sub[subnum]->maxage;
-		smb_status.attr		= cfg->sub[subnum]->misc&SUB_HYPER ? SMB_HYPERALLOC :0;
-	}
-	smb->retry_time = cfg->smb_retry_time;
-	if((retval = smb_open(smb)) == SMB_SUCCESS) {
-		if(smb_fgetlength(smb->shd_fp) < sizeof(smbhdr_t) + sizeof(smb->status)) {
-			smb->status = smb_status;
-			if((retval = smb_create(smb)) != SMB_SUCCESS)
-				smb_close(smb);
-		}
-		if(retval == SMB_SUCCESS)
-			smb->subnum = subnum;
-	}
-	return retval;
-}
diff --git a/src/sbbs3/scfgsave.h b/src/sbbs3/scfgsave.h
index e0363a72bb..15ce25b7cf 100644
--- a/src/sbbs3/scfgsave.h
+++ b/src/sbbs3/scfgsave.h
@@ -21,7 +21,6 @@
 #define _SCFGSAVE_H_
 
 #include "scfgdefs.h"
-#include "smbdefs.h"
 #include "dllexport.h"
 
 #ifdef __cplusplus
@@ -36,8 +35,6 @@ DLLEXPORT BOOL		write_file_cfg(scfg_t* cfg, int backup_level);
 DLLEXPORT BOOL		write_chat_cfg(scfg_t* cfg, int backup_level);
 DLLEXPORT BOOL		write_xtrn_cfg(scfg_t* cfg, int backup_level);
 DLLEXPORT void		refresh_cfg(scfg_t* cfg);
-DLLEXPORT int		smb_storage_mode(scfg_t*, smb_t*);
-DLLEXPORT int		smb_open_sub(scfg_t*, smb_t*, unsigned int subnum);
 
 #ifdef __cplusplus
 }
diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index 11efc7f59b..e1067a2d83 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -47,7 +47,8 @@
 #include "js_socket.h"
 #include "multisock.h"
 #include "ssl.h"
-#include "ver.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 /* Constants */
 
@@ -794,6 +795,10 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
 		if(js_CreateMsgBaseClass(js_cx, *glob, &scfg)==NULL)
 			break;
 
+		/* FileBase Class */
+		if(js_CreateFileBaseClass(js_cx, *glob, &scfg)==NULL)
+			break;
+
 		/* File Class */
 		if(js_CreateFileClass(js_cx, *glob)==NULL)
 			break;
@@ -1693,7 +1698,7 @@ const char* DLLCALL services_ver(void)
 #else
 		,""
 #endif
-		,git_branch, git_hash
+		,GIT_BRANCH, GIT_HASH
 		,__DATE__, __TIME__, compiler
 		);
 
@@ -1851,7 +1856,7 @@ void DLLCALL services_thread(void* arg)
 
 		DESCRIBE_COMPILER(compiler);
 
-		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", git_branch, git_hash, __DATE__, __TIME__, compiler);
+		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, compiler);
 
 		protected_uint32_init(&threads_pending_start,0);
 
diff --git a/src/sbbs3/services.vcxproj b/src/sbbs3/services.vcxproj
index 57beac0b87..b84a464865 100644
--- a/src/sbbs3/services.vcxproj
+++ b/src/sbbs3/services.vcxproj
@@ -176,7 +176,6 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
-    <ClCompile Include="ver.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\xpdev\xpdev_mt.vcxproj">
diff --git a/src/sbbs3/sexyz.vcxproj b/src/sbbs3/sexyz.vcxproj
index 1951389828..68a0a5161f 100644
--- a/src/sbbs3/sexyz.vcxproj
+++ b/src/sbbs3/sexyz.vcxproj
@@ -66,7 +66,7 @@
     <ClCompile>
       <Optimization>Disabled</Optimization>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_DEBUG;WIN32;_CONSOLE;SBBS_EXPORTS;RINGBUF_SEM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_DEBUG;WIN32;_CONSOLE;SBBS_EXPORTS;RINGBUF_SEM;RINGBUF_EVENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <PrecompiledHeaderOutputFile>.\msvc.win32.debug\sexyz/sexyz.pch</PrecompiledHeaderOutputFile>
@@ -110,7 +110,7 @@
       <Optimization>MaxSpeed</Optimization>
       <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>NDEBUG;WIN32;_CONSOLE;SBBS_EXPORTS;RINGBUF_SEM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NDEBUG;WIN32;_CONSOLE;SBBS_EXPORTS;RINGBUF_SEM;RINGBUF_EVENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <FunctionLevelLinking>true</FunctionLevelLinking>
diff --git a/src/sbbs3/slog.c b/src/sbbs3/slog.c
index 958cd65629..1de08ace1e 100644
--- a/src/sbbs3/slog.c
+++ b/src/sbbs3/slog.c
@@ -26,8 +26,8 @@ int main(int argc, char **argv)
 	int i,file,pause=0,lncntr=0;
     time_t timestamp;
     long l;
-    ulong   length,
-            logons,
+    off_t   length;
+    ulong	logons,
             timeon,
             posts,
             emails,
@@ -65,13 +65,13 @@ length=filelength(file);
 if(length<40) {
     close(file);
 	return(1); }
-if((buf=malloc(length))==0) {
+if((buf=malloc((size_t)length))==0) {
     close(file);
-	printf("error allocating %lu bytes\r\n",length);
+	printf("error allocating %lu bytes\r\n",(ulong)length);
 	return(1); }
-read(file,buf,length);
+read(file,buf,(uint)length);
 close(file);
-l=length-4;
+l=(long)(length-4);
 while(l>-1L) {
     fbacks=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
         |((long)buf[l+3]<<24);
diff --git a/src/sbbs3/smbactiv.c b/src/sbbs3/smbactiv.c
index ad888e6712..f9c7f8b01d 100644
--- a/src/sbbs3/smbactiv.c
+++ b/src/sbbs3/smbactiv.c
@@ -36,7 +36,7 @@ ulong first_msg()
 {
 	smbmsg_t msg;
 
-	msg.offset=0;
+	msg.idx_offset=0;
 	msg.hdr.number=0;
 	if(smb_getmsgidx(&smb,&msg))			/* Get first message index */
 		return(0);
@@ -84,7 +84,8 @@ int main(int argc, char **argv)
 {
 	char str[256],*p;
 	int i,j,file;
-	ulong length,max_users=0xffffffff;
+	off_t length;
+	ulong max_users=0xffffffff;
 	uint32_t l;
 	sub_status_t *sub_status;
 	scfg_t	cfg;
diff --git a/src/sbbs3/smbutil.c b/src/sbbs3/smbutil.c
index 47afdaf4cb..b99c81d10f 100644
--- a/src/sbbs3/smbutil.c
+++ b/src/sbbs3/smbutil.c
@@ -19,8 +19,7 @@
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
-#define SMBUTIL_VER "2.34"
-char	revision[16];
+#define SMBUTIL_VER "3.19"
 char	compiler[32];
 
 const char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
@@ -53,6 +52,9 @@ const char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
 #include "str_util.h"
 #include "utf8.h"
 #include "conwrap.h"
+#include "xpdatetime.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 /* gets is dangerous */
 #define gets(str)  fgets((str), sizeof(str), stdin)
@@ -87,6 +89,7 @@ char *usage=
 "       r[n] = read msgs starting at number n\n"
 "       x[n] = dump msg index at number n\n"
 "       v[n] = view msg headers starting at number n\n"
+"       V[n] = view msg headers starting at number n verbose\n"
 "       i[f] = import msg from text file f (or use stdin)\n"
 "       e[f] = import e-mail from text file f (or use stdin)\n"
 "       n[f] = import netmail from text file f (or use stdin)\n"
@@ -332,10 +335,10 @@ void postmsg(char type, char* to, char* to_number, char* to_address,
 		bail(1); 
 	}
 
-	safe_snprintf(str,sizeof(str),"SMBUTIL %s-%s r%s %s %s"
+	safe_snprintf(str,sizeof(str),"SMBUTIL %s-%s %s/%s %s %s"
 		,SMBUTIL_VER
 		,PLATFORM_DESC
-		,revision
+		,GIT_BRANCH, GIT_HASH
 		,__DATE__
 		,compiler
 		);
@@ -490,14 +493,15 @@ void listmsgs(ulong start, ulong count)
 	int i;
 	ulong l=0;
 	smbmsg_t msg;
+	size_t idxreclen = smb_idxreclen(&smb);
 
 	if(!start)
 		start=1;
 	if(!count)
 		count=~0;
-	fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
 	while(l<count) {
-		if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
+		fseek(smb.sid_fp,((start-1L) + l)*idxreclen,SEEK_SET);
+		if(!fread(&msg.idx,1,sizeof(msg.idx),smb.sid_fp))
 			break;
 		i=smb_lockmsghdr(&smb,&msg);
 		if(i) {
@@ -558,25 +562,43 @@ char *my_timestr(time_t intime)
 /****************************************************************************/
 void dumpindex(ulong start, ulong count)
 {
+	char tmp[128];
 	ulong l=0;
 	idxrec_t idx;
+	size_t idxreclen = smb_idxreclen(&smb);
 
 	if(!start)
 		start=1;
 	if(!count)
 		count=~0;
-	fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
 	while(l<count) {
+		fseek(smb.sid_fp,((start-1L) + l) * idxreclen,SEEK_SET);
 		if(!fread(&idx,1,sizeof(idx),smb.sid_fp))
 			break;
 		printf("%10"PRIu32"  ", idx.number);
-		if(idx.attr&MSG_VOTE && !(idx.attr&MSG_POLL))
-			printf("V  %04hX  %-10"PRIu32, idx.votes,idx.remsg);
-		else
-			printf("%c  %04hX  %04hX  %04X"
-				,(idx.attr&MSG_POLL_VOTE_MASK) == MSG_POLL_CLOSURE ? 'C' : (idx.attr&MSG_POLL ? 'P':' ')
-				,idx.from, idx.to, idx.subj);
-		printf("  %04X  %06X  %s\n", idx.attr, idx.offset, my_timestr(idx.time));
+		switch(smb_msg_type(idx.attr)) {
+			case SMB_MSG_TYPE_FILE:
+				printf("F %10lu  ", (ulong)idx.size);
+				break;
+			case SMB_MSG_TYPE_BALLOT:
+				printf("V  %04hX  %-10"PRIu32, idx.votes,idx.remsg);
+				break;
+			default:
+				printf("%c  %04hX  %04hX  %04X"
+					,(idx.attr&MSG_POLL_VOTE_MASK) == MSG_POLL_CLOSURE ? 'C' : (idx.attr&MSG_POLL ? 'P':' ')
+					,idx.from, idx.to, idx.subj);
+				break;
+		}
+		printf("  %04X  %06X  %s", idx.attr, idx.offset
+			,xpDate_to_isoDateStr(time_to_xpDate(idx.time), "-", tmp, sizeof(tmp)));
+		if(smb_msg_type(idx.attr) == SMB_MSG_TYPE_FILE && idxreclen == sizeof(fileidxrec_t)) {
+			fileidxrec_t fidx;
+			fseek(smb.sid_fp,((start-1L) + l) * idxreclen,SEEK_SET);
+			if(!fread(&fidx,1,sizeof(fidx),smb.sid_fp))
+				break;
+			printf("  %02X  %.*s", fidx.hash.flags, (int)sizeof(fidx.name), fidx.name);
+		}
+		printf("\n");
 		l++; 
 	}
 }
@@ -589,14 +611,15 @@ void viewmsgs(ulong start, ulong count, BOOL verbose)
 	int i,j;
 	ulong l=0;
 	smbmsg_t msg;
+	size_t idxreclen = smb_idxreclen(&smb);
 
 	if(!start)
 		start=1;
 	if(!count)
 		count=~0;
-	fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
 	while(l<count) {
-		if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
+		fseek(smb.sid_fp,((start-1L) + l) * idxreclen,SEEK_SET);
+		if(!fread(&msg.idx,1,sizeof(msg.idx),smb.sid_fp))
 			break;
 		i=smb_lockmsghdr(&smb,&msg);
 		if(i) {
@@ -613,7 +636,7 @@ void viewmsgs(ulong start, ulong count, BOOL verbose)
 		}
 
 		printf("--------------------\n");
-		printf("%-16.16s %ld\n"		,"index record",ftell(smb.sid_fp)/sizeof(idxrec_t));
+		printf("%-16.16s %ld\n"		,"index record",ftell(smb.sid_fp)/idxreclen);
 		smb_dump_msghdr(stdout,&msg);
 		if(verbose) {
 			for(i=0; i<msg.total_hfields; i++) {
@@ -654,11 +677,13 @@ void dump_hashes(void)
 		printf("%-10s: %s\n",		"Time",		my_timestr(hash.time));
 		printf("%-10s: %02x\n",		"Flags",	hash.flags);
 		if(hash.flags&SMB_HASH_CRC16)
-			printf("%-10s: %04x\n",	"CRC-16",	hash.crc16);
+			printf("%-10s: %04x\n",	"CRC-16",	hash.data.crc16);
 		if(hash.flags&SMB_HASH_CRC32)
-			printf("%-10s: %08"PRIx32"\n","CRC-32",	hash.crc32);
+			printf("%-10s: %08"PRIx32"\n","CRC-32",	hash.data.crc32);
 		if(hash.flags&SMB_HASH_MD5)
-			printf("%-10s: %s\n",	"MD5",		MD5_hex((BYTE*)tmp,hash.md5));
+			printf("%-10s: %s\n",	"MD5",		MD5_hex(tmp,hash.data.md5));
+		if(hash.flags&SMB_HASH_SHA1)
+			printf("%-10s: %s\n",	"SHA-1",	SHA1_hex(tmp,hash.data.sha1));
 	}
 
 	smb_close_hash(&smb);
@@ -675,6 +700,8 @@ void maint(void)
 	time_t now;
 	smbmsg_t msg;
 	idxrec_t *idx;
+	size_t idxreclen = smb_idxreclen(&smb);
+	uint8_t* idxbuf;
 
 	printf("Maintaining %s\r\n",smb.file);
 	now=time(NULL);
@@ -697,7 +724,7 @@ void maint(void)
 
 		printf("Maintaining %s hash file\r\n", smb.file);
 
-		if((smb.status.attr&(SMB_EMAIL|SMB_NOHASH)) == 0) {
+		if((smb.status.attr&(SMB_EMAIL|SMB_NOHASH|SMB_FILE_DIRECTORY)) == 0) {
 			max_hashes = smb.status.max_msgs;
 			if(smb.status.max_crcs > max_hashes)
 				max_hashes = smb.status.max_crcs;
@@ -726,21 +753,22 @@ void maint(void)
 		return; 
 	}
 	printf("Loading index...\n");
-	if((idx=(idxrec_t *)malloc(sizeof(idxrec_t)*smb.status.total_msgs))
+	if((idxbuf = malloc(idxreclen * smb.status.total_msgs))
 		==NULL) {
 		smb_unlocksmbhdr(&smb);
 		fprintf(errfp,"\n%s!Error allocating %" XP_PRIsize_t "u bytes of memory\n"
-			,beep,sizeof(idxrec_t)*smb.status.total_msgs);
+			,beep,idxreclen * smb.status.total_msgs);
 		return; 
 	}
 	fseek(smb.sid_fp,0L,SEEK_SET);
-	l = fread(idx, sizeof(idxrec_t), smb.status.total_msgs, smb.sid_fp);
+	l = fread(idxbuf, idxreclen, smb.status.total_msgs, smb.sid_fp);
 
 	printf("\nDone.\n\n");
 	printf("Scanning for pre-flagged messages...\n");
 	for(m=0;m<l;m++) {
+		idx = (idxrec_t*)(idxbuf + (m * idxreclen));
 //		printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
-		if(idx[m].attr&MSG_DELETE)
+		if(idx->attr&MSG_DELETE)
 			flagged++; 
 	}
 	printf("\r100%% (%lu pre-flagged for deletion)\n",flagged);
@@ -749,14 +777,15 @@ void maint(void)
 		printf("Scanning for messages more than %u days old...\n"
 			,smb.status.max_age);
 		for(m=f=0;m<l;m++) {
+			idx = (idxrec_t*)(idxbuf + (m * idxreclen));
 //			printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
-			if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
+			if(idx->attr&(MSG_PERMANENT|MSG_DELETE))
 				continue;
-			if((ulong)now>idx[m].time && (now-idx[m].time)/(24L*60L*60L)
+			if((ulong)now>idx->time && (now-idx->time)/(24L*60L*60L)
 				>smb.status.max_age) {
 				f++;
 				flagged++;
-				idx[m].attr|=MSG_DELETE; 
+				idx->attr|=MSG_DELETE; 
 			} 
 		}  /* mark for deletion */
 		printf("\r100%% (%lu flagged for deletion due to age)\n",f); 
@@ -765,34 +794,36 @@ void maint(void)
 	printf("Scanning for read messages to be killed...\n");
 	uint32_t total_msgs = 0;
 	for(m=f=0;m<l;m++) {
-		enum smb_msg_type type = smb_msg_type(idx[m].attr);
+		idx = (idxrec_t*)(idxbuf + (m * idxreclen));
+		enum smb_msg_type type = smb_msg_type(idx->attr);
 		if(type == SMB_MSG_TYPE_NORMAL || type == SMB_MSG_TYPE_POLL)
 			total_msgs++;
 //		printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
-		if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
+		if(idx->attr&(MSG_PERMANENT|MSG_DELETE))
 			continue;
-		if((idx[m].attr&(MSG_READ|MSG_KILLREAD))==(MSG_READ|MSG_KILLREAD)) {
+		if((idx->attr&(MSG_READ|MSG_KILLREAD))==(MSG_READ|MSG_KILLREAD)) {
 			f++;
 			flagged++;
-			idx[m].attr|=MSG_DELETE; 
-		}
+			idx->attr|=MSG_DELETE; 
+		} 
 	}
 	printf("\r100%% (%lu flagged for deletion due to read status)\n",f);
 
 	if(smb.status.max_msgs && total_msgs - flagged > smb.status.max_msgs) {
 		printf("Flagging excess messages for deletion...\n");
-		for(m=n=0,f=flagged; total_msgs - flagged > smb.status.max_msgs && m<l; m++) {
-			if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
+		for(m=n=0,f=flagged;l-flagged>smb.status.max_msgs && m<l;m++) {
+			idx = (idxrec_t*)(idxbuf + (m * idxreclen));
+			if(idx->attr&(MSG_PERMANENT|MSG_DELETE))
 				continue;
 			printf("%lu of %lu\r",++n,(total_msgs - f)-smb.status.max_msgs);
 			flagged++;
-			idx[m].attr|=MSG_DELETE; 
+			idx->attr|=MSG_DELETE; 
 		}			/* mark for deletion */
 		printf("\nDone.\n\n"); 
 	}
 
 	if(!flagged) {				/* No messages to delete */
-		free(idx);
+		free(idxbuf);
 		smb_unlocksmbhdr(&smb);
 		return; 
 	}
@@ -818,9 +849,10 @@ void maint(void)
 		}
 
 		for(m=n=0;m<l;m++) {
-			if(idx[m].attr&MSG_DELETE) {
+			idx = (idxrec_t*)(idxbuf + (m * idxreclen));
+			if(idx->attr&MSG_DELETE) {
 				printf("%lu of %lu\r",++n,flagged);
-				msg.idx=idx[m];
+				msg.idx=*idx;
 				msg.hdr.number=msg.idx.number;
 				if((i=smb_getmsgidx(&smb,&msg))!=0) {
 					fprintf(errfp,"\n%s!smb_getmsgidx returned %d: %s\n"
@@ -867,17 +899,18 @@ void maint(void)
 	printf("Re-writing index...\n");
 	rewind(smb.sid_fp);
 	for(m=n=0;m<l;m++) {
-		if(idx[m].attr&MSG_DELETE)
+		idx = (idxrec_t*)(idxbuf + (m * idxreclen));
+		if(idx->attr&MSG_DELETE)
 			continue;
 		n++;
 		printf("%lu of %lu\r", n, l-flagged);
-		fwrite(&idx[m],sizeof(idxrec_t),1,smb.sid_fp); 
+		fwrite(idx, idxreclen ,1 ,smb.sid_fp); 
 	}
 	fflush(smb.sid_fp);
-	CHSIZE_FP(smb.sid_fp, n * sizeof(idxrec_t));
+	CHSIZE_FP(smb.sid_fp, n * idxreclen);
 	printf("\nDone.\n\n");
 
-	free(idx);
+	free(idxbuf);
 	smb.status.total_msgs-=flagged;
 	smb_putstatus(&smb);
 	smb_unlocksmbhdr(&smb);
@@ -896,13 +929,15 @@ void packmsgs(ulong packable)
 	uchar	buf[SDT_BLOCK_LEN],ch;
 	char	fname[MAX_PATH+1],tmpfname[MAX_PATH+1];
 	int i,size;
-	ulong l,m,n,datoffsets=0,length,total;
+	ulong l,m,n,datoffsets=0,total;
+	off_t length;
 	FILE *tmp_sdt,*tmp_shd,*tmp_sid;
 	BOOL		error=FALSE;
 	smbhdr_t	hdr;
 	smbmsg_t	msg;
 	datoffset_t *datoffset=NULL;
 	time_t		now;
+	size_t		idxreclen = smb_idxreclen(&smb);
 
 	now=time(NULL);
 	printf("Packing %s\n",smb.file);
@@ -1104,11 +1139,11 @@ void packmsgs(ulong packable)
 		fread(&ch,1,1,smb.shd_fp);			/* copy additional base header records */
 		fwrite(&ch,1,1,tmp_shd); 
 	}
-	fseek(smb.sid_fp,0L,SEEK_SET);
 	total=0;
 	for(l=0;l<smb.status.total_msgs;l++) {
+		fseek(smb.sid_fp, l * idxreclen,SEEK_SET);
 		printf("%lu of %"PRIu32"\r",l+1,smb.status.total_msgs);
-		if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
+		if(!fread(&msg.idx, 1, sizeof(msg.idx), smb.sid_fp))
 			break;
 		if(msg.idx.attr&MSG_DELETE) {
 			printf("\nDeleted index %lu: msg number %lu\n", l,(ulong) msg.idx.number);
@@ -1158,8 +1193,8 @@ void packmsgs(ulong packable)
 			}
 
 			if(!(smb.status.attr&SMB_HYPERALLOC)) {
-				datoffset[datoffsets].new=msg.hdr.offset
-					=smb_fallocdat(&smb,m,1);
+				msg.hdr.offset = (uint32_t)smb_fallocdat(&smb,(uint32_t)m,1);
+				datoffset[datoffsets].new = msg.hdr.offset;
 				datoffsets++;
 				fseek(tmp_sdt,msg.hdr.offset,SEEK_SET); 
 			}
@@ -1189,9 +1224,10 @@ void packmsgs(ulong packable)
 		if(smb.status.attr&SMB_HYPERALLOC)
 			msg.idx.offset=ftell(tmp_shd);
 		else
-			msg.idx.offset=smb_fallochdr(&smb,length)+smb.status.header_offset;
+			msg.idx.offset=(uint32_t)smb_fallochdr(&smb,(ulong)length)+smb.status.header_offset;
 		smb_init_idx(&smb, &msg);
-		fwrite(&msg.idx,1,sizeof(idxrec_t),tmp_sid);
+		fseek(tmp_sid, l * idxreclen, SEEK_SET);
+		fwrite(&msg.idx, 1, sizeof(msg.idx), tmp_sid);
 
 		/* Write the new header entry */
 		fseek(tmp_shd,msg.idx.offset,SEEK_SET);
@@ -1376,15 +1412,16 @@ void readmsgs(ulong start, ulong count)
 	int 	i,done=0,domsg=1;
 	ulong	rd = 0;
 	smbmsg_t msg;
+	size_t	idxreclen = smb_idxreclen(&smb);
 
 	if(start)
-		msg.offset=start-1;
+		msg.idx_offset=start-1;
 	else
-		msg.offset=0;
+		msg.idx_offset=0;
 	while(!done) {
 		if(domsg) {
-			fseek(smb.sid_fp,msg.offset*sizeof(idxrec_t),SEEK_SET);
-			if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
+			fseek(smb.sid_fp,msg.idx_offset*idxreclen,SEEK_SET);
+			if(!fread(&msg.idx,1,sizeof(msg.idx),smb.sid_fp))
 				break;
 			i=smb_lockmsghdr(&smb,&msg);
 			if(i) {
@@ -1400,12 +1437,14 @@ void readmsgs(ulong start, ulong count)
 				break; 
 			}
 
-			printf("\n#%"PRIu32" (%d)\n",msg.hdr.number,msg.offset+1);
+			printf("\n#%"PRIu32" (%d)\n",msg.hdr.number,msg.idx_offset+1);
 			printf("Subj : %s\n",msg.subj);
-			printf("Attr : %04hX\n", msg.hdr.attr);
-			printf("To   : %s",msg.to);
-			if(msg.to_net.type)
-				printf(" (%s)",smb_netaddr(&msg.to_net));
+			printf("Attr : %04hX", msg.hdr.attr);
+			if(*msg.to) {
+				printf("\nTo   : %s",msg.to);
+				if(msg.to_net.type)
+					printf(" (%s)",smb_netaddr(&msg.to_net));
+			}
 			printf("\nFrom : %s",msg.from);
 			if(msg.from_net.type)
 				printf(" (%s)",smb_netaddr(&msg.from_net));
@@ -1413,7 +1452,7 @@ void readmsgs(ulong start, ulong count)
 				,my_timestr(msg.hdr.when_written.time)
 				,smb_zonestr(msg.hdr.when_written.zone,NULL));
 
-			printf("\n\n");
+			printf("\n%s\n", msg.summary ? msg.summary : "");
 
 			if((inbuf=smb_getmsgtxt(&smb,&msg, msgtxtmode))!=NULL) {
 				char* p;
@@ -1435,7 +1474,7 @@ void readmsgs(ulong start, ulong count)
 		if(count) {
 			if(rd >= count)
 				break;
-			msg.offset++;
+			msg.idx_offset++;
 			continue;
 		}
 		printf("\nReading %s (?=Menu): ",smb.file);
@@ -1462,13 +1501,13 @@ void readmsgs(ulong start, ulong count)
 				break;
 			case '-':
 				printf("Backwards\n");
-				if(msg.offset)
-					msg.offset--;
+				if(msg.idx_offset)
+					msg.idx_offset--;
 				break;
 			case 'T':
 				printf("Ten titles\n");
-				listmsgs(msg.offset+2,10);
-				msg.offset+=10;
+				listmsgs(msg.idx_offset+2,10);
+				msg.idx_offset+=10;
 				domsg=0;
 				break;
 			case 'L':
@@ -1489,7 +1528,7 @@ void readmsgs(ulong start, ulong count)
 			case '\n':
 			case '+':
 				printf("Next\n");
-				msg.offset++;
+				msg.idx_offset++;
 				break; 
 		} 
 	}
@@ -1548,7 +1587,7 @@ long getmsgnum(const char* str)
 		msg.hdr.number = atol(str + 1);
 		int result = smb_getmsgidx(&smb, &msg);
 		if(result == SMB_SUCCESS)
-			return msg.offset + 1;
+			return msg.idx_offset + 1;
 	}
 	return atol(str);
 }
@@ -1586,19 +1625,30 @@ int main(int argc, char **argv)
 	else	/* if redirected, don't send status messages to stderr */
 		statfp=nulfp;
 
-	sscanf("$Revision: 1.136 $", "%*s %s", revision);
-
 	DESCRIBE_COMPILER(compiler);
 
 	smb.file[0]=0;
-	fprintf(statfp,"\nSMBUTIL v%s-%s (rev %s) SMBLIB %s - Synchronet Message Base "\
+	fprintf(statfp,"\nSMBUTIL v%s-%s %s/%s SMBLIB %s - Synchronet Message Base "\
 		"Utility\n\n"
 		,SMBUTIL_VER
 		,PLATFORM_DESC
-		,revision
+		,GIT_BRANCH, GIT_HASH
 		,smb_lib_ver()
 		);
 
+	if(sizeof(hash_t) != SIZEOF_SMB_HASH_T) {
+		printf("!Size of hash_t unexpected: %d\n", (int)sizeof(hash_t));
+		return EXIT_FAILURE;
+	}
+	if(sizeof(idxrec_t) != SIZEOF_SMB_IDXREC_T) {
+		printf("!Size of idxrec_t unexpected: %d\n", (int)sizeof(idxrec_t));
+		return EXIT_FAILURE;
+	}
+	if(sizeof(fileidxrec_t) != SIZEOF_SMB_FILEIDXREC_T) {
+		printf("!Size of fileidxrec_t unexpected: %d\n", (int)sizeof(fileidxrec_t));
+		return EXIT_FAILURE;
+	}
+
 	/* Automatically detect the system time zone (if possible) */
 	tzset();
 	now=time(NULL);
@@ -1704,7 +1754,7 @@ int main(int argc, char **argv)
 						beep="\a";
 						break;
 					default:
-						printf("\nUnknown opt '%c'\n",argv[x][j]);
+						fprintf(stderr, "\nUnknown opt '%c'\n", argv[x][j]);
 					case '?':
 						printf("%s",usage);
 						bail(1);
@@ -1819,14 +1869,14 @@ int main(int argc, char **argv)
 							y=strlen(cmd)-1;
 							break;
 						case 'R':
-							printf("Re-initialzing %s SMB/status header\n", smb.file);
+							printf("Re-initializing %s SMB/status header\n", smb.file);
 							if((i=smb_initsmbhdr(&smb)) != SMB_SUCCESS) {
 								fprintf(errfp, "\n%s!error %d: %s\n", beep, i, smb.last_error);
 								return i;
 							}
 							memset(&smb.status, 0, sizeof(smb.status));
 							smb.status.header_offset = sizeof(smbhdr_t) + sizeof(smb.status);
-							smb.status.total_msgs = filelength(fileno(smb.sid_fp)) / sizeof(idxrec_t);
+							smb.status.total_msgs = (uint32_t)filelength(fileno(smb.sid_fp)) / smb_idxreclen(&smb);
 							idxrec_t idx;
 							if((i=smb_getlastidx(&smb, &idx)) != SMB_SUCCESS) {
 								fprintf(errfp, "\n%s!error %d: %s\n", beep, i, smb.last_error);
diff --git a/src/sbbs3/sortdir.cpp b/src/sbbs3/sortdir.cpp
deleted file mode 100644
index 01af61addf..0000000000
--- a/src/sbbs3/sortdir.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/* sortdir.cpp */
-
-/* Synchronet file database sorting routines */
-
-/* $Id: sortdir.cpp,v 1.8 2018/02/20 05:21:04 rswindell Exp $ */
-
-/****************************************************************************
- * @format.tab-size 4		(Plain Text/Source Code File Header)			*
- * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
- *																			*
- * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
- *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
- * as published by the Free Software Foundation; either version 2			*
- * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
- * For Synchronet coding style and modification guidelines, see				*
- * http://www.synchro.net/source.html										*
- *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
- * Note: If this box doesn't appear square, then you need to fix your tabs.	*
- ****************************************************************************/
-
-#include "sbbs.h"
-
-/****************************************************************************/
-/* Re-sorts file directory 'dirnum' according to dir[dirnum]->sort type     */
-/****************************************************************************/
-void sbbs_t::resort(uint dirnum)
-{
-	char	str[25],ixbfname[128],datfname[128],exbfname[128],txbfname[128]
-			,ext[512],nulbuf[512];
-	char 	tmp[512];
-	uchar*	ixbbuf, *datbuf;
-	uchar*	ixbptr[MAX_FILES];
-	int		ixbfile,datfile,exbfile,txbfile,i,j;
-	long	ixblen,datlen,offset,newoffset,l;
-
-	memset(nulbuf,0,512);
-	bprintf(text[ResortLineFmt],cfg.lib[cfg.dir[dirnum]->lib]->sname,cfg.dir[dirnum]->sname);
-	sprintf(ixbfname,"%s%s.ixb",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-	sprintf(datfname,"%s%s.dat",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-	sprintf(exbfname,"%s%s.exb",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-	sprintf(txbfname,"%s%s.txb",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
-
-	if(flength(ixbfname)<1L || flength(datfname)<1L) {
-		remove(exbfname);
-		remove(txbfname);
-		remove(ixbfname);
-		remove(datfname);
-		bputs(text[ResortEmptyDir]);
-		return; }
-	bputs(text[Sorting]);
-	if((ixbfile=nopen(ixbfname,O_RDONLY))==-1) {
-		errormsg(WHERE,ERR_OPEN,ixbfname,O_RDONLY);
-		return; }
-	if((datfile=nopen(datfname,O_RDONLY))==-1) {
-		close(ixbfile);
-		errormsg(WHERE,ERR_OPEN,datfname,O_RDONLY);
-		return; }
-	ixblen=(long)filelength(ixbfile);
-	datlen=(long)filelength(datfile);
-	if((ixbbuf=(uchar *)malloc(ixblen))==NULL) {
-		close(ixbfile);
-		close(datfile);
-		errormsg(WHERE,ERR_ALLOC,ixbfname,ixblen);
-		return; }
-	if((datbuf=(uchar *)malloc(datlen))==NULL) {
-		close(ixbfile);
-		close(datfile);
-		free((char *)ixbbuf);
-		errormsg(WHERE,ERR_ALLOC,datfname,datlen);
-		return; }
-	if(lread(ixbfile,ixbbuf,ixblen)!=ixblen) {
-		close(ixbfile);
-		close(datfile);
-		free((char *)ixbbuf);
-		free((char *)datbuf);
-		errormsg(WHERE,ERR_READ,ixbfname,ixblen);
-		return; }
-	if(lread(datfile,datbuf,datlen)!=datlen) {
-		close(ixbfile);
-		close(datfile);
-		free((char *)ixbbuf);
-		free((char *)datbuf);
-		errormsg(WHERE,ERR_READ,datfname,datlen);
-		return; }
-	close(ixbfile);
-	close(datfile);
-	if((ixbfile=nopen(ixbfname,O_WRONLY|O_TRUNC))==-1) {
-		free((char *)ixbbuf);
-		free((char *)datbuf);
-		errormsg(WHERE,ERR_OPEN,ixbfname,O_WRONLY|O_TRUNC);
-		return; }
-	if((datfile=nopen(datfname,O_WRONLY|O_TRUNC))==-1) {
-		close(ixbfile);
-		free((char *)ixbbuf);
-		free((char *)datbuf);
-		errormsg(WHERE,ERR_OPEN,datfname,O_WRONLY|O_TRUNC);
-		return; }
-	for(l=0,i=0;l<ixblen && i<MAX_FILES;l+=F_IXBSIZE,i++)
-		ixbptr[i]=ixbbuf+l;
-	switch(cfg.dir[dirnum]->sort) {
-		case SORT_NAME_A:
-			qsort((void *)ixbptr,ixblen/F_IXBSIZE,sizeof(ixbptr[0])
-				,(int(*)(const void*, const void*))fnamecmp_a);
-			break;
-		case SORT_NAME_D:
-			qsort((void *)ixbptr,ixblen/F_IXBSIZE,sizeof(ixbptr[0])
-				,(int(*)(const void*, const void*))fnamecmp_d);
-			break;
-		case SORT_DATE_A:
-			qsort((void *)ixbptr,ixblen/F_IXBSIZE,sizeof(ixbptr[0])
-				,(int(*)(const void*, const void*))fdatecmp_a);
-			break;
-		case SORT_DATE_D:
-			qsort((void *)ixbptr,ixblen/F_IXBSIZE,sizeof(ixbptr[0])
-				,(int(*)(const void*, const void*))fdatecmp_d);
-			break; }
-
-	if((exbfile=nopen(exbfname,O_RDWR|O_CREAT))==-1) {
-		close(ixbfile);
-		close(datfile);
-		free((char *)ixbbuf);
-		free((char *)datbuf);
-		errormsg(WHERE,ERR_OPEN,exbfname,O_RDWR|O_CREAT);
-		return; }
-	if((txbfile=nopen(txbfname,O_RDWR|O_CREAT))==-1) {
-		close(ixbfile);
-		close(datfile);
-		close(exbfile);
-		free((char *)ixbbuf);
-		free((char *)datbuf);
-		errormsg(WHERE,ERR_OPEN,txbfname,O_RDWR|O_CREAT);
-		return; }
-
-	for(i=0;i<ixblen/F_IXBSIZE;i++) {
-		offset=ixbptr[i][11]|((long)ixbptr[i][12]<<8)|((long)ixbptr[i][13]<<16);
-		lwrite(datfile,&datbuf[offset],F_LEN);
-
-		newoffset=(ulong)i*(ulong)F_LEN;
-
-		j=datbuf[offset+F_MISC];  /* misc bits */
-		if(j!=ETX) j-=' ';
-		if(j&FM_EXTDESC) { /* extended description */
-			lseek(exbfile,(offset/F_LEN)*512L,SEEK_SET);
-			memset(ext,0,512);
-			read(exbfile,ext,512);
-			while(filelength(txbfile)<(newoffset/F_LEN)*512L) {
-	//			  lseek(txbfile,0L,SEEK_END);
-				write(txbfile,nulbuf,512); }
-			lseek(txbfile,(newoffset/F_LEN)*512L,SEEK_SET);
-			write(txbfile,ext,512); }
-
-		str[0]=newoffset&0xff;	   /* Get offset within DAT file for IXB file */
-		str[1]=(newoffset>>8)&0xff;
-		str[2]=(newoffset>>16)&0xff;
-		lwrite(ixbfile,ixbptr[i],11);       /* filename */
-		lwrite(ixbfile,str,3);              /* offset */
-		lwrite(ixbfile,ixbptr[i]+14,8); }   /* upload and download times */
-	close(exbfile);
-	close(txbfile);
-	close(ixbfile);
-	close(datfile);
-	remove(exbfname);
-	rename(txbfname,exbfname);
-	if(!flength(exbfname))
-		remove(exbfname);
-	free((char *)ixbbuf);
-	free((char *)datbuf);
-	if(ixblen/F_IXBSIZE==datlen/F_LEN)
-		bputs(text[Sorted]);
-	else
-		bprintf(text[Compressed]
-			,(uint)((datlen/F_LEN)-(ixblen/F_IXBSIZE))
-			,ultoac(((datlen/F_LEN)-(ixblen/F_IXBSIZE))*F_LEN,tmp));
-}
-
-/****************************************************************************/
-/* Compares filenames for ascending name sort								*/
-/****************************************************************************/
-int fnamecmp_a(char **str1, char **str2)
-{
-	return(strnicmp(*str1,*str2,11));
-}
-
-/****************************************************************************/
-/* Compares filenames for descending name sort								*/
-/****************************************************************************/
-int fnamecmp_d(char **str1, char **str2)
-{
-	return(strnicmp(*str2,*str1,11));
-}
-
-/****************************************************************************/
-/* Compares file upload dates for ascending date sort						*/
-/****************************************************************************/
-int fdatecmp_a(uchar **buf1, uchar **buf2)
-{
-	time_t date1,date2;
-
-	date1=((*buf1)[14]|((long)(*buf1)[15]<<8)|((long)(*buf1)[16]<<16)
-		|((long)(*buf1)[17]<<24));
-	date2=((*buf2)[14]|((long)(*buf2)[15]<<8)|((long)(*buf2)[16]<<16)
-		|((long)(*buf2)[17]<<24));
-	if(date1>date2)	return(1);
-	if(date1<date2)	return(-1);
-	return(0);
-}
-
-/****************************************************************************/
-/* Compares file upload dates for descending date sort						*/
-/****************************************************************************/
-int fdatecmp_d(uchar **buf1, uchar **buf2)
-{
-	time_t date1,date2;
-
-	date1=((*buf1)[14]|((long)(*buf1)[15]<<8)|((long)(*buf1)[16]<<16)
-		|((long)(*buf1)[17]<<24));
-	date2=((*buf2)[14]|((long)(*buf2)[15]<<8)|((long)(*buf2)[16]<<16)
-		|((long)(*buf2)[17]<<24));
-	if(date1>date2)	return(-1);
-	if(date1<date2)	return(1);
-	return(0);
-}
diff --git a/src/sbbs3/str.cpp b/src/sbbs3/str.cpp
index 7f2ae5bd18..d9b29a8598 100644
--- a/src/sbbs3/str.cpp
+++ b/src/sbbs3/str.cpp
@@ -777,7 +777,8 @@ void sbbs_t::subinfo(uint subnum)
 	bprintf(text[SubInfoLongName],cfg.sub[subnum]->lname);
 	bprintf(text[SubInfoShortName],cfg.sub[subnum]->sname);
 	bprintf(text[SubInfoQWKName],cfg.sub[subnum]->qwkname);
-	bprintf(text[SubInfoMaxMsgs],cfg.sub[subnum]->maxmsgs);
+	if(cfg.sub[subnum]->maxmsgs)
+		bprintf(text[SubInfoMaxMsgs],cfg.sub[subnum]->maxmsgs);
 	if(cfg.sub[subnum]->misc&SUB_QNET)
 		bprintf(text[SubInfoTagLine],cfg.sub[subnum]->tagline);
 	if(cfg.sub[subnum]->misc&SUB_FIDO)
@@ -801,7 +802,8 @@ void sbbs_t::dirinfo(uint dirnum)
 	bprintf(text[DirInfoShortName],cfg.dir[dirnum]->sname);
 	if(cfg.dir[dirnum]->exts[0])
 		bprintf(text[DirInfoAllowedExts],cfg.dir[dirnum]->exts);
-	bprintf(text[DirInfoMaxFiles],cfg.dir[dirnum]->maxfiles);
+	if(cfg.dir[dirnum]->maxfiles)
+		bprintf(text[DirInfoMaxFiles],cfg.dir[dirnum]->maxfiles);
 	SAFEPRINTF2(str,"%s%s.msg",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
 	if(fexist(str) && yesno(text[DirInfoViewFileQ]))
 		printfile(str,0);
@@ -950,8 +952,7 @@ void sbbs_t::xfer_prot_menu(enum XFER_TYPE type)
 	if(menu(prot_menu_file[type], P_NOERROR)) {
 		return;
 	}
-
-	CRLF;
+	cond_blankline();
 	int printed=0;
 	for(int i=0;i<cfg.total_prots;i++) {
 		if(!chk_ar(cfg.prot[i]->ar,&useron,&client))
@@ -964,14 +965,12 @@ void sbbs_t::xfer_prot_menu(enum XFER_TYPE type)
 			continue;
 		if(type==XFER_BATCH_DOWNLOAD && cfg.prot[i]->batdlcmd[0]==0)
 			continue;
-		if(type==XFER_BIDIR && cfg.prot[i]->bicmd[0]==0)
-			continue;
 		if(printed && (cols < 80 || (printed%2)==0))
 			CRLF;
 		bprintf(text[TransferProtLstFmt],cfg.prot[i]->mnemonic,cfg.prot[i]->name);
 		printed++;
 	}
-	CRLF;
+	newline();
 }
 
 void sbbs_t::node_stats(uint node_num)
diff --git a/src/sbbs3/str_util.c b/src/sbbs3/str_util.c
index 829c5d13d8..3deaaa6803 100644
--- a/src/sbbs3/str_util.c
+++ b/src/sbbs3/str_util.c
@@ -135,34 +135,6 @@ char* strip_char(const char* str, char* dest, char ch)
 	return retval;
 }
 
-char* prep_file_desc(const char *str, char* dest)
-{
-	int	i,j;
-
-	if(dest==NULL && (dest=strdup(str))==NULL)
-		return NULL;
-	strip_ansi(dest);
-	for(i=j=0;str[i];i++)
-		if(str[i]==CTRL_A && str[i+1]!=0) {
-			i++;
-			if(str[i]==0 || str[i]=='Z')	/* EOF */
-				break;
-			/* convert non-destructive backspace to a destructive backspace */
-			if(str[i]=='<' && j)	
-				j--;
-		}
-		else if(j && str[i]<=' ' && dest[j-1]==' ')
-			continue;
-		else if(i && !IS_ALPHANUMERIC(str[i]) && str[i]==str[i-1])
-			continue;
-		else if((uchar)str[i]>=' ')
-			dest[j++]=str[i];
-		else if(str[i]==TAB || (str[i]==CR && str[i+1]==LF))
-			dest[j++]=' ';
-	dest[j]=0;
-	return dest;
-}
-
 /****************************************************************************/
 /* Pattern matching string search of 'insearchof' in 'string'.				*/
 /****************************************************************************/
@@ -830,6 +802,21 @@ char* subnewsgroupname(scfg_t* cfg, sub_t* sub, char* str, size_t size)
 	return str;
 }
 
+char* dir_area_tag(scfg_t* cfg, dir_t* dir, char* str, size_t size)
+{
+	char* p;
+
+	memset(str, 0, size);
+	if(dir->area_tag[0])
+		strncpy(str, dir->area_tag, size - 1);
+	else {
+		strncpy(str, dir->sname, size - 1);
+		REPLACE_CHARS(str, ' ', '_', p);
+		strupr(str);
+	}
+	return str;
+}
+
 char* get_ctrl_dir(BOOL warn)
 {
 	char* p = getenv("SBBSCTRL");
diff --git a/src/sbbs3/str_util.h b/src/sbbs3/str_util.h
index 987f3d9269..a09cdd3853 100644
--- a/src/sbbs3/str_util.h
+++ b/src/sbbs3/str_util.h
@@ -55,7 +55,6 @@ DLLEXPORT str_list_t trashcan_list(scfg_t* cfg, const char* name);
 DLLEXPORT char *	strip_ansi(char* str);
 DLLEXPORT char *	strip_exascii(const char *str, char* dest);
 DLLEXPORT char *	strip_space(const char *str, char* dest);
-DLLEXPORT char *	prep_file_desc(const char *str, char* dest);
 DLLEXPORT char *	strip_ctrl(const char *str, char* dest);
 DLLEXPORT char *	strip_char(const char* str, char* dest, char);
 DLLEXPORT char *	net_addr(net_t* net);
@@ -69,6 +68,7 @@ DLLEXPORT BOOL		str_has_ctrl(const char*);
 DLLEXPORT BOOL		str_is_ascii(const char*);
 DLLEXPORT char *	utf8_to_cp437_str(char* str);
 DLLEXPORT char *	subnewsgroupname(scfg_t*, sub_t*, char*, size_t);
+DLLEXPORT char *	dir_area_tag(scfg_t*, dir_t*, char*, size_t);
 DLLEXPORT char * 	get_ctrl_dir(BOOL warn);
 
 #ifdef __cplusplus
diff --git a/src/sbbs3/targets.mk b/src/sbbs3/targets.mk
index 43a3aef500..27329c90ae 100644
--- a/src/sbbs3/targets.mk
+++ b/src/sbbs3/targets.mk
@@ -40,6 +40,7 @@ READSAUCE	= $(EXEODIR)$(DIRSEP)readsauce$(EXEFILE)
 SHOWSTAT	= $(EXEODIR)$(DIRSEP)showstat$(EXEFILE)
 PKTDUMP		= $(EXEODIR)$(DIRSEP)pktdump$(EXEFILE)
 FMSGDUMP	= $(EXEODIR)$(DIRSEP)fmsgdump$(EXEFILE)
+UPGRADE_TO_V319 = $(EXEODIR)$(DIRSEP)upgrade_to_v319$(EXEFILE)
 
 UTILS		= $(FIXSMB) $(CHKSMB) \
 			  $(SMBUTIL) $(BAJA) $(NODE) \
@@ -49,7 +50,7 @@ UTILS		= $(FIXSMB) $(CHKSMB) \
 			  $(QWKNODES) $(SLOG) $(ALLUSERS) \
 			  $(DELFILES) $(DUPEFIND) $(SMBACTIV) \
 			  $(SEXYZ) $(DSTSEDIT) $(READSAUCE) $(SHOWSTAT) \
-			  $(PKTDUMP) $(FMSGDUMP)
+			  $(PKTDUMP) $(FMSGDUMP) $(UPGRADE_TO_V319)
 
 GIT_INFO	= git_hash.h git_branch.h
 
@@ -145,7 +146,7 @@ jsdoor: $(GIT_INFO) $(JS_DEPS) $(CRYPT_DEPS) $(XPDEV-MT_LIB) $(SMBLIB) $(UIFCLIB
 
 # Library dependencies
 $(SBBS):
-$(FTPSRVR): 
+$(FTPSRVR): $(SMBLIB) 
 $(WEBSRVR):
 $(MAILSRVR):
 $(SERVICES): 
@@ -161,8 +162,8 @@ $(CHKSMB): $(XPDEV_LIB) $(SMBLIB)
 $(SMBUTIL): $(XPDEV_LIB) $(SMBLIB)
 $(SBBSECHO): $(XPDEV_LIB) $(SMBLIB)
 $(ECHOCFG): $(XPDEV-MT_LIB) $(SMBLIB) $(UIFCLIB-MT) $(CIOLIB-MT)
-$(ADDFILES): $(XPDEV_LIB)
-$(FILELIST): $(XPDEV_LIB)
+$(ADDFILES): $(XPDEV_LIB) $(SMBLIB)
+$(FILELIST): $(XPDEV_LIB) $(SMBLIB)
 $(MAKEUSER): $(XPDEV_LIB)
 $(ANS2ASC):
 $(ASC2ANS):
@@ -170,9 +171,11 @@ $(SEXYZ): $(XPDEV-MT_LIB) $(SMBLIB)
 $(QWKNODES): $(XPDEV_LIB)
 $(SLOG): $(XPDEV_LIB)
 $(ALLUSERS): $(XPDEV_LIB)
-$(DELFILES): $(XPDEV_LIB)
+$(DELFILES): $(XPDEV_LIB) $(SMBLIB)
 $(DUPEFIND): $(XPDEV_LIB) $(SMBLIB)
 $(SMBACTIV): $(XPDEV_LIB) $(SMBLIB)
 $(DSTSEDIT): $(XPDEV_LIB)
 $(READSAUCE): $(XPDEV_LIB)
 $(SHOWSTAT): $(XPDEV_LIB)
+$(UPGRADE_TO_V319): $(XPDEV_LIB) $(SMBLIB)
+
diff --git a/src/sbbs3/text.h b/src/sbbs3/text.h
index fa0e685e31..1b0cef1ade 100644
--- a/src/sbbs3/text.h
+++ b/src/sbbs3/text.h
@@ -270,7 +270,7 @@ enum {
 	,EditCreditValue
 	,EditTimesDownloaded
 	,EditOpenCount
-	,EditAltPath
+	,Unused260
 	,YouOnlyHaveNCredits
 	,NotEnoughCredits
 	,NotEnoughTimeToDl
@@ -307,12 +307,12 @@ enum {
 	,TempFileInfo
 	,TempDirTotal
 	,NFilesRemoved
-	,ResortWarning
-	,ResortLineFmt
-	,ResortEmptyDir
-	,Sorting
-	,Sorted
-	,Compressed
+	,TagFileQ
+	,TagFilePrompt
+	,Unused299
+	,Unused300
+	,Unused301
+	,Unused302
 	,FileAlreadyInQueue
 	,FileIsNotOnline
 	,FileAddedToBatDlQueue
@@ -336,9 +336,9 @@ enum {
 	,FiDateDled
 	,FiTimesDled
 	,FiTransferTime
-	,FiAlternatePath
-	,InvalidAlternatePathN
-	,FileIsOpen
+	,FiTags
+	,Unused327
+	,FiChecksum
 	,HappyBirthday
 	,TimeToChangePw
 	,NewPasswordQ
@@ -605,7 +605,7 @@ enum {
 	,CreditedAccount
 	,ANSICaptureIsNow
 	,RetrievingFile
-	,AltULPathIsNow
+	,Unused595
 	,PrivatePostQ
 	,PostTo
 	,NoToUser
diff --git a/src/sbbs3/text_defaults.c b/src/sbbs3/text_defaults.c
index 99e587ddac..9c56f57b44 100644
--- a/src/sbbs3/text_defaults.c
+++ b/src/sbbs3/text_defaults.c
@@ -132,7 +132,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x0d\x0a\x59\x6f\x75\x20\x64\x69\x64\x6e\x27\x74\x20\x70\x6f\x73\x74\x20\x6d\x65\x73\x73\x61\x67\x65\x20\x23\x25\x64\x0d\x0a" // 072 YouDidntPostMsgN
 	,"\x01\x3f\x44\x65\x6c\x65\x74\x65\x20\x6d\x65\x73\x73\x61\x67\x65\x20\x23\x25\x75\x20\x27\x25\x73\x27" // 073 DeletePostQ
 	,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x49\x01\x6e\x01\x62\x5d\x20\x01\x68\x41\x75\x74\x6f\x4c\x6f\x67\x6f\x6e\x20\x76\x69\x61\x20"
-		"\x49\x50\x20\x61\x64\x64\x72\x65\x73\x73\x20\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a" // 074 UserDefaultsAutoLogon
+		"\x49\x50\x20\x61\x64\x64\x72\x65\x73\x73\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a" // 074 UserDefaultsAutoLogon
 	,"\x01\x6e\x0d\x0a\x01\x6d\x25\x73\x20\x73\x65\x6e\x74\x20\x74\x6f\x20\x01\x68\x25\x73\x20\x23\x25\x75\x0d\x0a" // 075 MsgSentToUser
 	,"\x01\x5f\x0d\x0a\x01\x79\x01\x68\x54\x65\x78\x74\x20\x74\x6f\x20\x73\x65\x61\x72\x63\x68\x20\x66\x6f\x72\x3a\x20" // 076 SearchStringPrompt
 	,"\x01\x77\x01\x68\xc4\xc4\xc4\xc4\xc4\x5b\x01\x69\x01\x72\x25\x63\x01\x6e\x01\x68\x5d\xc4\xc4\xc4\xc4\xb4\x20\x01\x79\x50\x72\x69"
@@ -270,10 +270,10 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x6e\x01\x67\x07\x54\x65\x6c\x65\x67\x72\x61\x6d\x20\x66\x72\x6f\x6d\x20\x01\x6e\x01\x68\x25\x73\x01\x6e\x01\x67\x20\x6f\x6e"
 		"\x20\x25\x73\x3a\x0d\x0a\x01\x68" // 164 TelegramFmt
 	,"\x0d\x0a\x0d\x0a\x59\x6f\x75\x20\x63\x61\x6e\x27\x74\x20\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x2e\x0d\x0a" // 165 R_Download
-	,"\x0d\x0a\x01\x77\x01\x68\x53\x65\x61\x72\x63\x68\x69\x6e\x67\x20\x61\x6c\x6c\x20\x64\x69\x72\x65\x63\x74\x6f\x72\x69\x65\x73\x20"
-		"\x40\x45\x4c\x4c\x49\x50\x53\x49\x53\x40\x0d\x0a" // 166 SearchingAllDirs
+	,"\x0d\x0a\x01\x77\x01\x68\x53\x65\x61\x72\x63\x68\x69\x6e\x67\x20\x63\x75\x72\x72\x65\x6e\x74\x20\x6c\x69\x62\x72\x61\x72\x79\x20"
+		"\x40\x45\x4c\x4c\x49\x50\x53\x49\x53\x40\x0d\x0a\x01\x71" // 166 SearchingAllDirs
 	,"\x01\x77\x01\x68\x53\x65\x61\x72\x63\x68\x69\x6e\x67\x20\x61\x6c\x6c\x20\x6c\x69\x62\x72\x61\x72\x69\x65\x73\x20\x40\x45\x4c\x4c"
-		"\x49\x50\x53\x49\x53\x40\x0d\x0a" // 167 SearchingAllLibs
+		"\x49\x50\x53\x49\x53\x40\x0d\x0a\x01\x71" // 167 SearchingAllLibs
 	,"\x0d\x0a\x01\x77\x01\x68\x25\x75\x20\x46\x69\x6c\x65\x73\x20\x4c\x69\x73\x74\x65\x64\x2e\x0d\x0a" // 168 NFilesListed
 	,"\x0d\x0a\x01\x77\x01\x68\x45\x6d\x70\x74\x79\x20\x64\x69\x72\x65\x63\x74\x6f\x72\x79\x2e\x0d\x0a" // 169 EmptyDir
 	,"\x0d\x0a\x01\x6e\x01\x63\x53\x65\x61\x72\x63\x68\x69\x6e\x67\x20\x66\x6f\x72\x20\x66\x69\x6c\x65\x73\x20\x75\x70\x6c\x6f\x61\x64"
@@ -376,8 +376,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x0d\x0a\x01\x6e\x01\x6d\x01\x68\x25\x73\x20\x01\x6e\x01\x6d\x61\x64\x64\x65\x64\x20\x74\x6f\x20\x62\x61\x74\x63\x68\x20\x75\x70"
 		"\x6c\x6f\x61\x64\x20\x71\x75\x65\x75\x65\x01\x63\x20\x2d\x20\x46\x69\x6c\x65\x73\x3a\x20\x01\x68\x25\x75\x20\x01\x6e\x01\x63\x28"
 		"\x01\x68\x25\x75\x01\x6e\x01\x63\x20\x4d\x61\x78\x29\x0d\x0a" // 230 FileAddedToUlQueue
-	,"\x07\x01\x5f\x01\x77\x01\x68\x4e\x6f\x64\x65\x20\x25\x32\x64\x3a\x20\x01\x67\x25\x73\x01\x6e\x01\x67\x20\x73\x65\x6e\x74\x20\x79"
-		"\x6f\x75\x20\x61\x20\x66\x69\x6c\x65\x2e\x0d\x0a" // 231 UserToUserXferNodeMsg
+	,"\x55\x6e\x75\x73\x65\x64\x20\x32\x33\x31" // 231 UserToUserXferNodeMsg
 	,"\x01\x6e\x01\x3f\x01\x67\x01\x68\x25\x73\x01\x79\x3a\x20\x01\x77\x7e\x42\x01\x79\x61\x74\x63\x68\x20\x64\x6f\x77\x6e\x6c\x6f\x61"
 		"\x64\x2c\x20\x01\x77\x7e\x45\x01\x79\x78\x74\x65\x6e\x64\x65\x64\x20\x69\x6e\x66\x6f\x2c\x20\x01\x77\x7e\x56\x01\x79\x69\x65\x77"
 		"\x20\x66\x69\x6c\x65\x2c\x20\x01\x77\x7e\x51\x01\x79\x75\x69\x74\x20\x6f\x72\x20\x5b\x7e\x4e\x65\x78\x74\x5d\x3a\x20\x01\x77" // 232 FileInfoPrompt
@@ -416,7 +415,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x01\x5f\x01\x79\x01\x68\x43\x72\x65\x64\x69\x74\x20\x76\x61\x6c\x75\x65\x20\x20\x20\x20\x20\x3a\x20\x01\x6e" // 257 EditCreditValue
 	,"\x01\x5f\x01\x79\x01\x68\x54\x69\x6d\x65\x73\x20\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x65\x64\x20\x3a\x20\x01\x6e" // 258 EditTimesDownloaded
 	,"\x01\x5f\x01\x79\x01\x68\x4f\x70\x65\x6e\x20\x63\x6f\x75\x6e\x74\x20\x20\x20\x20\x20\x20\x20\x3a\x20\x01\x6e" // 259 EditOpenCount
-	,"\x01\x5f\x01\x79\x01\x68\x41\x6c\x74\x65\x72\x6e\x61\x74\x65\x20\x50\x61\x74\x68\x20\x20\x20\x3a\x20\x01\x6e" // 260 EditAltPath
+	,"\x55\x4e\x55\x53\x45\x44\x32\x36\x30" // 260 Unused260
 	,"\x0d\x0a\x01\x77\x01\x68\x59\x6f\x75\x20\x6f\x6e\x6c\x79\x20\x68\x61\x76\x65\x20\x25\x73\x20\x63\x72\x65\x64\x69\x74\x73\x2e\x0d"
 		"\x0a" // 261 YouOnlyHaveNCredits
 	,"\x0d\x0a\x59\x6f\x75\x20\x64\x6f\x6e\x27\x74\x20\x68\x61\x76\x65\x20\x65\x6e\x6f\x75\x67\x68\x20\x63\x72\x65\x64\x69\x74\x73\x2e"
@@ -428,7 +427,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x0d\x0a\x42\x75\x6c\x6b\x20\x55\x70\x6c\x6f\x61\x64\x20\x25\x73\x20\x25\x73\x20\x44\x69\x72\x65\x63\x74\x6f\x72\x79\x0d\x0a\x28"
 		"\x45\x6e\x74\x65\x72\x20\x27\x2d\x27\x20\x66\x6f\x72\x20\x64\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20\x74\x6f\x20\x73\x6b\x69"
 		"\x70\x20\x66\x69\x6c\x65\x29\x3a\x0d\x0a" // 265 BulkUpload
-	,"\x01\x5f\x01\x79\x01\x68\x25\x73\x01\x77\x25\x37\x75\x6b\x01\x62\x3a" // 266 BulkUploadDescPrompt
+	,"\x01\x5f\x01\x79\x01\x68\x25\x2d\x31\x32\x73\x01\x77\x25\x37\x75\x6b\x01\x62\x3a" // 266 BulkUploadDescPrompt
 	,"\x0d\x0a\x01\x72\x01\x68\x01\x69\x4e\x6f\x20\x66\x69\x6c\x65\x73\x20\x69\x6e\x20\x62\x61\x74\x63\x68\x20\x71\x75\x65\x75\x65\x2e"
 		"\x01\x6e\x0d\x0a\x0d\x0a\x01\x6d\x55\x73\x65\x20\x01\x68\x44\x01\x6e\x01\x6d\x20\x6f\x72\x20\x01\x68\x55\x01\x6e\x01\x6d\x20\x74"
 		"\x6f\x20\x61\x64\x64\x20\x66\x69\x6c\x65\x73\x20\x74\x6f\x20\x74\x68\x65\x20\x71\x75\x65\x75\x65\x2e\x0d\x0a" // 267 NoFilesInBatchQueue
@@ -475,15 +474,13 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x0d\x0a\x55\x70\x6c\x6f\x61\x64\x65\x72\x3a\x20\x25\x73\x0d\x0a\x46\x69\x6c\x65\x6e\x61\x6d\x65\x3a\x20\x25\x73\x0d\x0a" // 294 TempFileInfo
 	,"\x0d\x0a\x25\x73\x20\x62\x79\x74\x65\x73\x20\x69\x6e\x20\x25\x75\x20\x66\x69\x6c\x65\x73\x0d\x0a" // 295 TempDirTotal
 	,"\x0d\x0a\x25\x75\x20\x66\x69\x6c\x65\x73\x20\x72\x65\x6d\x6f\x76\x65\x64\x2e\x0d\x0a" // 296 NFilesRemoved
-	,"\x01\x72\x01\x68\x01\x69\x41\x6c\x6c\x20\x6f\x74\x68\x65\x72\x20\x6e\x6f\x64\x65\x73\x20\x73\x68\x6f\x75\x6c\x64\x20\x4e\x4f\x54"
-		"\x20\x62\x65\x20\x69\x6e\x20\x75\x73\x65\x20\x64\x75\x72\x69\x6e\x67\x20\x72\x65\x73\x6f\x72\x74\x2f\x63\x6f\x6d\x70\x72\x65\x73"
-		"\x73\x69\x6f\x6e\x2e\x01\x6e\x0d\x0a" // 297 ResortWarning
-	,"\x01\x2d\x01\x63\x25\x2d\x31\x35\x2e\x31\x35\x73\x20\x01\x79\x01\x68\x25\x2d\x32\x35\x2e\x32\x35\x73\x20" // 298 ResortLineFmt
-	,"\x01\x62\x45\x6d\x70\x74\x79\x01\x6e\x0d\x0a" // 299 ResortEmptyDir
-	,"\x01\x77\x53\x6f\x72\x74\x69\x6e\x67\x20\x40\x45\x4c\x4c\x49\x50\x53\x49\x53\x40" // 300 Sorting
-	,"\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x01\x62\x53\x6f\x72\x74\x65\x64\x20\x20\x20\x20\x01\x6e\x0d\x0a" // 301 Sorted
-	,"\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x01\x62\x43\x6f\x6d\x70\x72\x65\x73\x73\x65\x64\x20\x25\x75\x20\x73\x6c\x6f\x74\x73\x20"
-		"\x28\x25\x73\x20\x62\x79\x74\x65\x73\x29\x01\x6e\x0d\x0a" // 302 Compressed
+	,"\x54\x61\x67\x20\x74\x68\x69\x73\x20\x66\x69\x6c\x65" // 297 TagFileQ
+	,"\x01\x68\x01\x79\x45\x6e\x74\x65\x72\x20\x28\x73\x70\x61\x63\x65\x2d\x73\x65\x70\x61\x72\x61\x74\x65\x64\x29\x20\x54\x61\x67\x73"
+		"\x3a\x20" // 298 TagFilePrompt
+	,"\x55\x4e\x55\x53\x45\x44\x32\x39\x39" // 299 Unused299
+	,"\x55\x4e\x55\x53\x45\x44\x33\x30\x30" // 300 Unused300
+	,"\x55\x4e\x55\x53\x45\x44\x33\x30\x31" // 301 Unused301
+	,"\x55\x4e\x55\x53\x45\x44\x33\x30\x32" // 302 Unused302
 	,"\x01\x77\x01\x68\x0d\x0a\x25\x73\x20\x69\x73\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x69\x6e\x20\x74\x68\x65\x20\x71\x75\x65\x75\x65"
 		"\x2e\x0d\x0a" // 303 FileAlreadyInQueue
 	,"\x01\x77\x01\x68\x01\x2f\x46\x69\x6c\x65\x20\x69\x73\x20\x6e\x6f\x74\x20\x6f\x6e\x6c\x69\x6e\x65\x2e\x0d\x0a" // 304 FileIsNotOnline
@@ -506,7 +503,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x0a\x01\x6e\x01\x67\x59\x6f\x75\x20\x77\x65\x72\x65\x20\x61\x77\x61\x72\x64\x65\x64\x20\x25\x73\x20\x63\x72\x65\x64\x69\x74\x73"
 		"\x2e\x0d\x0a" // 312 DownloadUserMsg
 	,"\x70\x61\x72\x74\x69\x61\x6c\x6c\x79\x20" // 313 Partially
-	,"\x0d\x0a\x01\x6e\x01\x67\x4c\x69\x62\x72\x61\x72\x79\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3a\x01\x68\x20\x28\x25\x75\x29\x20"
+	,"\x01\x6c\x01\x6e\x01\x67\x4c\x69\x62\x72\x61\x72\x79\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3a\x01\x68\x20\x28\x25\x75\x29\x20"
 		"\x25\x73" // 314 FiLib
 	,"\x0d\x0a\x01\x6e\x01\x67\x44\x69\x72\x65\x63\x74\x6f\x72\x79\x20\x20\x20\x20\x20\x20\x20\x20\x3a\x01\x68\x20\x28\x25\x75\x29\x20"
 		"\x25\x73" // 315 FiDir
@@ -521,11 +518,9 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x0d\x0a\x01\x6e\x01\x67\x4c\x61\x73\x74\x20\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x65\x64\x20\x20\x3a\x01\x68\x20\x25\x73" // 323 FiDateDled
 	,"\x0d\x0a\x01\x6e\x01\x67\x54\x69\x6d\x65\x73\x20\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x65\x64\x20\x3a\x01\x68\x20\x25\x75" // 324 FiTimesDled
 	,"\x0d\x0a\x01\x6e\x01\x67\x54\x69\x6d\x65\x20\x74\x6f\x20\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x20\x3a\x01\x68\x20\x25\x73" // 325 FiTransferTime
-	,"\x0d\x0a\x01\x6e\x01\x67\x41\x6c\x74\x65\x72\x6e\x61\x74\x65\x20\x50\x61\x74\x68\x20\x20\x20\x3a\x01\x68\x20\x25\x73" // 326 FiAlternatePath
-	,"\x0d\x0a\x01\x72\x01\x68\x01\x69\x49\x6e\x76\x61\x6c\x69\x64\x20\x41\x6c\x74\x65\x72\x6e\x61\x74\x65\x20\x50\x61\x74\x68\x20\x4e"
-		"\x75\x6d\x62\x65\x72\x3a\x20\x25\x75\x01\x6e" // 327 InvalidAlternatePathN
-	,"\x01\x5f\x01\x2f\x01\x77\x01\x68\x46\x69\x6c\x65\x20\x69\x73\x20\x63\x75\x72\x72\x65\x6e\x74\x6c\x79\x20\x6f\x70\x65\x6e\x20\x62"
-		"\x79\x20\x25\x64\x20\x75\x73\x65\x72\x25\x73\x2e\x0d\x0a" // 328 FileIsOpen
+	,"\x0d\x0a\x01\x6e\x01\x67\x54\x61\x67\x73\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3a\x01\x68\x20\x25\x73" // 326 FiTags
+	,"\x55\x4e\x55\x53\x45\x44\x33\x32\x37" // 327 Unused327
+	,"\x0d\x0a\x01\x6e\x01\x67\x46\x69\x6c\x65\x20\x25\x2d\x36\x2e\x36\x73\x20\x20\x20\x20\x20\x20\x3a\x01\x68\x20\x25\x73" // 328 FiChecksum
 	,"\x07\x07\x0d\x0a\x01\x68\x01\x72\x48\x01\x62\x61\x01\x67\x70\x01\x79\x70\x01\x63\x79\x20\x01\x6d\x42\x01\x77\x69\x01\x72\x72\x01"
 		"\x67\x74\x01\x62\x68\x01\x63\x64\x01\x6d\x61\x01\x79\x79\x20\x01\x77\x74\x01\x72\x6f\x20\x01\x67\x79\x01\x62\x6f\x01\x63\x75\x0d"
 		"\x0a\x07\x07\x01\x6d\x48\x01\x79\x61\x01\x77\x70\x01\x72\x70\x01\x67\x79\x20\x01\x62\x42\x01\x63\x69\x01\x6d\x72\x01\x79\x74\x01"
@@ -586,10 +581,8 @@ const char * const text_defaults[TOTAL_TEXT]={
 	,"\x07\x01\x72\x01\x68\x01\x69\x25\x64\x20\x63\x72\x69\x74\x69\x63\x61\x6c\x20\x65\x72\x72\x6f\x72\x73\x20\x68\x61\x76\x65\x20\x6f"
 		"\x63\x63\x75\x72\x72\x65\x64\x2e\x20\x54\x79\x70\x65\x20\x3b\x45\x52\x52\x20\x61\x74\x20\x6d\x61\x69\x6e\x20\x6d\x65\x6e\x75\x2e"
 		"\x01\x6e\x0d\x0a" // 359 CriticalErrors
-	,"\x01\x5f\x01\x77\x01\x68\x59\x6f\x75\x20\x68\x61\x76\x65\x20\x25\x64\x20\x55\x73\x65\x72\x20\x74\x6f\x20\x55\x73\x65\x72\x20\x54"
-		"\x72\x61\x6e\x73\x66\x65\x72\x25\x73\x20\x77\x61\x69\x74\x69\x6e\x67\x20\x66\x6f\x72\x20\x79\x6f\x75\x0d\x0a" // 360 UserXferForYou
-	,"\x01\x5f\x01\x77\x01\x68\x59\x6f\x75\x20\x68\x61\x76\x65\x20\x73\x65\x6e\x74\x20\x25\x64\x20\x75\x6e\x72\x65\x63\x65\x69\x76\x65"
-		"\x64\x20\x55\x73\x65\x72\x20\x74\x6f\x20\x55\x73\x65\x72\x20\x54\x72\x61\x6e\x73\x66\x65\x72\x25\x73\x0d\x0a" // 361 UnreceivedUserXfer
+	,"\x55\x6e\x75\x73\x65\x64\x33\x36\x30" // 360 UserXferForYou
+	,"\x55\x6e\x75\x73\x65\x64\x33\x36\x31" // 361 UnreceivedUserXfer
 	,"\x52\x65\x61\x64\x20\x79\x6f\x75\x72\x20\x6d\x61\x69\x6c\x20\x6e\x6f\x77" // 362 ReadYourMailNowQ
 	,"\x53\x6f\x72\x72\x79\x2c\x20\x74\x68\x65\x20\x73\x79\x73\x74\x65\x6d\x20\x69\x73\x20\x63\x6c\x6f\x73\x65\x64\x20\x74\x6f\x20\x6e"
 		"\x65\x77\x20\x75\x73\x65\x72\x73\x2e\x0d\x0a" // 363 NoNewUsers
@@ -991,8 +984,7 @@ const char * const text_defaults[TOTAL_TEXT]={
 		"\x79\x6f\x75\x72\x20\x61\x63\x63\x6f\x75\x6e\x74\x2e\x0d\x0a" // 592 CreditedAccount
 	,"\x0d\x0a\x41\x4e\x53\x49\x20\x43\x61\x70\x74\x75\x72\x65\x20\x69\x73\x20\x6e\x6f\x77\x20\x25\x73\x0d\x0a" // 593 ANSICaptureIsNow
 	,"\x01\x6e\x01\x6d\x0d\x0a\x52\x65\x74\x72\x69\x65\x76\x69\x6e\x67\x20\x01\x68\x25\x73\x01\x6e\x01\x6d\x2e\x2e\x2e" // 594 RetrievingFile
-	,"\x01\x6e\x0d\x0a\x41\x6c\x74\x65\x72\x6e\x61\x74\x65\x20\x75\x70\x6c\x6f\x61\x64\x20\x70\x61\x74\x68\x20\x6e\x6f\x77\x3a\x20\x25"
-		"\x73\x0d\x0a" // 595 AltULPathIsNow
+	,"\x55\x4e\x55\x53\x45\x44\x35\x39\x35" // 595 Unused595
 	,"\x0d\x0a\x50\x72\x69\x76\x61\x74\x65" // 596 PrivatePostQ
 	,"\x0d\x0a\x01\x5f\x01\x79\x01\x68\x50\x6f\x73\x74\x20\x74\x6f\x3a\x20" // 597 PostTo
 	,"\x0d\x0a\x50\x72\x69\x76\x61\x74\x65\x20\x70\x6f\x73\x74\x73\x20\x72\x65\x71\x75\x69\x72\x65\x20\x61\x20\x64\x65\x73\x74\x69\x6e"
diff --git a/src/sbbs3/tmp_xfer.cpp b/src/sbbs3/tmp_xfer.cpp
index 4969680f0c..e6cbbd0644 100644
--- a/src/sbbs3/tmp_xfer.cpp
+++ b/src/sbbs3/tmp_xfer.cpp
@@ -1,9 +1,4 @@
-/* tmp_xfer.cpp */
-
 /* Synchronet temp directory file transfer routines */
-// vi: tabstop=4
-
-/* $Id: tmp_xfer.cpp,v 1.51 2020/05/14 07:50:00 rswindell Exp $ */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -18,21 +13,9 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -44,6 +27,7 @@
 /*****************************************************************************/
 void sbbs_t::temp_xfer()
 {
+#if 0	// TODO
     char	str[256],tmp2[256],done=0,ch;
 	char 	tmp[512];
 	int		error;
@@ -195,7 +179,7 @@ void sbbs_t::temp_xfer()
 					if(cfg.dir[temp_dirnum]->misc&DIR_TFREE)
 						starttime+=end-start;
 					if(checkprotresult(cfg.prot[i],error,&f))
-						downloadfile(&f);
+						downloadedfile(&f);
 					else
 						notdownloaded(f.size,start,end);
 					autohangup(); 
@@ -279,6 +263,7 @@ void sbbs_t::temp_xfer()
 	}
 	free(cfg.dir[dirnum]);
 	cfg.total_dirs--;
+#endif
 }
 
 /*****************************************************************************/
@@ -286,6 +271,7 @@ void sbbs_t::temp_xfer()
 /*****************************************************************************/
 void sbbs_t::extract(uint dirnum)
 {
+#if 0 // NFB-TODO
     char	fname[13],str[256],excmd[256],path[256],done
 				,tmp[256],intmp=0;
     uint	i,j;
@@ -348,11 +334,11 @@ void sbbs_t::extract(uint dirnum)
 		bputs(text[UnextractableFile]);
 		return; 
 	}
-	if(!intmp && !findfile(&cfg,dirnum,f.name)) {    /* not temp dir */
+	if(!intmp && !findfile(&cfg, dirnum, f.name, NULL)) {    /* not temp dir */
 		bputs(text[SearchingAllDirs]);
 		for(i=0;i<usrdirs[curlib] && !msgabort();i++) {
 			if(i==dirnum) continue;
-			if(findfile(&cfg,usrdir[curlib][i],f.name))
+			if(findfile(&cfg, usrdir[curlib][i], f.name, NULL))
 				break; 
 		}
 		if(i==usrdirs[curlib]) { /* not found in cur lib */
@@ -360,7 +346,7 @@ void sbbs_t::extract(uint dirnum)
 			for(i=j=0;i<usrlibs;i++) {
 				if(i==curlib) continue;
 				for(j=0;j<usrdirs[i] && !msgabort();j++)
-					if(findfile(&cfg,usrdir[i][j],f.name))
+					if(findfile(&cfg, usrdir[i][j], f.name, NULL))
 						break;
 				if(j<usrdirs[i])
 					break; 
@@ -425,6 +411,7 @@ void sbbs_t::extract(uint dirnum)
 				break; 
 		} 
 	}
+#endif
 }
 
 /****************************************************************************/
@@ -434,21 +421,20 @@ void sbbs_t::extract(uint dirnum)
 ulong sbbs_t::create_filelist(const char *name, long mode)
 {
     char	str[256];
-	int		file;
+	FILE*	fp;
 	uint	i,j,d;
 	ulong	l,k;
 
 	if(online == ON_REMOTE)
 		bprintf(text[CreatingFileList],name);
 	SAFEPRINTF2(str,"%s%s",cfg.temp_dir,name);
-	if((file=nopen(str,O_CREAT|O_WRONLY|O_APPEND))==-1) {
+	if((fp = fopen(str,"ab")) == NULL) {
 		errormsg(WHERE,ERR_OPEN,str,O_CREAT|O_WRONLY|O_APPEND);
 		return(0);
 	}
 	k=0;
 	if(mode&FL_ULTIME) {
-		SAFEPRINTF(str,"New files since: %s\r\n",timestr(ns_time));
-		write(file,str,strlen(str));
+		fprintf(fp, "New files since: %s\r\n", timestr(ns_time));
 	}
 	for(i=j=d=0;i<usrlibs;i++) {
 		for(j=0;j<usrdirs[i];j++,d++) {
@@ -459,7 +445,7 @@ ulong sbbs_t::create_filelist(const char *name, long mode)
 				&& (cfg.lib[usrlib[i]]->offline_dir==usrdir[i][j]
 				|| cfg.dir[usrdir[i][j]]->misc&DIR_NOSCAN))
 				continue;
-			l=listfiles(usrdir[i][j],nulstr,file,mode);
+			l=listfiles(usrdir[i][j], nulstr, fp, mode);
 			if((long)l==-1)
 				break;
 			k+=l;
@@ -468,10 +454,9 @@ ulong sbbs_t::create_filelist(const char *name, long mode)
 			break;
 	}
 	if(k>1) {
-		SAFEPRINTF(str,"\r\n%ld Files Listed.\r\n",k);
-		write(file,str,strlen(str));
+		fprintf(fp,"\r\n%ld Files Listed.\r\n",k);
 	}
-	close(file);
+	fclose(fp);
 	if(k)
 		bprintf(text[CreatedFileList],name);
 	else {
@@ -489,7 +474,7 @@ ulong sbbs_t::create_filelist(const char *name, long mode)
 /* This function returns the command line for the temp file extension for	*/
 /* current user online. 													*/
 /****************************************************************************/
-char * sbbs_t::temp_cmd(void)
+const char* sbbs_t::temp_cmd(void)
 {
 	int i;
 
diff --git a/src/sbbs3/uedit/uedit.c b/src/sbbs3/uedit/uedit.c
index f6401ba2a3..293ea6d6f1 100644
--- a/src/sbbs3/uedit/uedit.c
+++ b/src/sbbs3/uedit/uedit.c
@@ -538,7 +538,7 @@ int edit_xedit(scfg_t *cfg, user_t *user)
 				if(j > 0)
 				    putuserrec(cfg,user->number,U_XEDIT,8,cfg->xedit[j-1]->code);
 				else
-				    putuserrec(cfg,user->number,U_XEDIT,8,nulstr);
+				    putuserrec(cfg,user->number,U_XEDIT,8,"");
 			}
 			break;
 	}
@@ -1632,7 +1632,7 @@ int edit_user(scfg_t *cfg, int usernum)
 				user.misc ^= DELETED;
 				putuserrec(cfg,user.number,U_MISC,8,ultoa(user.misc,str,16));
 				if(user.misc & DELETED)
-					putusername(cfg,user.number,nulstr);
+					putusername(cfg,user.number,"");
 				else
 					putusername(cfg,user.number,user.alias);
 				break;
diff --git a/src/sbbs3/un_qwk.cpp b/src/sbbs3/un_qwk.cpp
index 0d35a98cc6..ac05baf2f7 100644
--- a/src/sbbs3/un_qwk.cpp
+++ b/src/sbbs3/un_qwk.cpp
@@ -21,6 +21,7 @@
 
 #include "sbbs.h"
 #include "qwk.h"
+#include "filedat.h"
 
 static void log_qwk_import_stats(sbbs_t* sbbs, ulong msgs, time_t start)
 {
@@ -39,6 +40,7 @@ bool sbbs_t::unpack_qwk(char *packet,uint hubnum)
 {
 	char	str[MAX_PATH+1],fname[MAX_PATH+1];
 	char 	tmp[512];
+	char	error[256] = "";
 	char	inbox[MAX_PATH+1];
 	uchar	block[QWK_BLOCK_LEN];
 	int 	k,file;
@@ -74,10 +76,24 @@ bool sbbs_t::unpack_qwk(char *packet,uint hubnum)
 		return(false);
 	}
 	delfiles(cfg.temp_dir,ALLFILES);
-	i=external(cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),EX_OFFLINE);
-	if(i) {
-		errormsg(WHERE,ERR_EXEC,cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),i);
-		return(false); 
+	long file_count = extract_files_from_archive(packet
+		,/* outdir: */cfg.temp_dir
+		,/* allowed_filename_chars: */NULL /* any */
+		,/* with_path: */false
+		,/* max_files: */0 /* unlimited */
+		,/* file_list: */NULL /* all files */
+		,error, sizeof(error));
+	if(file_count >= 0) {
+		lprintf(LOG_DEBUG, "libarchive extracted %ld files from %s", file_count, packet);
+	} else {
+		lprintf(LOG_ERR, "libarchive error %ld (%s) extracting %s", file_count, error, packet);
+		if(*cfg.qhub[hubnum]->unpack == '\0')
+			return false;
+		i=external(cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),EX_OFFLINE);
+		if(i) {
+			errormsg(WHERE,ERR_EXEC,cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),i);
+			return(false); 
+		}
 	}
 	SAFEPRINTF(str,"%sMESSAGES.DAT",cfg.temp_dir);
 	if(!fexistcase(str)) {
diff --git a/src/sbbs3/un_rep.cpp b/src/sbbs3/un_rep.cpp
index 6e77cdc4da..26eb2c4026 100644
--- a/src/sbbs3/un_rep.cpp
+++ b/src/sbbs3/un_rep.cpp
@@ -21,6 +21,7 @@
 
 #include "sbbs.h"
 #include "qwk.h"
+#include "filedat.h"
 
 /****************************************************************************/
 /* Unpacks .REP packet, 'repfile' is the path and filename of the packet    */
@@ -31,6 +32,7 @@ bool sbbs_t::unpack_rep(char* repfile)
 	char	rep_fname[MAX_PATH+1];
 	char	msg_fname[MAX_PATH+1];
 	char 	tmp[512];
+	char	error[256];
 	char	inbox[MAX_PATH+1];
 	char	block[QWK_BLOCK_LEN];
 	int 	file;
@@ -70,20 +72,33 @@ bool sbbs_t::unpack_rep(char* repfile)
 		logline(LOG_NOTICE,nulstr,"REP file not received");
 		return(false); 
 	}
-	for(k=0;k<cfg.total_fextrs;k++)
-		if(!stricmp(cfg.fextr[k]->ext,useron.tmpext) && chk_ar(cfg.fextr[k]->ar,&useron,&client))
-			break;
-	if(k>=cfg.total_fextrs)
-		k=0;
-	ex=EX_STDOUT;
-	if(online!=ON_REMOTE)
-		ex|=EX_OFFLINE;
-	i=external(cmdstr(cfg.fextr[k]->cmd,rep_fname,ALLFILES,NULL),ex);
-	if(i) {
-		bputs(text[QWKExtractionFailed]);
-		logline(LOG_NOTICE,"U!",AttemptedToUploadREPpacket);
-		logline(LOG_NOTICE,nulstr,"Extraction failed");
-		return(false); 
+	long file_count = extract_files_from_archive(rep_fname
+		,/* outdir: */cfg.temp_dir
+		,/* allowed_filename_chars: */SAFEST_FILENAME_CHARS
+		,/* with_path: */false
+		,/* max_files */1000
+		,/* file_list: */NULL /* all files */
+		,error, sizeof(error));
+	if(file_count > 0) {
+		lprintf(LOG_DEBUG, "libarchive extracted %lu files from %s", file_count, rep_fname);
+	} else {
+		if(*error)
+			lprintf(LOG_NOTICE, "libarchive error (%s) extracting %s", error, rep_fname);
+		for(k=0;k<cfg.total_fextrs;k++)
+			if(!stricmp(cfg.fextr[k]->ext,useron.tmpext) && chk_ar(cfg.fextr[k]->ar,&useron,&client))
+				break;
+		if(k>=cfg.total_fextrs)
+			k=0;
+		ex=EX_STDOUT;
+		if(online!=ON_REMOTE)
+			ex|=EX_OFFLINE;
+		i=external(cmdstr(cfg.fextr[k]->cmd,rep_fname,ALLFILES,NULL),ex);
+		if(i) {
+			bputs(text[QWKExtractionFailed]);
+			logline(LOG_NOTICE,"U!",AttemptedToUploadREPpacket);
+			logline(LOG_NOTICE,nulstr,"Extraction failed");
+			return(false); 
+		}
 	}
 	SAFEPRINTF2(msg_fname,"%s%s.msg",cfg.temp_dir,cfg.sys_id);
 	if(!fexistcase(msg_fname)) {
diff --git a/src/sbbs3/unbaja.c b/src/sbbs3/unbaja.c
index 91e4ab271c..6da7e1af04 100644
--- a/src/sbbs3/unbaja.c
+++ b/src/sbbs3/unbaja.c
@@ -1330,10 +1330,10 @@ void decompile(FILE *bin, FILE *srcfile)
 	char	src[2048];
 	int		redo=FALSE;
 	char	*labels;
-	size_t	currpos=0;
+	off_t	currpos=0;
 
 	currpos=filelength(fileno(bin));
-	labels=(char *)calloc(1,filelength(fileno(bin)));
+	labels=(char *)calloc(1,(size_t)filelength(fileno(bin)));
 	if(labels==NULL) {
 		printf("ERROR allocating memory for labels\n");
 		return;
@@ -1351,7 +1351,7 @@ void decompile(FILE *bin, FILE *srcfile)
 		}
 		src[0]=0;
 		if(labels[currpos])
-			sprintf(src,":label_%04" XP_PRIsize_t "x\n",currpos);
+			sprintf(src,":label_%04" XP_PRIsize_t "x\n", (size_t)currpos);
 		switch(uch) {
 			case CS_USE_INT_VAR:
 				usevar=TRUE;
diff --git a/src/sbbs3/upgrade_to_v319.c b/src/sbbs3/upgrade_to_v319.c
new file mode 100644
index 0000000000..5bd114c4df
--- /dev/null
+++ b/src/sbbs3/upgrade_to_v319.c
@@ -0,0 +1,717 @@
+/* Upgrade Synchronet files from v3.18 to v3.19 */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
+ *																			*
+ * This program is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU General Public License				*
+ * as published by the Free Software Foundation; either version 2			*
+ * of the License, or (at your option) any later version.					*
+ * See the GNU General Public License for more details: gpl.txt or			*
+ * http://www.fsf.org/copyleft/gpl.html										*
+ *																			*
+ * For Synchronet coding style and modification guidelines, see				*
+ * http://www.synchro.net/source.html										*
+ *																			*
+ * Note: If this box doesn't appear square, then you need to fix your tabs.	*
+ ****************************************************************************/
+
+#include <stdbool.h>
+#include "sbbs.h"
+#include "sbbs4defs.h"
+#include "ini_file.h"
+#include "dat_file.h"
+#include "datewrap.h"
+#include "filedat.h"
+
+scfg_t scfg;
+BOOL overwrite_existing_files=TRUE;
+ini_style_t style = { 25, NULL, NULL, " = ", NULL };
+
+BOOL overwrite(const char* path)
+{
+	char	str[128];
+
+	if(!overwrite_existing_files && fexist(path)) {
+		printf("\n%s already exists, overwrite? ",path);
+		fgets(str,sizeof(str),stdin);
+		if(toupper(*str)!='Y')
+			return(FALSE);
+	}
+
+	return(TRUE);
+}
+
+int lprintf(int level, const char *fmt, ...)
+{
+	va_list argptr;
+	char sbuf[1024];
+
+    va_start(argptr,fmt);
+    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
+	sbuf[sizeof(sbuf)-1]=0;
+    va_end(argptr);
+    return(puts(sbuf));
+}
+
+/****************************************************************************/
+/* Converts a date string in format MM/DD/YY into unix time format			*/
+/****************************************************************************/
+long dstrtodate(scfg_t* cfg, char *instr)
+{
+	char*	p;
+	char*	day;
+	char	str[16];
+	struct tm tm;
+
+	if(!instr[0] || !strncmp(instr,"00/00/00",8))
+		return(0);
+
+	if(isdigit(instr[0]) && isdigit(instr[1])
+		&& isdigit(instr[3]) && isdigit(instr[4])
+		&& isdigit(instr[6]) && isdigit(instr[7]))
+		p=instr;	/* correctly formatted */
+	else {
+		p=instr;	/* incorrectly formatted */
+		while(*p && isdigit(*p)) p++;
+		if(*p==0)
+			return(0);
+		p++;
+		day=p;
+		while(*p && isdigit(*p)) p++;
+		if(*p==0)
+			return(0);
+		p++;
+		sprintf(str,"%02u/%02u/%02u"
+			,atoi(instr)%100,atoi(day)%100,atoi(p)%100);
+		p=str;
+	}
+
+	memset(&tm,0,sizeof(tm));
+	tm.tm_year=((p[6]&0xf)*10)+(p[7]&0xf);
+	if(cfg->sys_misc&SM_EURODATE) {
+		tm.tm_mon=((p[3]&0xf)*10)+(p[4]&0xf);
+		tm.tm_mday=((p[0]&0xf)*10)+(p[1]&0xf); }
+	else {
+		tm.tm_mon=((p[0]&0xf)*10)+(p[1]&0xf);
+		tm.tm_mday=((p[3]&0xf)*10)+(p[4]&0xf); }
+
+	return(((tm.tm_year+1900)*10000)+(tm.tm_mon*100)+tm.tm_mday);
+}
+
+/*****************************/
+/* LEGACY FILEBASE CONSTANTS */
+/*****************************/
+#define LEN_FCDT		 9	/* 9 digits for file credit values				*/
+/****************************************************************************/
+/* Offsets into DIR .DAT file for different fields for each file 			*/
+/****************************************************************************/
+#define F_CDT		0				/* Offset in DIR#.DAT file for cdts		*/
+#define F_DESC		(F_CDT+LEN_FCDT)/* Description							*/
+#define F_ULER		(F_DESC+LEN_FDESC+2)   /* Uploader						*/
+#define F_TIMESDLED (F_ULER+30+2) 	/* Number of times downloaded 			*/
+#define F_OPENCOUNT	(F_TIMESDLED+5+2)
+#define F_MISC		(F_OPENCOUNT+3+2)
+#define F_ALTPATH	(F_MISC+1)		/* Two hex digit alternate path */
+#define F_LEN		(F_ALTPATH+2+2) /* Total length of all fdat in file		*/
+
+#define F_IXBSIZE	22				/* Length of each index entry			*/
+
+#define F_EXBSIZE	512				/* Length of each ext-desc entry		*/
+
+/***********************/
+/* LEGACY FILEBASE API */
+/***********************/
+typedef struct {						/* File (transfers) Data */
+	char    name[13],					/* Name of file FILENAME.EXT */
+			desc[LEN_FDESC+1],			/* Uploader's Description */
+			uler[LEN_ALIAS+1];			/* User who uploaded */
+	uchar	opencount;					/* Times record is currently open */
+	time32_t  date,						/* File date/time */
+			dateuled,					/* Date/Time (Unix) Uploaded */
+			datedled;					/* Date/Time (Unix) Last downloaded */
+	uint16_t	dir,						/* Directory file is in */
+			altpath,
+			timesdled,					/* Total times downloaded */
+			timetodl;					/* How long transfer time */
+	int32_t	datoffset,					/* Offset into .DAT file */
+			size,						/* Size of file */
+			misc;						/* Miscellaneous bits */
+	uint32_t	cdt;						/* Credit value for this file */
+
+} oldfile_t;
+
+                                    /* Bit values for file_t.misc */
+#define FM_EXTDESC  (1<<0)          /* Extended description exists */
+#define FM_ANON 	(1<<1)			/* Anonymous upload */
+
+/****************************************************************************/
+/* Turns FILE.EXT into FILE    .EXT                                         */
+/****************************************************************************/
+char* padfname(const char *filename, char *str)
+{
+    int c,d;
+
+	for(c=0;c<8;c++)
+		if(filename[c]=='.' || !filename[c]) break;
+		else str[c]=filename[c];
+	d=c;
+	if(filename[c]=='.') c++;
+	while(d<8)
+		str[d++]=' ';
+	if(filename[c]>' ')	/* Change "FILE" to "FILE        " */
+		str[d++]='.';	/* (don't add a dot if there's no extension) */
+	else
+		str[d++]=' ';
+	while(d<12)
+		if(!filename[c]) break;
+		else str[d++]=filename[c++];
+	while(d<12)
+		str[d++]=' ';
+	str[d]=0;
+	return(str);
+}
+
+/****************************************************************************/
+/* Turns FILE    .EXT into FILE.EXT                                         */
+/****************************************************************************/
+char* unpadfname(const char *filename, char *str)
+{
+    int c,d;
+
+	for(c=0,d=0;filename[c];c++)
+		if(filename[c]!=' ') str[d++]=filename[c];
+	str[d]=0;
+	return(str);
+}
+
+/****************************************************************************/
+/* Returns full (case-corrected) path to specified file						*/
+/****************************************************************************/
+char* getoldfilepath(scfg_t* cfg, oldfile_t* f, char* path)
+{
+	char	fname[MAX_PATH+1];
+
+	unpadfname(f->name,fname);
+	if(f->dir>=cfg->total_dirs)
+		safe_snprintf(path,MAX_PATH,"%s%s",cfg->temp_dir,fname);
+	else
+		safe_snprintf(path,MAX_PATH,"%s%s",f->altpath>0 && f->altpath<=cfg->altpaths 
+			? cfg->altpath[f->altpath-1] : cfg->dir[f->dir]->path
+			,fname);
+	if(!fexistcase(path)) {
+		char tmp[MAX_PATH + 1];
+		safe_snprintf(tmp,MAX_PATH,"%s%s",f->altpath>0 && f->altpath<=cfg->altpaths 
+			? cfg->altpath[f->altpath-1] : cfg->dir[f->dir]->path
+			,f->desc);
+		if(fexistcase(tmp))
+			strcpy(path, tmp);
+	}
+	return(path);
+}
+
+int file_uldate_compare(const void* v1, const void* v2)
+{
+	oldfile_t* f1 = (oldfile_t*)v1;
+	oldfile_t* f2 = (oldfile_t*)v2;
+
+	return f1->dateuled - f2->dateuled;
+}
+
+/****************************************************************************/
+/* Gets filedata from dircode.DAT file										*/
+/* Need fields .name ,.dir and .offset to get other info    				*/
+/* Does not fill .dateuled or .datedled fields.                             */
+/****************************************************************************/
+BOOL getfiledat(scfg_t* cfg, oldfile_t* f)
+{
+	char buf[F_LEN+1],str[MAX_PATH+1];
+	int file;
+	long length;
+
+	SAFEPRINTF2(str,"%s%s.dat",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
+	if((file=sopen(str,O_RDONLY|O_BINARY,SH_DENYWR))==-1) {
+		return(FALSE); 
+	}
+	length=(long)filelength(file);
+	if(f->datoffset>length) {
+		close(file);
+		return(FALSE); 
+	}
+	if(length%F_LEN) {
+		close(file);
+		return(FALSE); 
+	}
+	lseek(file,f->datoffset,SEEK_SET);
+	if(read(file,buf,F_LEN)!=F_LEN) {
+		close(file);
+		return(FALSE); 
+	}
+	close(file);
+	getrec(buf,F_ALTPATH,2,str);
+	f->altpath=hptoi(str);
+	getrec(buf,F_CDT,LEN_FCDT,str);
+	f->cdt=atol(str);
+
+	if(f->size == 0) {					// only read disk if f->size == 0
+		struct stat st;
+		getoldfilepath(cfg,f,str);
+		if(stat(str, &st) == 0) {
+			f->size = (int32_t)st.st_size;
+			f->date = (time32_t)st.st_mtime;
+		} else
+			f->size = -1;	// indicates file does not exist
+	}
+#if 0
+	if((f->size>0L) && cur_cps)
+		f->timetodl=(ushort)(f->size/(ulong)cur_cps);
+	else
+#endif
+		f->timetodl=0;
+
+	getrec(buf,F_DESC,LEN_FDESC,f->desc);
+	getrec(buf,F_ULER,LEN_ALIAS,f->uler);
+	getrec(buf,F_TIMESDLED,5,str);
+	f->timesdled=atoi(str);
+	getrec(buf,F_OPENCOUNT,3,str);
+	f->opencount=atoi(str);
+	if(buf[F_MISC]!=ETX)
+		f->misc=buf[F_MISC]-' ';
+	else
+		f->misc=0;
+	return(TRUE);
+}
+
+/****************************************************************************/
+/* Puts filedata into DIR_code.DAT file                                     */
+/* Called from removefiles                                                  */
+/****************************************************************************/
+BOOL putfiledat(scfg_t* cfg, oldfile_t* f)
+{
+    char buf[F_LEN+1],str[MAX_PATH+1],tmp[128];
+    int file;
+    long length;
+
+	putrec(buf,F_CDT,LEN_FCDT,ultoa(f->cdt,tmp,10));
+	putrec(buf,F_DESC,LEN_FDESC,f->desc);
+	putrec(buf,F_DESC+LEN_FDESC,2, "\r\n");
+	putrec(buf,F_ULER,LEN_ALIAS+5,f->uler);
+	putrec(buf,F_ULER+LEN_ALIAS+5,2, "\r\n");
+	putrec(buf,F_TIMESDLED,5,ultoa(f->timesdled,tmp,10));
+	putrec(buf,F_TIMESDLED+5,2, "\r\n");
+	putrec(buf,F_OPENCOUNT,3,ultoa(f->opencount,tmp,10));
+	putrec(buf,F_OPENCOUNT+3,2, "\r\n");
+	buf[F_MISC]=(char)f->misc+' ';
+	putrec(buf,F_ALTPATH,2,hexplus(f->altpath,tmp));
+	putrec(buf,F_ALTPATH+2,2, "\r\n");
+	SAFEPRINTF2(str,"%s%s.dat",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
+	if((file=sopen(str,O_WRONLY|O_BINARY,SH_DENYRW))==-1) {
+		return(FALSE); 
+	}
+	length=(long)filelength(file);
+	if(length%F_LEN) {
+		close(file);
+		return(FALSE); 
+	}
+	if(f->datoffset>length) {
+		close(file);
+		return(FALSE); 
+	}
+	lseek(file,f->datoffset,SEEK_SET);
+	if(write(file,buf,F_LEN)!=F_LEN) {
+		close(file);
+		return(FALSE); 
+	}
+	length=(long)filelength(file);
+	close(file);
+	if(length%F_LEN) {
+		return(FALSE);
+	}
+	return(TRUE);
+}
+
+/****************************************************************************/
+/* Gets file data from dircode.ixb file										*/
+/* Need fields .name and .dir filled.                                       */
+/* only fills .offset, .dateuled, and .datedled                             */
+/****************************************************************************/
+BOOL getfileixb(scfg_t* cfg, oldfile_t* f)
+{
+	char			str[MAX_PATH+1],fname[13];
+	uchar *	ixbbuf;
+	int				file;
+	long			l,length;
+
+	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
+	if((file=sopen(str,O_RDONLY|O_BINARY,SH_DENYWR))==-1) {
+		return(FALSE); 
+	}
+	length=(long)filelength(file);
+	if(length%F_IXBSIZE) {
+		close(file);
+		return(FALSE); 
+	}
+	if((ixbbuf=(uchar *)malloc(length))==NULL) {
+		close(file);
+		return(FALSE); 
+	}
+	if(read(file,ixbbuf,length)!=length) {
+		close(file);
+		free(ixbbuf);
+		return(FALSE); 
+	}
+	close(file);
+	SAFECOPY(fname,f->name);
+	for(l=8;l<12;l++)	/* Turn FILENAME.EXT into FILENAMEEXT */
+		fname[l]=fname[l+1];
+	for(l=0;l<length;l+=F_IXBSIZE) {
+		SAFEPRINTF(str,"%11.11s",ixbbuf+l);
+		if(!stricmp(str,fname))
+			break; 
+	}
+	if(l>=length) {
+		free(ixbbuf);
+		return(FALSE); 
+	}
+	l+=11;
+	f->datoffset=ixbbuf[l]|((long)ixbbuf[l+1]<<8)|((long)ixbbuf[l+2]<<16);
+	f->dateuled=ixbbuf[l+3]|((long)ixbbuf[l+4]<<8)
+		|((long)ixbbuf[l+5]<<16)|((long)ixbbuf[l+6]<<24);
+	f->datedled=ixbbuf[l+7]|((long)ixbbuf[l+8]<<8)
+		|((long)ixbbuf[l+9]<<16)|((long)ixbbuf[l+10]<<24);
+	free(ixbbuf);
+	return(TRUE);
+}
+
+/****************************************************************************/
+/* Updates the datedled and dateuled index record fields for a file			*/
+/****************************************************************************/
+BOOL putfileixb(scfg_t* cfg, oldfile_t* f)
+{
+	char	str[MAX_PATH+1],fname[13];
+	uchar*	ixbbuf;
+	int		file;
+	long	l,length;
+
+	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
+	if((file=sopen(str,O_RDWR|O_BINARY,SH_DENYRW))==-1) {
+		return(FALSE); 
+	}
+	length=(long)filelength(file);
+	if(length%F_IXBSIZE) {
+		close(file);
+		return(FALSE); 
+	}
+	if((ixbbuf=(uchar *)malloc(length))==NULL) {
+		close(file);
+		return(FALSE); 
+	}
+	if(read(file,ixbbuf,length)!=length) {
+		close(file);
+		free(ixbbuf);
+		return(FALSE); 
+	}
+	SAFECOPY(fname,f->name);
+	for(l=8;l<12;l++)	/* Turn FILENAME.EXT into FILENAMEEXT */
+		fname[l]=fname[l+1];
+	for(l=0;l<length;l+=F_IXBSIZE) {
+		SAFEPRINTF(str,"%11.11s",ixbbuf+l);
+		if(!stricmp(str,fname))
+			break; 
+	}
+	free(ixbbuf);
+
+	if(l>=length) {
+		close(file);
+		return(FALSE); 
+	}
+	
+	lseek(file,l+11+3,SEEK_SET);
+
+	write(file,&f->dateuled,4);
+	write(file,&f->datedled,4);
+
+	close(file);
+
+	return(TRUE);
+}
+
+int openextdesc(scfg_t* cfg, uint dirnum)
+{
+	char str[MAX_PATH+1];
+	SAFEPRINTF2(str,"%s%s.exb",cfg->dir[dirnum]->data_dir,cfg->dir[dirnum]->code);
+	return nopen(str,O_RDONLY);
+}
+
+void closeextdesc(int file)
+{
+	if(file >= 0)
+		close(file);
+}
+
+void getextdesc(scfg_t* cfg, uint dirnum, ulong datoffset, char *ext)
+{
+	int file;
+
+	memset(ext,0,F_EXBSIZE+1);
+	if((file=openextdesc(cfg, dirnum))==-1)
+		return;
+	lseek(file,(datoffset/F_LEN)*F_EXBSIZE,SEEK_SET);
+	read(file,ext,F_EXBSIZE);
+	close(file);
+}
+
+// fast (operates on open .exb file)
+void fgetextdesc(scfg_t* cfg, uint dirnum, ulong datoffset, char *ext, int file)
+{
+	lseek(file,(datoffset/F_LEN)*F_EXBSIZE,SEEK_SET);
+	read(file,ext,F_EXBSIZE);
+}
+
+void putextdesc(scfg_t* cfg, uint dirnum, ulong datoffset, char *ext)
+{
+	char str[MAX_PATH+1],nulbuf[F_EXBSIZE];
+	int file;
+
+	strip_ansi(ext);
+	strip_invalid_attr(ext);	/* eliminate bogus ctrl-a codes */
+	memset(nulbuf,0,sizeof(nulbuf));
+	SAFEPRINTF2(str,"%s%s.exb",cfg->dir[dirnum]->data_dir,cfg->dir[dirnum]->code);
+	if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
+		return;
+	lseek(file,0L,SEEK_END);
+	while(filelength(file)<(long)(datoffset/F_LEN)*F_EXBSIZE)
+		write(file,nulbuf,sizeof(nulbuf));
+	lseek(file,(datoffset/F_LEN)*F_EXBSIZE,SEEK_SET);
+	write(file,ext,F_EXBSIZE);
+	close(file);
+}
+
+/****************************************************************************/
+/* Update the upload date for the file 'f'                                  */
+/****************************************************************************/
+int update_uldate(scfg_t* cfg, oldfile_t* f)
+{
+	char str[MAX_PATH+1],fname[13];
+	int i,file;
+	long l,length;
+
+	/*******************/
+	/* Update IXB File */
+	/*******************/
+	SAFEPRINTF2(str,"%s%s.ixb",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
+	if((file=nopen(str,O_RDWR))==-1)
+		return(errno); 
+	length=(long)filelength(file);
+	if(length%F_IXBSIZE) {
+		close(file);
+		return(-1); 
+	}
+	SAFECOPY(fname,f->name);
+	for(i=8;i<12;i++)   /* Turn FILENAME.EXT into FILENAMEEXT */
+		fname[i]=fname[i+1];
+	for(l=0;l<length;l+=F_IXBSIZE) {
+		read(file,str,F_IXBSIZE);      /* Look for the filename in the IXB file */
+		str[11]=0;
+		if(!stricmp(fname,str)) break; 
+	}
+	if(l>=length) {
+		close(file);
+		return(-2); 
+	}
+	lseek(file,l+14,SEEK_SET);
+	write(file,&f->dateuled,4);
+	close(file);
+
+	/*******************************************/
+	/* Update last upload date/time stamp file */
+	/*******************************************/
+	SAFEPRINTF2(str,"%s%s.dab",cfg->dir[f->dir]->data_dir,cfg->dir[f->dir]->code);
+	if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
+		return(errno);
+
+	write(file,&f->dateuled,4);
+	close(file); 
+	return(0);
+}
+
+bool upgrade_file_bases(bool hash)
+{
+	int result;
+	ulong total_files = 0;
+	time_t start = time(NULL);
+
+	printf("Upgrading File Bases...\n");
+
+	for(int i = 0; i < scfg.total_dirs; i++) {
+		smb_t smb;
+
+		SAFEPRINTF2(smb.file, "%s%s", scfg.dir[i]->data_dir, scfg.dir[i]->code);
+		if((result = smb_open(&smb)) != SMB_SUCCESS) {
+			fprintf(stderr, "Error %d (%s) opening %s\n", result, smb.last_error, smb.file);
+			return false;
+		}
+		smb.status.attr = SMB_FILE_DIRECTORY;
+		if(!hash || (scfg.dir[i]->misc & DIR_NOHASH))
+			smb.status.attr |= SMB_NOHASH;
+		smb.status.max_age = scfg.dir[i]->maxage;
+		smb.status.max_msgs = scfg.dir[i]->maxfiles;
+		if((result = smb_create(&smb)) != SMB_SUCCESS) {
+			fprintf(stderr, "Error %d (%s) creating %s\n", result, smb.last_error, smb.file);
+			return false;
+		}
+
+		char str[MAX_PATH+1];
+		int file;
+		int extfile = openextdesc(&scfg, i);
+
+		sprintf(str,"%s%s.ixb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
+		if((file=open(str,O_RDONLY|O_BINARY))==-1) {
+			smb_close(&smb);
+			continue;
+		}
+		long l=(long)filelength(file);
+		if(!l) {
+			close(file);
+			smb_close(&smb);
+			continue;
+		}
+		uchar* ixbbuf;
+		if((ixbbuf=(uchar *)malloc(l))==NULL) {
+			close(file);
+			printf("\7ERR_ALLOC %s %lu\n",str,l);
+			smb_close(&smb);
+			continue;
+		}
+		if(read(file,ixbbuf,l)!=(int)l) {
+			close(file);
+			printf("\7ERR_READ %s %lu\n",str,l);
+			free(ixbbuf);
+			smb_close(&smb);
+			continue;
+		}
+		close(file);
+		size_t file_count = l / F_IXBSIZE;
+		oldfile_t* filelist = malloc(sizeof(*filelist) * file_count);
+		if(filelist == NULL) {
+			printf("malloc failure");
+			return false;
+		}
+		memset(filelist, 0, sizeof(*filelist) * file_count);
+		oldfile_t* f = filelist;
+		long m=0L;
+		while(m + F_IXBSIZE <= l) {
+			int j;
+			f->dir = i;
+			for(j=0;j<12 && m<l;j++)
+				if(j==8)
+					f->name[j]=ixbbuf[m]>' ' ? '.' : ' ';
+				else
+					f->name[j]=ixbbuf[m++]; /* Turns FILENAMEEXT into FILENAME.EXT */
+			f->name[j]=0;
+			f->datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
+			f->dateuled=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
+				|((long)ixbbuf[m+6]<<24));
+			f->datedled =(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)|((long)ixbbuf[m+9]<<16)
+				|((long)ixbbuf[m+10]<<24));
+			m+=11;
+			f++;
+		};
+
+		/* SMB index is sorted by import (upload) time */
+		qsort(filelist, file_count, sizeof(*filelist), file_uldate_compare);
+
+		time_t latest = 0;
+		for(size_t fi = 0; fi < file_count; fi++) {
+			f = &filelist[fi];
+			if(!getfiledat(&scfg, f)) {
+				fprintf(stderr, "\nError getting file data for %s %s\n", scfg.dir[i]->code, f->name);
+				continue;
+			}
+			char fpath[MAX_PATH+1];
+			getoldfilepath(&scfg, f, fpath);
+			file_t file;
+			memset(&file, 0, sizeof(file));
+			file.hdr.when_imported.time = f->dateuled;
+			file.hdr.last_downloaded = f->datedled;
+			file.hdr.times_downloaded = f->timesdled;
+			smb_hfield_str(&file, SMB_FILENAME, getfname(fpath));
+			smb_hfield_str(&file, SMB_FILEDESC, f->desc);
+			smb_hfield_str(&file, SENDER, f->uler);
+			smb_hfield_bin(&file, SMB_COST, f->cdt);
+			if(f->misc&FM_ANON)
+				file.hdr.attr |= FILE_ANONYMOUS;
+			{
+				const char* body = NULL;
+				char extdesc[F_EXBSIZE+1] = {0};
+				if(f->misc&FM_EXTDESC && extfile > 0) {
+					fgetextdesc(&scfg, i, f->datoffset, extdesc, extfile);
+					truncsp(extdesc);
+					if(*extdesc)
+						body = extdesc;
+				}
+				result = smb_addfile(&smb, &file, SMB_FASTALLOC, body, fpath);
+			}
+			if(result != SMB_SUCCESS) {
+				fprintf(stderr, "\n!Error %d (%s) adding file to %s\n", result, smb.last_error, smb.file);
+			} else {
+				total_files++;
+				time_t diff = time(NULL) - start;
+				printf("\r%-16s (%-5u bases remain) %lu files imported (%lu files/second)"
+					, scfg.dir[i]->code, scfg.total_dirs - (i + 1), total_files, (ulong)(diff ? total_files / diff : total_files));
+			}
+			if(f->dateuled > latest)
+				latest = f->dateuled;
+			smb_freefilemem(&file);
+		}
+		free(filelist);
+		off_t new_count = filelength(fileno(smb.sid_fp)) / smb_idxreclen(&smb);
+		smb_close(&smb);
+		if(latest > 0)
+			update_newfiletime(&smb, latest);
+		closeextdesc(extfile);
+		free(ixbbuf);
+		if(new_count != file_count) {
+			printf("\n%s: New file base index has %u records instead of %u\n"
+				,scfg.dir[i]->code, (uint)new_count, (uint)file_count);
+		}
+	}
+	time_t diff = time(NULL) - start;
+	printf("\r%lu files imported in %u directories (%lu files/second)%40s\n"
+		,total_files, scfg.total_dirs, (ulong)(diff ? total_files / diff : total_files), "");
+
+	return true;
+}
+
+char *usage="\nusage: upgrade [ctrl_dir]\n";
+
+int main(int argc, char** argv)
+{
+	char	error[512];
+
+	fprintf(stderr,"\nupgrade - Upgrade Synchronet BBS to %s\n"
+		,VERSION
+		);
+
+	memset(&scfg, 0, sizeof(scfg));
+	scfg.size = sizeof(scfg);
+	SAFECOPY(scfg.ctrl_dir, get_ctrl_dir(/* warn: */true));
+
+	if(chdir(scfg.ctrl_dir) != 0)
+		fprintf(stderr,"!ERROR changing directory to: %s", scfg.ctrl_dir);
+
+	printf("\nLoading configuration files from %s\n",scfg.ctrl_dir);
+	if(!load_cfg(&scfg, NULL, TRUE, /* node: **/FALSE, error, sizeof(error))) {
+		fprintf(stderr,"!ERROR loading configuration files: %s\n",error);
+		return EXIT_FAILURE + __COUNTER__;
+	}
+
+	if(!upgrade_file_bases(/* hash: */true))
+		return EXIT_FAILURE + __COUNTER__;
+
+	printf("Upgrade successful.\n");
+    return EXIT_SUCCESS;
+}
diff --git a/src/sbbs3/upgrade_to_v319.vcxproj b/src/sbbs3/upgrade_to_v319.vcxproj
new file mode 100644
index 0000000000..c65d3d9826
--- /dev/null
+++ b/src/sbbs3/upgrade_to_v319.vcxproj
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectGuid>{b84cb739-8425-4612-bdef-b292beae858f}</ProjectGuid>
+    <RootNamespace>upgrade</RootNamespace>
+    <WindowsTargetPlatformVersion>7.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141_xp</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141_xp</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="..\xpdev\xpdev.props" />
+    <Import Project="..\smblib\smblib.props" />
+    <Import Project="..\hash\hash.props" />
+    <Import Project="..\build\undeprecate.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="..\xpdev\xpdev.props" />
+    <Import Project="..\smblib\smblib.props" />
+    <Import Project="..\hash\hash.props" />
+    <Import Project="..\build\undeprecate.props" />
+    <Import Project="..\..\3rdp\win32.release\libarchive\libarchive.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>.\msvc.win32.exe.debug\</OutDir>
+    <IntDir>.\msvc.win32.debug\upgrade\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>.\msvc.win32.exe.release\</OutDir>
+    <IntDir>.\msvc.win32.release\upgrade\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>SBBS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>SBBS_EXPORTS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="dat_rec.c" />
+    <ClCompile Include="filedat.c" />
+    <ClCompile Include="upgrade_to_v319.c" />
+    <ClCompile Include="userdat.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\smblib\smblib.vcxproj">
+      <Project>{d674842b-2f41-42cb-9426-b3c4b0682574}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\xpdev\xpdev.vcxproj">
+      <Project>{7428a1e8-56b7-4868-9c0e-29d031689feb}</Project>
+    </ProjectReference>
+    <ProjectReference Include="load_cfg.vcxproj">
+      <Project>{08fc395f-bc60-499d-9ce9-170ed718bb94}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/sbbs3/upload.cpp b/src/sbbs3/upload.cpp
index 13e6c2a9f5..c3431ab492 100644
--- a/src/sbbs3/upload.cpp
+++ b/src/sbbs3/upload.cpp
@@ -1,9 +1,5 @@
-/* upload.cpp */
-
 /* Synchronet file upload-related routines */
 
-/* $Id: upload.cpp,v 1.63 2019/08/02 10:36:45 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,89 +13,69 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include "sbbs.h"
+#include "filedat.h"
 
 /****************************************************************************/
-/* Adds file data in 'f' to DIR#.DAT and DIR#.IXB   and updates user        */
-/* info for uploader. Must have .name, .desc and .dir fields filled prior   */
-/* to a call to this function.                                              */
-/* Returns 1 if file uploaded sucessfully, 0 if not.                        */
 /****************************************************************************/
-bool sbbs_t::uploadfile(file_t *f)
+bool sbbs_t::uploadfile(file_t* f)
 {
 	char	path[MAX_PATH+1];
-	char	str[MAX_PATH+1],fname[25];
-	char	ext[F_EXBSIZE+1];
-	char	desc[F_EXBSIZE+1];
+	char	str[MAX_PATH+1] = "";
+	char	ext[LEN_EXTDESC + 1] = "";
 	char	tmp[MAX_PATH+1];
-	int		file;
     uint	i;
     long	length;
 	FILE*	stream;
 
-	// f->misc=0; Removed AUG-22-2001 - broken anonymous uploads
 	curdirnum=f->dir;
-	if(findfile(&cfg,f->dir,f->name)) {
-		errormsg(WHERE,ERR_CHK,f->name,f->dir);
-		return(0); 
+	if(findfile(&cfg, f->dir, f->name, NULL)) {
+		errormsg(WHERE, ERR_CHK, f->name, f->dir);
+		return false;
 	}
-	sprintf(path,"%s%s",f->altpath>0 && f->altpath<=cfg.altpaths
-		? cfg.altpath[f->altpath-1]
-		: cfg.dir[f->dir]->path,unpadfname(f->name,fname));
-	sprintf(tmp,"%s%s",cfg.temp_dir,fname);
+	getfilepath(&cfg, f, path);
+	SAFEPRINTF2(tmp, "%s%s", cfg.temp_dir, getfname(path));
 	if(!fexistcase(path) && fexistcase(tmp))
 		mv(tmp,path,0);
 	if(!fexistcase(path)) {
 		bprintf(text[FileNotReceived],f->name);
-		sprintf(str,"attempted to upload %s to %s %s (Not received)"
+		safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (Not received)"
 			,f->name
 			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
 		logline(LOG_NOTICE,"U!",str);
-		return(0); 
+		return false;
 	}
-	strcpy(tmp,f->name);
-	truncsp(tmp);
+	f->hdr.when_written.time = (uint32_t)fdate(path);
+	char* fext = getfext(f->name);
 	for(i=0;i<cfg.total_ftests;i++)
-		if(cfg.ftest[i]->ext[0]=='*' || !stricmp(tmp+9,cfg.ftest[i]->ext)) {
+		if(cfg.ftest[i]->ext[0]=='*' || (fext != NULL && stricmp(fext, cfg.ftest[i]->ext) == 0)) {
 			if(!chk_ar(cfg.ftest[i]->ar,&useron,&client))
 				continue;
 			attr(LIGHTGRAY);
 			bputs(cfg.ftest[i]->workstr);
 
-			sprintf(sbbsfilename,"SBBSFILENAME=%.64s",unpadfname(f->name,fname));
+			safe_snprintf(sbbsfilename,sizeof(sbbsfilename),"SBBSFILENAME=%s",f->name);
 			putenv(sbbsfilename);
-			sprintf(sbbsfiledesc,"SBBSFILEDESC=%.*s",LEN_FDESC,f->desc);
+			safe_snprintf(sbbsfiledesc,sizeof(sbbsfiledesc),"SBBSFILEDESC=%s",f->desc);
 			putenv(sbbsfiledesc);
-			sprintf(str,"%ssbbsfile.nam",cfg.node_dir);
+			SAFEPRINTF(str,"%ssbbsfile.nam",cfg.node_dir);
 			if((stream=fopen(str,"w"))!=NULL) {
-				fwrite(fname,1,strlen(fname),stream);
+				fprintf(stream, "%s", f->desc);
 				fclose(stream); 
 			}
-			sprintf(str,"%ssbbsfile.des",cfg.node_dir);
+			SAFEPRINTF(str,"%ssbbsfile.des",cfg.node_dir);
 			if((stream=fopen(str,"w"))!=NULL) {
 				fwrite(f->desc,1,strlen(f->desc),stream);
 				fclose(stream); 
 			}
 			if(external(cmdstr(cfg.ftest[i]->cmd,path,f->desc,NULL),EX_OFFLINE)) {
-				sprintf(str,"attempted to upload %s to %s %s (%s Errors)"
+				safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (%s Errors)"
 					,f->name
 					,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname,cfg.ftest[i]->ext);
 				logline(LOG_NOTICE,"U!",str);
@@ -112,6 +88,7 @@ bool sbbs_t::uploadfile(file_t *f)
 					remove(path);
 				return(0); 
 			} else {
+#if 0 // NFB-TODO - uploader tester changes filename or description
 				sprintf(str,"%ssbbsfile.nam",cfg.node_dir);
 				if((stream=fopen(str,"r"))!=NULL) {
 					if(fgets(str,128,stream)) {
@@ -119,8 +96,7 @@ bool sbbs_t::uploadfile(file_t *f)
 						padfname(str,f->name);
 						strcpy(tmp,f->name);
 						truncsp(tmp);
-						sprintf(path,"%s%s",f->altpath>0 && f->altpath<=cfg.altpaths
-							? cfg.altpath[f->altpath-1] : cfg.dir[f->dir]->path
+						sprintf(path,"%s%s", cfg.dir[f->dir]->path
 							,unpadfname(f->name,fname)); 
 					}
 					fclose(stream);
@@ -133,56 +109,71 @@ bool sbbs_t::uploadfile(file_t *f)
 					}
 					fclose(stream); 
 				}
-				CRLF; 
-			} 
+				CRLF;
+#endif
+			}
 		}
 
 	if((length=(long)flength(path))==0L) {
 		bprintf(text[FileZeroLength],f->name);
 		remove(path);
-		sprintf(str,"attempted to upload %s to %s %s (Zero length)"
+		safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (Zero length)"
 			,f->name
 			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
 		logline(LOG_NOTICE,"U!",str);
-		return(0); 
+		return false; 
 	}
-	if(cfg.dir[f->dir]->misc&DIR_DIZ) {
-		for(i=0;i<cfg.total_fextrs;i++)
-			if(!stricmp(cfg.fextr[i]->ext,tmp+9) && chk_ar(cfg.fextr[i]->ar,&useron,&client))
-				break;
-		if(i<cfg.total_fextrs) {
-			sprintf(str,"%sFILE_ID.DIZ",cfg.temp_dir);
-			if(fexistcase(str))
-				remove(str);
-			external(cmdstr(cfg.fextr[i]->cmd,path,"FILE_ID.DIZ",NULL),EX_OFFLINE);
-			if(!fexistcase(str)) {
-				sprintf(str,"%sDESC.SDI",cfg.temp_dir);
-				if(fexistcase(str))
-					remove(str);
-				external(cmdstr(cfg.fextr[i]->cmd,path,"DESC.SDI",NULL),EX_OFFLINE); 
-				fexistcase(str);
+
+	bputs(text[SearchingForDupes]);
+	/* Note: Hashes file *after* running upload-testers (which could modify file) */
+	if(hashfile(&cfg, f)) {
+		bputs(text[SearchedForDupes]);
+		for(uint i=0, k=0; i < usrlibs; i++) {
+			progress(text[Scanning], i, usrlibs, 1);
+			for(uint j=0; j < usrdirs[i]; j++,k++) {
+				if(cfg.dir[usrdir[i][j]]->misc&DIR_DUPES
+					&& findfile(&cfg, usrdir[i][j], /* filename: */NULL, f)) {
+					bprintf(text[FileAlreadyOnline], f->name);
+					if(!dir_op(f->dir)) {
+						remove(path);
+						safe_snprintf(str, sizeof(str), "attempted to upload %s to %s %s (duplicate hash)"
+							,f->name
+							,cfg.lib[cfg.dir[f->dir]->lib]->sname, cfg.dir[f->dir]->sname);
+						logline(LOG_NOTICE, "U!", str);
+						return(false); 	 /* File is in database for another dir */
+					}
+				}
 			}
-			if((file=nopen(str,O_RDONLY))!=-1) {
-				memset(ext,0,F_EXBSIZE+1);
-				read(file,ext,F_EXBSIZE);
-				for(i=F_EXBSIZE;i;i--)
-					if(ext[i-1]>' ')
+		}
+		progress(text[Done], usrlibs, usrlibs);
+	} else
+		bputs(text[SearchedForDupes]);
+
+	if(cfg.dir[f->dir]->misc&DIR_DIZ) {
+		lprintf(LOG_DEBUG, "Extracting DIZ from: %s", path);
+		if(extract_diz(&cfg, f, /* diz_fnames: */NULL, str, sizeof(str))) {
+			lprintf(LOG_DEBUG, "Parsing DIZ: %s", str);
+
+			str_list_t lines = read_diz(str, /* max_line_len: */80);
+			if(lines != NULL)
+				format_diz(lines, ext, sizeof(ext), /* allow_ansi: */false);
+			strListFree(&lines);
+
+			if(f->desc == NULL || f->desc[0] == 0) {
+				char	desc[LEN_FDESC];
+				SAFECOPY(desc, (char*)ext);
+				strip_exascii(desc, desc);
+				prep_file_desc(desc, desc);
+				for(i=0;desc[i];i++)
+					if(IS_ALPHANUMERIC(desc[i]))
 						break;
-				ext[i]=0;
-				if(!f->desc[0]) {
-					strcpy(desc,ext);
-					strip_exascii(desc, desc);
-					prep_file_desc(desc, desc);
-					for(i=0;desc[i];i++)
-						if(IS_ALPHANUMERIC(desc[i]))
-							break;
-					sprintf(f->desc,"%.*s",LEN_FDESC,desc+i); 
-				}
-				close(file);
-				remove(str);
-				f->misc|=FM_EXTDESC; 
-			} 
-		} 
+				if(desc[i] == '\0')
+					i = 0;
+				smb_hfield_str(f, SMB_FILEDESC, desc + i);
+			}
+			remove(str);
+		} else
+			lprintf(LOG_DEBUG, "DIZ does not exist in: %s", path);
 	}
 
 	if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
@@ -190,27 +181,15 @@ bool sbbs_t::uploadfile(file_t *f)
 		logon_uls++;
 	}
 	if(cfg.dir[f->dir]->misc&DIR_AONLY)  /* Forced anonymous */
-		f->misc|=FM_ANON;
-	f->cdt=length;
-	f->dateuled=time32(NULL);
-	f->timesdled=0;
-	f->datedled=0L;
-	f->opencount=0;
-	strcpy(f->uler,useron.alias);
+		f->hdr.attr |= MSG_ANONYMOUS;
+	uint32_t cdt = (uint32_t)length;
+	smb_hfield_bin(f, SMB_COST, cdt);
+	smb_hfield_str(f, SENDER, useron.alias);
 	bprintf(text[FileNBytesReceived],f->name,ultoac(length,tmp));
-	if(!f->desc[0]) {
-		if(stricmp(f->name,getfname(path)))
-			SAFECOPY(f->desc,getfname(path));
-		else
-			sprintf(f->desc,"%.*s",LEN_FDESC,text[NoDescription]);
-	}
-	if(!addfiledat(&cfg,f))
-		return(0);
+	if(!addfile(&cfg, f->dir, f, ext))
+		return false;
 
-	if(f->misc&FM_EXTDESC)
-		putextdesc(&cfg,f->dir,f->datoffset,ext);
-
-	sprintf(str,"uploaded %s to %s %s"
+	safe_snprintf(str,sizeof(str),"uploaded %s to %s %s"
 		,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname
 		,cfg.dir[f->dir]->sname);
 	if(cfg.dir[f->dir]->upload_sem[0])
@@ -226,12 +205,12 @@ bool sbbs_t::uploadfile(file_t *f)
 				,((ulong)(length*(cfg.dir[f->dir]->up_pct/100.0))/cur_cps)/60);
 		else
 			useron.cdt=adjustuserrec(&cfg,useron.number,U_CDT,10
-				,(ulong)(f->cdt*(cfg.dir[f->dir]->up_pct/100.0))); 
+				,(ulong)(f->cost * (cfg.dir[f->dir]->up_pct/100.0))); 
 	}
 
 	user_event(EVENT_UPLOAD);
 
-	return(true);
+	return true;
 }
 
 /****************************************************************************/
@@ -240,18 +219,14 @@ bool sbbs_t::uploadfile(file_t *f)
 bool sbbs_t::upload(uint dirnum)
 {
 	char	descbeg[25]={""},descend[25]={""}
-				,fname[13],keys[256],ch,*p;
+				,fname[MAX_FILENAME_LEN + 1],keys[256],ch,*p;
 	char	str[MAX_PATH+1];
 	char	path[MAX_PATH+1];
-	char	spath[MAX_PATH+1];
 	char 	tmp[512];
     time_t	start,end;
-    uint	i,j,k,destuser[MAX_USERXFER],destusers=0;
-	int		file;
+    uint	i,j,k;
 	ulong	space;
-    file_t	f;
-    user_t	user;
-    node_t	node;
+	file_t	f = {{}};
 
 	/* Security Checks */
 	if(useron.rest&FLAG('U')) {
@@ -276,10 +251,8 @@ bool sbbs_t::upload(uint dirnum)
 
 	if(sys_status&SS_EVENT && online==ON_REMOTE && !dir_op(dirnum))
 		bprintf(text[UploadBeforeEvent],timeleft/60);
-	if(altul)
-		strcpy(path,cfg.altpath[altul-1]);
-	else
-		strcpy(path,cfg.dir[dirnum]->path);
+
+	SAFECOPY(path,cfg.dir[dirnum]->path);
 
 	if(!isdir(path)) {
 		bprintf(text[DirectoryDoesNotExist], path);
@@ -298,32 +271,25 @@ bool sbbs_t::upload(uint dirnum)
 	bprintf(text[DiskNBytesFree],ultoac(space,tmp));
 
 	f.dir=curdirnum=dirnum;
-	f.misc=0;
-	f.altpath=altul;
 	bputs(text[Filename]);
-	if(!getstr(fname,12,0) || strchr(fname,'?') || strchr(fname,'*')
+	if(getstr(fname, sizeof(fname) - 1, 0) < 1 || strchr(fname,'?') || strchr(fname,'*')
 		|| !checkfname(fname) || (trashcan(fname,"file") && !dir_op(dirnum))) {
 		if(fname[0])
 			bputs(text[BadFilename]);
 		return(false); 
 	}
 	if(dirnum==cfg.sysop_dir)
-		sprintf(str,text[UploadToSysopDirQ],fname);
+		SAFEPRINTF(str,text[UploadToSysopDirQ],fname);
 	else if(dirnum==cfg.user_dir)
-		sprintf(str,text[UploadToUserDirQ],fname);
+		SAFEPRINTF(str,text[UploadToUserDirQ],fname);
 	else
-		sprintf(str,text[UploadToCurDirQ],fname,cfg.lib[cfg.dir[dirnum]->lib]->sname
+		SAFEPRINTF3(str,text[UploadToCurDirQ],fname,cfg.lib[cfg.dir[dirnum]->lib]->sname
 			,cfg.dir[dirnum]->sname);
 	if(!yesno(str)) return(false);
 	action=NODE_ULNG;
-	SAFEPRINTF2(str,"%s%s",path,fname);
-	if(fexistcase(str)) {   /* File is on disk */
-#ifdef _WIN32
-		GetShortPathName(str, spath, sizeof(spath));
-#else
-		SAFECOPY(spath,str);
-#endif
-		SAFECOPY(fname,getfname(spath));
+	SAFECOPY(f.file_idx.name, fname);
+	getfilepath(&cfg, &f, path);
+	if(fexistcase(path)) {   /* File is on disk */
 		if(!dir_op(dirnum) && online!=ON_LOCAL) {		 /* local users or sysops */
 			bprintf(text[FileAlreadyThere],fname);
 			return(false); 
@@ -331,18 +297,16 @@ bool sbbs_t::upload(uint dirnum)
 		if(!yesno(text[FileOnDiskAddQ]))
 			return(false); 
 	}
-	padfname(fname,f.name);
-	strcpy(str,cfg.dir[dirnum]->exts);
-	strcpy(tmp,f.name);
-	truncsp(tmp);
+	char* ext = getfext(fname);
+	SAFECOPY(str,cfg.dir[dirnum]->exts);
 	j=strlen(str);
 	for(i=0;i<j;i+=ch+1) { /* Check extension of upload with allowable exts */
 		p=strchr(str+i,',');
 		if(p!=NULL)
 			*p=0;
 		ch=(char)strlen(str+i);
-		if(!stricmp(tmp+9,str+i))
-			break; 
+		if(ext != NULL && stricmp(ext + 1, str + i) == 0)
+			break;
 	}
 	if(j && i>=j) {
 		bputs(text[TheseFileExtsOnly]);
@@ -351,20 +315,19 @@ bool sbbs_t::upload(uint dirnum)
 		if(!dir_op(dirnum)) return(false); 
 	}
 	bputs(text[SearchingForDupes]);
-	if(findfile(&cfg,dirnum,f.name)) {
-		bputs(text[SearchedForDupes]);
+	bool found = findfile(&cfg, dirnum, fname, NULL);
+	bputs(text[SearchedForDupes]);
+	if(found) {
 		bprintf(text[FileAlreadyOnline],fname);
 		return(false); 	 /* File is already in database */
 	}
 	for(i=k=0;i<usrlibs;i++) {
+		progress(text[SearchingForDupes], i, usrlibs, 1);
 		for(j=0;j<usrdirs[i];j++,k++) {
-			outchar('.');
-			if(k && !(k%5))
-				bputs("\b\b\b\b\b     \b\b\b\b\b");
 			if(usrdir[i][j]==dirnum)
 				continue;	/* we already checked this dir */
 			if(cfg.dir[usrdir[i][j]]->misc&DIR_DUPES
-				&& findfile(&cfg,usrdir[i][j],f.name)) {
+				&& findfile(&cfg, usrdir[i][j], fname, NULL)) {
 				bputs(text[SearchedForDupes]);
 				bprintf(text[FileAlreadyOnline],fname);
 				if(!dir_op(dirnum))
@@ -373,41 +336,6 @@ bool sbbs_t::upload(uint dirnum)
 		}
 	}
 	bputs(text[SearchedForDupes]);
-	if(dirnum==cfg.user_dir) {  /* User to User transfer */
-		bputs(text[EnterAfterLastDestUser]);
-		while((!dir_op(dirnum) && destusers<cfg.max_userxfer) || destusers<MAX_USERXFER) {
-			bputs(text[SendFileToUser]);
-			if(!getstr(str,LEN_ALIAS,cfg.uq&UQ_NOUPRLWR ? K_NONE:K_UPRLWR))
-				break;
-			if((user.number=finduser(str))!=0) {
-				if(!dir_op(dirnum) && user.number==useron.number) {
-					bputs(text[CantSendYourselfFiles]);
-					continue; 
-				}
-				for(i=0;i<destusers;i++)
-					if(user.number==destuser[i])
-						break;
-				if(i<destusers) {
-					bputs(text[DuplicateUser]);
-					continue; 
-				}
-				getuserdat(&cfg,&user);
-				if((user.rest&(FLAG('T')|FLAG('D')))
-					|| !chk_ar(cfg.lib[cfg.dir[cfg.user_dir]->lib]->ar,&user,/* client: */NULL)
-					|| !chk_ar(cfg.dir[cfg.user_dir]->dl_ar,&user,/* client: */NULL)) {
-					bprintf(text[UserWontBeAbleToDl],user.alias); 
-				} else {
-					bprintf(text[UserAddedToDestList],user.alias);
-					destuser[destusers++]=user.number; 
-				} 
-			}
-			else {
-				CRLF; 
-			} 
-		}
-		if(!destusers)
-			return(false); 
-	}
 	if(cfg.dir[dirnum]->misc&DIR_RATE) {
 		SYNC;
 		bputs(text[RateThisFile]);
@@ -415,13 +343,13 @@ bool sbbs_t::upload(uint dirnum)
 		if(!IS_ALPHA(ch) || sys_status&SS_ABORT)
 			return(false);
 		CRLF;
-		sprintf(descbeg,text[Rated],toupper(ch)); 
+		SAFEPRINTF(descbeg,text[Rated],toupper(ch)); 
 	}
 	if(cfg.dir[dirnum]->misc&DIR_ULDATE) {
 		now=time(NULL);
 		if(descbeg[0])
 			strcat(descbeg," ");
-		sprintf(str,"%s  ",unixtodstr(&cfg,(time32_t)now,tmp));
+		SAFEPRINTF(str,"%s  ",unixtodstr(&cfg,(time32_t)now,tmp));
 		strcat(descbeg,str); 
 	}
 	if(cfg.dir[dirnum]->misc&DIR_MULT) {
@@ -436,37 +364,49 @@ bool sbbs_t::upload(uint dirnum)
 			if(j==1)
 				upload_lastdesc[0]=0;
 			if(i>9)
-				sprintf(descend,text[FileOneOfTen],j,i);
+				SAFEPRINTF2(descend,text[FileOneOfTen],j,i);
 			else
-				sprintf(descend,text[FileOneOfTwo],j,i); 
+				SAFEPRINTF2(descend,text[FileOneOfTwo],j,i); 
 		} else
 			upload_lastdesc[0]=0; 
 	}
 	else
 		upload_lastdesc[0]=0;
+
+	char fdesc[LEN_FDESC + 1] = "";
 	bputs(text[EnterDescNow]);
 	i=LEN_FDESC-(strlen(descbeg)+strlen(descend));
-	getstr(upload_lastdesc,i,K_LINE|K_EDIT|K_AUTODEL);
+	getstr(upload_lastdesc,i,K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
 	if(sys_status&SS_ABORT)
 		return(false);
 	if(descend[0])      /* end of desc specified, so pad desc with spaces */
-		sprintf(f.desc,"%s%-*s%s",descbeg,i,upload_lastdesc,descend);
+		safe_snprintf(fdesc,sizeof(fdesc),"%s%-*s%s",descbeg,i,upload_lastdesc,descend);
 	else                /* no end specified, so string ends at desc end */
-		sprintf(f.desc,"%s%s",descbeg,upload_lastdesc);
+		safe_snprintf(fdesc,sizeof(fdesc),"%s%s",descbeg,upload_lastdesc);
+
+	char tags[64] = "";
+	if((cfg.dir[dirnum]->misc&DIR_FILETAGS) && (text[TagFileQ][0] == 0 || !noyes(text[TagFileQ]))) {
+		bputs(text[TagFilePrompt]);
+		getstr(tags, sizeof(tags)-1, K_EDIT|K_LINE|K_TRIM);
+	}
 
 	if(cfg.dir[dirnum]->misc&DIR_ANON && !(cfg.dir[dirnum]->misc&DIR_AONLY)
 		&& (dir_op(dirnum) || useron.exempt&FLAG('A'))) {
 		if(!noyes(text[AnonymousQ]))
-			f.misc|=FM_ANON; 
+			f.hdr.attr |= MSG_ANONYMOUS;
 	}
-	SAFEPRINTF2(str,"%s%s",path,fname);
-	if(fexistcase(str)) {   /* File is on disk */
-		if(!uploadfile(&f))
-			return(false); 
+
+	bool result = false;
+	smb_hfield_str(&f, SMB_FILENAME, fname);
+	smb_hfield_str(&f, SMB_FILEDESC, fdesc);
+	if(tags[0])
+		smb_hfield_str(&f, SMB_TAGS, tags);
+	if(fexistcase(path)) {   /* File is on disk */
+		result = uploadfile(&f);
 	} else {
 		xfer_prot_menu(XFER_UPLOAD);
 		SYNC;
-		sprintf(keys,"%c",text[YNQP][2]);
+		SAFEPRINTF(keys,"%c",text[YNQP][2]);
 		if(dirnum==cfg.user_dir || !cfg.max_batup)  /* no batch user to user xfers */
 			mnemonics(text[ProtocolOrQuit]);
 		else {
@@ -475,30 +415,22 @@ bool sbbs_t::upload(uint dirnum)
 		}
 		for(i=0;i<cfg.total_prots;i++)
 			if(cfg.prot[i]->ulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
-				sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
+				SAFEPRINTF(tmp,"%c",cfg.prot[i]->mnemonic);
 				strcat(keys,tmp); 
 			}
 		ch=(char)getkeys(keys,0);
 		if(ch==text[YNQP][2] || (sys_status&SS_ABORT))
-			return(false);
-		if(ch=='B') {
-			if(batup_total>=cfg.max_batup)
+			result = false;
+		else if(ch=='B') {
+			if(batup_total() >= cfg.max_batup)
 				bputs(text[BatchUlQueueIsFull]);
-			else {
-				for(i=0;i<batup_total;i++)
-					if(!strcmp(batup_name[i],f.name)) {
-						bprintf(text[FileAlreadyInQueue],fname);
-						return(false); 
-					}
-				strcpy(batup_name[batup_total],f.name);
-				strcpy(batup_desc[batup_total],f.desc);
-				batup_dir[batup_total]=dirnum;
-				batup_misc[batup_total]=f.misc;
-				batup_alt[batup_total]=altul;
-				batup_total++;
+			else if(batch_file_exists(&cfg, useron.number, XFER_BATCH_UPLOAD, f.name))
+				bprintf(text[FileAlreadyInQueue],fname);
+			else if(batch_file_add(&cfg, useron.number, XFER_BATCH_UPLOAD, &f)) {
 				bprintf(text[FileAddedToUlQueue]
-					,fname,batup_total,cfg.max_batup); 
-			} 
+					,fname, batup_total(), cfg.max_batup);
+				result = true;
+			}
 		} else {
 			for(i=0;i<cfg.total_prots;i++)
 				if(cfg.prot[i]->ulcmd[0] && cfg.prot[i]->mnemonic==ch
@@ -506,44 +438,17 @@ bool sbbs_t::upload(uint dirnum)
 					break;
 			if(i<cfg.total_prots) {
 				start=time(NULL);
-				protocol(cfg.prot[i],XFER_UPLOAD,str,nulstr,true);
+				protocol(cfg.prot[i],XFER_UPLOAD,path,nulstr,true);
 				end=time(NULL);
 				if(!(cfg.dir[dirnum]->misc&DIR_ULTIME)) /* Don't deduct upload time */
 					starttime+=end-start;
-				ch=uploadfile(&f);
+				result = uploadfile(&f);
 				autohangup();
-				if(!ch)  /* upload failed, don't process user to user xfer */
-					return(false); 
 			} 
 		} 
 	}
-	if(dirnum==cfg.user_dir) {  /* Add files to XFER.IXT in INDX dir */
-		sprintf(str,"%sxfer.ixt",cfg.data_dir);
-		if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
-			errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_APPEND);
-			return(false); 
-		}
-		for(j=0;j<destusers;j++) {
-			for(i=1;i<=cfg.sys_nodes;i++) { /* Tell user, if online */
-				getnodedat(i,&node,0);
-				if(node.useron==destuser[j] && !(node.misc&NODE_POFF)
-					&& (node.status==NODE_INUSE || node.status==NODE_QUIET)) {
-					sprintf(str,text[UserToUserXferNodeMsg],cfg.node_num,useron.alias);
-					putnmsg(&cfg,i,str);
-					break; 
-				} 
-			}
-			if(i>cfg.sys_nodes) {   /* User not online */
-				sprintf(str,text[UserSentYouFile],useron.alias);
-				putsmsg(&cfg,destuser[j],str); 
-			}
-			sprintf(str,"%4.4u %12.12s %4.4u\r\n"
-				,destuser[j],f.name,useron.number);
-			write(file,str,strlen(str)); 
-		}
-		close(file); 
-	}
-	return(true);
+	smb_freefilemem(&f);
+	return result;
 }
 
 /****************************************************************************/
@@ -555,21 +460,29 @@ bool sbbs_t::bulkupload(uint dirnum)
 {
     char	str[MAX_PATH+1];
 	char	path[MAX_PATH+1];
-	char	spath[MAX_PATH+1];
-    file_t	f;
+	char	desc[LEN_FDESC + 1];
+	smb_t	smb;
+    file_t f;
 	DIR*	dir;
 	DIRENT*	dirent;
 
-	memset(&f,0,sizeof(file_t));
+	memset(&f,0,sizeof(f));
 	f.dir=dirnum;
-	f.altpath=altul;
 	bprintf(text[BulkUpload],cfg.lib[cfg.dir[dirnum]->lib]->sname,cfg.dir[dirnum]->sname);
-	strcpy(path,altul>0 && altul<=cfg.altpaths ? cfg.altpath[altul-1]
-		: cfg.dir[dirnum]->path);
+	SAFECOPY(path, cfg.dir[dirnum]->path);
+
+	int result = smb_open_dir(&cfg, &smb, dirnum);
+	if(result != SMB_SUCCESS) {
+		errormsg(WHERE, ERR_OPEN, smb.file, result, smb.last_error);
+		return false;
+	}
 	action=NODE_ULNG;
 	SYNC;
+	str_list_t list = loadfilenames(&smb, ALLFILES, /* time_t */0, FILE_SORT_NATURAL, NULL);
+	smb_close(&smb);
 	dir=opendir(path);
 	while(dir!=NULL && (dirent=readdir(dir))!=NULL && !msgabort()) {
+		char fname[SMB_FILEIDX_NAMELEN + 1];
 		SAFEPRINTF2(str,"%s%s",path,dirent->d_name);
 		if(isdir(str))
 			continue;
@@ -578,28 +491,26 @@ bool sbbs_t::bulkupload(uint dirnum)
 		if(getfattr(str)&(_A_HIDDEN|_A_SYSTEM))
 			continue;
 #endif
-#ifdef _WIN32
-		GetShortPathName(str,spath,sizeof(spath));
-#else
-		strcpy(spath,str);
-#endif
-		padfname(getfname(spath),str);
-
-		if(findfile(&cfg,f.dir,str)==0) {
-			f.misc=0;
-			strcpy(f.name,str);
-			f.cdt=(long)flength(spath);
-			bprintf(text[BulkUploadDescPrompt],f.name,f.cdt/1024);
-			getstr(f.desc,LEN_FDESC,K_LINE);
+		smb_fileidxname(dirent->d_name, fname, sizeof(fname));
+		if(strListFind(list, fname, /* case-sensitive: */FALSE) < 0) {
+			smb_freemsgmem(&f);
+			smb_hfield_str(&f, SMB_FILENAME, dirent->d_name);
+			uint32_t cdt = (uint32_t)flength(str);
+			smb_hfield_bin(&f, SMB_COST, cdt);
+			bprintf(text[BulkUploadDescPrompt], format_filename(f.name, fname, 12, /* pad: */FALSE), cdt/1024);
+			getstr(desc, LEN_FDESC, K_LINE);
 			if(sys_status&SS_ABORT)
 				break;
-			if(strcmp(f.desc,"-")==0)	/* don't add this file */
+			if(strcmp(desc,"-")==0)	/* don't add this file */
 				continue;
-			uploadfile(&f); 
+			smb_hfield_str(&f, SMB_FILEDESC, desc);
+			uploadfile(&f);
 		}
 	}
 	if(dir!=NULL)
 		closedir(dir);
+	strListFree(&list);
+	smb_freemsgmem(&f);
 	if(sys_status&SS_ABORT)
 		return(true);
 	return(false);
@@ -617,7 +528,7 @@ bool sbbs_t::recvfile(char *fname, char prot, bool autohang)
 	else {
 		xfer_prot_menu(XFER_UPLOAD);
 		mnemonics(text[ProtocolOrQuit]);
-		sprintf(keys,"%c",text[YNQP][2]);
+		SAFEPRINTF(keys,"%c",text[YNQP][2]);
 		for(i=0;i<cfg.total_prots;i++)
 			if(cfg.prot[i]->ulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client))
 				sprintf(keys+strlen(keys),"%c",cfg.prot[i]->mnemonic);
diff --git a/src/sbbs3/userdat.c b/src/sbbs3/userdat.c
index 98053a4bd9..ada3b2ded3 100644
--- a/src/sbbs3/userdat.c
+++ b/src/sbbs3/userdat.c
@@ -31,15 +31,15 @@
 #include "smblib.h"
 #include "getstats.h"
 #include "msgdate.h"
+#include "scfglib.h"
 
 #ifndef USHRT_MAX
 	#define USHRT_MAX ((unsigned short)~0)
 #endif
 
 /* convenient space-saving global variables */
-char* crlf="\r\n";
-char* nulstr="";
-
+static const char* crlf="\r\n";
+static const char* nulstr="";
 static const char* strIpFilterExemptConfigFile = "ipfilter_exempt.cfg";
 
 #define VALID_CFG(cfg)	(cfg!=NULL && cfg->size==sizeof(scfg_t))
@@ -683,7 +683,7 @@ char* username(scfg_t* cfg, int usernumber, char *name)
 /****************************************************************************/
 /* Puts 'name' into slot 'number' in user/name.dat							*/
 /****************************************************************************/
-int putusername(scfg_t* cfg, int number, char *name)
+int putusername(scfg_t* cfg, int number, const char *name)
 {
 	char str[256];
 	int file;
@@ -1576,46 +1576,6 @@ int getnodeclient(scfg_t* cfg, uint number, client_t* client, time_t* done)
 	return sock;
 }
 
-static int getdirnum(scfg_t* cfg, char* code)
-{
-	size_t i;
-
-	for(i=0;i<cfg->total_dirs;i++)
-		if(stricmp(cfg->dir[i]->code,code)==0)
-			return(i);
-	return(-1);
-}
-
-static int getlibnum(scfg_t* cfg, char* code)
-{
-	size_t i;
-
-	for(i=0;i<cfg->total_dirs;i++)
-		if(stricmp(cfg->dir[i]->code,code)==0)
-			return(cfg->dir[i]->lib);
-	return(-1);
-}
-
-static int getsubnum(scfg_t* cfg, char* code)
-{
-	size_t i;
-
-	for(i=0;i<cfg->total_subs;i++)
-		if(stricmp(cfg->sub[i]->code,code)==0)
-			return(i);
-	return(-1);
-}
-
-static int getgrpnum(scfg_t* cfg, char* code)
-{
-	size_t i;
-
-	for(i=0;i<cfg->total_subs;i++)
-		if(stricmp(cfg->sub[i]->code,code)==0)
-			return(cfg->sub[i]->grp);
-	return(-1);
-}
-
 static BOOL ar_exp(scfg_t* cfg, uchar **ptrptr, user_t* user, client_t* client)
 {
 	BOOL	result,not,or,equal;
@@ -2456,51 +2416,51 @@ BOOL user_sent_email(scfg_t* cfg, user_t* user, int count, BOOL feedback)
 	return(TRUE);
 }
 
-BOOL user_downloaded(scfg_t* cfg, user_t* user, int files, long bytes)
+BOOL user_downloaded(scfg_t* cfg, user_t* user, int files, off_t bytes)
 {
 	if(user==NULL)
 		return(FALSE);
 
 	user->dls=(ushort)adjustuserrec(cfg, user->number, U_DLS, 5, files);
-	user->dlb=adjustuserrec(cfg, user->number, U_DLB, 10, bytes);
+	user->dlb=adjustuserrec(cfg, user->number, U_DLB, 10, (long)bytes);
 
 	return(TRUE);
 }
 
 #ifdef SBBS
 BOOL user_downloaded_file(scfg_t* cfg, user_t* user, client_t* client,
-	uint dirnum, const char* filename, ulong bytes)
+	uint dirnum, const char* filename, off_t bytes)
 {
-	file_t f = {{0}};
+	file_t f;
 
-	f.dir = dirnum;
-	padfname(getfname(filename), f.name);
-	if(!getfileixb(cfg, &f) || !getfiledat(cfg, &f))
+	if(!loadfile(cfg, dirnum, filename, &f, file_detail_normal))
 		return FALSE;
 
 	if(!bytes)
-		bytes = f.size;
+		bytes = getfilesize(cfg, &f);
 
-	f.timesdled++;
-	f.datedled=time32(NULL);
-	if(!putfiledat(cfg, &f) || !putfileixb(cfg, &f))
+	f.hdr.times_downloaded++;
+	f.hdr.last_downloaded = time32(NULL);
+	if(!updatefile(cfg, &f)) {
+		smb_freefilemem(&f);
 		return FALSE;
+	}
 
 	/**************************/
 	/* Update Uploader's Info */
 	/**************************/
 	user_t uploader = {0};
-	uploader.number=matchuser(cfg, f.uler, TRUE /*sysop_alias*/);
+	uploader.number=matchuser(cfg, f.from, TRUE /*sysop_alias*/);
 	if(uploader.number
 		&& uploader.number != user->number 
 		&& getuserdat(cfg, &uploader) == 0
-		&& uploader.firston < f.dateuled) {
-		ulong l = f.cdt;
-		if(!(cfg->dir[f.dir]->misc&DIR_CDTDL))	/* Don't give credits on d/l */
+		&& (uint32_t)uploader.firston < f.hdr.when_imported.time) {
+		ulong l = (ulong)f.cost;
+		if(!(cfg->dir[dirnum]->misc&DIR_CDTDL))	/* Don't give credits on d/l */
 			l=0;
-		ulong mod=(ulong)(l*(cfg->dir[f.dir]->dn_pct/100.0));
+		ulong mod=(ulong)(l*(cfg->dir[dirnum]->dn_pct/100.0));
 		adjustuserrec(cfg, uploader.number, U_CDT, 10, mod);
-		if(cfg->text != NULL && !(cfg->dir[f.dir]->misc&DIR_QUIET)) {
+		if(cfg->text != NULL && !(cfg->dir[dirnum]->misc&DIR_QUIET)) {
 			char str[256];
 			char tmp[128];
 			char prefix[128]="";
@@ -2513,7 +2473,7 @@ BOOL user_downloaded_file(scfg_t* cfg, user_t* user, client_t* client,
 					SAFEPRINTF2(username,"%s [%s]", user->alias, client->addr);
 			} else
 				SAFECOPY(username, user->alias);
-			if(strcmp(cfg->dir[f.dir]->code, "TEMP") == 0 || bytes < (ulong)f.size)
+			if(strcmp(cfg->dir[dirnum]->code, "TEMP") == 0 || bytes < (ulong)f.size)
 				SAFECOPY(prefix, cfg->text[Partially]);
 			if(client != NULL) {
 				SAFECAT(prefix, client->protocol);
@@ -2531,23 +2491,24 @@ BOOL user_downloaded_file(scfg_t* cfg, user_t* user, client_t* client,
 	/* Update Downloader's Info */
 	/****************************/
 	user_downloaded(cfg, user, /* files: */1, bytes);
-	if(!is_download_free(cfg, f.dir, user, client))
-		subtract_cdt(cfg, user, f.cdt);
+	if(!is_download_free(cfg, dirnum, user, client))
+		subtract_cdt(cfg, user, (long)f.cost);
 
-	if(!(cfg->dir[f.dir]->misc&DIR_NOSTAT))
-		inc_sys_download_stats(cfg, /* files: */1, bytes);
+	if(!(cfg->dir[dirnum]->misc&DIR_NOSTAT))
+		inc_sys_download_stats(cfg, /* files: */1, (ulong)bytes);
 
+	smb_freefilemem(&f);
 	return TRUE;
 }
 #endif
 
-BOOL user_uploaded(scfg_t* cfg, user_t* user, int files, long bytes)
+BOOL user_uploaded(scfg_t* cfg, user_t* user, int files, off_t bytes)
 {
 	if(user==NULL)
 		return(FALSE);
 
 	user->uls=(ushort)adjustuserrec(cfg, user->number, U_ULS, 5, files);
-	user->ulb=adjustuserrec(cfg, user->number, U_ULB, 10, bytes);
+	user->ulb=adjustuserrec(cfg, user->number, U_ULB, 10, (long)bytes);
 
 	return(TRUE);
 }
@@ -3172,7 +3133,7 @@ BOOL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* ho
 	char	exempt[MAX_PATH+1];
 	char	tstr[64];
     FILE*	fp;
-    time32_t now=time32(NULL);
+    time_t	now = time(NULL);
 
 	if(ip_addr==NULL)
 		return(FALSE);
@@ -3196,7 +3157,7 @@ BOOL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* ho
     fprintf(fp, "\n; %s %s ", prot, reason);
 	if(username != NULL)
 		fprintf(fp, "by %s ", username);
-    fprintf(fp,"on %s\n", timestr(cfg, now, tstr));
+    fprintf(fp,"on %.24s\n", ctime_r(&now, tstr));
 
 	if(host!=NULL)
 		fprintf(fp,"; Hostname: %s\n",host);
@@ -3599,6 +3560,14 @@ BOOL putmsgptrs(scfg_t* cfg, user_t* user, subscan_t* subscan)
 	return result;
 }
 
+BOOL newmsgs(smb_t* smb, time_t t)
+{
+	char index_fname[MAX_PATH + 1];
+
+	SAFEPRINTF(index_fname, "%s.sid", smb->file);
+	return fdate(index_fname) >= t;
+}
+
 /****************************************************************************/
 /* Initialize new-msg-scan pointers (e.g. for new users)					*/
 /* If 'days' is specified as 0, just set pointer to last message (faster)	*/
diff --git a/src/sbbs3/userdat.h b/src/sbbs3/userdat.h
index 4014af73a0..2f47bfadbd 100644
--- a/src/sbbs3/userdat.h
+++ b/src/sbbs3/userdat.h
@@ -33,9 +33,6 @@
 extern "C" {
 #endif
 
-extern char* crlf;
-extern char* nulstr;
-
 DLLEXPORT int	openuserdat(scfg_t*, BOOL for_modify);
 DLLEXPORT int	closeuserdat(int);
 DLLEXPORT int	readuserdat(scfg_t*, unsigned user_number, char* userdat, int infile);
@@ -47,7 +44,7 @@ DLLEXPORT int	newuserdat(scfg_t*, user_t*);	/* Create new userdat in user file *
 DLLEXPORT uint	matchuser(scfg_t*, const char *str, BOOL sysop_alias); /* Checks for a username match */
 DLLEXPORT BOOL	matchusername(scfg_t*, const char* name, const char* compare);
 DLLEXPORT char* alias(scfg_t*, const char* name, char* buf);
-DLLEXPORT int	putusername(scfg_t*, int number, char * name);
+DLLEXPORT int	putusername(scfg_t*, int number, const char* name);
 DLLEXPORT uint	total_users(scfg_t*);
 DLLEXPORT uint	lastuser(scfg_t*);
 DLLEXPORT BOOL	del_lastuser(scfg_t*);
@@ -110,19 +107,19 @@ DLLEXPORT BOOL	user_set_property(scfg_t*, unsigned user_number, const char* sect
 DLLEXPORT BOOL	user_set_time_property(scfg_t*, unsigned user_number, const char* section, const char* key, time_t);
 
 /* New-message-scan pointer functions: */
+DLLEXPORT BOOL	newmsgs(smb_t*, time_t);
 DLLEXPORT BOOL	getmsgptrs(scfg_t*, user_t*, subscan_t*, void (*progress)(void*, int, int), void* cbdata);
 DLLEXPORT BOOL	putmsgptrs(scfg_t*, user_t*, subscan_t*);
 DLLEXPORT BOOL	fixmsgptrs(scfg_t*, subscan_t*);
 DLLEXPORT BOOL	initmsgptrs(scfg_t*, subscan_t*, unsigned days, void (*progress)(void*, int, int), void* cbdata);
 
-
 /* New atomic numeric user field adjustment functions: */
 DLLEXPORT BOOL	user_posted_msg(scfg_t*, user_t*, int count);
 DLLEXPORT BOOL	user_sent_email(scfg_t*, user_t*, int count, BOOL feedback);
-DLLEXPORT BOOL	user_downloaded(scfg_t*, user_t*, int files, long bytes);
-DLLEXPORT BOOL	user_downloaded_file(scfg_t*, user_t*, client_t*, uint dirnum, const char* filename, ulong bytes);
+DLLEXPORT BOOL	user_downloaded(scfg_t*, user_t*, int files, off_t bytes);
+DLLEXPORT BOOL	user_downloaded_file(scfg_t*, user_t*, client_t*, uint dirnum, const char* filename, off_t bytes);
 
-DLLEXPORT BOOL	user_uploaded(scfg_t*, user_t*, int files, long bytes);
+DLLEXPORT BOOL	user_uploaded(scfg_t*, user_t*, int files, off_t bytes);
 DLLEXPORT BOOL	user_adjust_credits(scfg_t*, user_t*, long amount);
 DLLEXPORT BOOL	user_adjust_minutes(scfg_t*, user_t*, long amount);
 
diff --git a/src/sbbs3/useredit.cpp b/src/sbbs3/useredit.cpp
index 07f7176d08..77a27c4d9f 100644
--- a/src/sbbs3/useredit.cpp
+++ b/src/sbbs3/useredit.cpp
@@ -1,7 +1,5 @@
 /* Synchronet online sysop user editor */
 
-/* $Id: useredit.cpp,v 1.75 2020/08/04 04:26:03 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -15,21 +13,9 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -39,6 +25,7 @@
 
 #include "sbbs.h"
 #include "petdefs.h"
+#include "filedat.h"
 
 #define SEARCH_TXT 0
 #define SEARCH_ARS 1
@@ -1032,11 +1019,20 @@ void sbbs_t::maindflts(user_t* user)
 					putuserrec(&cfg,user->number,U_SHELL,8,cfg.shell[i]->code);
 				break;
 			case 'A':
-				for(i=0;i<cfg.total_fcomps;i++)
-					uselect(1,i,text[ArchiveTypeHeading],cfg.fcomp[i]->ext,cfg.fcomp[i]->ar);
+			{
+				str_list_t ext_list = strListDup((str_list_t)supported_archive_formats);
+				for(i=0; i < cfg.total_fcomps; i++) {
+					if(strListFind(ext_list, cfg.fcomp[i]->ext, /* case-sensitive */FALSE) < 0
+						&& chk_ar(cfg.fcomp[i]->ar, &useron, &client))
+						strListPush(&ext_list, cfg.fcomp[i]->ext);
+				}
+				for(i=0; ext_list[i] != NULL; i++)
+					uselect(1,i,text[ArchiveTypeHeading], ext_list[i], NULL);
 				if((i=uselect(0,0,0,0,0))>=0)
-					putuserrec(&cfg,user->number,U_TMPEXT,3,cfg.fcomp[i]->ext);
+					putuserrec(&cfg,user->number,U_TMPEXT,3,ext_list[i]);
+				strListFree(&ext_list);
 				break;
+			}
 			case 'L':
 				bputs(text[HowManyColumns]);
 				if((i = getnum(TERM_COLS_MAX)) < 0)
diff --git a/src/sbbs3/v4upgrade.c b/src/sbbs3/v4upgrade.c
index 05309ff23d..325ce68a67 100644
--- a/src/sbbs3/v4upgrade.c
+++ b/src/sbbs3/v4upgrade.c
@@ -33,6 +33,7 @@
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
+#include <stdbool.h>
 #include "sbbs.h"
 #include "sbbs4defs.h"
 #include "ini_file.h"
@@ -112,6 +113,7 @@ BOOL upgrade_users(void)
 	int		ret;
 	size_t	len;
 	user_t	user;
+	int		userdat;
 
 	printf("Upgrading user database...     ");
 
@@ -123,15 +125,21 @@ BOOL upgrade_users(void)
 		return(FALSE);
 	}
 
+	if((userdat = openuserdat(&scfg, /* for_modify: */FALSE)) < 0) {
+		perror("user.dat");
+		return FALSE;
+	}
+
 	fprintf(out,"%-*.*s\r\n",USER_REC_LEN,USER_REC_LEN,tabLineCreator(user_dat_columns));
 
 	total=lastuser(&scfg);
 	for(i=1;i<=total;i++) {
 		printf("\b\b\b\b\b%5u",total-i);
 		memset(&user,0,sizeof(user));
-		user.number=i;
-		if((ret=getuserdat(&scfg,&user))!=0) {
+		user.number = i;
+		if((ret=fgetuserdat(&scfg, &user, userdat))!=0) {
 			printf("\nError %d reading user.dat\n",ret);
+			closeuserdat(userdat);
 			return(FALSE);
 		}
 		/******************************************/
@@ -244,7 +252,7 @@ BOOL upgrade_users(void)
 		len+=sprintf(rec+len,"%u\t%c\t%s\t%s\t%s\t%s\t%s\t%s\t"
 			,user.rows
 			,user.prot
-			,user.xedit ? scfg.xedit[user.xedit]->code : ""
+			,user.xedit && user.xedit <= scfg.total_xedits ? scfg.xedit[user.xedit-1]->code : ""
 			,scfg.shell[user.shell]->code
 			,user.tmpext
 			,user.cursub
@@ -256,10 +264,12 @@ BOOL upgrade_users(void)
 		if((ret=fprintf(out,"%-*.*s\r\n",USER_REC_LEN,USER_REC_LEN,rec))!=USER_REC_LINE_LEN) {
 			printf("!Error %d (errno: %d) writing %u bytes to user.tab\n"
 				,ret, errno, USER_REC_LINE_LEN);
+			closeuserdat(userdat);
 			return(FALSE);
 		}
 	}
 	fclose(out);
+	closeuserdat(userdat);
 
 	printf("\n\tdata/user/user.dat -> %s (%u users)\n", outpath,total);
 
@@ -267,29 +277,29 @@ BOOL upgrade_users(void)
 }
 
 typedef struct {
-	time_t	time;
-	ulong	ltoday;
-	ulong	ttoday;
-	ulong	uls;
-	ulong	ulb;
-	ulong	dls;
-	ulong	dlb;
-	ulong	ptoday;
-	ulong	etoday;
-	ulong	ftoday;
+	time32_t	time;
+	uint32_t	ltoday;
+	uint32_t	ttoday;
+	uint32_t	uls;
+	uint32_t	ulb;
+	uint32_t	dls;
+	uint32_t	dlb;
+	uint32_t	ptoday;
+	uint32_t	etoday;
+	uint32_t	ftoday;
 } csts_t;
 
 BOOL upgrade_stats(void)
 {
-	char	inpath[MAX_PATH+1];
-	char	outpath[MAX_PATH+1];
-	BOOL	success;
-	ulong	count;
+	char		inpath[MAX_PATH+1];
+	char		outpath[MAX_PATH+1];
+	BOOL		success;
+	ulong		count;
 	time32_t	t;
-	stats_t	stats;
-	FILE*	in;
-	FILE*	out;
-	csts_t	csts;
+	stats_t		stats;
+	FILE*		in;
+	FILE*		out;
+	csts_t		csts;
 	str_list_t	list;
 
 	printf("Upgrading statistics data...\n");
@@ -317,7 +327,7 @@ BOOL upgrade_stats(void)
 		return(FALSE);
 	}
 
-	iniSetDateTime(&list,	ROOT_SECTION	,"TimeStamp"	,TRUE, t		,NULL);
+	iniSetDateTime(&list,	ROOT_SECTION	,"TimeStamp"	,/* include time: */TRUE, t, NULL);
 	iniSetInteger(&list,	ROOT_SECTION	,"Logons"		,stats.logons	,NULL);
 	iniSetInteger(&list,	ROOT_SECTION	,"LogonsToday"	,stats.ltoday	,NULL);
 	iniSetInteger(&list,	ROOT_SECTION	,"Timeon"		,stats.timeon	,NULL);
@@ -424,11 +434,12 @@ BOOL upgrade_event_data(void)
 	for(i=0;i<scfg.total_events;i++) {
 		t=0;
 		fread(&t,1,sizeof(t),in);
-		iniSetHexInt(&list, "Events", scfg.event[i]->code, t, NULL);
+		iniSetDateTime(&list, "Events", scfg.event[i]->code, /* include time: */TRUE, t, NULL);
 	}
 	t=0;
 	fread(&t,1,sizeof(t),in);
-	iniSetHexInt(&list,ROOT_SECTION,"QWKPrePack",t,NULL);
+	if(t != 0)
+		iniSetDateTime(&list,ROOT_SECTION,"QWKPrePack", /* include time: */TRUE,t,NULL);
 	fclose(in);
 
 	printf("-> %s (%u timed events)\n", outpath, i);
@@ -443,7 +454,7 @@ BOOL upgrade_event_data(void)
 		for(i=0;i<scfg.total_qhubs;i++) {
 			t=0;
 			fread(&t,1,sizeof(t),in);
-			iniSetHexInt(&list,"QWKNetworkHubs",scfg.qhub[i]->id,t,NULL);
+			iniSetDateTime(&list,"QWKNetworkHubs",scfg.qhub[i]->id, /* include time: */TRUE,t,NULL);
 		}
 		fclose(in);
 	}
@@ -931,107 +942,13 @@ BOOL upgrade_ftp_aliases(void)
 	return(success);
 }
 
-BOOL upgrade_socket_options(void)
-{
-	char*	p;
-	char*	key;
-	char*	val;
-	char*	section;
-	char	inpath[MAX_PATH+1];
-	char	outpath[MAX_PATH+1];
-	FILE*	in;
-	FILE*	out;
-	BOOL	success;
-	size_t	i;
-	size_t	total;
-	str_list_t	inlist;
-	str_list_t	outlist;
-
-	style.section_separator = "";
-	iniSetDefaultStyle(style);
-
-	SAFEPRINTF(inpath,"%ssockopts.cfg",scfg.ctrl_dir);
-	SAFEPRINTF(outpath,"%ssockopts.ini",scfg.ctrl_dir);
-
-	if(!fexistcase(inpath))
-		return(TRUE);
-
-	printf("Upgrading Socket Options...\n");
-
-	if(!overwrite(outpath))
-		return(TRUE);
-	if((out=fopen(outpath,"w"))==NULL) {
-		perror(outpath);
-		return(FALSE);
-	}
-
-	if((outlist = strListInit())==NULL) {
-		printf("!malloc failure\n");
-		return(FALSE);
-	}
-	printf("\t%s ",inpath);
-	if((in=fopen(inpath,"r"))==NULL) {
-		perror("open failure");
-		return(FALSE);
-	}
-
-	if((inlist = strListReadFile(in,NULL,4096))==NULL) {
-		printf("!failure reading %s\n",inpath);
-		return(FALSE);
-	}
-
-	total=0;
-	for(i=0;inlist[i]!=NULL;i++) {
-		p=truncsp(inlist[i]);
-		SKIP_WHITESPACE(p);
-		if(*p==';') {
-			strListPush(&outlist,p);
-			continue;
-		} else if(*p==0)
-			continue;
-		key=p;
-		FIND_WHITESPACE(p);
-		if(*p==0)
-			continue;
-		*(p++)=0;
-		SKIP_WHITESPACE(p);
-		val=p;
-		section=ROOT_SECTION;
-		if(!stricmp(key,"tcp_nodelay"))
-			section="telnet|rlogin";
-		else if(!stricmp(key,"keepalive"))
-			section="tcp";
-		iniSetString(&outlist,section,key,val,NULL);
-		total++;
-	}
-
-	printf("-> %s (%u Socket Options)\n", outpath, total);
-	fclose(in);
-	strListFree(&inlist);
-
-	success=iniWriteFile(out, outlist);
-
-	fclose(out);
-
-	if(!success) {
-		printf("!iniWriteFile failure\n");
-		return(FALSE);
-	}
-
-	strListFree(&outlist);
-
-	return(success);
-}
-
-
-
 #define upg_iniSetString(list,section,key,val) \
 		if(*val) iniSetString(list,section,key,val,NULL)
 
 #define upg_iniSetInteger(list,section,key,val) \
 		if(val) iniSetInteger(list,section,key,val,NULL)
 
-BOOL upgrade_msg_areas(void)
+BOOL upgrade_msg_area_cfg(void)
 {
 	char	str[128];
 	char	outpath[MAX_PATH+1];
@@ -1071,9 +988,8 @@ BOOL upgrade_msg_areas(void)
 		upg_iniSetString(&outlist,str,"CodePrefix",scfg.grp[i]->code_prefix);
 	}
 	for(i=0; i<scfg.total_subs; i++) {
-		sprintf(str,"%s",scfg.sub[i]->code_suffix);
+		sprintf(str,"Sub:%s:%s", scfg.grp[scfg.sub[i]->grp]->sname, scfg.sub[i]->code_suffix);
 		iniAppendSection(&outlist,str,NULL);
-		upg_iniSetString(&outlist,str,"Group",scfg.grp[scfg.sub[i]->grp]->sname);
 		upg_iniSetString(&outlist,str,"Name",scfg.sub[i]->sname);
 		upg_iniSetString(&outlist,str,"Newsgroup",scfg.sub[i]->newsgroup);
 		upg_iniSetString(&outlist,str,"QwkName",scfg.sub[i]->qwkname);
@@ -1115,6 +1031,136 @@ BOOL upgrade_msg_areas(void)
 	return(success);
 }
 
+int file_uldate_compare(const void* v1, const void* v2)
+{
+	file_t* f1 = (file_t*)v1;
+	file_t* f2 = (file_t*)v2;
+
+	return f1->dateuled - f2->dateuled;
+}
+
+bool upgrade_file_areas(void)
+{
+	int result;
+	ulong total_files = 0;
+	time_t start = time(NULL);
+
+	printf("Upgrading File areas...\n");
+
+	for(int i = 0; i < scfg.total_dirs; i++) {
+		smb_t smb;
+
+		SAFEPRINTF2(smb.file, "%s%s", scfg.dir[i]->data_dir, scfg.dir[i]->code);
+		if((result = smb_open(&smb)) != SMB_SUCCESS) {
+			fprintf(stderr, "Error %d (%s) opening %s\n", result, smb.last_error, smb.file);
+			return false;
+		}
+		smb.status.attr = SMB_FILE_DIRECTORY|SMB_NOHASH;
+		smb.status.max_age = scfg.dir[i]->maxage;
+		smb.status.max_msgs = scfg.dir[i]->maxfiles;
+		if((result = smb_create(&smb)) != SMB_SUCCESS)
+			return false;
+
+		char str[MAX_PATH+1];
+		int file;
+		int extfile = openextdesc(&scfg, i);
+
+		sprintf(str,"%s%s.ixb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
+		if((file=open(str,O_RDONLY|O_BINARY))==-1)
+			continue;
+		long l=filelength(file);
+		if(!l) {
+			close(file);
+			continue;
+		}
+		uchar* ixbbuf;
+		if((ixbbuf=(uchar *)malloc(l))==NULL) {
+			close(file);
+			printf("\7ERR_ALLOC %s %lu\n",str,l);
+			continue;
+		}
+		if(read(file,ixbbuf,l)!=(int)l) {
+			close(file);
+			printf("\7ERR_READ %s %lu\n",str,l);
+			free(ixbbuf);
+			continue;
+		}
+		close(file);
+		size_t file_count = l / F_IXBSIZE;
+		file_t* filelist = malloc(sizeof(file_t) * file_count);
+		memset(filelist, 0, sizeof(file_t) * file_count);
+		file_t* f = filelist;
+		long m=0L;
+		while(m<l) {
+			int j;
+			f->dir = i;
+			for(j=0;j<12 && m<l;j++)
+				if(j==8)
+					f->name[j]=ixbbuf[m]>' ' ? '.' : ' ';
+				else
+					f->name[j]=ixbbuf[m++]; /* Turns FILENAMEEXT into FILENAME.EXT */
+			f->name[j]=0;
+			f->datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
+			f->dateuled=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
+				|((long)ixbbuf[m+6]<<24));
+			f->datedled =(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)|((long)ixbbuf[m+9]<<16)
+				|((long)ixbbuf[m+10]<<24));
+			m+=11;
+			f++;
+		};
+
+		/* SMB index is sorted by import (upload) time */
+		qsort(filelist, file_count, sizeof(*filelist), file_uldate_compare);
+
+		for(size_t fi = 0; fi < file_count; fi++) {
+			f = &filelist[fi];
+			if(!getfiledat(&scfg, f)) {
+				fprintf(stderr, "Error getting file data for %s %s\n", scfg.dir[i]->code, f->name);
+				continue;
+			}
+			char fpath[MAX_PATH+1];
+			getfilepath(&scfg, f, fpath);
+			smbfile_t file;
+			memset(&file, 0, sizeof(file));
+			file.hdr.when_written.time = (time32_t)fdate(fpath);
+			file.hdr.when_imported.time = f->dateuled;
+			file.hdr.last_downloaded = f->datedled;
+			file.hdr.times_downloaded = f->timesdled;
+			file.hdr.altpath = f->altpath;
+			smb_hfield_str(&file, SMB_FILENAME, getfname(fpath));
+			smb_hfield_str(&file, SMB_FILEDESC, f->desc);
+			smb_hfield_str(&file, SENDER, f->uler);
+			smb_hfield_bin(&file, SMB_COST, f->cdt);
+			if(f->misc&FM_ANON)
+				file.hdr.attr |= MSG_ANONYMOUS;
+			{
+				const char* body = NULL;
+				char extdesc[F_EXBSIZE+1] = {0};
+				if(f->misc&FM_EXTDESC) {
+					fgetextdesc(&scfg, i, f->datoffset, extdesc, extfile);
+					truncsp(extdesc);
+					body = extdesc;
+				}
+				result = smb_addfile(&smb, &file, SMB_FASTALLOC, body);
+			}
+			if(result != SMB_SUCCESS) {
+				fprintf(stderr, "Error %d (%s) adding file to %s\n", result, smb.last_error, smb.file);
+			} else {
+				total_files++;
+				time_t diff = time(NULL) - start;
+				printf("\r%-16s (%-5u areas remain) %u files imported (%u files/second)"
+					, scfg.dir[i]->code, scfg.total_dirs - (i + 1), total_files, diff ? total_files / diff : total_files);
+			}
+		}
+		free(filelist);
+		smb_close(&smb);
+		closeextdesc(extfile);
+		free(ixbbuf);
+	}
+	printf("\r%u files imported in %u directories%40s\n", total_files, scfg.total_dirs,"");
+
+	return true;
+}
 
 char *usage="\nusage: v4upgrade [ctrl_dir]\n";
 
@@ -1139,7 +1185,7 @@ int main(int argc, char** argv)
 	if(p==NULL) {
 		printf("\nSBBSCTRL environment variable not set.\n");
 		printf("\nExample: SET SBBSCTRL=/sbbs/ctrl\n");
-		exit(1); 
+		return EXIT_FAILURE + __COUNTER__;
 	}
 
 	memset(&scfg,0,sizeof(scfg));
@@ -1152,61 +1198,63 @@ int main(int argc, char** argv)
 	printf("\nLoading configuration files from %s\n",scfg.ctrl_dir);
 	if(!load_cfg(&scfg,NULL,TRUE,error)) {
 		fprintf(stderr,"!ERROR loading configuration files: %s\n",error);
-		exit(1);
+		return EXIT_FAILURE + __COUNTER__;
 	}
 
 	iniSetDefaultStyle(style);
 
 	if(!upgrade_users())
-		return(1);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_stats())
-		return(2);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_event_data())
-		return(3);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_filters())
-		return(4);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_list("Twits", "twitlist.cfg", "twitlist.ini", TRUE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_list("RLogin allow", "rlogin.cfg", "rlogin.ini", TRUE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_list("E-Mail aliases", "alias.cfg", "alias.ini", FALSE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 	
 	if(!upgrade_list("E-Mail domains", "domains.cfg", "domains.ini", TRUE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_list("Allowed mail relayers", "relay.cfg", "relay.ini", TRUE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_list("SPAM bait addresses", "spambait.cfg", "spambait.ini", TRUE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 
+#if 0 /* temporary disable for testing purposes only */
 	if(!upgrade_list("Blocked spammers", "spamblock.cfg", "spamblock.ini", TRUE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
+#endif
 
 	if(!upgrade_list("DNS black-lists", "dns_blacklist.cfg", "dns_blacklist.ini", TRUE, "notice"))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_list("DNS black-list exemptions", "dnsbl_exempt.cfg", "dnsbl_exempt.ini", TRUE, NULL))
-		return(5);
+		return EXIT_FAILURE + __COUNTER__;
 
 	if(!upgrade_ftp_aliases())
-		return(-1);
-
-	if(!upgrade_socket_options())
-		return(-1);
+		return EXIT_FAILURE + __COUNTER__;
 
 	/* attr.cfg */
 
-	if(!upgrade_msg_areas())
-		return(-1);
+	if(!upgrade_msg_area_cfg())
+		return EXIT_FAILURE + __COUNTER__;
+
+	if(!upgrade_file_areas())
+		return EXIT_FAILURE + __COUNTER__;
 
 	printf("Upgrade successful.\n");
-    return(0);
+    return EXIT_SUCCESS;
 }
diff --git a/src/sbbs3/viewfile.cpp b/src/sbbs3/viewfile.cpp
index 79f930b824..b76ef3ff4d 100644
--- a/src/sbbs3/viewfile.cpp
+++ b/src/sbbs3/viewfile.cpp
@@ -1,9 +1,5 @@
-/* viewfile.cpp */
-
 /* Synchronet file contents display routines */
 
-/* $Id: viewfile.cpp,v 1.12 2020/05/11 08:57:19 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,47 +13,38 @@
  * See the GNU General Public License for more details: gpl.txt or			*
  * http://www.fsf.org/copyleft/gpl.html										*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include "sbbs.h"
+#include "filedat.h"
 
 /****************************************************************************/
 /* Views file with:                                                         */
 /* (B)atch download, (V)iew file (E)xtended info, (Q)uit, or [Next]:        */
 /* call with ext=1 for default to extended info, or 0 for file view         */
-/* Returns -1 for Batch, 1 for Next, or 0 for Quit                          */
+/* Returns -1 for Batch, 1 for Next, -2 for Previous, or 0 for Quit         */
 /****************************************************************************/
-int sbbs_t::viewfile(file_t* f, int ext)
+int sbbs_t::viewfile(file_t* f, bool ext)
 {
 	char	ch,str[256];
-	char 	tmp[512];
+	char	fname[13];	/* This is one of the only 8.3 filename formats left! (used for display purposes only) */
+	format_filename(f->name, fname, sizeof(fname)-1, /* pad: */FALSE);
 
 	curdirnum=f->dir;	/* for ARS */
 	while(online) {
+		sys_status &= ~SS_ABORT;
 		if(ext)
-			fileinfo(f);
+			showfileinfo(f);
 		else
 			viewfilecontents(f);
 		ASYNC;
-		sprintf(str,text[FileInfoPrompt],unpadfname(f->name,tmp));
+		SAFEPRINTF(str, text[FileInfoPrompt], fname);
 		mnemonics(str);
-		ch=(char)getkeys("BEVQN\r",0);
+		ch=(char)getkeys("BEVQPN\b-\r",0);
 		if(ch=='Q' || sys_status&SS_ABORT)
 			return(0);
 		switch(ch) {
@@ -71,6 +58,10 @@ int sbbs_t::viewfile(file_t* f, int ext)
 			case 'V':
 				ext=0;
 				continue;
+			case 'P':
+			case '\b':
+			case '-':
+				return -2;
 			case 'N':
 			case CR:
 				return(1); 
@@ -85,28 +76,31 @@ int sbbs_t::viewfile(file_t* f, int ext)
 /*****************************************************************************/
 void sbbs_t::viewfiles(uint dirnum, char *fspec)
 {
+	char	tmp[512];
     char	viewcmd[256];
-	char 	tmp[512];
     int		i;
 
 	curdirnum=dirnum;	/* for ARS */
-	sprintf(viewcmd,"%s%s",cfg.dir[dirnum]->path,fspec);
+	SAFEPRINTF2(viewcmd,"%s%s",cfg.dir[dirnum]->path,fspec);
 	if(!fexist(viewcmd)) {
 		bputs(text[FileNotFound]);
 		return; 
 	}
-	padfname(fspec,tmp);
-	truncsp(tmp);
+	char* file_ext = getfext(fspec);
+	if(file_ext == NULL) {
+		bprintf(text[NonviewableFile], fspec);
+		return; 
+	}
 	for(i=0;i<cfg.total_fviews;i++)
-		if(!stricmp(tmp+9,cfg.fview[i]->ext) && chk_ar(cfg.fview[i]->ar,&useron,&client)) {
-			strcpy(viewcmd,cfg.fview[i]->cmd);
+		if(!stricmp(file_ext + 1, cfg.fview[i]->ext) && chk_ar(cfg.fview[i]->ar,&useron,&client)) {
+			SAFECOPY(viewcmd,cfg.fview[i]->cmd);
 			break; 
 		}
 	if(i==cfg.total_fviews) {
-		bprintf(text[NonviewableFile],tmp+9);
+		bprintf(text[NonviewableFile], file_ext);
 		return; 
 	}
-	sprintf(tmp,"%s%s",cfg.dir[dirnum]->path,fspec);
+	SAFEPRINTF2(tmp, "%s%s", cfg.dir[dirnum]->path, fspec);
 	if((i=external(cmdstr(viewcmd,tmp,tmp,NULL),EX_STDIO|EX_SH))!=0)
 		errormsg(WHERE,ERR_EXEC,viewcmd,i);    /* must have EX_SH to ^C */
 }
@@ -121,9 +115,8 @@ void sbbs_t::viewfilecontents(file_t* f)
 	int		i;
 
 	getfilepath(&cfg, f, path);
-
-	if(f->size<=0L) {
-		bprintf(text[FileDoesNotExist],path);
+	if(getfilesize(&cfg, f) < 1) {
+		bprintf(text[FileDoesNotExist], path);
 		return; 
 	}
 	if((ext=getfext(path))!=NULL) {
@@ -131,7 +124,7 @@ void sbbs_t::viewfilecontents(file_t* f)
 		for(i=0;i<cfg.total_fviews;i++) {
 			if(!stricmp(ext,cfg.fview[i]->ext)
 				&& chk_ar(cfg.fview[i]->ar,&useron,&client)) {
-				strcpy(cmd,cfg.fview[i]->cmd);
+				SAFECOPY(cmd,cfg.fview[i]->cmd);
 				break; 
 			} 
 		}
diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c
index bc52448bc9..2329ab854d 100644
--- a/src/sbbs3/websrvr.c
+++ b/src/sbbs3/websrvr.c
@@ -65,7 +65,8 @@
 #include "xpprintf.h"
 #include "ssl.h"
 #include "fastcgi.h"
-#include "ver.h"
+#include "git_branch.h"
+#include "git_hash.h"
 
 static const char*	server_name="Synchronet Web Server";
 static const char*	newline="\r\n";
@@ -212,8 +213,8 @@ typedef struct  {
 	BOOL		finished;				/* Done processing request. */
 	BOOL		read_chunked;
 	BOOL		write_chunked;
-	long		range_start;
-	long		range_end;
+	off_t		range_start;
+	off_t		range_end;
 	BOOL		accept_ranges;
 	time_t		if_range;
 	BOOL		path_info_index;
@@ -1430,13 +1431,13 @@ static BOOL send_headers(http_session_t *session, const char *status, int chunke
 	return (ret);
 }
 
-static off_t sock_sendfile(http_session_t *session,char *path,unsigned long start, unsigned long end)
+static off_t sock_sendfile(http_session_t *session,char *path, off_t start, off_t end)
 {
 	int		file;
 	off_t	ret=0;
 	ssize_t	i;
 	char	buf[OUTBUF_LEN];		/* Input buffer */
-	unsigned long		remain;
+	uint64_t remain;
 
 	if(startup->options&WEB_OPT_DEBUG_TX)
 		lprintf(LOG_DEBUG,"%04d Sending %s",session->socket,path);
@@ -1454,7 +1455,7 @@ static off_t sock_sendfile(http_session_t *session,char *path,unsigned long star
 		else {
 			remain=-1L;
 		}
-		while((i=read(file, buf, remain>sizeof(buf)?sizeof(buf):remain))>0) {
+		while((i=read(file, buf, (size_t)(remain>sizeof(buf)?sizeof(buf):remain)))>0) {
 			if(writebuf(session,buf,i)!=i) {
 				lprintf(LOG_WARNING,"%04d !ERROR sending %s",session->socket,path);
 				close(file);
@@ -1737,7 +1738,7 @@ static BOOL digest_authentication(http_session_t* session, int auth_allowed, use
 	MD5_digest(&ctx, ":", 1);
 	MD5_digest(&ctx, thisuser.pass, strlen(thisuser.pass));
 	MD5_close(&ctx, digest);
-	MD5_hex((BYTE*)ha1, digest);
+	MD5_hex(ha1, digest);
 
 	/* H(A1)l */
 	pass=strdup(thisuser.pass);
@@ -1749,7 +1750,7 @@ static BOOL digest_authentication(http_session_t* session, int auth_allowed, use
 	MD5_digest(&ctx, ":", 1);
 	MD5_digest(&ctx, pass, strlen(pass));
 	MD5_close(&ctx, digest);
-	MD5_hex((BYTE*)ha1l, digest);
+	MD5_hex(ha1l, digest);
 
 	/* H(A1)u */
 	strupr(pass);
@@ -1760,7 +1761,7 @@ static BOOL digest_authentication(http_session_t* session, int auth_allowed, use
 	MD5_digest(&ctx, ":", 1);
 	MD5_digest(&ctx, thisuser.pass, strlen(thisuser.pass));
 	MD5_close(&ctx, digest);
-	MD5_hex((BYTE*)ha1u, digest);
+	MD5_hex(ha1u, digest);
 	free(pass);
 
 	/* H(A2) */
@@ -1775,7 +1776,7 @@ static BOOL digest_authentication(http_session_t* session, int auth_allowed, use
 		return(FALSE);
 	}
 	MD5_close(&ctx, digest);
-	MD5_hex((BYTE*)ha2, digest);
+	MD5_hex(ha2, digest);
 
 	/* Check password as in user.dat */
 	calculate_digest(session, ha1, ha2, digest);
@@ -3624,7 +3625,7 @@ static BOOL check_request(http_session_t * session)
 						for(sp=spath, nsp=find_first_slash(sp+1); nsp; nsp=find_first_slash(sp+1)) {
 							*nsp=0;
 							nsp++;
-							if(wildmatch(sp, pspec, TRUE)) {
+							if(wildmatch(sp, pspec, TRUE, /* case_sensitive: */TRUE)) {
 								read_webctrl_section(file, spec, session, curdir, &recheck_dynamic);
 							}
 							sp=nsp;
@@ -3632,7 +3633,7 @@ static BOOL check_request(http_session_t * session)
 						free(spath);
 						free(pspec);
 					}
-					else if(wildmatch(filename,spec,TRUE)) {
+					else if(wildmatch(filename,spec,TRUE, /* case_sensitive: */TRUE)) {
 						read_webctrl_section(file, spec, session, curdir, &recheck_dynamic);
 					}
 					free(spec);
@@ -6702,7 +6703,7 @@ const char* DLLCALL web_ver(void)
 #else
 		,""
 #endif
-		,git_branch, git_hash
+		,GIT_BRANCH, GIT_HASH
 		,__DATE__, __TIME__, compiler);
 
 	return(ver);
@@ -6922,7 +6923,7 @@ void DLLCALL web_server(void* arg)
 
 		DESCRIBE_COMPILER(compiler);
 
-		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", git_branch, git_hash, __DATE__, __TIME__, compiler);
+		lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, compiler);
 
 		if(!winsock_startup()) {
 			cleanup(1);
diff --git a/src/sbbs3/websrvr.vcxproj b/src/sbbs3/websrvr.vcxproj
index 94519cae70..931bfdd3b1 100644
--- a/src/sbbs3/websrvr.vcxproj
+++ b/src/sbbs3/websrvr.vcxproj
@@ -176,7 +176,6 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
-    <ClCompile Include="ver.cpp" />
     <ClCompile Include="websrvr.c">
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
diff --git a/src/sbbs3/writemsg.cpp b/src/sbbs3/writemsg.cpp
index 1cd3598eb7..b103380539 100644
--- a/src/sbbs3/writemsg.cpp
+++ b/src/sbbs3/writemsg.cpp
@@ -1111,7 +1111,7 @@ ulong sbbs_t::msgeditor(char *buf, const char *top, char *title)
 				break;
 			}
 			else if(!stricmp(strin,"/T")) { /* Edit title/subject */
-				if(title[0]) {
+				if(title != nulstr) { // hack
 					bputs(text[SubjectPrompt]);
 					getstr(title,LEN_TITLE,K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
 					SYNC;
@@ -1283,7 +1283,7 @@ bool sbbs_t::editfile(char *fname, bool msg)
 		buf[0]=0;
 		bputs(text[NewFile]); 
 	}
-	if(!msgeditor(buf,nulstr,nulstr)) {
+	if(!msgeditor(buf,nulstr,/* title: */(char*)nulstr)) {
 		free(buf);
 		return false; 
 	}
@@ -1605,7 +1605,8 @@ bool sbbs_t::editmsg(smb_t* smb, smbmsg_t *msg)
 	char	msgtmp[MAX_PATH+1];
 	uint16_t	xlat;
 	int 	file,i,j,x;
-	long	length,offset;
+	long	length;
+	off_t	offset;
 	FILE	*instream;
 
 	if(!msg->hdr.total_dfields)
@@ -1662,7 +1663,7 @@ bool sbbs_t::editmsg(smb_t* smb, smbmsg_t *msg)
 		smb_close_da(smb);
 	}
 
-	msg->hdr.offset=offset;
+	msg->hdr.offset=(uint32_t)offset;
 	if((file=open(msgtmp,O_RDONLY|O_BINARY))==-1
 		|| (instream=fdopen(file,"rb"))==NULL) {
 		smb_unlocksmbhdr(smb);
@@ -1672,7 +1673,7 @@ bool sbbs_t::editmsg(smb_t* smb, smbmsg_t *msg)
 	}
 
 	setvbuf(instream,NULL,_IOFBF,2*1024);
-	fseek(smb->sdt_fp,offset,SEEK_SET);
+	fseeko(smb->sdt_fp,offset,SEEK_SET);
 	xlat=XLAT_NONE;
 	fwrite(&xlat,2,1,smb->sdt_fp);
 	x=SDT_BLOCK_LEN-2;				/* Don't read/write more than 255 */
@@ -1704,7 +1705,8 @@ bool sbbs_t::movemsg(smbmsg_t* msg, uint subnum)
 	char str[256],*buf;
 	uint i;
 	int newgrp,newsub,storage;
-	ulong offset,length;
+	off_t offset;
+	ulong length;
 	smbmsg_t	newmsg=*msg;
 	smb_t		newsmb;
 
@@ -1786,10 +1788,10 @@ bool sbbs_t::movemsg(smbmsg_t* msg, uint subnum)
 		smb_close_da(&newsmb); 
 	}
 
-	newmsg.hdr.offset=offset;
+	newmsg.hdr.offset=(uint32_t)offset;
 	newmsg.hdr.version=smb_ver();
 
-	fseek(newsmb.sdt_fp,offset,SEEK_SET);
+	fseeko(newsmb.sdt_fp,offset,SEEK_SET);
 	fwrite(buf,length,1,newsmb.sdt_fp);
 	fflush(newsmb.sdt_fp);
 	free(buf);
diff --git a/src/sbbs3/xtrn.cpp b/src/sbbs3/xtrn.cpp
index 885b498936..457809718b 100644
--- a/src/sbbs3/xtrn.cpp
+++ b/src/sbbs3/xtrn.cpp
@@ -582,14 +582,11 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 		startup_info.dwFlags|=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
     	startup_info.wShowWindow=SW_HIDE;
 	}
-	if(native && !(mode&EX_OFFLINE)) {
-
-		if(!(mode&EX_STDIN)) {
-			if(passthru_thread_running)
-				passthru_socket_activate(true);
-			else
-				pthread_mutex_lock(&input_thread_mutex);
-		}
+	if(native && !(mode & (EX_OFFLINE | EX_STDIN))) {
+		if(passthru_thread_running)
+			passthru_socket_activate(true);
+		else
+			pthread_mutex_lock(&input_thread_mutex);
 	}
 
     success=CreateProcess(
@@ -609,7 +606,7 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 
 	if(!success) {
 		XTRN_CLEANUP;
-		if(!(mode&EX_STDIN)) {
+		if(native && !(mode & (EX_OFFLINE | EX_STDIN))) {
 			if(passthru_thread_running)
 				passthru_socket_activate(false);
 			else
@@ -848,13 +845,14 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 
 	if(!(mode&EX_OFFLINE)) {	/* !off-line execution */
 
-		if(native) {
-			if(!(mode&EX_STDIN)) {
-				if(passthru_thread_running)
-					passthru_socket_activate(false);
-				else
-					pthread_mutex_unlock(&input_thread_mutex);
-			}
+		if(!WaitForOutbufEmpty(5000))
+			lprintf(LOG_WARNING, "%s Timeout waiting for output buffer to empty", __FUNCTION__);
+
+		if(native && !(mode & EX_STDIN)) {
+			if(passthru_thread_running)
+				passthru_socket_activate(false);
+			else
+				pthread_mutex_unlock(&input_thread_mutex);
 		}
 
 		curatr=~0;			// Can't guarantee current attributes
@@ -1525,13 +1523,11 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 #endif
 	}
 
-	if(!(mode&EX_STDIN)) {
-		if(!(mode&EX_STDIN)) {
-			if(passthru_thread_running)
-				passthru_socket_activate(true);
-			else
-				pthread_mutex_lock(&input_thread_mutex);
-		}
+	if(!(mode & (EX_STDIN | EX_OFFLINE))) {
+		if(passthru_thread_running)
+			passthru_socket_activate(true);
+		else
+			pthread_mutex_lock(&input_thread_mutex);
 	}
 
 	if(!(mode&EX_NOLOG) && pipe(err_pipe)!=0) {
@@ -1557,7 +1553,7 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 		winsize.ws_row=rows;
 		winsize.ws_col=cols;
 		if((pid=forkpty(&in_pipe[1],NULL,&term,&winsize))==-1) {
-			if(!(mode&EX_STDIN)) {
+			if(!(mode & (EX_STDIN | EX_OFFLINE))) {
 				if(passthru_thread_running)
 					passthru_socket_activate(false);
 				else
@@ -1582,7 +1578,7 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 
 
 		if((pid=FORK())==-1) {
-			if(!(mode&EX_STDIN)) {
+			if(!(mode & (EX_STDIN | EX_OFFLINE))) {
 				if(passthru_thread_running)
 					passthru_socket_activate(false);
 				else
@@ -1868,6 +1864,16 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 	}
 	if(!(mode&EX_OFFLINE)) {	/* !off-line execution */
 
+		if(!WaitForOutbufEmpty(5000))
+			lprintf(LOG_WARNING, "%s Timeout waiting for output buffer to empty", __FUNCTION__);
+
+		if(!(mode&EX_STDIN)) {
+			if(passthru_thread_running)
+				passthru_socket_activate(false);
+			else
+				pthread_mutex_unlock(&input_thread_mutex);
+		}
+
 		curatr=~0;			// Can't guarantee current attributes
 		attr(LIGHTGRAY);	// Force to "normal"
 
@@ -1880,19 +1886,12 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 	if(!(mode&EX_NOLOG))
 		close(err_pipe[0]);
 
-	if(!(mode&EX_STDIN)) {
-		if(passthru_thread_running)
-			passthru_socket_activate(false);
-		else
-			pthread_mutex_unlock(&input_thread_mutex);
-	}
-
 	return(errorlevel = WEXITSTATUS(i));
 }
 
 #endif	/* !WIN32 */
 
-const char* quoted_string(const char* str, char* buf, size_t maxlen)
+static const char* quoted_string(const char* str, char* buf, size_t maxlen)
 {
 	if(strchr(str,' ')==NULL)
 		return(str);
@@ -2109,176 +2108,3 @@ char* sbbs_t::cmdstr(const char *instr, const char *fpath, const char *fspec, ch
 
     return(cmd);
 }
-
-/****************************************************************************/
-/* Returns command line generated from instr with %c replacments            */
-/* This is the C-exported version											*/
-/****************************************************************************/
-extern "C"
-char* DLLCALL cmdstr(scfg_t* cfg, user_t* user, const char* instr, const char* fpath
-						,const char* fspec, char* cmd)
-{
-	char	str[MAX_PATH+1];
-    int		i,j,len;
-	static char	buf[512];
-
-	if(cmd==NULL)	cmd=buf;
-    len=strlen(instr);
-	int maxlen = (int)sizeof(buf) - 1;
-    for(i=j=0; i<len && j < maxlen; i++) {
-        if(instr[i]=='%') {
-            i++;
-            cmd[j]=0;
-			int avail = maxlen - j;
-			char ch=instr[i];
-			if(IS_ALPHA(ch))
-				ch=toupper(ch);
-            switch(ch) {
-                case 'A':   /* User alias */
-					if(user!=NULL)
-						strncat(cmd,QUOTED_STRING(instr[i],user->alias,str,sizeof(str)), avail);
-                    break;
-                case 'B':   /* Baud (DTE) Rate */
-                    break;
-                case 'C':   /* Connect Description */
-					if(user!=NULL)
-						strncat(cmd,user->modem, avail);
-                    break;
-                case 'D':   /* Connect (DCE) Rate */
-                    break;
-                case 'E':   /* Estimated Rate */
-                    break;
-                case 'F':   /* File path */
-                    strncat(cmd,QUOTED_STRING(instr[i],fpath,str,sizeof(str)), avail);
-                    break;
-                case 'G':   /* Temp directory */
-                    strncat(cmd,cfg->temp_dir, avail);
-                    break;
-                case 'H':   /* Port Handle or Hardware Flow Control */
-                    break;
-                case 'I':   /* IP address */
-					if(user!=NULL)
-						strncat(cmd,user->note, avail);
-                    break;
-                case 'J':
-                    strncat(cmd,cfg->data_dir, avail);
-                    break;
-                case 'K':
-                    strncat(cmd,cfg->ctrl_dir, avail);
-                    break;
-                case 'L':   /* Lines per message */
-					if(user!=NULL)
-						strncat(cmd,ultoa(cfg->level_linespermsg[user->level],str,10), avail);
-                    break;
-                case 'M':   /* Minutes (credits) for user */
-					if(user!=NULL)
-						strncat(cmd,ultoa(user->min,str,10), avail);
-                    break;
-                case 'N':   /* Node Directory (same as SBBSNODE environment var) */
-                    strncat(cmd,cfg->node_dir, avail);
-                    break;
-                case 'O':   /* SysOp */
-                    strncat(cmd,QUOTED_STRING(instr[i],cfg->sys_op,str,sizeof(str)), avail);
-                    break;
-                case 'P':   /* Client protocol */
-                    break;
-                case 'Q':   /* QWK ID */
-                    strncat(cmd,cfg->sys_id, avail);
-                    break;
-                case 'R':   /* Rows */
-					if(user!=NULL)
-						strncat(cmd,ultoa(user->rows,str,10), avail);
-                    break;
-                case 'S':   /* File Spec */
-                    strncat(cmd, fspec, avail);
-                    break;
-                case 'T':   /* Time left in seconds */
-                    break;
-                case 'U':   /* UART I/O Address (in hex) */
-                    strncat(cmd,ultoa(cfg->com_base,str,16), avail);
-                    break;
-                case 'V':   /* Synchronet Version */
-                    sprintf(str,"%s%c",VERSION,REVISION);
-					strncat(cmd,str, avail);
-                    break;
-                case 'W':   /* Columns/width */
-                    break;
-                case 'X':
-					if(user!=NULL)
-						strncat(cmd,cfg->shell[user->shell]->code, avail);
-                    break;
-                case '&':   /* Address of msr */
-                    break;
-                case 'Y':
-                    break;
-                case 'Z':
-                    strncat(cmd,cfg->text_dir, avail);
-                    break;
-				case '~':	/* DOS-compatible (8.3) filename */
-#ifdef _WIN32
-					char sfpath[MAX_PATH+1];
-					SAFECOPY(sfpath,fpath);
-					GetShortPathName(fpath,sfpath,sizeof(sfpath));
-					strncat(cmd,sfpath, avail);
-#else
-                    strncat(cmd,QUOTED_STRING(instr[i],fpath,str,sizeof(str)), avail);
-#endif
-					break;
-                case '!':   /* EXEC Directory */
-                    strncat(cmd,cfg->exec_dir, avail);
-                    break;
-                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
-#ifndef __unix__
-                    strncat(cmd,cfg->exec_dir, avail);
-#endif
-                    break;
-
-                case '#':   /* Node number (same as SBBSNNUM environment var) */
-                    sprintf(str,"%d",cfg->node_num);
-                    strncat(cmd,str, avail);
-                    break;
-                case '*':
-                    sprintf(str,"%03d",cfg->node_num);
-                    strncat(cmd,str, avail);
-                    break;
-                case '$':   /* Credits */
-					if(user!=NULL)
-						strncat(cmd,ultoa(user->cdt+user->freecdt,str,10), avail);
-                    break;
-                case '%':   /* %% for percent sign */
-                    strncat(cmd,"%", avail);
-                    break;
-				case '.':	/* .exe for DOS/OS2/Win32, blank for Unix */
-#ifndef __unix__
-					strncat(cmd,".exe", avail);
-#endif
-					break;
-				case '?':	/* Platform */
-#ifdef __OS2__
-					strcpy(str,"OS2");
-#else
-					strcpy(str,PLATFORM_DESC);
-#endif
-					strlwr(str);
-					strncat(cmd,str, avail);
-					break;
-				case '^':	/* Architecture */
-					strncat(cmd, ARCHITECTURE_DESC, avail);
-					break;
-                default:    /* unknown specification */
-                    if(IS_DIGIT(instr[i]) && user!=NULL) {
-                        sprintf(str,"%0*d",instr[i]&0xf,user->number);
-                        strncat(cmd,str, avail);
-					}
-                    break;
-			}
-            j=strlen(cmd);
-		}
-        else
-            cmd[j++]=instr[i];
-	}
-    cmd[j]=0;
-
-    return(cmd);
-}
-
diff --git a/src/sbbs3/xtrn_sec.cpp b/src/sbbs3/xtrn_sec.cpp
index 2ee165883f..b36266b572 100644
--- a/src/sbbs3/xtrn_sec.cpp
+++ b/src/sbbs3/xtrn_sec.cpp
@@ -504,7 +504,7 @@ void sbbs_t::xtrndat(const char *name, const char *dropdir, uchar type, ulong tl
 		if(p)
 			*(p++)=0;
 		else
-			p=nulstr;
+			p=(char*)nulstr;
 
 		safe_snprintf(str, sizeof(str), "%s\n%s\n%s\nCOM%d\n%lu BAUD,N,8,1\n%u\n"
 			,cfg.sys_name						/* Name of BBS */
@@ -522,7 +522,7 @@ void sbbs_t::xtrndat(const char *name, const char *dropdir, uchar type, ulong tl
 		if(p)
 			*(p++)=0;
 		else
-			p=nulstr;
+			p=(char*)nulstr;
 		safe_snprintf(str, sizeof(str), "%s\n%s\n%s\n%d\n%u\n%lu\n"
 			,tmp								/* User's firstname */
 			,p									/* User's lastname */
@@ -1577,8 +1577,6 @@ bool sbbs_t::exec_xtrn(uint xtrnnum)
 
 	SAFEPRINTF(str,"%shangup.now",cfg.node_dir);
 	(void)removecase(str);
-	SAFEPRINTF2(str,"%sfile/%04u.dwn",cfg.data_dir,useron.number);
-	(void)removecase(str);
 
 	mode=0; 	
 	if(cfg.xtrn[xtrnnum]->misc&XTRN_SH)
@@ -1629,9 +1627,6 @@ bool sbbs_t::exec_xtrn(uint xtrnnum)
 			errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_APPEND);
 	}
 
-	SAFEPRINTF2(str,"%sfile/%04u.dwn",cfg.data_dir,useron.number);
-	batch_add_list(str);
-
 	SAFEPRINTF(str,"%shangup.now",cfg.node_dir);
 	if(fexistcase(str)) {
 		lprintf(LOG_NOTICE,"Node %d External program requested hangup (%s signaled)"
diff --git a/src/smblib/smbadd.c b/src/smblib/smbadd.c
index 0e7b6df8bf..c82f9ff9d3 100644
--- a/src/smblib/smbadd.c
+++ b/src/smblib/smbadd.c
@@ -1,7 +1,5 @@
 /* Synchronet message base (SMB) high-level "add message" function */
 
-/* $Id: smbadd.c,v 1.46 2020/04/12 06:09:33 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -15,21 +13,9 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -39,22 +25,23 @@
 #include "genwrap.h"
 #include "crc32.h"
 #include "lzh.h"
+#include "datewrap.h"
 
 /****************************************************************************/
 /****************************************************************************/
-int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hashes
+int smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hashes
 					   ,uint16_t xlat, const uchar* body, const uchar* tail)
 {
 	uchar*		lzhbuf=NULL;
 	long		lzhlen;
 	int			retval;
 	size_t		n;
-	size_t		l;
+	off_t		l;
 	off_t		length;
 	size_t		taillen=0;
 	size_t		bodylen=0;
 	size_t		chklen=0;
-	long		offset;
+	off_t		offset;
 	uint32_t	crc=0xffffffff;
 	hash_t		found;
 	hash_t**	hashes=NULL;	/* This is a NULL-terminated list of hashes */
@@ -83,7 +70,7 @@ int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hash
 			break;
 
 		msg->hdr.number=smb->status.last_msg+1;
-		if(!(smb->status.attr&(SMB_EMAIL|SMB_NOHASH))) {
+		if(!(smb->status.attr&(SMB_EMAIL | SMB_NOHASH | SMB_FILE_DIRECTORY))) {
 
 			hashes=smb_msghashes(msg,body,SMB_HASH_SOURCE_DUPE);
 
@@ -111,7 +98,7 @@ int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hash
 
 			/* Calculate CRC-32 of message text (before encoding, if any) */
 			if(smb->status.max_crcs && dupechk_hashes&(1<<SMB_HASH_SOURCE_BODY)) {
-				for(l=0;l<chklen;l++)
+				for(l=0;l<(off_t)chklen;l++)
 					crc=ucrc32(body[l],crc); 
 				crc=~crc;
 
@@ -164,12 +151,16 @@ int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hash
 			}
 
 			if(offset<0) {
-				retval=offset;
+				retval=(int)offset;
 				break;
 			}
-			msg->hdr.offset=offset;
+			msg->hdr.offset=(uint32_t)offset;
 
-			smb_fseek(smb->sdt_fp,offset,SEEK_SET);
+			if(smb_fseek(smb->sdt_fp,offset,SEEK_SET) != 0) {
+				sprintf(smb->last_error, "%s seek error %d", __FUNCTION__, errno);
+				retval=SMB_ERR_SEEK;
+				break;
+			}
 
 			if(bodylen) {
 				if((retval=smb_dfield(msg,TEXT_BODY,bodylen))!=SMB_SUCCESS)
@@ -298,10 +289,10 @@ int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hash
 			}
 		}
 
-		if(!(smb->status.attr&(SMB_EMAIL|SMB_NOHASH))
+		if(!(smb->status.attr&(SMB_EMAIL | SMB_NOHASH | SMB_FILE_DIRECTORY))
 			&& smb_addhashes(smb,hashes,/* skip_marked? */FALSE)==SMB_SUCCESS)
 			msg->flags|=MSG_FLAG_HASHED;
-		if(msg->to==NULL)	/* no recipient, don't add header (required for bulkmail) */
+		if(msg->hdr.type == SMB_MSG_TYPE_NORMAL && msg->to == NULL)	/* no recipient, don't add header (required for bulkmail) */
 			break;
 
 		retval=smb_addmsghdr(smb,msg,storage); /* calls smb_unlocksmbhdr() */
@@ -320,7 +311,7 @@ int SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hash
 	return(retval);
 }
 
-int SMBCALL smb_addvote(smb_t* smb, smbmsg_t* msg, int storage)
+int smb_addvote(smb_t* smb, smbmsg_t* msg, int storage)
 {
 	int			retval;
 
@@ -358,7 +349,7 @@ int SMBCALL smb_addvote(smb_t* smb, smbmsg_t* msg, int storage)
 	return retval;
 }
 
-int SMBCALL smb_addpoll(smb_t* smb, smbmsg_t* msg, int storage)
+int smb_addpoll(smb_t* smb, smbmsg_t* msg, int storage)
 {
 	int			retval;
 
@@ -398,7 +389,7 @@ int SMBCALL smb_addpoll(smb_t* smb, smbmsg_t* msg, int storage)
 	return retval;
 }
 
-int SMBCALL smb_addpollclosure(smb_t* smb, smbmsg_t* msg, int storage)
+int smb_addpollclosure(smb_t* smb, smbmsg_t* msg, int storage)
 {
 	smbmsg_t	remsg;
 	int			retval;
diff --git a/src/smblib/smballoc.c b/src/smblib/smballoc.c
index f1c00722ec..8396a939d5 100644
--- a/src/smblib/smballoc.c
+++ b/src/smblib/smballoc.c
@@ -1,7 +1,4 @@
 /* Synchronet message base (SMB) alloc/free routines */
-// vi: tabstop=4
-
-/* $Id: smballoc.c,v 1.14 2019/04/11 01:00:29 rswindell Exp $ */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -16,21 +13,9 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -46,10 +31,11 @@
 /* smb_close_da() should be called after									*/
 /* Returns negative on error												*/
 /****************************************************************************/
-long SMBCALL smb_allocdat(smb_t* smb, ulong length, uint16_t refs)
+off_t smb_allocdat(smb_t* smb, off_t length, uint16_t refs)
 {
     uint16_t  i;
-	ulong	j,l,blocks,offset=0L;
+	ulong	j,l,blocks;
+	off_t offset=0;
 
 	if(smb->sda_fp==NULL) {
 		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s msgbase not open", __FUNCTION__);
@@ -75,7 +61,7 @@ long SMBCALL smb_allocdat(smb_t* smb, ulong length, uint16_t refs)
 		return(SMB_ERR_DAT_OFFSET);
 	}
 	clearerr(smb->sda_fp);
-	if(fseek(smb->sda_fp,(offset/SDT_BLOCK_LEN)*sizeof(refs),SEEK_SET)) {
+	if(fseeko(smb->sda_fp,(offset/SDT_BLOCK_LEN)*sizeof(refs),SEEK_SET)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s seeking to: %ld", __FUNCTION__
 			,(offset/SDT_BLOCK_LEN)*sizeof(refs));
 		return(SMB_ERR_SEEK);
@@ -95,9 +81,10 @@ long SMBCALL smb_allocdat(smb_t* smb, ulong length, uint16_t refs)
 /* Allocates space for data, but doesn't search for unused blocks           */
 /* Returns negative on error												*/
 /****************************************************************************/
-long SMBCALL smb_fallocdat(smb_t* smb, ulong length, uint16_t refs)
+off_t smb_fallocdat(smb_t* smb, off_t length, uint16_t refs)
 {
-	ulong	l,blocks,offset;
+	ulong	l,blocks;
+	off_t offset;
 
 	if(smb->sda_fp==NULL) {
 		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s msgbase not open", __FUNCTION__);
@@ -133,13 +120,13 @@ long SMBCALL smb_fallocdat(smb_t* smb, ulong length, uint16_t refs)
 /* Returns non-zero on error												*/
 /* Always unlocks the SMB header (when not hyper-alloc)						*/
 /****************************************************************************/
-int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, uint16_t refs)
+int smb_freemsgdat(smb_t* smb, off_t offset, ulong length, uint16_t refs)
 {
 	BOOL	da_opened=FALSE;
 	int		retval=SMB_SUCCESS;
 	uint16_t	i;
 	long	l,blocks;
-	ulong	sda_offset;
+	off_t	sda_offset;
 	off_t	flen;
 
 	if(smb->status.attr&SMB_HYPERALLOC)	/* do nothing */
@@ -166,7 +153,7 @@ int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, uint16_t refs
 	// Free from the last block first
 	for(l=blocks-1; l >= 0; l--) {
 		sda_offset=((offset/SDT_BLOCK_LEN)+l)*sizeof(i);
-		if(fseek(smb->sda_fp,sda_offset,SEEK_SET)) {
+		if(fseeko(smb->sda_fp,sda_offset,SEEK_SET)) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
 				,"%s %d '%s' seeking to %lu (0x%lX) of allocation file", __FUNCTION__
 				,get_errno(),STRERROR(get_errno())
@@ -188,7 +175,7 @@ int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, uint16_t refs
 
 		// Completely free? and at end of SDA? Just truncate record from end of file
 		if(i == 0 && ftell(smb->sda_fp) == flen) {
-			if(chsize(fileno(smb->sda_fp), sda_offset) == 0) {
+			if(chsize(fileno(smb->sda_fp), (long)sda_offset) == 0) {
 				flen = sda_offset;
 				continue;
 			}
@@ -211,7 +198,7 @@ int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, uint16_t refs
 	}
 	fflush(smb->sda_fp);
 	if(filelength(fileno(smb->sdt_fp)) / SDT_BLOCK_LEN > (long)(filelength(fileno(smb->sda_fp)) / sizeof(uint16_t)))
-		chsize(fileno(smb->sdt_fp), (filelength(fileno(smb->sda_fp)) / sizeof(uint16_t)) * SDT_BLOCK_LEN);
+		chsize(fileno(smb->sdt_fp), (long)(filelength(fileno(smb->sda_fp)) / sizeof(uint16_t)) * SDT_BLOCK_LEN);
 	if(da_opened)
 		smb_close_da(smb);
 	smb_unlocksmbhdr(smb);
@@ -223,7 +210,7 @@ int SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, uint16_t refs
 /* SMB header should be locked before calling this function					*/
 /* Returns non-zero on error												*/
 /****************************************************************************/
-int SMBCALL smb_incdat(smb_t* smb, ulong offset, ulong length, uint16_t refs)
+int smb_incdat(smb_t* smb, off_t offset, ulong length, uint16_t refs)
 {
 	uint16_t	i;
 	ulong	l,blocks;
@@ -235,7 +222,7 @@ int SMBCALL smb_incdat(smb_t* smb, ulong offset, ulong length, uint16_t refs)
 	clearerr(smb->sda_fp);
 	blocks=smb_datblocks(length);
 	for(l=0;l<blocks;l++) {
-		if(fseek(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*sizeof(i),SEEK_SET)) {
+		if(fseeko(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*sizeof(i),SEEK_SET)) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s seeking to %ld", __FUNCTION__
 				,((offset/SDT_BLOCK_LEN)+l)*sizeof(i));
 			return(SMB_ERR_SEEK);
@@ -267,7 +254,7 @@ int SMBCALL smb_incdat(smb_t* smb, ulong offset, ulong length, uint16_t refs)
 /* The opposite function of smb_freemsg()									*/
 /* Always unlocks the SMB header (when not hyper-alloc)						*/
 /****************************************************************************/
-int SMBCALL smb_incmsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs)
+int smb_incmsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs)
 {
 	int		i=SMB_SUCCESS;
 	BOOL	da_opened=FALSE;
@@ -302,7 +289,7 @@ int SMBCALL smb_incmsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs)
 /* De-allocates blocks for header record									*/
 /* Returns non-zero on error												*/
 /****************************************************************************/
-int SMBCALL smb_freemsghdr(smb_t* smb, ulong offset, ulong length)
+int smb_freemsghdr(smb_t* smb, off_t offset, ulong length)
 {
 	uchar	c=0;
 	long	l,blocks;
@@ -319,13 +306,13 @@ int SMBCALL smb_freemsghdr(smb_t* smb, ulong offset, ulong length)
 
 	sha_offset = offset/SHD_BLOCK_LEN;
 	if(filelength(fileno(smb->sha_fp)) <= (sha_offset + blocks)) {
-		if(chsize(fileno(smb->sha_fp), sha_offset) == 0) {
-			chsize(fileno(smb->shd_fp), smb->status.header_offset + offset);
+		if(chsize(fileno(smb->sha_fp), (long)sha_offset) == 0) {
+			chsize(fileno(smb->shd_fp), (long)(smb->status.header_offset + offset));
 			return SMB_SUCCESS;
 		}
 	}
 
-	if(fseek(smb->sha_fp, sha_offset, SEEK_SET)) {
+	if(fseeko(smb->sha_fp, sha_offset, SEEK_SET)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s seeking to %ld", __FUNCTION__, (long)sha_offset);
 		return(SMB_ERR_SEEK);
 	}
@@ -340,7 +327,7 @@ int SMBCALL smb_freemsghdr(smb_t* smb, ulong offset, ulong length)
 
 /****************************************************************************/
 /****************************************************************************/
-int SMBCALL smb_freemsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs)
+int smb_freemsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs)
 {
 	int		i;
 	uint16_t	x;
@@ -356,7 +343,7 @@ int SMBCALL smb_freemsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs)
 /****************************************************************************/
 /* Frees all allocated header and data blocks (1 reference) for 'msg'       */
 /****************************************************************************/
-int SMBCALL smb_freemsg(smb_t* smb, smbmsg_t* msg)
+int smb_freemsg(smb_t* smb, smbmsg_t* msg)
 {
 	int 	i;
 
@@ -382,7 +369,7 @@ int SMBCALL smb_freemsg(smb_t* smb, smbmsg_t* msg)
 /* smb_close_ha() should be called after									*/
 /* Returns negative value on error 											*/
 /****************************************************************************/
-long SMBCALL smb_allochdr(smb_t* smb, ulong length)
+off_t smb_allochdr(smb_t* smb, ulong length)
 {
 	uchar	c;
 	ulong	i,l,blocks,offset=0;
@@ -425,7 +412,7 @@ long SMBCALL smb_allochdr(smb_t* smb, ulong length)
 /* Allocates space for header, but doesn't search for unused blocks          */
 /* Returns negative value on error 											*/
 /****************************************************************************/
-long SMBCALL smb_fallochdr(smb_t* smb, ulong length)
+off_t smb_fallochdr(smb_t* smb, ulong length)
 {
 	uchar	c=1;
 	ulong	l,blocks,offset;
@@ -457,7 +444,7 @@ long SMBCALL smb_fallochdr(smb_t* smb, ulong length)
 /* this function should be most likely not be called from anywhere but	*/
 /* smb_addmsghdr()														*/
 /************************************************************************/
-long SMBCALL smb_hallochdr(smb_t* smb)
+off_t smb_hallochdr(smb_t* smb)
 {
 	ulong offset;
 
@@ -488,9 +475,9 @@ long SMBCALL smb_hallochdr(smb_t* smb)
 /* unlocked until all data fields for this message have been written	*/
 /* to the SDT file														*/
 /************************************************************************/
-long SMBCALL smb_hallocdat(smb_t* smb)
+off_t smb_hallocdat(smb_t* smb)
 {
-	long offset;
+	off_t offset;
 
 	if(smb->sdt_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
@@ -518,5 +505,5 @@ long SMBCALL smb_hallocdat(smb_t* smb)
 	/* Make sure even block boundry */
 	offset+=PAD_LENGTH_FOR_ALIGNMENT(offset,SDT_BLOCK_LEN);
 
-	return(offset);
+	return (long)offset;
 }
diff --git a/src/smblib/smbdefs.h b/src/smblib/smbdefs.h
index 36e7797d95..64ec8d0d4d 100644
--- a/src/smblib/smbdefs.h
+++ b/src/smblib/smbdefs.h
@@ -31,8 +31,9 @@
 #include "dirwrap.h"	/* MAX_PATH */
 #include "filewrap.h"	/* SH_DENYRW */
 
-/* SMBLIB Headers */
+/* hash lib Headers */
 #include "md5.h"		/* MD5_DIGEST_SIZE */
+#include "sha1.h"
 
 /**********/
 /* Macros */
@@ -77,9 +78,10 @@
 #define SMB_FASTALLOC		1			/* Fast allocation */
 
 										/* status.attr bit flags: */
-#define SMB_EMAIL			1			/* User numbers stored in Indexes */
-#define SMB_HYPERALLOC		2			/* No allocation (also storage value for smb_addmsghdr) */
-#define SMB_NOHASH			4			/* Do not calculate or store hashes */
+#define SMB_EMAIL			(1<<0)		/* User numbers stored in Indexes */
+#define SMB_HYPERALLOC		(1<<1)		/* No allocation (also storage value for smb_addmsghdr) */
+#define SMB_NOHASH			(1<<2)		/* Do not calculate or store hashes */
+#define SMB_FILE_DIRECTORY	(1<<3)		/* Storage for a file area (for file transfers/downloads) */
 
 										/* Time zone macros for when_t.zone */
 #define DAYLIGHT			0x8000		/* Daylight savings is active */
@@ -197,6 +199,36 @@
 #define	SMB_EDITOR			0x68	/* Associated with FTN ^aNOTE: control line */
 #define SMB_TAGS			0x69	/* List of tags (ala hash-tags) related to this message */
 #define SMB_TAG_DELIMITER	" "
+
+#define SMB_FILEIDX_NAMELEN	64
+#define SMB_FILENAME		SUBJECT
+#define	SMB_FILEDESC		SMB_SUMMARY
+#define SMB_FILEUPLOADER	SENDER
+
+#define FILEATTACH			0x70
+#define DESTFILE			0x71
+#define FILEATTACHLIST		0x72
+#define DESTFILELIST		0x73
+#define FILEREQUEST 		0x74
+#define FILEPASSWORD		0x75
+#define FILEREQUESTLIST 	0x76
+#define FILEPASSWORDLIST	0x77
+
+#define IMAGEATTACH 		0x80
+#define ANIMATTACH			0x81
+#define FONTATTACH			0x82
+#define SOUNDATTACH 		0x83
+#define PRESENTATTACH		0x84
+#define VIDEOATTACH 		0x85
+#define APPDATAATTACH		0x86
+
+#define IMAGETRIGGER		0x90
+#define ANIMTRIGGER 		0x91
+#define FONTTRIGGER 		0x92
+#define SOUNDTRIGGER		0x93
+#define PRESENTTRIGGER		0x94
+#define VIDEOTRIGGER		0x95
+#define APPDATATRIGGER		0x96
 #define SMB_COLUMNS			0x6a	/* original text editor width in fixed-width columns */
 
 #define FIDOCTRL			0xa0
@@ -235,8 +267,8 @@
 
 #define SMB_POLL_ANSWER		0xe0		/* the subject is the question */
 
-#define UNKNOWN 			0xf1
-#define UNKNOWNASCII		0xf2
+#define UNKNOWN 			0xf1		/* specified as 0xf0 in smb.txt/html - oops */
+#define UNKNOWNASCII		0xf2		/* specified as 0xf1 in smb.txt/html - oops */
 #define UNUSED				0xff
 
 										/* Valid dfield_t.types */
@@ -262,6 +294,7 @@
 #define MSG_DOWNVOTE		(1<<12)		/* This message is a downvote */
 #define MSG_POLL			(1<<13)		/* This message is a poll */
 #define MSG_SPAM			(1<<14)		/* This message has been flagged as SPAM */
+#define MSG_FILE			(1<<15)		/* This is a file */
 
 #define MSG_VOTE			(MSG_UPVOTE|MSG_DOWNVOTE)	/* This message is a poll-vote */
 #define MSG_POLL_CLOSURE	(MSG_POLL|MSG_VOTE)			/* This message is a poll-closure */
@@ -269,6 +302,8 @@
 
 #define MSG_POLL_MAX_ANSWERS	16
 
+#define FILE_ANONYMOUS		MSG_ANONYMOUS
+
 										/* Auxiliary header attributes */
 #define MSG_FILEREQUEST 	(1<<0)		/* File request */
 #define MSG_FILEATTACH		(1<<1)		/* File(s) attached to Msg (file paths/names in subject) */
@@ -330,21 +365,9 @@ enum smb_priority {			/* msghdr_t.priority */
 /* Typedefs */
 /************/
 
-#if defined(_WIN32) || defined(__BORLANDC__) 
-	#define PRAGMA_PACK
-#endif
+#pragma pack(push,1)	/* Disk image structures must be packed */
 
-#if defined(PRAGMA_PACK) || defined(__WATCOMC__)
-	#define _PACK
-#else
-	#define _PACK __attribute__ ((packed))
-#endif
-
-#if defined(PRAGMA_PACK)
-	#pragma pack(push,1)	/* Disk image structures must be packed */
-#endif
-
-typedef struct _PACK {		/* Time with time-zone */
+typedef struct {		/* Time with time-zone */
 
 	uint32_t	time;			/* Local time (unix format) */
 	int16_t		zone;			/* Time zone */
@@ -353,17 +376,21 @@ typedef struct _PACK {		/* Time with time-zone */
 
 typedef uint16_t smb_msg_attr_t;
 
-typedef struct _PACK {		/* Index record */
+typedef struct {	/* Index record */
 
 	union {
-		struct _PACK {
-			uint16_t	to; 		/* 16-bit CRC of recipient name (lower case) or user # */
-			uint16_t	from;		/* 16-bit CRC of sender name (lower case) or user # */
-			uint16_t	subj;		/* 16-bit CRC of subject (lower case, w/o RE:) */
+		struct {			/* when msg.type != BALLOT */
+			uint16_t	to; 	/* 16-bit CRC of recipient name (lower case) or user # */
+			uint16_t	from;	/* 16-bit CRC of sender name (lower case) or user # */
+			uint16_t	subj;	/* 16-bit CRC of subject (lower case, w/o RE:) */
+		};
+		struct {			/* when msg.type == BALLOT */
+			uint16_t	votes;	/* votes value */
+			uint32_t	remsg;	/* number of message this vote is in response to */
 		};
-		struct _PACK {
-			uint16_t	votes;		/* votes value */
-			uint32_t	remsg;		/* number of message this vote is in response to */
+		struct {			/* when msg.type == FILE */
+			uint32_t	size;
+			uint16_t	unused;	/* possibly store additional 16-bits of file size here */
 		};
 	};
 	smb_msg_attr_t	attr;		/* attributes (read, permanent, etc.) */
@@ -372,13 +399,40 @@ typedef struct _PACK {		/* Index record */
 	uint32_t	time;			/* time/date message was imported/posted */
 
 } idxrec_t;
+#define SIZEOF_SMB_IDXREC_T 20
 
-										/* valid bits in hash_t.flags		*/
+struct hash_data {
+	uint16_t	crc16;					/* CRC-16 of source */
+	uint32_t	crc32;					/* CRC-32 of source */
+	uint8_t		md5[MD5_DIGEST_SIZE];	/* MD5 digest of source */
+	uint8_t		sha1[SHA1_DIGEST_SIZE];	/* SHA1 hash of source */
+};
+
+typedef uint8_t	hashflags_t;
+
+struct hash_info {
+	hashflags_t flags;
+	struct hash_data data;
+};
+
+typedef struct {		/* File index record */
+	union {
+		idxrec_t	idx;
+		struct {
+			idxrec_t idx_;	// only here for storage, no need to reference
+			char name[SMB_FILEIDX_NAMELEN + 1];
+			struct hash_info hash;
+		};
+	};
+} fileidxrec_t;
+#define SIZEOF_SMB_FILEIDXREC_T 128
+										/* valid bits in hashflags_t		*/
 #define SMB_HASH_CRC16			(1<<0)	/* CRC-16 hash is valid				*/
 #define SMB_HASH_CRC32			(1<<1)	/* CRC-32 hash is valid				*/
 #define SMB_HASH_MD5			(1<<2)	/* MD5 digest is valid				*/
-#define SMB_HASH_MASK			(SMB_HASH_CRC16|SMB_HASH_CRC32|SMB_HASH_MD5)
-								
+#define SMB_HASH_SHA1			(1<<3)	/* SHA1 hsah is valid				*/
+#define SMB_HASH_MASK			(SMB_HASH_CRC16|SMB_HASH_CRC32|SMB_HASH_MD5|SMB_HASH_SHA1)
+
 #define SMB_HASH_MARKED			(1<<4)	/* Used by smb_findhash()			*/
 
 #define SMB_HASH_STRIP_CTRL_A	(1<<5)	/* Strip Ctrl-A codes first			*/
@@ -406,37 +460,43 @@ enum smb_hash_source_type {
 								/* These are the hash sources stored/compared for SPAM message detection: */
 #define SMB_HASH_SOURCE_SPAM	((1<<SMB_HASH_SOURCE_BODY))
 
-typedef struct _PACK {
-
+typedef struct {
 	uint32_t	number;					/* Message number */
 	uint32_t	time;					/* Local time of fingerprinting */
 	uint32_t	length;					/* Length (in bytes) of source */
-	uchar		source;					/* SMB_HASH_SOURCE* (in low 5-bits) */
-	uchar		flags;					/* indications of valid hashes and pre-processing */
-	uint16_t	crc16;					/* CRC-16 of source */
-	uint32_t	crc32;					/* CRC-32 of source */
-	uchar		md5[MD5_DIGEST_SIZE];	/* MD5 digest of source */
-	uchar		reserved[28];			/* sizeof(hash_t) = 64 */
-
+	uint8_t		source;					/* SMB_HASH_SOURCE* (in low 5-bits) */
+	hashflags_t flags;
+	struct hash_data data;
+	uint8_t		reserved[8];			/* sizeof(hash_t) = 64 */
 } hash_t;
+#define SIZEOF_SMB_HASH_T 64
 
-typedef struct _PACK {		/* Message base header (fixed portion) */
+typedef struct {		/* Message base header (fixed portion) */
 
-    uchar		id[LEN_HEADER_ID];	/* SMB<^Z> */
+    uchar		smbhdr_id[LEN_HEADER_ID];	/* SMB<^Z> */
     uint16_t	version;        /* version number (initially 100h for 1.00) */
     uint16_t	length;         /* length including this struct */
 
 } smbhdr_t;
 
-typedef struct _PACK {		/* Message base status header */
+typedef struct {		/* Message/File base status header */
 
-	uint32_t	last_msg;		/* last message number */
-	uint32_t	total_msgs; 	/* total messages */
+	union {
+		uint32_t	last_msg;	/* last message number */
+		uint32_t	last_file;	/* last file number */
+	};
+	union {
+		uint32_t	total_msgs; /* total messages */
+		uint32_t	total_files; /* total files */
+	};
 	uint32_t	header_offset;	/* byte offset to first header record */
 	uint32_t	max_crcs;		/* Maximum number of CRCs to keep in history */
-    uint32_t	max_msgs;       /* Maximum number of message to keep in sub */
-    uint16_t	max_age;        /* Maximum age of message to keep in sub (in days) */
-	uint16_t	attr;			/* Attributes for this message base (SMB_HYPER,etc) */
+	union {
+		uint32_t	max_msgs;	/* Maximum number of message to keep in sub */
+		uint32_t	max_files;	/* Maximum number of files to keep in dir */
+	};
+    uint16_t	max_age;        /* Maximum age of message/file to keep in sub (in days) */
+	uint16_t	attr;			/* Attributes for this message/file base (SMB_HYPER,etc) */
 
 } smbstatus_t;
 
@@ -445,11 +505,12 @@ enum smb_msg_type {
 	,SMB_MSG_TYPE_POLL			/* A poll question  */
 	,SMB_MSG_TYPE_BALLOT		/* Voter response to poll or normal message */
 	,SMB_MSG_TYPE_POLL_CLOSURE	/* Closure of an existing poll */
+	,SMB_MSG_TYPE_FILE			/* A file (e.g. for download) */
 };
 
-typedef struct _PACK {		/* Message header */
+typedef struct {		/* Message/File header */
 
-	/* 00 */ uchar		id[LEN_HEADER_ID];	/* SHD<^Z> */
+	/* 00 */ uchar		msghdr_id[LEN_HEADER_ID];	/* SHD<^Z> */
     /* 04 */ uint16_t	type;				/* Message type (enum smb_msg_type) */
     /* 06 */ uint16_t	version;			/* Version of type (initially 100h for 1.00) */
     /* 08 */ uint16_t	length;				/* Total length of fixed record + all fields */
@@ -462,7 +523,7 @@ typedef struct _PACK {		/* Message header */
     /* 24 */ uint32_t	thread_back;		/* Message number for backwards threading (aka thread_orig) */
     /* 28 */ uint32_t	thread_next;		/* Next message in thread */
     /* 2c */ uint32_t	thread_first;		/* First reply to this message */
-	/* 30 */ uint16_t	delivery_attempts;	/* Delivery attempt counter */
+	/* 30 */ uint16_t	delivery_attempts;	/* Delivery attempt counter (for SMTP) */
 	/* 32 */ int16_t	votes;				/* Votes value (response to poll) or maximum votes per ballot (poll) */
 	/* 34 */ uint32_t	thread_id;			/* Number of original message in thread (or 0 if unknown) */
 	union {	/* 38-3f */
@@ -481,7 +542,7 @@ typedef struct _PACK {		/* Message header */
 
 #define thread_orig	thread_back	/* for backwards compatibility with older code */
 
-typedef struct _PACK {		/* Data field */
+typedef struct {		/* Data field */
 
 	uint16_t	type;			/* Type of data field */
     uint32_t	offset;         /* Offset into buffer */ 
@@ -489,14 +550,14 @@ typedef struct _PACK {		/* Data field */
 
 } dfield_t;
 
-typedef struct _PACK {		/* Header field */
+typedef struct {		/* Header field */
 
 	uint16_t	type;
 	uint16_t	length; 		/* Length of buffer */
 
 } hfield_t;
 
-typedef struct _PACK {		/* FidoNet address (zone:net/node.point) */
+typedef struct {		/* FidoNet address (zone:net/node.point) */
 
 	uint16_t	zone;
 	uint16_t	net;
@@ -505,9 +566,7 @@ typedef struct _PACK {		/* FidoNet address (zone:net/node.point) */
 
 } fidoaddr_t;
 
-#if defined(PRAGMA_PACK)
 #pragma pack(pop)		/* original packing */
-#endif
 
 typedef uint16_t smb_net_type_t;
 
@@ -521,9 +580,12 @@ typedef struct {		/* Network (type and address) */
 								/* Valid bits in smbmsg_t.flags					*/
 #define MSG_FLAG_HASHED	(1<<0)	/* Message has been hashed with smb_hashmsg()	*/
 
-typedef struct {				/* Message */
+typedef struct {				/* Message or File */
 
-	idxrec_t	idx;			/* Index */
+	union {						/* Index */
+		idxrec_t		idx;
+		fileidxrec_t	file_idx;
+	};
 	msghdr_t	hdr;			/* Header record (fixed portion) */
 	char		*to,			/* To name */
 				*to_ext,		/* To extension */
@@ -552,8 +614,18 @@ typedef struct {				/* Message */
 				*ftn_bbsid,		/* FTN BBSID */
 				*ftn_msgid,		/* FTN MSGID */
 				*ftn_reply;		/* FTN REPLY */
-	char*		summary;		/* Summary  */
-	char*		subj;			/* Subject  */
+	union {
+		char*	summary;		/* Message Summary  */
+		char*	desc;			/* File description */
+	};
+	union {
+		char*	subj;			/* Subject  */
+		char*	name;			/* Filename */
+	};
+	union {
+		uchar*	text;			/* Message body text (optional) */
+		char*	extdesc;		/* File extended description */
+	};
 	char*		tags;			/* Message tags (space-delimited) */
 	char*		editor;			/* Message editor (if known) */
 	char*		mime_version;	/* MIME Version (if applicable) */
@@ -571,7 +643,7 @@ typedef struct {				/* Message */
 	hfield_t	*hfield;		/* Header fields (fixed length portion) */
 	void		**hfield_dat;	/* Header fields (variable length portion) */
 	dfield_t	*dfield;		/* Data fields (fixed length portion) */
-	int32_t		offset; 		/* Offset (number of records) into index */
+	int32_t		idx_offset;		/* Offset (number of records) into index */
 	BOOL		forwarded;		/* Forwarded from agent to another */
 	uint32_t	expiration; 	/* Message will expire on this day (if >0) */
 	uint32_t	cost;			/* Cost to download/read */
@@ -580,11 +652,15 @@ typedef struct {				/* Message */
 	uint32_t	upvotes;		/* Vote tally for this message */
 	uint32_t	downvotes;		/* Vote tally for this message */
 	uint32_t	total_votes;	/* Total votes for this message or poll */
+								/* Not written to the database: */
+	int32_t		dir;			/* Directory number */
+	off_t		size;			/* File size (current) */
+	time_t		time;			/* File modification date/timestamp (current) */
 	uint8_t		columns;		/* 0 means unknown or N/A */
 
-} smbmsg_t;
+} smbmsg_t, smbfile_t;
 
-typedef struct {				/* Message base */
+typedef struct {				/* Message/File base */
 
     char		file[128];      /* Path and base filename (no extension) */
     FILE*		sdt_fp;			/* File pointer for data (.sdt) file */
@@ -597,12 +673,18 @@ typedef struct {				/* Message base */
 	uint32_t	retry_delay;	/* Time-slice yield (milliseconds) while retrying */
 	smbstatus_t status; 		/* Status header record */
 	BOOL		locked;			/* SMB header is locked */
-	BOOL		continue_on_error;			/* Attempt recovery after some normaly fatal errors */
+	BOOL		continue_on_error;			/* Attempt recovery after some normally fatal errors */
 	char		last_error[MAX_PATH*2];		/* Last error message */
 
 	/* Private member variables (not initialized by or used by smblib) */
-	uint32_t	subnum;			/* Sub-board number */
-	uint32_t	msgs;			/* Number of messages loaded (for user) */
+	union {
+		uint32_t	subnum;		/* Sub-board number */
+		uint32_t	dirnum;		/* Directory number */
+	};
+	union {
+		uint32_t	msgs;		/* Number of messages loaded (for user) */
+		uint32_t	files;		/* Number of files loaded */
+	};
 	uint32_t	curmsg;			/* Current message number (for user, 0-based) */
 
 } smb_t;
diff --git a/src/smblib/smbdump.c b/src/smblib/smbdump.c
index 107bd66615..ccd753905a 100644
--- a/src/smblib/smbdump.c
+++ b/src/smblib/smbdump.c
@@ -46,7 +46,7 @@ static char *binstr(uchar *buf, uint16_t length)
 	return(str);
 }
 
-str_list_t SMBCALL smb_msghdr_str_list(smbmsg_t* msg)
+str_list_t smb_msghdr_str_list(smbmsg_t* msg)
 {
 	char tmp[128];
 	int i;
@@ -61,6 +61,11 @@ str_list_t SMBCALL smb_msghdr_str_list(smbmsg_t* msg)
 	/* variable fields */
 	for(i=0;i<msg->total_hfields;i++) {
 		switch(msg->hfield[i].type) {
+			case SMB_COST:
+				strListAppendFormat(&list, HFIELD_NAME_FMT "%lu"
+					,smb_hfieldtype(msg->hfield[i].type)
+					,(ulong)*(uint32_t*)msg->hfield_dat[i]);
+				break;
 			case SMB_COLUMNS:
 				strListAppendFormat(&list, HFIELD_NAME_FMT "%u"
 					,smb_hfieldtype(msg->hfield[i].type)
@@ -168,7 +173,7 @@ str_list_t SMBCALL smb_msghdr_str_list(smbmsg_t* msg)
 	return list;
 }
 
-void SMBCALL smb_dump_msghdr(FILE* fp, smbmsg_t* msg)
+void smb_dump_msghdr(FILE* fp, smbmsg_t* msg)
 {
 	int i;
 
diff --git a/src/smblib/smbfile.c b/src/smblib/smbfile.c
index c1269cb726..f96426376b 100644
--- a/src/smblib/smbfile.c
+++ b/src/smblib/smbfile.c
@@ -1,6 +1,4 @@
-/* Synchronet message base (SMB) FILE stream I/O routines */
-
-/* $Id: smbfile.c,v 1.17 2020/04/14 07:08:50 rswindell Exp $ */
+/* Synchronet message base (SMB) FILE stream and FileBase routines  */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -15,82 +13,70 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
 #include "smblib.h"
 
-int SMBCALL smb_feof(FILE* fp)
+int smb_feof(FILE* fp)
 {
 	return(feof(fp));
 }
 
-int SMBCALL smb_ferror(FILE* fp)
+int smb_ferror(FILE* fp)
 {
 	return(ferror(fp));
 }
 
-int SMBCALL smb_fflush(FILE* fp)
+int smb_fflush(FILE* fp)
 {
 	return(fflush(fp));
 }
 
-int SMBCALL smb_fgetc(FILE* fp)
+int smb_fgetc(FILE* fp)
 {
 	return(fgetc(fp));
 }
 
-int SMBCALL smb_fputc(int ch, FILE* fp)
+int smb_fputc(int ch, FILE* fp)
 {
 	return(fputc(ch,fp));
 }
 
-int SMBCALL smb_fseek(FILE* fp, long offset, int whence)
+int smb_fseek(FILE* fp, off_t offset, int whence)
 {
-	return(fseek(fp,offset,whence));
+	return(fseeko(fp,offset,whence));
 }
 
-long SMBCALL smb_ftell(FILE* fp)
+off_t smb_ftell(FILE* fp)
 {
-	return(ftell(fp));
+	return(ftello(fp));
 }
 
-long SMBCALL smb_fgetlength(FILE* fp)
+off_t smb_fgetlength(FILE* fp)
 {
 	return(filelength(fileno(fp)));
 }
 
-int SMBCALL smb_fsetlength(FILE* fp, long length)
+int smb_fsetlength(FILE* fp, long length)
 {
 	return(chsize(fileno(fp),length));
 }
 
-void SMBCALL smb_rewind(FILE* fp)
+void smb_rewind(FILE* fp)
 {
 	rewind(fp);
 }
 
-void SMBCALL smb_clearerr(FILE* fp)
+void smb_clearerr(FILE* fp)
 {
 	clearerr(fp);
 }
 
-size_t SMBCALL smb_fread(smb_t* smb, void* buf, size_t bytes, FILE* fp)
+size_t smb_fread(smb_t* smb, void* buf, size_t bytes, FILE* fp)
 {
 	size_t ret;
 	time_t start=0;
@@ -114,7 +100,7 @@ size_t SMBCALL smb_fread(smb_t* smb, void* buf, size_t bytes, FILE* fp)
 	#pragma argsused
 #endif
 
-size_t SMBCALL smb_fwrite(smb_t* smb, const void* buf, size_t bytes, FILE* fp)
+size_t smb_fwrite(smb_t* smb, const void* buf, size_t bytes, FILE* fp)
 {
 	return(fwrite(buf,1,bytes,fp));
 }
@@ -124,7 +110,7 @@ size_t SMBCALL smb_fwrite(smb_t* smb, const void* buf, size_t bytes, FILE* fp)
 /* Retries for retry_time number of seconds									*/
 /* Return 0 on success, non-zero otherwise									*/
 /****************************************************************************/
-int SMBCALL smb_open_fp(smb_t* smb, FILE** fp, int share)
+int smb_open_fp(smb_t* smb, FILE** fp, int share)
 {
 	int 	file;
 	char	path[MAX_PATH+1];
@@ -188,7 +174,7 @@ int SMBCALL smb_open_fp(smb_t* smb, FILE** fp, int share)
 
 /****************************************************************************/
 /****************************************************************************/
-void SMBCALL smb_close_fp(FILE** fp)
+void smb_close_fp(FILE** fp)
 {
 	if(fp!=NULL) {
 		if(*fp!=NULL)
@@ -196,3 +182,256 @@ void SMBCALL smb_close_fp(FILE** fp)
 		*fp=NULL;
 	}
 }
+
+/****************************************************************************/
+/* maxlen includes the NUL terminator										*/
+/****************************************************************************/
+char* smb_fileidxname(const char* filename, char* buf, size_t maxlen)
+{
+	size_t fnlen = strlen(filename);
+	char* ext = getfext(filename);
+	if(ext != NULL) {
+		size_t extlen = strlen(ext);
+		if(extlen >= maxlen - 1) {
+			strncpy(buf, filename, maxlen);
+			buf[maxlen - 1] = '\0';
+		}
+		else {
+			fnlen -= extlen;
+			if(fnlen > (maxlen - 1) - extlen)
+				fnlen = (maxlen - 1) - extlen;
+			safe_snprintf(buf, maxlen, "%-.*s%s", (int)fnlen, filename, ext);
+		}
+	} else {	/* no extension */
+		strncpy(buf, filename, maxlen);
+		buf[maxlen - 1] = '\0';
+	}
+	return buf;
+}
+
+/****************************************************************************/
+/* Find file in index via either/or:										*/
+/* -  CASE-INSENSITIVE 'filename' search through index (no wildcards)		*/
+/* -  file content size and hash details found in 'file'					*/
+/****************************************************************************/
+int smb_findfile(smb_t* smb, const char* filename, smbfile_t* file)
+{
+	long offset = 0;
+	smbfile_t* f = file;
+	smbfile_t file_ = {0};
+	if(f == NULL)
+		f = &file_;
+	char fname[SMB_FILEIDX_NAMELEN + 1] = "";
+	if(filename != NULL)
+		smb_fileidxname(filename, fname, sizeof(fname));
+
+	if(smb->sid_fp == NULL) {
+		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s msgbase not open", __FUNCTION__);
+		return SMB_ERR_NOT_OPEN;
+	}
+	f->dir = smb->dirnum;
+	rewind(smb->sid_fp);
+	while(!feof(smb->sid_fp)) {
+		fileidxrec_t fidx;
+
+		if(smb_fread(smb, &fidx, sizeof(fidx), smb->sid_fp) != sizeof(fidx))
+			break;
+
+		f->idx_offset = offset++;
+
+		if(filename != NULL) {
+			if(stricmp(fidx.name, fname) != 0)
+				continue;
+			f->file_idx = fidx;
+			return SMB_SUCCESS;
+		}
+
+		if(file == NULL)
+			continue;
+
+		if((f->file_idx.hash.flags & SMB_HASH_MASK) != 0 || f->file_idx.idx.size > 0) {
+			if(f->file_idx.idx.size > 0 && f->file_idx.idx.size != fidx.idx.size)
+				continue;
+			if((f->file_idx.hash.flags & SMB_HASH_CRC16) && f->file_idx.hash.data.crc16 != fidx.hash.data.crc16)
+				continue;
+			if((f->file_idx.hash.flags & SMB_HASH_CRC32) && f->file_idx.hash.data.crc32 != fidx.hash.data.crc32)
+				continue;
+			if((f->file_idx.hash.flags & SMB_HASH_MD5)
+				&& memcmp(f->file_idx.hash.data.md5, fidx.hash.data.md5, sizeof(fidx.hash.data.md5)) !=0)
+				continue;
+			if((f->file_idx.hash.flags & SMB_HASH_SHA1)
+				&& memcmp(f->file_idx.hash.data.sha1, fidx.hash.data.sha1, sizeof(fidx.hash.data.sha1)) !=0)
+				continue;
+			f->file_idx = fidx;
+			return SMB_SUCCESS;
+		}
+	}
+	return SMB_ERR_NOT_FOUND;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+int smb_loadfile(smb_t* smb, const char* filename, smbfile_t* file, enum file_detail detail)
+{
+	int result;
+
+	memset(file, 0, sizeof(*file));
+
+	if((result = smb_findfile(smb, filename, file)) != SMB_SUCCESS)
+		return result;
+
+	return smb_getfile(smb, file, detail);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+int smb_getfile(smb_t* smb, smbfile_t* file, enum file_detail detail)
+{
+	int result;
+
+	file->name = file->file_idx.name;
+	file->hdr.when_written.time = file->idx.time;
+	if(detail > file_detail_index) {
+		if((result = smb_getmsghdr(smb, file)) != SMB_SUCCESS)
+			return result;
+		if(detail >= file_detail_extdesc)
+			file->extdesc = smb_getmsgtxt(smb, file, GETMSGTXT_ALL);
+	}
+	file->dir = smb->dirnum;
+
+	return SMB_SUCCESS;
+}
+
+/****************************************************************************/
+/* Writes both header and index information for file 'file'                 */
+/* Like smb_putmsg() but doesn't (re)-initialize index (idx)				*/
+/****************************************************************************/
+int smb_putfile(smb_t* smb, smbfile_t* file)
+{
+	int result;
+
+	if((result = smb_putmsghdr(smb, file))!=SMB_SUCCESS)
+		return result;
+
+	return smb_putmsgidx(smb, file);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+void smb_freefilemem(smbfile_t* file)
+{
+	smb_freemsgmem(file);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+int smb_addfile(smb_t* smb, smbfile_t* file, int storage, const char* extdesc, const char* path)
+{
+	if(file->name == NULL || *file->name == '\0') {
+		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s missing name", __FUNCTION__);
+		return SMB_ERR_HDR_FIELD;
+	}
+	if(smb_findfile(smb, file->name, NULL) == SMB_SUCCESS) {
+		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s duplicate name found: %s", __FUNCTION__, file->name);
+		return SMB_DUPE_MSG;
+	}
+	if(path != NULL) {
+		file->size = flength(path);
+		file->hdr.when_written.time = (uint32_t)fdate(path);
+		if(!(smb->status.attr & SMB_NOHASH) && file->file_idx.hash.flags == 0)
+			file->file_idx.hash.flags = smb_hashfile(path, file->size, &file->file_idx.hash.data);
+	}
+	file->hdr.attr |= MSG_FILE;
+	file->hdr.type = SMB_MSG_TYPE_FILE;
+	return smb_addmsg(smb, file, storage, SMB_HASH_SOURCE_NONE, XLAT_NONE, /* body: */(const uchar*)extdesc, /* tail: */NULL);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+int smb_renewfile(smb_t* smb, smbfile_t* file, int storage, const char* path)
+{
+	int result;
+	if((result = smb_removefile(smb, file)) != SMB_SUCCESS)
+		return result;
+	return smb_addfile(smb, file, storage, file->extdesc, path);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+int smb_removefile(smb_t* smb, smbfile_t* file)
+{
+	int result;
+	int removed = 0;
+
+	if(!smb->locked && smb_locksmbhdr(smb) != SMB_SUCCESS)
+		return SMB_ERR_LOCK;
+
+	file->hdr.attr |= MSG_DELETE;
+	if((result = smb_putmsghdr(smb, file)) != SMB_SUCCESS) {
+		smb_unlocksmbhdr(smb);
+		return result;
+	}
+	if((result = smb_getstatus(smb)) != SMB_SUCCESS) {
+		smb_unlocksmbhdr(smb);
+		return result;
+	}
+	if((result = smb_open_ha(smb)) != SMB_SUCCESS) {
+		smb_unlocksmbhdr(smb);
+		return result;
+	}
+	if((result = smb_open_da(smb)) != SMB_SUCCESS) {
+		smb_unlocksmbhdr(smb);
+		return result;
+	}
+	result = smb_freemsg(smb, file);
+	smb_close_ha(smb);
+	smb_close_da(smb);
+
+	// Now remove from index:
+	if(result == SMB_SUCCESS) {
+		rewind(smb->sid_fp);
+		fileidxrec_t* fidx = malloc(smb->status.total_files * sizeof(*fidx));
+		if(fidx == NULL) {
+			smb_unlocksmbhdr(smb);
+			return SMB_ERR_MEM;
+		}
+		if(fread(fidx, sizeof(*fidx), smb->status.total_files, smb->sid_fp) != smb->status.total_files) {
+			free(fidx);
+			smb_unlocksmbhdr(smb);
+			return SMB_ERR_READ;
+		}
+		rewind(smb->sid_fp);
+		for(uint32_t i = 0; i < smb->status.total_files; i++) {
+			if(stricmp(fidx[i].name, file->name) == 0) {
+				removed++;
+				continue;
+			}
+			if(fwrite(fidx + i, sizeof(*fidx), 1, smb->sid_fp) != 1) {
+				safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s re-writing index"
+					,__FUNCTION__);
+				result = SMB_ERR_WRITE;
+				break;
+			}
+		}
+		free(fidx);
+		if(result == SMB_SUCCESS) {
+			if(removed < 1) {
+				safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s name found: %s"
+					,__FUNCTION__, file->name);
+				result = SMB_ERR_NOT_FOUND;
+			} else {
+				fflush(smb->sid_fp);
+				smb->status.total_files -= removed;
+				if(chsize(fileno(smb->sid_fp), smb->status.total_files * sizeof(*fidx)) != 0) {
+					safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s error %d truncating index"
+						,__FUNCTION__, errno);
+					result = SMB_ERR_DELETE;
+				} else
+					result = smb_putstatus(smb);
+			}
+		}
+	}
+
+	smb_unlocksmbhdr(smb);
+	return result;
+}
diff --git a/src/smblib/smbhash.c b/src/smblib/smbhash.c
index 49d3c054b9..e884c5235b 100644
--- a/src/smblib/smbhash.c
+++ b/src/smblib/smbhash.c
@@ -1,8 +1,5 @@
 /* Synchronet message base (SMB) hash-related functions */
 
-/* $Id: smbhash.c,v 1.36 2019/04/11 01:00:30 rswindell Exp $ */
-// vi: tabstop=4
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -16,21 +13,9 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -39,12 +24,13 @@
 #include <ctype.h>		/* isspace()*/
 #include "smblib.h"
 #include "md5.h"
+#include "sha1.h"
 #include "crc16.h"
 #include "crc32.h"
 #include "genwrap.h"
 
 /* If return value is SMB_ERR_NOT_FOUND, hash file is left open */
-int SMBCALL smb_findhash(smb_t* smb, hash_t** compare, hash_t* found_hash, 
+int smb_findhash(smb_t* smb, hash_t** compare, hash_t* found_hash, 
 						 long source_mask, BOOL mark)
 {
 	int		retval;
@@ -87,15 +73,18 @@ int SMBCALL smb_findhash(smb_t* smb, hash_t** compare, hash_t* found_hash,
 				if((compare[c]->flags&hash.flags&SMB_HASH_MASK)==0)	
 					continue;	/* no matching hashes */
 				if((compare[c]->flags&hash.flags&SMB_HASH_CRC16)
-					&& compare[c]->crc16!=hash.crc16)
+					&& compare[c]->data.crc16!=hash.data.crc16)
 					continue;	/* wrong crc-16 */
 				if((compare[c]->flags&hash.flags&SMB_HASH_CRC32)
-					&& compare[c]->crc32!=hash.crc32)
+					&& compare[c]->data.crc32!=hash.data.crc32)
 					continue;	/* wrong crc-32 */
 				if((compare[c]->flags&hash.flags&SMB_HASH_MD5)
-					&& memcmp(compare[c]->md5,hash.md5,sizeof(hash.md5)))
+					&& memcmp(compare[c]->data.md5,hash.data.md5,sizeof(hash.data.md5)))
 					continue;	/* wrong MD5 */
-				
+				if((compare[c]->flags&hash.flags&SMB_HASH_SHA1)
+					&& memcmp(compare[c]->data.sha1,hash.data.sha1,sizeof(hash.data.sha1)))
+					continue;	/* wrong SHA1 */
+
 				/* successful match! */
 				break;	/* can't match more than one, so stop comparing */
 			}
@@ -123,7 +112,7 @@ int SMBCALL smb_findhash(smb_t* smb, hash_t** compare, hash_t* found_hash,
 	return(SMB_ERR_NOT_FOUND);
 }
 
-int SMBCALL smb_addhashes(smb_t* smb, hash_t** hashes, BOOL skip_marked)
+int smb_addhashes(smb_t* smb, hash_t** hashes, BOOL skip_marked)
 {
 	int		retval;
 	size_t	h;
@@ -187,7 +176,7 @@ static char* strip_ctrla(uchar* dst, const uchar* src)
 
 /* Allocates and calculates hashes of data (based on flags)					*/
 /* Returns NULL on failure													*/
-hash_t* SMBCALL smb_hash(ulong msgnum, uint32_t t, unsigned source, unsigned flags
+hash_t* smb_hash(ulong msgnum, uint32_t t, unsigned source, unsigned flags
 						 ,const void* data, size_t length)
 {
 	hash_t*	hash;
@@ -205,11 +194,13 @@ hash_t* SMBCALL smb_hash(ulong msgnum, uint32_t t, unsigned source, unsigned fla
 	hash->source=source;
 	hash->flags=flags;
 	if(flags&SMB_HASH_CRC16)
-		hash->crc16=crc16((char*)data,length);
+		hash->data.crc16=crc16((char*)data,length);
 	if(flags&SMB_HASH_CRC32)
-		hash->crc32=crc32((char*)data,length);
+		hash->data.crc32=crc32((char*)data,length);
 	if(flags&SMB_HASH_MD5)
-		MD5_calc(hash->md5,data,length);
+		MD5_calc(hash->data.md5,data,length);
+	if(flags&SMB_HASH_SHA1)
+		SHA1_calc(hash->data.sha1, data, length);
 
 	return(hash);
 }
@@ -217,7 +208,7 @@ hash_t* SMBCALL smb_hash(ulong msgnum, uint32_t t, unsigned source, unsigned fla
 /* Allocates and calculates hashes of data (based on flags)					*/
 /* Supports string hash "pre-processing" (e.g. lowercase, strip whitespace)	*/
 /* Returns NULL on failure													*/
-hash_t* SMBCALL smb_hashstr(ulong msgnum, uint32_t t, unsigned source, unsigned flags
+hash_t* smb_hashstr(ulong msgnum, uint32_t t, unsigned source, unsigned flags
 							,const char* str)
 {
 	char*	p=NULL;
@@ -245,10 +236,10 @@ hash_t* SMBCALL smb_hashstr(ulong msgnum, uint32_t t, unsigned source, unsigned
 
 /* Allocates and calculates all hashes for a single message					*/
 /* Returns NULL on failure													*/
-hash_t** SMBCALL smb_msghashes(smbmsg_t* msg, const uchar* body, long source_mask)
+hash_t** smb_msghashes(smbmsg_t* msg, const uchar* body, long source_mask)
 {
 	size_t		h=0;
-	uchar		flags=SMB_HASH_CRC16|SMB_HASH_CRC32|SMB_HASH_MD5;
+	uchar		flags=SMB_HASH_CRC16|SMB_HASH_CRC32|SMB_HASH_MD5|SMB_HASH_SHA1;
 	hash_t**	hashes;	/* This is a NULL-terminated list of hashes */
 	hash_t*		hash;
 	time_t		t=time(NULL);
@@ -289,7 +280,7 @@ hash_t** SMBCALL smb_msghashes(smbmsg_t* msg, const uchar* body, long source_mas
 	return(hashes);
 }
 
-void SMBCALL smb_freehashes(hash_t** hashes)
+void smb_freehashes(hash_t** hashes)
 {
 	size_t		n;
 
@@ -297,14 +288,14 @@ void SMBCALL smb_freehashes(hash_t** hashes)
 }
 
 /* Calculates and stores the hashes for a single message					*/
-int SMBCALL smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL update)
+int smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL update)
 {
 	size_t		n;
 	int			retval=SMB_SUCCESS;
 	hash_t		found;
 	hash_t**	hashes;	/* This is a NULL-terminated list of hashes */
 
-	if(smb->status.attr&(SMB_EMAIL|SMB_NOHASH))
+	if(smb->status.attr&(SMB_EMAIL | SMB_NOHASH | SMB_FILE_DIRECTORY))
 		return(SMB_SUCCESS);
 
 	hashes=smb_msghashes(msg,text,SMB_HASH_SOURCE_DUPE);
@@ -326,7 +317,7 @@ int SMBCALL smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL updat
 }
 
 /* length=0 specifies ASCIIZ data											*/
-int SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
+int smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
 								 ,unsigned flags, const void* data, size_t length)
 {
 	int			retval;
@@ -360,7 +351,7 @@ int SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
 	return(retval);
 }
 
-int SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
+int smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
 								 ,unsigned flags, const void* data, size_t length)
 {
 	int retval;
@@ -378,7 +369,7 @@ int SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
 	return(retval);
 }
 
-uint16_t SMBCALL smb_subject_crc(const char* subj)
+uint16_t smb_subject_crc(const char* subj)
 {
 	char*	str;
 	uint16_t	crc;
@@ -402,7 +393,7 @@ uint16_t SMBCALL smb_subject_crc(const char* subj)
 	return(crc);
 }
 
-uint16_t SMBCALL smb_name_crc(const char* name)
+uint16_t smb_name_crc(const char* name)
 {
 	char*	str;
 	uint16_t	crc;
@@ -419,3 +410,38 @@ uint16_t SMBCALL smb_name_crc(const char* name)
 
 	return(crc);
 }
+
+// Returns hashflags_t on success
+int smb_hashfile(const char* path, off_t size, struct hash_data* data)
+{
+	char buf[256 * 1024];
+	FILE*	fp;
+	MD5 md5_ctx;
+	SHA1_CTX sha1_ctx;
+
+	if(size < 1)
+		return 0;
+
+	if((fp = fopen(path, "rb")) == NULL)
+		return 0;
+
+	MD5_open(&md5_ctx);
+	SHA1Init(&sha1_ctx);
+	data->crc16 = 0;
+	data->crc32 = 0;
+	off_t off = 0;
+	while(!feof(fp) && off < size) {
+		size_t rd = fread(buf, sizeof(uint8_t), sizeof(buf), fp);
+		if(rd < 1)
+			break;
+		data->crc32 = crc32i(~data->crc32, buf, rd);
+		data->crc16 = icrc16(data->crc16, buf, rd);
+		MD5_digest(&md5_ctx, buf, rd);
+		SHA1Update(&sha1_ctx, (unsigned char*)buf, rd);
+		off += rd;
+	}
+	fclose(fp);
+	MD5_close(&md5_ctx, data->md5);
+	SHA1Final(&sha1_ctx, data->sha1);
+	return SMB_HASH_CRC16 | SMB_HASH_CRC32 | SMB_HASH_MD5 | SMB_HASH_SHA1;
+}
diff --git a/src/smblib/smblib.c b/src/smblib/smblib.c
index 41b8ae62e2..36a5659e41 100644
--- a/src/smblib/smblib.c
+++ b/src/smblib/smblib.c
@@ -36,18 +36,18 @@
 #include "filewrap.h"
 
 /* Use smb_ver() and smb_lib_ver() to obtain these values */
-#define SMBLIB_VERSION		"2.61"      /* SMB library version */
-#define SMB_VERSION 		0x0121		/* SMB format version */
+#define SMBLIB_VERSION		"3.00"      /* SMB library version */
+#define SMB_VERSION 		0x0300		/* SMB format version */
 										/* High byte major, low byte minor */
 
 static char* nulstr="";
 
-int SMBCALL smb_ver(void)
+int smb_ver(void)
 {
 	return(SMB_VERSION);
 }
 
-char* SMBCALL smb_lib_ver(void)
+char* smb_lib_ver(void)
 {
 	return(SMBLIB_VERSION);
 }
@@ -56,7 +56,7 @@ char* SMBCALL smb_lib_ver(void)
 /* Open a message base of name 'smb->file'                                  */
 /* Opens files for READing messages or updating message indices only        */
 /****************************************************************************/
-int SMBCALL smb_open(smb_t* smb)
+int smb_open(smb_t* smb)
 {
 	int			i;
 	time_t		start=0;
@@ -100,13 +100,13 @@ int SMBCALL smb_open(smb_t* smb)
 			smb_close(smb);
 			return(SMB_ERR_READ);
 		}
-		if(memcmp(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID) && !smb->continue_on_error) {
+		if(memcmp(hdr.smbhdr_id,SMB_HEADER_ID,LEN_HEADER_ID) && !smb->continue_on_error) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
 				,"%s corrupt SMB header ID: %02X %02X %02X %02X", __FUNCTION__
-				,hdr.id[0]
-				,hdr.id[1]
-				,hdr.id[2]
-				,hdr.id[3]
+				,hdr.smbhdr_id[0]
+				,hdr.smbhdr_id[1]
+				,hdr.smbhdr_id[2]
+				,hdr.smbhdr_id[3]
 				);
 			smb_close(smb);
 			return(SMB_ERR_HDR_ID); 
@@ -139,7 +139,7 @@ int SMBCALL smb_open(smb_t* smb)
 	return(SMB_SUCCESS);
 }
 
-int SMBCALL smb_open_index(smb_t* smb)
+int smb_open_index(smb_t* smb)
 {
 	return smb_open_fp(smb, &smb->sid_fp, SH_DENYNO);
 }
@@ -147,7 +147,7 @@ int SMBCALL smb_open_index(smb_t* smb)
 /****************************************************************************/
 /* Closes the currently open message base									*/
 /****************************************************************************/
-void SMBCALL smb_close(smb_t* smb)
+void smb_close(smb_t* smb)
 {
 	if(smb->shd_fp!=NULL) {
 		smb_unlocksmbhdr(smb);		   /* In case it's been locked */
@@ -176,7 +176,7 @@ static char* smb_lockfname(smb_t* smb, char* fname, size_t maxlen)
 /* This function is used to lock an entire message base for exclusive		*/
 /* (typically for maintenance/repair)										*/
 /****************************************************************************/
-int SMBCALL smb_lock(smb_t* smb)
+int smb_lock(smb_t* smb)
 {
 	char	path[MAX_PATH+1];
 	int		file;
@@ -199,7 +199,7 @@ int SMBCALL smb_lock(smb_t* smb)
 	return(SMB_SUCCESS);
 }
 
-int SMBCALL smb_unlock(smb_t* smb)
+int smb_unlock(smb_t* smb)
 {
 	char	path[MAX_PATH+1];
 
@@ -213,7 +213,7 @@ int SMBCALL smb_unlock(smb_t* smb)
 	return(SMB_SUCCESS);
 }
 
-BOOL SMBCALL smb_islocked(smb_t* smb)
+BOOL smb_islocked(smb_t* smb)
 {
 	char	path[MAX_PATH+1];
 
@@ -228,7 +228,7 @@ BOOL SMBCALL smb_islocked(smb_t* smb)
 /* Retries for smb.retry_time number of seconds								*/
 /* Return 0 on success, non-zero otherwise									*/
 /****************************************************************************/
-int SMBCALL smb_trunchdr(smb_t* smb)
+int smb_trunchdr(smb_t* smb)
 {
 	time_t	start=0;
 
@@ -267,7 +267,7 @@ int SMBCALL smb_trunchdr(smb_t* smb)
 /****************************************************************************/
 /* Attempts for smb.retry_time number of seconds to lock the msg base hdr	*/
 /****************************************************************************/
-int SMBCALL smb_locksmbhdr(smb_t* smb)
+int smb_locksmbhdr(smb_t* smb)
 {
 	time_t	start=0;
 
@@ -302,7 +302,7 @@ int SMBCALL smb_locksmbhdr(smb_t* smb)
 /****************************************************************************/
 /* Read the SMB header from the header file and place into smb.status		*/
 /****************************************************************************/
-int SMBCALL smb_getstatus(smb_t* smb)
+int smb_getstatus(smb_t* smb)
 {
 	int 	i;
 
@@ -329,7 +329,7 @@ int SMBCALL smb_getstatus(smb_t* smb)
 /****************************************************************************/
 /* Writes message base header												*/
 /****************************************************************************/
-int SMBCALL smb_putstatus(smb_t* smb)
+int smb_putstatus(smb_t* smb)
 {
 	int i;
 
@@ -356,7 +356,7 @@ int SMBCALL smb_putstatus(smb_t* smb)
 /****************************************************************************/
 /* Unlocks previously locked message base header 							*/
 /****************************************************************************/
-int SMBCALL smb_unlocksmbhdr(smb_t* smb)
+int smb_unlocksmbhdr(smb_t* smb)
 {
 	if(smb->locked) {
 		if(smb->shd_fp==NULL) {
@@ -380,7 +380,7 @@ int SMBCALL smb_unlocksmbhdr(smb_t* smb)
 /****************************************************************************/
 /* Is the offset a valid message header offset?								*/
 /****************************************************************************/
-BOOL SMBCALL smb_valid_hdr_offset(smb_t* smb, ulong offset)
+BOOL smb_valid_hdr_offset(smb_t* smb, ulong offset)
 {
 	if(offset<sizeof(smbhdr_t)+sizeof(smbstatus_t) 
 		|| offset<smb->status.header_offset) {
@@ -395,7 +395,7 @@ BOOL SMBCALL smb_valid_hdr_offset(smb_t* smb, ulong offset)
 /****************************************************************************/
 /* Attempts for smb.retry_time number of seconds to lock the hdr for 'msg'  */
 /****************************************************************************/
-int SMBCALL smb_lockmsghdr(smb_t* smb, smbmsg_t* msg)
+int smb_lockmsghdr(smb_t* smb, smbmsg_t* msg)
 {
 	time_t	start=0;
 
@@ -430,12 +430,13 @@ int SMBCALL smb_lockmsghdr(smb_t* smb, smbmsg_t* msg)
 /* Either msg->hdr.number or msg->offset must be initialized before 		*/
 /* calling this function													*/
 /****************************************************************************/
-int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
+int smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
 {
 	idxrec_t	idx;
 	long		byte_offset;
 	ulong		l,total,bot,top;
-	long		length;
+	off_t		length;
+	size_t		idxreclen = smb_idxreclen(smb);
 
 	if(smb->sid_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s index not open", __FUNCTION__);
@@ -444,12 +445,12 @@ int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
 	clearerr(smb->sid_fp);
 
 	length=filelength(fileno(smb->sid_fp));
-	if(length<(long)sizeof(idxrec_t)) {
+	if(length<(long)idxreclen) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s invalid index file length: %ld", __FUNCTION__,length);
 		return(SMB_ERR_FILE_LEN);
 	}
-	total=length/sizeof(idxrec_t);
+	total=(ulong)(length/idxreclen);
 	if(!total) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s invalid index file length: %ld", __FUNCTION__,length);
@@ -457,14 +458,14 @@ int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
 	}
 
 	if(!msg->hdr.number) {
-		if(msg->offset<0)
-			byte_offset=length-((-msg->offset)*sizeof(idxrec_t));
+		if(msg->idx_offset<0)
+			byte_offset=(long)(length-((-msg->idx_offset)*idxreclen));
 		else
-			byte_offset=msg->offset*sizeof(idxrec_t);
+			byte_offset=msg->idx_offset*idxreclen;
 		if(byte_offset>=length) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
 				,"%s invalid index offset: %ld, byte offset: %ld, length: %ld", __FUNCTION__
-				,(long)msg->offset, byte_offset, length);
+				,(long)msg->idx_offset, byte_offset, length);
 			return(SMB_ERR_HDR_OFFSET);
 		}
 		if(ftell(smb->sid_fp) != byte_offset) {
@@ -472,18 +473,18 @@ int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
 				safe_snprintf(smb->last_error,sizeof(smb->last_error)
 					,"%s %d '%s' seeking to offset %ld (byte %lu) in index file", __FUNCTION__
 					,get_errno(),STRERROR(get_errno())
-					,(long)msg->offset,byte_offset);
+					,(long)msg->idx_offset,byte_offset);
 				return(SMB_ERR_SEEK);
 			}
 		}
-		if(smb_fread(smb,&msg->idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
+		if(smb_fread(smb,&msg->idx,sizeof(msg->idx),smb->sid_fp)!=sizeof(msg->idx)) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
 				,"%s reading index at offset %ld (byte %lu)", __FUNCTION__
-				,(long)msg->offset,byte_offset);
+				,(long)msg->idx_offset,byte_offset);
 			return(SMB_ERR_READ);
 		}
 		/* Save the correct offset (from the beginning of the file) */
-		msg->offset=byte_offset/sizeof(idxrec_t);
+		msg->idx_offset=byte_offset/idxreclen;
 		return(SMB_SUCCESS); 
 	}
 
@@ -496,17 +497,17 @@ int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
 				, __FUNCTION__, (ulong)msg->hdr.number);
 			return(SMB_ERR_NOT_FOUND);
 		}
-		if(fseek(smb->sid_fp,l*sizeof(idxrec_t),SEEK_SET)) {
+		if(fseek(smb->sid_fp,l*idxreclen,SEEK_SET)) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
 				,"%s %d '%s' seeking to offset %lu (byte %lu) in index file", __FUNCTION__
 				,get_errno(),STRERROR(get_errno())
-				,l,l*sizeof(idxrec_t));
+				,l,l*idxreclen);
 			return(SMB_ERR_SEEK);
 		}
-		if(smb_fread(smb,&idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
+		if(smb_fread(smb,&idx,sizeof(idx),smb->sid_fp)!=sizeof(idx)) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
 				,"%s reading index at offset %lu (byte %lu)", __FUNCTION__
-				,l,l*sizeof(idxrec_t));
+				,l,l*sizeof(idx));
 			return(SMB_ERR_READ);
 		}
 		if(bot==top-1 && idx.number!=msg->hdr.number) {
@@ -527,14 +528,43 @@ int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
 		break; 
 	}
 	msg->idx=idx;
-	msg->offset=l;
+	msg->idx_offset=l;
 	return(SMB_SUCCESS);
 }
 
+/****************************************************************************/
+/* Count the number of msg index records with specific attribute flags		*/
+/****************************************************************************/
+uint32_t smb_count_idx_records(smb_t* smb, uint16_t mask, uint16_t cmp)
+{
+	int32_t offset = 0;
+	uint32_t count = 0;
+	for(offset = 0; ;offset++) {
+		smbmsg_t msg;
+		memset(&msg, 0, sizeof(msg));
+		msg.idx_offset = offset;
+		if(smb_getmsgidx(smb, &msg) != SMB_SUCCESS)
+			break;
+		if((msg.idx.attr & mask) == cmp)
+			count++;
+	}
+	return count;
+}
+
+/****************************************************************************/
+/* Returns the length (in bytes) of the SMB's index records					*/
+/****************************************************************************/
+size_t smb_idxreclen(smb_t* smb)
+{
+	if(smb->status.attr&SMB_FILE_DIRECTORY)
+		return sizeof(fileidxrec_t);
+	return sizeof(idxrec_t);
+}
+
 /****************************************************************************/
 /* Reads the first index record in the open message base 					*/
 /****************************************************************************/
-int SMBCALL smb_getfirstidx(smb_t* smb, idxrec_t *idx)
+int smb_getfirstidx(smb_t* smb, idxrec_t *idx)
 {
 	if(smb->sid_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s index not open", __FUNCTION__);
@@ -547,7 +577,7 @@ int SMBCALL smb_getfirstidx(smb_t* smb, idxrec_t *idx)
 			,get_errno(),STRERROR(get_errno()));
 		return(SMB_ERR_SEEK);
 	}
-	if(smb_fread(smb,idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
+	if(smb_fread(smb,idx,sizeof(*idx),smb->sid_fp)!=sizeof(*idx)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s reading first index", __FUNCTION__);
 		return(SMB_ERR_READ);
@@ -558,9 +588,10 @@ int SMBCALL smb_getfirstidx(smb_t* smb, idxrec_t *idx)
 /****************************************************************************/
 /* Reads the last index record in the open message base 					*/
 /****************************************************************************/
-int SMBCALL smb_getlastidx(smb_t* smb, idxrec_t *idx)
+int smb_getlastidx(smb_t* smb, idxrec_t *idx)
 {
-	long length;
+	off_t length;
+	size_t idxreclen = smb_idxreclen(smb);
 
 	if(smb->sid_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s index not open", __FUNCTION__);
@@ -568,19 +599,19 @@ int SMBCALL smb_getlastidx(smb_t* smb, idxrec_t *idx)
 	}
 	clearerr(smb->sid_fp);
 	length=filelength(fileno(smb->sid_fp));
-	if(length<(long)sizeof(idxrec_t)) {
+	if(length<(long)idxreclen) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s invalid index file length: %ld", __FUNCTION__,length);
 		return(SMB_ERR_FILE_LEN);
 	}
-	if(fseek(smb->sid_fp,length-sizeof(idxrec_t),SEEK_SET)) {
+	if(fseeko(smb->sid_fp,length-idxreclen,SEEK_SET)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s %d '%s' seeking to %u in index file", __FUNCTION__
 			,get_errno(),STRERROR(get_errno())
 			,(unsigned)(length-sizeof(idxrec_t)));
 		return(SMB_ERR_SEEK);
 	}
-	if(smb_fread(smb,idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
+	if(smb_fread(smb,idx,sizeof(*idx),smb->sid_fp)!=sizeof(*idx)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s reading last index", __FUNCTION__);
 		return(SMB_ERR_READ);
@@ -594,12 +625,13 @@ int SMBCALL smb_getlastidx(smb_t* smb, idxrec_t *idx)
 /* must call smb_locksmbhdr() before, smb_unlocksmbhdr() after.				*/
 /* Returns >= 0 on success, negative (SMB_* error) on failure.				*/
 /****************************************************************************/
-long SMBCALL smb_getmsgidx_by_time(smb_t* smb, idxrec_t* match, time_t t)
+long smb_getmsgidx_by_time(smb_t* smb, idxrec_t* match, time_t t)
 {
     int			result;
 	long		match_offset;
 	ulong		total, bot, top;
 	idxrec_t	idx;
+	size_t		idxreclen = smb_idxreclen(smb);
 
 	if(match == NULL)
 		return SMB_BAD_PARAMETER;
@@ -609,7 +641,7 @@ long SMBCALL smb_getmsgidx_by_time(smb_t* smb, idxrec_t* match, time_t t)
 	if(t <= 0)
 		return SMB_BAD_PARAMETER;
 
-	total = filelength(fileno(smb->sid_fp))/sizeof(idxrec_t);
+	total = (ulong)(filelength(fileno(smb->sid_fp))/idxreclen);
 
 	if(!total)	/* Empty base */
 		return SMB_ERR_NOT_FOUND;
@@ -629,9 +661,9 @@ long SMBCALL smb_getmsgidx_by_time(smb_t* smb, idxrec_t* match, time_t t)
 	clearerr(smb->sid_fp);
 	while(bot <= top) {
 		long idx_offset = (bot + top) / 2;
-		if(fseek(smb->sid_fp, idx_offset * sizeof(idxrec_t), SEEK_SET) != 0)
+		if(fseek(smb->sid_fp, idx_offset * idxreclen, SEEK_SET) != 0)
 			return SMB_ERR_SEEK;
-		if(fread(&idx, 1, sizeof(idx), smb->sid_fp) != sizeof(idxrec_t))
+		if(fread(&idx, 1, sizeof(idx), smb->sid_fp) != sizeof(idx))
 			return SMB_ERR_READ;
 		if((time_t)idx.time < t) {
 			bot = idx_offset + 1;
@@ -653,7 +685,7 @@ long SMBCALL smb_getmsgidx_by_time(smb_t* smb, idxrec_t* match, time_t t)
 /* Figures out the total length of the header record for 'msg'              */
 /* Returns length 															*/
 /****************************************************************************/
-ulong SMBCALL smb_getmsghdrlen(smbmsg_t* msg)
+ulong smb_getmsghdrlen(smbmsg_t* msg)
 {
 	int i;
 	ulong length;
@@ -674,7 +706,7 @@ ulong SMBCALL smb_getmsghdrlen(smbmsg_t* msg)
 /* Figures out the total length of the data buffer for 'msg'                */
 /* Returns length															*/
 /****************************************************************************/
-ulong SMBCALL smb_getmsgdatlen(smbmsg_t* msg)
+ulong smb_getmsgdatlen(smbmsg_t* msg)
 {
 	int i;
 	ulong length=0L;
@@ -688,7 +720,7 @@ ulong SMBCALL smb_getmsgdatlen(smbmsg_t* msg)
 /* Figures out the total length of the text buffer for 'msg'                */
 /* Returns length															*/
 /****************************************************************************/
-ulong SMBCALL smb_getmsgtxtlen(smbmsg_t* msg)
+ulong smb_getmsgtxtlen(smbmsg_t* msg)
 {
 	int i;
 	ulong length=0L;
@@ -922,12 +954,12 @@ static void clear_convenience_ptrs(smbmsg_t* msg)
 /* Must call smb_freemsgmem() to free memory allocated for var len strs 	*/
 /* Returns 0 on success, non-zero if error									*/
 /****************************************************************************/
-int SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
+int smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
 {
 	void	*vp,**vpp;
 	size_t	i;
 	long	l,offset;
-	idxrec_t idx;
+	fileidxrec_t idx;
 
 	if(smb->shd_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s msgbase not open", __FUNCTION__);
@@ -941,37 +973,37 @@ int SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
 	if(offset != msg->idx.offset) {
 		if(fseek(smb->shd_fp,msg->idx.offset,SEEK_SET) != 0) {
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
-				,"%s %d '%s' seeking to %lu in header file", __FUNCTION__
+				,"%s %d '%s' seeking to offset %lu in header file", __FUNCTION__
 				,get_errno(),STRERROR(get_errno())
 				,(ulong)msg->idx.offset);
 			return(SMB_ERR_SEEK);
 		}
 	}
 
-	idx=msg->idx;
-	offset=msg->offset;
+	idx = msg->file_idx;
+	offset=msg->idx_offset;
 	memset(msg,0,sizeof(smbmsg_t));
-	msg->idx=idx;
-	msg->offset=offset;
+	msg->file_idx = idx;
+	msg->idx_offset=offset;
 	if(smb_fread(smb,&msg->hdr,sizeof(msghdr_t),smb->shd_fp)!=sizeof(msghdr_t)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
-			,"%s reading msg header", __FUNCTION__);
+			,"%s reading msg header at offset %lu", __FUNCTION__, (ulong)msg->idx.offset);
 		return(SMB_ERR_READ);
 	}
-	if(memcmp(msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID)) {
+	if(memcmp(msg->hdr.msghdr_id,SHD_HEADER_ID,LEN_HEADER_ID)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s corrupt message header ID (%02X %02X %02X %02X) at offset %lu", __FUNCTION__
-			,msg->hdr.id[0]
-			,msg->hdr.id[1]
-			,msg->hdr.id[2]
-			,msg->hdr.id[3]
+			,msg->hdr.msghdr_id[0]
+			,msg->hdr.msghdr_id[1]
+			,msg->hdr.msghdr_id[2]
+			,msg->hdr.msghdr_id[3]
 			,(ulong)msg->idx.offset);
 		return(SMB_ERR_HDR_ID);
 	}
 	if(msg->hdr.version<0x110) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
-			,"%s insufficient header version: %X", __FUNCTION__
-			,msg->hdr.version);
+			,"%s insufficient header version: %X at offset %lu", __FUNCTION__
+			,msg->hdr.version, (ulong)msg->idx.offset);
 		return(SMB_ERR_HDR_VER);
 	}
 	l=sizeof(msg->hdr);
@@ -1059,7 +1091,7 @@ int SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
 /****************************************************************************/
 /* Frees memory allocated for variable-length header fields in 'msg'        */
 /****************************************************************************/
-void SMBCALL smb_freemsghdrmem(smbmsg_t* msg)
+void smb_freemsghdrmem(smbmsg_t* msg)
 {
 	uint16_t	i;
 
@@ -1083,7 +1115,7 @@ void SMBCALL smb_freemsghdrmem(smbmsg_t* msg)
 /****************************************************************************/
 /* Frees memory allocated for 'msg'                                         */
 /****************************************************************************/
-void SMBCALL smb_freemsgmem(smbmsg_t* msg)
+void smb_freemsgmem(smbmsg_t* msg)
 {
 	if(msg->dfield) {
 		free(msg->dfield);
@@ -1093,12 +1125,16 @@ void SMBCALL smb_freemsgmem(smbmsg_t* msg)
 	FREE_AND_NULL(msg->text_subtype);
 	FREE_AND_NULL(msg->text_charset);
 	smb_freemsghdrmem(msg);
+	if(msg->text != NULL) {
+		free(msg->text);
+		msg->text = NULL;
+	}
 }
 
 /****************************************************************************/
 /* Copies memory allocated for 'srcmsg' to 'msg'							*/
 /****************************************************************************/
-int SMBCALL smb_copymsgmem(smb_t* smb, smbmsg_t* msg, smbmsg_t* srcmsg)
+int smb_copymsgmem(smb_t* smb, smbmsg_t* msg, smbmsg_t* srcmsg)
 {
 	int i;
 
@@ -1157,7 +1193,7 @@ int SMBCALL smb_copymsgmem(smb_t* smb, smbmsg_t* msg, smbmsg_t* srcmsg)
 /****************************************************************************/
 /* Unlocks header for 'msg'                                                 */
 /****************************************************************************/
-int SMBCALL smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg)
+int smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg)
 {
 	if(smb->shd_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s msgbase not open", __FUNCTION__);
@@ -1172,7 +1208,7 @@ int SMBCALL smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg)
 /****************************************************************************/
 /* Adds a header field to the 'msg' structure (in memory only)              */
 /****************************************************************************/
-int SMBCALL smb_hfield_add(smbmsg_t* msg, uint16_t type, size_t length, void* data, BOOL insert)
+int smb_hfield_add(smbmsg_t* msg, uint16_t type, size_t length, void* data, BOOL insert)
 {
 	void**		vpp;
 	hfield_t*	hp;
@@ -1210,7 +1246,7 @@ int SMBCALL smb_hfield_add(smbmsg_t* msg, uint16_t type, size_t length, void* da
 /****************************************************************************/
 /* Adds a list of header fields to the 'msg' structure (in memory only)     */
 /****************************************************************************/
-int	SMBCALL smb_hfield_add_list(smbmsg_t* msg, hfield_t** hfield_list, void** hfield_dat, BOOL insert)
+int	smb_hfield_add_list(smbmsg_t* msg, hfield_t** hfield_list, void** hfield_dat, BOOL insert)
 {
 	int			retval;
 	unsigned	n;
@@ -1229,7 +1265,7 @@ int	SMBCALL smb_hfield_add_list(smbmsg_t* msg, hfield_t** hfield_list, void** hf
 /****************************************************************************/
 /* Convenience function to add an ASCIIZ string header field (or blank)		*/
 /****************************************************************************/
-int SMBCALL smb_hfield_add_str(smbmsg_t* msg, uint16_t type, const char* str, BOOL insert)
+int smb_hfield_add_str(smbmsg_t* msg, uint16_t type, const char* str, BOOL insert)
 {
 	return smb_hfield_add(msg, type, str==NULL ? 0:strlen(str), (void*)str, insert);
 }
@@ -1237,7 +1273,7 @@ int SMBCALL smb_hfield_add_str(smbmsg_t* msg, uint16_t type, const char* str, BO
 /****************************************************************************/
 /* Convenience function to add an ASCIIZ string header field (NULL ignored)	*/
 /****************************************************************************/
-int SMBCALL smb_hfield_string(smbmsg_t* msg, uint16_t type, const char* str)
+int smb_hfield_string(smbmsg_t* msg, uint16_t type, const char* str)
 {
 	if(str == NULL)
 		return SMB_ERR_HDR_FIELD;
@@ -1249,7 +1285,7 @@ int SMBCALL smb_hfield_string(smbmsg_t* msg, uint16_t type, const char* str)
 /* Pass NULL for net_type to have the auto-detected net_type hfield	added	*/
 /* as well.																	*/
 /****************************************************************************/
-int	SMBCALL smb_hfield_add_netaddr(smbmsg_t* msg, uint16_t type, const char* addr, uint16_t* net_type, BOOL insert)
+int	smb_hfield_add_netaddr(smbmsg_t* msg, uint16_t type, const char* addr, uint16_t* net_type, BOOL insert)
 {
 	int			result;
 	fidoaddr_t	sys_addr = {0,0,0,0};	/* replace unspecified fields with 0 (don't assume 1:1/1) */
@@ -1292,7 +1328,7 @@ int	SMBCALL smb_hfield_add_netaddr(smbmsg_t* msg, uint16_t type, const char* add
 /****************************************************************************/
 /* Appends data to an existing header field (in memory only)				*/
 /****************************************************************************/
-int SMBCALL smb_hfield_append(smbmsg_t* msg, uint16_t type, size_t length, void* data)
+int smb_hfield_append(smbmsg_t* msg, uint16_t type, size_t length, void* data)
 {
 	int		i;
 	BYTE*	p;
@@ -1329,7 +1365,7 @@ int SMBCALL smb_hfield_append(smbmsg_t* msg, uint16_t type, size_t length, void*
 /****************************************************************************/
 /* Appends data to an existing ASCIIZ header field (in memory only)			*/
 /****************************************************************************/
-int SMBCALL smb_hfield_append_str(smbmsg_t* msg, uint16_t type, const char* str)
+int smb_hfield_append_str(smbmsg_t* msg, uint16_t type, const char* str)
 {
 	return smb_hfield_append(msg, type, str==NULL ? 0:strlen(str), (void*)str);
 }
@@ -1337,7 +1373,7 @@ int SMBCALL smb_hfield_append_str(smbmsg_t* msg, uint16_t type, const char* str)
 /****************************************************************************/
 /* Replaces an header field value (in memory only)							*/
 /****************************************************************************/
-int SMBCALL smb_hfield_replace(smbmsg_t* msg, uint16_t type, size_t length, void* data)
+int smb_hfield_replace(smbmsg_t* msg, uint16_t type, size_t length, void* data)
 {
 	int		i;
 	void*	p;
@@ -1367,7 +1403,7 @@ int SMBCALL smb_hfield_replace(smbmsg_t* msg, uint16_t type, size_t length, void
 /****************************************************************************/
 /* Replace an existing ASCIIZ header field value (in memory only)			*/
 /****************************************************************************/
-int SMBCALL smb_hfield_replace_str(smbmsg_t* msg, uint16_t type, const char* str)
+int smb_hfield_replace_str(smbmsg_t* msg, uint16_t type, const char* str)
 {
 	return smb_hfield_replace(msg, type, str==NULL ? 0:strlen(str), (void*)str);
 }
@@ -1375,7 +1411,7 @@ int SMBCALL smb_hfield_replace_str(smbmsg_t* msg, uint16_t type, const char* str
 /****************************************************************************/
 /* Searches for a specific header field (by type) and returns it			*/
 /****************************************************************************/
-void* SMBCALL smb_get_hfield(smbmsg_t* msg, uint16_t type, hfield_t** hfield)
+void* smb_get_hfield(smbmsg_t* msg, uint16_t type, hfield_t** hfield)
 {
 	int i;
 
@@ -1389,12 +1425,31 @@ void* SMBCALL smb_get_hfield(smbmsg_t* msg, uint16_t type, hfield_t** hfield)
 	return(NULL);
 }
 
+/****************************************************************************/
+/* Add or replace a specific header field (by type)							*/
+/****************************************************************************/
+int smb_new_hfield(smbmsg_t* msg, uint16_t type, size_t length, void* data)
+{
+	if(smb_get_hfield(msg, type, NULL))
+		return smb_hfield_replace(msg, type, length, data);
+	else
+		return smb_hfield_add(msg, type, length, data, /* insert */FALSE);
+}
+
+/****************************************************************************/
+/* Add or replace a specific string header field (by type)					*/
+/****************************************************************************/
+int smb_new_hfield_str(smbmsg_t* msg, uint16_t type, const char* str)
+{
+	return smb_new_hfield(msg, type, str == NULL ? 0 : strlen(str), (void*)str);
+}
+
 /****************************************************************************/
 /* Adds a data field to the 'msg' structure (in memory only)                */
 /* Automatically figures out the offset into the data buffer from existing	*/
 /* dfield lengths															*/
 /****************************************************************************/
-int SMBCALL smb_dfield(smbmsg_t* msg, uint16_t type, ulong length)
+int smb_dfield(smbmsg_t* msg, uint16_t type, ulong length)
 {
 	dfield_t* dp;
 	int i,j;
@@ -1416,12 +1471,12 @@ int SMBCALL smb_dfield(smbmsg_t* msg, uint16_t type, ulong length)
 /* Checks CRC history file for duplicate crc. If found, returns SMB_DUPE_MSG*/
 /* If no dupe, adds to CRC history and returns 0, or negative if error. 	*/
 /****************************************************************************/
-int SMBCALL smb_addcrc(smb_t* smb, uint32_t crc)
+int smb_addcrc(smb_t* smb, uint32_t crc)
 {
 	char	str[MAX_PATH+1];
 	int 	file;
 	int		wr;
-	long	length;
+	off_t	length;
 	long	newlen;
 	ulong	l;
 	uint32_t *buf;
@@ -1461,7 +1516,7 @@ int SMBCALL smb_addcrc(smb_t* smb, uint32_t crc)
 	}
 
 	if(length!=0) {
-		if((buf=(uint32_t*)malloc(length))==NULL) {
+		if((buf=(uint32_t*)malloc((size_t)length))==NULL) {
 			close(file);
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
 				,"%s malloc failure of %ld bytes", __FUNCTION__
@@ -1469,7 +1524,7 @@ int SMBCALL smb_addcrc(smb_t* smb, uint32_t crc)
 			return(SMB_ERR_MEM); 
 		}
 
-		if(read(file,buf,length)!=length) {
+		if(read(file,buf,(uint)length)!=length) {
 			close(file);
 			free(buf);
 			safe_snprintf(smb->last_error,sizeof(smb->last_error)
@@ -1517,12 +1572,13 @@ int SMBCALL smb_addcrc(smb_t* smb, uint32_t crc)
 /* If storage is SMB_HYPERALLOC, no allocation tables are used (fastest)	*/
 /* This function will UN-lock the SMB header								*/
 /****************************************************************************/
-int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
+int smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
 {
 	int		i;
-	long	l;
+	off_t	l;
 	ulong	hdrlen;
-	long	idxlen;
+	off_t	idxlen;
+	size_t	idxreclen = smb_idxreclen(smb);
 
 	if(smb->shd_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s msgbase not open", __FUNCTION__);
@@ -1547,10 +1603,10 @@ int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
 	}
 
 	idxlen = filelength(fileno(smb->sid_fp));
-	if(idxlen != (smb->status.total_msgs * sizeof(idxrec_t))) {
+	if(idxlen != (smb->status.total_msgs * idxreclen)) {
 		safe_snprintf(smb->last_error, sizeof(smb->last_error)
-			,"%s index file length (%ld) unexpected (%ld)", __FUNCTION__
-			,idxlen, (long)(smb->status.total_msgs * sizeof(idxrec_t)));
+			,"%s index file length (%ld), expected (%ld)", __FUNCTION__
+			,idxlen, smb->status.total_msgs * idxreclen);
 		smb_unlocksmbhdr(smb);
 		return SMB_ERR_FILE_LEN;
 	}
@@ -1585,11 +1641,11 @@ int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
 		smb_close_ha(smb);
 	if(l<0) {
 		smb_unlocksmbhdr(smb);
-		return(l); 
+		return (int)l; 
 	}
 
-	msg->idx.offset=smb->status.header_offset+l;
-	msg->offset=smb->status.total_msgs;
+	msg->idx.offset=(uint32_t)(smb->status.header_offset + l);
+	msg->idx_offset=smb->status.total_msgs;
 	i=smb_putmsg(smb,msg);
 	if(i==SMB_SUCCESS) {
 		smb->status.last_msg++;
@@ -1605,7 +1661,7 @@ int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
 /* Nothing should be locked prior to calling this function and nothing		*/
 /* should (normally) be locked when it exits								*/
 /****************************************************************************/
-int SMBCALL smb_updatemsg(smb_t* smb, smbmsg_t* msg)
+int smb_updatemsg(smb_t* smb, smbmsg_t* msg)
 {
 	int retval;
 
@@ -1627,7 +1683,7 @@ int SMBCALL smb_updatemsg(smb_t* smb, smbmsg_t* msg)
 /****************************************************************************/
 /* Writes both header and index information for msg 'msg'                   */
 /****************************************************************************/
-int SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg)
+int smb_putmsg(smb_t* smb, smbmsg_t* msg)
 {
 	int i;
 
@@ -1643,27 +1699,32 @@ int SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg)
 /* Initializes/re-synchronizes all the fields of the message index record	*/
 /* with the values from the message header (except for the header offset)	*/
 /****************************************************************************/
-int SMBCALL smb_init_idx(smb_t* smb, smbmsg_t* msg)
+int smb_init_idx(smb_t* smb, smbmsg_t* msg)
 {
-	msg->idx.subj=smb_subject_crc(msg->subj);
-
-	if(smb->status.attr&SMB_EMAIL) {
-		if(msg->to_ext)
-			msg->idx.to=atoi(msg->to_ext);
-		else
-			msg->idx.to=0;
-		if(msg->from_ext)
-			msg->idx.from=atoi(msg->from_ext);
-		else
-			msg->idx.from=0; 
-	} else if(msg->hdr.type == SMB_MSG_TYPE_BALLOT) {
+	if(msg->hdr.type == SMB_MSG_TYPE_BALLOT) {
 		msg->idx.votes = msg->hdr.votes;
 		msg->idx.remsg = msg->hdr.thread_back;
+	} else if(msg->hdr.type == SMB_MSG_TYPE_FILE) {
+		if(msg->name != NULL)
+			smb_fileidxname(msg->name, msg->file_idx.name, sizeof(msg->file_idx.name));
+		if(msg->size > 0)
+			msg->idx.size = (uint32_t)msg->size;
 	} else {
-		msg->idx.to=smb_name_crc(msg->to);
-		msg->idx.from=smb_name_crc(msg->from);
+		msg->idx.subj = smb_subject_crc(msg->subj);
+		if(smb->status.attr & SMB_EMAIL) {
+			if(msg->to_ext)
+				msg->idx.to = atoi(msg->to_ext);
+			else
+				msg->idx.to = 0;
+			if(msg->from_ext)
+				msg->idx.from = atoi(msg->from_ext);
+			else
+				msg->idx.from = 0; 
+		} else {
+			msg->idx.to = smb_name_crc(msg->to);
+			msg->idx.from = smb_name_crc(msg->from);
+		}
 	}
-
 	/* Make sure these index/header fields are always *nsync */
 	msg->idx.number	= msg->hdr.number;
 	msg->idx.attr	= msg->hdr.attr;	
@@ -1672,7 +1733,7 @@ int SMBCALL smb_init_idx(smb_t* smb, smbmsg_t* msg)
 	return(SMB_SUCCESS);
 }
 
-BOOL SMBCALL smb_msg_is_from(smbmsg_t* msg, const char* name, enum smb_net_type net_type, const void* net_addr)
+BOOL smb_msg_is_from(smbmsg_t* msg, const char* name, enum smb_net_type net_type, const void* net_addr)
 {
 	if(stricmp(msg->from, name) != 0)
 		return FALSE;
@@ -1690,7 +1751,7 @@ BOOL SMBCALL smb_msg_is_from(smbmsg_t* msg, const char* name, enum smb_net_type
 	}
 }
 
-BOOL SMBCALL smb_msg_is_utf8(const smbmsg_t* msg)
+BOOL smb_msg_is_utf8(const smbmsg_t* msg)
 {
 	for(int i=0; i < msg->total_hfields; i++) {
 		switch(msg->hfield[i].type) {
@@ -1704,7 +1765,7 @@ BOOL SMBCALL smb_msg_is_utf8(const smbmsg_t* msg)
 	return msg->text_charset != NULL && stricmp(msg->text_charset, "utf-8") == 0;
 }
 
-uint16_t SMBCALL smb_voted_already(smb_t* smb, uint32_t msgnum, const char* name, enum smb_net_type net_type, void* net_addr)
+uint16_t smb_voted_already(smb_t* smb, uint32_t msgnum, const char* name, enum smb_net_type net_type, void* net_addr)
 {
 	uint16_t votes = 0;
 	smbmsg_t msg = {0};
@@ -1720,6 +1781,7 @@ uint16_t SMBCALL smb_voted_already(smb_t* smb, uint32_t msgnum, const char* name
 			,get_errno(), STRERROR(get_errno()));
 		return SMB_ERR_SEEK;
 	}
+	memset(&msg, 0, sizeof(msg));
 	while(!votes && smb_fread(smb, &msg.idx, sizeof(msg.idx), smb->sid_fp) == sizeof(msg.idx)) {
 		if(!(msg.idx.attr&MSG_VOTE) || msg.idx.attr&MSG_POLL)
 			continue;
@@ -1751,9 +1813,10 @@ uint16_t SMBCALL smb_voted_already(smb_t* smb, uint32_t msgnum, const char* name
 /* and msg->offset must be set prior to calling to this function			*/
 /* Returns 0 if everything ok                                               */
 /****************************************************************************/
-int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
+int smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
 {
-	long length;
+	off_t length;
+	size_t	idxreclen = smb_idxreclen(smb);
 
 	if(smb->sid_fp==NULL) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s index not open", __FUNCTION__);
@@ -1761,23 +1824,32 @@ int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
 	}
 	clearerr(smb->sid_fp);
 	length = filelength(fileno(smb->sid_fp));
-	if(length < (long)(msg->offset*sizeof(idxrec_t))) {
+	if(length < (long)(msg->idx_offset*idxreclen)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
-			,"%s invalid index offset: %ld, byte offset: %ld, length: %lu", __FUNCTION__
-			,(long)msg->offset, (long)(msg->offset*sizeof(idxrec_t)), length);
+			,"%s invalid index offset: %ld, byte offset: %lu, length: %lu", __FUNCTION__
+			,(long)msg->idx_offset, msg->idx_offset*idxreclen, length);
 		return(SMB_ERR_HDR_OFFSET);
 	}
-	if(fseek(smb->sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET)) {
+	if(fseek(smb->sid_fp,msg->idx_offset*idxreclen,SEEK_SET)) {
 		safe_snprintf(smb->last_error,sizeof(smb->last_error)
 			,"%s %d '%s' seeking to %u in index file", __FUNCTION__
 			,get_errno(),STRERROR(get_errno())
-			,(unsigned)(msg->offset*sizeof(idxrec_t)));
+			,(unsigned)(msg->idx_offset*idxreclen));
 		return(SMB_ERR_SEEK);
 	}
-	if(!fwrite(&msg->idx,sizeof(idxrec_t),1,smb->sid_fp)) {
-		safe_snprintf(smb->last_error,sizeof(smb->last_error)
-			,"%s writing index", __FUNCTION__);
-		return(SMB_ERR_WRITE);
+	if(smb->status.attr & SMB_FILE_DIRECTORY) {
+		if(!fwrite(&msg->file_idx, sizeof(msg->file_idx), 1, smb->sid_fp)) {
+			safe_snprintf(smb->last_error,sizeof(smb->last_error)
+				,"%s %d '%s' writing index", __FUNCTION__
+				,get_errno(),STRERROR(get_errno()));
+			return(SMB_ERR_WRITE);
+		}
+	} else {
+		if(!fwrite(&msg->idx,sizeof(msg->idx),1,smb->sid_fp)) {
+			safe_snprintf(smb->last_error,sizeof(smb->last_error)
+				,"%s writing index", __FUNCTION__);
+			return(SMB_ERR_WRITE);
+		}
 	}
 	return fflush(smb->sid_fp);	/* SMB_SUCCESS == 0 */
 }
@@ -1789,7 +1861,7 @@ int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
 /* and msg->offset must be set prior to calling to this function			*/
 /* Returns 0 if everything ok                                               */
 /****************************************************************************/
-int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
+int smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
 {
 	uint16_t	i;
 	ulong	hdrlen;
@@ -1829,7 +1901,7 @@ int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
 	/**********************************/
 	/* Set the message header ID here */
 	/**********************************/
-	memcpy(&msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID);
+	memcpy(&msg->hdr.msghdr_id,SHD_HEADER_ID,LEN_HEADER_ID);
 
 	/************************************************/
 	/* Write the fixed portion of the header record */
@@ -1880,7 +1952,7 @@ int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
 /****************************************************************************/
 /* Initializes a message base's header (SMBHDR) record 						*/
 /****************************************************************************/
-int SMBCALL smb_initsmbhdr(smb_t* smb)
+int smb_initsmbhdr(smb_t* smb)
 {
 	smbhdr_t	hdr;
 
@@ -1892,7 +1964,7 @@ int SMBCALL smb_initsmbhdr(smb_t* smb)
 		&& smb_locksmbhdr(smb)!=SMB_SUCCESS)  /* header exists, so lock it */
 		return(SMB_ERR_LOCK);
 	memset(&hdr,0,sizeof(smbhdr_t));
-	memcpy(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID);
+	memcpy(hdr.smbhdr_id,SMB_HEADER_ID,LEN_HEADER_ID);
 	hdr.version=SMB_VERSION;
 	hdr.length=sizeof(smbhdr_t)+sizeof(smbstatus_t);
 	smb->status.last_msg=smb->status.total_msgs=0;
@@ -1910,7 +1982,7 @@ int SMBCALL smb_initsmbhdr(smb_t* smb)
 /* Creates a sub-board's initial header file                                */
 /* Truncates and deletes other associated SMB files 						*/
 /****************************************************************************/
-int SMBCALL smb_create(smb_t* smb)
+int smb_create(smb_t* smb)
 {
     char        str[MAX_PATH+1];
 	FILE*		fp;
@@ -1948,11 +2020,11 @@ int SMBCALL smb_create(smb_t* smb)
 /****************************************************************************/
 /* Returns number of data blocks required to store "length" amount of data  */
 /****************************************************************************/
-ulong SMBCALL smb_datblocks(ulong length)
+ulong smb_datblocks(off_t length)
 {
 	ulong blocks;
 
-	blocks=length/SDT_BLOCK_LEN;
+	blocks=(ulong)(length / SDT_BLOCK_LEN);
 	if(length%SDT_BLOCK_LEN)
 		blocks++;
 	return(blocks);
@@ -1961,7 +2033,7 @@ ulong SMBCALL smb_datblocks(ulong length)
 /****************************************************************************/
 /* Returns number of header blocks required to store "length" size header   */
 /****************************************************************************/
-ulong SMBCALL smb_hdrblocks(ulong length)
+ulong smb_hdrblocks(ulong length)
 {
 	ulong blocks;
 
@@ -1974,7 +2046,7 @@ ulong SMBCALL smb_hdrblocks(ulong length)
 /****************************************************************************/
 /* Returns difference from specified timezone and UTC/GMT (in minutes)		*/
 /****************************************************************************/
-int SMBCALL smb_tzutc(int16_t zone)
+int smb_tzutc(int16_t zone)
 {
 	int tz;
 
@@ -1995,14 +2067,14 @@ int SMBCALL smb_tzutc(int16_t zone)
 /****************************************************************************/
 /* The caller needs to call smb_unlockmsghdr(smb,remsg)						*/
 /****************************************************************************/
-int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum)
+int smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum)
 {
 	int			retval=SMB_ERR_NOT_FOUND;
 	ulong		nextmsgnum;
 	smbmsg_t	nextmsg;
 
  	if(!remsg->hdr.thread_first) {	/* New msg is first reply */
-		if((remsg->offset==0 || remsg->idx.offset==0)		/* index not read? */
+		if((remsg->idx_offset==0 || remsg->idx.offset==0)		/* index not read? */
 			&& (retval=smb_getmsgidx(smb,remsg))!=SMB_SUCCESS)
 			return(retval);
 		if(!remsg->hdr.length) {	/* header not read? */
@@ -2049,7 +2121,7 @@ int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum)
 }
 
 /* Find oldest *existing* message in the thread referenced by the passed msg */
-uint32_t SMBCALL smb_first_in_thread(smb_t* smb, smbmsg_t* remsg, msghdr_t* hdr)
+uint32_t smb_first_in_thread(smb_t* smb, smbmsg_t* remsg, msghdr_t* hdr)
 {
 	smbmsg_t msg;
 
@@ -2088,7 +2160,7 @@ uint32_t SMBCALL smb_first_in_thread(smb_t* smb, smbmsg_t* remsg, msghdr_t* hdr)
 	return msgnum;
 }
 
-uint32_t SMBCALL smb_next_in_thread(smb_t* smb, smbmsg_t* remsg, msghdr_t* hdr)
+uint32_t smb_next_in_thread(smb_t* smb, smbmsg_t* remsg, msghdr_t* hdr)
 {
 	smbmsg_t msg;
 
@@ -2107,7 +2179,7 @@ uint32_t SMBCALL smb_next_in_thread(smb_t* smb, smbmsg_t* remsg, msghdr_t* hdr)
 }
 
 /* Last in this context does not mean newest */
-uint32_t SMBCALL smb_last_in_branch(smb_t* smb, smbmsg_t* remsg)
+uint32_t smb_last_in_branch(smb_t* smb, smbmsg_t* remsg)
 {
 	smbmsg_t msg;
 
@@ -2125,7 +2197,7 @@ uint32_t SMBCALL smb_last_in_branch(smb_t* smb, smbmsg_t* remsg)
 
 
 /* Last in this context does not mean newest */
-uint32_t SMBCALL smb_last_in_thread(smb_t* smb, smbmsg_t* remsg)
+uint32_t smb_last_in_thread(smb_t* smb, smbmsg_t* remsg)
 {
 	smbmsg_t msg;
 	memset(&msg, 0, sizeof(msg));
@@ -2140,6 +2212,8 @@ uint32_t SMBCALL smb_last_in_thread(smb_t* smb, smbmsg_t* remsg)
 
 SMBEXPORT enum smb_msg_type smb_msg_type(smb_msg_attr_t attr)
 {
+	if(attr & MSG_FILE)
+		return SMB_MSG_TYPE_FILE;
 	switch (attr&MSG_POLL_VOTE_MASK) {
 		case 0:
 			return SMB_MSG_TYPE_NORMAL;
@@ -2154,13 +2228,13 @@ SMBEXPORT enum smb_msg_type smb_msg_type(smb_msg_attr_t attr)
 
 // Return count of messages of the desired types (bit-mask), as read from index
 // Does so as fast as possible, without locking
-SMBEXPORT size_t SMBCALL smb_msg_count(smb_t* smb, unsigned types)
+SMBEXPORT size_t smb_msg_count(smb_t* smb, unsigned types)
 {
 	off_t index_length = filelength(fileno(smb->sid_fp));
 	if(index_length < sizeof(idxrec_t))
 		return 0;
 
-	uint32_t total = index_length / sizeof(idxrec_t);
+	uint32_t total = (uint32_t)(index_length / sizeof(idxrec_t));
 	if(total < 1)
 		return 0;
 
diff --git a/src/smblib/smblib.h b/src/smblib/smblib.h
index fbe37ffbf9..660db76ff3 100644
--- a/src/smblib/smblib.h
+++ b/src/smblib/smblib.h
@@ -1,8 +1,5 @@
 /* Synchronet message base (SMB) library function prototypes */
 
-/* $Id: smblib.h,v 1.99 2020/05/25 00:39:47 rswindell Exp $ */
-// vi: tabstop=4
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -16,21 +13,9 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -42,11 +27,6 @@
 #endif
 
 #ifdef _WIN32
-	#ifdef __BORLANDC__
-		#define SMBCALL
-	#else
-		#define SMBCALL
-	#endif
 	#if defined(SMB_IMPORTS) || defined(SMB_EXPORTS)
 		#if defined(SMB_IMPORTS)
 			#define SMBEXPORT __declspec( dllimport )
@@ -56,11 +36,7 @@
 	#else	/* self-contained executable */
 		#define SMBEXPORT
 	#endif
-#elif defined __unix__
-	#define SMBCALL
-	#define SMBEXPORT
 #else
-	#define SMBCALL
 	#define SMBEXPORT
 #endif
 
@@ -70,6 +46,7 @@
 #define SMB_SUCCESS			0			/* Successful result/return code */
 #define SMB_FAILURE			-1			/* Generic error (discouraged) */
 #define SMB_BAD_PARAMETER	-2			/* Invalid API function parameter value */
+
 										/* Standard smblib errors values */
 #define SMB_ERR_NOT_OPEN	-100		/* Message base not open */
 #define SMB_ERR_HDR_LEN		-101		/* Invalid message header length (>64k) */
@@ -90,6 +67,7 @@
 #define SMB_ERR_FILE_LEN	-206		/* File length invalid */
 #define SMB_ERR_DELETE		-207		/* File deletion error */
 #define SMB_ERR_UNLOCK		-208		/* File unlock error */
+#define SMB_ERR_RENAME		-209		/* File rename error */
 #define SMB_ERR_MEM			-300		/* Memory allocation error */
 
 #define SMB_DUPE_MSG		1			/* Duplicate message detected by smb_addcrc() */
@@ -125,42 +103,42 @@
 extern "C" {
 #endif
 
-SMBEXPORT int 		SMBCALL smb_ver(void);
-SMBEXPORT char*		SMBCALL smb_lib_ver(void);
-SMBEXPORT int 		SMBCALL smb_open(smb_t* smb);
-SMBEXPORT int		SMBCALL smb_open_index(smb_t* smb);
-SMBEXPORT void		SMBCALL smb_close(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_initsmbhdr(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_create(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_trunchdr(smb_t* smb);
-SMBEXPORT int		SMBCALL smb_lock(smb_t* smb);
-SMBEXPORT int		SMBCALL smb_unlock(smb_t* smb);
-SMBEXPORT BOOL		SMBCALL smb_islocked(smb_t* smb);
-SMBEXPORT int		SMBCALL Smb_initsmbhdr(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_locksmbhdr(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_getstatus(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_putstatus(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_unlocksmbhdr(smb_t* smb);
-SMBEXPORT int 		SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT int 		SMBCALL smb_getfirstidx(smb_t* smb, idxrec_t *idx);
-SMBEXPORT int 		SMBCALL smb_getlastidx(smb_t* smb, idxrec_t *idx);
-SMBEXPORT ulong		SMBCALL smb_getmsghdrlen(smbmsg_t* msg);
-SMBEXPORT ulong		SMBCALL smb_getmsgdatlen(smbmsg_t* msg);
-SMBEXPORT ulong		SMBCALL smb_getmsgtxtlen(smbmsg_t* msg);
-SMBEXPORT int 		SMBCALL smb_lockmsghdr(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT int 		SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT int 		SMBCALL smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT int 		SMBCALL smb_addcrc(smb_t* smb, uint32_t crc);
+SMBEXPORT int 		smb_ver(void);
+SMBEXPORT char*		smb_lib_ver(void);
+SMBEXPORT int 		smb_open(smb_t*);
+SMBEXPORT int		smb_open_index(smb_t*);
+SMBEXPORT void		smb_close(smb_t*);
+SMBEXPORT int 		smb_initsmbhdr(smb_t*);
+SMBEXPORT int 		smb_create(smb_t*);
+SMBEXPORT int 		smb_trunchdr(smb_t*);
+SMBEXPORT int		smb_lock(smb_t*);
+SMBEXPORT int		smb_unlock(smb_t*);
+SMBEXPORT BOOL		smb_islocked(smb_t*);
+SMBEXPORT int		Smb_initsmbhdr(smb_t*);
+SMBEXPORT int 		smb_locksmbhdr(smb_t*);
+SMBEXPORT int 		smb_getstatus(smb_t*);
+SMBEXPORT int 		smb_putstatus(smb_t*);
+SMBEXPORT int 		smb_unlocksmbhdr(smb_t*);
+SMBEXPORT int 		smb_getmsgidx(smb_t*, smbmsg_t*);
+SMBEXPORT int 		smb_getfirstidx(smb_t*, idxrec_t*);
+SMBEXPORT int 		smb_getlastidx(smb_t*, idxrec_t*);
+SMBEXPORT ulong		smb_getmsghdrlen(smbmsg_t*);
+SMBEXPORT ulong		smb_getmsgdatlen(smbmsg_t*);
+SMBEXPORT ulong		smb_getmsgtxtlen(smbmsg_t*);
+SMBEXPORT int 		smb_lockmsghdr(smb_t*, smbmsg_t*);
+SMBEXPORT int 		smb_getmsghdr(smb_t*, smbmsg_t*);
+SMBEXPORT int 		smb_unlockmsghdr(smb_t*, smbmsg_t*);
+SMBEXPORT int 		smb_addcrc(smb_t*, uint32_t crc);
 
-SMBEXPORT int 		SMBCALL smb_hfield_add(smbmsg_t* msg, uint16_t type, size_t length, void* data, BOOL insert);
-SMBEXPORT int		SMBCALL smb_hfield_add_str(smbmsg_t* msg, uint16_t type, const char* str, BOOL insert);
-SMBEXPORT int		SMBCALL	smb_hfield_replace(smbmsg_t* msg, uint16_t type, size_t length, void* data);
-SMBEXPORT int		SMBCALL	smb_hfield_replace_str(smbmsg_t* msg, uint16_t type, const char* str);
-SMBEXPORT int		SMBCALL smb_hfield_append(smbmsg_t* msg, uint16_t type, size_t length, void* data);
-SMBEXPORT int		SMBCALL smb_hfield_append_str(smbmsg_t* msg, uint16_t type, const char* data);
-SMBEXPORT int		SMBCALL smb_hfield_add_list(smbmsg_t* msg, hfield_t** hfield_list, void** hfield_dat, BOOL insert);
-SMBEXPORT int		SMBCALL smb_hfield_add_netaddr(smbmsg_t* msg, uint16_t type, const char* str, uint16_t* nettype, BOOL insert);
-SMBEXPORT int		SMBCALL	smb_hfield_string(smbmsg_t*, uint16_t type, const char*);
+SMBEXPORT int 		smb_hfield_add(smbmsg_t*, uint16_t type, size_t, void* data, BOOL insert);
+SMBEXPORT int		smb_hfield_add_str(smbmsg_t*, uint16_t type, const char* str, BOOL insert);
+SMBEXPORT int		smb_hfield_replace(smbmsg_t*, uint16_t type, size_t, void* data);
+SMBEXPORT int		smb_hfield_replace_str(smbmsg_t*, uint16_t type, const char* str);
+SMBEXPORT int		smb_hfield_append(smbmsg_t*, uint16_t type, size_t, void* data);
+SMBEXPORT int		smb_hfield_append_str(smbmsg_t*, uint16_t type, const char* data);
+SMBEXPORT int		smb_hfield_add_list(smbmsg_t*, hfield_t** hfield_list, void** hfield_dat, BOOL insert);
+SMBEXPORT int		smb_hfield_add_netaddr(smbmsg_t*, uint16_t type, const char* str, uint16_t* nettype, BOOL insert);
+SMBEXPORT int		smb_hfield_string(smbmsg_t*, uint16_t type, const char*);
 /* Convenience macro: */
 #define smb_hfield_bin(msg, type, data) smb_hfield_add(msg, type, sizeof(data), &(data), /* insert: */FALSE)
 /* Backward compatibility macros: */
@@ -168,75 +146,80 @@ SMBEXPORT int		SMBCALL	smb_hfield_string(smbmsg_t*, uint16_t type, const char*);
 #define smb_hfield_str(msg, type, str)	smb_hfield_add_str(msg, type, str, /* insert: */FALSE)
 #define smb_hfield_netaddr(msg, type, str, nettype) smb_hfield_add_netaddr(msg, type, str, nettype, /* insert: */FALSE)
 
-SMBEXPORT int 		SMBCALL smb_dfield(smbmsg_t* msg, uint16_t type, ulong length);
-SMBEXPORT void*		SMBCALL smb_get_hfield(smbmsg_t* msg, uint16_t type, hfield_t** hfield);
-SMBEXPORT int 		SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage);
-SMBEXPORT int 		SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT int 		SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT int 		SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT void		SMBCALL smb_freemsgmem(smbmsg_t* msg);
-SMBEXPORT void		SMBCALL smb_freemsghdrmem(smbmsg_t* msg);
-SMBEXPORT ulong		SMBCALL smb_hdrblocks(ulong length);
-SMBEXPORT ulong		SMBCALL smb_datblocks(ulong length);
-SMBEXPORT int		SMBCALL	smb_copymsgmem(smb_t* smb, smbmsg_t* destmsg, smbmsg_t* srcmsg);
-SMBEXPORT int		SMBCALL smb_tzutc(int16_t timezone);
-SMBEXPORT int		SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum);
-SMBEXPORT int		SMBCALL smb_updatemsg(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT BOOL		SMBCALL smb_valid_hdr_offset(smb_t* smb, ulong offset);
-SMBEXPORT int		SMBCALL smb_init_idx(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT uint16_t	SMBCALL	smb_voted_already(smb_t*, uint32_t msgnum, const char* name, enum smb_net_type, void* net_addr);
-SMBEXPORT BOOL		SMBCALL smb_msg_is_from(smbmsg_t* msg, const char* name, enum smb_net_type net_type, const void* net_addr);
-SMBEXPORT uint32_t	SMBCALL smb_first_in_thread(smb_t*, smbmsg_t*, msghdr_t*);
-SMBEXPORT uint32_t	SMBCALL smb_next_in_thread(smb_t*, smbmsg_t*, msghdr_t*);
-SMBEXPORT uint32_t	SMBCALL smb_last_in_branch(smb_t*, smbmsg_t*);
-SMBEXPORT uint32_t	SMBCALL smb_last_in_thread(smb_t*, smbmsg_t*);
-SMBEXPORT BOOL		SMBCALL smb_msg_is_utf8(const smbmsg_t*);
-SMBEXPORT size_t	SMBCALL smb_msg_count(smb_t*, unsigned types);
+SMBEXPORT int 		smb_dfield(smbmsg_t*, uint16_t type, ulong length);
+SMBEXPORT void*		smb_get_hfield(smbmsg_t*, uint16_t type, hfield_t** hfield);
+SMBEXPORT int		smb_new_hfield(smbmsg_t*, uint16_t type, size_t, void* data);
+SMBEXPORT int		smb_new_hfield_str(smbmsg_t*, uint16_t type, const char*);
+SMBEXPORT int 		smb_addmsghdr(smb_t*, smbmsg_t*, int storage);
+SMBEXPORT int 		smb_putmsg(smb_t*, smbmsg_t*);
+SMBEXPORT int 		smb_putmsgidx(smb_t*, smbmsg_t*);
+SMBEXPORT int 		smb_putmsghdr(smb_t*, smbmsg_t*);
+SMBEXPORT void		smb_freemsgmem(smbmsg_t*);
+SMBEXPORT void		smb_freemsghdrmem(smbmsg_t*);
+SMBEXPORT ulong		smb_hdrblocks(ulong length);
+SMBEXPORT ulong		smb_datblocks(off_t length);
+SMBEXPORT int		smb_copymsgmem(smb_t*, smbmsg_t* destmsg, smbmsg_t* srcmsg);
+SMBEXPORT int		smb_tzutc(int16_t timezone);
+SMBEXPORT int		smb_updatethread(smb_t*, smbmsg_t* remsg, ulong newmsgnum);
+SMBEXPORT int		smb_updatemsg(smb_t*, smbmsg_t*);
+SMBEXPORT BOOL		smb_valid_hdr_offset(smb_t*, ulong offset);
+SMBEXPORT int		smb_init_idx(smb_t*, smbmsg_t*);
+SMBEXPORT uint16_t	smb_voted_already(smb_t*, uint32_t msgnum, const char* name, enum smb_net_type, void* net_addr);
+SMBEXPORT BOOL		smb_msg_is_from(smbmsg_t*, const char* name, enum smb_net_type net_type, const void* net_addr);
+SMBEXPORT uint32_t	smb_first_in_thread(smb_t*, smbmsg_t*, msghdr_t*);
+SMBEXPORT uint32_t	smb_next_in_thread(smb_t*, smbmsg_t*, msghdr_t*);
+SMBEXPORT uint32_t	smb_last_in_branch(smb_t*, smbmsg_t*);
+SMBEXPORT uint32_t	smb_last_in_thread(smb_t*, smbmsg_t*);
+SMBEXPORT size_t	smb_idxreclen(smb_t*);
+SMBEXPORT uint32_t	smb_count_idx_records(smb_t*, uint16_t mask, uint16_t cmp);
+SMBEXPORT BOOL		smb_msg_is_utf8(const smbmsg_t*);
+SMBEXPORT size_t	smb_msg_count(smb_t*, unsigned types);
 SMBEXPORT enum smb_msg_type smb_msg_type(smb_msg_attr_t);
 
 /* smbadd.c */
-SMBEXPORT int		SMBCALL smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, long dupechk_hashes
+SMBEXPORT int		smb_addmsg(smb_t*, smbmsg_t*, int storage, long dupechk_hashes
 						,uint16_t xlat, const uchar* body, const uchar* tail);
-SMBEXPORT int		SMBCALL smb_addvote(smb_t* smb, smbmsg_t* msg, int storage);
-SMBEXPORT int		SMBCALL smb_addpoll(smb_t* smb, smbmsg_t* msg, int storage);
-SMBEXPORT int		SMBCALL smb_addpollclosure(smb_t* smb, smbmsg_t* msg, int storage);
+SMBEXPORT int		smb_addvote(smb_t*, smbmsg_t*, int storage);
+SMBEXPORT int		smb_addpoll(smb_t*, smbmsg_t*, int storage);
+SMBEXPORT int		smb_addpollclosure(smb_t*, smbmsg_t*, int storage);
 
 /* smballoc.c */
-SMBEXPORT long		SMBCALL smb_allochdr(smb_t* smb, ulong length);
-SMBEXPORT long		SMBCALL smb_fallochdr(smb_t* smb, ulong length);
-SMBEXPORT long		SMBCALL smb_hallochdr(smb_t* smb);
-SMBEXPORT long		SMBCALL smb_allocdat(smb_t* smb, ulong length, uint16_t int16_trefs);
-SMBEXPORT long		SMBCALL smb_fallocdat(smb_t* smb, ulong length, uint16_t refs);
-SMBEXPORT long		SMBCALL smb_hallocdat(smb_t* smb);
-SMBEXPORT int		SMBCALL smb_incmsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs);
-SMBEXPORT int 		SMBCALL smb_incmsgdat(smb_t* smb, ulong offset, ulong length, uint16_t refs);
-SMBEXPORT int 		SMBCALL smb_freemsg(smb_t* smb, smbmsg_t* msg);
-SMBEXPORT int		SMBCALL smb_freemsg_dfields(smb_t* smb, smbmsg_t* msg, uint16_t refs);
-SMBEXPORT int 		SMBCALL smb_freemsgdat(smb_t* smb, ulong offset, ulong length, uint16_t refs);
-SMBEXPORT int 		SMBCALL smb_freemsghdr(smb_t* smb, ulong offset, ulong length);
-SMBEXPORT void		SMBCALL smb_freemsgtxt(char* buf);
+SMBEXPORT off_t		smb_allochdr(smb_t*, ulong length);
+SMBEXPORT off_t		smb_fallochdr(smb_t*, ulong length);
+SMBEXPORT off_t		smb_hallochdr(smb_t*);
+SMBEXPORT off_t		smb_allocdat(smb_t*, off_t length, uint16_t int16_trefs);
+SMBEXPORT off_t		smb_fallocdat(smb_t*, off_t length, uint16_t refs);
+SMBEXPORT off_t		smb_hallocdat(smb_t*);
+SMBEXPORT int		smb_incmsg_dfields(smb_t*, smbmsg_t*, uint16_t refs);
+SMBEXPORT int 		smb_incmsgdat(smb_t*, off_t offset, ulong length, uint16_t refs);
+SMBEXPORT int 		smb_freemsg(smb_t*, smbmsg_t*);
+SMBEXPORT int		smb_freemsg_dfields(smb_t*, smbmsg_t*, uint16_t refs);
+SMBEXPORT int 		smb_freemsgdat(smb_t*, off_t offset, ulong length, uint16_t refs);
+SMBEXPORT int 		smb_freemsghdr(smb_t*, off_t offset, ulong length);
+SMBEXPORT void		smb_freemsgtxt(char* buf);
 
 /* smbhash.c */
-SMBEXPORT int		SMBCALL smb_findhash(smb_t* smb, hash_t** compare_list, hash_t* found
+SMBEXPORT int		smb_findhash(smb_t*, hash_t** compare_list, hash_t* found
 										 ,long source_mask, BOOL mark);
-SMBEXPORT int		SMBCALL smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL update);
-SMBEXPORT hash_t*	SMBCALL	smb_hash(ulong msgnum, uint32_t time, unsigned source
-								,unsigned flags, const void* data, size_t length);
-SMBEXPORT hash_t*	SMBCALL	smb_hashstr(ulong msgnum, uint32_t time, unsigned source
+SMBEXPORT int		smb_hashmsg(smb_t*, smbmsg_t*, const uchar* text, BOOL update);
+SMBEXPORT hash_t*	smb_hash(ulong msgnum, uint32_t time, unsigned source
+								,unsigned flags, const void* data, size_t);
+SMBEXPORT hash_t*	smb_hashstr(ulong msgnum, uint32_t time, unsigned source
 								,unsigned flags, const char* str);
 
-SMBEXPORT hash_t**	SMBCALL smb_msghashes(smbmsg_t* msg, const uchar* text, long source_mask);
-SMBEXPORT int		SMBCALL smb_addhashes(smb_t* smb, hash_t** hash_list, BOOL skip_marked);
-SMBEXPORT uint16_t	SMBCALL smb_name_crc(const char* name);
-SMBEXPORT uint16_t	SMBCALL smb_subject_crc(const char *subj);
-SMBEXPORT void		SMBCALL smb_freehashes(hash_t**);
-SMBEXPORT long		SMBCALL	smb_getmsgidx_by_time(smb_t*, idxrec_t*, time_t);
+SMBEXPORT hash_t**	smb_msghashes(smbmsg_t*, const uchar* text, long source_mask);
+SMBEXPORT int		smb_addhashes(smb_t*, hash_t** hash_list, BOOL skip_marked);
+SMBEXPORT uint16_t	smb_name_crc(const char* name);
+SMBEXPORT uint16_t	smb_subject_crc(const char *subj);
+SMBEXPORT void		smb_freehashes(hash_t**);
+SMBEXPORT long		smb_getmsgidx_by_time(smb_t*, idxrec_t*, time_t);
+SMBEXPORT int		smb_hashfile(const char* path, off_t, struct hash_data*);
 
 /* Fast look-up functions (using hashes) */
-SMBEXPORT int 		SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
-								 ,unsigned flags, const void* data, size_t length);
-SMBEXPORT int 		SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
-								 ,unsigned flags, const void* data, size_t length);
+SMBEXPORT int 		smb_getmsgidx_by_hash(smb_t*, smbmsg_t*, unsigned source
+								 ,unsigned flags, const void* data, size_t);
+SMBEXPORT int 		smb_getmsghdr_by_hash(smb_t*, smbmsg_t*, unsigned source
+								 ,unsigned flags, const void* data, size_t);
 
 /* 0-length specifies ASCIIZ data (length calculated automatically) */
 #define smb_getmsgidx_by_hashstr(smb, msg, source, flags, data) \
@@ -255,49 +238,61 @@ SMBEXPORT int 		SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigne
 		smb_getmsghdr_by_hashstr(smb, msg, SMB_HASH_SOURCE_FTN_ID, SMB_HASH_MASK, id)
 
 /* smbstr.c */
-SMBEXPORT char*		SMBCALL smb_hfieldtype(uint16_t type);
-SMBEXPORT uint16_t	SMBCALL smb_hfieldtypelookup(const char*);
-SMBEXPORT char*		SMBCALL smb_dfieldtype(uint16_t type);
-SMBEXPORT char*		SMBCALL smb_faddrtoa(fidoaddr_t* addr, char* outstr);
-SMBEXPORT char*		SMBCALL smb_netaddr(net_t* net);
-SMBEXPORT char*		SMBCALL smb_netaddrstr(net_t* net, char* fidoaddr_buf);
-SMBEXPORT char*		SMBCALL	smb_nettype(enum smb_net_type);
-SMBEXPORT char*		SMBCALL smb_zonestr(int16_t zone, char* outstr);
-SMBEXPORT char*		SMBCALL smb_msgattrstr(int16_t attr, char* outstr, size_t maxlen);
-SMBEXPORT char*		SMBCALL smb_auxattrstr(int32_t attr, char* outstr, size_t maxlen);
-SMBEXPORT char*		SMBCALL smb_netattrstr(int32_t attr, char* outstr, size_t maxlen);
-SMBEXPORT char*		SMBCALL smb_hashsource(smbmsg_t* msg, int source);
-SMBEXPORT char*		SMBCALL smb_hashsourcetype(uchar type);
-SMBEXPORT fidoaddr_t SMBCALL smb_atofaddr(const fidoaddr_t* sys_addr, const char *str);
-SMBEXPORT enum smb_net_type SMBCALL smb_netaddr_type(const char* addr);
-SMBEXPORT enum smb_net_type SMBCALL smb_get_net_type_by_addr(const char* addr);
+SMBEXPORT char*		smb_hfieldtype(uint16_t type);
+SMBEXPORT uint16_t	smb_hfieldtypelookup(const char*);
+SMBEXPORT char*		smb_dfieldtype(uint16_t type);
+SMBEXPORT char*		smb_faddrtoa(fidoaddr_t* addr, char* outstr);
+SMBEXPORT char*		smb_netaddr(net_t* net);
+SMBEXPORT char*		smb_netaddrstr(net_t* net, char* fidoaddr_buf);
+SMBEXPORT char*		smb_nettype(enum smb_net_type);
+SMBEXPORT char*		smb_zonestr(int16_t zone, char* outstr);
+SMBEXPORT char*		smb_msgattrstr(int16_t attr, char* outstr, size_t maxlen);
+SMBEXPORT char*		smb_auxattrstr(int32_t attr, char* outstr, size_t maxlen);
+SMBEXPORT char*		smb_netattrstr(int32_t attr, char* outstr, size_t maxlen);
+SMBEXPORT char*		smb_hashsource(smbmsg_t*, int source);
+SMBEXPORT char*		smb_hashsourcetype(uchar type);
+SMBEXPORT fidoaddr_t smb_atofaddr(const fidoaddr_t* sys_addr, const char *str);
+SMBEXPORT enum smb_net_type smb_netaddr_type(const char* addr);
+SMBEXPORT enum smb_net_type smb_get_net_type_by_addr(const char* addr);
 /* smbdump.c */
-SMBEXPORT void		SMBCALL smb_dump_msghdr(FILE*, smbmsg_t*);
-SMBEXPORT str_list_t SMBCALL smb_msghdr_str_list(smbmsg_t*);
+SMBEXPORT void		smb_dump_msghdr(FILE*, smbmsg_t*);
+SMBEXPORT str_list_t smb_msghdr_str_list(smbmsg_t*);
 
 /* smbtxt.c */
-SMBEXPORT char*		SMBCALL smb_getmsgtxt(smb_t*, smbmsg_t*, ulong mode);
-SMBEXPORT char*		SMBCALL smb_getplaintext(smbmsg_t*, char* body);
-SMBEXPORT uint8_t*	SMBCALL smb_getattachment(smbmsg_t*, char* body, char* filename, size_t filename_len, uint32_t* filelen, int index);
-SMBEXPORT ulong		SMBCALL	smb_countattachments(smb_t*, smbmsg_t*, const char* body);
-SMBEXPORT void		SMBCALL smb_parse_content_type(const char* content_type, char** subtype, char** charset);
+SMBEXPORT char*		smb_getmsgtxt(smb_t*, smbmsg_t*, ulong mode);
+SMBEXPORT char*		smb_getplaintext(smbmsg_t*, char* body);
+SMBEXPORT uint8_t*	smb_getattachment(smbmsg_t*, char* body, char* filename, size_t filename_len, uint32_t* filelen, int index);
+SMBEXPORT ulong		smb_countattachments(smb_t*, smbmsg_t*, const char* body);
+SMBEXPORT void		smb_parse_content_type(const char* content_type, char** subtype, char** charset);
 
 /* smbfile.c */
-SMBEXPORT int 		SMBCALL smb_feof(FILE* fp);
-SMBEXPORT int 		SMBCALL smb_ferror(FILE* fp);
-SMBEXPORT int 		SMBCALL smb_fflush(FILE* fp);
-SMBEXPORT int 		SMBCALL smb_fgetc(FILE* fp);
-SMBEXPORT int 		SMBCALL smb_fputc(int ch, FILE* fp);
-SMBEXPORT int 		SMBCALL smb_fseek(FILE* fp, long offset, int whence);
-SMBEXPORT long		SMBCALL smb_ftell(FILE* fp);
-SMBEXPORT size_t	SMBCALL smb_fread(smb_t*, void* buf, size_t bytes, FILE* fp);
-SMBEXPORT size_t	SMBCALL smb_fwrite(smb_t*, const void* buf, size_t bytes, FILE* fp);
-SMBEXPORT long		SMBCALL smb_fgetlength(FILE* fp);
-SMBEXPORT int 		SMBCALL smb_fsetlength(FILE* fp, long length);
-SMBEXPORT void		SMBCALL smb_rewind(FILE* fp);
-SMBEXPORT void		SMBCALL smb_clearerr(FILE* fp);
-SMBEXPORT int 		SMBCALL smb_open_fp(smb_t* smb, FILE**, int share);
-SMBEXPORT void		SMBCALL smb_close_fp(FILE**);
+SMBEXPORT int 		smb_feof(FILE* fp);
+SMBEXPORT int 		smb_ferror(FILE* fp);
+SMBEXPORT int 		smb_fflush(FILE* fp);
+SMBEXPORT int 		smb_fgetc(FILE* fp);
+SMBEXPORT int 		smb_fputc(int ch, FILE* fp);
+SMBEXPORT int 		smb_fseek(FILE* fp, off_t offset, int whence);
+SMBEXPORT off_t		smb_ftell(FILE* fp);
+SMBEXPORT size_t	smb_fread(smb_t*, void* buf, size_t bytes, FILE* fp);
+SMBEXPORT size_t	smb_fwrite(smb_t*, const void* buf, size_t bytes, FILE* fp);
+SMBEXPORT off_t		smb_fgetlength(FILE* fp);
+SMBEXPORT int 		smb_fsetlength(FILE* fp, long length);
+SMBEXPORT void		smb_rewind(FILE* fp);
+SMBEXPORT void		smb_clearerr(FILE* fp);
+SMBEXPORT int 		smb_open_fp(smb_t*, FILE**, int share);
+SMBEXPORT void		smb_close_fp(FILE**);
+
+/* New FileBase API: */
+enum file_detail { file_detail_index, file_detail_normal, file_detail_extdesc };
+SMBEXPORT int		smb_addfile(smb_t*, smbfile_t*, int storage, const char* extdesc, const char* path);
+SMBEXPORT int		smb_renewfile(smb_t*, smbfile_t*, int storage, const char* path);
+SMBEXPORT int		smb_getfile(smb_t*, smbfile_t*, enum file_detail);
+SMBEXPORT int		smb_putfile(smb_t*, smbfile_t*);
+SMBEXPORT int		smb_findfile(smb_t*, const char* filename, smbfile_t*);
+SMBEXPORT int		smb_loadfile(smb_t*, const char* filename, smbfile_t*, enum file_detail);
+SMBEXPORT void		smb_freefilemem(smbfile_t*);
+SMBEXPORT int		smb_removefile(smb_t*, smbfile_t*);
+SMBEXPORT char*		smb_fileidxname(const char* filename, char* buf, size_t);
 
 #ifdef __cplusplus
 }
diff --git a/src/smblib/smblib.vcxproj b/src/smblib/smblib.vcxproj
index bec0680c3d..c0ee164868 100644
--- a/src/smblib/smblib.vcxproj
+++ b/src/smblib/smblib.vcxproj
@@ -118,6 +118,7 @@
     <ClCompile Include="..\hash\crc16.c" />
     <ClCompile Include="..\hash\crc32.c" />
     <ClCompile Include="..\hash\md5.c" />
+    <ClCompile Include="..\hash\sha1.c" />
     <ClCompile Include="smbadd.c">
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
diff --git a/src/smblib/smbstr.c b/src/smblib/smbstr.c
index 245f4ef402..365b9b3b15 100644
--- a/src/smblib/smbstr.c
+++ b/src/smblib/smbstr.c
@@ -23,7 +23,7 @@
 #include <genwrap.h> 		/* stricmp */
 #include "smblib.h"
 
-char* SMBCALL smb_hfieldtype(uint16_t type)
+char* smb_hfieldtype(uint16_t type)
 {
 	static char str[8];
 
@@ -113,7 +113,7 @@ char* SMBCALL smb_hfieldtype(uint16_t type)
 	return(str);
 }
 
-uint16_t SMBCALL smb_hfieldtypelookup(const char* str)
+uint16_t smb_hfieldtypelookup(const char* str)
 {
 	uint16_t type;
 
@@ -127,7 +127,7 @@ uint16_t SMBCALL smb_hfieldtypelookup(const char* str)
 	return(UNKNOWN);
 }
 
-char* SMBCALL smb_dfieldtype(uint16_t type)
+char* smb_dfieldtype(uint16_t type)
 {
 	static char str[8];
 
@@ -140,7 +140,7 @@ char* SMBCALL smb_dfieldtype(uint16_t type)
 	return(str);
 }
 
-char* SMBCALL smb_hashsourcetype(uchar type)
+char* smb_hashsourcetype(uchar type)
 {
 	static char str[8];
 
@@ -154,7 +154,7 @@ char* SMBCALL smb_hashsourcetype(uchar type)
 	return(str);
 }
 
-char* SMBCALL smb_hashsource(smbmsg_t* msg, int source)
+char* smb_hashsource(smbmsg_t* msg, int source)
 {
 	switch(source) {
 		case SMB_HASH_SOURCE_MSG_ID:
@@ -170,7 +170,7 @@ char* SMBCALL smb_hashsource(smbmsg_t* msg, int source)
 /****************************************************************************/
 /* Converts when_t.zone into ASCII format                                   */
 /****************************************************************************/
-char* SMBCALL smb_zonestr(int16_t zone, char* str)
+char* smb_zonestr(int16_t zone, char* str)
 {
 	char*		plus;
     static char buf[32];
@@ -248,7 +248,7 @@ char* SMBCALL smb_zonestr(int16_t zone, char* str)
 /****************************************************************************/
 /* Returns an ASCII string for FidoNet address 'addr'                       */
 /****************************************************************************/
-char* SMBCALL smb_faddrtoa(fidoaddr_t* addr, char* str)
+char* smb_faddrtoa(fidoaddr_t* addr, char* str)
 {
 	static char buf[64];
     char point[25];
@@ -268,7 +268,7 @@ char* SMBCALL smb_faddrtoa(fidoaddr_t* addr, char* str)
 /****************************************************************************/
 /* Returns the FidoNet address parsed from str.								*/
 /****************************************************************************/
-fidoaddr_t SMBCALL smb_atofaddr(const fidoaddr_t* sys_addr, const char *str)
+fidoaddr_t smb_atofaddr(const fidoaddr_t* sys_addr, const char *str)
 {
 	char*		p;
 	const char*	terminator;
@@ -306,7 +306,7 @@ fidoaddr_t SMBCALL smb_atofaddr(const fidoaddr_t* sys_addr, const char *str)
 /* Returns ASCIIZ representation of network address (net_t)					*/
 /* NOT THREAD-SAFE!															*/
 /****************************************************************************/
-char* SMBCALL smb_netaddr(net_t* net)
+char* smb_netaddr(net_t* net)
 {
 	return(smb_netaddrstr(net, NULL));
 }
@@ -314,7 +314,7 @@ char* SMBCALL smb_netaddr(net_t* net)
 /****************************************************************************/
 /* Copies ASCIIZ representation of network address (net_t) into buf			*/
 /****************************************************************************/
-char* SMBCALL smb_netaddrstr(net_t* net, char* fidoaddr_buf)
+char* smb_netaddrstr(net_t* net, char* fidoaddr_buf)
 {
 	if(net->type==NET_FIDO)
 		return(smb_faddrtoa((fidoaddr_t*)net->addr,fidoaddr_buf));
@@ -326,7 +326,7 @@ char* SMBCALL smb_netaddrstr(net_t* net, char* fidoaddr_buf)
 /* QWKnet and Internet addresses must have an '@'.							*/
 /* FidoNet addresses may be in form: "user@addr" or just "addr".			*/
 /****************************************************************************/
-enum smb_net_type SMBCALL smb_netaddr_type(const char* str)
+enum smb_net_type smb_netaddr_type(const char* str)
 {
 	const char*	p;
 
@@ -365,7 +365,7 @@ enum smb_net_type SMBCALL smb_netaddr_type(const char* str)
 /*	"someone@anywhere"	= NET_INTERNET										*/
 /*	"someone@some.host"	= NET_INTERNET										*/
 /****************************************************************************/
-enum smb_net_type SMBCALL smb_get_net_type_by_addr(const char* addr)
+enum smb_net_type smb_get_net_type_by_addr(const char* addr)
 {
 	const char*	p = addr;
 	const char*	tp;
@@ -420,7 +420,7 @@ enum smb_net_type SMBCALL smb_get_net_type_by_addr(const char* addr)
 	return NET_UNKNOWN;
 }
 
-char* SMBCALL smb_nettype(enum smb_net_type type)
+char* smb_nettype(enum smb_net_type type)
 {
 	switch(type) {
 		case NET_NONE:		return "NONE";
diff --git a/src/xpdev/dirwrap.c b/src/xpdev/dirwrap.c
index 44122d0e70..5f996cb76e 100644
--- a/src/xpdev/dirwrap.c
+++ b/src/xpdev/dirwrap.c
@@ -60,7 +60,6 @@
 #endif
 
 #include <sys/types.h>	/* _dev_t */
-#include <sys/stat.h>	/* struct stat */
 
 #include <stdio.h>		/* sprintf */
 #include <stdlib.h>		/* rand */
@@ -68,7 +67,7 @@
 
 #include "genwrap.h"	/* strupr/strlwr */
 #include "dirwrap.h"	/* DLLCALL */
-#include "filewrap.h"	/* filetime() */
+#include "filewrap.h"	/* stat */
 
 #if !defined(S_ISDIR)
 	#define S_ISDIR(x)	((x)&S_IFDIR)
@@ -1095,7 +1094,7 @@ BOOL DLLCALL isfullpath(const char* filename)
 /* Optionally not allowing * to match PATH_DELIM (for paths)				*/
 /****************************************************************************/
 
-BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path)
+BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path, BOOL case_sensitive)
 {
 	char *specp;
 	char *fnamep;
@@ -1127,12 +1126,14 @@ BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path)
 				else
 					wildend=strchr(fnamep, 0);
 				for(;wildend >= fnamep;wildend--) {
-					if(wildmatch(wildend, specp, path))
+					if(wildmatch(wildend, specp, path, case_sensitive))
 						return(TRUE);
 				}
 				return(FALSE);
 			default:
-				if(*specp != *fnamep)
+				if(case_sensitive && *specp != *fnamep)
+					return(FALSE);
+				if((!case_sensitive) && toupper(*specp) != toupper(*fnamep))
 					return(FALSE);
 		}
 		if(!(*specp && *fnamep))
@@ -1142,6 +1143,8 @@ BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path)
 		specp++;
 	if(*specp==*fnamep)
 		return(TRUE);
+	if((!case_sensitive) && toupper(*specp) == toupper(*fnamep))
+		return(TRUE);
 	return(FALSE);
 }
 
@@ -1150,22 +1153,7 @@ BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path)
 /****************************************************************************/
 BOOL DLLCALL wildmatchi(const char *fname, const char *spec, BOOL path)
 {
-	char* s1;
-	char* s2;
-	BOOL result;
-
-	if((s1=strdup(fname))==NULL)
-		return(FALSE);
-	if((s2=strdup(spec))==NULL) {
-		free(s1);
-		return(FALSE);
-	}
-	strupr(s1);
-	strupr(s2);
-	result = wildmatch(s1, s2, path);
-	free(s1);
-	free(s2);
-	return(result);
+	return wildmatch(fname, spec, path, /* case_sensitive: */FALSE);
 }
 
 /****************************************************************************/
diff --git a/src/xpdev/dirwrap.h b/src/xpdev/dirwrap.h
index 4bb505b22f..8c4ba2381b 100644
--- a/src/xpdev/dirwrap.h
+++ b/src/xpdev/dirwrap.h
@@ -1,7 +1,4 @@
 /* Directory system-call wrappers */
-// vi: tabstop=4
-
-/* $Id: dirwrap.h,v 1.55 2019/09/20 08:59:34 rswindell Exp $ */
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -16,21 +13,9 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -54,13 +39,14 @@
 extern "C" {
 #endif
 
+#define ALLFILES "*"	/* matches all files in a directory */
+
 /****************/
 /* RTL-specific */
 /****************/
 
 #if defined(__unix__)
 
-	#define ALLFILES "*"	/* matches all files in a directory */
 	#include <sys/types.h>
 	#include <sys/stat.h>
 	#include <glob.h>		/* POSIX.2 directory pattern matching function */
@@ -81,7 +67,6 @@ extern "C" {
 
 	#include <direct.h>		/* mkdir() */
 
-	#define ALLFILES "*.*"	/* matches all files in a directory */
 	#ifdef __WATCOMC__
 		#define MKDIR(dir)		mkdir(dir)
 	#else
@@ -236,7 +221,7 @@ DLLEXPORT ulong		DLLCALL getfreediskspace(const char* path, ulong unit);
 DLLEXPORT uint64_t	DLLCALL getfilesizetotal(const char *path);
 DLLEXPORT long		DLLCALL delfiles(const char *inpath, const char *spec, size_t keep);
 DLLEXPORT char*		DLLCALL backslash(char* path);
-DLLEXPORT BOOL 		DLLCALL wildmatch(const char *fname, const char *spec, BOOL path);
+DLLEXPORT BOOL 		DLLCALL wildmatch(const char *fname, const char *spec, BOOL path, BOOL case_sensitive);
 DLLEXPORT BOOL 		DLLCALL wildmatchi(const char *fname, const char *spec, BOOL path);
 DLLEXPORT int		DLLCALL	mkpath(const char* path);
 
diff --git a/src/xpdev/gen_defs.h b/src/xpdev/gen_defs.h
index ecbd93a3a6..b516a8e0fb 100644
--- a/src/xpdev/gen_defs.h
+++ b/src/xpdev/gen_defs.h
@@ -273,6 +273,9 @@ typedef intmax_t	intptr_t;
 typedef int32_t         time32_t;
 
 #if defined(_WIN32)
+#  if defined _MSC_VER && !defined _FILE_OFFSET_BITS
+#    define _FILE_OFFSET_BITS 64
+#  endif
 #  if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64)
 #    define off_t       int64_t
 #    define PRIdOFF     PRId64
@@ -459,22 +462,22 @@ typedef struct {
 #define IS_DIGIT(c)						isdigit((unsigned char)(c))
 #define IS_HEXDIGIT(c)					isxdigit((unsigned char)(c))
 #define IS_OCTDIGIT(c)					((c) >= '0' && (c) <= '7')
-#define SKIP_WHITESPACE(p)              while(*(p) && IS_WHITESPACE(*(p)))        (p)++;
-#define FIND_WHITESPACE(p)              while(*(p) && !IS_WHITESPACE(*(p)))       (p)++;
-#define SKIP_CHAR(p,c)                  while(*(p)==c)                            (p)++;
-#define FIND_CHAR(p,c)                  while(*(p) && *(p)!=c)                    (p)++;
-#define SKIP_CHARSET(p,s)               while(*(p) && strchr(s,*(p))!=NULL)       (p)++;
-#define FIND_CHARSET(p,s)               while(*(p) && strchr(s,*(p))==NULL)       (p)++;
+#define SKIP_WHITESPACE(p)              while((p) && *(p) && IS_WHITESPACE(*(p)))        (p)++;
+#define FIND_WHITESPACE(p)              while((p) && *(p) && !IS_WHITESPACE(*(p)))       (p)++;
+#define SKIP_CHAR(p,c)                  while((p) && *(p)==c)                            (p)++;
+#define FIND_CHAR(p,c)                  while((p) && *(p) && *(p)!=c)                    (p)++;
+#define SKIP_CHARSET(p,s)               while((p) && *(p) && strchr(s,*(p))!=NULL)       (p)++;
+#define FIND_CHARSET(p,s)               while((p) && *(p) && strchr(s,*(p))==NULL)       (p)++;
 #define SKIP_CRLF(p)					SKIP_CHARSET(p, "\r\n")
 #define FIND_CRLF(p)					FIND_CHARSET(p, "\r\n")
-#define SKIP_ALPHA(p)                   while(*(p) && IS_ALPHA(*(p)))             (p)++;
-#define FIND_ALPHA(p)                   while(*(p) && !IS_ALPHA(*(p)))            (p)++;
-#define SKIP_ALPHANUMERIC(p)            while(*(p) && IS_ALPHANUMERIC(*(p)))      (p)++;
-#define FIND_ALPHANUMERIC(p)            while(*(p) && !IS_ALPHANUMERIC(*(p)))     (p)++;
-#define SKIP_DIGIT(p)                   while(*(p) && IS_DIGIT(*(p)))             (p)++;
-#define FIND_DIGIT(p)                   while(*(p) && !IS_DIGIT(*(p)))            (p)++;
-#define SKIP_HEXDIGIT(p)                while(*(p) && IS_HEXDIGIT(*(p)))          (p)++;
-#define FIND_HEXDIGIT(p)                while(*(p) && !IS_HEXDIGIT(*(p)))         (p)++;
+#define SKIP_ALPHA(p)                   while((p) && *(p) && IS_ALPHA(*(p)))             (p)++;
+#define FIND_ALPHA(p)                   while((p) && *(p) && !IS_ALPHA(*(p)))            (p)++;
+#define SKIP_ALPHANUMERIC(p)            while((p) && *(p) && IS_ALPHANUMERIC(*(p)))      (p)++;
+#define FIND_ALPHANUMERIC(p)            while((p) && *(p) && !IS_ALPHANUMERIC(*(p)))     (p)++;
+#define SKIP_DIGIT(p)                   while((p) && *(p) && IS_DIGIT(*(p)))             (p)++;
+#define FIND_DIGIT(p)                   while((p) && *(p) && !IS_DIGIT(*(p)))            (p)++;
+#define SKIP_HEXDIGIT(p)                while((p) && *(p) && IS_HEXDIGIT(*(p)))          (p)++;
+#define FIND_HEXDIGIT(p)                while((p) && *(p) && !IS_HEXDIGIT(*(p)))         (p)++;
 
 #define HEX_CHAR_TO_INT(ch) 			(((ch)&0xf)+(((ch)>>6)&1)*9)
 #define DEC_CHAR_TO_INT(ch)				((ch)&0xf)
diff --git a/src/xpdev/ini_file.c b/src/xpdev/ini_file.c
index b347d72cba..c20f5a700e 100644
--- a/src/xpdev/ini_file.c
+++ b/src/xpdev/ini_file.c
@@ -312,6 +312,9 @@ BOOL iniSectionExists(str_list_t list, const char* section)
 {
 	size_t	i;
 
+	if(list==NULL)
+		return(FALSE);
+
 	if(section==ROOT_SECTION)
 		return(TRUE);
 
diff --git a/src/xpdev/str_list.c b/src/xpdev/str_list.c
index 21fb5819b1..d374157d1b 100644
--- a/src/xpdev/str_list.c
+++ b/src/xpdev/str_list.c
@@ -1,9 +1,5 @@
-/* str_list.c */
-
 /* Functions to deal with NULL-terminated string lists */
 
-/* $Id: str_list.c,v 1.61 2020/05/26 02:46:15 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,21 +13,9 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -167,6 +151,28 @@ char* strListRemove(str_list_t* list, size_t index)
 	return(str);
 }
 
+// Remove without realloc
+char* strListFastRemove(str_list_t list, size_t index)
+{
+	char*	str;
+	size_t	i;
+	size_t	count;
+
+	count = strListCount(list);
+
+	if(index == STR_LIST_LAST_INDEX && count)
+		index = count-1;
+
+	if(index >= count)	/* invalid index, do nothing */
+		return NULL;
+
+	str = list[index];
+	for(i = index; i < count; i++)
+		list[i] = list[i + 1];
+
+	return str;
+}
+
 BOOL strListDelete(str_list_t* list, size_t index)
 {
 	char*	str;
@@ -179,6 +185,18 @@ BOOL strListDelete(str_list_t* list, size_t index)
 	return(TRUE);
 }
 
+BOOL strListFastDelete(str_list_t list, size_t index)
+{
+	char*	str;
+
+	if((str=strListFastRemove(list, index))==NULL)
+		return(FALSE);
+
+	free(str);
+
+	return(TRUE);
+}
+
 char* strListReplace(const str_list_t list, size_t index, const char* str)
 {
 	char*	buf;
@@ -818,3 +836,35 @@ int strListDedupe(str_list_t* list, BOOL case_sensitive)
 	}
 	return i;
 }
+
+int strListDeleteBlanks(str_list_t* list)
+{
+	size_t		i;
+
+	if(list == NULL || *list == NULL)
+		return 0;
+
+	for(i = 0; (*list)[i] != NULL; ) {
+		if((*list)[i][0] == '\0')
+			strListDelete(list, i);
+		else
+			i++;
+	}
+	return i;
+}
+
+int strListFastDeleteBlanks(str_list_t list)
+{
+	size_t		i;
+
+	if(list == NULL || *list == NULL)
+		return 0;
+
+	for(i = 0; list[i] != NULL; ) {
+		if(list[i][0] == '\0')
+			strListFastDelete(list, i);
+		else
+			i++;
+	}
+	return i;
+}
diff --git a/src/xpdev/str_list.h b/src/xpdev/str_list.h
index 0bafae0984..a5994b359e 100644
--- a/src/xpdev/str_list.h
+++ b/src/xpdev/str_list.h
@@ -1,9 +1,5 @@
-/* str_list.h */
-
 /* Functions to deal with NULL-terminated string lists */
 
-/* $Id: str_list.h,v 1.32 2020/04/24 07:02:17 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -17,21 +13,9 @@
  * See the GNU Lesser General Public License for more details: lgpl.txt or	*
  * http://www.fsf.org/copyleft/lesser.html									*
  *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
  * For Synchronet coding style and modification guidelines, see				*
  * http://www.synchro.net/source.html										*
  *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
@@ -86,9 +70,11 @@ DLLEXPORT char*			strListInsertFormat(str_list_t* list, size_t index, const char
 
 /* Remove a string at a specific index */
 DLLEXPORT char*			strListRemove(str_list_t*, size_t index);
+DLLEXPORT char*			strListFastRemove(str_list_t, size_t index);
 
 /* Remove and free a string at a specific index */
 DLLEXPORT BOOL			strListDelete(str_list_t*, size_t index);
+DLLEXPORT BOOL			strListFastDelete(str_list_t, size_t index);
 
 /* Replace a string at a specific index */
 DLLEXPORT char*			strListReplace(const str_list_t, size_t index, const char* str);
@@ -113,7 +99,7 @@ DLLEXPORT BOOL			strListSwap(const str_list_t, size_t index1, size_t index2);
 #define		strListPush(list, str)	strListAppend(list, str, STR_LIST_LAST_INDEX)
 #define		strListPop(list)		strListRemove(list, STR_LIST_LAST_INDEX)
 
-/* Add to an exiting or new string list by splitting specified string (str) */
+/* Add to an existing or new string list by splitting specified string (str) */
 /* into multiple strings, separated by one of the delimit characters */
 DLLEXPORT str_list_t	strListSplit(str_list_t*, char* str, const char* delimit);
 
@@ -168,6 +154,9 @@ DLLEXPORT int			strListTruncateStrings(str_list_t, const char* set);
 DLLEXPORT int			strListStripStrings(str_list_t, const char* set);
 /* Remove duplicate strings from list, return the new list length */
 DLLEXPORT int			strListDedupe(str_list_t*, BOOL case_sensitive);
+/* Remove blank strings from list, return the new list length */
+DLLEXPORT int			strListDeleteBlanks(str_list_t*);
+DLLEXPORT int			strListFastDeleteBlanks(str_list_t);
 
 /************/
 /* File I/O */
diff --git a/src/xpdev/xpdatetime.c b/src/xpdev/xpdatetime.c
index de6363d88f..c5ebcf1eb1 100644
--- a/src/xpdev/xpdatetime.c
+++ b/src/xpdev/xpdatetime.c
@@ -171,6 +171,20 @@ xpDateTime_t DLLCALL time_to_xpDateTime(time_t ti, xpTimeZone_t zone)
 		,zone==xpTimeZone_LOCAL ? xpTimeZone_local() : zone);
 }
 
+xpDate_t DLLCALL time_to_xpDate(time_t ti)
+{
+	xpDate_t never;
+	struct tm tm;
+
+	ZERO_VAR(never);
+	ZERO_VAR(tm);
+	if(localtime_r(&ti,&tm)==NULL)
+		return never;
+
+	return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday
+		,tm.tm_hour,tm.tm_min,(float)tm.tm_sec, /* zone: */0).date;
+}
+
 xpDateTime_t DLLCALL gmtime_to_xpDateTime(time_t ti)
 {
 	xpDateTime_t	never;
diff --git a/src/xpdev/xpdatetime.h b/src/xpdev/xpdatetime.h
index 942a78413c..bd9dc0fd2c 100644
--- a/src/xpdev/xpdatetime.h
+++ b/src/xpdev/xpdatetime.h
@@ -79,6 +79,7 @@ DLLEXPORT xpDateTime_t	DLLCALL xpDateTime_create(unsigned year, unsigned month,
 DLLEXPORT xpDateTime_t	DLLCALL xpDateTime_now(void);
 DLLEXPORT time_t		DLLCALL xpDateTime_to_time(xpDateTime_t);
 DLLEXPORT time_t		DLLCALL xpDateTime_to_localtime(xpDateTime_t);
+DLLEXPORT xpDate_t		DLLCALL time_to_xpDate(time_t);
 DLLEXPORT xpDateTime_t	DLLCALL time_to_xpDateTime(time_t, xpTimeZone_t);
 DLLEXPORT xpDateTime_t	DLLCALL gmtime_to_xpDateTime(time_t);
 DLLEXPORT xpTimeZone_t	DLLCALL xpTimeZone_local(void);
diff --git a/text/menu/sysxfer.asc b/text/menu/sysxfer.asc
index 895c330e0c..0c26ee5554 100644
--- a/text/menu/sysxfer.asc
+++ b/text/menu/sysxfer.asc
@@ -5,10 +5,7 @@ PUT [s]         Direct upload file s to any drive or directory (remote)
 GET [s]         Direct download file s from any drive or directory (remote)
 OLD           *	Remove, Edit, or Move files not downloaded since new-scan date
 OLDUL         *	Remove, Edit, or Move files uploaded before new-scan date
-CLOSE         *	Search for and optionally close open file records
-ALTUL [x]	Perform uploads using alternate file path number x
 UPLOAD        *	Bulk local upload - add files on disk to database
-RESORT        *	Re-sort files by sort value and compress empty slots
 OFFLINE       *	Remove, Edit, or Move files in database that aren't on disk
 
 * Commands can be followed by LIB or ALL to specify the action to take place
diff --git a/text/menu/transfer.msg b/text/menu/transfer.msg
index 44e427fd7c..5dd9070b88 100644
--- a/text/menu/transfer.msg
+++ b/text/menu/transfer.msg
@@ -9,9 +9,9 @@
  �� hy[ ] c/# ncSelect library   b�  hy& ncFile scan config
    hyD ncDownload file�b���  hyR ncRemove/edit file
    hyU ncUpload file�b����������4 hwGo to nb����������  hyI ncInformation
-  hy/D ncDownload from user   b���  hyV ncView file contents
-  hy/U ncUpload to user�b� hyQ ncMain/Message section  b� hy/L ncNode activity
-   hyZ ncUpload to sysop�b� hyC ncChat section�b� hy^K ncCtrl-key menu
-   hyB ncBatch/Bi-dir xfers   b� hyT ncTemp dir/Archive cmds b�  hyO ncLogoff BBS (or hy/Onc)
+   hyZ ncUpload to sysop      b���  hyV ncView file contents
+   b������������������������hy Q ncMain/Message section  b� hy/L ncNode activity
+   hyB ncBatch/Bi-dir xfers   b� hyC ncChat section�b� hy^K ncCtrl-key menu
+                          b� hyT ncTemp dir/Archive cmds b�  hyO ncLogoff BBS (or hy/Onc)
 b ����  @SYSONLY@hy!nc Sysop Menu@SYSONLY@
 @HOT:OFF@@INCLUDE:%zmenu/tail.msg@
\ No newline at end of file
-- 
GitLab