js_file.c 72.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 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
	size_t	bufsize;
	int		bufmode;
57
58
	BOOL	external;	/* externally created, don't close */
	BOOL	debug;
59
	BOOL	rot13;
60
	BOOL	yencoded;
61
	BOOL	uuencoded;
62
63
	BOOL	b64encoded;
	BOOL	network_byte_order;
64
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
65
66
67

} private_t;

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

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

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

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

122
123
124
	if(strchr(mode,'e'))
		flags|=O_EXCL;

125
126
	return(flags);
}
127
128
129
130

/* File Object Methods */

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

143
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
144

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

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

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

171
	rc=JS_SUSPENDREQUEST(cx);
172
173
174
175
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
176
177
178
179
180
181
182
183
184
185
			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);
186
187
		}
	}
188
	if(p->fp!=NULL) {
189
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
190
		dbprintf(FALSE, p, "opened: %s",p->name);
191
192
193
		if(!bufsize) {
			p->bufmode = _IONBF;
		}
194
195
196
197
198
		else {
#ifdef _WIN32
			if(bufsize < 2)
				bufsize = 2;
#endif
199
			p->bufmode = _IOFBF;
200
		}
201
		setvbuf(p->fp,NULL,p->bufmode,p->bufsize);
202
	}
203
	JS_RESUMEREQUEST(cx, rc);
204
205
206
207

	return(JS_TRUE);
}

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

219
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
220
221
222
223
224
225
226
227
228

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

229
	SAFECOPY(p->mode,"r+");	/* default mode */
230
231
232
233
234
235
	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);
			}
236
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
237
238
239
240
241
242
243
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}

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

	return(JS_TRUE);
}
259
260

static JSBool
261
js_close(JSContext *cx, uintN argc, jsval *arglist)
262
{
263
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
264
	private_t*	p;
deuce's avatar
deuce committed
265
	jsrefcount	rc;
266

deuce's avatar
deuce committed
267
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
268
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
269
		JS_ReportError(cx,getprivate_failure,WHERE);
270
		return(JS_FALSE);
271
	}
272
273
274
275

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

276
	rc=JS_SUSPENDREQUEST(cx);
277
278
279
280
281
282
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
283
284
285
286

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 
287
	JS_RESUMEREQUEST(cx, rc);
288
289
290
291
292

	return(JS_TRUE);
}

static JSBool
293
js_read(JSContext *cx, uintN argc, jsval *arglist)
294
{
295
296
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
297
	char*		cp;
298
	char*		buf;
299
	char*		uubuf;
300
301
	int32		len;
	int32		offset;
302
	int32		uulen;
303
304
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
305
	jsrefcount	rc;
306

307
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
308

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

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

317
318
319
320
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
321
		rc=JS_SUSPENDREQUEST(cx);
322
323
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
324
325
		if(offset>0)
			len-=offset;
326
		JS_RESUMEREQUEST(cx, rc);
327
328
329
	}
	if(len<0)
		len=512;
330

331
	if((buf=malloc(len+1))==NULL)
332
333
		return(JS_TRUE);

334
	rc=JS_SUSPENDREQUEST(cx);
335
336
337
338
339
340
341
342
	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; 
343
		len=strlen(buf);
344
345
	}

346
347
348
	if(p->rot13)
		rot13(buf);

349
	if(p->uuencoded || p->b64encoded || p->yencoded) {
350
		uulen=len*2;
deuce's avatar
deuce committed
351
		if((uubuf=malloc(uulen))==NULL) {
352
			free(buf);
353
			JS_RESUMEREQUEST(cx, rc);
354
			return(JS_TRUE);
355
		}
356
357
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
358
359
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
360
361
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
362
		if(uulen>=0) {
363
			free(buf);
364
			buf=uubuf;
365
			len=uulen;
deuce's avatar
deuce committed
366
		}
367
368
		else
			free(uubuf);
369
	}
370
	JS_RESUMEREQUEST(cx, rc);
371

372
	str = JS_NewStringCopyN(cx, buf, len);
373
	free(buf);
374

375
376
377
	if(str==NULL)
		return(JS_FALSE);

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

380
	rc=JS_SUSPENDREQUEST(cx);
381
	dbprintf(FALSE, p, "read %u bytes",len);
382
	JS_RESUMEREQUEST(cx, rc);
383
384
385
386
387
		
	return(JS_TRUE);
}

static JSBool
388
js_readln(JSContext *cx, uintN argc, jsval *arglist)
389
{
390
391
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
392
393
	char*		cp;
	char*		buf;
394
	int32		len=512;
395
	JSString*	js_str;
396
	private_t*	p;
deuce's avatar
deuce committed
397
	jsrefcount	rc;
398

399
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
400

401
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
402
		JS_ReportError(cx,getprivate_failure,WHERE);
403
		return(JS_FALSE);
404
	}
405
406
407

	if(p->fp==NULL)
		return(JS_TRUE);
408
	
409
410
411
412
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
413

deuce's avatar
deuce committed
414
415
	if((buf=malloc(len))==NULL)
		return(JS_FALSE);
416

417
	rc=JS_SUSPENDREQUEST(cx);
418
	if(fgets(buf,len,p->fp)!=NULL) {
419
420
421
422
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
423
424
425
426
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
427
428
		if(p->rot13)
			rot13(buf);
429
		JS_RESUMEREQUEST(cx, rc);
430
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
431
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
432
433
	} else {
		JS_RESUMEREQUEST(cx, rc);
434
	}
deuce's avatar
deuce committed
435
	free(buf);
436
437
438
439
440

	return(JS_TRUE);
}

static JSBool
441
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
442
{
443
444
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
445
446
447
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
448
	int32		size=sizeof(DWORD);
449
	private_t*	p;
450
	int32		count=1;
451
452
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
453
	size_t		i;
454
455
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
456
	jsrefcount	rc;
457

458
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
459

460
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
461
		JS_ReportError(cx,getprivate_failure,WHERE);
462
		return(JS_FALSE);
463
	}
464
465
466
467

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

468
	if(argc) {
469
		if(!JS_ValueToInt32(cx,argv[0],&size))
470
			return(JS_FALSE);
471
		if(argc>1) {
472
			if(!JS_ValueToInt32(cx,argv[1],&count))
473
474
				return(JS_FALSE);
		}
475
	}
476

477
	rc=JS_SUSPENDREQUEST(cx);
478
479
480
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
481
		JS_RESUMEREQUEST(cx, rc);
482
483
484
485
486
487
		return(JS_TRUE);
	}

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

end:
	free(buffer);
536
	JS_RESUMEREQUEST(cx, rc);
537
538
539
540
	return(JS_TRUE);
}

static JSBool
541
js_readall(JSContext *cx, uintN argc, jsval *arglist)
542
{
543
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
544
545
    jsint       len=0;
    JSObject*	array;
546
547
	private_t*	p;

548
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
549

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

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

558
    array = JS_NewArrayObject(cx, 0, NULL);
559

560
    while(!feof(p->fp)) {
561
562
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
563
			break;
564
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
565
			break;
566
	}
567
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
568

569
570
    return(JS_TRUE);
}
571

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

deuce's avatar
deuce committed
619
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
620
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
621
	}
deuce's avatar
deuce committed
622
623
624
	return JSVAL_TO_DOUBLE(rval);
}

625
static JSBool
626
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
627
{
628
629
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
630
	char*	section=ROOT_SECTION;
631
	char*	key;
632
	char**	list;
633
	char	buf[INI_MAX_VALUE_LEN];
634
635
	int32	i;
	jsval	val;
636
637
	jsval	dflt=argv[2];
	private_t*	p;
638
	JSObject*	array;
639
640
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
641
642
643
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
644
	char*		cstr=NULL;
deuce's avatar
deuce committed
645
	char*		cstr2;
646

647
648
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

654
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
655
656
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
657
	if(JS_IsExceptionPending(cx)) {
658
659
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
deuce's avatar
deuce committed
660
		return JS_FALSE;
661
	}
662
663
664
665
666
667
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
668
		FREE_AND_NULL(section);
669
670
		return JS_FALSE;
	}
671

672
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
673
		rc=JS_SUSPENDREQUEST(cx);
674
		cstr=iniReadString(p->fp,section,key,NULL,buf);
675
676
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
677
		JS_RESUMEREQUEST(cx, rc);
678
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr));
679
680
681
		return(JS_TRUE);
	}

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

	return(JS_TRUE);
}

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

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

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

782
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
783
784
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
785
	if(JS_IsExceptionPending(cx)) {
786
787
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
788
789
		return JS_FALSE;
	}
790

deuce's avatar
deuce committed
791
	if(value==JSVAL_VOID) { 	/* unspecified value */
792
		rc=JS_SUSPENDREQUEST(cx);
793
		result = iniSetString(list,section,key,"",NULL);
794
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
795
	}
deuce's avatar
deuce committed
796
	else if(JSVAL_IS_BOOLEAN(value)) {
797
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
deuce's avatar
deuce committed
798
799
	}
	else if(JSVAL_IS_DOUBLE(value)) {
800
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),NULL);
deuce's avatar
deuce committed
801
802
	}
	else if(JSVAL_IS_NUMBER(value)) {
803
		if(!JS_ValueToInt32(cx,value,&i)) {
804
805
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
806
807
			return JS_FALSE;
		}
deuce's avatar
deuce committed
808
		rc=JS_SUSPENDREQUEST(cx);
809
		result = iniSetInteger(list,section,key,i,NULL);
deuce's avatar
deuce committed
810
811
812
813
814
815
		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);
816
		result = iniSetDateTime(list,section,key,/* include_time */TRUE, tt,NULL);
deuce's avatar
deuce committed
817
818
		JS_RESUMEREQUEST(cx, rc);
	} else {
819
		cstr=NULL;
820
		JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
821
		if(JS_IsExceptionPending(cx)) {
822
823
824
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
825
826
			return JS_FALSE;
		}
deuce's avatar
deuce committed
827
		rc=JS_SUSPENDREQUEST(cx);
828
829
		result = iniSetString(list,section,key, cstr,NULL);
		FREE_AND_NULL(cstr);
deuce's avatar
deuce committed
830
		JS_RESUMEREQUEST(cx, rc);
831
	}
832
833
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
834

835
	return(result != NULL);
836
837
}

deuce's avatar
deuce committed
838
839
840
841
842
static JSBool
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
	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
863
864

	JS_SET_RVAL(cx, arglist, rval);
865
	return JS_TRUE;
deuce's avatar
deuce committed
866
867
}

868
static JSBool
869
js_iniRemoveKey(JSContext *cx, uintN argc, jsval *arglist)
870
{
871
872
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
873
	char*	section=ROOT_SECTION;
874
	char*	key=NULL;
875
876
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
877
	jsrefcount	rc;
878

879
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
880
881
882
883
884
885
886
887
888

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

889
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
890
891
892
893
894
		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");
895
		FREE_AND_NULL(section);
896
897
		return JS_FALSE;
	}
898

899
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
900
	if((list=iniReadFile(p->fp))==NULL) {
901
		JS_RESUMEREQUEST(cx, rc);
902
903
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
904
		return(JS_TRUE);