upload.cpp 18.5 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 || !checkfname(fname)) {
280
		if(fname[0])
281
			bprintf(text[BadFilename], fname);
282 283
		return(false); 
	}
284
	if(dirnum==cfg.sysop_dir)
285
		SAFEPRINTF(str,text[UploadToSysopDirQ],fname);
286
	else if(dirnum==cfg.user_dir)
287
		SAFEPRINTF(str,text[UploadToUserDirQ],fname);
288
	else
289
		SAFEPRINTF3(str,text[UploadToCurDirQ],fname,cfg.lib[cfg.dir[dirnum]->lib]->sname
290
			,cfg.dir[dirnum]->sname);
291
	if(!yesno(str)) return(false);
292
	action=NODE_ULNG;
293 294 295
	SAFECOPY(f.file_idx.name, fname);
	getfilepath(&cfg, &f, path);
	if(fexistcase(path)) {   /* File is on disk */
296 297
		if(!dir_op(dirnum) && online!=ON_LOCAL) {		 /* local users or sysops */
			bprintf(text[FileAlreadyThere],fname);
298 299
			return(false); 
		}
300
		if(!yesno(text[FileOnDiskAddQ]))
301 302
			return(false); 
	}
303 304
	char* ext = getfext(fname);
	SAFECOPY(str,cfg.dir[dirnum]->exts);
305 306 307 308 309
	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;
310
		ch=(char)strlen(str+i);
311 312
		if(ext != NULL && stricmp(ext + 1, str + i) == 0)
			break;
313
	}
314 315 316 317
	if(j && i>=j) {
		bputs(text[TheseFileExtsOnly]);
		bputs(cfg.dir[dirnum]->exts);
		CRLF;
318 319
		if(!dir_op(dirnum)) return(false); 
	}
320
	bputs(text[SearchingForDupes]);
321 322 323
	bool found = findfile(&cfg, dirnum, fname, NULL);
	bputs(text[SearchedForDupes]);
	if(found) {
324 325 326
		bprintf(text[FileAlreadyOnline],fname);
		return(false); 	 /* File is already in database */
	}
327
	for(i=k=0;i<usrlibs;i++) {
328
		progress(text[SearchingForDupes], i, usrlibs, 1);
329
		for(j=0;j<usrdirs[i];j++,k++) {
330 331 332
			if(usrdir[i][j]==dirnum)
				continue;	/* we already checked this dir */
			if(cfg.dir[usrdir[i][j]]->misc&DIR_DUPES
333
				&& findfile(&cfg, usrdir[i][j], fname, NULL)) {
334
				bputs(text[SearchedForDupes]);
335
				bprintf(text[FileAlreadyOnline],fname);
336
				if(!dir_op(dirnum))
337
					return(false); 	 /* File is in database for another dir */
338 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);
}