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 */
39 * - Impliment most of proto-p10 irc_* commands for calling from scripts
40 * - Impliment functions to look up whois, channel, account, and reg-channel info for scripts
41 * - Impliment x3.conf settings for python variables like include path, etc.
42 * - modpython.py calls for everything you can reg_ a handler for in x3
43 * - Some kind of system for getting needed binds bound automagicaly to make it easier
44 * to run peoples scripts and mod-python in general.
45 * - An interface to reading/writing data to x3.db. Maybe generic, or attached to account or channel reg records?
48 static const struct message_entry msgtab
[] = {
49 { "PYMSG_RELOAD_SUCCESS", "Reloaded Python scripts successfully." },
50 { "PYMSG_RELOAD_FAILED", "Error reloading Python scripts." },
51 { "PYMSG_RUN_UNKNOWN_EXCEPTION", "Error running python: unknown exception." },
52 { "PYMSG_RUN_EXCEPTION", "Error running python: %s." },
53 { NULL
, NULL
} /* sentenal */
56 #define MODPYTHON_CONF_NAME "modules/python"
60 char const* scripts_dir
;
63 static struct log_type
*PY_LOG
;
64 const char *python_module_deps
[] = { NULL
};
65 static struct module *python_module
;
67 PyObject
*base_module
= NULL
; /* Base python handling library */
68 PyObject
*handler_object
= NULL
; /* instanciation of handler class */
71 extern struct userNode
*global
, *chanserv
, *opserv
, *nickserv
, *spamserv
;
73 /* ---------------------------------------------------------------------- *
74 Some hooks you can call from modpython.py to interact with the
75 service, and IRC. These emb_* functions are available as svc.*
80 emb_dump(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
82 /* Dump a raw string into the socket
83 usage: svc.dump(<P10 string>)
90 if(!PyArg_ParseTuple(args
, "s:dump", &buf
))
92 safestrncpy(linedup
, buf
, sizeof(linedup
));
93 if(parse_line(linedup
, 1)) {
97 return Py_BuildValue("i", ret
);
101 emb_send_target_privmsg(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
104 usage: svc.send_target_privmsg(<servicenick_from>, <nick_to>, <message>)
111 struct service
*service
;
114 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &channel
, &buf
))
116 if(!(service
= service_find(servicenick
))) {
117 /* TODO: generate python exception here */
120 send_target_message(5, channel
, service
->bot
, "%s", buf
);
121 return Py_BuildValue("i", ret
);
125 emb_send_target_notice(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
128 usage: svc.send_target_notice(<servicenick_from>, <nick_to>, <message>)
135 struct service
*service
;
138 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &target
, &buf
))
140 if(!(service
= service_find(servicenick
))) {
141 /* TODO: generate python exception here */
144 send_target_message(4, target
, service
->bot
, "%s", buf
);
145 return Py_BuildValue("i", ret
);
149 emb_get_user(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
151 /* Get a python object containing everything x3 knows about a user, by nick.
152 usage: svc.get_user(<nick>)
155 struct userNode
*user
;
161 if(!PyArg_ParseTuple(args
, "s", &nick
))
163 if(!(user
= GetUserH(nick
))) {
164 /* TODO: generate python exception here */
167 pChanList
= PyTuple_New(user
->channels
.used
);
168 for(n
=0;n
<user
->channels
.used
;n
++) {
169 mn
= user
->channels
.list
[n
];
170 PyTuple_SetItem(pChanList
, n
, Py_BuildValue("s", mn
->channel
->name
));
172 return Py_BuildValue("{s:s,s:s,s:s,s:s,s:s" /* format strings. s=string, i=int */
173 ",s:s,s:s,s:s,s:s,s:s" /* (format is key:value) O=object */
174 ",s:i,s:i,s:s,s:s,s:s" /* blocks of 5 for readability */
178 "ident", user
->ident
,
180 "hostname", user
->hostname
,
181 "ip", irc_ntoa(&user
->ip
),
183 "fakehost", user
->fakehost
,
184 "sethost", user
->sethost
,
185 "crypthost", user
->crypthost
,
186 "cryptip", user
->cryptip
,
187 "numeric", user
->numeric
, /* TODO: only ifdef WITH_PROTOCOL_P10 */
190 "no_notice", user
->no_notice
,
192 "version_reply", user
->version_reply
,
193 "account", user
->handle_info
?user
->handle_info
->handle
:NULL
,
194 "channels", pChanList
);
198 emb_get_channel(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
200 /* Returns a python dict object with all sorts of info about a channel.
201 usage: svc.get_channel(<name>)
204 struct chanNode
*channel
;
206 PyObject
*pChannelMembers
;
207 PyObject
*pChannelBans
;
208 PyObject
*pChannelExempts
;
211 if(!PyArg_ParseTuple(args
, "s", &name
))
213 if(!(channel
= GetChannel(name
))) {
214 /* TODO: generate py exception here */
218 /* build tuple of nicks in channel */
219 pChannelMembers
= PyTuple_New(channel
->members
.used
);
220 for(n
=0;n
< channel
->members
.used
;n
++) {
221 struct modeNode
*mn
= channel
->members
.list
[n
];
222 PyTuple_SetItem(pChannelMembers
, n
, Py_BuildValue("s", mn
->user
->nick
));
225 /* build tuple of bans */
226 pChannelBans
= PyTuple_New(channel
->banlist
.used
);
227 for(n
=0; n
< channel
->banlist
.used
;n
++) {
228 struct banNode
*bn
= channel
->banlist
.list
[n
];
229 PyTuple_SetItem(pChannelBans
, n
,
230 Py_BuildValue("{s:s,s:s,s:i}",
237 /* build tuple of exempts */
238 pChannelExempts
= PyTuple_New(channel
->exemptlist
.used
);
239 for(n
=0; n
< channel
->exemptlist
.used
;n
++) {
240 struct exemptNode
*en
= channel
->exemptlist
.list
[n
];
241 PyTuple_SetItem(pChannelExempts
, n
,
242 Py_BuildValue("{s:s,s:s,s:i}",
249 return Py_BuildValue("{s:s,s:s,s:s,s:i"
250 ",s:i,s:i,s:O,s:O,s:O}",
252 "name", channel
->name
,
253 "topic", channel
->topic
,
254 "topic_nick", channel
->topic_nick
,
255 "topic_time", channel
->topic_time
,
257 "timestamp", channel
->timestamp
,
258 "modes", channel
->modes
,
259 "members", pChannelMembers
,
260 "bans", pChannelBans
,
261 "exempts", pChannelExempts
266 emb_get_account(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
268 /* Returns a python dict object with all sorts of info about an account.
269 usage: svc.get_account(<account name>)
272 struct handle_info
*hi
;
275 if(!PyArg_ParseTuple(args
, "s", &name
))
278 hi
= get_handle_info(name
);
282 return Py_BuildValue("{s:s,s:i,s:s,s:s,s:s"
285 "account", hi
->handle
,
286 "registered", hi
->registered
,
287 "last_seen", hi
->lastseen
,
288 "infoline", hi
->infoline
? hi
->infoline
: "",
289 "email", hi
->email_addr
? hi
->email_addr
: "",
291 "fakehost", hi
->fakehost
? hi
->fakehost
: "",
292 "last_quit_host", hi
->last_quit_host
295 /* users online authed to this account */
297 /* nicks (nickserv nets only?) */
305 emb_get_info(UNUSED_ARG(PyObject
*self
), UNUSED_ARG(PyObject
*args
))
307 /* return some info about the general setup
308 * of X3, such as what the chanserv's nickname
313 return Py_BuildValue("{s:s,s:s,s:s,s:s,s:s}",
314 "chanserv", chanserv
? chanserv
->nick
: "ChanServ",
315 "nickserv", nickserv
?nickserv
->nick
: "NickServ",
316 "opserv", opserv
?opserv
->nick
: "OpServ",
317 "global", global
?global
->nick
: "Global",
318 "spamserv", spamserv
?spamserv
->nick
: "SpamServ");
322 emb_log_module(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
324 /* a gateway to standard X3 logging subsystem.
325 * level is a value 0 to 9 as defined by the log_severity enum in log.h.
326 * LOG_INFO is 3, LOG_WARNING is 6, LOG_ERROR is 7.
328 * for now, all logs go to the PY_LOG log. In the future this will change.
335 if(!PyArg_ParseTuple(args
, "is", &level
, &message
))
338 log_module(PY_LOG
, level
, "%s", message
);
340 return Py_BuildValue("i", ret
);
343 static PyMethodDef EmbMethods
[] = {
344 /* Communication methods */
345 {"dump", emb_dump
, METH_VARARGS
, "Dump raw P10 line to server"},
346 {"send_target_privmsg", emb_send_target_privmsg
, METH_VARARGS
, "Send a message to somewhere"},
347 {"send_target_notice", emb_send_target_notice
, METH_VARARGS
, "Send a notice to somewhere"},
348 {"log_module", emb_log_module
, METH_VARARGS
, "Log something using the X3 log subsystem"},
349 //TODO: {"exec_cmd", emb_exec_cmd, METH_VARARGS, "execute x3 command provided"},
350 // This should use environment from "python command" call to pass in, if available
354 //TODO: {"gline", emb_gline, METH_VARARGS, "gline a mask"},
355 //TODO: {"ungline", emb_ungline, METH_VARARGS, "remove a gline"},
356 //TODO: {"kick", emb_kick, METH_VARARGS, "kick someone from a channel"},
357 //TODO: {"channel_mode", emb_channel_mode, METH_VARARGS, "set modes on a channel"},
358 //TODO: {"user_mode", emb_user_mode, METH_VARARGS, "Have x3 set usermodes on one of its own nicks"},
360 //TODO: {"get_config", emb_get_config, METH_VARARGS, "get x3.conf settings into a nested dict"},
361 //TODO: {"config_set", emb_config_set, METH_VARARGS, "change a config setting 'on-the-fly'."},
363 //TODO: {"timeq_add", emb_timeq_new, METH_VARARGS, "some kind of interface to the timed event system."},
364 //TODO: {"timeq_del", emb_timeq_new, METH_VARARGS, "some kind of interface to the timed event system."},
365 /* Information gathering methods */
366 {"get_user", emb_get_user
, METH_VARARGS
, "Get details about a nickname"},
367 {"get_channel", emb_get_channel
, METH_VARARGS
, "Get details about a channel"},
368 {"get_account", emb_get_account
, METH_VARARGS
, "Get details about an account"},
369 {"get_info", emb_get_info
, METH_VARARGS
, "Get various misc info about x3"},
370 /* null terminator */
371 {NULL
, NULL
, 0, NULL
}
375 /* ------------------------------------------------------------------------------------------------ *
376 Thes functions set up the embedded environment for us to call out to modpython.py class
380 void python_log_module() {
381 /* Attempt to convert python errors to x3 log system */
382 PyObject
*exc
, *tb
, *value
, *tmp
;
383 char *str_exc
= "NONE";
384 char *str_value
= "NONE";
385 char *str_tb
= "NONE";
387 PyErr_Fetch(&exc
, &value
, &tb
);
390 if((tmp
= PyObject_Str(exc
)))
391 str_exc
= PyString_AsString(tmp
);
394 if((tmp
= PyObject_Str(value
)))
395 str_value
= PyString_AsString(tmp
);
398 if((tmp
= PyObject_Str(tb
)))
399 str_tb
= PyString_AsString(tmp
);
402 /* Now restore it so we can print it (just in case)
403 * (should we do this only when running in debug mode?) */
404 PyErr_Restore(exc
, value
, tb
);
405 PyErr_Print(); /* which of course, clears it again.. */
407 log_module(PY_LOG
, LOG_WARNING
, "PYTHON error: %s, value: %s", str_exc
, str_value
);
409 /* TODO: get the traceback using the traceback module via C api so we can add it to the X3 logs. See
410 * http://mail.python.org/pipermail/python-list/2003-March/192226.html */
411 // (this doesnt work, str_tb is just an object hashid) log_module(PY_LOG, LOG_INFO, "PYTHON error, traceback: %s", str_tb);
415 PyObject
*python_build_handler_args(size_t argc
, char *args
[], PyObject
*pIrcObj
) {
416 /* Sets up a python tuple with passed in arguments, prefixed by the Irc instance
417 which handlers use to interact with c.
418 argc = number of args
420 pIrcObj = instance of the irc class
423 PyObject
*pArgs
= NULL
;
425 pArgs
= PyTuple_New(argc
+ 1);
427 PyTuple_SetItem(pArgs
, i
++, pIrcObj
);
431 for(n
= 0; n
< argc
; ++n
) {
432 pValue
= PyString_FromString(args
[n
]);
435 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[n
]);
438 PyTuple_SetItem(pArgs
, n
+i
, pValue
);
444 PyObject
*python_build_args(size_t argc
, char *args
[]) {
445 /* Builds the passed in arguments into a python argument tuple.
446 argc = number of args
450 PyObject
*pArgs
= NULL
;
453 pArgs
= PyTuple_New(argc
);
455 for(i
= 0; i
< argc
; ++i
) {
456 pValue
= PyString_FromString(args
[i
]);
459 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[i
]);
462 PyTuple_SetItem(pArgs
, i
, pValue
);
469 PyObject
*new_irc_object(char *command_service
, char *command_caller
, char *command_target
) {
470 /* Creates a new instance of the irc class (from modpython.py) which is initalized
471 with current environment details like which service were talking to.
472 command_service = which service we are talking to, or empty string if none
473 command_caller = nick of user generating message, or empty string if none
474 command_target = If were reacting to something on a channel, this will
475 be set to the name of the channel. Otherwise empty
477 PyObject
*pIrcArgs
= NULL
;
481 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate irc class; %s %s %s", command_service
, command_caller
, command_target
);
482 pIrcClass
= PyObject_GetAttrString(base_module
, "irc");
483 /* pIrcClass is a new reference */
484 if(pIrcClass
&& PyCallable_Check(pIrcClass
)) {
486 char *ircargs
[] = {command_service
, command_caller
, command_target
};
489 pIrcArgs
= python_build_args(3, ircargs
);
490 pIrcObj
= PyObject_CallObject(pIrcClass
, pIrcArgs
);
492 log_module(PY_LOG
, LOG_ERROR
, "IRC Class failed to load");
496 if(pIrcArgs
!= NULL
) {
499 Py_DECREF(pIrcClass
);
503 /* need to free pIrcClass here if it WAS found but was NOT callable? */
504 log_module(PY_LOG
, LOG_ERROR
, "Unable to find irc class");
509 int python_call_handler(char *handler
, char *args
[], size_t argc
, char *command_service
, char *command_caller
, char *command_target
) {
510 /* This is how we talk to modpython.c. First a new instance of the irc class is created using these
511 arguments to setup the current environment. Then the named method of the handler object is called
512 with the givin arguments.
519 log_module(PY_LOG
, LOG_INFO
, "attempting to call handler %s.", handler
);
520 if(base_module
!= NULL
&& handler_object
!= NULL
) {
521 pIrcObj
= new_irc_object(command_service
, command_caller
, command_target
);
523 log_module(PY_LOG
, LOG_INFO
, "Can't get irc object. Bailing.");
527 pArgs
= python_build_handler_args(argc
, args
, pIrcObj
);
528 pMethod
= PyObject_GetAttrString(handler_object
, handler
);
529 if(pMethod
&& PyCallable_Check(pMethod
)) {
530 /* Call the method, with the arguments */
531 pValue
= PyObject_CallObject(pMethod
, pArgs
);
537 ret
= PyInt_AsLong(pValue
);
538 if(ret
== -1 && PyErr_Occurred()) {
540 log_module(PY_LOG
, LOG_INFO
, "error converting return value of handler %s to type long. ", handler
);
544 log_module(PY_LOG
, LOG_INFO
, "handler %s was run successfully, returned %d.", handler
, ret
);
551 /* TODO: instead of print errors, get them as strings
552 * and deal with them with normal x3 log system. */
553 log_module(PY_LOG
, LOG_WARNING
, "call to handler %s failed", handler
);
561 else { /* couldn't find handler methed */
563 /* Free pMethod if it was found but not callable? */
564 log_module(PY_LOG
, LOG_ERROR
, "Cannot find handler %s.", handler
);
569 else { /* No base module.. no python? */
570 log_module(PY_LOG
, LOG_INFO
, "Cannot handle %s, Python is not initialized.", handler
);
575 PyObject
*python_new_handler_object() {
576 /* Create a new instance of the handler class.
577 This is called during python initilization (or reload)
578 and the result is saved and re-used.
580 PyObject
*pHandlerClass
, *pHandlerObj
;
582 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate python class handler");
583 pHandlerClass
= PyObject_GetAttrString(base_module
, "handler");
584 /* Class is a new reference */
585 if(pHandlerClass
&& PyCallable_Check(pHandlerClass
)) {
586 /*PyObject *pValue; */
588 pHandlerObj
= PyObject_CallObject(pHandlerClass
, NULL
);
589 if(pHandlerObj
!= NULL
) {
590 log_module(PY_LOG
, LOG_INFO
, "Created new python handler object.");
594 log_module(PY_LOG
, LOG_ERROR
, "Unable to instanciate handler object");
601 log_module(PY_LOG
, LOG_ERROR
, "Unable to find handler class");
605 Py_DECREF(pHandlerClass
);
611 /* ------------------------------------------------------------------------------- *
612 Some gateway functions to convert x3 callbacks into modpython.py callbacks.
613 Mostly we just build relevant args and call the proper handler method
615 debate: do we just register these and check them in python
616 for every one (slow?) or actually work out if a plugin needs
617 it first? We will start by doing it every time.
620 python_handle_join(struct modeNode
*mNode
)
622 /* callback for handle_join events.
624 struct userNode
*user
= mNode
->user
;
625 struct chanNode
*channel
= mNode
->channel
;
628 log_module(PY_LOG
, LOG_INFO
, "python module handle_join");
629 if(!channel
||!user
) {
630 log_module(PY_LOG
, LOG_WARNING
, "Python code got join without channel or user!");
634 char *args
[] = {channel
->name
, user
->nick
};
635 return python_call_handler("join", args
, 2, "", "", "");
640 python_handle_server_link(struct server
*server
)
642 log_module(PY_LOG
, LOG_INFO
, "python module handle_server_link");
644 log_module(PY_LOG
, LOG_WARNING
, "Python code got server link without server!");
648 char *args
[] = {server
->name
, server
->description
};
649 return python_call_handler("server_link", args
, 2, "", "", "");
654 python_handle_new_user(struct userNode
*user
)
656 log_module(PY_LOG
, LOG_INFO
, "Python module handle_new_user");
658 log_module(PY_LOG
, LOG_WARNING
, "Python code got new_user without the user");
662 char *args
[] = {user
->nick
, user
->ident
, user
->hostname
, user
->info
};
663 return python_call_handler("new_user", args
, 4, "", "", "");
668 python_handle_nick_change(struct userNode
*user
, const char *old_nick
)
670 log_module(PY_LOG
, LOG_INFO
, "Python module handle_nick_change");
672 log_module(PY_LOG
, LOG_WARNING
, "Python code got nick_change without the user!");
675 char *args
[] = {user
->nick
, (char *)old_nick
};
676 python_call_handler("nick_change", args
, 2, "", "", "");
680 /* ----------------------------------------------------------------------------- */
684 /* Init the python engine and do init work on modpython.py
685 This is called during x3 startup, and on a python reload
689 char* env
= getenv("PYTHONPATH");
695 setenv("PYTHONPATH", modpython_conf
.scripts_dir
, 1);
696 else if (!strstr(env
, modpython_conf
.scripts_dir
)) {
697 buffer
= (char*)malloc(strlen(env
) + strlen(modpython_conf
.scripts_dir
) + 2);
698 sprintf(buffer
, "%s:%s", modpython_conf
.scripts_dir
, env
);
699 setenv("PYTHONPATH", buffer
, 1);
705 Py_InitModule("svc", EmbMethods
);
706 /* TODO: get "modpython" from x3.conf */
707 pName
= PyString_FromString("modpython");
708 base_module
= PyImport_Import(pName
);
710 if(base_module
!= NULL
) {
711 handler_object
= python_new_handler_object();
713 python_call_handler("init", NULL
, 0, "", "", "");
717 /* error handler class not found */
718 log_module(PY_LOG
, LOG_WARNING
, "Failed to create handler object");
725 log_module(PY_LOG
, LOG_WARNING
, "Failed to load modpython.py");
732 python_finalize(void) {
733 /* Called after X3 is fully up and running.
734 Code can be put here that needs to run to init things, but
735 which is sensitive to everything else in x3 being up and ready
739 PyRun_SimpleString("print 'Hello, World of Python!'");
740 log_module(PY_LOG
, LOG_INFO
, "python module finalize");
746 python_cleanup(void) {
747 /* Called on shutdown of the python module (or before reloading)
750 log_module(PY_LOG
, LOG_INFO
, "python module cleanup");
751 if (PyErr_Occurred())
753 Py_Finalize(); /* Shut down python enterpriter */
757 /* ---------------------------------------------------------------------------------- *
758 Python module command handlers.
760 static MODCMD_FUNC(cmd_reload
) {
761 /* reload the python system completely
763 log_module(PY_LOG
, LOG_INFO
, "Shutting python down");
765 log_module(PY_LOG
, LOG_INFO
, "Loading python stuff");
767 reply("PYMSG_RELOAD_SUCCESS");
770 reply("PYMSG_RELOAD_FAILED");
775 static char* format_python_error(int space_nls
) {
776 PyObject
* extype
= NULL
, *exvalue
= NULL
, *extraceback
= NULL
;
777 PyObject
* pextypestr
= NULL
, *pexvaluestr
= NULL
;
778 char* extypestr
= NULL
, *exvaluestr
= NULL
;
779 size_t retvallen
= 0;
780 char* retval
= NULL
, *tmp
;
782 PyErr_Fetch(&extype
, &exvalue
, &extraceback
);
786 pextypestr
= PyObject_Str(extype
);
789 extypestr
= PyString_AsString(pextypestr
);
793 pexvaluestr
= PyObject_Str(exvalue
);
795 exvaluestr
= PyString_AsString(pexvaluestr
);
797 retvallen
= strlen(extypestr
) + (exvaluestr
? strlen(exvaluestr
) + 2 : 0) + 1;
798 retval
= (char*)malloc(retvallen
);
800 snprintf(retval
, retvallen
, "%s: %s", extypestr
, exvaluestr
);
802 strncpy(retval
, extypestr
, retvallen
);
814 if (PyErr_Occurred())
815 PyErr_Clear(); /* ignore errors caused by formatting */
818 Py_XDECREF(extraceback
);
819 Py_XDECREF(pextypestr
);
820 Py_XDECREF(pexvaluestr
);
825 return strdup("unknown exception");
828 static int python_run_statements(char const* msg
, char** err
) {
831 PyObject
* py_main_module
= NULL
;
832 PyObject
* py_globals
;
834 py_main_module
= PyImport_AddModule("__main__");
835 if (!py_main_module
) {
836 exmsg
= format_python_error(1);
840 *err
= strdup("unknown exception");
844 py_globals
= PyModule_GetDict(py_main_module
);
846 o
= PyRun_String(msg
, Py_file_input
, py_globals
, py_globals
);
848 exmsg
= format_python_error(1);
852 *err
= strdup("unknown exception");
862 static MODCMD_FUNC(cmd_run
) {
863 /* this method allows running arbitrary python commands.
869 msg
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
871 if (python_run_statements(msg
, &exmsg
)) {
873 reply("PYMSG_RUN_EXCEPTION", exmsg
);
876 reply("PYMSG_RUN_UNKNOWN_EXCEPTION");
882 #define numstrargs(X) sizeof(X) / sizeof(*X)
883 static MODCMD_FUNC(cmd_command
) {
884 char *plugin
= argv
[1];
885 char *command
= argv
[2];
886 char *msg
; /* args */
888 msg
= unsplit_string(argv
+ 3, argc
- 3, NULL
);
893 char *args
[] = {plugin
, command
, msg
};
894 python_call_handler("cmd_command", args
, numstrargs(args
), cmd
->parent
->bot
->nick
, user
?user
->nick
:"", channel
?channel
->name
:"");
898 static void modpython_conf_read(void) {
902 if (!(conf_node
= conf_get_data(MODPYTHON_CONF_NAME
, RECDB_OBJECT
))) {
903 log_module(PY_LOG
, LOG_ERROR
, "config node '%s' is missing or has wrong type", MODPYTHON_CONF_NAME
);
907 str
= database_get_data(conf_node
, "scripts_dir", RECDB_QSTRING
);
908 modpython_conf
.scripts_dir
= str
? str
: "./";
911 int python_init(void) {
912 /* X3 calls this function on init of the module during startup. We use it to
913 do all our setup tasks and bindings
916 PY_LOG
= log_register_type("Python", "file:python.log");
917 python_module
= module_register("python", PY_LOG
, "mod-python.help", NULL
);
918 conf_register_reload(modpython_conf_read
);
920 log_module(PY_LOG
, LOG_INFO
, "python module init");
921 message_register_table(msgtab
);
924 reg_auth_func(python_check_messages);
925 reg_handle_rename_func(python_rename_account);
926 reg_unreg_func(python_unreg_account);
927 conf_register_reload(python_conf_read);
928 saxdb_register("python", python_saxdb_read, python_saxdb_write);
929 modcmd_register(python_module, "send", cmd_send, 3, MODCMD_REQUIRE_AUTHED, NULL);
931 modcmd_register(python_module
, "reload", cmd_reload
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
932 modcmd_register(python_module
, "run", cmd_run
, 2, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
933 modcmd_register(python_module
, "command", cmd_command
, 3, MODCMD_REQUIRE_STAFF
, NULL
);
935 // Please help us by implimenting any of the callbacks listed as TODO below. They already exist
936 // in x3, they just need handle_ bridges implimented. (see python_handle_join for an example)
937 reg_server_link_func(python_handle_server_link
);
938 reg_new_user_func(python_handle_new_user
);
939 reg_nick_change_func(python_handle_nick_change
);
940 //TODO: reg_del_user_func(python_handle_del_user);
941 //TODO: reg_account_func(python_handle_account); /* stamping of account name to the ircd */
942 //TODO: reg_handle_rename_func(python_handle_handle_rename); /* handle used to ALSO mean account name */
943 //TODO: reg_failpw_func(python_handle_failpw);
944 //TODO: reg_allowauth_func(python_handle_allowauth);
945 //TODO: reg_handle_merge_func(python_handle_merge);
947 //TODO: reg_oper_func(python_handle_oper);
948 //TODO: reg_new_channel_func(python_handle_new_channel);
949 reg_join_func(python_handle_join
);
950 //TODO: reg_del_channel_func(python_handle_del_channel);
951 //TODO: reg_part_func(python_handle_part);
952 //TODO: reg_kick_func(python_handle_kick);
953 //TODO: reg_topic_func(python_handle_topic);
954 //TODO: reg_channel_mode_func(python_handle_channel_mode);
956 //TODO: reg_privmsg_func(python_handle_privmsg);
957 //TODO: reg_notice_func
958 //TODO: reg_svccmd_unbind_func(python_handle_svccmd_unbind);
959 //TODO: reg_chanmsg_func(python_handle_chanmsg);
960 //TODO: reg_allchanmsg_func
961 //TODO: reg_user_mode_func
963 reg_exit_func(python_cleanup
);
969 #endif /* WITH_PYTHON */