Added SILC Thread Queue API
[runtime.git] / apps / irssi / src / perl / perl-common.c
index 76fa3f3fbe1b4792dfd5d7e302d7a1bd77ef424c..03dcc01ec6778f864b2de1eaa614d24e9a433934 100644 (file)
@@ -40,6 +40,7 @@
 #include "queries.h"
 #include "nicklist.h"
 
+#include "perl-core.h"
 #include "perl-common.h"
 
 typedef struct {
@@ -94,6 +95,31 @@ SV *perl_func_sv_inc(SV *func, const char *package)
         return func;
 }
 
+static int magic_free_object(pTHX_ SV *sv, MAGIC *mg)
+{
+       sv_setiv(sv, 0);
+       return 0;
+}
+
+static MGVTBL vtbl_free_object =
+{
+    NULL, NULL, NULL, NULL, magic_free_object
+};
+
+static SV *create_sv_ptr(void *object)
+{
+       SV *sv;
+
+       sv = newSViv((IV)object);
+
+       sv_magic(sv, NULL, '~', NULL, 0);
+
+       SvMAGIC(sv)->mg_private = 0x1551; /* HF */
+       SvMAGIC(sv)->mg_virtual = &vtbl_free_object;
+
+       return sv;
+}
+
 SV *irssi_bless_iobject(int type, int chat_type, void *object)
 {
         PERL_OBJECT_REC *rec;
@@ -106,13 +132,13 @@ SV *irssi_bless_iobject(int type, int chat_type, void *object)
                                  GINT_TO_POINTER(type | (chat_type << 16)));
        if (rec == NULL) {
                 /* unknown iobject */
-               return newSViv(GPOINTER_TO_INT(object));
+               return create_sv_ptr(object);
        }
 
        stash = gv_stashpv(rec->stash, 1);
 
        hv = newHV();
-       hv_store(hv, "_irssi", 6, newSViv(GPOINTER_TO_INT(object)), 0);
+       hv_store(hv, "_irssi", 6, create_sv_ptr(object), 0);
         rec->fill_func(hv, object);
        return sv_bless(newRV_noinc((SV*)hv), stash);
 }
@@ -125,7 +151,7 @@ SV *irssi_bless_plain(const char *stash, void *object)
        fill_func = g_hash_table_lookup(plain_stashes, stash);
 
        hv = newHV();
-       hv_store(hv, "_irssi", 6, newSViv(GPOINTER_TO_INT(object)), 0);
+       hv_store(hv, "_irssi", 6, create_sv_ptr(object), 0);
        if (fill_func != NULL)
                fill_func(hv, object);
        return sv_bless(newRV_noinc((SV*)hv), gv_stashpv((char *)stash, 1));
@@ -150,6 +176,7 @@ void *irssi_ref_object(SV *o)
 {
         SV **sv;
        HV *hv;
+       void *p;
 
         hv = hvref(o);
        if (hv == NULL)
@@ -157,8 +184,9 @@ void *irssi_ref_object(SV *o)
 
        sv = hv_fetch(hv, "_irssi", 6, 0);
        if (sv == NULL)
-                croak("variable is damaged");
-       return GINT_TO_POINTER(SvIV(*sv));
+               croak("variable is damaged");
+       p = GINT_TO_POINTER(SvIV(*sv));
+       return p;
 }
 
 void irssi_add_object(int type, int chat_type, const char *stash,
@@ -219,12 +247,12 @@ char *perl_get_use_list(void)
         return ret;
 }
 
-void irssi_callXS(void (*subaddr)(CV* cv), CV *cv, SV **mark)
+void irssi_callXS(void (*subaddr)(pTHX_ CV* cv), CV *cv, SV **mark)
 {
        dSP;
 
        PUSHMARK(mark);
-       (*subaddr)(cv);
+       (*subaddr)(aTHX_ cv);
 
        PUTBACK;
 }
@@ -265,6 +293,7 @@ void perl_connect_fill_hash(HV *hv, SERVER_CONNECT_REC *conn)
        hv_store(hv, "type", 4, new_pv(type), 0);
        hv_store(hv, "chat_type", 9, new_pv(chat_type), 0);
 
+       hv_store(hv, "tag", 3, new_pv(conn->tag), 0);
        hv_store(hv, "address", 7, new_pv(conn->address), 0);
        hv_store(hv, "port", 4, newSViv(conn->port), 0);
        hv_store(hv, "chatnet", 7, new_pv(conn->chatnet), 0);
@@ -273,6 +302,12 @@ void perl_connect_fill_hash(HV *hv, SERVER_CONNECT_REC *conn)
        hv_store(hv, "wanted_nick", 11, new_pv(conn->nick), 0);
        hv_store(hv, "username", 8, new_pv(conn->username), 0);
        hv_store(hv, "realname", 8, new_pv(conn->realname), 0);
+
+       hv_store(hv, "reconnection", 12, newSViv(conn->reconnection), 0);
+       hv_store(hv, "no_autojoin_channels", 20, newSViv(conn->no_autojoin_channels), 0);
+       hv_store(hv, "unix_socket", 11, newSViv(conn->unix_socket), 0);
+       hv_store(hv, "use_ssl", 7, newSViv(conn->use_ssl), 0);
+       hv_store(hv, "no_connect", 10, newSViv(conn->no_connect), 0);
 }
 
 void perl_server_fill_hash(HV *hv, SERVER_REC *server)
@@ -298,7 +333,7 @@ void perl_server_fill_hash(HV *hv, SERVER_REC *server)
        hv_store(hv, "connection_lost", 15, newSViv(server->connection_lost), 0);
 
        stash = gv_stashpv("Irssi::Rawlog", 0);
-       hv_store(hv, "rawlog", 6, sv_bless(newRV_noinc(newSViv(GPOINTER_TO_INT(server->rawlog))), stash), 0);
+       hv_store(hv, "rawlog", 6, sv_bless(newRV_noinc(newSViv((IV)server->rawlog)), stash), 0);
 
        hv_store(hv, "version", 7, new_pv(server->version), 0);
        hv_store(hv, "away_reason", 11, new_pv(server->away_reason), 0);
@@ -326,11 +361,11 @@ void perl_window_item_fill_hash(HV *hv, WI_ITEM_REC *item)
        if (item->server != NULL) {
                hv_store(hv, "server", 6, iobject_bless(item->server), 0);
        }
-       hv_store(hv, "name", 4, new_pv(item->name), 0);
+       hv_store(hv, "visible_name", 12, new_pv(item->visible_name), 0);
 
        hv_store(hv, "createtime", 10, newSViv(item->createtime), 0);
-       hv_store(hv, "data_level", 8, newSViv(item->data_level), 0);
-       hv_store(hv, "hilight_color", 10, new_pv(item->hilight_color), 0);
+       hv_store(hv, "data_level", 10, newSViv(item->data_level), 0);
+       hv_store(hv, "hilight_color", 13, new_pv(item->hilight_color), 0);
 }
 
 void perl_channel_fill_hash(HV *hv, CHANNEL_REC *channel)
@@ -340,6 +375,10 @@ void perl_channel_fill_hash(HV *hv, CHANNEL_REC *channel)
 
        perl_window_item_fill_hash(hv, (WI_ITEM_REC *) channel);
 
+        if (channel->ownnick != NULL)
+               hv_store(hv, "ownnick", 7, iobject_bless(channel->ownnick), 0);
+
+       hv_store(hv, "name", 4, new_pv(channel->name), 0);
        hv_store(hv, "topic", 5, new_pv(channel->topic), 0);
        hv_store(hv, "topic_by", 8, new_pv(channel->topic_by), 0);
        hv_store(hv, "topic_time", 10, newSViv(channel->topic_time), 0);
@@ -366,6 +405,8 @@ void perl_query_fill_hash(HV *hv, QUERY_REC *query)
 
        perl_window_item_fill_hash(hv, (WI_ITEM_REC *) query);
 
+       hv_store(hv, "name", 4, new_pv(query->name), 0);
+       hv_store(hv, "last_unread_msg", 15, newSViv(query->last_unread_msg), 0);
        hv_store(hv, "address", 7, new_pv(query->address), 0);
        hv_store(hv, "server_tag", 10, new_pv(query->server_tag), 0);
        hv_store(hv, "unwanted", 8, newSViv(query->unwanted), 0);
@@ -395,6 +436,7 @@ void perl_nick_fill_hash(HV *hv, NICK_REC *nick)
        hv_store(hv, "op", 2, newSViv(nick->op), 0);
        hv_store(hv, "halfop", 6, newSViv(nick->halfop), 0);
        hv_store(hv, "voice", 5, newSViv(nick->voice), 0);
+       hv_store(hv, "other", 5, newSViv(nick->other), 0);
 
        hv_store(hv, "last_check", 10, newSViv(nick->last_check), 0);
        hv_store(hv, "send_massjoin", 13, newSViv(nick->send_massjoin), 0);
@@ -414,15 +456,17 @@ static void perl_ignore_fill_hash(HV *hv, IGNORE_REC *ignore)
        hv_store(hv, "mask", 4, new_pv(ignore->mask), 0);
        hv_store(hv, "servertag", 9, new_pv(ignore->servertag), 0);
        av = newAV();
-       for (tmp = ignore->channels; *tmp != NULL; tmp++) {
-               av_push(av, new_pv(*tmp));
+       if (ignore->channels != NULL) {
+               for (tmp = ignore->channels; *tmp != NULL; tmp++) {
+                       av_push(av, new_pv(*tmp));
+               }
        }
        hv_store(hv, "channels", 8, newRV_noinc((SV*)av), 0);
        hv_store(hv, "pattern", 7, new_pv(ignore->pattern), 0);
 
        hv_store(hv, "level", 5, newSViv(ignore->level), 0);
 
-       hv_store(hv, "exception", 6, newSViv(ignore->exception), 0);
+       hv_store(hv, "exception", 9, newSViv(ignore->exception), 0);
        hv_store(hv, "regexp", 6, newSViv(ignore->regexp), 0);
        hv_store(hv, "fullword", 8, newSViv(ignore->fullword), 0);
 }
@@ -474,6 +518,24 @@ static void perl_reconnect_fill_hash(HV *hv, RECONNECT_REC *reconnect)
        hv_store(hv, "next_connect", 12, newSViv(reconnect->next_connect), 0);
 }
 
+static void perl_script_fill_hash(HV *hv, PERL_SCRIPT_REC *script)
+{
+       hv_store(hv, "name", 4, new_pv(script->name), 0);
+       hv_store(hv, "package", 7, new_pv(script->package), 0);
+       hv_store(hv, "path", 4, new_pv(script->path), 0);
+       hv_store(hv, "data", 4, new_pv(script->data), 0);
+}
+
+static void remove_newlines(char *str)
+{
+       char *writing = str;
+
+       for (;*str;str++)
+               if (*str != '\n' && *str != '\r')
+                       *(writing++) = *str;
+       *writing = '\0';
+}
+
 void perl_command(const char *cmd, SERVER_REC *server, WI_ITEM_REC *item)
 {
         const char *cmdchars;
@@ -488,6 +550,14 @@ void perl_command(const char *cmd, SERVER_REC *server, WI_ITEM_REC *item)
                sendcmd = g_strdup_printf("%c%s", *cmdchars, cmd);
        }
 
+       /* remove \r and \n from commands,
+          to make it harder to introduce a security bug in a script */
+       if(strpbrk(sendcmd, "\r\n")) {
+               if (sendcmd == cmd)
+                       sendcmd = strdup(cmd);
+               remove_newlines(sendcmd);
+       }
+
        signal_emit("send command", 3, sendcmd, server, item);
        if (sendcmd != cmd) g_free(sendcmd);
 }
@@ -514,8 +584,13 @@ static void perl_register_protocol(CHAT_PROTOCOL_REC *rec)
        chat_type = chat_protocol_lookup(rec->name);
        g_return_if_fail(chat_type >= 0);
 
+#if GLIB_MAJOR_VERSION < 2
        name = g_strdup(rec->name);
        g_strdown(name+1);
+#else
+       name = g_ascii_strdown(rec->name,-1);
+       *name = *(rec->name);
+#endif
 
        /* window items: channel, query */
        type = module_get_uniq_id_str("WINDOW ITEM TYPE", "CHANNEL");
@@ -589,13 +664,14 @@ static int free_iobject_proto(void *key, void *value, void *chat_type)
 
 static void perl_unregister_protocol(CHAT_PROTOCOL_REC *rec)
 {
-        GSList *item;
+       GSList *item;
+       void *data;
 
        item = gslist_find_icase_string(use_protocols, rec->name);
        if (item != NULL) {
-               g_free(item->data);
-               use_protocols =
-                       g_slist_remove(use_protocols, item->data);
+               data = item->data;
+               use_protocols = g_slist_remove(use_protocols, data);
+               g_free(data);
        }
        g_hash_table_foreach_remove(iobject_stashes,
                                    (GHRFunc) free_iobject_proto,
@@ -611,6 +687,7 @@ void perl_common_start(void)
                { "Irssi::Logitem", (PERL_OBJECT_FUNC) perl_log_item_fill_hash },
                { "Irssi::Rawlog", (PERL_OBJECT_FUNC) perl_rawlog_fill_hash },
                { "Irssi::Reconnect", (PERL_OBJECT_FUNC) perl_reconnect_fill_hash },
+               { "Irssi::Script", (PERL_OBJECT_FUNC) perl_script_fill_hash },
 
                { NULL, NULL }
        };