📄 silc.c
字号:
/* silcpurple.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 "silcpurple.h"#include "version.h"#include "wb.h"extern SilcClientOperations ops;static PurplePlugin *silc_plugin = NULL;static const char *silcpurple_list_icon(PurpleAccount *a, PurpleBuddy *b){ return (const char *)"silc";}static GList *silcpurple_away_states(PurpleAccount *account){ PurpleStatusType *type; GList *types = NULL; type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, SILCPURPLE_STATUS_ID_AVAILABLE, NULL, FALSE, TRUE, FALSE); types = g_list_append(types, type); type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, SILCPURPLE_STATUS_ID_HYPER, _("Hyper Active"), FALSE, TRUE, FALSE); types = g_list_append(types, type); type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_AWAY, NULL, FALSE, TRUE, FALSE); types = g_list_append(types, type); type = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, SILCPURPLE_STATUS_ID_BUSY, _("Busy"), FALSE, TRUE, FALSE); types = g_list_append(types, type); type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_INDISPOSED, _("Indisposed"), FALSE, TRUE, FALSE); types = g_list_append(types, type); type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_PAGE, _("Wake Me Up"), FALSE, TRUE, FALSE); types = g_list_append(types, type); type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, SILCPURPLE_STATUS_ID_OFFLINE, NULL, FALSE, TRUE, FALSE); types = g_list_append(types, type); return types;}static voidsilcpurple_set_status(PurpleAccount *account, PurpleStatus *status){ PurpleConnection *gc = purple_account_get_connection(account); SilcPurple 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 = purple_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 voidsilcpurple_keepalive(PurpleConnection *gc){ SilcPurple sg = gc->proto_data; silc_client_send_packet(sg->client, sg->conn, SILC_PACKET_HEARTBEAT, NULL, 0);}static gbooleansilcpurple_scheduler(gpointer *context){ SilcPurple sg = (SilcPurple)context; silc_client_run_one(sg->client); return TRUE;}static voidsilcpurple_nickname_parse(const char *nickname, char **ret_nickname){ silc_parse_userfqdn(nickname, ret_nickname, NULL);}static voidsilcpurple_login_connected(gpointer data, gint source, const gchar *error_message){ PurpleConnection *gc = data; SilcPurple sg; SilcClient client; SilcClientConnection conn; PurpleAccount *account; SilcClientConnectionParams params; SilcUInt32 mask; const char *dfile, *tmp;#ifdef SILC_ATTRIBUTE_USER_ICON PurpleStoredImage *img;#endif#ifdef HAVE_SYS_UTSNAME_H struct utsname u;#endif g_return_if_fail(gc != NULL); sg = gc->proto_data; if (source < 0) { purple_connection_error(gc, _("Connection failed")); return; } client = sg->client; account = sg->account; /* Get session detachment data, if available */ memset(¶ms, 0, sizeof(params)); dfile = silcpurple_session_file(purple_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 *)purple_account_get_string(account, "server", "silc.silcnet.org"), purple_account_get_int(account, "port", 706), sg); if (!conn) { purple_connection_error(gc, _("Cannot initialize SILC Client connection")); gc->proto_data = NULL; return; } sg->conn = conn; /* Progress */ if (params.detach_data) { purple_connection_update_progress(gc, _("Resuming session"), 2, 5); sg->resuming = TRUE; } else { purple_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 */ 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 */ img = purple_buddy_icons_find_account_icon(account); silcpurple_buddy_set_icon(gc, img); purple_imgstore_unref(img);#endif silc_free(params.detach_data);}static voidsilcpurple_login(PurpleAccount *account){ SilcPurple sg; SilcClient client; SilcClientParams params; PurpleConnection *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 = silcpurple_nickname_parse; params.ignore_requested_attributes = FALSE; /* Allocate SILC client */ client = silc_client_alloc(&ops, ¶ms, gc, NULL); if (!client) { purple_connection_error(gc, _("Out of memory")); return; } /* Get username, real name and local hostname for SILC library */ if (purple_account_get_username(account)) { const char *u = purple_account_get_username(account); char **up = g_strsplit(u, "@", 2); client->username = strdup(up[0]); g_strfreev(up); } else { client->username = silc_get_username(); purple_account_set_username(account, client->username); } realname = silc_get_real_name(); if (purple_account_get_user_info(account)) { client->realname = strdup(purple_account_get_user_info(account)); free(realname); } else if ((silc_get_real_name() != NULL) && (*realname != '\0')) { client->realname = realname; purple_account_set_user_info(account, client->realname); } else { free(realname); client->realname = strdup(_("John Noname")); } client->hostname = silc_net_localhost(); purple_connection_set_display_name(gc, client->username); /* Register requested cipher and HMAC */ cipher = purple_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 = purple_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; purple_connection_error(gc, _("Cannot initialize SILC protocol")); return; } /* Check the ~/.silc dir and create it, and new key pair if necessary. */ if (!silcpurple_check_silc_dir(gc)) { gc->wants_to_die = TRUE; purple_connection_error(gc, _("Cannot find/access ~/.silc directory")); return; } /* Progress */ purple_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", silcpurple_silcdir()); g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd), (char *)purple_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)); purple_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 (purple_proxy_connect(gc, account, purple_account_get_string(account, "server", "silc.silcnet.org"), purple_account_get_int(account, "port", 706), silcpurple_login_connected, gc) == NULL) { purple_connection_error(gc, _("Unable to create connection")); return; } /* Schedule SILC using Glib's event loop */ sg->scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, sg);}static intsilcpurple_close_final(gpointer *context){ SilcPurple sg = (SilcPurple)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 voidsilcpurple_close(PurpleConnection *gc){ SilcPurple sg = gc->proto_data; g_return_if_fail(sg != NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -