summaryrefslogtreecommitdiffstats
path: root/src/perl/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/perl/common')
-rw-r--r--src/perl/common/Channel.xs117
-rw-r--r--src/perl/common/Core.xs750
-rw-r--r--src/perl/common/Expando.xs181
-rw-r--r--src/perl/common/Ignore.xs74
-rw-r--r--src/perl/common/Irssi.pm171
-rw-r--r--src/perl/common/Irssi.xs44
-rw-r--r--src/perl/common/Log.xs69
-rw-r--r--src/perl/common/Makefile.PL.in7
-rw-r--r--src/perl/common/Masks.xs62
-rw-r--r--src/perl/common/Query.xs58
-rw-r--r--src/perl/common/Rawlog.xs59
-rw-r--r--src/perl/common/Server.xs119
-rw-r--r--src/perl/common/Settings.xs215
-rw-r--r--src/perl/common/meson.build40
-rw-r--r--src/perl/common/module.h45
-rw-r--r--src/perl/common/typemap32
16 files changed, 2043 insertions, 0 deletions
diff --git a/src/perl/common/Channel.xs b/src/perl/common/Channel.xs
new file mode 100644
index 0000000..69141c7
--- /dev/null
+++ b/src/perl/common/Channel.xs
@@ -0,0 +1,117 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+MODULE = Irssi::Channel PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+channels()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = channels; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(iobject_bless((CHANNEL_REC *) tmp->data)));
+ }
+
+Irssi::Channel
+channel_find(channel)
+ char *channel
+CODE:
+ RETVAL = channel_find(NULL, channel);
+OUTPUT:
+ RETVAL
+
+#*******************************
+MODULE = Irssi::Channel PACKAGE = Irssi::Server
+#*******************************
+
+void
+channels(server)
+ Irssi::Server server
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(iobject_bless((CHANNEL_REC *) tmp->data)));
+ }
+
+void
+channels_join(server, channels, automatic)
+ Irssi::Server server
+ char *channels
+ int automatic
+CODE:
+ server->channels_join(server, channels, automatic);
+
+Irssi::Channel
+channel_find(server, name)
+ Irssi::Server server
+ char *name
+
+void
+nicks_get_same(server, nick)
+ Irssi::Server server
+ char *nick
+PREINIT:
+ GSList *list, *tmp;
+PPCODE:
+ list = nicklist_get_same(server, nick);
+
+ for (tmp = list; tmp != NULL; tmp = tmp->next->next) {
+ XPUSHs(sv_2mortal(iobject_bless((CHANNEL_REC *) tmp->data)));
+ XPUSHs(sv_2mortal(iobject_bless((NICK_REC *) tmp->next->data)));
+ }
+ g_slist_free(list);
+
+#*******************************
+MODULE = Irssi::Channel PACKAGE = Irssi::Channel PREFIX = channel_
+#*******************************
+
+void
+channel_destroy(channel)
+ Irssi::Channel channel
+
+void
+nick_insert(channel, nick)
+ Irssi::Channel channel
+ Irssi::Nick nick
+CODE:
+ nicklist_insert(channel, nick);
+
+void
+nick_remove(channel, nick)
+ Irssi::Channel channel
+ Irssi::Nick nick
+CODE:
+ nicklist_remove(channel, nick);
+
+Irssi::Nick
+nick_find(channel, nick)
+ Irssi::Channel channel
+ char *nick
+CODE:
+ RETVAL = nicklist_find(channel, nick);
+OUTPUT:
+ RETVAL
+
+Irssi::Nick
+nick_find_mask(channel, mask)
+ Irssi::Channel channel
+ char *mask
+CODE:
+ RETVAL = nicklist_find_mask(channel, mask);
+OUTPUT:
+ RETVAL
+
+void
+nicks(channel)
+ Irssi::Channel channel
+PREINIT:
+ GSList *list, *tmp;
+PPCODE:
+ list = nicklist_getnicks(channel);
+
+ for (tmp = list; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(iobject_bless((NICK_REC *) tmp->data)));
+ }
+ g_slist_free(list);
diff --git a/src/perl/common/Core.xs b/src/perl/common/Core.xs
new file mode 100644
index 0000000..9e582a7
--- /dev/null
+++ b/src/perl/common/Core.xs
@@ -0,0 +1,750 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+#include <irssi/irssi-version.h>
+#include <irssi/src/core/core.h>
+#include <irssi/src/core/utf8.h>
+#include <irssi/src/core/recode.h>
+
+#include <irssi/src/core/pidwait.h>
+#include <irssi/src/core/session.h>
+
+#define DEFAULT_COMMAND_CATEGORY "Perl scripts' commands"
+
+static void perl_signal_add_hash(int priority, SV *sv)
+{
+ HV *hv;
+ HE *he;
+ I32 len;
+
+ if (!is_hvref(sv))
+ croak("Usage: Irssi::signal_add(hash)");
+
+ hv = hvref(sv);
+ hv_iterinit(hv);
+ while ((he = hv_iternext(hv)) != NULL)
+ perl_signal_add_full(hv_iterkey(he, &len), HeVAL(he), priority);
+}
+
+static void perl_command_bind_add_hash(int priority, SV *sv, char *category)
+{
+ HV *hv;
+ HE *he;
+ I32 len;
+
+ hv = hvref(sv);
+ hv_iterinit(hv);
+ while ((he = hv_iternext(hv)) != NULL)
+ perl_command_bind_to(hv_iterkey(he, &len), category, HeVAL(he), priority);
+}
+
+static void handle_command_bind(int priority, int items, SV *p0, SV *p1, SV *p2)
+{
+ char *category;
+ int hash;
+
+ hash = items > 0 && is_hvref(p0);
+ if (!hash) {
+ if (items < 2 || items > 3)
+ croak("Usage: Irssi::command_bind(signal, func, category)");
+ } else if (items > 2)
+ croak("Usage: Irssi::command_bind(signals_hash, category)");
+
+ if (!hash) {
+ category = items < 3 ? DEFAULT_COMMAND_CATEGORY :
+ SvPV_nolen(p2);
+ perl_command_bind_to(SvPV_nolen(p0), category, p1, priority);
+ } else {
+ category = items < 2 ? DEFAULT_COMMAND_CATEGORY :
+ SvPV_nolen(p1);
+ perl_command_bind_add_hash(priority, p0, category);
+ }
+}
+
+static void add_tuple(gpointer key_, gpointer value_, gpointer user_data)
+{
+ HV *hash = user_data;
+ char *key = key_;
+ char *value = value_;
+ (void) hv_store(hash, key, strlen(key), new_pv(value), 0);
+}
+
+static void wrap_signal_emit(void *signal, int params, void **p)
+{
+ signal_emit(signal, params, p[0], p[1], p[2], p[3], p[4], p[5]);
+}
+
+static void wrap_signal_continue(void *dummy, int params, void **p)
+{
+ (void)dummy;
+ signal_continue(params, p[0], p[1], p[2], p[3], p[4], p[5]);
+}
+
+MODULE = Irssi::Core PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+signal_emit(signal, ...)
+ char *signal
+CODE:
+ int signal_id;
+
+ signal_id = signal_get_uniq_id(signal);
+ perl_signal_args_to_c(wrap_signal_emit, signal, signal_id, &ST(1), items - 1);
+
+void
+signal_continue(...)
+CODE:
+ perl_signal_args_to_c(wrap_signal_continue, NULL, signal_get_emitted_id(), &ST(0), items);
+
+void
+signal_add(...)
+CODE:
+ if (items != 1 && items != 2)
+ croak("Usage: Irssi::signal_add(signal, func)");
+ if (items == 2)
+ perl_signal_add_full(SvPV_nolen(ST(0)), ST(1),
+ SIGNAL_PRIORITY_DEFAULT);
+ else
+ perl_signal_add_hash(SIGNAL_PRIORITY_DEFAULT, ST(0));
+
+void
+signal_add_first(...)
+CODE:
+ if (items != 1 && items != 2)
+ croak("Usage: Irssi::signal_add_first(signal, func)");
+ if (items == 2)
+ perl_signal_add_full(SvPV_nolen(ST(0)), ST(1),
+ SIGNAL_PRIORITY_HIGH);
+ else
+ perl_signal_add_hash(SIGNAL_PRIORITY_HIGH, ST(0));
+
+void
+signal_add_last(...)
+CODE:
+ if (items != 1 && items != 2)
+ croak("Usage: Irssi::signal_add_last(signal, func)");
+ if (items == 2)
+ perl_signal_add_full(SvPV_nolen(ST(0)), ST(1),
+ SIGNAL_PRIORITY_LOW);
+ else
+ perl_signal_add_hash(SIGNAL_PRIORITY_LOW, ST(0));
+
+void
+signal_add_priority(...)
+CODE:
+ if (items != 2 && items != 3)
+ croak("Usage: Irssi::signal_add_priority(signal, func, priority)");
+ if (items == 3)
+ perl_signal_add_full(SvPV_nolen(ST(0)), ST(1), SvIV(ST(2)));
+ else
+ perl_signal_add_hash(SvIV(ST(0)), ST(1));
+
+void
+signal_register(...)
+PREINIT:
+ HV *hv;
+ HE *he;
+ I32 len, pos;
+ const char *arr[SIGNAL_MAX_ARGUMENTS + 1];
+CODE:
+ if (items != 1 || !is_hvref(ST(0)))
+ croak("Usage: Irssi::signal_register(hash)");
+
+ hv = hvref(ST(0));
+ hv_iterinit(hv);
+ while ((he = hv_iternext(hv)) != NULL) {
+ const char *key = hv_iterkey(he, &len);
+ SV *val = HeVAL(he);
+ AV *av;
+
+ if (!SvROK(val) || SvTYPE(SvRV(val)) != SVt_PVAV)
+ croak("not array reference");
+
+ av = (AV *) SvRV(val);
+ len = av_len(av)+1;
+ if (len > SIGNAL_MAX_ARGUMENTS)
+ len = SIGNAL_MAX_ARGUMENTS;
+ for (pos = 0; pos < len; pos++) {
+ SV **val = av_fetch(av, pos, 0);
+ arr[pos] = SvPV_nolen(*val);
+ }
+ arr[pos] = NULL;
+ perl_signal_register(key, arr);
+ }
+
+
+int
+SIGNAL_PRIORITY_LOW()
+CODE:
+ RETVAL = SIGNAL_PRIORITY_LOW;
+OUTPUT:
+ RETVAL
+
+int
+SIGNAL_PRIORITY_DEFAULT()
+CODE:
+ RETVAL = SIGNAL_PRIORITY_DEFAULT;
+OUTPUT:
+ RETVAL
+
+int
+SIGNAL_PRIORITY_HIGH()
+CODE:
+ RETVAL = SIGNAL_PRIORITY_HIGH;
+OUTPUT:
+ RETVAL
+
+void
+signal_remove(signal, func)
+ char *signal
+ SV *func
+CODE:
+ perl_signal_remove(signal, func);
+
+void
+signal_stop()
+
+void
+signal_stop_by_name(signal)
+ char *signal
+
+char *
+signal_get_emitted()
+CODE:
+ RETVAL = (char *) signal_get_emitted();
+OUTPUT:
+ RETVAL
+
+int
+signal_get_emitted_id()
+
+int
+timeout_add(msecs, func, data)
+ int msecs
+ SV *func
+ SV *data
+CODE:
+ if (msecs < 10) {
+ croak("Irssi::timeout() : msecs must be >= 10");
+ RETVAL = -1;
+ } else {
+ RETVAL = perl_timeout_add(msecs, func, data, FALSE);
+ }
+OUTPUT:
+ RETVAL
+
+int
+timeout_add_once(msecs, func, data)
+ int msecs
+ SV *func
+ SV *data
+CODE:
+ if (msecs < 10) {
+ croak("Irssi::timeout_once() : msecs must be >= 10");
+ RETVAL = -1;
+ } else {
+ RETVAL = perl_timeout_add(msecs, func, data, TRUE);
+ }
+OUTPUT:
+ RETVAL
+
+void
+timeout_remove(tag)
+ int tag
+CODE:
+ perl_source_remove(tag);
+
+
+int
+INPUT_READ()
+CODE:
+ RETVAL = I_INPUT_READ;
+OUTPUT:
+ RETVAL
+
+int
+INPUT_WRITE()
+CODE:
+ RETVAL = I_INPUT_WRITE;
+OUTPUT:
+ RETVAL
+
+int
+input_add(source, condition, func, data)
+ int source
+ int condition
+ SV *func
+ SV *data
+CODE:
+ RETVAL = perl_input_add(source, condition, func, data, FALSE);
+OUTPUT:
+ RETVAL
+
+void
+input_remove(tag)
+ int tag
+CODE:
+ perl_source_remove(tag);
+
+# maybe there's some easier way than this..? :)
+int
+MSGLEVEL_HIDDEN()
+CODE:
+ RETVAL = MSGLEVEL_HIDDEN;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_CRAP()
+CODE:
+ RETVAL = MSGLEVEL_CRAP;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_MSGS()
+CODE:
+ RETVAL = MSGLEVEL_MSGS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_PUBLIC()
+CODE:
+ RETVAL = MSGLEVEL_PUBLIC;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_NOTICES()
+CODE:
+ RETVAL = MSGLEVEL_NOTICES;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_SNOTES()
+CODE:
+ RETVAL = MSGLEVEL_SNOTES;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_CTCPS()
+CODE:
+ RETVAL = MSGLEVEL_CTCPS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_ACTIONS()
+CODE:
+ RETVAL = MSGLEVEL_ACTIONS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_JOINS()
+CODE:
+ RETVAL = MSGLEVEL_JOINS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_PARTS()
+CODE:
+ RETVAL = MSGLEVEL_PARTS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_QUITS()
+CODE:
+ RETVAL = MSGLEVEL_QUITS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_KICKS()
+CODE:
+ RETVAL = MSGLEVEL_KICKS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_MODES()
+CODE:
+ RETVAL = MSGLEVEL_MODES;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_TOPICS()
+CODE:
+ RETVAL = MSGLEVEL_TOPICS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_WALLOPS()
+CODE:
+ RETVAL = MSGLEVEL_WALLOPS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_INVITES()
+CODE:
+ RETVAL = MSGLEVEL_INVITES;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_NICKS()
+CODE:
+ RETVAL = MSGLEVEL_NICKS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_DCC()
+CODE:
+ RETVAL = MSGLEVEL_DCC;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_DCCMSGS()
+CODE:
+ RETVAL = MSGLEVEL_DCCMSGS;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_CLIENTNOTICE()
+CODE:
+ RETVAL = MSGLEVEL_CLIENTNOTICE;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_CLIENTCRAP()
+CODE:
+ RETVAL = MSGLEVEL_CLIENTCRAP;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_CLIENTERROR()
+CODE:
+ RETVAL = MSGLEVEL_CLIENTERROR;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_HILIGHT()
+CODE:
+ RETVAL = MSGLEVEL_HILIGHT;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_ALL()
+CODE:
+ RETVAL = MSGLEVEL_ALL;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_NOHILIGHT()
+CODE:
+ RETVAL = MSGLEVEL_NOHILIGHT;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_NO_ACT()
+CODE:
+ RETVAL = MSGLEVEL_NO_ACT;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_NEVER()
+CODE:
+ RETVAL = MSGLEVEL_NEVER;
+OUTPUT:
+ RETVAL
+
+int
+MSGLEVEL_LASTLOG()
+CODE:
+ RETVAL = MSGLEVEL_LASTLOG;
+OUTPUT:
+ RETVAL
+
+int
+level2bits(str)
+ char *str
+CODE:
+ RETVAL = level2bits(str, NULL);
+OUTPUT:
+ RETVAL
+
+void
+bits2level(bits)
+ int bits
+PREINIT:
+ char *ret;
+PPCODE:
+ ret = bits2level(bits);
+ XPUSHs(sv_2mortal(new_pv(ret)));
+ g_free(ret);
+
+int
+combine_level(level, str)
+ int level
+ char *str
+
+void
+command(cmd)
+ char *cmd
+CODE:
+ perl_command(cmd, NULL, NULL);
+
+void
+commands()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = commands; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(plain_bless(tmp->data, "Irssi::Command")));
+ }
+
+void
+command_bind_first(...)
+CODE:
+ handle_command_bind(SIGNAL_PRIORITY_HIGH, items, ST(0), ST(1), ST(2));
+
+void
+command_bind(...)
+CODE:
+ handle_command_bind(SIGNAL_PRIORITY_DEFAULT, items, ST(0), ST(1), ST(2));
+
+void
+command_bind_last(...)
+CODE:
+ handle_command_bind(SIGNAL_PRIORITY_LOW, items, ST(0), ST(1), ST(2));
+
+void
+command_runsub(cmd, data, server, item)
+ char *cmd
+ char *data
+ Irssi::Server server
+ Irssi::Windowitem item
+CODE:
+ perl_command_runsub(cmd, data, server, item);
+
+void
+command_unbind(cmd, func)
+ char *cmd
+ SV *func
+CODE:
+ perl_command_unbind(cmd, func);
+
+void
+command_set_options(cmd, options)
+ char *cmd
+ char *options
+
+void
+command_parse_options(cmd, data)
+ char *cmd
+ char *data
+PREINIT:
+ HV *hash;
+ GHashTable *optlist;
+ void *free_arg;
+ char *ptr;
+PPCODE:
+ if (cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS | PARAM_FLAG_GETREST,
+ cmd, &optlist, &ptr)) {
+ hash = newHV();
+ g_hash_table_foreach(optlist, add_tuple, hash);
+ XPUSHs(sv_2mortal(newRV_noinc((SV*)hash)));
+ XPUSHs(sv_2mortal(new_pv(ptr)));
+ cmd_params_free(free_arg);
+ } else {
+ XPUSHs(&PL_sv_undef);
+ XPUSHs(&PL_sv_undef);
+ }
+
+void
+pidwait_add(pid)
+ int pid
+
+void
+pidwait_remove(pid)
+ int pid
+
+void
+parse_special(cmd, data="", flags=0)
+ char *cmd
+ char *data
+ int flags
+PREINIT:
+ char *ret;
+PPCODE:
+ ret = parse_special_string(cmd, NULL, NULL, data, NULL, flags);
+ XPUSHs(sv_2mortal(new_pv(ret)));
+ g_free_not_null(ret);
+
+char *
+get_irssi_dir()
+CODE:
+ RETVAL = (char *) get_irssi_dir();
+OUTPUT:
+ RETVAL
+
+char *
+get_irssi_config()
+CODE:
+ RETVAL = (char *) get_irssi_config();
+OUTPUT:
+ RETVAL
+
+char *
+get_irssi_binary()
+CODE:
+ RETVAL = irssi_binary;
+OUTPUT:
+ RETVAL
+
+char *
+version()
+PREINIT:
+ char version[100];
+CODE:
+ g_snprintf(version, sizeof(version), "%d.%04d",
+ IRSSI_VERSION_DATE, IRSSI_VERSION_TIME);
+ RETVAL = version;
+OUTPUT:
+ RETVAL
+
+int
+get_gui()
+CODE:
+ RETVAL = irssi_gui;
+OUTPUT:
+ RETVAL
+
+int
+IRSSI_GUI_NONE()
+CODE:
+ RETVAL = IRSSI_GUI_NONE;
+OUTPUT:
+ RETVAL
+
+int
+IRSSI_GUI_TEXT()
+CODE:
+ RETVAL = IRSSI_GUI_TEXT;
+OUTPUT:
+ RETVAL
+
+int
+IRSSI_GUI_GTK()
+CODE:
+ RETVAL = IRSSI_GUI_GTK;
+OUTPUT:
+ RETVAL
+
+int
+IRSSI_GUI_GNOME()
+CODE:
+ RETVAL = IRSSI_GUI_GNOME;
+OUTPUT:
+ RETVAL
+
+int
+IRSSI_GUI_QT()
+CODE:
+ RETVAL = IRSSI_GUI_QT;
+OUTPUT:
+ RETVAL
+
+int
+IRSSI_GUI_KDE()
+CODE:
+ RETVAL = IRSSI_GUI_KDE;
+OUTPUT:
+ RETVAL
+
+int
+string_width(str)
+ char *str
+C_ARGS:
+ str, is_utf8() ? TREAT_STRING_AS_UTF8 : TREAT_STRING_AS_BYTES
+
+void
+string_chars_for_width(str, width)
+ char *str
+ unsigned int width
+PREINIT:
+ int retval;
+ unsigned int bytes;
+PPCODE:
+ retval = string_chars_for_width(str, is_utf8() ? TREAT_STRING_AS_UTF8 : TREAT_STRING_AS_BYTES, width, &bytes);
+ mXPUSHi(retval);
+ mXPUSHu(bytes);
+
+
+#*******************************
+MODULE = Irssi::Core PACKAGE = Irssi::Server
+#*******************************
+
+void
+parse_special(server, cmd, data="", flags=0)
+ Irssi::Server server
+ char *cmd
+ char *data
+ int flags
+PREINIT:
+ char *ret;
+PPCODE:
+ ret = parse_special_string(cmd, server, NULL, data, NULL, flags);
+ XPUSHs(sv_2mortal(new_pv(ret)));
+ g_free_not_null(ret);
+
+void
+command(server, cmd)
+ Irssi::Server server
+ char *cmd
+CODE:
+ perl_command(cmd, server, NULL);
+
+
+#*******************************
+MODULE = Irssi::Core PACKAGE = Irssi::Windowitem
+#*******************************
+
+void
+parse_special(item, cmd, data="", flags=0)
+ Irssi::Windowitem item
+ char *cmd
+ char *data
+ int flags
+PREINIT:
+ char *ret;
+PPCODE:
+ ret = parse_special_string(cmd, item->server, item, data, NULL, flags);
+ XPUSHs(sv_2mortal(new_pv(ret)));
+ g_free_not_null(ret);
+
+void
+command(item, cmd)
+ Irssi::Windowitem item
+ char *cmd
+CODE:
+ perl_command(cmd, item->server, item);
+
diff --git a/src/perl/common/Expando.xs b/src/perl/common/Expando.xs
new file mode 100644
index 0000000..1dc36d2
--- /dev/null
+++ b/src/perl/common/Expando.xs
@@ -0,0 +1,181 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+#include <irssi/src/core/expandos.h>
+
+typedef struct {
+ PERL_SCRIPT_REC *script;
+ SV *func;
+} PerlExpando;
+
+static GHashTable *perl_expando_defs;
+
+static char *sig_perl_expando(SERVER_REC *server, void *item, int *free_ret);
+
+static int check_expando_destroy(char *key, PerlExpando *rec,
+ PERL_SCRIPT_REC *script)
+{
+ if (rec->script == script) {
+ expando_destroy(key, sig_perl_expando);
+ SvREFCNT_dec(rec->func);
+ g_free(key);
+ g_free(rec);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void script_unregister_expandos(PERL_SCRIPT_REC *script)
+{
+ g_hash_table_foreach_remove(perl_expando_defs,
+ (GHRFunc) check_expando_destroy, script);
+}
+
+void perl_expando_init(void)
+{
+ perl_expando_defs = g_hash_table_new((GHashFunc) g_str_hash,
+ (GCompareFunc) g_str_equal);
+ signal_add("script destroyed", (SIGNAL_FUNC) script_unregister_expandos);
+}
+
+static void expando_def_destroy(char *key, PerlExpando *rec)
+{
+ SvREFCNT_dec(rec->func);
+ g_free(key);
+ g_free(rec);
+}
+
+void perl_expando_deinit(void)
+{
+ signal_remove("script destroyed", (SIGNAL_FUNC) script_unregister_expandos);
+
+ g_hash_table_foreach(perl_expando_defs,
+ (GHFunc) expando_def_destroy, NULL);
+ g_hash_table_destroy(perl_expando_defs);
+}
+
+static char *perl_expando_event(PerlExpando *rec, SERVER_REC *server,
+ WI_ITEM_REC *item, int *free_ret)
+{
+ dSP;
+ char *ret;
+ int retcount;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(iobject_bless(server)));
+ XPUSHs(sv_2mortal(iobject_bless(item)));
+ PUTBACK;
+
+ retcount = perl_call_sv(rec->func, G_EVAL|G_SCALAR);
+ SPAGAIN;
+
+ ret = NULL;
+ if (SvTRUE(ERRSV)) {
+ char *error;
+ PERL_SCRIPT_REC *script = rec->script;
+
+ (void) POPs;
+ /* call putback before emitting script error signal as that
+ * could manipulate the perl stack. */
+ PUTBACK;
+ /* make sure we don't get back here */
+ if (script != NULL)
+ script_unregister_expandos(script);
+ /* rec has been freed now */
+
+ error = g_strdup(SvPV_nolen(ERRSV));
+ signal_emit("script error", 2, script, error);
+ g_free(error);
+ } else if (retcount > 0) {
+ ret = g_strdup(POPp);
+ *free_ret = TRUE;
+ PUTBACK;
+ }
+
+ FREETMPS;
+ LEAVE;
+
+ return ret;
+}
+
+static char *sig_perl_expando(SERVER_REC *server, void *item, int *free_ret)
+{
+ PerlExpando *rec;
+
+ rec = g_hash_table_lookup(perl_expando_defs, current_expando);
+ if (rec != NULL)
+ return perl_expando_event(rec, server, item, free_ret);
+ return NULL;
+}
+
+static void expando_signals_add_hash(const char *key, SV *signals)
+{
+ HV *hv;
+ HE *he;
+ I32 len;
+ const char *argstr;
+ ExpandoArg arg;
+
+ if (!is_hvref(signals)) {
+ croak("Usage: Irssi::expando_create(key, func, hash)");
+ return;
+ }
+
+ hv = hvref(signals);
+ hv_iterinit(hv);
+ while ((he = hv_iternext(hv)) != NULL) {
+ SV *argsv = HeVAL(he);
+ argstr = SvPV_nolen(argsv);
+
+ if (g_ascii_strcasecmp(argstr, "none") == 0)
+ arg = EXPANDO_ARG_NONE;
+ else if (g_ascii_strcasecmp(argstr, "server") == 0)
+ arg = EXPANDO_ARG_SERVER;
+ else if (g_ascii_strcasecmp(argstr, "window") == 0)
+ arg = EXPANDO_ARG_WINDOW;
+ else if (g_ascii_strcasecmp(argstr, "windowitem") == 0)
+ arg = EXPANDO_ARG_WINDOW_ITEM;
+ else if (g_ascii_strcasecmp(argstr, "never") == 0)
+ arg = EXPANDO_NEVER;
+ else {
+ croak("Unknown signal type: %s", argstr);
+ break;
+ }
+ expando_add_signal(key, hv_iterkey(he, &len), arg);
+ }
+}
+
+MODULE = Irssi::Expando PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+expando_create(key, func, signals)
+ char *key
+ SV *func
+ SV *signals
+PREINIT:
+ PerlExpando *rec;
+CODE:
+ rec = g_new0(PerlExpando, 1);
+ rec->script = perl_script_find_package(perl_get_package());
+ rec->func = perl_func_sv_inc(func, perl_get_package());
+
+ expando_create(key, sig_perl_expando, NULL);
+ g_hash_table_insert(perl_expando_defs, g_strdup(key), rec);
+ expando_signals_add_hash(key, signals);
+
+void
+expando_destroy(name)
+ char *name
+PREINIT:
+ gpointer key, value;
+CODE:
+ if (g_hash_table_lookup_extended(perl_expando_defs, name, &key, &value)) {
+ g_hash_table_remove(perl_expando_defs, name);
+ g_free(key);
+ SvREFCNT_dec((SV *) value);
+ }
+ expando_destroy(name, sig_perl_expando);
diff --git a/src/perl/common/Ignore.xs b/src/perl/common/Ignore.xs
new file mode 100644
index 0000000..144497d
--- /dev/null
+++ b/src/perl/common/Ignore.xs
@@ -0,0 +1,74 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+MODULE = Irssi::Ignore PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+ignores()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = ignores; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(plain_bless(tmp->data, "Irssi::Ignore")));
+ }
+
+int
+ignore_check(nick, host, channel, text, level)
+ char *nick
+ char *host
+ char *channel
+ char *text
+ int level
+CODE:
+ RETVAL = ignore_check(NULL, nick, host, channel, text, level);
+OUTPUT:
+ RETVAL
+
+int
+ignore_check_flags(nick, host, channel, text, level, flags)
+ char *nick
+ char *host
+ char *channel
+ char *text
+ int level
+ int flags
+CODE:
+ RETVAL = ignore_check_flags(NULL, nick, host, channel, text, level, flags);
+OUTPUT:
+ RETVAL
+
+#*******************************
+MODULE = Irssi::Ignore PACKAGE = Irssi::Server
+#*******************************
+
+int
+ignore_check(server, nick, host, channel, text, level)
+ Irssi::Server server
+ char *nick
+ char *host
+ char *channel
+ char *text
+ int level
+
+int
+ignore_check_flags(server, nick, host, channel, text, level, flags)
+ Irssi::Server server
+ char *nick
+ char *host
+ char *channel
+ char *text
+ int level
+ int flags
+
+#*******************************
+MODULE = Irssi::Ignore PACKAGE = Irssi::Ignore PREFIX = ignore_
+#*******************************
+
+void
+ignore_add_rec(rec)
+ Irssi::Ignore rec
+
+void
+ignore_update_rec(rec)
+ Irssi::Ignore rec
diff --git a/src/perl/common/Irssi.pm b/src/perl/common/Irssi.pm
new file mode 100644
index 0000000..bca0084
--- /dev/null
+++ b/src/perl/common/Irssi.pm
@@ -0,0 +1,171 @@
+#
+# Perl interface to irssi functions.
+#
+
+package Irssi;
+
+use strict;
+use Carp;
+use vars qw($VERSION $in_irssi @ISA @EXPORT @EXPORT_OK);
+
+# TIEHANDLE methods
+
+sub TIEHANDLE {
+ my ($class, $level, $object, $target) = @_;
+ return bless [ $level, $object, $target ], $class;
+}
+
+sub WRITE {
+ croak "Cannot syswrite() to an Irssi handle"
+}
+
+sub PRINT {
+ my ($self, @list) = @_;
+ if (defined $self->[1]) {
+ if (defined $self->[2]) {
+ $self->[1]->print($self->[2], join('', @list), $self->[0]);
+ } else {
+ $self->[1]->print(join('', @list), $self->[0]);
+ }
+ } else {
+ Irssi::print(join('', @list), $self->[0]);
+ }
+}
+
+sub PRINTF {
+ my ($self, $format, @list) = @_;
+ if (defined $self->[1]) {
+ if (defined $self->[2]) {
+ $self->[1]->print($self->[2], sprintf($format, @list), $self->[0]);
+ } else {
+ $self->[1]->print(sprintf($format, @list), $self->[0]);
+ }
+ } else {
+ Irssi::print(sprintf($format, @list), $self->[0]);
+ }
+}
+
+sub READ {
+ croak "Cannot [sys]read() from an Irssi handle"
+}
+
+sub READLINE {
+ croak "Cannot readline() from an Irssi handle"
+}
+
+sub GETC {
+ croak "Cannot getc() from an Irssi handle"
+}
+
+sub CLOSE {}
+sub UNTIE {}
+sub DESTROY {}
+
+# End of TIEHANDLE methods
+
+# Handle creators
+
+sub create_window_handle {
+ my ($object, $level) = @_;
+ $object = eval 'active_win' unless defined $object;
+ $level = eval 'MSGLEVEL_CLIENTCRAP' unless defined $level;
+ croak 'Usage: create_window_handle([$window[, $level]])'
+ if ref $object !~ /::Window$/i;
+ no strict 'refs';
+ my $symref = 'Irssi::Handles::' . $object . '/' . $level;
+ my $fh = \*{$symref};
+ tie *{$symref}, __PACKAGE__, $level, $object;
+ return $fh;
+}
+
+sub create_server_handle {
+ my ($object, $target, $level) = @_;
+ croak 'Usage: create_server_handle($server, $target[, $level])'
+ if not defined $object
+ or not defined $target
+ or ref $object !~ /::Server$/i;
+ $level = eval 'MSGLEVEL_CLIENTCRAP' unless defined $level;
+ no strict 'refs';
+ my $symref = 'Irssi::Handles::' . $object . '/' . $target . '/' . $level;
+ my $fh = \*{$symref};
+ tie *{$symref}, __PACKAGE__, $level, $object, $target;
+ return $fh;
+}
+
+# Object interface for create_server_handle
+
+sub Irssi::Server::create_handle {
+ goto &Irssi::create_server_handle;
+}
+
+# Normal Irssi.pm stuff
+
+sub VERSION {
+ my $version = $_[1];
+ die "This script requires irssi version $version or later"
+ if ($version > version());
+}
+
+sub EXPORT_ALL () {
+ my %exports = map { $_ => undef } @EXPORT, @EXPORT_OK;
+ no strict 'refs';
+ for (keys %Irssi::) {
+ if (/^MSGLEVEL_/) {
+ (my $short = $_) =~ s///;
+ next if exists $exports{"*$short"};
+ tie *{ $short }, __PACKAGE__, &$_();
+ push @EXPORT, "*$short";
+ } else {
+ next if exists $exports{$_};
+ push @EXPORT_OK, $_ if /[a-z]/ && defined *{$_}{CODE};
+ }
+ }
+
+ tie *DEFAULT, __PACKAGE__, MSGLEVEL_CLIENTCRAP();
+ select DEFAULT;
+}
+
+sub in_irssi {
+ return $in_irssi;
+}
+
+$VERSION = "0.9";
+
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader);
+@EXPORT = qw(INPUT_READ INPUT_WRITE
+ MSGLEVEL_CRAP MSGLEVEL_MSGS MSGLEVEL_PUBLIC MSGLEVEL_NOTICES
+ MSGLEVEL_SNOTES MSGLEVEL_CTCPS MSGLEVEL_ACTIONS MSGLEVEL_JOINS
+ MSGLEVEL_PARTS MSGLEVEL_QUITS MSGLEVEL_KICKS MSGLEVEL_MODES
+ MSGLEVEL_TOPICS MSGLEVEL_WALLOPS MSGLEVEL_INVITES MSGLEVEL_NICKS
+ MSGLEVEL_DCC MSGLEVEL_DCCMSGS MSGLEVEL_CLIENTNOTICE MSGLEVEL_CLIENTCRAP
+ MSGLEVEL_CLIENTERROR MSGLEVEL_HILIGHT MSGLEVEL_ALL MSGLEVEL_NOHILIGHT
+ MSGLEVEL_NO_ACT MSGLEVEL_NEVER MSGLEVEL_LASTLOG MSGLEVEL_HIDDEN
+);
+
+my $static = 0;
+
+eval {
+ $static = Irssi::Core::is_static();
+};
+$in_irssi = $@ ? 0 : 1;
+
+if (!in_irssi()) {
+ print STDERR "Warning: This script should be run inside irssi\n";
+} else {
+ bootstrap Irssi $VERSION if (!$static);
+
+ @Irssi::Channel::ISA = qw(Irssi::Windowitem);
+ @Irssi::Query::ISA = qw(Irssi::Windowitem);
+ @Irssi::UI::Exec::ISA = qw(Irssi::Windowitem);
+ @Irssi::Chatnet::ISA = qw();
+ @Irssi::Nick::ISA = qw();
+
+ Irssi::init();
+
+ Irssi::EXPORT_ALL();
+}
+
+1;
diff --git a/src/perl/common/Irssi.xs b/src/perl/common/Irssi.xs
new file mode 100644
index 0000000..dc354bb
--- /dev/null
+++ b/src/perl/common/Irssi.xs
@@ -0,0 +1,44 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+static int initialized = FALSE;
+
+void perl_expando_init(void);
+void perl_expando_deinit(void);
+
+void perl_settings_init(void);
+void perl_settings_deinit(void);
+
+MODULE = Irssi PACKAGE = Irssi
+
+PROTOTYPES: ENABLE
+
+void
+init()
+CODE:
+ if (initialized) return;
+ perl_api_version_check("Irssi");
+ initialized = TRUE;
+
+ perl_settings_init();
+ perl_expando_init();
+
+void
+deinit()
+CODE:
+ if (!initialized) return;
+ perl_expando_deinit();
+ perl_settings_deinit();
+ initialized = FALSE;
+
+BOOT:
+ irssi_boot(Channel);
+ irssi_boot(Core);
+ irssi_boot(Expando);
+ irssi_boot(Ignore);
+ irssi_boot(Log);
+ irssi_boot(Masks);
+ irssi_boot(Query);
+ irssi_boot(Rawlog);
+ irssi_boot(Server);
+ irssi_boot(Settings);
diff --git a/src/perl/common/Log.xs b/src/perl/common/Log.xs
new file mode 100644
index 0000000..532095f
--- /dev/null
+++ b/src/perl/common/Log.xs
@@ -0,0 +1,69 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+MODULE = Irssi::Log PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+logs()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = logs; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(plain_bless(tmp->data, "Irssi::Log")));
+ }
+
+Irssi::Log
+log_create_rec(fname, level)
+ char *fname
+ int level
+
+Irssi::Log
+log_find(fname)
+ char *fname
+
+#*******************************
+MODULE = Irssi::Log PACKAGE = Irssi::Log PREFIX = log_
+#*******************************
+
+void
+log_item_add(log, type, name, servertag)
+ Irssi::Log log
+ int type
+ char *name
+ char *servertag
+
+void
+log_item_destroy(log, item)
+ Irssi::Log log
+ Irssi::Logitem item
+
+Irssi::Logitem
+log_item_find(log, type, item, servertag)
+ Irssi::Log log
+ int type
+ char *item
+ char *servertag
+
+void
+log_update(log)
+ Irssi::Log log
+
+void
+log_close(log)
+ Irssi::Log log
+
+void
+log_write_rec(log, str, level, now = -1)
+ Irssi::Log log
+ char *str
+ int level
+ time_t now
+
+void
+log_start_logging(log)
+ Irssi::Log log
+
+void
+log_stop_logging(log)
+ Irssi::Log log
diff --git a/src/perl/common/Makefile.PL.in b/src/perl/common/Makefile.PL.in
new file mode 100644
index 0000000..2b087d0
--- /dev/null
+++ b/src/perl/common/Makefile.PL.in
@@ -0,0 +1,7 @@
+use ExtUtils::MakeMaker;our $AM_DEFAULT_VERBOSITY='@AM_DEFAULT_VERBOSITY@';require "@top_srcdir@/src/perl/Makefile_silent.pm";
+
+WriteMakefile('NAME' => 'Irssi',
+ 'LIBS' => '',
+ 'OBJECT' => '$(O_FILES)',
+ 'INC' => '-I../../.. @GLIB_CFLAGS@',
+ 'VERSION_FROM' => '@srcdir@/Irssi.pm');
diff --git a/src/perl/common/Masks.xs b/src/perl/common/Masks.xs
new file mode 100644
index 0000000..9612911
--- /dev/null
+++ b/src/perl/common/Masks.xs
@@ -0,0 +1,62 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+MODULE = Irssi::Masks PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+int
+mask_match(mask, nick, user, host)
+ char *mask
+ char *nick
+ char *user
+ char *host
+CODE:
+ RETVAL = mask_match(NULL, mask, nick, user, host);
+OUTPUT:
+ RETVAL
+
+int
+mask_match_address(mask, nick, address)
+ char *mask
+ char *nick
+ char *address
+CODE:
+ RETVAL = mask_match_address(NULL, mask, nick, address);
+OUTPUT:
+ RETVAL
+
+int
+masks_match(masks, nick, address)
+ char *masks
+ char *nick
+ char *address
+CODE:
+ RETVAL = masks_match(NULL, masks, nick, address);
+OUTPUT:
+ RETVAL
+
+#*******************************
+MODULE = Irssi::Masks PACKAGE = Irssi::Server
+#*******************************
+
+int
+mask_match(server, mask, nick, user, host)
+ Irssi::Server server
+ char *mask
+ char *nick
+ char *user
+ char *host
+
+int
+mask_match_address(server, mask, nick, address)
+ Irssi::Server server
+ char *mask
+ char *nick
+ char *address
+
+int
+masks_match(server, masks, nick, address)
+ Irssi::Server server
+ char *masks
+ char *nick
+ char *address
diff --git a/src/perl/common/Query.xs b/src/perl/common/Query.xs
new file mode 100644
index 0000000..9d8cd52
--- /dev/null
+++ b/src/perl/common/Query.xs
@@ -0,0 +1,58 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+MODULE = Irssi::Query PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+queries()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = queries; tmp != NULL; tmp = tmp->next) {
+ QUERY_REC *rec = tmp->data;
+
+ XPUSHs(sv_2mortal(iobject_bless(rec)));
+ }
+
+Irssi::Query
+query_find(nick)
+ char *nick
+CODE:
+ RETVAL = query_find(NULL, nick);
+OUTPUT:
+ RETVAL
+
+#*******************************
+MODULE = Irssi::Query PACKAGE = Irssi::Server
+#*******************************
+
+void
+queries(server)
+ Irssi::Server server
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
+ QUERY_REC *rec = tmp->data;
+
+ XPUSHs(sv_2mortal(iobject_bless(rec)));
+ }
+
+Irssi::Query
+query_find(server, nick)
+ Irssi::Server server
+ char *nick
+
+#*******************************
+MODULE = Irssi::Query PACKAGE = Irssi::Query PREFIX = query_
+#*******************************
+
+void
+query_destroy(query)
+ Irssi::Query query
+
+void
+query_change_server(query, server)
+ Irssi::Query query
+ Irssi::Server server
diff --git a/src/perl/common/Rawlog.xs b/src/perl/common/Rawlog.xs
new file mode 100644
index 0000000..3c946c7
--- /dev/null
+++ b/src/perl/common/Rawlog.xs
@@ -0,0 +1,59 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+MODULE = Irssi::Rawlog PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+rawlog_set_size(lines)
+ int lines
+
+Irssi::Rawlog
+rawlog_create()
+
+#*******************************
+MODULE = Irssi::Rawlog PACKAGE = Irssi::Rawlog PREFIX = rawlog_
+#*******************************
+
+void
+rawlog_get_lines(rawlog)
+ Irssi::Rawlog rawlog
+PREINIT:
+ GList *tmp;
+PPCODE:
+ for (tmp = rawlog->lines->head; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(new_pv(tmp->data)));
+ }
+
+void
+rawlog_destroy(rawlog)
+ Irssi::Rawlog rawlog
+
+void
+rawlog_input(rawlog, str)
+ Irssi::Rawlog rawlog
+ char *str
+
+void
+rawlog_output(rawlog, str)
+ Irssi::Rawlog rawlog
+ char *str
+
+void
+rawlog_redirect(rawlog, str)
+ Irssi::Rawlog rawlog
+ char *str
+
+void
+rawlog_open(rawlog, fname)
+ Irssi::Rawlog rawlog
+ char *fname
+
+void
+rawlog_close(rawlog)
+ Irssi::Rawlog rawlog
+
+void
+rawlog_save(rawlog, fname)
+ Irssi::Rawlog rawlog
+ char *fname
diff --git a/src/perl/common/Server.xs b/src/perl/common/Server.xs
new file mode 100644
index 0000000..60878a6
--- /dev/null
+++ b/src/perl/common/Server.xs
@@ -0,0 +1,119 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+
+MODULE = Irssi::Server PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+servers()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = servers; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(iobject_bless((SERVER_REC *) tmp->data)));
+ }
+
+void
+reconnects()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(plain_bless(tmp->data, "Irssi::Reconnect")));
+ }
+
+void
+chatnets()
+PREINIT:
+ GSList *tmp;
+PPCODE:
+ for (tmp = chatnets; tmp != NULL; tmp = tmp->next) {
+ XPUSHs(sv_2mortal(iobject_bless((CHATNET_REC *) tmp->data)));
+ }
+
+Irssi::Connect
+server_create_conn(chat_type, dest, port, chatnet=NULL, password=NULL, nick=NULL)
+ int chat_type
+ char *dest
+ int port
+ char *chatnet
+ char *password
+ char *nick
+
+Irssi::Server
+server_find_tag(tag)
+ char *tag
+
+Irssi::Server
+server_find_chatnet(chatnet)
+ char *chatnet
+
+Irssi::Chatnet
+chatnet_find(name)
+ char *name
+
+#*******************************
+MODULE = Irssi::Server PACKAGE = Irssi::Server PREFIX = server_
+#*******************************
+
+void
+server_disconnect(server)
+ Irssi::Server server
+
+void
+server_ref(server)
+ Irssi::Server server
+
+void
+server_unref(server)
+ Irssi::Server server
+
+int
+isnickflag(server, flag)
+ Irssi::Server server
+ char flag
+CODE:
+ RETVAL = server->isnickflag(server, flag);
+OUTPUT:
+ RETVAL
+
+int
+ischannel(server, data)
+ Irssi::Server server
+ char *data
+CODE:
+ RETVAL = server->ischannel(server, data);
+OUTPUT:
+ RETVAL
+
+char *
+get_nick_flags(server)
+ Irssi::Server server
+CODE:
+ RETVAL = (char *) server->get_nick_flags(server);
+OUTPUT:
+ RETVAL
+
+void
+send_message(server, target, msg, target_type)
+ Irssi::Server server
+ char *target
+ char *msg
+ int target_type
+CODE:
+ server->send_message(server, target, msg, target_type);
+
+void
+server_meta_stash(server, meta_key, meta_value)
+ Irssi::Server server
+ char *meta_key
+ char *meta_value
+
+char *
+server_meta_stash_find(server, meta_key)
+ Irssi::Server server
+ char *meta_key
+CODE:
+ RETVAL = (char *) server_meta_stash_find(server, meta_key);
+OUTPUT:
+ RETVAL
diff --git a/src/perl/common/Settings.xs b/src/perl/common/Settings.xs
new file mode 100644
index 0000000..0f17241
--- /dev/null
+++ b/src/perl/common/Settings.xs
@@ -0,0 +1,215 @@
+#define PERL_NO_GET_CONTEXT
+#include "module.h"
+#include <irssi/src/core/misc.h>
+
+static GHashTable *perl_settings;
+
+static void perl_settings_add(const char *key)
+{
+ PERL_SCRIPT_REC *script;
+ GSList *list;
+
+ script = perl_script_find_package(perl_get_package());
+ g_return_if_fail(script != NULL);
+
+ list = g_hash_table_lookup(perl_settings, script);
+ list = g_slist_append(list, g_strdup(key));
+ g_hash_table_insert(perl_settings, script, list);
+}
+
+static void perl_settings_remove(const char *key)
+{
+ PERL_SCRIPT_REC *script;
+ GSList *list, *pos;
+
+ script = perl_script_find_package(perl_get_package());
+ g_return_if_fail(script != NULL);
+
+ list = g_hash_table_lookup(perl_settings, script);
+ pos = i_slist_find_icase_string(list, key);
+ if (pos != NULL) {
+ list = g_slist_remove(list, pos->data);
+ g_hash_table_insert(perl_settings, script, list);
+ }
+}
+
+static void perl_settings_free(PERL_SCRIPT_REC *script, GSList *list)
+{
+ g_slist_foreach(list, (GFunc) g_free, NULL);
+ g_slist_free(list);
+}
+
+static void sig_script_destroyed(PERL_SCRIPT_REC *script)
+{
+ GSList *list;
+
+ list = g_hash_table_lookup(perl_settings, script);
+ if (list != NULL) {
+ g_slist_foreach(list, (GFunc) settings_remove, NULL);
+ perl_settings_free(script, list);
+ g_hash_table_remove(perl_settings, script);
+ }
+}
+
+void perl_settings_init(void)
+{
+ perl_settings = g_hash_table_new((GHashFunc) g_direct_hash,
+ (GCompareFunc) g_direct_equal);
+ signal_add("script destroyed", (SIGNAL_FUNC) sig_script_destroyed);
+}
+
+void perl_settings_deinit(void)
+{
+ signal_remove("script destroyed", (SIGNAL_FUNC) sig_script_destroyed);
+
+ g_hash_table_foreach(perl_settings, (GHFunc) perl_settings_free, NULL);
+ g_hash_table_destroy(perl_settings);
+}
+
+MODULE = Irssi::Settings PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+SV *
+settings_get_str(key)
+ char *key
+PREINIT:
+ const char *str;
+CODE:
+ str = settings_get_str(key);
+ RETVAL = new_pv(str);
+OUTPUT:
+ RETVAL
+
+int
+settings_get_int(key)
+ char *key
+
+int
+settings_get_bool(key)
+ char *key
+
+int
+settings_get_time(key)
+ char *key
+
+int
+settings_get_level(key)
+ char *key
+
+int
+settings_get_level_negative(key)
+ char *key
+
+int
+settings_get_size(key)
+ char *key
+
+int
+settings_get_choice(key)
+ char *key
+
+void
+settings_set_str(key, value)
+ char *key
+ char *value
+
+void
+settings_set_int(key, value)
+ char *key
+ int value
+
+void
+settings_set_bool(key, value)
+ char *key
+ int value
+
+int
+settings_set_time(key, value)
+ char *key
+ char *value
+
+int
+settings_set_level(key, value)
+ char *key
+ char *value
+
+int
+settings_set_size(key, value)
+ char *key
+ char *value
+
+int
+settings_set_choice(key, value)
+ char *key
+ char *value
+
+void
+settings_add_str(section, key, def)
+ char *section
+ char *key
+ char *def
+CODE:
+ perl_settings_add(key);
+ settings_add_str_module(MODULE_NAME"/scripts", section, key, def);
+
+void
+settings_add_int(section, key, def)
+ char *section
+ char *key
+ int def
+CODE:
+ perl_settings_add(key);
+ settings_add_int_module(MODULE_NAME"/scripts", section, key, def);
+
+void
+settings_add_bool(section, key, def)
+ char *section
+ char *key
+ int def
+CODE:
+ perl_settings_add(key);
+ settings_add_bool_module(MODULE_NAME"/scripts", section, key, def);
+
+void
+settings_add_time(section, key, def)
+ char *section
+ char *key
+ char *def
+CODE:
+ perl_settings_add(key);
+ settings_add_time_module(MODULE_NAME"/scripts", section, key, def);
+
+void
+settings_add_level(section, key, def)
+ char *section
+ char *key
+ char *def
+CODE:
+ perl_settings_add(key);
+ settings_add_level_module(MODULE_NAME"/scripts", section, key, def);
+
+void
+settings_add_size(section, key, def)
+ char *section
+ char *key
+ char *def
+CODE:
+ perl_settings_add(key);
+ settings_add_size_module(MODULE_NAME"/scripts", section, key, def);
+
+void
+settings_add_choice(section, key, def, choices)
+ char *section
+ char *key
+ int def
+ char *choices
+CODE:
+ perl_settings_add(key);
+ settings_add_choice_module(MODULE_NAME "/scripts", section, key, def, choices);
+
+void
+settings_remove(key)
+ char *key
+CODE:
+ perl_settings_remove(key);
+ settings_remove(key);
diff --git a/src/perl/common/meson.build b/src/perl/common/meson.build
new file mode 100644
index 0000000..4162756
--- /dev/null
+++ b/src/perl/common/meson.build
@@ -0,0 +1,40 @@
+
+libperl_Irssi_a = shared_module('Irssi',
+ [ xsubpp.process(
+ files(
+ 'Channel.xs',
+ 'Core.xs',
+ 'Expando.xs',
+ 'Ignore.xs',
+ 'Irssi.xs',
+ 'Log.xs',
+ 'Masks.xs',
+ 'Query.xs',
+ 'Rawlog.xs',
+ 'Server.xs',
+ 'Settings.xs',
+ )
+ ) ]
+ + files(
+ 'module.h',
+ )
+ + [ irssi_version_h ],
+ name_prefix : '',
+ name_suffix : perl_module_suffix,
+ install : true,
+ install_dir : perlmoddir / 'auto' / 'Irssi',
+ include_directories : rootinc,
+ implicit_include_directories : true,
+ dependencies : dep + [ perl_dep ],
+ link_with : dl_cross_perl_core,
+)
+
+install_headers(
+ files(
+ 'Irssi.pm',
+ ),
+ install_dir : perlmoddir,
+)
+
+# 'Makefile.PL.in',
+# 'typemap',
diff --git a/src/perl/common/module.h b/src/perl/common/module.h
new file mode 100644
index 0000000..92a712f
--- /dev/null
+++ b/src/perl/common/module.h
@@ -0,0 +1,45 @@
+#define NEED_PERL_H
+#define HAVE_CONFIG_H
+#include <irssi/src/perl/module.h>
+#include <XSUB.h>
+
+#include <irssi/src/core/network.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/commands.h>
+#include <irssi/src/core/log.h>
+#include <irssi/src/core/rawlog.h>
+#include <irssi/src/core/ignore.h>
+#include <irssi/src/core/settings.h>
+#include <irssi/src/core/masks.h>
+#include <irssi/src/core/special-vars.h>
+#include <irssi/src/core/window-item-def.h>
+
+#include <irssi/src/core/chat-protocols.h>
+#include <irssi/src/core/chatnets.h>
+#include <irssi/src/core/servers.h>
+#include <irssi/src/core/servers-reconnect.h>
+#include <irssi/src/core/servers-setup.h>
+#include <irssi/src/core/channels.h>
+#include <irssi/src/core/queries.h>
+#include <irssi/src/core/nicklist.h>
+
+#include <irssi/src/perl/perl-core.h>
+#include <irssi/src/perl/perl-common.h>
+#include <irssi/src/perl/perl-signals.h>
+#include <irssi/src/perl/perl-sources.h>
+
+typedef COMMAND_REC *Irssi__Command;
+typedef LOG_REC *Irssi__Log;
+typedef LOG_ITEM_REC *Irssi__Logitem;
+typedef RAWLOG_REC *Irssi__Rawlog;
+typedef IGNORE_REC *Irssi__Ignore;
+typedef MODULE_REC *Irssi__Module;
+typedef WI_ITEM_REC *Irssi__Windowitem;
+
+typedef CHATNET_REC *Irssi__Chatnet;
+typedef SERVER_REC *Irssi__Server;
+typedef SERVER_CONNECT_REC *Irssi__Connect;
+typedef RECONNECT_REC *Irssi__Reconnect;
+typedef CHANNEL_REC *Irssi__Channel;
+typedef QUERY_REC *Irssi__Query;
+typedef NICK_REC *Irssi__Nick;
diff --git a/src/perl/common/typemap b/src/perl/common/typemap
new file mode 100644
index 0000000..9b6c666
--- /dev/null
+++ b/src/perl/common/typemap
@@ -0,0 +1,32 @@
+TYPEMAP
+Irssi::Chatnet T_IrssiObj
+Irssi::Server T_IrssiObj
+Irssi::Connect T_IrssiObj
+Irssi::Reconnect T_PlainObj
+Irssi::Channel T_IrssiObj
+Irssi::Query T_IrssiObj
+Irssi::Command T_PlainObj
+Irssi::Nick T_IrssiObj
+Irssi::Ignore T_PlainObj
+Irssi::Log T_PlainObj
+Irssi::Logitem T_PlainObj
+Irssi::Rawlog T_PlainObj
+Irssi::Module T_PlainObj
+Irssi::Windowitem T_IrssiObj
+
+INPUT
+
+T_IrssiObj
+ $var = irssi_ref_object($arg)
+
+T_PlainObj
+ $var = irssi_ref_object($arg)
+
+OUTPUT
+
+T_IrssiObj
+ $arg = iobject_bless((SERVER_REC *)$var);
+
+T_PlainObj
+ $arg = plain_bless($var, \"$ntype\");
+