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

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

	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++) {
127
			progress(text[Scanning], i, usrlibs);
128
129
130
131
132
133
134
135
136
137
138
139
140
			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 */
					}
				}
141
			}
142
143
144
145
146
147
148
149
		}
		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))) {
150
			struct sauce_charinfo sauce;
151
152
			lprintf(LOG_DEBUG, "Parsing DIZ: %s", str);

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

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

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

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

	user_event(EVENT_UPLOAD);
209

210
	return true;
211
212
213
214
215
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

580
		ch=(char)getkeys(keys,0);
581

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

	return(result);
}