upload.cpp 18.4 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
			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
				fprintf(stream, "%s", f->desc);
72 73
				fclose(stream); 
			}
74
			if(external(cmdstr(cfg.ftest[i]->cmd,path,f->desc,NULL),EX_OFFLINE)) {
75
				safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (%s Errors)"
76
					,f->name
77
					,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname,cfg.ftest[i]->ext);
78
				logline(LOG_NOTICE,"U!",str);
79 80 81 82 83 84 85
#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);
86 87
				return(0); 
			} else {
88
#if 0 // NFB-TODO - uploader tester changes filename or description
89
				sprintf(str,"%ssbbsfile.nam",cfg.node_dir);
90 91 92 93 94 95
				if((stream=fopen(str,"r"))!=NULL) {
					if(fgets(str,128,stream)) {
						truncsp(str);
						padfname(str,f->name);
						strcpy(tmp,f->name);
						truncsp(tmp);
96
						sprintf(path,"%s%s", cfg.dir[f->dir]->path
97 98
							,unpadfname(f->name,fname)); 
					}
99 100
					fclose(stream);
					}
101
				sprintf(str,"%ssbbsfile.des",cfg.node_dir);
102 103 104
				if((stream=fopen(str,"r"))!=NULL) {
					if(fgets(str,128,stream)) {
						truncsp(str);
105 106 107 108
						sprintf(f->desc,"%.*s",LEN_FDESC,str); 
					}
					fclose(stream); 
				}
109 110 111
				CRLF;
#endif
			}
112
		}
113

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

	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 */
					}
				}
143
			}
144 145 146 147 148 149 150 151
		}
		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))) {
152
			struct sauce_charinfo sauce;
153 154
			lprintf(LOG_DEBUG, "Parsing DIZ: %s", str);

155
			char* lines = read_diz(str, &sauce);
156
			if(lines != NULL)
157 158 159
				format_diz(lines, ext, sizeof(ext), sauce.width, sauce.ice_color);
			free(lines);
			file_sauce_hfields(f, &sauce);
160 161

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

178 179 180 181
	if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
		logon_ulb+=length;  /* Update 'this call' stats */
		logon_uls++;
	}
182
	if(cfg.dir[f->dir]->misc&DIR_AONLY)  /* Forced anonymous */
183 184 185 186
		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);
187
	bprintf(text[FileNBytesReceived],f->name,ultoac(length,tmp));
188
	if(!addfile(&cfg, f->dir, f, ext, /* metadata: */NULL, &client))
189
		return false;
190

191
	safe_snprintf(str,sizeof(str),"uploaded %s to %s %s"
192
		,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname
193 194
		,cfg.dir[f->dir]->sname);
	if(cfg.dir[f->dir]->upload_sem[0])
195
		ftouch(cmdstr(cfg.dir[f->dir]->upload_sem,nulstr,nulstr,NULL));
196 197 198 199
	logline("U+",str);
	/**************************/
	/* Update Uploader's Info */
	/**************************/
200
	user_uploaded(&cfg, &useron, 1, length);
201 202 203 204 205 206
	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
207
				,(ulong)(f->cost * (cfg.dir[f->dir]->up_pct/100.0))); 
208 209 210
	}

	user_event(EVENT_UPLOAD);
211

212
	return true;
213 214 215 216 217
}

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

231 232 233 234 235 236 237 238 239
	/* Security Checks */
	if(useron.rest&FLAG('U')) {
		bputs(text[R_Upload]);
		return(false); 
	}
	if(dirnum==INVALID_DIR) {
		bputs(text[CantUploadHere]);
		return(false);
	}
240 241 242 243 244 245 246 247 248 249
	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);
		}
250 251
	}

252 253
	if(sys_status&SS_EVENT && online==ON_REMOTE && !dir_op(dirnum))
		bprintf(text[UploadBeforeEvent],timeleft/60);
254 255

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

257 258
	if(!isdir(path)) {
		bprintf(text[DirectoryDoesNotExist], path);
259
		lprintf(LOG_ERR,"File directory does not exist: %s", path);
260 261
		return(false);
	}
262 263

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

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

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

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

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

/****************************************************************************/
/* 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)
{
504 505
    char	str[MAX_PATH+1];
	char	path[MAX_PATH+1];
506 507 508
	char	desc[LEN_FDESC + 1];
	smb_t	smb;
    file_t f;
509 510
	DIR*	dir;
	DIRENT*	dirent;
511

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

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

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

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

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

	return(result);
}