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 */
25 #ifndef WITH_PROTOCOL_P10
26 #error mod-python is only supported with p10 protocol enabled
27 #endif /* WITH_PROTOCOL_P10 */
43 * - Implement most of proto-p10 irc_* commands for calling from scripts
44 * - Implement functions to look up whois, channel, account, and reg-channel info for scripts
45 * - Implement x3.conf settings for python variables like include path, etc.
46 * - modpython.py calls for everything you can reg_ a handler for in x3
47 * - Some kind of system for getting needed binds bound automagicaly to make it easier
48 * to run peoples' scripts and mod-python in general.
49 * - Create a (python side) command registry that plugins register into
50 * - In modcmd.c check that list first, before the usual (c based) command search
51 * - If python version returns 0, go on with the built-in search, otherwise just quit (allows plugins to override)
53 * - Mechanism for python plugins to register themselves like x3 plugins? (*module.____) ??
54 * - Then, same problem as other x3 modules, pain to set up commands 1st time etc, maybe solve that for all modules?
55 * - An interface to reading/writing data to x3.db. Maybe generic, or attached to account or channel reg records?
57 * basic startup for now:
58 * configure --enable-modules=python
59 * Make install will copy modpython.py and plugins/ directory to start out with hangman example/test
61 * x3.conf: in the "moduleS" section add:
63 * "scripts_dir" "/home/you/x3rundirectory";
64 * "main_module" "modpython";
67 * /msg o3 bind o3 py\ run *python.run
68 * /msg o3 bind o3 py\ reload *python.reload
69 * /msg o3 bind o3 py\ command *python.command
71 * example script bindings (for now)
72 * /msg o3 bind x3 hangman *modcmd.joiner
73 * /msg o3 bind x3 hangman\ start *python.command hangman start
74 * /msg o3 bind x3 hangman\ end *python.command hangman end
75 * /msg o3 bind x3 hangman\ guess *python.command hangman guess $1
78 static const struct message_entry msgtab
[] = {
79 { "PYMSG_RELOAD_SUCCESS", "Reloaded Python scripts successfully." },
80 { "PYMSG_RELOAD_FAILED", "Error reloading Python scripts." },
81 { "PYMSG_RUN_UNKNOWN_EXCEPTION", "Error running python: unknown exception." },
82 { "PYMSG_RUN_EXCEPTION", "Error running python: %s: %s." },
83 { NULL
, NULL
} /* sentinel */
86 #define MODPYTHON_CONF_NAME "modules/python"
90 char const* scripts_dir
;
91 char const* main_module
;
94 static struct log_type
*PY_LOG
;
95 const char *python_module_deps
[] = { NULL
};
96 static struct module *python_module
;
98 PyObject
*base_module
= NULL
; /* Base python handling library */
99 PyObject
*handler_object
= NULL
; /* instance of handler class */
102 extern struct userNode
*global
, *chanserv
, *opserv
, *nickserv
, *spamserv
;
105 Some hooks you can call from modpython.py to interact with the
106 service. These emb_* functions are available as _svc.* in python. */
108 struct _tuple_dict_extra
{
113 static void pyobj_release_tuple(PyObject
* tuple
, size_t n
) {
119 for (i
= 0; i
< n
; ++i
)
120 Py_XDECREF(PyTuple_GET_ITEM(tuple
, i
));
125 static int _dict_iter_fill_tuple(char const* key
, UNUSED_ARG(void* data
), void* extra
) {
127 struct _tuple_dict_extra
* real_extra
= (struct _tuple_dict_extra
*)extra
;
129 if ((tmp
= PyString_FromString(key
)) == NULL
)
132 if (PyTuple_SetItem(real_extra
->data
, *(int*)real_extra
->extra
, tmp
)) {
137 *real_extra
->extra
= *real_extra
->extra
+ 1;
142 pyobj_from_dict_t(dict_t d
) {
145 struct _tuple_dict_extra extra
;
147 if ((retval
= PyTuple_New(dict_size(d
))) == NULL
)
153 if (dict_foreach(d
, _dict_iter_fill_tuple
, (void*)&extra
) != NULL
) {
154 pyobj_release_tuple(retval
, n
);
161 PyDoc_STRVAR(emb_get_users__doc__
,
162 "get_users() -> tuple with user nicks");
165 emb_get_users(UNUSED_ARG(PyObject
*self
), PyObject
*args
) {
166 if (!PyArg_ParseTuple(args
, ""))
169 return pyobj_from_dict_t(clients
);
172 PyDoc_STRVAR(emb_get_channels__doc__
,
173 "get_channels() -> tuple with channel names");
176 emb_get_channels(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
177 if (!PyArg_ParseTuple(args
, ""))
180 return pyobj_from_dict_t(channels
);
183 PyDoc_STRVAR(emb_get_servers__doc__
,
184 "get_servers() -> tuple with server names");
187 emb_get_servers(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
188 if (!PyArg_ParseTuple(args
, ""))
191 return pyobj_from_dict_t(servers
);
194 PyDoc_STRVAR(emb_get_accounts__doc__
,
195 "get_accounts() -> tuple with all nickserv account names");
198 emb_get_accounts(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
199 if (!PyArg_ParseTuple(args
, ""))
202 return pyobj_from_dict_t(nickserv_handle_dict
);
205 PyDoc_STRVAR(emb_dump__doc__
,
206 "dump(dump) -> an integer detailing success\n\n"
207 "Dumps a string to the server socket for propagation to other servers.\n\n"
208 "Return value is 1 on success and 0 on failure.\n");
211 emb_dump(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
213 /* Dump a raw string into the socket
214 usage: _svc.dump(<P10 string>)
218 char linedup
[MAXLEN
];
221 if(!PyArg_ParseTuple(args
, "s:dump", &buf
))
224 safestrncpy(linedup
, buf
, sizeof(linedup
));
226 if(parse_line(linedup
, 1)) {
230 PyErr_SetString(PyExc_Exception
, "invalid protocol message");
234 return Py_BuildValue("i", ret
);
237 PyDoc_STRVAR(emb_send_target_privmsg__doc__
,
238 "send_target_privmsg(servicenick, target, message) -> amount of message sent");
241 emb_send_target_privmsg(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
244 usage: _svc.send_target_privmsg(<servicenick_from>, <nick_to>, <message>)
251 struct service
*service
;
254 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &channel
, &buf
))
257 if (buf
== NULL
|| strlen(buf
) == 0) {
258 PyErr_SetString(PyExc_Exception
, "invalid empty message");
262 if(!(service
= service_find(servicenick
))) {
263 PyErr_SetString(PyExc_Exception
, "no such service nick");
267 ret
= send_target_message(5, channel
, service
->bot
, "%s", buf
);
268 return Py_BuildValue("i", ret
);
271 PyDoc_STRVAR(emb_send_target_notice__doc__
,
272 "send_target_notice(servicenick, target, message) -> amount of message sent");
275 emb_send_target_notice(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
278 usage: _svc.send_target_notice(<servicenick_from>, <nick_to>, <message>)
285 struct service
*service
;
287 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &target
, &buf
))
290 if (buf
== NULL
|| strlen(buf
) == 0) {
291 PyErr_SetString(PyExc_Exception
, "invalid empty message");
295 if(!(service
= service_find(servicenick
))) {
296 PyErr_SetString(PyExc_Exception
, "no such service nick");
300 ret
= send_target_message(4, target
, service
->bot
, "%s", buf
);
302 return Py_BuildValue("i", ret
);
306 pyobj_from_usernode(struct userNode
* user
) {
309 PyObject
* retval
= NULL
;
310 PyObject
* pChanList
= PyTuple_New(user
->channels
.used
);
312 if (pChanList
== NULL
)
315 for (n
=0; n
< user
->channels
.used
; n
++) {
316 mn
= user
->channels
.list
[n
];
317 if (PyTuple_SetItem(pChanList
, n
, Py_BuildValue("s", mn
->channel
->name
)))
321 retval
= Py_BuildValue("{"
325 "s: s, " /* hostname */
327 "s: s, " /* fakehost */
328 "s: s, " /* sethost */
329 "s: s, " /* crypthost */
330 "s: s, " /* cryptip */
331 "s: s, " /* numeric */
333 "s: i, " /* no_notice */
335 "s: s, " /* version_reply */
336 "s: s, " /* account */
337 "s: O}", /* channels */
339 "ident", user
->ident
,
341 "hostname", user
->hostname
,
342 "ip", irc_ntoa(&user
->ip
),
343 "fakehost", user
->fakehost
,
344 "sethost", user
->sethost
,
345 "crypthost", user
->crypthost
,
346 "cryptip", user
->cryptip
,
347 "numeric", user
->numeric
,
349 "no_notice", user
->no_notice
,
351 "version_reply", user
->version_reply
,
352 "account", user
->handle_info
? user
->handle_info
->handle
: NULL
,
353 "channels", pChanList
);
362 pyobj_release_tuple(pChanList
, n
);
367 PyDoc_STRVAR(emb_get_user__doc__
,
368 "get_user(nick) -> dict with user information\n\n"
369 "Updating the returned dictionary will not be reflected in the user's\n"
373 emb_get_user(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
375 /* Get a python object containing everything x3 knows about a user, by nick.
376 usage: _svc.get_user(<nick>)
379 struct userNode
*user
;
381 if(!PyArg_ParseTuple(args
, "s", &nick
))
384 if(!(user
= GetUserH(nick
))) {
385 PyErr_SetString(PyExc_Exception
, "no such user");
389 return pyobj_from_usernode(user
);
393 pyobj_from_server(struct server
* srv
) {
395 PyObject
* tmp
= NULL
;
396 PyObject
* retval
= NULL
;
397 PyObject
* users
= PyTuple_New(srv
->clients
);
403 for (n
= 0; n
< srv
->num_mask
; ++n
) {
404 if (srv
->users
[n
] == NULL
)
407 tmp
= PyString_FromString(srv
->users
[n
]->nick
);
411 if (PyTuple_SetItem(users
, idx
++, tmp
))
415 retval
= Py_BuildValue("{"
418 "s:l," /* link_time */
419 "s:s," /* description */
421 "s:I," /* num_mask */
424 "s:I," /* max_clients */
426 "s:I," /* self_burst */
433 "link_time", srv
->link_time
,
434 "description", srv
->description
,
435 "numeric", srv
->numeric
,
436 "num_mask", srv
->num_mask
,
438 "clients", srv
->clients
,
439 "max_clients", srv
->max_clients
,
441 "self_burst", srv
->self_burst
,
442 "uplink", srv
->uplink
? srv
->uplink
->name
: NULL
,
453 pyobj_release_tuple(users
, idx
);
458 PyDoc_STRVAR(emb_get_server__doc__
,
459 "get_server(name) -> dict with information\n\n"
460 "Changes made to the returned dictionary will not reflect in the server's\n"
464 emb_get_server(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
468 if (!PyArg_ParseTuple(args
, "s", &name
))
471 if (name
== NULL
|| strlen(name
) == 0) {
472 PyErr_SetString(PyExc_Exception
, "invalid server name");
476 if ((srv
= GetServerH(name
)) == NULL
) {
477 PyErr_SetString(PyExc_Exception
, "unknown server");
481 return pyobj_from_server(srv
);
485 pyobj_from_modelist(struct modeList
* mode
) {
488 PyObject
* retval
= PyTuple_New(mode
->used
);
493 for (n
= 0; n
< mode
->used
; ++n
) {
494 struct modeNode
* mn
= mode
->list
[n
];
495 tmp
= PyString_FromString(mn
->user
->nick
);
497 pyobj_release_tuple(retval
, n
);
501 if (PyTuple_SetItem(retval
, n
, tmp
)) {
502 pyobj_release_tuple(retval
, n
);
511 pyobj_from_banlist(struct banList
* bans
) {
515 PyObject
* retval
= PyTuple_New(bans
->used
);
520 for (n
= 0; n
< bans
->used
; ++n
) {
523 tmp
= Py_BuildValue("{s:s,s:s,s:l}",
524 "ban", bn
->ban
, "who", bn
->who
, "set", bn
->set
);
526 if (tmp
== NULL
|| PyTuple_SetItem(retval
, n
, tmp
)) {
527 pyobj_release_tuple(retval
, n
);
536 pyobj_from_exemptlist(struct exemptList
* exmp
) {
538 struct exemptNode
* en
;
540 PyObject
* retval
= PyTuple_New(exmp
->used
);
545 for (n
= 0; n
< exmp
->used
; ++n
) {
548 tmp
= Py_BuildValue("{s:s,s:s,s:l}",
549 "ban", en
->exempt
, "who", en
->who
, "set", en
->set
);
551 if (tmp
== NULL
|| PyTuple_SetItem(retval
, n
, tmp
)) {
552 pyobj_release_tuple(retval
, n
);
561 pyobj_from_channode(struct chanNode
* channel
) {
562 PyObject
*pChannelMembers
= NULL
;
563 PyObject
*pChannelBans
= NULL
;
564 PyObject
*pChannelExempts
= NULL
;
565 PyObject
*retval
= NULL
;
567 /* build tuple of nicks in channel */
568 pChannelMembers
= pyobj_from_modelist(&channel
->members
);
569 if (pChannelMembers
== NULL
)
572 /* build tuple of bans */
573 pChannelBans
= pyobj_from_banlist(&channel
->banlist
);
574 if (pChannelBans
== NULL
)
577 /* build tuple of exempts */
578 pChannelExempts
= pyobj_from_exemptlist(&channel
->exemptlist
);
579 if (pChannelExempts
== NULL
)
582 retval
= Py_BuildValue("{s:s,s:s,s:s,s:i"
583 ",s:i,s:i,s:O,s:O,s:O}",
585 "name", channel
->name
,
586 "topic", channel
->topic
,
587 "topic_nick", channel
->topic_nick
,
588 "topic_time", channel
->topic_time
,
590 "timestamp", channel
->timestamp
,
591 "modes", channel
->modes
,
592 "members", pChannelMembers
,
593 "bans", pChannelBans
,
594 "exempts", pChannelExempts
603 pyobj_release_tuple(pChannelExempts
, channel
->exemptlist
.used
);
604 pyobj_release_tuple(pChannelBans
, channel
->banlist
.used
);
605 pyobj_release_tuple(pChannelMembers
, channel
->members
.used
);
610 PyDoc_STRVAR(emb_get_channel__doc__
,
611 "get_channel(channel) -> dict with channel information\n\n"
612 "Updates made to the returned dictionary does not reflect in the channel\n"
616 emb_get_channel(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
618 /* Returns a python dict object with all sorts of info about a channel.
619 usage: _svc.get_channel(<name>)
622 struct chanNode
*channel
;
624 if(!PyArg_ParseTuple(args
, "s", &name
))
627 if(!(channel
= GetChannel(name
))) {
628 PyErr_SetString(PyExc_Exception
, "unknown channel");
632 return pyobj_from_channode(channel
);
635 PyDoc_STRVAR(emb_get_account__doc__
,
636 "get_account(account) -> dict with account information\n\n"
637 "Changes made to the returned dictionary will not be reflected in the\n"
638 "account's information.");
641 emb_get_account(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
643 /* Returns a python dict object with all sorts of info about an account.
644 usage: _svc.get_account(<account name>)
647 struct handle_info
*hi
;
650 if(!PyArg_ParseTuple(args
, "s", &name
))
653 hi
= get_handle_info(name
);
656 PyErr_SetString(PyExc_Exception
, "unknown account name");
660 return Py_BuildValue("{s:s,s:i,s:s,s:s,s:s"
663 "account", hi
->handle
,
664 "registered", hi
->registered
,
665 "last_seen", hi
->lastseen
,
666 "infoline", hi
->infoline
? hi
->infoline
: "",
667 "email", hi
->email_addr
? hi
->email_addr
: "",
669 "fakehost", hi
->fakehost
? hi
->fakehost
: "",
670 "last_quit_host", hi
->last_quit_host
673 /* users online authed to this account */
675 /* nicks (nickserv nets only?) */
682 PyDoc_STRVAR(emb_get_info__doc__
,
683 "get_info() -> dict with general service setup information\n\n"
684 "The dictionary contains the nicks of the different services.");
687 emb_get_info(UNUSED_ARG(PyObject
*self
), UNUSED_ARG(PyObject
*args
))
689 /* return some info about the general setup
690 * of X3, such as what the chanserv's nickname
695 return Py_BuildValue("{s:s,s:s,s:s,s:s,s:s}",
696 "chanserv", chanserv
? chanserv
->nick
: "ChanServ",
697 "nickserv", nickserv
?nickserv
->nick
: "NickServ",
698 "opserv", opserv
?opserv
->nick
: "OpServ",
699 "global", global
?global
->nick
: "Global",
700 "spamserv", spamserv
?spamserv
->nick
: "SpamServ");
703 PyDoc_STRVAR(emb_log_module__doc__
,
704 "log_module(level, message)\n\n"
705 "Logs a message in the PY_LOG subsystem given a severity level and a message.");
708 emb_log_module(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
710 /* a gateway to standard X3 logging subsystem.
711 * level is a value 0 to 9 as defined by the log_severity enum in log.h.
713 * for now, all logs go to the PY_LOG log. In the future this will change.
718 if(!PyArg_ParseTuple(args
, "is", &level
, &message
))
721 log_module(PY_LOG
, level
, "%s", message
);
727 PyDoc_STRVAR(emb_kill__doc__
,
728 "kill(servicenick, target, message)\n\n"
729 "Kills a given user.");
732 emb_kill(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
733 char const* from_nick
, *target_nick
, *message
;
734 struct userNode
*target
;
735 struct service
*service
;
737 if (!PyArg_ParseTuple(args
, "sss", &from_nick
, &target_nick
, &message
))
740 if(!(service
= service_find(from_nick
))) {
741 PyErr_SetString(PyExc_Exception
, "unknown service user specified as from user");
745 if ((target
= GetUserH(target_nick
)) == NULL
) {
746 PyErr_SetString(PyExc_Exception
, "unknown target user");
750 irc_kill(service
->bot
, target
, message
);
756 struct py_timeq_extra
{
762 void py_timeq_callback(void* data
) {
763 struct py_timeq_extra
* extra
= (struct py_timeq_extra
*)data
;
765 PyObject
* retval
= PyObject_Call(extra
->func
, extra
->arg
, NULL
);
768 Py_DECREF(extra
->func
);
769 Py_DECREF(extra
->arg
);
772 PyDoc_STRVAR(emb_timeq_add__doc__
,
773 "timeq_add(when, function, args)\n\n"
774 "Adds a callback to the service timer system.\n\n"
775 "The specific function must be callable, and the specified arguments must be\n"
776 "a tuple with the arguments that the function expects.");
779 emb_timeq_add(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
781 PyObject
* func
, *arg
;
782 struct py_timeq_extra
* extra
;
784 if (!PyArg_ParseTuple(args
, "lOO", &when
, &func
, &arg
))
787 if (!PyFunction_Check(func
)) {
788 PyErr_SetString(PyExc_Exception
, "first argument must be a function");
792 if (!PyTuple_Check(arg
)) {
793 PyErr_SetString(PyExc_Exception
, "second argument must be a tuple");
797 extra
= malloc(sizeof(struct py_timeq_extra
));
799 PyErr_SetString(PyExc_Exception
, "out of memory");
809 timeq_add(when
, py_timeq_callback
, (void*)extra
);
815 PyDoc_STRVAR(emb_timeq_del__doc__
,
816 "timeq_del(when)\n\n"
817 "This function deletes all python-added callbacks registered to run at the\n"
818 "given time, regardless of their data. This is due to the unnecessary extra\n"
819 "burden it would require to get the same data for multiple runs.");
822 emb_timeq_del(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
825 if (!PyArg_ParseTuple(args
, "l", &when
))
828 timeq_del(when
, py_timeq_callback
, NULL
, TIMEQ_IGNORE_DATA
);
834 static int pyobj_config_make_dict(char const* key
, void* data_
, void* extra
) {
835 struct record_data
* data
= (struct record_data
*)data_
;
836 PyObject
* dict
= (PyObject
*)extra
;
837 PyObject
* value
= NULL
, *tmp
;
841 switch (data
->type
) {
843 value
= PyString_FromString(data
->d
.qstring
);
846 case RECDB_STRING_LIST
:
847 value
= PyList_New(data
->d
.slist
->used
);
852 for (n
= 0; n
< data
->d
.slist
->used
; ++n
) {
853 tmp
= PyString_FromString(data
->d
.slist
->list
[n
]);
859 if (PyList_SetItem(value
, n
, tmp
)) {
866 for (idx
= 0; idx
< n
; ++idx
) {
867 tmp
= PyList_GET_ITEM(value
, idx
);
869 PyList_SET_ITEM(value
, idx
, NULL
);
877 value
= PyDict_New();
881 if (dict_foreach(data
->d
.object
, pyobj_config_make_dict
, (void*)value
) != NULL
) {
897 if (PyDict_SetItemString(dict
, key
, value
))
903 PyDoc_STRVAR(emb_get_config__doc__
,
904 "get_config() -> dict with config elements and values\n\n"
905 "Updates to the returned dictionary will not reflect in the service's\n"
909 emb_get_config(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
912 if (!PyArg_ParseTuple(args
, ""))
919 if (conf_enum_root(pyobj_config_make_dict
, (void*)dict
) != NULL
) {
921 PyErr_SetString(PyExc_Exception
, "unable to iterate config");
928 PyDoc_STRVAR(emb_kick__doc__
,
929 "kick(who, target, message)\n\n"
930 "Kicks a given target as if the who user kicked them using the given message.");
932 static PyObject
* emb_kick(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
933 struct userNode
* who
, *target
;
934 struct chanNode
* channel
;
937 char const* who_s
, *target_s
, *channel_s
;
939 if (!PyArg_ParseTuple(args
, "ssss", &who_s
, &target_s
, &channel_s
, &msg
))
942 if ((who
= GetUserH(who_s
)) == NULL
) {
943 PyErr_SetString(PyExc_Exception
, "no such user");
947 if ((target
= GetUserH(target_s
)) == NULL
) {
948 PyErr_SetString(PyExc_Exception
, "no such target");
952 if ((channel
= GetChannel(channel_s
)) == NULL
) {
953 PyErr_SetString(PyExc_Exception
, "no such channel");
957 irc_kick(who
, target
, channel
, msg
);
963 PyDoc_STRVAR(emb_channel_mode__doc__
,
964 "channel_mode(who, channel, modes)\n\n"
965 "Lets a current server's user set a specified channel's modes as specified.");
967 static PyObject
* emb_channel_mode(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
968 struct userNode
* who
;
969 struct chanNode
* channel
;
972 char const* who_s
, *channel_s
;
974 if (!PyArg_ParseTuple(args
, "sss", &who_s
, &channel_s
, &modes
))
977 if ((who
= GetUserH(who_s
)) == NULL
) {
978 PyErr_SetString(PyExc_Exception
, "unknown user");
982 if (who
->uplink
!= self
) {
983 PyErr_SetString(PyExc_Exception
, "user not on current server");
987 if ((channel
= GetChannel(channel_s
)) == NULL
) {
988 PyErr_SetString(PyExc_Exception
, "unknown channel");
992 irc_mode(who
, channel
, modes
);
998 PyDoc_STRVAR(emb_user_mode__doc__
,
999 "user_mode(target, modes)\n\n"
1000 "Sets target's modes as specified. The modes are in normal +f-n syntax.");
1002 static PyObject
* emb_user_mode(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
1003 struct userNode
* target
;
1006 char const* target_s
;
1008 if (!PyArg_ParseTuple(args
, "ss", &target_s
, &modes
))
1011 if ((target
= GetUserH(target_s
)) == NULL
) {
1012 PyErr_SetString(PyExc_Exception
, "unknown user");
1016 irc_umode(target
, modes
);
1022 PyDoc_STRVAR(emb_fakehost__doc__
,
1023 "fakehost(target, host)\n\n"
1024 "Sets the fakehost of a given user to the specified host.");
1026 static PyObject
* emb_fakehost(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
1027 struct userNode
* target
;
1030 char const* target_s
;
1032 if (!PyArg_ParseTuple(args
, "ss", &target_s
, &host
))
1035 if ((target
= GetUserH(target_s
)) == NULL
) {
1036 PyErr_SetString(PyExc_Exception
, "unknown user");
1040 irc_fakehost(target
, host
);
1046 PyDoc_STRVAR(emb_svsnick__doc__
,
1047 "svsnick(from, target, newnick)\n\n"
1048 "The from nick must be on the service server.");
1051 emb_svsnick(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1052 struct userNode
* from
, *target
;
1053 const char* newnick
;
1055 const char* from_s
, *target_s
;
1057 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &newnick
))
1060 if ((from
= GetUserH(from_s
)) == NULL
) {
1061 PyErr_SetString(PyExc_Exception
, "unknown from user");
1065 if ((target
= GetUserH(target_s
)) == NULL
) {
1066 PyErr_SetString(PyExc_Exception
, "unknown target user");
1070 if (from
->uplink
!= self
) {
1071 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1075 irc_svsnick(from
, target
, newnick
);
1081 PyDoc_STRVAR(emb_svsquit__doc__
,
1082 "svsquit(from, target, reason)\n\n"
1083 "The from user must be on the service server.");
1086 emb_svsquit(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1087 struct userNode
* from
, *target
;
1090 char const* from_s
, *target_s
;
1092 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &reason
))
1095 if ((from
= GetUserH(from_s
)) == NULL
) {
1096 PyErr_SetString(PyExc_Exception
, "unknown from user");
1100 if (from
->uplink
!= self
) {
1101 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1105 if ((target
= GetUserH(target_s
)) == NULL
) {
1106 PyErr_SetString(PyExc_Exception
, "unknown target user");
1110 irc_svsquit(from
, target
, reason
);
1116 PyDoc_STRVAR(emb_svsjoin__doc__
,
1117 "svsjoin(from, target, to)\n\n"
1118 "From user from must a user on the service server.\n"
1119 "To must be an existing channel name.");
1122 emb_svsjoin(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1123 struct userNode
* from
, *target
;
1124 struct chanNode
* to
;
1126 const char* from_s
, *target_s
, *to_s
;
1128 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &to_s
))
1131 if ((from
= GetUserH(from_s
)) == NULL
) {
1132 PyErr_SetString(PyExc_Exception
, "unknown from user");
1136 if (from
->uplink
!= self
) {
1137 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1141 if ((target
= GetUserH(target_s
)) == NULL
) {
1142 PyErr_SetString(PyExc_Exception
, "unknown target user");
1146 if ((to
= GetChannel(to_s
)) == NULL
)
1147 to
= AddChannel(to_s
, now
, NULL
, NULL
, NULL
);
1149 irc_svsjoin(from
, target
, to
);
1155 PyDoc_STRVAR(emb_adduser__doc__
,
1156 "adduser(nick, ident, hostname, description, modes) -> dict with user information\n\n"
1157 "Adds a new local user with the given information.");
1160 emb_adduser(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1161 char const* nick
, *ident
, *hostname
, *desc
, *modes
;
1162 struct userNode
* user
;
1165 if (!PyArg_ParseTuple(args
, "sssss", &nick
, &ident
, &hostname
, &desc
, &modes
))
1168 user
= AddLocalUser(nick
, ident
, hostname
, desc
, modes
);
1170 retval
= pyobj_from_usernode(user
);
1175 /* TODO: Add the rest of the service members to the dict */
1177 pyobj_from_service(struct service
* serv
) {
1178 PyObject
* bot
, *retval
;
1180 bot
= pyobj_from_usernode(serv
->bot
);
1184 retval
= Py_BuildValue("{s:O,s:c,s:I}",
1186 "trigger", serv
->trigger
,
1187 "privileged", serv
->privileged
);
1198 PyDoc_STRVAR(emb_service_register__doc__
,
1199 "service_register(nick)\n\n"
1200 "Registers nick as a service. The specified nick must be on the local server.");
1203 emb_service_register(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1204 struct userNode
* user
;
1207 if (!PyArg_ParseTuple(args
, "s", &user_s
))
1210 if ((user
= GetUserH(user_s
)) == NULL
) {
1211 PyErr_SetString(PyExc_Exception
, "unknown user");
1215 if (user
->uplink
!= self
) {
1216 PyErr_SetString(PyExc_Exception
, "user is not on service server");
1220 return pyobj_from_service(service_register(user
));
1223 size_t logs_size
= 0;
1224 static struct log_type
**logs_list
= NULL
;
1226 PyDoc_STRVAR(emb_log_register_type__doc__
,
1227 "registers a log source to write event data to.");
1228 static PyObject
* emb_log_register_type(UNUSED_ARG(PyObject
*self
), PyObject
* args
) {
1229 const char* logName
;
1230 const char* defaultLog
;
1231 struct log_type
* log
;
1232 struct log_type
** newlogs
;
1234 if (!PyArg_ParseTuple(args
, "ss", &logName
, &defaultLog
))
1237 newlogs
= realloc(logs_list
, (logs_size
+1)*sizeof(struct log_type
*));
1238 if (newlogs
== NULL
) {
1239 PyErr_SetString(PyExc_Exception
, "unable to allocate memory for log structures. aborting.");
1242 logs_list
= newlogs
;
1244 log
= log_register_type(logName
, defaultLog
);
1246 PyErr_SetString(PyExc_Exception
, "unable to register log");
1250 logs_list
[logs_size
++] = log
;
1252 return Py_BuildValue("O", PyCObject_FromVoidPtr(log
, NULL
));
1255 PyDoc_STRVAR(emb_module_register__doc__
, "registers a module");
1256 PyObject
* emb_module_register(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
1258 char const *name
, *helpfile
;
1259 struct log_type
* log
;
1262 if (!PyArg_ParseTuple(args
, "sOs", &name
, &pylog
, &helpfile
))
1265 log
= PyCObject_AsVoidPtr(pylog
);
1267 mod
= module_register(name
, log
, helpfile
, NULL
);
1270 PyErr_SetString(PyExc_Exception
, "unable to register module");
1274 return Py_BuildValue("O", PyCObject_FromVoidPtr(mod
, NULL
));
1277 static PyMethodDef EmbMethods
[] = {
1278 /* Communication methods */
1279 {"dump", emb_dump
, METH_VARARGS
, emb_dump__doc__
},
1280 {"send_target_privmsg", emb_send_target_privmsg
, METH_VARARGS
, emb_send_target_privmsg__doc__
},
1281 {"send_target_notice", emb_send_target_notice
, METH_VARARGS
, emb_send_target_notice__doc__
},
1282 {"log_module", emb_log_module
, METH_VARARGS
, emb_log_module__doc__
},
1283 //TODO: {"exec_cmd", emb_exec_cmd, METH_VARARGS, "execute x3 command provided"},
1284 // This should use environment from "python command" call to pass in, if available
1285 {"kill", emb_kill
, METH_VARARGS
, emb_kill__doc__
},
1286 {"fakehost", emb_fakehost
, METH_VARARGS
, emb_fakehost__doc__
},
1287 {"svsnick", emb_svsnick
, METH_VARARGS
, emb_svsnick__doc__
},
1288 {"svsquit", emb_svsquit
, METH_VARARGS
, emb_svsquit__doc__
},
1289 {"svsjoin", emb_svsjoin
, METH_VARARGS
, emb_svsjoin__doc__
},
1290 {"adduser", emb_adduser
, METH_VARARGS
, emb_adduser__doc__
},
1291 {"service_register", emb_service_register
, METH_VARARGS
, emb_service_register__doc__
},
1292 //TODO: svsmode, svsident, nick, quit, join, part, ident, vhost
1295 //TODO: {"gline", emb_gline, METH_VARARGS, "gline a mask"},
1296 //TODO: {"ungline", emb_ungline, METH_VARARGS, "remove a gline"},
1297 {"kick", emb_kick
, METH_VARARGS
, emb_kick__doc__
},
1298 {"channel_mode", emb_channel_mode
, METH_VARARGS
, emb_channel_mode__doc__
},
1299 {"user_mode", emb_user_mode
, METH_VARARGS
, emb_user_mode__doc__
},
1301 {"get_config", emb_get_config
, METH_VARARGS
, emb_get_config__doc__
},
1302 //TODO: {"config_set", emb_config_set, METH_VARARGS, "change a config setting 'on-the-fly'."},
1304 {"timeq_add", emb_timeq_add
, METH_VARARGS
, emb_timeq_add__doc__
},
1305 {"timeq_del", emb_timeq_del
, METH_VARARGS
, emb_timeq_del__doc__
},
1307 /* module registration methods */
1308 {"log_register_type", emb_log_register_type
, METH_VARARGS
,
1309 emb_log_register_type__doc__
},
1310 {"module_register", emb_module_register
, METH_VARARGS
,
1311 emb_module_register__doc__
},
1313 /* Information gathering methods */
1314 {"get_user", emb_get_user
, METH_VARARGS
, emb_get_user__doc__
},
1315 {"get_users", emb_get_users
, METH_VARARGS
, emb_get_users__doc__
},
1316 {"get_channel", emb_get_channel
, METH_VARARGS
, emb_get_channel__doc__
},
1317 {"get_channels", emb_get_channels
, METH_VARARGS
, emb_get_channels__doc__
},
1318 {"get_server", emb_get_server
, METH_VARARGS
, emb_get_server__doc__
},
1319 {"get_servers", emb_get_servers
, METH_VARARGS
, emb_get_servers__doc__
},
1320 {"get_account", emb_get_account
, METH_VARARGS
, emb_get_account__doc__
},
1321 {"get_accounts", emb_get_accounts
, METH_VARARGS
, emb_get_accounts__doc__
},
1322 {"get_info", emb_get_info
, METH_VARARGS
, emb_get_info__doc__
},
1323 /* null terminator */
1324 {NULL
, NULL
, 0, NULL
}
1329 These functions set up the embedded environment for us to call out to
1330 modpython.py class methods.
1333 void python_log_module() {
1334 /* Attempt to convert python errors to x3 log system */
1335 PyObject
*exc
, *tb
, *value
, *tmp
;
1336 char *str_exc
= "NONE";
1337 char *str_value
= "NONE";
1338 char *str_tb
= "NONE";
1340 PyErr_Fetch(&exc
, &value
, &tb
);
1343 if((tmp
= PyObject_Str(exc
)))
1344 str_exc
= PyString_AsString(tmp
);
1347 if((tmp
= PyObject_Str(value
)))
1348 str_value
= PyString_AsString(tmp
);
1351 if((tmp
= PyObject_Str(tb
)))
1352 str_tb
= PyString_AsString(tmp
);
1355 /* Now restore it so we can print it (just in case)
1356 * (should we do this only when running in debug mode?) */
1357 PyErr_Restore(exc
, value
, tb
);
1358 PyErr_Print(); /* which of course, clears it again.. */
1360 log_module(PY_LOG
, LOG_WARNING
, "PYTHON error: %s, value: %s", str_exc
, str_value
);
1362 /* TODO: get the traceback using the traceback module via C api so we can add it to the X3 logs. See
1363 * http://mail.python.org/pipermail/python-list/2003-March/192226.html */
1364 // (this doesnt work, str_tb is just an object hashid) log_module(PY_LOG, LOG_INFO, "PYTHON error, traceback: %s", str_tb);
1368 PyObject
*python_build_handler_args(size_t argc
, char *args
[], PyObject
*pIrcObj
) {
1369 /* Sets up a python tuple with passed in arguments, prefixed by the Irc instance
1370 which handlers use to interact with C.
1371 argc = number of args
1372 args = array of args
1373 pIrcObj = instance of the irc class
1376 PyObject
*pArgs
= NULL
;
1378 pArgs
= PyTuple_New(argc
+ 1);
1380 PyTuple_SetItem(pArgs
, i
++, pIrcObj
);
1384 for(n
= 0; n
< argc
; ++n
) {
1385 pValue
= PyString_FromString(args
[n
]);
1388 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[n
]);
1391 PyTuple_SetItem(pArgs
, n
+i
, pValue
);
1397 PyObject
*python_build_args(size_t argc
, char *args
[]) {
1398 /* Builds the passed in arguments into a python argument tuple.
1399 argc = number of args
1400 args = array of args
1403 PyObject
*pArgs
= NULL
;
1406 pArgs
= PyTuple_New(argc
);
1408 for(i
= 0; i
< argc
; ++i
) {
1409 pValue
= PyString_FromString(args
[i
]);
1412 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[i
]);
1415 PyTuple_SetItem(pArgs
, i
, pValue
);
1422 PyObject
*new_irc_object(char *command_service
, char *command_caller
, char *command_target
) {
1423 /* Creates a new instance of the irc class (from modpython.py) which is initalized
1424 with current environment details like which service were talking to.
1425 command_service = which service we are talking to, or empty string if none
1426 command_caller = nick of user generating message, or empty string if none
1427 command_target = If were reacting to something on a channel, this will
1428 be set to the name of the channel. Otherwise empty
1430 PyObject
*pIrcArgs
= NULL
;
1431 PyObject
*pIrcClass
;
1434 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate irc class; %s %s %s", command_service
, command_caller
, command_target
);
1435 pIrcClass
= PyObject_GetAttrString(base_module
, "irc");
1436 /* pIrcClass is a new reference */
1437 if(pIrcClass
&& PyCallable_Check(pIrcClass
)) {
1439 char *ircargs
[] = {command_service
, command_caller
, command_target
};
1442 pIrcArgs
= python_build_args(3, ircargs
);
1443 pIrcObj
= PyObject_CallObject(pIrcClass
, pIrcArgs
);
1445 log_module(PY_LOG
, LOG_ERROR
, "IRC Class failed to load");
1446 python_log_module();
1449 if(pIrcArgs
!= NULL
) {
1450 Py_DECREF(pIrcArgs
);
1452 Py_DECREF(pIrcClass
);
1456 /* need to free pIrcClass here if it WAS found but was NOT callable? */
1457 log_module(PY_LOG
, LOG_ERROR
, "Unable to find irc class");
1462 int python_call_handler(char *handler
, char *args
[], size_t argc
, char *command_service
, char *command_caller
, char *command_target
) {
1463 /* This is how we talk to modpython.c. First a new instance of the irc class is created using these
1464 arguments to setup the current environment. Then the named method of the handler object is called
1465 with the givin arguments.
1472 log_module(PY_LOG
, LOG_INFO
, "attempting to call handler %s.", handler
);
1473 if(base_module
!= NULL
&& handler_object
!= NULL
) {
1474 pIrcObj
= new_irc_object(command_service
, command_caller
, command_target
);
1476 log_module(PY_LOG
, LOG_INFO
, "Can't get irc object. Bailing.");
1480 pArgs
= python_build_handler_args(argc
, args
, pIrcObj
);
1481 pMethod
= PyObject_GetAttrString(handler_object
, handler
);
1482 if(pMethod
&& PyCallable_Check(pMethod
)) {
1483 /* Call the method, with the arguments */
1484 pValue
= PyObject_CallObject(pMethod
, pArgs
);
1488 if(pValue
!= NULL
) {
1490 ret
= PyInt_AsLong(pValue
);
1491 if(ret
== -1 && PyErr_Occurred()) {
1493 log_module(PY_LOG
, LOG_INFO
, "error converting return value of handler %s to type long. ", handler
);
1494 python_log_module();
1497 log_module(PY_LOG
, LOG_INFO
, "handler %s was run successfully, returned %d.", handler
, ret
);
1504 /* TODO: instead of print errors, get them as strings
1505 * and deal with them with normal x3 log system. */
1506 log_module(PY_LOG
, LOG_WARNING
, "call to handler %s failed", handler
);
1508 python_log_module();
1514 else { /* couldn't find handler methed */
1516 /* Free pMethod if it was found but not callable? */
1517 log_module(PY_LOG
, LOG_ERROR
, "Cannot find handler %s.", handler
);
1522 else { /* No base module.. no python? */
1523 log_module(PY_LOG
, LOG_INFO
, "Cannot handle %s, Python is not initialized.", handler
);
1528 PyObject
*python_new_handler_object() {
1529 /* Create a new instance of the handler class.
1530 This is called during python initilization (or reload)
1531 and the result is saved and re-used.
1533 PyObject
*pHandlerClass
, *pHandlerObj
;
1535 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate python class handler");
1536 pHandlerClass
= PyObject_GetAttrString(base_module
, "handler");
1537 /* Class is a new reference */
1538 if(pHandlerClass
&& PyCallable_Check(pHandlerClass
)) {
1539 /*PyObject *pValue; */
1541 pHandlerObj
= PyObject_CallObject(pHandlerClass
, NULL
);
1542 if(pHandlerObj
!= NULL
) {
1543 log_module(PY_LOG
, LOG_INFO
, "Created new python handler object.");
1547 log_module(PY_LOG
, LOG_ERROR
, "Unable to instanciate handler object");
1549 python_log_module();
1554 log_module(PY_LOG
, LOG_ERROR
, "Unable to find handler class");
1556 python_log_module();
1558 Py_DECREF(pHandlerClass
);
1564 /* ------------------------------------------------------------------------------- *
1565 Some gateway functions to convert x3 callbacks into modpython.py callbacks.
1566 Mostly we just build relevant args and call the proper handler method
1568 debate: do we just register these and check them in python
1569 for every one (slow?) or actually work out if a plugin needs
1570 it first? We will start by doing it every time.
1573 python_handle_join(struct modeNode
*mNode
, UNUSED_ARG(void *extra
))
1575 /* callback for handle_join events.
1577 struct userNode
*user
= mNode
->user
;
1578 struct chanNode
*channel
= mNode
->channel
;
1581 log_module(PY_LOG
, LOG_INFO
, "python module handle_join");
1582 if(!channel
||!user
) {
1583 log_module(PY_LOG
, LOG_WARNING
, "Python code got join without channel or user!");
1587 char *args
[] = {channel
->name
, user
->nick
};
1588 return python_call_handler("join", args
, 2, "", "", "");
1593 python_handle_server_link(struct server
*server
, UNUSED_ARG(void *extra
))
1595 PyObject
* srv
= NULL
;
1596 PyObject
* funcname
= NULL
;
1597 PyObject
* retval
= NULL
;
1598 char const* err
= NULL
;
1601 if (handler_object
== NULL
) {
1602 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1606 if (server
== NULL
) {
1607 err
= "Python code got server link without server!";
1611 if ((srv
= pyobj_from_server(server
)) == NULL
) {
1612 err
= "Python code unable to get PyObject with server!";
1616 funcname
= PyString_FromString("server_link");
1617 if (funcname
== NULL
) {
1618 err
= "Unable to allocate memory";
1622 retval
= PyObject_CallMethodObjArgs(handler_object
, funcname
, srv
, NULL
);
1623 if (retval
== NULL
) {
1624 err
= "Error calling server_link handler";
1630 Py_XDECREF(funcname
);
1632 if (retval
!= NULL
&& PyInt_Check(retval
))
1633 i
= (int)PyInt_AsLong(retval
);
1638 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1644 python_handle_new_user(struct userNode
*user
, UNUSED_ARG(void *extra
))
1646 PyObject
* name
= NULL
;
1647 PyObject
* usr
= NULL
;
1648 PyObject
* retval
= NULL
;
1650 const char* err
= NULL
;
1652 if (handler_object
== NULL
) {
1653 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1658 log_module(PY_LOG
, LOG_WARNING
, "Python code got new_user without the user");
1662 if ((usr
= pyobj_from_usernode(user
)) == NULL
) {
1663 err
= "unable to allocate python user information";
1667 name
= PyString_FromString("new_user");
1669 err
= "unable to allocate memory for handler function name";
1673 if ((retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, NULL
)) == NULL
) {
1674 err
= "error calling new_user handler";
1682 if (retval
!= NULL
&& PyInt_Check(retval
))
1683 i
= (int)PyInt_AsLong(retval
);
1688 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1694 python_handle_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
))
1696 PyObject
* usr
= NULL
;
1697 PyObject
* name
= NULL
;
1698 PyObject
* oldnick
= NULL
;
1699 PyObject
* retval
= NULL
;
1700 char const* err
= NULL
;
1702 if (handler_object
== NULL
) {
1703 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1708 err
= "Python code got nick_change without the user!";
1712 if ((usr
= pyobj_from_usernode(user
)) == NULL
) {
1713 err
= "unable to allocate Python usernode";
1717 name
= PyString_FromString("nick_change");
1719 err
= "unable to allocate memory for handler function name";
1723 oldnick
= PyString_FromString(old_nick
);
1725 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, oldnick
, NULL
);
1726 if (retval
== NULL
) {
1727 err
= "error calling nick_change handler";
1734 Py_XDECREF(oldnick
);
1738 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1741 void python_handle_del_user(struct userNode
*user
, struct userNode
*killer
, const char *why
, UNUSED_ARG(void *extra
)) {
1742 PyObject
*usr
= NULL
, *killr
= NULL
, *name
= NULL
;
1743 PyObject
*reason
= NULL
, *retval
= NULL
;
1744 char const* err
= NULL
;
1746 if (handler_object
== NULL
) {
1747 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1755 usr
= pyobj_from_usernode(user
);
1757 err
= "unable to allocate usernode for user";
1762 if (killer
== NULL
) {
1766 killr
= pyobj_from_usernode(killer
);
1767 if (killr
== NULL
) {
1768 err
= "unable to allocate usernode for killer";
1777 reason
= PyString_FromString(why
);
1778 if (reason
== NULL
) {
1779 err
= "unable to allocate memory for reason";
1784 name
= PyString_FromString("del_user");
1786 err
= "unable to allocate memory for handler function name";
1790 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, killr
, reason
, NULL
);
1791 if (retval
== NULL
) {
1792 err
= "error calling del_user handler";
1804 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1807 int python_handle_topic(struct userNode
*who
, struct chanNode
*chan
, const char *old_topic
, UNUSED_ARG(void *extra
)) {
1808 PyObject
* pwho
= NULL
, *pchan
= NULL
, *oldtopic
= NULL
;
1809 PyObject
* name
= NULL
, *retval
= NULL
;
1810 const char* err
= NULL
;
1817 if ((pwho
= pyobj_from_usernode(who
)) == NULL
) {
1818 err
= "unable to allocate usernode";
1823 if ((pchan
= pyobj_from_channode(chan
)) == NULL
) {
1824 err
= "unable to allocate channode";
1828 if (old_topic
== NULL
) {
1832 oldtopic
= PyString_FromString(old_topic
);
1833 if (oldtopic
== NULL
) {
1834 err
= "unable to allocate memory for old topic string";
1839 name
= PyString_FromString("topic");
1841 err
= "unable to allocate memory for topic handler function name";
1845 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, pwho
, pchan
, oldtopic
, NULL
);
1846 if (retval
== NULL
) {
1847 err
= "error calling topic handler";
1854 Py_XDECREF(oldtopic
);
1857 if (retval
!= NULL
&& PyInt_Check(retval
))
1858 i
= (int)PyInt_AsLong(retval
);
1863 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1867 /* ----------------------------------------------------------------------------- */
1871 /* Init the python engine and do init work on modpython.py
1872 This is called during x3 startup, and on a python reload
1876 char* env
= getenv("PYTHONPATH");
1882 setenv("PYTHONPATH", modpython_conf
.scripts_dir
, 1);
1883 else if (!strstr(env
, modpython_conf
.scripts_dir
)) {
1884 buffer
= (char*)malloc(strlen(env
) + strlen(modpython_conf
.scripts_dir
) + 2);
1885 sprintf(buffer
, "%s:%s", modpython_conf
.scripts_dir
, env
);
1886 setenv("PYTHONPATH", buffer
, 1);
1891 log_module(PY_LOG
, LOG_DEBUG
, "Starting Python Init from python_load");
1893 Py_InitModule("_svc", EmbMethods
);
1894 pName
= PyString_FromString(modpython_conf
.main_module
);
1895 base_module
= PyImport_Import(pName
);
1898 Py_XDECREF(handler_object
);
1899 handler_object
= NULL
;
1901 if(base_module
!= NULL
) {
1902 handler_object
= python_new_handler_object();
1903 if(handler_object
) {
1904 python_call_handler("init", NULL
, 0, "", "", "");
1908 /* error handler class not found */
1909 log_module(PY_LOG
, LOG_WARNING
, "Failed to create handler object");
1916 python_log_module();
1917 log_module(PY_LOG
, LOG_WARNING
, "Failed to load modpython.py");
1925 python_finalize(void) {
1926 /* Called after X3 is fully up and running.
1927 Code can be put here that needs to run to init things, but
1928 which is sensitive to everything else in x3 being up and ready
1932 PyRun_SimpleString("print 'Hello, World of Python!'");
1933 log_module(PY_LOG
, LOG_INFO
, "python module finalize");
1939 python_cleanup(UNUSED_ARG(void *extra
)) {
1940 /* Called on shutdown of the python module (or before reloading)
1943 log_module(PY_LOG
, LOG_INFO
, "python module cleanup");
1945 Py_XDECREF(handler_object
);
1946 handler_object
= NULL
;
1948 if (PyErr_Occurred())
1950 Py_Finalize(); /* Shut down python enterpreter */
1952 log_module(PY_LOG
, LOG_INFO
, "python module cleanup done");
1955 /* ---------------------------------------------------------------------------------- *
1956 Python module command handlers.
1958 static MODCMD_FUNC(cmd_reload
) {
1959 /* reload the python system completely
1961 log_module(PY_LOG
, LOG_INFO
, "Shutting python down");
1962 python_cleanup(NULL
);
1963 log_module(PY_LOG
, LOG_INFO
, "Loading python stuff");
1965 reply("PYMSG_RELOAD_SUCCESS");
1968 reply("PYMSG_RELOAD_FAILED");
1973 static MODCMD_FUNC(cmd_run
) {
1974 /* this method allows running arbitrary python commands.
1978 PyObject
* py_main_module
;
1979 PyObject
* py_globals
;
1980 PyObject
* py_locals
;
1981 PyObject
* py_retval
;
1982 PyObject
* extype
, *exvalue
, *extraceback
;
1983 PyObject
* exvaluestr
= NULL
;
1984 char* exmsg
= NULL
, *exmsgptr
;
1986 py_main_module
= PyImport_AddModule("__main__");
1987 py_globals
= py_locals
= PyModule_GetDict(py_main_module
);
1989 msg
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
1991 py_retval
= PyRun_String(msg
, Py_file_input
, py_globals
, py_locals
);
1992 if (py_retval
== NULL
) {
1993 PyErr_Fetch(&extype
, &exvalue
, &extraceback
);
1994 if (exvalue
!= NULL
) {
1995 exvaluestr
= PyObject_Str(exvalue
);
1996 exmsg
= strdup(PyString_AS_STRING(exvaluestr
));
1998 while (exmsgptr
&& *exmsgptr
) {
1999 if (*exmsgptr
== '\n' || *exmsgptr
== '\r' || *exmsgptr
== '\t')
2004 if (extype
!= NULL
&& exvalue
!= NULL
&& PyType_Check(extype
)) {
2005 reply("PYMSG_RUN_EXCEPTION", ((PyTypeObject
*)extype
)->tp_name
, exmsg
);
2007 reply("PYMSG_RUN_UNKNOWN_EXCEPTION");
2011 if (exvalue
!= NULL
)
2013 if (extraceback
!= NULL
)
2014 Py_DECREF(extraceback
);
2015 if (exvaluestr
!= NULL
)
2016 Py_DECREF(exvaluestr
);
2020 Py_DECREF(py_retval
);
2026 #define numstrargs(X) sizeof(X) / sizeof(*X)
2027 static MODCMD_FUNC(cmd_command
) {
2028 char *plugin
= argv
[1];
2029 char *command
= argv
[2];
2030 char *msg
; /* args */
2032 msg
= unsplit_string(argv
+ 3, argc
- 3, NULL
);
2037 char *args
[] = {strdup(plugin
), strdup(command
), strdup(msg
)};
2038 python_call_handler("cmd_command", args
, numstrargs(args
), cmd
->parent
->bot
->nick
, user
?user
->nick
:"", channel
?channel
->name
:"");
2045 static void modpython_conf_read(void) {
2049 if (!(conf_node
= conf_get_data(MODPYTHON_CONF_NAME
, RECDB_OBJECT
))) {
2050 log_module(PY_LOG
, LOG_ERROR
, "config node '%s' is missing or has wrong type", MODPYTHON_CONF_NAME
);
2054 str
= database_get_data(conf_node
, "scripts_dir", RECDB_QSTRING
);
2055 modpython_conf
.scripts_dir
= strdup(str
? str
: "./");
2057 str
= database_get_data(conf_node
, "main_module", RECDB_QSTRING
);
2058 modpython_conf
.main_module
= strdup(str
? str
: "modpython");
2061 int python_init(void) {
2062 /* X3 calls this function on init of the module during startup. We use it to
2063 do all our setup tasks and bindings
2066 PY_LOG
= log_register_type("Python", "file:python.log");
2067 python_module
= module_register("python", PY_LOG
, "mod-python.help", NULL
);
2068 conf_register_reload(modpython_conf_read
);
2070 log_module(PY_LOG
, LOG_INFO
, "python module init");
2071 message_register_table(msgtab
);
2074 reg_auth_func(python_check_messages);
2075 reg_handle_rename_func(python_rename_account);
2076 reg_unreg_func(python_unreg_account);
2077 conf_register_reload(python_conf_read);
2078 saxdb_register("python", python_saxdb_read, python_saxdb_write);
2079 modcmd_register(python_module, "send", cmd_send, 3, MODCMD_REQUIRE_AUTHED, NULL);
2081 modcmd_register(python_module
, "reload", cmd_reload
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
2082 modcmd_register(python_module
, "run", cmd_run
, 2, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
2083 modcmd_register(python_module
, "command", cmd_command
, 3, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
2085 // Please help us by implementing any of the callbacks listed as TODO below. They already exist
2086 // in x3, they just need handle_ bridges implemented. (see python_handle_join for an example)
2087 reg_server_link_func(python_handle_server_link
, NULL
);
2088 reg_new_user_func(python_handle_new_user
, NULL
);
2089 reg_nick_change_func(python_handle_nick_change
, NULL
);
2090 reg_del_user_func(python_handle_del_user
, NULL
);
2091 //TODO: reg_account_func(python_handle_account); /* stamping of account name to the ircd */
2092 //TODO: reg_handle_rename_func(python_handle_handle_rename); /* handle used to ALSO mean account name */
2093 //TODO: reg_failpw_func(python_handle_failpw);
2094 //TODO: reg_allowauth_func(python_handle_allowauth);
2095 //TODO: reg_handle_merge_func(python_handle_merge);
2097 //TODO: reg_oper_func(python_handle_oper);
2098 //TODO: reg_new_channel_func(python_handle_new_channel);
2099 reg_join_func(python_handle_join
, NULL
);
2100 //TODO: reg_del_channel_func(python_handle_del_channel);
2101 //TODO: reg_part_func(python_handle_part);
2102 //TODO: reg_kick_func(python_handle_kick);
2103 reg_topic_func(python_handle_topic
, NULL
);
2104 //TODO: reg_channel_mode_func(python_handle_channel_mode);
2106 //TODO: reg_privmsg_func(python_handle_privmsg);
2107 //TODO: reg_notice_func
2108 //TODO: reg_svccmd_unbind_func(python_handle_svccmd_unbind);
2109 //TODO: reg_chanmsg_func(python_handle_chanmsg);
2110 //TODO: reg_allchanmsg_func
2111 //TODO: reg_user_mode_func
2113 reg_exit_func(python_cleanup
, NULL
);
2119 #endif /* WITH_PYTHON */