Created
May 11, 2011 03:09
-
-
Save Maxdamantus/965852 to your computer and use it in GitHub Desktop.
XJS thing from a while ago
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
XJS - JavaScript (SpiderMonkey) plugin for XChat, by Maxdamantus | |
http://ntus.uni.cc/xjs | |
http://ntus.uni.cc/xjs/xjs-8.c | |
== Description == | |
This is a fairly simple extension, which allows for JavaScript scripts and code | |
to be used in XChat. The /js command usage: | |
Usage: /js e <code> - evaluate code in the "<commandline>" context | |
/js o <file> - create new context, executing code from <file> | |
/js i <id> <code> - inject <code> into context <id> | |
/js l - list existing contexts | |
/js k <id> - kill context <id> | |
== Compilation == | |
You'll need to have xchat-plugin.h in the compilation directory (http://xchat.org/docs/xchat-plugin.h), | |
and know where the include path is for SpiderMonkey (usually /usr/include/js), and the library name | |
(seems to differ between libjs and libmozjs, and if the library is in a funny path, that path | |
(specify with -L)) | |
There's a compiler command (uses gcc - might work with other compilers, who knows? Not me (I'm lazy)) | |
in the comments of the .c file | |
It doesn't want to work in Windows - the DLL system seems a real mess (that's all | |
that should be in the way, other than removal of the XP_UNIX define), if you get it to load, let me | |
know (Freenode) | |
== Stuff == | |
The xjs directory is "xjs", under your XChat home directory, eg: ($HOME/.xchat2/xjs) | |
It holds scripts which are loaded by the /js command, or the load() function | |
== Wrapper interface == | |
I made a wrapper interface which is more JS-like, http://ntus.uni.cc/xjs/xchat.js | |
Put it in the xjs directory and load it with load("xchat.js") in scripts | |
== Functions == | |
A brief overview of JavaScript functions provided by the extension, most are somewhat simplified | |
versions of the normal XChat plugin interface: | |
* print(str, ..) | |
- Prints (to the current context) each argument passed, separated by a newline | |
* xchat_print(str) | |
- Prints the string, <str> | |
* xchat_emit_print(name, arg, ..) | |
- Check XChat plugin docs for description | |
- Returns 1 on success, 0 on failure | |
* xchat_command(cmd) | |
- Does <cmd> in the current context (no first slash) | |
* xchat_get_prefs(name) | |
- Gets the value of the XChat preference <name> | |
- Returns the value (boolean, number, or string) or undefined on failure | |
* xchat_send_modes(nicks [,perline ], sign, mode) | |
- <nicks> is an array of nicks to set <sign><mode> on, with optionally <perline> modes per line | |
eg: xchat_send_modes(["Alex", "Pete", "Georgie", "Dim"], 2, "-", "v") | |
* xchat_nickcmp(a, b) | |
- Compare nicks/channels a and b, according to the context's server | |
- Returns < 0, 0, or > 0, refer to XChat plugin docs | |
* xchat_hook_command(name, pri, callback, help) | |
- Hooks the callback function <callback> to command <name> with priority <pri> and help text <help> | |
Refer to XChat plugin docs for callback function, though there's no userdata here | |
- Returns a unique hook object | |
* xchat_hook_timer(timeout, callback) | |
- Creates a timer that calls <callback> after <timeout> ms (no args) | |
If the callback returns non-zero, the callback is called again after <timeout> ms | |
- Returns a unique hook object | |
* xchat_hook_server(name, pri, callback) | |
- Hooks the callback <callback> to server message <name>, refer to XChat plugin docs | |
Callback format the same as the xchat_hook_command callback | |
- Returns a unique hook object | |
* xchat_hook_print(name, pri, callback) | |
- Refer to XChat plugin docs, though there's no userdata here | |
- Returns a unique hook object | |
* xchat_unhook(hook) | |
- Unhooks hook object <hook>, which must've been returned from a xchat_hook_* function | |
* xchat_unhook_all() | |
- Unhooks all hooks in this JS context | |
* xchat_strip(str [, flags]) | |
- Strips IRC colours and text attributes from str, with optional flags <flags> (XChat plugin docs) | |
flags defaults to 2 | |
- Returns the new string, which has been stripped of stuff | |
* xchat_list_get(name) | |
- See XChat plugin docs #lists for a list of lists - this function returns a whole list (array of objects) | |
rather than a handle to a list | |
eg: xchat_list_get("users")[0].nick will be the first (apparently alphabetically) nick in the context's | |
channel | |
Member of an object could be a string, number, or context object | |
- Returns the array of list member objects (all duplicated at call time) | |
* xchat_get_context() | |
- Returns a context object representing the current context | |
* xchat_set_context(context) | |
- Sets the current context to the context represented by the <context> context object | |
* xchat_cmp_context(a, b) | |
- Returns true if the two context objects <a> and <b> represent the same context | |
* xchat_find_context(servername, channel) | |
- Check XChat plugin docs (NULL is non-string in this case) | |
- Returns a context object representing the context found, or undefined | |
* xchat_get_info(id) | |
- Check XChat plugin docs for list of values for <id> | |
- Returns the string of information assosciated with <id> (will not handle win_ptr), or undefined | |
* JsInfo() | |
- Get information about the current JS context | |
- Returns an object with the members: | |
* jsver: String representing current JS version according to SpiderMonkey (to do with feature availability) | |
* scriptname: Name of the script (the one that's always open is called <commandline>) | |
* scriptid: Integer representing the JS context | |
* JsSet(name, value) | |
- Sets values that affect the current JS context | |
Only value so far is jsver (string), list at https://developer.mozilla.org/en/SpiderMonkey/JSAPI_Reference/JS_VersionToString | |
* load(name) | |
- Evaluates contents frome the file <name> in the current JS context | |
- Returns the value of the last statement evaluated | |
* DynObj(callback) | |
- Creates an object that allows the function <callback> to define all sets and gets on that object | |
The function will be passed two or three arguments: | |
- Boolean representing whether the action is a set or a get (true for set) | |
- The member's key (could essentially be anything: foo[/bar/]) | |
- If the action is a set, the value being set | |
The function should return the value being get/set | |
- Returns the DynObj object | |
* DBG() | |
- Prints some stuff that you shouldn't need to care about | |
== Number constants == | |
These are here for return values of callbacks etc, and have the values from xchat-plugin.h | |
* XCHAT_IFACE_MAJOR | |
* XCHAT_IFACE_MINOR | |
* XCHAT_IFACE_MICRO | |
* XCHAT_PRI_HIGHEST | |
* XCHAT_PRI_HIGH | |
* XCHAT_PRI_NORM | |
* XCHAT_PRI_LOW | |
* XCHAT_PRI_LOWEST | |
* XCHAT_FD_READ | |
* XCHAT_FD_WRITE | |
* XCHAT_FD_EXCEPTION | |
* XCHAT_FD_NOTSOCKET | |
* XCHAT_EAT_NONE | |
* XCHAT_EAT_XCHAT | |
* XCHAT_EAT_PLUGIN | |
* XCHAT_EAT_ALL | |
== External libraries == | |
I couldn't find any good looking external SpiderMonkey libraries that would work on x86_64 atleast, so.. Meh | |
I'm on Freenode if you have any suggestions |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var xchat = (function(){ | |
var xchatt, config, saylock = false; | |
function newhook(hook){ | |
return { | |
unhook : function(){ | |
xchat_unhook(hook); | |
} | |
} | |
} | |
function parse2space(str){ | |
var bd, qs, x; | |
for(x = bd = qs = 0; str[x]; x++) | |
switch(str[x]){ | |
case "(": case "[": case "{": | |
bd++; break; | |
case ")": case "]": case "}": | |
if(--bd < 0) | |
return x; | |
break; | |
case ",": case ".": case "?": | |
if(!str[x+1] || str[x+1] == " ") | |
return x; | |
break; | |
case "/": qs++; case "\"": qs++; case "'": qs++; | |
if(!bd && x > 0 && (str[x-1].toLowerCase() > "a" && str[x-1].toLowerCase() < "z" || ")]}'\"".indexOf(str[x-1]) >= 0)) | |
return x; | |
for(x++; str[x]; x++) | |
if(str[x] == "\\") x++; | |
else if(str[x] == (qs == 3? "/" : qs == 2? "\"" : "'")) break; | |
qs = 0; break; | |
case " ": | |
if(bd == 0) | |
return x; | |
} | |
return x; | |
} | |
function newcx(cx){ | |
var cxself, ocx; | |
function scx(){cx && (ocx = xchat_get_context(), xchat_set_context(cx))} | |
function ecx(){cx && xchat_set_context(ocx)} | |
return cxself = { | |
p2s: parse2space, | |
get rawcx(){ | |
return cx? cx : xchat_get_context(); | |
}, | |
get config(){ | |
return config; | |
}, | |
hkcmd : function(name, func){ var rv; | |
return newhook(xchat_hook_command(name, XCHAT_PRI_NORM, function(){ scx(); | |
rv = func.apply(global, arguments); | |
ecx(); return rv;})); | |
}, | |
hkprint : function(name, func){ var rv; | |
return newhook(xchat_hook_print(name, XCHAT_PRI_NORM, function(){ scx(); | |
rv = func.apply(global, arguments); | |
ecx(); return rv;})); | |
}, | |
hkserver : function(name, func){ var rv; | |
return newhook(xchat_hook_server(name, XCHAT_PRI_NORM, function(){ scx(); | |
rv = func.apply(global, arguments); | |
ecx(); return rv;})); | |
}, | |
timer : function(ms, func){ var rv; | |
return newhook(xchat_hook_timer(ms, function(){ scx(); | |
rv = func.apply(global, arguments); | |
ecx(); return rv;})); | |
}, | |
cmd : function(text){ scx(); | |
xchat_command(text); | |
ecx(); }, | |
print : function(){ var x; scx(); | |
for(x = 0; x < arguments.length; x++) | |
xchat_print(arguments[x]); | |
ecx(); }, | |
ls : DynObj(function(set, key, val){ var rv; scx(); | |
rv = set? val : xchat_list_get(key); | |
if(!set && rv && rv[0] && rv[0].context) | |
for(x in rv) | |
rv[x].context = newcx(rv[x].context); | |
ecx(); return rv; }), | |
info : DynObj(function(set, key, val){ var x, rv; scx(); | |
rv = set? val : xchat_get_info(key); | |
ecx(); return rv; }), | |
prefs : DynObj(function(set, key, val){ var rv; scx(); | |
rv = set? (xchat.cmd("SET " + key + " " + (typeof val == "boolean"? val? 1 : 0 : val)), val) : xchat_get_prefs(key); | |
ecx(); return rv; }), | |
get chan(){ return cxself.info.channel; }, | |
get serv(){ return cxself.info.server; }, | |
get net(){ return cxself.info.network; }, | |
get me(){ return cxself.info.nick; }, | |
set me(nick){ cxself.cmd("NICK " + nick); return nick; }, | |
get topic(){ return cxself.info.topic; }, | |
get modes(){ return cxself.info.modes; }, | |
get ver(){ return cxself.info.version; }, | |
strip : function(str, flags){ | |
return xchat_strip(str, flags == undefined? 3 : flags); | |
}, | |
ncmp : function(s1, s2){ var rv; scx(); | |
rv = xchat_nickcmp(s1, s2); | |
ecx(); return rv; }, | |
cmp : function(s1, s2){ return cxself.ncmp(s1, s2); }, | |
chancx : function(a, b){ var rv; scx(); | |
(rv = xchat_find_context(b == undefined? undefined : a, b == undefined? a : b)) && (rv = newcx(rv)); | |
ecx(); return rv; }, | |
say : function(text){ | |
for each(x in text.toString().split("\n")) | |
cxself.cmd("SAY " + x); | |
}, | |
msg : function(to, text){ | |
for each(x in text.toString().split("\n")) | |
cxself.cmd("MSG " + to + " " + x); | |
} | |
} | |
} | |
(xchatt = { | |
get cx(){ | |
return newcx(xchat_get_context()); | |
}, | |
eat: { | |
none: XCHAT_EAT_NONE, | |
xchat: XCHAT_EAT_XCHAT, | |
plugin: XCHAT_EAT_PLUGIN, | |
all: XCHAT_EAT_ALL | |
} | |
}).__proto__ = newcx(); | |
config = { | |
evchar: "," | |
}; | |
xchat_unhook_all(); | |
if(JsInfo().scriptname == "<commandline>") | |
xchatt.hkcmd("", function(w, we){ | |
var line, x, y, p, ret; | |
if(saylock || we[1].substr(0, config.evchar.length) != config.evchar) | |
return xchat.eat.none; | |
if((line = we[1].substr(config.evchar.length)).substr(0, config.evchar.length) == config.evchar) | |
return saylock = true, xchat.cmd("SAY " + line), saylock = false, XCHAT_EAT_ALL; | |
for(x = 0, ret = ""; (p = line.indexOf("@", x)) >= 0;){ | |
ret += line.substr(x, p - x); | |
if(line[p+1] == "@") | |
x = p + 2; | |
else{ | |
with(xchat) | |
ret += eval(line.substr(p + 1, y = parse2space(line.substr(p + 1))), xchat); | |
x = p + y + 1; | |
} | |
} | |
xchat.say(ret += line.substr(x)); | |
return xchat.eat.all; | |
}); | |
return xchatt; | |
})(); | |
/* | |
* xchat.cx - object representing the current context, has functions that are done in that context, can take xchat.cx and save for later use | |
* xchat - the same functions as in xchat.cx, but not context-specific, xchat.timer(10000, (){xchat.cmd(..)}) will execute the command in | |
* the channel that's active in 10 secs | |
* This will also install a hook, if loaded in the <commandline> context, which will allow for quick JS evaluation in messages, which start with | |
* a comma (,) - JS statements start with @ and end with a space, unless there's a bracket, in which case it'll do crazy stuff to figure out the | |
* end. Use a double comma to escape the evals (like the double slash for commands) | |
* ,5+5 is @5+5 | |
* -> 5+5 is 10 | |
* ,@"this is a test".split(" ") test | |
* -> this,is,a,test test | |
* ,Sum of {1..100} is @{for(y = x = 0; x <= 100; x++) y += x} | |
* -> Sum of {1..100} is 5050 | |
* ,,@5+5 | |
* -> ,@5+5 | |
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* xjs-8.c | |
* | |
* gcc -Wl,--export-dynamic -shared -fPIC -I/usr/include/js xjs.c -o xjs.so -ljs | |
* | |
* XJS - JavaScript (SpiderMonkey) plugin for XChat, by Maxdamantus | |
* http://ntus.uni.cc/xjs | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#define XP_UNIX | |
#include <jsapi.h> | |
#include "xchat-plugin.h" | |
#define PLUGNAME "XJS" | |
#define PLUGDESC "SpiderMonkey plugin" | |
#define PLUGVER "8" | |
#define XCMD_JS_HELP \ | |
"Usage: /js e <code> - evaluate code in the \"<commandline>\" context\n" \ | |
" /js o <file> - create new context, executing code from <file>\n" \ | |
" /js i <id> <code> - inject <code> into context <id>\n" \ | |
" /js l - list existing contexts\n" \ | |
" /js k <id> - kill context <id>\n" | |
xchat_plugin *ph; | |
JSRuntime *rt; | |
JSClass xjs_class_scriptglobal = { | |
"ScriptGlobal", 0, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub | |
}; | |
struct xjs_hookll { | |
struct xjs_hookll *next; | |
xchat_hook *hook; | |
JSObject *oval; | |
}; | |
struct xjs_instance { | |
struct xjs_instance *next; | |
xchat_context *xcx; | |
JSContext *cx; | |
JSObject *global; | |
struct xjs_hookll *hookf, *hookl; | |
int hookp, id; | |
char name[]; | |
} *xjs_instf, *xjs_instl; | |
struct xjs_instance *xjs_cmdline; | |
struct jscb { | |
int type; | |
jsval func; | |
struct xjs_instance *inst; | |
xchat_hook *hook; | |
int cpid; | |
}; | |
void js_errorhandler(JSContext *cx, const char *msg, JSErrorReport *report){ | |
xchat_printf(ph, "Error [%s:%u] %s\n", ((struct xjs_instance*) JS_GetContextPrivate(cx))->name, report->lineno, msg); | |
} | |
JSClass xjs_class_hook = { | |
"XChatHook", JSCLASS_HAS_PRIVATE, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub | |
}; | |
JSClass xjs_class_context = { | |
"XChatContext", JSCLASS_HAS_PRIVATE, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub | |
}; | |
JSBool xjs_dynobj_set(JSContext *cx, JSObject *obj, jsval idval, jsval *rval){ | |
jsval func, argv[3]; | |
JS_GetReservedSlot(cx, obj, 0, &func); | |
argv[0] = JSVAL_TRUE; | |
argv[1] = idval; | |
argv[2] = *rval; | |
JS_CallFunctionValue(cx, JS_GetGlobalObject(cx), func, 3, argv, rval); | |
return JS_TRUE; | |
} | |
JSBool xjs_dynobj_get(JSContext *cx, JSObject *obj, jsval idval, jsval *rval){ | |
jsval func, argv[2]; | |
JS_GetReservedSlot(cx, obj, 0, &func); | |
argv[0] = JSVAL_FALSE; | |
argv[1] = idval; | |
JS_CallFunctionValue(cx, JS_GetGlobalObject(cx), func, 2, argv, rval); | |
return JS_TRUE; | |
} | |
JSClass xjs_class_dynobj = { | |
"DynObj", JSCLASS_HAS_RESERVED_SLOTS(1), | |
xjs_dynobj_set, JS_PropertyStub, xjs_dynobj_get, xjs_dynobj_set, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, | |
}; | |
void xjs_reghook(JSContext *cx, xchat_hook *hook, JSObject *oval){ | |
struct xjs_instance *xjs; | |
xjs = JS_GetContextPrivate(cx); | |
xjs->hookl = *(xjs->hookl? &xjs->hookl->next : &xjs->hookf) = JS_malloc(cx, sizeof(*xjs->hookl)); | |
xjs->hookl->next = NULL; | |
xjs->hookl->hook = hook; | |
xjs->hookl->oval = oval; | |
JS_SetPrivate(cx, oval, hook); | |
JS_AddRoot(cx, &xjs->hookl->oval); | |
} | |
void xjs_unreghook(JSContext *cx, xchat_hook *hook){ | |
struct xjs_instance *xjs; | |
struct xjs_hookll *ll, *ll2; | |
xjs = JS_GetContextPrivate(cx); | |
for(ll = xjs->hookf; ll; ll2 = ll, ll = ll->next) | |
if(ll->hook == hook) | |
break; | |
JS_SetPrivate(cx, ll->oval, NULL); | |
JS_RemoveRoot(cx, &ll->oval); | |
if(ll == xjs->hookf){ | |
if(!(xjs->hookf = ll->next)) | |
xjs->hookl = NULL; | |
}else | |
ll2->next = ll->next; | |
JS_free(cx, ll); | |
} | |
void xjs_clearhooks(struct xjs_instance *inst){ | |
while(inst->hookf){ | |
xchat_unhook(ph, inst->hookf->hook); | |
xjs_unreghook(inst->cx, inst->hookf->hook); | |
} | |
} | |
jsval xjs_hook_to_jsval(JSContext *cx, xchat_hook *hook){ | |
JSObject *oval; | |
oval = JS_NewObject(cx, &xjs_class_hook, NULL, NULL); | |
xjs_reghook(cx, hook, oval); | |
return OBJECT_TO_JSVAL(oval); | |
} | |
jsval xjs_context_to_jsval(JSContext *cx, xchat_context *context){ | |
JSObject *oval; | |
oval = JS_NewObject(cx, &xjs_class_context, NULL, NULL); | |
JS_SetPrivate(cx, oval, context); | |
return OBJECT_TO_JSVAL(oval); | |
} | |
JSBool xjs_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
int x; | |
for(x = 0; x < argc; x++) | |
xchat_printf(ph, "%s\n", JS_GetStringBytes(JS_ValueToString(cx, argv[x]))); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xchat_print(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_emit_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
int x; | |
char *s[6]; | |
for(x = 0; x < 6; x++) | |
s[x] = x < argc? JS_EncodeString(cx, JS_ValueToString(cx, argv[x])) : NULL; | |
JS_NewNumberValue(cx, xchat_emit_print(ph, s[0], s[1], s[2], s[3], s[4], s[5]), rval); | |
for(x = 0; x < 6; x++) | |
if(s[x]) | |
JS_free(cx, s[x]); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_command(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xchat_command(ph, JS_EncodeString(cx, JS_ValueToString(cx, argv[0]))); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_get_prefs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *a; | |
const char *string; | |
int integer; | |
switch(xchat_get_prefs(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), &string, &integer)){ | |
case 0: | |
*rval = JSVAL_VOID; | |
break; | |
case 1: | |
a = JS_strdup(cx, string); | |
*rval = STRING_TO_JSVAL(JS_NewString(cx, a, strlen(a))); | |
break; | |
case 2: | |
JS_NewNumberValue(cx, integer, rval); | |
break; | |
case 3: | |
*rval = integer? JSVAL_TRUE : JSVAL_FALSE; | |
break; | |
} | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_send_modes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *nicks; | |
jsuint len; | |
jsval vp; | |
int x; | |
char *t1, *t2, **targets; | |
*rval = JSVAL_VOID; | |
if(JSVAL_IS_NULL(argv[0]) || !JSVAL_IS_OBJECT(argv[0]) || !JS_ValueToObject(cx, argv[0], &nicks) || !JS_IsArrayObject(cx, nicks)) | |
return JS_TRUE; | |
JS_GetArrayLength(cx, nicks, &len); | |
targets = JS_malloc(cx, (len > 10000? (len = 10000) : len) * sizeof(*targets)); | |
for(x = 0; x < len; x++){ | |
JS_GetElement(cx, nicks, x, &vp); | |
targets[x] = JS_EncodeString(cx, JS_ValueToString(cx, vp)); | |
} | |
if(argc <= 3 || !JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
xchat_send_modes(ph, (const char**) targets, len, x, /* fuck you, const keyword */ | |
*(t1 = JS_EncodeString(cx, JS_ValueToString(cx, argv[1 + (argc > 3)]))), | |
*(t2 = JS_EncodeString(cx, JS_ValueToString(cx, argv[2 + (argc > 3)])))); | |
JS_free(cx, t1); | |
JS_free(cx, t2); | |
for(x = 0; x < len; x++) | |
JS_free(cx, targets[x]); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_nickcmp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *t1, *t2; | |
JS_NewNumberValue(cx, xchat_nickcmp(ph, t1 = JS_EncodeString(cx, JS_ValueToString(cx, argv[0])), t2 = JS_EncodeString(cx, JS_ValueToString(cx, argv[1]))), rval); | |
JS_free(cx, t1); | |
JS_free(cx, t2); | |
return JS_TRUE; | |
} | |
int xjs_cmdcb(char **word, char **word_eol, void *udata){ | |
jsval rval, argv[2]; | |
JSObject *aword, *aword_eol; | |
struct jscb *cb; | |
int x; | |
cb = udata; | |
aword = JS_NewArrayObject(cb->inst->cx, 0, NULL); | |
for(x = 1; word[x] && *word[x]; x++) | |
JS_DefineElement(cb->inst->cx, aword, x, STRING_TO_JSVAL(JS_NewStringCopyZ(cb->inst->cx, word[x])), NULL, NULL, JSPROP_ENUMERATE); | |
aword_eol = JS_NewArrayObject(cb->inst->cx, 0, NULL); | |
for(x = 1; word_eol[x] && *word_eol[x]; x++) | |
JS_DefineElement(cb->inst->cx, aword_eol, x, STRING_TO_JSVAL(JS_NewStringCopyZ(cb->inst->cx, word_eol[x])), NULL, NULL, JSPROP_ENUMERATE); | |
argv[0] = OBJECT_TO_JSVAL(aword); | |
argv[1] = OBJECT_TO_JSVAL(aword_eol); | |
if(!JS_CallFunctionValue(cb->inst->cx, cb->inst->global, cb->func, 2, argv, &rval) || !JS_ValueToInt32(cb->inst->cx, rval, &x)) | |
x = 0; | |
JS_MaybeGC(cb->inst->cx); | |
return x; | |
} | |
int xjs_hpcb(char **word, void *udata){ | |
jsval rval, argv[1]; | |
JSObject *aword; | |
struct jscb *cb; | |
int x = 0; | |
cb = udata; | |
aword = JS_NewArrayObject(cb->inst->cx, 0, NULL); | |
for(x = 1; word[x] && *word[x]; x++) | |
JS_DefineElement(cb->inst->cx, aword, x, STRING_TO_JSVAL(JS_NewStringCopyZ(cb->inst->cx, word[x])), NULL, NULL, JSPROP_ENUMERATE); | |
argv[0] = OBJECT_TO_JSVAL(aword); | |
if(!JS_CallFunctionValue(cb->inst->cx, cb->inst->global, cb->func, 1, argv, &rval) || !JS_ValueToInt32(cb->inst->cx, rval, &x)) | |
x = 0; | |
JS_MaybeGC(cb->inst->cx); | |
return x; | |
} | |
int xjs_timecb(void *udata){ | |
jsval rval; | |
struct jscb *cb; | |
int x; | |
cb = udata; | |
JS_CallFunctionValue(cb->inst->cx, cb->inst->global, cb->func, 0, NULL, &rval); | |
if(JSVAL_IS_VOID(rval) || !JS_ValueToInt32(cb->inst->cx, rval, &x)) | |
x = 0; | |
if(!x){ | |
xjs_unreghook(cb->inst->cx, cb->hook); | |
xchat_unhook(ph, cb->hook); | |
JS_RemoveRoot(cb->inst->cx, &cb->func); | |
JS_free(cb->inst->cx, cb); | |
} | |
JS_MaybeGC(cb->inst->cx); | |
return x; | |
} | |
JSBool xjs_xchat_hook_command(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
char *t1, *t2; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 0; | |
cb->func = argv[2]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, | |
cb->hook = xchat_hook_command(ph, t1 = JS_EncodeString(cx, JS_ValueToString(cx, argv[0])), x, xjs_cmdcb, t2 = JS_EncodeString(cx, JS_ValueToString(cx, argv[3])), cb)); | |
JS_free(cx, t1); | |
JS_free(cx, t2); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_hook_timer(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 1; | |
cb->func = argv[1]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[0], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_timer(ph, x, xjs_timecb, cb)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_hook_server(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 2; | |
cb->func = argv[2]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_server(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), x, xjs_cmdcb, cb)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_hook_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 3; | |
cb->func = argv[2]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_print(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), x, xjs_hpcb, cb)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_unhook(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval; | |
xchat_hook *hook; | |
if(!JSVAL_IS_OBJECT(argv[0]) || JS_GET_CLASS(cx, oval = JSVAL_TO_OBJECT(argv[0])) != &xjs_class_hook) | |
JS_ReportWarning(cx, "Not an XChatHook object"); | |
else if(hook = JS_GetPrivate(cx, oval)){ | |
xjs_unreghook(cx, hook); | |
xchat_unhook(ph, hook); | |
} | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_unhook_all(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xjs_clearhooks(JS_GetContextPrivate(cx)); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_strip(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *r; | |
int x; | |
if(JSVAL_IS_VOID(argv[1]) || !JS_ValueToInt32(cx, argv[1], &x)) | |
x = 2; | |
if(r = xchat_strip(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), -1, x)) | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, r)); | |
else | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_list_get(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *listobj, *listarray; | |
jsval listval; | |
xchat_list *xcl; | |
int x; | |
char *lname; | |
const char *const *sfields, *const *fields; | |
printf("lname = %s\n", lname = JS_EncodeString(cx, JS_ValueToString(cx, argv[0]))); | |
if(xcl = xchat_list_get(ph, lname)){ | |
*rval = OBJECT_TO_JSVAL(listarray = JS_NewArrayObject(cx, 0, NULL)); | |
sfields = xchat_list_fields(ph, lname); | |
for(x = 0; xchat_list_next(ph, xcl); x++){ | |
listobj = JS_NewObject(cx, NULL, NULL, NULL); | |
for(fields = sfields; *fields; fields++){ | |
switch(**fields){ | |
case 's': | |
listval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, xchat_list_str(ph, xcl, *fields+1))); | |
break; | |
case 'i': | |
JS_NewNumberValue(cx, xchat_list_int(ph, xcl, *fields+1), &listval); | |
break; | |
case 'p': | |
if(!strcmp(*fields+1, "context")){ | |
listval = xjs_context_to_jsval(cx, (xchat_context*)xchat_list_str(ph, xcl, *fields+1)); | |
break; | |
} | |
default: | |
continue; /* Any more pointers? */ | |
} | |
JS_SetProperty(cx, listobj, *fields+1, &listval); | |
} | |
JS_DefineElement(cx, listarray, x, OBJECT_TO_JSVAL(listobj), NULL, NULL, JSPROP_ENUMERATE); | |
} | |
xchat_list_free(ph, xcl); | |
}else | |
*rval = JSVAL_VOID; | |
JS_free(cx, lname); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_get_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
*rval = xjs_context_to_jsval(cx, xchat_get_context(ph)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_cmp_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval1, *oval2; | |
if(!JSVAL_IS_OBJECT(argv[0]) || JS_GET_CLASS(cx, oval1 = JSVAL_TO_OBJECT(argv[0])) != &xjs_class_context | |
|| !JSVAL_IS_OBJECT(argv[1]) || JS_GET_CLASS(cx, oval2 = JSVAL_TO_OBJECT(argv[1])) != &xjs_class_context){ | |
JS_ReportWarning(cx, "Not an XChatContext object"); | |
*rval = JSVAL_VOID; | |
}else | |
*rval = JS_GetPrivate(cx, oval1) == JS_GetPrivate(cx, oval2)? JSVAL_TRUE : JSVAL_FALSE; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_set_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval; | |
if(!JSVAL_IS_OBJECT(argv[0]) || JS_GET_CLASS(cx, oval = JSVAL_TO_OBJECT(argv[0])) != &xjs_class_context){ | |
JS_ReportWarning(cx, "Not an XChatContext object"); | |
*rval = JSVAL_VOID; | |
}else | |
JS_NewNumberValue(cx, xchat_set_context(ph, JS_GetPrivate(cx, oval)), rval); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_find_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xchat_context *xccx; | |
char *t1, *t2; | |
*rval = (xccx = xchat_find_context(ph, | |
t1 = JSVAL_IS_STRING(argv[0])? JS_GetStringBytes(JS_ValueToString(cx, argv[0])) : NULL, | |
t2 = JSVAL_IS_STRING(argv[1])? JS_GetStringBytes(JS_ValueToString(cx, argv[1])) : NULL))? | |
xjs_context_to_jsval(cx, xccx) : JSVAL_VOID; | |
if(t1) JS_free(cx, t1); | |
if(t2) JS_free(cx, t2); | |
return JS_TRUE; | |
} | |
JSBool xjs_jsinfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_instance *xjs; | |
JSObject *oval; | |
xjs = JS_GetContextPrivate(cx); | |
oval = JS_NewObject(cx, NULL, NULL, NULL); | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, JS_VersionToString(JS_GetVersion(cx)))); | |
JS_SetProperty(cx, oval, "jsver", rval); | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, xjs->name)); | |
JS_SetProperty(cx, oval, "scriptname", rval); | |
JS_NewNumberValue(cx, xjs->id, rval); | |
JS_SetProperty(cx, oval, "scriptid", rval); | |
*rval = OBJECT_TO_JSVAL(oval); | |
return JS_TRUE; | |
} | |
JSBool xjs_jsset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSVersion jsver; | |
char *key, *val; | |
if(JSVAL_IS_STRING(argv[0])){ | |
key = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); | |
if(!strcmp(key, "jsver")){ | |
if((jsver = JS_StringToVersion(val = JS_GetStringBytes(JS_ValueToString(cx, argv[1])))) != JSVERSION_UNKNOWN){ | |
JS_SetVersion(cx, jsver); | |
*rval = JSVAL_TRUE; | |
}else | |
*rval = JSVAL_FALSE; | |
JS_free(cx, val); | |
}else | |
*rval = JSVAL_VOID; | |
JS_free(cx, key); | |
} | |
return JS_TRUE; | |
} | |
JSBool xjs_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
static char fnbuf[1024]; | |
JSScript *script; | |
snprintf(fnbuf, 1024, "%s/xjs/%s", xchat_get_info(ph, "xchatdirfs"), JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); | |
if(script = JS_CompileFile(cx, JS_GetGlobalObject(cx), fnbuf)){ | |
JS_ExecuteScript(cx, JS_GetGlobalObject(cx), script, rval); | |
JS_DestroyScript(cx, script); | |
}else | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_dynobj(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval; | |
oval = JS_NewObject(cx, &xjs_class_dynobj, NULL, NULL); | |
*rval = OBJECT_TO_JSVAL(oval); | |
JS_SetReservedSlot(cx, oval, 0, argv[0]); | |
return JS_TRUE; | |
} | |
JSBool xjs_DBG(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_instance *xjs; | |
struct xjs_hookll *ll; | |
xchat_printf(ph, "** cx = %p **\n", (void*)cx); | |
xchat_printf(ph, "** hook list **\n"); | |
xjs = JS_GetContextPrivate(cx); | |
for(ll = xjs->hookf; ll; ll = ll->next) | |
xchat_printf(ph, "-> %p: %p, %p\n", (void*)ll, (void*)ll->hook, (void*)ll->oval); | |
xchat_printf(ph, "** end **\n"); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_get_info(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *s; | |
if(!strcmp("win_ptr", s = JS_GetStringBytes(JS_ValueToString(cx, argv[0])))) | |
*rval = JSVAL_VOID; | |
else | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, xchat_get_info(ph, s))); | |
JS_free(cx, s); | |
return JS_TRUE; | |
} | |
JSFunctionSpec global_functions[] = { | |
{"print", xjs_print, 1, 0, 0}, | |
{"xchat_print", xjs_xchat_print, 1, 0, 0}, | |
{"xchat_emit_print", xjs_xchat_emit_print, 0, 0, 0}, | |
{"xchat_command", xjs_xchat_command, 1, 0, 0}, | |
{"xchat_get_prefs", xjs_xchat_get_prefs, 1, 0, 0}, | |
{"xchat_send_modes", xjs_xchat_send_modes, 3, 0, 0}, | |
{"xchat_nickcmp", xjs_xchat_nickcmp, 2, 0, 0}, | |
{"xchat_hook_command", xjs_xchat_hook_command, 4, 0, 0}, | |
{"xchat_hook_timer", xjs_xchat_hook_timer, 2, 0, 0}, | |
{"xchat_hook_server", xjs_xchat_hook_server, 3, 0, 0}, | |
{"xchat_hook_print", xjs_xchat_hook_print, 3, 0, 0}, | |
{"xchat_unhook", xjs_xchat_unhook, 1, 0, 0}, | |
{"xchat_unhook_all", xjs_xchat_unhook_all, 0, 0, 0}, | |
{"xchat_strip", xjs_xchat_strip, 2, 0, 0}, | |
{"xchat_list_get", xjs_xchat_list_get, 1, 0, 0}, | |
{"xchat_get_context", xjs_xchat_get_context, 0, 0, 0}, | |
{"xchat_cmp_context", xjs_xchat_cmp_context, 2, 0, 0}, | |
{"xchat_set_context", xjs_xchat_set_context, 1, 0, 0}, | |
{"xchat_find_context", xjs_xchat_find_context, 2, 0, 0}, | |
{"xchat_get_info", xjs_xchat_get_info, 1, 0, 0}, | |
{"DynObj", xjs_dynobj, 1, 0, 0}, | |
{"JsInfo", xjs_jsinfo, 0, 0, 0}, | |
{"JsSet", xjs_jsset, 2, 0, 0}, | |
{"load", xjs_load, 1, 0, 0}, | |
{"DBG", xjs_DBG, 0, 0, 0}, | |
{} | |
}; | |
JSConstDoubleSpec global_properties[] = { | |
{XCHAT_IFACE_MAJOR, "XCHAT_IFACE_MAJOR", JSPROP_READONLY}, | |
{XCHAT_IFACE_MINOR, "XCHAT_IFACE_MINOR", JSPROP_READONLY}, | |
{XCHAT_IFACE_MICRO, "XCHAT_IFACE_MICRO", JSPROP_READONLY}, | |
{XCHAT_PRI_HIGHEST, "XCHAT_PRI_HIGHEST", JSPROP_READONLY}, | |
{XCHAT_PRI_HIGH, "XCHAT_PRI_HIGH", JSPROP_READONLY}, | |
{XCHAT_PRI_NORM, "XCHAT_PRI_NORM", JSPROP_READONLY}, | |
{XCHAT_PRI_LOW, "XCHAT_PRI_LOW", JSPROP_READONLY}, | |
{XCHAT_PRI_LOWEST, "XCHAT_PRI_LOWEST", JSPROP_READONLY}, | |
{XCHAT_FD_READ, "XCHAT_FD_READ", JSPROP_READONLY}, | |
{XCHAT_FD_WRITE, "XCHAT_FD_WRITE", JSPROP_READONLY}, | |
{XCHAT_FD_EXCEPTION, "XCHAT_FD_EXCEPTION", JSPROP_READONLY}, | |
{XCHAT_FD_NOTSOCKET, "XCHAT_FD_NOTSOCKET", JSPROP_READONLY}, | |
{XCHAT_EAT_NONE, "XCHAT_EAT_NONE", JSPROP_READONLY}, | |
{XCHAT_EAT_XCHAT, "XCHAT_EAT_XCHAT", JSPROP_READONLY}, | |
{XCHAT_EAT_PLUGIN, "XCHAT_EAT_PLUGIN", JSPROP_READONLY}, | |
{XCHAT_EAT_ALL, "XCHAT_EAT_ALL", JSPROP_READONLY}, | |
{} | |
}; | |
struct xjs_instance *xjs_init(char *name){ | |
struct xjs_instance *inst; | |
jsval oval; | |
inst = malloc(sizeof(*inst) + strlen(name) + 1); | |
strcpy(inst->name, name); | |
inst->cx = JS_NewContext(rt, 0x1000); | |
JS_SetContextPrivate(inst->cx, inst); | |
oval = OBJECT_TO_JSVAL(inst->global = JS_NewObject(inst->cx, &xjs_class_scriptglobal, NULL, NULL)); | |
inst->hookf = inst->hookl = NULL; | |
inst->next = NULL; | |
inst->id = xjs_instl? xjs_instl->id + 1 : 0; | |
xjs_instl = *(xjs_instl? &xjs_instl->next : &xjs_instf) = inst; | |
JS_SetProperty(inst->cx, inst->global, "global", &oval); | |
JS_SetErrorReporter(inst->cx, js_errorhandler); | |
JS_InitStandardClasses(inst->cx, inst->global); | |
JS_DefineFunctions(inst->cx, inst->global, global_functions); | |
JS_DefineConstDoubles(inst->cx, inst->global, global_properties); | |
return inst; | |
} | |
void xjs_exit(struct xjs_instance *inst, int destroyall){ | |
struct xjs_instance *inst1, *inst2; | |
for(inst1 = xjs_instf; inst1; inst2 = inst1, inst1 = inst1->next) | |
if(inst1 == inst) | |
break; | |
if(inst == xjs_instf) | |
(xjs_instf = inst->next) == NULL && (xjs_instl = NULL); | |
else | |
inst2->next = inst->next; | |
xjs_clearhooks(inst); | |
JS_DestroyContext(inst->cx); | |
free(inst); | |
if(!destroyall && inst == xjs_cmdline) | |
xjs_cmdline = xjs_init("<commandline>"); | |
} | |
int xjs_eval(struct xjs_instance *inst, char *str, jsval *rval){ | |
return !!JS_EvaluateScript(inst->cx, inst->global, str, strlen(str), inst->name, 0, rval); | |
} | |
char *xjs_eval2str(struct xjs_instance *inst, char *str){ | |
jsval rval; | |
if(xjs_eval(inst, str, &rval)) | |
return JSVAL_IS_VOID(rval)? NULL : JS_GetStringBytes(JS_ValueToString(inst->cx, rval)); | |
else | |
return NULL; | |
} | |
struct xjs_instance *xjs_run(char *fname){ | |
struct xjs_instance *inst; | |
char *name; | |
int x; | |
jsval rval; | |
JSScript *script; | |
for(name = fname, x = 0; fname[x]; x++) | |
if(fname[x] == '/') | |
name = fname + x + 1; | |
inst = xjs_init(name); | |
if(!(script = JS_CompileFile(inst->cx, inst->global, fname))) | |
return NULL; | |
else{ | |
JS_ExecuteScript(inst->cx, inst->global, script, &rval); | |
JS_DestroyScript(inst->cx, script); | |
} | |
return inst; | |
} | |
int xcmd_js(char **word, char **word_eol, void *udata){ | |
struct xjs_instance *instl; | |
int id; | |
static char fnbuf[1024], *t; | |
if(!strcasecmp(word[2], "l")){ | |
xchat_printf(ph, " Ref# Name\n"); | |
for(instl = xjs_instf; instl; instl = instl->next) | |
xchat_printf(ph, "%5i %s\n", instl->id, instl->name); | |
}else if(!strcasecmp(word[2], "e")){ | |
if(t = xjs_eval2str(xjs_cmdline, word_eol[3])) | |
xchat_printf(ph, "%s\n", t); | |
}else if(!strcasecmp(word[2], "i") && *word[3] && *word_eol[4]){ | |
id = atoi(word[3]); | |
for(instl = xjs_instf; instl; instl = instl->next) | |
if(instl->id == id) | |
break; | |
if(instl && instl->id == id){ | |
if(t = xjs_eval2str(instl, word_eol[4])) | |
xchat_printf(ph, "%s\n", t); | |
}else | |
xchat_printf(ph, "Couldn't find context ID %i\n", id); | |
}else if(!strcasecmp(word[2], "o") && *word_eol[3]){ | |
snprintf(fnbuf, 1024, "%s/xjs/%s", xchat_get_info(ph, "xchatdirfs"), word_eol[3]); | |
if(instl = xjs_run(fnbuf)) | |
xchat_printf(ph, "Loaded %s with ID=%i\n", instl->name, instl->id); | |
else | |
xchat_printf(ph, "Failed to load %s\n", fnbuf); | |
}else if(!strcasecmp(word[2], "k") && *word[3]){ | |
id = atoi(word[3]); | |
for(instl = xjs_instf; instl; instl = instl->next) | |
if(instl->id == id) | |
break; | |
if(instl && instl->id == id){ | |
if(!JS_IsRunning(instl->cx)){ | |
xchat_printf(ph, "Killing %s with ID=%i\n", instl->name, instl->id); | |
xjs_exit(instl, 0); | |
}else | |
xchat_printf(ph, "Cannot kill active context\n"); | |
} | |
}else | |
xchat_print(ph, XCMD_JS_HELP); | |
return XCHAT_EAT_ALL; | |
} | |
void xchat_plugin_get_info(char **name, char **desc, char **version, void **reserved){ | |
*name = PLUGNAME; | |
*desc = PLUGDESC; | |
*version = PLUGVER; | |
} | |
int xchat_plugin_init(xchat_plugin *xph, char **name, char **desc, char **version, char *arg){ | |
ph = xph; | |
xchat_plugin_get_info(name, desc, version, NULL); | |
xchat_hook_command(ph, "JS", XCHAT_PRI_NORM, xcmd_js, XCMD_JS_HELP, NULL); | |
rt = JS_NewRuntime(0x100000); | |
xjs_cmdline = xjs_init("<commandline>"); | |
xchat_print(ph, "XJS (JavaScript plugin) loaded!"); | |
return 1; | |
} | |
int xchat_plugin_deinit(){ | |
while(xjs_instf) | |
xjs_exit(xjs_instf, 1); | |
JS_DestroyRuntime(rt); | |
JS_ShutDown(); | |
return 1; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* xjs-9.c | |
* | |
* gcc -Wl,--export-dynamic -shared -fPIC -I/usr/include/js xjs.c -o xjs.so -ljs | |
* | |
* XJS - JavaScript (SpiderMonkey) plugin for XChat, by Maxdamantus | |
* http://ntus.uni.cc/xjs | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <netdb.h> | |
#include <netinet/in.h> | |
#include <sys/socket.h> | |
#ifndef __WIN32__ | |
#include <unistd.h> | |
#include <fcntl.h> | |
#endif | |
#define XP_UNIX | |
#include <jsapi.h> | |
#include "xchat-plugin.h" | |
#define PLUGNAME "XJS" | |
#define PLUGDESC "SpiderMonkey plugin" | |
#define PLUGVER "9" | |
#define XCMD_JS_HELP \ | |
"Usage: /js e <code> - evaluate code in the \"<commandline>\" context\n" \ | |
" /js o <file> - create new context, executing code from <file>\n" \ | |
" /js i <id> <code> - inject <code> into context <id>\n" \ | |
" /js l - list existing contexts\n" \ | |
" /js k <id> - kill context <id>\n" | |
enum xjs_fpipetypes { | |
xjs_pipe_file | |
}; | |
xchat_plugin *ph; | |
JSRuntime *rt; | |
JSClass xjs_class_scriptglobal = { | |
"ScriptGlobal", 0, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub | |
}; | |
JSClass xjs_class_file = { | |
"File", 0, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub | |
}; | |
struct xjs_hookll { | |
struct xjs_hookll *next; | |
xchat_hook *hook; | |
JSObject *oval; | |
}; | |
struct xjs_instance { | |
struct xjs_instance *next; | |
xchat_context *xcx; | |
JSContext *cx; | |
JSObject *global; | |
struct xjs_hookll *hookf, *hookl; | |
int hookp, id; | |
char name[]; | |
} *xjs_instf, *xjs_instl, *xjs_cmdline; | |
struct xjs_fpipe { | |
int type, fd; | |
}; | |
struct jscb { | |
int type; | |
jsval func; | |
struct xjs_instance *inst; | |
xchat_hook *hook; | |
int cpid; | |
}; | |
void js_errorhandler(JSContext *cx, const char *msg, JSErrorReport *report){ | |
xchat_printf(ph, "Error [%s:%u] %s\n", ((struct xjs_instance*) JS_GetContextPrivate(cx))->name, report->lineno, msg); | |
} | |
JSClass xjs_class_hook = { | |
"XChatHook", JSCLASS_HAS_PRIVATE, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub | |
}; | |
JSClass xjs_class_context = { | |
"XChatContext", JSCLASS_HAS_PRIVATE, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub | |
}; | |
void xjs_reghook(JSContext *cx, xchat_hook *hook, JSObject *oval){ | |
struct xjs_instance *xjs; | |
xjs = JS_GetContextPrivate(cx); | |
xjs->hookl = *(xjs->hookl? &xjs->hookl->next : &xjs->hookf) = JS_malloc(cx, sizeof(*xjs->hookl)); | |
xjs->hookl->next = NULL; | |
xjs->hookl->hook = hook; | |
xjs->hookl->oval = oval; | |
JS_SetPrivate(cx, oval, hook); | |
JS_AddRoot(cx, &xjs->hookl->oval); | |
} | |
void xjs_unreghook(JSContext *cx, xchat_hook *hook){ | |
struct xjs_instance *xjs; | |
struct xjs_hookll *ll, *ll2; | |
xjs = JS_GetContextPrivate(cx); | |
for(ll = xjs->hookf; ll; ll2 = ll, ll = ll->next) | |
if(ll->hook == hook) | |
break; | |
JS_SetPrivate(cx, ll->oval, NULL); | |
JS_RemoveRoot(cx, &ll->oval); | |
if(ll == xjs->hookf){ | |
if(!(xjs->hookf = ll->next)) | |
xjs->hookl = NULL; | |
}else | |
ll2->next = ll->next; | |
JS_free(cx, ll); | |
} | |
jsval xjs_hook_to_jsval(JSContext *cx, xchat_hook *hook){ | |
JSObject *oval; | |
oval = JS_NewObject(cx, &xjs_class_hook, NULL, NULL); | |
xjs_reghook(cx, hook, oval); | |
return OBJECT_TO_JSVAL(oval); | |
} | |
jsval xjs_context_to_jsval(JSContext *cx, xchat_context *context){ | |
JSObject *oval; | |
oval = JS_NewObject(cx, &xjs_class_context, NULL, NULL); | |
JS_SetPrivate(cx, oval, context); | |
return OBJECT_TO_JSVAL(oval); | |
} | |
JSBool xjs_file_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_fpipe *fpipe; | |
int rs; | |
static char rbuf[32768]; | |
JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), 0, rval); | |
fpipe = JS_GetPrivate(cx, JSVAL_TO_OBJECT(*rval)); | |
if(!JS_ValueToInt32(cx, argv[0], &rs)) | |
rs = 32768; | |
rs = read(fpipe->fd, rbuf, rs); | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyN(cx, rbuf, rs > 0? rs : 0)); | |
return JS_TRUE; | |
} | |
JSBool xjs_file_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_fpipe *fpipe; | |
JSString *str; | |
JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), 0, rval); | |
fpipe = JS_GetPrivate(cx, JSVAL_TO_OBJECT(*rval)); | |
str = JS_ValueToString(cx, argv[0]); | |
JS_NewNumberValue(cx, write(fpipe->fd, JS_GetStringBytes(str), JS_GetStringLength(str)), rval); | |
return JS_TRUE; | |
} | |
JSBool xjs_file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_fpipe *fpipe; | |
JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), 0, rval); | |
fpipe = JS_GetPrivate(cx, JSVAL_TO_OBJECT(*rval)); | |
if(fpipe->fd >= 0){ | |
close(fpipe->fd); | |
fpipe->fd = -1; | |
*rval = JSVAL_TRUE; | |
}else | |
*rval = JSVAL_FALSE; | |
return JS_TRUE; | |
} | |
int xjs_fdcb(int fd, int flags, void *udata){ | |
int xjs_timecb(void*); | |
return xjs_timecb(udata); | |
} | |
JSBool xjs_file_onread(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_fpipe *fpipe; | |
struct jscb *cb; | |
JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), 0, rval); | |
fpipe = JS_GetPrivate(cx, JSVAL_TO_OBJECT(*rval)); | |
if(fpipe->fd < 0){ | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 4; | |
cb->func = argv[0]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_fd(ph, fpipe->fd, XCHAT_FD_READ, xjs_fdcb, cb)); | |
return JS_TRUE; | |
} | |
JSBool xjs_file_onwrite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_fpipe *fpipe; | |
struct jscb *cb; | |
JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), 0, rval); | |
fpipe = JS_GetPrivate(cx, JSVAL_TO_OBJECT(*rval)); | |
if(fpipe->fd < 0){ | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 4; | |
cb->func = argv[0]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_fd(ph, fpipe->fd, XCHAT_FD_WRITE, xjs_fdcb, cb)); | |
return JS_TRUE; | |
} | |
void xjs_file_finalhandle(JSContext *cx, JSObject *obj){ | |
struct xjs_fpipe *fpipe; | |
fpipe = JS_GetPrivate(cx, obj); | |
if(fpipe->fd >= 0) | |
close(fpipe->fd); | |
free(fpipe); | |
} | |
JSPropertySpec xjs_file_props[] = { | |
{"read", 0, JSPROP_ENUMERATE}, | |
{"write", 1, JSPROP_ENUMERATE}, | |
{"close", 2, JSPROP_ENUMERATE}, | |
{"onread", 3, JSPROP_ENUMERATE}, | |
{"onwrite", 4, JSPROP_ENUMERATE}, | |
{NULL} | |
}; | |
JSBool xjs_file_prophandle(JSContext *cx, JSObject *obj, jsval id, jsval *rv){ | |
JSFunction *fv; | |
fv = NULL; | |
if(JSVAL_IS_INT(id)) | |
switch(JSVAL_TO_INT(id)){ | |
case 0: | |
fv = JS_NewFunction(cx, xjs_file_read, 1, 0, NULL, "File.read"); | |
break; | |
case 1: | |
fv = JS_NewFunction(cx, xjs_file_write, 1, 0, NULL, "File.write"); | |
break; | |
case 2: | |
fv = JS_NewFunction(cx, xjs_file_close, 0, 0, NULL, "File.close"); | |
break; | |
case 3: | |
fv = JS_NewFunction(cx, xjs_file_onread, 1, 0, NULL, "File.onread"); | |
break; | |
case 4: | |
fv = JS_NewFunction(cx, xjs_file_onwrite, 1, 0, NULL, "File.onwrite"); | |
break; | |
} | |
if(fv){ | |
JS_SetReservedSlot(cx, (JSObject*)fv, 0, OBJECT_TO_JSVAL(obj)); | |
*rv = OBJECT_TO_JSVAL((JSObject*)fv); | |
}else | |
*rv = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSClass xjs_socket_class = { | |
"Socket", JSCLASS_HAS_PRIVATE, | |
JS_PropertyStub, JS_PropertyStub, xjs_file_prophandle, JS_PropertyStub, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xjs_file_finalhandle | |
}; | |
JSBool xjs_dynobj_set(JSContext *cx, JSObject *obj, jsval idval, jsval *rval){ | |
jsval func, argv[3]; | |
JS_GetReservedSlot(cx, obj, 0, &func); | |
argv[0] = JSVAL_TRUE; | |
argv[1] = idval; | |
argv[2] = *rval; | |
JS_CallFunctionValue(cx, JS_GetGlobalObject(cx), func, 3, argv, rval); | |
return JS_TRUE; | |
} | |
JSBool xjs_dynobj_get(JSContext *cx, JSObject *obj, jsval idval, jsval *rval){ | |
jsval func, argv[2]; | |
JS_GetReservedSlot(cx, obj, 0, &func); | |
argv[0] = JSVAL_FALSE; | |
argv[1] = idval; | |
JS_CallFunctionValue(cx, JS_GetGlobalObject(cx), func, 2, argv, rval); | |
return JS_TRUE; | |
} | |
JSClass xjs_class_dynobj = { | |
"DynObj", JSCLASS_HAS_RESERVED_SLOTS(1), | |
xjs_dynobj_set, JS_PropertyStub, xjs_dynobj_get, xjs_dynobj_set, | |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, | |
}; | |
void xjs_clearhooks(struct xjs_instance *inst){ | |
while(inst->hookf){ | |
xchat_unhook(ph, inst->hookf->hook); | |
xjs_unreghook(inst->cx, inst->hookf->hook); | |
} | |
} | |
JSBool xjs_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
int x; | |
for(x = 0; x < argc; x++) | |
xchat_printf(ph, "%s\n", JS_GetStringBytes(JS_ValueToString(cx, argv[x]))); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xchat_print(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_emit_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
int x; | |
char *s[6]; | |
for(x = 0; x < 6; x++) | |
s[x] = x < argc? JS_EncodeString(cx, JS_ValueToString(cx, argv[x])) : NULL; | |
JS_NewNumberValue(cx, xchat_emit_print(ph, s[0], s[1], s[2], s[3], s[4], s[5]), rval); | |
for(x = 0; x < 6; x++) | |
if(s[x]) | |
JS_free(cx, s[x]); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_command(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xchat_command(ph, JS_EncodeString(cx, JS_ValueToString(cx, argv[0]))); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_get_prefs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *a; | |
const char *string; | |
int integer; | |
switch(xchat_get_prefs(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), &string, &integer)){ | |
case 0: | |
*rval = JSVAL_VOID; | |
break; | |
case 1: | |
a = JS_strdup(cx, string); | |
*rval = STRING_TO_JSVAL(JS_NewString(cx, a, strlen(a))); | |
break; | |
case 2: | |
JS_NewNumberValue(cx, integer, rval); | |
break; | |
case 3: | |
*rval = integer? JSVAL_TRUE : JSVAL_FALSE; | |
break; | |
} | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_send_modes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *nicks; | |
jsuint len; | |
jsval vp; | |
int x; | |
char *t1, *t2, **targets; | |
*rval = JSVAL_VOID; | |
if(JSVAL_IS_NULL(argv[0]) || !JSVAL_IS_OBJECT(argv[0]) || !JS_ValueToObject(cx, argv[0], &nicks) || !JS_IsArrayObject(cx, nicks)) | |
return JS_TRUE; | |
JS_GetArrayLength(cx, nicks, &len); | |
targets = JS_malloc(cx, (len > 10000? (len = 10000) : len) * sizeof(*targets)); | |
for(x = 0; x < len; x++){ | |
JS_GetElement(cx, nicks, x, &vp); | |
targets[x] = JS_EncodeString(cx, JS_ValueToString(cx, vp)); | |
} | |
if(argc <= 3 || !JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
xchat_send_modes(ph, (const char**) targets, len, x, /* fuck you, const keyword */ | |
*(t1 = JS_EncodeString(cx, JS_ValueToString(cx, argv[1 + (argc > 3)]))), | |
*(t2 = JS_EncodeString(cx, JS_ValueToString(cx, argv[2 + (argc > 3)])))); | |
JS_free(cx, t1); | |
JS_free(cx, t2); | |
for(x = 0; x < len; x++) | |
JS_free(cx, targets[x]); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_nickcmp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *t1, *t2; | |
JS_NewNumberValue(cx, xchat_nickcmp(ph, t1 = JS_EncodeString(cx, JS_ValueToString(cx, argv[0])), t2 = JS_EncodeString(cx, JS_ValueToString(cx, argv[1]))), rval); | |
JS_free(cx, t1); | |
JS_free(cx, t2); | |
return JS_TRUE; | |
} | |
int xjs_cmdcb(char **word, char **word_eol, void *udata){ | |
jsval rval, argv[2]; | |
JSObject *aword, *aword_eol; | |
struct jscb *cb; | |
int x; | |
cb = udata; | |
aword = JS_NewArrayObject(cb->inst->cx, 0, NULL); | |
for(x = 1; word[x] && *word[x]; x++) | |
JS_DefineElement(cb->inst->cx, aword, x, STRING_TO_JSVAL(JS_NewStringCopyZ(cb->inst->cx, word[x])), NULL, NULL, JSPROP_ENUMERATE); | |
aword_eol = JS_NewArrayObject(cb->inst->cx, 0, NULL); | |
for(x = 1; word_eol[x] && *word_eol[x]; x++) | |
JS_DefineElement(cb->inst->cx, aword_eol, x, STRING_TO_JSVAL(JS_NewStringCopyZ(cb->inst->cx, word_eol[x])), NULL, NULL, JSPROP_ENUMERATE); | |
argv[0] = OBJECT_TO_JSVAL(aword); | |
argv[1] = OBJECT_TO_JSVAL(aword_eol); | |
if(!JS_CallFunctionValue(cb->inst->cx, cb->inst->global, cb->func, 2, argv, &rval) || !JS_ValueToInt32(cb->inst->cx, rval, &x)) | |
x = 0; | |
JS_MaybeGC(cb->inst->cx); | |
return x; | |
} | |
int xjs_hpcb(char **word, void *udata){ | |
jsval rval, argv[1]; | |
JSObject *aword; | |
struct jscb *cb; | |
int x = 0; | |
cb = udata; | |
aword = JS_NewArrayObject(cb->inst->cx, 0, NULL); | |
for(x = 1; word[x] && *word[x]; x++) | |
JS_DefineElement(cb->inst->cx, aword, x, STRING_TO_JSVAL(JS_NewStringCopyZ(cb->inst->cx, word[x])), NULL, NULL, JSPROP_ENUMERATE); | |
argv[0] = OBJECT_TO_JSVAL(aword); | |
if(!JS_CallFunctionValue(cb->inst->cx, cb->inst->global, cb->func, 1, argv, &rval) || !JS_ValueToInt32(cb->inst->cx, rval, &x)) | |
x = 0; | |
JS_MaybeGC(cb->inst->cx); | |
return x; | |
} | |
int xjs_timecb(void *udata){ | |
jsval rval; | |
struct jscb *cb; | |
int x; | |
JSContext *cx; | |
cb = udata; | |
JS_CallFunctionValue(cx = cb->inst->cx, cb->inst->global, cb->func, 0, NULL, &rval); | |
if(JSVAL_IS_VOID(rval) || !JS_ValueToInt32(cx, rval, &x)) | |
x = 0; | |
if(!x){ | |
xjs_unreghook(cb->inst->cx, cb->hook); | |
xchat_unhook(ph, cb->hook); | |
JS_RemoveRoot(cb->inst->cx, &cb->func); | |
JS_free(cb->inst->cx, cb); | |
} | |
JS_MaybeGC(cx); | |
return x; | |
} | |
JSBool xjs_xchat_hook_command(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
char *t1, *t2; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 0; | |
cb->func = argv[2]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, | |
cb->hook = xchat_hook_command(ph, t1 = JS_EncodeString(cx, JS_ValueToString(cx, argv[0])), x, xjs_cmdcb, t2 = JS_EncodeString(cx, JS_ValueToString(cx, argv[3])), cb)); | |
JS_free(cx, t1); | |
JS_free(cx, t2); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_hook_timer(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 1; | |
cb->func = argv[1]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[0], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_timer(ph, x, xjs_timecb, cb)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_hook_server(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 2; | |
cb->func = argv[2]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_server(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), x, xjs_cmdcb, cb)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_hook_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct jscb *cb; | |
int x; | |
cb = JS_malloc(cx, sizeof(*cb)); | |
cb->type = 3; | |
cb->func = argv[2]; | |
cb->inst = JS_GetContextPrivate(cx); | |
JS_AddRoot(cx, &cb->func); | |
if(!JS_ValueToInt32(cx, argv[1], &x)) | |
x = 0; | |
*rval = xjs_hook_to_jsval(cx, cb->hook = xchat_hook_print(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), x, xjs_hpcb, cb)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_unhook(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval; | |
xchat_hook *hook; | |
if(!JSVAL_IS_OBJECT(argv[0]) || JS_GET_CLASS(cx, oval = JSVAL_TO_OBJECT(argv[0])) != &xjs_class_hook) | |
JS_ReportWarning(cx, "Not an XChatHook object"); | |
else if(hook = JS_GetPrivate(cx, oval)){ | |
xjs_unreghook(cx, hook); | |
xchat_unhook(ph, hook); | |
} | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_unhook_all(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xjs_clearhooks(JS_GetContextPrivate(cx)); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_strip(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *r; | |
int x; | |
if(JSVAL_IS_VOID(argv[1]) || !JS_ValueToInt32(cx, argv[1], &x)) | |
x = 2; | |
if(r = xchat_strip(ph, JS_GetStringBytes(JS_ValueToString(cx, argv[0])), -1, x)) | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, r)); | |
else | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_list_get(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *listobj, *listarray; | |
jsval listval; | |
xchat_list *xcl; | |
int x; | |
char *lname; | |
const char *const *sfields, *const *fields; | |
printf("lname = %s\n", lname = JS_EncodeString(cx, JS_ValueToString(cx, argv[0]))); | |
if(xcl = xchat_list_get(ph, lname)){ | |
*rval = OBJECT_TO_JSVAL(listarray = JS_NewArrayObject(cx, 0, NULL)); | |
sfields = xchat_list_fields(ph, lname); | |
for(x = 0; xchat_list_next(ph, xcl); x++){ | |
listobj = JS_NewObject(cx, NULL, NULL, NULL); | |
for(fields = sfields; *fields; fields++){ | |
switch(**fields){ | |
case 's': | |
listval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, xchat_list_str(ph, xcl, *fields+1))); | |
break; | |
case 'i': | |
JS_NewNumberValue(cx, xchat_list_int(ph, xcl, *fields+1), &listval); | |
break; | |
case 'p': | |
if(!strcmp(*fields+1, "context")){ | |
listval = xjs_context_to_jsval(cx, (xchat_context*)xchat_list_str(ph, xcl, *fields+1)); | |
break; | |
} | |
default: | |
continue; /* Any more pointers? */ | |
} | |
JS_SetProperty(cx, listobj, *fields+1, &listval); | |
} | |
JS_DefineElement(cx, listarray, x, OBJECT_TO_JSVAL(listobj), NULL, NULL, JSPROP_ENUMERATE); | |
} | |
xchat_list_free(ph, xcl); | |
}else | |
*rval = JSVAL_VOID; | |
JS_free(cx, lname); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_get_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
*rval = xjs_context_to_jsval(cx, xchat_get_context(ph)); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_cmp_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval1, *oval2; | |
if(!JSVAL_IS_OBJECT(argv[0]) || JS_GET_CLASS(cx, oval1 = JSVAL_TO_OBJECT(argv[0])) != &xjs_class_context | |
|| !JSVAL_IS_OBJECT(argv[1]) || JS_GET_CLASS(cx, oval2 = JSVAL_TO_OBJECT(argv[1])) != &xjs_class_context){ | |
JS_ReportWarning(cx, "Not an XChatContext object"); | |
*rval = JSVAL_VOID; | |
}else | |
*rval = JS_GetPrivate(cx, oval1) == JS_GetPrivate(cx, oval2)? JSVAL_TRUE : JSVAL_FALSE; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_set_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval; | |
if(!JSVAL_IS_OBJECT(argv[0]) || JS_GET_CLASS(cx, oval = JSVAL_TO_OBJECT(argv[0])) != &xjs_class_context){ | |
JS_ReportWarning(cx, "Not an XChatContext object"); | |
*rval = JSVAL_VOID; | |
}else | |
JS_NewNumberValue(cx, xchat_set_context(ph, JS_GetPrivate(cx, oval)), rval); | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_find_context(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
xchat_context *xccx; | |
char *t1, *t2; | |
*rval = (xccx = xchat_find_context(ph, | |
t1 = JSVAL_IS_STRING(argv[0])? JS_GetStringBytes(JS_ValueToString(cx, argv[0])) : NULL, | |
t2 = JSVAL_IS_STRING(argv[1])? JS_GetStringBytes(JS_ValueToString(cx, argv[1])) : NULL))? | |
xjs_context_to_jsval(cx, xccx) : JSVAL_VOID; | |
/* if(t1) JS_free(cx, t1); | |
if(t2) JS_free(cx, t2);*/ | |
return JS_TRUE; | |
} | |
JSBool xjs_jsinfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_instance *xjs; | |
JSObject *oval; | |
xjs = JS_GetContextPrivate(cx); | |
oval = JS_NewObject(cx, NULL, NULL, NULL); | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, JS_VersionToString(JS_GetVersion(cx)))); | |
JS_SetProperty(cx, oval, "jsver", rval); | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, xjs->name)); | |
JS_SetProperty(cx, oval, "scriptname", rval); | |
JS_NewNumberValue(cx, xjs->id, rval); | |
JS_SetProperty(cx, oval, "scriptid", rval); | |
*rval = OBJECT_TO_JSVAL(oval); | |
return JS_TRUE; | |
} | |
JSBool xjs_jsset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSVersion jsver; | |
char *key, *val; | |
if(JSVAL_IS_STRING(argv[0])){ | |
key = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); | |
if(!strcmp(key, "jsver")){ | |
if((jsver = JS_StringToVersion(val = JS_GetStringBytes(JS_ValueToString(cx, argv[1])))) != JSVERSION_UNKNOWN){ | |
JS_SetVersion(cx, jsver); | |
*rval = JSVAL_TRUE; | |
}else | |
*rval = JSVAL_FALSE; | |
JS_free(cx, val); | |
}else | |
*rval = JSVAL_VOID; | |
JS_free(cx, key); | |
} | |
return JS_TRUE; | |
} | |
JSBool xjs_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
static char fnbuf[1024]; | |
JSScript *script; | |
snprintf(fnbuf, 1024, "%s/xjs/%s", xchat_get_info(ph, "xchatdirfs"), JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); | |
if(script = JS_CompileFile(cx, JS_GetGlobalObject(cx), fnbuf)){ | |
JS_ExecuteScript(cx, JS_GetGlobalObject(cx), script, rval); | |
JS_DestroyScript(cx, script); | |
}else | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_dynobj(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
JSObject *oval; | |
oval = JS_NewObject(cx, &xjs_class_dynobj, NULL, NULL); | |
*rval = OBJECT_TO_JSVAL(oval); | |
JS_SetReservedSlot(cx, oval, 0, argv[0]); | |
return JS_TRUE; | |
} | |
JSBool xjs_DBG(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
struct xjs_instance *xjs; | |
struct xjs_hookll *ll; | |
xchat_printf(ph, "** cx = %p **\n", (void*)cx); | |
xchat_printf(ph, "** hook list **\n"); | |
xjs = JS_GetContextPrivate(cx); | |
for(ll = xjs->hookf; ll; ll = ll->next) | |
xchat_printf(ph, "-> %p: %p, %p\n", (void*)ll, (void*)ll->hook, (void*)ll->oval); | |
xchat_printf(ph, "** end **\n"); | |
*rval = JSVAL_VOID; | |
return JS_TRUE; | |
} | |
JSBool xjs_xchat_get_info(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
char *s; | |
if(!strcmp("win_ptr", s = JS_GetStringBytes(JS_ValueToString(cx, argv[0])))) | |
*rval = JSVAL_VOID; | |
else | |
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, xchat_get_info(ph, s))); | |
JS_free(cx, s); | |
return JS_TRUE; | |
} | |
void xjs_fd2obj(JSContext *cx, int fd, jsval *rval){ | |
JSObject *obj; | |
struct xjs_fpipe *pipes; | |
*rval = OBJECT_TO_JSVAL(obj = JS_NewObject(cx, &xjs_socket_class, NULL, NULL)); | |
JS_SetPrivate(cx, obj, pipes = malloc(sizeof(*pipes))); | |
JS_DefineProperties(cx, obj, xjs_file_props); | |
pipes->type = xjs_pipe_file; | |
pipes->fd = fd; | |
} | |
JSBool xjs_file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
int x, l, fd, fl, mo, r, w; | |
jschar *fo; | |
if(JSVAL_IS_STRING(argv[1])){ | |
l = JS_GetStringLength(JSVAL_TO_STRING(argv[1])); | |
fo = JS_GetStringChars(JSVAL_TO_STRING(argv[1])); | |
for(x = w = r = fl = 0; x < l; x++){ | |
fl |= fo[x] == 'a'? O_APPEND : 0; | |
fl |= fo[x] == 'c'? O_CREAT : 0; | |
fl |= fo[x] == 't'? O_TRUNC : 0; | |
r |= fo[x] == 'r'; | |
w |= fo[x] == 'w'; | |
} | |
fl |= r && w? O_RDWR : w? O_WRONLY : O_RDONLY; | |
}else | |
fl = O_RDONLY; | |
if(!JS_ValueToInt32(cx, argv[2], &mo)) | |
mo = 0644; | |
if((fd = open(JS_GetStringBytes(JS_ValueToString(cx, argv[0])), fl, mo)) < 0) | |
*rval = JSVAL_FALSE; | |
else | |
xjs_fd2obj(cx, fd, rval); | |
return JS_TRUE; | |
} | |
JSBool xjs_file_tcp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ | |
int sock, po; | |
struct hostent *she; | |
struct sockaddr_in saddr; | |
if((she = gethostbyname(JS_GetStringBytes(JS_ValueToString(cx, argv[0])))) == NULL){ | |
*rval = JSVAL_FALSE; | |
return JS_TRUE; | |
} | |
sock = socket(PF_INET, SOCK_STREAM, 0); | |
if(!JS_ValueToInt32(cx, argv[1], &po)) | |
po = 0; | |
saddr.sin_family = AF_INET; | |
saddr.sin_port = htons(po); | |
memcpy(&saddr.sin_addr, she->h_addr, she->h_length); | |
memset(saddr.sin_zero, 0, sizeof(saddr.sin_zero)); | |
if(connect(sock, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) | |
*rval = JSVAL_FALSE; | |
else | |
xjs_fd2obj(cx, sock, rval); | |
return JS_TRUE; | |
} | |
JSFunctionSpec file_functions[] = { | |
{"open", xjs_file_open, 3, 0, 0}, | |
{"tcp", xjs_file_tcp, 2, 0, 0}, | |
{NULL} | |
}; | |
JSFunctionSpec global_functions[] = { | |
{"print", xjs_print, 1, 0, 0}, | |
{"xchat_print", xjs_xchat_print, 1, 0, 0}, | |
{"xchat_emit_print", xjs_xchat_emit_print, 0, 0, 0}, | |
{"xchat_command", xjs_xchat_command, 1, 0, 0}, | |
{"xchat_get_prefs", xjs_xchat_get_prefs, 1, 0, 0}, | |
{"xchat_send_modes", xjs_xchat_send_modes, 3, 0, 0}, | |
{"xchat_nickcmp", xjs_xchat_nickcmp, 2, 0, 0}, | |
{"xchat_hook_command", xjs_xchat_hook_command, 4, 0, 0}, | |
{"xchat_hook_timer", xjs_xchat_hook_timer, 2, 0, 0}, | |
{"xchat_hook_server", xjs_xchat_hook_server, 3, 0, 0}, | |
{"xchat_hook_print", xjs_xchat_hook_print, 3, 0, 0}, | |
{"xchat_unhook", xjs_xchat_unhook, 1, 0, 0}, | |
{"xchat_unhook_all", xjs_xchat_unhook_all, 0, 0, 0}, | |
{"xchat_strip", xjs_xchat_strip, 2, 0, 0}, | |
{"xchat_list_get", xjs_xchat_list_get, 1, 0, 0}, | |
{"xchat_get_context", xjs_xchat_get_context, 0, 0, 0}, | |
{"xchat_cmp_context", xjs_xchat_cmp_context, 2, 0, 0}, | |
{"xchat_set_context", xjs_xchat_set_context, 1, 0, 0}, | |
{"xchat_find_context", xjs_xchat_find_context, 2, 0, 0}, | |
{"xchat_get_info", xjs_xchat_get_info, 1, 0, 0}, | |
{"DynObj", xjs_dynobj, 1, 0, 0}, | |
{"JsInfo", xjs_jsinfo, 0, 0, 0}, | |
{"JsSet", xjs_jsset, 2, 0, 0}, | |
{"load", xjs_load, 1, 0, 0}, | |
{"DBG", xjs_DBG, 0, 0, 0}, | |
{NULL} | |
}; | |
JSConstDoubleSpec global_properties[] = { | |
{XCHAT_IFACE_MAJOR, "XCHAT_IFACE_MAJOR", JSPROP_READONLY}, | |
{XCHAT_IFACE_MINOR, "XCHAT_IFACE_MINOR", JSPROP_READONLY}, | |
{XCHAT_IFACE_MICRO, "XCHAT_IFACE_MICRO", JSPROP_READONLY}, | |
{XCHAT_PRI_HIGHEST, "XCHAT_PRI_HIGHEST", JSPROP_READONLY}, | |
{XCHAT_PRI_HIGH, "XCHAT_PRI_HIGH", JSPROP_READONLY}, | |
{XCHAT_PRI_NORM, "XCHAT_PRI_NORM", JSPROP_READONLY}, | |
{XCHAT_PRI_LOW, "XCHAT_PRI_LOW", JSPROP_READONLY}, | |
{XCHAT_PRI_LOWEST, "XCHAT_PRI_LOWEST", JSPROP_READONLY}, | |
{XCHAT_FD_READ, "XCHAT_FD_READ", JSPROP_READONLY}, | |
{XCHAT_FD_WRITE, "XCHAT_FD_WRITE", JSPROP_READONLY}, | |
{XCHAT_FD_EXCEPTION, "XCHAT_FD_EXCEPTION", JSPROP_READONLY}, | |
{XCHAT_FD_NOTSOCKET, "XCHAT_FD_NOTSOCKET", JSPROP_READONLY}, | |
{XCHAT_EAT_NONE, "XCHAT_EAT_NONE", JSPROP_READONLY}, | |
{XCHAT_EAT_XCHAT, "XCHAT_EAT_XCHAT", JSPROP_READONLY}, | |
{XCHAT_EAT_PLUGIN, "XCHAT_EAT_PLUGIN", JSPROP_READONLY}, | |
{XCHAT_EAT_ALL, "XCHAT_EAT_ALL", JSPROP_READONLY}, | |
{0} | |
}; | |
struct xjs_instance *xjs_init(char *name){ | |
struct xjs_instance *inst; | |
JSObject *file; | |
jsval oval, fval; | |
inst = malloc(sizeof(*inst) + strlen(name) + 1); | |
strcpy(inst->name, name); | |
inst->cx = JS_NewContext(rt, 0x1000); | |
JS_SetContextPrivate(inst->cx, inst); | |
oval = OBJECT_TO_JSVAL(inst->global = JS_NewObject(inst->cx, &xjs_class_scriptglobal, NULL, NULL)); | |
JS_AddRoot(inst->cx, &inst->global); | |
inst->hookf = inst->hookl = NULL; | |
inst->next = NULL; | |
inst->id = xjs_instl? xjs_instl->id + 1 : 0; | |
xjs_instl = *(xjs_instl? &xjs_instl->next : &xjs_instf) = inst; | |
JS_SetProperty(inst->cx, inst->global, "global", &oval); | |
JS_SetErrorReporter(inst->cx, js_errorhandler); | |
JS_InitStandardClasses(inst->cx, inst->global); | |
JS_DefineFunctions(inst->cx, inst->global, global_functions); | |
JS_DefineConstDoubles(inst->cx, inst->global, global_properties); | |
fval = OBJECT_TO_JSVAL(file = JS_NewObject(inst->cx, &xjs_class_file, NULL, NULL)); | |
JS_SetProperty(inst->cx, inst->global, "File", &fval); | |
JS_DefineFunctions(inst->cx, file, file_functions); | |
return inst; | |
} | |
void xjs_exit(struct xjs_instance *inst, int destroyall){ | |
struct xjs_instance *inst1, *inst2; | |
for(inst1 = xjs_instf; inst1; inst2 = inst1, inst1 = inst1->next) | |
if(inst1 == inst) | |
break; | |
if(inst == xjs_instf) | |
(xjs_instf = inst->next) == NULL && (xjs_instl = NULL); | |
else | |
inst2->next = inst->next; | |
xjs_clearhooks(inst); | |
JS_RemoveRoot(inst->cx, &inst->global); | |
JS_DestroyContext(inst->cx); | |
free(inst); | |
if(!destroyall && inst == xjs_cmdline) | |
xjs_cmdline = xjs_init("<commandline>"); | |
} | |
int xjs_eval(struct xjs_instance *inst, char *str, jsval *rval){ | |
return !!JS_EvaluateScript(inst->cx, inst->global, str, strlen(str), inst->name, 0, rval); | |
} | |
char *xjs_eval2str(struct xjs_instance *inst, char *str){ | |
jsval rval; | |
if(xjs_eval(inst, str, &rval)) | |
return JSVAL_IS_VOID(rval)? NULL : JS_GetStringBytes(JS_ValueToString(inst->cx, rval)); | |
else | |
return NULL; | |
} | |
struct xjs_instance *xjs_run(char *fname){ | |
struct xjs_instance *inst; | |
char *name; | |
int x; | |
jsval rval; | |
JSScript *script; | |
for(name = fname, x = 0; fname[x]; x++) | |
if(fname[x] == '/') | |
name = fname + x + 1; | |
inst = xjs_init(name); | |
if(!(script = JS_CompileFile(inst->cx, inst->global, fname))) | |
return NULL; | |
else{ | |
JS_ExecuteScript(inst->cx, inst->global, script, &rval); | |
JS_DestroyScript(inst->cx, script); | |
} | |
return inst; | |
} | |
int xcmd_js(char **word, char **word_eol, void *udata){ | |
struct xjs_instance *instl; | |
int id; | |
static char fnbuf[1024], *t; | |
if(!strcasecmp(word[2], "l")){ | |
xchat_printf(ph, " Ref# Name\n"); | |
for(instl = xjs_instf; instl; instl = instl->next) | |
xchat_printf(ph, "%5i %s\n", instl->id, instl->name); | |
}else if(!strcasecmp(word[2], "e")){ | |
if(t = xjs_eval2str(xjs_cmdline, word_eol[3])) | |
xchat_printf(ph, "%s\n", t); | |
}else if(!strcasecmp(word[2], "i") && *word[3] && *word_eol[4]){ | |
id = atoi(word[3]); | |
for(instl = xjs_instf; instl; instl = instl->next) | |
if(instl->id == id) | |
break; | |
if(instl && instl->id == id){ | |
if(t = xjs_eval2str(instl, word_eol[4])) | |
xchat_printf(ph, "%s\n", t); | |
}else | |
xchat_printf(ph, "Couldn't find context ID %i\n", id); | |
}else if(!strcasecmp(word[2], "o") && *word_eol[3]){ | |
snprintf(fnbuf, 1024, "%s/xjs/%s", xchat_get_info(ph, "xchatdirfs"), word_eol[3]); | |
if(instl = xjs_run(fnbuf)) | |
xchat_printf(ph, "Loaded %s with ID=%i\n", instl->name, instl->id); | |
else | |
xchat_printf(ph, "Failed to load %s\n", fnbuf); | |
}else if(!strcasecmp(word[2], "k") && *word[3]){ | |
id = atoi(word[3]); | |
for(instl = xjs_instf; instl; instl = instl->next) | |
if(instl->id == id) | |
break; | |
if(instl && instl->id == id){ | |
if(!JS_IsRunning(instl->cx)){ | |
xchat_printf(ph, "Killing %s with ID=%i\n", instl->name, instl->id); | |
xjs_exit(instl, 0); | |
}else | |
xchat_printf(ph, "Cannot kill active context\n"); | |
} | |
}else | |
xchat_print(ph, XCMD_JS_HELP); | |
return XCHAT_EAT_ALL; | |
} | |
void xchat_plugin_get_info(char **name, char **desc, char **version, void **reserved){ | |
*name = PLUGNAME; | |
*desc = PLUGDESC; | |
*version = PLUGVER; | |
} | |
int xchat_plugin_init(xchat_plugin *xph, char **name, char **desc, char **version, char *arg){ | |
ph = xph; | |
xchat_plugin_get_info(name, desc, version, NULL); | |
xchat_hook_command(ph, "JS", XCHAT_PRI_NORM, xcmd_js, XCMD_JS_HELP, NULL); | |
rt = JS_NewRuntime(0x100000); | |
xjs_cmdline = xjs_init("<commandline>"); | |
xchat_print(ph, "XJS (JavaScript plugin) loaded!"); | |
return 1; | |
} | |
int xchat_plugin_deinit(){ | |
while(xjs_instf) | |
xjs_exit(xjs_instf, 1); | |
JS_DestroyRuntime(rt); | |
JS_ShutDown(); | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment