js_file.c 29.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
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
37
38
/* js_file.c */

/* Synchronet JavaScript "File" Object */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright 2001 Rob Swindell - http://www.synchro.net/copyright.html		*
 *																			*
 * 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"
39
40
#include "md5.h"
#include "base64.h"
41
#include "uucode.h"
42
43
44
45
46

#ifdef JAVASCRIPT

typedef struct
{
47
	FILE*	fp;
48
49
	char	name[MAX_PATH+1];
	char	mode[4];
50
	uchar	etx;
51
52
	BOOL	external;	/* externally created, don't close */
	BOOL	debug;
53
	BOOL	rot13;
54
	BOOL	uuencoded;
55
56
	BOOL	b64encoded;
	BOOL	network_byte_order;
57
58
59

} private_t;

60
static const char* getprivate_failure = "line %d %s JS_GetPrivate failed";
61
62
63
64
65
66
67
68
69
70

static void dbprintf(BOOL error, private_t* p, char* fmt, ...)
{
	va_list argptr;
	char sbuf[1024];

	if(p==NULL || (!p->debug && !error))
		return;

    va_start(argptr,fmt);
71
72
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
73
74
    va_end(argptr);
	
75
	lprintf("%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
76
77
}

78
79
80
81
82
83
84
85
/* Converts fopen() style 'mode' string into open() style 'flags' integer */

static int fopenflags(char *mode)
{
	int flags=0;

	if(strchr(mode,'b'))
		flags|=O_BINARY;
86
87
	else
		flags|=O_TEXT;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

	if(strchr(mode,'w')) {
		flags|=O_CREAT|O_TRUNC;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'a')) {
		flags|=O_CREAT|O_APPEND;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'r')) {
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_RDONLY;
	}

	return(flags);
}
116
117
118
119
120
121
122

/* File Object Methods */

static JSBool
js_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		mode="w+";	/* default mode */
123
124
	BOOL		shareable=FALSE;
	int			file;
125
	uintN		i;
126
	jsint		bufsize=2*1024;
127
128
129
	JSString*	str;
	private_t*	p;

130
	*rval = JSVAL_FALSE;
131

132
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
133
		JS_ReportError(cx,getprivate_failure,WHERE);
134
		return(JS_FALSE);
135
	}
136
137
138

	if(p->fp!=NULL)  
		return(JS_TRUE);
139
140
141
142

	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
143
144
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
145
146
			}
			mode=JS_GetStringBytes(str);
147
148
149
		} else if(JSVAL_IS_BOOLEAN(argv[i]))	/* shareable */
			shareable=JSVAL_TO_BOOLEAN(argv[i]);
		else	/* bufsize */
150
			JS_ValueToInt32(cx,argv[i],&bufsize);
151
	}
152
	SAFECOPY(p->mode,mode);
153

154
155
156
157
158
159
160
161
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
			if((p->fp=fdopen(file,p->mode))==NULL)
				close(file);
		}
	}
162
	if(p->fp!=NULL) {
163
		*rval = JSVAL_TRUE;
164
		dbprintf(FALSE, p, "opened: %s",p->name);
165
166
167
168
169
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
170
171
172
173
174
175
176
177
178
179

	return(JS_TRUE);
}


static JSBool
js_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

180
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
181
		JS_ReportError(cx,getprivate_failure,WHERE);
182
		return(JS_FALSE);
183
	}
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

	*rval = JSVAL_VOID;

	if(p->fp==NULL)
		return(JS_TRUE);

	fclose(p->fp);

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 

	return(JS_TRUE);
}

static JSBool
200
js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
201
202
{
	char*		cp;
203
	char*		buf;
204
	char*		uubuf;
205
206
	int32		len;
	int32		offset;
207
	int32		uulen;
208
209
210
	JSString*	str;
	private_t*	p;

211
212
	*rval = JSVAL_NULL;

213
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
214
		JS_ReportError(cx,getprivate_failure,WHERE);
215
		return(JS_FALSE);
216
	}
217

218
219
	if(p->fp==NULL)
		return(JS_TRUE);
220

221
	if(argc)
222
		JS_ValueToInt32(cx,argv[0],&len);
223
224
225
226
227
228
229
230
	else {
		len=filelength(fileno(p->fp));
		offset=ftell(p->fp);
		if(offset>0)
			len-=offset;
	}
	if(len<0)
		len=512;
231

232
233
234
235
236
237
238
239
240
241
242
243
244
	if((buf=malloc(len+1))==NULL)
		return(JS_TRUE);

	len = fread(buf,1,len,p->fp);
	if(len<0) 
		len=0;
	buf[len]=0;

	if(p->etx) {
		cp=strchr(buf,p->etx);
		if(cp) *cp=0; 
	}

245
246
247
	if(p->rot13)
		rot13(buf);

248
	if(p->uuencoded || p->b64encoded) {
249
250
251
		uulen=len*2;
		if((uubuf=malloc(uulen))==NULL)
			return(JS_TRUE);
252
253
254
255
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
256
257
258
259
260
261
262
		if(uulen>=0) {
			free(buf);
			buf=uubuf;
		} else
			free(uubuf);
	}

263
264
265
266
	str = JS_NewStringCopyZ(cx, buf);

	free(buf);

267
268
269
	if(str==NULL)
		return(JS_FALSE);

270
271
272
	*rval = STRING_TO_JSVAL(str);

	dbprintf(FALSE, p, "read %u bytes",len);
273
274
275
276
277
		
	return(JS_TRUE);
}

static JSBool
278
js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
279
{
280
281
	char*		cp;
	char*		buf;
282
	int32		len=512;
283
	JSString*	js_str;
284
285
	private_t*	p;

286
	*rval = JSVAL_NULL;
287

288
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
289
		JS_ReportError(cx,getprivate_failure,WHERE);
290
		return(JS_FALSE);
291
	}
292
293
294

	if(p->fp==NULL)
		return(JS_TRUE);
295
296
	
	if(argc)
297
		JS_ValueToInt32(cx,argv[0],&len);
298

299
300
301
302
	if((buf=malloc(len))==NULL)
		return(JS_TRUE);

	if(fgets(buf,len,p->fp)!=NULL) {
303
304
305
306
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
307
308
309
310
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
311
312
		if(p->rot13)
			rot13(buf);
313
314
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)
			*rval = STRING_TO_JSVAL(js_str);
315
316
	}

317
318
	free(buf);

319
320
321
322
	return(JS_TRUE);
}

static JSBool
323
js_readbin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
324
325
326
327
328
329
330
{
	BYTE		b;
	WORD		w;
	DWORD		l;
	size_t		size=sizeof(DWORD);
	private_t*	p;

331
	*rval = INT_TO_JSVAL(-1);
332

333
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
334
		JS_ReportError(cx,getprivate_failure,WHERE);
335
		return(JS_FALSE);
336
	}
337
338
339
340

	if(p->fp==NULL)
		return(JS_TRUE);

341
	if(argc) 
342
		JS_ValueToInt32(cx,argv[0],(int32*)&size);
343
344
345

	switch(size) {
		case sizeof(BYTE):
346
347
			if(fread(&b,1,size,p->fp)==size)
				*rval = INT_TO_JSVAL(b);
348
349
			break;
		case sizeof(WORD):
350
351
352
			if(fread(&w,1,size,p->fp)==size) {
				if(p->network_byte_order)
					w=ntohs(w);
353
				*rval = INT_TO_JSVAL(w);
354
			}
355
356
			break;
		case sizeof(DWORD):
357
358
359
			if(fread(&l,1,size,p->fp)==size) {
				if(p->network_byte_order)
					l=ntohl(l);
360
				JS_NewNumberValue(cx,l,rval);
361
			}
362
363
364
365
366
367
368
			break;
	}
		
	return(JS_TRUE);
}

static JSBool
369
js_readall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
370
{
371
372
373
    jsint       len=0;
    jsval       line;
    JSObject*	array;
374
375
	private_t*	p;

376
377
	*rval = JSVAL_NULL;

378
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
379
		JS_ReportError(cx,getprivate_failure,WHERE);
380
		return(JS_FALSE);
381
	}
382

383
384
	if(p->fp==NULL)
		return(JS_TRUE);
385

386
    array = JS_NewArrayObject(cx, 0, NULL);
387

388
389
390
391
    while(!feof(p->fp)) {
		js_readln(cx, obj, 0, NULL, &line); 
		if(line==JSVAL_NULL)
			break;
392
393
        if(!JS_SetElement(cx, array, len++, &line))
			break;
394
	}
395
    *rval = OBJECT_TO_JSVAL(array);
396

397
398
    return(JS_TRUE);
}
399

400
401
402
403
static JSBool
js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		cp;
404
405
406
	char*		uubuf=NULL;
	int			len;	/* string length */
	int			tlen;	/* total length to write (may be greater than len) */
407
	private_t*	p;
408

409
	*rval = JSVAL_FALSE;
410

411
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
412
		JS_ReportError(cx,getprivate_failure,WHERE);
413
		return(JS_FALSE);
414
	}
415
416
417
418

	if(p->fp==NULL)
		return(JS_TRUE);

419
420
421
	cp=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
	len=strlen(cp);

422
423
424
425
426
427
	if((p->uuencoded || p->b64encoded)
		&& len && (uubuf=malloc(len))!=NULL) {
		if(p->uuencoded)
			len=uudecode(uubuf,len,cp,len);
		else
			len=b64_decode(uubuf,len,cp,len);
428
429
430
431
432
433
434
		if(len<0) {
			free(uubuf);
			return(JS_TRUE);
		}
		cp=uubuf;
	}

435
436
437
	if(p->rot13)
		rot13(cp);

438
	tlen=len;
439
	if(argc>1) {
440
		JS_ValueToInt32(cx,argv[1],(int32*)&tlen);
441
442
443
		if(len>tlen)
			len=tlen;
	}
444
445

	if(fwrite(cp,1,len,p->fp)==(size_t)len) {
446
447
448
449
450
451
452
453
454
455
456
		if(tlen>len) {
			len=tlen-len;
			if((cp=malloc(len))==NULL) {
				dbprintf(TRUE, p, "malloc failure of %u bytes", len);
				return(JS_TRUE);
			}
			memset(cp,p->etx,len);
			fwrite(cp,1,len,p->fp);
			free(cp);
		}
		dbprintf(FALSE, p, "wrote %u bytes",tlen);
457
		*rval = JSVAL_TRUE;
458
459
	} else 
		dbprintf(TRUE, p, "write of %u bytes failed",len);
460
		
461
462
463
	if(uubuf!=NULL)
		free(uubuf);

464
465
466
467
	return(JS_TRUE);
}

static JSBool
468
js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
469
{
470
471
472
473
	char*		cp="";
	JSString*	str;
	private_t*	p;

474
	*rval = JSVAL_FALSE;
475

476
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
477
		JS_ReportError(cx,getprivate_failure,WHERE);
478
		return(JS_FALSE);
479
	}
480
481
482
483
484

	if(p->fp==NULL)
		return(JS_TRUE);

	if(argc) {
485
486
		if((str = JS_ValueToString(cx, argv[0]))==NULL) {
			JS_ReportError(cx,"JS_ValueToString failed");
487
			return(JS_FALSE);
488
		}
489
490
491
		cp = JS_GetStringBytes(str);
	}

492
493
494
	if(p->rot13)
		rot13(cp);

495
	if(fprintf(p->fp,"%s\n",cp)!=0)
496
		*rval = JSVAL_TRUE;
497

498
499
	return(JS_TRUE);
}
500

501
static JSBool
502
js_writebin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
503
{
504
505
506
	BYTE		b;
	WORD		w;
	DWORD		l;
507
	int32		val=0;
508
	size_t		wr=0;
509
	size_t		size=sizeof(DWORD);
510
511
	private_t*	p;

512
	*rval = JSVAL_FALSE;
513

514
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
515
		JS_ReportError(cx,getprivate_failure,WHERE);
516
		return(JS_FALSE);
517
	}
518

519
520
	if(p->fp==NULL)
		return(JS_TRUE);
521

522
	JS_ValueToInt32(cx,argv[0],&val);
523
	if(argc>1) 
524
		JS_ValueToInt32(cx,argv[1],(int32*)&size);
525

526
527
	switch(size) {
		case sizeof(BYTE):
528
			b = (BYTE)val;
529
			wr=fwrite(&b,1,size,p->fp);
530
531
			break;
		case sizeof(WORD):
532
			w = (WORD)val;
533
534
			if(p->network_byte_order)
				w=htons(w);
535
			wr=fwrite(&w,1,size,p->fp);
536
537
			break;
		case sizeof(DWORD):
538
			l = val;
539
540
			if(p->network_byte_order)
				l=htonl(l);
541
542
543
544
545
			wr=fwrite(&l,1,size,p->fp);
			break;
		default:	
			/* unknown size */
			dbprintf(TRUE, p, "unsupported binary write size: %d",size);
546
547
			break;
	}
548
	if(wr==size)
549
		*rval = JSVAL_TRUE;
550
		
551
552
553
	return(JS_TRUE);
}

554
555
556
557
558
559
560
561
562
static JSBool
js_writeall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    jsuint      i;
    jsuint      limit;
    JSObject*	array;
    jsval       elemval;
	private_t*	p;

563
	*rval = JSVAL_FALSE;
564

565
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
566
		JS_ReportError(cx,getprivate_failure,WHERE);
567
		return(JS_FALSE);
568
	}
569
570
571
572

	if(p->fp==NULL)
		return(JS_TRUE);

573
	if(!JSVAL_IS_OBJECT(argv[0]))
574
575
576
577
		return(JS_TRUE);

    array = JSVAL_TO_OBJECT(argv[0]);

578
579
580
    if(!JS_IsArrayObject(cx, array))
		return(JS_TRUE);

581
582
    if(!JS_GetArrayLength(cx, array, &limit))
		return(JS_FALSE);
583

584
    *rval = JSVAL_TRUE;
585

586
587
588
589
    for(i=0;i<limit;i++) {
        if(!JS_GetElement(cx, array, i, &elemval))
			break;
        js_writeln(cx, obj, 1, &elemval, rval);
590
		if(*rval!=JSVAL_TRUE)
591
			break;
592
593
594
595
596
    }

    return(JS_TRUE);
}

597
static JSBool
598
js_lock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
599
{
600
601
	int32		offset=0;
	int32		len=0;
602
603
	private_t*	p;

604
	*rval = JSVAL_FALSE;
605

606
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
607
		JS_ReportError(cx,getprivate_failure,WHERE);
608
		return(JS_FALSE);
609
	}
610
611
612
613

	if(p->fp==NULL)
		return(JS_TRUE);

614
615
616
617
618
619
620
621
622
623
624
625
	/* offset */
	if(argc)
		JS_ValueToInt32(cx,argv[0],&offset);

	/* length */
	if(argc>1)
		JS_ValueToInt32(cx,argv[1],&len);

	if(len==0)
		len=filelength(fileno(p->fp))-offset;

	if(lock(fileno(p->fp),offset,len)==0)
626
		*rval = JSVAL_TRUE;
627

628
629
	return(JS_TRUE);
}
630

631
static JSBool
632
js_unlock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
633
{
634
635
	int32		offset=0;
	int32		len=0;
636
637
	private_t*	p;

638
	*rval = JSVAL_FALSE;
639

640
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
641
		JS_ReportError(cx,getprivate_failure,WHERE);
642
		return(JS_FALSE);
643
	}
644
645
646
647

	if(p->fp==NULL)
		return(JS_TRUE);

648
649
650
651
652
653
654
655
656
657
658
	/* offset */
	if(argc)
		JS_ValueToInt32(cx,argv[0],&offset);

	/* length */
	if(argc>1)
		JS_ValueToInt32(cx,argv[1],&len);

	if(len==0)
		len=filelength(fileno(p->fp))-offset;

659
	if(unlock(fileno(p->fp),offset,len)==0)
660
		*rval = JSVAL_TRUE;
661

662
663
664
	return(JS_TRUE);
}

665
666
667
668
669
static JSBool
js_delete(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

670
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
671
		JS_ReportError(cx,getprivate_failure,WHERE);
672
		return(JS_FALSE);
673
	}
674
675
676
677
678
679
680
681
682
683

	if(p->fp!=NULL) {	/* close it if it's open */
		fclose(p->fp);
		p->fp=NULL;
	}

	*rval = BOOLEAN_TO_JSVAL(remove(p->name)==0);

	return(JS_TRUE);
}
684
685
686
687
688
689

static JSBool
js_flush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

690
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
691
		JS_ReportError(cx,getprivate_failure,WHERE);
692
		return(JS_FALSE);
693
	}
694
695

	if(p->fp==NULL)
696
		*rval = JSVAL_FALSE;
697
698
699
700
701
702
703
704
705
706
707
	else 
		*rval = BOOLEAN_TO_JSVAL(fflush(p->fp)==0);

	return(JS_TRUE);
}

static JSBool
js_clear_error(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

708
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
709
		JS_ReportError(cx,getprivate_failure,WHERE);
710
		return(JS_FALSE);
711
	}
712
713

	if(p->fp==NULL)
714
		*rval = JSVAL_FALSE;
715
716
	else  {
		clearerr(p->fp);
717
		*rval = JSVAL_TRUE;
718
719
720
721
722
	}

	return(JS_TRUE);
}

723
724
725
726
727
728
729
730
731
732
static JSBool
js_fprintf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		cp;
    uintN		i;
	JSString *	fmt;
    JSString *	str;
	va_list		arglist[64];
	private_t*	p;

733
	*rval = JSVAL_FALSE;
734

735
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
736
		JS_ReportError(cx,getprivate_failure,WHERE);
737
		return(JS_FALSE);
738
	}
739
740
741
742

	if(p->fp==NULL)
		return(JS_TRUE);

743
744
	if((fmt=JS_ValueToString(cx, argv[0]))==NULL) {
		JS_ReportError(cx,"JS_ValueToString failed");
745
		return(JS_FALSE);
746
	}
747
748
749
750
751

	memset(arglist,0,sizeof(arglist));	/* Initialize arglist to NULLs */

    for (i = 1; i < argc && i<sizeof(arglist)/sizeof(arglist[0]); i++) {
		if(JSVAL_IS_STRING(argv[i])) {
752
753
			if((str=JS_ValueToString(cx, argv[i]))==NULL) {
				JS_ReportError(cx,"JS_ValueToString failed");
754
			    return(JS_FALSE);
755
			}
756
757
758
759
760
761
762
763
764
765
			arglist[i-1]=JS_GetStringBytes(str);	/* exception here July-29-2002 */
		}
		else if(JSVAL_IS_DOUBLE(argv[i]))
			arglist[i-1]=(char*)(unsigned long)*JSVAL_TO_DOUBLE(argv[i]);
		else if(JSVAL_IS_INT(argv[i]) || JSVAL_IS_BOOLEAN(argv[i]))
			arglist[i-1]=(char *)JSVAL_TO_INT(argv[i]);
		else
			arglist[i-1]=NULL;
	}

766
767
	if((cp=JS_vsmprintf(JS_GetStringBytes(fmt),(char*)arglist))==NULL) {
		JS_ReportError(cx,"JS_vsmprintf failed");
768
		return(JS_FALSE);
769
	}
770
771
772
773
774
775
776

	*rval = INT_TO_JSVAL(fwrite(cp,1,strlen(cp),p->fp));
	JS_smprintf_free(cp);
	
    return(JS_TRUE);
}

777
778
779
780

/* File Object Properites */
enum {
	 FILE_PROP_NAME		
781
782
	,FILE_PROP_MODE
	,FILE_PROP_ETX
783
784
785
786
787
788
789
790
791
792
	,FILE_PROP_EXISTS	
	,FILE_PROP_DATE		
	,FILE_PROP_IS_OPEN	
	,FILE_PROP_EOF		
	,FILE_PROP_ERROR	
	,FILE_PROP_DESCRIPTOR
	,FILE_PROP_DEBUG	
	,FILE_PROP_POSITION	
	,FILE_PROP_LENGTH	
	,FILE_PROP_ATTRIBUTES
793
	,FILE_PROP_UUENCODED
794
	,FILE_PROP_B64ENCODED
795
	,FILE_PROP_ROT13
796
	,FILE_PROP_NETWORK_ORDER
797
798
799
800
801
	/* dynamically calculated */
	,FILE_PROP_CHKSUM
	,FILE_PROP_CRC16
	,FILE_PROP_CRC32
	,FILE_PROP_MD5_HEX
802
	,FILE_PROP_MD5_B64
803
804
};

rswindell's avatar
rswindell committed
805

806
807
808
809
810
static JSBool js_file_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
    jsint       tiny;
	private_t*	p;

811
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
812
		JS_ReportError(cx,getprivate_failure,WHERE);
813
		return(JS_FALSE);
814
	}
815
816
817
818
819
820
821

    tiny = JSVAL_TO_INT(id);

	dbprintf(FALSE, p, "setting property %d",tiny);

	switch(tiny) {
		case FILE_PROP_DEBUG:
822
			JS_ValueToBoolean(cx,*vp,&(p->debug));
823
			break;
824
		case FILE_PROP_UUENCODED:
825
826
827
828
829
			JS_ValueToBoolean(cx,*vp,&(p->uuencoded));
			break;
		case FILE_PROP_B64ENCODED:
			JS_ValueToBoolean(cx,*vp,&(p->b64encoded));
			break;
830
831
832
		case FILE_PROP_ROT13:
			JS_ValueToBoolean(cx,*vp,&(p->rot13));
			break;
833
834
		case FILE_PROP_NETWORK_ORDER:
			JS_ValueToBoolean(cx,*vp,&(p->network_byte_order));
835
			break;
836
837
838
839
840
841
842
843
844
845
846
		case FILE_PROP_POSITION:
			if(p->fp!=NULL)
				fseek(p->fp,JSVAL_TO_INT(*vp),SEEK_SET);
			break;
		case FILE_PROP_LENGTH:
			if(p->fp!=NULL)
				chsize(fileno(p->fp),JSVAL_TO_INT(*vp));
			break;
		case FILE_PROP_ATTRIBUTES:
			CHMOD(p->name,JSVAL_TO_INT(*vp));
			break;
847
848
849
		case FILE_PROP_ETX:
			p->etx = (uchar)JSVAL_TO_INT(*vp);
			break;
850
851
852
853
854
855
856
	}

	return(JS_TRUE);
}

static JSBool js_file_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
857
858
859
860
861
862
	BYTE*		buf;
	long		l;
	long		len;
	long		offset;
	ulong		sum;
	BYTE		digest[MD5_DIGEST_SIZE];
863
    jsint       tiny;
864
	JSString*	js_str=NULL;
865
866
	private_t*	p;

867
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
868
		JS_ReportError(cx,getprivate_failure,WHERE);
869
		return(JS_FALSE);
870
	}
871
872
873
874
875
876
877
878
879

    tiny = JSVAL_TO_INT(id);

#if 0 /* just too much */
	dbprintf(FALSE, sock, "getting property %d",tiny);
#endif

	switch(tiny) {
		case FILE_PROP_NAME:
880
881
882
			if((js_str=JS_NewStringCopyZ(cx, p->name))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
883
884
			break;
		case FILE_PROP_MODE:
885
886
887
			if((js_str=JS_NewStringCopyZ(cx, p->mode))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
888
889
890
			break;
		case FILE_PROP_EXISTS:
			if(p->fp)	/* open? */
891
				*vp = JSVAL_TRUE;
892
893
894
895
			else
				*vp = BOOLEAN_TO_JSVAL(fexist(p->name));
			break;
		case FILE_PROP_DATE:
896
			JS_NewNumberValue(cx,fdate(p->name),vp);
897
898
899
900
901
			break;
		case FILE_PROP_IS_OPEN:
			*vp = BOOLEAN_TO_JSVAL(p->fp!=NULL);
			break;
		case FILE_PROP_EOF:
902
903
904
			if(p->fp)
				*vp = BOOLEAN_TO_JSVAL(feof(p->fp)!=0);
			else
905
				*vp = JSVAL_TRUE;
906
907
			break;
		case FILE_PROP_ERROR:
908
909
910
			if(p->fp)
				*vp = INT_TO_JSVAL(ferror(p->fp));
			else
911
				*vp = INT_TO_JSVAL(errno);
912
913
			break;
		case FILE_PROP_POSITION:
914
			if(p->fp)
915
				JS_NewNumberValue(cx,ftell(p->fp),vp);
916
917
			else
				*vp = INT_TO_JSVAL(-1);
918
919
920
			break;
		case FILE_PROP_LENGTH:
			if(p->fp)	/* open? */
921
				JS_NewNumberValue(cx,filelength(fileno(p->fp)),vp);
922
			else
923
				JS_NewNumberValue(cx,flength(p->name),vp);
924
925
			break;
		case FILE_PROP_ATTRIBUTES:
926
			JS_NewNumberValue(cx,getfattr(p->name),vp);
927
928
			break;
		case FILE_PROP_DEBUG:
929
930
931
932
			*vp = BOOLEAN_TO_JSVAL(p->debug);
			break;
		case FILE_PROP_UUENCODED:
			*vp = BOOLEAN_TO_JSVAL(p->uuencoded);
933
			break;
934
935
936
		case FILE_PROP_B64ENCODED:
			*vp = BOOLEAN_TO_JSVAL(p->b64encoded);
			break;
937
938
939
		case FILE_PROP_ROT13:
			*vp = BOOLEAN_TO_JSVAL(p->rot13);
			break;
940
941
942
		case FILE_PROP_NETWORK_ORDER:
			*vp = BOOLEAN_TO_JSVAL(p->network_byte_order);
			break;
943
		case FILE_PROP_DESCRIPTOR:
944
945
946
947
			if(p->fp)
				*vp = INT_TO_JSVAL(fileno(p->fp));
			else
				*vp = INT_TO_JSVAL(-1);
948
			break;
949
950
951
		case FILE_PROP_ETX:
			*vp = INT_TO_JSVAL(p->etx);
			break;
952
953
954
		case FILE_PROP_CHKSUM:
		case FILE_PROP_CRC16:
		case FILE_PROP_CRC32:
955
956
957
958
			*vp = JSVAL_ZERO;
			if(p->fp==NULL)
				break;
			/* fall-through */
959
		case FILE_PROP_MD5_HEX:
960
		case FILE_PROP_MD5_B64:
961
962
963
964
965
966
967
968
969
970
971
			*vp = JSVAL_VOID;
			if(p->fp==NULL)
				break;
			offset=ftell(p->fp);			/* save current file position */
			fseek(p->fp,0,SEEK_SET);
			len=filelength(fileno(p->fp));
			if(len<1)
				break;
			if((buf=malloc(len*2))==NULL)
				break;
			len=fread(buf,sizeof(BYTE),len,p->fp);
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
			if(len>0) 
				switch(tiny) {
					case FILE_PROP_CHKSUM:
						for(sum=l=0;l<len;l++)
							sum+=buf[l];
						JS_NewNumberValue(cx,sum,vp);
						break;
					case FILE_PROP_CRC16:
						JS_NewNumberValue(cx,crc16(buf,len),vp);
						break;
					case FILE_PROP_CRC32:
						JS_NewNumberValue(cx,crc32(buf,len),vp);
						break;
					case FILE_PROP_MD5_HEX:
						MD5_calc(digest,buf,len);
						MD5_hex(buf,digest);
						js_str=JS_NewStringCopyZ(cx, buf);
						break;
					case FILE_PROP_MD5_B64:
						MD5_calc(digest,buf,len);
						b64_encode(buf,len*2,digest,sizeof(digest));
						js_str=JS_NewStringCopyZ(cx, buf);
						break;
				}
996
997
998
999
1000
			free(buf);
			fseek(p->fp,offset,SEEK_SET);	/* restore saved file position */
			if(js_str!=NULL)
				*vp = STRING_TO_JSVAL(js_str);
			break;
1001
1002
	}

1003
	return(JS_TRUE);
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
}

#define FILE_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY

static struct JSPropertySpec js_file_properties[] = {
/*		 name				,tinyid					,flags,				getter,	setter	*/
	{	"name"				,FILE_PROP_NAME			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"mode"				,FILE_PROP_MODE			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"exists"			,FILE_PROP_EXISTS		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"date"				,FILE_PROP_DATE			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"is_open"			,FILE_PROP_IS_OPEN		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"eof"				,FILE_PROP_EOF			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"error"				,FILE_PROP_ERROR		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"descriptor"		,FILE_PROP_DESCRIPTOR	,FILE_PROP_FLAGS,	NULL,NULL},
	/* writeable */
1019
	{	"etx"				,FILE_PROP_ETX			,JSPROP_ENUMERATE,  NULL,NULL},
1020
1021
1022
1023
	{	"debug"				,FILE_PROP_DEBUG		,JSPROP_ENUMERATE,	NULL,NULL},
	{	"position"			,FILE_PROP_POSITION		,JSPROP_ENUMERATE,	NULL,NULL},
	{	"length"			,FILE_PROP_LENGTH		,JSPROP_ENUMERATE,	NULL,NULL},
	{	"attributes"		,FILE_PROP_ATTRIBUTES	,JSPROP_ENUMERATE,	NULL,NULL},
1024
	{	"network_byte_order",FILE_PROP_NETWORK_ORDER,JSPROP_ENUMERATE,	NULL,NULL},
1025
	{	"rot13"				,FILE_PROP_ROT13		,JSPROP_ENUMERATE,	NULL,NULL},
1026
1027
	{	"uue"				,FILE_PROP_UUENCODED	,JSPROP_ENUMERATE,	NULL,NULL},
	{	"base64"			,FILE_PROP_B64ENCODED	,JSPROP_ENUMERATE,	NULL,NULL},
1028
1029
1030
	/* dynamically calculated */
	{	"crc16"				,FILE_PROP_CRC16		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"crc32"				,FILE_PROP_CRC32		,FILE_PROP_FLAGS,	NULL,NULL},
1031
	{	"chksum"			,FILE_PROP_CHKSUM		,FILE_PROP_FLAGS,	NULL,NULL},
1032
	{	"md5_hex"			,FILE_PROP_MD5_HEX		,FILE_PROP_FLAGS,	NULL,NULL},
1033
	{	"md5_base64"		,FILE_PROP_MD5_B64		,FILE_PROP_FLAGS,	NULL,NULL},
1034
1035
1036
	{0}
};

rswindell's avatar
rswindell committed
1037
1038
1039
1040
1041
1042
1043
#ifdef _DEBUG
static char* file_prop_desc[] = {
	 "filename specified in constructor - <small>READ ONLY</small>"
	,"mode string specified in <i>open</i> call - <small>READ ONLY</small>"
	,"<i>true</i> if the file exists - <small>READ ONLY</small>"
	,"last modified date/time (time_t format) - <small>READ ONLY</small>"
	,"<i>true</i> if the file has been opened successfully - <small>READ ONLY</small>"
1044
	,"<i>true</i> if the current file position is at the <i>end of file</i> - <small>READ ONLY</small>"
rswindell's avatar
rswindell committed
1045
1046
1047
	,"the last occurred error value (use clear_error to clear) - <small>READ ONLY</small>"
	,"the open file descriptor (advanced use only) - <small>READ ONLY</small>"
	,"end-of-text character (advanced use only), if non-zero used by <i>read</i>, <i>readln</i>, and <i>write</i>"
1048
	,"set to <i>true</i> to enabel debug log output"
rswindell's avatar
rswindell committed
1049
1050
1051
	,"the current file position (offset in bytes), change value to seek within file"
	,"the current length of the file (in bytes)"
	,"file mode/attributes"
1052
	,"set to <i>true</i> if binary data is to be written and read in Network Byte Order (big end first)"
1053
	,"set to <i>true</i> to enable automatic ROT13 translatation of text"
1054
1055
	,"set to <i>true</i> to enable automatic unix-to-unix encode and decode on <tt>read</tt> and <tt>write</tt> calls"
	,"set to <i>true</i> to enable automatic base64 encode and decode on <tt>read</tt> and <tt>write</tt> calls"