--- a/libpurple/protocols/silc/ops.c Wed Oct 26 01:13:45 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1825 +0,0 @@ -/* - - silcpurple_ops.c - - Author: Pekka Riikonen <priikone@silcnet.org> - - Copyright (C) 2004 - 2007 Pekka Riikonen - - 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; version 2 of the License. - - 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. - -*/ - -#include <glib/gi18n-lib.h> -#include <glib/gstdio.h> - -#include "libpurple/glibcompat.h" - -#include "silcpurple.h" -#include "wb.h" - -static void -silc_channel_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcChannelEntry channel, - SilcMessagePayload payload, - SilcChannelPrivateKey key, SilcMessageFlags flags, - const unsigned char *message, - SilcUInt32 message_len); -static void -silc_private_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcMessagePayload payload, - SilcMessageFlags flags, const unsigned char *message, - SilcUInt32 message_len); -static void -silc_ask_passphrase(SilcClient client, SilcClientConnection conn, - SilcAskPassphrase completion, void *context); - -/* Message sent to the application by library. `conn' associates the - message to a specific connection. `conn', however, may be NULL. - The `type' indicates the type of the message sent by the library. - The application can for example filter the message according the - type. */ - -void silc_say(SilcClient client, SilcClientConnection conn, - SilcClientMessageType type, char *msg, ...) -{ - char tmp[256]; - va_list va; - PurpleConnection *gc = NULL; - PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - - va_start(va, msg); - silc_vsnprintf(tmp, sizeof(tmp), msg, va); - va_end(va); - - if (type != SILC_CLIENT_MESSAGE_ERROR) { - purple_debug_misc("silc", "silc_say (%d) %s\n", type, tmp); - return; - } - - purple_debug_error("silc", "silc_say error: %s\n", tmp); - - if (purple_strequal(tmp, "Authentication failed")) - reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; - - if (client != NULL) - gc = client->application; - - if (gc != NULL) - purple_connection_error(gc, reason, tmp); - else - purple_notify_error(NULL, _("Error"), _("Error occurred"), tmp, NULL); -} - -/* Processes incoming MIME message. Can be private message or channel - message. Returns TRUE if the message `mime' was displayed. */ - -static SilcBool -silcpurple_mime_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcChannelEntry channel, - SilcMessagePayload payload, SilcChannelPrivateKey key, - SilcMessageFlags flags, SilcMime mime, - gboolean recursive) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = purple_connection_get_protocol_data(gc); - const char *type; - const unsigned char *data; - SilcUInt32 data_len; - PurpleMessageFlags cflags = 0; - PurpleConversation *chat = NULL; - PurpleConversationManager *manager = NULL; - SilcBool ret = FALSE; - - if (!mime) - return FALSE; - - /* Check for fragmented MIME message */ - if (silc_mime_is_partial(mime)) { - if (!sg->mimeass) - sg->mimeass = silc_mime_assembler_alloc(); - - /* Defragment */ - mime = silc_mime_assemble(sg->mimeass, mime); - if (!mime) - /* More fragments to come */ - return FALSE; - - /* Process the complete message */ - return silcpurple_mime_message(client, conn, sender, channel, - payload, key, flags, mime, - FALSE); - } - - /* Check for multipart message */ - if (silc_mime_is_multipart(mime)) { - SilcMime p; - const char *mtype; - SilcDList parts = silc_mime_get_multiparts(mime, &mtype); - - if (purple_strequal(mtype, "mixed")) { - /* Contains multiple messages */ - silc_dlist_start(parts); - while ((p = silc_dlist_get(parts)) != SILC_LIST_END) { - /* Recursively process parts */ - ret = silcpurple_mime_message(client, conn, sender, channel, - payload, key, flags, p, TRUE); - } - } - - if (purple_strequal(mtype, "alternative")) { - /* Same message in alternative formats. Kopete sends - these. Go in order from last to first. */ - silc_dlist_end(parts); - while ((p = silc_dlist_get(parts)) != SILC_LIST_END) { - /* Go through the alternatives and display the first - one we support. */ - if (silcpurple_mime_message(client, conn, sender, channel, - payload, key, flags, p, TRUE)) { - ret = TRUE; - break; - } - } - } - - goto out; - } - - /* Get content type and MIME data */ - type = silc_mime_get_field(mime, "Content-Type"); - if (!type) - goto out; - data = silc_mime_get_data(mime, &data_len); - if (!data) - goto out; - - /* Process according to content type */ - - /* Plain text */ - if (strstr(type, "text/plain")) { - /* Default is UTF-8, don't check for other charsets */ - if (!strstr(type, "utf-8")) - goto out; - - if (channel) - silc_channel_message(client, conn, sender, channel, - payload, key, - SILC_MESSAGE_FLAG_UTF8, data, - data_len); - else - silc_private_message(client, conn, sender, payload, - SILC_MESSAGE_FLAG_UTF8, data, - data_len); - ret = TRUE; - goto out; - } - - manager = purple_conversation_manager_get_default(); - - /* Image */ - if (g_str_has_prefix(type, "image/")) { - char tmp[32]; - PurpleImage *img; - guint img_id; - - /* Get channel chat (if message is for channel) */ - if (key && channel) { - GList *l; - SilcPurplePrvgrp prv; - - for (l = sg->grps; l; l = l->next) - if (((SilcPurplePrvgrp)l->data)->key == key) { - prv = l->data; - chat = purple_conversation_manager_find_chat(manager, - sg->account, - prv->channel); - break; - } - } - if (channel && !chat) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - } - - if (channel && !chat) { - goto out; - } - - img = purple_image_new_from_data(data, data_len); - if (!img) - goto out; - img_id = purple_image_store_add_temporary(img); - if (!img_id) { - g_clear_object(&img); - goto out; - } - - cflags |= PURPLE_MESSAGE_IMAGES | PURPLE_MESSAGE_RECV; - g_snprintf(tmp, sizeof(tmp), "<img src=\"" - PURPLE_IMAGE_STORE_PROTOCOL "%u\">", img_id); - - if (channel) { - purple_serv_got_chat_in(gc, - purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat)), - sender->nickname, cflags, tmp, time(NULL)); - } else { - purple_serv_got_im(gc, sender->nickname, - tmp, cflags, time(NULL)); - } - - g_clear_object(&img); - - goto out; - } - - /* Whiteboard message */ - if (strstr(type, "application/x-wb") && - !purple_account_get_bool(sg->account, "block-wb", FALSE)) { - if (channel) - silcpurple_wb_receive_ch(client, conn, sender, channel, - payload, flags, data, data_len); - else - silcpurple_wb_receive(client, conn, sender, payload, - flags, data, data_len); - ret = TRUE; - goto out; - } - - out: - if (!recursive) - silc_mime_free(mime); - return ret; -} - -/* Message for a channel. The `sender' is the sender of the message - The `channel' is the channel. The `message' is the message. Note - that `message' maybe NULL. The `flags' indicates message flags - and it is used to determine how the message can be interpreted - (like it may tell the message is multimedia message). */ - -static void -silc_channel_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcChannelEntry channel, - SilcMessagePayload payload, - SilcChannelPrivateKey key, SilcMessageFlags flags, - const unsigned char *message, - SilcUInt32 message_len) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = purple_connection_get_protocol_data(gc); - PurpleConversation *chat = NULL; - PurpleConversationManager *manager = NULL; - char *msg, *tmp; - - if (!message) - return; - - manager = purple_conversation_manager_get_default(); - - if (key) { - GList *l; - SilcPurplePrvgrp prv; - - for (l = sg->grps; l; l = l->next) - if (((SilcPurplePrvgrp)l->data)->key == key) { - prv = l->data; - chat = purple_conversation_manager_find_chat(manager, sg->account, - prv->channel); - break; - } - } - if (!chat) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - } - - if (!chat) { - return; - } - - if (flags & SILC_MESSAGE_FLAG_SIGNED && - purple_account_get_bool(sg->account, "sign-verify", FALSE)) { - /* XXX */ - } - - if (flags & SILC_MESSAGE_FLAG_DATA) { - /* Process MIME message */ - SilcMime mime; - mime = silc_mime_decode(NULL, message, message_len); - silcpurple_mime_message(client, conn, sender, channel, payload, - key, flags, mime, FALSE); - return; - } - - if (flags & SILC_MESSAGE_FLAG_ACTION) { - msg = g_strdup_printf("/me %s", - (const char *)message); - if (!msg) - return; - - tmp = g_markup_escape_text(msg, -1); - /* Send to Purple */ - purple_serv_got_chat_in(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat)), - sender->nickname, PURPLE_MESSAGE_RECV, tmp, time(NULL)); - g_free(tmp); - g_free(msg); - return; - } - - if (flags & SILC_MESSAGE_FLAG_NOTICE) { - msg = g_strdup_printf("(notice) <I>%s</I> %s", - sender->nickname, (const char *)message); - if (!msg) - return; - - /* Send to Purple */ - purple_conversation_write_system_message( - PURPLE_CONVERSATION(chat), msg, 0); - g_free(msg); - return; - } - - if (flags & SILC_MESSAGE_FLAG_UTF8) { - const char *msg = (const char *)message; - char *salvaged = NULL; - if (!g_utf8_validate((const char *)message, -1, NULL)) { - salvaged = g_utf8_make_valid((const char *)message, -1); - msg = salvaged; - } - tmp = g_markup_escape_text(msg, -1); - /* Send to Purple */ - purple_serv_got_chat_in(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat)), - sender->nickname, PURPLE_MESSAGE_RECV, tmp, time(NULL)); - g_free(salvaged); - g_free(tmp); - } -} - - -/* Private message to the client. The `sender' is the sender of the - message. The message is `message'and maybe NULL. The `flags' - indicates message flags and it is used to determine how the message - can be interpreted (like it may tell the message is multimedia - message). */ - -static void -silc_private_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcMessagePayload payload, - SilcMessageFlags flags, const unsigned char *message, - SilcUInt32 message_len) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = purple_connection_get_protocol_data(gc); - PurpleConversation *convo; - PurpleConversationManager *manager = NULL; - char *msg, *tmp; - - if (!message) { - return; - } - - manager = purple_conversation_manager_get_default(); - /* XXX - Should this be PURPLE_CONV_TYPE_IM? */ - convo = purple_conversation_manager_find(manager, sg->account, - sender->nickname); - - if (flags & SILC_MESSAGE_FLAG_SIGNED && - purple_account_get_bool(sg->account, "sign-verify", FALSE)) { - /* XXX */ - } - - if (flags & SILC_MESSAGE_FLAG_DATA) { - /* Process MIME message */ - SilcMime mime; - mime = silc_mime_decode(NULL, message, message_len); - silcpurple_mime_message(client, conn, sender, NULL, payload, - NULL, flags, mime, FALSE); - return; - } - - if (flags & SILC_MESSAGE_FLAG_ACTION && convo) { - msg = g_strdup_printf("/me %s", - (const char *)message); - if (!msg) - return; - - /* Send to Purple */ - tmp = g_markup_escape_text(msg, -1); - purple_serv_got_im(gc, sender->nickname, tmp, 0, time(NULL)); - g_free(msg); - g_free(tmp); - return; - } - - if (flags & SILC_MESSAGE_FLAG_NOTICE && convo) { - msg = g_strdup_printf("(notice) <I>%s</I> %s", - sender->nickname, (const char *)message); - if (!msg) - return; - - /* Send to Purple */ - purple_conversation_write_system_message(convo, msg, 0); - g_free(msg); - return; - } - - if (flags & SILC_MESSAGE_FLAG_UTF8) { - const char *msg = (const char *)message; - char *salvaged = NULL; - if (!g_utf8_validate((const char *)message, -1, NULL)) { - salvaged = g_utf8_make_valid((const char *)message, -1); - msg = salvaged; - } - tmp = g_markup_escape_text(msg, -1); - /* Send to Purple */ - purple_serv_got_im(gc, sender->nickname, tmp, 0, time(NULL)); - g_free(salvaged); - g_free(tmp); - } -} - - -/* Notify message to the client. The notify arguments are sent in the - same order as servers sends them. The arguments are same as received - from the server except for ID's. If ID is received application receives - the corresponding entry to the ID. For example, if Client ID is received - application receives SilcClientEntry. Also, if the notify type is - for channel the channel entry is sent to application (even if server - does not send it because client library gets the channel entry from - the Channel ID in the packet's header). */ - -static void -silc_notify(SilcClient client, SilcClientConnection conn, - SilcNotifyType type, ...) -{ - va_list va; - PurpleConnection *gc = client->application; - PurpleConversationManager *manager; - SilcPurple sg = purple_connection_get_protocol_data(gc); - PurpleAccount *account = purple_connection_get_account(gc); - PurpleConversation *chat; - SilcClientEntry client_entry, client_entry2; - SilcChannelEntry channel; - SilcServerEntry server_entry; - SilcIdType idtype; - void *entry; - SilcUInt32 mode; - SilcHashTableList htl; - SilcChannelUser chu; - char buf[512], buf2[512], *tmp, *name; - SilcNotifyType notify; - PurpleBuddy *b; - SilcDList list; - - va_start(va, type); - memset(buf, 0, sizeof(buf)); - - manager = purple_conversation_manager_get_default(); - - switch (type) { - - case SILC_NOTIFY_TYPE_NONE: - break; - - case SILC_NOTIFY_TYPE_INVITE: - { - GHashTable *components; - (void)va_arg(va, SilcChannelEntry); - name = va_arg(va, char *); - client_entry = va_arg(va, SilcClientEntry); - - components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_insert(components, g_strdup("channel"), g_strdup(name)); - purple_serv_got_chat_invite(gc, name, client_entry->nickname, NULL, components); - } - break; - - case SILC_NOTIFY_TYPE_JOIN: - client_entry = va_arg(va, SilcClientEntry); - channel = va_arg(va, SilcChannelEntry); - - /* If we joined channel, do nothing */ - if (client_entry == conn->local_entry) - break; - - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - break; - } - - /* Join user to channel */ - g_snprintf(buf, sizeof(buf), "%s@%s", - client_entry->username, client_entry->hostname); - purple_chat_conversation_add_user(PURPLE_CHAT_CONVERSATION(chat), - client_entry->nickname, buf, PURPLE_CHAT_USER_NONE, TRUE); - - break; - - case SILC_NOTIFY_TYPE_LEAVE: - client_entry = va_arg(va, SilcClientEntry); - channel = va_arg(va, SilcChannelEntry); - - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - break; - } - - /* Remove user from channel */ - purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), - client_entry->nickname, NULL); - - break; - - case SILC_NOTIFY_TYPE_SIGNOFF: - client_entry = va_arg(va, SilcClientEntry); - tmp = va_arg(va, char *); - - /* Remove from all channels */ - silc_hash_table_list(client_entry->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - chu->channel->channel_name); - if (!chat) { - continue; - } - purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), - client_entry->nickname, - tmp); - } - silc_hash_table_list_reset(&htl); - - break; - - case SILC_NOTIFY_TYPE_TOPIC_SET: - { - char *esc, *tmp2; - idtype = va_arg(va, int); - entry = va_arg(va, void *); - tmp = va_arg(va, char *); - channel = va_arg(va, SilcChannelEntry); - - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - break; - } - - if (!tmp) { - break; - } - - esc = g_markup_escape_text(tmp, -1); - tmp2 = purple_markup_linkify(esc); - g_free(esc); - - if (idtype == SILC_ID_CLIENT) { - client_entry = (SilcClientEntry)entry; - g_snprintf(buf, sizeof(buf), - _("%s has changed the topic of <I>%s</I> to: %s"), - client_entry->nickname, channel->channel_name, tmp2); - purple_conversation_write_system_message( - PURPLE_CONVERSATION(chat), buf, 0); - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), - client_entry->nickname, tmp); - } else if (idtype == SILC_ID_SERVER) { - server_entry = (SilcServerEntry)entry; - g_snprintf(buf, sizeof(buf), - _("%s has changed the topic of <I>%s</I> to: %s"), - server_entry->server_name, channel->channel_name, tmp2); - purple_conversation_write_system_message( - PURPLE_CONVERSATION(chat), buf, 0); - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), - server_entry->server_name, tmp); - } else if (idtype == SILC_ID_CHANNEL) { - channel = (SilcChannelEntry)entry; - g_snprintf(buf, sizeof(buf), - _("%s has changed the topic of <I>%s</I> to: %s"), - channel->channel_name, channel->channel_name, tmp2); - purple_conversation_write_system_message( - PURPLE_CONVERSATION(chat), buf, 0); - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), - channel->channel_name, tmp); - } else { - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), NULL, tmp); - } - - g_free(tmp2); - - break; - - } - case SILC_NOTIFY_TYPE_NICK_CHANGE: - client_entry = va_arg(va, SilcClientEntry); - tmp = va_arg(va, char *); /* Old nick */ - name = va_arg(va, char *); /* New nick */ - - if (purple_strequal(tmp, name)) - break; - - /* Change nick on all channels */ - silc_hash_table_list(client_entry->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - chu->channel->channel_name); - if (!chat) { - continue; - } - if (purple_chat_conversation_has_user(PURPLE_CHAT_CONVERSATION(chat), client_entry->nickname)) { - purple_chat_conversation_rename_user(PURPLE_CHAT_CONVERSATION(chat), - tmp, name); - } - } - silc_hash_table_list_reset(&htl); - - break; - - case SILC_NOTIFY_TYPE_CMODE_CHANGE: - idtype = va_arg(va, int); - entry = va_arg(va, void *); - mode = va_arg(va, SilcUInt32); - (void)va_arg(va, char *); - (void)va_arg(va, char *); - (void)va_arg(va, char *); - (void)va_arg(va, SilcPublicKey); - (void)va_arg(va, SilcDList); - channel = va_arg(va, SilcChannelEntry); - - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - break; - } - - if (idtype == SILC_ID_CLIENT) { - name = ((SilcClientEntry)entry)->nickname; - } else if (idtype == SILC_ID_SERVER) { - name = ((SilcServerEntry)entry)->server_name; - } else { - name = ((SilcChannelEntry)entry)->channel_name; - } - - if (!name) { - break; - } - - if (mode) { - silcpurple_get_chmode_string(mode, buf2, sizeof(buf2)); - g_snprintf(buf, sizeof(buf), - _("<I>%s</I> set channel <I>%s</I> modes to: %s"), name, - channel->channel_name, buf2); - } else { - g_snprintf(buf, sizeof(buf), - _("<I>%s</I> removed all channel <I>%s</I> modes"), name, - channel->channel_name); - } - purple_conversation_write_system_message(PURPLE_CONVERSATION(chat), buf, 0); - break; - - case SILC_NOTIFY_TYPE_CUMODE_CHANGE: - { - PurpleChatUserFlags flags = PURPLE_CHAT_USER_NONE; - idtype = va_arg(va, int); - entry = va_arg(va, void *); - mode = va_arg(va, SilcUInt32); - client_entry2 = va_arg(va, SilcClientEntry); - channel = va_arg(va, SilcChannelEntry); - - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - break; - } - - if (idtype == SILC_ID_CLIENT) { - name = ((SilcClientEntry)entry)->nickname; - } else if (idtype == SILC_ID_SERVER) { - name = ((SilcServerEntry)entry)->server_name; - } else { - name = ((SilcChannelEntry)entry)->channel_name; - } - - if (!name) { - break; - } - - if (mode) { - silcpurple_get_chumode_string(mode, buf2, sizeof(buf2)); - g_snprintf(buf, sizeof(buf), - _("<I>%s</I> set <I>%s's</I> modes to: %s"), name, - client_entry2->nickname, buf2); - if (mode & SILC_CHANNEL_UMODE_CHANFO) - flags |= PURPLE_CHAT_USER_FOUNDER; - if (mode & SILC_CHANNEL_UMODE_CHANOP) - flags |= PURPLE_CHAT_USER_OP; - } else { - g_snprintf(buf, sizeof(buf), - _("<I>%s</I> removed all <I>%s's</I> modes"), name, - client_entry2->nickname); - } - purple_conversation_write_system_message(chat, buf, 0); - purple_chat_user_set_flags(purple_chat_conversation_find_user( - PURPLE_CHAT_CONVERSATION(chat), client_entry2->nickname), flags); - break; - } - - case SILC_NOTIFY_TYPE_MOTD: - tmp = va_arg(va, char *); - silc_free(sg->motd); - sg->motd = silc_memdup(tmp, strlen(tmp)); - break; - - case SILC_NOTIFY_TYPE_KICKED: - client_entry = va_arg(va, SilcClientEntry); - tmp = va_arg(va, char *); - client_entry2 = va_arg(va, SilcClientEntry); - channel = va_arg(va, SilcChannelEntry); - - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - break; - } - - if (client_entry == conn->local_entry) { - /* Remove us from channel */ - g_snprintf(buf, sizeof(buf), - _("You have been kicked off <I>%s</I> by <I>%s</I> (%s)"), - channel->channel_name, client_entry2->nickname, - tmp ? tmp : ""); - purple_conversation_write_system_message(chat, buf, 0); - purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat))); - } else { - /* Remove user from channel */ - g_snprintf(buf, sizeof(buf), _("Kicked by %s (%s)"), - client_entry2->nickname, tmp ? tmp : ""); - purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), - client_entry->nickname, - buf); - } - - break; - - case SILC_NOTIFY_TYPE_KILLED: - client_entry = va_arg(va, SilcClientEntry); - tmp = va_arg(va, char *); - idtype = va_arg(va, int); - entry = va_arg(va, SilcClientEntry); - - if (client_entry == conn->local_entry) { - if (idtype == SILC_ID_CLIENT) { - client_entry2 = (SilcClientEntry)entry; - g_snprintf(buf, sizeof(buf), - _("You have been killed by %s (%s)"), - client_entry2->nickname, tmp ? tmp : ""); - } else if (idtype == SILC_ID_SERVER) { - server_entry = (SilcServerEntry)entry; - g_snprintf(buf, sizeof(buf), - _("You have been killed by %s (%s)"), - server_entry->server_name, tmp ? tmp : ""); - } else if (idtype == SILC_ID_CHANNEL) { - channel = (SilcChannelEntry)entry; - g_snprintf(buf, sizeof(buf), - _("You have been killed by %s (%s)"), - channel->channel_name, tmp ? tmp : ""); - } - - /* Remove us from all channels */ - silc_hash_table_list(client_entry->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - chu->channel->channel_name); - if (!chat) { - continue; - } - purple_conversation_write_system_message(chat, buf, 0); - purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat))); - } - silc_hash_table_list_reset(&htl); - - } else { - if (idtype == SILC_ID_CLIENT) { - client_entry2 = (SilcClientEntry)entry; - g_snprintf(buf, sizeof(buf), - _("Killed by %s (%s)"), - client_entry2->nickname, tmp ? tmp : ""); - } else if (idtype == SILC_ID_SERVER) { - server_entry = (SilcServerEntry)entry; - g_snprintf(buf, sizeof(buf), - _("Killed by %s (%s)"), - server_entry->server_name, tmp ? tmp : ""); - } else if (idtype == SILC_ID_CHANNEL) { - channel = (SilcChannelEntry)entry; - g_snprintf(buf, sizeof(buf), - _("Killed by %s (%s)"), - channel->channel_name, tmp ? tmp : ""); - } - - /* Remove user from all channels */ - silc_hash_table_list(client_entry->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - chu->channel->channel_name); - if (!chat) { - continue; - } - purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), - client_entry->nickname, tmp); - } - silc_hash_table_list_reset(&htl); - } - - break; - - case SILC_NOTIFY_TYPE_CHANNEL_CHANGE: - break; - - case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: - (void)va_arg(va, void *); - list = va_arg(va, SilcDList); - - silc_dlist_start(list); - while ((client_entry = silc_dlist_get(list))) { - /* Remove from all channels */ - silc_hash_table_list(client_entry->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - chu->channel->channel_name); - if (!chat) { - continue; - } - purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), - client_entry->nickname, - _("Server signoff")); - } - silc_hash_table_list_reset(&htl); - } - break; - - case SILC_NOTIFY_TYPE_ERROR: - { - SilcStatus error = va_arg(va, int); - purple_notify_error(gc, "Error Notify", - silc_get_status_message(error), - NULL, purple_request_cpar_from_connection(gc)); - } - break; - - case SILC_NOTIFY_TYPE_WATCH: - { - SilcPublicKey public_key; - unsigned char *pk; - SilcUInt32 pk_len; - char *fingerprint; - - client_entry = va_arg(va, SilcClientEntry); - (void)va_arg(va, char *); - mode = va_arg(va, SilcUInt32); - notify = va_arg(va, int); - public_key = va_arg(va, SilcPublicKey); - - b = NULL; - if (public_key) { - GSList *buddies; - const char *f; - gsize i; - - pk = silc_pkcs_public_key_encode(public_key, &pk_len); - if (!pk) - break; - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - for (i = 0; i < strlen(fingerprint); i++) - if (fingerprint[i] == ' ') - fingerprint[i] = '_'; - g_snprintf(buf, sizeof(buf) - 1, - "%s" G_DIR_SEPARATOR_S "clientkeys" - G_DIR_SEPARATOR_S "clientkey_%s.pub", - silcpurple_silcdir(), fingerprint); - silc_free(fingerprint); - silc_free(pk); - - /* Find buddy by associated public key */ - for (buddies = purple_blist_find_buddies(account, NULL); buddies; - buddies = g_slist_delete_link(buddies, buddies)) { - b = buddies->data; - f = purple_blist_node_get_string(PURPLE_BLIST_NODE(b), "public-key"); - if (purple_strequal(f, buf)) - goto cont; - b = NULL; - } - } - cont: - if (!b) { - /* Find buddy by nickname */ - b = purple_blist_find_buddy(sg->account, client_entry->nickname); - if (!b) { - purple_debug_warning("silc", "WATCH for %s, unknown buddy\n", - client_entry->nickname); - break; - } - } - - silc_free(purple_buddy_get_protocol_data(b)); - purple_buddy_set_protocol_data(b, silc_memdup(&client_entry->id, - sizeof(client_entry->id))); - if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) { - break; - } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) { - /* See if client was away and is now present */ - if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED | - SILC_UMODE_BUSY | SILC_UMODE_PAGE | - SILC_UMODE_DETACHED)) && - (client_entry->mode & SILC_UMODE_GONE || - client_entry->mode & SILC_UMODE_INDISPOSED || - client_entry->mode & SILC_UMODE_BUSY || - client_entry->mode & SILC_UMODE_PAGE || - client_entry->mode & SILC_UMODE_DETACHED)) { - client_entry->mode = mode; - purple_protocol_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_AVAILABLE, NULL); - } - else if ((mode & SILC_UMODE_GONE) || - (mode & SILC_UMODE_INDISPOSED) || - (mode & SILC_UMODE_BUSY) || - (mode & SILC_UMODE_PAGE) || - (mode & SILC_UMODE_DETACHED)) { - client_entry->mode = mode; - purple_protocol_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); - } - } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF || - notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF || - notify == SILC_NOTIFY_TYPE_KILLED) { - client_entry->mode = mode; - purple_protocol_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); - } else if (notify == SILC_NOTIFY_TYPE_NONE) { - client_entry->mode = mode; - purple_protocol_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_AVAILABLE, NULL); - } - } - break; - - default: - purple_debug_info("silc", "Unhandled notification: %d\n", type); - break; - } - - va_end(va); -} - - -/* Command handler. This function is called always after application has - called a command. It will be called to indicate that the command - was processed. It will also be called if error occurs while processing - the command. The `success' indicates whether the command was sent - or if error occurred. The `status' indicates the actual error. - The `argc' and `argv' are the command line arguments sent to the - command by application. Note that, this is not reply to the command - from server, this is merely and indication to application that the - command was processed. */ - -static void -silc_command(SilcClient client, SilcClientConnection conn, - SilcBool success, SilcCommand command, SilcStatus status, - SilcUInt32 argc, unsigned char **argv) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = purple_connection_get_protocol_data(gc); - - switch (command) { - - case SILC_COMMAND_CMODE: - if (argc == 3 && purple_strequal((char *)argv[2], "+C")) - sg->chpk = TRUE; - else - sg->chpk = FALSE; - break; - - default: - break; - } -} - - -/* Command reply handler. Delivers a reply to command that was sent - earlier. The `conn' is the associated client connection. The `command' - indicates the command reply type. If the `status' other than - SILC_STATUS_OK an error occurred. In this case the `error' will indicate - the error. It is possible to receive list of command replies and list - of errors. In this case the `status' will indicate it is an list entry - (the `status' is SILC_STATUS_LIST_START, SILC_STATUS_LIST_ITEM and/or - SILC_STATUS_LIST_END). - - The arguments received in `ap' are command specific. See a separate - documentation in the Toolkit Reference Manual for the command reply - arguments. */ - -static void -silc_command_reply(SilcClient client, SilcClientConnection conn, - SilcCommand command, SilcStatus status, - SilcStatus error, va_list ap) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = purple_connection_get_protocol_data(gc); - PurpleConversation *chat; - PurpleConversationManager *manager; - - manager = purple_conversation_manager_get_default(); - - switch (command) { - case SILC_COMMAND_JOIN: - { - SilcChannelEntry channel; - SilcHashTableList *user_list; - SilcChannelUser chu; - GList *users = NULL, *flags = NULL; - char tmp[256], *topic; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Join Chat"), _("Cannot join channel"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - (void)va_arg(ap, char *); - channel = va_arg(ap, SilcChannelEntry); - (void)va_arg(ap, SilcUInt32); - user_list = va_arg(ap, SilcHashTableList *); - topic = va_arg(ap, char *); - - /* Add channel to Purple */ - channel->context = SILC_32_TO_PTR(++sg->channel_ids); - purple_serv_got_joined_chat(gc, sg->channel_ids, channel->channel_name); - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - return; - } - - /* Add all users to channel */ - while (silc_hash_table_get(user_list, NULL, (void *)&chu)) { - PurpleChatUserFlags f = PURPLE_CHAT_USER_NONE; - chu->context = SILC_32_TO_PTR(sg->channel_ids); - - if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) - f |= PURPLE_CHAT_USER_FOUNDER; - if (chu->mode & SILC_CHANNEL_UMODE_CHANOP) - f |= PURPLE_CHAT_USER_OP; - users = g_list_append(users, chu->client->nickname); - flags = g_list_append(flags, GINT_TO_POINTER(f)); - - if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { - if (chu->client == conn->local_entry) - g_snprintf(tmp, sizeof(tmp), - _("You are channel founder on <I>%s</I>"), - channel->channel_name); - else - g_snprintf(tmp, sizeof(tmp), - _("Channel founder on <I>%s</I> is <I>%s</I>"), - channel->channel_name, chu->client->nickname); - - purple_conversation_write_system_message(chat, tmp, 0); - } - } - - purple_chat_conversation_add_users(PURPLE_CHAT_CONVERSATION(chat), - users, NULL, flags, FALSE); - g_list_free(users); - g_list_free(flags); - - /* Set topic */ - if(topic) { - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), - NULL, topic); - } - - /* Set nick */ - purple_chat_conversation_set_nick(PURPLE_CHAT_CONVERSATION(chat), - conn->local_entry->nickname); - } - break; - - case SILC_COMMAND_LEAVE: - break; - - case SILC_COMMAND_USERS: - break; - - case SILC_COMMAND_WHOIS: - { - SilcUInt32 *user_modes; - SilcDList channels; - SilcClientEntry client_entry; - char tmp[1024]; - char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; - PurpleNotifyUserInfo *user_info; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("User Information"), - _("Cannot get user information"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - break; - } - - client_entry = va_arg(ap, SilcClientEntry); - (void)va_arg(ap, char *); - (void)va_arg(ap, char *); - (void)va_arg(ap, char *); - channels = va_arg(ap, SilcDList); - (void)va_arg(ap, SilcUInt32); - (void)va_arg(ap, SilcUInt32); /* idle */ - (void)va_arg(ap, unsigned char *); - user_modes = va_arg(ap, SilcUInt32 *); - - user_info = purple_notify_user_info_new(); - purple_notify_user_info_add_pair_plaintext(user_info, _("Nickname"), client_entry->nickname); - if (client_entry->realname) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Real Name"), client_entry->realname); - } - if (*client_entry->hostname) { - gchar *tmp2; - tmp2 = g_strdup_printf("%s@%s", client_entry->username, client_entry->hostname); - purple_notify_user_info_add_pair_plaintext(user_info, _("Username"), tmp2); - g_free(tmp2); - } else - purple_notify_user_info_add_pair_plaintext(user_info, _("Username"), client_entry->username); - - if (client_entry->mode) { - memset(tmp, 0, sizeof(tmp)); - silcpurple_get_umode_string(client_entry->mode, - tmp, sizeof(tmp) - strlen(tmp)); - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("User Modes"), tmp); - } - - silcpurple_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); - if (moodstr) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Mood"), moodstr); - g_free(moodstr); - } - - if (statusstr) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Status Text"), statusstr); - g_free(statusstr); - } - - if (contactstr) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Preferred Contact"), contactstr); - g_free(contactstr); - } - - if (langstr) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Preferred Language"), langstr); - g_free(langstr); - } - - if (devicestr) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Device"), devicestr); - g_free(devicestr); - } - - if (tzstr) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Timezone"), tzstr); - g_free(tzstr); - } - - if (geostr) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Geolocation"), geostr); - g_free(geostr); - } - - if (*client_entry->server) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Server"), client_entry->server); - } - - if (channels && user_modes) { - SilcChannelPayload entry; - int i = 0; - - memset(tmp, 0, sizeof(tmp)); - silc_dlist_start(channels); - while ((entry = silc_dlist_get(channels))) { - SilcUInt32 name_len; - char *m = silc_client_chumode_char(user_modes[i++]); - char *name = (char *)silc_channel_get_name(entry, &name_len); - if (m) - silc_strncat(tmp, sizeof(tmp) - 1, m, strlen(m)); - silc_strncat(tmp, sizeof(tmp) - 1, name, name_len); - silc_strncat(tmp, sizeof(tmp) - 1, " ", 1); - silc_free(m); - } - purple_notify_user_info_add_pair_plaintext(user_info, _("Currently on"), tmp); - } - - if (client_entry->public_key) { - char *fingerprint, *babbleprint; - unsigned char *pk; - SilcUInt32 pk_len; - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); - if (pk) { - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); - purple_notify_user_info_add_pair_plaintext(user_info, _("Public Key Fingerprint"), fingerprint); - purple_notify_user_info_add_pair_plaintext(user_info, _("Public Key Babbleprint"), babbleprint); - silc_free(fingerprint); - silc_free(babbleprint); - silc_free(pk); - } - } - - purple_notify_userinfo(gc, client_entry->nickname, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - } - break; - - case SILC_COMMAND_WHOWAS: - { - SilcClientEntry client_entry; - char *nickname, *realname, *username; - PurpleNotifyUserInfo *user_info; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("User Information"), - _("Cannot get user information"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - break; - } - - client_entry = va_arg(ap, SilcClientEntry); - nickname = va_arg(ap, char *); - username = va_arg(ap, char *); - realname = va_arg(ap, char *); - if (!nickname) - break; - - user_info = purple_notify_user_info_new(); - purple_notify_user_info_add_pair_plaintext(user_info, _("Nickname"), nickname); - if (realname) - purple_notify_user_info_add_pair_plaintext(user_info, _("Real Name"), realname); - if (username) { - if (client_entry && *client_entry->hostname) { - gchar *tmp; - tmp = g_strdup_printf("%s@%s", username, client_entry->hostname); - purple_notify_user_info_add_pair_plaintext(user_info, _("Username"), tmp); - g_free(tmp); - } else - purple_notify_user_info_add_pair_plaintext(user_info, _("Username"), username); - } - if (client_entry && *client_entry->server) { - /* TODO: Check whether it's correct to call add_pair_html, - or if we should be using add_pair_plaintext */ - purple_notify_user_info_add_pair_html(user_info, _("Server"), client_entry->server); - } - - - if (client_entry && client_entry->public_key) { - char *fingerprint, *babbleprint; - unsigned char *pk; - SilcUInt32 pk_len; - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); - if (pk) { - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); - purple_notify_user_info_add_pair_plaintext(user_info, _("Public Key Fingerprint"), fingerprint); - purple_notify_user_info_add_pair_plaintext(user_info, _("Public Key Babbleprint"), babbleprint); - silc_free(fingerprint); - silc_free(babbleprint); - silc_free(pk); - } - } - - purple_notify_userinfo(gc, nickname, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - } - break; - - case SILC_COMMAND_DETACH: - { - const char *file; - SilcBuffer detach_data; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Detach From Server"), _("Cannot detach"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - detach_data = va_arg(ap, SilcBuffer); - - /* Save the detachment data to file. */ - file = silcpurple_session_file(purple_account_get_username(sg->account)); - g_unlink(file); - silc_file_writefile(file, (const char *)silc_buffer_data(detach_data), - silc_buffer_len(detach_data)); - } - break; - - case SILC_COMMAND_TOPIC: - { - SilcChannelEntry channel; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Topic"), _("Cannot set topic"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - channel = va_arg(ap, SilcChannelEntry); - - chat = purple_conversation_manager_find_chat(manager, sg->account, - channel->channel_name); - if (!chat) { - purple_debug_error("silc", "Got a topic for %s, which doesn't exist\n", - channel->channel_name); - break; - } - - /* Set topic */ - if (channel->topic) { - purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), - NULL, channel->topic); - } - } - break; - - case SILC_COMMAND_NICK: - { - SilcClientEntry local_entry; - SilcHashTableList htl; - SilcChannelUser chu; - const char *oldnick, *newnick; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Nick"), _("Failed to change nickname"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - local_entry = va_arg(ap, SilcClientEntry); - newnick = va_arg(ap, char *); - - /* Change nick on all channels */ - silc_hash_table_list(local_entry->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - chat = purple_conversation_manager_find_chat(manager, sg->account, - chu->channel->channel_name); - if (!chat) { - continue; - } - oldnick = purple_chat_conversation_get_nick(PURPLE_CHAT_CONVERSATION(chat)); - if (!purple_strequal(oldnick, - purple_normalize(purple_conversation_get_account(chat), - newnick))) - { - - purple_chat_conversation_rename_user(PURPLE_CHAT_CONVERSATION(chat), - oldnick, newnick); - purple_chat_conversation_set_nick(PURPLE_CHAT_CONVERSATION(chat), newnick); - } - } - silc_hash_table_list_reset(&htl); - - purple_connection_set_display_name(gc, newnick); - } - break; - - case SILC_COMMAND_LIST: - { - char *topic, *name; - int usercount; - PurpleRoomlistRoom *room; - - if (sg->roomlist_cancelled) - break; - - if (error != SILC_STATUS_OK) { - purple_notify_error(gc, _("Error"), _("Error retrieving room list"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - purple_roomlist_set_in_progress(sg->roomlist, FALSE); - g_object_unref(sg->roomlist); - sg->roomlist = NULL; - return; - } - - (void)va_arg(ap, SilcChannelEntry); - name = va_arg(ap, char *); - if (!name) { - purple_notify_error(gc, _("Roomlist"), _("Cannot get room list"), - _("Network is empty"), - purple_request_cpar_from_connection(gc)); - purple_roomlist_set_in_progress(sg->roomlist, FALSE); - g_object_unref(sg->roomlist); - sg->roomlist = NULL; - return; - } - topic = va_arg(ap, char *); - usercount = va_arg(ap, int); - - room = purple_roomlist_room_new(name, topic); - purple_roomlist_room_set_user_count(room, usercount); - purple_roomlist_room_add_field(room, "channel", g_strdup(name)); - purple_roomlist_room_add(sg->roomlist, room); - g_object_unref(room); - - if (status == SILC_STATUS_LIST_END || - status == SILC_STATUS_OK) { - purple_roomlist_set_in_progress(sg->roomlist, FALSE); - g_object_unref(sg->roomlist); - sg->roomlist = NULL; - } - } - break; - - case SILC_COMMAND_GETKEY: - { - SilcPublicKey public_key; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Get Public Key"), - _("Cannot fetch the public key"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - (void)va_arg(ap, SilcUInt32); - (void)va_arg(ap, void *); - public_key = va_arg(ap, SilcPublicKey); - - if (!public_key) - purple_notify_error(gc, _("Get Public Key"), - _("Cannot fetch the public key"), - _("No public key was received"), - purple_request_cpar_from_connection(gc)); - } - break; - - case SILC_COMMAND_INFO: - { - - char *server_name; - char *server_info; - char tmp[256]; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Server Information"), - _("Cannot get server information"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - (void)va_arg(ap, SilcServerEntry); - server_name = va_arg(ap, char *); - server_info = va_arg(ap, char *); - - if (server_name && server_info) { - g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s", - server_name, server_info); - purple_notify_info(gc, NULL, _("Server Information"), tmp, - purple_request_cpar_from_connection(gc)); - } - } - break; - - case SILC_COMMAND_STATS: - { - SilcClientStats *stats; - char *msg; - - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Server Statistics"), - _("Cannot get server statistics"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - stats = va_arg(ap, SilcClientStats *); - - msg = g_strdup_printf(_("Local server start time: %s\n" - "Local server uptime: %s\n" - "Local server clients: %d\n" - "Local server channels: %d\n" - "Local server operators: %d\n" - "Local router operators: %d\n" - "Local cell clients: %d\n" - "Local cell channels: %d\n" - "Local cell servers: %d\n" - "Total clients: %d\n" - "Total channels: %d\n" - "Total servers: %d\n" - "Total routers: %d\n" - "Total server operators: %d\n" - "Total router operators: %d\n"), - silc_time_string(stats->starttime), - purple_str_seconds_to_string((int)stats->uptime), - (int)stats->my_clients, - (int)stats->my_channels, - (int)stats->my_server_ops, - (int)stats->my_router_ops, - (int)stats->cell_clients, - (int)stats->cell_channels, - (int)stats->cell_servers, - (int)stats->clients, - (int)stats->channels, - (int)stats->servers, - (int)stats->routers, - (int)stats->server_ops, - (int)stats->router_ops); - - purple_notify_info(gc, NULL, - _("Network Statistics"), msg, - purple_request_cpar_from_connection(gc)); - g_free(msg); - } - break; - - case SILC_COMMAND_PING: - { - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Ping"), _("Ping failed"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - - purple_notify_info(gc, _("Ping"), _("Ping reply received from server"), - NULL, purple_request_cpar_from_connection(gc)); - } - break; - - case SILC_COMMAND_KILL: - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("Kill User"), - _("Could not kill user"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - break; - - case SILC_COMMAND_CMODE: - { - SilcChannelEntry channel_entry; - SilcDList channel_pubkeys, list; - SilcArgumentDecodedList e; - - if (status != SILC_STATUS_OK) - return; - - channel_entry = va_arg(ap, SilcChannelEntry); - (void)va_arg(ap, SilcUInt32); - (void)va_arg(ap, SilcPublicKey); - channel_pubkeys = va_arg(ap, SilcDList); - - if (!sg->chpk) - break; - - list = silc_dlist_init(); - - if (channel_pubkeys) { - silc_dlist_start(channel_pubkeys); - while ((e = silc_dlist_get(channel_pubkeys))) { - if (e->arg_type == 0x00 || - e->arg_type == 0x03) - silc_dlist_add(list, silc_pkcs_public_key_copy(e->argument)); - } - } - silcpurple_chat_chauth_show(sg, channel_entry, list); - } - break; - - case SILC_COMMAND_WATCH: - if (status != SILC_STATUS_OK) { - purple_notify_error(gc, _("WATCH"), _("Cannot watch user"), - silc_get_status_message(error), - purple_request_cpar_from_connection(gc)); - return; - } - break; - - default: - if (status == SILC_STATUS_OK) - purple_debug_info("silc", "Unhandled command: %d (succeeded)\n", command); - else - purple_debug_info("silc", "Unhandled command: %d (failed: %s)\n", command, - silc_get_status_message(error)); - break; - } -} - -/* Generic command reply callback for silc_client_command_send. Simply - calls the default command_reply client operation callback */ - -SilcBool silcpurple_command_reply(SilcClient client, SilcClientConnection conn, - SilcCommand command, SilcStatus status, - SilcStatus error, void *context, va_list ap) -{ - silc_command_reply(client, conn, command, status, error, ap); - return TRUE; -} - - -typedef struct { - union { - SilcAskPassphrase ask_pass; - SilcGetAuthMeth get_auth; - } u; - void *context; -} *SilcPurpleAskPassphrase; - -static void -silc_ask_auth_password_cb(const unsigned char *passphrase, - SilcUInt32 passphrase_len, void *context) -{ - SilcPurpleAskPassphrase internal = context; - - if (!passphrase || !(*passphrase)) - internal->u.get_auth(SILC_AUTH_NONE, NULL, 0, internal->context); - else - internal->u.get_auth(SILC_AUTH_PASSWORD, - (unsigned char *)passphrase, - passphrase_len, internal->context); - silc_free(internal); -} - -/* Find authentication method and authentication data by hostname and - port. The hostname may be IP address as well. The `auth_method' is - the authentication method the remote connection requires. It is - however possible that remote accepts also some other authentication - method. Application should use the method that may have been - configured for this connection. If none has been configured it should - use the required `auth_method'. If the `auth_method' is - SILC_AUTH_NONE, server does not require any authentication or the - required authentication method is not known. The `completion' - callback must be called to deliver the chosen authentication method - and data. The `conn' may be NULL. */ - -static void -silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, SilcUInt16 port, - SilcAuthMethod auth_method, - SilcGetAuthMeth completion, void *context) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = purple_connection_get_protocol_data(gc); - SilcPurpleAskPassphrase internal; - const char *password; - - /* Check configuration if we have this connection configured. */ - if (auth_method == SILC_AUTH_PUBLIC_KEY && - purple_account_get_bool(sg->account, "pubkey-auth", FALSE)) { - completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context); - return; - } - if (auth_method == SILC_AUTH_PASSWORD) { - password = purple_connection_get_password(gc); - if (password && *password) { - completion(SILC_AUTH_PASSWORD, (unsigned char *)password, strlen(password), context); - return; - } - - /* Ask password from user */ - internal = silc_calloc(1, sizeof(*internal)); - if (!internal) - return; - internal->u.get_auth = completion; - internal->context = context; - silc_ask_passphrase(client, conn, silc_ask_auth_password_cb, - internal); - return; - } - - completion(SILC_AUTH_NONE, NULL, 0, context); -} - - -/* Called to verify received public key. The `conn_type' indicates which - entity (server or client) has sent the public key. If user decides to - trust the key the application may save the key as trusted public key for - later use. The `completion' must be called after the public key has - been verified. */ - -static void -silc_verify_public_key(SilcClient client, SilcClientConnection conn, - SilcConnectionType conn_type, - SilcPublicKey public_key, - SilcVerifyPublicKey completion, void *context) -{ - /* Verify public key */ - silcpurple_verify_public_key(client, conn, NULL, conn_type, - public_key, completion, context); -} - -static void -silc_ask_passphrase_cb(SilcPurpleAskPassphrase internal, const char *passphrase) -{ - if (!passphrase || !(*passphrase)) - internal->u.ask_pass(NULL, 0, internal->context); - else - internal->u.ask_pass((unsigned char *)passphrase, - strlen(passphrase), internal->context); - silc_free(internal); -} - -/* Ask (interact, that is) a passphrase from user. The passphrase is - returned to the library by calling the `completion' callback with - the `context'. The returned passphrase SHOULD be in UTF-8 encoded, - if not then the library will attempt to encode. */ - -static void -silc_ask_passphrase(SilcClient client, SilcClientConnection conn, - SilcAskPassphrase completion, void *context) -{ - PurpleConnection *gc = client->application; - SilcPurpleAskPassphrase internal = silc_calloc(1, sizeof(*internal)); - - if (!internal) - return; - internal->u.ask_pass = completion; - internal->context = context; - purple_request_input(gc, _("Passphrase"), NULL, - _("Passphrase required"), NULL, FALSE, TRUE, NULL, - _("OK"), G_CALLBACK(silc_ask_passphrase_cb), - _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb), - purple_request_cpar_from_connection(gc), internal); -} - - -/* Called to indicate that incoming key agreement request has been - received. If the application wants to perform key agreement it may - call silc_client_perform_key_agreement to initiate key agreement or - silc_client_send_key_agreement to provide connection point to the - remote client in case the `hostname' is NULL. If key agreement is - not desired this request can be ignored. The `protocol' is either - value 0 for TCP or value 1 for UDP. */ - -static void -silc_key_agreement(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, - const char *hostname, SilcUInt16 protocol, - SilcUInt16 port) -{ - silcpurple_buddy_keyagr_request(client, conn, client_entry, - hostname, port, protocol); -} - - -/* Notifies application that file transfer protocol session is being - requested by the remote client indicated by the `client_entry' from - the `hostname' and `port'. The `session_id' is the file transfer - session and it can be used to either accept or reject the file - transfer request, by calling the silc_client_file_receive or - silc_client_file_close, respectively. */ - -static void -silc_ftp(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, SilcUInt32 session_id, - const char *hostname, SilcUInt16 port) -{ - silcpurple_ftp_request(client, conn, client_entry, session_id, - hostname, port); -} - -SilcClientOperations ops = { - silc_say, - silc_channel_message, - silc_private_message, - silc_notify, - silc_command, - silc_command_reply, - silc_get_auth_method, - silc_verify_public_key, - silc_ask_passphrase, - silc_key_agreement, - silc_ftp -};