Mercurial > pidgin
diff libpurple/protocols/silc/silc.c @ 15373:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children | 21bc8d84974f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc/silc.c Sat Jan 20 02:32:10 2007 +0000 @@ -0,0 +1,1920 @@ +/* + + silcgaim.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 - 2005 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 "version.h" +#include "wb.h" + +extern SilcClientOperations ops; +static GaimPlugin *silc_plugin = NULL; + +static const char * +silcgaim_list_icon(GaimAccount *a, GaimBuddy *b) +{ + return (const char *)"silc"; +} + +static void +silcgaim_list_emblems(GaimBuddy *b, const char **se, const char **sw, + const char **nw, const char **ne) +{ +} + +static GList * +silcgaim_away_states(GaimAccount *account) +{ + GaimStatusType *type; + GList *types = NULL; + + type = gaim_status_type_new_full(GAIM_STATUS_AVAILABLE, SILCGAIM_STATUS_ID_AVAILABLE, NULL, FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = gaim_status_type_new_full(GAIM_STATUS_AVAILABLE, SILCGAIM_STATUS_ID_HYPER, _("Hyper Active"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = gaim_status_type_new_full(GAIM_STATUS_AWAY, SILCGAIM_STATUS_ID_AWAY, NULL, FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = gaim_status_type_new_full(GAIM_STATUS_UNAVAILABLE, SILCGAIM_STATUS_ID_BUSY, _("Busy"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = gaim_status_type_new_full(GAIM_STATUS_AWAY, SILCGAIM_STATUS_ID_INDISPOSED, _("Indisposed"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = gaim_status_type_new_full(GAIM_STATUS_AWAY, SILCGAIM_STATUS_ID_PAGE, _("Wake Me Up"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = gaim_status_type_new_full(GAIM_STATUS_OFFLINE, SILCGAIM_STATUS_ID_OFFLINE, NULL, FALSE, TRUE, FALSE); + types = g_list_append(types, type); + + return types; +} + +static void +silcgaim_set_status(GaimAccount *account, GaimStatus *status) +{ + GaimConnection *gc = gaim_account_get_connection(account); + SilcGaim sg = NULL; + SilcUInt32 mode; + SilcBuffer idp; + unsigned char mb[4]; + const char *state; + + if (gc != NULL) + sg = gc->proto_data; + + if (status == NULL) + return; + + state = gaim_status_get_id(status); + + if (state == NULL) + return; + + if ((sg == NULL) || (sg->conn == NULL)) + return; + + mode = sg->conn->local_entry->mode; + mode &= ~(SILC_UMODE_GONE | + SILC_UMODE_HYPER | + SILC_UMODE_BUSY | + SILC_UMODE_INDISPOSED | + SILC_UMODE_PAGE); + + if (!strcmp(state, "hyper")) + mode |= SILC_UMODE_HYPER; + else if (!strcmp(state, "away")) + mode |= SILC_UMODE_GONE; + else if (!strcmp(state, "busy")) + mode |= SILC_UMODE_BUSY; + else if (!strcmp(state, "indisposed")) + mode |= SILC_UMODE_INDISPOSED; + else if (!strcmp(state, "page")) + mode |= SILC_UMODE_PAGE; + + /* Send UMODE */ + idp = silc_id_payload_encode(sg->conn->local_id, SILC_ID_CLIENT); + SILC_PUT32_MSB(mode, mb); + silc_client_command_send(sg->client, sg->conn, SILC_COMMAND_UMODE, + ++sg->conn->cmd_ident, 2, + 1, idp->data, idp->len, + 2, mb, sizeof(mb)); + silc_buffer_free(idp); +} + + +/*************************** Connection Routines *****************************/ + +static void +silcgaim_keepalive(GaimConnection *gc) +{ + SilcGaim sg = gc->proto_data; + silc_client_send_packet(sg->client, sg->conn, SILC_PACKET_HEARTBEAT, + NULL, 0); +} + +static int +silcgaim_scheduler(gpointer *context) +{ + SilcGaim sg = (SilcGaim)context; + silc_client_run_one(sg->client); + return 1; +} + +static void +silcgaim_nickname_parse(const char *nickname, + char **ret_nickname) +{ + silc_parse_userfqdn(nickname, ret_nickname, NULL); +} + +static void +silcgaim_login_connected(gpointer data, gint source, const gchar *error_message) +{ + GaimConnection *gc = data; + SilcGaim sg; + SilcClient client; + SilcClientConnection conn; + GaimAccount *account; + SilcClientConnectionParams params; + const char *dfile; + + g_return_if_fail(gc != NULL); + + sg = gc->proto_data; + + if (source < 0) { + gaim_connection_error(gc, _("Connection failed")); + return; + } + + client = sg->client; + account = sg->account; + + /* Get session detachment data, if available */ + memset(¶ms, 0, sizeof(params)); + dfile = silcgaim_session_file(gaim_account_get_username(sg->account)); + params.detach_data = (unsigned char *)silc_file_readfile(dfile, ¶ms.detach_data_len); + if (params.detach_data) + params.detach_data[params.detach_data_len] = 0; + + /* Add connection to SILC client library */ + conn = silc_client_add_connection( + sg->client, ¶ms, + (char *)gaim_account_get_string(account, "server", + "silc.silcnet.org"), + gaim_account_get_int(account, "port", 706), sg); + if (!conn) { + gaim_connection_error(gc, _("Cannot initialize SILC Client connection")); + gc->proto_data = NULL; + return; + } + sg->conn = conn; + + /* Progress */ + if (params.detach_data) { + gaim_connection_update_progress(gc, _("Resuming session"), 2, 5); + sg->resuming = TRUE; + } else { + gaim_connection_update_progress(gc, _("Performing key exchange"), 2, 5); + } + + /* Perform SILC Key Exchange. The "silc_connected" will be called + eventually. */ + silc_client_start_key_exchange(sg->client, sg->conn, source); + + /* Set default attributes */ + if (!gaim_account_get_bool(account, "reject-attrs", FALSE)) { + SilcUInt32 mask; + const char *tmp; +#ifdef SILC_ATTRIBUTE_USER_ICON + char *icon; +#endif +#ifdef HAVE_SYS_UTSNAME_H + struct utsname u; +#endif + + mask = SILC_ATTRIBUTE_MOOD_NORMAL; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_STATUS_MOOD, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); + mask = SILC_ATTRIBUTE_CONTACT_CHAT; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_PREFERRED_CONTACT, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); +#ifdef HAVE_SYS_UTSNAME_H + if (!uname(&u)) { + SilcAttributeObjDevice dev; + memset(&dev, 0, sizeof(dev)); + dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER; + dev.version = u.release; + dev.model = u.sysname; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_DEVICE_INFO, + (void *)&dev, sizeof(dev)); + } +#endif +#ifdef _WIN32 + tmp = _tzname[0]; +#else + tmp = tzname[0]; +#endif + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_TIMEZONE, + (void *)tmp, strlen(tmp)); + +#ifdef SILC_ATTRIBUTE_USER_ICON + /* Set our buddy icon */ + icon = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(account)); + silcgaim_buddy_set_icon(gc, icon); + g_free(icon); +#endif + } + + silc_free(params.detach_data); +} + +static void +silcgaim_login(GaimAccount *account) +{ + SilcGaim sg; + SilcClient client; + SilcClientParams params; + GaimConnection *gc; + char pkd[256], prd[256]; + const char *cipher, *hmac; + char *realname; + int i; + + gc = account->gc; + if (!gc) + return; + gc->proto_data = NULL; + + memset(¶ms, 0, sizeof(params)); + strcat(params.nickname_format, "%n@%h%a"); + params.nickname_parse = silcgaim_nickname_parse; + params.ignore_requested_attributes = + gaim_account_get_bool(account, "reject-attrs", FALSE); + + /* Allocate SILC client */ + client = silc_client_alloc(&ops, ¶ms, gc, NULL); + if (!client) { + gaim_connection_error(gc, _("Out of memory")); + return; + } + + /* Get username, real name and local hostname for SILC library */ + if (gaim_account_get_username(account)) { + const char *u = gaim_account_get_username(account); + char **up = g_strsplit(u, "@", 2); + client->username = strdup(up[0]); + g_strfreev(up); + } else { + client->username = silc_get_username(); + gaim_account_set_username(account, client->username); + } + realname = silc_get_real_name(); + if (gaim_account_get_user_info(account)) { + client->realname = strdup(gaim_account_get_user_info(account)); + free(realname); + } else if ((silc_get_real_name() != NULL) && (*realname != '\0')) { + client->realname = realname; + gaim_account_set_user_info(account, client->realname); + } else { + free(realname); + client->realname = strdup(_("Gaim User")); + } + client->hostname = silc_net_localhost(); + + gaim_connection_set_display_name(gc, client->username); + + /* Register requested cipher and HMAC */ + cipher = gaim_account_get_string(account, "cipher", SILC_DEFAULT_CIPHER); + for (i = 0; silc_default_ciphers[i].name; i++) + if (!strcmp(silc_default_ciphers[i].name, cipher)) { + silc_cipher_register(&(silc_default_ciphers[i])); + break; + } + hmac = gaim_account_get_string(account, "hmac", SILC_DEFAULT_HMAC); + for (i = 0; silc_default_hmacs[i].name; i++) + if (!strcmp(silc_default_hmacs[i].name, hmac)) { + silc_hmac_register(&(silc_default_hmacs[i])); + break; + } + + /* Init SILC client */ + if (!silc_client_init(client)) { + gc->wants_to_die = TRUE; + gaim_connection_error(gc, _("Cannot initialize SILC protocol")); + return; + } + + /* Check the ~/.silc dir and create it, and new key pair if necessary. */ + if (!silcgaim_check_silc_dir(gc)) { + gc->wants_to_die = TRUE; + gaim_connection_error(gc, _("Cannot find/access ~/.silc directory")); + return; + } + + /* Progress */ + gaim_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5); + + /* Load SILC key pair */ + g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcgaim_silcdir()); + g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcgaim_silcdir()); + if (!silc_load_key_pair((char *)gaim_account_get_string(account, "public-key", pkd), + (char *)gaim_account_get_string(account, "private-key", prd), + (gc->password == NULL) ? "" : gc->password, &client->pkcs, + &client->public_key, &client->private_key)) { + g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair: %s"), strerror(errno)); + gaim_connection_error(gc, pkd); + return; + } + + sg = silc_calloc(1, sizeof(*sg)); + if (!sg) + return; + memset(sg, 0, sizeof(*sg)); + sg->client = client; + sg->gc = gc; + sg->account = account; + gc->proto_data = sg; + + /* Connect to the SILC server */ + if (gaim_proxy_connect(gc, account, + gaim_account_get_string(account, "server", + "silc.silcnet.org"), + gaim_account_get_int(account, "port", 706), + silcgaim_login_connected, gc) == NULL) + { + gaim_connection_error(gc, _("Unable to create connection")); + return; + } + + /* Schedule SILC using Glib's event loop */ +#ifndef _WIN32 + sg->scheduler = g_timeout_add(5, (GSourceFunc)silcgaim_scheduler, sg); +#else + sg->scheduler = g_timeout_add(300, (GSourceFunc)silcgaim_scheduler, sg); +#endif +} + +static int +silcgaim_close_final(gpointer *context) +{ + SilcGaim sg = (SilcGaim)context; + silc_client_stop(sg->client); + silc_client_free(sg->client); +#ifdef HAVE_SILCMIME_H + if (sg->mimeass) + silc_mime_assembler_free(sg->mimeass); +#endif + silc_free(sg); + return 0; +} + +static void +silcgaim_close(GaimConnection *gc) +{ + SilcGaim sg = gc->proto_data; + + g_return_if_fail(sg != NULL); + + /* Send QUIT */ + silc_client_command_call(sg->client, sg->conn, NULL, + "QUIT", "Download Gaim: " GAIM_WEBSITE, NULL); + + if (sg->conn) + silc_client_close_connection(sg->client, sg->conn); + + g_source_remove(sg->scheduler); + g_timeout_add(1, (GSourceFunc)silcgaim_close_final, sg); +} + + +/****************************** Protocol Actions *****************************/ + +static void +silcgaim_attrs_cancel(GaimConnection *gc, GaimRequestFields *fields) +{ + /* Nothing */ +} + +static void +silcgaim_attrs_cb(GaimConnection *gc, GaimRequestFields *fields) +{ + SilcGaim sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + GaimRequestField *f; + char *tmp; + SilcUInt32 tmp_len, mask; + SilcAttributeObjService service; + SilcAttributeObjDevice dev; + SilcVCardStruct vcard; + const char *val; + + sg = gc->proto_data; + if (!sg) + return; + + memset(&service, 0, sizeof(service)); + memset(&dev, 0, sizeof(dev)); + memset(&vcard, 0, sizeof(vcard)); + + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_USER_INFO, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_SERVICE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_STATUS_MOOD, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_STATUS_FREETEXT, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_STATUS_MESSAGE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_TIMEZONE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_GEOLOCATION, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_DEVICE_INFO, NULL); + + /* Set mood */ + mask = 0; + f = gaim_request_fields_get_field(fields, "mood_normal"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_NORMAL; + f = gaim_request_fields_get_field(fields, "mood_happy"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_HAPPY; + f = gaim_request_fields_get_field(fields, "mood_sad"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_SAD; + f = gaim_request_fields_get_field(fields, "mood_angry"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_ANGRY; + f = gaim_request_fields_get_field(fields, "mood_jealous"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_JEALOUS; + f = gaim_request_fields_get_field(fields, "mood_ashamed"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_ASHAMED; + f = gaim_request_fields_get_field(fields, "mood_invincible"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_INVINCIBLE; + f = gaim_request_fields_get_field(fields, "mood_inlove"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_INLOVE; + f = gaim_request_fields_get_field(fields, "mood_sleepy"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_SLEEPY; + f = gaim_request_fields_get_field(fields, "mood_bored"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_BORED; + f = gaim_request_fields_get_field(fields, "mood_excited"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_EXCITED; + f = gaim_request_fields_get_field(fields, "mood_anxious"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_ANXIOUS; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_STATUS_MOOD, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); + + /* Set preferred contact */ + mask = 0; + f = gaim_request_fields_get_field(fields, "contact_chat"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_CHAT; + f = gaim_request_fields_get_field(fields, "contact_email"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_EMAIL; + f = gaim_request_fields_get_field(fields, "contact_call"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_CALL; + f = gaim_request_fields_get_field(fields, "contact_sms"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_SMS; + f = gaim_request_fields_get_field(fields, "contact_mms"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_MMS; + f = gaim_request_fields_get_field(fields, "contact_video"); + if (f && gaim_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_VIDEO; + if (mask) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_PREFERRED_CONTACT, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); + + /* Set status text */ + val = NULL; + f = gaim_request_fields_get_field(fields, "status_text"); + if (f) + val = gaim_request_field_string_get_value(f); + if (val && *val) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_STATUS_FREETEXT, + (void *)val, strlen(val)); + + /* Set vcard */ + val = NULL; + f = gaim_request_fields_get_field(fields, "vcard"); + if (f) + val = gaim_request_field_string_get_value(f); + if (val && *val) { + gaim_account_set_string(sg->account, "vcard", val); + tmp = silc_file_readfile(val, &tmp_len); + if (tmp) { + tmp[tmp_len] = 0; + if (silc_vcard_decode((unsigned char *)tmp, tmp_len, &vcard)) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_USER_INFO, + (void *)&vcard, + sizeof(vcard)); + } + silc_vcard_free(&vcard); + silc_free(tmp); + } else { + gaim_account_set_string(sg->account, "vcard", ""); + } + +#ifdef HAVE_SYS_UTSNAME_H + /* Set device info */ + f = gaim_request_fields_get_field(fields, "device"); + if (f && gaim_request_field_bool_get_value(f)) { + struct utsname u; + if (!uname(&u)) { + dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER; + dev.version = u.release; + dev.model = u.sysname; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_DEVICE_INFO, + (void *)&dev, sizeof(dev)); + } + } +#endif + + /* Set timezone */ + val = NULL; + f = gaim_request_fields_get_field(fields, "timezone"); + if (f) + val = gaim_request_field_string_get_value(f); + if (val && *val) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_TIMEZONE, + (void *)val, strlen(val)); +} + +static void +silcgaim_attrs(GaimPluginAction *action) +{ + GaimConnection *gc = (GaimConnection *) action->context; + SilcGaim sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + GaimRequestFields *fields; + GaimRequestFieldGroup *g; + GaimRequestField *f; + SilcHashTable attrs; + SilcAttributePayload attr; + gboolean mnormal = TRUE, mhappy = FALSE, msad = FALSE, + mangry = FALSE, mjealous = FALSE, mashamed = FALSE, + minvincible = FALSE, minlove = FALSE, msleepy = FALSE, + mbored = FALSE, mexcited = FALSE, manxious = FALSE; + gboolean cemail = FALSE, ccall = FALSE, csms = FALSE, + cmms = FALSE, cchat = TRUE, cvideo = FALSE; + gboolean device = TRUE; + char status[1024]; + + sg = gc->proto_data; + if (!sg) + return; + + memset(status, 0, sizeof(status)); + + attrs = silc_client_attributes_get(client, conn); + if (attrs) { + if (silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_MOOD), + NULL, (void *)&attr)) { + SilcUInt32 mood = 0; + silc_attribute_get_object(attr, &mood, sizeof(mood)); + mnormal = !mood; + mhappy = (mood & SILC_ATTRIBUTE_MOOD_HAPPY); + msad = (mood & SILC_ATTRIBUTE_MOOD_SAD); + mangry = (mood & SILC_ATTRIBUTE_MOOD_ANGRY); + mjealous = (mood & SILC_ATTRIBUTE_MOOD_JEALOUS); + mashamed = (mood & SILC_ATTRIBUTE_MOOD_ASHAMED); + minvincible = (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE); + minlove = (mood & SILC_ATTRIBUTE_MOOD_INLOVE); + msleepy = (mood & SILC_ATTRIBUTE_MOOD_SLEEPY); + mbored = (mood & SILC_ATTRIBUTE_MOOD_BORED); + mexcited = (mood & SILC_ATTRIBUTE_MOOD_EXCITED); + manxious = (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS); + } + + if (silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_PREFERRED_CONTACT), + NULL, (void *)&attr)) { + SilcUInt32 contact = 0; + silc_attribute_get_object(attr, &contact, sizeof(contact)); + cemail = (contact & SILC_ATTRIBUTE_CONTACT_EMAIL); + ccall = (contact & SILC_ATTRIBUTE_CONTACT_CALL); + csms = (contact & SILC_ATTRIBUTE_CONTACT_SMS); + cmms = (contact & SILC_ATTRIBUTE_CONTACT_MMS); + cchat = (contact & SILC_ATTRIBUTE_CONTACT_CHAT); + cvideo = (contact & SILC_ATTRIBUTE_CONTACT_VIDEO); + } + + if (silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_FREETEXT), + NULL, (void *)&attr)) + silc_attribute_get_object(attr, &status, sizeof(status)); + + if (!silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_DEVICE_INFO), + NULL, (void *)&attr)) + device = FALSE; + } + + fields = gaim_request_fields_new(); + + g = gaim_request_field_group_new(NULL); + f = gaim_request_field_label_new("l3", _("Your Current Mood")); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_normal", _("Normal"), mnormal); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_happy", _("Happy"), mhappy); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_sad", _("Sad"), msad); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_angry", _("Angry"), mangry); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_jealous", _("Jealous"), mjealous); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_ashamed", _("Ashamed"), mashamed); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_invincible", _("Invincible"), minvincible); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_inlove", _("In love"), minlove); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_sleepy", _("Sleepy"), msleepy); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_bored", _("Bored"), mbored); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_excited", _("Excited"), mexcited); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("mood_anxious", _("Anxious"), manxious); + gaim_request_field_group_add_field(g, f); + + f = gaim_request_field_label_new("l4", _("\nYour Preferred Contact Methods")); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("contact_chat", _("Chat"), cchat); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("contact_email", _("E-mail"), cemail); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("contact_call", _("Phone"), ccall); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("contact_sms", _("SMS"), csms); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("contact_mms", _("MMS"), cmms); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("contact_video", _("Video conferencing"), cvideo); + gaim_request_field_group_add_field(g, f); + gaim_request_fields_add_group(fields, g); + + g = gaim_request_field_group_new(NULL); + f = gaim_request_field_string_new("status_text", _("Your Current Status"), + status[0] ? status : NULL, TRUE); + gaim_request_field_group_add_field(g, f); + gaim_request_fields_add_group(fields, g); + + g = gaim_request_field_group_new(NULL); +#if 0 + f = gaim_request_field_label_new("l2", _("Online Services")); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_bool_new("services", + _("Let others see what services you are using"), + TRUE); + gaim_request_field_group_add_field(g, f); +#endif +#ifdef HAVE_SYS_UTSNAME_H + f = gaim_request_field_bool_new("device", + _("Let others see what computer you are using"), + device); + gaim_request_field_group_add_field(g, f); +#endif + gaim_request_fields_add_group(fields, g); + + g = gaim_request_field_group_new(NULL); + f = gaim_request_field_string_new("vcard", _("Your VCard File"), + gaim_account_get_string(sg->account, "vcard", ""), + FALSE); + gaim_request_field_group_add_field(g, f); +#ifdef _WIN32 + f = gaim_request_field_string_new("timezone", _("Timezone"), _tzname[0], FALSE); +#else + f = gaim_request_field_string_new("timezone", _("Timezone"), tzname[0], FALSE); +#endif + gaim_request_field_group_add_field(g, f); + gaim_request_fields_add_group(fields, g); + + gaim_request_fields(gc, _("User Online Status Attributes"), + _("User Online Status Attributes"), + _("You can let other users see your online status information " + "and your personal information. Please fill the information " + "you would like other users to see about yourself."), + fields, + _("OK"), G_CALLBACK(silcgaim_attrs_cb), + _("Cancel"), G_CALLBACK(silcgaim_attrs_cancel), gc); +} + +static void +silcgaim_detach(GaimPluginAction *action) +{ + GaimConnection *gc = (GaimConnection *) action->context; + SilcGaim sg; + + if (!gc) + return; + sg = gc->proto_data; + if (!sg) + return; + + /* Call DETACH */ + silc_client_command_call(sg->client, sg->conn, "DETACH"); + sg->detaching = TRUE; +} + +static void +silcgaim_view_motd(GaimPluginAction *action) +{ + GaimConnection *gc = (GaimConnection *) action->context; + SilcGaim sg; + char *tmp; + + if (!gc) + return; + sg = gc->proto_data; + if (!sg) + return; + + if (!sg->motd) { + gaim_notify_error( + gc, _("Message of the Day"), _("No Message of the Day available"), + _("There is no Message of the Day associated with this connection")); + return; + } + + tmp = g_markup_escape_text(sg->motd, -1); + gaim_notify_formatted(gc, NULL, _("Message of the Day"), NULL, + tmp, NULL, NULL); + g_free(tmp); +} + +static void +silcgaim_create_keypair_cancel(GaimConnection *gc, GaimRequestFields *fields) +{ + /* Nothing */ +} + +static void +silcgaim_create_keypair_cb(GaimConnection *gc, GaimRequestFields *fields) +{ + SilcGaim sg = gc->proto_data; + GaimRequestField *f; + const char *val, *pkfile = NULL, *prfile = NULL; + const char *pass1 = NULL, *pass2 = NULL, *un = NULL, *hn = NULL; + const char *rn = NULL, *e = NULL, *o = NULL, *c = NULL; + char *identifier; + int keylen = SILCGAIM_DEF_PKCS_LEN; + SilcPublicKey public_key; + + sg = gc->proto_data; + if (!sg) + return; + + val = NULL; + f = gaim_request_fields_get_field(fields, "pass1"); + if (f) + val = gaim_request_field_string_get_value(f); + if (val && *val) + pass1 = val; + else + pass1 = ""; + val = NULL; + f = gaim_request_fields_get_field(fields, "pass2"); + if (f) + val = gaim_request_field_string_get_value(f); + if (val && *val) + pass2 = val; + else + pass2 = ""; + + if (strcmp(pass1, pass2)) { + gaim_notify_error( + gc, _("Create New SILC Key Pair"), _("Passphrases do not match"), NULL); + return; + } + + val = NULL; + f = gaim_request_fields_get_field(fields, "key"); + if (f) + val = gaim_request_field_string_get_value(f); + if (val && *val) + keylen = atoi(val); + f = gaim_request_fields_get_field(fields, "pkfile"); + if (f) + pkfile = gaim_request_field_string_get_value(f); + f = gaim_request_fields_get_field(fields, "prfile"); + if (f) + prfile = gaim_request_field_string_get_value(f); + + f = gaim_request_fields_get_field(fields, "un"); + if (f) + un = gaim_request_field_string_get_value(f); + f = gaim_request_fields_get_field(fields, "hn"); + if (f) + hn = gaim_request_field_string_get_value(f); + f = gaim_request_fields_get_field(fields, "rn"); + if (f) + rn = gaim_request_field_string_get_value(f); + f = gaim_request_fields_get_field(fields, "e"); + if (f) + e = gaim_request_field_string_get_value(f); + f = gaim_request_fields_get_field(fields, "o"); + if (f) + o = gaim_request_field_string_get_value(f); + f = gaim_request_fields_get_field(fields, "c"); + if (f) + c = gaim_request_field_string_get_value(f); + + identifier = silc_pkcs_encode_identifier((char *)un, (char *)hn, + (char *)rn, (char *)e, (char *)o, (char *)c); + + /* Create the key pair */ + if (!silc_create_key_pair(SILCGAIM_DEF_PKCS, keylen, pkfile, prfile, + identifier, pass1, NULL, &public_key, NULL, + FALSE)) { + gaim_notify_error( + gc, _("Create New SILC Key Pair"), _("Key Pair Generation failed"), NULL); + return; + } + + silcgaim_show_public_key(sg, NULL, public_key, NULL, NULL); + + silc_pkcs_public_key_free(public_key); + silc_free(identifier); +} + +static void +silcgaim_create_keypair(GaimPluginAction *action) +{ + GaimConnection *gc = (GaimConnection *) action->context; + SilcGaim sg = gc->proto_data; + GaimRequestFields *fields; + GaimRequestFieldGroup *g; + GaimRequestField *f; + const char *username, *realname; + char *hostname, **u; + char tmp[256], pkd[256], pkd2[256], prd[256], prd2[256]; + + username = gaim_account_get_username(sg->account); + u = g_strsplit(username, "@", 2); + username = u[0]; + realname = gaim_account_get_user_info(sg->account); + hostname = silc_net_localhost(); + g_snprintf(tmp, sizeof(tmp), "%s@%s", username, hostname); + + g_snprintf(pkd2, sizeof(pkd2), "%s" G_DIR_SEPARATOR_S"public_key.pub", silcgaim_silcdir()); + g_snprintf(prd2, sizeof(prd2), "%s" G_DIR_SEPARATOR_S"private_key.prv", silcgaim_silcdir()); + g_snprintf(pkd, sizeof(pkd) - 1, "%s", + gaim_account_get_string(gc->account, "public-key", pkd2)); + g_snprintf(prd, sizeof(prd) - 1, "%s", + gaim_account_get_string(gc->account, "private-key", prd2)); + + fields = gaim_request_fields_new(); + + g = gaim_request_field_group_new(NULL); + f = gaim_request_field_string_new("key", _("Key length"), "2048", FALSE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("pkfile", _("Public key file"), pkd, FALSE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("prfile", _("Private key file"), prd, FALSE); + gaim_request_field_group_add_field(g, f); + gaim_request_fields_add_group(fields, g); + + g = gaim_request_field_group_new(NULL); + f = gaim_request_field_string_new("un", _("Username"), username ? username : "", FALSE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("hn", _("Hostname"), hostname ? hostname : "", FALSE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("rn", _("Real name"), realname ? realname : "", FALSE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("e", _("E-mail"), tmp, FALSE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("o", _("Organization"), "", FALSE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("c", _("Country"), "", FALSE); + gaim_request_field_group_add_field(g, f); + gaim_request_fields_add_group(fields, g); + + g = gaim_request_field_group_new(NULL); + f = gaim_request_field_string_new("pass1", _("Passphrase"), "", FALSE); + gaim_request_field_string_set_masked(f, TRUE); + gaim_request_field_group_add_field(g, f); + f = gaim_request_field_string_new("pass2", _("Passphrase (retype)"), "", FALSE); + gaim_request_field_string_set_masked(f, TRUE); + gaim_request_field_group_add_field(g, f); + gaim_request_fields_add_group(fields, g); + + gaim_request_fields(gc, _("Create New SILC Key Pair"), + _("Create New SILC Key Pair"), NULL, fields, + _("Generate Key Pair"), G_CALLBACK(silcgaim_create_keypair_cb), + _("Cancel"), G_CALLBACK(silcgaim_create_keypair_cancel), gc); + + g_strfreev(u); + silc_free(hostname); +} + +static void +silcgaim_change_pass(GaimPluginAction *action) +{ + GaimConnection *gc = (GaimConnection *) action->context; + gaim_account_request_change_password(gaim_connection_get_account(gc)); +} + +static void +silcgaim_change_passwd(GaimConnection *gc, const char *old, const char *new) +{ + char prd[256]; + g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcgaim_silcdir()); + silc_change_private_key_passphrase(gaim_account_get_string(gc->account, + "private-key", + prd), old, new); +} + +static void +silcgaim_show_set_info(GaimPluginAction *action) +{ + GaimConnection *gc = (GaimConnection *) action->context; + gaim_account_request_change_user_info(gaim_connection_get_account(gc)); +} + +static void +silcgaim_set_info(GaimConnection *gc, const char *text) +{ +} + +static GList * +silcgaim_actions(GaimPlugin *plugin, gpointer context) +{ + GaimConnection *gc = context; + GList *list = NULL; + GaimPluginAction *act; + + if (!gaim_account_get_bool(gc->account, "reject-attrs", FALSE)) { + act = gaim_plugin_action_new(_("Online Status"), + silcgaim_attrs); + list = g_list_append(list, act); + } + + act = gaim_plugin_action_new(_("Detach From Server"), + silcgaim_detach); + list = g_list_append(list, act); + + act = gaim_plugin_action_new(_("View Message of the Day"), + silcgaim_view_motd); + list = g_list_append(list, act); + + act = gaim_plugin_action_new(_("Create SILC Key Pair..."), + silcgaim_create_keypair); + list = g_list_append(list, act); + + act = gaim_plugin_action_new(_("Change Password..."), + silcgaim_change_pass); + list = g_list_append(list, act); + + act = gaim_plugin_action_new(_("Set User Info..."), + silcgaim_show_set_info); + list = g_list_append(list, act); + + return list; +} + + +/******************************* IM Routines *********************************/ + +typedef struct { + char *nick; + char *message; + SilcUInt32 message_len; + SilcMessageFlags flags; + GaimMessageFlags gflags; +} *SilcGaimIM; + +static void +silcgaim_send_im_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + GaimConnection *gc = client->application; + SilcGaim sg = gc->proto_data; + SilcGaimIM im = context; + GaimConversation *convo; + char tmp[256], *nickname = NULL; + SilcClientEntry client_entry; +#ifdef HAVE_SILCMIME_H + SilcDList list; +#endif + + convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, im->nick, + sg->account); + if (!convo) + return; + + if (!clients) + goto err; + + if (clients_count > 1) { + silc_parse_userfqdn(im->nick, &nickname, NULL); + + /* Find the correct one. The im->nick might be a formatted nick + so this will find the correct one. */ + clients = silc_client_get_clients_local(client, conn, + nickname, im->nick, + &clients_count); + if (!clients) + goto err; + client_entry = clients[0]; + silc_free(clients); + } else { + client_entry = clients[0]; + } + +#ifdef HAVE_SILCMIME_H + /* Check for images */ + if (im->gflags & GAIM_MESSAGE_IMAGES) { + list = silcgaim_image_message(im->message, (SilcUInt32 *)&im->flags); + if (list) { + /* Send one or more MIME message. If more than one, they + are MIME fragments due to over large message */ + SilcBuffer buf; + + silc_dlist_start(list); + while ((buf = silc_dlist_get(list)) != SILC_LIST_END) + silc_client_send_private_message(client, conn, + client_entry, im->flags, + buf->data, buf->len, + TRUE); + silc_mime_partial_free(list); + gaim_conv_im_write(GAIM_CONV_IM(convo), conn->local_entry->nickname, + im->message, 0, time(NULL)); + goto out; + } + } +#endif + + /* Send the message */ + silc_client_send_private_message(client, conn, client_entry, im->flags, + (unsigned char *)im->message, im->message_len, TRUE); + gaim_conv_im_write(GAIM_CONV_IM(convo), conn->local_entry->nickname, + im->message, 0, time(NULL)); + goto out; + + err: + g_snprintf(tmp, sizeof(tmp), + _("User <I>%s</I> is not present in the network"), im->nick); + gaim_conversation_write(convo, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL)); + + out: + g_free(im->nick); + g_free(im->message); + silc_free(im); + silc_free(nickname); +} + +static int +silcgaim_send_im(GaimConnection *gc, const char *who, const char *message, + GaimMessageFlags flags) +{ + SilcGaim sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcClientEntry *clients; + SilcUInt32 clients_count, mflags; + char *nickname, *msg, *tmp; + int ret = 0; + gboolean sign = gaim_account_get_bool(sg->account, "sign-verify", FALSE); +#ifdef HAVE_SILCMIME_H + SilcDList list; +#endif + + if (!who || !message) + return 0; + + mflags = SILC_MESSAGE_FLAG_UTF8; + + tmp = msg = gaim_unescape_html(message); + + if (!g_ascii_strncasecmp(msg, "/me ", 4)) { + msg += 4; + if (!*msg) { + g_free(tmp); + return 0; + } + mflags |= SILC_MESSAGE_FLAG_ACTION; + } else if (strlen(msg) > 1 && msg[0] == '/') { + if (!silc_client_command_call(client, conn, msg + 1)) + gaim_notify_error(gc, _("Call Command"), _("Cannot call command"), + _("Unknown command")); + g_free(tmp); + return 0; + } + + + if (!silc_parse_userfqdn(who, &nickname, NULL)) { + g_free(tmp); + return 0; + } + + if (sign) + mflags |= SILC_MESSAGE_FLAG_SIGNED; + + /* Find client entry */ + clients = silc_client_get_clients_local(client, conn, nickname, who, + &clients_count); + if (!clients) { + /* Resolve unknown user */ + SilcGaimIM im = silc_calloc(1, sizeof(*im)); + if (!im) { + g_free(tmp); + return 0; + } + im->nick = g_strdup(who); + im->message = g_strdup(message); + im->message_len = strlen(im->message); + im->flags = mflags; + im->gflags = flags; + silc_client_get_clients(client, conn, nickname, NULL, + silcgaim_send_im_resolved, im); + silc_free(nickname); + g_free(tmp); + return 0; + } + +#ifdef HAVE_SILCMIME_H + /* Check for images */ + if (flags & GAIM_MESSAGE_IMAGES) { + list = silcgaim_image_message(message, &mflags); + if (list) { + /* Send one or more MIME message. If more than one, they + are MIME fragments due to over large message */ + SilcBuffer buf; + + silc_dlist_start(list); + while ((buf = silc_dlist_get(list)) != SILC_LIST_END) + ret = + silc_client_send_private_message(client, conn, + clients[0], mflags, + buf->data, buf->len, + TRUE); + silc_mime_partial_free(list); + g_free(tmp); + silc_free(nickname); + silc_free(clients); + return ret; + } + } +#endif + + /* Send private message directly */ + ret = silc_client_send_private_message(client, conn, clients[0], + mflags, + (unsigned char *)msg, + strlen(msg), TRUE); + + g_free(tmp); + silc_free(nickname); + silc_free(clients); + return ret; +} + + +static GList *silcgaim_blist_node_menu(GaimBlistNode *node) { + /* split this single menu building function back into the two + original: one for buddies and one for chats */ + + if(GAIM_BLIST_NODE_IS_CHAT(node)) { + return silcgaim_chat_menu((GaimChat *) node); + } else if(GAIM_BLIST_NODE_IS_BUDDY(node)) { + return silcgaim_buddy_menu((GaimBuddy *) node); + } else { + g_return_val_if_reached(NULL); + } +} + +/********************************* Commands **********************************/ + +static GaimCmdRet silcgaim_cmd_chat_part(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + GaimConversation *convo = conv; + int id = 0; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + if(args && args[0]) + convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, args[0], + gc->account); + + if (convo != NULL) + id = gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)); + + if (id == 0) + return GAIM_CMD_RET_FAILED; + + silcgaim_chat_leave(gc, id); + + return GAIM_CMD_RET_OK; + +} + +static GaimCmdRet silcgaim_cmd_chat_topic(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + int id = 0; + char *buf, *tmp, *tmp2; + const char *topic; + + gc = gaim_conversation_get_gc(conv); + id = gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)); + + if (gc == NULL || id == 0) + return GAIM_CMD_RET_FAILED; + + if (!args || !args[0]) { + topic = gaim_conv_chat_get_topic (GAIM_CONV_CHAT(conv)); + if (topic) { + tmp = g_markup_escape_text(topic, -1); + tmp2 = gaim_markup_linkify(tmp); + buf = g_strdup_printf(_("current topic is: %s"), tmp2); + g_free(tmp); + g_free(tmp2); + } else + buf = g_strdup(_("No topic is set")); + gaim_conv_chat_write(GAIM_CONV_CHAT(conv), gc->account->username, buf, + GAIM_MESSAGE_SYSTEM|GAIM_MESSAGE_NO_LOG, time(NULL)); + g_free(buf); + + } + + if (args && args[0] && (strlen(args[0]) > 255)) { + *error = g_strdup(_("Topic too long")); + return GAIM_CMD_RET_FAILED; + } + + silcgaim_chat_set_topic(gc, id, args ? args[0] : NULL); + + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_chat_join(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GHashTable *comp; + + if(!args || !args[0]) + return GAIM_CMD_RET_FAILED; + + comp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); + + g_hash_table_replace(comp, "channel", args[0]); + if(args[1]) + g_hash_table_replace(comp, "passphrase", args[1]); + + silcgaim_chat_join(gaim_conversation_get_gc(conv), comp); + + g_hash_table_destroy(comp); + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_chat_list(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + gc = gaim_conversation_get_gc(conv); + gaim_roomlist_show_with_account(gaim_connection_get_account(gc)); + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_whois(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + silcgaim_get_info(gc, args[0]); + + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_msg(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + int ret; + GaimConnection *gc; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + ret = silcgaim_send_im(gc, args[0], args[1], GAIM_MESSAGE_SEND); + + if (ret) + return GAIM_CMD_RET_OK; + else + return GAIM_CMD_RET_FAILED; +} + +static GaimCmdRet silcgaim_cmd_query(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + int ret = 1; + GaimConversation *convo; + GaimConnection *gc; + GaimAccount *account; + + if (!args || !args[0]) { + *error = g_strdup(_("You must specify a nick")); + return GAIM_CMD_RET_FAILED; + } + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + account = gaim_connection_get_account(gc); + + convo = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, args[0]); + + if (args[1]) { + ret = silcgaim_send_im(gc, args[0], args[1], GAIM_MESSAGE_SEND); + gaim_conv_im_write(GAIM_CONV_IM(convo), gaim_connection_get_display_name(gc), + args[1], GAIM_MESSAGE_SEND, time(NULL)); + } + + if (ret) + return GAIM_CMD_RET_OK; + else + return GAIM_CMD_RET_FAILED; +} + +static GaimCmdRet silcgaim_cmd_motd(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + SilcGaim sg; + char *tmp; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return GAIM_CMD_RET_FAILED; + + if (!sg->motd) { + *error = g_strdup(_("There is no Message of the Day associated with this connection")); + return GAIM_CMD_RET_FAILED; + } + + tmp = g_markup_escape_text(sg->motd, -1); + gaim_notify_formatted(gc, NULL, _("Message of the Day"), NULL, + tmp, NULL, NULL); + g_free(tmp); + + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_detach(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + SilcGaim sg; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return GAIM_CMD_RET_FAILED; + + silc_client_command_call(sg->client, sg->conn, "DETACH"); + sg->detaching = TRUE; + + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_cmode(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + SilcGaim sg; + SilcChannelEntry channel; + char *silccmd, *silcargs, *msg, tmp[256]; + const char *chname; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL || !args || gc->proto_data == NULL) + return GAIM_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (args[0]) + chname = args[0]; + else + chname = gaim_conversation_get_name(conv); + + if (!args[1]) { + channel = silc_client_get_channel(sg->client, sg->conn, + (char *)chname); + if (!channel) { + *error = g_strdup_printf(_("channel %s not found"), chname); + return GAIM_CMD_RET_FAILED; + } + if (channel->mode) { + silcgaim_get_chmode_string(channel->mode, tmp, sizeof(tmp)); + msg = g_strdup_printf(_("channel modes for %s: %s"), chname, tmp); + } else { + msg = g_strdup_printf(_("no channel modes are set on %s"), chname); + } + gaim_conv_chat_write(GAIM_CONV_CHAT(conv), "", + msg, GAIM_MESSAGE_SYSTEM|GAIM_MESSAGE_NO_LOG, time(NULL)); + g_free(msg); + return GAIM_CMD_RET_OK; + } + + silcargs = g_strjoinv(" ", args); + silccmd = g_strconcat(cmd, " ", args ? silcargs : NULL, NULL); + g_free(silcargs); + if (!silc_client_command_call(sg->client, sg->conn, silccmd)) { + g_free(silccmd); + *error = g_strdup_printf(_("Failed to set cmodes for %s"), args[0]); + return GAIM_CMD_RET_FAILED; + } + g_free(silccmd); + + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_generic(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + SilcGaim sg; + char *silccmd, *silcargs; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return GAIM_CMD_RET_FAILED; + + silcargs = g_strjoinv(" ", args); + silccmd = g_strconcat(cmd, " ", args ? silcargs : NULL, NULL); + g_free(silcargs); + if (!silc_client_command_call(sg->client, sg->conn, silccmd)) { + g_free(silccmd); + *error = g_strdup_printf(_("Unknown command: %s, (may be a Gaim bug)"), cmd); + return GAIM_CMD_RET_FAILED; + } + g_free(silccmd); + + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_quit(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + SilcGaim sg; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return GAIM_CMD_RET_FAILED; + + silc_client_command_call(sg->client, sg->conn, NULL, + "QUIT", (args && args[0]) ? args[0] : "Download Gaim: " GAIM_WEBSITE, NULL); + + return GAIM_CMD_RET_OK; +} + +static GaimCmdRet silcgaim_cmd_call(GaimConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GaimConnection *gc; + SilcGaim sg; + + gc = gaim_conversation_get_gc(conv); + + if (gc == NULL) + return GAIM_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return GAIM_CMD_RET_FAILED; + + if (!silc_client_command_call(sg->client, sg->conn, args[0])) { + *error = g_strdup_printf(_("Unknown command: %s"), args[0]); + return GAIM_CMD_RET_FAILED; + } + + return GAIM_CMD_RET_OK; +} + + +/************************** Plugin Initialization ****************************/ + +static void +silcgaim_register_commands(void) +{ + gaim_cmd_register("part", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | + GAIM_CMD_FLAG_PRPL_ONLY | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, + "prpl-silc", silcgaim_cmd_chat_part, _("part [channel]: Leave the chat"), NULL); + gaim_cmd_register("leave", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | + GAIM_CMD_FLAG_PRPL_ONLY | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, + "prpl-silc", silcgaim_cmd_chat_part, _("leave [channel]: Leave the chat"), NULL); + gaim_cmd_register("topic", "s", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", + silcgaim_cmd_chat_topic, _("topic [<new topic>]: View or change the topic"), NULL); + gaim_cmd_register("join", "ws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | + GAIM_CMD_FLAG_PRPL_ONLY | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, + "prpl-silc", silcgaim_cmd_chat_join, + _("join <channel> [<password>]: Join a chat on this network"), NULL); + gaim_cmd_register("list", "", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", + silcgaim_cmd_chat_list, _("list: List channels on this network"), NULL); + gaim_cmd_register("whois", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", + silcgaim_cmd_whois, _("whois <nick>: View nick's information"), NULL); + gaim_cmd_register("msg", "ws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_msg, + _("msg <nick> <message>: Send a private message to a user"), NULL); + gaim_cmd_register("query", "ws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_query, + _("query <nick> [<message>]: Send a private message to a user"), NULL); + gaim_cmd_register("motd", "", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_motd, + _("motd: View the server's Message Of The Day"), NULL); + gaim_cmd_register("detach", "", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_detach, + _("detach: Detach this session"), NULL); + gaim_cmd_register("quit", "s", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_quit, + _("quit [message]: Disconnect from the server, with an optional message"), NULL); + gaim_cmd_register("call", "s", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_call, + _("call <command>: Call any silc client command"), NULL); + /* These below just get passed through for the silc client library to deal + * with */ + gaim_cmd_register("kill", "ws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic, + _("kill <nick> [-pubkey|<reason>]: Kill nick"), NULL); + gaim_cmd_register("nick", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_generic, + _("nick <newnick>: Change your nickname"), NULL); + gaim_cmd_register("whowas", "ww", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic, + _("whowas <nick>: View nick's information"), NULL); + gaim_cmd_register("cmode", "wws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_cmode, + _("cmode <channel> [+|-<modes>] [arguments]: Change or display channel modes"), NULL); + gaim_cmd_register("cumode", "wws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic, + _("cumode <channel> +|-<modes> <nick>: Change nick's modes on channel"), NULL); + gaim_cmd_register("umode", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_generic, + _("umode <usermodes>: Set your modes in the network"), NULL); + gaim_cmd_register("oper", "s", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_generic, + _("oper <nick> [-pubkey]: Get server operator privileges"), NULL); + gaim_cmd_register("invite", "ws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic, + _("invite <channel> [-|+]<nick>: invite nick or add/remove from channel invite list"), NULL); + gaim_cmd_register("kick", "wws", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic, + _("kick <channel> <nick> [comment]: Kick client from channel"), NULL); + gaim_cmd_register("info", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic, + _("info [server]: View server administrative details"), NULL); + gaim_cmd_register("ban", "ww", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic, + _("ban [<channel> +|-<nick>]: Ban client from channel"), NULL); + gaim_cmd_register("getkey", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_generic, + _("getkey <nick|server>: Retrieve client's or server's public key"), NULL); + gaim_cmd_register("stats", "", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_generic, + _("stats: View server and network statistics"), NULL); + gaim_cmd_register("ping", "", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_generic, + _("ping: Send PING to the connected server"), NULL); +#if 0 /* Gaim doesn't handle these yet */ + gaim_cmd_register("users", "w", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcgaim_cmd_users, + _("users <channel>: List users in channel")); + gaim_cmd_register("names", "ww", GAIM_CMD_P_PRPL, + GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | + GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_names, + _("names [-count|-ops|-halfops|-voices|-normal] <channel(s)>: List specific users in channel(s)")); +#endif +} + +static GaimWhiteboardPrplOps silcgaim_wb_ops = +{ + silcgaim_wb_start, + silcgaim_wb_end, + silcgaim_wb_get_dimensions, + silcgaim_wb_set_dimensions, + silcgaim_wb_get_brush, + silcgaim_wb_set_brush, + silcgaim_wb_send, + silcgaim_wb_clear, +}; + +static GaimPluginProtocolInfo prpl_info = +{ +#ifdef HAVE_SILCMIME_H + OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | + OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE, +#else + OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | + OPT_PROTO_PASSWORD_OPTIONAL, +#endif + NULL, /* user_splits */ + NULL, /* protocol_options */ +#ifdef SILC_ATTRIBUTE_USER_ICON + {"jpeg,gif,png,bmp", 0, 0, 96, 96, 0, GAIM_ICON_SCALE_DISPLAY}, /* icon_spec */ +#else + NO_BUDDY_ICONS, +#endif + silcgaim_list_icon, /* list_icon */ + silcgaim_list_emblems, /* list_emblems */ + silcgaim_status_text, /* status_text */ + silcgaim_tooltip_text, /* tooltip_text */ + silcgaim_away_states, /* away_states */ + silcgaim_blist_node_menu, /* blist_node_menu */ + silcgaim_chat_info, /* chat_info */ + silcgaim_chat_info_defaults,/* chat_info_defaults */ + silcgaim_login, /* login */ + silcgaim_close, /* close */ + silcgaim_send_im, /* send_im */ + silcgaim_set_info, /* set_info */ + NULL, /* send_typing */ + silcgaim_get_info, /* get_info */ + silcgaim_set_status, /* set_status */ + silcgaim_idle_set, /* set_idle */ + silcgaim_change_passwd, /* change_passwd */ + silcgaim_add_buddy, /* add_buddy */ + NULL, /* add_buddies */ + silcgaim_remove_buddy, /* remove_buddy */ + NULL, /* remove_buddies */ + NULL, /* add_permit */ + NULL, /* add_deny */ + NULL, /* rem_permit */ + NULL, /* rem_deny */ + NULL, /* set_permit_deny */ + silcgaim_chat_join, /* join_chat */ + NULL, /* reject_chat */ + silcgaim_get_chat_name, /* get_chat_name */ + silcgaim_chat_invite, /* chat_invite */ + silcgaim_chat_leave, /* chat_leave */ + NULL, /* chat_whisper */ + silcgaim_chat_send, /* chat_send */ + silcgaim_keepalive, /* keepalive */ + NULL, /* register_user */ + NULL, /* get_cb_info */ + NULL, /* get_cb_away */ + NULL, /* alias_buddy */ + NULL, /* group_buddy */ + NULL, /* rename_group */ + NULL, /* buddy_free */ + NULL, /* convo_closed */ + NULL, /* normalize */ +#ifdef SILC_ATTRIBUTE_USER_ICON + silcgaim_buddy_set_icon, /* set_buddy_icon */ +#else + NULL, +#endif + NULL, /* remove_group */ + NULL, /* get_cb_real_name */ + silcgaim_chat_set_topic, /* set_chat_topic */ + NULL, /* find_blist_chat */ + silcgaim_roomlist_get_list, /* roomlist_get_list */ + silcgaim_roomlist_cancel, /* roomlist_cancel */ + NULL, /* roomlist_expand_category */ + NULL, /* can_receive_file */ + silcgaim_ftp_send_file, /* send_file */ + silcgaim_ftp_new_xfer, /* new_xfer */ + NULL, /* offline_message */ + &silcgaim_wb_ops, /* whiteboard_prpl_ops */ + NULL, /* send_raw */ + NULL, /* roomlist_room_serialize */ +}; + +static GaimPluginInfo info = +{ + GAIM_PLUGIN_MAGIC, + GAIM_MAJOR_VERSION, + GAIM_MINOR_VERSION, + GAIM_PLUGIN_PROTOCOL, /**< type */ + NULL, /**< ui_requirement */ + 0, /**< flags */ + NULL, /**< dependencies */ + GAIM_PRIORITY_DEFAULT, /**< priority */ + + "prpl-silc", /**< id */ + "SILC", /**< name */ + "1.0", /**< version */ + /** summary */ + N_("SILC Protocol Plugin"), + /** description */ + N_("Secure Internet Live Conferencing (SILC) Protocol"), + "Pekka Riikonen", /**< author */ + "http://silcnet.org/", /**< homepage */ + + NULL, /**< load */ + NULL, /**< unload */ + NULL, /**< destroy */ + + NULL, /**< ui_info */ + &prpl_info, /**< extra_info */ + NULL, /**< prefs_info */ + silcgaim_actions +}; + +static void +init_plugin(GaimPlugin *plugin) +{ + GaimAccountOption *option; + GaimAccountUserSplit *split; + char tmp[256]; + int i; + GaimKeyValuePair *kvp; + GList *list = NULL; + + silc_plugin = plugin; + + split = gaim_account_user_split_new(_("Network"), "silcnet.org", '@'); + prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); + + /* Account options */ + option = gaim_account_option_string_new(_("Connect server"), + "server", + "silc.silcnet.org"); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_int_new(_("Port"), "port", 706); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcgaim_silcdir()); + option = gaim_account_option_string_new(_("Public Key file"), + "public-key", tmp); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcgaim_silcdir()); + option = gaim_account_option_string_new(_("Private Key file"), + "private-key", tmp); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + for (i = 0; silc_default_ciphers[i].name; i++) { + kvp = g_new0(GaimKeyValuePair, 1); + kvp->key = g_strdup(silc_default_ciphers[i].name); + kvp->value = g_strdup(silc_default_ciphers[i].name); + list = g_list_append(list, kvp); + } + option = gaim_account_option_list_new(_("Cipher"), "cipher", list); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + list = NULL; + for (i = 0; silc_default_hmacs[i].name; i++) { + kvp = g_new0(GaimKeyValuePair, 1); + kvp->key = g_strdup(silc_default_hmacs[i].name); + kvp->value = g_strdup(silc_default_hmacs[i].name); + list = g_list_append(list, kvp); + } + option = gaim_account_option_list_new(_("HMAC"), "hmac", list); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = gaim_account_option_bool_new(_("Public key authentication"), + "pubkey-auth", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_bool_new(_("Reject watching by other users"), + "reject-watch", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_bool_new(_("Block invites"), + "block-invites", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_bool_new(_("Block IMs without Key Exchange"), + "block-ims", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_bool_new(_("Reject online status attribute requests"), + "reject-attrs", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_bool_new(_("Block messages to whiteboard"), + "block-wb", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_bool_new(_("Automatically open whiteboard"), + "open-wb", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = gaim_account_option_bool_new(_("Digitally sign and verify all messages"), + "sign-verify", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + gaim_prefs_remove("/plugins/prpl/silc"); + + silcgaim_register_commands(); + +#ifdef _WIN32 + silc_net_win32_init(); +#endif +} + +GAIM_INIT_PLUGIN(silc, init_plugin, info);