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 * - An interface to reading/writing data to x3.db. Maybe generic, or attached to account or channel reg records?
52 static const struct message_entry msgtab
[] = {
53 { "PYMSG_RELOAD_SUCCESS", "Reloaded Python scripts successfully." },
54 { "PYMSG_RELOAD_FAILED", "Error reloading Python scripts." },
55 { "PYMSG_RUN_UNKNOWN_EXCEPTION", "Error running python: unknown exception." },
56 { "PYMSG_RUN_EXCEPTION", "Error running python: %s: %s." },
57 { NULL
, NULL
} /* sentinel */
60 #define MODPYTHON_CONF_NAME "modules/python"
64 char const* scripts_dir
;
65 char const* main_module
;
68 static struct log_type
*PY_LOG
;
69 const char *python_module_deps
[] = { NULL
};
70 static struct module *python_module
;
72 PyObject
*base_module
= NULL
; /* Base python handling library */
73 PyObject
*handler_object
= NULL
; /* instance of handler class */
76 extern struct userNode
*global
, *chanserv
, *opserv
, *nickserv
, *spamserv
;
79 Some hooks you can call from modpython.py to interact with the
80 service. These emb_* functions are available as _svc.* in python. */
82 struct _tuple_dict_extra
{
87 static void pyobj_release_tuple(PyObject
* tuple
, size_t n
) {
93 for (i
= 0; i
< n
; ++i
)
94 Py_XDECREF(PyTuple_GET_ITEM(tuple
, i
));
99 static int _dict_iter_fill_tuple(char const* key
, UNUSED_ARG(void* data
), void* extra
) {
101 struct _tuple_dict_extra
* real_extra
= (struct _tuple_dict_extra
*)extra
;
103 if ((tmp
= PyString_FromString(key
)) == NULL
)
106 if (PyTuple_SetItem(real_extra
->data
, *(int*)real_extra
->extra
, tmp
)) {
111 *real_extra
->extra
= *real_extra
->extra
+ 1;
116 pyobj_from_dict_t(dict_t d
) {
119 struct _tuple_dict_extra extra
;
121 if ((retval
= PyTuple_New(dict_size(d
))) == NULL
)
127 if (dict_foreach(d
, _dict_iter_fill_tuple
, (void*)&extra
) != NULL
) {
128 pyobj_release_tuple(retval
, n
);
135 PyDoc_STRVAR(emb_get_users__doc__
,
136 "get_users() -> tuple with user nicks");
139 emb_get_users(UNUSED_ARG(PyObject
*self
), PyObject
*args
) {
140 if (!PyArg_ParseTuple(args
, ""))
143 return pyobj_from_dict_t(clients
);
146 PyDoc_STRVAR(emb_get_channels__doc__
,
147 "get_channels() -> tuple with channel names");
150 emb_get_channels(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
151 if (!PyArg_ParseTuple(args
, ""))
154 return pyobj_from_dict_t(channels
);
157 PyDoc_STRVAR(emb_get_servers__doc__
,
158 "get_servers() -> tuple with server names");
161 emb_get_servers(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
162 if (!PyArg_ParseTuple(args
, ""))
165 return pyobj_from_dict_t(servers
);
168 PyDoc_STRVAR(emb_get_accounts__doc__
,
169 "get_accounts() -> tuple with all nickserv account names");
172 emb_get_accounts(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
173 if (!PyArg_ParseTuple(args
, ""))
176 return pyobj_from_dict_t(nickserv_handle_dict
);
179 PyDoc_STRVAR(emb_dump__doc__
,
180 "dump(dump) -> an integer detailing success\n\n"
181 "Dumps a string to the server socket for propagation to other servers.\n\n"
182 "Return value is 1 on success and 0 on failure.\n");
185 emb_dump(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
187 /* Dump a raw string into the socket
188 usage: _svc.dump(<P10 string>)
192 char linedup
[MAXLEN
];
195 if(!PyArg_ParseTuple(args
, "s:dump", &buf
))
198 safestrncpy(linedup
, buf
, sizeof(linedup
));
200 if(parse_line(linedup
, 1)) {
204 PyErr_SetString(PyExc_Exception
, "invalid protocol message");
208 return Py_BuildValue("i", ret
);
211 PyDoc_STRVAR(emb_send_target_privmsg__doc__
,
212 "send_target_privmsg(servicenick, target, message) -> amount of message sent");
215 emb_send_target_privmsg(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
218 usage: _svc.send_target_privmsg(<servicenick_from>, <nick_to>, <message>)
225 struct service
*service
;
228 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &channel
, &buf
))
231 if (buf
== NULL
|| strlen(buf
) == 0) {
232 PyErr_SetString(PyExc_Exception
, "invalid empty message");
236 if(!(service
= service_find(servicenick
))) {
237 PyErr_SetString(PyExc_Exception
, "no such service nick");
241 ret
= send_target_message(5, channel
, service
->bot
, "%s", buf
);
242 return Py_BuildValue("i", ret
);
245 PyDoc_STRVAR(emb_send_target_notice__doc__
,
246 "send_target_notice(servicenick, target, message) -> amount of message sent");
249 emb_send_target_notice(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
252 usage: _svc.send_target_notice(<servicenick_from>, <nick_to>, <message>)
259 struct service
*service
;
261 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &target
, &buf
))
264 if (buf
== NULL
|| strlen(buf
) == 0) {
265 PyErr_SetString(PyExc_Exception
, "invalid empty message");
269 if(!(service
= service_find(servicenick
))) {
270 PyErr_SetString(PyExc_Exception
, "no such service nick");
274 ret
= send_target_message(4, target
, service
->bot
, "%s", buf
);
276 return Py_BuildValue("i", ret
);
280 pyobj_from_usernode(struct userNode
* user
) {
283 PyObject
* retval
= NULL
;
284 PyObject
* pChanList
= PyTuple_New(user
->channels
.used
);
286 if (pChanList
== NULL
)
289 for (n
=0; n
< user
->channels
.used
; n
++) {
290 mn
= user
->channels
.list
[n
];
291 if (PyTuple_SetItem(pChanList
, n
, Py_BuildValue("s", mn
->channel
->name
)))
295 retval
= Py_BuildValue("{"
299 "s: s, " /* hostname */
301 "s: s, " /* fakehost */
302 "s: s, " /* sethost */
303 "s: s, " /* crypthost */
304 "s: s, " /* cryptip */
305 "s: s, " /* numeric */
307 "s: i, " /* no_notice */
309 "s: s, " /* version_reply */
310 "s: s, " /* account */
311 "s: O}", /* channels */
313 "ident", user
->ident
,
315 "hostname", user
->hostname
,
316 "ip", irc_ntoa(&user
->ip
),
317 "fakehost", user
->fakehost
,
318 "sethost", user
->sethost
,
319 "crypthost", user
->crypthost
,
320 "cryptip", user
->cryptip
,
321 "numeric", user
->numeric
,
323 "no_notice", user
->no_notice
,
325 "version_reply", user
->version_reply
,
326 "account", user
->handle_info
? user
->handle_info
->handle
: NULL
,
327 "channels", pChanList
);
336 pyobj_release_tuple(pChanList
, n
);
341 PyDoc_STRVAR(emb_get_user__doc__
,
342 "get_user(nick) -> dict with user information\n\n"
343 "Updating the returned dictionary will not be reflected in the user's\n"
347 emb_get_user(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
349 /* Get a python object containing everything x3 knows about a user, by nick.
350 usage: _svc.get_user(<nick>)
353 struct userNode
*user
;
355 if(!PyArg_ParseTuple(args
, "s", &nick
))
358 if(!(user
= GetUserH(nick
))) {
359 PyErr_SetString(PyExc_Exception
, "no such user");
363 return pyobj_from_usernode(user
);
367 pyobj_from_server(struct server
* srv
) {
369 PyObject
* tmp
= NULL
;
370 PyObject
* retval
= NULL
;
371 PyObject
* users
= PyTuple_New(srv
->clients
);
377 for (n
= 0; n
< srv
->num_mask
; ++n
) {
378 if (srv
->users
[n
] == NULL
)
381 tmp
= PyString_FromString(srv
->users
[n
]->nick
);
385 if (PyTuple_SetItem(users
, idx
++, tmp
))
389 retval
= Py_BuildValue("{"
392 "s:l," /* link_time */
393 "s:s," /* description */
395 "s:I," /* num_mask */
398 "s:I," /* max_clients */
400 "s:I," /* self_burst */
407 "link_time", srv
->link_time
,
408 "description", srv
->description
,
409 "numeric", srv
->numeric
,
410 "num_mask", srv
->num_mask
,
412 "clients", srv
->clients
,
413 "max_clients", srv
->max_clients
,
415 "self_burst", srv
->self_burst
,
416 "uplink", srv
->uplink
? srv
->uplink
->name
: NULL
,
427 pyobj_release_tuple(users
, idx
);
432 PyDoc_STRVAR(emb_get_server__doc__
,
433 "get_server(name) -> dict with information\n\n"
434 "Changes made to the returned dictionary will not reflect in the server's\n"
438 emb_get_server(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
442 if (!PyArg_ParseTuple(args
, "s", &name
))
445 if (name
== NULL
|| strlen(name
) == 0) {
446 PyErr_SetString(PyExc_Exception
, "invalid server name");
450 if ((srv
= GetServerH(name
)) == NULL
) {
451 PyErr_SetString(PyExc_Exception
, "unknown server");
455 return pyobj_from_server(srv
);
459 pyobj_from_modelist(struct modeList
* mode
) {
462 PyObject
* retval
= PyTuple_New(mode
->used
);
467 for (n
= 0; n
< mode
->used
; ++n
) {
468 struct modeNode
* mn
= mode
->list
[n
];
469 tmp
= PyString_FromString(mn
->user
->nick
);
471 pyobj_release_tuple(retval
, n
);
475 if (PyTuple_SetItem(retval
, n
, tmp
)) {
476 pyobj_release_tuple(retval
, n
);
485 pyobj_from_banlist(struct banList
* bans
) {
489 PyObject
* retval
= PyTuple_New(bans
->used
);
494 for (n
= 0; n
< bans
->used
; ++n
) {
497 tmp
= Py_BuildValue("{s:s,s:s,s:l}",
498 "ban", bn
->ban
, "who", bn
->who
, "set", bn
->set
);
500 if (tmp
== NULL
|| PyTuple_SetItem(retval
, n
, tmp
)) {
501 pyobj_release_tuple(retval
, n
);
510 pyobj_from_exemptlist(struct exemptList
* exmp
) {
512 struct exemptNode
* en
;
514 PyObject
* retval
= PyTuple_New(exmp
->used
);
519 for (n
= 0; n
< exmp
->used
; ++n
) {
522 tmp
= Py_BuildValue("{s:s,s:s,s:l}",
523 "ban", en
->exempt
, "who", en
->who
, "set", en
->set
);
525 if (tmp
== NULL
|| PyTuple_SetItem(retval
, n
, tmp
)) {
526 pyobj_release_tuple(retval
, n
);
535 pyobj_from_channode(struct chanNode
* channel
) {
536 PyObject
*pChannelMembers
= NULL
;
537 PyObject
*pChannelBans
= NULL
;
538 PyObject
*pChannelExempts
= NULL
;
539 PyObject
*retval
= NULL
;
541 /* build tuple of nicks in channel */
542 pChannelMembers
= pyobj_from_modelist(&channel
->members
);
543 if (pChannelMembers
== NULL
)
546 /* build tuple of bans */
547 pChannelBans
= pyobj_from_banlist(&channel
->banlist
);
548 if (pChannelBans
== NULL
)
551 /* build tuple of exempts */
552 pChannelExempts
= pyobj_from_exemptlist(&channel
->exemptlist
);
553 if (pChannelExempts
== NULL
)
556 retval
= Py_BuildValue("{s:s,s:s,s:s,s:i"
557 ",s:i,s:i,s:O,s:O,s:O}",
559 "name", channel
->name
,
560 "topic", channel
->topic
,
561 "topic_nick", channel
->topic_nick
,
562 "topic_time", channel
->topic_time
,
564 "timestamp", channel
->timestamp
,
565 "modes", channel
->modes
,
566 "members", pChannelMembers
,
567 "bans", pChannelBans
,
568 "exempts", pChannelExempts
577 pyobj_release_tuple(pChannelExempts
, channel
->exemptlist
.used
);
578 pyobj_release_tuple(pChannelBans
, channel
->banlist
.used
);
579 pyobj_release_tuple(pChannelMembers
, channel
->members
.used
);
584 PyDoc_STRVAR(emb_get_channel__doc__
,
585 "get_channel(channel) -> dict with channel information\n\n"
586 "Updates made to the returned dictionary does not reflect in the channel\n"
590 emb_get_channel(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
592 /* Returns a python dict object with all sorts of info about a channel.
593 usage: _svc.get_channel(<name>)
596 struct chanNode
*channel
;
598 if(!PyArg_ParseTuple(args
, "s", &name
))
601 if(!(channel
= GetChannel(name
))) {
602 PyErr_SetString(PyExc_Exception
, "unknown channel");
606 return pyobj_from_channode(channel
);
609 PyDoc_STRVAR(emb_get_account__doc__
,
610 "get_account(account) -> dict with account information\n\n"
611 "Changes made to the returned dictionary will not be reflected in the\n"
612 "account's information.");
615 emb_get_account(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
617 /* Returns a python dict object with all sorts of info about an account.
618 usage: _svc.get_account(<account name>)
621 struct handle_info
*hi
;
624 if(!PyArg_ParseTuple(args
, "s", &name
))
627 hi
= get_handle_info(name
);
630 PyErr_SetString(PyExc_Exception
, "unknown account name");
634 return Py_BuildValue("{s:s,s:i,s:s,s:s,s:s"
637 "account", hi
->handle
,
638 "registered", hi
->registered
,
639 "last_seen", hi
->lastseen
,
640 "infoline", hi
->infoline
? hi
->infoline
: "",
641 "email", hi
->email_addr
? hi
->email_addr
: "",
643 "fakehost", hi
->fakehost
? hi
->fakehost
: "",
644 "last_quit_host", hi
->last_quit_host
647 /* users online authed to this account */
649 /* nicks (nickserv nets only?) */
656 PyDoc_STRVAR(emb_get_info__doc__
,
657 "get_info() -> dict with general service setup information\n\n"
658 "The dictionary contains the nicks of the different services.");
661 emb_get_info(UNUSED_ARG(PyObject
*self
), UNUSED_ARG(PyObject
*args
))
663 /* return some info about the general setup
664 * of X3, such as what the chanserv's nickname
669 return Py_BuildValue("{s:s,s:s,s:s,s:s,s:s}",
670 "chanserv", chanserv
? chanserv
->nick
: "ChanServ",
671 "nickserv", nickserv
?nickserv
->nick
: "NickServ",
672 "opserv", opserv
?opserv
->nick
: "OpServ",
673 "global", global
?global
->nick
: "Global",
674 "spamserv", spamserv
?spamserv
->nick
: "SpamServ");
677 PyDoc_STRVAR(emb_log_module__doc__
,
678 "log_module(level, message)\n\n"
679 "Logs a message in the PY_LOG subsystem given a severity level and a message.");
682 emb_log_module(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
684 /* a gateway to standard X3 logging subsystem.
685 * level is a value 0 to 9 as defined by the log_severity enum in log.h.
687 * for now, all logs go to the PY_LOG log. In the future this will change.
692 if(!PyArg_ParseTuple(args
, "is", &level
, &message
))
695 log_module(PY_LOG
, level
, "%s", message
);
701 PyDoc_STRVAR(emb_kill__doc__
,
702 "kill(servicenick, target, message)\n\n"
703 "Kills a given user.");
706 emb_kill(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
707 char const* from_nick
, *target_nick
, *message
;
708 struct userNode
*target
;
709 struct service
*service
;
711 if (!PyArg_ParseTuple(args
, "sss", &from_nick
, &target_nick
, &message
))
714 if(!(service
= service_find(from_nick
))) {
715 PyErr_SetString(PyExc_Exception
, "unknown service user specified as from user");
719 if ((target
= GetUserH(target_nick
)) == NULL
) {
720 PyErr_SetString(PyExc_Exception
, "unknown target user");
724 irc_kill(service
->bot
, target
, message
);
730 struct py_timeq_extra
{
736 void py_timeq_callback(void* data
) {
737 struct py_timeq_extra
* extra
= (struct py_timeq_extra
*)data
;
739 PyObject
* retval
= PyObject_Call(extra
->func
, extra
->arg
, NULL
);
742 Py_DECREF(extra
->func
);
743 Py_DECREF(extra
->arg
);
746 PyDoc_STRVAR(emb_timeq_add__doc__
,
747 "timeq_add(when, function, args)\n\n"
748 "Adds a callback to the service timer system.\n\n"
749 "The specific function must be callable, and the specified arguments must be\n"
750 "a tuple with the arguments that the function expects.");
753 emb_timeq_add(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
755 PyObject
* func
, *arg
;
756 struct py_timeq_extra
* extra
;
758 if (!PyArg_ParseTuple(args
, "lOO", &when
, &func
, &arg
))
761 if (!PyFunction_Check(func
)) {
762 PyErr_SetString(PyExc_Exception
, "first argument must be a function");
766 if (!PyTuple_Check(arg
)) {
767 PyErr_SetString(PyExc_Exception
, "second argument must be a tuple");
771 extra
= malloc(sizeof(struct py_timeq_extra
));
773 PyErr_SetString(PyExc_Exception
, "out of memory");
783 timeq_add(when
, py_timeq_callback
, (void*)extra
);
789 PyDoc_STRVAR(emb_timeq_del__doc__
,
790 "timeq_del(when)\n\n"
791 "This function deletes all python-added callbacks registered to run at the\n"
792 "given time, regardless of their data. This is due to the unnecessary extra\n"
793 "burden it would require to get the same data for multiple runs.");
796 emb_timeq_del(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
799 if (!PyArg_ParseTuple(args
, "l", &when
))
802 timeq_del(when
, py_timeq_callback
, NULL
, TIMEQ_IGNORE_DATA
);
808 static int pyobj_config_make_dict(char const* key
, void* data_
, void* extra
) {
809 struct record_data
* data
= (struct record_data
*)data_
;
810 PyObject
* dict
= (PyObject
*)extra
;
811 PyObject
* value
= NULL
, *tmp
;
815 switch (data
->type
) {
817 value
= PyString_FromString(data
->d
.qstring
);
820 case RECDB_STRING_LIST
:
821 value
= PyList_New(data
->d
.slist
->used
);
826 for (n
= 0; n
< data
->d
.slist
->used
; ++n
) {
827 tmp
= PyString_FromString(data
->d
.slist
->list
[n
]);
833 if (PyList_SetItem(value
, n
, tmp
)) {
840 for (idx
= 0; idx
< n
; ++idx
) {
841 tmp
= PyList_GET_ITEM(value
, idx
);
843 PyList_SET_ITEM(value
, idx
, NULL
);
851 value
= PyDict_New();
855 if (dict_foreach(data
->d
.object
, pyobj_config_make_dict
, (void*)value
) != NULL
) {
871 if (PyDict_SetItemString(dict
, key
, value
))
877 PyDoc_STRVAR(emb_get_config__doc__
,
878 "get_config() -> dict with config elements and values\n\n"
879 "Updates to the returned dictionary will not reflect in the service's\n"
883 emb_get_config(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
886 if (!PyArg_ParseTuple(args
, ""))
893 if (conf_enum_root(pyobj_config_make_dict
, (void*)dict
) != NULL
) {
895 PyErr_SetString(PyExc_Exception
, "unable to iterate config");
902 PyDoc_STRVAR(emb_kick__doc__
,
903 "kick(who, target, message)\n\n"
904 "Kicks a given target as if the who user kicked them using the given message.");
906 static PyObject
* emb_kick(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
907 struct userNode
* who
, *target
;
908 struct chanNode
* channel
;
911 char const* who_s
, *target_s
, *channel_s
;
913 if (!PyArg_ParseTuple(args
, "ssss", &who_s
, &target_s
, &channel_s
, &msg
))
916 if ((who
= GetUserH(who_s
)) == NULL
) {
917 PyErr_SetString(PyExc_Exception
, "no such user");
921 if ((target
= GetUserH(target_s
)) == NULL
) {
922 PyErr_SetString(PyExc_Exception
, "no such target");
926 if ((channel
= GetChannel(channel_s
)) == NULL
) {
927 PyErr_SetString(PyExc_Exception
, "no such channel");
931 irc_kick(who
, target
, channel
, msg
);
937 PyDoc_STRVAR(emb_channel_mode__doc__
,
938 "channel_mode(who, channel, modes)\n\n"
939 "Lets a current server's user set a specified channel's modes as specified.");
941 static PyObject
* emb_channel_mode(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
942 struct userNode
* who
;
943 struct chanNode
* channel
;
946 char const* who_s
, *channel_s
;
948 if (!PyArg_ParseTuple(args
, "sss", &who_s
, &channel_s
, &modes
))
951 if ((who
= GetUserH(who_s
)) == NULL
) {
952 PyErr_SetString(PyExc_Exception
, "unknown user");
956 if (who
->uplink
!= self
) {
957 PyErr_SetString(PyExc_Exception
, "user not on current server");
961 if ((channel
= GetChannel(channel_s
)) == NULL
) {
962 PyErr_SetString(PyExc_Exception
, "unknown channel");
966 irc_mode(who
, channel
, modes
);
972 PyDoc_STRVAR(emb_user_mode__doc__
,
973 "user_mode(target, modes)\n\n"
974 "Sets target's modes as specified. The modes are in normal +f-n syntax.");
976 static PyObject
* emb_user_mode(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
977 struct userNode
* target
;
980 char const* target_s
;
982 if (!PyArg_ParseTuple(args
, "ss", &target_s
, &modes
))
985 if ((target
= GetUserH(target_s
)) == NULL
) {
986 PyErr_SetString(PyExc_Exception
, "unknown user");
990 irc_umode(target
, modes
);
996 PyDoc_STRVAR(emb_fakehost__doc__
,
997 "fakehost(target, host)\n\n"
998 "Sets the fakehost of a given user to the specified host.");
1000 static PyObject
* emb_fakehost(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
1001 struct userNode
* target
;
1004 char const* target_s
;
1006 if (!PyArg_ParseTuple(args
, "ss", &target_s
, &host
))
1009 if ((target
= GetUserH(target_s
)) == NULL
) {
1010 PyErr_SetString(PyExc_Exception
, "unknown user");
1014 irc_fakehost(target
, host
);
1020 PyDoc_STRVAR(emb_svsnick__doc__
,
1021 "svsnick(from, target, newnick)\n\n"
1022 "The from nick must be on the service server.");
1025 emb_svsnick(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1026 struct userNode
* from
, *target
;
1027 const char* newnick
;
1029 const char* from_s
, *target_s
;
1031 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &newnick
))
1034 if ((from
= GetUserH(from_s
)) == NULL
) {
1035 PyErr_SetString(PyExc_Exception
, "unknown from user");
1039 if ((target
= GetUserH(target_s
)) == NULL
) {
1040 PyErr_SetString(PyExc_Exception
, "unknown target user");
1044 if (from
->uplink
!= self
) {
1045 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1049 irc_svsnick(from
, target
, newnick
);
1055 PyDoc_STRVAR(emb_svsquit__doc__
,
1056 "svsquit(from, target, reason)\n\n"
1057 "The from user must be on the service server.");
1060 emb_svsquit(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1061 struct userNode
* from
, *target
;
1064 char const* from_s
, *target_s
;
1066 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &reason
))
1069 if ((from
= GetUserH(from_s
)) == NULL
) {
1070 PyErr_SetString(PyExc_Exception
, "unknown from user");
1074 if (from
->uplink
!= self
) {
1075 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1079 if ((target
= GetUserH(target_s
)) == NULL
) {
1080 PyErr_SetString(PyExc_Exception
, "unknown target user");
1084 irc_svsquit(from
, target
, reason
);
1090 PyDoc_STRVAR(emb_svsjoin__doc__
,
1091 "svsjoin(from, target, to)\n\n"
1092 "From user from must a user on the service server.\n"
1093 "To must be an existing channel name.");
1096 emb_svsjoin(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1097 struct userNode
* from
, *target
;
1098 struct chanNode
* to
;
1100 const char* from_s
, *target_s
, *to_s
;
1102 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &to_s
))
1105 if ((from
= GetUserH(from_s
)) == NULL
) {
1106 PyErr_SetString(PyExc_Exception
, "unknown from user");
1110 if (from
->uplink
!= self
) {
1111 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1115 if ((target
= GetUserH(target_s
)) == NULL
) {
1116 PyErr_SetString(PyExc_Exception
, "unknown target user");
1120 if ((to
= GetChannel(to_s
)) == NULL
)
1121 to
= AddChannel(to_s
, now
, NULL
, NULL
, NULL
);
1123 irc_svsjoin(from
, target
, to
);
1129 PyDoc_STRVAR(emb_adduser__doc__
,
1130 "adduser(nick, ident, hostname, description, modes) -> dict with user information\n\n"
1131 "Adds a new local user with the given information.");
1134 emb_adduser(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1135 char const* nick
, *ident
, *hostname
, *desc
, *modes
;
1136 struct userNode
* user
;
1139 if (!PyArg_ParseTuple(args
, "sssss", &nick
, &ident
, &hostname
, &desc
, &modes
))
1142 user
= AddLocalUser(nick
, ident
, hostname
, desc
, modes
);
1144 retval
= pyobj_from_usernode(user
);
1149 /* TODO: Add the rest of the service members to the dict */
1151 pyobj_from_service(struct service
* serv
) {
1152 PyObject
* bot
, *retval
;
1154 bot
= pyobj_from_usernode(serv
->bot
);
1158 retval
= Py_BuildValue("{s:O,s:c,s:I}",
1160 "trigger", serv
->trigger
,
1161 "privileged", serv
->privileged
);
1172 PyDoc_STRVAR(emb_service_register__doc__
,
1173 "service_register(nick)\n\n"
1174 "Registers nick as a service. The specified nick must be on the local server.");
1177 emb_service_register(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1178 struct userNode
* user
;
1181 if (!PyArg_ParseTuple(args
, "s", &user_s
))
1184 if ((user
= GetUserH(user_s
)) == NULL
) {
1185 PyErr_SetString(PyExc_Exception
, "unknown user");
1189 if (user
->uplink
!= self
) {
1190 PyErr_SetString(PyExc_Exception
, "user is not on service server");
1194 return pyobj_from_service(service_register(user
));
1197 size_t logs_size
= 0;
1198 static struct log_type
**logs_list
= NULL
;
1200 PyDoc_STRVAR(emb_log_register_type__doc__
,
1201 "registers a log source to write event data to.");
1202 static PyObject
* emb_log_register_type(UNUSED_ARG(PyObject
*self
), PyObject
* args
) {
1203 const char* logName
;
1204 const char* defaultLog
;
1205 struct log_type
* log
;
1206 struct log_type
** newlogs
;
1208 if (!PyArg_ParseTuple(args
, "ss", &logName
, &defaultLog
))
1211 newlogs
= realloc(logs_list
, (logs_size
+1)*sizeof(struct log_type
*));
1212 if (newlogs
== NULL
) {
1213 PyErr_SetString(PyExc_Exception
, "unable to allocate memory for log structures. aborting.");
1216 logs_list
= newlogs
;
1218 log
= log_register_type(logName
, defaultLog
);
1220 PyErr_SetString(PyExc_Exception
, "unable to register log");
1224 logs_list
[logs_size
++] = log
;
1226 return Py_BuildValue("O", PyCObject_FromVoidPtr(log
, NULL
));
1229 PyDoc_STRVAR(emb_module_register__doc__
, "registers a module");
1230 PyObject
* emb_module_register(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
1232 char const *name
, *helpfile
;
1233 struct log_type
* log
;
1236 if (!PyArg_ParseTuple(args
, "sOs", &name
, &pylog
, &helpfile
))
1239 log
= PyCObject_AsVoidPtr(pylog
);
1241 mod
= module_register(name
, log
, helpfile
, NULL
);
1244 PyErr_SetString(PyExc_Exception
, "unable to register module");
1248 return Py_BuildValue("O", PyCObject_FromVoidPtr(mod
, NULL
));
1251 static PyMethodDef EmbMethods
[] = {
1252 /* Communication methods */
1253 {"dump", emb_dump
, METH_VARARGS
, emb_dump__doc__
},
1254 {"send_target_privmsg", emb_send_target_privmsg
, METH_VARARGS
, emb_send_target_privmsg__doc__
},
1255 {"send_target_notice", emb_send_target_notice
, METH_VARARGS
, emb_send_target_notice__doc__
},
1256 {"log_module", emb_log_module
, METH_VARARGS
, emb_log_module__doc__
},
1257 //TODO: {"exec_cmd", emb_exec_cmd, METH_VARARGS, "execute x3 command provided"},
1258 // This should use environment from "python command" call to pass in, if available
1259 {"kill", emb_kill
, METH_VARARGS
, emb_kill__doc__
},
1260 {"fakehost", emb_fakehost
, METH_VARARGS
, emb_fakehost__doc__
},
1261 {"svsnick", emb_svsnick
, METH_VARARGS
, emb_svsnick__doc__
},
1262 {"svsquit", emb_svsquit
, METH_VARARGS
, emb_svsquit__doc__
},
1263 {"svsjoin", emb_svsjoin
, METH_VARARGS
, emb_svsjoin__doc__
},
1264 {"adduser", emb_adduser
, METH_VARARGS
, emb_adduser__doc__
},
1265 {"service_register", emb_service_register
, METH_VARARGS
, emb_service_register__doc__
},
1266 //TODO: svsmode, svsident, nick, quit, join, part, ident, vhost
1269 //TODO: {"gline", emb_gline, METH_VARARGS, "gline a mask"},
1270 //TODO: {"ungline", emb_ungline, METH_VARARGS, "remove a gline"},
1271 {"kick", emb_kick
, METH_VARARGS
, emb_kick__doc__
},
1272 {"channel_mode", emb_channel_mode
, METH_VARARGS
, emb_channel_mode__doc__
},
1273 {"user_mode", emb_user_mode
, METH_VARARGS
, emb_user_mode__doc__
},
1275 {"get_config", emb_get_config
, METH_VARARGS
, emb_get_config__doc__
},
1276 //TODO: {"config_set", emb_config_set, METH_VARARGS, "change a config setting 'on-the-fly'."},
1278 {"timeq_add", emb_timeq_add
, METH_VARARGS
, emb_timeq_add__doc__
},
1279 {"timeq_del", emb_timeq_del
, METH_VARARGS
, emb_timeq_del__doc__
},
1281 /* module registration methods */
1282 {"log_register_type", emb_log_register_type
, METH_VARARGS
,
1283 emb_log_register_type__doc__
},
1284 {"module_register", emb_module_register
, METH_VARARGS
,
1285 emb_module_register__doc__
},
1287 /* Information gathering methods */
1288 {"get_user", emb_get_user
, METH_VARARGS
, emb_get_user__doc__
},
1289 {"get_users", emb_get_users
, METH_VARARGS
, emb_get_users__doc__
},
1290 {"get_channel", emb_get_channel
, METH_VARARGS
, emb_get_channel__doc__
},
1291 {"get_channels", emb_get_channels
, METH_VARARGS
, emb_get_channels__doc__
},
1292 {"get_server", emb_get_server
, METH_VARARGS
, emb_get_server__doc__
},
1293 {"get_servers", emb_get_servers
, METH_VARARGS
, emb_get_servers__doc__
},
1294 {"get_account", emb_get_account
, METH_VARARGS
, emb_get_account__doc__
},
1295 {"get_accounts", emb_get_accounts
, METH_VARARGS
, emb_get_accounts__doc__
},
1296 {"get_info", emb_get_info
, METH_VARARGS
, emb_get_info__doc__
},
1297 /* null terminator */
1298 {NULL
, NULL
, 0, NULL
}
1303 These functions set up the embedded environment for us to call out to
1304 modpython.py class methods.
1307 void python_log_module() {
1308 /* Attempt to convert python errors to x3 log system */
1309 PyObject
*exc
, *tb
, *value
, *tmp
;
1310 char *str_exc
= "NONE";
1311 char *str_value
= "NONE";
1312 char *str_tb
= "NONE";
1314 PyErr_Fetch(&exc
, &value
, &tb
);
1317 if((tmp
= PyObject_Str(exc
)))
1318 str_exc
= PyString_AsString(tmp
);
1321 if((tmp
= PyObject_Str(value
)))
1322 str_value
= PyString_AsString(tmp
);
1325 if((tmp
= PyObject_Str(tb
)))
1326 str_tb
= PyString_AsString(tmp
);
1329 /* Now restore it so we can print it (just in case)
1330 * (should we do this only when running in debug mode?) */
1331 PyErr_Restore(exc
, value
, tb
);
1332 PyErr_Print(); /* which of course, clears it again.. */
1334 log_module(PY_LOG
, LOG_WARNING
, "PYTHON error: %s, value: %s", str_exc
, str_value
);
1336 /* TODO: get the traceback using the traceback module via C api so we can add it to the X3 logs. See
1337 * http://mail.python.org/pipermail/python-list/2003-March/192226.html */
1338 // (this doesnt work, str_tb is just an object hashid) log_module(PY_LOG, LOG_INFO, "PYTHON error, traceback: %s", str_tb);
1342 PyObject
*python_build_handler_args(size_t argc
, char *args
[], PyObject
*pIrcObj
) {
1343 /* Sets up a python tuple with passed in arguments, prefixed by the Irc instance
1344 which handlers use to interact with C.
1345 argc = number of args
1346 args = array of args
1347 pIrcObj = instance of the irc class
1350 PyObject
*pArgs
= NULL
;
1352 pArgs
= PyTuple_New(argc
+ 1);
1354 PyTuple_SetItem(pArgs
, i
++, pIrcObj
);
1358 for(n
= 0; n
< argc
; ++n
) {
1359 pValue
= PyString_FromString(args
[n
]);
1362 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[n
]);
1365 PyTuple_SetItem(pArgs
, n
+i
, pValue
);
1371 PyObject
*python_build_args(size_t argc
, char *args
[]) {
1372 /* Builds the passed in arguments into a python argument tuple.
1373 argc = number of args
1374 args = array of args
1377 PyObject
*pArgs
= NULL
;
1380 pArgs
= PyTuple_New(argc
);
1382 for(i
= 0; i
< argc
; ++i
) {
1383 pValue
= PyString_FromString(args
[i
]);
1386 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[i
]);
1389 PyTuple_SetItem(pArgs
, i
, pValue
);
1396 PyObject
*new_irc_object(char *command_service
, char *command_caller
, char *command_target
) {
1397 /* Creates a new instance of the irc class (from modpython.py) which is initalized
1398 with current environment details like which service were talking to.
1399 command_service = which service we are talking to, or empty string if none
1400 command_caller = nick of user generating message, or empty string if none
1401 command_target = If were reacting to something on a channel, this will
1402 be set to the name of the channel. Otherwise empty
1404 PyObject
*pIrcArgs
= NULL
;
1405 PyObject
*pIrcClass
;
1408 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate irc class; %s %s %s", command_service
, command_caller
, command_target
);
1409 pIrcClass
= PyObject_GetAttrString(base_module
, "irc");
1410 /* pIrcClass is a new reference */
1411 if(pIrcClass
&& PyCallable_Check(pIrcClass
)) {
1413 char *ircargs
[] = {command_service
, command_caller
, command_target
};
1416 pIrcArgs
= python_build_args(3, ircargs
);
1417 pIrcObj
= PyObject_CallObject(pIrcClass
, pIrcArgs
);
1419 log_module(PY_LOG
, LOG_ERROR
, "IRC Class failed to load");
1420 python_log_module();
1423 if(pIrcArgs
!= NULL
) {
1424 Py_DECREF(pIrcArgs
);
1426 Py_DECREF(pIrcClass
);
1430 /* need to free pIrcClass here if it WAS found but was NOT callable? */
1431 log_module(PY_LOG
, LOG_ERROR
, "Unable to find irc class");
1436 int python_call_handler(char *handler
, char *args
[], size_t argc
, char *command_service
, char *command_caller
, char *command_target
) {
1437 /* This is how we talk to modpython.c. First a new instance of the irc class is created using these
1438 arguments to setup the current environment. Then the named method of the handler object is called
1439 with the givin arguments.
1446 log_module(PY_LOG
, LOG_INFO
, "attempting to call handler %s.", handler
);
1447 if(base_module
!= NULL
&& handler_object
!= NULL
) {
1448 pIrcObj
= new_irc_object(command_service
, command_caller
, command_target
);
1450 log_module(PY_LOG
, LOG_INFO
, "Can't get irc object. Bailing.");
1454 pArgs
= python_build_handler_args(argc
, args
, pIrcObj
);
1455 pMethod
= PyObject_GetAttrString(handler_object
, handler
);
1456 if(pMethod
&& PyCallable_Check(pMethod
)) {
1457 /* Call the method, with the arguments */
1458 pValue
= PyObject_CallObject(pMethod
, pArgs
);
1462 if(pValue
!= NULL
) {
1464 ret
= PyInt_AsLong(pValue
);
1465 if(ret
== -1 && PyErr_Occurred()) {
1467 log_module(PY_LOG
, LOG_INFO
, "error converting return value of handler %s to type long. ", handler
);
1468 python_log_module();
1471 log_module(PY_LOG
, LOG_INFO
, "handler %s was run successfully, returned %d.", handler
, ret
);
1478 /* TODO: instead of print errors, get them as strings
1479 * and deal with them with normal x3 log system. */
1480 log_module(PY_LOG
, LOG_WARNING
, "call to handler %s failed", handler
);
1482 python_log_module();
1488 else { /* couldn't find handler methed */
1490 /* Free pMethod if it was found but not callable? */
1491 log_module(PY_LOG
, LOG_ERROR
, "Cannot find handler %s.", handler
);
1496 else { /* No base module.. no python? */
1497 log_module(PY_LOG
, LOG_INFO
, "Cannot handle %s, Python is not initialized.", handler
);
1502 PyObject
*python_new_handler_object() {
1503 /* Create a new instance of the handler class.
1504 This is called during python initilization (or reload)
1505 and the result is saved and re-used.
1507 PyObject
*pHandlerClass
, *pHandlerObj
;
1509 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate python class handler");
1510 pHandlerClass
= PyObject_GetAttrString(base_module
, "handler");
1511 /* Class is a new reference */
1512 if(pHandlerClass
&& PyCallable_Check(pHandlerClass
)) {
1513 /*PyObject *pValue; */
1515 pHandlerObj
= PyObject_CallObject(pHandlerClass
, NULL
);
1516 if(pHandlerObj
!= NULL
) {
1517 log_module(PY_LOG
, LOG_INFO
, "Created new python handler object.");
1521 log_module(PY_LOG
, LOG_ERROR
, "Unable to instanciate handler object");
1523 python_log_module();
1528 log_module(PY_LOG
, LOG_ERROR
, "Unable to find handler class");
1530 python_log_module();
1532 Py_DECREF(pHandlerClass
);
1538 /* ------------------------------------------------------------------------------- *
1539 Some gateway functions to convert x3 callbacks into modpython.py callbacks.
1540 Mostly we just build relevant args and call the proper handler method
1542 debate: do we just register these and check them in python
1543 for every one (slow?) or actually work out if a plugin needs
1544 it first? We will start by doing it every time.
1547 python_handle_join(struct modeNode
*mNode
, UNUSED_ARG(void *extra
))
1549 /* callback for handle_join events.
1551 struct userNode
*user
= mNode
->user
;
1552 struct chanNode
*channel
= mNode
->channel
;
1555 log_module(PY_LOG
, LOG_INFO
, "python module handle_join");
1556 if(!channel
||!user
) {
1557 log_module(PY_LOG
, LOG_WARNING
, "Python code got join without channel or user!");
1561 char *args
[] = {channel
->name
, user
->nick
};
1562 return python_call_handler("join", args
, 2, "", "", "");
1567 python_handle_server_link(struct server
*server
, UNUSED_ARG(void *extra
))
1569 PyObject
* srv
= NULL
;
1570 PyObject
* funcname
= NULL
;
1571 PyObject
* retval
= NULL
;
1572 char const* err
= NULL
;
1575 if (handler_object
== NULL
) {
1576 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1580 if (server
== NULL
) {
1581 err
= "Python code got server link without server!";
1585 if ((srv
= pyobj_from_server(server
)) == NULL
) {
1586 err
= "Python code unable to get PyObject with server!";
1590 funcname
= PyString_FromString("server_link");
1591 if (funcname
== NULL
) {
1592 err
= "Unable to allocate memory";
1596 retval
= PyObject_CallMethodObjArgs(handler_object
, funcname
, srv
, NULL
);
1597 if (retval
== NULL
) {
1598 err
= "Error calling server_link handler";
1604 Py_XDECREF(funcname
);
1606 if (retval
!= NULL
&& PyInt_Check(retval
))
1607 i
= (int)PyInt_AsLong(retval
);
1612 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1618 python_handle_new_user(struct userNode
*user
, UNUSED_ARG(void *extra
))
1620 PyObject
* name
= NULL
;
1621 PyObject
* usr
= NULL
;
1622 PyObject
* retval
= NULL
;
1624 const char* err
= NULL
;
1626 if (handler_object
== NULL
) {
1627 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1632 log_module(PY_LOG
, LOG_WARNING
, "Python code got new_user without the user");
1636 if ((usr
= pyobj_from_usernode(user
)) == NULL
) {
1637 err
= "unable to allocate python user information";
1641 name
= PyString_FromString("new_user");
1643 err
= "unable to allocate memory for handler function name";
1647 if ((retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, NULL
)) == NULL
) {
1648 err
= "error calling new_user handler";
1656 if (retval
!= NULL
&& PyInt_Check(retval
))
1657 i
= (int)PyInt_AsLong(retval
);
1662 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1668 python_handle_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
))
1670 PyObject
* usr
= NULL
;
1671 PyObject
* name
= NULL
;
1672 PyObject
* oldnick
= NULL
;
1673 PyObject
* retval
= NULL
;
1674 char const* err
= NULL
;
1676 if (handler_object
== NULL
) {
1677 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1682 err
= "Python code got nick_change without the user!";
1686 if ((usr
= pyobj_from_usernode(user
)) == NULL
) {
1687 err
= "unable to allocate Python usernode";
1691 name
= PyString_FromString("nick_change");
1693 err
= "unable to allocate memory for handler function name";
1697 oldnick
= PyString_FromString(old_nick
);
1699 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, oldnick
, NULL
);
1700 if (retval
== NULL
) {
1701 err
= "error calling nick_change handler";
1708 Py_XDECREF(oldnick
);
1712 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1715 void python_handle_del_user(struct userNode
*user
, struct userNode
*killer
, const char *why
, UNUSED_ARG(void *extra
)) {
1716 PyObject
*usr
= NULL
, *killr
= NULL
, *name
= NULL
;
1717 PyObject
*reason
= NULL
, *retval
= NULL
;
1718 char const* err
= NULL
;
1720 if (handler_object
== NULL
) {
1721 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1729 usr
= pyobj_from_usernode(user
);
1731 err
= "unable to allocate usernode for user";
1736 if (killer
== NULL
) {
1740 killr
= pyobj_from_usernode(killer
);
1741 if (killr
== NULL
) {
1742 err
= "unable to allocate usernode for killer";
1751 reason
= PyString_FromString(why
);
1752 if (reason
== NULL
) {
1753 err
= "unable to allocate memory for reason";
1758 name
= PyString_FromString("del_user");
1760 err
= "unable to allocate memory for handler function name";
1764 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, killr
, reason
, NULL
);
1765 if (retval
== NULL
) {
1766 err
= "error calling del_user handler";
1778 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1781 int python_handle_topic(struct userNode
*who
, struct chanNode
*chan
, const char *old_topic
, UNUSED_ARG(void *extra
)) {
1782 PyObject
* pwho
= NULL
, *pchan
= NULL
, *oldtopic
= NULL
;
1783 PyObject
* name
= NULL
, *retval
= NULL
;
1784 const char* err
= NULL
;
1791 if ((pwho
= pyobj_from_usernode(who
)) == NULL
) {
1792 err
= "unable to allocate usernode";
1797 if ((pchan
= pyobj_from_channode(chan
)) == NULL
) {
1798 err
= "unable to allocate channode";
1802 if (old_topic
== NULL
) {
1806 oldtopic
= PyString_FromString(old_topic
);
1807 if (oldtopic
== NULL
) {
1808 err
= "unable to allocate memory for old topic string";
1813 name
= PyString_FromString("topic");
1815 err
= "unable to allocate memory for topic handler function name";
1819 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, pwho
, pchan
, oldtopic
, NULL
);
1820 if (retval
== NULL
) {
1821 err
= "error calling topic handler";
1828 Py_XDECREF(oldtopic
);
1831 if (retval
!= NULL
&& PyInt_Check(retval
))
1832 i
= (int)PyInt_AsLong(retval
);
1837 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1841 /* ----------------------------------------------------------------------------- */
1845 /* Init the python engine and do init work on modpython.py
1846 This is called during x3 startup, and on a python reload
1850 char* env
= getenv("PYTHONPATH");
1856 setenv("PYTHONPATH", modpython_conf
.scripts_dir
, 1);
1857 else if (!strstr(env
, modpython_conf
.scripts_dir
)) {
1858 buffer
= (char*)malloc(strlen(env
) + strlen(modpython_conf
.scripts_dir
) + 2);
1859 sprintf(buffer
, "%s:%s", modpython_conf
.scripts_dir
, env
);
1860 setenv("PYTHONPATH", buffer
, 1);
1866 Py_InitModule("_svc", EmbMethods
);
1867 pName
= PyString_FromString(modpython_conf
.main_module
);
1868 base_module
= PyImport_Import(pName
);
1871 Py_XDECREF(handler_object
);
1872 handler_object
= NULL
;
1874 if(base_module
!= NULL
) {
1875 handler_object
= python_new_handler_object();
1876 if(handler_object
) {
1877 python_call_handler("init", NULL
, 0, "", "", "");
1881 /* error handler class not found */
1882 log_module(PY_LOG
, LOG_WARNING
, "Failed to create handler object");
1888 python_log_module();
1889 log_module(PY_LOG
, LOG_WARNING
, "Failed to load modpython.py");
1896 python_finalize(void) {
1897 /* Called after X3 is fully up and running.
1898 Code can be put here that needs to run to init things, but
1899 which is sensitive to everything else in x3 being up and ready
1903 PyRun_SimpleString("print 'Hello, World of Python!'");
1904 log_module(PY_LOG
, LOG_INFO
, "python module finalize");
1910 python_cleanup(UNUSED_ARG(void *extra
)) {
1911 /* Called on shutdown of the python module (or before reloading)
1914 log_module(PY_LOG
, LOG_INFO
, "python module cleanup");
1916 Py_XDECREF(handler_object
);
1917 handler_object
= NULL
;
1919 if (PyErr_Occurred())
1921 Py_Finalize(); /* Shut down python enterpreter */
1923 log_module(PY_LOG
, LOG_INFO
, "python module cleanup done");
1926 /* ---------------------------------------------------------------------------------- *
1927 Python module command handlers.
1929 static MODCMD_FUNC(cmd_reload
) {
1930 /* reload the python system completely
1932 log_module(PY_LOG
, LOG_INFO
, "Shutting python down");
1933 python_cleanup(NULL
);
1934 log_module(PY_LOG
, LOG_INFO
, "Loading python stuff");
1936 reply("PYMSG_RELOAD_SUCCESS");
1939 reply("PYMSG_RELOAD_FAILED");
1944 static MODCMD_FUNC(cmd_run
) {
1945 /* this method allows running arbitrary python commands.
1949 PyObject
* py_main_module
;
1950 PyObject
* py_globals
;
1951 PyObject
* py_locals
;
1952 PyObject
* py_retval
;
1953 PyObject
* extype
, *exvalue
, *extraceback
;
1954 PyObject
* exvaluestr
= NULL
;
1955 char* exmsg
= NULL
, *exmsgptr
;
1957 py_main_module
= PyImport_AddModule("__main__");
1958 py_globals
= py_locals
= PyModule_GetDict(py_main_module
);
1960 msg
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
1962 py_retval
= PyRun_String(msg
, Py_file_input
, py_globals
, py_locals
);
1963 if (py_retval
== NULL
) {
1964 PyErr_Fetch(&extype
, &exvalue
, &extraceback
);
1965 if (exvalue
!= NULL
) {
1966 exvaluestr
= PyObject_Str(exvalue
);
1967 exmsg
= strdup(PyString_AS_STRING(exvaluestr
));
1969 while (exmsgptr
&& *exmsgptr
) {
1970 if (*exmsgptr
== '\n' || *exmsgptr
== '\r' || *exmsgptr
== '\t')
1975 if (extype
!= NULL
&& exvalue
!= NULL
&& PyType_Check(extype
)) {
1976 reply("PYMSG_RUN_EXCEPTION", ((PyTypeObject
*)extype
)->tp_name
, exmsg
);
1978 reply("PYMSG_RUN_UNKNOWN_EXCEPTION");
1982 if (exvalue
!= NULL
)
1984 if (extraceback
!= NULL
)
1985 Py_DECREF(extraceback
);
1986 if (exvaluestr
!= NULL
)
1987 Py_DECREF(exvaluestr
);
1991 Py_DECREF(py_retval
);
1997 #define numstrargs(X) sizeof(X) / sizeof(*X)
1998 static MODCMD_FUNC(cmd_command
) {
1999 char *plugin
= argv
[1];
2000 char *command
= argv
[2];
2001 char *msg
; /* args */
2003 msg
= unsplit_string(argv
+ 3, argc
- 3, NULL
);
2008 char *args
[] = {plugin
, command
, msg
};
2009 python_call_handler("cmd_command", args
, numstrargs(args
), cmd
->parent
->bot
->nick
, user
?user
->nick
:"", channel
?channel
->name
:"");
2013 static void modpython_conf_read(void) {
2017 if (!(conf_node
= conf_get_data(MODPYTHON_CONF_NAME
, RECDB_OBJECT
))) {
2018 log_module(PY_LOG
, LOG_ERROR
, "config node '%s' is missing or has wrong type", MODPYTHON_CONF_NAME
);
2022 str
= database_get_data(conf_node
, "scripts_dir", RECDB_QSTRING
);
2023 modpython_conf
.scripts_dir
= str
? str
: "./";
2025 str
= database_get_data(conf_node
, "main_module", RECDB_QSTRING
);
2026 modpython_conf
.main_module
= str
? str
: "modpython";
2029 int python_init(void) {
2030 /* X3 calls this function on init of the module during startup. We use it to
2031 do all our setup tasks and bindings
2034 PY_LOG
= log_register_type("Python", "file:python.log");
2035 python_module
= module_register("python", PY_LOG
, "mod-python.help", NULL
);
2036 conf_register_reload(modpython_conf_read
);
2038 log_module(PY_LOG
, LOG_INFO
, "python module init");
2039 message_register_table(msgtab
);
2042 reg_auth_func(python_check_messages);
2043 reg_handle_rename_func(python_rename_account);
2044 reg_unreg_func(python_unreg_account);
2045 conf_register_reload(python_conf_read);
2046 saxdb_register("python", python_saxdb_read, python_saxdb_write);
2047 modcmd_register(python_module, "send", cmd_send, 3, MODCMD_REQUIRE_AUTHED, NULL);
2049 modcmd_register(python_module
, "reload", cmd_reload
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
2050 modcmd_register(python_module
, "run", cmd_run
, 2, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
2051 modcmd_register(python_module
, "command", cmd_command
, 3, MODCMD_REQUIRE_STAFF
, NULL
);
2053 // Please help us by implementing any of the callbacks listed as TODO below. They already exist
2054 // in x3, they just need handle_ bridges implemented. (see python_handle_join for an example)
2055 reg_server_link_func(python_handle_server_link
, NULL
);
2056 reg_new_user_func(python_handle_new_user
, NULL
);
2057 reg_nick_change_func(python_handle_nick_change
, NULL
);
2058 reg_del_user_func(python_handle_del_user
, NULL
);
2059 //TODO: reg_account_func(python_handle_account); /* stamping of account name to the ircd */
2060 //TODO: reg_handle_rename_func(python_handle_handle_rename); /* handle used to ALSO mean account name */
2061 //TODO: reg_failpw_func(python_handle_failpw);
2062 //TODO: reg_allowauth_func(python_handle_allowauth);
2063 //TODO: reg_handle_merge_func(python_handle_merge);
2065 //TODO: reg_oper_func(python_handle_oper);
2066 //TODO: reg_new_channel_func(python_handle_new_channel);
2067 reg_join_func(python_handle_join
, NULL
);
2068 //TODO: reg_del_channel_func(python_handle_del_channel);
2069 //TODO: reg_part_func(python_handle_part);
2070 //TODO: reg_kick_func(python_handle_kick);
2071 reg_topic_func(python_handle_topic
, NULL
);
2072 //TODO: reg_channel_mode_func(python_handle_channel_mode);
2074 //TODO: reg_privmsg_func(python_handle_privmsg);
2075 //TODO: reg_notice_func
2076 //TODO: reg_svccmd_unbind_func(python_handle_svccmd_unbind);
2077 //TODO: reg_chanmsg_func(python_handle_chanmsg);
2078 //TODO: reg_allchanmsg_func
2079 //TODO: reg_user_mode_func
2081 reg_exit_func(python_cleanup
, NULL
);
2087 #endif /* WITH_PYTHON */