[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