bat_xfer.cpp 21.9 KB
Newer Older
1 2 3 4 5 6
/* Synchronet batch file transfer functions */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *																			*
 * 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"
23
#include "filedat.h"
24 25 26 27 28 29

/****************************************************************************/
/* This is the batch menu section                                           */
/****************************************************************************/
void sbbs_t::batchmenu()
{
30 31
    char	str[129],tmp2[250],done=0,ch;
	char 	tmp[512];
32
	char	keys[32];
33
	uint	i,n,xfrprot,xfrdir;
34
    int64_t	totalcdt,totalsize;
35
    time_t	start,end;
36 37
	str_list_t ini;
	str_list_t filenames;
38

39
	if(batdn_total() < 1 && batup_total() < 1 && cfg.upload_dir==INVALID_DIR) {
40
		bputs(text[NoFilesInBatchQueue]);
41 42
		return; 
	}
43
	if(useron.misc&(RIP|WIP|HTML) && !(useron.misc&EXPERT))
44
		menu("batchxfer");
45
	lncntr=0;
46
	while(online && !done && (cfg.upload_dir!=INVALID_DIR || batdn_total() || batup_total())) {
47
		if(!(useron.misc&(EXPERT|RIP|WIP|HTML))) {
48 49 50 51 52
			sys_status&=~SS_ABORT;
			if(lncntr) {
				SYNC;
				CRLF;
				if(lncntr)          /* CRLF or SYNC can cause pause */
53 54 55 56
					pause(); 
			}
			menu("batchxfr"); 
		}
57 58
		ASYNC;
		bputs(text[BatchMenuPrompt]);
59
		SAFEPRINTF(keys,"CDLRU?\r%c", quit_key());
60
		ch=(char)getkeys(keys,0);
61
		if(ch>' ')
62
			logch(ch,0);
63
		if(ch==quit_key() || ch=='\r') {	/* Quit */
64 65 66 67
			lncntr=0;
			done=1;
			break;
		}
68 69
		switch(ch) {
			case '?':
70
				if(useron.misc&(EXPERT|RIP|WIP|HTML))
71
					menu("batchxfr");
72 73
				break;
			case 'C':
74 75 76
				if(batup_total() < 1) {
					bputs(text[UploadQueueIsEmpty]);
				} else {
77
					if(text[ClearUploadQueueQ][0]==0 || !noyes(text[ClearUploadQueueQ])) {
78 79
						if(clearbatul())
							bputs(text[UploadQueueCleared]);
80 81
					} 
				}
82 83 84
				if(batdn_total() <1 ) {
					bputs(text[DownloadQueueIsEmpty]);
				} else {
85
					if(text[ClearDownloadQueueQ][0]==0 || !noyes(text[ClearDownloadQueueQ])) {
86 87
						if(clearbatdl())
							bputs(text[DownloadQueueCleared]); 
88 89
					} 
				}
90 91 92 93 94
				break;
			case 'D':
				start_batch_download();
				break;
			case 'L':
95 96
			{
				bool sort = !noyes(text[SortAlphaQ]);
97 98 99
				ini = batch_list_read(&cfg, useron.number, XFER_BATCH_UPLOAD);
				filenames = iniGetSectionList(ini, NULL);
				if(strListCount(filenames)) {
100 101
					if(sort)
						strListSortAlphaCase(filenames);
102
					bputs(text[UploadQueueLstHdr]);
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
					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)) {
121 122
					if(sort)
						strListSortAlphaCase(filenames);
123
					bputs(text[DownloadQueueLstHdr]);
124 125 126 127 128 129 130
					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);
131
						bprintf(text[DownloadQueueLstFmt],i+1
132
							,filename
133 134
							,byte_estimate_to_str(f.cost, tmp, sizeof(tmp), 1, 1)
							,byte_estimate_to_str(f.size, str, sizeof(str), 1, 1)
135
							,cur_cps
136
								? sectostr((uint)(f.size/(uint64_t)cur_cps), tmp2)
137 138 139 140 141
								: "??:??:??"
							,datestr(f.time)
						);
						totalsize += f.size;
						totalcdt += f.cost;
142
						smb_freefilemem(&f);
143
					}
144
					bprintf(text[DownloadQueueTotals]
145 146 147
						,byte_estimate_to_str(totalcdt, tmp, sizeof(tmp), 1, 1)
						,byte_estimate_to_str(totalsize, str, sizeof(tmp), 1, 1)
						,cur_cps ? sectostr((uint)(totalsize/(uint64_t)cur_cps), tmp2) : "??:??:??"); 
148 149 150 151 152
				} else
					bputs(text[DownloadQueueIsEmpty]);
				iniFreeStringList(filenames);
				iniFreeStringList(ini);
				break;
153
			}
154
			case 'R':
155 156 157
				if((n = batup_total()) > 0) {
					bprintf(text[RemoveWhichFromUlQueue], n);
					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
158 159
						if(!batch_file_remove(&cfg, useron.number, XFER_BATCH_UPLOAD, str) && (n = atoi(str)) > 0)
							batch_file_remove_n(&cfg, useron.number, XFER_BATCH_UPLOAD, n - 1);
160
				}
161 162 163
				if((n = batdn_total()) > 0) {
					bprintf(text[RemoveWhichFromDlQueue], n);
					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
164 165
						if(!batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, str) && (n = atoi(str)) > 0)
							batch_file_remove_n(&cfg, useron.number, XFER_BATCH_DOWNLOAD, n - 1);
166
				}
167 168 169 170
				break;
		   case 'U':
				if(useron.rest&FLAG('U')) {
					bputs(text[R_Upload]);
171 172
					break; 
				}
173
				if(batup_total() < 1 && cfg.upload_dir==INVALID_DIR) {
174
					bputs(text[UploadQueueIsEmpty]);
175 176
					break; 
				}
177
				xfer_prot_menu(XFER_BATCH_UPLOAD);
178 179 180 181
				if(!create_batchup_lst())
					break;
				ASYNC;
				mnemonics(text[ProtocolOrQuit]);
182
				SAFEPRINTF(str,"%c",quit_key());
183
				for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
184
					if(cfg.prot[i]->batulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
185
						sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
186
						SAFECAT(str,tmp); 
187
					}
188
				ch=(char)getkeys(str,0);
189
				if(ch==quit_key())
190 191 192
					break;
				for(i=0;i<cfg.total_prots;i++)
					if(cfg.prot[i]->batulcmd[0] && cfg.prot[i]->mnemonic==ch
rswindell's avatar
rswindell committed
193
						&& chk_ar(cfg.prot[i]->ar,&useron,&client))
194 195
						break;
				if(i<cfg.total_prots) {
196
					SAFEPRINTF(str,"%sBATCHUP.LST",cfg.node_dir);
197
					xfrprot=i;
198
					xfrdir=cfg.upload_dir;
199 200 201
					action=NODE_ULNG;
					SYNC;
					if(online==ON_REMOTE) {
202
						delfiles(cfg.temp_dir,ALLFILES);
203
						start=time(NULL);
204
						protocol(cfg.prot[xfrprot],XFER_BATCH_UPLOAD,str,nulstr,true);
205
						end=time(NULL);
206
						if(xfrdir != INVALID_DIR && !(cfg.dir[xfrdir]->misc&DIR_ULTIME))
207 208
							starttime+=end-start; 
					}
209
					batch_upload();
210
					delfiles(cfg.temp_dir,ALLFILES);
211 212 213 214 215
					autohangup(); 
				}
				break; 
		} 
	}
216
	delfiles(cfg.temp_dir,ALLFILES);
217 218 219 220 221
}

/****************************************************************************/
/* Download files from batch queue                                          */
/****************************************************************************/
222
BOOL sbbs_t::start_batch_download()
223
{
224 225 226 227
	char	ch;
	char	tmp[32];
	char	str[MAX_PATH+1];
	char 	path[MAX_PATH+1];
228
	char	list[1024] = "";
229
	int		error;
230 231
    uint	i,xfrprot;
    time_t	start,end,t;
232
	struct	tm tm;
233 234 235

	if(useron.rest&FLAG('D')) {     /* Download restriction */
		bputs(text[R_Download]);
236 237
		return(FALSE); 
	}
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

	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;
	}

263
	uint64_t totalcdt = 0;
264 265 266 267 268 269 270
	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);
		}
	}
271
	if(totalcdt > useron.cdt+useron.freecdt) {
272
		bprintf(text[YouOnlyHaveNCredits]
273
			,u64toac(useron.cdt+useron.freecdt,tmp));
274 275
		iniFreeStringList(ini);
		iniFreeStringList(filenames);
276
		return(FALSE); 
277
	}
278

279 280 281 282 283 284 285 286 287 288 289
	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);
290
	}
291 292 293 294
	iniFreeStringList(ini);
	iniFreeStringList(filenames);

	if(!(useron.exempt&FLAG('T')) && !SYSOP && totaltime > (int64_t)timeleft) {
295
		bputs(text[NotEnoughTimeToDl]);
296
		return(FALSE); 
297
	}
298
	xfer_prot_menu(XFER_BATCH_DOWNLOAD);
299 300
	ASYNC;
	mnemonics(text[ProtocolOrQuit]);
301
	SAFEPRINTF(str,"%c",quit_key());
302
	for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
303
		if(cfg.prot[i]->batdlcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
304
			sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
305
			SAFECAT(str,tmp); 
306
		}
307
	ungetkey(useron.prot);
308
	ch=(char)getkeys(str,0);
309
	if(ch==quit_key() || sys_status&SS_ABORT)
310
		return(FALSE);
311 312
	for(i=0;i<cfg.total_prots;i++)
		if(cfg.prot[i]->batdlcmd[0] && cfg.prot[i]->mnemonic==ch
rswindell's avatar
rswindell committed
313
			&& chk_ar(cfg.prot[i]->ar,&useron,&client))
314
			break;
315
	if(i>=cfg.total_prots || !create_batchdn_lst((cfg.prot[i]->misc&PROT_NATIVE) ? true:false)) {
316
		return(FALSE);
317
	}
318
	xfrprot=i;
319
#if 0 // NFB-TODO: Download events
320 321 322 323 324 325
	list=NULL;
	for(i=0;i<batdn_total;i++) {
		curdirnum=batdn_dir[i]; 		/* for ARS */
		unpadfname(batdn_name[i],fname);
		if(cfg.dir[batdn_dir[i]]->seqdev) {
			lncntr=0;
326
			SAFEPRINTF2(path,"%s%s",cfg.temp_dir,fname);
327
			if(!fexistcase(path)) {
328 329
				seqwait(cfg.dir[batdn_dir[i]]->seqdev);
				bprintf(text[RetrievingFile],fname);
330
				SAFEPRINTF2(str,"%s%s"
331
					,cfg.dir[batdn_dir[i]]->path
332
					,fname);
333
				mv(str,path,1); /* copy the file to temp dir */
334 335 336 337
				if(getnodedat(cfg.node_num,&thisnode,true)==0) {
					thisnode.aux=40; /* clear the seq dev # */
					putnodedat(cfg.node_num,&thisnode);
				}
338
				CRLF; 
339
			} 
340
		}
341
		else
342
			SAFEPRINTF2(path,"%s%s"
343 344 345 346 347 348 349 350
				,batdn_alt[i]>0 && batdn_alt[i]<=cfg.altpaths
				? cfg.altpath[batdn_alt[i]-1]
				: cfg.dir[batdn_dir[i]]->path
				,fname);
		if(list==NULL)
			list_len=0;
		else
			list_len=strlen(list)+1;	/* add one for ' ' */
351 352 353
		char* np;
		if((np=(char*)realloc(list,list_len+strlen(path)+1	/* add one for '\0'*/))==NULL) {
			free(list);
354
			errormsg(WHERE,ERR_ALLOC,"list",list_len+strlen(path));
355
			return(FALSE);
356
		}
357
		list = np;
358 359 360 361 362 363 364 365 366
		if(!list_len)
			strcpy(list,path);
		else {
			strcat(list," ");
			strcat(list,path);
		}
		for(j=0;j<cfg.total_dlevents;j++) {
			if(stricmp(cfg.dlevent[j]->ext,batdn_name[i]+9))
				continue;
rswindell's avatar
rswindell committed
367
			if(!chk_ar(cfg.dlevent[j]->ar,&useron,&client))
368 369 370
				continue;
			bputs(cfg.dlevent[j]->workstr);
			external(cmdstr(cfg.dlevent[j]->cmd,path,nulstr,NULL),EX_OUTL);
371
			clearline(); 
372
		}
373
	}
374
#endif
375

376
	SAFEPRINTF(str,"%sBATCHDN.LST",cfg.node_dir);
377 378 379 380
	action=NODE_DLNG;
	t=now;
	if(cur_cps) 
		t+=(totalsize/(ulong)cur_cps);
381
	localtime_r(&t,&tm);
382 383 384 385 386
	if(getnodedat(cfg.node_num,&thisnode,true)==0) {
		thisnode.aux=(tm.tm_hour*60)+tm.tm_min;
		thisnode.action=action;
		putnodedat(cfg.node_num,&thisnode); /* calculate ETA */
	}
387
	start=time(NULL);
388
	error=protocol(cfg.prot[xfrprot],XFER_BATCH_DOWNLOAD,str,list,false);
389 390 391
	end=time(NULL);
	if(cfg.prot[xfrprot]->misc&PROT_DSZLOG || !error)
		batch_download(xfrprot);
392 393 394
	if(batdn_total())
		notdownloaded((ulong)totalsize,start,end);
	autohangup();
395

396
	return TRUE;
397
}
398 399 400 401 402

/****************************************************************************/
/* Creates the file BATCHDN.LST in the node directory. Returns true if      */
/* everything goes okay, false if not.                                      */
/****************************************************************************/
403
bool sbbs_t::create_batchdn_lst(bool native)
404
{
405
	char	path[MAX_PATH+1];
406

407 408 409 410 411
	SAFEPRINTF(path, "%sBATCHDN.LST", cfg.node_dir);
	FILE* fp = fopen(path, "wb");
	if(fp == NULL) {
		errormsg(WHERE, ERR_OPEN, path);
		return false;
412
	}
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	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);
440
	}
441 442 443 444
	fclose(fp);
	iniFreeStringList(ini);
	iniFreeStringList(filenames);
	return true;
445 446 447 448 449 450 451 452 453
}

/****************************************************************************/
/* Creates the file BATCHUP.LST in the node directory. Returns true if      */
/* everything goes okay, false if not.                                      */
/* This list is not used by any protocols to date.                          */
/****************************************************************************/
bool sbbs_t::create_batchup_lst()
{
454
    char	path[MAX_PATH + 1];
455

456 457 458 459 460
	SAFEPRINTF(path,"%sBATCHUP.LST",cfg.node_dir);
	FILE* fp = fopen(path, "wb");
	if(fp == NULL) {
		errormsg(WHERE, ERR_OPEN, path);
		return false;
461
	}
462 463 464 465 466 467 468 469
	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);
470
		smb_freefilemem(&f);
471
	}
472 473 474 475
	fclose(fp);
	iniFreeStringList(ini);
	iniFreeStringList(filenames);
	return true;
476 477 478 479 480 481 482
}

/****************************************************************************/
/* Processes files that were supposed to be received in the batch queue     */
/****************************************************************************/
void sbbs_t::batch_upload()
{
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
	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;
500
		}
501 502 503 504 505 506 507 508 509

		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);
510
		smb_freefilemem(&f);
511
	}
512 513 514 515
	iniFreeStringList(filenames);
	iniFreeStringList(ini);

	if(cfg.upload_dir == INVALID_DIR) // no blind upload dir specified
516
		return;
517 518 519

	DIR* dir = opendir(cfg.temp_dir);
	DIRENT* dirent;
520
	while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
521 522
		SAFEPRINTF2(src, "%s%s", cfg.temp_dir,dirent->d_name);
		if(isdir(src))
rswindell's avatar
rswindell committed
523
			continue;
524 525 526 527
		if(!checkfname(dirent->d_name)) {
			bprintf(text[BadFilename], dirent->d_name);
			continue;
		}
528 529
		SAFEPRINTF2(dest, "%s%s", cfg.dir[cfg.upload_dir]->path, dirent->d_name);
		if(fexistcase(dest)) {
rswindell's avatar
rswindell committed
530 531 532
			bprintf(text[FileAlreadyOnline], dirent->d_name);
			continue;
		}
533
		if(mv(src, dest, /* copy: */false))
534
			continue;
535

536
		uint x,y;
537
		for(x=0;x<usrlibs;x++) {
538
			progress(text[SearchingForDupes], x, usrlibs);
539 540
			for(y=0;y<usrdirs[x];y++)
				if(cfg.dir[usrdir[x][y]]->misc&DIR_DUPES
541
					&& findfile(&cfg,usrdir[x][y], dirent->d_name, NULL))
542 543 544
					break;
			if(y<usrdirs[x])
				break; 
545
		}
546
		bputs(text[SearchedForDupes]);
rswindell's avatar
rswindell committed
547
		if(x<usrlibs) {
548
			bprintf(text[FileAlreadyOnline], dirent->d_name);
549
		} else {
550 551 552 553 554
			file_t f = {{}};
			f.dir = cfg.upload_dir;
			smb_hfield_str(&f, SMB_FILENAME, dirent->d_name);
			uploadfile(&f);
			smb_freefilemem(&f);
555 556
		}
	}
557 558
	if(dir!=NULL)
		closedir(dir);
559 560 561 562 563 564 565 566
}

/****************************************************************************/
/* Processes files that were supposed to be sent from the batch queue       */
/* xfrprot is -1 if downloading files from within QWK (no DSZLOG)           */
/****************************************************************************/
void sbbs_t::batch_download(int xfrprot)
{
567 568 569 570 571
	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);
572

573 574
	for(size_t i = 0; filenames[i] != NULL; ++i) {
		char* filename = filenames[i];
575
		lncntr=0;                               /* defeat pause */
576 577 578 579 580 581 582
		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);
583 584
			if(cfg.dir[f.dir]->misc&DIR_TFREE && cur_cps)
				starttime+=f.size/(ulong)cur_cps;
585 586
			downloadedfile(&f);
			smb_freefilemem(&f);
587 588
		}
	}
589 590 591 592
	iniWriteFile(fp, ini);
	iniCloseFile(fp);
	iniFreeStringList(ini);
	iniFreeStringList(filenames);
593 594 595 596 597 598 599
}

/****************************************************************************/
/* Adds a list of files to the batch download queue 						*/
/****************************************************************************/
void sbbs_t::batch_add_list(char *list)
{
600 601
    char	str[1024];
	char	path[MAX_PATH + 1];
602 603 604 605 606 607 608 609 610 611 612
	int		file;
	uint	i,j,k;
    FILE *	stream;
	file_t	f;

	if((stream=fnopen(&file,list,O_RDONLY))!=NULL) {
		bputs(text[SearchingAllLibs]);
		while(!feof(stream)) {
			checkline();
			if(!online)
				break;
613
			if(!fgets(str, sizeof(str) - 1,stream))
614
				break;
615
			truncnl(str);
616
			lncntr=0;
617
			for(i=j=k=0;i<usrlibs;i++) {
618 619 620 621
				for(j=0;j<usrdirs[i];j++,k++) {
					outchar('.');
					if(k && !(k%5))
						bputs("\b\b\b\b\b     \b\b\b\b\b");
622 623 624 625 626 627 628 629
					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;
					}
630
				}
631
				if(j<usrdirs[i])
632 633 634
					break; 
			}
		}
635 636
		fclose(stream);
		remove(list);
637
		CRLF;
638 639
	}
}
640 641 642 643 644 645

/**************************************************************************/
/* Add file 'f' to batch download queue. Return 1 if successful, 0 if not */
/**************************************************************************/
bool sbbs_t::addtobatdl(file_t* f)
{
646 647 648
    char	str[256],tmp2[256];
	char 	tmp[512];
    uint	i;
649 650
	uint64_t	totalcost, totalsize;
	uint64_t	totaltime;
651 652 653

	if(useron.rest&FLAG('D')) {
		bputs(text[R_Download]);
654
		return false;
655
	}
rswindell's avatar
rswindell committed
656
	if(!chk_ar(cfg.dir[f->dir]->dl_ar,&useron,&client)) {
657 658
		bprintf(text[CantAddToQueue],f->name);
		bputs(text[CantDownloadFromDir]);
659
		return false;
660
	}
661 662 663 664
	if(getfilesize(&cfg, f) < 1) {
		bprintf(text[CantAddToQueue], f->name);
		bprintf(text[FileIsNotOnline], f->name);
		return false;
665
	}
666 667 668 669 670 671

	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;
672
	}
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699

	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);
700
			bprintf(text[YouOnlyHaveNCredits],u64toac(useron.cdt+useron.freecdt,tmp));
701 702 703 704 705 706 707 708 709 710
		} 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]
711 712 713 714
						,f->name, strListCount(filenames) + 1, cfg.max_batdn
						,byte_estimate_to_str(totalcost, tmp, sizeof(tmp), 1, 1)
						,byte_estimate_to_str(totalsize, tmp2, sizeof(tmp2), 1, 1)
						,sectostr((uint)(totalsize/MAX((uint64_t)cur_cps, 1)),str));
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
					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);
743
}