js_file.c 74.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* 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)		*
 *																			*
11
 * Copyright 2013 Rob Swindell - http://www.synchro.net/copyright.html		*
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
 *																			*
 * 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
#include "yenc.h"
43
#include "ini_file.h"
44
45
46

#ifdef JAVASCRIPT

47
#include "js_request.h"
48

49
50
typedef struct
{
51
	FILE*	fp;
52
53
	char	name[MAX_PATH+1];
	char	mode[4];
54
	uchar	etx;
55
56
	BOOL	external;	/* externally created, don't close */
	BOOL	debug;
57
	BOOL	rot13;
58
	BOOL	yencoded;
59
	BOOL	uuencoded;
60
61
	BOOL	b64encoded;
	BOOL	network_byte_order;
62
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
63
64
65

} private_t;

66
static const char* getprivate_failure = "line %d %s JS_GetPrivate failed";
67
68
69
70
71
72
73
74
75
76

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);
77
78
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
79
80
    va_end(argptr);
	
81
	lprintf(LOG_DEBUG,"%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
82
83
}

84
85
86
87
88
89
90
91
/* 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;
92
93
	else
		flags|=O_TEXT;
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

	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;
	}

120
121
122
	if(strchr(mode,'e'))
		flags|=O_EXCL;

123
124
	return(flags);
}
125
126
127
128

/* File Object Methods */

static JSBool
129
js_open(JSContext *cx, uintN argc, jsval *arglist)
130
{
131
132
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
133
134
	BOOL		shareable=FALSE;
	int			file;
135
	uintN		i;
136
	jsint		bufsize=2*1024;
137
138
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
139
	jsrefcount	rc;
140

141
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
142

143
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
144
		JS_ReportError(cx,getprivate_failure,WHERE);
145
		return(JS_FALSE);
146
	}
147
148
149

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

151
	SAFECOPY(p->mode,"w+");		/* default mode */
152
153
154
	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
155
156
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
157
			}
158
159
160
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
		}
		else if(JSVAL_IS_BOOLEAN(argv[i]))	/* shareable */
161
			shareable=JSVAL_TO_BOOLEAN(argv[i]);
162
163
164
165
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
166
167
	}

168
	rc=JS_SUSPENDREQUEST(cx);
169
170
171
172
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
173
174
175
176
177
178
179
180
181
182
			char *fdomode=strdup(p->mode);
			char *e=fdomode;

			if(fdomode && e) {
				for(e=strchr(fdomode, 'e'); e ; e=strchr(e, 'e'))
					memmove(e, e+1, strlen(e));
				if((p->fp=fdopen(file,fdomode))==NULL)
					close(file);
			}
			free(fdomode);
183
184
		}
	}
185
	if(p->fp!=NULL) {
186
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
187
		dbprintf(FALSE, p, "opened: %s",p->name);
188
189
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
190
191
192
193
194
		else {
#ifdef _WIN32
			if(bufsize < 2)
				bufsize = 2;
#endif
195
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
196
		}
197
	}
198
	JS_RESUMEREQUEST(cx, rc);
199
200
201
202

	return(JS_TRUE);
}

203
static JSBool
204
js_popen(JSContext *cx, uintN argc, jsval *arglist)
205
{
206
207
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
208
209
210
211
	uintN		i;
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
212
	jsrefcount	rc;
213

214
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
215
216
217
218
219
220
221
222
223

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

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

224
	SAFECOPY(p->mode,"r+");	/* default mode */
225
226
227
228
229
230
	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
			}
231
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
232
233
234
235
236
237
238
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}

239
	rc=JS_SUSPENDREQUEST(cx);
240
241
242
	p->fp=popen(p->name,p->mode);
	if(p->fp!=NULL) {
		p->pipe=TRUE;
243
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
244
245
246
247
248
249
		dbprintf(FALSE, p, "popened: %s",p->name);
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
250
	JS_RESUMEREQUEST(cx, rc);
251
252
253

	return(JS_TRUE);
}
254
255

static JSBool
256
js_close(JSContext *cx, uintN argc, jsval *arglist)
257
{
258
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
259
	private_t*	p;
deuce's avatar
deuce committed
260
	jsrefcount	rc;
261

deuce's avatar
deuce committed
262
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
263
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
264
		JS_ReportError(cx,getprivate_failure,WHERE);
265
		return(JS_FALSE);
266
	}
267
268
269
270

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

271
	rc=JS_SUSPENDREQUEST(cx);
272
273
274
275
276
277
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
278
279
280
281

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 
282
	JS_RESUMEREQUEST(cx, rc);
283
284
285
286

	return(JS_TRUE);
}

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
static JSBool
js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	private_t*	p;
	jsrefcount	rc;
	int32		timeout = -1;
#ifdef __unix__
	fd_set		rd;
	struct	timeval tv = {0, 0};
#endif

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

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

	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&timeout))
			return(JS_FALSE);
	}

	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(FALSE));
	rc=JS_SUSPENDREQUEST(cx);
#ifdef __unix__
	if (timeout >= 0) {
		tv.tv_sec = timeout / 1000;
		tv.tv_usec = (timeout%1000)*1000;
	}
	FD_ZERO(&rd);
	FD_SET(fileno(p->fp), &rd);
	if (select(fileno(p->fp)+1, &rd, NULL, NULL, timeout < 0 ? NULL : &tv) == 1)
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
#else
	while(timeout) {
		if (isatty(fileno(p->fp))) {
			if (kbhit()) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
		else {
			if (!eof(fileno(p->fp))) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
	}
#endif
	JS_RESUMEREQUEST(cx, rc);
	return JS_TRUE;
}

354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
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
static JSBool
js_raw_read(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	char*		buf;
	int32		len;
	JSString*	str;
	private_t*	p;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

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

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

	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else
		len = 1;
	if(len<0)
		len=1;

	if((buf=malloc(len))==NULL)
		return(JS_TRUE);

	rc=JS_SUSPENDREQUEST(cx);
	len = read(fileno(p->fp),buf,len);
	if(len<0) 
		len=0;

	JS_RESUMEREQUEST(cx, rc);

	str = JS_NewStringCopyN(cx, buf, len);
	free(buf);

	if(str==NULL)
		return(JS_FALSE);

	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));

	rc=JS_SUSPENDREQUEST(cx);
	dbprintf(FALSE, p, "read %u raw bytes",len);
	JS_RESUMEREQUEST(cx, rc);
		
	return(JS_TRUE);
}


409
static JSBool
410
js_read(JSContext *cx, uintN argc, jsval *arglist)
411
{
412
413
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
414
	char*		cp;
415
	char*		buf;
416
	char*		uubuf;
417
418
	int32		len;
	int32		offset;
419
	int32		uulen;
420
421
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
422
	jsrefcount	rc;
423

424
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
425

426
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
427
		JS_ReportError(cx,getprivate_failure,WHERE);
428
		return(JS_FALSE);
429
	}
430

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

434
435
436
437
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
438
		rc=JS_SUSPENDREQUEST(cx);
439
440
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
441
442
		if(offset>0)
			len-=offset;
443
		JS_RESUMEREQUEST(cx, rc);
444
445
446
	}
	if(len<0)
		len=512;
447

448
	if((buf=malloc(len+1))==NULL)
449
450
		return(JS_TRUE);

451
	rc=JS_SUSPENDREQUEST(cx);
452
453
454
455
456
457
458
459
	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; 
460
		len=strlen(buf);
461
462
	}

463
464
465
	if(p->rot13)
		rot13(buf);

466
	if(p->uuencoded || p->b64encoded || p->yencoded) {
467
		uulen=len*2;
deuce's avatar
deuce committed
468
		if((uubuf=malloc(uulen))==NULL) {
469
			free(buf);
470
			JS_RESUMEREQUEST(cx, rc);
471
			return(JS_TRUE);
472
		}
473
474
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
475
476
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
477
478
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
479
		if(uulen>=0) {
480
			free(buf);
481
			buf=uubuf;
482
			len=uulen;
deuce's avatar
deuce committed
483
		}
484
485
		else
			free(uubuf);
486
	}
487
	JS_RESUMEREQUEST(cx, rc);
488

489
	str = JS_NewStringCopyN(cx, buf, len);
490
	free(buf);
491

492
493
494
	if(str==NULL)
		return(JS_FALSE);

495
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
496

497
	rc=JS_SUSPENDREQUEST(cx);
498
	dbprintf(FALSE, p, "read %u bytes",len);
499
	JS_RESUMEREQUEST(cx, rc);
500
501
502
503
504
		
	return(JS_TRUE);
}

static JSBool
505
js_readln(JSContext *cx, uintN argc, jsval *arglist)
506
{
507
508
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
509
510
	char*		cp;
	char*		buf;
511
	int32		len=512;
512
	JSString*	js_str;
513
	private_t*	p;
deuce's avatar
deuce committed
514
	jsrefcount	rc;
515

516
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
517

518
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
519
		JS_ReportError(cx,getprivate_failure,WHERE);
520
		return(JS_FALSE);
521
	}
522
523
524

	if(p->fp==NULL)
		return(JS_TRUE);
525
	
526
527
528
529
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
530

deuce's avatar
deuce committed
531
532
	if((buf=malloc(len))==NULL)
		return(JS_FALSE);
533

534
	rc=JS_SUSPENDREQUEST(cx);
535
	if(fgets(buf,len,p->fp)!=NULL) {
536
537
538
539
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
540
541
542
543
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
544
545
		if(p->rot13)
			rot13(buf);
546
		JS_RESUMEREQUEST(cx, rc);
547
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
548
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
549
550
	} else {
		JS_RESUMEREQUEST(cx, rc);
551
	}
deuce's avatar
deuce committed
552
	free(buf);
553
554
555
556
557

	return(JS_TRUE);
}

static JSBool
558
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
559
{
560
561
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
562
563
564
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
565
	int32		size=sizeof(DWORD);
566
	private_t*	p;
567
	int32		count=1;
568
569
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
570
	size_t		i;
571
572
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
573
	jsrefcount	rc;
574

575
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
576

577
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
578
		JS_ReportError(cx,getprivate_failure,WHERE);
579
		return(JS_FALSE);
580
	}
581
582
583
584

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

585
	if(argc) {
586
		if(!JS_ValueToInt32(cx,argv[0],&size))
587
			return(JS_FALSE);
588
		if(argc>1) {
589
			if(!JS_ValueToInt32(cx,argv[1],&count))
590
591
				return(JS_FALSE);
		}
592
	}
593

594
	rc=JS_SUSPENDREQUEST(cx);
595
596
597
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
598
		JS_RESUMEREQUEST(cx, rc);
599
600
601
602
603
604
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
605
		JS_RESUMEREQUEST(cx, rc);
606
607
608
609
610
611
612
613
614
615
		return(JS_FALSE);
	}
	b=buffer;
	w=buffer;
	l=buffer;
	retlen=fread(buffer, size, count, p->fp);
	if(count==1) {
		if(retlen==1) {
			switch(size) {
				case sizeof(BYTE):
616
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
617
618
					break;
				case sizeof(WORD):
619
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
620
621
					break;
				case sizeof(DWORD):
622
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
623
					break;
624
			}
625
626
627
		}
	}
	else {
628
		JS_RESUMEREQUEST(cx, rc);
629
630
631
632
633
634
635
636
637
638
639
    	array = JS_NewArrayObject(cx, 0, NULL);

		for(i=0; i<retlen; i++) {
			switch(size) {
				case sizeof(BYTE):
					v = INT_TO_JSVAL(*(b++));
					break;
				case sizeof(WORD):
					v = INT_TO_JSVAL(*(w++));
					break;
				case sizeof(DWORD):
640
					v=UINT_TO_JSVAL(*(l++));
641
					break;
642
			}
deuce's avatar
deuce committed
643
        	if(!JS_SetElement(cx, array, i, &v)) {
644
				rc=JS_SUSPENDREQUEST(cx);
645
				goto end;
deuce's avatar
deuce committed
646
			}
647
		}
648
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
649
	}
650
651
652

end:
	free(buffer);
653
	JS_RESUMEREQUEST(cx, rc);
654
655
656
657
	return(JS_TRUE);
}

static JSBool
658
js_readall(JSContext *cx, uintN argc, jsval *arglist)
659
{
660
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
661
662
    jsint       len=0;
    JSObject*	array;
663
664
	private_t*	p;

665
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
666

667
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
668
		JS_ReportError(cx,getprivate_failure,WHERE);
669
		return(JS_FALSE);
670
	}
671

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

675
    array = JS_NewArrayObject(cx, 0, NULL);
676

677
    while(!feof(p->fp)) {
678
679
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
680
			break;
681
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
682
			break;
683
	}
684
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
685

686
687
    return(JS_TRUE);
}
688

689
690
691
692
693
694
695
696
697
698
699
static jsval get_value(JSContext *cx, char* value)
{
	char*	p;
	BOOL	f=FALSE;
	jsval	val;

	if(value==NULL || *value==0)
		return(JSVAL_VOID);

	/* integer or float? */
	for(p=value;*p;p++) {
700
		if(*p=='.' && !f)
701
			f=TRUE;
702
		else if(!isdigit((uchar)*p))
703
704
			break;
	}
705
706
707
708
709
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
710
711
712
713
714
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
715
			if(!isxdigit((uchar)*p))
716
717
				break;
		if(*p==0) {	
718
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
719
720
721
722
723
724
725
726
727
728
729
730
731
			return(val);
		}
	}
	/* Boolean? */
	if(!stricmp(value,"true"))
		return(JSVAL_TRUE);
	if(!stricmp(value,"false"))
		return(JSVAL_FALSE);

	/* String */
	return(STRING_TO_JSVAL(JS_NewStringCopyZ(cx,value)));
}

deuce's avatar
deuce committed
732
733
734
735
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

deuce's avatar
deuce committed
736
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
737
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
738
	}
deuce's avatar
deuce committed
739
740
741
	return JSVAL_TO_DOUBLE(rval);
}

742
static JSBool
743
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
744
{
745
746
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
747
	char*	section=ROOT_SECTION;
748
	char*	key;
749
	char**	list;
750
	char	buf[INI_MAX_VALUE_LEN];
751
752
	int32	i;
	jsval	val;
753
754
	jsval	dflt=argv[2];
	private_t*	p;
755
	JSObject*	array;
756
757
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
758
759
760
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
761
	char*		cstr=NULL;
deuce's avatar
deuce committed
762
	char*		cstr2;
763

764
765
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

766
767
768
769
770
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

771
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
772
773
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
774
	if(JS_IsExceptionPending(cx)) {
775
776
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
deuce's avatar
deuce committed
777
		return JS_FALSE;
778
	}
779
780
781
782
783
784
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
785
		FREE_AND_NULL(section);
786
787
		return JS_FALSE;
	}
788

789
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
790
		rc=JS_SUSPENDREQUEST(cx);
791
		cstr=iniReadString(p->fp,section,key,NULL,buf);
792
793
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
794
		JS_RESUMEREQUEST(cx, rc);
795
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr));
796
797
798
		return(JS_TRUE);
	}

deuce's avatar
deuce committed
799
800
801
802
803
804
805
	if(JSVAL_IS_BOOLEAN(dflt)) {
		JS_SET_RVAL(cx,arglist,BOOLEAN_TO_JSVAL(
			iniReadBool(p->fp,section,key,JSVAL_TO_BOOLEAN(dflt))));
	}
	else if(JSVAL_IS_OBJECT(dflt)) {
		if((dflt_obj = JSVAL_TO_OBJECT(dflt))!=NULL && (strcmp("Date",JS_GetClass(cx, dflt_obj)->name)==0)) {
			tt=(time_t)(js_DateGetMsecSinceEpoch(cx,dflt_obj)/1000.0);
806
			rc=JS_SUSPENDREQUEST(cx);
807
			dbl=(double)iniReadDateTime(p->fp,section,key,tt);
deuce's avatar
deuce committed
808
			dbl *= 1000;
809
			JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
810
811
			date_obj = JS_NewDateObjectMsec(cx, dbl);
			if(date_obj!=NULL) {
deuce's avatar
deuce committed
812
				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
deuce's avatar
deuce committed
813
			}
deuce's avatar
deuce committed
814
815
		}
		else {
816
		    array = JS_NewArrayObject(cx, 0, NULL);
817
			cstr=NULL;
818
			JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
819
			if(JS_IsExceptionPending(cx)) {
820
821
822
				FREE_AND_NULL(cstr);
				FREE_AND_NULL(section);
				FREE_AND_NULL(key);
823
824
				return JS_FALSE;
			}
825
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
826
			list=iniReadStringList(p->fp,section,key,",",cstr);
827
			FREE_AND_NULL(cstr);
828
			JS_RESUMEREQUEST(cx, rc);
829
830
831
832
833
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
834
			rc=JS_SUSPENDREQUEST(cx);
835
			iniFreeStringList(list);
836
			JS_RESUMEREQUEST(cx, rc);
837
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
deuce's avatar
deuce committed
838
839
840
841
842
843
844
845
846
		}
	}
	else if(JSVAL_IS_DOUBLE(dflt)) {
		rc=JS_SUSPENDREQUEST(cx);
		dbl=iniReadFloat(p->fp,section,key,JSVAL_TO_DOUBLE(dflt));
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist,DOUBLE_TO_JSVAL(dbl));
	}
	else if(JSVAL_IS_NUMBER(dflt)) {
847
		if(!JS_ValueToInt32(cx,dflt,&i)) {
848
849
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
deuce's avatar
deuce committed
850
			return(JS_FALSE);
851
		}
deuce's avatar
deuce committed
852
853
854
855
856
		rc=JS_SUSPENDREQUEST(cx);
		i=iniReadInteger(p->fp,section,key,i);
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist,INT_TO_JSVAL(i));
	} else {
857
		cstr=NULL;
858
		JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
859
		if(JS_IsExceptionPending(cx)) {
860
861
862
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
863
864
			return JS_FALSE;
		}
deuce's avatar
deuce committed
865
866
867
868
		rc=JS_SUSPENDREQUEST(cx);
		cstr2=iniReadString(p->fp,section,key,cstr,buf);
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2)));
869
		FREE_AND_NULL(cstr);
870
	}
871
872
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
873
874
875
876

	return(JS_TRUE);
}

877
static JSBool
878
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, str_list_t* list)
879
{
rswindell's avatar
rswindell committed
880
	char*	section=ROOT_SECTION;
881
	char*	key=NULL;
882
883
884
885
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
886
	JSObject*	value_obj;
deuce's avatar
deuce committed
887
888
889
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
890
891
892
893
894
895

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

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

899
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
900
901
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
902
	if(JS_IsExceptionPending(cx)) {
903
904
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
905
906
		return JS_FALSE;
	}
907

deuce's avatar
deuce committed
908
	if(value==JSVAL_VOID) { 	/* unspecified value */
909
		rc=JS_SUSPENDREQUEST(cx);
910
		result = iniSetString(list,section,key,"",NULL);
911
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
912
	}
deuce's avatar
deuce committed
913
	else if(JSVAL_IS_BOOLEAN(value)) {
914
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
deuce's avatar
deuce committed
915
916
	}
	else if(JSVAL_IS_DOUBLE(value)) {
917
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),NULL);
deuce's avatar
deuce committed
918
919
	}
	else if(JSVAL_IS_NUMBER(value)) {
920
		if(!JS_ValueToInt32(cx,value,&i)) {
921
922
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
923
924
			return JS_FALSE;
		}
deuce's avatar
deuce committed
925
		rc=JS_SUSPENDREQUEST(cx);
926
		result = iniSetInteger(list,section,key,i,NULL);
deuce's avatar
deuce committed
927
928
929
930
931
932
		JS_RESUMEREQUEST(cx, rc);
	} else if(JSVAL_IS_OBJECT(value) 
			&& (value_obj = JSVAL_TO_OBJECT(value))!=NULL
			&& (strcmp("Date",JS_GetClass(cx, value_obj)->name)==0)) {
		tt=(time_t)(js_DateGetMsecSinceEpoch(cx,value_obj)/1000.0);
		rc=JS_SUSPENDREQUEST(cx);
933
		result = iniSetDateTime(list,section,key,/* include_time */TRUE, tt,NULL);
deuce's avatar
deuce committed
934
935
		JS_RESUMEREQUEST(cx, rc);
	} else {
936
		cstr=NULL;
937
		JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
938
		if(JS_IsExceptionPending(cx)) {
939
940
941
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
942
943
			return JS_FALSE;
		}
deuce's avatar
deuce committed
944
		rc=JS_SUSPENDREQUEST(cx);
945
946
		result = iniSetString(list,section,key, cstr,NULL);
		FREE_AND_NULL(cstr);
deuce's avatar
deuce committed
947
		JS_RESUMEREQUEST(cx, rc);
948
	}
949
950
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
951

952
	return(result != NULL);
953
954
}

deuce's avatar
deuce committed
955
956
957
958
959
static JSBool
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
	jsval	rval=JSVAL_FALSE;
	private_t*	p;
	str_list_t	list;
	jsrefcount	rc;

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

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

	rc=JS_SUSPENDREQUEST(cx);
	if((list=iniReadFile(p->fp)) != NULL) {
		if(js_iniSetValue_internal(cx, obj, argc, argv, &list))
			rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));
	}
	strListFree(&list);
	JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
980
981

	JS_SET_RVAL(cx, arglist, rval);
982
	return JS_TRUE;
deuce's avatar
deuce committed
983
984
}

985
static JSBool
986
js_iniRemoveKey(JSContext *cx, uintN argc, jsval *arglist)
987
{