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",quit_key());
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==quit_key() || (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",quit_key());
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==quit_key() || 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);
}