bat_xfer.cpp 21.6 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 97
				ini = batch_list_read(&cfg, useron.number, XFER_BATCH_UPLOAD);
				filenames = iniGetSectionList(ini, NULL);
				if(strListCount(filenames)) {
98
					bputs(text[UploadQueueLstHdr]);
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
					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)) {
117
					bputs(text[DownloadQueueLstHdr]);
118 119 120 121 122 123 124
					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);
125
						bprintf(text[DownloadQueueLstFmt],i+1
126 127 128
							,filename
							,ultoac(f.cost, tmp)
							,ultoac((ulong)f.size, str)
129
							,cur_cps
130 131 132 133 134 135
								? sectostr((uint)(f.size/(ulong)cur_cps),tmp2)
								: "??:??:??"
							,datestr(f.time)
						);
						totalsize += f.size;
						totalcdt += f.cost;
136
						smb_freefilemem(&f);
137
					}
138
					bprintf(text[DownloadQueueTotals]
139 140
						,ultoac((ulong)totalcdt,tmp),ultoac((ulong)totalsize,str),cur_cps
						? sectostr((ulong)totalsize/(ulong)cur_cps,tmp2)
141
						: "??:??:??"); 
142 143 144 145 146
				} else
					bputs(text[DownloadQueueIsEmpty]);
				iniFreeStringList(filenames);
				iniFreeStringList(ini);
				break;
147
			case 'R':
148 149 150
				if((n = batup_total()) > 0) {
					bprintf(text[RemoveWhichFromUlQueue], n);
					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
151 152
						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);
153
				}
154 155 156
				if((n = batdn_total()) > 0) {
					bprintf(text[RemoveWhichFromDlQueue], n);
					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
157 158
						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);
159
				}
160 161 162 163
				break;
		   case 'U':
				if(useron.rest&FLAG('U')) {
					bputs(text[R_Upload]);
164 165
					break; 
				}
166
				if(batup_total() < 1 && cfg.upload_dir==INVALID_DIR) {
167
					bputs(text[UploadQueueIsEmpty]);
168 169
					break; 
				}
170
				xfer_prot_menu(XFER_BATCH_UPLOAD);
171 172 173 174
				if(!create_batchup_lst())
					break;
				ASYNC;
				mnemonics(text[ProtocolOrQuit]);
175
				SAFEPRINTF(str,"%c",quit_key());
176
				for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
177
					if(cfg.prot[i]->batulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
178
						sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
179
						SAFECAT(str,tmp); 
180
					}
181
				ch=(char)getkeys(str,0);
182
				if(ch==quit_key())
183 184 185
					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
186
						&& chk_ar(cfg.prot[i]->ar,&useron,&client))
187 188
						break;
				if(i<cfg.total_prots) {
189
					SAFEPRINTF(str,"%sBATCHUP.LST",cfg.node_dir);
190
					xfrprot=i;
191
					xfrdir=cfg.upload_dir;
192 193 194
					action=NODE_ULNG;
					SYNC;
					if(online==ON_REMOTE) {
195
						delfiles(cfg.temp_dir,ALLFILES);
196
						start=time(NULL);
197
						protocol(cfg.prot[xfrprot],XFER_BATCH_UPLOAD,str,nulstr,true);
198
						end=time(NULL);
199
						if(xfrdir != INVALID_DIR && !(cfg.dir[xfrdir]->misc&DIR_ULTIME))
200 201
							starttime+=end-start; 
					}
202
					batch_upload();
203
					delfiles(cfg.temp_dir,ALLFILES);
204 205 206 207 208
					autohangup(); 
				}
				break; 
		} 
	}
209
	delfiles(cfg.temp_dir,ALLFILES);
210 211 212 213 214
}

/****************************************************************************/
/* Download files from batch queue                                          */
/****************************************************************************/
215
BOOL sbbs_t::start_batch_download()
216
{
217 218 219 220
	char	ch;
	char	tmp[32];
	char	str[MAX_PATH+1];
	char 	path[MAX_PATH+1];
221
	char	list[1024] = "";
222
	int		error;
223 224
    uint	i,xfrprot;
    time_t	start,end,t;
225
	struct	tm tm;
226 227 228

	if(useron.rest&FLAG('D')) {     /* Download restriction */
		bputs(text[R_Download]);
229 230
		return(FALSE); 
	}
231 232 233 234 235 236 237 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 263 264

	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)) {
265 266
		bprintf(text[YouOnlyHaveNCredits]
			,ultoac(useron.cdt+useron.freecdt,tmp));
267 268
		iniFreeStringList(ini);
		iniFreeStringList(filenames);
269
		return(FALSE); 
270
	}
271

272 273 274 275 276 277 278 279 280 281 282
	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);
283
	}
284 285 286 287
	iniFreeStringList(ini);
	iniFreeStringList(filenames);

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

369
	SAFEPRINTF(str,"%sBATCHDN.LST",cfg.node_dir);
370 371 372 373
	action=NODE_DLNG;
	t=now;
	if(cur_cps) 
		t+=(totalsize/(ulong)cur_cps);
374
	localtime_r(&t,&tm);
375 376 377 378 379
	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 */
	}
380
	start=time(NULL);
381
	error=protocol(cfg.prot[xfrprot],XFER_BATCH_DOWNLOAD,str,list,false);
382 383 384
	end=time(NULL);
	if(cfg.prot[xfrprot]->misc&PROT_DSZLOG || !error)
		batch_download(xfrprot);
385 386 387
	if(batdn_total())
		notdownloaded((ulong)totalsize,start,end);
	autohangup();
388

389
	return TRUE;
390
}
391 392 393 394 395

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

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

/****************************************************************************/
/* 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()
{
447
    char	path[MAX_PATH + 1];
448

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

/****************************************************************************/
/* Processes files that were supposed to be received in the batch queue     */
/****************************************************************************/
void sbbs_t::batch_upload()
{
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
	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;
493
		}
494 495 496 497 498 499 500 501 502

		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);
503
		smb_freefilemem(&f);
504
	}
505 506 507 508
	iniFreeStringList(filenames);
	iniFreeStringList(ini);

	if(cfg.upload_dir == INVALID_DIR) // no blind upload dir specified
509
		return;
510 511 512

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

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

/****************************************************************************/
/* 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)
{
560 561 562 563 564
	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);
565

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

/****************************************************************************/
/* Adds a list of files to the batch download queue 						*/
/****************************************************************************/
void sbbs_t::batch_add_list(char *list)
{
593 594
    char	str[1024];
	char	path[MAX_PATH + 1];
595 596 597 598 599 600 601 602 603 604 605
	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;
606
			if(!fgets(str, sizeof(str) - 1,stream))
607
				break;
608
			truncnl(str);
609
			lncntr=0;
610
			for(i=j=k=0;i<usrlibs;i++) {
611 612 613 614
				for(j=0;j<usrdirs[i];j++,k++) {
					outchar('.');
					if(k && !(k%5))
						bputs("\b\b\b\b\b     \b\b\b\b\b");
615 616 617 618 619 620 621 622
					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;
					}
623
				}
624
				if(j<usrdirs[i])
625 626 627
					break; 
			}
		}
628 629
		fclose(stream);
		remove(list);
630
		CRLF;
631 632
	}
}
633 634 635 636 637 638

/**************************************************************************/
/* Add file 'f' to batch download queue. Return 1 if successful, 0 if not */
/**************************************************************************/
bool sbbs_t::addtobatdl(file_t* f)
{
639 640 641
    char	str[256],tmp2[256];
	char 	tmp[512];
    uint	i;
642 643
	uint64_t	totalcost, totalsize;
	uint64_t	totaltime;
644 645 646

	if(useron.rest&FLAG('D')) {
		bputs(text[R_Download]);
647
		return false;
648
	}
rswindell's avatar
rswindell committed
649
	if(!chk_ar(cfg.dir[f->dir]->dl_ar,&useron,&client)) {
650 651
		bprintf(text[CantAddToQueue],f->name);
		bputs(text[CantDownloadFromDir]);
652
		return false;
653
	}
654 655 656 657
	if(getfilesize(&cfg, f) < 1) {
		bprintf(text[CantAddToQueue], f->name);
		bprintf(text[FileIsNotOnline], f->name);
		return false;
658
	}
659 660 661 662 663 664

	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;
665
	}
666 667 668 669 670 671 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 700 701 702 703 704 705

	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)
706
						,sectostr((ulong)totalsize/MAX((ulong)cur_cps, 1),str));
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
					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);
735
}