📄 chat.c
字号:
/* silcpurple_chat.c Author: Pekka Riikonen <priikone@silcnet.org> Copyright (C) 2004 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.*/#include "silc.h"#include "silcclient.h"#include "silcpurple.h"#include "wb.h"/***************************** Channel Routines ******************************/GList *silcpurple_chat_info(PurpleConnection *gc){ GList *ci = NULL; struct proto_chat_entry *pce; pce = g_new0(struct proto_chat_entry, 1); pce->label = _("_Channel:"); pce->identifier = "channel"; pce->required = TRUE; ci = g_list_append(ci, pce); pce = g_new0(struct proto_chat_entry, 1); pce->label = _("_Passphrase:"); pce->identifier = "passphrase"; pce->secret = TRUE; ci = g_list_append(ci, pce); return ci;}GHashTable *silcpurple_chat_info_defaults(PurpleConnection *gc, const char *chat_name){ GHashTable *defaults; defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); if (chat_name != NULL) g_hash_table_insert(defaults, "channel", g_strdup(chat_name)); return defaults;}static voidsilcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components);static voidsilcpurple_chat_getinfo_res(SilcClient client, SilcClientConnection conn, SilcStatus status, SilcDList channels, void *context){ GHashTable *components = context; PurpleConnection *gc = client->application; const char *chname; char tmp[256]; chname = g_hash_table_lookup(components, "channel"); if (!chname) return; if (!channels) { g_snprintf(tmp, sizeof(tmp), _("Channel %s does not exist in the network"), chname); purple_notify_error(gc, _("Channel Information"), _("Cannot get channel information"), tmp); return; } silcpurple_chat_getinfo(gc, components);}static voidsilcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components){ SilcPurple sg = gc->proto_data; const char *chname; char *buf, tmp[256], *tmp2; GString *s; SilcChannelEntry channel; SilcHashTableList htl; SilcChannelUser chu; if (!components) return; chname = g_hash_table_lookup(components, "channel"); if (!chname) return; channel = silc_client_get_channel(sg->client, sg->conn, (char *)chname); if (!channel) { silc_client_get_channel_resolve(sg->client, sg->conn, (char *)chname, silcpurple_chat_getinfo_res, components); return; } s = g_string_new(""); tmp2 = g_markup_escape_text(channel->channel_name, -1); g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2); g_free(tmp2); if (channel->user_list && silc_hash_table_count(channel->user_list)) g_string_append_printf(s, _("<br><b>User Count:</b> %d"), (int)silc_hash_table_count(channel->user_list)); silc_hash_table_list(channel->user_list, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { tmp2 = g_markup_escape_text(chu->client->nickname, -1); g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"), tmp2); g_free(tmp2); break; } } silc_hash_table_list_reset(&htl); if (channel->cipher) g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"), channel->cipher); if (channel->hmac) /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */ g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"), channel->hmac); if (channel->topic) { tmp2 = g_markup_escape_text(channel->topic, -1); g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2); g_free(tmp2); } if (channel->mode) { g_string_append_printf(s, _("<br><b>Channel Modes:</b> ")); silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp)); g_string_append(s, tmp); } if (channel->founder_key) { char *fingerprint, *babbleprint; unsigned char *pk; SilcUInt32 pk_len; pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len); fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint); g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint); silc_free(fingerprint); silc_free(babbleprint); silc_free(pk); } buf = g_string_free(s, FALSE); purple_notify_formatted(gc, NULL, _("Channel Information"), NULL, buf, NULL, NULL); g_free(buf);}static voidsilcpurple_chat_getinfo_menu(PurpleBlistNode *node, gpointer data){ PurpleChat *chat = (PurpleChat *)node; silcpurple_chat_getinfo(chat->account->gc, chat->components);}#if 0 /* XXX For now these are not implemented. We need better listview dialog from Purple for these. *//************************** Channel Invite List ******************************/static voidsilcpurple_chat_invitelist(PurpleBlistNode *node, gpointer data);{}/**************************** Channel Ban List *******************************/static voidsilcpurple_chat_banlist(PurpleBlistNode *node, gpointer data);{}#endif/************************* Channel Authentication ****************************/typedef struct { SilcPurple sg; SilcChannelEntry channel; PurpleChat *c; SilcDList pubkeys;} *SilcPurpleChauth;static voidsilcpurple_chat_chpk_add(void *user_data, const char *name){ SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; SilcPurple sg = sgc->sg; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; SilcPublicKey public_key; SilcBuffer chpks, pk, chidp; unsigned char mode[4]; SilcUInt32 m; /* Load the public key */ if (!silc_pkcs_load_public_key(name, &public_key)) { silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); silc_dlist_uninit(sgc->pubkeys); silc_free(sgc); purple_notify_error(client->application, _("Add Channel Public Key"), _("Could not load public key"), NULL); return; } pk = silc_public_key_payload_encode(public_key); chpks = silc_buffer_alloc_size(2); SILC_PUT16_MSB(1, chpks->head); chpks = silc_argument_payload_encode_one(chpks, pk->data, silc_buffer_len(pk), 0x00); silc_buffer_free(pk); m = sgc->channel->mode; m |= SILC_CHANNEL_MODE_CHANNEL_AUTH; /* Send CMODE */ SILC_PUT32_MSB(m, mode); chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL); silc_client_command_send(client, conn, SILC_COMMAND_CMODE, silcpurple_command_reply, NULL, 3, 1, chidp->data, silc_buffer_len(chidp), 2, mode, sizeof(mode), 9, chpks->data, silc_buffer_len(chpks)); silc_buffer_free(chpks); silc_buffer_free(chidp); if (sgc->pubkeys) { silc_dlist_start(sgc->pubkeys); while ((public_key = silc_dlist_get(sgc->pubkeys))) silc_pkcs_public_key_free(public_key); silc_dlist_uninit(sgc->pubkeys); } silc_free(sgc);}static voidsilcpurple_chat_chpk_cancel(void *user_data, const char *name){ SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; SilcPublicKey public_key; silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); if (sgc->pubkeys) { silc_dlist_start(sgc->pubkeys); while ((public_key = silc_dlist_get(sgc->pubkeys))) silc_pkcs_public_key_free(public_key); silc_dlist_uninit(sgc->pubkeys); } silc_free(sgc);}static voidsilcpurple_chat_chpk_cb(SilcPurpleChauth sgc, PurpleRequestFields *fields){ SilcPurple sg = sgc->sg; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; PurpleRequestField *f; const GList *list; SilcPublicKey public_key; SilcBuffer chpks, pk, chidp; SilcUInt16 c = 0, ct; unsigned char mode[4]; SilcUInt32 m; f = purple_request_fields_get_field(fields, "list"); if (!purple_request_field_list_get_selected(f)) { /* Add new public key */ purple_request_file(sg->gc, _("Open Public Key..."), NULL, FALSE, G_CALLBACK(silcpurple_chat_chpk_add), G_CALLBACK(silcpurple_chat_chpk_cancel), purple_connection_get_account(sg->gc), NULL, NULL, sgc); return; } list = purple_request_field_list_get_items(f); chpks = silc_buffer_alloc_size(2); for (ct = 0; list; list = list->next, ct++) { public_key = purple_request_field_list_get_data(f, list->data); if (purple_request_field_list_is_selected(f, list->data)) { /* Delete this public key */ pk = silc_public_key_payload_encode(public_key); chpks = silc_argument_payload_encode_one(chpks, pk->data, silc_buffer_len(pk), 0x01); silc_buffer_free(pk); c++; } } if (!c) { silc_buffer_free(chpks); return; } SILC_PUT16_MSB(c, chpks->head); m = sgc->channel->mode; if (ct == c) m &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH; /* Send CMODE */ SILC_PUT32_MSB(m, mode); chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL); silc_client_command_send(client, conn, SILC_COMMAND_CMODE, silcpurple_command_reply, NULL, 3, 1, chidp->data, silc_buffer_len(chidp), 2, mode, sizeof(mode), 9, chpks->data, silc_buffer_len(chpks)); silc_buffer_free(chpks); silc_buffer_free(chidp); if (sgc->pubkeys) { silc_dlist_start(sgc->pubkeys); while ((public_key = silc_dlist_get(sgc->pubkeys))) silc_pkcs_public_key_free(public_key); silc_dlist_uninit(sgc->pubkeys); } silc_free(sgc);}static voidsilcpurple_chat_chauth_ok(SilcPurpleChauth sgc, PurpleRequestFields *fields){ SilcPurple sg = sgc->sg; PurpleRequestField *f; SilcPublicKey public_key; const char *curpass, *val; int set; f = purple_request_fields_get_field(fields, "passphrase"); val = purple_request_field_string_get_value(f); curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase"); if (!val && curpass) set = 0; else if (val && !curpass) set = 1; else if (val && curpass && strcmp(val, curpass)) set = 1; else set = -1; if (set == 1) { silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", sgc->channel->channel_name, "+a", val, NULL); purple_blist_node_set_string((PurpleBlistNode *)sgc->c, "passphrase", val); } else if (set == 0) { silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", sgc->channel->channel_name, "-a", NULL); purple_blist_node_remove_setting((PurpleBlistNode *)sgc->c, "passphrase"); } if (sgc->pubkeys) { silc_dlist_start(sgc->pubkeys); while ((public_key = silc_dlist_get(sgc->pubkeys))) silc_pkcs_public_key_free(public_key); silc_dlist_uninit(sgc->pubkeys); } silc_free(sgc);}void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel, SilcDList channel_pubkeys){ SilcPublicKey public_key; SilcSILCPublicKey silc_pubkey; unsigned char *pk; SilcUInt32 pk_len; char *fingerprint, *babbleprint; SilcPublicKeyIdentifier ident; char tmp2[1024], t[512]; PurpleRequestFields *fields; PurpleRequestFieldGroup *g; PurpleRequestField *f; SilcPurpleChauth sgc; const char *curpass = NULL; sgc = silc_calloc(1, sizeof(*sgc)); if (!sgc) return; sgc->sg = sg; sgc->channel = channel; fields = purple_request_fields_new(); if (sgc->c) curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase"); g = purple_request_field_group_new(NULL); f = purple_request_field_string_new("passphrase", _("Channel Passphrase"), curpass, FALSE); purple_request_field_string_set_masked(f, TRUE); purple_request_field_group_add_field(g, f); purple_request_fields_add_group(fields, g); g = purple_request_field_group_new(NULL); f = purple_request_field_label_new("l1", _("Channel Public Keys List")); purple_request_field_group_add_field(g, f); purple_request_fields_add_group(fields, g); g_snprintf(t, sizeof(t), _("Channel authentication is used to secure the channel from " "unauthorized access. The authentication may be based on " "passphrase and digital signatures. If passphrase is set, it " "is required to be able to join. If channel public keys are set " "then only users whose public keys are listed are able to join.")); if (!channel_pubkeys || !silc_dlist_count(channel_pubkeys)) { f = purple_request_field_list_new("list", NULL); purple_request_field_group_add_field(g, f); purple_request_fields(sg->gc, _("Channel Authentication"), _("Channel Authentication"), t, fields, _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), purple_connection_get_account(sg->gc), NULL, NULL, sgc); if (channel_pubkeys) silc_dlist_uninit(channel_pubkeys); return; } sgc->pubkeys = channel_pubkeys; g = purple_request_field_group_new(NULL); f = purple_request_field_list_new("list", NULL); purple_request_field_group_add_field(g, f); purple_request_fields_add_group(fields, g); silc_dlist_start(channel_pubkeys); while ((public_key = silc_dlist_get(channel_pubkeys))) { pk = silc_pkcs_public_key_encode(public_key, &pk_len); fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4); babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4); silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); ident = &silc_pubkey->identifier; g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s", ident->realname ? ident->realname : ident->username ? ident->username : "", fingerprint, babbleprint); purple_request_field_list_add(f, tmp2, public_key); silc_free(fingerprint); silc_free(babbleprint); } purple_request_field_list_set_multi_select(f, FALSE); purple_request_fields(sg->gc, _("Channel Authentication"), _("Channel Authentication"), t, fields, _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -