addfiles.c 25.9 KB
Newer Older
1
2
/* Program to add files to a Synchronet file database */

Rob Swindell's avatar
Rob Swindell committed
3
/* $Id: addfiles.c,v 1.63 2020/08/17 00:48:27 rswindell Exp $ */
4
5
6
7
8

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
9
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *																			*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
37
#include <stdbool.h>
38

39
#define ADDFILES_VER "3.04"
40
41
42
43
44
45
46

scfg_t scfg;

int cur_altpath=0;

long files=0,removed=0,mode=0;

47
char lib[LEN_GSNAME+1];
48
const char* datefmt = NULL;
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#define DEL_LIST	(1L<<0)
#define NO_EXTEND	(1L<<1)
#define FILE_DATE	(1L<<2)
#define TODAYS_DATE (1L<<3)
#define FILE_ID 	(1L<<4)
#define NO_UPDATE	(1L<<5)
#define NO_NEWDATE	(1L<<6)
#define ASCII_ONLY	(1L<<7)
#define UL_STATS	(1L<<8)
#define ULDATE_ONLY (1L<<9)
#define KEEP_DESC	(1L<<10)
#define AUTO_ADD	(1L<<11)
#define SEARCH_DIR	(1L<<12)
#define SYNC_LIST	(1L<<13)
#define KEEP_SPACE	(1L<<14)
rswindell's avatar
rswindell committed
65
#define CHECK_DATE	(1L<<15)
66
67

/****************************************************************************/
68
/* This is needed by load_cfg.c												*/
69
/****************************************************************************/
70
int lprintf(int level, const char *fmat, ...)
71
72
{
	va_list argptr;
73
	char sbuf[512];
74
75
76
77
78
	int chcount;

	va_start(argptr,fmat);
	chcount=vsprintf(sbuf,fmat,argptr);
	va_end(argptr);
79
80
	truncsp(sbuf);
	printf("%s\n",sbuf);
81
82
83
	return(chcount);
}

84
void prep_desc(char *str)
85
86
87
88
89
{
	char tmp[1024];
	int i,j;

	for(i=j=0;str[i] && j < sizeof(tmp)-1;i++) {
90
		if(j && str[i]==' ' && tmp[j-1]==' ' && (mode&KEEP_SPACE))
91
			tmp[j++]=str[i];
92
		else if(j && str[i]<=' ' && str[i] > 0&& tmp[j-1]==' ')
93
			continue;
94
		else if(i && !isalnum((uchar)str[i]) && str[i]==str[i-1])
95
			continue;
96
		else if(str[i]>=' ' || str[i]<0)
97
98
			tmp[j++]=str[i];
		else if(str[i]==TAB || (str[i]==CR && str[i+1]==LF))
99
			tmp[j++]=' ';
100
101
102
103
104
	}
	tmp[j]=0;
	strcpy(str,tmp);
}

105
106
107
/*****************************************************************************/
/* Returns command line generated from instr with %c replacments             */
/*****************************************************************************/
108
char *mycmdstr(const char *instr, const char *fpath, const char *fspec, char *outstr)
109
110
111
112
{
    static char cmd[MAX_PATH+1];
    char str[MAX_PATH+1];
    int i,j,len;
rswindell's avatar
rswindell committed
113
114
115
#ifdef _WIN32
	char sfpath[MAX_PATH+1];
#endif
116
117
118
119
120
121
122
123

	len=strlen(instr);
	for(i=j=0;i<len && j<128;i++) {
		if(instr[i]=='%') {
			i++;
			cmd[j]=0;
			switch(toupper(instr[i])) {
				case 'F':   /* File path */
124
					SAFECAT(cmd,fpath);
125
126
127
128
129
					break;
				case '~':	/* DOS-compatible (8.3) filename */
#ifdef _WIN32
					SAFECOPY(sfpath,fpath);
					GetShortPathName(fpath,sfpath,sizeof(sfpath));
130
					SAFECAT(cmd,sfpath);
131
#else
132
                    SAFECAT(cmd,fpath);
133
#endif
134
135
					break;
				case 'G':   /* Temp directory */
136
					SAFECAT(cmd,scfg.temp_dir);
137
138
					break;
                case 'J':
139
                    SAFECAT(cmd,scfg.data_dir);
140
141
                    break;
                case 'K':
142
                    SAFECAT(cmd,scfg.ctrl_dir);
143
144
                    break;
				case 'N':   /* Node Directory (same as SBBSNODE environment var) */
145
					SAFECAT(cmd,scfg.node_dir);
146
147
					break;
				case 'S':   /* File Spec */
148
					SAFECAT(cmd,fspec);
149
150
					break;
                case 'Z':
151
                    SAFECAT(cmd,scfg.text_dir);
152
153
                    break;
				case '!':   /* EXEC Directory */
154
					SAFECAT(cmd,scfg.exec_dir);
155
					break;
156
157
                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
158
                    SAFECAT(cmd,scfg.exec_dir);
159
160
#endif
                    break;
161
162
				case '#':   /* Node number (same as SBBSNNUM environment var) */
					sprintf(str,"%d",scfg.node_num);
163
					SAFECAT(cmd,str);
164
165
					break;
				case '%':   /* %% for percent sign */
166
					SAFECAT(cmd,"%");
167
168
					break;
				default:    /* unknown specification */
169
					break;
170
			}
171
			j=strlen(cmd);
172
173
		}
		else
174
			cmd[j++]=instr[i];
175
176
177
178
179
180
181
182
183
184
185
186
187
	}
	cmd[j]=0;

	return(cmd);
}

/****************************************************************************/
/* Updates dstst.dab file													*/
/****************************************************************************/
void updatestats(ulong size)
{
    char	str[MAX_PATH+1];
    int		file;
deuce's avatar
64-bit    
deuce committed
188
	uint32_t	l;
189

190
	sprintf(str,"%sdsts.dab",scfg.ctrl_dir);
191
	if((file=nopen(str,O_RDWR|O_BINARY))==-1) {
192
		printf("ERR_OPEN %s\n",str);
193
		return;
194
195
196
197
198
199
200
201
202
203
204
205
206
	}
	lseek(file,20L,SEEK_SET);	/* Skip timestamp, logons and logons today */
	read(file,&l,4);			/* Uploads today		 */
	l++;
	lseek(file,-4L,SEEK_CUR);
	write(file,&l,4);
	read(file,&l,4);			/* Upload bytes today	 */
	l+=size;
	lseek(file,-4L,SEEK_CUR);
	write(file,&l,4);
	close(file);
}

207
bool get_file_diz(file_t* f, const char* filepath, char* ext)
208
209
210
{
	int i,file;
	char tmp[MAX_PATH+1];
211
	char tmpext[513];
212
213

	for(i=0;i<scfg.total_fextrs;i++)
214
215
		if(!stricmp(scfg.fextr[i]->ext,f->name+9)
			&& chk_ar(&scfg,scfg.fextr[i]->ar,/* user: */NULL, /* client: */NULL))
216
			break;
217
218
219
220
221
222
223
224
225
226
227
228
229
230
	// If we could not find an extractor which matches our requirements, use any
	if(i >= scfg.total_fextrs) {
		for(i=0;i<scfg.total_fextrs;i++)
			if(!stricmp(scfg.fextr[i]->ext,f->name+9))
				break;
	}
	if(i >= scfg.total_fextrs)
		return false;

	SAFEPRINTF(tmp,"%sFILE_ID.DIZ",scfg.temp_dir);
	removecase(tmp);
	system(mycmdstr(scfg.fextr[i]->cmd,filepath,"FILE_ID.DIZ",NULL));
	if(!fexistcase(tmp)) {
		SAFEPRINTF(tmp,"%sDESC.SDI",scfg.temp_dir);
231
		removecase(tmp);
232
233
		system(mycmdstr(scfg.fextr[i]->cmd,filepath,"DESC.SDI",NULL));
		fexistcase(tmp);
234
	}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259

	if((file=nopen(tmp,O_RDONLY|O_BINARY)) == -1)
		return false;

	memset(ext,0,513);
	read(file,ext,512);
	for(i=512;i;i--)
		if(ext[i-1]>' ' || ext[i-1]<0)
			break;
	ext[i]=0;
	if(mode&ASCII_ONLY)
		strip_exascii(ext, ext);
	if(!(mode&KEEP_DESC)) {
		sprintf(tmpext,"%.256s",ext);
		prep_desc(tmpext);
		for(i=0;tmpext[i];i++)
			if(isalpha((uchar)tmpext[i]))
				break;
		sprintf(f->desc,"%.*s",LEN_FDESC,tmpext+i);
		for(i=0;(f->desc[i]>=' ' || f->desc[i]<0) && i<LEN_FDESC;i++)
			;
		f->desc[i]=0; }
	close(file);
	f->misc|=FM_EXTDESC;
	return true;
260
261
}

262
263
void addlist(char *inpath, file_t f, uint dskip, uint sskip)
{
264
265
266
267
268
269
	char str[MAX_PATH+1];
	char tmp[MAX_PATH+1];
	char fname[MAX_PATH+1];
	char listpath[MAX_PATH+1];
	char filepath[MAX_PATH+1];
	char curline[256],nextline[256];
270
	char *p;
271
272
	char ext[1024];
	int i;
273
	long l;
274
	BOOL exist;
275
276
277
278
279
	FILE *stream;
	DIR*	dir;
	DIRENT*	dirent;

	if(mode&SEARCH_DIR) {
280
		SAFECOPY(str,cur_altpath ? scfg.altpath[cur_altpath-1] : scfg.dir[f.dir]->path);
281
282
283
284
		printf("Searching %s\n\n",str);
		dir=opendir(str);

		while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
rswindell's avatar
rswindell committed
285
286
287
			sprintf(tmp,"%s%s"
				,cur_altpath ? scfg.altpath[cur_altpath-1] : scfg.dir[f.dir]->path
				,dirent->d_name);
288
289
290
291
292
			if(isdir(tmp))
				continue;
#ifdef _WIN32
			GetShortPathName(tmp, filepath, sizeof(filepath));
#else
293
			SAFECOPY(filepath,tmp);
294
#endif
295
296
			f.misc=0;
			f.desc[0]=0;
297
			memset(ext, 0, sizeof(ext));
298
			f.cdt=flength(filepath);
rswindell's avatar
rswindell committed
299
			time_t file_timestamp = fdate(filepath);
300
			padfname(getfname(filepath),f.name);
deuce's avatar
deuce committed
301
			printf("%s  %10"PRIu32"  %s\n"
rswindell's avatar
rswindell committed
302
				,f.name,f.cdt,unixtodstr(&scfg,(time32_t)file_timestamp,str));
303
304
305
306
			exist=findfile(&scfg,f.dir,f.name);
			if(exist) {
				if(mode&NO_UPDATE)
					continue;
307
308
309
310
311
312
				if(!getfileixb(&scfg,&f)) {
					fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
					continue;
				}
				if((mode&CHECK_DATE) && file_timestamp <= f.dateuled)
					continue;
313
				if(mode&ULDATE_ONLY) {
314
					f.dateuled=time32(NULL);
315
					update_uldate(&scfg, &f);
316
317
					continue;
				}
318
319
				if(f.misc & FM_EXTDESC)
					getextdesc(&scfg, f.dir, f.datoffset, ext);
320
321
322
			}

			if(mode&TODAYS_DATE) {		/* put today's date in desc */
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
				time_t now = time(NULL);
				if(datefmt) {
					struct tm tm = {0};
					localtime_r(&now, &tm);
					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
				} else
					unixtodstr(&scfg, (time32_t)now, f.desc);
				SAFECAT(f.desc,"  ");
			}
			else if(mode&FILE_DATE) {		/* get the file date and put into desc */
				if(datefmt) {
					struct tm tm = {0};
					localtime_r(&file_timestamp, &tm);
					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
				} else
					unixtodstr(&scfg,(time32_t)file_timestamp,f.desc);
				SAFECAT(f.desc,"  ");
340
341
			}

342
			if(mode&FILE_ID)
343
				get_file_diz(&f, filepath, ext);
344

345
			f.dateuled=time32(NULL);
346
			f.altpath=cur_altpath;
347
			prep_desc(f.desc);
348
			if(mode&ASCII_ONLY)
349
				strip_exascii(f.desc, f.desc);
350
351
352
			if(exist) {
				putfiledat(&scfg,&f);
				if(!(mode&NO_NEWDATE))
353
					update_uldate(&scfg, &f);
354
			}
355
356
357
358
			else
				addfiledat(&scfg,&f);
			if(f.misc&FM_EXTDESC) {
				truncsp(ext);
359
				putextdesc(&scfg,f.dir,f.datoffset,ext);
360
			}
361
362
			if(mode&UL_STATS)
				updatestats(f.cdt);
363
			files++;
364
365
366
		}
		if(dir!=NULL)
			closedir(dir);
367
		return;
368
369
370
	}


371
	SAFECOPY(listpath,inpath);
372
	fexistcase(listpath);
373
	if((stream=fopen(listpath,"r"))==NULL) {
374
375
		fprintf(stderr,"Error %d (%s) opening %s\n"
			,errno,strerror(errno),listpath);
376
377
		sprintf(listpath,"%s%s",cur_altpath ? scfg.altpath[cur_altpath-1]
				: scfg.dir[f.dir]->path,inpath);
378
		fexistcase(listpath);
379
		if((stream=fopen(listpath,"r"))==NULL) {
380
381
			printf("Can't open: %s\n"
				   "        or: %s\n",inpath,listpath);
382
383
			return;
		}
384
	}
385
386
387
388
389

	printf("Adding %s to %s %s\n\n"
		,listpath,scfg.lib[scfg.dir[f.dir]->lib]->sname,scfg.dir[f.dir]->sname);

	fgets(nextline,255,stream);
390
	do {
391
392
		f.misc=0;
		f.desc[0]=0;
393
		memset(ext, 0, sizeof(ext));
394
		SAFECOPY(curline,nextline);
395
396
397
		nextline[0]=0;
		fgets(nextline,255,stream);
		truncsp(curline);
398
		if(curline[0]<=' ' || (mode&ASCII_ONLY && (uchar)curline[0]>=0x7e))
399
400
			continue;
		printf("%s\n",curline);
401
		SAFECOPY(fname,curline);
402

403
#if 0	/* Files without dots are valid on modern systems */
404
405
406
		p=strchr(fname,'.');
		if(!p || p==fname || p>fname+8)    /* no dot or invalid dot location */
			continue;
407
408
#endif
		p=strchr(fname,' ');
409
		if(p) *p=0;
rswindell's avatar
rswindell committed
410
#if 0 // allow import of bare filename list
411
412
		else				   /* no space after filename? */
			continue;
rswindell's avatar
rswindell committed
413
#endif
414
415
416
		if(!isalnum(*fname)) {	// filename doesn't begin with an alpha-numeric char?
			continue;
		}
rswindell's avatar
rswindell committed
417
		SAFEPRINTF2(filepath,"%s%s",cur_altpath ? scfg.altpath[cur_altpath-1]
418
419
420
421
422
423
424
425
			: scfg.dir[f.dir]->path,fname);

#ifdef _WIN32
		{
			char shortpath[MAX_PATH+1];
			GetShortPathName(filepath, shortpath, sizeof(shortpath));
			SAFECOPY(fname, getfname(shortpath));
		}
rswindell's avatar
rswindell committed
426
427
428
#else
		fexistcase(filepath);
		SAFECOPY(fname, getfname(filepath));
429
430
#endif

431
432
433
434
435
		padfname(fname,f.name);
		if(strcspn(f.name,"\\/|<>+[]:=\";,")!=strlen(f.name))
			continue;

		for(i=0;i<12;i++)
436
			if(f.name[i]<' ' || (mode&ASCII_ONLY && (uchar)f.name[i]>0x7e))
437
438
439
440
				break;

		if(i<12)					/* Ctrl chars or EX-ASCII in filename? */
			continue;
rswindell's avatar
rswindell committed
441
		time_t file_timestamp = fdate(filepath);
442
443
444
445
		exist=findfile(&scfg,f.dir,f.name);
		if(exist) {
			if(mode&NO_UPDATE)
				continue;
446
447
448
449
450
451
			if(!getfileixb(&scfg,&f)) {
				fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
				continue;
			}
			if((mode&CHECK_DATE) && file_timestamp <= f.dateuled)
				continue;
452
			if(mode&ULDATE_ONLY) {
453
				f.dateuled=time32(NULL);
454
				update_uldate(&scfg, &f);
455
456
				continue;
			}
457
458
			if (f.misc & FM_EXTDESC)
				getextdesc(&scfg, f.dir, f.datoffset, ext);
459
		}
460
461

		if(mode&TODAYS_DATE) {		/* put today's date in desc */
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
			time_t now = time(NULL);
			if(datefmt) {
				struct tm tm = {0};
				localtime_r(&now, &tm);
				strftime(f.desc, sizeof(f.desc), datefmt, &tm);
			} else
				unixtodstr(&scfg, (time32_t)now, f.desc);
			SAFECAT(f.desc,"  ");
		}
		else if(mode&FILE_DATE) {		/* get the file date and put into desc */
			if(datefmt) {
				struct tm tm = {0};
				localtime_r(&file_timestamp, &tm);
				strftime(f.desc, sizeof(f.desc), datefmt, &tm);
			} else
				unixtodstr(&scfg,(time32_t)file_timestamp,f.desc);
			SAFECAT(f.desc,"  ");
479
		}
480
481
482

		if(dskip && strlen(curline)>=dskip) p=curline+dskip;
		else {
483
484
			p = curline;
			FIND_WHITESPACE(p);
485
			SKIP_WHITESPACE(p);
486
		}
487
488
489
		SAFECOPY(tmp,p);
		prep_desc(tmp);
		sprintf(f.desc+strlen(f.desc),"%.*s",(int)(LEN_FDESC-strlen(f.desc)),tmp);
490

491
		if(nextline[0]==' ' || strlen(p)>LEN_FDESC) {	/* ext desc */
492
			if(!(mode&NO_EXTEND)) {
493
				memset(ext, 0, sizeof(ext));
494
				f.misc|=FM_EXTDESC;
495
				sprintf(ext,"%s\r\n",p);
496
			}
497

498
			if(nextline[0]==' ') {
499
				SAFECOPY(str,nextline);				   /* tack on to end of desc */
500
				p=str+dskip;
501
				while(*p>0 && *p<=' ') p++;
502
503
504
505
506
				i=LEN_FDESC-strlen(f.desc);
				if(i>1) {
					p[i-1]=0;
					truncsp(p);
					if(p[0]) {
507
508
						SAFECAT(f.desc," ");
						SAFECAT(f.desc,p);
509
510
					}
				}
511
			}
512
513

			while(!feof(stream) && !ferror(stream) && strlen(ext)<512) {
514
				if(nextline[0]!=' ')
515
516
517
518
519
520
					break;
				truncsp(nextline);
				printf("%s\n",nextline);
				if(!(mode&NO_EXTEND)) {
					f.misc|=FM_EXTDESC;
					p=nextline+dskip;
521
					while(*p==' ') p++;
522
523
					SAFECAT(ext,p);
					SAFECAT(ext,"\r\n");
524
				}
525
				nextline[0]=0;
526
527
				fgets(nextline,255,stream);
			}
528
		}
529
530


531
532
533
534
		l=flength(filepath);
		if(l<0L) {
			printf("%s not found.\n",filepath);
			continue;
535
		}
536
537
538
539
540
		if(l == 0L) {
			printf("%s is a zero length file.\n",filepath);
			continue;
		}
		if(sskip) l=atol(fname+sskip);
541

542
		if(mode&FILE_ID)
543
			get_file_diz(&f, filepath, ext);
544
545

		f.cdt=l;
546
		f.dateuled=time32(NULL);
547
		f.altpath=cur_altpath;
548
		prep_desc(f.desc);
549
		if(mode&ASCII_ONLY)
550
			strip_exascii(f.desc, f.desc);
551
552
553
		if(exist) {
			putfiledat(&scfg,&f);
			if(!(mode&NO_NEWDATE))
554
				update_uldate(&scfg, &f);
555
		}
556
557
558
559
		else
			addfiledat(&scfg,&f);
		if(f.misc&FM_EXTDESC) {
			truncsp(ext);
560
			putextdesc(&scfg,f.dir,f.datoffset,ext);
561
		}
562
563
564

		if(mode&UL_STATS)
			updatestats(l);
565
		files++;
566
	} while(!feof(stream) && !ferror(stream));
567
568
569
	fclose(stream);
	if(mode&DEL_LIST && !(mode&SYNC_LIST)) {
		printf("\nDeleting %s\n",listpath);
570
		remove(listpath);
571
	}
572
573
574
575
576

}

void synclist(char *inpath, int dirnum)
{
577
	char	str[1024];
578
579
580
	char	fname[MAX_PATH+1];
	char	listpath[MAX_PATH+1];
	uchar*	ixbbuf;
581
	char*	p;
582
583
584
585
	int		i,file,found;
	long	l,m,length;
	FILE*	stream;
	file_t	f;
586

587
	sprintf(str,"%s%s.ixb",scfg.dir[dirnum]->data_dir,scfg.dir[dirnum]->code);
588
	if((file=nopen(str,O_RDONLY|O_BINARY))==-1) {
589
		printf("ERR_OPEN %s\n",str);
590
		return;
591
	}
592
593
594
	length=filelength(file);
	if(length%F_IXBSIZE) {
		close(file);
rswindell's avatar
rswindell committed
595
		printf("ERR_LEN (%ld) of %s\n",length,str);
596
		return;
597
	}
deuce's avatar
deuce committed
598
	if((ixbbuf=(uchar *)malloc(length))==NULL) {
599
600
		close(file);
		printf("ERR_ALLOC %s\n",str);
601
		return;
602
	}
603
604
	if(lread(file,ixbbuf,length)!=length) {
		close(file);
deuce's avatar
deuce committed
605
		free((char *)ixbbuf);
606
		printf("ERR_READ %s\n",str);
607
		return;
608
	}
609
610
	close(file);

611
	SAFECOPY(listpath,inpath);
612
	if((stream=fopen(listpath,"r"))==NULL) {
613
614
		sprintf(listpath,"%s%s",cur_altpath ? scfg.altpath[cur_altpath-1]
				: scfg.dir[dirnum]->path,inpath);
615
		if((stream=fopen(listpath,"r"))==NULL) {
616
617
			printf("Can't open: %s\n"
				   "        or: %s\n",inpath,listpath);
618
619
			return;
		}
620
	}
621
622
623
624
625
626
627
628

	printf("\nSynchronizing %s with %s %s\n\n"
		,listpath,scfg.lib[scfg.dir[dirnum]->lib]->sname,scfg.dir[dirnum]->sname);

	for(l=0;l<length;l+=F_IXBSIZE) {
		m=l;
		for(i=0;i<12 && l<length;i++)
			if(i==8)
629
				str[i]=ixbbuf[m]>' ' ? '.' : ' ';
630
631
632
633
634
635
636
637
638
639
			else
				str[i]=ixbbuf[m++]; 	/* Turns FILENAMEEXT into FILENAME.EXT */
		str[i]=0;
		unpadfname(str,fname);
		rewind(stream);
		found=0;
		while(!found) {
			if(!fgets(str,1000,stream))
				break;
			truncsp(str);
640
			p=strchr(str,' ');
641
642
			if(p) *p=0;
			if(!stricmp(str,fname))
643
				found=1;
644
		}
645
646
647
648
649
650
		if(found)
			continue;
		padfname(fname,f.name);
		printf("%s not found in list - ",f.name);
		f.dir=dirnum;
		f.datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
651
652
653
654
		if(!getfiledat(&scfg,&f)) {
			fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
			continue;
		}
655
656
		if(f.opencount) {
			printf("currently OPEN by %u users\n",f.opencount);
657
			continue;
658
		}
659
		removefiledat(&scfg,&f);
660
		if(remove(getfilepath(&scfg,&f,str)))
661
662
			printf("Error removing %s\n",str);
		removed++;
663
		printf("Removed from database\n");
664
	}
665
666
667

	if(mode&DEL_LIST) {
		printf("\nDeleting %s\n",listpath);
668
		remove(listpath);
669
	}
670
671
}

672
char *usage="\nusage: addfiles code [.alt_path] [-opts] +list "
673
			 "[desc_off] [size_off]"
674
	"\n   or: addfiles code [.alt_path] [-opts] file "
675
676
		"\"description\"\n"
	"\navailable opts:"
677
678
679
680
681
682
	"\n      -a         import ASCII only (no extended ASCII)"
	"\n      -b         synchronize database with file list (use with caution)"
	"\n      -c         do not remove extra spaces from file description"
	"\n      -d         delete list after import"
	"\n      -e         do not import extended descriptions"
	"\n      -f         include file date in descriptions"
683
	"\n      -F <fmt>   include file date in descriptions, using strftime format"
684
685
686
687
	"\n      -t         include today's date in descriptions"
	"\n      -i         include added files in upload statistics"
	"\n      -n         do not update information for existing files"
	"\n      -o         update upload date only for existing files"
rswindell's avatar
rswindell committed
688
	"\n      -p         compare file date with upload date for existing files"
689
690
691
692
693
694
	"\n      -u         do not update upload date for existing files"
	"\n      -z         check for and import FILE_ID.DIZ and DESC.SDI"
	"\n      -k         keep original short description (not DIZ)"
	"\n      -s         search directory for files (no file list)"
	"\n      -l <lib>   specify library (short name) to Auto-ADD"
	"\n      -x <name>  specify uploader's user name (may require quotes)"
695
	"\n"
696
697
	"\nAuto-ADD:   use - in place of code for Auto-ADD of FILES.BBS"
	"\n            use -filename to Auto-ADD a different filename"
698
	"\n            use -l \"libname\" to only Auto-ADD files to a specific library"
699
700
701
702
703
704
705
706
	;

/*********************/
/* Entry point (duh) */
/*********************/
int main(int argc, char **argv)
{
	char error[512];
707
	char revision[16];
708
709
	char str[MAX_PATH+1];
	char tmp[MAX_PATH+1];
710
711
	char *p;
	char exist,listgiven=0,namegiven=0,ext[513]
712
		,auto_name[MAX_PATH+1]="FILES.BBS";
713
	int i,j;
714
	uint desc_offset=0, size_offset=0;
715
716
717
	long l;
	file_t	f;

Rob Swindell's avatar
Rob Swindell committed
718
	sscanf("$Revision: 1.63 $", "%*s %s", revision);
719

720
	fprintf(stderr,"\nADDFILES v%s-%s (rev %s) - Adds Files to Synchronet "
721
722
723
		"Filebase\n"
		,ADDFILES_VER
		,PLATFORM_DESC
724
		,revision
725
726
727
		);

	if(argc<2) {
728
		puts(usage);
729
		return(1);
730
	}
731

732
	p = get_ctrl_dir(/* warn: */true);
733

734
735
	memset(&scfg,0,sizeof(scfg));
	scfg.size=sizeof(scfg);
736
	SAFECOPY(scfg.ctrl_dir,p);
737
738
739
740
741

	if(chdir(scfg.ctrl_dir)!=0)
		fprintf(stderr,"!ERROR changing directory to: %s", scfg.ctrl_dir);

	printf("\nLoading configuration files from %s\n",scfg.ctrl_dir);
742
743
744
745
	if(!load_cfg(&scfg,NULL,TRUE,error)) {
		fprintf(stderr,"!ERROR loading configuration files: %s\n",error);
		exit(1);
	}
rswindell's avatar
rswindell committed
746
747
	SAFECOPY(scfg.temp_dir,"../temp");
	prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
748

749
750
	if(argv[1][0]=='*' || argv[1][0]=='-') {
		if(argv[1][1]=='?') {
751
			puts(usage);
752
753
			exit(0);
		}
754
		if(argv[1][1])
755
			SAFECOPY(auto_name,argv[1]+1);
756
		mode|=AUTO_ADD;
757
		i=0;
758
	} else {
759
		if(!isalnum((uchar)argv[1][0]) && argc==2) {
760
			puts(usage);
761
			return(1);
762
763
		}

764
		for(i=0;i<scfg.total_dirs;i++)
765
			if(!stricmp(scfg.dir[i]->code,argv[1])) /* use matchmatchi() instead? */
766
767
768
769
				break;

		if(i>=scfg.total_dirs) {
			printf("Directory code '%s' not found.\n",argv[1]);
770
771
			exit(1);
		}
772
	}
773
774
775

	memset(&f,0,sizeof(file_t));
	f.dir=i;
776
	SAFECOPY(f.uler,"-> ADDFILES <-");
777
778

	for(j=2;j<argc;j++) {
779
780
		if(argv[j][0]=='*')     /* set the uploader name (legacy) */
			SAFECOPY(f.uler,argv[j]+1);
781
		else
782
783
784
			if(argv[j][0]=='-'
			|| argv[j][0]=='/'
			) {      /* options */
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
			for(i=1;argv[j][i];i++)
				switch(toupper(argv[j][i])) {
					case 'A':
						mode|=ASCII_ONLY;
						break;
					case 'B':
						mode|=(SYNC_LIST|NO_UPDATE);
						break;
					case 'C':
						mode|=KEEP_SPACE;
						break;
					case 'D':
						mode|=DEL_LIST;
						break;
					case 'E':
						mode|=NO_EXTEND;
						break;
					case 'I':
						mode|=UL_STATS;
						break;
805
806
807
					case 'L':
						j++;
						if(argv[j]==NULL) {
808
							puts(usage);
809
810
811
812
813
							return(-1);
						}
						SAFECOPY(lib,argv[j]);
						i=strlen(argv[j])-1;
						break;
814
815
816
					case 'X':
						j++;
						if(argv[j]==NULL) {
817
							puts(usage);
818
819
820
821
822
							return(-1);
						}
						SAFECOPY(f.uler,argv[j]);
						i=strlen(argv[j])-1;
						break;
823
824
825
826
827
828
829
830
831
832
833
834
					case 'Z':
						mode|=FILE_ID;
						break;
					case 'K':
						mode|=KEEP_DESC;	 /* Don't use DIZ for short desc */
						break;
					case 'N':
						mode|=NO_UPDATE;
						break;
					case 'O':
						mode|=ULDATE_ONLY;
						break;
rswindell's avatar
rswindell committed
835
836
837
					case 'P':
						mode|=CHECK_DATE;
						break;
838
839
840
841
842
					case 'U':
						mode|=NO_NEWDATE;
						break;
					case 'F':
						mode|=FILE_DATE;
843
844
845
846
847
848
849
850
851
852
						if(argv[j][i] == 'F') {
							j++;
							if(argv[j]==NULL) {
								puts(usage);
								return(-1);
							}
							datefmt = argv[j];
							i=strlen(argv[j]) - 1;
							break;
						}
853
854
855
856
857
858
859
860
						break;
					case 'T':
						mode|=TODAYS_DATE;
						break;
					case 'S':
						mode|=SEARCH_DIR;
						break;
					default:
861
						puts(usage);
862
863
						return(1);
			}
864
		}
865
		else if(isdigit((uchar)argv[j][0])) {
866
867
868
869
870
871
			if(desc_offset==0)
				desc_offset=atoi(argv[j]);
			else
				size_offset=atoi(argv[j]);
			continue;
		}
872
873
		else if(argv[j][0]=='+') {      /* filelist - FILES.BBS */
			listgiven=1;
rswindell's avatar
rswindell committed
874
			if(argc > j+1
875
				&& isdigit((uchar)argv[j+1][0])) { /* skip x characters before description */
rswindell's avatar
rswindell committed
876
				if(argc > j+2
877
					&& isdigit((uchar)argv[j+2][0])) { /* skip x characters before size */
878
					addlist(argv[j]+1,f,atoi(argv[j+1]),atoi(argv[j+2]));
879
					j+=2;
880
				}
881
882
				else {
					addlist(argv[j]+1,f,atoi(argv[j+1]),0);
883
884
					j++;
				}
885
			}
886
887
888
			else
				addlist(argv[j]+1,f,0,0);
			if(mode&SYNC_LIST)
889
				synclist(argv[j]+1,f.dir);
890
		}
891
892
893
894
		else if(argv[j][0]=='.') {      /* alternate file path */
			cur_altpath=atoi(argv[j]+1);
			if(cur_altpath>scfg.altpaths) {
				printf("Invalid alternate path.\n");
895
896
				exit(1);
			}
897
		}
898
899
900
901
		else {
			namegiven=1;
			padfname(argv[j],f.name);
			f.desc[0]=0;
902
			memset(ext, 0, sizeof(ext));
903
#if 0
904
			strupr(f.name);
905
#endif
906
907
			if(j+1==argc) {
				printf("%s no description given.\n",f.name);
908
				continue;
909
			}
910
911
			sprintf(str,"%s%s",cur_altpath ? scfg.altpath[cur_altpath-1]
				: scfg.dir[f.dir]->path,argv[j]);
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
			if(mode&TODAYS_DATE) {
				time_t now = time(NULL);
				if(datefmt) {
					struct tm tm = {0};
					localtime_r(&now, &tm);
					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
				} else
					SAFECOPY(f.desc, unixtodstr(&scfg, (time32_t)now, tmp));
				SAFECAT(f.desc, "  ");
			}
			else if(mode&FILE_DATE) {
				time_t file_timestamp = fdate(str);
				if(datefmt) {
					struct tm tm = {0};
					localtime_r(&file_timestamp, &tm);
					strftime(f.desc, sizeof(f.desc), datefmt, &tm);
				} else
					SAFECOPY(f.desc, unixtodstr(&scfg,(time32_t)file_timestamp,tmp));
				SAFECAT(f.desc, "  ");
			}
			j++;
			SAFECAT(f.desc, argv[j]);
934
935
936
			l=flength(str);
			if(l==-1) {
				printf("%s not found.\n",str);
937
				continue;
938
			}
939
940
941
942
			exist=findfile(&scfg,f.dir,f.name);
			if(exist) {
				if(mode&NO_UPDATE)
					continue;
943
944
945
946
947
948
				if(!getfileixb(&scfg,&f)) {
					fprintf(stderr, "!ERROR reading index of directory %u\n", f.dir);
					continue;
				}
				if((mode&CHECK_DATE) && fdate(str) <= f.dateuled)
					continue;
949
				if(mode&ULDATE_ONLY) {
950
					f.dateuled=time32(NULL);
951
					update_uldate(&scfg, &f);
952
953
					continue;
				}
954
955
				if (f.misc & FM_EXTDESC)
					getextdesc(&scfg, f.dir, f.datoffset, ext);
956
			}
957
			f.cdt=l;
958
			f.dateuled=time32(NULL);
959
			f.altpath=cur_altpath;
960
			prep_desc(f.desc);
961
			if(mode&ASCII_ONLY)
962
				strip_exascii(f.desc, f.desc);
deuce's avatar
deuce committed
963
			printf("%s %7"PRIu32" %s\n",f.name,f.cdt,f.desc);
964
			if(mode&FILE_ID)
965
				get_file_diz(&f, str, ext);
966

967
968
969
			if(exist) {
				putfiledat(&scfg,&f);
				if(!(mode&NO_NEWDATE))
970
					update_uldate(&scfg, &f);