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
364
365
				continue;
			bputs(cfg.dlevent[j]->workstr);
			external(cmdstr(cfg.dlevent[j]->cmd,path,nulstr,NULL),EX_OUTL);
			CRLF; 
		}
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
706
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

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