[mw-devel] MW3 r964 - trunk/src
psycodom at sucs.org
psycodom at sucs.org
Sun May 27 19:05:17 BST 2007
Author: psycodom
Date: 2007-05-27 19:05:17 +0100 (Sun, 27 May 2007)
New Revision: 964
Modified:
trunk/src/js.c
trunk/src/js.h
trunk/src/main.c
trunk/src/script.c
Log:
Sets a 3 second execution time limit on javascripts and allows them to be Ctrl-Ced.
Updates javascript execution errors to use JS_ReportError meaning javascript provides a more useful report which can be supressed.
Fixes floodlimit to work correctly for javascript. (previously only reset if a non javascript function was called between calls)
Modified: trunk/src/js.c
===================================================================
--- trunk/src/js.c 2007-05-21 09:22:26 UTC (rev 963)
+++ trunk/src/js.c 2007-05-27 18:05:17 UTC (rev 964)
@@ -21,6 +21,7 @@
#include "talker_privs.h"
#include "iconv.h"
#include "alias.h"
+#include "alarm.h"
extern Alias alias_list;
extern Alias bind_list;
@@ -41,6 +42,8 @@
static JSRuntime *jsrt = NULL;
static JSContext *jscx = NULL;
static JSObject *jsroot = NULL;
+int js_interrupted=1;
+struct alarm *js_timeout_event=NULL;
enum bindtype { K_BIND=0, K_BIND_EVENT, K_BIND_ONOFF, K_BIND_IPC, K_BIND_FORCE, K_BIND_SHUTDOWN, K_BIND_ALIAS, K_BIND_RPC };
#define K_BROADCAST 1
@@ -102,8 +105,27 @@
return retval;
}
+void js_timeout(void *ptr)
+{
+ js_interrupted=2;
+}
+void js_clear_timeout(void)
+{
+ if(js_timeout_event != NULL)
+ {
+ js_timeout_event->how = NULL;
+ }
+}
+void js_start_timeout(void)
+{
+ js_clear_timeout();
+ alarm_enable();
+ js_timeout_event=alarm_after(3, 0, NULL, &js_timeout);
+}
+
+
/* Function for printing to standard out from javascript (helpful for
* debugging and demonstrates how to call C from js) - also useful for event functions
*/
@@ -171,11 +193,13 @@
int conversion_result;
if (argc < 1) {
return JS_FALSE;
+ JS_ReportError(cx, "say() expects an argument.");
+
}
flood++;
if (flood > flood_limit) {
- printf("FLOOD: This script has flooded the room.\n");
+ JS_ReportError(cx, "FLOOD: This script has flooded the room.");
return JS_FALSE;
}
@@ -183,12 +207,14 @@
conversion_result=jsval_to_utf8string(cx, argv[0], msg, MAXTEXTLENGTH-100);
if( conversion_result >= 0) {
if( conversion_result & WOUTPUTTOOSHORT ) {
- printf("JavaScript say() command produced too much text. It was truncated\n");
+ JS_ReportError(cx, "Warning: say() command produced too much text. It was truncated");
}
chat_say(msg);
return JS_TRUE;
}
}
+ JS_ReportError(cx, "Error: say() expects a string.");
+
return JS_FALSE;
}
@@ -202,7 +228,7 @@
int conversion_result;
if (argc < 3) {
- printf("Error: javascript rpc() expects 3 arguments\n");
+ JS_ReportError(cx, "Error: javascript rpc() expects 3 arguments");
return JS_FALSE;
}
if(JSVAL_IS_INT(argv[0])) {
@@ -214,25 +240,25 @@
if (JSVAL_IS_STRING(argv[0])) {
conversion_result=jsval_to_utf8string(cx, argv[0], username, NAMESIZE+1);
if( conversion_result < 0) {
- printf("Error: javascript rpc(): major argument conversion error\n");
+ JS_ReportError(cx, "Error: javascript rpc(): major argument conversion error");
return JS_FALSE;
}
}
conversion_result=jsval_to_utf8string(cx, argv[1], rpc_type, MAXTEXTLENGTH-100);
if( conversion_result < 0) {
- printf("Error: javascript rpc(): major argument conversion error\n");
+ JS_ReportError(cx, "Error: javascript rpc(): major argument conversion error");
return JS_FALSE;
}
conversion_result=jsval_to_utf8string(cx, argv[2], msg, MAXTEXTLENGTH-100);
if( conversion_result < 0) {
- printf("Error: javascript rpc(): major argument conversion error\n");
+ JS_ReportError(cx, "Error: javascript rpc(): major argument conversion error");
return JS_FALSE;
}
// something is empty
if( (broadcast==0 && username[0]=='\0') || rpc_type[0]=='\0') {
- printf("Error: javascript rpc(): invalid arguments\n");
+ JS_ReportError(cx, "Error: javascript rpc(): invalid arguments");
return JS_FALSE;
}
@@ -249,7 +275,7 @@
int broadcast=0;
int conversion_result;
if (argc < 2) {
- printf("Error: javascript ipc() expects 2 arguments\n");
+ JS_ReportError(cx, "Error: javascript ipc() expects 2 arguments");
return JS_FALSE;
}
if(JSVAL_IS_INT(argv[0])) {
@@ -260,7 +286,7 @@
if (JSVAL_IS_STRING(argv[0])) {
conversion_result=jsval_to_utf8string(cx, argv[0], username, NAMESIZE+1);
if( conversion_result < 0) {
- printf("Error: javascript ipc(): major argument conversion error\n");
+ JS_ReportError(cx, "Error: javascript ipc(): major argument conversion error");
return JS_FALSE;
}
}
@@ -268,12 +294,12 @@
conversion_result=jsval_to_utf8string(cx, argv[1], msg, MAXTEXTLENGTH-100);
if( conversion_result < 0) {
- printf("Error: javascript ipc(): major argument conversion error\n");
+ JS_ReportError(cx, "Error: javascript ipc(): major argument conversion error");
return JS_FALSE;
}
// not broadcast and no username
if(broadcast==0 && username[0]=='\0') {
- printf("Error: javascript ipc(): expects a username or K_BROADCAST\n");
+ JS_ReportError(cx, "Error: javascript ipc(): expects a username or K_BROADCAST");
return JS_FALSE;
}
@@ -318,7 +344,9 @@
}
busy++;
+ js_clear_timeout();
if ((line=readline(prompt))==NULL) line=strdup("");
+ js_start_timeout();
busy--;
free(prompt);
@@ -358,10 +386,10 @@
beeps=JSVAL_TO_INT(argv[0]);
if(beeps < 1 || beeps > 5) {
beeps=0;
- printf("Warning: javascript beep will only do between 1 and 5 beeps.\n");
+ JS_ReportError(cx, "Warning: javascript beep will only do between 1 and 5 beeps.");
}
} else {
- printf("Warning: javascript beep command expects an integer.\n");
+ JS_ReportError(cx, "Warning: javascript beep command expects an integer.");
}
for(i=0;i<beeps;i++)
{
@@ -380,14 +408,14 @@
int bind_type=-1;
int i=1;
if (argc < 2) {
- printf("Error in javascript: bind expects 2 arguments\n");
+ JS_ReportError(cx, "Error in javascript: bind expects 2 arguments");
return JS_TRUE;
}
if (JSVAL_IS_STRING(argv[0])) {
conversion_result=jsval_to_utf8string(cx, argv[0], bind, MAXTEXTLENGTH-100);
if( conversion_result != 0) {
- printf("Error in string conversion binding javascript\n");
+ JS_ReportError(cx, "Error in string conversion binding javascript");
return JS_TRUE;
}
@@ -398,30 +426,30 @@
i++;
conversion_result=jsval_to_utf8string(cx, argv[1], bind, MAXTEXTLENGTH-100);
if( conversion_result != 0) {
- printf("Error in string conversion binding javascript\n");
+ JS_ReportError(cx, "Error in string conversion binding javascript");
return JS_TRUE;
}
}
} else {
- printf("Error in javascript: bind expects first argument to be a string or a recognised bind id\n");
+ JS_ReportError(cx, "Error in javascript: bind expects first argument to be a string or a recognised bind id");
return JS_TRUE;
}
if (argc>= i-1 && JSVAL_IS_STRING(argv[i])) {
conversion_result=jsval_to_utf8string(cx, argv[i], function_name, MAXTEXTLENGTH-100);
if( conversion_result != 0) {
- printf("Error in string conversion binding javascript\n");
+ JS_ReportError(cx, "Error in string conversion binding javascript");
return JS_TRUE;
}
} else {
- printf("Error in javascript: bind expects final argument to be a string.\n");
+ JS_ReportError(cx, "Error in javascript: bind expects final argument to be a string.");
return JS_TRUE;
}
switch(bind_type) {
case K_BIND:
if(bind[0]=='\0') {
- printf("Error: Empty bind\n");
+ JS_ReportError(cx, "Error: Empty bind");
return JS_TRUE;
}
if (AddLink(&bind_list, bind, function_name))
@@ -490,6 +518,117 @@
return JS_TRUE;
}
+/* bind something to a javascript function */
+static JSBool js_unbind(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval)
+{
+ char bind[MAXTEXTLENGTH]="";
+ char function_name[MAXTEXTLENGTH]="";
+ int conversion_result;
+ int bind_type=-1;
+ int i=1;
+ if (argc < 2) {
+ JS_ReportError(cx, "Error in javascript: unbind expects 2 arguments");
+ return JS_TRUE;
+ }
+
+ if (JSVAL_IS_STRING(argv[0])) {
+ conversion_result=jsval_to_utf8string(cx, argv[0], bind, MAXTEXTLENGTH-100);
+ if( conversion_result != 0) {
+ JS_ReportError(cx, "Error in string conversion binding javascript");
+ return JS_TRUE;
+
+ }
+ bind_type=K_BIND;
+ } else if (JSVAL_IS_INT(argv[0])) {
+ bind_type=JSVAL_TO_INT(argv[0]);
+ } else {
+ JS_ReportError(cx, "Error in javascript: bind expects first argument to be a string or a recognised bind id");
+ return JS_TRUE;
+ }
+ if (argc>= i-1 && JSVAL_IS_STRING(argv[i])) {
+ conversion_result=jsval_to_utf8string(cx, argv[i], function_name, MAXTEXTLENGTH-100);
+ if( conversion_result != 0) {
+ JS_ReportError(cx, "Error in string conversion binding javascript");
+ return JS_TRUE;
+
+ }
+ } else {
+ JS_ReportError(cx, "Error in javascript: bind expects final argument to be a string.");
+ return JS_TRUE;
+ }
+
+ switch(bind_type) {
+ case K_BIND:
+ if(bind[0]=='\0') {
+ JS_ReportError(cx, "Error: Empty bind");
+ return JS_TRUE;
+ }
+ if(DestroyLink(&bind_list, bind))
+ {
+ printf("Bind %s does not exist for unbinding.\n", bind);
+ }
+
+ break;
+ case K_BIND_ALIAS:
+ if(bind[0]=='\0') {
+ printf("Error: Empty bind\n");
+ return JS_TRUE;
+ }
+ if (DestroyLink(&alias_list, bind))
+ {
+ printf("Alias %s does not exist for unbinding.\n", bind);
+ }
+
+ break;
+ case K_BIND_RPC:
+ if(bind[0]=='\0') {
+ printf("Error: Empty bind\n");
+ return JS_TRUE;
+ }
+ if (DestroyLink(&rpc_list, bind))
+ {
+ printf("RPC %s does not exist for unbinding.\n", bind);
+ }
+
+ break;
+ case K_BIND_EVENT:
+ if(DestroyLink(&event_list, function_name))
+ {
+ printf("Event bind %s does not exist for unbinding.\n", function_name);
+ }
+ break;
+ case K_BIND_ONOFF:
+ if(DestroyLink(&onoff_list, function_name))
+ {
+ printf("CheckOnOff bind %s does not exist for unbinding.\n", function_name);
+ }
+ break;
+ case K_BIND_IPC:
+ if(DestroyLink(&ipc_list, function_name))
+ {
+ printf("IPC bind %s does not exist for unbinding.\n", function_name);
+ }
+ break;
+ case K_BIND_FORCE:
+ if(DestroyLink(&force_list, function_name))
+ {
+ printf("Force bind %s does not exist for unbinding.\n", function_name);
+ }
+ break;
+ case K_BIND_SHUTDOWN:
+ if(DestroyLink(&shutdown_list, function_name))
+ {
+ printf("Shutdown bind %s does not exist for unbinding.\n", function_name);
+ }
+
+ break;
+ default:
+ printf("Unknown unbind type %d\n", bind_type);
+ break;
+ }
+ return JS_TRUE;
+}
+
// return the users terminal dimensions
static JSBool js_termsize(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval)
{
@@ -500,6 +639,8 @@
result_object=JS_NewObject(cx, &js_termsizeclass, NULL, NULL);
if(result_object==NULL)
{
+ JS_ReportError(cx, "An error occured creating an object to hold the term dimensions.");
+
return JS_FALSE;
}
jv=OBJECT_TO_JSVAL(result_object);
@@ -525,8 +666,11 @@
wfile=openwhofile(O_RDWR);
ufile=openuserfile(O_RDONLY);
- if (wfile<0 || ufile<0) return JS_FALSE;
-
+ if (wfile<0 || ufile<0) {
+ JS_ReportError(cx, "wholist() could not open userdb.");
+
+ return JS_FALSE;
+ }
res = JS_NewArrayObject(cx, 0, NULL);
JS_AddRoot(cx, res);
@@ -751,20 +895,22 @@
JSBool retval;
if ((pw=getpwuid(getuid()))==NULL) {
- fprintf(stderr, "Error getting user information\n");
+ JS_ReportError(cx, "Error getting user information");
return JS_FALSE;
}
if (strcasecmp(pw->pw_name, "bbs")==0) {
- printf("bbs user is not allowed db access\n");
+ JS_ReportError(cx, "bbs user is not allowed db access");
return JS_FALSE;
}
if (argc != 2) {
+ JS_ReportError(cx, "Error: db_query expects two arguments");
return JS_FALSE;
}
if (!(JSVAL_IS_STRING(argv[0]) && JSVAL_IS_STRING(argv[1]))) {
+ JS_ReportError(cx, "Error: db_query strings");
return JS_FALSE;
}
@@ -772,13 +918,14 @@
conversion_result=jsval_to_utf8string(cx, argv[1], query, MAXTEXTLENGTH*2);
//query = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
if(conversion_result != 0) {
+ JS_ReportError(cx, "String conversion error");
return JS_FALSE;
}
if (dbname[0] == '/'
|| strncmp(dbname, "../", 3)==0
|| strstr(dbname, "/../")) {
- printf("Illegal path element in dbname '%s'\n", dbname);
+ JS_ReportError(cx, "Illegal path element in dbname '%s'", dbname);
return JS_FALSE;
}
snprintf(path, sizeof(path), "%s/%s", pw->pw_dir, dbname);
@@ -789,7 +936,7 @@
seteuid(myid);
if (!dbres) {
- printf("Major error in javascript database query.\n");
+ JS_ReportError(cx, "Major error in javascript database query.");
return JS_FALSE;
}
@@ -865,13 +1012,15 @@
}
}
-
+ js_interrupted=0;
+ js_start_timeout();
ret = JS_CallFunctionName(jscx, jsroot, name, argc, argv, &rval);
if (ret) {
if (JSVAL_IS_BOOLEAN(rval) && JSVAL_TO_BOOLEAN(rval)==0) {
script_output=0;
}
}
+ js_clear_timeout();
//show_type("js_exec(rval)", rval);
free(argv);
JS_GC(jscx); // do we still need to do this now the actual bug has been found?
@@ -986,12 +1135,14 @@
}
/* Execute the compiled script */
+ js_interrupted=0;
+ js_start_timeout();
success = JS_ExecuteScript(jscx, jsroot, script, &retval);
if (success == JS_FALSE) {
printf("Failed to execute js script: %s\n", filename);
return 0;
}
-
+ js_clear_timeout();
// now the script has been run we can destroy it (the context retains the functions/objects it created)
JS_DestroyScript(jscx, script);
@@ -1017,6 +1168,34 @@
return 0;
}
+JSBool js_branch_callback(JSContext *cx, JSScript *script) {
+ JSObject *global = JS_GetGlobalObject(cx);
+ if (global) {
+ if (js_interrupted==1) {
+ JS_ReportError(cx,"Script execution interupted");
+ return JS_FALSE;
+ } else if (js_interrupted==2) {
+ JS_ReportError(cx,"Script execution time exceeded 3 second limit");
+ return JS_FALSE;
+ }
+
+ }
+
+ return JS_TRUE;
+}
+
+
+
+void js_stop_execution(void)
+{
+ js_interrupted=1;
+}
+
+int js_isrunning(void)
+{
+ return JS_IsRunning(jscx);
+}
+
// cleans up the javascript environment
int stop_js(void)
{
@@ -1060,7 +1239,11 @@
/* initiate builtin classes */
builtins = JS_InitStandardClasses(jscx, jsroot);
-
+
+ /* create a callback function that is run when javascript branches backwards */
+ /* allows us to interupt looping scripts */
+ JS_SetBranchCallback(jscx, js_branch_callback);
+
/* initiate local stuff */
JS_DefineFunction(jscx, jsroot, "print", js_print, 1, 0);
@@ -1077,6 +1260,7 @@
JS_DefineFunction(jscx, jsroot, "termsize", js_termsize, 0, 0);
JS_DefineFunction(jscx, jsroot, "bind", js_bind, 2, 0);
+ JS_DefineFunction(jscx, jsroot, "unbind", js_unbind, 2, 0);
// Set the bind type constants
JS_DefineProperty(jscx, jsroot, "K_BIND_EVENT", INT_TO_JSVAL(K_BIND_EVENT), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
Modified: trunk/src/js.h
===================================================================
--- trunk/src/js.h 2007-05-21 09:22:26 UTC (rev 963)
+++ trunk/src/js.h 2007-05-27 18:05:17 UTC (rev 964)
@@ -1,7 +1,9 @@
/* js.c */
+int js_isrunning();
int js_exec(char *name, int argc, char **argvc);
int load_jsfile(FILE *f, char *filename);
int load_js(char *filename);
int is_js(char *name);
+void js_stop_execution(void);
int stop_js(void);
int setup_js(void);
Modified: trunk/src/main.c
===================================================================
--- trunk/src/main.c 2007-05-21 09:22:26 UTC (rev 963)
+++ trunk/src/main.c 2007-05-27 18:05:17 UTC (rev 964)
@@ -1435,6 +1435,11 @@
script_terminate = 2;
write(1, msg, strlen(msg));
}
+ if (js_isrunning())
+ {
+ js_stop_execution();
+ write(1, msg, strlen(msg));
+ }
}
void time_out(void *idle_count_p)
Modified: trunk/src/script.c
===================================================================
--- trunk/src/script.c 2007-05-21 09:22:26 UTC (rev 963)
+++ trunk/src/script.c 2007-05-27 18:05:17 UTC (rev 964)
@@ -657,6 +657,7 @@
int num;
int i;
char *function_name;
+ flood=0;
if ((num=ParseLine(line, bits))<1) return;
@@ -670,7 +671,6 @@
return;
}
runaway=0;
- flood=0;
script_terminate=0;
script_jump=NULL;
compare_count=0;
More information about the mw-devel
mailing list