Commit f45e2156 authored by rswindell's avatar rswindell
Browse files

Added JS load() search path extensibility:

Configurable via ctrl/sbbs.ini file JavaScriptLoadPath key value
(comma-separate listed of search directories), default value is "load".
This list is exposed in the JS object model via the js.load_path_list array
(may be modified by scripts).
For JSexec, the default load path list may be over-ridden with the '-i' option.
For relative load paths (e.g. not beginning with '/' or '\'), the path is
assumed to be a sub-directory of the (configurable) mods or exec directories
and is searched accordingly.
So, by default, load("somefile.js") will search in this order:
mods/load/somefile.js
exec/load/somefile.js
mods/somefile.js
exec/somefile.js
parent ec07bbb6
......@@ -503,7 +503,7 @@ js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp)
do {
lprintf(LOG_DEBUG,"%04d JavaScript: Initializing Global object",sock);
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL))==NULL)
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL, &startup->js))==NULL)
break;
if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
......
......@@ -55,8 +55,9 @@
#ifdef JAVASCRIPT
typedef struct {
scfg_t *cfg;
jsSyncMethodSpec *methods;
scfg_t* cfg;
jsSyncMethodSpec* methods;
js_startup_t* startup;
} private_t;
/* Global Object Properites */
......@@ -253,11 +254,13 @@ js_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
bg->parent_cx = cx;
/* Setup default values for branch settings */
bg->branch.limit=JAVASCRIPT_BRANCH_LIMIT;
bg->branch.gc_interval=JAVASCRIPT_GC_INTERVAL;
bg->branch.yield_interval=JAVASCRIPT_YIELD_INTERVAL;
bg->branch.limit=p->startup->branch_limit;
bg->branch.gc_interval=p->startup->gc_interval;
bg->branch.yield_interval=p->startup->yield_interval;
#if 0
if(JS_GetProperty(cx, obj,"js",&val)) /* copy branch settings from parent */
memcpy(&bg->branch,JS_GetPrivate(cx,JSVAL_TO_OBJECT(val)),sizeof(bg->branch));
#endif
bg->branch.terminated=NULL; /* could be bad pointer at any time */
bg->branch.counter=0;
bg->branch.gc_attempts=0;
......@@ -277,6 +280,7 @@ js_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
,"" /* hostname */
,"" /* socklib_desc */
,&bg->branch /* js */
,p->startup /* js */
,NULL /* client */
,INVALID_SOCKET /* client_socket */
,NULL /* server props */
......@@ -340,11 +344,45 @@ js_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
rc=JS_SUSPENDREQUEST(cx);
errno = 0;
if(isfullpath(filename))
strcpy(path,filename);
SAFECOPY(path,filename);
else {
sprintf(path,"%s%s",p->cfg->mods_dir,filename);
if(p->cfg->mods_dir[0]==0 || !fexistcase(path))
sprintf(path,"%s%s",p->cfg->exec_dir,filename);
path[0]=0;
if(JS_GetProperty(cx, obj, "js", &val)) {
JSObject* js = JSVAL_TO_OBJECT(val);
if(JS_GetProperty(cx, js, JAVASCRIPT_LOAD_PATH_LIST, &val) && JSVAL_IS_OBJECT(val)) {
JSObject* list = JSVAL_TO_OBJECT(val);
jsuint i;
char prefix[MAX_PATH+1];
for(i=0;path[0]==0;i++) {
if(!JS_GetElement(cx, list, i, &val) || val==JSVAL_VOID)
break;
if(!JSVAL_IS_STRING(val))
continue;
SAFECOPY(prefix,js_ValueToStringBytes(cx, val, NULL));
if(prefix[0]==0)
continue;
backslash(prefix);
if(isfullpath(prefix)) {
SAFEPRINTF2(path,"%s%s",prefix,filename);
if(!fexistcase(path))
path[0]=0;
} else {
/* relative path */
SAFEPRINTF3(path,"%s%s%s",p->cfg->mods_dir,prefix,filename);
if(p->cfg->mods_dir[0]==0 || !fexistcase(path)) {
SAFEPRINTF3(path,"%s%s%s",p->cfg->exec_dir,prefix,filename);
if(!fexistcase(path))
path[0]=0;
}
}
}
}
}
if(path[0]==0) {
SAFEPRINTF2(path,"%s%s",p->cfg->mods_dir,filename);
if(p->cfg->mods_dir[0]==0 || !fexistcase(path))
SAFEPRINTF2(path,"%s%s",p->cfg->exec_dir,filename);
}
}
JS_RESUMEREQUEST(cx, rc);
......@@ -3433,7 +3471,7 @@ static JSClass js_global_class = {
,js_global_finalize /* finalize */
};
JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods)
JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t* startup)
{
JSObject* glob;
private_t* p;
......@@ -3443,6 +3481,7 @@ JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethod
p->cfg = cfg;
p->methods = methods;
p->startup = startup;
if((glob = JS_NewObject(cx, &js_global_class, NULL, NULL)) ==NULL)
return(NULL);
......@@ -3469,6 +3508,7 @@ JSObject* DLLCALL js_CreateCommonObjects(JSContext* js_cx
,char* host_name /* system */
,char* socklib_desc /* system */
,js_branch_t* branch /* js */
,js_startup_t* js_startup /* js */
,client_t* client /* client */
,SOCKET client_socket /* client */
,js_server_props_t* props /* server */
......@@ -3480,7 +3520,7 @@ JSObject* DLLCALL js_CreateCommonObjects(JSContext* js_cx
node_cfg=cfg;
/* Global Object */
if((js_glob=js_CreateGlobalObject(js_cx, cfg, methods))==NULL)
if((js_glob=js_CreateGlobalObject(js_cx, cfg, methods, js_startup))==NULL)
return(NULL);
/* System Object */
......@@ -3489,7 +3529,7 @@ JSObject* DLLCALL js_CreateCommonObjects(JSContext* js_cx
/* Internal JS Object */
if(branch!=NULL
&& js_CreateInternalJsObject(js_cx, js_glob, branch)==NULL)
&& js_CreateInternalJsObject(js_cx, js_glob, branch, js_startup)==NULL)
return(NULL);
/* Client Object */
......
......@@ -441,7 +441,7 @@ void DLLCALL js_EvalOnExit(JSContext *cx, JSObject *obj, js_branch_t* branch)
branch->auto_terminate = auto_terminate;
}
JSObject* DLLCALL js_CreateInternalJsObject(JSContext* cx, JSObject* parent, js_branch_t* branch)
JSObject* DLLCALL js_CreateInternalJsObject(JSContext* cx, JSObject* parent, js_branch_t* branch, js_startup_t* startup)
{
JSObject* obj;
......@@ -452,6 +452,30 @@ JSObject* DLLCALL js_CreateInternalJsObject(JSContext* cx, JSObject* parent, js_
if(!JS_SetPrivate(cx, obj, branch)) /* Store a pointer to js_branch_t */
return(NULL);
if(startup!=NULL) {
JSObject* load_path_list;
jsval val;
if((load_path_list=JS_NewArrayObject(cx, 0, NULL))==NULL)
return(NULL);
val=OBJECT_TO_JSVAL(load_path_list);
if(!JS_SetProperty(cx, obj, JAVASCRIPT_LOAD_PATH_LIST, &val))
return(NULL);
if(startup->load_path!=NULL) {
JSString* js_str;
unsigned i;
for(i=0; startup->load_path[i]!=NULL; i++) {
if((js_str=JS_NewStringCopyZ(cx, startup->load_path[i]))==NULL)
return(NULL);
val=STRING_TO_JSVAL(js_str);
if(!JS_SetElement(cx, load_path_list, i, &val))
return(NULL);
}
}
}
#ifdef BUILD_JSDOCS
js_DescribeSyncObject(cx,obj,"JavaScript execution and garbage collection control object",311);
js_CreateArrayOfStrings(cx, obj, "_property_desc_list", prop_desc, JSPROP_READONLY);
......
......@@ -67,6 +67,7 @@ char revision[16];
char compiler[32];
char* host_name=NULL;
char host_name_buf[128];
char* load_path_list=JAVASCRIPT_LOAD_PATH;
BOOL pause_on_exit=FALSE;
BOOL pause_on_error=FALSE;
BOOL terminated=FALSE;
......@@ -116,6 +117,7 @@ void usage(FILE* fp)
"\t-u<mask> set file creation permissions mask (in octal)\n"
"\t-L<level> set log level (default=%u)\n"
"\t-E<level> set error log level threshold (default=%d)\n"
"\t-i<path_list> set load() comma-sep search path list (default=\"%s\")\n"
"\t-f use non-buffered stream for console messages\n"
"\t-a append instead of overwriting message output files\n"
"\t-e<filename> send error messages to file in addition to stderr\n"
......@@ -135,6 +137,7 @@ void usage(FILE* fp)
,JAVASCRIPT_GC_INTERVAL
,DEFAULT_LOG_LEVEL
,DEFAULT_ERR_LOG_LVL
,load_path_list
,_PATH_DEVNULL
,_PATH_DEVNULL
);
......@@ -612,6 +615,11 @@ static BOOL js_CreateEnvObject(JSContext* cx, JSObject* glob, char** env)
static BOOL js_init(char** environ)
{
js_startup_t startup;
memset(&startup,0,sizeof(startup));
startup.load_path=strListSplit(NULL, load_path_list, ",");
fprintf(statfp,"%s\n",(char *)JS_GetImplementationVersion());
fprintf(statfp,"JavaScript: Creating runtime: %lu bytes\n"
......@@ -636,7 +644,7 @@ static BOOL js_init(char** environ)
/* Global Object */
if((js_glob=js_CreateCommonObjects(js_cx, &scfg, NULL, js_global_functions
,time(NULL), host_name, SOCKLIB_DESC /* system */
,&branch /* js */
,&branch,&startup /* js */
,NULL,INVALID_SOCKET /* client */
,NULL /* server */
))==NULL) {
......@@ -970,6 +978,10 @@ int main(int argc, char **argv, char** environ)
if(*p==0) p=argv[++argn];
SAFECOPY(scfg.ctrl_dir,p);
break;
case 'i':
if(*p==0) p=argv[++argn];
load_path_list=p;
break;
case 'v':
banner(statfp);
fprintf(statfp,"%s\n",(char *)JS_GetImplementationVersion());
......
......@@ -8,7 +8,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2008 Rob Swindell - http://www.synchro.net/copyright.html *
* Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -138,7 +138,7 @@ static struct init_field mail_init_fields[] = {
#define MAIL_OPT_DNSBL_BADUSER (1<<17) /* Refuse mail (bad user name) */
#define MAIL_OPT_DNSBL_CHKRECVHDRS (1<<18) /* Check all Recieved: from addresses */
#define MAIL_OPT_DNSBL_THROTTLE (1<<19) /* Throttle receive from blacklisted servers */
#define MAIL_OPT_DNSBL_DEBUG (1<<20) /* Debug DNSBL activity */
#define MAIL_OPT_DNSBL_SPAMHASH (1<<20) /* Store hashes of ignored or tagged messages in spam.hash */
#define MAIL_OPT_SMTP_AUTH_VIA_IP (1<<21) /* Allow SMTP authentication via IP */
#define MAIL_OPT_SEND_INTRANSIT (1<<22) /* Send mail, even if already "in transit" */
#define MAIL_OPT_RELAY_AUTH_PLAIN (1<<23)
......@@ -177,7 +177,7 @@ static ini_bitdesc_t mail_options[] = {
{ MAIL_OPT_DNSBL_BADUSER ,"DNSBL_BADUSER" },
{ MAIL_OPT_DNSBL_CHKRECVHDRS ,"DNSBL_CHKRECVHDRS" },
{ MAIL_OPT_DNSBL_THROTTLE ,"DNSBL_THROTTLE" },
{ MAIL_OPT_DNSBL_DEBUG ,"DNSBL_DEBUG" },
{ MAIL_OPT_DNSBL_SPAMHASH ,"DNSBL_SPAMHASH" },
{ MAIL_OPT_SEND_INTRANSIT ,"SEND_INTRANSIT" },
{ MAIL_OPT_RELAY_AUTH_PLAIN ,"RELAY_AUTH_PLAIN" },
{ MAIL_OPT_RELAY_AUTH_LOGIN ,"RELAY_AUTH_LOGIN" },
......
......@@ -1066,6 +1066,7 @@ bool sbbs_t::js_init(ulong* stack_frame)
if((js_glob=js_CreateCommonObjects(js_cx, &scfg, &cfg, js_global_functions
,uptime, startup->host_name, SOCKLIB_DESC /* system */
,&js_branch /* js */
,&startup->js
,&client, client_socket /* client */
,&js_server_props /* server */
))==NULL)
......
......@@ -119,8 +119,8 @@ extern int thread_suid_broken; /* NPTL is no longer broken */
/***********************/
/* Synchronet-specific */
/***********************/
#include "startup.h"
#ifdef __cplusplus
#include "startup.h"
#include "threadwrap.h" /* pthread_mutex_t */
#endif
......@@ -1001,7 +1001,7 @@ extern "C" {
,js_server_props_t* props);
/* js_global.c */
DLLEXPORT JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods);
DLLEXPORT JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t*);
DLLEXPORT JSObject* DLLCALL js_CreateCommonObjects(JSContext* cx
,scfg_t* cfg /* common */
,scfg_t* node_cfg /* node-specific */
......@@ -1009,14 +1009,15 @@ extern "C" {
,time_t uptime /* system */
,char* host_name /* system */
,char* socklib_desc /* system */
,js_branch_t* js_branch /* js */
,js_branch_t* /* js */
,js_startup_t* /* js */
,client_t* client /* client */
,SOCKET client_socket /* client */
,js_server_props_t* props /* server */
);
/* js_internal.c */
DLLEXPORT JSObject* DLLCALL js_CreateInternalJsObject(JSContext*, JSObject* parent, js_branch_t* branch);
DLLEXPORT JSObject* DLLCALL js_CreateInternalJsObject(JSContext*, JSObject* parent, js_branch_t*, js_startup_t*);
DLLEXPORT JSBool DLLCALL js_CommonBranchCallback(JSContext*, js_branch_t*);
DLLEXPORT void DLLCALL js_EvalOnExit(JSContext*, JSObject*, js_branch_t*);
......
......@@ -8,7 +8,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2008 Rob Swindell - http://www.synchro.net/copyright.html *
* Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -65,6 +65,7 @@ static const char* strJavaScriptThreadStack ="JavaScriptThreadStack";
static const char* strJavaScriptBranchLimit ="JavaScriptBranchLimit";
static const char* strJavaScriptGcInterval ="JavaScriptGcInterval";
static const char* strJavaScriptYieldInterval ="JavaScriptYieldInterval";
static const char* strJavaScriptLoadPath ="JavaScriptLoadPath";
static const char* strSemFileCheckFrequency ="SemFileCheckFrequency";
#define DEFAULT_LOG_LEVEL LOG_DEBUG
......@@ -125,6 +126,8 @@ void sbbs_get_js_settings(
,js_startup_t* js
,js_startup_t* defaults)
{
str_list_t load_path;
js->max_bytes = iniGetInteger(list,section,strJavaScriptMaxBytes ,defaults->max_bytes);
js->cx_stack = iniGetInteger(list,section,strJavaScriptContextStack ,defaults->cx_stack);
js->thread_stack = iniGetInteger(list,section,strJavaScriptThreadStack ,defaults->thread_stack);
......@@ -132,6 +135,11 @@ void sbbs_get_js_settings(
js->gc_interval = iniGetInteger(list,section,strJavaScriptGcInterval ,defaults->gc_interval);
js->yield_interval = iniGetInteger(list,section,strJavaScriptYieldInterval ,defaults->yield_interval);
iniFreeStringList(js->load_path);
if((load_path = iniGetStringList(list, section,strJavaScriptLoadPath,",",NULL)) == NULL)
load_path = defaults->load_path;
js->load_path = load_path;
sbbs_fix_js_settings(js);
}
......@@ -229,6 +237,7 @@ static void get_ini_globals(str_list_t list, global_startup_t* global)
global->js.branch_limit = JAVASCRIPT_BRANCH_LIMIT;
global->js.gc_interval = JAVASCRIPT_GC_INTERVAL;
global->js.yield_interval = JAVASCRIPT_YIELD_INTERVAL;
global->js.load_path = strListSplit(NULL, JAVASCRIPT_LOAD_PATH, ",");
/* Read .ini values here */
sbbs_get_js_settings(list, section, &global->js, &global->js);
......
......@@ -76,6 +76,8 @@
#define JAVASCRIPT_BRANCH_LIMIT 99999999
#define JAVASCRIPT_YIELD_INTERVAL 10000
#define JAVASCRIPT_GC_INTERVAL 100
#define JAVASCRIPT_LOAD_PATH "load"
#define JAVASCRIPT_LOAD_PATH_LIST "load_path_list"
typedef struct {
ulong counter;
......@@ -391,6 +393,7 @@ typedef enum { /* Values for xtrn_t.event */
#define XTRN_SH (1<<18) /* Use command shell to execute */
#define XTRN_PAUSE (1<<19) /* Force a screen pause on exit */
#define XTRN_NOECHO (1<<20) /* Don't echo stdin to stdout */
#define QUOTEWRAP (1<<21) /* Word-wrap the quoted text */
/* Bits in cfg.xtrn_misc */
#define XTRN_NO_MUTEX (1<<0) /* Do not use exec_mutex for FOSSIL VXD */
......
......@@ -846,14 +846,14 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
JS_SetContextPrivate(js_cx, service_client);
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL))==NULL)
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL, &service_client->service->js))==NULL)
break;
if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
break;
/* Internal JS Object */
if(js_CreateInternalJsObject(js_cx, js_glob, &service_client->branch)==NULL)
if(js_CreateInternalJsObject(js_cx, js_glob, &service_client->branch, &service_client->service->js)==NULL)
break;
/* Client Object */
......
......@@ -52,6 +52,7 @@ typedef struct {
ulong branch_limit; /* maximum number of branches (for infinite loop detection) */
ulong gc_interval; /* number of branches between garbage collection attempts */
ulong yield_interval; /* number of branches between time-slice yields */
str_list_t load_path; /* additional directories to search for load()ed scripts */
} js_startup_t;
typedef struct {
......
......@@ -3663,7 +3663,7 @@ static BOOL exec_cgi(http_session_t *session)
/* Check socket for received POST Data */
if(!socket_check(session->socket, &rd, NULL, /* timeout: */0)) {
lprintf(LOG_WARNING,"%04d CGI Socket disconected", session->socket);
lprintf(LOG_WARNING,"%04d CGI Socket disconnected", session->socket);
break;
}
if(rd) {
......@@ -4452,6 +4452,7 @@ js_initcx(http_session_t *session)
,startup->host_name /* system */
,SOCKLIB_DESC /* system */
,&session->js_branch /* js */
,&startup->js /* js */
,&session->client /* client */
,session->socket /* client */
,&js_server_props /* server */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment