--- a/src/protocols/silc/buddy.c Mon Apr 16 00:43:53 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1739 +0,0 @@ -/* - - silcgaim_buddy.c - - Author: Pekka Riikonen <priikone@silcnet.org> - - Copyright (C) 2004 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 "silcincludes.h" -#include "silcclient.h" -#include "silcgaim.h" -#include "wb.h" - -/***************************** Key Agreement *********************************/ - -static void -silcgaim_buddy_keyagr(GaimBlistNode *node, gpointer data); - -static void -silcgaim_buddy_keyagr_do(GaimConnection *gc, const char *name, - gboolean force_local); - -typedef struct { - char *nick; - GaimConnection *gc; -} *SilcGaimResolve; - -static void -silcgaim_buddy_keyagr_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) -{ - GaimConnection *gc = client->application; - SilcGaimResolve r = context; - char tmp[256]; - - if (!clients) { - g_snprintf(tmp, sizeof(tmp), - _("User %s is not present in the network"), r->nick); - gaim_notify_error(gc, _("Key Agreement"), - _("Cannot perform the key agreement"), tmp); - silc_free(r->nick); - silc_free(r); - return; - } - - silcgaim_buddy_keyagr_do(gc, r->nick, FALSE); - silc_free(r->nick); - silc_free(r); -} - -typedef struct { - gboolean responder; -} *SilcGaimKeyAgr; - -static void -silcgaim_buddy_keyagr_cb(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - SilcKeyAgreementStatus status, - SilcSKEKeyMaterial *key, - void *context) -{ - GaimConnection *gc = client->application; - SilcGaim sg = gc->proto_data; - SilcGaimKeyAgr a = context; - - if (!sg->conn) - return; - - switch (status) { - case SILC_KEY_AGREEMENT_OK: - { - GaimConversation *convo; - char tmp[128]; - - /* Set the private key for this client */ - silc_client_del_private_message_key(client, conn, client_entry); - silc_client_add_private_message_key_ske(client, conn, client_entry, - NULL, NULL, key, a->responder); - silc_ske_free_key_material(key); - - - /* Open IM window */ - convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, - client_entry->nickname, sg->account); - if (convo) { - /* we don't have windows in the core anymore...but we may want to - * provide some method for asking the UI to show the window - gaim_conv_window_show(gaim_conversation_get_window(convo)); - */ - } else { - convo = gaim_conversation_new(GAIM_CONV_TYPE_IM, sg->account, - client_entry->nickname); - } - g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); - gaim_conversation_set_title(convo, tmp); - } - break; - - case SILC_KEY_AGREEMENT_ERROR: - gaim_notify_error(gc, _("Key Agreement"), - _("Error occurred during key agreement"), NULL); - break; - - case SILC_KEY_AGREEMENT_FAILURE: - gaim_notify_error(gc, _("Key Agreement"), _("Key Agreement failed"), NULL); - break; - - case SILC_KEY_AGREEMENT_TIMEOUT: - gaim_notify_error(gc, _("Key Agreement"), - _("Timeout during key agreement"), NULL); - break; - - case SILC_KEY_AGREEMENT_ABORTED: - gaim_notify_error(gc, _("Key Agreement"), - _("Key agreement was aborted"), NULL); - break; - - case SILC_KEY_AGREEMENT_ALREADY_STARTED: - gaim_notify_error(gc, _("Key Agreement"), - _("Key agreement is already started"), NULL); - break; - - case SILC_KEY_AGREEMENT_SELF_DENIED: - gaim_notify_error(gc, _("Key Agreement"), - _("Key agreement cannot be started with yourself"), - NULL); - break; - - default: - break; - } - - silc_free(a); -} - -static void -silcgaim_buddy_keyagr_do(GaimConnection *gc, const char *name, - gboolean force_local) -{ - SilcGaim sg = gc->proto_data; - SilcClientEntry *clients; - SilcUInt32 clients_count; - char *local_ip = NULL, *remote_ip = NULL; - gboolean local = TRUE; - char *nickname; - SilcGaimKeyAgr a; - - if (!sg->conn || !name) - return; - - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; - - /* Find client entry */ - clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name, - &clients_count); - if (!clients) { - /* Resolve unknown user */ - SilcGaimResolve r = silc_calloc(1, sizeof(*r)); - if (!r) - return; - r->nick = g_strdup(name); - r->gc = gc; - silc_client_get_clients(sg->client, sg->conn, nickname, NULL, - silcgaim_buddy_keyagr_resolved, r); - silc_free(nickname); - return; - } - - /* Resolve the local IP from the outgoing socket connection. We resolve - it to check whether we have a private range IP address or public IP - address. If we have public then we will assume that we are not behind - NAT and will provide automatically the point of connection to the - agreement. If we have private range address we assume that we are - behind NAT and we let the responder provide the point of connection. - - The algorithm also checks the remote IP address of server connection. - If it is private range address and we have private range address we - assume that we are chatting in LAN and will provide the point of - connection. - - Naturally this algorithm does not always get things right. */ - - if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) { - /* Check if the IP is private */ - if (!force_local && silcgaim_ip_is_private(local_ip)) { - local = FALSE; - - /* Local IP is private, resolve the remote server IP to see whether - we are talking to Internet or just on LAN. */ - if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL, - &remote_ip)) - if (silcgaim_ip_is_private(remote_ip)) - /* We assume we are in LAN. Let's provide - the connection point. */ - local = TRUE; - } - } - - if (force_local) - local = TRUE; - - if (local && !local_ip) - local_ip = silc_net_localip(); - - a = silc_calloc(1, sizeof(*a)); - if (!a) - return; - a->responder = local; - - /* Send the key agreement request */ - silc_client_send_key_agreement(sg->client, sg->conn, clients[0], - local ? local_ip : NULL, NULL, 0, 60, - silcgaim_buddy_keyagr_cb, a); - - silc_free(local_ip); - silc_free(remote_ip); - silc_free(clients); -} - -typedef struct { - SilcClient client; - SilcClientConnection conn; - SilcClientID client_id; - char *hostname; - SilcUInt16 port; -} *SilcGaimKeyAgrAsk; - -static void -silcgaim_buddy_keyagr_request_cb(SilcGaimKeyAgrAsk a, gint id) -{ - SilcGaimKeyAgr ai; - SilcClientEntry client_entry; - - if (id != 1) - goto out; - - /* Get the client entry. */ - client_entry = silc_client_get_client_by_id(a->client, a->conn, - &a->client_id); - if (!client_entry) { - gaim_notify_error(a->client->application, _("Key Agreement"), - _("The remote user is not present in the network any more"), - NULL); - goto out; - } - - /* If the hostname was provided by the requestor perform the key agreement - now. Otherwise, we will send him a request to connect to us. */ - if (a->hostname) { - ai = silc_calloc(1, sizeof(*ai)); - if (!ai) - goto out; - ai->responder = FALSE; - silc_client_perform_key_agreement(a->client, a->conn, client_entry, - a->hostname, a->port, - silcgaim_buddy_keyagr_cb, ai); - } else { - /* Send request. Force us as the point of connection since requestor - did not provide the point of connection. */ - silcgaim_buddy_keyagr_do(a->client->application, - client_entry->nickname, TRUE); - } - - out: - silc_free(a->hostname); - silc_free(a); -} - -void silcgaim_buddy_keyagr_request(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - const char *hostname, SilcUInt16 port) -{ - char tmp[128], tmp2[128]; - SilcGaimKeyAgrAsk a; - - g_snprintf(tmp, sizeof(tmp), - _("Key agreement request received from %s. Would you like to " - "perform the key agreement?"), client_entry->nickname); - if (hostname) - g_snprintf(tmp2, sizeof(tmp2), - _("The remote user is waiting key agreement on:\n" - "Remote host: %s\nRemote port: %d"), hostname, port); - - a = silc_calloc(1, sizeof(*a)); - if (!a) - return; - a->client = client; - a->conn = conn; - a->client_id = *client_entry->id; - if (hostname) - a->hostname = strdup(hostname); - a->port = port; - - gaim_request_action(client->application, _("Key Agreement Request"), tmp, - hostname ? tmp2 : NULL, 1, a, 2, - _("Yes"), G_CALLBACK(silcgaim_buddy_keyagr_request_cb), - _("No"), G_CALLBACK(silcgaim_buddy_keyagr_request_cb)); -} - -static void -silcgaim_buddy_keyagr(GaimBlistNode *node, gpointer data) -{ - GaimBuddy *buddy; - - buddy = (GaimBuddy *)node; - silcgaim_buddy_keyagr_do(buddy->account->gc, buddy->name, FALSE); -} - - -/**************************** Static IM Key **********************************/ - -static void -silcgaim_buddy_resetkey(GaimBlistNode *node, gpointer data) -{ - GaimBuddy *b; - GaimConnection *gc; - SilcGaim sg; - char *nickname; - SilcClientEntry *clients; - SilcUInt32 clients_count; - - g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); - - b = (GaimBuddy *) node; - gc = gaim_account_get_connection(b->account); - sg = gc->proto_data; - - if (!silc_parse_userfqdn(b->name, &nickname, NULL)) - return; - - /* Find client entry */ - clients = silc_client_get_clients_local(sg->client, sg->conn, - nickname, b->name, - &clients_count); - if (!clients) { - silc_free(nickname); - return; - } - - clients[0]->prv_resp = FALSE; - silc_client_del_private_message_key(sg->client, sg->conn, - clients[0]); - silc_free(clients); - silc_free(nickname); -} - -typedef struct { - SilcClient client; - SilcClientConnection conn; - SilcClientID client_id; -} *SilcGaimPrivkey; - -static void -silcgaim_buddy_privkey(GaimConnection *gc, const char *name); - -static void -silcgaim_buddy_privkey_cb(SilcGaimPrivkey p, const char *passphrase) -{ - SilcClientEntry client_entry; - - if (!passphrase || !(*passphrase)) { - silc_free(p); - return; - } - - /* Get the client entry. */ - client_entry = silc_client_get_client_by_id(p->client, p->conn, - &p->client_id); - if (!client_entry) { - gaim_notify_error(p->client->application, _("IM With Password"), - _("The remote user is not present in the network any more"), - NULL); - silc_free(p); - return; - } - - /* Set the private message key */ - silc_client_del_private_message_key(p->client, p->conn, - client_entry); - silc_client_add_private_message_key(p->client, p->conn, - client_entry, NULL, NULL, - (unsigned char *)passphrase, - strlen(passphrase), FALSE, - client_entry->prv_resp); - if (!client_entry->prv_resp) - silc_client_send_private_message_key_request(p->client, - p->conn, - client_entry); - silc_free(p); -} - -static void -silcgaim_buddy_privkey_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) -{ - char tmp[256]; - - if (!clients) { - g_snprintf(tmp, sizeof(tmp), - _("User %s is not present in the network"), - (const char *)context); - gaim_notify_error(client->application, _("IM With Password"), - _("Cannot set IM key"), tmp); - g_free(context); - return; - } - - silcgaim_buddy_privkey(client->application, context); - silc_free(context); -} - -static void -silcgaim_buddy_privkey(GaimConnection *gc, const char *name) -{ - SilcGaim sg = gc->proto_data; - char *nickname; - SilcGaimPrivkey p; - SilcClientEntry *clients; - SilcUInt32 clients_count; - - if (!name) - return; - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; - - /* Find client entry */ - clients = silc_client_get_clients_local(sg->client, sg->conn, - nickname, name, - &clients_count); - if (!clients) { - silc_client_get_clients(sg->client, sg->conn, nickname, NULL, - silcgaim_buddy_privkey_resolved, - g_strdup(name)); - silc_free(nickname); - return; - } - - p = silc_calloc(1, sizeof(*p)); - if (!p) - return; - p->client = sg->client; - p->conn = sg->conn; - p->client_id = *clients[0]->id; - gaim_request_input(gc, _("IM With Password"), NULL, - _("Set IM Password"), NULL, FALSE, TRUE, NULL, - _("OK"), G_CALLBACK(silcgaim_buddy_privkey_cb), - _("Cancel"), G_CALLBACK(silcgaim_buddy_privkey_cb), - p); - - silc_free(clients); - silc_free(nickname); -} - -static void -silcgaim_buddy_privkey_menu(GaimBlistNode *node, gpointer data) -{ - GaimBuddy *buddy; - GaimConnection *gc; - - g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); - - buddy = (GaimBuddy *) node; - gc = gaim_account_get_connection(buddy->account); - - silcgaim_buddy_privkey(gc, buddy->name); -} - - -/**************************** Get Public Key *********************************/ - -typedef struct { - SilcClient client; - SilcClientConnection conn; - SilcClientID client_id; -} *SilcGaimBuddyGetkey; - -static void -silcgaim_buddy_getkey(GaimConnection *gc, const char *name); - -static void -silcgaim_buddy_getkey_cb(SilcGaimBuddyGetkey g, - SilcClientCommandReplyContext cmd) -{ - SilcClientEntry client_entry; - unsigned char *pk; - SilcUInt32 pk_len; - - /* Get the client entry. */ - client_entry = silc_client_get_client_by_id(g->client, g->conn, - &g->client_id); - if (!client_entry) { - gaim_notify_error(g->client->application, _("Get Public Key"), - _("The remote user is not present in the network any more"), - NULL); - silc_free(g); - return; - } - - if (!client_entry->public_key) { - silc_free(g); - return; - } - - /* Now verify the public key */ - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); - silcgaim_verify_public_key(g->client, g->conn, client_entry->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - NULL, NULL); - silc_free(pk); - silc_free(g); -} - -static void -silcgaim_buddy_getkey_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) -{ - char tmp[256]; - - if (!clients) { - g_snprintf(tmp, sizeof(tmp), - _("User %s is not present in the network"), - (const char *)context); - gaim_notify_error(client->application, _("Get Public Key"), - _("Cannot fetch the public key"), tmp); - g_free(context); - return; - } - - silcgaim_buddy_getkey(client->application, context); - silc_free(context); -} - -static void -silcgaim_buddy_getkey(GaimConnection *gc, const char *name) -{ - SilcGaim sg = gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; - SilcClientEntry *clients; - SilcUInt32 clients_count; - SilcGaimBuddyGetkey g; - char *nickname; - - if (!name) - return; - - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; - - /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, name, - &clients_count); - if (!clients) { - silc_client_get_clients(client, conn, nickname, NULL, - silcgaim_buddy_getkey_resolved, - g_strdup(name)); - silc_free(nickname); - return; - } - - /* Call GETKEY */ - g = silc_calloc(1, sizeof(*g)); - if (!g) - return; - g->client = client; - g->conn = conn; - g->client_id = *clients[0]->id; - silc_client_command_call(client, conn, NULL, "GETKEY", - clients[0]->nickname, NULL); - silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcgaim_buddy_getkey_cb, g); - silc_free(clients); - silc_free(nickname); -} - -static void -silcgaim_buddy_getkey_menu(GaimBlistNode *node, gpointer data) -{ - GaimBuddy *buddy; - GaimConnection *gc; - - g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); - - buddy = (GaimBuddy *) node; - gc = gaim_account_get_connection(buddy->account); - - silcgaim_buddy_getkey(gc, buddy->name); -} - -static void -silcgaim_buddy_showkey(GaimBlistNode *node, gpointer data) -{ - GaimBuddy *b; - GaimConnection *gc; - SilcGaim sg; - SilcPublicKey public_key; - const char *pkfile; - - g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); - - b = (GaimBuddy *) node; - gc = gaim_account_get_connection(b->account); - sg = gc->proto_data; - - pkfile = gaim_blist_node_get_string(node, "public-key"); - if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) { - gaim_notify_error(gc, - _("Show Public Key"), - _("Could not load public key"), NULL); - return; - } - - silcgaim_show_public_key(sg, b->name, public_key, NULL, NULL); - silc_pkcs_public_key_free(public_key); -} - - -/**************************** Buddy routines *********************************/ - -/* The buddies are implemented by using the WHOIS and WATCH commands that - can be used to search users by their public key. Since nicknames aren't - unique in SILC we cannot trust the buddy list using their nickname. We - associate public keys to buddies and use those to search and watch - in the network. - - The problem is that Gaim does not return GaimBuddy contexts to the - callbacks but the buddy names. Naturally, this is not going to work - with SILC. But, for now, we have to do what we can... */ - -typedef struct { - SilcClient client; - SilcClientConnection conn; - SilcClientID client_id; - GaimBuddy *b; - unsigned char *offline_pk; - SilcUInt32 offline_pk_len; - unsigned int offline : 1; - unsigned int pubkey_search : 1; - unsigned int init : 1; -} *SilcGaimBuddyRes; - -static void -silcgaim_add_buddy_ask_pk_cb(SilcGaimBuddyRes r, gint id); -static void -silcgaim_add_buddy_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context); - -void silcgaim_get_info(GaimConnection *gc, const char *who) -{ - SilcGaim sg = gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; - SilcClientEntry client_entry; - GaimBuddy *b; - const char *filename, *nick = who; - char tmp[256]; - - if (!who) - return; - if (strlen(who) > 1 && who[0] == '@') - nick = who + 1; - if (strlen(who) > 1 && who[0] == '*') - nick = who + 1; - if (strlen(who) > 2 && who[0] == '*' && who[1] == '@') - nick = who + 2; - - b = gaim_find_buddy(gc->account, nick); - if (b) { - /* See if we have this buddy's public key. If we do use that - to search the details. */ - filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); - if (filename) { - /* Call WHOIS. The user info is displayed in the WHOIS - command reply. */ - silc_client_command_call(client, conn, NULL, "WHOIS", - "-details", "-pubkey", filename, NULL); - return; - } - - if (!b->proto_data) { - g_snprintf(tmp, sizeof(tmp), - _("User %s is not present in the network"), b->name); - gaim_notify_error(gc, _("User Information"), - _("Cannot get user information"), tmp); - return; - } - - client_entry = silc_client_get_client_by_id(client, conn, b->proto_data); - if (client_entry) { - /* Call WHOIS. The user info is displayed in the WHOIS - command reply. */ - silc_client_command_call(client, conn, NULL, "WHOIS", - client_entry->nickname, "-details", NULL); - } - } else { - /* Call WHOIS just with nickname. */ - silc_client_command_call(client, conn, NULL, "WHOIS", nick, NULL); - } -} - -static void -silcgaim_add_buddy_pk_no(SilcGaimBuddyRes r) -{ - char tmp[512]; - g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"), - r->b->name); - gaim_notify_error(r->client->application, _("Add Buddy"), tmp, - _("You cannot receive buddy notifications until you " - "import his/her public key. You can use the Get Public Key " - "command to get the public key.")); - gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_OFFLINE, NULL); -} - -static void -silcgaim_add_buddy_save(bool success, void *context) -{ - SilcGaimBuddyRes r = context; - GaimBuddy *b = r->b; - SilcClient client = r->client; - SilcClientEntry client_entry; - SilcAttributePayload attr; - SilcAttribute attribute; - SilcVCardStruct vcard; - SilcAttributeObjMime message, extension; -#ifdef SILC_ATTRIBUTE_USER_ICON - SilcAttributeObjMime usericon; -#endif - SilcAttributeObjPk serverpk, usersign, serversign; - gboolean usign_success = TRUE, ssign_success = TRUE; - char filename[512], filename2[512], *fingerprint = NULL, *tmp; - SilcUInt32 len; - int i; - - if (!success) { - /* The user did not trust the public key. */ - silcgaim_add_buddy_pk_no(r); - silc_free(r); - return; - } - - if (r->offline) { - /* User is offline. Associate the imported public key with - this user. */ - fingerprint = silc_hash_fingerprint(NULL, r->offline_pk, - r->offline_pk_len); - for (i = 0; i < strlen(fingerprint); i++) - if (fingerprint[i] == ' ') - fingerprint[i] = '_'; - g_snprintf(filename, sizeof(filename) - 1, - "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", - silcgaim_silcdir(), fingerprint); - gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); - gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_OFFLINE, NULL); - silc_free(fingerprint); - silc_free(r->offline_pk); - silc_free(r); - return; - } - - /* Get the client entry. */ - client_entry = silc_client_get_client_by_id(r->client, r->conn, - &r->client_id); - if (!client_entry) { - silc_free(r); - return; - } - - memset(&vcard, 0, sizeof(vcard)); - memset(&message, 0, sizeof(message)); - memset(&extension, 0, sizeof(extension)); -#ifdef SILC_ATTRIBUTE_USER_ICON - memset(&usericon, 0, sizeof(usericon)); -#endif - memset(&serverpk, 0, sizeof(serverpk)); - memset(&usersign, 0, sizeof(usersign)); - memset(&serversign, 0, sizeof(serversign)); - - /* Now that we have the public key and we trust it now we - save the attributes of the buddy and update its status. */ - - if (client_entry->attrs) { - silc_dlist_start(client_entry->attrs); - while ((attr = silc_dlist_get(client_entry->attrs)) - != SILC_LIST_END) { - attribute = silc_attribute_get_attribute(attr); - - switch (attribute) { - case SILC_ATTRIBUTE_USER_INFO: - if (!silc_attribute_get_object(attr, (void *)&vcard, - sizeof(vcard))) - continue; - break; - - case SILC_ATTRIBUTE_STATUS_MESSAGE: - if (!silc_attribute_get_object(attr, (void *)&message, - sizeof(message))) - continue; - break; - - case SILC_ATTRIBUTE_EXTENSION: - if (!silc_attribute_get_object(attr, (void *)&extension, - sizeof(extension))) - continue; - break; - -#ifdef SILC_ATTRIBUTE_USER_ICON - case SILC_ATTRIBUTE_USER_ICON: - if (!silc_attribute_get_object(attr, (void *)&usericon, - sizeof(usericon))) - continue; - break; -#endif - - case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: - if (serverpk.type) - continue; - if (!silc_attribute_get_object(attr, (void *)&serverpk, - sizeof(serverpk))) - continue; - break; - - case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: - if (usersign.data) - continue; - if (!silc_attribute_get_object(attr, (void *)&usersign, - sizeof(usersign))) - continue; - break; - - case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: - if (serversign.data) - continue; - if (!silc_attribute_get_object(attr, (void *)&serversign, - sizeof(serversign))) - continue; - break; - - default: - break; - } - } - } - - /* Verify the attribute signatures */ - - if (usersign.data) { - SilcPKCS pkcs; - unsigned char *verifyd; - SilcUInt32 verify_len; - - silc_pkcs_alloc((unsigned char*)"rsa", &pkcs); - verifyd = silc_attribute_get_verify_data(client_entry->attrs, - FALSE, &verify_len); - if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ - if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, - usersign.data, - usersign.data_len, - verifyd, verify_len)) - usign_success = FALSE; - } - silc_free(verifyd); - } - - if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { - SilcPublicKey public_key; - SilcPKCS pkcs; - unsigned char *verifyd; - SilcUInt32 verify_len; - - if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, - &public_key)) { - silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); - verifyd = silc_attribute_get_verify_data(client_entry->attrs, - TRUE, &verify_len); - if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { - if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, - serversign.data, - serversign.data_len, - verifyd, verify_len)) - ssign_success = FALSE; - } - silc_pkcs_public_key_free(public_key); - silc_free(verifyd); - } - } - - fingerprint = silc_fingerprint(client_entry->fingerprint, - client_entry->fingerprint_len); - for (i = 0; i < strlen(fingerprint); i++) - if (fingerprint[i] == ' ') - fingerprint[i] = '_'; - - if (usign_success || ssign_success) { - struct passwd *pw; - struct stat st; - - memset(filename2, 0, sizeof(filename2)); - - /* Filename for dir */ - tmp = fingerprint + strlen(fingerprint) - 9; - g_snprintf(filename, sizeof(filename) - 1, - "%s" G_DIR_SEPARATOR_S "friends" G_DIR_SEPARATOR_S "%s", - silcgaim_silcdir(), tmp); - - pw = getpwuid(getuid()); - if (!pw) - return; - - /* Create dir if it doesn't exist */ - if ((g_stat(filename, &st)) == -1) { - if (errno == ENOENT) { - if (pw->pw_uid == geteuid()) - g_mkdir(filename, 0755); - } - } - - /* Save VCard */ - g_snprintf(filename2, sizeof(filename2) - 1, - "%s" G_DIR_SEPARATOR_S "vcard", filename); - if (vcard.full_name) { - tmp = (char *)silc_vcard_encode(&vcard, &len); - silc_file_writefile(filename2, tmp, len); - silc_free(tmp); - } - - /* Save status message */ - if (message.mime) { - memset(filename2, 0, sizeof(filename2)); - g_snprintf(filename2, sizeof(filename2) - 1, - "%s" G_DIR_SEPARATOR_S "status_message.mime", - filename); - silc_file_writefile(filename2, (char *)message.mime, - message.mime_len); - } - - /* Save extension data */ - if (extension.mime) { - memset(filename2, 0, sizeof(filename2)); - g_snprintf(filename2, sizeof(filename2) - 1, - "%s" G_DIR_SEPARATOR_S "extension.mime", - filename); - silc_file_writefile(filename2, (char *)extension.mime, - extension.mime_len); - } - -#ifdef SILC_ATTRIBUTE_USER_ICON - /* Save user icon */ - if (usericon.mime) { - SilcMime m = silc_mime_decode(usericon.mime, - usericon.mime_len); - if (m) { - const char *type = silc_mime_get_field(m, "Content-Type"); - if (!strcmp(type, "image/jpeg") || - !strcmp(type, "image/gif") || - !strcmp(type, "image/bmp") || - !strcmp(type, "image/png")) { - const unsigned char *data; - SilcUInt32 data_len; - data = silc_mime_get_data(m, &data_len); - if (data) - gaim_buddy_icons_set_for_user(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), (void *)data, data_len); - } - silc_mime_free(m); - } - } -#endif - } - - /* Save the public key path to buddy properties, as it is used - to identify the buddy in the network (and not the nickname). */ - memset(filename, 0, sizeof(filename)); - g_snprintf(filename, sizeof(filename) - 1, - "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", - silcgaim_silcdir(), fingerprint); - gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); - - /* Update online status */ - gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_AVAILABLE, NULL); - - /* Finally, start watching this user so we receive its status - changes from the server */ - g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename); - silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", - filename2, NULL); - - silc_free(fingerprint); - silc_free(r); -} - -static void -silcgaim_add_buddy_ask_import(void *user_data, const char *name) -{ - SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; - SilcPublicKey public_key; - - /* Load the public key */ - if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { - silcgaim_add_buddy_ask_pk_cb(r, 0); - gaim_notify_error(r->client->application, - _("Add Buddy"), _("Could not load public key"), NULL); - return; - } - - /* Now verify the public key */ - r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); - silcgaim_verify_public_key(r->client, r->conn, r->b->name, - SILC_SOCKET_TYPE_CLIENT, - r->offline_pk, r->offline_pk_len, - SILC_SKE_PK_TYPE_SILC, - silcgaim_add_buddy_save, r); -} - -static void -silcgaim_add_buddy_ask_pk_cancel(void *user_data, const char *name) -{ - SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; - - /* The user did not import public key. The buddy is unusable. */ - silcgaim_add_buddy_pk_no(r); - silc_free(r); -} - -static void -silcgaim_add_buddy_ask_pk_cb(SilcGaimBuddyRes r, gint id) -{ - if (id != 0) { - /* The user did not import public key. The buddy is unusable. */ - silcgaim_add_buddy_pk_no(r); - silc_free(r); - return; - } - - /* Open file selector to select the public key. */ - gaim_request_file(r->client->application, _("Open..."), NULL, FALSE, - G_CALLBACK(silcgaim_add_buddy_ask_import), - G_CALLBACK(silcgaim_add_buddy_ask_pk_cancel), r); -} - -static void -silcgaim_add_buddy_ask_pk(SilcGaimBuddyRes r) -{ - char tmp[512]; - g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), - r->b->name); - gaim_request_action(r->client->application, _("Add Buddy"), tmp, - _("To add the buddy you must import his/her public key. " - "Press Import to import a public key."), 0, r, 2, - _("Cancel"), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb), - _("_Import..."), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb)); -} - -static void -silcgaim_add_buddy_getkey_cb(SilcGaimBuddyRes r, - SilcClientCommandReplyContext cmd) -{ - SilcClientEntry client_entry; - unsigned char *pk; - SilcUInt32 pk_len; - - /* Get the client entry. */ - client_entry = silc_client_get_client_by_id(r->client, r->conn, - &r->client_id); - if (!client_entry || !client_entry->public_key) { - /* The buddy is offline/nonexistent. We will require user - to associate a public key with the buddy or the buddy - cannot be added. */ - r->offline = TRUE; - silcgaim_add_buddy_ask_pk(r); - return; - } - - /* Now verify the public key */ - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); - silcgaim_verify_public_key(r->client, r->conn, client_entry->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - silcgaim_add_buddy_save, r); - silc_free(pk); -} - -static void -silcgaim_add_buddy_select_cb(SilcGaimBuddyRes r, GaimRequestFields *fields) -{ - GaimRequestField *f; - const GList *list; - SilcClientEntry client_entry; - - f = gaim_request_fields_get_field(fields, "list"); - list = gaim_request_field_list_get_selected(f); - if (!list) { - /* The user did not select any user. */ - silcgaim_add_buddy_pk_no(r); - silc_free(r); - return; - } - - client_entry = gaim_request_field_list_get_data(f, list->data); - silcgaim_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); -} - -static void -silcgaim_add_buddy_select_cancel(SilcGaimBuddyRes r, GaimRequestFields *fields) -{ - /* The user did not select any user. */ - silcgaim_add_buddy_pk_no(r); - silc_free(r); -} - -static void -silcgaim_add_buddy_select(SilcGaimBuddyRes r, - SilcClientEntry *clients, - SilcUInt32 clients_count) -{ - GaimRequestFields *fields; - GaimRequestFieldGroup *g; - GaimRequestField *f; - char tmp[512], tmp2[128]; - int i; - char *fingerprint; - - fields = gaim_request_fields_new(); - g = gaim_request_field_group_new(NULL); - f = gaim_request_field_list_new("list", NULL); - gaim_request_field_group_add_field(g, f); - gaim_request_field_list_set_multi_select(f, FALSE); - gaim_request_fields_add_group(fields, g); - - for (i = 0; i < clients_count; i++) { - fingerprint = NULL; - if (clients[i]->fingerprint) { - fingerprint = silc_fingerprint(clients[i]->fingerprint, - clients[i]->fingerprint_len); - g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint); - } - g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s", - clients[i]->realname, clients[i]->nickname, - clients[i]->username, clients[i]->hostname ? - clients[i]->hostname : "", - fingerprint ? tmp2 : ""); - gaim_request_field_list_add(f, tmp, clients[i]); - silc_free(fingerprint); - } - - gaim_request_fields(r->client->application, _("Add Buddy"), - _("Select correct user"), - r->pubkey_search - ? _("More than one user was found with the same public key. Select " - "the correct user from the list to add to the buddy list.") - : _("More than one user was found with the same name. Select " - "the correct user from the list to add to the buddy list."), - fields, - _("OK"), G_CALLBACK(silcgaim_add_buddy_select_cb), - _("Cancel"), G_CALLBACK(silcgaim_add_buddy_select_cancel), r); -} - -static void -silcgaim_add_buddy_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) -{ - SilcGaimBuddyRes r = context; - GaimBuddy *b = r->b; - SilcAttributePayload pub; - SilcAttributeObjPk userpk; - unsigned char *pk; - SilcUInt32 pk_len; - const char *filename; - - filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); - - /* If the buddy is offline/nonexistent, we will require user - to associate a public key with the buddy or the buddy - cannot be added. */ - if (!clients_count) { - if (r->init) { - silc_free(r); - return; - } - - r->offline = TRUE; - /* If the user has already associated a public key, try loading it - * before prompting the user to load it again */ - if (filename != NULL) - silcgaim_add_buddy_ask_import(r, filename); - else - silcgaim_add_buddy_ask_pk(r); - return; - } - - /* If more than one client was found with nickname, we need to verify - from user which one is the correct. */ - if (clients_count > 1 && !r->pubkey_search) { - if (r->init) { - silc_free(r); - return; - } - - silcgaim_add_buddy_select(r, clients, clients_count); - return; - } - - /* If we searched using public keys and more than one entry was found - the same person is logged on multiple times. */ - if (clients_count > 1 && r->pubkey_search && b->name) { - if (r->init) { - /* Find the entry that closest matches to the - buddy nickname. */ - int i; - for (i = 0; i < clients_count; i++) { - if (!strncasecmp(b->name, clients[i]->nickname, - strlen(b->name))) { - clients[0] = clients[i]; - break; - } - } - } else { - /* Verify from user which one is correct */ - silcgaim_add_buddy_select(r, clients, clients_count); - return; - } - } - - /* The client was found. Now get its public key and verify - that before adding the buddy. */ - memset(&userpk, 0, sizeof(userpk)); - b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); - r->client_id = *clients[0]->id; - - /* Get the public key from attributes, if not present then - resolve it with GETKEY unless we have it cached already. */ - if (clients[0]->attrs && !clients[0]->public_key) { - pub = silcgaim_get_attr(clients[0]->attrs, - SILC_ATTRIBUTE_USER_PUBLIC_KEY); - if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, - sizeof(userpk))) { - /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); - silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcgaim_add_buddy_getkey_cb, - r); - return; - } - if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, - &clients[0]->public_key)) - return; - silc_free(userpk.data); - } else if (filename && !clients[0]->public_key) { - if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(filename, &clients[0]->public_key, - SILC_PKCS_FILE_BIN)) { - /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); - silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcgaim_add_buddy_getkey_cb, - r); - return; - } - } else if (!clients[0]->public_key) { - /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); - silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcgaim_add_buddy_getkey_cb, - r); - return; - } - - /* We have the public key, verify it. */ - pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); - silcgaim_verify_public_key(client, conn, clients[0]->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - silcgaim_add_buddy_save, r); - silc_free(pk); -} - -static void -silcgaim_add_buddy_i(GaimConnection *gc, GaimBuddy *b, gboolean init) -{ - SilcGaim sg = gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; - SilcGaimBuddyRes r; - SilcBuffer attrs; - const char *filename, *name = b->name; - - r = silc_calloc(1, sizeof(*r)); - if (!r) - return; - r->client = client; - r->conn = conn; - r->b = b; - r->init = init; - - /* See if we have this buddy's public key. If we do use that - to search the details. */ - filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); - if (filename) { - SilcPublicKey public_key; - SilcAttributeObjPk userpk; - - if (!silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_BIN)) - return; - - /* Get all attributes, and use the public key to search user */ - name = NULL; - attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, - SILC_ATTRIBUTE_SERVICE, - SILC_ATTRIBUTE_STATUS_MOOD, - SILC_ATTRIBUTE_STATUS_FREETEXT, - SILC_ATTRIBUTE_STATUS_MESSAGE, - SILC_ATTRIBUTE_PREFERRED_LANGUAGE, - SILC_ATTRIBUTE_PREFERRED_CONTACT, - SILC_ATTRIBUTE_TIMEZONE, - SILC_ATTRIBUTE_GEOLOCATION, -#ifdef SILC_ATTRIBUTE_USER_ICON - SILC_ATTRIBUTE_USER_ICON, -#endif - SILC_ATTRIBUTE_DEVICE_INFO, 0); - userpk.type = "silc-rsa"; - userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); - attrs = silc_attribute_payload_encode(attrs, - SILC_ATTRIBUTE_USER_PUBLIC_KEY, - SILC_ATTRIBUTE_FLAG_VALID, - &userpk, sizeof(userpk)); - silc_free(userpk.data); - silc_pkcs_public_key_free(public_key); - r->pubkey_search = TRUE; - } else { - /* Get all attributes */ - attrs = silc_client_attributes_request(0); - } - - /* Resolve */ - silc_client_get_clients_whois(client, conn, name, NULL, attrs, - silcgaim_add_buddy_resolved, r); - silc_buffer_free(attrs); -} - -void silcgaim_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) -{ - silcgaim_add_buddy_i(gc, buddy, FALSE); -} - -void silcgaim_send_buddylist(GaimConnection *gc) -{ - GaimBuddyList *blist; - GaimBlistNode *gnode, *cnode, *bnode; - GaimBuddy *buddy; - GaimAccount *account; - - account = gaim_connection_get_account(gc); - - if ((blist = gaim_get_blist()) != NULL) - { - for (gnode = blist->root; gnode != NULL; gnode = gnode->next) - { - if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) - continue; - for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) - { - if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) - continue; - for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) - { - if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) - continue; - buddy = (GaimBuddy *)bnode; - if (gaim_buddy_get_account(buddy) == account) - silcgaim_add_buddy_i(gc, buddy, TRUE); - } - } - } - } -} - -void silcgaim_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, - GaimGroup *group) -{ - silc_free(buddy->proto_data); -} - -void silcgaim_idle_set(GaimConnection *gc, int idle) - -{ - SilcGaim sg = gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; - SilcAttributeObjService service; - const char *server; - int port; - - server = gaim_account_get_string(sg->account, "server", - "silc.silcnet.org"); - port = gaim_account_get_int(sg->account, "port", 706), - - memset(&service, 0, sizeof(service)); - silc_client_attribute_del(client, conn, - SILC_ATTRIBUTE_SERVICE, NULL); - service.port = port; - g_snprintf(service.address, sizeof(service.address), "%s", server); - service.idle = idle; - silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_SERVICE, - &service, sizeof(service)); -} - -char *silcgaim_status_text(GaimBuddy *b) -{ - SilcGaim sg = b->account->gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; - SilcClientID *client_id = b->proto_data; - SilcClientEntry client_entry; - SilcAttributePayload attr; - SilcAttributeMood mood = 0; - - /* Get the client entry. */ - client_entry = silc_client_get_client_by_id(client, conn, client_id); - if (!client_entry) - return NULL; - - /* If user is online, we show the mood status, if available. - If user is offline or away that status is indicated. */ - - if (client_entry->mode & SILC_UMODE_DETACHED) - return g_strdup(_("Detached")); - if (client_entry->mode & SILC_UMODE_GONE) - return g_strdup(_("Away")); - if (client_entry->mode & SILC_UMODE_INDISPOSED) - return g_strdup(_("Indisposed")); - if (client_entry->mode & SILC_UMODE_BUSY) - return g_strdup(_("Busy")); - if (client_entry->mode & SILC_UMODE_PAGE) - return g_strdup(_("Wake Me Up")); - if (client_entry->mode & SILC_UMODE_HYPER) - return g_strdup(_("Hyper Active")); - if (client_entry->mode & SILC_UMODE_ROBOT) - return g_strdup(_("Robot")); - - attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD); - if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { - /* The mood is a bit mask, so we could show multiple moods, - but let's show only one for now. */ - if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) - return g_strdup(_("Happy")); - if (mood & SILC_ATTRIBUTE_MOOD_SAD) - return g_strdup(_("Sad")); - if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) - return g_strdup(_("Angry")); - if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) - return g_strdup(_("Jealous")); - if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) - return g_strdup(_("Ashamed")); - if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) - return g_strdup(_("Invincible")); - if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) - return g_strdup(_("In Love")); - if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) - return g_strdup(_("Sleepy")); - if (mood & SILC_ATTRIBUTE_MOOD_BORED) - return g_strdup(_("Bored")); - if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) - return g_strdup(_("Excited")); - if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) - return g_strdup(_("Anxious")); - } - - return NULL; -} - -void silcgaim_tooltip_text(GaimBuddy *b, GString *str, gboolean full) -{ - SilcGaim sg = b->account->gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; - SilcClientID *client_id = b->proto_data; - SilcClientEntry client_entry; - char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; - char tmp[256]; - - /* Get the client entry. */ - client_entry = silc_client_get_client_by_id(client, conn, client_id); - if (!client_entry) - return; - - if (client_entry->nickname) - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Nickname"), - client_entry->nickname); - if (client_entry->username && client_entry->hostname) - g_string_append_printf(str, "\n<b>%s:</b> %s@%s", _("Username"), - client_entry->username, client_entry->hostname); - if (client_entry->mode) { - g_string_append_printf(str, "\n<b>%s:</b> ", _("User Modes")); - memset(tmp, 0, sizeof(tmp)); - silcgaim_get_umode_string(client_entry->mode, - tmp, sizeof(tmp) - strlen(tmp)); - g_string_append_printf(str, "%s", tmp); - } - - silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); - - if (statusstr) { - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Message"), statusstr); - g_free(statusstr); - } - - if (full) { - if (moodstr) { - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Mood"), moodstr); - g_free(moodstr); - } - - if (contactstr) { - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Preferred Contact"), contactstr); - g_free(contactstr); - } - - if (langstr) { - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Preferred Language"), langstr); - g_free(langstr); - } - - if (devicestr) { - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Device"), devicestr); - g_free(devicestr); - } - - if (tzstr) { - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Timezone"), tzstr); - g_free(tzstr); - } - - if (geostr) { - g_string_append_printf(str, "\n<b>%s:</b> %s", _("Geolocation"), geostr); - g_free(geostr); - } - } -} - -static void -silcgaim_buddy_kill(GaimBlistNode *node, gpointer data) -{ - GaimBuddy *b; - GaimConnection *gc; - SilcGaim sg; - - g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); - - b = (GaimBuddy *) node; - gc = gaim_account_get_connection(b->account); - sg = gc->proto_data; - - /* Call KILL */ - silc_client_command_call(sg->client, sg->conn, NULL, "KILL", - b->name, "Killed by operator", NULL); -} - -typedef struct { - SilcGaim sg; - SilcClientEntry client_entry; -} *SilcGaimBuddyWb; - -static void -silcgaim_buddy_wb(GaimBlistNode *node, gpointer data) -{ - SilcGaimBuddyWb wb = data; - silcgaim_wb_init(wb->sg, wb->client_entry); - silc_free(wb); -} - -GList *silcgaim_buddy_menu(GaimBuddy *buddy) -{ - GaimConnection *gc = gaim_account_get_connection(buddy->account); - SilcGaim sg = gc->proto_data; - SilcClientConnection conn = sg->conn; - const char *pkfile = NULL; - SilcClientEntry client_entry = NULL; - GaimMenuAction *act; - GList *m = NULL; - SilcGaimBuddyWb wb; - - pkfile = gaim_blist_node_get_string((GaimBlistNode *) buddy, "public-key"); - client_entry = silc_client_get_client_by_id(sg->client, - sg->conn, - buddy->proto_data); - - if (client_entry && client_entry->send_key) { - act = gaim_menu_action_new(_("Reset IM Key"), - GAIM_CALLBACK(silcgaim_buddy_resetkey), - NULL, NULL); - m = g_list_append(m, act); - - } else { - act = gaim_menu_action_new(_("IM with Key Exchange"), - GAIM_CALLBACK(silcgaim_buddy_keyagr), - NULL, NULL); - m = g_list_append(m, act); - - act = gaim_menu_action_new(_("IM with Password"), - GAIM_CALLBACK(silcgaim_buddy_privkey_menu), - NULL, NULL); - m = g_list_append(m, act); - } - - if (pkfile) { - act = gaim_menu_action_new(_("Show Public Key"), - GAIM_CALLBACK(silcgaim_buddy_showkey), - NULL, NULL); - m = g_list_append(m, act); - - } else { - act = gaim_menu_action_new(_("Get Public Key..."), - GAIM_CALLBACK(silcgaim_buddy_getkey_menu), - NULL, NULL); - m = g_list_append(m, act); - } - - if (conn && conn->local_entry->mode & SILC_UMODE_ROUTER_OPERATOR) { - act = gaim_menu_action_new(_("Kill User"), - GAIM_CALLBACK(silcgaim_buddy_kill), - NULL, NULL); - m = g_list_append(m, act); - } - - if (client_entry) { - wb = silc_calloc(1, sizeof(*wb)); - wb->sg = sg; - wb->client_entry = client_entry; - act = gaim_menu_action_new(_("Draw On Whiteboard"), - GAIM_CALLBACK(silcgaim_buddy_wb), - (void *)wb, NULL); - m = g_list_append(m, act); - } - return m; -} - -#ifdef SILC_ATTRIBUTE_USER_ICON -void silcgaim_buddy_set_icon(GaimConnection *gc, const char *iconfile) -{ - SilcGaim sg = gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; - SilcMime mime; - GaimBuddyIcon ic; - char type[32]; - unsigned char *icon; - const char *t; - struct stat st; - FILE *fp; - SilcAttributeObjMime obj; - - /* Remove */ - if (!iconfile) { - silc_client_attribute_del(client, conn, - SILC_ATTRIBUTE_USER_ICON, NULL); - return; - } - - /* Add */ - if (g_stat(iconfile, &st) < 0) - return; - fp = g_fopen(iconfile, "rb"); - if (!fp) - return; - ic.data = g_malloc(st.st_size); - if (!ic.data) - return; - ic.len = fread(ic.data, 1, st.st_size, fp); - fclose(fp); - - mime = silc_mime_alloc(); - if (!mime) { - g_free(ic.data); - return; - } - - t = gaim_buddy_icon_get_type((const GaimBuddyIcon *)&ic); - if (!t) { - g_free(ic.data); - silc_mime_free(mime); - return; - } - if (!strcmp(t, "jpg")) - t = "jpeg"; - g_snprintf(type, sizeof(type), "image/%s", t); - silc_mime_add_field(mime, "Content-Type", type); - silc_mime_add_data(mime, ic.data, ic.len); - - obj.mime = icon = silc_mime_encode(mime, &obj.mime_len); - if (obj.mime) - silc_client_attribute_add(client, conn, - SILC_ATTRIBUTE_USER_ICON, &obj, sizeof(obj)); - - silc_free(icon); - g_free(ic.data); - silc_mime_free(mime); -} -#endif