upload.cpp 17.1 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 "filedat.h"
24
25
26

/****************************************************************************/
/****************************************************************************/
27
bool sbbs_t::uploadfile(file_t* f)
28
{
29
	char	path[MAX_PATH+1];
30
31
	char	str[MAX_PATH+1] = "";
	char	ext[LEN_EXTDESC + 1] = "";
32
33
34
35
	char	tmp[MAX_PATH+1];
    uint	i;
    long	length;
	FILE*	stream;
36
37

	curdirnum=f->dir;
38
39
40
	if(findfile(&cfg, f->dir, f->name, NULL)) {
		errormsg(WHERE, ERR_CHK, f->name, f->dir);
		return false;
41
	}
42
43
	getfilepath(&cfg, f, path);
	SAFEPRINTF2(tmp, "%s%s", cfg.temp_dir, getfname(path));
44
	if(!fexistcase(path) && fexistcase(tmp))
45
		mv(tmp,path,0);
46
	if(!fexistcase(path)) {
47
		bprintf(text[FileNotReceived],f->name);
48
		safe_snprintf(str,sizeof(str),"attempted to upload %s to %s %s (Not received)"
49
			,f->name
50
			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
51
		logline(LOG_NOTICE,"U!",str);
52
		return false;
53
	}
54
55
	f->hdr.when_written.time = (uint32_t)fdate(path);
	char* fext = getfext(f->name);
56
	for(i=0;i<cfg.total_ftests;i++)
57
		if(cfg.ftest[i]->ext[0]=='*' || (fext != NULL && stricmp(fext, cfg.ftest[i]->ext) == 0)) {
rswindell's avatar
rswindell committed
58
			if(!chk_ar(cfg.ftest[i]->ar,&useron,&client))
59
60
61
62
				continue;
			attr(LIGHTGRAY);
			bputs(cfg.ftest[i]->workstr);

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

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

	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 */
					}
				}
146
			}
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
		}
		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))) {
			lprintf(LOG_DEBUG, "Parsing DIZ: %s", str);

			str_list_t lines = read_diz(str, /* max_line_len: */80);
			if(lines != NULL)
				format_diz(lines, ext, sizeof(ext), /* allow_ansi: */false);
			strListFree(&lines);

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

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

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

	user_event(EVENT_UPLOAD);
212

213
	return true;
214
215
216
217
218
}

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

	char fdesc[LEN_FDESC + 1] = "";
377
378
	bputs(text[EnterDescNow]);
	i=LEN_FDESC-(strlen(descbeg)+strlen(descend));
379
	getstr(upload_lastdesc,i,K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
380
	if(sys_status&SS_ABORT)
381
		return(false);
382
	if(descend[0])      /* end of desc specified, so pad desc with spaces */
383
		safe_snprintf(fdesc,sizeof(fdesc),"%s%-*s%s",descbeg,i,upload_lastdesc,descend);
384
	else                /* no end specified, so string ends at desc end */
385
386
387
388
389
390
391
		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);
	}
392
393
394
395

	if(cfg.dir[dirnum]->misc&DIR_ANON && !(cfg.dir[dirnum]->misc&DIR_AONLY)
		&& (dir_op(dirnum) || useron.exempt&FLAG('A'))) {
		if(!noyes(text[AnonymousQ]))
396
			f.hdr.attr |= MSG_ANONYMOUS;
397
	}
398
399
400
401
402
403
404
405

	bool result = false;
	smb_hfield_str(&f, SMB_FILENAME, fname);
	smb_hfield_str(&f, SMB_FILEDESC, fdesc);
	if(tags[0])
		smb_hfield_str(&f, SMB_TAGS, tags);
	if(fexistcase(path)) {   /* File is on disk */
		result = uploadfile(&f);
406
	} else {
407
		xfer_prot_menu(XFER_UPLOAD);
408
		SYNC;
409
		SAFEPRINTF(keys,"%c",text[YNQP][2]);
410
411
412
413
		if(dirnum==cfg.user_dir || !cfg.max_batup)  /* no batch user to user xfers */
			mnemonics(text[ProtocolOrQuit]);
		else {
			mnemonics(text[ProtocolBatchOrQuit]);
414
415
			strcat(keys,"B"); 
		}
416
		for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
417
			if(cfg.prot[i]->ulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
418
				SAFEPRINTF(tmp,"%c",cfg.prot[i]->mnemonic);
419
420
				strcat(keys,tmp); 
			}
421
		ch=(char)getkeys(keys,0);
422
		if(ch==text[YNQP][2] || (sys_status&SS_ABORT))
423
424
425
			result = false;
		else if(ch=='B') {
			if(batup_total() >= cfg.max_batup)
426
				bputs(text[BatchUlQueueIsFull]);
427
428
429
			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)) {
430
				bprintf(text[FileAddedToUlQueue]
431
432
433
					,fname, batup_total(), cfg.max_batup);
				result = true;
			}
434
		} else {
435
436
			for(i=0;i<cfg.total_prots;i++)
				if(cfg.prot[i]->ulcmd[0] && cfg.prot[i]->mnemonic==ch
rswindell's avatar
rswindell committed
437
					&& chk_ar(cfg.prot[i]->ar,&useron,&client))
438
439
440
					break;
			if(i<cfg.total_prots) {
				start=time(NULL);
441
				protocol(cfg.prot[i],XFER_UPLOAD,path,nulstr,true);
442
443
444
				end=time(NULL);
				if(!(cfg.dir[dirnum]->misc&DIR_ULTIME)) /* Don't deduct upload time */
					starttime+=end-start;
445
				result = uploadfile(&f);
446
				autohangup();
447
448
449
			} 
		} 
	}
450
451
	smb_freefilemem(&f);
	return result;
452
453
454
455
456
457
458
459
460
}

/****************************************************************************/
/* 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)
{
461
462
    char	str[MAX_PATH+1];
	char	path[MAX_PATH+1];
463
464
465
	char	desc[LEN_FDESC + 1];
	smb_t	smb;
    file_t f;
466
467
	DIR*	dir;
	DIRENT*	dirent;
468

469
	memset(&f,0,sizeof(f));
470
471
	f.dir=dirnum;
	bprintf(text[BulkUpload],cfg.lib[cfg.dir[dirnum]->lib]->sname,cfg.dir[dirnum]->sname);
472
473
474
475
476
477
478
	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;
	}
479
480
	action=NODE_ULNG;
	SYNC;
481
482
	str_list_t list = loadfilenames(&smb, ALLFILES, /* time_t */0, FILE_SORT_NATURAL, NULL);
	smb_close(&smb);
483
	dir=opendir(path);
484
	while(dir!=NULL && (dirent=readdir(dir))!=NULL && !msgabort()) {
485
		char fname[SMB_FILEIDX_NAMELEN + 1];
486
		SAFEPRINTF2(str,"%s%s",path,dirent->d_name);
487
488
		if(isdir(str))
			continue;
489
490
491
492
493
#ifdef _WIN32
		/* Skip hidden/system files on Win32 */
		if(getfattr(str)&(_A_HIDDEN|_A_SYSTEM))
			continue;
#endif
494
495
496
497
498
499
500
501
		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);
			smb_hfield_bin(&f, SMB_COST, cdt);
			bprintf(text[BulkUploadDescPrompt], format_filename(f.name, fname, 12, /* pad: */FALSE), cdt/1024);
			getstr(desc, LEN_FDESC, K_LINE);
502
503
			if(sys_status&SS_ABORT)
				break;
504
			if(strcmp(desc,"-")==0)	/* don't add this file */
505
				continue;
506
507
			smb_hfield_str(&f, SMB_FILEDESC, desc);
			uploadfile(&f);
508
509
		}
	}
510
511
	if(dir!=NULL)
		closedir(dir);
512
513
	strListFree(&list);
	smb_freemsgmem(&f);
514
515
	if(sys_status&SS_ABORT)
		return(true);
516
517
518
	return(false);
}

519
bool sbbs_t::recvfile(char *fname, char prot, bool autohang)
520
521
522
523
524
525
{
	char	keys[32];
	char	ch;
	size_t	i;
	bool	result=false;

526
527
528
529
530
	if(prot)
		ch=toupper(prot);
	else {
		xfer_prot_menu(XFER_UPLOAD);
		mnemonics(text[ProtocolOrQuit]);
531
		SAFEPRINTF(keys,"%c",text[YNQP][2]);
532
		for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
533
			if(cfg.prot[i]->ulcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client))
534
				sprintf(keys+strlen(keys),"%c",cfg.prot[i]->mnemonic);
535

536
		ch=(char)getkeys(keys,0);
537

538
		if(ch==text[YNQP][2] || sys_status&SS_ABORT)
539
540
			return(false); 
	}
541
	for(i=0;i<cfg.total_prots;i++)
rswindell's avatar
rswindell committed
542
		if(cfg.prot[i]->mnemonic==ch && chk_ar(cfg.prot[i]->ar,&useron,&client))
543
544
			break;
	if(i<cfg.total_prots) {
545
		if(protocol(cfg.prot[i], XFER_UPLOAD, fname, fname, true, autohang)==0)
546
547
548
549
550
551
			result=true;
		autohangup(); 
	}

	return(result);
}