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?
51 * basic startup for now:
52 * configure --enable-modules=python
53 * /msg o3 bind o3 py\ run *python.run
54 * /msg o3 bind o3 py\ reload *python.reload
55 * /msg o3 bind o3 py\ command *python.command
57 * example script bindings (for now)
58 * /msg o3 bind x3 hangman *modcmd.joiner
59 * /msg o3 bind x3 hangman\ start *python.command hangman start
60 * /msg o3 bind x3 hangman\ end *python.command hangman end
61 * /msg o3 bind x3 hangman\ guess *python.command hangman guess
64 static const struct message_entry msgtab
[] = {
65 { "PYMSG_RELOAD_SUCCESS", "Reloaded Python scripts successfully." },
66 { "PYMSG_RELOAD_FAILED", "Error reloading Python scripts." },
67 { "PYMSG_RUN_UNKNOWN_EXCEPTION", "Error running python: unknown exception." },
68 { "PYMSG_RUN_EXCEPTION", "Error running python: %s: %s." },
69 { NULL
, NULL
} /* sentinel */
72 #define MODPYTHON_CONF_NAME "modules/python"
76 char const* scripts_dir
;
77 char const* main_module
;
80 static struct log_type
*PY_LOG
;
81 const char *python_module_deps
[] = { NULL
};
82 static struct module *python_module
;
84 PyObject
*base_module
= NULL
; /* Base python handling library */
85 PyObject
*handler_object
= NULL
; /* instance of handler class */
88 extern struct userNode
*global
, *chanserv
, *opserv
, *nickserv
, *spamserv
;
91 Some hooks you can call from modpython.py to interact with the
92 service. These emb_* functions are available as _svc.* in python. */
94 struct _tuple_dict_extra
{
99 static void pyobj_release_tuple(PyObject
* tuple
, size_t n
) {
105 for (i
= 0; i
< n
; ++i
)
106 Py_XDECREF(PyTuple_GET_ITEM(tuple
, i
));
111 static int _dict_iter_fill_tuple(char const* key
, UNUSED_ARG(void* data
), void* extra
) {
113 struct _tuple_dict_extra
* real_extra
= (struct _tuple_dict_extra
*)extra
;
115 if ((tmp
= PyString_FromString(key
)) == NULL
)
118 if (PyTuple_SetItem(real_extra
->data
, *(int*)real_extra
->extra
, tmp
)) {
123 *real_extra
->extra
= *real_extra
->extra
+ 1;
128 pyobj_from_dict_t(dict_t d
) {
131 struct _tuple_dict_extra extra
;
133 if ((retval
= PyTuple_New(dict_size(d
))) == NULL
)
139 if (dict_foreach(d
, _dict_iter_fill_tuple
, (void*)&extra
) != NULL
) {
140 pyobj_release_tuple(retval
, n
);
147 PyDoc_STRVAR(emb_get_users__doc__
,
148 "get_users() -> tuple with user nicks");
151 emb_get_users(UNUSED_ARG(PyObject
*self
), PyObject
*args
) {
152 if (!PyArg_ParseTuple(args
, ""))
155 return pyobj_from_dict_t(clients
);
158 PyDoc_STRVAR(emb_get_channels__doc__
,
159 "get_channels() -> tuple with channel names");
162 emb_get_channels(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
163 if (!PyArg_ParseTuple(args
, ""))
166 return pyobj_from_dict_t(channels
);
169 PyDoc_STRVAR(emb_get_servers__doc__
,
170 "get_servers() -> tuple with server names");
173 emb_get_servers(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
174 if (!PyArg_ParseTuple(args
, ""))
177 return pyobj_from_dict_t(servers
);
180 PyDoc_STRVAR(emb_get_accounts__doc__
,
181 "get_accounts() -> tuple with all nickserv account names");
184 emb_get_accounts(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
185 if (!PyArg_ParseTuple(args
, ""))
188 return pyobj_from_dict_t(nickserv_handle_dict
);
191 PyDoc_STRVAR(emb_dump__doc__
,
192 "dump(dump) -> an integer detailing success\n\n"
193 "Dumps a string to the server socket for propagation to other servers.\n\n"
194 "Return value is 1 on success and 0 on failure.\n");
197 emb_dump(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
199 /* Dump a raw string into the socket
200 usage: _svc.dump(<P10 string>)
204 char linedup
[MAXLEN
];
207 if(!PyArg_ParseTuple(args
, "s:dump", &buf
))
210 safestrncpy(linedup
, buf
, sizeof(linedup
));
212 if(parse_line(linedup
, 1)) {
216 PyErr_SetString(PyExc_Exception
, "invalid protocol message");
220 return Py_BuildValue("i", ret
);
223 PyDoc_STRVAR(emb_send_target_privmsg__doc__
,
224 "send_target_privmsg(servicenick, target, message) -> amount of message sent");
227 emb_send_target_privmsg(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
230 usage: _svc.send_target_privmsg(<servicenick_from>, <nick_to>, <message>)
237 struct service
*service
;
240 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &channel
, &buf
))
243 if (buf
== NULL
|| strlen(buf
) == 0) {
244 PyErr_SetString(PyExc_Exception
, "invalid empty message");
248 if(!(service
= service_find(servicenick
))) {
249 PyErr_SetString(PyExc_Exception
, "no such service nick");
253 ret
= send_target_message(5, channel
, service
->bot
, "%s", buf
);
254 return Py_BuildValue("i", ret
);
257 PyDoc_STRVAR(emb_send_target_notice__doc__
,
258 "send_target_notice(servicenick, target, message) -> amount of message sent");
261 emb_send_target_notice(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
264 usage: _svc.send_target_notice(<servicenick_from>, <nick_to>, <message>)
271 struct service
*service
;
273 if(!PyArg_ParseTuple(args
, "sss:reply", &servicenick
, &target
, &buf
))
276 if (buf
== NULL
|| strlen(buf
) == 0) {
277 PyErr_SetString(PyExc_Exception
, "invalid empty message");
281 if(!(service
= service_find(servicenick
))) {
282 PyErr_SetString(PyExc_Exception
, "no such service nick");
286 ret
= send_target_message(4, target
, service
->bot
, "%s", buf
);
288 return Py_BuildValue("i", ret
);
292 pyobj_from_usernode(struct userNode
* user
) {
295 PyObject
* retval
= NULL
;
296 PyObject
* pChanList
= PyTuple_New(user
->channels
.used
);
298 if (pChanList
== NULL
)
301 for (n
=0; n
< user
->channels
.used
; n
++) {
302 mn
= user
->channels
.list
[n
];
303 if (PyTuple_SetItem(pChanList
, n
, Py_BuildValue("s", mn
->channel
->name
)))
307 retval
= Py_BuildValue("{"
311 "s: s, " /* hostname */
313 "s: s, " /* fakehost */
314 "s: s, " /* sethost */
315 "s: s, " /* crypthost */
316 "s: s, " /* cryptip */
317 "s: s, " /* numeric */
319 "s: i, " /* no_notice */
321 "s: s, " /* version_reply */
322 "s: s, " /* account */
323 "s: O}", /* channels */
325 "ident", user
->ident
,
327 "hostname", user
->hostname
,
328 "ip", irc_ntoa(&user
->ip
),
329 "fakehost", user
->fakehost
,
330 "sethost", user
->sethost
,
331 "crypthost", user
->crypthost
,
332 "cryptip", user
->cryptip
,
333 "numeric", user
->numeric
,
335 "no_notice", user
->no_notice
,
337 "version_reply", user
->version_reply
,
338 "account", user
->handle_info
? user
->handle_info
->handle
: NULL
,
339 "channels", pChanList
);
348 pyobj_release_tuple(pChanList
, n
);
353 PyDoc_STRVAR(emb_get_user__doc__
,
354 "get_user(nick) -> dict with user information\n\n"
355 "Updating the returned dictionary will not be reflected in the user's\n"
359 emb_get_user(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
361 /* Get a python object containing everything x3 knows about a user, by nick.
362 usage: _svc.get_user(<nick>)
365 struct userNode
*user
;
367 if(!PyArg_ParseTuple(args
, "s", &nick
))
370 if(!(user
= GetUserH(nick
))) {
371 PyErr_SetString(PyExc_Exception
, "no such user");
375 return pyobj_from_usernode(user
);
379 pyobj_from_server(struct server
* srv
) {
381 PyObject
* tmp
= NULL
;
382 PyObject
* retval
= NULL
;
383 PyObject
* users
= PyTuple_New(srv
->clients
);
389 for (n
= 0; n
< srv
->num_mask
; ++n
) {
390 if (srv
->users
[n
] == NULL
)
393 tmp
= PyString_FromString(srv
->users
[n
]->nick
);
397 if (PyTuple_SetItem(users
, idx
++, tmp
))
401 retval
= Py_BuildValue("{"
404 "s:l," /* link_time */
405 "s:s," /* description */
407 "s:I," /* num_mask */
410 "s:I," /* max_clients */
412 "s:I," /* self_burst */
419 "link_time", srv
->link_time
,
420 "description", srv
->description
,
421 "numeric", srv
->numeric
,
422 "num_mask", srv
->num_mask
,
424 "clients", srv
->clients
,
425 "max_clients", srv
->max_clients
,
427 "self_burst", srv
->self_burst
,
428 "uplink", srv
->uplink
? srv
->uplink
->name
: NULL
,
439 pyobj_release_tuple(users
, idx
);
444 PyDoc_STRVAR(emb_get_server__doc__
,
445 "get_server(name) -> dict with information\n\n"
446 "Changes made to the returned dictionary will not reflect in the server's\n"
450 emb_get_server(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
454 if (!PyArg_ParseTuple(args
, "s", &name
))
457 if (name
== NULL
|| strlen(name
) == 0) {
458 PyErr_SetString(PyExc_Exception
, "invalid server name");
462 if ((srv
= GetServerH(name
)) == NULL
) {
463 PyErr_SetString(PyExc_Exception
, "unknown server");
467 return pyobj_from_server(srv
);
471 pyobj_from_modelist(struct modeList
* mode
) {
474 PyObject
* retval
= PyTuple_New(mode
->used
);
479 for (n
= 0; n
< mode
->used
; ++n
) {
480 struct modeNode
* mn
= mode
->list
[n
];
481 tmp
= PyString_FromString(mn
->user
->nick
);
483 pyobj_release_tuple(retval
, n
);
487 if (PyTuple_SetItem(retval
, n
, tmp
)) {
488 pyobj_release_tuple(retval
, n
);
497 pyobj_from_banlist(struct banList
* bans
) {
501 PyObject
* retval
= PyTuple_New(bans
->used
);
506 for (n
= 0; n
< bans
->used
; ++n
) {
509 tmp
= Py_BuildValue("{s:s,s:s,s:l}",
510 "ban", bn
->ban
, "who", bn
->who
, "set", bn
->set
);
512 if (tmp
== NULL
|| PyTuple_SetItem(retval
, n
, tmp
)) {
513 pyobj_release_tuple(retval
, n
);
522 pyobj_from_exemptlist(struct exemptList
* exmp
) {
524 struct exemptNode
* en
;
526 PyObject
* retval
= PyTuple_New(exmp
->used
);
531 for (n
= 0; n
< exmp
->used
; ++n
) {
534 tmp
= Py_BuildValue("{s:s,s:s,s:l}",
535 "ban", en
->exempt
, "who", en
->who
, "set", en
->set
);
537 if (tmp
== NULL
|| PyTuple_SetItem(retval
, n
, tmp
)) {
538 pyobj_release_tuple(retval
, n
);
547 pyobj_from_channode(struct chanNode
* channel
) {
548 PyObject
*pChannelMembers
= NULL
;
549 PyObject
*pChannelBans
= NULL
;
550 PyObject
*pChannelExempts
= NULL
;
551 PyObject
*retval
= NULL
;
553 /* build tuple of nicks in channel */
554 pChannelMembers
= pyobj_from_modelist(&channel
->members
);
555 if (pChannelMembers
== NULL
)
558 /* build tuple of bans */
559 pChannelBans
= pyobj_from_banlist(&channel
->banlist
);
560 if (pChannelBans
== NULL
)
563 /* build tuple of exempts */
564 pChannelExempts
= pyobj_from_exemptlist(&channel
->exemptlist
);
565 if (pChannelExempts
== NULL
)
568 retval
= Py_BuildValue("{s:s,s:s,s:s,s:i"
569 ",s:i,s:i,s:O,s:O,s:O}",
571 "name", channel
->name
,
572 "topic", channel
->topic
,
573 "topic_nick", channel
->topic_nick
,
574 "topic_time", channel
->topic_time
,
576 "timestamp", channel
->timestamp
,
577 "modes", channel
->modes
,
578 "members", pChannelMembers
,
579 "bans", pChannelBans
,
580 "exempts", pChannelExempts
589 pyobj_release_tuple(pChannelExempts
, channel
->exemptlist
.used
);
590 pyobj_release_tuple(pChannelBans
, channel
->banlist
.used
);
591 pyobj_release_tuple(pChannelMembers
, channel
->members
.used
);
596 PyDoc_STRVAR(emb_get_channel__doc__
,
597 "get_channel(channel) -> dict with channel information\n\n"
598 "Updates made to the returned dictionary does not reflect in the channel\n"
602 emb_get_channel(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
604 /* Returns a python dict object with all sorts of info about a channel.
605 usage: _svc.get_channel(<name>)
608 struct chanNode
*channel
;
610 if(!PyArg_ParseTuple(args
, "s", &name
))
613 if(!(channel
= GetChannel(name
))) {
614 PyErr_SetString(PyExc_Exception
, "unknown channel");
618 return pyobj_from_channode(channel
);
621 PyDoc_STRVAR(emb_get_account__doc__
,
622 "get_account(account) -> dict with account information\n\n"
623 "Changes made to the returned dictionary will not be reflected in the\n"
624 "account's information.");
627 emb_get_account(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
629 /* Returns a python dict object with all sorts of info about an account.
630 usage: _svc.get_account(<account name>)
633 struct handle_info
*hi
;
636 if(!PyArg_ParseTuple(args
, "s", &name
))
639 hi
= get_handle_info(name
);
642 PyErr_SetString(PyExc_Exception
, "unknown account name");
646 return Py_BuildValue("{s:s,s:i,s:s,s:s,s:s"
649 "account", hi
->handle
,
650 "registered", hi
->registered
,
651 "last_seen", hi
->lastseen
,
652 "infoline", hi
->infoline
? hi
->infoline
: "",
653 "email", hi
->email_addr
? hi
->email_addr
: "",
655 "fakehost", hi
->fakehost
? hi
->fakehost
: "",
656 "last_quit_host", hi
->last_quit_host
659 /* users online authed to this account */
661 /* nicks (nickserv nets only?) */
668 PyDoc_STRVAR(emb_get_info__doc__
,
669 "get_info() -> dict with general service setup information\n\n"
670 "The dictionary contains the nicks of the different services.");
673 emb_get_info(UNUSED_ARG(PyObject
*self
), UNUSED_ARG(PyObject
*args
))
675 /* return some info about the general setup
676 * of X3, such as what the chanserv's nickname
681 return Py_BuildValue("{s:s,s:s,s:s,s:s,s:s}",
682 "chanserv", chanserv
? chanserv
->nick
: "ChanServ",
683 "nickserv", nickserv
?nickserv
->nick
: "NickServ",
684 "opserv", opserv
?opserv
->nick
: "OpServ",
685 "global", global
?global
->nick
: "Global",
686 "spamserv", spamserv
?spamserv
->nick
: "SpamServ");
689 PyDoc_STRVAR(emb_log_module__doc__
,
690 "log_module(level, message)\n\n"
691 "Logs a message in the PY_LOG subsystem given a severity level and a message.");
694 emb_log_module(UNUSED_ARG(PyObject
*self
), PyObject
*args
)
696 /* a gateway to standard X3 logging subsystem.
697 * level is a value 0 to 9 as defined by the log_severity enum in log.h.
699 * for now, all logs go to the PY_LOG log. In the future this will change.
704 if(!PyArg_ParseTuple(args
, "is", &level
, &message
))
707 log_module(PY_LOG
, level
, "%s", message
);
713 PyDoc_STRVAR(emb_kill__doc__
,
714 "kill(servicenick, target, message)\n\n"
715 "Kills a given user.");
718 emb_kill(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
719 char const* from_nick
, *target_nick
, *message
;
720 struct userNode
*target
;
721 struct service
*service
;
723 if (!PyArg_ParseTuple(args
, "sss", &from_nick
, &target_nick
, &message
))
726 if(!(service
= service_find(from_nick
))) {
727 PyErr_SetString(PyExc_Exception
, "unknown service user specified as from user");
731 if ((target
= GetUserH(target_nick
)) == NULL
) {
732 PyErr_SetString(PyExc_Exception
, "unknown target user");
736 irc_kill(service
->bot
, target
, message
);
742 struct py_timeq_extra
{
748 void py_timeq_callback(void* data
) {
749 struct py_timeq_extra
* extra
= (struct py_timeq_extra
*)data
;
751 PyObject
* retval
= PyObject_Call(extra
->func
, extra
->arg
, NULL
);
754 Py_DECREF(extra
->func
);
755 Py_DECREF(extra
->arg
);
758 PyDoc_STRVAR(emb_timeq_add__doc__
,
759 "timeq_add(when, function, args)\n\n"
760 "Adds a callback to the service timer system.\n\n"
761 "The specific function must be callable, and the specified arguments must be\n"
762 "a tuple with the arguments that the function expects.");
765 emb_timeq_add(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
767 PyObject
* func
, *arg
;
768 struct py_timeq_extra
* extra
;
770 if (!PyArg_ParseTuple(args
, "lOO", &when
, &func
, &arg
))
773 if (!PyFunction_Check(func
)) {
774 PyErr_SetString(PyExc_Exception
, "first argument must be a function");
778 if (!PyTuple_Check(arg
)) {
779 PyErr_SetString(PyExc_Exception
, "second argument must be a tuple");
783 extra
= malloc(sizeof(struct py_timeq_extra
));
785 PyErr_SetString(PyExc_Exception
, "out of memory");
795 timeq_add(when
, py_timeq_callback
, (void*)extra
);
801 PyDoc_STRVAR(emb_timeq_del__doc__
,
802 "timeq_del(when)\n\n"
803 "This function deletes all python-added callbacks registered to run at the\n"
804 "given time, regardless of their data. This is due to the unnecessary extra\n"
805 "burden it would require to get the same data for multiple runs.");
808 emb_timeq_del(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
811 if (!PyArg_ParseTuple(args
, "l", &when
))
814 timeq_del(when
, py_timeq_callback
, NULL
, TIMEQ_IGNORE_DATA
);
820 static int pyobj_config_make_dict(char const* key
, void* data_
, void* extra
) {
821 struct record_data
* data
= (struct record_data
*)data_
;
822 PyObject
* dict
= (PyObject
*)extra
;
823 PyObject
* value
= NULL
, *tmp
;
827 switch (data
->type
) {
829 value
= PyString_FromString(data
->d
.qstring
);
832 case RECDB_STRING_LIST
:
833 value
= PyList_New(data
->d
.slist
->used
);
838 for (n
= 0; n
< data
->d
.slist
->used
; ++n
) {
839 tmp
= PyString_FromString(data
->d
.slist
->list
[n
]);
845 if (PyList_SetItem(value
, n
, tmp
)) {
852 for (idx
= 0; idx
< n
; ++idx
) {
853 tmp
= PyList_GET_ITEM(value
, idx
);
855 PyList_SET_ITEM(value
, idx
, NULL
);
863 value
= PyDict_New();
867 if (dict_foreach(data
->d
.object
, pyobj_config_make_dict
, (void*)value
) != NULL
) {
883 if (PyDict_SetItemString(dict
, key
, value
))
889 PyDoc_STRVAR(emb_get_config__doc__
,
890 "get_config() -> dict with config elements and values\n\n"
891 "Updates to the returned dictionary will not reflect in the service's\n"
895 emb_get_config(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
898 if (!PyArg_ParseTuple(args
, ""))
905 if (conf_enum_root(pyobj_config_make_dict
, (void*)dict
) != NULL
) {
907 PyErr_SetString(PyExc_Exception
, "unable to iterate config");
914 PyDoc_STRVAR(emb_kick__doc__
,
915 "kick(who, target, message)\n\n"
916 "Kicks a given target as if the who user kicked them using the given message.");
918 static PyObject
* emb_kick(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
919 struct userNode
* who
, *target
;
920 struct chanNode
* channel
;
923 char const* who_s
, *target_s
, *channel_s
;
925 if (!PyArg_ParseTuple(args
, "ssss", &who_s
, &target_s
, &channel_s
, &msg
))
928 if ((who
= GetUserH(who_s
)) == NULL
) {
929 PyErr_SetString(PyExc_Exception
, "no such user");
933 if ((target
= GetUserH(target_s
)) == NULL
) {
934 PyErr_SetString(PyExc_Exception
, "no such target");
938 if ((channel
= GetChannel(channel_s
)) == NULL
) {
939 PyErr_SetString(PyExc_Exception
, "no such channel");
943 irc_kick(who
, target
, channel
, msg
);
949 PyDoc_STRVAR(emb_channel_mode__doc__
,
950 "channel_mode(who, channel, modes)\n\n"
951 "Lets a current server's user set a specified channel's modes as specified.");
953 static PyObject
* emb_channel_mode(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
954 struct userNode
* who
;
955 struct chanNode
* channel
;
958 char const* who_s
, *channel_s
;
960 if (!PyArg_ParseTuple(args
, "sss", &who_s
, &channel_s
, &modes
))
963 if ((who
= GetUserH(who_s
)) == NULL
) {
964 PyErr_SetString(PyExc_Exception
, "unknown user");
968 if (who
->uplink
!= self
) {
969 PyErr_SetString(PyExc_Exception
, "user not on current server");
973 if ((channel
= GetChannel(channel_s
)) == NULL
) {
974 PyErr_SetString(PyExc_Exception
, "unknown channel");
978 irc_mode(who
, channel
, modes
);
984 PyDoc_STRVAR(emb_user_mode__doc__
,
985 "user_mode(target, modes)\n\n"
986 "Sets target's modes as specified. The modes are in normal +f-n syntax.");
988 static PyObject
* emb_user_mode(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
989 struct userNode
* target
;
992 char const* target_s
;
994 if (!PyArg_ParseTuple(args
, "ss", &target_s
, &modes
))
997 if ((target
= GetUserH(target_s
)) == NULL
) {
998 PyErr_SetString(PyExc_Exception
, "unknown user");
1002 irc_umode(target
, modes
);
1008 PyDoc_STRVAR(emb_fakehost__doc__
,
1009 "fakehost(target, host)\n\n"
1010 "Sets the fakehost of a given user to the specified host.");
1012 static PyObject
* emb_fakehost(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
1013 struct userNode
* target
;
1016 char const* target_s
;
1018 if (!PyArg_ParseTuple(args
, "ss", &target_s
, &host
))
1021 if ((target
= GetUserH(target_s
)) == NULL
) {
1022 PyErr_SetString(PyExc_Exception
, "unknown user");
1026 irc_fakehost(target
, host
);
1032 PyDoc_STRVAR(emb_svsnick__doc__
,
1033 "svsnick(from, target, newnick)\n\n"
1034 "The from nick must be on the service server.");
1037 emb_svsnick(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1038 struct userNode
* from
, *target
;
1039 const char* newnick
;
1041 const char* from_s
, *target_s
;
1043 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &newnick
))
1046 if ((from
= GetUserH(from_s
)) == NULL
) {
1047 PyErr_SetString(PyExc_Exception
, "unknown from user");
1051 if ((target
= GetUserH(target_s
)) == NULL
) {
1052 PyErr_SetString(PyExc_Exception
, "unknown target user");
1056 if (from
->uplink
!= self
) {
1057 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1061 irc_svsnick(from
, target
, newnick
);
1067 PyDoc_STRVAR(emb_svsquit__doc__
,
1068 "svsquit(from, target, reason)\n\n"
1069 "The from user must be on the service server.");
1072 emb_svsquit(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1073 struct userNode
* from
, *target
;
1076 char const* from_s
, *target_s
;
1078 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &reason
))
1081 if ((from
= GetUserH(from_s
)) == NULL
) {
1082 PyErr_SetString(PyExc_Exception
, "unknown from user");
1086 if (from
->uplink
!= self
) {
1087 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1091 if ((target
= GetUserH(target_s
)) == NULL
) {
1092 PyErr_SetString(PyExc_Exception
, "unknown target user");
1096 irc_svsquit(from
, target
, reason
);
1102 PyDoc_STRVAR(emb_svsjoin__doc__
,
1103 "svsjoin(from, target, to)\n\n"
1104 "From user from must a user on the service server.\n"
1105 "To must be an existing channel name.");
1108 emb_svsjoin(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1109 struct userNode
* from
, *target
;
1110 struct chanNode
* to
;
1112 const char* from_s
, *target_s
, *to_s
;
1114 if (!PyArg_ParseTuple(args
, "sss", &from_s
, &target_s
, &to_s
))
1117 if ((from
= GetUserH(from_s
)) == NULL
) {
1118 PyErr_SetString(PyExc_Exception
, "unknown from user");
1122 if (from
->uplink
!= self
) {
1123 PyErr_SetString(PyExc_Exception
, "from user is not on service server");
1127 if ((target
= GetUserH(target_s
)) == NULL
) {
1128 PyErr_SetString(PyExc_Exception
, "unknown target user");
1132 if ((to
= GetChannel(to_s
)) == NULL
)
1133 to
= AddChannel(to_s
, now
, NULL
, NULL
, NULL
);
1135 irc_svsjoin(from
, target
, to
);
1141 PyDoc_STRVAR(emb_adduser__doc__
,
1142 "adduser(nick, ident, hostname, description, modes) -> dict with user information\n\n"
1143 "Adds a new local user with the given information.");
1146 emb_adduser(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1147 char const* nick
, *ident
, *hostname
, *desc
, *modes
;
1148 struct userNode
* user
;
1151 if (!PyArg_ParseTuple(args
, "sssss", &nick
, &ident
, &hostname
, &desc
, &modes
))
1154 user
= AddLocalUser(nick
, ident
, hostname
, desc
, modes
);
1156 retval
= pyobj_from_usernode(user
);
1161 /* TODO: Add the rest of the service members to the dict */
1163 pyobj_from_service(struct service
* serv
) {
1164 PyObject
* bot
, *retval
;
1166 bot
= pyobj_from_usernode(serv
->bot
);
1170 retval
= Py_BuildValue("{s:O,s:c,s:I}",
1172 "trigger", serv
->trigger
,
1173 "privileged", serv
->privileged
);
1184 PyDoc_STRVAR(emb_service_register__doc__
,
1185 "service_register(nick)\n\n"
1186 "Registers nick as a service. The specified nick must be on the local server.");
1189 emb_service_register(UNUSED_ARG(PyObject
* self_
), PyObject
* args
) {
1190 struct userNode
* user
;
1193 if (!PyArg_ParseTuple(args
, "s", &user_s
))
1196 if ((user
= GetUserH(user_s
)) == NULL
) {
1197 PyErr_SetString(PyExc_Exception
, "unknown user");
1201 if (user
->uplink
!= self
) {
1202 PyErr_SetString(PyExc_Exception
, "user is not on service server");
1206 return pyobj_from_service(service_register(user
));
1209 size_t logs_size
= 0;
1210 static struct log_type
**logs_list
= NULL
;
1212 PyDoc_STRVAR(emb_log_register_type__doc__
,
1213 "registers a log source to write event data to.");
1214 static PyObject
* emb_log_register_type(UNUSED_ARG(PyObject
*self
), PyObject
* args
) {
1215 const char* logName
;
1216 const char* defaultLog
;
1217 struct log_type
* log
;
1218 struct log_type
** newlogs
;
1220 if (!PyArg_ParseTuple(args
, "ss", &logName
, &defaultLog
))
1223 newlogs
= realloc(logs_list
, (logs_size
+1)*sizeof(struct log_type
*));
1224 if (newlogs
== NULL
) {
1225 PyErr_SetString(PyExc_Exception
, "unable to allocate memory for log structures. aborting.");
1228 logs_list
= newlogs
;
1230 log
= log_register_type(logName
, defaultLog
);
1232 PyErr_SetString(PyExc_Exception
, "unable to register log");
1236 logs_list
[logs_size
++] = log
;
1238 return Py_BuildValue("O", PyCObject_FromVoidPtr(log
, NULL
));
1241 PyDoc_STRVAR(emb_module_register__doc__
, "registers a module");
1242 PyObject
* emb_module_register(UNUSED_ARG(PyObject
* self
), PyObject
* args
) {
1244 char const *name
, *helpfile
;
1245 struct log_type
* log
;
1248 if (!PyArg_ParseTuple(args
, "sOs", &name
, &pylog
, &helpfile
))
1251 log
= PyCObject_AsVoidPtr(pylog
);
1253 mod
= module_register(name
, log
, helpfile
, NULL
);
1256 PyErr_SetString(PyExc_Exception
, "unable to register module");
1260 return Py_BuildValue("O", PyCObject_FromVoidPtr(mod
, NULL
));
1263 static PyMethodDef EmbMethods
[] = {
1264 /* Communication methods */
1265 {"dump", emb_dump
, METH_VARARGS
, emb_dump__doc__
},
1266 {"send_target_privmsg", emb_send_target_privmsg
, METH_VARARGS
, emb_send_target_privmsg__doc__
},
1267 {"send_target_notice", emb_send_target_notice
, METH_VARARGS
, emb_send_target_notice__doc__
},
1268 {"log_module", emb_log_module
, METH_VARARGS
, emb_log_module__doc__
},
1269 //TODO: {"exec_cmd", emb_exec_cmd, METH_VARARGS, "execute x3 command provided"},
1270 // This should use environment from "python command" call to pass in, if available
1271 {"kill", emb_kill
, METH_VARARGS
, emb_kill__doc__
},
1272 {"fakehost", emb_fakehost
, METH_VARARGS
, emb_fakehost__doc__
},
1273 {"svsnick", emb_svsnick
, METH_VARARGS
, emb_svsnick__doc__
},
1274 {"svsquit", emb_svsquit
, METH_VARARGS
, emb_svsquit__doc__
},
1275 {"svsjoin", emb_svsjoin
, METH_VARARGS
, emb_svsjoin__doc__
},
1276 {"adduser", emb_adduser
, METH_VARARGS
, emb_adduser__doc__
},
1277 {"service_register", emb_service_register
, METH_VARARGS
, emb_service_register__doc__
},
1278 //TODO: svsmode, svsident, nick, quit, join, part, ident, vhost
1281 //TODO: {"gline", emb_gline, METH_VARARGS, "gline a mask"},
1282 //TODO: {"ungline", emb_ungline, METH_VARARGS, "remove a gline"},
1283 {"kick", emb_kick
, METH_VARARGS
, emb_kick__doc__
},
1284 {"channel_mode", emb_channel_mode
, METH_VARARGS
, emb_channel_mode__doc__
},
1285 {"user_mode", emb_user_mode
, METH_VARARGS
, emb_user_mode__doc__
},
1287 {"get_config", emb_get_config
, METH_VARARGS
, emb_get_config__doc__
},
1288 //TODO: {"config_set", emb_config_set, METH_VARARGS, "change a config setting 'on-the-fly'."},
1290 {"timeq_add", emb_timeq_add
, METH_VARARGS
, emb_timeq_add__doc__
},
1291 {"timeq_del", emb_timeq_del
, METH_VARARGS
, emb_timeq_del__doc__
},
1293 /* module registration methods */
1294 {"log_register_type", emb_log_register_type
, METH_VARARGS
,
1295 emb_log_register_type__doc__
},
1296 {"module_register", emb_module_register
, METH_VARARGS
,
1297 emb_module_register__doc__
},
1299 /* Information gathering methods */
1300 {"get_user", emb_get_user
, METH_VARARGS
, emb_get_user__doc__
},
1301 {"get_users", emb_get_users
, METH_VARARGS
, emb_get_users__doc__
},
1302 {"get_channel", emb_get_channel
, METH_VARARGS
, emb_get_channel__doc__
},
1303 {"get_channels", emb_get_channels
, METH_VARARGS
, emb_get_channels__doc__
},
1304 {"get_server", emb_get_server
, METH_VARARGS
, emb_get_server__doc__
},
1305 {"get_servers", emb_get_servers
, METH_VARARGS
, emb_get_servers__doc__
},
1306 {"get_account", emb_get_account
, METH_VARARGS
, emb_get_account__doc__
},
1307 {"get_accounts", emb_get_accounts
, METH_VARARGS
, emb_get_accounts__doc__
},
1308 {"get_info", emb_get_info
, METH_VARARGS
, emb_get_info__doc__
},
1309 /* null terminator */
1310 {NULL
, NULL
, 0, NULL
}
1315 These functions set up the embedded environment for us to call out to
1316 modpython.py class methods.
1319 void python_log_module() {
1320 /* Attempt to convert python errors to x3 log system */
1321 PyObject
*exc
, *tb
, *value
, *tmp
;
1322 char *str_exc
= "NONE";
1323 char *str_value
= "NONE";
1324 char *str_tb
= "NONE";
1326 PyErr_Fetch(&exc
, &value
, &tb
);
1329 if((tmp
= PyObject_Str(exc
)))
1330 str_exc
= PyString_AsString(tmp
);
1333 if((tmp
= PyObject_Str(value
)))
1334 str_value
= PyString_AsString(tmp
);
1337 if((tmp
= PyObject_Str(tb
)))
1338 str_tb
= PyString_AsString(tmp
);
1341 /* Now restore it so we can print it (just in case)
1342 * (should we do this only when running in debug mode?) */
1343 PyErr_Restore(exc
, value
, tb
);
1344 PyErr_Print(); /* which of course, clears it again.. */
1346 log_module(PY_LOG
, LOG_WARNING
, "PYTHON error: %s, value: %s", str_exc
, str_value
);
1348 /* TODO: get the traceback using the traceback module via C api so we can add it to the X3 logs. See
1349 * http://mail.python.org/pipermail/python-list/2003-March/192226.html */
1350 // (this doesnt work, str_tb is just an object hashid) log_module(PY_LOG, LOG_INFO, "PYTHON error, traceback: %s", str_tb);
1354 PyObject
*python_build_handler_args(size_t argc
, char *args
[], PyObject
*pIrcObj
) {
1355 /* Sets up a python tuple with passed in arguments, prefixed by the Irc instance
1356 which handlers use to interact with C.
1357 argc = number of args
1358 args = array of args
1359 pIrcObj = instance of the irc class
1362 PyObject
*pArgs
= NULL
;
1364 pArgs
= PyTuple_New(argc
+ 1);
1366 PyTuple_SetItem(pArgs
, i
++, pIrcObj
);
1370 for(n
= 0; n
< argc
; ++n
) {
1371 pValue
= PyString_FromString(args
[n
]);
1374 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[n
]);
1377 PyTuple_SetItem(pArgs
, n
+i
, pValue
);
1383 PyObject
*python_build_args(size_t argc
, char *args
[]) {
1384 /* Builds the passed in arguments into a python argument tuple.
1385 argc = number of args
1386 args = array of args
1389 PyObject
*pArgs
= NULL
;
1392 pArgs
= PyTuple_New(argc
);
1394 for(i
= 0; i
< argc
; ++i
) {
1395 pValue
= PyString_FromString(args
[i
]);
1398 log_module(PY_LOG
, LOG_INFO
, "Unable to convert '%s' to python string", args
[i
]);
1401 PyTuple_SetItem(pArgs
, i
, pValue
);
1408 PyObject
*new_irc_object(char *command_service
, char *command_caller
, char *command_target
) {
1409 /* Creates a new instance of the irc class (from modpython.py) which is initalized
1410 with current environment details like which service were talking to.
1411 command_service = which service we are talking to, or empty string if none
1412 command_caller = nick of user generating message, or empty string if none
1413 command_target = If were reacting to something on a channel, this will
1414 be set to the name of the channel. Otherwise empty
1416 PyObject
*pIrcArgs
= NULL
;
1417 PyObject
*pIrcClass
;
1420 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate irc class; %s %s %s", command_service
, command_caller
, command_target
);
1421 pIrcClass
= PyObject_GetAttrString(base_module
, "irc");
1422 /* pIrcClass is a new reference */
1423 if(pIrcClass
&& PyCallable_Check(pIrcClass
)) {
1425 char *ircargs
[] = {command_service
, command_caller
, command_target
};
1428 pIrcArgs
= python_build_args(3, ircargs
);
1429 pIrcObj
= PyObject_CallObject(pIrcClass
, pIrcArgs
);
1431 log_module(PY_LOG
, LOG_ERROR
, "IRC Class failed to load");
1432 python_log_module();
1435 if(pIrcArgs
!= NULL
) {
1436 Py_DECREF(pIrcArgs
);
1438 Py_DECREF(pIrcClass
);
1442 /* need to free pIrcClass here if it WAS found but was NOT callable? */
1443 log_module(PY_LOG
, LOG_ERROR
, "Unable to find irc class");
1448 int python_call_handler(char *handler
, char *args
[], size_t argc
, char *command_service
, char *command_caller
, char *command_target
) {
1449 /* This is how we talk to modpython.c. First a new instance of the irc class is created using these
1450 arguments to setup the current environment. Then the named method of the handler object is called
1451 with the givin arguments.
1458 log_module(PY_LOG
, LOG_INFO
, "attempting to call handler %s.", handler
);
1459 if(base_module
!= NULL
&& handler_object
!= NULL
) {
1460 pIrcObj
= new_irc_object(command_service
, command_caller
, command_target
);
1462 log_module(PY_LOG
, LOG_INFO
, "Can't get irc object. Bailing.");
1466 pArgs
= python_build_handler_args(argc
, args
, pIrcObj
);
1467 pMethod
= PyObject_GetAttrString(handler_object
, handler
);
1468 if(pMethod
&& PyCallable_Check(pMethod
)) {
1469 /* Call the method, with the arguments */
1470 pValue
= PyObject_CallObject(pMethod
, pArgs
);
1474 if(pValue
!= NULL
) {
1476 ret
= PyInt_AsLong(pValue
);
1477 if(ret
== -1 && PyErr_Occurred()) {
1479 log_module(PY_LOG
, LOG_INFO
, "error converting return value of handler %s to type long. ", handler
);
1480 python_log_module();
1483 log_module(PY_LOG
, LOG_INFO
, "handler %s was run successfully, returned %d.", handler
, ret
);
1490 /* TODO: instead of print errors, get them as strings
1491 * and deal with them with normal x3 log system. */
1492 log_module(PY_LOG
, LOG_WARNING
, "call to handler %s failed", handler
);
1494 python_log_module();
1500 else { /* couldn't find handler methed */
1502 /* Free pMethod if it was found but not callable? */
1503 log_module(PY_LOG
, LOG_ERROR
, "Cannot find handler %s.", handler
);
1508 else { /* No base module.. no python? */
1509 log_module(PY_LOG
, LOG_INFO
, "Cannot handle %s, Python is not initialized.", handler
);
1514 PyObject
*python_new_handler_object() {
1515 /* Create a new instance of the handler class.
1516 This is called during python initilization (or reload)
1517 and the result is saved and re-used.
1519 PyObject
*pHandlerClass
, *pHandlerObj
;
1521 log_module(PY_LOG
, LOG_INFO
, "Attempting to instanciate python class handler");
1522 pHandlerClass
= PyObject_GetAttrString(base_module
, "handler");
1523 /* Class is a new reference */
1524 if(pHandlerClass
&& PyCallable_Check(pHandlerClass
)) {
1525 /*PyObject *pValue; */
1527 pHandlerObj
= PyObject_CallObject(pHandlerClass
, NULL
);
1528 if(pHandlerObj
!= NULL
) {
1529 log_module(PY_LOG
, LOG_INFO
, "Created new python handler object.");
1533 log_module(PY_LOG
, LOG_ERROR
, "Unable to instanciate handler object");
1535 python_log_module();
1540 log_module(PY_LOG
, LOG_ERROR
, "Unable to find handler class");
1542 python_log_module();
1544 Py_DECREF(pHandlerClass
);
1550 /* ------------------------------------------------------------------------------- *
1551 Some gateway functions to convert x3 callbacks into modpython.py callbacks.
1552 Mostly we just build relevant args and call the proper handler method
1554 debate: do we just register these and check them in python
1555 for every one (slow?) or actually work out if a plugin needs
1556 it first? We will start by doing it every time.
1559 python_handle_join(struct modeNode
*mNode
, UNUSED_ARG(void *extra
))
1561 /* callback for handle_join events.
1563 struct userNode
*user
= mNode
->user
;
1564 struct chanNode
*channel
= mNode
->channel
;
1567 log_module(PY_LOG
, LOG_INFO
, "python module handle_join");
1568 if(!channel
||!user
) {
1569 log_module(PY_LOG
, LOG_WARNING
, "Python code got join without channel or user!");
1573 char *args
[] = {channel
->name
, user
->nick
};
1574 return python_call_handler("join", args
, 2, "", "", "");
1579 python_handle_server_link(struct server
*server
, UNUSED_ARG(void *extra
))
1581 PyObject
* srv
= NULL
;
1582 PyObject
* funcname
= NULL
;
1583 PyObject
* retval
= NULL
;
1584 char const* err
= NULL
;
1587 if (handler_object
== NULL
) {
1588 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1592 if (server
== NULL
) {
1593 err
= "Python code got server link without server!";
1597 if ((srv
= pyobj_from_server(server
)) == NULL
) {
1598 err
= "Python code unable to get PyObject with server!";
1602 funcname
= PyString_FromString("server_link");
1603 if (funcname
== NULL
) {
1604 err
= "Unable to allocate memory";
1608 retval
= PyObject_CallMethodObjArgs(handler_object
, funcname
, srv
, NULL
);
1609 if (retval
== NULL
) {
1610 err
= "Error calling server_link handler";
1616 Py_XDECREF(funcname
);
1618 if (retval
!= NULL
&& PyInt_Check(retval
))
1619 i
= (int)PyInt_AsLong(retval
);
1624 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1630 python_handle_new_user(struct userNode
*user
, UNUSED_ARG(void *extra
))
1632 PyObject
* name
= NULL
;
1633 PyObject
* usr
= NULL
;
1634 PyObject
* retval
= NULL
;
1636 const char* err
= NULL
;
1638 if (handler_object
== NULL
) {
1639 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1644 log_module(PY_LOG
, LOG_WARNING
, "Python code got new_user without the user");
1648 if ((usr
= pyobj_from_usernode(user
)) == NULL
) {
1649 err
= "unable to allocate python user information";
1653 name
= PyString_FromString("new_user");
1655 err
= "unable to allocate memory for handler function name";
1659 if ((retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, NULL
)) == NULL
) {
1660 err
= "error calling new_user handler";
1668 if (retval
!= NULL
&& PyInt_Check(retval
))
1669 i
= (int)PyInt_AsLong(retval
);
1674 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1680 python_handle_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
))
1682 PyObject
* usr
= NULL
;
1683 PyObject
* name
= NULL
;
1684 PyObject
* oldnick
= NULL
;
1685 PyObject
* retval
= NULL
;
1686 char const* err
= NULL
;
1688 if (handler_object
== NULL
) {
1689 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1694 err
= "Python code got nick_change without the user!";
1698 if ((usr
= pyobj_from_usernode(user
)) == NULL
) {
1699 err
= "unable to allocate Python usernode";
1703 name
= PyString_FromString("nick_change");
1705 err
= "unable to allocate memory for handler function name";
1709 oldnick
= PyString_FromString(old_nick
);
1711 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, oldnick
, NULL
);
1712 if (retval
== NULL
) {
1713 err
= "error calling nick_change handler";
1720 Py_XDECREF(oldnick
);
1724 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1727 void python_handle_del_user(struct userNode
*user
, struct userNode
*killer
, const char *why
, UNUSED_ARG(void *extra
)) {
1728 PyObject
*usr
= NULL
, *killr
= NULL
, *name
= NULL
;
1729 PyObject
*reason
= NULL
, *retval
= NULL
;
1730 char const* err
= NULL
;
1732 if (handler_object
== NULL
) {
1733 err
= "No Python handler is allocated. Ignoring python_handle_server_link.";
1741 usr
= pyobj_from_usernode(user
);
1743 err
= "unable to allocate usernode for user";
1748 if (killer
== NULL
) {
1752 killr
= pyobj_from_usernode(killer
);
1753 if (killr
== NULL
) {
1754 err
= "unable to allocate usernode for killer";
1763 reason
= PyString_FromString(why
);
1764 if (reason
== NULL
) {
1765 err
= "unable to allocate memory for reason";
1770 name
= PyString_FromString("del_user");
1772 err
= "unable to allocate memory for handler function name";
1776 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, usr
, killr
, reason
, NULL
);
1777 if (retval
== NULL
) {
1778 err
= "error calling del_user handler";
1790 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1793 int python_handle_topic(struct userNode
*who
, struct chanNode
*chan
, const char *old_topic
, UNUSED_ARG(void *extra
)) {
1794 PyObject
* pwho
= NULL
, *pchan
= NULL
, *oldtopic
= NULL
;
1795 PyObject
* name
= NULL
, *retval
= NULL
;
1796 const char* err
= NULL
;
1803 if ((pwho
= pyobj_from_usernode(who
)) == NULL
) {
1804 err
= "unable to allocate usernode";
1809 if ((pchan
= pyobj_from_channode(chan
)) == NULL
) {
1810 err
= "unable to allocate channode";
1814 if (old_topic
== NULL
) {
1818 oldtopic
= PyString_FromString(old_topic
);
1819 if (oldtopic
== NULL
) {
1820 err
= "unable to allocate memory for old topic string";
1825 name
= PyString_FromString("topic");
1827 err
= "unable to allocate memory for topic handler function name";
1831 retval
= PyObject_CallMethodObjArgs(handler_object
, name
, pwho
, pchan
, oldtopic
, NULL
);
1832 if (retval
== NULL
) {
1833 err
= "error calling topic handler";
1840 Py_XDECREF(oldtopic
);
1843 if (retval
!= NULL
&& PyInt_Check(retval
))
1844 i
= (int)PyInt_AsLong(retval
);
1849 log_module(PY_LOG
, LOG_WARNING
, "%s", err
);
1853 /* ----------------------------------------------------------------------------- */
1857 /* Init the python engine and do init work on modpython.py
1858 This is called during x3 startup, and on a python reload
1862 char* env
= getenv("PYTHONPATH");
1868 setenv("PYTHONPATH", modpython_conf
.scripts_dir
, 1);
1869 else if (!strstr(env
, modpython_conf
.scripts_dir
)) {
1870 buffer
= (char*)malloc(strlen(env
) + strlen(modpython_conf
.scripts_dir
) + 2);
1871 sprintf(buffer
, "%s:%s", modpython_conf
.scripts_dir
, env
);
1872 setenv("PYTHONPATH", buffer
, 1);
1878 Py_InitModule("_svc", EmbMethods
);
1879 pName
= PyString_FromString(modpython_conf
.main_module
);
1880 base_module
= PyImport_Import(pName
);
1883 Py_XDECREF(handler_object
);
1884 handler_object
= NULL
;
1886 if(base_module
!= NULL
) {
1887 handler_object
= python_new_handler_object();
1888 if(handler_object
) {
1889 python_call_handler("init", NULL
, 0, "", "", "");
1893 /* error handler class not found */
1894 log_module(PY_LOG
, LOG_WARNING
, "Failed to create handler object");
1900 python_log_module();
1901 log_module(PY_LOG
, LOG_WARNING
, "Failed to load modpython.py");
1908 python_finalize(void) {
1909 /* Called after X3 is fully up and running.
1910 Code can be put here that needs to run to init things, but
1911 which is sensitive to everything else in x3 being up and ready
1915 PyRun_SimpleString("print 'Hello, World of Python!'");
1916 log_module(PY_LOG
, LOG_INFO
, "python module finalize");
1922 python_cleanup(UNUSED_ARG(void *extra
)) {
1923 /* Called on shutdown of the python module (or before reloading)
1926 log_module(PY_LOG
, LOG_INFO
, "python module cleanup");
1928 Py_XDECREF(handler_object
);
1929 handler_object
= NULL
;
1931 if (PyErr_Occurred())
1933 Py_Finalize(); /* Shut down python enterpreter */
1935 log_module(PY_LOG
, LOG_INFO
, "python module cleanup done");
1938 /* ---------------------------------------------------------------------------------- *
1939 Python module command handlers.
1941 static MODCMD_FUNC(cmd_reload
) {
1942 /* reload the python system completely
1944 log_module(PY_LOG
, LOG_INFO
, "Shutting python down");
1945 python_cleanup(NULL
);
1946 log_module(PY_LOG
, LOG_INFO
, "Loading python stuff");
1948 reply("PYMSG_RELOAD_SUCCESS");
1951 reply("PYMSG_RELOAD_FAILED");
1956 static MODCMD_FUNC(cmd_run
) {
1957 /* this method allows running arbitrary python commands.
1961 PyObject
* py_main_module
;
1962 PyObject
* py_globals
;
1963 PyObject
* py_locals
;
1964 PyObject
* py_retval
;
1965 PyObject
* extype
, *exvalue
, *extraceback
;
1966 PyObject
* exvaluestr
= NULL
;
1967 char* exmsg
= NULL
, *exmsgptr
;
1969 py_main_module
= PyImport_AddModule("__main__");
1970 py_globals
= py_locals
= PyModule_GetDict(py_main_module
);
1972 msg
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
1974 py_retval
= PyRun_String(msg
, Py_file_input
, py_globals
, py_locals
);
1975 if (py_retval
== NULL
) {
1976 PyErr_Fetch(&extype
, &exvalue
, &extraceback
);
1977 if (exvalue
!= NULL
) {
1978 exvaluestr
= PyObject_Str(exvalue
);
1979 exmsg
= strdup(PyString_AS_STRING(exvaluestr
));
1981 while (exmsgptr
&& *exmsgptr
) {
1982 if (*exmsgptr
== '\n' || *exmsgptr
== '\r' || *exmsgptr
== '\t')
1987 if (extype
!= NULL
&& exvalue
!= NULL
&& PyType_Check(extype
)) {
1988 reply("PYMSG_RUN_EXCEPTION", ((PyTypeObject
*)extype
)->tp_name
, exmsg
);
1990 reply("PYMSG_RUN_UNKNOWN_EXCEPTION");
1994 if (exvalue
!= NULL
)
1996 if (extraceback
!= NULL
)
1997 Py_DECREF(extraceback
);
1998 if (exvaluestr
!= NULL
)
1999 Py_DECREF(exvaluestr
);
2003 Py_DECREF(py_retval
);
2009 #define numstrargs(X) sizeof(X) / sizeof(*X)
2010 static MODCMD_FUNC(cmd_command
) {
2011 char *plugin
= argv
[1];
2012 char *command
= argv
[2];
2013 char *msg
; /* args */
2015 msg
= unsplit_string(argv
+ 3, argc
- 3, NULL
);
2020 char *args
[] = {plugin
, command
, msg
};
2021 python_call_handler("cmd_command", args
, numstrargs(args
), cmd
->parent
->bot
->nick
, user
?user
->nick
:"", channel
?channel
->name
:"");
2025 static void modpython_conf_read(void) {
2029 if (!(conf_node
= conf_get_data(MODPYTHON_CONF_NAME
, RECDB_OBJECT
))) {
2030 log_module(PY_LOG
, LOG_ERROR
, "config node '%s' is missing or has wrong type", MODPYTHON_CONF_NAME
);
2034 str
= database_get_data(conf_node
, "scripts_dir", RECDB_QSTRING
);
2035 modpython_conf
.scripts_dir
= strdup(str
? str
: "./");
2037 str
= database_get_data(conf_node
, "main_module", RECDB_QSTRING
);
2038 modpython_conf
.main_module
= strdup(str
? str
: "modpython");
2041 int python_init(void) {
2042 /* X3 calls this function on init of the module during startup. We use it to
2043 do all our setup tasks and bindings
2046 //PY_LOG = log_register_type("Python", "file:python.log");
2047 python_module
= module_register("python", PY_LOG
, "mod-python.help", NULL
);
2048 conf_register_reload(modpython_conf_read
);
2050 log_module(PY_LOG
, LOG_INFO
, "python module init");
2051 message_register_table(msgtab
);
2054 reg_auth_func(python_check_messages);
2055 reg_handle_rename_func(python_rename_account);
2056 reg_unreg_func(python_unreg_account);
2057 conf_register_reload(python_conf_read);
2058 saxdb_register("python", python_saxdb_read, python_saxdb_write);
2059 modcmd_register(python_module, "send", cmd_send, 3, MODCMD_REQUIRE_AUTHED, NULL);
2061 modcmd_register(python_module
, "reload", cmd_reload
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
2062 modcmd_register(python_module
, "run", cmd_run
, 2, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
2063 // modcmd_register(python_module, "command", cmd_command, 3, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL);
2065 // Please help us by implementing any of the callbacks listed as TODO below. They already exist
2066 // in x3, they just need handle_ bridges implemented. (see python_handle_join for an example)
2067 reg_server_link_func(python_handle_server_link
, NULL
);
2068 reg_new_user_func(python_handle_new_user
, NULL
);
2069 reg_nick_change_func(python_handle_nick_change
, NULL
);
2070 reg_del_user_func(python_handle_del_user
, NULL
);
2071 //TODO: reg_account_func(python_handle_account); /* stamping of account name to the ircd */
2072 //TODO: reg_handle_rename_func(python_handle_handle_rename); /* handle used to ALSO mean account name */
2073 //TODO: reg_failpw_func(python_handle_failpw);
2074 //TODO: reg_allowauth_func(python_handle_allowauth);
2075 //TODO: reg_handle_merge_func(python_handle_merge);
2077 //TODO: reg_oper_func(python_handle_oper);
2078 //TODO: reg_new_channel_func(python_handle_new_channel);
2079 reg_join_func(python_handle_join
, NULL
);
2080 //TODO: reg_del_channel_func(python_handle_del_channel);
2081 //TODO: reg_part_func(python_handle_part);
2082 //TODO: reg_kick_func(python_handle_kick);
2083 reg_topic_func(python_handle_topic
, NULL
);
2084 //TODO: reg_channel_mode_func(python_handle_channel_mode);
2086 //TODO: reg_privmsg_func(python_handle_privmsg);
2087 //TODO: reg_notice_func
2088 //TODO: reg_svccmd_unbind_func(python_handle_svccmd_unbind);
2089 //TODO: reg_chanmsg_func(python_handle_chanmsg);
2090 //TODO: reg_allchanmsg_func
2091 //TODO: reg_user_mode_func
2093 reg_exit_func(python_cleanup
, NULL
);
2099 #endif /* WITH_PYTHON */