diff options
-rw-r--r-- | libpurple/protocols/irc/cmds.c | 792 | ||||
-rw-r--r-- | libpurple/protocols/irc/dcc_send.c | 413 | ||||
-rw-r--r-- | libpurple/protocols/irc/irc.c | 1282 | ||||
-rw-r--r-- | libpurple/protocols/irc/irc.h | 222 | ||||
-rw-r--r-- | libpurple/protocols/irc/meson.build | 23 | ||||
-rw-r--r-- | libpurple/protocols/irc/msgs.c | 1733 | ||||
-rw-r--r-- | libpurple/protocols/irc/parse.c | 819 | ||||
-rw-r--r-- | libpurple/protocols/irc/resources/icons/16x16/apps/im-irc.png | bin | 618 -> 0 bytes | |||
-rw-r--r-- | libpurple/protocols/irc/resources/icons/16x16/apps/scalable/im-irc.svg | 222 | ||||
-rw-r--r-- | libpurple/protocols/irc/resources/icons/22x22/apps/im-irc.png | bin | 558 -> 0 bytes | |||
-rw-r--r-- | libpurple/protocols/irc/resources/icons/22x22/apps/scalable/im-irc.svg | 237 | ||||
-rw-r--r-- | libpurple/protocols/irc/resources/icons/48x48/apps/im-irc.png | bin | 1003 -> 0 bytes | |||
-rw-r--r-- | libpurple/protocols/irc/resources/icons/scalable/apps/im-irc.svg | 238 | ||||
-rw-r--r-- | libpurple/protocols/irc/resources/irc.gresource.xml | 11 | ||||
-rw-r--r-- | libpurple/protocols/meson.build | 1 | ||||
-rw-r--r-- | po/POTFILES.in | 5 |
16 files changed, 0 insertions, 5998 deletions
diff --git a/libpurple/protocols/irc/cmds.c b/libpurple/protocols/irc/cmds.c deleted file mode 100644 index 2709247e46..0000000000 --- a/libpurple/protocols/irc/cmds.c +++ /dev/null @@ -1,792 +0,0 @@ -/** - * purple - * - * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib/gi18n-lib.h> - -#include <purple.h> - -#include "irc.h" - - -static void irc_do_mode(struct irc_conn *irc, const char *target, const char *sign, char **ops); - -int -irc_cmd_default(struct irc_conn *irc, const char *cmd, const char *target, - G_GNUC_UNUSED const char **args) -{ - PurpleConversation *convo; - PurpleConversationManager *manager; - char *buf; - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find(manager, irc->account, target); - - if (!convo) { - return 1; - } - - buf = g_strdup_printf(_("Unknown command: %s"), cmd); - purple_conversation_write_system_message(convo, buf, PURPLE_MESSAGE_NO_LOG); - g_free(buf); - - return 1; -} - -int -irc_cmd_away(struct irc_conn *irc, const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf, *message; - - if (args[0] && !purple_strequal(cmd, "back")) { - message = purple_markup_strip_html(args[0]); - purple_util_chrreplace(message, '\n', ' '); - buf = irc_format(irc, "v:", "AWAY", message); - g_free(message); - } else { - buf = irc_format(irc, "v", "AWAY"); - } - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_ctcp(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - /* we have defined args as args[0] is target and args[1] is ctcp command */ - char *buf; - GString *string; - - /* check if we have args */ - if (!args || !args[0] || !args[1]) - return 0; - - /* TODO:strip newlines or send each line as separate ctcp or something - * actually, this shouldn't be done here but somewhere else since irc should support escaping newlines */ - - string = g_string_new(args[1]); - g_string_prepend_c (string,'\001'); - g_string_append_c (string,'\001'); - buf = irc_format(irc, "vn:", "PRIVMSG", args[0], string->str); - g_string_free(string,TRUE); - - irc_send(irc, buf); - g_free(buf); - - return 1; -} - -int irc_cmd_ctcp_action(struct irc_conn *irc, const char *cmd, const char *target, const char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - gchar *action, *escaped, *dst, **newargs; - const gchar *src, *me; - gchar *msg; - PurpleContactInfo *info = NULL; - PurpleConversation *convo; - PurpleConversationManager *manager; - PurpleMessage *pmsg; - - if (!args || !args[0] || !gc) { - return 0; - } - - info = PURPLE_CONTACT_INFO(irc->account); - me = purple_contact_info_get_name_for_display(info); - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find(manager, irc->account, target); - - msg = g_strdup_printf("/me %s", args[0]); - - /* XXX: we'd prefer to keep this in conversation.c */ - if (PURPLE_IS_IM_CONVERSATION(convo)) { - const gchar *conv_name = purple_conversation_get_name(convo); - pmsg = purple_message_new_outgoing(irc->account, me, conv_name, msg, - 0); - - purple_signal_emit(purple_conversations_get_handle(), - "sending-im-msg", irc->account, pmsg); - } else { - pmsg = purple_message_new_outgoing(irc->account, me, NULL, msg, 0); - - purple_signal_emit(purple_conversations_get_handle(), - "sending-chat-msg", irc->account, pmsg, - purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo))); - } - - /* We free the original message because it could have been changed by the - * sending-*-msg signals above. - */ - g_free(msg); - - /* if the message was eaten by a signal we bail */ - if(purple_message_is_empty(pmsg)) { - g_object_unref(G_OBJECT(pmsg)); - - return 0; - } - - /* create a copy of the updated message, which should not be null because - * we just tested if it was empty in the above conditional. - */ - msg = g_strdup(purple_message_get_contents(pmsg)); - - if (strncmp(msg, "/me ", 4) != 0) { - newargs = g_new0(char *, 2); - newargs[0] = g_strdup(target); - newargs[1] = msg; - - irc_cmd_privmsg(irc, cmd, target, (const char **)newargs); - - g_free(newargs[0]); - g_free(newargs); - } else { - action = g_malloc(strlen(&msg[4]) + 10); - - sprintf(action, "\001ACTION "); - - src = &msg[4]; - dst = action + 8; - while (*src) { - if (*src == '\n') { - if (*(src + 1) == '\0') { - break; - } else { - *dst++ = ' '; - src++; - continue; - } - } - *dst++ = *src++; - } - *dst++ = '\001'; - *dst = '\0'; - - newargs = g_new0(char *, 2); - newargs[0] = g_strdup(target); - newargs[1] = action; - irc_cmd_privmsg(irc, cmd, target, (const char **)newargs); - g_free(newargs[0]); - g_free(newargs); - g_free(action); - } - - /* XXX: we'd prefer to keep this in conversation.c */ - if (PURPLE_IS_IM_CONVERSATION(convo)) { - purple_signal_emit(purple_conversations_get_handle(), - "sent-im-msg", irc->account, pmsg); - } else { - purple_signal_emit(purple_conversations_get_handle(), - "sent-chat-msg", irc->account, pmsg, - purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo))); - } - - g_free(msg); - - if (convo) { - escaped = g_markup_escape_text(args[0], -1); - action = g_strdup_printf("/me %s", escaped); - g_free(escaped); - if (action[strlen(action) - 1] == '\n') { - action[strlen(action) - 1] = '\0'; - } - if (PURPLE_IS_CHAT_CONVERSATION(convo)) { - purple_serv_got_chat_in(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo)), - purple_connection_get_display_name(gc), - PURPLE_MESSAGE_SEND, action, time(NULL)); - } else { - purple_message_set_recipient(pmsg, - purple_connection_get_display_name(gc)); - purple_conversation_write_message(convo, pmsg); - } - g_free(action); - } - - g_object_unref(G_OBJECT(pmsg)); - - return 1; -} - -int -irc_cmd_ctcp_version(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - buf = irc_format(irc, "vn:", "PRIVMSG", args[0], "\001VERSION\001"); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_invite(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0] || !(args[1] || target)) - return 0; - - buf = irc_format(irc, "vnc", "INVITE", args[0], args[1] ? args[1] : target); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_join(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - if (args[1]) - buf = irc_format(irc, "vcv", "JOIN", args[0], args[1]); - else - buf = irc_format(irc, "vc", "JOIN", args[0]); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_kick(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - const char *target, const char **args) -{ - PurpleConversationManager *manager; - char *buf; - - if(!args || !args[0]) { - return 0; - } - - manager = purple_conversation_manager_get_default(); - if(!purple_conversation_manager_find_chat(manager, irc->account, target)) { - return 0; - } - - if(args[1]) { - buf = irc_format(irc, "vcn:", "KICK", target, args[0], args[1]); - } else { - buf = irc_format(irc, "vcn", "KICK", target, args[0]); - } - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_list(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, G_GNUC_UNUSED const char **args) -{ - purple_roomlist_show_with_account(irc->account); - - return 0; -} - -int irc_cmd_mode(struct irc_conn *irc, const char *cmd, const char *target, const char **args) -{ - PurpleConnection *gc; - char *buf; - - if (!args) - return 0; - - if (purple_strequal(cmd, "mode")) { - if (!args[0] && irc_ischannel(target)) - buf = irc_format(irc, "vc", "MODE", target); - else if (args[0] && (*args[0] == '+' || *args[0] == '-')) - buf = irc_format(irc, "vcn", "MODE", target, args[0]); - else if (args[0]) - buf = irc_format(irc, "vn", "MODE", args[0]); - else - return 0; - } else if (purple_strequal(cmd, "umode")) { - if (!args[0]) - return 0; - gc = purple_account_get_connection(irc->account); - buf = irc_format(irc, "vnc", "MODE", purple_connection_get_display_name(gc), args[0]); - } else { - return 0; - } - - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_names(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - const char *target, const char **args) -{ - char *buf; - - if (!args || (!args[0] && !irc_ischannel(target))) - return 0; - - buf = irc_format(irc, "vc", "NAMES", args[0] ? args[0] : target); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_nick(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - buf = irc_format(irc, "v:", "NICK", args[0]); - g_free(irc->reqnick); - irc->reqnick = g_strdup(args[0]); - irc->nickused = FALSE; - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int irc_cmd_op(struct irc_conn *irc, const char *cmd, const char *target, const char **args) -{ - char **nicks, **ops, *sign, *mode; - int i = 0, used = 0; - - if (!args || !args[0] || !*args[0]) - return 0; - - if (purple_strequal(cmd, "op")) { - sign = "+"; - mode = "o"; - } else if (purple_strequal(cmd, "deop")) { - sign = "-"; - mode = "o"; - } else if (purple_strequal(cmd, "voice")) { - sign = "+"; - mode = "v"; - } else if (purple_strequal(cmd, "devoice")) { - sign = "-"; - mode = "v"; - } else { - purple_debug_error("irc", "invalid 'op' command '%s'", cmd); - return 0; - } - - nicks = g_strsplit(args[0], " ", -1); - - for (i = 0; nicks[i]; i++) - /* nothing */; - ops = g_new0(char *, i * 2 + 1); - - for (i = 0; nicks[i]; i++) { - if (*nicks[i]) { - ops[used++] = mode; - ops[used++] = nicks[i]; - } - } - - irc_do_mode(irc, target, sign, ops); - g_free(ops); - g_strfreev(nicks); - - return 0; -} - -int -irc_cmd_part(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - const char *target, const char **args) -{ - char *buf; - - if (!args) - return 0; - - if (args[1]) - buf = irc_format(irc, "vc:", "PART", args[0] ? args[0] : target, args[1]); - else - buf = irc_format(irc, "vc", "PART", args[0] ? args[0] : target); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_ping(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - const char *target, const char **args) -{ - char *stamp; - char *buf; - - if (args && args[0]) { - if (irc_ischannel(args[0])) - return 0; - stamp = g_strdup_printf("\001PING %" G_GINT64_FORMAT "\001", - g_get_monotonic_time()); - buf = irc_format(irc, "vn:", "PRIVMSG", args[0], stamp); - g_free(stamp); - } else if (target) { - stamp = g_strdup_printf("%s %" G_GINT64_FORMAT, target, - g_get_monotonic_time()); - buf = irc_format(irc, "v:", "PING", stamp); - g_free(stamp); - } else { - stamp = g_strdup_printf("%" G_GUINT64_FORMAT, g_get_monotonic_time()); - buf = irc_format(irc, "vv", "PING", stamp); - g_free(stamp); - } - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_privmsg(struct irc_conn *irc, const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - int max_privmsg_arg_len; - const char *cur, *end; - gchar *salvaged; - char *msg, *buf; - - if (!args || !args[0] || !args[1]) - return 0; - - max_privmsg_arg_len = IRC_MAX_MSG_SIZE - strlen(args[0]) - 64; - salvaged = g_utf8_make_valid(args[1], -1); - cur = salvaged; - end = salvaged; - while (*end && *cur) { - end = strchr(cur, '\n'); - if (!end) - end = cur + strlen(cur); - if (end - cur > max_privmsg_arg_len) { - /* this call is used to find the last valid character position in the first - * max_privmsg_arg_len bytes of the utf-8 message - */ - g_utf8_validate(cur, max_privmsg_arg_len, &end); - } - - msg = g_strndup(cur, end - cur); - - if(purple_strequal(cmd, "notice")) - buf = irc_format(irc, "vt:", "NOTICE", args[0], msg); - else - buf = irc_format(irc, "vt:", "PRIVMSG", args[0], msg); - - irc_send(irc, buf); - g_free(msg); - g_free(buf); - cur = end; - if(*cur == '\n') { - cur++; - } - } - - g_free(salvaged); - - return 0; -} - -int -irc_cmd_quit(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!irc->quitting) { - /* - * Use purple_account_get_string(irc->account, "quitmsg", IRC_DEFAULT_QUIT) - * and uncomment the appropriate account preference in irc.c if we - * decide we want custom quit messages. - */ - buf = irc_format(irc, "v:", "QUIT", (args && args[0]) ? args[0] : IRC_DEFAULT_QUIT); - irc_send(irc, buf); - g_free(buf); - - irc->quitting = TRUE; - - if (!purple_account_is_disconnecting(irc->account)) - purple_account_set_status(irc->account, "offline", TRUE, NULL); - } - - return 0; -} - -int -irc_cmd_quote(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - buf = irc_format(irc, "n", args[0]); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int irc_cmd_query(struct irc_conn *irc, const char *cmd, const char *target, const char **args) -{ - PurpleConversation *im; - PurpleConnection *gc; - - if (!args || !args[0]) - return 0; - - im = purple_im_conversation_new(irc->account, args[0]); - purple_conversation_present(im); - - if (args[1]) { - PurpleMessage *message = NULL; - PurpleContactInfo *info = PURPLE_CONTACT_INFO(irc->account); - const gchar *me = NULL; - const gchar *recipient = NULL; - - gc = purple_account_get_connection(irc->account); - irc_cmd_privmsg(irc, cmd, target, args); - - me = purple_contact_info_get_name_for_display(info); - recipient = purple_connection_get_display_name(gc); - message = purple_message_new_outgoing(irc->account, me, recipient, - args[1], 0); - - purple_conversation_write_message(im, message); - - g_object_unref(G_OBJECT(message)); - } - - return 0; -} - -int -irc_cmd_remove(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - if (!irc_ischannel(target)) /* not a channel, punt */ - return 0; - - if (args[1]) - buf = irc_format(irc, "vcn:", "REMOVE", target, args[0], args[1]); - else - buf = irc_format(irc, "vcn", "REMOVE", target, args[0]); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_service(struct irc_conn *irc, const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *capital_cmd, *buf; - - if (!args || !args[0]) - return 0; - - /* cmd will be one of nickserv, chanserv, memoserv or operserv */ - capital_cmd = g_ascii_strup(cmd, -1); - buf = irc_format(irc, "v:", capital_cmd, args[0]); - irc_send(irc, buf); - g_free(capital_cmd); - g_free(buf); - - return 0; -} - -int -irc_cmd_time(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, G_GNUC_UNUSED const char **args) -{ - char *buf; - - buf = irc_format(irc, "v", "TIME"); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_topic(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - const char *target, const char **args) -{ - PurpleConversation *chat; - PurpleConversationManager *manager; - char *buf; - const char *topic; - - if (!args) { - return 0; - } - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, target); - if (!chat) { - return 0; - } - - if (!args[0]) { - topic = purple_chat_conversation_get_topic (PURPLE_CHAT_CONVERSATION(chat)); - - if (topic) { - char *tmp, *tmp2; - tmp = g_markup_escape_text(topic, -1); - tmp2 = purple_markup_linkify(tmp); - buf = g_strdup_printf(_("current topic is: %s"), tmp2); - g_free(tmp); - g_free(tmp2); - } else - buf = g_strdup(_("No topic is set")); - purple_conversation_write_system_message( - chat, buf, PURPLE_MESSAGE_NO_LOG); - g_free(buf); - - return 0; - } - - buf = irc_format(irc, "vt:", "TOPIC", target, args[0]); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_wallops(struct irc_conn *irc, const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - if (purple_strequal(cmd, "wallops")) - buf = irc_format(irc, "v:", "WALLOPS", args[0]); - else if (purple_strequal(cmd, "operwall")) - buf = irc_format(irc, "v:", "OPERWALL", args[0]); - else - return 0; - - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_whois(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - if (args[1]) { - buf = irc_format(irc, "vvn", "WHOIS", args[0], args[1]); - irc->whois.nick = g_strdup(args[1]); - } else { - buf = irc_format(irc, "vn", "WHOIS", args[0]); - irc->whois.nick = g_strdup(args[0]); - } - - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -int -irc_cmd_whowas(struct irc_conn *irc, G_GNUC_UNUSED const char *cmd, - G_GNUC_UNUSED const char *target, const char **args) -{ - char *buf; - - if (!args || !args[0]) - return 0; - - buf = irc_format(irc, "vn", "WHOWAS", args[0]); - - irc->whois.nick = g_strdup(args[0]); - irc_send(irc, buf); - g_free(buf); - - return 0; -} - -static void irc_do_mode(struct irc_conn *irc, const char *target, const char *sign, char **ops) -{ - char *buf, mode[5]; - int i = 0; - - if (!sign) - return; - - while (ops[i]) { - if (ops[i + 2] && ops[i + 4]) { - g_snprintf(mode, sizeof(mode), "%s%s%s%s", sign, - ops[i], ops[i + 2], ops[i + 4]); - buf = irc_format(irc, "vcvnnn", "MODE", target, mode, - ops[i + 1], ops[i + 3], ops[i + 5]); - i += 6; - } else if (ops[i + 2]) { - g_snprintf(mode, sizeof(mode), "%s%s%s", - sign, ops[i], ops[i + 2]); - buf = irc_format(irc, "vcvnn", "MODE", target, mode, - ops[i + 1], ops[i + 3]); - i += 4; - } else { - g_snprintf(mode, sizeof(mode), "%s%s", sign, ops[i]); - buf = irc_format(irc, "vcvn", "MODE", target, mode, ops[i + 1]); - i += 2; - } - irc_send(irc, buf); - g_free(buf); - } -} diff --git a/libpurple/protocols/irc/dcc_send.c b/libpurple/protocols/irc/dcc_send.c deleted file mode 100644 index 35fc61518c..0000000000 --- a/libpurple/protocols/irc/dcc_send.c +++ /dev/null @@ -1,413 +0,0 @@ -/** - * purple - * - * Copyright (C) 2004, Timothy T Ringenbach <omarvo@hotmail.com> - * Copyright (C) 2003, Robbert Haarman <purple@inglorion.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <errno.h> - -#include <glib/gi18n-lib.h> - -#ifndef _WIN32 -# include <arpa/inet.h> -#endif - -#include <purple.h> -#include "libpurple/glibcompat.h" - -#include "irc.h" - -struct _IrcXfer { - PurpleXfer parent; - - /* receive properties */ - gchar *ip; - guint remote_port; - - /* send properties */ - GSocketService *service; - GSocketConnection *conn; - gint inpa; - guchar *rxqueue; - guint rxlen; -}; - -G_DEFINE_DYNAMIC_TYPE(IrcXfer, irc_xfer, PURPLE_TYPE_XFER); - -/*************************************************************************** - * Functions related to receiving files via DCC SEND - ***************************************************************************/ - -/* - * This function is called whenever data is received. - * It sends the acknowledgement (in the form of a total byte count as an - * unsigned 4 byte integer in network byte order) - */ -static void -irc_dccsend_recv_ack(PurpleXfer *xfer, G_GNUC_UNUSED const guchar *data, - G_GNUC_UNUSED size_t size) -{ - guint32 l; - gssize result; - - if(purple_xfer_get_xfer_type(xfer) != PURPLE_XFER_TYPE_RECEIVE) { - return; - } - - l = g_htonl(purple_xfer_get_bytes_sent(xfer)); - result = purple_xfer_write(xfer, (guchar *)&l, sizeof(l)); - if (result != sizeof(l)) { - purple_debug_error("irc", "unable to send acknowledgement: %s\n", g_strerror(errno)); - /* TODO: We should probably close the connection here or something. */ - } -} - -static void irc_dccsend_recv_init(PurpleXfer *xfer) { - IrcXfer *xd = IRC_XFER(xfer); - - purple_xfer_start(xfer, -1, xd->ip, xd->remote_port); -} - -/* This function makes the necessary arrangements for receiving files */ -void irc_dccsend_recv(struct irc_conn *irc, const char *from, const char *msg) { - IrcXfer *xfer; - gchar **token; - GString *filename; - int i = 0; - guint32 nip; - - token = g_strsplit(msg, " ", 0); - if (!token[0] || !token[1] || !token[2]) { - g_strfreev(token); - return; - } - - filename = g_string_new(""); - if (token[0][0] == '"') { - if (!strchr(&(token[0][1]), '"')) { - g_string_append(filename, &(token[0][1])); - for (i = 1; token[i]; i++) - if (!strchr(token[i], '"')) { - g_string_append_printf(filename, " %s", token[i]); - } else { - g_string_append_len(filename, token[i], strlen(token[i]) - 1); - break; - } - } else { - g_string_append_len(filename, &(token[0][1]), strlen(&(token[0][1])) - 1); - } - } else { - g_string_append(filename, token[0]); - } - - if (!token[i] || !token[i+1] || !token[i+2]) { - g_strfreev(token); - g_string_free(filename, TRUE); - return; - } - i++; - - xfer = g_object_new( - IRC_TYPE_XFER, - "account", irc->account, - "type", PURPLE_XFER_TYPE_RECEIVE, - "remote-user", from, - NULL - ); - - purple_xfer_set_filename(PURPLE_XFER(xfer), filename->str); - - xfer->remote_port = atoi(token[i+1]); - - nip = strtoul(token[i], NULL, 10); - if (nip) { - GInetAddress *addr = g_inet_address_new_from_bytes( - (const guchar *)&nip, G_SOCKET_FAMILY_IPV4); - xfer->ip = g_inet_address_to_string(addr); - g_object_unref(addr); - } else { - xfer->ip = g_strdup(token[i]); - } - - purple_debug_info("irc", "Receiving file (%s) from %s", filename->str, xfer->ip); - purple_xfer_set_size(PURPLE_XFER(xfer), token[i+2] ? atoi(token[i+2]) : 0); - - purple_xfer_request(PURPLE_XFER(xfer)); - - g_strfreev(token); - g_string_free(filename, TRUE); -} - -/******************************************************************* - * Functions related to sending files via DCC SEND - *******************************************************************/ - -/* just in case you were wondering, this is why DCC is crappy */ -static void -irc_dccsend_send_read(gpointer data, int source, - G_GNUC_UNUSED PurpleInputCondition cond) -{ - PurpleXfer *xfer = PURPLE_XFER(data); - IrcXfer *xd = IRC_XFER(xfer); - char buffer[64]; - int len; - - len = read(source, buffer, sizeof(buffer)); - - if (len < 0 && errno == EAGAIN) - return; - else if (len <= 0) { - /* XXX: Shouldn't this be canceling the transfer? */ - g_clear_handle_id(&xd->inpa, g_source_remove); - return; - } - - xd->rxqueue = g_realloc(xd->rxqueue, len + xd->rxlen); - memcpy(xd->rxqueue + xd->rxlen, buffer, len); - xd->rxlen += len; - - while (1) { - gint32 val; - size_t acked; - - if (xd->rxlen < 4) - break; - - memcpy(&val, xd->rxqueue, sizeof(val)); - acked = g_ntohl(val); - - xd->rxlen -= 4; - if (xd->rxlen) { - unsigned char *tmp = g_memdup2(xd->rxqueue + 4, xd->rxlen); - g_free(xd->rxqueue); - xd->rxqueue = tmp; - } else { - g_free(xd->rxqueue); - xd->rxqueue = NULL; - } - - if ((goffset)acked >= purple_xfer_get_size(xfer)) { - g_clear_handle_id(&xd->inpa, g_source_remove); - purple_xfer_set_completed(xfer, TRUE); - purple_xfer_end(xfer); - return; - } - } -} - -static gssize irc_dccsend_send_write(PurpleXfer *xfer, const guchar *buffer, size_t size) -{ - gssize s; - gssize ret; - - s = MIN((gssize)purple_xfer_get_bytes_remaining(xfer), (gssize)size); - if (!s) { - return 0; - } - - ret = PURPLE_XFER_CLASS(irc_xfer_parent_class)->write(xfer, buffer, s); - - if (ret < 0 && errno == EAGAIN) { - ret = 0; - } - - return ret; -} - -static void -irc_dccsend_send_connected(G_GNUC_UNUSED GSocketService *service, - GSocketConnection *connection, - GObject *source_object, G_GNUC_UNUSED gpointer data) -{ - PurpleXfer *xfer = PURPLE_XFER(source_object); - IrcXfer *xd = IRC_XFER(xfer); - GSocket *sock; - int fd = -1; - - xd->conn = g_object_ref(connection); - g_socket_service_stop(xd->service); - g_clear_object(&xd->service); - - sock = g_socket_connection_get_socket(connection); - fd = g_socket_get_fd(sock); - _purple_network_set_common_socket_flags(fd); - - xd->inpa = purple_input_add(fd, PURPLE_INPUT_READ, irc_dccsend_send_read, - xfer); - /* Start the transfer */ - purple_xfer_start(xfer, fd, NULL, 0); -} - -/* - * This function is called after the user has selected a file to send. - */ -static void -irc_dccsend_send_init(PurpleXfer *xfer) -{ - IrcXfer *xd = IRC_XFER(xfer); - PurpleConnection *gc = - purple_account_get_connection(purple_xfer_get_account(xfer)); - struct irc_conn *irc; - const char *arg[2]; - char *tmp; - GInetAddress *addr = NULL; - const guint8 *bytes = NULL; - guint32 ip = 0; - guint16 port; - GError *error = NULL; - - purple_xfer_set_filename( - xfer, g_path_get_basename(purple_xfer_get_local_filename(xfer))); - - /* Create a listening socket */ - xd->service = g_socket_service_new(); - if (xd->service == NULL) { - purple_notify_error(gc, NULL, _("File Transfer Failed"), - _("Unable to open a listening port."), - purple_request_cpar_from_connection(gc)); - purple_xfer_cancel_local(xfer); - return; - } - - /* Monitor the listening socket */ - g_signal_connect(xd->service, "incoming", - G_CALLBACK(irc_dccsend_send_connected), NULL); - - port = purple_socket_listener_add_any_inet_port( - G_SOCKET_LISTENER(xd->service), G_OBJECT(xfer), &error); - if (port != 0) { - purple_xfer_set_local_port(xfer, port); - } else { - purple_notify_error(gc, NULL, _("File Transfer Failed"), - _("Unable to open a listening port."), - purple_request_cpar_from_connection(gc)); - g_error_free(error); - g_clear_object(&xd->service); - purple_xfer_cancel_local(xfer); - return; - } - - irc = purple_connection_get_protocol_data(gc); - - purple_debug_misc("irc", "port is %hu\n", port); - - /* Send the intended recipient the DCC request */ - arg[0] = purple_xfer_get_remote_user(xfer); - tmp = purple_network_get_my_ip_from_gio(irc->conn); - addr = g_inet_address_new_from_string(tmp); - bytes = g_inet_address_to_bytes(addr); - ip = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; - g_object_unref(addr); - g_free(tmp); - arg[1] = tmp = g_strdup_printf( - "\001DCC SEND \"%s\" %u %hu %" G_GOFFSET_FORMAT "\001", - purple_xfer_get_filename(xfer), ip, port, - purple_xfer_get_size(xfer)); - - irc_cmd_privmsg(purple_connection_get_protocol_data(gc), "msg", NULL, arg); - g_free(tmp); -} - -PurpleXfer * -irc_dccsend_new_xfer(G_GNUC_UNUSED PurpleProtocolXfer *prplxfer, - PurpleConnection *gc, const char *who) -{ - return g_object_new( - IRC_TYPE_XFER, - "account", purple_connection_get_account(gc), - "type", PURPLE_XFER_TYPE_SEND, - "remote-user", who, - NULL - ); -} - -/** - * Purple calls this function when the user selects Send File from the - * buddy menu - * It sets up the PurpleXfer struct and tells Purple to go ahead - */ -void irc_dccsend_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who, const char *file) { - PurpleXfer *xfer = irc_dccsend_new_xfer(prplxfer, gc, who); - - /* Perform the request */ - if (file) - purple_xfer_request_accepted(xfer, file); - else - purple_xfer_request(xfer); -} - -/****************************************************************************** - * PurpleXfer Implementation - *****************************************************************************/ -static void -irc_dccsend_init(PurpleXfer *xfer) { - PurpleXferType type = purple_xfer_get_xfer_type(xfer); - - if(type == PURPLE_XFER_TYPE_SEND) { - irc_dccsend_send_init(xfer); - } else if(type == PURPLE_XFER_TYPE_RECEIVE) { - irc_dccsend_recv_init(xfer); - } -} - -/****************************************************************************** - * GObject Implementation - *****************************************************************************/ -static void -irc_xfer_init(G_GNUC_UNUSED IrcXfer *xfer) { -} - -static void -irc_xfer_finalize(GObject *obj) { - IrcXfer *xfer = IRC_XFER(obj); - - /* clean up the receiving proprties */ - g_free(xfer->ip); - g_free(xfer->rxqueue); - - /* clean up the sending properties */ - if (xfer->service) { - g_socket_service_stop(xfer->service); - } - g_clear_object(&xfer->service); - g_clear_handle_id(&xfer->inpa, g_source_remove); - g_clear_object(&xfer->conn); - - G_OBJECT_CLASS(irc_xfer_parent_class)->finalize(obj); -} - -static void -irc_xfer_class_finalize(G_GNUC_UNUSED IrcXferClass *klass) { -} - -static void -irc_xfer_class_init(IrcXferClass *klass) { - GObjectClass *obj_class = G_OBJECT_CLASS(klass); - PurpleXferClass *xfer_class = PURPLE_XFER_CLASS(klass); - - obj_class->finalize = irc_xfer_finalize; - - xfer_class->init = irc_dccsend_init; - xfer_class->ack = irc_dccsend_recv_ack; - xfer_class->write = irc_dccsend_send_write; -} - -void -irc_xfer_register(GTypeModule *module) { - irc_xfer_register_type(module); -} diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c deleted file mode 100644 index 4304650b88..0000000000 --- a/libpurple/protocols/irc/irc.c +++ /dev/null @@ -1,1282 +0,0 @@ -/** - * purple - * - * Copyright (C) 2003, Robbert Haarman <purple@inglorion.net> - * Copyright (C) 2003, 2012 Ethan Blanton <elb@pidgin.im> - * Copyright (C) 2000-2003, Rob Flynn <rob@tgflinux.com> - * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <errno.h> - -#include <glib/gi18n-lib.h> - -#include <gplugin.h> -#include <gplugin-native.h> - -#include <purple.h> - -#include "irc.h" - -#define PING_TIMEOUT 60 - -struct _IRCProtocol { - PurpleProtocol parent; -}; - -static void irc_ison_buddy_init(char *name, struct irc_buddy *ib, GList **list); - -static GList *irc_status_types(PurpleProtocol *protocol, PurpleAccount *account); -/* static GList *irc_chat_info(PurpleConnection *gc); */ -static void irc_login(PurpleProtocol *protocol, PurpleAccount *account); -static void irc_login_cb(GObject *source, GAsyncResult *res, gpointer user_data); -static void irc_close(PurpleProtocol *protocol, PurpleConnection *gc); -static int irc_im_send(PurpleProtocolIM *im, PurpleConnection *gc, PurpleMessage *msg); -static int irc_chat_send(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, PurpleMessage *msg); -static void irc_chat_join(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, GHashTable *data); -static void irc_read_input_cb(GObject *source, GAsyncResult *res, gpointer data); - -static guint irc_nick_hash(const char *nick); -static gboolean irc_nick_equal(const char *nick1, const char *nick2); -static void irc_buddy_free(struct irc_buddy *ib); - -PurpleProtocol *_irc_protocol = NULL; - -static gint -irc_uri_handler_match_server(PurpleAccount *account, const gchar *match_server) -{ - const gchar *protocol_id; - const gchar *username; - gchar *server; - - protocol_id = purple_account_get_protocol_id(account); - - if (!purple_strequal(protocol_id, "prpl-irc") || - !purple_account_is_connected(account)) { - return -1; - } - - if (match_server == NULL || match_server[0] == '\0') { - /* No server specified, match any IRC account */ - return 0; - } - - username = purple_contact_info_get_username(PURPLE_CONTACT_INFO(account)); - server = strchr(username, '@'); - - /* +1 to skip '@' */ - if (server == NULL || !purple_strequal(match_server, server + 1)) { - return -1; - } - - return 0; -} - -static gboolean -irc_uri_handler(const gchar *scheme, const gchar *uri, GHashTable *params) -{ - PurpleAccountManager *manager = NULL; - gchar *target; - gchar *server; - gchar **target_tokens; - PurpleAccount *account; - gchar **modifier; - gboolean isnick = FALSE; - - g_return_val_if_fail(uri != NULL, FALSE); - - if (!purple_strequal(scheme, "irc")) { - /* Not a scheme we handle here */ - return FALSE; - } - - if (g_str_has_prefix(uri, "//")) { - /* Skip initial '//' if it exists */ - uri += 2; - } - - /* Find the target (aka room or user) */ - target = strchr(uri, '/'); - - /* [1] to skip the '/' */ - if (target == NULL || target[1] == '\0') { - purple_debug_warning("irc", - "URI missing valid target: %s", uri); - return FALSE; - } - - server = g_strndup(uri, target - uri); - - /* Find account with correct server */ - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_custom(manager, - (GEqualFunc)irc_uri_handler_match_server, - server); - - if (account == NULL) { - purple_debug_warning("irc", - "No account online on '%s' for handling URI", - server); - g_free(server); - return FALSE; - } - - /* Tokenize modifiers, +1 to skip the initial '/' */ - target_tokens = g_strsplit(target + 1, ",", 0); - target = g_strdup_printf("#%s", target_tokens[0]); - - /* Parse modifiers, start at 1 to skip the actual target */ - for (modifier = target_tokens + 1; *modifier != NULL; ++modifier) { - if (purple_strequal(*modifier, "isnick")) { - isnick = TRUE; - break; - } - } - - g_strfreev(target_tokens); - - if (isnick) { - PurpleConversation *im; - - /* 'server' isn't needed here. Free it immediately. */ - g_free(server); - - /* +1 to skip '#' target prefix */ - im = purple_im_conversation_new(account, target + 1); - g_free(target); - - purple_conversation_present(im); - - if (params != NULL) { - const gchar *msg = g_hash_table_lookup(params, "msg"); - - if (msg != NULL) { - purple_conversation_send_confirm(im, msg); - } - } - - return TRUE; - } else { - GHashTable *components; - - components = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, g_free); - - /* Transfer ownership of these to the hash table */ - g_hash_table_insert(components, "server", server); - g_hash_table_insert(components, "channel", target); - - if (params != NULL) { - const gchar *key = g_hash_table_lookup(params, "key"); - - if (key != NULL) { - g_hash_table_insert(components, "password", - g_strdup(key)); - } - } - - purple_serv_join_chat(purple_account_get_connection(account), - components); - g_hash_table_destroy(components); - return TRUE; - } - - return FALSE; -} - -static void -irc_view_motd(G_GNUC_UNUSED GSimpleAction *action, - GVariant *parameter, - G_GNUC_UNUSED gpointer data) -{ - const gchar *account_id = NULL; - PurpleAccountManager *manager = NULL; - PurpleAccount *account = NULL; - PurpleConnection *gc = NULL; - struct irc_conn *irc; - char *title, *body; - - if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - g_critical("IRC View MOTD action parameter is of incorrect type %s", - g_variant_get_type_string(parameter)); - } - - account_id = g_variant_get_string(parameter, NULL); - manager = purple_account_manager_get_default(); - account = purple_account_manager_find_by_id(manager, account_id); - gc = purple_account_get_connection(account); - - if (gc == NULL || purple_connection_get_protocol_data(gc) == NULL) { - purple_debug_error("irc", "got MOTD request for NULL gc"); - return; - } - irc = purple_connection_get_protocol_data(gc); - if (irc->motd == NULL) { - purple_notify_error(gc, _("Error displaying MOTD"), - _("No MOTD available"), - _("There is no MOTD associated with this connection."), - purple_request_cpar_from_connection(gc)); - return; - } - title = g_strdup_printf(_("MOTD for %s"), irc->server); - body = g_strdup_printf("<span style=\"font-family: monospace;\">%s</span>", irc->motd->str); - purple_notify_formatted(gc, title, title, NULL, body, NULL, NULL); - g_free(title); - g_free(body); -} - -static int -irc_send_raw(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, const gchar *buf, gint len) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - if (len == -1) { - len = strlen(buf); - } - irc_send_len(irc, buf, len); - return len; -} - -static void -irc_push_bytes_cb(GObject *source, GAsyncResult *res, gpointer data) -{ - PurpleQueuedOutputStream *stream = PURPLE_QUEUED_OUTPUT_STREAM(source); - PurpleConnection *gc = data; - gboolean result; - GError *error = NULL; - - result = purple_queued_output_stream_push_bytes_finish(stream, - res, &error); - - if (!result) { - purple_queued_output_stream_clear_queue(stream); - - g_prefix_error(&error, "%s", _("Lost connection with server: ")); - purple_connection_take_error(gc, error); - return; - } -} - -int irc_send(struct irc_conn *irc, const char *buf) -{ - return irc_send_len(irc, buf, strlen(buf)); -} - -int -irc_send_len(struct irc_conn *irc, const char *buf, G_GNUC_UNUSED int buflen) { - char *tosend = g_strdup(buf); - int len; - GBytes *data; - - purple_signal_emit(_irc_protocol, "irc-sending-text", purple_account_get_connection(irc->account), &tosend); - - if (tosend == NULL) - return 0; - - if (purple_debug_is_verbose()) { - gchar *clean = g_utf8_make_valid(tosend, -1); - clean = g_strstrip(clean); - purple_debug_misc("irc", "<< %s\n", clean); - g_free(clean); - } - - len = strlen(tosend); - data = g_bytes_new_take(tosend, len); - purple_queued_output_stream_push_bytes_async(irc->output, data, - G_PRIORITY_DEFAULT, irc->cancellable, irc_push_bytes_cb, - purple_account_get_connection(irc->account)); - g_bytes_unref(data); - - return len; -} - -/* XXX I don't like messing directly with these buddies */ -gboolean irc_blist_timeout(struct irc_conn *irc) -{ - if (irc->ison_outstanding) { - return TRUE; - } - - g_hash_table_foreach(irc->buddies, (GHFunc)irc_ison_buddy_init, - (gpointer *)&irc->buddies_outstanding); - - irc_buddy_query(irc); - - return TRUE; -} - -void irc_buddy_query(struct irc_conn *irc) -{ - GList *lp; - GString *string; - struct irc_buddy *ib; - char *buf; - - string = g_string_sized_new(512); - - while ((lp = g_list_first(irc->buddies_outstanding))) { - ib = (struct irc_buddy *)lp->data; - if (string->len + strlen(ib->name) + 1 > 450) - break; - g_string_append_printf(string, "%s ", ib->name); - ib->new_online_status = FALSE; - irc->buddies_outstanding = g_list_delete_link(irc->buddies_outstanding, lp); - } - - if (string->len) { - buf = irc_format(irc, "vn", "ISON", string->str); - irc_send(irc, buf); - g_free(buf); - irc->ison_outstanding = TRUE; - } else - irc->ison_outstanding = FALSE; - - g_string_free(string, TRUE); -} - -static void -irc_ison_buddy_init(G_GNUC_UNUSED char *name, struct irc_buddy *ib, - GList **list) -{ - *list = g_list_append(*list, ib); -} - - -static void irc_ison_one(struct irc_conn *irc, struct irc_buddy *ib) -{ - char *buf; - - if (irc->buddies_outstanding != NULL) { - irc->buddies_outstanding = g_list_append(irc->buddies_outstanding, ib); - return; - } - - ib->new_online_status = FALSE; - buf = irc_format(irc, "vn", "ISON", ib->name); - irc_send(irc, buf); - g_free(buf); -} - -static GList * -irc_protocol_get_account_options(G_GNUC_UNUSED PurpleProtocol *protocol) { - PurpleAccountOption *option; - GList *opts = NULL; - - option = purple_account_option_int_new(_("Port"), "port", - IRC_DEFAULT_PORT); - opts = g_list_append(opts, option); - - option = purple_account_option_string_new(_("Encodings"), "encoding", - IRC_DEFAULT_CHARSET); - opts = g_list_append(opts, option); - - option = purple_account_option_bool_new(_("Auto-detect incoming UTF-8"), - "autodetect_utf8", - IRC_DEFAULT_AUTODETECT); - opts = g_list_append(opts, option); - - option = purple_account_option_string_new(_("Ident name"), "username", ""); - opts = g_list_append(opts, option); - - option = purple_account_option_string_new(_("Real name"), "realname", ""); - opts = g_list_append(opts, option); - - /* - option = purple_account_option_string_new(_("Quit message"), "quitmsg", - IRC_DEFAULT_QUIT); - opts = g_list_append(opts, option); - */ - - option = purple_account_option_bool_new(_("Use SSL"), "ssl", FALSE); - opts = g_list_append(opts, option); - - option = purple_account_option_bool_new(_("Authenticate with SASL"), - "sasl", FALSE); - opts = g_list_append(opts, option); - - option = purple_account_option_bool_new(_("Allow plaintext SASL auth over " - "unencrypted connection"), - "auth_plain_in_clear", FALSE); - opts = g_list_append(opts, option); - - return opts; -} - -static GList * -irc_protocol_get_user_splits(G_GNUC_UNUSED PurpleProtocol *protocol) { - PurpleAccountUserSplit *split; - - split = purple_account_user_split_new(_("Server"), IRC_DEFAULT_SERVER, - '@'); - - return g_list_append(NULL, split); -} - -static GList * -irc_status_types(G_GNUC_UNUSED PurpleProtocol *protocol, - G_GNUC_UNUSED PurpleAccount *account) -{ - PurpleStatusType *type; - GList *types = NULL; - - type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE); - types = g_list_append(types, type); - - type = purple_status_type_new_with_attrs( - PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE, - "message", _("Message"), purple_value_new(G_TYPE_STRING), - NULL); - types = g_list_append(types, type); - - type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE); - types = g_list_append(types, type); - - return types; -} - -static const gchar * -irc_protocol_actions_get_prefix(G_GNUC_UNUSED PurpleProtocolActions *actions) { - return "prpl-irc"; -} - -static GActionGroup * -irc_protocol_actions_get_action_group(G_GNUC_UNUSED PurpleProtocolActions *actions, - G_GNUC_UNUSED PurpleConnection *connection) -{ - GSimpleActionGroup *group = NULL; - GActionEntry entries[] = { - { - .name = "view-motd", - .activate = irc_view_motd, - .parameter_type = "s", - }, - }; - gsize nentries = G_N_ELEMENTS(entries); - - group = g_simple_action_group_new(); - g_action_map_add_action_entries(G_ACTION_MAP(group), entries, nentries, - NULL); - - return G_ACTION_GROUP(group); -} - -static GMenu * -irc_protocol_actions_get_menu(G_GNUC_UNUSED PurpleProtocolActions *actions, - G_GNUC_UNUSED PurpleConnection *connection) -{ - GMenu *menu = NULL; - GMenuItem *item = NULL; - - menu = g_menu_new(); - - item = g_menu_item_new(_("View MOTD"), "prpl-irc.view-motd"); - g_menu_item_set_attribute(item, PURPLE_MENU_ATTRIBUTE_DYNAMIC_TARGET, "s", - "account"); - g_menu_append_item(menu, item); - - g_object_unref(item); - - - return menu; -} - -static GList * -irc_chat_join_info(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - G_GNUC_UNUSED PurpleConnection *gc) -{ - GList *m = NULL; - PurpleProtocolChatEntry *pce; - - pce = g_new0(PurpleProtocolChatEntry, 1); - pce->label = _("_Channel"); - pce->identifier = "channel"; - pce->required = TRUE; - m = g_list_append(m, pce); - - pce = g_new0(PurpleProtocolChatEntry, 1); - pce->label = _("_Password"); - pce->identifier = "password"; - pce->secret = TRUE; - m = g_list_append(m, pce); - - return m; -} - -static GHashTable * -irc_chat_info_defaults(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - G_GNUC_UNUSED PurpleConnection *gc, - const gchar *chat_name) -{ - GHashTable *defaults; - - defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); - - if (chat_name != NULL) - g_hash_table_insert(defaults, "channel", g_strdup(chat_name)); - - return defaults; -} - -static void -irc_login(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleAccount *account) { - PurpleConnection *gc; - struct irc_conn *irc; - char **userparts; - const char *username = NULL; - GSocketClient *client; - GError *error = NULL; - - username = purple_contact_info_get_username(PURPLE_CONTACT_INFO(account)); - - gc = purple_account_get_connection(account); - purple_connection_set_flags(gc, PURPLE_CONNECTION_FLAG_NO_NEWLINES | - PURPLE_CONNECTION_FLAG_NO_IMAGES); - - if (strpbrk(username, " \t\v\r\n") != NULL) { - purple_connection_take_error(gc, g_error_new_literal( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, - _("IRC nick and server may not contain whitespace"))); - return; - } - - irc = g_new0(struct irc_conn, 1); - purple_connection_set_protocol_data(gc, irc); - irc->account = account; - irc->cancellable = g_cancellable_new(); - - userparts = g_strsplit(username, "@", 2); - purple_connection_set_display_name(gc, userparts[0]); - irc->server = g_strdup(userparts[1]); - g_strfreev(userparts); - - irc->buddies = g_hash_table_new_full((GHashFunc)irc_nick_hash, (GEqualFunc)irc_nick_equal, - NULL, (GDestroyNotify)irc_buddy_free); - irc->cmds = g_hash_table_new(g_str_hash, g_str_equal); - irc_cmd_table_build(irc); - irc->msgs = g_hash_table_new(g_str_hash, g_str_equal); - irc_msg_table_build(irc); - - client = purple_gio_socket_client_new(account, &error); - - if (client == NULL) { - purple_connection_take_error(gc, error); - return; - } - - /* Optionally use TLS if it's set in the account settings */ - g_socket_client_set_tls(client, - purple_account_get_bool(account, "ssl", FALSE)); - - g_socket_client_connect_to_host_async(client, irc->server, - purple_account_get_int(account, "port", - g_socket_client_get_tls(client) ? - IRC_DEFAULT_SSL_PORT : - IRC_DEFAULT_PORT), - irc->cancellable, irc_login_cb, gc); - g_object_unref(client); -} - -static gboolean do_login(PurpleConnection *gc) { - char *buf = NULL; - char *server; - const char *nickname, *identname, *realname; - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - const char *pass = purple_connection_get_password(gc); - const gboolean use_sasl = purple_account_get_bool(irc->account, "sasl", FALSE); - - if (pass && *pass) { - if (use_sasl) - buf = irc_format(irc, "vv:", "CAP", "REQ", "sasl"); - else - buf = irc_format(irc, "v:", "PASS", pass); - if (irc_send(irc, buf) < 0) { - g_free(buf); - return FALSE; - } - g_free(buf); - } - - nickname = purple_connection_get_display_name(gc); - - realname = purple_account_get_string(irc->account, "realname", ""); - if(realname == NULL || *realname == '\0') { - realname = IRC_DEFAULT_ALIAS; - } - - identname = purple_account_get_string(irc->account, "username", ""); - if(identname == NULL || *identname == '\0') { - identname = nickname; - } - - if (*irc->server == ':') { - /* Same as hostname, above. */ - server = g_strdup_printf("0%s", irc->server); - } else { - server = g_strdup(irc->server); - } - - buf = irc_format(irc, "vvvv:", "USER", identname, "*", server, realname); - g_free(server); - if (irc_send(irc, buf) < 0) { - g_free(buf); - return FALSE; - } - g_free(buf); - buf = irc_format(irc, "vn", "NICK", nickname); - irc->reqnick = g_strdup(nickname); - irc->nickused = FALSE; - if (irc_send(irc, buf) < 0) { - g_free(buf); - return FALSE; - } - g_free(buf); - - irc->recv_time = time(NULL); - - return TRUE; -} - -static void -irc_login_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - PurpleConnection *gc = user_data; - GSocketConnection *conn; - GError *error = NULL; - struct irc_conn *irc; - - conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source), - res, &error); - - if (conn == NULL) { - g_prefix_error(&error, "%s", _("Unable to connect: ")); - purple_connection_take_error(gc, error); - return; - } - - irc = purple_connection_get_protocol_data(gc); - irc->conn = conn; - irc->output = purple_queued_output_stream_new( - g_io_stream_get_output_stream(G_IO_STREAM(irc->conn))); - - if (do_login(gc)) { - irc->input = g_data_input_stream_new( - g_io_stream_get_input_stream( - G_IO_STREAM(irc->conn))); - g_data_input_stream_read_line_async(irc->input, - G_PRIORITY_DEFAULT, irc->cancellable, - irc_read_input_cb, gc); - } -} - -static void -irc_close(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleConnection *gc) { - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - - if (irc == NULL) - return; - - if (irc->conn != NULL) - irc_cmd_quit(irc, "quit", NULL, NULL); - - if (irc->cancellable != NULL) { - g_cancellable_cancel(irc->cancellable); - g_clear_object(&irc->cancellable); - } - - if (irc->conn != NULL) { - purple_gio_graceful_close(G_IO_STREAM(irc->conn), - G_INPUT_STREAM(irc->input), - G_OUTPUT_STREAM(irc->output)); - } - - g_clear_object(&irc->input); - g_clear_object(&irc->output); - g_clear_object(&irc->conn); - - g_clear_handle_id(&irc->timer, g_source_remove); - g_hash_table_destroy(irc->cmds); - g_hash_table_destroy(irc->msgs); - g_hash_table_destroy(irc->buddies); - if (irc->motd) - g_string_free(irc->motd, TRUE); - g_free(irc->server); - - g_free(irc->mode_chars); - g_free(irc->reqnick); - - g_clear_object(&irc->hasl_ctx); - - g_free(irc); -} - -static int -irc_im_send(G_GNUC_UNUSED PurpleProtocolIM *im, PurpleConnection *gc, - PurpleMessage *msg) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - char *plain; - const char *args[2]; - - args[0] = irc_nick_skip_mode(irc, purple_message_get_recipient(msg)); - - purple_markup_html_to_xhtml(purple_message_get_contents(msg), - NULL, &plain); - args[1] = plain; - - irc_cmd_privmsg(irc, "msg", NULL, args); - g_free(plain); - return 1; -} - -static void -irc_get_info(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, const gchar *who) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - const char *args[2]; - args[0] = who; - args[1] = NULL; - irc_cmd_whois(irc, "whois", NULL, args); -} - -static void -irc_set_status(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleAccount *account, PurpleStatus *status) -{ - PurpleConnection *gc = purple_account_get_connection(account); - struct irc_conn *irc; - const char *args[1]; - const char *status_id = purple_status_get_id(status); - - g_return_if_fail(gc != NULL); - irc = purple_connection_get_protocol_data(gc); - - if (!purple_status_is_active(status)) - return; - - args[0] = NULL; - - if (purple_strequal(status_id, "away")) { - args[0] = purple_status_get_attr_string(status, "message"); - if ((args[0] == NULL) || (*args[0] == '\0')) - args[0] = _("Away"); - irc_cmd_away(irc, "away", NULL, args); - } else if (purple_strequal(status_id, "available")) { - irc_cmd_away(irc, "back", NULL, args); - } -} - -static void -irc_add_buddy(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, PurpleBuddy *buddy, - G_GNUC_UNUSED PurpleGroup *group, - G_GNUC_UNUSED const gchar *message) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - struct irc_buddy *ib; - const char *bname = purple_buddy_get_name(buddy); - - ib = g_hash_table_lookup(irc->buddies, bname); - if (ib != NULL) { - ib->ref++; - purple_protocol_got_user_status(irc->account, bname, - ib->online ? "available" : "offline", NULL); - } else { - ib = g_new0(struct irc_buddy, 1); - ib->name = g_strdup(bname); - ib->ref = 1; - g_hash_table_replace(irc->buddies, ib->name, ib); - } - - /* if the timer isn't set, this is during signon, so we don't want to flood - * ourself off with ISON's, so we don't, but after that we want to know when - * someone's online asap */ - if (irc->timer) - irc_ison_one(irc, ib); -} - -static void -irc_remove_buddy(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc, PurpleBuddy *buddy, - G_GNUC_UNUSED PurpleGroup *group) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - struct irc_buddy *ib; - - ib = g_hash_table_lookup(irc->buddies, purple_buddy_get_name(buddy)); - if (ib && --ib->ref == 0) { - g_hash_table_remove(irc->buddies, purple_buddy_get_name(buddy)); - } -} - -static void -irc_read_input_cb(GObject *source, GAsyncResult *res, gpointer data) -{ - PurpleConnection *gc = data; - struct irc_conn *irc; - gchar *line; - gsize len; - gsize start = 0; - GError *error = NULL; - - line = g_data_input_stream_read_line_finish( - G_DATA_INPUT_STREAM(source), res, &len, &error); - - if (line == NULL && error != NULL) { - g_prefix_error(&error, "%s", _("Lost connection with server: ")); - purple_connection_take_error(gc, error); - return; - } else if (line == NULL) { - purple_connection_take_error(gc, g_error_new_literal( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Server closed the connection"))); - return; - } - - irc = purple_connection_get_protocol_data(gc); - - purple_connection_update_last_received(gc); - - if (len > 0 && line[len - 1] == '\r') - line[len - 1] = '\0'; - - /* This is a hack to work around the fact that marv gets messages - * with null bytes in them while using some weird irc server at work - */ - while (start < len && line[start] == '\0') - ++start; - - if (start < len) { - irc_parse_msg(irc, line + start); - } - - g_free(line); - - g_data_input_stream_read_line_async(irc->input, - G_PRIORITY_DEFAULT, irc->cancellable, - irc_read_input_cb, gc); -} - -static void -irc_chat_join(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, GHashTable *data) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - const char *args[2]; - - args[0] = g_hash_table_lookup(data, "channel"); - args[1] = g_hash_table_lookup(data, "password"); - irc_cmd_join(irc, "join", NULL, args); -} - -static gchar * -irc_get_chat_name(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - GHashTable *data) -{ - return g_strdup(g_hash_table_lookup(data, "channel")); -} - -static void -irc_chat_invite(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, gint id, - G_GNUC_UNUSED const gchar *message, const gchar *name) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - PurpleConversation *convo; - PurpleConversationManager *manager; - const char *args[2]; - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find_chat_by_id(manager, - purple_connection_get_account(gc), - id); - if (!convo) { - purple_debug_error("irc", "Got chat invite request for bogus chat"); - return; - } - args[0] = name; - args[1] = purple_conversation_get_name(convo); - irc_cmd_invite(irc, "invite", purple_conversation_get_name(convo), args); -} - - -static void -irc_chat_leave(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, gint id) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - PurpleConversation *convo; - PurpleConversationManager *manager; - const char *args[2]; - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find_chat_by_id(manager, - purple_connection_get_account(gc), - id); - if (!convo) { - return; - } - - args[0] = purple_conversation_get_name(convo); - args[1] = NULL; - irc_cmd_part(irc, "part", purple_conversation_get_name(convo), args); - purple_serv_got_chat_left(gc, id); -} - -static gint -irc_chat_send(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, gint id, PurpleMessage *msg) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - PurpleConversation *convo; - PurpleConversationManager *manager; - const char *args[2]; - char *tmp; - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find_chat_by_id(manager, - purple_connection_get_account(gc), - id); - - if (!convo) { - purple_debug_error("irc", "chat send on nonexistent chat"); - return -EINVAL; - } - purple_markup_html_to_xhtml(purple_message_get_contents(msg), NULL, &tmp); - args[0] = purple_conversation_get_name(convo); - args[1] = tmp; - - irc_cmd_privmsg(irc, "msg", NULL, args); - - /* TODO: use msg */ - purple_serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), - purple_message_get_flags(msg), - purple_message_get_contents(msg), time(NULL)); - g_free(tmp); - return 0; -} - -static guint irc_nick_hash(const char *nick) -{ - char *lc; - guint bucket; - - lc = g_utf8_strdown(nick, -1); - bucket = g_str_hash(lc); - g_free(lc); - - return bucket; -} - -static gboolean irc_nick_equal(const char *nick1, const char *nick2) -{ - return (purple_utf8_strcasecmp(nick1, nick2) == 0); -} - -static void irc_buddy_free(struct irc_buddy *ib) -{ - g_free(ib->name); - g_free(ib); -} - -static void -irc_chat_set_topic(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat, - PurpleConnection *gc, gint id, const gchar *topic) -{ - PurpleConversation *conv; - PurpleConversationManager *manager; - char *buf; - const char *name = NULL; - struct irc_conn *irc; - - manager = purple_conversation_manager_get_default(); - conv = purple_conversation_manager_find_chat_by_id(manager, - purple_connection_get_account(gc), - id); - - irc = purple_connection_get_protocol_data(gc); - name = purple_conversation_get_name(conv); - - if (name == NULL) { - return; - } - - buf = irc_format(irc, "vt:", "TOPIC", name, topic); - irc_send(irc, buf); - g_free(buf); -} - -static PurpleRoomlist * -irc_roomlist_get_list(G_GNUC_UNUSED PurpleProtocolRoomlist *protocol_roomlist, - PurpleConnection *gc) -{ - struct irc_conn *irc; - char *buf; - - irc = purple_connection_get_protocol_data(gc); - - if (irc->roomlist) - g_object_unref(irc->roomlist); - - irc->roomlist = purple_roomlist_new(purple_connection_get_account(gc)); - - buf = irc_format(irc, "v", "LIST"); - irc_send(irc, buf); - g_free(buf); - - return irc->roomlist; -} - -static void -irc_roomlist_cancel(G_GNUC_UNUSED PurpleProtocolRoomlist *protocol_roomlist, - PurpleRoomlist *list) -{ - PurpleAccount *account = purple_roomlist_get_account(list); - PurpleConnection *gc = purple_account_get_connection(account); - struct irc_conn *irc; - - if (gc == NULL) - return; - - irc = purple_connection_get_protocol_data(gc); - - purple_roomlist_set_in_progress(list, FALSE); - - if (irc->roomlist == list) { - irc->roomlist = NULL; - g_object_unref(list); - } -} - -static void -irc_keepalive(G_GNUC_UNUSED PurpleProtocolServer *protocol_server, - PurpleConnection *gc) -{ - struct irc_conn *irc = purple_connection_get_protocol_data(gc); - if ((time(NULL) - irc->recv_time) > PING_TIMEOUT) - irc_cmd_ping(irc, NULL, NULL, NULL); -} - -static const char * -irc_normalize(G_GNUC_UNUSED PurpleProtocolClient *client, - G_GNUC_UNUSED PurpleAccount *account, - const char *who) -{ - return purple_normalize_nocase(who); -} - -static gssize -irc_get_max_message_size(G_GNUC_UNUSED PurpleProtocolClient *client, - G_GNUC_UNUSED PurpleConversation *conv) -{ - /* TODO: this static value is got from pidgin-otr, but it depends on - * some factors, for example IRC channel name. */ - return 417; -} - -static void -irc_protocol_init(G_GNUC_UNUSED IRCProtocol *self) { -} - -static void -irc_protocol_class_init(IRCProtocolClass *klass) -{ - PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass); - - protocol_class->login = irc_login; - protocol_class->close = irc_close; - protocol_class->status_types = irc_status_types; - - protocol_class->get_account_options = irc_protocol_get_account_options; - protocol_class->get_user_splits = irc_protocol_get_user_splits; -} - -static void -irc_protocol_class_finalize(G_GNUC_UNUSED IRCProtocolClass *klass) -{ -} - -static void -irc_protocol_actions_iface_init(PurpleProtocolActionsInterface *iface) -{ - iface->get_prefix = irc_protocol_actions_get_prefix; - iface->get_action_group = irc_protocol_actions_get_action_group; - iface->get_menu = irc_protocol_actions_get_menu; -} - -static void -irc_protocol_client_iface_init(PurpleProtocolClientInterface *client_iface) -{ - client_iface->normalize = irc_normalize; - client_iface->get_max_message_size = irc_get_max_message_size; -} - -static void -irc_protocol_server_iface_init(PurpleProtocolServerInterface *server_iface) -{ - server_iface->set_status = irc_set_status; - server_iface->get_info = irc_get_info; - server_iface->add_buddy = irc_add_buddy; - server_iface->remove_buddy = irc_remove_buddy; - server_iface->keepalive = irc_keepalive; - server_iface->send_raw = irc_send_raw; -} - -static void -irc_protocol_im_iface_init(PurpleProtocolIMInterface *im_iface) -{ - im_iface->send = irc_im_send; -} - -static void -irc_protocol_chat_iface_init(PurpleProtocolChatInterface *chat_iface) -{ - chat_iface->info = irc_chat_join_info; - chat_iface->info_defaults = irc_chat_info_defaults; - chat_iface->join = irc_chat_join; - chat_iface->get_name = irc_get_chat_name; - chat_iface->invite = irc_chat_invite; - chat_iface->leave = irc_chat_leave; - chat_iface->send = irc_chat_send; - chat_iface->set_topic = irc_chat_set_topic; -} - -static void -irc_protocol_roomlist_iface_init(PurpleProtocolRoomlistInterface *roomlist_iface) -{ - roomlist_iface->get_list = irc_roomlist_get_list; - roomlist_iface->cancel = irc_roomlist_cancel; -} - -static void -irc_protocol_xfer_iface_init(PurpleProtocolXferInterface *xfer_iface) -{ - xfer_iface->send_file = irc_dccsend_send_file; - xfer_iface->new_xfer = irc_dccsend_new_xfer; -} - -G_DEFINE_DYNAMIC_TYPE_EXTENDED( - IRCProtocol, - irc_protocol, - PURPLE_TYPE_PROTOCOL, - G_TYPE_FLAG_FINAL, - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_ACTIONS, - irc_protocol_actions_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT, - irc_protocol_client_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER, - irc_protocol_server_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM, - irc_protocol_im_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CHAT, - irc_protocol_chat_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_ROOMLIST, - irc_protocol_roomlist_iface_init) - G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_XFER, - irc_protocol_xfer_iface_init)) - -static PurpleProtocol * -irc_protocol_new(void) { - return PURPLE_PROTOCOL(g_object_new( - IRC_TYPE_PROTOCOL, - "id", "prpl-irc", - "name", "IRC", - "description", _("Internet Relay Chat (IRC) is a text-based chat " - "system."), - "icon-name", "im-irc", - "icon-resource-path", "/im/pidgin/libpurple/irc/icons", - "options", OPT_PROTO_CHAT_TOPIC | OPT_PROTO_PASSWORD_OPTIONAL | - OPT_PROTO_SLASH_COMMANDS_NATIVE, - NULL)); -} - -static GPluginPluginInfo * -irc_query(G_GNUC_UNUSED GError **error) { - return purple_plugin_info_new( - "id", "prpl-irc", - "name", "IRC Protocol", - "version", DISPLAY_VERSION, - "category", N_("Protocol"), - "summary", N_("IRC Protocol Plugin"), - "description", N_("The IRC Protocol Plugin that Sucks Less"), - "website", PURPLE_WEBSITE, - "abi-version", PURPLE_ABI_VERSION, - "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL | - PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD, - NULL - ); -} - -static gboolean -irc_load(GPluginPlugin *plugin, GError **error) -{ - PurpleProtocolManager *manager = purple_protocol_manager_get_default(); - - irc_protocol_register_type(G_TYPE_MODULE(plugin)); - - irc_xfer_register(G_TYPE_MODULE(plugin)); - - _irc_protocol = irc_protocol_new(); - if(!purple_protocol_manager_register(manager, _irc_protocol, error)) { - g_clear_object(&_irc_protocol); - - return FALSE; - } - - purple_prefs_remove("/plugins/prpl/irc/quitmsg"); - purple_prefs_remove("/plugins/prpl/irc"); - - irc_register_commands(); - - purple_signal_register(_irc_protocol, "irc-sending-text", - purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, - PURPLE_TYPE_CONNECTION, - G_TYPE_POINTER); /* pointer to a string */ - purple_signal_register(_irc_protocol, "irc-receiving-text", - purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, - PURPLE_TYPE_CONNECTION, - G_TYPE_POINTER); /* pointer to a string */ - - purple_signal_connect(purple_get_core(), "uri-handler", plugin, - G_CALLBACK(irc_uri_handler), NULL); - - return TRUE; -} - -static gboolean -irc_unload(GPluginPlugin *plugin, G_GNUC_UNUSED gboolean shutdown, - GError **error) -{ - PurpleProtocolManager *manager = purple_protocol_manager_get_default(); - - if(!purple_protocol_manager_unregister(manager, _irc_protocol, error)) { - return FALSE; - } - - irc_unregister_commands(); - - purple_signal_disconnect(purple_get_core(), "uri-handler", plugin, - G_CALLBACK(irc_uri_handler)); - - g_clear_object(&_irc_protocol); - - return TRUE; -} - -GPLUGIN_NATIVE_PLUGIN_DECLARE(irc) diff --git a/libpurple/protocols/irc/irc.h b/libpurple/protocols/irc/irc.h deleted file mode 100644 index 3ca5e72cd2..0000000000 --- a/libpurple/protocols/irc/irc.h +++ /dev/null @@ -1,222 +0,0 @@ -/** - * purple - * - * Copyright (C) 2003, 2012 Ethan Blanton <elb@pidgin.im> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_IRC_IRC_H -#define PURPLE_IRC_IRC_H - -#include <glib.h> -#include <gmodule.h> - -#include <config.h> - -#include <hasl.h> - -#include <purple.h> - -#define IRC_TYPE_PROTOCOL (irc_protocol_get_type()) -G_DECLARE_FINAL_TYPE(IRCProtocol, irc_protocol, IRC, PROTOCOL, PurpleProtocol) - -#define IRC_DEFAULT_SERVER "irc.libera.chat" -#define IRC_DEFAULT_PORT 6667 -#define IRC_DEFAULT_SSL_PORT 994 - -#define IRC_DEFAULT_CHARSET "UTF-8" -#define IRC_DEFAULT_AUTODETECT FALSE -#define IRC_DEFAULT_ALIAS "purple" - -#define IRC_DEFAULT_QUIT "Leaving." - -#define IRC_BUFSIZE_INCREMENT 1024 -#define IRC_MAX_BUFSIZE 16384 - -#define IRC_MAX_MSG_SIZE 512 - -#define IRC_NAMES_FLAG "irc-namelist" - -enum { IRC_USEROPT_SERVER, IRC_USEROPT_PORT, IRC_USEROPT_CHARSET }; -enum irc_state { IRC_STATE_NEW, IRC_STATE_ESTABLISHED }; - -struct irc_conn { - PurpleAccount *account; - GHashTable *msgs; - GHashTable *cmds; - char *server; - GSocketConnection *conn; - GCancellable *cancellable; - guint timer; - GHashTable *buddies; - - gboolean ison_outstanding; - GList *buddies_outstanding; - - GDataInputStream *input; - PurpleQueuedOutputStream *output; - - GString *motd; - GString *names; - struct _whois { - char *nick; - char *real; - char *login; - char *ident; - char *host; - char *away; - char *server; - char *serverinfo; - GString *channels; - int ircop; - int identified; - int idle; - time_t signon; - } whois; - PurpleRoomlist *roomlist; - - gboolean quitting; - - time_t recv_time; - - char *mode_chars; - char *reqnick; - gboolean nickused; - - HaslContext *hasl_ctx; -}; - -struct irc_buddy { - char *name; - gboolean online; - gboolean flag; - gboolean new_online_status; - int ref; -}; - -typedef int (*IRCCmdCallback) (struct irc_conn *irc, const char *cmd, const char *target, const char **args); - -int irc_send(struct irc_conn *irc, const char *buf); -int irc_send_len(struct irc_conn *irc, const char *buf, int len); -gboolean irc_blist_timeout(struct irc_conn *irc); -gboolean irc_who_channel_timeout(struct irc_conn *irc); -void irc_buddy_query(struct irc_conn *irc); - -char *irc_escape_privmsg(const char *text, gssize length); - -char *irc_mirc2html(const char *string); -char *irc_mirc2txt(const char *string); - -const char *irc_nick_skip_mode(struct irc_conn *irc, const char *string); - -gboolean irc_ischannel(const char *string); - -void irc_register_commands(void); -void irc_unregister_commands(void); -void irc_msg_table_build(struct irc_conn *irc); -void irc_parse_msg(struct irc_conn *irc, char *input); -char *irc_parse_ctcp(struct irc_conn *irc, const char *from, const char *to, const char *msg, int notice); -char *irc_format(struct irc_conn *irc, const char *format, ...); - -void irc_msg_default(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_away(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_badmode(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_badnick(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_ban(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_banfull(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_banned(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_chanmode(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_endwhois(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_features(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_invite(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_inviteonly(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_ison(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_join(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_kick(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_list(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_luser(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_mode(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_motd(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_names(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_nick(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_nickused(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_nochan(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_nonick(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_nochangenick(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_nosend(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_notice(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_notinchan(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_notop(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_part(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_ping(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_pong(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_privmsg(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_quit(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_regonly(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_time(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_topic(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_topicinfo(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_unavailable(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_unknown(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_wallops(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_whois(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_who(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_cap(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_auth(struct irc_conn *irc, char *arg); -void irc_msg_authenticate(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_authok(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_authtryagain(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_authfail(struct irc_conn *irc, const char *name, const char *from, char **args); - -void irc_cmd_table_build(struct irc_conn *irc); - -int irc_cmd_default(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_away(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_ctcp(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_ctcp_action(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_ctcp_version(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_invite(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_join(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_kick(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_list(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_mode(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_names(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_nick(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_op(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_privmsg(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_part(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_ping(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_quit(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_quote(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_query(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_remove(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_service(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_time(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_topic(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_wallops(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_whois(struct irc_conn *irc, const char *cmd, const char *target, const char **args); -int irc_cmd_whowas(struct irc_conn *irc, const char *cmd, const char *target, const char **args); - -#define IRC_TYPE_XFER (irc_xfer_get_type()) -G_DECLARE_FINAL_TYPE(IrcXfer, irc_xfer, IRC, XFER, PurpleXfer); - -void irc_xfer_register(GTypeModule *module); - -PurpleXfer *irc_dccsend_new_xfer(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who); -void irc_dccsend_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who, const char *file); -void irc_dccsend_recv(struct irc_conn *irc, const char *from, const char *msg); - -#endif /* PURPLE_IRC_IRC_H */ diff --git a/libpurple/protocols/irc/meson.build b/libpurple/protocols/irc/meson.build deleted file mode 100644 index 14bfefbdda..0000000000 --- a/libpurple/protocols/irc/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -IRC_SOURCES = [ - 'cmds.c', - 'dcc_send.c', - 'irc.c', - 'irc.h', - 'msgs.c', - 'parse.c' -] - -if DYNAMIC_IRC - irc_resources = gnome.compile_resources('ircresource', - 'resources/irc.gresource.xml', - source_dir : 'resources', - c_name : 'irc') - IRC_SOURCES += irc_resources - - irc_prpl = shared_library('irc', IRC_SOURCES, - c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Purple-IRC"'], - dependencies : [hasl, libpurple_dep, glib, gio, ws2_32], - install : true, install_dir : PURPLE_PLUGINDIR) - - devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) -endif diff --git a/libpurple/protocols/irc/msgs.c b/libpurple/protocols/irc/msgs.c deleted file mode 100644 index af90fd9198..0000000000 --- a/libpurple/protocols/irc/msgs.c +++ /dev/null @@ -1,1733 +0,0 @@ -/** - * purple - * - * Copyright (C) 2003, 2012 Ethan Blanton <elb@pidgin.im> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -/* - * Note: If you change any of these functions to use additional args you - * MUST ensure the arg count is correct in parse.c. Otherwise it may be - * possible for a malicious server or man-in-the-middle to trigger a crash. - */ - -#include <glib/gi18n-lib.h> - -#include <ctype.h> - -#include <purple.h> - -#include "irc.h" - -#include <stdio.h> -#include <stdlib.h> - -#include <hasl.h> - -static char *irc_mask_nick(const char *mask); -static char *irc_mask_userhost(const char *mask); -static void irc_chat_remove_buddy(PurpleChatConversation *chat, char *data[2]); -static void irc_buddy_status(char *name, struct irc_buddy *ib, struct irc_conn *irc); -static void irc_connected(struct irc_conn *irc, const char *nick); - -static void irc_msg_handle_privmsg(struct irc_conn *irc, const char *name, - const char *from, const char *to, - const char *rawmsg, gboolean notice); - -static void irc_sasl_finish(struct irc_conn *irc); - -static char *irc_mask_nick(const char *mask) -{ - char *end, *buf; - - end = strchr(mask, '!'); - if (!end) - buf = g_strdup(mask); - else - buf = g_strndup(mask, end - mask); - - return buf; -} - -static char *irc_mask_userhost(const char *mask) -{ - return g_strdup(strchr(mask, '!') + 1); -} - -static void irc_chat_remove_buddy(PurpleChatConversation *chat, char *data[2]) -{ - char *message, *stripped; - - stripped = data[1] ? irc_mirc2txt(data[1]) : NULL; - message = g_strdup_printf("quit: %s", stripped); - g_free(stripped); - - if (purple_chat_conversation_has_user(chat, data[0])) - purple_chat_conversation_remove_user(chat, data[0], message); - - g_free(message); -} - -static void irc_connected(struct irc_conn *irc, const char *nick) -{ - PurpleConnection *gc; - PurpleStatus *status; - GSList *buddies; - PurpleAccount *account; - - if ((gc = purple_account_get_connection(irc->account)) == NULL - || PURPLE_CONNECTION_IS_CONNECTED(gc)) - return; - - purple_connection_set_display_name(gc, nick); - purple_connection_set_state(gc, PURPLE_CONNECTION_STATE_CONNECTED); - account = purple_connection_get_account(gc); - - /* If we're away then set our away message */ - status = purple_account_get_active_status(irc->account); - if (purple_status_type_get_primitive(purple_status_get_status_type(status)) != PURPLE_STATUS_AVAILABLE) { - PurpleProtocol *protocol = purple_connection_get_protocol(gc); - purple_protocol_server_set_status(PURPLE_PROTOCOL_SERVER(protocol), irc->account, status); - } - - /* this used to be in the core, but it's not now */ - for (buddies = purple_blist_find_buddies(account, NULL); buddies; - buddies = g_slist_delete_link(buddies, buddies)) - { - PurpleBuddy *b = buddies->data; - struct irc_buddy *ib = g_new0(struct irc_buddy, 1); - ib->name = g_strdup(purple_buddy_get_name(b)); - ib->ref = 1; - g_hash_table_replace(irc->buddies, ib->name, ib); - } - - irc_blist_timeout(irc); - if (!irc->timer) - irc->timer = g_timeout_add_seconds(45, (GSourceFunc)irc_blist_timeout, (gpointer)irc); -} - -/* This function is ugly, but it's really an error handler. */ -void -irc_msg_default(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - int i; - const char *end, *cur, *numeric = NULL; - char *clean, *tmp, *convname; - PurpleConversation *convo; - PurpleConversationManager *manager; - - for (cur = args[0], i = 0; i < 4; i++) { - end = strchr(cur, ' '); - if (end == NULL) { - goto undirected; - } - /* Check for 3-digit numeric in second position */ - if (i == 1) { - if (end - cur != 3 - || !isdigit(cur[0]) || !isdigit(cur[1]) - || !isdigit(cur[2])) { - goto undirected; - } - /* Save the numeric for printing to the channel */ - numeric = cur; - } - /* Don't advance cur if we're on the final iteration. */ - if (i != 3) { - cur = end + 1; - } - } - - /* At this point, cur is the beginning of the fourth position, - * end is the following space, and there are remaining - * arguments. We'll check to see if this argument is a - * currently active conversation (private message or channel, - * either one), and print the numeric to that conversation if it - * is. */ - - tmp = g_strndup(cur, end - cur); - convname = g_utf8_make_valid(tmp, -1); - g_free(tmp); - - /* Check for an existing conversation */ - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find(manager, irc->account, convname); - g_free(convname); - - if (convo == NULL) { - goto undirected; - } - - /* end + 1 is the first argument past the target. The initial - * arguments we've skipped are routing info, numeric, recipient - * (this account's nick, most likely), and target (this - * channel). If end + 1 is an ASCII :, skip it, because it's - * meaningless in this context. This won't catch all - * :-arguments, but it'll catch the easy case. */ - if (*++end == ':') { - end++; - } - - /* We then print "numeric: remainder". */ - clean = g_utf8_make_valid(end, -1); - tmp = g_strdup_printf("%.3s: %s", numeric, clean); - g_free(clean); - purple_conversation_write_system_message(convo, tmp, - PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_RAW | - PURPLE_MESSAGE_NO_LINKIFY); - g_free(tmp); - return; - - undirected: - /* This, too, should be escaped somehow (smarter) */ - clean = g_utf8_make_valid(args[0], -1); - purple_debug_info("irc", "Unrecognized message: %s", clean); - g_free(clean); -} - -void -irc_msg_features(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - gchar **features; - int i; - - features = g_strsplit(args[1], " ", -1); - for (i = 0; features[i]; i++) { - char *val; - if (!strncmp(features[i], "PREFIX=", 7)) { - if ((val = strchr(features[i] + 7, ')')) != NULL) - irc->mode_chars = g_strdup(val + 1); - } - } - - g_strfreev(features); -} - -void -irc_msg_luser(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - if (purple_strequal(name, "251")) { - /* 251 is required, so we pluck our nick from here and - * finalize connection */ - irc_connected(irc, args[0]); - /* Some IRC servers seem to not send a 255 numeric, so - * I guess we can't require it; 251 will do. */ - /* } else if (purple_strequal(name, "255")) { */ - } -} - -void irc_msg_away(struct irc_conn *irc, const char *name, const char *from, char **args) -{ - PurpleConnection *gc; - char *msg; - - if (irc->whois.nick && !purple_utf8_strcasecmp(irc->whois.nick, args[1])) { - /* We're doing a whois, show this in the whois dialog */ - irc_msg_whois(irc, name, from, args); - return; - } - - gc = purple_account_get_connection(irc->account); - if (gc) { - msg = g_markup_escape_text(args[2], -1); - purple_serv_got_im(gc, args[1], msg, PURPLE_MESSAGE_AUTO_RESP, time(NULL)); - g_free(msg); - } -} - -void -irc_msg_badmode(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - - g_return_if_fail(gc); - - purple_notify_error(gc, NULL, _("Bad mode"), args[1], - purple_request_cpar_from_connection(gc)); -} - -void -irc_msg_ban(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConversation *chat; - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - - if (purple_strequal(name, "367")) { - char *msg = NULL; - /* Ban list entry */ - if (args[3] && args[4]) { - /* This is an extended syntax, not in RFC 1459 */ - int t1 = atoi(args[4]); - time_t t2 = time(NULL); - char *time = purple_str_seconds_to_string(t2 - t1); - msg = g_strdup_printf(_("Ban on %s by %s, set %s ago"), - args[2], args[3], time); - g_free(time); - } else { - msg = g_strdup_printf(_("Ban on %s"), args[2]); - } - if (chat) { - purple_conversation_write_system_message( - chat, msg, PURPLE_MESSAGE_NO_LOG); - } else { - purple_debug_info("irc", "%s\n", msg); - } - g_free(msg); - } else if (purple_strequal(name, "368")) { - if (!chat) - return; - /* End of ban list */ - purple_conversation_write_system_message(chat, - _("End of ban list"), PURPLE_MESSAGE_NO_LOG); - } -} - -void -irc_msg_banned(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - char *buf; - - g_return_if_fail(gc); - - buf = g_strdup_printf(_("You are banned from %s."), args[1]); - purple_notify_error(gc, _("Banned"), _("Banned"), buf, - purple_request_cpar_from_connection(gc)); - g_free(buf); -} - -void -irc_msg_banfull(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConversation *chat; - PurpleConversationManager *manager; - char *buf, *nick; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - if (!chat) { - return; - } - - nick = g_markup_escape_text(args[2], -1); - buf = g_strdup_printf(_("Cannot ban %s: banlist is full"), nick); - g_free(nick); - purple_conversation_write_system_message(chat, buf, PURPLE_MESSAGE_NO_LOG); - g_free(buf); -} - -void -irc_msg_chanmode(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConversation *chat; - PurpleConversationManager *manager; - char *buf, *escaped; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - if (!chat) { /* XXX punt on channels we are not in for now */ - return; - } - - escaped = (args[3] != NULL) ? g_markup_escape_text(args[3], -1) : NULL; - buf = g_strdup_printf("mode for %s: %s %s", args[1], args[2], escaped ? escaped : ""); - purple_conversation_write_system_message(chat, buf, 0); - g_free(escaped); - g_free(buf); -} - -void -irc_msg_whois(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - if (!irc->whois.nick) { - purple_debug_warning("irc", "Unexpected %s reply for %s", - purple_strequal(name, "314") ? "WHOWAS" : "WHOIS", args[1]); - return; - } - - if (purple_utf8_strcasecmp(irc->whois.nick, args[1])) { - purple_debug_warning("irc", "Got %s reply for %s while waiting for %s", - purple_strequal(name, "314") ? "WHOWAS" : "WHOIS", args[1], irc->whois.nick); - return; - } - - if (purple_strequal(name, "301")) { - irc->whois.away = g_strdup(args[2]); - } else if (purple_strequal(name, "311") || purple_strequal(name, "314")) { - irc->whois.ident = g_strdup(args[2]); - irc->whois.host = g_strdup(args[3]); - irc->whois.real = g_strdup(args[5]); - } else if (purple_strequal(name, "312")) { - irc->whois.server = g_strdup(args[2]); - irc->whois.serverinfo = g_strdup(args[3]); - } else if (purple_strequal(name, "313")) { - irc->whois.ircop = 1; - } else if (purple_strequal(name, "317")) { - irc->whois.idle = atoi(args[2]); - if (args[3]) - irc->whois.signon = (time_t)atoi(args[3]); - } else if (purple_strequal(name, "319")) { - if (irc->whois.channels == NULL) { - irc->whois.channels = g_string_new(args[2]); - } else { - irc->whois.channels = g_string_append(irc->whois.channels, args[2]); - } - } else if (purple_strequal(name, "320")) { - irc->whois.identified = 1; - } else if (purple_strequal(name, "330")) { - purple_debug_info("irc", "330 %s: 1=[%s] 2=[%s] 3=[%s]", - name, args[1], args[2], args[3]); - if (purple_strequal(args[3], "is logged in as")) - irc->whois.login = g_strdup(args[2]); - } -} - -void -irc_msg_endwhois(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc; - char *tmp, *tmp2; - PurpleNotifyUserInfo *user_info; - - if (!irc->whois.nick) { - purple_debug_warning("irc", "Unexpected End of %s for %s", - purple_strequal(name, "369") ? "WHOWAS" : "WHOIS", args[1]); - return; - } - if (purple_utf8_strcasecmp(irc->whois.nick, args[1])) { - purple_debug_warning("irc", "Received end of %s for %s, expecting %s", - purple_strequal(name, "369") ? "WHOWAS" : "WHOIS", args[1], irc->whois.nick); - return; - } - - user_info = purple_notify_user_info_new(); - - tmp2 = g_markup_escape_text(args[1], -1); - tmp = g_strdup_printf("%s%s%s", tmp2, - (irc->whois.ircop ? _(" <i>(ircop)</i>") : ""), - (irc->whois.identified ? _(" <i>(identified)</i>") : "")); - purple_notify_user_info_add_pair_html(user_info, _("Nick"), tmp); - g_free(tmp2); - g_free(tmp); - - if (irc->whois.away) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Away"), irc->whois.away); - g_free(irc->whois.away); - } - if (irc->whois.real) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Real name"), irc->whois.real); - g_free(irc->whois.real); - } - if (irc->whois.login) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Login name"), irc->whois.login); - g_free(irc->whois.login); - } - if (irc->whois.ident) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Ident name"), irc->whois.ident); - g_free(irc->whois.ident); - } - if (irc->whois.host) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Host name"), irc->whois.host); - g_free(irc->whois.host); - } - if (irc->whois.server) { - tmp = g_strdup_printf("%s (%s)", irc->whois.server, irc->whois.serverinfo); - purple_notify_user_info_add_pair_plaintext(user_info, _("Server"), tmp); - g_free(tmp); - g_free(irc->whois.server); - g_free(irc->whois.serverinfo); - } - if (irc->whois.channels) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Currently on"), irc->whois.channels->str); - g_string_free(irc->whois.channels, TRUE); - } - if (irc->whois.idle) { - GDateTime *signon = NULL; - - tmp = purple_str_seconds_to_string(irc->whois.idle); - purple_notify_user_info_add_pair_plaintext(user_info, _("Idle for"), - tmp); - g_free(tmp); - - signon = g_date_time_new_from_unix_local(irc->whois.signon); - tmp = g_date_time_format(signon, "%c"); - purple_notify_user_info_add_pair_plaintext(user_info, - _("Online since"), tmp); - g_free(tmp); - g_date_time_unref(signon); - } - if (purple_strequal(irc->whois.nick, "elb")) { - purple_notify_user_info_add_pair_plaintext(user_info, - _("<b>Defining adjective:</b>"), _("Glorious")); - } - - gc = purple_account_get_connection(irc->account); - - purple_notify_userinfo(gc, irc->whois.nick, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - - g_free(irc->whois.nick); - memset(&irc->whois, 0, sizeof(irc->whois)); -} - -void -irc_msg_who(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - if (purple_strequal(name, "352")) { - PurpleConversation *chat; - PurpleConversationManager *manager; - PurpleChatUser *cb; - - char *cur, *userhost, *realname; - - PurpleChatUserFlags flags; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - if (!chat) { - purple_debug_error("irc", "Got a WHO response for %s, which doesn't exist", args[1]); - return; - } - - cb = purple_chat_conversation_find_user(PURPLE_CHAT_CONVERSATION(chat), args[5]); - if (!cb) { - purple_debug_error("irc", "Got a WHO response for %s who isn't a buddy.", args[5]); - return; - } - - userhost = g_strdup_printf("%s@%s", args[2], args[3]); - - /* The final argument is a :-argument, but annoyingly - * contains two "words", the hop count and real name. */ - for (cur = args[7]; *cur; cur++) { - if (*cur == ' ') { - cur++; - break; - } - } - realname = g_strdup(cur); - - g_object_set_data_full(G_OBJECT(cb), "userhost", userhost, g_free); - g_object_set_data_full(G_OBJECT(cb), "realname", realname, g_free); - - flags = purple_chat_user_get_flags(cb); - - /* FIXME: I'm not sure this is really a good idea, now - * that we no longer do periodic WHO. It seems to me - * like it's more likely to be confusing than not. - * Comments? */ - if (args[6][0] == 'G' && !(flags & PURPLE_CHAT_USER_AWAY)) { - purple_chat_user_set_flags(cb, flags | PURPLE_CHAT_USER_AWAY); - } else if(args[6][0] == 'H' && (flags & PURPLE_CHAT_USER_AWAY)) { - purple_chat_user_set_flags(cb, flags & ~PURPLE_CHAT_USER_AWAY); - } - } -} - -void -irc_msg_list(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - if (!irc->roomlist) - return; - - if (purple_strequal(name, "321")) { - purple_roomlist_set_in_progress(irc->roomlist, TRUE); - return; - } - - if (purple_strequal(name, "323")) { - purple_roomlist_set_in_progress(irc->roomlist, FALSE); - g_object_unref(irc->roomlist); - irc->roomlist = NULL; - return; - } - - if (purple_strequal(name, "322")) { - PurpleRoomlistRoom *room; - char *topic; - - if (!purple_roomlist_get_in_progress(irc->roomlist)) { - purple_debug_warning("irc", "Buggy server didn't send RPL_LISTSTART.\n"); - purple_roomlist_set_in_progress(irc->roomlist, TRUE); - } - - topic = irc_mirc2txt(args[3]); - room = purple_roomlist_room_new(args[1], topic); - g_free(topic); - - purple_roomlist_room_set_user_count(room, strtol(args[2], NULL, 10)); - purple_roomlist_room_add_field(room, "channel", args[1]); - purple_roomlist_room_add(irc->roomlist, room); - g_object_unref(room); - } -} - -void irc_msg_topic(struct irc_conn *irc, const char *name, const char *from, char **args) -{ - char *chan, *topic, *msg, *nick, *tmp, *tmp2; - PurpleConversation *chat; - PurpleConversationManager *manager; - - if (purple_strequal(name, "topic")) { - chan = args[0]; - topic = irc_mirc2txt (args[1]); - } else { - chan = args[1]; - topic = irc_mirc2txt (args[2]); - } - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, chan); - if (!chat) { - purple_debug_error("irc", "Got a topic for %s, which doesn't exist", chan); - g_free(topic); - return; - } - - /* If this is an interactive update, print it out */ - tmp = g_markup_escape_text(topic, -1); - tmp2 = purple_markup_linkify(tmp); - g_free(tmp); - if (purple_strequal(name, "topic")) { - const char *current_topic = purple_chat_conversation_get_topic(PURPLE_CHAT_CONVERSATION(chat)); - if (!(current_topic != NULL && purple_strequal(tmp2, current_topic))) - { - char *nick_esc; - nick = irc_mask_nick(from); - nick_esc = g_markup_escape_text(nick, -1); - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), nick, topic); - if (*tmp2) - msg = g_strdup_printf(_("%s has changed the topic to: %s"), nick_esc, tmp2); - else - msg = g_strdup_printf(_("%s has cleared the topic."), nick_esc); - g_free(nick_esc); - g_free(nick); - purple_conversation_write_system_message( - chat, msg, 0); - g_free(msg); - } - } else { - char *chan_esc = g_markup_escape_text(chan, -1); - msg = g_strdup_printf(_("The topic for %s is: %s"), chan_esc, tmp2); - g_free(chan_esc); - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), NULL, topic); - purple_conversation_write_system_message(chat, msg, 0); - g_free(msg); - } - g_free(tmp2); - g_free(topic); -} - -void -irc_msg_topicinfo(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConversation *chat; - PurpleConversationManager *manager; - GDateTime *dt, *local; - gint64 mtime; - char *msg, *timestamp, *datestamp; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - if (!chat) { - purple_debug_error("irc", "Got topic info for %s, which doesn't exist", args[1]); - return; - } - - mtime = g_ascii_strtoll(args[3], NULL, 10); - if(mtime == 0 || mtime == G_MININT64 || mtime == G_MAXINT64) { - purple_debug_error("irc", "Got apparently nonsensical topic timestamp %s", args[3]); - return; - } - - dt = g_date_time_new_from_unix_utc(mtime); - if(dt == NULL) { - purple_debug_error("irc", "Failed to turn %" G_GINT64_FORMAT " into a GDateTime", mtime); - return; - } - - local = g_date_time_to_local(dt); - g_date_time_unref(dt); - - timestamp = g_date_time_format(local, "%X"); - datestamp = g_date_time_format(local, "%x"); - msg = g_strdup_printf(_("Topic for %s set by %s at %s on %s"), args[1], args[2], timestamp, datestamp); - purple_conversation_write_system_message(chat, - msg, PURPLE_MESSAGE_NO_LINKIFY); - g_free(timestamp); - g_free(datestamp); - g_free(msg); - g_date_time_unref(local); -} - -void -irc_msg_unknown(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - char *buf; - - g_return_if_fail(gc); - - buf = g_strdup_printf(_("Unknown message '%s'"), args[1]); - purple_notify_error(gc, _("Unknown message"), buf, _("The IRC server " - "received a message it did not understand."), - purple_request_cpar_from_connection(gc)); - g_free(buf); -} - -void -irc_msg_names(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - char *names, *cur, *end, *tmp, *msg; - - if (purple_strequal(name, "366")) { - PurpleConversation *convo; - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find(manager, irc->account, - args[1]); - if (!convo) { - purple_debug_error("irc", "Got a NAMES list for %s, which doesn't exist", args[1]); - g_string_free(irc->names, TRUE); - irc->names = NULL; - return; - } - - names = cur = g_string_free(irc->names, FALSE); - irc->names = NULL; - if (g_object_get_data(G_OBJECT(convo), IRC_NAMES_FLAG)) { - msg = g_strdup_printf(_("Users on %s: %s"), args[1], names ? names : ""); - purple_conversation_write_system_message(convo, msg, PURPLE_MESSAGE_NO_LOG); - g_free(msg); - } else if (cur != NULL) { - GList *users = NULL; - GList *flags = NULL; - - while (*cur) { - PurpleChatUserFlags f = PURPLE_CHAT_USER_NONE; - end = strchr(cur, ' '); - if (!end) - end = cur + strlen(cur); - if (*cur == '@') { - f = PURPLE_CHAT_USER_OP; - cur++; - } else if (*cur == '%') { - f = PURPLE_CHAT_USER_HALFOP; - cur++; - } else if(*cur == '+') { - f = PURPLE_CHAT_USER_VOICE; - cur++; - } else if(irc->mode_chars - && strchr(irc->mode_chars, *cur)) { - if (*cur == '~') - f = PURPLE_CHAT_USER_FOUNDER; - cur++; - } - tmp = g_strndup(cur, end - cur); - users = g_list_prepend(users, tmp); - flags = g_list_prepend(flags, GINT_TO_POINTER(f)); - cur = end; - if (*cur) - cur++; - } - - if (users != NULL) { - purple_chat_conversation_add_users(PURPLE_CHAT_CONVERSATION(convo), users, NULL, flags, FALSE); - - g_list_free_full(users, g_free); - g_list_free(flags); - } - - g_object_set_data(G_OBJECT(convo), IRC_NAMES_FLAG, - GINT_TO_POINTER(TRUE)); - } - g_free(names); - } else { - if (!irc->names) - irc->names = g_string_new(""); - - if (irc->names->len && irc->names->str[irc->names->len - 1] != ' ') - irc->names = g_string_append_c(irc->names, ' '); - irc->names = g_string_append(irc->names, args[3]); - } -} - -void -irc_msg_motd(struct irc_conn *irc, const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - char *escaped; - - if (purple_strequal(name, "375")) { - if (irc->motd) { - g_string_free(irc->motd, TRUE); - irc->motd = NULL; - } - irc->motd = g_string_new(""); - return; - } else if (purple_strequal(name, "376")) { - /* dircproxy 1.0.5 does not send 251 on reconnection, so - * finalize the connection here if it is not already done. */ - irc_connected(irc, args[0]); - return; - } else if (purple_strequal(name, "422")) { - /* in case there is no 251, and no MOTD set, finalize the connection. - * (and clear the motd for good measure). */ - - if (irc->motd) { - g_string_free(irc->motd, TRUE); - irc->motd = NULL; - } - - irc_connected(irc, args[0]); - return; - } - - if (!irc->motd) { - purple_debug_error("irc", "IRC server sent MOTD without STARTMOTD\n"); - return; - } - - if (!args[1]) - return; - - escaped = g_markup_escape_text(args[1], -1); - g_string_append_printf(irc->motd, "%s<br>", escaped); - g_free(escaped); -} - -void -irc_msg_time(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc; - - gc = purple_account_get_connection(irc->account); - - g_return_if_fail(gc); - - purple_notify_message(gc, PURPLE_NOTIFY_MSG_INFO, _("Time Response"), - _("The IRC server's local time is:"), args[2], NULL, NULL, - purple_request_cpar_from_connection(gc)); -} - -void -irc_msg_nochan(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - - g_return_if_fail(gc); - - purple_notify_error(gc, NULL, _("No such channel"), args[1], - purple_request_cpar_from_connection(gc)); -} - -void -irc_msg_nonick(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc; - PurpleConversation *convo; - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find(manager, irc->account, args[1]); - if (convo) { - purple_conversation_write_system_message(convo, - PURPLE_IS_IM_CONVERSATION(convo) ? _("User is not logged in") : _("no such channel"), - PURPLE_MESSAGE_NO_LOG); - - } else { - if ((gc = purple_account_get_connection(irc->account)) == NULL) - return; - purple_notify_error(gc, NULL, _("No such nick or channel"), - args[1], purple_request_cpar_from_connection(gc)); - } - - if (irc->whois.nick && !purple_utf8_strcasecmp(irc->whois.nick, args[1])) { - g_free(irc->whois.nick); - irc->whois.nick = NULL; - } -} - -void -irc_msg_nosend(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc; - PurpleConversation *chat; - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - if (chat) { - purple_conversation_write_system_message(chat, args[2], - PURPLE_MESSAGE_NO_LOG); - } else { - if ((gc = purple_account_get_connection(irc->account)) == NULL) - return; - purple_notify_error(gc, NULL, _("Could not send"), args[2], - purple_request_cpar_from_connection(gc)); - } -} - -void -irc_msg_notinchan(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConversation *chat; - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - - purple_debug_info("irc", "We're apparently not in %s, but tried to use it", args[1]); - if (chat) { - /*g_slist_remove(irc->gc->buddy_chats, chat); - purple_conversation_set_account(chat, NULL);*/ - purple_conversation_write_system_message(chat, - args[2], PURPLE_MESSAGE_NO_LOG); - } -} - -void -irc_msg_notop(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConversation *chat; - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[1]); - if (!chat) { - return; - } - - purple_conversation_write_system_message(chat, args[2], 0); -} - -void -irc_msg_invite(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - GHashTable *components; - gchar *nick; - - g_return_if_fail(gc); - - components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - nick = irc_mask_nick(from); - - g_hash_table_insert(components, g_strdup("channel"), g_strdup(args[1])); - - purple_serv_got_chat_invite(gc, args[1], nick, NULL, components); - g_free(nick); -} - -void -irc_msg_inviteonly(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - char *buf; - - g_return_if_fail(gc); - - buf = g_strdup_printf(_("Joining %s requires an invitation."), args[1]); - purple_notify_error(gc, _("Invitation only"), _("Invitation only"), buf, - purple_request_cpar_from_connection(gc)); - g_free(buf); -} - -void -irc_msg_ison(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - char **nicks; - struct irc_buddy *ib; - int i; - - nicks = g_strsplit(args[1], " ", -1); - for (i = 0; nicks[i]; i++) { - if ((ib = g_hash_table_lookup(irc->buddies, (gconstpointer)nicks[i])) == NULL) { - continue; - } - ib->new_online_status = TRUE; - } - g_strfreev(nicks); - - if (irc->ison_outstanding) - irc_buddy_query(irc); - - if (!irc->ison_outstanding) - g_hash_table_foreach(irc->buddies, (GHFunc)irc_buddy_status, (gpointer)irc); -} - -static void irc_buddy_status(char *name, struct irc_buddy *ib, struct irc_conn *irc) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - PurpleBuddy *buddy = purple_blist_find_buddy(irc->account, name); - - if (!gc || !buddy) - return; - - if (ib->online && !ib->new_online_status) { - purple_protocol_got_user_status(irc->account, name, "offline", NULL); - ib->online = FALSE; - } else if (!ib->online && ib->new_online_status) { - purple_protocol_got_user_status(irc->account, name, "available", NULL); - ib->online = TRUE; - } -} - -void -irc_msg_join(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - PurpleConversation *chat; - PurpleConversationManager *manager; - PurpleChatUser *cb; - - char *nick, *userhost, *buf; - struct irc_buddy *ib; - static int id = 1; - - g_return_if_fail(gc); - - nick = irc_mask_nick(from); - - manager = purple_conversation_manager_get_default(); - - if (!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc))) { - /* We are joining a channel for the first time */ - purple_serv_got_joined_chat(gc, id++, args[0]); - g_free(nick); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[0]); - - if (chat == NULL) { - purple_debug_error("irc", "tried to join %s but couldn't\n", args[0]); - return; - } - g_object_set_data(G_OBJECT(chat), IRC_NAMES_FLAG, - GINT_TO_POINTER(FALSE)); - - // Get the real name and user host for all participants. - buf = irc_format(irc, "vc", "WHO", args[0]); - irc_send(irc, buf); - g_free(buf); - - /* Until purple_conversation_present does something that - * one would expect in Pidgin, this call produces buggy - * behavior both for the /join and auto-join cases. */ - /* purple_conversation_present(chat); */ - return; - } - - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[0]); - if (chat == NULL) { - purple_debug_error("irc", "JOIN for %s failed", args[0]); - g_free(nick); - return; - } - - userhost = irc_mask_userhost(from); - - purple_chat_conversation_add_user(PURPLE_CHAT_CONVERSATION(chat), nick, userhost, PURPLE_CHAT_USER_NONE, TRUE); - - cb = purple_chat_conversation_find_user(PURPLE_CHAT_CONVERSATION(chat), nick); - - if (cb) { - g_object_set_data_full(G_OBJECT(cb), "userhost", userhost, g_free); - } - - if ((ib = g_hash_table_lookup(irc->buddies, nick)) != NULL) { - ib->new_online_status = TRUE; - irc_buddy_status(nick, ib, irc); - } - - g_free(nick); -} - -void -irc_msg_kick(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - PurpleConversation *chat; - PurpleConversationManager *manager; - char *nick, *buf; - - g_return_if_fail(gc); - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[0]); - - nick = irc_mask_nick(from); - - if (!chat) { - purple_debug_error("irc", "Received a KICK for unknown channel %s", args[0]); - g_free(nick); - return; - } - - if (!purple_utf8_strcasecmp(purple_connection_get_display_name(gc), args[1])) { - buf = g_strdup_printf(_("You have been kicked by %s: (%s)"), nick, args[2]); - purple_conversation_write_system_message(PURPLE_CONVERSATION(chat), buf, 0); - g_free(buf); - purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat))); - } else { - buf = g_strdup_printf(_("Kicked by %s (%s)"), nick, args[2]); - purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), args[1], buf); - g_free(buf); - } - - g_free(nick); -} - -void -irc_msg_mode(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - char *nick = irc_mask_nick(from), *buf; - - if (*args[0] == '#' || *args[0] == '&') { /* Channel */ - PurpleConversation *chat; - PurpleConversationManager *manager; - char *escaped; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - args[0]); - if (!chat) { - purple_debug_error("irc", "MODE received for %s, which we are not in", args[0]); - g_free(nick); - return; - } - escaped = (args[2] != NULL) ? g_markup_escape_text(args[2], -1) : NULL; - buf = g_strdup_printf(_("mode (%s %s) by %s"), args[1], escaped ? escaped : "", nick); - purple_conversation_write_system_message(chat, buf, 0); - g_free(escaped); - g_free(buf); - if(args[2]) { - PurpleChatUser *cb; - PurpleChatUserFlags newflag, flags; - char *mcur, *cur, *end, *user; - gboolean add = FALSE; - mcur = args[1]; - cur = args[2]; - while (*cur && *mcur) { - if ((*mcur == '+') || (*mcur == '-')) { - add = (*mcur == '+') ? TRUE : FALSE; - mcur++; - continue; - } - end = strchr(cur, ' '); - if (!end) - end = cur + strlen(cur); - user = g_strndup(cur, end - cur); - cb = purple_chat_conversation_find_user(PURPLE_CHAT_CONVERSATION(chat), user); - flags = purple_chat_user_get_flags(cb); - newflag = PURPLE_CHAT_USER_NONE; - if (*mcur == 'o') - newflag = PURPLE_CHAT_USER_OP; - else if (*mcur =='h') - newflag = PURPLE_CHAT_USER_HALFOP; - else if (*mcur == 'v') - newflag = PURPLE_CHAT_USER_VOICE; - else if(irc->mode_chars - && strchr(irc->mode_chars, '~') && (*mcur == 'q')) - newflag = PURPLE_CHAT_USER_FOUNDER; - if (newflag) { - if (add) - flags |= newflag; - else - flags &= ~newflag; - purple_chat_user_set_flags(cb, flags); - } - g_free(user); - cur = end; - if (*cur) - cur++; - if (*mcur) - mcur++; - } - } - } else { /* User */ - } - g_free(nick); -} - -void -irc_msg_nick(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - PurpleConversation *im; - PurpleConversationManager *manager; - GSList *chats; - char *nick = irc_mask_nick(from); - - irc->nickused = FALSE; - - if (!gc) { - g_free(nick); - return; - } - chats = purple_connection_get_active_chats(gc); - - if (!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc))) { - purple_connection_set_display_name(gc, args[0]); - } - - while (chats) { - PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(chats->data); - /* This is ugly ... */ - if (purple_chat_conversation_has_user(chat, nick)) - purple_chat_conversation_rename_user(chat, nick, args[0]); - chats = chats->next; - } - - manager = purple_conversation_manager_get_default(); - im = purple_conversation_manager_find_im(manager, irc->account, nick); - if (im != NULL) { - purple_conversation_set_name(im, args[0]); - } - - g_free(nick); -} - -void -irc_msg_badnick(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, G_GNUC_UNUSED char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - if (purple_connection_get_state(gc) == PURPLE_CONNECTION_STATE_CONNECTED) { - purple_notify_error(gc, _("Invalid nickname"), _("Invalid " - "nickname"), _("Your selected nickname was rejected by " - "the server. It probably contains invalid characters."), - purple_request_cpar_from_connection(gc)); - - } else { - purple_connection_take_error(gc, g_error_new_literal( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, - _("Your selected account name was rejected by the server. It probably contains invalid characters."))); - } -} - -void -irc_msg_nickused(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - char *newnick, *buf, *end; - PurpleConnection *gc = purple_account_get_connection(irc->account); - - if (gc && purple_connection_get_state(gc) == PURPLE_CONNECTION_STATE_CONNECTED) { - /* We only want to do the following dance if the connection - has not been successfully completed. If it has, just - notify the user that their /nick command didn't go. */ - buf = g_strdup_printf(_("The nickname \"%s\" is already being used."), - irc->reqnick); - purple_notify_error(gc, _("Nickname in use"), _("Nickname in " - "use"), buf, purple_request_cpar_from_connection(gc)); - g_free(buf); - g_free(irc->reqnick); - irc->reqnick = NULL; - return; - } - - if (strlen(args[1]) < strlen(irc->reqnick) || irc->nickused) - newnick = g_strdup(args[1]); - else - newnick = g_strdup_printf("%s0", args[1]); - end = newnick + strlen(newnick) - 1; - /* try fallbacks */ - if((*end < '9') && (*end >= '1')) { - *end = *end + 1; - } else *end = '1'; - - g_free(irc->reqnick); - irc->reqnick = newnick; - irc->nickused = TRUE; - - purple_connection_set_display_name( - purple_account_get_connection(irc->account), newnick); - - buf = irc_format(irc, "vn", "NICK", newnick); - irc_send(irc, buf); - g_free(buf); -} - -void irc_msg_notice(struct irc_conn *irc, const char *name, const char *from, char **args) -{ - irc_msg_handle_privmsg(irc, name, from, args[0], args[1], TRUE); -} - -void -irc_msg_nochangenick(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - - g_return_if_fail(gc); - - purple_notify_error(gc, _("Cannot change nick"), - _("Could not change nick"), args[2], - purple_request_cpar_from_connection(gc)); -} - -void -irc_msg_part(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - PurpleConversation *chat; - PurpleConversationManager *manager; - char *nick, *msg, *channel; - - g_return_if_fail(gc); - - /* Undernet likes to :-quote the channel name, for no good reason - * that I can see. This catches that. */ - channel = (args[0][0] == ':') ? &args[0][1] : args[0]; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - channel); - if (!chat) { - purple_debug_info("irc", "Got a PART on %s, which doesn't exist -- probably closed", channel); - return; - } - - nick = irc_mask_nick(from); - if (!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc))) { - char *escaped = args[1] ? g_markup_escape_text(args[1], -1) : NULL; - msg = g_strdup_printf(_("You have parted the channel%s%s"), - (args[1] && *args[1]) ? ": " : "", - (escaped && *escaped) ? escaped : ""); - g_free(escaped); - purple_conversation_write_system_message(chat, msg, 0); - g_free(msg); - purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat))); - } else { - msg = args[1] ? irc_mirc2txt(args[1]) : NULL; - purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), nick, msg); - g_free(msg); - } - g_free(nick); -} - -void -irc_msg_ping(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - char *buf; - - buf = irc_format(irc, "v:", "PONG", args[0]); - irc_send(irc, buf); - g_free(buf); -} - -void -irc_msg_pong(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConversation *convo; - PurpleConversationManager *manager; - PurpleConnection *gc; - char **parts, *msg; - gint64 oldstamp; - - parts = g_strsplit(args[1], " ", 2); - - if (!parts[0] || !parts[1]) { - g_strfreev(parts); - return; - } - - if (sscanf(parts[1], "%" G_GINT64_FORMAT, &oldstamp) != 1) { - msg = g_strdup(_("Error: invalid PONG from server")); - } else { - msg = g_strdup_printf(_("PING reply -- Lag: %f seconds"), - (g_get_monotonic_time() - oldstamp) / - (gdouble)G_USEC_PER_SEC); - } - - manager = purple_conversation_manager_get_default(); - convo = purple_conversation_manager_find(manager, irc->account, parts[0]); - g_strfreev(parts); - if (convo) { - purple_conversation_write_system_message(convo, msg, PURPLE_MESSAGE_NO_LOG); - } else { - gc = purple_account_get_connection(irc->account); - if (!gc) { - g_free(msg); - return; - } - purple_notify_info(gc, NULL, "PONG", msg, - purple_request_cpar_from_connection(gc)); - } - g_free(msg); -} - -void irc_msg_privmsg(struct irc_conn *irc, const char *name, const char *from, char **args) -{ - irc_msg_handle_privmsg(irc, name, from, args[0], args[1], FALSE); -} - -static void -irc_msg_handle_privmsg(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, const char *to, const char *rawmsg, - gboolean notice) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - PurpleConversation *chat; - char *tmp; - char *msg; - char *nick; - - if (!gc) - return; - - nick = irc_mask_nick(from); - tmp = irc_parse_ctcp(irc, nick, to, rawmsg, notice); - if (!tmp) { - g_free(nick); - return; - } - - msg = irc_escape_privmsg(tmp, -1); - g_free(tmp); - - tmp = irc_mirc2html(msg); - g_free(msg); - msg = tmp; - if (notice) { - tmp = g_strdup_printf("(notice) %s", msg); - g_free(msg); - msg = tmp; - } - - if (!purple_utf8_strcasecmp(to, purple_connection_get_display_name(gc))) { - purple_serv_got_im(gc, nick, msg, 0, time(NULL)); - } else { - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - chat = purple_conversation_manager_find_chat(manager, irc->account, - irc_nick_skip_mode(irc, to)); - if (chat) { - purple_serv_got_chat_in(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat)), - nick, PURPLE_MESSAGE_RECV, msg, time(NULL)); - } else - purple_debug_info("irc", "Got a %s on %s, which does not exist\n", - notice ? "NOTICE" : "PRIVMSG", to); - } - g_free(msg); - g_free(nick); -} - -void -irc_msg_regonly(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - PurpleConversationManager *manager; - char *msg; - - g_return_if_fail(gc); - - manager = purple_conversation_manager_get_default(); - - if(purple_conversation_manager_find_chat(manager, irc->account, args[1])) { - /* This is a channel we're already in; for some reason, - * freenode feels the need to notify us that in some - * hypothetical other situation this might not have - * succeeded. Suppress that. */ - return; - } - - msg = g_strdup_printf(_("Cannot join %s: Registration is required."), args[1]); - purple_notify_error(gc, _("Cannot join channel"), msg, args[2], - purple_request_cpar_from_connection(gc)); - g_free(msg); -} - -void -irc_msg_quit(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - struct irc_buddy *ib; - char *data[2]; - - g_return_if_fail(gc); - - data[0] = irc_mask_nick(from); - data[1] = args[0]; - /* XXX this should have an API, I shouldn't grab this directly */ - g_slist_foreach(purple_connection_get_active_chats(gc), - (GFunc)irc_chat_remove_buddy, data); - - if ((ib = g_hash_table_lookup(irc->buddies, data[0])) != NULL) { - ib->new_online_status = FALSE; - irc_buddy_status(data[0], ib, irc); - } - g_free(data[0]); -} - -void -irc_msg_unavailable(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - - purple_notify_error(gc, NULL, _("Nick or channel is temporarily " - "unavailable."), args[1], - purple_request_cpar_from_connection(gc)); -} - -void -irc_msg_wallops(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - char *nick, *msg; - - g_return_if_fail(gc); - - nick = irc_mask_nick(from); - msg = g_strdup_printf (_("Wallops from %s"), nick); - g_free(nick); - purple_notify_info(gc, NULL, msg, args[0], - purple_request_cpar_from_connection(gc)); - g_free(msg); -} - -static void -irc_auth_sasl_attempt(struct irc_conn *irc) { - PurpleAccount *account = irc->account; - PurpleConnection *gc = purple_account_get_connection(account); - char *buf; - const char *current_mechanism = NULL; - const char *next_mechanism = NULL; - - current_mechanism = hasl_context_get_current_mechanism(irc->hasl_ctx); - if(current_mechanism != NULL) { - g_message("SASL '%s' mechanism failed", current_mechanism); - } - - next_mechanism = hasl_context_next(irc->hasl_ctx); - if(next_mechanism == NULL) { - purple_connection_take_error(gc, - g_error_new_literal( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, - _("SASL authentication failed: No worthy authentication mechanisms found."))); - irc_sasl_finish(irc); - - return; - } - - g_message("Using SASL: %s", next_mechanism); - buf = irc_format(irc, "vv", "AUTHENTICATE", next_mechanism); - irc_send(irc, buf); - g_free(buf); -} - -/* SASL authentication */ -void -irc_msg_cap(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - gboolean allow_clear_text = FALSE; - - if (strncmp(g_strstrip(args[2]), "sasl", 5)) - return; - if (strncmp(args[1], "ACK", 4)) { - purple_connection_take_error(gc, g_error_new_literal( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, - _("SASL authentication failed: Server does not support SASL authentication."))); - - irc_sasl_finish(irc); - return; - } - - irc->hasl_ctx = hasl_context_new(); - hasl_context_set_allowed_mechanisms(irc->hasl_ctx, "PLAIN"); - - hasl_context_set_username(irc->hasl_ctx, - purple_connection_get_display_name(gc)); - hasl_context_set_password(irc->hasl_ctx, - purple_connection_get_password(gc)); - hasl_context_set_authzid(irc->hasl_ctx, ""); - hasl_context_set_tls(irc->hasl_ctx, G_IS_TLS_CONNECTION(irc->conn)); - - allow_clear_text = purple_account_get_bool(irc->account, - "auth_plain_in_clear", - FALSE); - hasl_context_set_allow_clear_text(irc->hasl_ctx, allow_clear_text); - - irc_auth_sasl_attempt(irc); -} - -void -irc_msg_auth(struct irc_conn *irc, char *arg) -{ - PurpleConnection *gc = purple_account_get_connection(irc->account); - HaslMechanismResult res; - GError *error = NULL; - char *buf, *authinfo; - char *serverin = NULL; - gsize serverinlen = 0; - guint8 *c_out; - gsize clen; - - if(!arg) { - return; - } - - if(arg[0] != '+') { - serverin = (char *)g_base64_decode(arg, &serverinlen); - } - - res = hasl_context_step(irc->hasl_ctx, (guint8 *)serverin, serverinlen, - &c_out, &clen, &error); - g_free(serverin); - - if(res == HASL_MECHANISM_RESULT_ERROR) { - const char *error_msg = "unknown error"; - - if(error != NULL && error->message != NULL) { - error_msg = error->message; - } - - purple_connection_take_error(gc, g_error_new( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, - _("SASL authentication failed: %s"), - error_msg)); - - g_clear_error(&error); - - irc_sasl_finish(irc); - - return; - } - - if(error != NULL) { - g_warning("hasl_context_step returned an error without an error " - "status: %s", error->message); - g_clear_error(&error); - } - - if(clen > 0) { - authinfo = g_base64_encode(c_out, clen); - g_free(c_out); - } else { - authinfo = g_strdup("+"); - } - - buf = irc_format(irc, "vv", "AUTHENTICATE", authinfo); - irc_send(irc, buf); - g_free(buf); - g_free(authinfo); - g_free(serverin); -} - -void -irc_msg_authenticate(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, char **args) -{ - irc_msg_auth(irc, args[0]); -} - -void -irc_msg_authok(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, G_GNUC_UNUSED char **args) -{ - char *buf; - - g_clear_object(&irc->hasl_ctx); - purple_debug_info("irc", "Successfully authenticated using SASL.\n"); - - /* Finish auth session */ - buf = irc_format(irc, "vv", "CAP", "END"); - irc_send(irc, buf); - g_free(buf); -} - -void -irc_msg_authtryagain(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, G_GNUC_UNUSED char **args) -{ - irc_auth_sasl_attempt(irc); -} - -void -irc_msg_authfail(struct irc_conn *irc, G_GNUC_UNUSED const char *name, - G_GNUC_UNUSED const char *from, - G_GNUC_UNUSED char **args) -{ - irc_auth_sasl_attempt(irc); -} - -static void -irc_sasl_finish(struct irc_conn *irc) -{ - char *buf; - - g_clear_object(&irc->hasl_ctx); - - /* Auth failed, abort */ - buf = irc_format(irc, "vv", "CAP", "END"); - irc_send(irc, buf); - g_free(buf); -} diff --git a/libpurple/protocols/irc/parse.c b/libpurple/protocols/irc/parse.c deleted file mode 100644 index 12d0136dd8..0000000000 --- a/libpurple/protocols/irc/parse.c +++ /dev/null @@ -1,819 +0,0 @@ -/** - * purple - * - * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include <glib/gi18n-lib.h> - -#include <purple.h> - -#include "irc.h" - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> - -static GSList *cmds = NULL; - -static char *irc_send_convert(struct irc_conn *irc, const char *string); -static char *irc_recv_convert(struct irc_conn *irc, const char *string); - -static void irc_parse_error_cb(struct irc_conn *irc, char *input); - -static char *irc_mirc_colors[16] = { - "white", "black", "blue", "dark green", "red", "brown", "purple", - "orange", "yellow", "green", "teal", "cyan", "light blue", - "pink", "grey", "light grey" }; - -extern PurpleProtocol *_irc_protocol; - -/*typedef void (*IRCMsgCallback)(struct irc_conn *irc, char *from, char *name, char **args);*/ -static struct _irc_msg { - char *name; - char *format; - - /** The required parameter count, based on values we use, not protocol - * specification. */ - int req_cnt; - - void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args); -} _irc_msgs[] = { - { "005", "n*", 2, irc_msg_features }, /* Feature list */ - { "251", "n:", 1, irc_msg_luser }, /* Client & Server count */ - { "255", "n:", 1, irc_msg_luser }, /* Client & Server count Mk. II */ - { "301", "nn:", 3, irc_msg_away }, /* User is away */ - { "303", "n:", 2, irc_msg_ison }, /* ISON reply */ - { "311", "nnvvv:", 6, irc_msg_whois }, /* Whois user */ - { "312", "nnv:", 4, irc_msg_whois }, /* Whois server */ - { "313", "nn:", 2, irc_msg_whois }, /* Whois ircop */ - { "314", "nnnvv:", 6, irc_msg_whois }, /* Whowas user */ - { "315", "nt:", 0, irc_msg_who }, /* end of WHO channel */ - { "317", "nnvv", 3, irc_msg_whois }, /* Whois idle */ - { "318", "nt:", 2, irc_msg_endwhois }, /* End of WHOIS */ - { "319", "nn:", 3, irc_msg_whois }, /* Whois channels */ - { "320", "nn:", 2, irc_msg_whois }, /* Whois (fn ident) */ - { "321", "*", 0, irc_msg_list }, /* Start of list */ - { "322", "ncv:", 4, irc_msg_list }, /* List. */ - { "323", ":", 0, irc_msg_list }, /* End of list. */ - { "324", "ncv:", 3, irc_msg_chanmode }, /* Channel modes */ - { "330", "nnv:", 4, irc_msg_whois }, /* Whois (fn login) */ - { "331", "nc:", 3, irc_msg_topic }, /* No channel topic */ - { "332", "nc:", 3, irc_msg_topic }, /* Channel topic */ - { "333", "ncvv", 4, irc_msg_topicinfo }, /* Topic setter stuff */ - { "352", "ncvvvnv:", 8, irc_msg_who }, /* Channel WHO */ - { "353", "nvc:", 4, irc_msg_names }, /* Names list */ - { "366", "nc:", 2, irc_msg_names }, /* End of names */ - { "367", "ncnnv", 3, irc_msg_ban }, /* Ban list */ - { "368", "nc:", 2, irc_msg_ban }, /* End of ban list */ - { "369", "nt:", 2, irc_msg_endwhois }, /* End of WHOWAS */ - { "372", "n:", 1, irc_msg_motd }, /* MOTD */ - { "375", "n:", 1, irc_msg_motd }, /* Start MOTD */ - { "376", "n:", 1, irc_msg_motd }, /* End of MOTD */ - { "391", "nv:", 3, irc_msg_time }, /* Time reply */ - { "401", "nt:", 2, irc_msg_nonick }, /* No such nick/chan */ - { "403", "nc:", 2, irc_msg_nochan }, /* No such channel */ - { "404", "nt:", 3, irc_msg_nosend }, /* Cannot send to chan */ - { "406", "nt:", 2, irc_msg_nonick }, /* No such nick for WHOWAS */ - { "421", "nv:", 2, irc_msg_unknown }, /* Unknown command */ - { "422", "n:", 1, irc_msg_motd }, /* MOTD file missing */ - { "432", "vn:", 0, irc_msg_badnick }, /* Erroneous nickname */ - { "433", "vn:", 2, irc_msg_nickused }, /* Nickname already in use */ - { "437", "nc:", 2, irc_msg_unavailable }, /* Nick/channel is unavailable */ - { "438", "nn:", 3, irc_msg_nochangenick }, /* Nick may not change */ - { "442", "nc:", 3, irc_msg_notinchan }, /* Not in channel */ - { "473", "nc:", 2, irc_msg_inviteonly }, /* Tried to join invite-only */ - { "474", "nc:", 2, irc_msg_banned }, /* Banned from channel */ - { "477", "nc:", 3, irc_msg_regonly }, /* Registration Required */ - { "478", "nct:", 3, irc_msg_banfull }, /* Banlist is full */ - { "482", "nc:", 3, irc_msg_notop }, /* Need to be op to do that */ - { "501", "n:", 2, irc_msg_badmode }, /* Unknown mode flag */ - { "506", "nc:", 3, irc_msg_nosend }, /* Must identify to send */ - { "515", "nc:", 3, irc_msg_regonly }, /* Registration required */ - { "903", "*", 0, irc_msg_authok}, /* SASL auth successful */ - { "904", "*", 0, irc_msg_authtryagain }, /* SASL auth failed, can recover*/ - { "905", "*", 0, irc_msg_authfail }, /* SASL auth failed */ - { "906", "*", 0, irc_msg_authfail }, /* SASL auth failed */ - { "907", "*", 0, irc_msg_authfail }, /* SASL auth failed */ - { "cap", "vv:", 3, irc_msg_cap }, /* SASL capable */ - { "authenticate", ":", 1, irc_msg_authenticate }, /* SASL authenticate */ - { "invite", "n:", 2, irc_msg_invite }, /* Invited */ - { "join", ":", 1, irc_msg_join }, /* Joined a channel */ - { "kick", "cn:", 3, irc_msg_kick }, /* KICK */ - { "mode", "tv:", 2, irc_msg_mode }, /* MODE for channel */ - { "nick", ":", 1, irc_msg_nick }, /* Nick change */ - { "notice", "t:", 2, irc_msg_notice }, /* NOTICE recv */ - { "part", "c:", 1, irc_msg_part }, /* Parted a channel */ - { "ping", ":", 1, irc_msg_ping }, /* Received PING from server */ - { "pong", "v:", 2, irc_msg_pong }, /* Received PONG from server */ - { "privmsg", "t:", 2, irc_msg_privmsg }, /* Received private message */ - { "topic", "c:", 2, irc_msg_topic }, /* TOPIC command */ - { "quit", ":", 1, irc_msg_quit }, /* QUIT notice */ - { "wallops", ":", 1, irc_msg_wallops }, /* WALLOPS command */ - { NULL, NULL, 0, NULL } -}; - -static struct _irc_user_cmd { - char *name; - char *format; - IRCCmdCallback cb; - char *help; -} _irc_cmds[] = { - { "action", ":", irc_cmd_ctcp_action, N_("action <action to perform>: Perform an action.") }, - { "authserv", ":", irc_cmd_service, N_("authserv: Send a command to authserv") }, - { "away", ":", irc_cmd_away, N_("away [message]: Set an away message, or use no message to return from being away.") }, - { "ctcp", "t:", irc_cmd_ctcp, N_("ctcp <nick> <msg>: sends ctcp msg to nick.") }, - { "chanserv", ":", irc_cmd_service, N_("chanserv: Send a command to chanserv") }, - { "deop", ":", irc_cmd_op, N_("deop <nick1> [nick2] ...: Remove channel operator status from someone. You must be a channel operator to do this.") }, - { "devoice", ":", irc_cmd_op, N_("devoice <nick1> [nick2] ...: Remove channel voice status from someone, preventing them from speaking if the channel is moderated (+m). You must be a channel operator to do this.") }, - { "invite", ":", irc_cmd_invite, N_("invite <nick> [room]: Invite someone to join you in the specified channel, or the current channel.") }, - { "j", "cv", irc_cmd_join, N_("j <room1>[,room2][,...] [key1[,key2][,...]]: Enter one or more channels, optionally providing a channel key for each if needed.") }, - { "join", "cv", irc_cmd_join, N_("join <room1>[,room2][,...] [key1[,key2][,...]]: Enter one or more channels, optionally providing a channel key for each if needed.") }, - { "kick", "n:", irc_cmd_kick, N_("kick <nick> [message]: Remove someone from a channel. You must be a channel operator to do this.") }, - { "list", ":", irc_cmd_list, N_("list: Display a list of chat rooms on the network. <i>Warning, some servers may disconnect you upon doing this.</i>") }, - { "me", ":", irc_cmd_ctcp_action, N_("me <action to perform>: Perform an action.") }, - { "memoserv", ":", irc_cmd_service, N_("memoserv: Send a command to memoserv") }, - { "mode", ":", irc_cmd_mode, N_("mode <+|-><A-Za-z> <nick|channel>: Set or unset a channel or user mode.") }, - { "msg", "t:", irc_cmd_privmsg, N_("msg <nick> <message>: Send a private message to a user (as opposed to a channel).") }, - { "names", "c", irc_cmd_names, N_("names [channel]: List the users currently in a channel.") }, - { "nick", "n", irc_cmd_nick, N_("nick <new nickname>: Change your nickname.") }, - { "nickserv", ":", irc_cmd_service, N_("nickserv: Send a command to nickserv") }, - { "notice", "t:", irc_cmd_privmsg, N_("notice <target<: Send a notice to a user or channel.") }, - { "op", ":", irc_cmd_op, N_("op <nick1> [nick2] ...: Grant channel operator status to someone. You must be a channel operator to do this.") }, - { "operwall", ":", irc_cmd_wallops, N_("operwall <message>: If you don't know what this is, you probably can't use it.") }, - { "operserv", ":", irc_cmd_service, N_("operserv: Send a command to operserv") }, - { "part", "c:", irc_cmd_part, N_("part [room] [message]: Leave the current channel, or a specified channel, with an optional message.") }, - { "ping", "n", irc_cmd_ping, N_("ping [nick]: Asks how much lag a user (or the server if no user specified) has.") }, - { "query", "n:", irc_cmd_query, N_("query <nick> <message>: Send a private message to a user (as opposed to a channel).") }, - { "quit", ":", irc_cmd_quit, N_("quit [message]: Disconnect from the server, with an optional message.") }, - { "quote", "*", irc_cmd_quote, N_("quote [...]: Send a raw command to the server.") }, - { "remove", "n:", irc_cmd_remove, N_("remove <nick> [message]: Remove someone from a room. You must be a channel operator to do this.") }, - { "time", "", irc_cmd_time, N_("time: Displays the current local time at the IRC server.") }, - { "topic", ":", irc_cmd_topic, N_("topic [new topic]: View or change the channel topic.") }, - { "umode", ":", irc_cmd_mode, N_("umode <+|-><A-Za-z>: Set or unset a user mode.") }, - { "version", ":", irc_cmd_ctcp_version, N_("version [nick]: send CTCP VERSION request to a user") }, - { "voice", ":", irc_cmd_op, N_("voice <nick1> [nick2] ...: Grant channel voice status to someone. You must be a channel operator to do this.") }, - { "wallops", ":", irc_cmd_wallops, N_("wallops <message>: If you don't know what this is, you probably can't use it.") }, - { "whois", "tt", irc_cmd_whois, N_("whois [server] <nick>: Get information on a user.") }, - { "whowas", "t", irc_cmd_whowas, N_("whowas <nick>: Get information on a user that has logged off.") }, - { NULL, NULL, NULL, NULL } -}; - -static PurpleCmdRet -irc_parse_purple_cmd(PurpleConversation *conv, const gchar *cmd, - gchar **args, G_GNUC_UNUSED gchar **error, - G_GNUC_UNUSED gpointer data) -{ - PurpleConnection *gc; - struct irc_conn *irc; - struct _irc_user_cmd *cmdent; - - gc = purple_conversation_get_connection(conv); - if (!gc) - return PURPLE_CMD_RET_FAILED; - - irc = purple_connection_get_protocol_data(gc); - - if ((cmdent = g_hash_table_lookup(irc->cmds, cmd)) == NULL) - return PURPLE_CMD_RET_FAILED; - - (cmdent->cb)(irc, cmd, purple_conversation_get_name(conv), (const char **)args); - - return PURPLE_CMD_RET_OK; -} - -static void irc_register_command(struct _irc_user_cmd *c) -{ - PurpleCmdId id; - PurpleCmdFlag f; - char args[10]; - char *format; - size_t i; - - f = PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PROTOCOL_ONLY - | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS; - - format = c->format; - - for (i = 0; (i < (sizeof(args) - 1)) && *format; i++, format++) - switch (*format) { - case 'v': - case 'n': - case 'c': - case 't': - args[i] = 'w'; - break; - case ':': - case '*': - args[i] = 's'; - break; - } - - args[i] = '\0'; - - id = purple_cmd_register(c->name, args, PURPLE_CMD_P_PROTOCOL, f, "prpl-irc", - irc_parse_purple_cmd, _(c->help), NULL); - cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id)); -} - -void irc_register_commands(void) -{ - struct _irc_user_cmd *c; - - for (c = _irc_cmds; c && c->name; c++) - irc_register_command(c); -} - -void irc_unregister_commands(void) -{ - g_clear_slist(&cmds, (GDestroyNotify)(gpointer)purple_cmd_unregister); -} - -static char *irc_send_convert(struct irc_conn *irc, const char *string) -{ - char *utf8; - GError *err = NULL; - gchar **encodings; - const gchar *enclist; - - enclist = purple_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET); - encodings = g_strsplit(enclist, ",", 2); - - if (encodings[0] == NULL || !g_ascii_strcasecmp("UTF-8", encodings[0])) { - g_strfreev(encodings); - return NULL; - } - - utf8 = g_convert(string, strlen(string), encodings[0], "UTF-8", NULL, NULL, &err); - if (err) { - purple_debug_error("irc", "Send conversion error: %s", err->message); - purple_debug_error("irc", "Sending as UTF-8 instead of %s", encodings[0]); - utf8 = g_strdup(string); - g_error_free(err); - } - g_strfreev(encodings); - - return utf8; -} - -static char *irc_recv_convert(struct irc_conn *irc, const char *string) -{ - char *utf8 = NULL; - const gchar *charset, *enclist; - gchar **encodings; - gboolean autodetect; - int i; - - autodetect = purple_account_get_bool(irc->account, "autodetect_utf8", IRC_DEFAULT_AUTODETECT); - - if (autodetect && g_utf8_validate(string, -1, NULL)) { - return g_strdup(string); - } - - enclist = purple_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET); - encodings = g_strsplit(enclist, ",", -1); - - if (encodings[0] == NULL) { - g_strfreev(encodings); - return g_utf8_make_valid(string, -1); - } - - for (i = 0; encodings[i] != NULL; i++) { - charset = encodings[i]; - while (*charset == ' ') - charset++; - - if (!g_ascii_strcasecmp("UTF-8", charset)) { - if (g_utf8_validate(string, -1, NULL)) - utf8 = g_strdup(string); - } else { - utf8 = g_convert(string, -1, "UTF-8", charset, NULL, NULL, NULL); - } - - if (utf8) { - g_strfreev(encodings); - return utf8; - } - } - g_strfreev(encodings); - - return g_utf8_make_valid(string, -1); -} - -/* This function is shamelessly stolen from glib--it is an old version of the - * private function append_escaped_text, used by g_markup_escape_text, whose - * behavior changed in glib 2.12. */ -static void irc_append_escaped_text(GString *str, const char *text, gssize length) -{ - const char *p = text; - const char *end = text + length; - const char *next = NULL; - - while(p != end) { - next = g_utf8_next_char(p); - - switch(*p) { - case '&': - g_string_append(str, "&"); - break; - case '<': - g_string_append(str, "<"); - break; - case '>': - g_string_append(str, ">"); - break; - case '\'': - g_string_append(str, "'"); - break; - case '"': - g_string_append(str, """); - break; - default: - g_string_append_len(str, p, next - p); - break; - } - - p = next; - } -} - -/* This function is shamelessly stolen from glib--it is an old version of the - * function g_markup_escape_text, whose behavior changed in glib 2.12. */ -char *irc_escape_privmsg(const char *text, gssize length) -{ - GString *str; - - g_return_val_if_fail(text != NULL, NULL); - - if(length < 0) - length = strlen(text); - - str = g_string_sized_new(length); - - irc_append_escaped_text(str, text, length); - - return g_string_free(str, FALSE); -} - -/* XXX tag closings are not necessarily correctly nested here! If we - * get a ^O or reach the end of the string and there are open - * tags, they are closed in a fixed order ... this means, for - * example, you might see <FONT COLOR="blue">some text <B>with - * various attributes</FONT></B> (notice that B and FONT overlap - * and are not cleanly nested). This is imminently fixable but - * I am not fixing it right now. - */ -char *irc_mirc2html(const char *string) -{ - const char *cur, *end; - char fg[3] = "\0\0", bg[3] = "\0\0"; - int fgnum, bgnum; - int font = 0, bold = 0, underline = 0, italic = 0; - GString *decoded; - - if (string == NULL) - return NULL; - - decoded = g_string_sized_new(strlen(string)); - - cur = string; - do { - end = strpbrk(cur, "\002\003\007\017\026\037"); - - decoded = g_string_append_len(decoded, cur, (end ? (gssize)(end - cur) : (gssize)strlen(cur))); - cur = end ? end : cur + strlen(cur); - - switch (*cur) { - case '\002': - cur++; - if (!bold) { - decoded = g_string_append(decoded, "<B>"); - bold = TRUE; - } else { - decoded = g_string_append(decoded, "</B>"); - bold = FALSE; - } - break; - case '\003': - cur++; - fg[0] = fg[1] = bg[0] = bg[1] = '\0'; - if (isdigit(*cur)) - fg[0] = *cur++; - if (isdigit(*cur)) - fg[1] = *cur++; - if (*cur == ',') { - cur++; - if (isdigit(*cur)) - bg[0] = *cur++; - if (isdigit(*cur)) - bg[1] = *cur++; - } - if (font) { - decoded = g_string_append(decoded, "</FONT>"); - font = FALSE; - } - - if (fg[0]) { - fgnum = atoi(fg); - if (fgnum < 0 || fgnum > 15) - continue; - font = TRUE; - g_string_append_printf(decoded, "<FONT COLOR=\"%s\"", irc_mirc_colors[fgnum]); - if (bg[0]) { - bgnum = atoi(bg); - if (bgnum >= 0 && bgnum < 16) - g_string_append_printf(decoded, " BACK=\"%s\"", irc_mirc_colors[bgnum]); - } - decoded = g_string_append_c(decoded, '>'); - } - break; - case '\011': - cur++; - if (!italic) { - decoded = g_string_append(decoded, "<I>"); - italic = TRUE; - } else { - decoded = g_string_append(decoded, "</I>"); - italic = FALSE; - } - break; - case '\037': - cur++; - if (!underline) { - decoded = g_string_append(decoded, "<U>"); - underline = TRUE; - } else { - decoded = g_string_append(decoded, "</U>"); - underline = FALSE; - } - break; - case '\007': - case '\026': - cur++; - break; - case '\017': - cur++; - /* fallthrough */ - case '\000': - if (bold) - decoded = g_string_append(decoded, "</B>"); - if (italic) - decoded = g_string_append(decoded, "</I>"); - if (underline) - decoded = g_string_append(decoded, "</U>"); - if (font) - decoded = g_string_append(decoded, "</FONT>"); - bold = italic = underline = font = FALSE; - break; - default: - purple_debug_error("irc", "Unexpected mIRC formatting character %d", *cur); - } - } while (*cur); - - return g_string_free(decoded, FALSE); -} - -char *irc_mirc2txt (const char *string) -{ - char *result; - int i, j; - - if (string == NULL) - return NULL; - - result = g_strdup (string); - - for (i = 0, j = 0; result[i]; i++) { - switch (result[i]) { - case '\002': - case '\003': - /* Foreground color */ - if (isdigit(result[i + 1])) - i++; - if (isdigit(result[i + 1])) - i++; - /* Optional comma and background color */ - if (result[i + 1] == ',') { - i++; - if (isdigit(result[i + 1])) - i++; - if (isdigit(result[i + 1])) - i++; - } - /* Note that i still points to the last character - * of the color selection string. */ - continue; - case '\007': - case '\017': - case '\026': - case '\037': - continue; - default: - result[j++] = result[i]; - } - } - result[j] = '\0'; - return result; -} - -const char *irc_nick_skip_mode(struct irc_conn *irc, const char *nick) -{ - static const char *default_modes = "@+%&"; - const char *mode_chars; - - mode_chars = irc->mode_chars ? irc->mode_chars : default_modes; - - while (*nick && strchr(mode_chars, *nick) != NULL) - nick++; - - return nick; -} - -gboolean irc_ischannel(const char *string) -{ - return (string[0] == '#' || string[0] == '&'); -} - -char *irc_parse_ctcp(struct irc_conn *irc, const char *from, const char *to, const char *msg, int notice) -{ - PurpleConnection *gc; - const char *cur = msg + 1; - char *buf, *ctcp; - - /* Note that this is NOT correct w.r.t. multiple CTCPs in one - * message and low-level quoting ... but if you want that crap, - * use a real IRC client. */ - - if (msg[0] != '\001' || msg[1] == '\0' || msg[strlen(msg) - 1] != '\001') - return g_strdup(msg); - - if (!strncmp(cur, "ACTION ", 7)) { - cur += 7; - buf = g_strdup_printf("/me %s", cur); - buf[strlen(buf) - 1] = '\0'; - return buf; - } else if (!strncmp(cur, "PING ", 5)) { - if (notice) { /* reply */ - gint64 timestamp; - gc = purple_account_get_connection(irc->account); - if (!gc) - return NULL; - if (sscanf(cur, "PING %" G_GINT64_FORMAT, ×tamp) == 1) { - buf = g_strdup_printf(_("Reply time from %s: %f seconds"), from, - (g_get_monotonic_time() - timestamp) / - (gdouble)G_USEC_PER_SEC); - purple_notify_info(gc, _("PONG"), - _("CTCP PING reply"), buf, - purple_request_cpar_from_connection(gc)); - g_free(buf); - } else { - purple_debug_error("irc", "Unable to parse PING timestamp"); - } - return NULL; - } else { - buf = irc_format(irc, "vt:", "NOTICE", from, msg); - irc_send(irc, buf); - g_free(buf); - } - } else if (!strncmp(cur, "VERSION", 7) && !notice) { - buf = irc_format(irc, "vt:", "NOTICE", from, "\001VERSION Purple IRC\001"); - irc_send(irc, buf); - g_free(buf); - } else if (!strncmp(cur, "DCC SEND ", 9)) { - irc_dccsend_recv(irc, from, msg + 10); - return NULL; - } - - ctcp = g_strdup(msg + 1); - ctcp[strlen(ctcp) - 1] = '\0'; - buf = g_strdup_printf("Received CTCP '%s' (to %s) from %s", ctcp, to, from); - g_free(ctcp); - return buf; -} - -void irc_msg_table_build(struct irc_conn *irc) -{ - int i; - - if (!irc || !irc->msgs) { - purple_debug_error("irc", "Attempt to build a message table on a bogus structure"); - return; - } - - for (i = 0; _irc_msgs[i].name; i++) { - g_hash_table_insert(irc->msgs, (gpointer)_irc_msgs[i].name, (gpointer)&_irc_msgs[i]); - } -} - -void irc_cmd_table_build(struct irc_conn *irc) -{ - int i; - - if (!irc || !irc->cmds) { - purple_debug_error("irc", "Attempt to build a command table on a bogus structure"); - return; - } - - for (i = 0; _irc_cmds[i].name ; i++) { - g_hash_table_insert(irc->cmds, (gpointer)_irc_cmds[i].name, (gpointer)&_irc_cmds[i]); - } -} - -char * -irc_format(G_GNUC_UNUSED struct irc_conn *irc, const char *format, ...) -{ - GString *string = g_string_new(""); - char *tok, *tmp; - const char *cur; - va_list ap; - - va_start(ap, format); - for (cur = format; *cur; cur++) { - if (cur != format) - g_string_append_c(string, ' '); - - tok = va_arg(ap, char *); - switch (*cur) { - case 'v': - g_string_append(string, tok); - break; - case ':': - g_string_append_c(string, ':'); - G_GNUC_FALLTHROUGH; - case 't': - case 'n': - case 'c': - tmp = irc_send_convert(irc, tok); - g_string_append(string, tmp ? tmp : tok); - g_free(tmp); - break; - default: - purple_debug_error("irc", "Invalid format character '%c'", *cur); - break; - } - } - va_end(ap); - g_string_append(string, "\r\n"); - return (g_string_free(string, FALSE)); -} - -void irc_parse_msg(struct irc_conn *irc, char *input) -{ - struct _irc_msg *msgent; - char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; - guint i; - PurpleConnection *gc = purple_account_get_connection(irc->account); - gboolean fmt_valid; - int args_cnt; - - irc->recv_time = time(NULL); - - /* - * The data passed to irc-receiving-text is the raw protocol data. - * TODO: It should be passed as an array of bytes and a length - * instead of a null terminated string. - */ - purple_signal_emit(_irc_protocol, "irc-receiving-text", gc, &input); - - if (purple_debug_is_verbose()) { - char *clean = g_utf8_make_valid(input, -1); - clean = g_strstrip(clean); - purple_debug_misc("irc", ">> %s\n", clean); - g_free(clean); - } - - if (!strncmp(input, "PING ", 5)) { - msg = irc_format(irc, "vv", "PONG", input + 5); - irc_send(irc, msg); - g_free(msg); - return; - } else if (!strncmp(input, "ERROR ", 6)) { - GError *error = NULL; - if (g_utf8_validate(input, -1, NULL)) { - error = g_error_new( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - "%s\n%s", _("Disconnected."), input); - } else { - error = g_error_new_literal( - PURPLE_CONNECTION_ERROR, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Disconnected.")); - } - purple_connection_take_error(gc, error); - return; - } else if (!strncmp(input, "AUTHENTICATE ", 13)) { - irc_msg_auth(irc, input + 13); - return; - } - - if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) { - irc_parse_error_cb(irc, input); - return; - } - - from = g_strndup(&input[1], cur - &input[1]); - cur++; - end = strchr(cur, ' '); - if (!end) - end = cur + strlen(cur); - - tmp = g_strndup(cur, end - cur); - msgname = g_ascii_strdown(tmp, -1); - g_free(tmp); - - if ((msgent = g_hash_table_lookup(irc->msgs, msgname)) == NULL) { - irc_msg_default(irc, "", from, &input); - g_free(msgname); - g_free(from); - return; - } - g_free(msgname); - - fmt_valid = TRUE; - args = g_new0(char *, strlen(msgent->format)); - args_cnt = 0; - for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { - switch (fmt[i]) { - case 'v': - if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); - /* This is a string of unknown encoding which we do not - * want to transcode, but it may or may not be valid - * UTF-8, so we'll salvage it. If a nick/channel/target - * field has inadvertently been marked verbatim, this - * could cause weirdness. */ - tmp = g_strndup(cur, end - cur); - args[i] = g_utf8_make_valid(tmp, -1); - g_free(tmp); - cur += end - cur; - break; - case 't': - case 'n': - case 'c': - if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); - tmp = g_strndup(cur, end - cur); - args[i] = irc_recv_convert(irc, tmp); - g_free(tmp); - cur += end - cur; - break; - case ':': - if (*cur == ':') cur++; - args[i] = irc_recv_convert(irc, cur); - cur = cur + strlen(cur); - break; - case '*': - /* Ditto 'v' above; we're going to salvage this in case - * it leaks past the IRC protocol */ - args[i] = g_utf8_make_valid(cur, -1); - cur = cur + strlen(cur); - break; - default: - purple_debug_error("irc", "invalid message format character '%c'", fmt[i]); - fmt_valid = FALSE; - break; - } - if (fmt_valid) - args_cnt = i + 1; - } - if (G_UNLIKELY(!fmt_valid)) { - purple_debug_error("irc", "message format was invalid"); - } else if (G_LIKELY(args_cnt >= msgent->req_cnt)) { - tmp = irc_recv_convert(irc, from); - (msgent->cb)(irc, msgent->name, tmp, args); - g_free(tmp); - } else { - purple_debug_error("irc", "args count (%d) doesn't reach " - "expected value of %d for the '%s' command", - args_cnt, msgent->req_cnt, msgent->name); - } - for (i = 0; i < strlen(msgent->format); i++) { - g_free(args[i]); - } - g_free(args); - g_free(from); -} - -static void -irc_parse_error_cb(G_GNUC_UNUSED struct irc_conn *irc, char *input) -{ - char *clean; - /* This really should be escaped somehow that you can tell what - * the junk was -- but as it is, it can crash glib. */ - clean = g_utf8_make_valid(input, -1); - purple_debug_warning("irc", "Unrecognized string: %s", clean); - g_free(clean); -} diff --git a/libpurple/protocols/irc/resources/icons/16x16/apps/im-irc.png b/libpurple/protocols/irc/resources/icons/16x16/apps/im-irc.png Binary files differdeleted file mode 100644 index 2d22c75a04..0000000000 --- a/libpurple/protocols/irc/resources/icons/16x16/apps/im-irc.png +++ /dev/null diff --git a/libpurple/protocols/irc/resources/icons/16x16/apps/scalable/im-irc.svg b/libpurple/protocols/irc/resources/icons/16x16/apps/scalable/im-irc.svg deleted file mode 100644 index d218f8db53..0000000000 --- a/libpurple/protocols/irc/resources/icons/16x16/apps/scalable/im-irc.svg +++ /dev/null @@ -1,222 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="16" - height="16" - id="svg4345" - sodipodi:version="0.32" - inkscape:version="0.46" - sodipodi:docbase="/home/hbons/Desktop" - sodipodi:docname="irc.svg" - inkscape:export-filename="/home/hbons/Bureaublad/irc.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" - version="1.0" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4347"> - <linearGradient - inkscape:collect="always" - id="linearGradient8648"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop8650" /> - <stop - style="stop-color:#729fcf;stop-opacity:1" - offset="1" - id="stop8652" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient8632"> - <stop - style="stop-color:#729fcf;stop-opacity:1" - offset="0" - id="stop8634" /> - <stop - style="stop-color:#386ca5;stop-opacity:1" - offset="1" - id="stop8636" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient5235"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop5237" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop5239" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient4179" - gradientUnits="userSpaceOnUse" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient5235" - id="radialGradient5241" - cx="23.234518" - cy="40.688972" - fx="23.234518" - fy="40.688972" - r="16.956987" - gradientTransform="matrix(1,0,0,0.133183,0,35.2699)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8632" - id="linearGradient8638" - x1="12.031081" - y1="3.9636562" - x2="14.700418" - y2="10.228306" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8648" - id="linearGradient8654" - x1="11.198016" - y1="1.0312058" - x2="11.198016" - y2="14.496081" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8648" - id="linearGradient8660" - gradientUnits="userSpaceOnUse" - x1="11.198016" - y1="1.1643296" - x2="11.198016" - y2="14.496081" - gradientTransform="matrix(-1,0,0,1,16.00001,5)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8632" - id="linearGradient8662" - gradientUnits="userSpaceOnUse" - x1="9.7651443" - y1="4.0303011" - x2="9.0022526" - y2="9.9950476" - gradientTransform="matrix(-1,0,0,1,16.00001,5)" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="15.004829" - inkscape:cx="21.840023" - inkscape:cy="16.645163" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - inkscape:window-width="1440" - inkscape:window-height="847" - inkscape:window-x="0" - inkscape:window-y="0" - width="16px" - height="16px" - inkscape:snap-bbox="true" - inkscape:snap-nodes="false" - objecttolerance="10" - gridtolerance="10" - showguides="true" - inkscape:guide-bbox="true"> - <inkscape:grid - type="xygrid" - id="grid7860" - visible="true" - enabled="true" /> - </sodipodi:namedview> - <metadata - id="metadata4350"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="layer1" - inkscape:label="Layer 1" - inkscape:groupmode="layer"> - <path - style="opacity:0.66000000000000003;fill:url(#linearGradient8654);fill-opacity:1;stroke:url(#linearGradient8638);stroke-width:0.99999928000000005;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 14.875001,0.49999963 C 15.217688,0.49999963 15.5,0.74481173 15.5,1.049489 L 15.5,3.7114598 L 15.5,4.7860168 L 15.5,7.9687565 C 15.5,8.2734337 15.217688,8.5182463 14.875001,8.5182459 L 13.523824,8.5182459 C 13.523824,8.5182459 13.500261,10.537057 13.500261,10.537057 C 12.189929,10.537057 10.901093,8.5069021 10.901093,8.5069021 L 6.1250097,8.5182459 C 5.7823233,8.5182459 5.5000104,8.2734333 5.5000104,7.9687565 L 5.5000104,4.7860168 L 5.5000104,3.7114598 L 5.5000104,1.049489 C 5.5000104,0.74481189 5.7823228,0.49999967 6.1250097,0.49999963 L 8.8380752,0.49999963 L 12.375003,0.49999963 L 14.875001,0.49999963 z" - id="path5540" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999892999999995;stroke-miterlimit:4;stroke-opacity:1;opacity:0.66" - d="M 14.326096,1.4999995 C 14.416734,1.4999995 14.500009,1.5636953 14.500009,1.6546223 L 14.500009,3.9018072 L 14.500009,4.8089277 L 14.500009,7.35505 C 14.500009,7.4459764 14.416733,7.5096728 14.326096,7.5096728 L 12.610239,7.5206242 C 12.405479,7.52273 12.449632,8.6309999 12.449632,8.6309999 L 11.44851,7.4434005 L 6.6739127,7.5096728 C 6.5832743,7.5096728 6.4999995,7.4459761 6.4999995,7.35505 L 6.4999995,4.8089277 L 6.4999995,3.9018072 L 6.4999995,1.6546223 C 6.4999995,1.5636954 6.5832739,1.4999995 6.6739127,1.4999995 L 9.0465863,1.4999995 L 12.139758,1.4999995 L 14.326096,1.4999995 z" - id="path5542" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - sodipodi:type="arc" - style="opacity:0.52838428;fill:url(#radialGradient5241);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path4340" - sodipodi:cx="23.234518" - sodipodi:cy="40.688972" - sodipodi:rx="16.956987" - sodipodi:ry="2.2583797" - d="M 40.191505 40.688972 A 16.956987 2.2583797 0 1 1 6.2775307,40.688972 A 16.956987 2.2583797 0 1 1 40.191505 40.688972 z" - transform="matrix(1.208941,0,0,1.980928,-1.589159,5.924394)" /> - <path - transform="matrix(2.539812,0,0,0.410815,-57.0204,65.80212)" - sodipodi:type="arc" - style="opacity:1;color:black;fill:url(#radialGradient4179);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path4306" - sodipodi:cx="31.112698" - sodipodi:cy="19.008621" - sodipodi:rx="8.6620579" - sodipodi:ry="8.6620579" - d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" /> - <path - style="opacity:1;fill:url(#linearGradient8660);fill-opacity:1;stroke:url(#linearGradient8662);stroke-width:0.99999928000000005;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 1.125011,5.4999996 C 0.78232384,5.4999996 0.50001184,5.7448117 0.50001184,6.049489 L 0.50001184,8.7114598 L 0.50001184,9.7860168 L 0.50001184,12.968757 C 0.50001184,13.273434 0.78232384,13.518247 1.125011,13.518246 L 2.476188,13.518246 C 2.476188,13.518246 2.499751,15.631308 2.499751,15.631308 C 3.810083,15.631308 5.0989186,13.506902 5.0989186,13.506902 L 9.8750026,13.518246 C 10.217687,13.518246 10.5,13.273434 10.5,12.968757 L 10.5,9.7860168 L 10.5,8.7114598 L 10.5,6.049489 C 10.5,5.7448118 10.217688,5.4999996 9.8750026,5.4999996 L 7.1619366,5.4999996 L 3.625009,5.4999996 L 1.125011,5.4999996 z" - id="path8656" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - style="opacity:0.375;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999893;stroke-miterlimit:4;stroke-opacity:1" - d="M 1.673916,6.4999995 C 1.583278,6.4999995 1.500003,6.5636953 1.500003,6.6546223 L 1.500003,8.9018072 L 1.500003,9.8089277 L 1.500003,12.35505 C 1.500003,12.445977 1.583279,12.509673 1.673916,12.509673 L 3.389773,12.520625 C 3.594533,12.52273 3.5714046,13.578902 3.5032546,14.008003 L 4.551502,12.443401 L 9.3260996,12.509673 C 9.4167376,12.509673 9.5000126,12.445976 9.5000126,12.35505 L 9.5000126,9.8089277 L 9.5000126,8.9018072 L 9.5000126,6.6546223 C 9.5000126,6.5636954 9.4167376,6.4999995 9.3260996,6.4999995 L 6.9534256,6.4999995 L 3.860254,6.4999995 L 1.673916,6.4999995 z" - id="path8658" - sodipodi:nodetypes="cccccccccccccccccc" /> - </g> -</svg> diff --git a/libpurple/protocols/irc/resources/icons/22x22/apps/im-irc.png b/libpurple/protocols/irc/resources/icons/22x22/apps/im-irc.png Binary files differdeleted file mode 100644 index 4fa09abe9c..0000000000 --- a/libpurple/protocols/irc/resources/icons/22x22/apps/im-irc.png +++ /dev/null diff --git a/libpurple/protocols/irc/resources/icons/22x22/apps/scalable/im-irc.svg b/libpurple/protocols/irc/resources/icons/22x22/apps/scalable/im-irc.svg deleted file mode 100644 index a4ab01eea2..0000000000 --- a/libpurple/protocols/irc/resources/icons/22x22/apps/scalable/im-irc.svg +++ /dev/null @@ -1,237 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="24" - height="24" - id="svg4345" - sodipodi:version="0.32" - inkscape:version="0.46" - sodipodi:docbase="/home/hbons/Desktop" - sodipodi:docname="irc.svg" - inkscape:export-filename="/home/hbons/Desktop/pidgin.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" - version="1.0" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4347"> - <linearGradient - id="linearGradient2804"> - <stop - style="stop-color:black;stop-opacity:0;" - offset="0" - id="stop2806" /> - <stop - id="stop2812" - offset="0.5" - style="stop-color:black;stop-opacity:1;" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop2808" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2804" - id="linearGradient1516" - gradientUnits="userSpaceOnUse" - x1="21.875" - y1="48.000977" - x2="21.875" - y2="40" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient1514" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,36,8.8)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <linearGradient - inkscape:collect="always" - id="linearGradient2781"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop2783" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop2785" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient1512" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <linearGradient - inkscape:collect="always" - id="linearGradient5235"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop5237" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop5239" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient4179" - gradientUnits="userSpaceOnUse" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient5235" - id="radialGradient5241" - cx="23.234518" - cy="40.688972" - fx="23.234518" - fy="40.688972" - r="16.956987" - gradientTransform="matrix(1,0,0,0.133183,0,35.2699)" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="28" - inkscape:cx="17.768242" - inkscape:cy="11.945133" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - inkscape:window-width="1274" - inkscape:window-height="966" - inkscape:window-x="3" - inkscape:window-y="25" - width="24px" - height="24px" /> - <metadata - id="metadata4350"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="layer1" - inkscape:label="Layer 1" - inkscape:groupmode="layer"> - <g - id="g1504" - style="opacity:0.12663754" - transform="matrix(0.496192,0,0,0.581846,-0.128303,-4.772994)"> - <rect - transform="scale(-1,-1)" - y="-48" - x="-11" - height="8" - width="10" - id="rect1506" - style="opacity:1;color:black;fill:url(#radialGradient1512);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="38" - height="8" - width="10" - id="rect1508" - style="opacity:1;color:black;fill:url(#radialGradient1514);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="11" - height="8" - width="27" - id="rect1510" - style="opacity:1;color:black;fill:url(#linearGradient1516);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - </g> - <path - sodipodi:type="arc" - style="opacity:0.52838428;fill:url(#radialGradient5241);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path4340" - sodipodi:cx="23.234518" - sodipodi:cy="40.688972" - sodipodi:rx="16.956987" - sodipodi:ry="2.2583797" - d="M 40.191505 40.688972 A 16.956987 2.2583797 0 1 1 6.2775307,40.688972 A 16.956987 2.2583797 0 1 1 40.191505 40.688972 z" - transform="matrix(1.208941,0,0,1.980928,-0.589159,7.924396)" /> - <path - style="opacity:1;fill:#efefef;fill-opacity:1;stroke:#787878;stroke-width:1.69608581;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 2.875,7.5 C 2.1210885,7.5 1.5,8.1265217 1.5,8.90625 L 1.5,15.71875 L 1.5,18.46875 L 1.5,26.613999 C 1.5,27.393727 2.1210885,28.02025 2.875,28.020249 L 4.9145119,28.020249 L 4.9145119,30.532781 L 8.1141033,27.991218 L 22.125,28.020249 C 22.878911,28.020249 23.5,27.393726 23.5,26.613999 L 23.5,18.46875 L 23.5,15.71875 L 23.5,8.90625 C 23.5,8.1265221 22.878912,7.5000001 22.125,7.5 L 16.15625,7.5 L 8.375,7.5 L 2.875,7.5 z " - id="path4334" - transform="matrix(-0.590909,0,0,0.588279,23.38636,-1.912091)" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - transform="matrix(-0.546584,0,0,0.546584,22.8323,-1.111803)" - style="fill:none;fill-opacity:1;stroke:white;stroke-width:1.82954407;stroke-miterlimit:4;stroke-opacity:1" - d="M 2.875,8.4375 C 2.6469872,8.4375 2.4375,8.6305983 2.4375,8.90625 L 2.4375,15.71875 L 2.4375,18.46875 L 2.4375,26.1875 C 2.4375,26.46315 2.6469898,26.65625 2.875,26.65625 L 5.0575572,26.65625 C 5.5726565,26.662634 5.9886729,27.078651 5.9950572,27.59375 L 7.0909095,26.8125 C 7.2621189,26.685027 8.9741324,26.618972 9.1875,26.625 L 22.125,26.65625 C 22.353012,26.65625 22.5625,26.463149 22.5625,26.1875 L 22.5625,18.46875 L 22.5625,15.71875 L 22.5625,8.90625 C 22.5625,8.6305986 22.353013,8.4375 22.125,8.4375 L 16.15625,8.4375 L 8.375,8.4375 L 2.875,8.4375 z " - id="path4336" - sodipodi:nodetypes="ccccccccccccccccccc" /> - <path - transform="matrix(2.539812,0,0,0.410815,-56.0204,67.80212)" - sodipodi:type="arc" - style="opacity:1;color:black;fill:url(#radialGradient4179);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path4306" - sodipodi:cx="31.112698" - sodipodi:cy="19.008621" - sodipodi:rx="8.6620579" - sodipodi:ry="8.6620579" - d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" /> - <path - style="opacity:1;fill:#efefef;fill-opacity:1;stroke:#787878;stroke-width:1.69608581;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 2.875,7.5 C 2.1210885,7.5 1.5,8.1265217 1.5,8.90625 L 1.5,15.71875 L 1.5,18.46875 L 1.5,26.613999 C 1.5,27.393727 2.1210885,28.02025 2.875,28.020249 L 4.9145119,28.020249 L 4.9145119,30.532781 L 8.1141033,27.991218 L 22.125,28.020249 C 22.878911,28.020249 23.5,27.393726 23.5,26.613999 L 23.5,18.46875 L 23.5,15.71875 L 23.5,8.90625 C 23.5,8.1265221 22.878912,7.5000001 22.125,7.5 L 16.15625,7.5 L 8.375,7.5 L 2.875,7.5 z " - id="path5534" - transform="matrix(0.590909,0,0,0.588279,0.613639,3.087907)" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - transform="matrix(0.546584,0,0,0.546584,1.167699,3.888195)" - style="fill:none;fill-opacity:1;stroke:white;stroke-width:1.82954407;stroke-miterlimit:4;stroke-opacity:1" - d="M 2.875,8.4375 C 2.6469872,8.4375 2.4375,8.6305983 2.4375,8.90625 L 2.4375,15.71875 L 2.4375,18.46875 L 2.4375,26.1875 C 2.4375,26.46315 2.6469898,26.65625 2.875,26.65625 L 5.0575572,26.65625 C 5.5726565,26.662634 5.9886729,27.078651 5.9950572,27.59375 L 7.0909095,26.8125 C 7.2621189,26.685027 8.9741324,26.618972 9.1875,26.625 L 22.125,26.65625 C 22.353012,26.65625 22.5625,26.463149 22.5625,26.1875 L 22.5625,18.46875 L 22.5625,15.71875 L 22.5625,8.90625 C 22.5625,8.6305986 22.353013,8.4375 22.125,8.4375 L 16.15625,8.4375 L 8.375,8.4375 L 2.875,8.4375 z " - id="path5536" - sodipodi:nodetypes="ccccccccccccccccccc" /> - </g> -</svg> diff --git a/libpurple/protocols/irc/resources/icons/48x48/apps/im-irc.png b/libpurple/protocols/irc/resources/icons/48x48/apps/im-irc.png Binary files differdeleted file mode 100644 index 606425fabb..0000000000 --- a/libpurple/protocols/irc/resources/icons/48x48/apps/im-irc.png +++ /dev/null diff --git a/libpurple/protocols/irc/resources/icons/scalable/apps/im-irc.svg b/libpurple/protocols/irc/resources/icons/scalable/apps/im-irc.svg deleted file mode 100644 index 28e8cb6ee4..0000000000 --- a/libpurple/protocols/irc/resources/icons/scalable/apps/im-irc.svg +++ /dev/null @@ -1,238 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="48px" - height="48px" - id="svg4345" - sodipodi:version="0.32" - inkscape:version="0.46" - sodipodi:docbase="/home/hbons/Desktop" - sodipodi:docname="irc.svg" - inkscape:export-filename="/home/hbons/Desktop/pidgin.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4347"> - <linearGradient - id="linearGradient2804"> - <stop - style="stop-color:black;stop-opacity:0;" - offset="0" - id="stop2806" /> - <stop - id="stop2812" - offset="0.5" - style="stop-color:black;stop-opacity:1;" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop2808" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2804" - id="linearGradient1516" - gradientUnits="userSpaceOnUse" - x1="21.875" - y1="48.000977" - x2="21.875" - y2="40" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient1514" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,36,8.8)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <linearGradient - inkscape:collect="always" - id="linearGradient2781"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop2783" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop2785" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient1512" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <linearGradient - inkscape:collect="always" - id="linearGradient5235"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop5237" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop5239" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient4179" - gradientUnits="userSpaceOnUse" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient5235" - id="radialGradient5241" - cx="23.234518" - cy="40.688972" - fx="23.234518" - fy="40.688972" - r="16.956987" - gradientTransform="matrix(1,0,0,0.133183,0,35.2699)" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="13.062462" - inkscape:cx="40.814762" - inkscape:cy="25.717712" - inkscape:current-layer="layer1" - showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - inkscape:window-width="1274" - inkscape:window-height="966" - inkscape:window-x="3" - inkscape:window-y="25" /> - <metadata - id="metadata4350"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="layer1" - inkscape:label="Layer 1" - inkscape:groupmode="layer"> - <g - id="g1504" - style="opacity:0.12663754" - transform="matrix(0.851064,0,0,0.999995,3.148928,-3.9998)"> - <rect - transform="scale(-1,-1)" - y="-48" - x="-11" - height="8" - width="10" - id="rect1506" - style="opacity:1;color:black;fill:url(#radialGradient1512);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="38" - height="8" - width="10" - id="rect1508" - style="opacity:1;color:black;fill:url(#radialGradient1514);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="11" - height="8" - width="27" - id="rect1510" - style="opacity:1;color:black;fill:url(#linearGradient1516);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - </g> - <path - sodipodi:type="arc" - style="opacity:0.52838428;fill:url(#radialGradient5241);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path4340" - sodipodi:cx="23.234518" - sodipodi:cy="40.688972" - sodipodi:rx="16.956987" - sodipodi:ry="2.2583797" - d="M 40.191505 40.688972 A 16.956987 2.2583797 0 1 1 6.2775307,40.688972 A 16.956987 2.2583797 0 1 1 40.191505 40.688972 z" - transform="matrix(1.208941,0,0,1.980928,3.410841,15.87176)" /> - <path - style="opacity:1;fill:#efefef;fill-opacity:1;stroke:#787878;stroke-width:0.95516169;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 2.875,7.5 C 2.1210885,7.5 1.5,8.1265217 1.5,8.90625 L 1.5,15.71875 L 1.5,18.46875 L 1.5,26.189031 C 1.5,26.968759 2.1210885,27.595282 2.875,27.595281 L 5.5,27.595281 L 5.5,30.532781 L 9.2020155,27.56625 L 22.125,27.595281 C 22.878911,27.595281 23.5,26.968758 23.5,26.189031 L 23.5,18.46875 L 23.5,15.71875 L 23.5,8.90625 C 23.5,8.1265221 22.878912,7.5000001 22.125,7.5 L 16.15625,7.5 L 8.375,7.5 L 2.875,7.5 z " - id="path4334" - transform="matrix(-1.045455,0,0,1.048433,44.0682,0.636752)" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-0.94924349" - inkscape:original="M 2.875 7.5 C 2.1210885 7.5 1.5 8.1265217 1.5 8.90625 L 1.5 15.71875 L 1.5 18.46875 L 1.5 26.1875 C 1.5 26.967227 2.1210885 27.593751 2.875 27.59375 L 5.5 27.59375 L 5.5 30.53125 L 9.1875 27.5625 L 22.125 27.59375 C 22.878911 27.593749 23.5 26.967227 23.5 26.1875 L 23.5 18.46875 L 23.5 15.71875 L 23.5 8.90625 C 23.5 8.1265221 22.878912 7.5000001 22.125 7.5 L 16.15625 7.5 L 8.375 7.5 L 2.875 7.5 z " - style="opacity:1;fill:none;fill-opacity:1;stroke:white;stroke-width:0.95516169;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path4336" - d="M 2.875,8.4375 C 2.6469872,8.4375 2.4375,8.6305983 2.4375,8.90625 L 2.4375,15.71875 L 2.4375,18.46875 L 2.4375,26.1875 C 2.4375,26.46315 2.6469898,26.65625 2.875,26.65625 L 5.5,26.65625 C 6.0150993,26.662634 6.4311157,27.078651 6.4375,27.59375 L 6.4375,28.5625 L 8.59375,26.8125 C 8.7649594,26.685027 8.9741324,26.618972 9.1875,26.625 L 22.125,26.65625 C 22.353012,26.65625 22.5625,26.463149 22.5625,26.1875 L 22.5625,18.46875 L 22.5625,15.71875 L 22.5625,8.90625 C 22.5625,8.6305986 22.353013,8.4375 22.125,8.4375 L 16.15625,8.4375 L 8.375,8.4375 L 2.875,8.4375 z " - transform="matrix(-1.045455,0,0,1.048433,44.0682,0.636752)" /> - <path - transform="matrix(2.539812,0,0,0.410815,-52.0204,75.74948)" - sodipodi:type="arc" - style="opacity:1;color:black;fill:url(#radialGradient4179);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path4306" - sodipodi:cx="31.112698" - sodipodi:cy="19.008621" - sodipodi:rx="8.6620579" - sodipodi:ry="8.6620579" - d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" /> - <path - style="opacity:1;fill:#efefef;fill-opacity:1;stroke:#787878;stroke-width:0.95516169;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 2.875,7.5 C 2.1210885,7.5 1.5,8.1265217 1.5,8.90625 L 1.5,15.71875 L 1.5,18.46875 L 1.5,26.189031 C 1.5,26.968759 2.1210885,27.595282 2.875,27.595281 L 5.5,27.595281 L 5.5,30.532781 L 9.2020155,27.56625 L 22.125,27.595281 C 22.878911,27.595281 23.5,26.968758 23.5,26.189031 L 23.5,18.46875 L 23.5,15.71875 L 23.5,8.90625 C 23.5,8.1265221 22.878912,7.5000001 22.125,7.5 L 16.15625,7.5 L 8.375,7.5 L 2.875,7.5 z " - id="rect1326" - transform="matrix(1.045455,0,0,1.048433,3.931818,8.785079)" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-0.94924349" - inkscape:original="M 2.875 7.5 C 2.1210885 7.5 1.5 8.1265217 1.5 8.90625 L 1.5 15.71875 L 1.5 18.46875 L 1.5 26.1875 C 1.5 26.967227 2.1210885 27.593751 2.875 27.59375 L 5.5 27.59375 L 5.5 30.53125 L 9.1875 27.5625 L 22.125 27.59375 C 22.878911 27.593749 23.5 26.967227 23.5 26.1875 L 23.5 18.46875 L 23.5 15.71875 L 23.5 8.90625 C 23.5 8.1265221 22.878912 7.5000001 22.125 7.5 L 16.15625 7.5 L 8.375 7.5 L 2.875 7.5 z " - style="opacity:1;fill:none;fill-opacity:1;stroke:white;stroke-width:0.95516169;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path5034" - d="M 2.875,8.4375 C 2.6469872,8.4375 2.4375,8.6305983 2.4375,8.90625 L 2.4375,15.71875 L 2.4375,18.46875 L 2.4375,26.1875 C 2.4375,26.46315 2.6469898,26.65625 2.875,26.65625 L 5.5,26.65625 C 6.0150993,26.662634 6.4311157,27.078651 6.4375,27.59375 L 6.4375,28.5625 L 8.59375,26.8125 C 8.7649594,26.685027 8.9741324,26.618972 9.1875,26.625 L 22.125,26.65625 C 22.353012,26.65625 22.5625,26.463149 22.5625,26.1875 L 22.5625,18.46875 L 22.5625,15.71875 L 22.5625,8.90625 C 22.5625,8.6305986 22.353013,8.4375 22.125,8.4375 L 16.15625,8.4375 L 8.375,8.4375 L 2.875,8.4375 z " - transform="matrix(1.045455,0,0,1.048433,3.931818,8.785079)" /> - </g> -</svg> diff --git a/libpurple/protocols/irc/resources/irc.gresource.xml b/libpurple/protocols/irc/resources/irc.gresource.xml deleted file mode 100644 index 5e890b4aa3..0000000000 --- a/libpurple/protocols/irc/resources/irc.gresource.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<gresources> - <gresource prefix="/im/pidgin/libpurple/irc"> - <file>icons/16x16/apps/im-irc.png</file> - <file>icons/16x16/apps/scalable/im-irc.svg</file> - <file>icons/22x22/apps/im-irc.png</file> - <file>icons/22x22/apps/scalable/im-irc.svg</file> - <file>icons/48x48/apps/im-irc.png</file> - <file>icons/scalable/apps/im-irc.svg</file> - </gresource> -</gresources> diff --git a/libpurple/protocols/meson.build b/libpurple/protocols/meson.build index c62892598f..256aaf4868 100644 --- a/libpurple/protocols/meson.build +++ b/libpurple/protocols/meson.build @@ -2,6 +2,5 @@ subdir('bonjour') subdir('demo') subdir('facebook') subdir('gg') -subdir('irc') subdir('ircv3') subdir('jabber') diff --git a/po/POTFILES.in b/po/POTFILES.in index f8b546f066..37a8f3610f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -111,11 +111,6 @@ libpurple/protocols/gg/tcpsocket.c libpurple/protocols/gg/utils.c libpurple/protocols/gg/validator.c libpurple/protocols/gg/xml.c -libpurple/protocols/irc/cmds.c -libpurple/protocols/irc/dcc_send.c -libpurple/protocols/irc/irc.c -libpurple/protocols/irc/msgs.c -libpurple/protocols/irc/parse.c libpurple/protocols/jabber/adhoccommands.c libpurple/protocols/jabber/auth.c libpurple/protocols/jabber/auth_digest_md5.c |