upload.cpp 18.1 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
	char	tmp[MAX_PATH+1];
    uint	i;
35
    off_t	length;
36
	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 + 1, 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
			SAFEPRINTF(str,"%ssbbsfile.nam",cfg.node_dir);
65
			if((stream=fopen(str,"w"))!=NULL) {
66
				fprintf(stream, "%s", f->name);
67 68
				fclose(stream); 
			}
69
			SAFEPRINTF(str,"%ssbbsfile.des",cfg.node_dir);
70
			if((stream=fopen(str,"w"))!=NULL) {
71 72
				if(f->desc != NULL)
					fprintf(stream, "%s", f->desc);
73 74
				fclose(stream); 
			}
75 76
			// Note: str (%s) is path/to/sbbsfile.des (used to be the description itself)
			int result = external(cmdstr(cfg.ftest[i]->cmd, path, str, NULL), EX_OFFLINE);
77 78 79
			clearline();
			if(result != 0) {
				safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (%s error code %d)"
80
					,f->name
81 82
					,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname,cfg.ftest[i]->ext
					,result);
83
				logline(LOG_NOTICE,"U!",str);
84 85 86
				bprintf(text[FileHadErrors],f->name,cfg.ftest[i]->ext);
				if(!SYSOP || yesno(text[DeleteFileQ]))
					remove(path);
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
				return false;
			}
			SAFEPRINTF(str,"%ssbbsfile.nam",cfg.node_dir);
			if((stream=fopen(str,"r"))!=NULL) {
				if(fgets(str, sizeof(str), stream)) {
					truncsp(str);
					smb_new_hfield_str(f, SMB_FILENAME, str);
					getfilepath(&cfg, f, path);
				}
				fclose(stream);
			}
			SAFEPRINTF(str,"%ssbbsfile.des",cfg.node_dir);
			if((stream=fopen(str,"r"))!=NULL) {
				if(fgets(str, sizeof(str), stream)) {
					truncsp(str);
102 103
					if(*str)
						smb_new_hfield_str(f, SMB_FILEDESC, str);
104
				}
105
				fclose(stream); 
106
			}
107
		}
108

109
	if((length = flength(path))==0L) {
110 111
		bprintf(text[FileZeroLength],f->name);
		remove(path);
112
		safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (Zero length)"
113
			,f->name
114
			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
115
		logline(LOG_NOTICE,"U!",str);
116
		return false; 
117
	}
118

119
	bputs(text[HashingFile]);
120
	/* Note: Hashes file *after* running upload-testers (which could modify file) */
121 122 123
	bool hashed = hashfile(&cfg, f);
	bputs(text[HashedFile]);
	if(hashed) {
124
		for(uint i=0, k=0; i < usrlibs; i++) {
125
			progress(text[Scanning], i, usrlibs);
126 127 128 129 130 131 132 133 134 135 136 137 138
			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 */
					}
				}
139
			}
140 141
		}
		progress(text[Done], usrlibs, usrlibs);
142
	}
143 144 145 146

	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))) {
147
			struct sauce_charinfo sauce;
148 149
			lprintf(LOG_DEBUG, "Parsing DIZ: %s", str);

150
			char* lines = read_diz(str, &sauce);
151 152
			format_diz(lines, ext, sizeof(ext), sauce.width, sauce.ice_color);
			free_diz(lines);
153
			file_sauce_hfields(f, &sauce);
154 155

			if(f->desc == NULL || f->desc[0] == 0) {
156
				char desc[LEN_EXTDESC + 1];
157 158
				SAFECOPY(desc, (char*)ext);
				prep_file_desc(desc, desc);
159
				smb_new_hfield_str(f, SMB_FILEDESC, desc);
160 161 162 163
			}
			remove(str);
		} else
			lprintf(LOG_DEBUG, "DIZ does not exist in: %s", path);
164
	}
165

166 167 168
	if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
		logon_ulb+=length;  /* Update 'this call' stats */
		logon_uls++;
Rob Swindell's avatar
Rob Swindell committed
169
		inc_upload_stats(&cfg, 1, length);
170
	}
171
	if(cfg.dir[f->dir]->misc&DIR_AONLY)  /* Forced anonymous */
172
		f->hdr.attr |= MSG_ANONYMOUS;
173
	smb_hfield_bin(f, SMB_COST, length);
174
	smb_hfield_str(f, SENDER, useron.alias);
175
	bprintf(text[FileNBytesReceived],f->name, u64toac(length,tmp));
176
	if(!addfile(&cfg, f, ext, /* metadata: */NULL, &client))
177
		return false;
178

179
	safe_snprintf(str,sizeof(str),"uploaded %s to %s %s"
180
		,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname
181 182
		,cfg.dir[f->dir]->sname);
	if(cfg.dir[f->dir]->upload_sem[0])
183
		ftouch(cmdstr(cfg.dir[f->dir]->upload_sem,nulstr,nulstr,NULL));
184 185 186 187
	logline("U+",str);
	/**************************/
	/* Update Uploader's Info */
	/**************************/
188
	user_uploaded(&cfg, &useron, 1, length);
189 190
	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 */
191
			useron.min=(uint32_t)adjustuserrec(&cfg,useron.number,U_MIN
192 193
				,((ulong)(length*(cfg.dir[f->dir]->up_pct/100.0))/cur_cps)/60);
		else
194 195
			useron.cdt=adjustuserrec(&cfg,useron.number,U_CDT
				,(int64_t)(f->cost * (cfg.dir[f->dir]->up_pct/100.0))); 
196 197 198
	}

	user_event(EVENT_UPLOAD);
199

200
	return true;
201 202 203 204 205
}

/****************************************************************************/
/* Uploads files                                                            */
/****************************************************************************/
206
bool sbbs_t::upload(uint dirnum)
207
{
208
	char	descbeg[25]={""},descend[25]={""}
209
				,fname[MAX_FILENAME_LEN + 1],keys[256],ch,*p;
210 211
	char	str[MAX_PATH+1];
	char	path[MAX_PATH+1];
212
	char 	tmp[512];
213
    time_t	start,end;
214
    uint	i,j,k;
215
	ulong	space;
216
	file_t	f = {{}};
217
	str_list_t dest_user_list = NULL;
218

219 220 221 222 223 224 225 226 227
	/* Security Checks */
	if(useron.rest&FLAG('U')) {
		bputs(text[R_Upload]);
		return(false); 
	}
	if(dirnum==INVALID_DIR) {
		bputs(text[CantUploadHere]);
		return(false);
	}
228 229 230 231 232 233 234 235 236 237
	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);
		}
238 239
	}

240 241
	if(sys_status&SS_EVENT && online==ON_REMOTE && !dir_op(dirnum))
		bprintf(text[UploadBeforeEvent],timeleft/60);
242 243

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

245 246
	if(!isdir(path)) {
		bprintf(text[DirectoryDoesNotExist], path);
247
		lprintf(LOG_ERR,"File directory does not exist: %s", path);
248 249
		return(false);
	}
250 251

	/* get free disk space */
252 253
	space=getfreediskspace(path,1024);
	if(space<(ulong)cfg.min_dspace) {
254
		bputs(text[LowDiskSpace]);
255
		lprintf(LOG_ERR,"Diskspace is low: %s (%lu kilobytes)",path,space);
256
		if(!dir_op(dirnum))
257 258
			return(false); 
	}
259 260 261 262
	bprintf(text[DiskNBytesFree],ultoac(space,tmp));

	f.dir=curdirnum=dirnum;
	bputs(text[Filename]);
263
	if(getstr(fname, sizeof(fname) - 1, K_TRIM) < 1 || !checkfname(fname)) {
264
		if(fname[0])
265
			bprintf(text[BadFilename], fname);
266 267
		return(false); 
	}
268
	if(dirnum==cfg.sysop_dir)
269
		SAFEPRINTF(str,text[UploadToSysopDirQ],fname);
270
	else if(dirnum==cfg.user_dir)
271
		SAFEPRINTF(str,text[UploadToUserDirQ],fname);
272
	else
273
		SAFEPRINTF3(str,text[UploadToCurDirQ],fname,cfg.lib[cfg.dir[dirnum]->lib]->sname
274
			,cfg.dir[dirnum]->sname);
275
	if(!yesno(str)) return(false);
276
	action=NODE_ULNG;
277 278 279
	SAFECOPY(f.file_idx.name, fname);
	getfilepath(&cfg, &f, path);
	if(fexistcase(path)) {   /* File is on disk */
280 281
		if(!dir_op(dirnum) && online!=ON_LOCAL) {		 /* local users or sysops */
			bprintf(text[FileAlreadyThere],fname);
282 283
			return(false); 
		}
284
		if(!yesno(text[FileOnDiskAddQ]))
285 286
			return(false); 
	}
287 288
	char* ext = getfext(fname);
	SAFECOPY(str,cfg.dir[dirnum]->exts);
289 290 291 292 293
	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;
294
		ch=(char)strlen(str+i);
295 296
		if(ext != NULL && stricmp(ext + 1, str + i) == 0)
			break;
297
	}
298 299 300 301
	if(j && i>=j) {
		bputs(text[TheseFileExtsOnly]);
		bputs(cfg.dir[dirnum]->exts);
		CRLF;
302 303
		if(!dir_op(dirnum)) return(false); 
	}
304
	bputs(text[SearchingForDupes]);
305 306 307
	bool found = findfile(&cfg, dirnum, fname, NULL);
	bputs(text[SearchedForDupes]);
	if(found) {
308 309 310
		bprintf(text[FileAlreadyOnline],fname);
		return(false); 	 /* File is already in database */
	}
311
	for(i=k=0;i<usrlibs;i++) {
312
		progress(text[SearchingForDupes], i, usrlibs);
313
		for(j=0;j<usrdirs[i];j++,k++) {
314 315 316
			if(usrdir[i][j]==dirnum)
				continue;	/* we already checked this dir */
			if(cfg.dir[usrdir[i][j]]->misc&DIR_DUPES
317
				&& findfile(&cfg, usrdir[i][j], fname, NULL)) {
318
				bputs(text[SearchedForDupes]);
319
				bprintf(text[FileAlreadyOnline],fname);
320
				if(!dir_op(dirnum))
321
					return(false); 	 /* File is in database for another dir */
322
			}
323 324 325 326
			if(msgabort(true)) {
				bputs(text[SearchedForDupes]);
				return false;
			}
327 328
		}
	}
329 330 331 332 333
	bputs(text[SearchedForDupes]);
	if(cfg.dir[dirnum]->misc&DIR_RATE) {
		SYNC;
		bputs(text[RateThisFile]);
		ch=getkey(K_ALPHA);
334
		if(!IS_ALPHA(ch) || sys_status&SS_ABORT)
335
			return(false);
336
		CRLF;
337
		SAFEPRINTF(descbeg,text[Rated],toupper(ch)); 
338
	}
339 340 341 342
	if(cfg.dir[dirnum]->misc&DIR_ULDATE) {
		now=time(NULL);
		if(descbeg[0])
			strcat(descbeg," ");
343
		SAFEPRINTF(str,"%s  ",unixtodstr(&cfg,(time32_t)now,tmp));
344 345
		strcat(descbeg,str); 
	}
346 347 348 349
	if(cfg.dir[dirnum]->misc&DIR_MULT) {
		SYNC;
		if(!noyes(text[MultipleDiskQ])) {
			bputs(text[HowManyDisksTotal]);
350
			if((int)(i=getnum(99))<2)
351
				return(false);
352
			bputs(text[NumberOfFile]);
353
			if((int)(j=getnum(i))<1)
354
				return(false);
355 356 357
			if(j==1)
				upload_lastdesc[0]=0;
			if(i>9)
358
				SAFEPRINTF2(descend,text[FileOneOfTen],j,i);
359
			else
360
				SAFEPRINTF2(descend,text[FileOneOfTwo],j,i); 
361 362 363
		} else
			upload_lastdesc[0]=0; 
	}
364 365
	else
		upload_lastdesc[0]=0;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
	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;
	}
401 402

	char fdesc[LEN_FDESC + 1] = "";
403 404
	bputs(text[EnterDescNow]);
	i=LEN_FDESC-(strlen(descbeg)+strlen(descend));
405
	getstr(upload_lastdesc,i,K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
406 407
	if(sys_status&SS_ABORT) {
		strListFree(&dest_user_list);
408
		return(false);
409
	}
410
	if(descend[0])      /* end of desc specified, so pad desc with spaces */
411
		safe_snprintf(fdesc,sizeof(fdesc),"%s%-*s%s",descbeg,i,upload_lastdesc,descend);
412
	else                /* no end specified, so string ends at desc end */
413 414 415 416 417 418 419
		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);
	}
420 421 422 423

	if(cfg.dir[dirnum]->misc&DIR_ANON && !(cfg.dir[dirnum]->misc&DIR_AONLY)
		&& (dir_op(dirnum) || useron.exempt&FLAG('A'))) {
		if(!noyes(text[AnonymousQ]))
424
			f.hdr.attr |= MSG_ANONYMOUS;
425
	}
426 427 428 429

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

/****************************************************************************/
/* 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)
{
492 493
    char	str[MAX_PATH+1];
	char	path[MAX_PATH+1];
494 495 496
	char	desc[LEN_FDESC + 1];
	smb_t	smb;
    file_t f;
497 498
	DIR*	dir;
	DIRENT*	dirent;
499

500
	memset(&f,0,sizeof(f));
501 502
	f.dir=dirnum;
	bprintf(text[BulkUpload],cfg.lib[cfg.dir[dirnum]->lib]->sname,cfg.dir[dirnum]->sname);
503 504 505 506 507 508 509
	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;
	}
510 511
	action=NODE_ULNG;
	SYNC;
512 513
	str_list_t list = loadfilenames(&smb, ALLFILES, /* time_t */0, FILE_SORT_NATURAL, NULL);
	smb_close(&smb);
514
	dir=opendir(path);
515
	while(dir!=NULL && (dirent=readdir(dir))!=NULL && !msgabort()) {
516
		char fname[SMB_FILEIDX_NAMELEN + 1];
517
		SAFEPRINTF2(str,"%s%s",path,dirent->d_name);
518 519
		if(isdir(str))
			continue;
520 521 522 523 524
#ifdef _WIN32
		/* Skip hidden/system files on Win32 */
		if(getfattr(str)&(_A_HIDDEN|_A_SYSTEM))
			continue;
#endif
525 526 527 528
		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);
529 530
			off_t flen = flength(str);
			bprintf(text[BulkUploadDescPrompt], format_filename(f.name, fname, 12, /* pad: */FALSE), flen/1024);
531 532 533 534 535
			if(strcmp(f.name, fname) != 0)
				SAFECOPY(desc, f.name);
			else
				desc[0] = 0;
			getstr(desc, LEN_FDESC, K_LINE|K_EDIT|K_AUTODEL);
536 537
			if(sys_status&SS_ABORT)
				break;
538
			if(strcmp(desc,"-")==0)	/* don't add this file */
539
				continue;
540 541
			smb_hfield_str(&f, SMB_FILEDESC, desc);
			uploadfile(&f);
542 543
		}
	}
544 545
	if(dir!=NULL)
		closedir(dir);
546 547
	strListFree(&list);
	smb_freemsgmem(&f);
548 549
	if(sys_status&SS_ABORT)
		return(true);
550 551 552
	return(false);
}

553
bool sbbs_t::recvfile(char *fname, char prot, bool autohang)
554 555 556 557 558 559
{
	char	keys[32];
	char	ch;
	size_t	i;
	bool	result=false;

560 561 562 563 564
	if(prot)
		ch=toupper(prot);
	else {
		xfer_prot_menu(XFER_UPLOAD);
		mnemonics(text[ProtocolOrQuit]);
565
		SAFEPRINTF(keys,"%c",quit_key());
566
		for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
567
			if(cfg.prot[i]->ulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client))
568
				sprintf(keys+strlen(keys),"%c",cfg.prot[i]->mnemonic);
569

570
		ch=(char)getkeys(keys,0);
571

572
		if(ch==quit_key() || sys_status&SS_ABORT)
573 574
			return(false); 
	}
575
	for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
576
		if(cfg.prot[i]->mnemonic==ch && chk_ar(cfg.prot[i]->ar,&useron,&client))
577 578
			break;
	if(i<cfg.total_prots) {
579
		if(protocol(cfg.prot[i], XFER_UPLOAD, fname, fname, true, autohang)==0)
580 581 582 583 584 585
			result=true;
		autohangup(); 
	}

	return(result);
}