From 9db7a6145f17baa1323f11f957c47c0b564d1165 Mon Sep 17 00:00:00 2001
From: Rob Swindell <rob@synchro.net>
Date: Mon, 21 Mar 2022 01:27:15 -0700
Subject: [PATCH] SMB items (messages or files) can now have 32-bit or 64-bit
 cost value

To fully support files > 4GB in size in file bases, credit values larger than 32-bits must be supported too.

There's a couple of todo comments/items included in this commit, but that's mainly to do with messages (which don't really have costs anyway).

The main thing to deal with now is the fact that users can't have more than 4GB in credits in the first place! That's got to be fixed next.
---
 src/sbbs3/atcodes.cpp   |  2 +-
 src/sbbs3/bat_xfer.cpp  | 10 +++++-----
 src/sbbs3/file.cpp      |  4 ++--
 src/sbbs3/filelist.c    |  3 ++-
 src/sbbs3/ftpsrvr.c     |  2 +-
 src/sbbs3/js_bbs.cpp    |  2 +-
 src/sbbs3/js_filebase.c |  9 ++-------
 src/sbbs3/js_msgbase.c  |  2 +-
 src/sbbs3/pack_qwk.cpp  |  4 ++--
 src/sbbs3/upload.cpp    |  3 +--
 src/smblib/smbdefs.h    |  6 +++---
 src/smblib/smblib.c     | 17 ++++++++++-------
 12 files changed, 31 insertions(+), 33 deletions(-)

diff --git a/src/sbbs3/atcodes.cpp b/src/sbbs3/atcodes.cpp
index ff5538e84c..f189baee21 100644
--- a/src/sbbs3/atcodes.cpp
+++ b/src/sbbs3/atcodes.cpp
@@ -2056,7 +2056,7 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, long* pmode, bool
 			return str;
 		}
 		if(strcmp(sp, "FILE_CREDITS") == 0) {
-			safe_snprintf(str, maxlen, "%lu", (ulong)current_file->cost);
+			safe_snprintf(str, maxlen, "%" PRIu64, current_file->cost);
 			return str;
 		}
 		if(strcmp(sp, "FILE_TIME") == 0)
diff --git a/src/sbbs3/bat_xfer.cpp b/src/sbbs3/bat_xfer.cpp
index c3954ace90..f34a3ef208 100644
--- a/src/sbbs3/bat_xfer.cpp
+++ b/src/sbbs3/bat_xfer.cpp
@@ -124,8 +124,8 @@ void sbbs_t::batchmenu()
 						getfiletime(&cfg, &f);
 						bprintf(text[DownloadQueueLstFmt],i+1
 							,filename
-							,ultoac(f.cost, tmp)
-							,ultoac((ulong)f.size, str)
+							,i64toac(f.cost, tmp)
+							,i64toac(f.size, str)
 							,cur_cps
 								? sectostr((uint)(f.size/(ulong)cur_cps),tmp2)
 								: "??:??:??"
@@ -701,9 +701,9 @@ bool sbbs_t::addtobatdl(file_t* f)
 			} 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/MAX((ulong)cur_cps, 1),str));
+						,f->name, strListCount(filenames) + 1, cfg.max_batdn, i64toac(totalcost,tmp)
+						,i64toac(totalsize,tmp2)
+						,sectostr((ulong)(totalsize/MAX((ulong)cur_cps, 1)),str));
 					result = true;
 				}
 			}
diff --git a/src/sbbs3/file.cpp b/src/sbbs3/file.cpp
index 4c905c8c09..1c952b019f 100644
--- a/src/sbbs3/file.cpp
+++ b/src/sbbs3/file.cpp
@@ -43,7 +43,7 @@ void sbbs_t::showfileinfo(file_t* f, bool show_extdesc)
 			, byte_estimate_to_str(f->size, tmp2, sizeof(tmp2), /* units: */1024, /* precision: */1));
 
 	bprintf(P_TRUNCATE, text[FiCredits]
-		,(cfg.dir[f->dir]->misc&DIR_FREE || !f->cost) ? "FREE" : ultoac((ulong)f->cost,tmp));
+		,(cfg.dir[f->dir]->misc&DIR_FREE || !f->cost) ? "FREE" : i64toac(f->cost,tmp));
 	if(getfilesize(&cfg, f) > 0 &&  f->size == smb_getfilesize(&f->idx)) {
 #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) {
@@ -344,7 +344,7 @@ bool sbbs_t::editfileinfo(file_t* f)
 			return false;
 		if(*uploader != '\0' || *f->from != '\0')
 			smb_new_hfield_str(f, SMB_FILEUPLOADER, uploader);
-		ultoa(f->cost,str,10);
+		SAFEPRINTF(str, "%"PRIu64, f->cost);
 		bputs(text[EditCreditValue]);
 		getstr(str,10,K_NUMBER|K_EDIT|K_AUTODEL);
 		if(msgabort(true))
diff --git a/src/sbbs3/filelist.c b/src/sbbs3/filelist.c
index 540ee54420..b2eadb5012 100644
--- a/src/sbbs3/filelist.c
+++ b/src/sbbs3/filelist.c
@@ -109,7 +109,8 @@ int main(int argc, char **argv)
 	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;
+	ulong	m,misc=0,total_cdt=0,total_files=0,dir_files;
+	uint64_t cdt;
 	long	max_age=0;
 	FILE*	out=NULL;
 
diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index 131ada764e..6fc323c791 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -560,7 +560,7 @@ static void send_thread(void* arg)
 	int			rd;
 	int			wr;
 	long		mod;
-	ulong		l;
+	uint64_t	l;
 	off_t		total=0;
 	off_t		last_total=0;
 	ulong		dur;
diff --git a/src/sbbs3/js_bbs.cpp b/src/sbbs3/js_bbs.cpp
index aa6044f596..ec2b0c421e 100644
--- a/src/sbbs3/js_bbs.cpp
+++ b/src/sbbs3/js_bbs.cpp
@@ -733,7 +733,7 @@ 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->cost;
+				val=(uint32_t)sbbs->current_file->cost; // TODO (cost is now 64-bit)
 			break;
 		case BBS_PROP_FILE_DIR:
 			if(sbbs->current_file==NULL)
diff --git a/src/sbbs3/js_filebase.c b/src/sbbs3/js_filebase.c
index e6d0950845..0583c2d398 100644
--- a/src/sbbs3/js_filebase.c
+++ b/src/sbbs3/js_filebase.c
@@ -247,7 +247,7 @@ set_file_properties(JSContext *cx, JSObject* obj, file_t* f, enum file_detail de
 		return false;
 
 	if(f->cost > 0 || detail > file_detail_metadata) {
-		val = UINT_TO_JSVAL(f->cost);
+		val = DOUBLE_TO_JSVAL((double)f->cost);
 		if(!JS_DefineProperty(cx, obj, "cost", val, NULL, NULL, flags))
 			return false;
 	}
@@ -571,12 +571,7 @@ parse_file_properties(JSContext *cx, JSObject* obj, file_t* file, char** extdesc
 	}
 	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)) {
-			free(cp);
-			JS_ReportError(cx, "Error converting '%s' property to Uint32", prop_name);
-			return SMB_FAILURE;
-		}
+		uint64_t cost = (uint64_t)JSVAL_TO_DOUBLE(val);
 		if((file->cost != 0 || cost != 0) && (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);
diff --git a/src/sbbs3/js_msgbase.c b/src/sbbs3/js_msgbase.c
index 79601aca93..df4159c42d 100644
--- a/src/sbbs3/js_msgbase.c
+++ b/src/sbbs3/js_msgbase.c
@@ -1420,7 +1420,7 @@ static JSBool js_get_msg_header_resolve(JSContext *cx, JSObject *obj, jsid id)
 	LAZY_STRING_COND("sender_time", (val=smb_get_hfield(&(p->msg),SENDERTIME,NULL))!=NULL, val, JSPROP_ENUMERATE);
 	LAZY_UINTEGER_EXPAND("forwarded", p->msg.forwarded, JSPROP_ENUMERATE);
 	LAZY_UINTEGER_EXPAND("expiration", p->msg.expiration, JSPROP_ENUMERATE);
-	LAZY_UINTEGER_EXPAND("cost", p->msg.cost, JSPROP_ENUMERATE);
+	LAZY_UINTEGER_EXPAND("cost", (uint32)p->msg.cost, JSPROP_ENUMERATE);
 	LAZY_STRING_TRUNCSP_NULL("editor", p->msg.editor, JSPROP_ENUMERATE);
 	LAZY_UINTEGER_EXPAND("columns", p->msg.columns, JSPROP_ENUMERATE);
 	LAZY_STRING_TRUNCSP_NULL("mime_version", p->msg.mime_version, JSPROP_ENUMERATE|JSPROP_READONLY);
diff --git a/src/sbbs3/pack_qwk.cpp b/src/sbbs3/pack_qwk.cpp
index 0727e71969..0da138a1fd 100644
--- a/src/sbbs3/pack_qwk.cpp
+++ b/src/sbbs3/pack_qwk.cpp
@@ -646,7 +646,7 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 			CRLF; 
 	}
 	{
-		int64_t totalcdt = 0;
+		uint64_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++) {
@@ -655,7 +655,7 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 			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)) {
+				if(totalcdt + f.cost > (uint64_t)(useron.cdt+useron.freecdt)) {
 					bprintf(text[YouOnlyHaveNCredits]
 						,ultoac(useron.cdt+useron.freecdt,tmp));
 					batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, filename);
diff --git a/src/sbbs3/upload.cpp b/src/sbbs3/upload.cpp
index f05c86df75..92217d759d 100644
--- a/src/sbbs3/upload.cpp
+++ b/src/sbbs3/upload.cpp
@@ -170,8 +170,7 @@ bool sbbs_t::uploadfile(file_t* f)
 	}
 	if(cfg.dir[f->dir]->misc&DIR_AONLY)  /* Forced anonymous */
 		f->hdr.attr |= MSG_ANONYMOUS;
-	uint32_t cdt = (uint32_t)MIN(length, UINT32_MAX);
-	smb_hfield_bin(f, SMB_COST, cdt);
+	smb_hfield_bin(f, SMB_COST, length);
 	smb_hfield_str(f, SENDER, useron.alias);
 	bprintf(text[FileNBytesReceived],f->name, i64toac(length,tmp));
 	if(!addfile(&cfg, f->dir, f, ext, /* metadata: */NULL, &client))
diff --git a/src/smblib/smbdefs.h b/src/smblib/smbdefs.h
index 9adb5ed8bc..0412dc058a 100644
--- a/src/smblib/smbdefs.h
+++ b/src/smblib/smbdefs.h
@@ -198,10 +198,11 @@
 #define SMB_GROUP			0x64
 #define SMB_EXPIRATION		0x65
 #define SMB_PRIORITY		0x66	/* DEPRECATED */
-#define SMB_COST			0x67
+#define SMB_COST			0x67	/* 32-bit or 64-bit cost value */
 #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_COLUMNS			0x6a	/* original text editor width in fixed-width columns */
 
 #define SMB_FILEIDX_NAMELEN	64
 #define SMB_FILENAME		SUBJECT
@@ -232,7 +233,6 @@
 #define PRESENTTRIGGER		0x94
 #define VIDEOTRIGGER		0x95
 #define APPDATATRIGGER		0x96
-#define SMB_COLUMNS			0x6a	/* original text editor width in fixed-width columns */
 
 #define FIDOCTRL			0xa0
 #define FIDOAREA			0xa1
@@ -656,7 +656,7 @@ typedef struct {				/* Message or File */
 	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 */
+	uint64_t	cost;			/* Cost to download/read */
 	uint32_t	flags;			/* Various smblib run-time flags (see MSG_FLAG_*) */
 	uint16_t	user_voted;		/* How the current user viewing this message, voted on it */
 	uint32_t	upvotes;		/* Vote tally for this message */
diff --git a/src/smblib/smblib.c b/src/smblib/smblib.c
index ef2771d493..53b8863921 100644
--- a/src/smblib/smblib.c
+++ b/src/smblib/smblib.c
@@ -740,7 +740,7 @@ ulong smb_getmsgtxtlen(smbmsg_t* msg)
 	return(length);
 }
 
-static void set_convenience_ptr(smbmsg_t* msg, uint16_t hfield_type, void* hfield_dat)
+static void set_convenience_ptr(smbmsg_t* msg, uint16_t hfield_type, size_t len, void* hfield_dat)
 {
 	switch(hfield_type) {	/* convenience variables */
 		case SENDER:
@@ -840,7 +840,10 @@ static void set_convenience_ptr(smbmsg_t* msg, uint16_t hfield_type, void* hfiel
 			msg->expiration=*(uint32_t*)hfield_dat;
 			break;
 		case SMB_COST:
-			msg->cost=*(uint32_t*)hfield_dat;
+			if(len == sizeof(uint32_t))
+				msg->cost=*(uint32_t*)hfield_dat;
+			else if(len == sizeof(uint64_t))
+				msg->cost=*(uint64_t*)hfield_dat;
 			break;
 		case RFC822MSGID:
 			msg->id=(char*)hfield_dat;
@@ -1079,7 +1082,7 @@ int smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
 				,"%s reading header field data", __FUNCTION__);
 			return(SMB_ERR_READ); 
 		}
-		set_convenience_ptr(msg,msg->hfield[i].type,msg->hfield_dat[i]);
+		set_convenience_ptr(msg,msg->hfield[i].type,msg->hfield[i].length,msg->hfield_dat[i]);
 
 		l+=msg->hfield[i].length; 
 	}
@@ -1199,7 +1202,7 @@ int smb_copymsgmem(smb_t* smb, smbmsg_t* msg, smbmsg_t* srcmsg)
 			}
 			memset(msg->hfield_dat[i],0,msg->hfield[i].length+1);
 			memcpy(msg->hfield_dat[i],srcmsg->hfield_dat[i],msg->hfield[i].length);
-			set_convenience_ptr(msg, msg->hfield[i].type, msg->hfield_dat[i]);
+			set_convenience_ptr(msg, msg->hfield[i].type, msg->hfield[i].length, msg->hfield_dat[i]);
 		}
 	}
 
@@ -1254,7 +1257,7 @@ int smb_hfield_add(smbmsg_t* msg, uint16_t type, size_t length, void* data, BOOL
 		return(SMB_ERR_MEM);	/* Allocate 1 extra for ASCIIZ terminator */
 	memset(msg->hfield_dat[i],0,length+1);
 	memcpy(msg->hfield_dat[i],data,length); 
-	set_convenience_ptr(msg,type,msg->hfield_dat[i]);
+	set_convenience_ptr(msg,type,length,msg->hfield_dat[i]);
 
 	return(SMB_SUCCESS);
 }
@@ -1373,7 +1376,7 @@ int smb_hfield_append(smbmsg_t* msg, uint16_t type, size_t length, void* data)
 	memset(p,0,length+1);
 	memcpy(p,data,length);		/* append */
 	msg->hfield[i].length+=(uint16_t)length;
-	set_convenience_ptr(msg,type,msg->hfield_dat[i]);
+	set_convenience_ptr(msg,type,length,msg->hfield_dat[i]);
 
 	return(SMB_SUCCESS);
 }
@@ -1411,7 +1414,7 @@ int smb_hfield_replace(smbmsg_t* msg, uint16_t type, size_t length, void* data)
 	memset(p,0,length+1);
 	memcpy(p,data,length);
 	msg->hfield[i].length=(uint16_t)length;
-	set_convenience_ptr(msg,type,msg->hfield_dat[i]);
+	set_convenience_ptr(msg,type,length,msg->hfield_dat[i]);
 
 	return SMB_SUCCESS;
 }
-- 
GitLab