upload.cpp 18.6 KB
Newer Older
1 2 3 4 5 6
/* Synchronet file upload-related routines */

/****************************************************************************
 * @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 "sauce.h"
24
#include "filedat.h"
25 26 27

/****************************************************************************/
/****************************************************************************/
28
bool sbbs_t::uploadfile(file_t* f)
29
{
30
	char	path[MAX_PATH+1];
31 32
	char	str[MAX_PATH+1] = "";
	char	ext[LEN_EXTDESC + 1] = "";
33 34 35 36
	char	tmp[MAX_PATH+1];
    uint	i;
    long	length;
	FILE*	stream;
37 38

	curdirnum=f->dir;
39 40 41
	if(findfile(&cfg, f->dir, f->name, NULL)) {
		errormsg(WHERE, ERR_CHK, f->name, f->dir);
		return false;
42
	}
43 44
	getfilepath(&cfg, f, path);
	SAFEPRINTF2(tmp, "%s%s", cfg.temp_dir, getfname(path));
45
	if(!fexistcase(path) && fexistcase(tmp))
46
		mv(tmp,path,0);
47
	if(!fexistcase(path)) {
48
		bprintf(text[FileNotReceived],f->name);
49
		safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (Not received)"
50
			,f->name
51
			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
52
		logline(LOG_NOTICE,"U!",str);
53
		return false;
54
	}
55 56
	f->hdr.when_written.time = (uint32_t)fdate(path);
	char* fext = getfext(f->name);
57
	for(i=0;i<cfg.total_ftests;i++)
58
		if(cfg.ftest[i]->ext[0]=='*' || (fext != NULL && stricmp(fext, cfg.ftest[i]->ext) == 0)) {
rswindell's avatar
rswindell committed
59
			if(!chk_ar(cfg.ftest[i]->ar,&useron,&client))
60 61 62 63
				continue;
			attr(LIGHTGRAY);
			bputs(cfg.ftest[i]->workstr);

64
			safe_snprintf(sbbsfilename,sizeof(sbbsfilename),"SBBSFILENAME=%s",f->name);
65
			putenv(sbbsfilename);
66
			safe_snprintf(sbbsfiledesc,sizeof(sbbsfiledesc),"SBBSFILEDESC=%s",f->desc);
67
			putenv(sbbsfiledesc);
68
			SAFEPRINTF(str,"%ssbbsfile.nam",cfg.node_dir);
69
			if((stream=fopen(str,"w"))!=NULL) {
70
				fprintf(stream, "%s", f->desc);
71 72
				fclose(stream); 
			}
73
			SAFEPRINTF(str,"%ssbbsfile.des",cfg.node_dir);
74 75
			if((stream=fopen(str,"w"))!=NULL) {
				fwrite(f->desc,1,strlen(f->desc),stream);
76 77
				fclose(stream); 
			}
78
			if(external(cmdstr(cfg.ftest[i]->cmd,path,f->desc,NULL),EX_OFFLINE)) {
79
				safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (%s Errors)"
80
					,f->name
81
					,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname,cfg.ftest[i]->ext);
82
				logline(LOG_NOTICE,"U!",str);
83 84 85 86 87 88 89
#if 0
				sprintf(str,"Failed test: %s", cmdstr(cfg.ftest[i]->cmd,path,f->desc,NULL));
				logline("  ",str);
#endif
				bprintf(text[FileHadErrors],f->name,cfg.ftest[i]->ext);
				if(!SYSOP || yesno(text[DeleteFileQ]))
					remove(path);
90 91
				return(0); 
			} else {
92
#if 0 // NFB-TODO - uploader tester changes filename or description
93
				sprintf(str,"%ssbbsfile.nam",cfg.node_dir);
94 95 96 97 98 99
				if((stream=fopen(str,"r"))!=NULL) {
					if(fgets(str,128,stream)) {
						truncsp(str);
						padfname(str,f->name);
						strcpy(tmp,f->name);
						truncsp(tmp);
100
						sprintf(path,"%s%s", cfg.dir[f->dir]->path
101 102
							,unpadfname(f->name,fname)); 
					}
103 104
					fclose(stream);
					}
105
				sprintf(str,"%ssbbsfile.des",cfg.node_dir);
106 107 108
				if((stream=fopen(str,"r"))!=NULL) {
					if(fgets(str,128,stream)) {
						truncsp(str);
109 110 111 112
						sprintf(f->desc,"%.*s",LEN_FDESC,str); 
					}
					fclose(stream); 
				}
113 114 115
				CRLF;
#endif
			}
116
		}
117

118
	if((length=(long)flength(path))==0L) {
119 120
		bprintf(text[FileZeroLength],f->name);
		remove(path);
121
		safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (Zero length)"
122
			,f->name
123
			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
124
		logline(LOG_NOTICE,"U!",str);
125
		return false; 
126
	}
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

	bputs(text[SearchingForDupes]);
	/* Note: Hashes file *after* running upload-testers (which could modify file) */
	if(hashfile(&cfg, f)) {
		bputs(text[SearchedForDupes]);
		for(uint i=0, k=0; i < usrlibs; i++) {
			progress(text[Scanning], i, usrlibs, 1);
			for(uint j=0; j < usrdirs[i]; j++,k++) {
				if(cfg.dir[usrdir[i][j]]->misc&DIR_DUPES
					&& findfile(&cfg, usrdir[i][j], /* filename: */NULL, f)) {
					bprintf(text[FileAlreadyOnline], f->name);
					if(!dir_op(f->dir)) {
						remove(path);
						safe_snprintf(str, sizeof(str), "attempted to upload %s to %s %s (duplicate hash)"
							,f->name
							,cfg.lib[cfg.dir[f->dir]->lib]->sname, cfg.dir[f->dir]->sname);
						logline(LOG_NOTICE, "U!", str);
						return(false); 	 /* File is in database for another dir */
					}
				}
147
			}
148 149 150 151 152 153 154 155
		}
		progress(text[Done], usrlibs, usrlibs);
	} else
		bputs(text[SearchedForDupes]);

	if(cfg.dir[f->dir]->misc&DIR_DIZ) {
		lprintf(LOG_DEBUG, "Extracting DIZ from: %s", path);
		if(extract_diz(&cfg, f, /* diz_fnames: */NULL, str, sizeof(str))) {
156
			struct sauce_charinfo sauce;
157 158
			lprintf(LOG_DEBUG, "Parsing DIZ: %s", str);

159
			char* lines = read_diz(str, &sauce);
160
			if(lines != NULL)
161 162 163
				format_diz(lines, ext, sizeof(ext), sauce.width, sauce.ice_color);
			free(lines);
			file_sauce_hfields(f, &sauce);
164 165

			if(f->desc == NULL || f->desc[0] == 0) {
166
				char	desc[LEN_FDESC + 1];
167 168 169 170 171
				SAFECOPY(desc, (char*)ext);
				strip_exascii(desc, desc);
				prep_file_desc(desc, desc);
				for(i=0;desc[i];i++)
					if(IS_ALPHANUMERIC(desc[i]))
172
						break;
173 174
				if(desc[i] == '\0')
					i = 0;
175
				smb_new_hfield_str(f, SMB_FILEDESC, desc + i);
176 177 178 179
			}
			remove(str);
		} else
			lprintf(LOG_DEBUG, "DIZ does not exist in: %s", path);
180
	}
181

182 183 184 185
	if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
		logon_ulb+=length;  /* Update 'this call' stats */
		logon_uls++;
	}
186
	if(cfg.dir[f->dir]->misc&DIR_AONLY)  /* Forced anonymous */
187 188 189 190
		f->hdr.attr |= MSG_ANONYMOUS;
	uint32_t cdt = (uint32_t)length;
	smb_hfield_bin(f, SMB_COST, cdt);
	smb_hfield_str(f, SENDER, useron.alias);
191
	bprintf(text[FileNBytesReceived],f->name,ultoac(length,tmp));
192
	if(!addfile(&cfg, f->dir, f, ext, &client))
193
		return false;
194

195
	safe_snprintf(str,sizeof(str),"uploaded %s to %s %s"
196
		,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname
197 198
		,cfg.dir[f->dir]->sname);
	if(cfg.dir[f->dir]->upload_sem[0])
199
		ftouch(cmdstr(cfg.dir[f->dir]->upload_sem,nulstr,nulstr,NULL));
200 201 202 203
	logline("U+",str);
	/**************************/
	/* Update Uploader's Info */
	/**************************/
204
	user_uploaded(&cfg, &useron, 1, length);
205 206 207 208 209 210
	if(cfg.dir[f->dir]->up_pct && cfg.dir[f->dir]->misc&DIR_CDTUL) { /* credit for upload */
		if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps)    /* Give min instead of cdt */
			useron.min=adjustuserrec(&cfg,useron.number,U_MIN,10
				,((ulong)(length*(cfg.dir[f->dir]->up_pct/100.0))/cur_cps)/60);
		else
			useron.cdt=adjustuserrec(&cfg,useron.number,U_CDT,10
211
				,(ulong)(f->cost * (cfg.dir[f->dir]->up_pct/100.0))); 
212 213 214
	}

	user_event(EVENT_UPLOAD);
215

216
	return true;
217 218 219 220 221
}

/****************************************************************************/
/* Uploads files                                                            */
/****************************************************************************/
222
bool sbbs_t::upload(uint dirnum)
223
{
224
	char	descbeg[25]={""},descend[25]={""}
225
				,fname[MAX_FILENAME_LEN + 1],keys[256],ch,*p;
226 227
	char	str[MAX_PATH+1];
	char	path[MAX_PATH+1];
228
	char 	tmp[512];
229
    time_t	start,end;
230
    uint	i,j,k;
231
	ulong	space;
232
	file_t	f = {{}};
233
	str_list_t dest_user_list = NULL;
234

235 236 237 238 239 240 241 242 243
	/* Security Checks */
	if(useron.rest&FLAG('U')) {
		bputs(text[R_Upload]);
		return(false); 
	}
	if(dirnum==INVALID_DIR) {
		bputs(text[CantUploadHere]);
		return(false);
	}
244 245 246 247 248 249 250 251 252 253
	if(!(useron.exempt&FLAG('U')) && !dir_op(dirnum)) {
		if(!chk_ar(cfg.dir[dirnum]->ul_ar,&useron,&client)) {
			bputs(dirnum==cfg.user_dir ? text[CantUploadToUser] : 
				dirnum==cfg.sysop_dir ? text[CantUploadToSysop] : text[CantUploadHere]);
			return(false); 
		}
		if(cfg.dir[dirnum]->maxfiles && getfiles(&cfg,dirnum)>=cfg.dir[dirnum]->maxfiles) {
			bputs(dirnum==cfg.user_dir ? text[UserDirFull] : text[DirFull]);
			return(false);
		}
254 255
	}

256 257
	if(sys_status&SS_EVENT && online==ON_REMOTE && !dir_op(dirnum))
		bprintf(text[UploadBeforeEvent],timeleft/60);
258 259

	SAFECOPY(path,cfg.dir[dirnum]->path);
260

261 262
	if(!isdir(path)) {
		bprintf(text[DirectoryDoesNotExist], path);
263
		lprintf(LOG_ERR,"File directory does not exist: %s", path);
264 265
		return(false);
	}
266 267

	/* get free disk space */
268 269
	space=getfreediskspace(path,1024);
	if(space<(ulong)cfg.min_dspace) {
270
		bputs(text[LowDiskSpace]);
271
		lprintf(LOG_ERR,"Diskspace is low: %s (%lu kilobytes)",path,space);
272
		if(!dir_op(dirnum))
273 274
			return(false); 
	}
275 276 277 278
	bprintf(text[DiskNBytesFree],ultoac(space,tmp));

	f.dir=curdirnum=dirnum;
	bputs(text[Filename]);
279
	if(getstr(fname, sizeof(fname) - 1, 0) < 1 || strchr(fname,'?') || strchr(fname,'*')
280
		|| !checkfname(fname) || (trashcan(fname,"file") && !dir_op(dirnum))) {
281 282
		if(fname[0])
			bputs(text[BadFilename]);
283 284
		return(false); 
	}
285
	if(dirnum==cfg.sysop_dir)
286
		SAFEPRINTF(str,text[UploadToSysopDirQ],fname);
287
	else if(dirnum==cfg.user_dir)
288
		SAFEPRINTF(str,text[UploadToUserDirQ],fname);
289
	else
290
		SAFEPRINTF3(str,text[UploadToCurDirQ],fname,cfg.lib[cfg.dir[dirnum]->lib]->sname
291
			,cfg.dir[dirnum]->sname);
292
	if(!yesno(str)) return(false);
293
	action=NODE_ULNG;
294 295 296
	SAFECOPY(f.file_idx.name, fname);
	getfilepath(&cfg, &f, path);
	if(fexistcase(path)) {   /* File is on disk */
297 298
		if(!dir_op(dirnum) && online!=ON_LOCAL) {		 /* local users or sysops */
			bprintf(text[FileAlreadyThere],fname);
299 300
			return(false); 
		}
301
		if(!yesno(text[FileOnDiskAddQ]))
302 303
			return(false); 
	}
304 305
	char* ext = getfext(fname);
	SAFECOPY(str,cfg.dir[dirnum]->exts);
306 307 308 309 310
	j=strlen(str);
	for(i=0;i<j;i+=ch+1) { /* Check extension of upload with allowable exts */
		p=strchr(str+i,',');
		if(p!=NULL)
			*p=0;
311
		ch=(char)strlen(str+i);
312 313
		if(ext != NULL && stricmp(ext + 1, str + i) == 0)
			break;
314
	}
315 316 317 318
	if(j && i>=j) {
		bputs(text[TheseFileExtsOnly]);
		bputs(cfg.dir[dirnum]->exts);
		CRLF;
319 320
		if(!dir_op(dirnum)) return(false); 
	}
321
	bputs(text[SearchingForDupes]);
322 323 324
	bool found = findfile(&cfg, dirnum, fname, NULL);
	bputs(text[SearchedForDupes]);
	if(found) {
325 326 327
		bprintf(text[FileAlreadyOnline],fname);
		return(false); 	 /* File is already in database */
	}
328
	for(i=k=0;i<usrlibs;i++) {
329
		progress(text[SearchingForDupes], i, usrlibs, 1);
330
		for(j=0;j<usrdirs[i];j++,k++) {
331 332 333
			if(usrdir[i][j]==dirnum)
				continue;	/* we already checked this dir */
			if(cfg.dir[usrdir[i][j]]->misc&DIR_DUPES
334
				&& findfile(&cfg, usrdir[i][j], fname, NULL)) {
335
				bputs(text[SearchedForDupes]);
336
				bprintf(text[FileAlreadyOnline],fname);
337
				if(!dir_op(dirnum))
338
					return(false); 	 /* File is in database for another dir */
339 340 341
			}
		}
	}
342 343 344 345 346
	bputs(text[SearchedForDupes]);
	if(cfg.dir[dirnum]->misc&DIR_RATE) {
		SYNC;
		bputs(text[RateThisFile]);
		ch=getkey(K_ALPHA);
347
		if(!IS_ALPHA(ch) || sys_status&SS_ABORT)
348
			return(false);
349
		CRLF;
350
		SAFEPRINTF(descbeg,text[Rated],toupper(ch)); 
351
	}
352 353 354 355
	if(cfg.dir[dirnum]->misc&DIR_ULDATE) {
		now=time(NULL);
		if(descbeg[0])
			strcat(descbeg," ");
356
		SAFEPRINTF(str,"%s  ",unixtodstr(&cfg,(time32_t)now,tmp));
357 358
		strcat(descbeg,str); 
	}
359 360 361 362
	if(cfg.dir[dirnum]->misc&DIR_MULT) {
		SYNC;
		if(!noyes(text[MultipleDiskQ])) {
			bputs(text[HowManyDisksTotal]);
363
			if((int)(i=getnum(99))<2)
364
				return(false);
365
			bputs(text[NumberOfFile]);
366
			if((int)(j=getnum(i))<1)
367
				return(false);
368 369 370
			if(j==1)
				upload_lastdesc[0]=0;
			if(i>9)
371
				SAFEPRINTF2(descend,text[FileOneOfTen],j,i);
372
			else
373
				SAFEPRINTF2(descend,text[FileOneOfTwo],j,i); 
374 375 376
		} else
			upload_lastdesc[0]=0; 
	}
377 378
	else
		upload_lastdesc[0]=0;
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
	if(dirnum == cfg.user_dir) {  /* User to User transfer */
		bputs(text[EnterAfterLastDestUser]);
		while(dir_op(dirnum) || strListCount(dest_user_list) < cfg.max_userxfer) {
			bputs(text[SendFileToUser]);
			if(!getstr(str,LEN_ALIAS,cfg.uq&UQ_NOUPRLWR ? K_NONE:K_UPRLWR))
				break;
			user_t user;
			if((user.number=finduser(str))!=0) {
				if(!dir_op(dirnum) && user.number==useron.number) {
					bputs(text[CantSendYourselfFiles]);
					continue; 
				}
				char usernum[16];
				SAFEPRINTF(usernum, "%u", user.number);
				if(strListFind(dest_user_list, usernum, /* case-sensitive: */true) >= 0) {
					bputs(text[DuplicateUser]);
					continue; 
				}
				getuserdat(&cfg,&user);
				if((user.rest&(FLAG('T')|FLAG('D')))
					|| !chk_ar(cfg.lib[cfg.dir[cfg.user_dir]->lib]->ar,&user,/* client: */NULL)
					|| !chk_ar(cfg.dir[cfg.user_dir]->dl_ar,&user,/* client: */NULL)) {
					bprintf(text[UserWontBeAbleToDl],user.alias); 
				} else {
					bprintf(text[UserAddedToDestList],user.alias,usernum);
					strListPush(&dest_user_list, usernum);
				} 
			}
			else {
				CRLF;
			}
		}
		if(strListCount(dest_user_list) < 1)
			return false;
	}
414 415

	char fdesc[LEN_FDESC + 1] = "";
416 417
	bputs(text[EnterDescNow]);
	i=LEN_FDESC-(strlen(descbeg)+strlen(descend));
418
	getstr(upload_lastdesc,i,K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
419 420
	if(sys_status&SS_ABORT) {
		strListFree(&dest_user_list);
421
		return(false);
422
	}
423
	if(descend[0])      /* end of desc specified, so pad desc with spaces */
424
		safe_snprintf(fdesc,sizeof(fdesc),"%s%-*s%s",descbeg,i,upload_lastdesc,descend);
425
	else                /* no end specified, so string ends at desc end */
426 427 428 429 430 431 432
		safe_snprintf(fdesc,sizeof(fdesc),"%s%s",descbeg,upload_lastdesc);

	char tags[64] = "";
	if((cfg.dir[dirnum]->misc&DIR_FILETAGS) && (text[TagFileQ][0] == 0 || !noyes(text[TagFileQ]))) {
		bputs(text[TagFilePrompt]);
		getstr(tags, sizeof(tags)-1, K_EDIT|K_LINE|K_TRIM);
	}
433 434 435 436

	if(cfg.dir[dirnum]->misc&DIR_ANON && !(cfg.dir[dirnum]->misc&DIR_AONLY)
		&& (dir_op(dirnum) || useron.exempt&FLAG('A'))) {
		if(!noyes(text[AnonymousQ]))
437
			f.hdr.attr |= MSG_ANONYMOUS;
438
	}
439 440 441 442

	bool result = false;
	smb_hfield_str(&f, SMB_FILENAME, fname);
	smb_hfield_str(&f, SMB_FILEDESC, fdesc);
443 444
	if(strListCount(dest_user_list) > 0)
		smb_hfield_str(&f, RECIPIENTLIST, strListCombine(dest_user_list, tmp, sizeof(tmp), ","));
445 446 447 448
	if(tags[0])
		smb_hfield_str(&f, SMB_TAGS, tags);
	if(fexistcase(path)) {   /* File is on disk */
		result = uploadfile(&f);
449
	} else {
450
		xfer_prot_menu(XFER_UPLOAD);
451
		SYNC;
452
		SAFEPRINTF(keys,"%c",text[YNQP][2]);
453 454 455 456
		if(dirnum==cfg.user_dir || !cfg.max_batup)  /* no batch user to user xfers */
			mnemonics(text[ProtocolOrQuit]);
		else {
			mnemonics(text[ProtocolBatchOrQuit]);
457 458
			strcat(keys,"B"); 
		}
459
		for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
460
			if(cfg.prot[i]->ulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
461
				SAFEPRINTF(tmp,"%c",cfg.prot[i]->mnemonic);
462 463
				strcat(keys,tmp); 
			}
464
		ch=(char)getkeys(keys,0);
465
		if(ch==text[YNQP][2] || (sys_status&SS_ABORT))
466 467 468
			result = false;
		else if(ch=='B') {
			if(batup_total() >= cfg.max_batup)
469
				bputs(text[BatchUlQueueIsFull]);
470 471 472
			else if(batch_file_exists(&cfg, useron.number, XFER_BATCH_UPLOAD, f.name))
				bprintf(text[FileAlreadyInQueue],fname);
			else if(batch_file_add(&cfg, useron.number, XFER_BATCH_UPLOAD, &f)) {
473
				bprintf(text[FileAddedToUlQueue]
474 475 476
					,fname, batup_total(), cfg.max_batup);
				result = true;
			}
477
		} else {
478 479
			for(i=0;i<cfg.total_prots;i++)
				if(cfg.prot[i]->ulcmd[0] && cfg.prot[i]->mnemonic==ch
rswindell's avatar
rswindell committed
480
					&& chk_ar(cfg.prot[i]->ar,&useron,&client))
481 482 483
					break;
			if(i<cfg.total_prots) {
				start=time(NULL);
484
				protocol(cfg.prot[i],XFER_UPLOAD,path,nulstr,true);
485 486 487
				end=time(NULL);
				if(!(cfg.dir[dirnum]->misc&DIR_ULTIME)) /* Don't deduct upload time */
					starttime+=end-start;
488
				result = uploadfile(&f);
489
				autohangup();
490 491 492
			} 
		} 
	}
493
	smb_freefilemem(&f);
494
	strListFree(&dest_user_list);
495
	return result;
496 497 498 499 500 501 502 503 504
}

/****************************************************************************/
/* Checks directory for 'dir' and prompts user to enter description for     */
/* the files that aren't in the database.                                   */
/* Returns 1 if the user aborted, 0 if not.                                 */
/****************************************************************************/
bool sbbs_t::bulkupload(uint dirnum)
{
505 506
    char	str[MAX_PATH+1];
	char	path[MAX_PATH+1];
507 508 509
	char	desc[LEN_FDESC + 1];
	smb_t	smb;
    file_t f;
510 511
	DIR*	dir;
	DIRENT*	dirent;
512

513
	memset(&f,0,sizeof(f));
514 515
	f.dir=dirnum;
	bprintf(text[BulkUpload],cfg.lib[cfg.dir[dirnum]->lib]->sname,cfg.dir[dirnum]->sname);
516 517 518 519 520 521 522
	SAFECOPY(path, cfg.dir[dirnum]->path);

	int result = smb_open_dir(&cfg, &smb, dirnum);
	if(result != SMB_SUCCESS) {
		errormsg(WHERE, ERR_OPEN, smb.file, result, smb.last_error);
		return false;
	}
523 524
	action=NODE_ULNG;
	SYNC;
525 526
	str_list_t list = loadfilenames(&smb, ALLFILES, /* time_t */0, FILE_SORT_NATURAL, NULL);
	smb_close(&smb);
527
	dir=opendir(path);
528
	while(dir!=NULL && (dirent=readdir(dir))!=NULL && !msgabort()) {
529
		char fname[SMB_FILEIDX_NAMELEN + 1];
530
		SAFEPRINTF2(str,"%s%s",path,dirent->d_name);
531 532
		if(isdir(str))
			continue;
533 534 535 536 537
#ifdef _WIN32
		/* Skip hidden/system files on Win32 */
		if(getfattr(str)&(_A_HIDDEN|_A_SYSTEM))
			continue;
#endif
538 539 540 541 542 543
		smb_fileidxname(dirent->d_name, fname, sizeof(fname));
		if(strListFind(list, fname, /* case-sensitive: */FALSE) < 0) {
			smb_freemsgmem(&f);
			smb_hfield_str(&f, SMB_FILENAME, dirent->d_name);
			uint32_t cdt = (uint32_t)flength(str);
			bprintf(text[BulkUploadDescPrompt], format_filename(f.name, fname, 12, /* pad: */FALSE), cdt/1024);
544 545 546 547 548
			if(strcmp(f.name, fname) != 0)
				SAFECOPY(desc, f.name);
			else
				desc[0] = 0;
			getstr(desc, LEN_FDESC, K_LINE|K_EDIT|K_AUTODEL);
549 550
			if(sys_status&SS_ABORT)
				break;
551
			if(strcmp(desc,"-")==0)	/* don't add this file */
552
				continue;
553 554
			smb_hfield_str(&f, SMB_FILEDESC, desc);
			uploadfile(&f);
555 556
		}
	}
557 558
	if(dir!=NULL)
		closedir(dir);
559 560
	strListFree(&list);
	smb_freemsgmem(&f);
561 562
	if(sys_status&SS_ABORT)
		return(true);
563 564 565
	return(false);
}

566
bool sbbs_t::recvfile(char *fname, char prot, bool autohang)
567 568 569 570 571 572
{
	char	keys[32];
	char	ch;
	size_t	i;
	bool	result=false;

573 574 575 576 577
	if(prot)
		ch=toupper(prot);
	else {
		xfer_prot_menu(XFER_UPLOAD);
		mnemonics(text[ProtocolOrQuit]);
578
		SAFEPRINTF(keys,"%c",text[YNQP][2]);
579
		for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
580
			if(cfg.prot[i]->ulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client))
581
				sprintf(keys+strlen(keys),"%c",cfg.prot[i]->mnemonic);
582

583
		ch=(char)getkeys(keys,0);
584

585
		if(ch==text[YNQP][2] || sys_status&SS_ABORT)
586 587
			return(false); 
	}
588
	for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
589
		if(cfg.prot[i]->mnemonic==ch && chk_ar(cfg.prot[i]->ar,&useron,&client))
590 591
			break;
	if(i<cfg.total_prots) {
592
		if(protocol(cfg.prot[i], XFER_UPLOAD, fname, fname, true, autohang)==0)
593 594 595 596 597 598
			result=true;
		autohangup(); 
	}

	return(result);
}