file.cpp 12.1 KB
Newer Older
1
/* Synchronet file transfer-related sbbs_t class methods */
2
3
4
5
6

/****************************************************************************
 * @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

/****************************************************************************/
/* Prints all information of file in file_t structure 'f'					*/
/****************************************************************************/
28
void sbbs_t::showfileinfo(file_t* f, bool show_extdesc)
29
{
30
	char 	tmp[512];
31
	char	tmp2[64];
32
	char	path[MAX_PATH+1];
33
	bool	is_op = dir_op(f->dir);
34

35
	current_file = f;
36
37
38
39
	getfilepath(&cfg, f, path);
	bprintf(P_TRUNCATE, text[FiLib], getusrlib(f->dir), cfg.lib[cfg.dir[f->dir]->lib]->lname);
	bprintf(P_TRUNCATE, text[FiDir], getusrdir(f->dir), cfg.dir[f->dir]->lname);
	bprintf(P_TRUNCATE, text[FiFilename],f->name);
40

41
42
	if(getfilesize(&cfg, f) >= 0)
		bprintf(P_TRUNCATE, text[FiFileSize], ultoac((ulong)f->size,tmp)
43
			, byte_estimate_to_str(f->size, tmp2, sizeof(tmp2), /* units: */1024, /* precision: */1));
44
45
46
47
48
49
50
51
52
53
54
55
56

	bprintf(P_TRUNCATE, text[FiCredits]
		,(cfg.dir[f->dir]->misc&DIR_FREE || !f->cost) ? "FREE" : ultoac((ulong)f->cost,tmp));
	if(getfilesize(&cfg, f) > 0 &&  f->size == f->file_idx.idx.size) {
#if 0 // I don't think anyone cares about the CRC-16 checksum value of a file
		if(f->file_idx.hash.flags & SMB_HASH_CRC16) {
			SAFEPRINTF(tmp, "%04x", f->file_idx.hash.data.crc16);
			bprintf(P_TRUNCATE, text[FiChecksum], "CRC-16", tmp);
		}
#endif
		if(f->file_idx.hash.flags & SMB_HASH_CRC32) {
			SAFEPRINTF(tmp, "%08x", f->file_idx.hash.data.crc32);
			bprintf(P_TRUNCATE, text[FiChecksum], "CRC-32", tmp);
57
		}
58
59
60
61
		if(f->file_idx.hash.flags & SMB_HASH_MD5)
			bprintf(P_TRUNCATE, text[FiChecksum], "MD5", MD5_hex(tmp, f->file_idx.hash.data.md5));
		if(f->file_idx.hash.flags & SMB_HASH_SHA1)
			bprintf(P_TRUNCATE, text[FiChecksum], "SHA-1", SHA1_hex(tmp, f->file_idx.hash.data.sha1));
62
	}
63
64
65
66
	if(f->desc && f->desc[0])
		bprintf(P_TRUNCATE, text[FiDescription],f->desc);
	if(f->tags && f->tags[0])
		bprintf(P_TRUNCATE, text[FiTags], f->tags);
67
68
69
70
	if(f->author)
		bprintf(P_TRUNCATE, text[FiAuthor], f->author);
	if(f->author_org)
		bprintf(P_TRUNCATE, text[FiGroup], f->author_org);
71
72
73
	char* p = f->hdr.attr&MSG_ANONYMOUS ? text[UNKNOWN_USER] : f->from;
	if(p != NULL && *p != '\0')
		bprintf(P_TRUNCATE, text[FiUploadedBy], p);
74
	if(is_op) {
75
		*tmp = '\0';
76
		if(f->from_ip != NULL)
77
78
79
80
81
82
83
84
85
86
87
			SAFEPRINTF(tmp, "[%s] ", f->from_ip);
		if(f->from_host != NULL) {
			SAFEPRINTF(tmp2, "%s ", f->from_host);
			SAFECAT(tmp, tmp2);
		}
		if(f->from_prot != NULL) {
			SAFEPRINTF(tmp2, "via %s ", f->from_prot);
			SAFECAT(tmp, tmp2);
		}
		if(*tmp != '\0')
			bprintf(P_TRUNCATE, text[FiUploadedBy], tmp);
88
	}
89
90
	if(f->to_list != NULL && *f->to_list != '\0')
		bprintf(P_TRUNCATE, text[FiUploadedTo], f->to_list);
91
92
93
94
95
96
97
98
99
100
101
102
103
	bprintf(P_TRUNCATE, text[FiDateUled],timestr(f->hdr.when_imported.time));
	if(getfiletime(&cfg, f) > 0)
		bprintf(P_TRUNCATE, text[FiFileDate],timestr(f->time));
	bprintf(P_TRUNCATE, text[FiDateDled],f->hdr.last_downloaded ? timestr(f->hdr.last_downloaded) : "Never");
	bprintf(P_TRUNCATE, text[FiTimesDled],f->hdr.times_downloaded);
	ulong timetodl = gettimetodl(&cfg, f, cur_cps);
	if(timetodl > 0)
		bprintf(text[FiTransferTime],sectostr(timetodl,tmp));
	bputs(P_TRUNCATE, text[FileHdrDescSeparator]);
	if(show_extdesc && f->extdesc != NULL && *f->extdesc) {
		char* p = f->extdesc;
		SKIP_CRLF(p);
		truncsp(p);
104
		putmsg(p, P_NOATCODES | P_CPM_EOF);
105
		newline();
106
	}
107
	if(f->size == -1) {
108
		bprintf(text[FileIsNotOnline],f->name);
109
		if(SYSOP)
110
			bprintf("%s\r\n",path);
111
	}
112
	current_file = NULL;
113
114
115
}

/****************************************************************************/
116
/* Prompts user for file specification. <CR> is *							*/
117
118
119
/* Returns padded file specification.                                       */
/* Returns NULL if input was aborted.                                       */
/****************************************************************************/
120
char* sbbs_t::getfilespec(char *str)
121
122
{
	bputs(text[FileSpecStarDotStar]);
123
124
	if(!getstr(str, MAX_FILENAME_LEN, K_NONE))
		strcpy(str, ALLFILES);
125
	if(msgabort(true))
126
		return NULL;
127
128
129
130
131
132
	return(str);
}

/****************************************************************************/
/* Checks to see if filename matches filespec. Returns 1 if yes, 0 if no    */
/****************************************************************************/
133
extern "C" BOOL filematch(const char *filename, const char *filespec)
134
{
135
	return wildmatchi(filename, filespec, /* path: */FALSE);
136
137
138
139
140
141
142
143
144
}

/*****************************************************************************/
/* Checks the filename 'fname' for invalid symbol or character sequences     */
/*****************************************************************************/
bool sbbs_t::checkfname(char *fname)
{
    int		c=0,d;

145
	if(fname[0]=='-'
146
147
		|| strcspn(fname,ILLEGAL_FILENAME_CHARS)!=strlen(fname)
		|| strstr(fname, "..") != NULL) {
148
		lprintf(LOG_WARNING,"Suspicious filename attempt: '%s'",fname);
deuce's avatar
deuce committed
149
		hacklog((char *)"Filename", fname);
150
151
		return(false); 
	}
152
153
	d=strlen(fname);
	while(c<d) {
154
		if(fname[c]<=' ' || fname[c]&0x80)
155
			return(false);
156
157
		c++; 
	}
158
159
	return(true);
}
160
161
162
163
164
165
166
167

long sbbs_t::delfiles(const char *inpath, const char *spec, size_t keep)
{
	long result = ::delfiles(inpath, spec, keep);
	if(result < 0)
		errormsg(WHERE, ERR_REMOVE, inpath, result, spec);
	return result;
}
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

/****************************************************************************/
/* Remove credits or minutes and adjust statistics of uploader of file 'f'	*/
/****************************************************************************/
bool sbbs_t::removefcdt(file_t* f)
{
	char	str[128];
	char 	tmp[512];
	int		u;
	long	cdt;

	if((u=matchuser(&cfg,f->from,TRUE /*sysop_alias*/))==0) {
	   bputs(text[UnknownUser]);
	   return(false); 
	}
	cdt=0L;
	if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps) {
		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
			cdt=((ulong)(f->cost*(cfg.dir[f->dir]->up_pct/100.0))/cur_cps)/60;
		if(cfg.dir[f->dir]->misc&DIR_CDTDL
			&& f->hdr.times_downloaded)  /* all downloads */
			cdt+=((ulong)((long)f->hdr.times_downloaded
				*f->cost*(cfg.dir[f->dir]->dn_pct/100.0))/cur_cps)/60;
Rob Swindell's avatar
Rob Swindell committed
191
192
193
194
195
		adjustuserrec(&cfg,u,U_MIN,10,-cdt);
		sprintf(str,"%lu minute",cdt);
		sprintf(tmp,text[FileRemovedUserMsg]
			,f->name,cdt ? str : text[No]);
		putsmsg(&cfg,u,tmp);
196
197
198
199
200
201
202
203
204
205
206
207
	}
	else {
		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
			cdt=(ulong)(f->cost*(cfg.dir[f->dir]->up_pct/100.0));
		if(cfg.dir[f->dir]->misc&DIR_CDTDL
			&& f->hdr.times_downloaded)  /* all downloads */
			cdt+=(ulong)((long)f->hdr.times_downloaded
				*f->cost*(cfg.dir[f->dir]->dn_pct/100.0));
		if(dir_op(f->dir)) {
			ultoa(cdt, str, 10);
			bputs(text[CreditsToRemove]);
			getstr(str, 10, K_NUMBER|K_LINE|K_EDIT|K_AUTODEL);
208
			if(msgabort(true))
209
210
211
				return false;
			cdt = atol(str); 
		}
Rob Swindell's avatar
Rob Swindell committed
212
213
214
215
		adjustuserrec(&cfg,u,U_CDT,10,-cdt);
		sprintf(tmp,text[FileRemovedUserMsg]
			,f->name,cdt ? ultoac(cdt,str) : text[No]);
		putsmsg(&cfg,u,tmp);
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
	}

	adjustuserrec(&cfg,u,U_ULB,10,(long)-f->size);
	adjustuserrec(&cfg,u,U_ULS,5,-1);
	return(true);
}

/****************************************************************************/
/****************************************************************************/
bool sbbs_t::removefile(smb_t* smb, file_t* f)
{
	char str[256];
	int result;

	if((result = smb_removefile(smb ,f)) == SMB_SUCCESS) {
231
		SAFEPRINTF3(str,"removed %s from %s %s"
232
233
234
			,f->name
			,cfg.lib[cfg.dir[smb->dirnum]->lib]->sname,cfg.dir[smb->dirnum]->sname);
		logline("U-",str);
235
		f->hdr.attr |= MSG_DELETE;
236
237
238
239
240
241
242
243
244
245
		return true;
	}
	errormsg(WHERE, ERR_REMOVE, f->name, result, smb->last_error);
	return false;
}

/****************************************************************************/
/****************************************************************************/
bool sbbs_t::movefile(smb_t* smb, file_t* f, int newdir)
{
246
	file_t newfile = *f;
247
248
249
250
251
	if(findfile(&cfg, newdir, f->name, NULL)) {
		bprintf(text[FileAlreadyThere], f->name);
		return false; 
	}

252
	if(!addfile(&cfg, newdir, &newfile, newfile.extdesc, /* client: */NULL))
253
		return false;
254
	if(!removefile(smb, f))	// Use ::removefile() here instead?
Rob Swindell's avatar
Rob Swindell committed
255
		return false;
256
257
258
259
260
261
262
263
264
265
266
267
	bprintf(text[MovedFile],f->name
		,cfg.lib[cfg.dir[newdir]->lib]->sname,cfg.dir[newdir]->sname);
	char str[MAX_PATH+1];
	SAFEPRINTF4(str, "%s moved %s to %s %s",f->name
		,useron.alias
		,cfg.lib[cfg.dir[newdir]->lib]->sname
		,cfg.dir[newdir]->sname);
	logline(nulstr,str);

	/* move actual file */
	char oldpath[MAX_PATH + 1];
	getfilepath(&cfg, f, oldpath);
268
	newfile.dir = newdir;
269
	char newpath[MAX_PATH + 1];
270
	getfilepath(&cfg, &newfile, newpath);
271
272
273
274
	mv(oldpath, newpath, /* copy */false); 
	
	return true;
}
275
276
277
278
279
280
281
282
283
284
285

bool sbbs_t::editfilename(file_t* f)
{
	char str[MAX_FILENAME_LEN + 1];
	char tmp[MAX_PATH + 1];
	char path[MAX_PATH + 1];

	bputs(text[EditFilename]);
	SAFECOPY(str, f->name);
	if(!getstr(str, sizeof(str) - 1, K_EDIT|K_AUTODEL))
		return false;
286
	if(msgabort(true))
287
288
289
290
291
292
293
294
		return false;
	if(strcmp(str,f->name) == 0)  
		return true;
	/* rename */
	if(stricmp(str,f->name)	&& findfile(&cfg, f->dir, path, NULL)) {
		bprintf(text[FileAlreadyThere],path);
		return false;
	}
295
296
	SAFEPRINTF2(path,"%s%s", cfg.dir[f->dir]->path, f->name);
	SAFEPRINTF2(tmp,"%s%s", cfg.dir[f->dir]->path, str);
297
298
299
300
301
302
303
	if(fexistcase(path) && rename(path,tmp) != 0) {
		bprintf(text[CouldntRenameFile],path,tmp);
		return false;
	}
	bprintf(text[FileRenamed],path,tmp);
	smb_new_hfield_str(f, SMB_FILENAME, str);
	return updatefile(&cfg, f);
304
305
}

306
bool sbbs_t::editfiledesc(file_t* f)
307
308
309
{
	// Description
	bputs(text[EditDescription]);
310
311
312
	char fdesc[LEN_FDESC + 1] = "";
	if(f->desc != NULL)
		SAFECOPY(fdesc, f->desc);
313
	getstr(fdesc, sizeof(fdesc)-1, K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
314
	if(msgabort(true))
315
		return false;
316
	if(f->desc != NULL && strcmp(fdesc, f->desc) == 0)
317
318
		return true;
	smb_new_hfield_str(f, SMB_FILEDESC, fdesc);
319
320
321
322
323
324
325
	return updatefile(&cfg, f);
}

bool sbbs_t::editfileinfo(file_t* f)
{
	char str[MAX_PATH + 1];

326
327
328
329
330
331
332
	// Tags
	if((cfg.dir[f->dir]->misc & DIR_FILETAGS) || dir_op(f->dir)) {
		char tags[64] = "";
		bputs(text[TagFilePrompt]);
		if(f->tags != NULL)
			SAFECOPY(tags, f->tags);
		getstr(tags, sizeof(tags)-1, K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
333
		if(msgabort(true))
334
335
336
337
			return false;
		if((f->tags == NULL && *tags != '\0') || (f->tags != NULL && strcmp(tags, f->tags)))
			smb_new_hfield_str(f, SMB_TAGS, tags);
	}
338
339
340
341
342
343
	if(!noyes(text[EditExtDescriptionQ])) {
		if(editmsg(&smb, f)) {
			if(f->extdesc != NULL)
				smb_freemsgtxt(f->extdesc);
			f->extdesc = smb_getmsgtxt(&smb, f, GETMSGTXT_BODY_ONLY);
		}
344
345
346
347
348
	}
	if(dir_op(f->dir)) {
		char uploader[LEN_ALIAS + 1];
		SAFECOPY(uploader, f->from);
		bputs(text[EditUploader]);
349
350
		getstr(uploader, sizeof(uploader), K_EDIT|K_AUTODEL);
		if(msgabort(true))
351
			return false;
352
353
		if(*uploader != '\0' || *f->from != '\0')
			smb_new_hfield_str(f, SMB_FILEUPLOADER, uploader);
354
355
356
		ultoa(f->cost,str,10);
		bputs(text[EditCreditValue]);
		getstr(str,10,K_NUMBER|K_EDIT|K_AUTODEL);
357
		if(msgabort(true))
358
359
360
361
362
363
			return false;
		f->cost = atol(str);
		smb_new_hfield(f, SMB_COST, sizeof(f->cost), &f->cost);
		ultoa(f->hdr.times_downloaded,str,10);
		bputs(text[EditTimesDownloaded]);
		getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL);
364
		if(msgabort(true))
365
366
			return false;
		f->hdr.times_downloaded=atoi(str);
367
		if(msgabort(true))
368
369
370
371
372
			return false;
		inputnstime32((time32_t*)&f->hdr.when_imported.time);
	}
	return updatefile(&cfg, f);
}