js_file.c 73.1 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
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);
}


342
static JSBool
343
js_read(JSContext *cx, uintN argc, jsval *arglist)
344
{
345
346
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
347
	char*		cp;
348
	char*		buf;
349
	char*		uubuf;
350
351
	int32		len;
	int32		offset;
352
	int32		uulen;
353
354
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
355
	jsrefcount	rc;
356

357
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
358

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

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

367
368
369
370
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
371
		rc=JS_SUSPENDREQUEST(cx);
372
373
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
374
375
		if(offset>0)
			len-=offset;
376
		JS_RESUMEREQUEST(cx, rc);
377
378
379
	}
	if(len<0)
		len=512;
380

381
	if((buf=malloc(len+1))==NULL)
382
383
		return(JS_TRUE);

384
	rc=JS_SUSPENDREQUEST(cx);
385
386
387
388
389
390
391
392
	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; 
393
		len=strlen(buf);
394
395
	}

396
397
398
	if(p->rot13)
		rot13(buf);

399
	if(p->uuencoded || p->b64encoded || p->yencoded) {
400
		uulen=len*2;
deuce's avatar
deuce committed
401
		if((uubuf=malloc(uulen))==NULL) {
402
			free(buf);
403
			JS_RESUMEREQUEST(cx, rc);
404
			return(JS_TRUE);
405
		}
406
407
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
408
409
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
410
411
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
412
		if(uulen>=0) {
413
			free(buf);
414
			buf=uubuf;
415
			len=uulen;
deuce's avatar
deuce committed
416
		}
417
418
		else
			free(uubuf);
419
	}
420
	JS_RESUMEREQUEST(cx, rc);
421

422
	str = JS_NewStringCopyN(cx, buf, len);
423
	free(buf);
424

425
426
427
	if(str==NULL)
		return(JS_FALSE);

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

430
	rc=JS_SUSPENDREQUEST(cx);
431
	dbprintf(FALSE, p, "read %u bytes",len);
432
	JS_RESUMEREQUEST(cx, rc);
433
434
435
436
437
		
	return(JS_TRUE);
}

static JSBool
438
js_readln(JSContext *cx, uintN argc, jsval *arglist)
439
{
440
441
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
442
443
	char*		cp;
	char*		buf;
444
	int32		len=512;
445
	JSString*	js_str;
446
	private_t*	p;
deuce's avatar
deuce committed
447
	jsrefcount	rc;
448

449
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
450

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

	if(p->fp==NULL)
		return(JS_TRUE);
458
	
459
460
461
462
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
463

deuce's avatar
deuce committed
464
465
	if((buf=malloc(len))==NULL)
		return(JS_FALSE);
466

467
	rc=JS_SUSPENDREQUEST(cx);
468
	if(fgets(buf,len,p->fp)!=NULL) {
469
470
471
472
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
473
474
475
476
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
477
478
		if(p->rot13)
			rot13(buf);
479
		JS_RESUMEREQUEST(cx, rc);
480
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
481
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
482
483
	} else {
		JS_RESUMEREQUEST(cx, rc);
484
	}
deuce's avatar
deuce committed
485
	free(buf);
486
487
488
489
490

	return(JS_TRUE);
}

static JSBool
491
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
492
{
493
494
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
495
496
497
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
498
	int32		size=sizeof(DWORD);
499
	private_t*	p;
500
	int32		count=1;
501
502
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
503
	size_t		i;
504
505
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
506
	jsrefcount	rc;
507

508
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
509

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

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

518
	if(argc) {
519
		if(!JS_ValueToInt32(cx,argv[0],&size))
520
			return(JS_FALSE);
521
		if(argc>1) {
522
			if(!JS_ValueToInt32(cx,argv[1],&count))
523
524
				return(JS_FALSE);
		}
525
	}
526

527
	rc=JS_SUSPENDREQUEST(cx);
528
529
530
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
531
		JS_RESUMEREQUEST(cx, rc);
532
533
534
535
536
537
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
538
		JS_RESUMEREQUEST(cx, rc);
539
540
541
542
543
544
545
546
547
548
		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):
549
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
550
551
					break;
				case sizeof(WORD):
552
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
553
554
					break;
				case sizeof(DWORD):
555
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
556
					break;
557
			}
558
559
560
		}
	}
	else {
561
		JS_RESUMEREQUEST(cx, rc);
562
563
564
565
566
567
568
569
570
571
572
    	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):
573
					v=UINT_TO_JSVAL(*(l++));
574
					break;
575
			}
deuce's avatar
deuce committed
576
        	if(!JS_SetElement(cx, array, i, &v)) {
577
				rc=JS_SUSPENDREQUEST(cx);
578
				goto end;
deuce's avatar
deuce committed
579
			}
580
		}
581
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
582
	}
583
584
585

end:
	free(buffer);
586
	JS_RESUMEREQUEST(cx, rc);
587
588
589
590
	return(JS_TRUE);
}

static JSBool
591
js_readall(JSContext *cx, uintN argc, jsval *arglist)
592
{
593
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
594
595
    jsint       len=0;
    JSObject*	array;
596
597
	private_t*	p;

598
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
599

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

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

608
    array = JS_NewArrayObject(cx, 0, NULL);
609

610
    while(!feof(p->fp)) {
611
612
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
613
			break;
614
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
615
			break;
616
	}
617
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
618

619
620
    return(JS_TRUE);
}
621

622
623
624
625
626
627
628
629
630
631
632
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++) {
633
		if(*p=='.' && !f)
634
			f=TRUE;
635
		else if(!isdigit((uchar)*p))
636
637
			break;
	}
638
639
640
641
642
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
643
644
645
646
647
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
648
			if(!isxdigit((uchar)*p))
649
650
				break;
		if(*p==0) {	
651
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
652
653
654
655
656
657
658
659
660
661
662
663
664
			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
665
666
667
668
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

deuce's avatar
deuce committed
669
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
670
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
671
	}
deuce's avatar
deuce committed
672
673
674
	return JSVAL_TO_DOUBLE(rval);
}

675
static JSBool
676
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
677
{
678
679
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
680
	char*	section=ROOT_SECTION;
681
	char*	key;
682
	char**	list;
683
	char	buf[INI_MAX_VALUE_LEN];
684
685
	int32	i;
	jsval	val;
686
687
	jsval	dflt=argv[2];
	private_t*	p;
688
	JSObject*	array;
689
690
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
691
692
693
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
694
	char*		cstr=NULL;
deuce's avatar
deuce committed
695
	char*		cstr2;
696

697
698
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

704
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
705
706
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
707
	if(JS_IsExceptionPending(cx)) {
708
709
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
deuce's avatar
deuce committed
710
		return JS_FALSE;
711
	}
712
713
714
715
716
717
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
718
		FREE_AND_NULL(section);
719
720
		return JS_FALSE;
	}
721

722
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
723
		rc=JS_SUSPENDREQUEST(cx);
724
		cstr=iniReadString(p->fp,section,key,NULL,buf);
725
726
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
727
		JS_RESUMEREQUEST(cx, rc);
728
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr));
729
730
731
		return(JS_TRUE);
	}

deuce's avatar
deuce committed
732
733
734
735
736
737
738
	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);
739
			rc=JS_SUSPENDREQUEST(cx);
740
			dbl=(double)iniReadDateTime(p->fp,section,key,tt);
deuce's avatar
deuce committed
741
			dbl *= 1000;
742
			JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
743
744
			date_obj = JS_NewDateObjectMsec(cx, dbl);
			if(date_obj!=NULL) {
deuce's avatar
deuce committed
745
				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
deuce's avatar
deuce committed
746
			}
deuce's avatar
deuce committed
747
748
		}
		else {
749
		    array = JS_NewArrayObject(cx, 0, NULL);
750
			cstr=NULL;
751
			JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
752
			if(JS_IsExceptionPending(cx)) {
753
754
755
				FREE_AND_NULL(cstr);
				FREE_AND_NULL(section);
				FREE_AND_NULL(key);
756
757
				return JS_FALSE;
			}
758
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
759
			list=iniReadStringList(p->fp,section,key,",",cstr);
760
			FREE_AND_NULL(cstr);
761
			JS_RESUMEREQUEST(cx, rc);
762
763
764
765
766
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
767
			rc=JS_SUSPENDREQUEST(cx);
768
			iniFreeStringList(list);
769
			JS_RESUMEREQUEST(cx, rc);
770
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
deuce's avatar
deuce committed
771
772
773
774
775
776
777
778
779
		}
	}
	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)) {
780
		if(!JS_ValueToInt32(cx,dflt,&i)) {
781
782
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
deuce's avatar
deuce committed
783
			return(JS_FALSE);
784
		}
deuce's avatar
deuce committed
785
786
787
788
789
		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 {
790
		cstr=NULL;
791
		JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
792
		if(JS_IsExceptionPending(cx)) {
793
794
795
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
796
797
			return JS_FALSE;
		}
deuce's avatar
deuce committed
798
799
800
801
		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)));
802
		FREE_AND_NULL(cstr);
803
	}
804
805
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
806
807
808
809

	return(JS_TRUE);
}

810
static JSBool
811
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, str_list_t* list)
812
{
rswindell's avatar
rswindell committed
813
	char*	section=ROOT_SECTION;
814
	char*	key=NULL;
815
816
817
818
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
819
	JSObject*	value_obj;
deuce's avatar
deuce committed
820
821
822
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
823
824
825
826
827
828

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

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

832
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
833
834
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
835
	if(JS_IsExceptionPending(cx)) {
836
837
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
838
839
		return JS_FALSE;
	}
840

deuce's avatar
deuce committed
841
	if(value==JSVAL_VOID) { 	/* unspecified value */
842
		rc=JS_SUSPENDREQUEST(cx);
843
		result = iniSetString(list,section,key,"",NULL);
844
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
845
	}
deuce's avatar
deuce committed
846
	else if(JSVAL_IS_BOOLEAN(value)) {
847
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
deuce's avatar
deuce committed
848
849
	}
	else if(JSVAL_IS_DOUBLE(value)) {
850
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),NULL);
deuce's avatar
deuce committed
851
852
	}
	else if(JSVAL_IS_NUMBER(value)) {
853
		if(!JS_ValueToInt32(cx,value,&i)) {
854
855
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
856
857
			return JS_FALSE;
		}
deuce's avatar
deuce committed
858
		rc=JS_SUSPENDREQUEST(cx);
859
		result = iniSetInteger(list,section,key,i,NULL);
deuce's avatar
deuce committed
860
861
862
863
864
865
		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);
866
		result = iniSetDateTime(list,section,key,/* include_time */TRUE, tt,NULL);
deuce's avatar
deuce committed
867
868
		JS_RESUMEREQUEST(cx, rc);
	} else {
869
		cstr=NULL;
870
		JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
871
		if(JS_IsExceptionPending(cx)) {
872
873
874
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
875
876
			return JS_FALSE;
		}
deuce's avatar
deuce committed
877
		rc=JS_SUSPENDREQUEST(cx);
878
879
		result = iniSetString(list,section,key, cstr,NULL);
		FREE_AND_NULL(cstr);
deuce's avatar
deuce committed
880
		JS_RESUMEREQUEST(cx, rc);
881
	}
882
883
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
884

885
	return(result != NULL);
886
887
}

deuce's avatar
deuce committed
888
889
890
891
892
static JSBool
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
	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
913
914

	JS_SET_RVAL(cx, arglist, rval);
915
	return JS_TRUE;
deuce's avatar
deuce committed
916
917
}

918
static JSBool
919
js_iniRemoveKey(JSContext *cx, uintN argc, jsval *arglist)
920
{
921
922
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
923
	char*	section=ROOT_SECTION;
924
	char*	key=NULL;
925
926
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
927
	jsrefcount	rc;
928

929
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
930
931
932
933
934
935
936
937
938

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

939
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
940
941
942
943
944
		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");
945