📄 chat.c
字号:
/* silcpurple_chat.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 "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, SilcChannelEntry *channels, SilcUInt32 channels_count, 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->channel_key) g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"), silc_cipher_get_name(channel->channel_key)); if (channel->hmac) /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */ g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"), silc_hmac_get_name(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; SilcBuffer 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, SILC_PKCS_FILE_PEM) && !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); silc_buffer_free(sgc->pubkeys); silc_free(sgc); purple_notify_error(client->application, _("Add Channel Public Key"), _("Could not load public key"), NULL); return; } pk = silc_pkcs_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, pk->len, 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, ++conn->cmd_ident, 3, 1, chidp->data, chidp->len, 2, mode, sizeof(mode), 9, chpks->data, chpks->len); silc_buffer_free(chpks); silc_buffer_free(chidp); silc_buffer_free(sgc->pubkeys); silc_free(sgc);}static voidsilcpurple_chat_chpk_cancel(void *user_data, const char *name){ SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); silc_buffer_free(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_pkcs_public_key_payload_encode(public_key); chpks = silc_argument_payload_encode_one(chpks, pk->data, pk->len, 0x01); silc_buffer_free(pk); c++; } silc_pkcs_public_key_free(public_key); } 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, ++conn->cmd_ident, 3, 1, chidp->data, chidp->len, 2, mode, sizeof(mode), 9, chpks->data, chpks->len); silc_buffer_free(chpks); silc_buffer_free(chidp); silc_buffer_free(sgc->pubkeys); silc_free(sgc);}static voidsilcpurple_chat_chauth_ok(SilcPurpleChauth sgc, PurpleRequestFields *fields){ SilcPurple sg = sgc->sg; PurpleRequestField *f; 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"); } silc_buffer_free(sgc->pubkeys); silc_free(sgc);}void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel, SilcBuffer channel_pubkeys){ SilcUInt16 argc; SilcArgumentPayload chpks; unsigned char *pk; SilcUInt32 pk_len, type; char *fingerprint, *babbleprint; SilcPublicKey pubkey; 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) { 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); return; } sgc->pubkeys = silc_buffer_copy(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_GET16_MSB(argc, channel_pubkeys->data); chpks = silc_argument_payload_parse(channel_pubkeys->data + 2, channel_pubkeys->len - 2, argc); if (!chpks) return; pk = silc_argument_get_first_arg(chpks, &type, &pk_len); while (pk) { fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4); babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4); silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey); ident = silc_pkcs_decode_identifier(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, pubkey); silc_free(fingerprint); silc_free(babbleprint); silc_pkcs_free_identifier(ident); pk = silc_argument_get_next_arg(chpks, &type, &pk_len); } 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), _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), purple_connection_get_account(sg->gc), NULL, NULL, sgc); silc_argument_payload_free(chpks);}static voidsilcpurple_chat_chauth(PurpleBlistNode *node, gpointer data){ PurpleChat *chat; PurpleConnection *gc; SilcPurple sg; g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); chat = (PurpleChat *) node; gc = purple_account_get_connection(chat->account); sg = gc->proto_data; silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", g_hash_table_lookup(chat->components, "channel"), "+C", NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -