]>
jfr.im git - irc/evilnet/x3.git/blob - src/mod-python.c
1 /* mod-python.c - Script module for x3
2 * Copyright 2003-2004 Martijn Smit and srvx Development Team
3 * Copyright 2005-2006 X3 Development Team
5 * This file is part of x3.
7 * x3 is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with srvx; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 #ifdef WITH_PYTHON /* just disable this file if python doesnt exist */
38 * - Impliment most of proto-p10 irc_* commands for calling from scripts
39 * - Impliment functions to look up whois, channel, account, and reg-channel info for scripts
40 * - Impliment x3.conf settings for python variables like include path, etc.
41 * - kod-python.py calls for everything you can reg_ a handler for in x3
42 * - Some kind of system for getting needed binds bound automagicaly to make it easier
43 * to run peoples scripts and mod-python in general.
46 static const struct message_entry msgtab
[] = {
47 { "PYMSG_RELOAD_SUCCESS", "Reloaded Python scripts successfully." },
48 { "PYMSG_RELOAD_FAILED", "Error reloading Python scripts." },
49 { NULL
, NULL
} /* sentenal */
52 static struct log_type
*PY_LOG
;
53 const char *python_module_deps
[] = { NULL
};
54 static struct module *python_module
;
56 PyObject
*base_module
= NULL
; /* Base python handling library */
57 PyObject
*handler_object
= NULL
; /* instanciation of handler class */
60 emb_dump(PyObject
*self
, PyObject
*args
)
66 if(!PyArg_ParseTuple(args
, "s:dump", &buf
))
68 safestrncpy(linedup
, buf
, sizeof(linedup
));
69 if(parse_line(linedup
, 1)) {
73 return Py_BuildValue("i", ret
);
77 emb_send_target_privmsg(PyObject
*self
, PyObject
*args
)
84 struct service
*service
;
86 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &channel
, &buf
))
88 if(!(service
= service_find(servicenick
))) {
89 /* TODO: generate python exception here */
92 send_target_message(5, channel
, service
->bot
, "%s", buf
);
93 return Py_BuildValue("i", ret
);
97 emb_send_target_notice(PyObject
*self
, PyObject
*args
)
104 struct service
*service
;
106 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &target
, &buf
))
108 if(!(service
= service_find(servicenick
))) {
109 /* TODO: generate python exception here */
112 send_target_message(4, target
, service
->bot
, "%s", buf
);
113 return Py_BuildValue("i", ret
);
118 emb_get_user(PyObject
*self
, PyObject
*args
)
121 struct userNode
*user
;
125 if(!PyArg_ParseTuple(args
, "s", &nick
))
127 if(!(user
= GetUserH(nick
))) {
128 /* TODO: generate python exception here */
131 pChanList
= PyTuple_New(user
->channels
.used
);
132 for(n
=0;n
<user
->channels
.used
;n
++) {
133 mn
= user
->channels
.list
[n
];
134 PyTuple_SetItem(pChanList
, n
, Py_BuildValue("s", mn
->channel
->name
));
136 return Py_BuildValue("{s:s,s:s,s:s,s:s,s:s" /* format strings. s=string, i=int */
137 ",s:s,s:s,s:s,s:s,s:s" /* (format is key:value) O=object */
138 ",s:i,s:i,s:s,s:s,s:s" /* blocks of 5 for readability */
142 "ident", user
->ident
,
144 "hostname", user
->hostname
,
145 "ip", irc_ntoa(&user
->ip
),
147 "fakehost", user
->fakehost
,
148 "sethost", user
->sethost
,
149 "crypthost", user
->crypthost
,
150 "cryptip", user
->cryptip
,
151 "numeric", user
->numeric
, /* TODO: only ifdef WITH_PROTOCOL_P10 */
154 "no_notice", user
->no_notice
,
156 "version_reply", user
->version_reply
,
157 "account", user
->handle_info
?user
->handle_info
->handle
:NULL
,
158 "channels", pChanList
);
162 emb_get_channel(PyObject
*self
, PyObject
*args
)
165 struct chanNode
*channel
;
167 PyObject
*pChannelMembers
;
168 PyObject
*pChannelBans
;
169 PyObject
*pChannelExempts
;
171 if(!PyArg_ParseTuple(args
, "s", &name
))
173 if(!(channel
= GetChannel(name
))) {
174 /* TODO: generate py exception here */
178 /* build tuple of nicks in channel */
179 pChannelMembers
= PyTuple_New(channel
->members
.used
);
180 for(n
=0;n
< channel
->members
.used
;n
++) {
181 struct modeNode
*mn
= channel
->members
.list
[n
];
182 PyTuple_SetItem(pChannelMembers
, n
, Py_BuildValue("s", mn
->user
->nick
));
185 /* build tuple of bans */
186 pChannelBans
= PyTuple_New(channel
->banlist
.used
);
187 for(n
=0; n
< channel
->banlist
.used
;n
++) {
188 struct banNode
*bn
= channel
->banlist
.list
[n
];
189 PyTuple_SetItem(pChannelBans
, n
,
190 Py_BuildValue("{s:s,s:s,s:i}",
198 /* build tuple of exempts */
199 pChannelExempts
= PyTuple_New(channel
->exemptlist
.used
);
200 for(n
=0; n
< channel
->exemptlist
.used
;n
++) {
201 struct exemptNode
*en
= channel
->exemptlist
.list
[n
];
202 PyTuple_SetItem(pChannelExempts
, n
,
203 Py_BuildValue("{s:s,s:s,s:i}",
212 return Py_BuildValue("{s:s,s:s,s:s,s:i"
213 ",s:i,s:i,s:O,s:O,s:O}",
215 "name", channel
->name
,
216 "topic", channel
->topic
,
217 "topic_nick", channel
->topic_nick
,
218 "topic_time", channel
->topic_time
,
220 "timestamp", channel
->timestamp
,
221 "modes", channel
->modes
,
222 "members", pChannelMembers
,
223 "bans", pChannelBans
,
224 "exempts", pChannelExempts
230 emb_get_account(PyObject *self, PyObject *args)
233 if(!PyArg_ParseTuple(args, "s", &name))
239 static PyMethodDef EmbMethods
[] = {
240 {"dump", emb_dump
, METH_VARARGS
, "Dump raw P10 line to server"},
241 {"send_target_privmsg", emb_send_target_privmsg
, METH_VARARGS
, "Send a message to somewhere"},
242 {"send_target_notice", emb_send_target_notice
, METH_VARARGS
, "Send a notice to somewhere"},
243 {"get_user", emb_get_user
, METH_VARARGS
, "Get details about a nickname"},
244 {"get_channel", emb_get_channel
, METH_VARARGS
, "Get details about a channel"},
245 {NULL
, NULL
, 0, NULL
}
250 /* This is just a hack-job for testing. It'll go away. */
251 int python_call_func_real(char *function
, char *args
[], size_t argc
) {
252 /* TODO: get arguments, pass through to python function */
253 PyObject
*pFunc
, *pValue
;
254 PyObject
*pArgs
= NULL
;
255 if(base_module
!= NULL
) {
256 log_module(PY_LOG
, LOG_INFO
, "Attempting to run python function %s", function
);
257 pFunc
= PyObject_GetAttrString(base_module
, function
);
258 /* pFunc is a new reference */
259 if(pFunc
&& PyCallable_Check(pFunc
)) {
262 pArgs
= PyTuple_New(argc
);
263 for(i
= 0; i
< argc
; ++i
) {
264 pValue
= PyString_FromString(args
[i
]);
268 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[i
]);
271 PyTuple_SetItem(pArgs
, i
, pValue
);
275 pValue
= PyObject_CallObject(pFunc
, pArgs
);
281 ret
= PyInt_AsLong(pValue
);
282 if(ret
== -1 && PyErr_Occurred()) {
284 log_module(PY_LOG
, LOG_INFO
, "error converting return value of %s to type long. ", function
);
287 log_module(PY_LOG
, LOG_INFO
, "%s was run successfully, returned %d.", function
, ret
);
288 /* TODO: convert pValue to c int, return it below */
294 /* TODO: instead of print errors, get them as strings
295 * and deal with them with normal x3 log system. */
297 log_module(PY_LOG
, LOG_WARNING
, "call to %s failed", function
);
304 log_module(PY_LOG
, LOG_WARNING
, "function %s not found or uncallable", function
);
313 /* This is just a hack-job for testing. It will go away */
314 int python_call_func(char *function
, char *args
[], size_t argc
, char *command_caller
, char *command_target
, char *command_service
) {
315 char *setargs
[] = {command_caller
?command_caller
:"",
316 command_target
?command_target
:"",
317 command_service
?command_service
:""};
318 python_call_func_real("command_set", setargs
, 3);
319 python_call_func_real(function
, args
, argc
);
320 python_call_func_real("command_clear", NULL
, 0);
324 PyObject
*python_build_handler_args(size_t argc
, char *args
[], PyObject
*pIrcObj
) {
326 PyObject
*pArgs
= NULL
;
328 pArgs
= PyTuple_New(argc
+ 1);
330 PyTuple_SetItem(pArgs
, i
++, pIrcObj
);
334 for(n
= 0; n
< argc
; ++n
) {
335 pValue
= PyString_FromString(args
[n
]);
338 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[n
]);
341 PyTuple_SetItem(pArgs
, n
+i
, pValue
);
347 PyObject
*python_build_args(size_t argc
, char *args
[]) {
349 PyObject
*pArgs
= NULL
;
352 pArgs
= PyTuple_New(argc
);
354 for(i
= 0; i
< argc
; ++i
) {
355 pValue
= PyString_FromString(args
[i
]);
358 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[i
]);
361 PyTuple_SetItem(pArgs
, i
, pValue
);
368 PyObject
*new_irc_object(char *command_service
, char *command_caller
, char *command_target
) {
369 PyObject
*pIrcArgs
= NULL
;
373 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate irc class");
374 pIrcClass
= PyObject_GetAttrString(base_module
, "irc");
375 /* pIrcClass is a new reference */
376 if(pIrcClass
&& PyCallable_Check(pIrcClass
)) {
378 char *ircargs
[] = {command_service
, command_caller
, command_target
};
381 pIrcArgs
= python_build_args(3, ircargs
);
383 pIrcArgs = PyTuple_New(sizeof(ircargs));
384 for(i = 0; i< ircargc; ++i) {
386 pValue = PyString_FromString(ircargs[i]);
389 log_module(PY_LOG, LOG_ERROR, "Unable to convert '%s' to python string", ircargs[i]);
397 PyTuple_SetItem(pIrcArgs, i, pValue);
400 pIrcObj
= PyObject_CallObject(pIrcClass
, pIrcArgs
);
402 log_module(PY_LOG
, LOG_ERROR
, "IRC Class failed to load");
405 if(pIrcArgs
!= NULL
) {
411 log_module(PY_LOG
, LOG_ERROR
, "Unable to find irc class");
417 int python_call_handler(char *handler
, char *args
[], size_t argc
, char *command_service
, char *command_caller
, char *command_target
) {
419 * - Instanciate class 'irc' with command-* arguments and save it.
420 * - get/find handler class instance
421 * - call handler.<handler> passing in proper args
422 * - destroy irc instance
423 * - return something useful?
430 log_module(PY_LOG
, LOG_INFO
, "attempting to call handler %s.", handler
);
431 if(base_module
!= NULL
) {
432 pIrcObj
= new_irc_object(command_service
, command_caller
, command_target
);
434 log_module(PY_LOG
, LOG_INFO
, "Can't get irc object. Bailing.");
438 pArgs
= python_build_handler_args(argc
, args
, pIrcObj
);
439 pMethod
= PyObject_GetAttrString(handler_object
, handler
);
440 if(pMethod
&& PyCallable_Check(pMethod
)) {
441 pValue
= PyObject_CallObject(pMethod
, pArgs
);
447 ret
= PyInt_AsLong(pValue
);
448 if(ret
== -1 && PyErr_Occurred()) {
450 log_module(PY_LOG
, LOG_INFO
, "error converting return value of handler %s to type long. ", handler
);
453 log_module(PY_LOG
, LOG_INFO
, "handler %s was run successfully, returned %d.", handler
, ret
);
454 /* TODO: convert pValue to c int, return it below */
461 /* TODO: instead of print errors, get them as strings
462 * and deal with them with normal x3 log system. */
464 log_module(PY_LOG
, LOG_WARNING
, "call to handler %s failed", handler
);
468 else { /* couldn't find handler methed */
469 log_module(PY_LOG
, LOG_ERROR
, "Cannot find handler %s.", handler
);
474 else { /* No base module.. no python? */
475 log_module(PY_LOG
, LOG_INFO
, "Cannot handle %s, Python is not initialized.", handler
);
480 PyObject
*python_new_handler_object() {
481 PyObject
*pHandlerClass
, *pHandlerObj
;
483 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate python class handler");
484 pHandlerClass
= PyObject_GetAttrString(base_module
, "handler");
485 /* Class is a new reference */
486 if(pHandlerClass
&& PyCallable_Check(pHandlerClass
)) {
487 /*PyObject *pValue; */
489 pHandlerObj
= PyObject_CallObject(pHandlerClass
, NULL
);
493 log_module(PY_LOG
, LOG_ERROR
, "Unable to find handler class");
498 /* debate: do we just register these and check them in python
499 * for every one (slow?) or actually work out if a plugin needs
500 * it first? We will start by doing it every time.
503 python_handle_join(struct modeNode
*mNode
)
505 struct userNode
*user
= mNode
->user
;
506 struct chanNode
*channel
= mNode
->channel
;
509 log_module(PY_LOG
, LOG_INFO
, "python module handle_join");
510 if(!channel
||!user
) {
511 log_module(PY_LOG
, LOG_WARNING
, "Join without channel or user?");
515 char *args
[] = {channel
->name
, user
->nick
};
516 return python_call_handler("join", args
, 2, "", "", "");
524 setenv("PYTHONPATH", "/home/rubin/afternet/services/x3/x3-run/", 1);
526 Py_InitModule("svc", EmbMethods
);
527 //PyRun_SimpleString("import svc");
528 /* TODO: get "modpython" from x3.conf */
529 pName
= PyString_FromString("modpython");
530 base_module
= PyImport_Import(pName
);
532 if(base_module
!= NULL
) {
533 handler_object
= python_new_handler_object();
535 python_call_handler("init", NULL
, 0, "", "", "");
539 /* error handler class not found */
540 log_module(PY_LOG
, LOG_WARNING
, "Failed to create handler object");
546 log_module(PY_LOG
, LOG_WARNING
, "Failed to load modpython.py");
552 /* Called after X3 is fully up and running */
554 python_finalize(void) {
556 PyRun_SimpleString("print 'Hello, World of Python!'");
557 log_module(PY_LOG
, LOG_INFO
, "python module finalize");
562 /* Called on shutdown of the module */
566 log_module(PY_LOG
, LOG_INFO
, "python module cleanup");
567 Py_Finalize(); /* Shut down python enterpriter */
571 static MODCMD_FUNC(cmd_reload
) {
572 log_module(PY_LOG
, LOG_INFO
, "Shutting python down");
574 log_module(PY_LOG
, LOG_INFO
, "Loading python stuff");
576 reply("PYMSG_RELOAD_SUCCESS");
579 reply("PYMSG_RELOAD_FAILED");
584 static MODCMD_FUNC(cmd_run
) {
587 msg
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
588 /* PyRun_SimpleString(msg); */
589 char *args
[] = {msg
};
590 python_call_func("run", args
, 1, user
?user
->nick
:"", channel
?channel
->name
:"", cmd
->parent
->bot
->nick
);
594 /* Called on init of the module during startup */
595 int python_init(void) {
597 PY_LOG
= log_register_type("Python", "file:python.log");
598 python_module
= module_register("python", PY_LOG
, "mod-python.help", NULL
);
599 log_module(PY_LOG
, LOG_INFO
, "python module init");
600 message_register_table(msgtab
);
603 reg_auth_func(python_check_messages);
604 reg_handle_rename_func(python_rename_account);
605 reg_unreg_func(python_unreg_account);
606 conf_register_reload(python_conf_read);
607 saxdb_register("python", python_saxdb_read, python_saxdb_write);
608 modcmd_register(python_module, "send", cmd_send, 3, MODCMD_REQUIRE_AUTHED, NULL);
610 modcmd_register(python_module
, "reload", cmd_reload
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
611 modcmd_register(python_module
, "run", cmd_run
, 2, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
612 reg_join_func(python_handle_join
);
613 reg_exit_func(python_cleanup
);
619 #endif /* WITH_PYTHON */