upload.cpp 18.2 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
			// 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);
76
77
78
			clearline();
			if(result != 0) {
				safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (%s error code %d)"
79
					,f->name
80
81
					,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname,cfg.ftest[i]->ext
					,result);
82
				logline(LOG_NOTICE,"U!",str);
83
84
85
				bprintf(text[FileHadErrors],f->name,cfg.ftest[i]->ext);
				if(!SYSOP || yesno(text[DeleteFileQ]))
					remove(path);
86
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);
					smb_new_hfield_str(f, SMB_FILEDESC, str);
102
				}
103
				fclose(stream); 
104
			}
105
		}
106

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

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

148
			char* lines = read_diz(str, &sauce);
149
			if(lines != NULL)
150
151
152
				format_diz(lines, ext, sizeof(ext), sauce.width, sauce.ice_color);
			free(lines);
			file_sauce_hfields(f, &sauce);
153
154

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

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

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

	user_event(EVENT_UPLOAD);
204

205
	return true;
206
207
208
209
210
}

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

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

245
246
	if(sys_status&SS_EVENT && online==ON_REMOTE && !dir_op(dirnum))
		bprintf(text[UploadBeforeEvent],timeleft/60);
247
248

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

250
251
	if(!isdir(path)) {
		bprintf(text[DirectoryDoesNotExist], path);
252
		lprintf(LOG_ERR,"File directory does not exist: %s", path);
253
254
		return(false);
	}
255
256

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

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

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

	if(cfg.dir[dirnum]->misc&DIR_ANON && !(cfg.dir[dirnum]->misc&DIR_AONLY)
		&& (dir_op(dirnum) || useron.exempt&FLAG('A'))) {
		if(!noyes(text[AnonymousQ]))
429
			f.hdr.attr |= MSG_ANONYMOUS;
430
	}
431
432
433
434

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

/****************************************************************************/
/* 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)
{
497
498
    char	str[MAX_PATH+1];
	char	path[MAX_PATH+1];
499
500
501
	char	desc[LEN_FDESC + 1];
	smb_t	smb;
    file_t f;
502
503
	DIR*	dir;
	DIRENT*	dirent;
504

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

558
bool sbbs_t::recvfile(char *fname, char prot, bool autohang)
559
560
561
562
563
564
{
	char	keys[32];
	char	ch;
	size_t	i;
	bool	result=false;

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

575
		ch=(char)getkeys(keys,0);
576

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

	return(result);
}