bat_xfer.cpp 21.2 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", text[YNQP][2]);
60
		ch=(char)getkeys(keys,0);
61
		if(ch>' ')
62
			logch(ch,0);
63
64
65
66
67
		if(ch==text[YNQP][2] || ch=='\r') {	/* Quit */
			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
136
								? sectostr((uint)(f.size/(ulong)cur_cps),tmp2)
								: "??:??:??"
							,datestr(f.time)
						);
						totalsize += f.size;
						totalcdt += f.cost;
						smb_freemsgmem(&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
151
				if((n = batup_total()) > 0) {
					bprintf(text[RemoveWhichFromUlQueue], n);
					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
						batch_file_remove(&cfg, useron.number, XFER_BATCH_UPLOAD, str);
152
				}
153
154
155
156
				if((n = batdn_total()) > 0) {
					bprintf(text[RemoveWhichFromDlQueue], n);
					if(getstr(str, MAX_FILENAME_LEN, K_NONE) > 0)
						batch_file_remove(&cfg, useron.number, XFER_BATCH_DOWNLOAD, str);
157
				}
158
159
160
161
				break;
		   case 'U':
				if(useron.rest&FLAG('U')) {
					bputs(text[R_Upload]);
162
163
					break; 
				}
164
				if(batup_total() < 1 && cfg.upload_dir==INVALID_DIR) {
165
					bputs(text[UploadQueueIsEmpty]);
166
167
					break; 
				}
168
				xfer_prot_menu(XFER_BATCH_UPLOAD);
169
170
171
172
				if(!create_batchup_lst())
					break;
				ASYNC;
				mnemonics(text[ProtocolOrQuit]);
173
				SAFEPRINTF(str,"%c",text[YNQP][2]);
174
				for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
175
					if(cfg.prot[i]->batulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
176
						sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
177
						SAFECAT(str,tmp); 
178
					}
179
				ch=(char)getkeys(str,0);
180
				if(ch==text[YNQP][2])
181
182
183
					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
184
						&& chk_ar(cfg.prot[i]->ar,&useron,&client))
185
186
						break;
				if(i<cfg.total_prots) {
187
					SAFEPRINTF(str,"%sBATCHUP.LST",cfg.node_dir);
188
					xfrprot=i;
189
					xfrdir=cfg.upload_dir;
190
191
192
					action=NODE_ULNG;
					SYNC;
					if(online==ON_REMOTE) {
193
						delfiles(cfg.temp_dir,ALLFILES);
194
						start=time(NULL);
195
						protocol(cfg.prot[xfrprot],XFER_BATCH_UPLOAD,str,nulstr,true);
196
197
						end=time(NULL);
						if(!(cfg.dir[xfrdir]->misc&DIR_ULTIME))
198
199
							starttime+=end-start; 
					}
200
					batch_upload();
201
					delfiles(cfg.temp_dir,ALLFILES);
202
203
204
205
206
					autohangup(); 
				}
				break; 
		} 
	}
207
	delfiles(cfg.temp_dir,ALLFILES);
208
209
210
211
212
}

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

	if(useron.rest&FLAG('D')) {     /* Download restriction */
		bputs(text[R_Download]);
227
228
		return(FALSE); 
	}
229
230
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

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

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

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

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

387
	return TRUE;
388
}
389
390
391
392
393

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

398
399
400
401
402
	SAFEPRINTF(path, "%sBATCHDN.LST", cfg.node_dir);
	FILE* fp = fopen(path, "wb");
	if(fp == NULL) {
		errormsg(WHERE, ERR_OPEN, path);
		return false;
403
	}
404
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
	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);
431
	}
432
433
434
435
	fclose(fp);
	iniFreeStringList(ini);
	iniFreeStringList(filenames);
	return true;
436
437
438
439
440
441
442
443
444
}

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

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

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

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

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

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

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

/****************************************************************************/
/* 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)
{
554
555
556
557
558
	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);
559

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

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

/**************************************************************************/
/* Add file 'f' to batch download queue. Return 1 if successful, 0 if not */
/**************************************************************************/
bool sbbs_t::addtobatdl(file_t* f)
{
633
634
635
    char	str[256],tmp2[256];
	char 	tmp[512];
    uint	i;
636
637
	uint64_t	totalcost, totalsize;
	uint64_t	totaltime;
638
639
640

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

	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;
659
	}
660
661
662
663
664
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

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