diff --git a/src/sbbs3/pack_rep.cpp b/src/sbbs3/pack_rep.cpp
index 86b3e5297d34aa2c686fc9205343795f44887b3d..190bba9ebbbc6ec16c001f0a2b3502386651d52c 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/scfg/scfgnet.c b/src/sbbs3/scfg/scfgnet.c
index ff8317fef04777d1e44b6e6f37db317ab7dbd774..360a8a32619c8b38473ac0c281b01eefaa3163de 100644
--- a/src/sbbs3/scfg/scfgnet.c
+++ b/src/sbbs3/scfg/scfgnet.c
@@ -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/scfgdefs.h b/src/sbbs3/scfgdefs.h
index 77aa946882d6fba7f365a80681e8cbd7c85ae1b7..6ebf654d046f39b5b1e4f46da877e4642d5587bc 100644
--- a/src/sbbs3/scfgdefs.h
+++ b/src/sbbs3/scfgdefs.h
@@ -312,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/scfglib1.c b/src/sbbs3/scfglib1.c
index f3e92c7db298aec2d5ce92210a37ed0c9690c82f..f274307026e731eb0449316a818463476895243b 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);
 	}
 
diff --git a/src/sbbs3/scfgsave.c b/src/sbbs3/scfgsave.c
index 14ab2dcb6a3c5cc671a3da3bed04638095a8fbdd..5be3129b0d4d4560f28446d7dae8198f283206fb 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;
diff --git a/src/sbbs3/un_qwk.cpp b/src/sbbs3/un_qwk.cpp
index 0d35a98cc6325465695361370cbc5eab6d366745..ac05baf2f7003144c0e4db524a0d2573e2d6499c 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)) {