📄 silc.c
字号:
/* silcpurple.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 "version.h"#include "wb.h"extern SilcClientOperations ops;static PurplePlugin *silc_plugin = NULL;/* Error log message callback */static SilcBool silcpurple_log_error(SilcLogType type, char *message, void *context){ silc_say(NULL, NULL, SILC_CLIENT_MESSAGE_ERROR, message); return TRUE;}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, silcpurple_command_reply, NULL, 2, 1, idp->data, silc_buffer_len(idp), 2, mb, sizeof(mb)); silc_buffer_free(idp);}/*************************** Connection Routines *****************************/static voidsilcpurple_keepalive(PurpleConnection *gc){ SilcPurple sg = gc->proto_data; silc_packet_send(sg->conn->stream, SILC_PACKET_HEARTBEAT, 0, NULL, 0);}static gbooleansilcpurple_scheduler(gpointer *context){ SilcClient client = (SilcClient)context; silc_client_run_one(client); return TRUE;}static voidsilcpurple_connect_cb(SilcClient client, SilcClientConnection conn, SilcClientConnectionStatus status, SilcStatus error, const char *message, void *context){ PurpleConnection *gc = context; SilcPurple sg; SilcUInt32 mask; char tz[16]; PurpleStoredImage *img;#ifdef HAVE_SYS_UTSNAME_H struct utsname u;#endif sg = gc->proto_data; switch (status) { case SILC_CLIENT_CONN_SUCCESS: case SILC_CLIENT_CONN_SUCCESS_RESUME: sg->conn = conn; /* Connection created successfully */ purple_connection_set_state(gc, PURPLE_CONNECTED); /* Send the server our buddy list */ silcpurple_send_buddylist(gc); g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); /* Send any UMODEs configured for account */ if (purple_account_get_bool(sg->account, "block-ims", FALSE)) { silc_client_command_call(sg->client, sg->conn, NULL, "UMODE", "+P", NULL); } /* 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 silc_timezone(tz, sizeof(tz)); silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_TIMEZONE, (void *)tz, strlen(tz)); /* Set our buddy icon */ img = purple_buddy_icons_find_account_icon(sg->account); silcpurple_buddy_set_icon(gc, img); purple_imgstore_unref(img); return; break; case SILC_CLIENT_CONN_DISCONNECTED: /* Disconnected */ if (sg->resuming && !sg->detaching) g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); /* Close the connection */ if (!sg->detaching) purple_connection_error(gc, _("Disconnected by server")); else /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */ purple_account_disconnect(purple_connection_get_account(gc)); break; case SILC_CLIENT_CONN_ERROR: purple_connection_error(gc, _("Error during connecting to SILC Server")); g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); break; case SILC_CLIENT_CONN_ERROR_KE: purple_connection_error(gc, _("Key Exchange failed")); break; case SILC_CLIENT_CONN_ERROR_AUTH: purple_connection_error(gc, _("Authentication failed")); break; case SILC_CLIENT_CONN_ERROR_RESUME: purple_connection_error(gc, _("Resuming detached session failed. " "Press Reconnect to create new connection.")); g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); break; case SILC_CLIENT_CONN_ERROR_TIMEOUT: purple_connection_error(gc, _("Connection Timeout")); break; } /* Error */ sg->conn = NULL;}static voidsilcpurple_stream_created(SilcSocketStreamStatus status, SilcStream stream, void *context){ PurpleConnection *gc = context; SilcPurple sg; SilcClient client; SilcClientConnectionParams params; const char *dfile; sg = gc->proto_data; if (status != SILC_SOCKET_OK) { purple_connection_error(gc, _("Connection failed")); silc_pkcs_public_key_free(sg->public_key); silc_pkcs_private_key_free(sg->private_key); silc_free(sg); gc->proto_data = NULL; return; } client = sg->client; /* 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); } /* 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; params.ignore_requested_attributes = FALSE; params.pfs = purple_account_get_bool(sg->account, "pfs", FALSE); /* Perform SILC Key Exchange. */ silc_client_key_exchange(sg->client, ¶ms, sg->public_key, sg->private_key, stream, SILC_CONN_SERVER, silcpurple_connect_cb, gc); silc_free(params.detach_data);}static voidsilcpurple_login_connected(gpointer data, gint source, const gchar *error_message){ PurpleConnection *gc = data; SilcPurple sg; g_return_if_fail(gc != NULL); sg = gc->proto_data; if (source < 0) { purple_connection_error(gc, _("Connection failed")); silc_pkcs_public_key_free(sg->public_key); silc_pkcs_private_key_free(sg->private_key); silc_free(sg); gc->proto_data = NULL; return; } /* Wrap socket to TCP stream */ silc_socket_tcp_stream_create(source, TRUE, FALSE, sg->client->schedule, silcpurple_stream_created, gc);}static void silcpurple_running(SilcClient client, void *context){ PurpleAccount *account = context; PurpleConnection *gc = account->gc; SilcPurple sg; char pkd[256], prd[256]; sg = silc_calloc(1, sizeof(*sg)); if (!sg) return; memset(sg, 0, sizeof(*sg)); sg->client = client; sg->gc = gc; sg->account = account; sg->scheduler = SILC_PTR_TO_32(gc->proto_data); gc->proto_data = sg; /* 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, &sg->public_key, &sg->private_key)) { g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair")); purple_connection_error(gc, pkd); gc->proto_data = NULL; silc_free(sg); return; } /* 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")); gc->proto_data = NULL; silc_free(sg); return; }}static voidsilcpurple_login(PurpleAccount *account){ SilcClient client; PurpleConnection *gc; SilcClientParams params; const char *cipher, *hmac; char *username, *hostname, *realname, **up; guint scheduler; int i; gc = account->gc; if (!gc) return; gc->proto_data = NULL; memset(¶ms, 0, sizeof(params)); strcat(params.nickname_format, "%n#a"); /* Allocate SILC client */ client = silc_client_alloc(&ops, ¶ms, gc, NULL); if (!client) { purple_connection_error(gc, _("Out of memory")); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -