js_file.c 69.2 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 2012 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
190
191
192
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
193
	JS_RESUMEREQUEST(cx, rc);
194
195
196
197

	return(JS_TRUE);
}

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

209
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
210
211
212
213
214
215
216
217
218

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

219
	SAFECOPY(p->mode,"r+");	/* default mode */
220
221
222
223
224
225
	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);
			}
226
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
227
228
229
230
231
232
233
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}

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

	return(JS_TRUE);
}
249
250

static JSBool
251
js_close(JSContext *cx, uintN argc, jsval *arglist)
252
{
253
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
254
	private_t*	p;
deuce's avatar
deuce committed
255
	jsrefcount	rc;
256

deuce's avatar
deuce committed
257
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
258
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
259
		JS_ReportError(cx,getprivate_failure,WHERE);
260
		return(JS_FALSE);
261
	}
262
263
264
265

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

266
	rc=JS_SUSPENDREQUEST(cx);
267
268
269
270
271
272
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
273
274
275
276

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 
277
	JS_RESUMEREQUEST(cx, rc);
278
279
280
281
282

	return(JS_TRUE);
}

static JSBool
283
js_read(JSContext *cx, uintN argc, jsval *arglist)
284
{
285
286
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
287
	char*		cp;
288
	char*		buf;
289
	char*		uubuf;
290
291
	int32		len;
	int32		offset;
292
	int32		uulen;
293
294
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
295
	jsrefcount	rc;
296

297
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
298

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

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

307
308
309
310
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
311
		rc=JS_SUSPENDREQUEST(cx);
312
313
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
314
315
		if(offset>0)
			len-=offset;
316
		JS_RESUMEREQUEST(cx, rc);
317
318
319
	}
	if(len<0)
		len=512;
320

321
	if((buf=malloc(len+1))==NULL)
322
323
		return(JS_TRUE);

324
	rc=JS_SUSPENDREQUEST(cx);
325
326
327
328
329
330
331
332
	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; 
333
		len=strlen(buf);
334
335
	}

336
337
338
	if(p->rot13)
		rot13(buf);

339
	if(p->uuencoded || p->b64encoded || p->yencoded) {
340
		uulen=len*2;
deuce's avatar
deuce committed
341
		if((uubuf=malloc(uulen))==NULL) {
342
			free(buf);
343
			JS_RESUMEREQUEST(cx, rc);
344
			return(JS_TRUE);
345
		}
346
347
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
348
349
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
350
351
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
352
		if(uulen>=0) {
353
			free(buf);
354
			buf=uubuf;
355
			len=uulen;
deuce's avatar
deuce committed
356
		}
357
358
		else
			free(uubuf);
359
	}
360
	JS_RESUMEREQUEST(cx, rc);
361

362
	str = JS_NewStringCopyN(cx, buf, len);
363
	free(buf);
364

365
366
367
	if(str==NULL)
		return(JS_FALSE);

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

370
	rc=JS_SUSPENDREQUEST(cx);
371
	dbprintf(FALSE, p, "read %u bytes",len);
372
	JS_RESUMEREQUEST(cx, rc);
373
374
375
376
377
		
	return(JS_TRUE);
}

static JSBool
378
js_readln(JSContext *cx, uintN argc, jsval *arglist)
379
{
380
381
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
382
383
	char*		cp;
	char*		buf;
384
	int32		len=512;
385
	JSString*	js_str;
386
	private_t*	p;
deuce's avatar
deuce committed
387
	jsrefcount	rc;
388

389
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
390

391
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
392
		JS_ReportError(cx,getprivate_failure,WHERE);
393
		return(JS_FALSE);
394
	}
395
396
397

	if(p->fp==NULL)
		return(JS_TRUE);
398
	
399
400
401
402
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
403

deuce's avatar
deuce committed
404
405
	if((buf=malloc(len))==NULL)
		return(JS_FALSE);
406

407
	rc=JS_SUSPENDREQUEST(cx);
408
	if(fgets(buf,len,p->fp)!=NULL) {
409
410
411
412
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
413
414
415
416
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
417
418
		if(p->rot13)
			rot13(buf);
419
		JS_RESUMEREQUEST(cx, rc);
420
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
421
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
422
423
	} else {
		JS_RESUMEREQUEST(cx, rc);
424
	}
deuce's avatar
deuce committed
425
	free(buf);
426
427
428
429
430

	return(JS_TRUE);
}

static JSBool
431
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
432
{
433
434
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
435
436
437
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
438
439
	size_t		size=sizeof(DWORD);
	private_t*	p;
440
441
442
	size_t		count=1;
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
443
	size_t		i;
444
445
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
446
	jsrefcount	rc;
447

448
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
449

450
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
451
		JS_ReportError(cx,getprivate_failure,WHERE);
452
		return(JS_FALSE);
453
	}
454
455
456
457

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

458
459
460
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],(int32*)&size))
			return(JS_FALSE);
461
462
463
464
		if(argc>1) {
			if(!JS_ValueToInt32(cx,argv[1],(int32*)&count))
				return(JS_FALSE);
		}
465
	}
466

467
	rc=JS_SUSPENDREQUEST(cx);
468
469
470
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
471
		JS_RESUMEREQUEST(cx, rc);
472
473
474
475
476
477
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
478
		JS_RESUMEREQUEST(cx, rc);
479
480
481
482
483
484
485
486
487
488
		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):
489
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
490
491
					break;
				case sizeof(WORD):
492
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
493
494
					break;
				case sizeof(DWORD):
495
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
496
					break;
497
			}
498
499
500
		}
	}
	else {
501
		JS_RESUMEREQUEST(cx, rc);
502
503
504
505
506
507
508
509
510
511
512
    	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):
513
					v=UINT_TO_JSVAL(*(l++));
514
					break;
515
			}
deuce's avatar
deuce committed
516
        	if(!JS_SetElement(cx, array, i, &v)) {
517
				rc=JS_SUSPENDREQUEST(cx);
518
				goto end;
deuce's avatar
deuce committed
519
			}
520
		}
521
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
522
	}
523
524
525

end:
	free(buffer);
526
	JS_RESUMEREQUEST(cx, rc);
527
528
529
530
	return(JS_TRUE);
}

static JSBool
531
js_readall(JSContext *cx, uintN argc, jsval *arglist)
532
{
533
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
534
535
    jsint       len=0;
    JSObject*	array;
536
537
	private_t*	p;

538
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
539

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

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

548
    array = JS_NewArrayObject(cx, 0, NULL);
549

550
    while(!feof(p->fp)) {
551
552
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
553
			break;
554
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
555
			break;
556
	}
557
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
558

559
560
    return(JS_TRUE);
}
561

562
563
564
565
566
567
568
569
570
571
572
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++) {
573
		if(*p=='.' && !f)
574
575
576
577
			f=TRUE;
		else if(!isdigit(*p))
			break;
	}
578
579
580
581
582
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
583
584
585
586
587
588
589
590
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
			if(!isxdigit(*p))
				break;
		if(*p==0) {	
591
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
592
593
594
595
596
597
598
599
600
601
602
603
604
			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
605
606
607
608
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

deuce's avatar
deuce committed
609
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
610
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
611
	}
deuce's avatar
deuce committed
612
613
614
	return JSVAL_TO_DOUBLE(rval);
}

615
static JSBool
616
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
617
{
618
619
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
620
	char*	section=ROOT_SECTION;
621
	char*	key;
622
	char**	list;
623
	char	buf[INI_MAX_VALUE_LEN];
624
625
	int32	i;
	jsval	val;
626
627
	jsval	dflt=argv[2];
	private_t*	p;
628
	JSObject*	array;
629
630
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
631
632
633
634
635
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
	char*		cstr;
	char*		cstr2;
636

637
638
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

644
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
645
646
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
647
648
649
650
651
	if(JS_IsExceptionPending(cx)) {
		if(section)
			free(section);
		if(key)
			free(key);
deuce's avatar
deuce committed
652
		return JS_FALSE;
653
	}
654
655
656
657
658
659
660
661
662
663
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
		if(section)
			free(section);
		return JS_FALSE;
	}
664

665
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
666
		rc=JS_SUSPENDREQUEST(cx);
667
		cstr=iniReadString(p->fp,section,key,NULL,buf);
668
669
670
671
		if(section)
			free(section);
		if(key)
			free(key);
672
		JS_RESUMEREQUEST(cx, rc);
673
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr));
674
675
676
		return(JS_TRUE);
	}

deuce's avatar
deuce committed
677
678
679
680
681
682
683
	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);
684
			rc=JS_SUSPENDREQUEST(cx);
685
			dbl=(double)iniReadDateTime(p->fp,section,key,tt);
deuce's avatar
deuce committed
686
			dbl *= 1000;
687
			JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
688
689
			date_obj = JS_NewDateObjectMsec(cx, dbl);
			if(date_obj!=NULL) {
deuce's avatar
deuce committed
690
				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
deuce's avatar
deuce committed
691
			}
deuce's avatar
deuce committed
692
693
		}
		else {
694
		    array = JS_NewArrayObject(cx, 0, NULL);
695
			JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
696
697
698
699
700
701
702
			if(JS_IsExceptionPending(cx)) {
				if(section)
					free(section);
				if(key)
					free(key);
				return JS_FALSE;
			}
703
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
704
			list=iniReadStringList(p->fp,section,key,",",cstr);
705
706
			if(cstr)
				free(cstr);
707
			JS_RESUMEREQUEST(cx, rc);
708
709
710
711
712
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
713
			rc=JS_SUSPENDREQUEST(cx);
714
			iniFreeStringList(list);
715
			JS_RESUMEREQUEST(cx, rc);
716
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
deuce's avatar
deuce committed
717
718
719
720
721
722
723
724
725
		}
	}
	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)) {
726
727
728
729
730
		if(!JS_ValueToInt32(cx,dflt,&i)) {
			if(section)
				free(section);
			if(key)
				free(key);
deuce's avatar
deuce committed
731
			return(JS_FALSE);
732
		}
deuce's avatar
deuce committed
733
734
735
736
737
		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 {
738
		JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
739
740
741
742
743
744
745
746
		if(JS_IsExceptionPending(cx)) {
			if(section)
				free(section);
			if(key)
				free(key);

			return JS_FALSE;
		}
deuce's avatar
deuce committed
747
748
		rc=JS_SUSPENDREQUEST(cx);
		cstr2=iniReadString(p->fp,section,key,cstr,buf);
749
750
		if(cstr)
			free(cstr);
deuce's avatar
deuce committed
751
752
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2)));
753
	}
754
755
756
757
	if(section)
		free(section);
	if(key)
		free(key);
758
759
760
761

	return(JS_TRUE);
}

762
static JSBool
deuce's avatar
deuce committed
763
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, jsval *rval)
764
{
rswindell's avatar
rswindell committed
765
	char*	section=ROOT_SECTION;
766
	char*	key=NULL;
767
768
769
770
771
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
	str_list_t	list;
772
	JSObject*	value_obj;
deuce's avatar
deuce committed
773
774
775
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
776

deuce's avatar
deuce committed
777
	*rval = JSVAL_FALSE;
778
779
780
781
782
783

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

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

787
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
788
789
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
790
791
792
793
794
795
796
	if(JS_IsExceptionPending(cx)) {
		if(section)
			free(section);
		if(key)
			free(key);
		return JS_FALSE;
	}
797

798
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
799
	if((list=iniReadFile(p->fp))==NULL) {
800
		JS_RESUMEREQUEST(cx, rc);
801
802
803
804
805
		if(section)
			free(section);
		if(key)
			free(key);
		return JS_TRUE;
deuce's avatar
deuce committed
806
	}
807
	JS_RESUMEREQUEST(cx, rc);
808

deuce's avatar
deuce committed
809
	if(value==JSVAL_VOID) { 	/* unspecified value */
810
		rc=JS_SUSPENDREQUEST(cx);
811
		result = iniSetString(&list,section,key,"",NULL);
812
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
813
	}
deuce's avatar
deuce committed
814
815
816
817
818
819
820
	else if(JSVAL_IS_BOOLEAN(value)) {
		result = iniSetBool(&list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
	}
	else if(JSVAL_IS_DOUBLE(value)) {
		result = iniSetFloat(&list,section,key,JSVAL_TO_DOUBLE(value),NULL);
	}
	else if(JSVAL_IS_NUMBER(value)) {
821
822
823
824
825
826
827
		if(!JS_ValueToInt32(cx,value,&i)) {
			if(section)
				free(section);
			if(key)
				free(key);
			return JS_FALSE;
		}
deuce's avatar
deuce committed
828
829
830
831
832
833
834
835
836
837
838
		rc=JS_SUSPENDREQUEST(cx);
		result = iniSetInteger(&list,section,key,i,NULL);
		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);
		result = iniSetDateTime(&list,section,key,/* include_time */TRUE, tt,NULL);
		JS_RESUMEREQUEST(cx, rc);
	} else {
839
		JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
840
841
842
843
844
845
846
		if(JS_IsExceptionPending(cx)) {
			if(section)
				free(section);
			if(key)
				free(key);
			return JS_FALSE;
		}
deuce's avatar
deuce committed
847
848
		rc=JS_SUSPENDREQUEST(cx);
		result = iniSetString(&list,section,key, cstr,NULL);
849
850
		if(cstr)
			free(cstr);
deuce's avatar
deuce committed
851
		JS_RESUMEREQUEST(cx, rc);
852
	}
853
854
855
856
	if(section)
		free(section);
	if(key)
		free(key);
857

858
	rc=JS_SUSPENDREQUEST(cx);
859
	if(result != NULL)
deuce's avatar
deuce committed
860
		*rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));
861
862

	strListFree(&list);
863
	JS_RESUMEREQUEST(cx, rc);
864
865
866
867

	return(JS_TRUE);
}

deuce's avatar
deuce committed
868
869
870
871
872
873
874
875
876
877
878
879
880
static JSBool
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	jsval	rval;
	JSBool	ret;

	ret=js_iniSetValue_internal(cx, obj, argc, argv, &rval);
	JS_SET_RVAL(cx, arglist, rval);
	return ret;
}

881
static JSBool
882
js_iniRemoveKey(JSContext *cx, uintN argc, jsval *arglist)
883
{
884
885
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
886
	char*	section=ROOT_SECTION;
887
	char*	key=NULL;
888
889
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
890
	jsrefcount	rc;
891

892
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
893
894
895
896
897
898
899
900
901

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

902
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
903
904
905
906
907
908
909
910
911
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
	HANDLE_PENDING(cx);
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
		if(section)
			free(section);
		return JS_FALSE;
	}
912

913
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
914
	if((list=iniReadFile(p->fp))==NULL) {
915
		JS_RESUMEREQUEST(cx, rc);
916
917
918
		if(section)
			free(section);
		free(key);
919
		return(JS_TRUE);
deuce's avatar
deuce committed
920
	}
921
922

	if(iniRemoveKey(&list,section,key))
923
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
924
925
926
	if(section)
		free(section);
	free(key);
927
928

	strListFree(&list);
929
	JS_RESUMEREQUEST(cx, rc);
930
931
932
933
934

	return(JS_TRUE);
}

static JSBool
935
js_iniRemoveSection(JSContext *cx, uintN argc, jsval *arglist)
936
{
937
938
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
939
940
941
	char*	section=ROOT_SECTION;
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
942
	jsrefcount	rc;
943

944
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
945
946
947
948
949
950
951
952
953

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

954
955
956
957
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL) {
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
		HANDLE_PENDING(cx);
	}
958

959
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
960
	if((list=iniReadFile(p->fp))==NULL) {
961
		JS_RESUMEREQUEST(cx, rc);
962
963
		if(section)
			free(section);
964
		return(JS_TRUE);
deuce's avatar
deuce committed
965
	}
966
967

	if(iniRemoveSection(&list,section))