⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irc.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/** * @file irc.c * * purple * * Copyright (C) 2003, Robbert Haarman <purple@inglorion.net> * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu> * Copyright (C) 2000-2003, Rob Flynn <rob@tgflinux.com> * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> * * 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; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "internal.h"#include "accountopt.h"#include "blist.h"#include "conversation.h"#include "debug.h"#include "notify.h"#include "prpl.h"#include "plugin.h"#include "util.h"#include "version.h"#include "irc.h"#define PING_TIMEOUT 60static void irc_buddy_append(char *name, struct irc_buddy *ib, GString *string);static const char *irc_blist_icon(PurpleAccount *a, PurpleBuddy *b);static GList *irc_status_types(PurpleAccount *account);static GList *irc_actions(PurplePlugin *plugin, gpointer context);/* static GList *irc_chat_info(PurpleConnection *gc); */static void irc_login(PurpleAccount *account);static void irc_login_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond);static void irc_login_cb(gpointer data, gint source, const gchar *error_message);static void irc_ssl_connect_failure(PurpleSslConnection *gsc, PurpleSslErrorType error, gpointer data);static void irc_close(PurpleConnection *gc);static int irc_im_send(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags);static int irc_chat_send(PurpleConnection *gc, int id, const char *what, PurpleMessageFlags flags);static void irc_chat_join (PurpleConnection *gc, GHashTable *data);static void irc_input_cb(gpointer data, gint source, PurpleInputCondition cond);static void irc_input_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond);static guint irc_nick_hash(const char *nick);static gboolean irc_nick_equal(const char *nick1, const char *nick2);static void irc_buddy_free(struct irc_buddy *ib);PurplePlugin *_irc_plugin = NULL;static const char *status_chars = "@+%&";static void irc_view_motd(PurplePluginAction *action){	PurpleConnection *gc = (PurpleConnection *) action->context;	struct irc_conn *irc;	char *title;	if (gc == NULL || gc->proto_data == NULL) {		purple_debug(PURPLE_DEBUG_ERROR, "irc", "got MOTD request for NULL gc\n");		return;	}	irc = gc->proto_data;	if (irc->motd == NULL) {		purple_notify_error(gc, _("Error displaying MOTD"), _("No MOTD available"),				  _("There is no MOTD associated with this connection."));		return;	}	title = g_strdup_printf(_("MOTD for %s"), irc->server);	purple_notify_formatted(gc, title, title, NULL, irc->motd->str, NULL, NULL);	g_free(title);}static int do_send(struct irc_conn *irc, const char *buf, gsize len){	int ret;	if (irc->gsc) {		ret = purple_ssl_write(irc->gsc, buf, len);	} else {		ret = write(irc->fd, buf, len);	}	return ret;}static int irc_send_raw(PurpleConnection *gc, const char *buf, int len){	struct irc_conn *irc = (struct irc_conn*)gc->proto_data;	return do_send(irc, buf, len);}static voidirc_send_cb(gpointer data, gint source, PurpleInputCondition cond){	struct irc_conn *irc = data;	int ret, writelen;	writelen = purple_circ_buffer_get_max_read(irc->outbuf);	if (writelen == 0) {		purple_input_remove(irc->writeh);		irc->writeh = 0;		return;	}	ret = do_send(irc, irc->outbuf->outptr, writelen);	if (ret < 0 && errno == EAGAIN)		return;	else if (ret <= 0) {		purple_connection_error(purple_account_get_connection(irc->account),			      _("Server has disconnected"));		return;	}	purple_circ_buffer_mark_read(irc->outbuf, ret);#if 0	/* We *could* try to write more if we wrote it all */	if (ret == write_len) {		irc_send_cb(data, source, cond);	}#endif}int irc_send(struct irc_conn *irc, const char *buf){	int ret, buflen; 	char *tosend= g_strdup(buf);	purple_signal_emit(_irc_plugin, "irc-sending-text", purple_account_get_connection(irc->account), &tosend);	if (tosend == NULL)		return 0;	buflen = strlen(tosend);	/* If we're not buffering writes, try to send immediately */	if (!irc->writeh)		ret = do_send(irc, tosend, buflen);	else {		ret = -1;		errno = EAGAIN;	}	/* purple_debug(PURPLE_DEBUG_MISC, "irc", "sent%s: %s",		irc->gsc ? " (ssl)" : "", tosend); */	if (ret <= 0 && errno != EAGAIN) {		purple_connection_error(purple_account_get_connection(irc->account),				      _("Server has disconnected"));	} else if (ret < buflen) {		if (ret < 0)			ret = 0;		if (!irc->writeh)			irc->writeh = purple_input_add(				irc->gsc ? irc->gsc->fd : irc->fd,				PURPLE_INPUT_WRITE, irc_send_cb, irc);		purple_circ_buffer_append(irc->outbuf, tosend + ret,			buflen - ret);	}	g_free(tosend);	return ret;}/* XXX I don't like messing directly with these buddies */gboolean irc_blist_timeout(struct irc_conn *irc){	GString *string = g_string_sized_new(512);	char *list, *buf;	g_hash_table_foreach(irc->buddies, (GHFunc)irc_buddy_append, (gpointer)string);	list = g_string_free(string, FALSE);	if (!list || !strlen(list)) {		g_free(list);		return TRUE;	}	buf = irc_format(irc, "vn", "ISON", list);	g_free(list);	irc_send(irc, buf);	g_free(buf);	return TRUE;}static void irc_buddy_append(char *name, struct irc_buddy *ib, GString *string){	ib->flag = FALSE;	g_string_append_printf(string, "%s ", name);}static void irc_ison_one(struct irc_conn *irc, struct irc_buddy *ib){	char *buf;	ib->flag = FALSE;	buf = irc_format(irc, "vn", "ISON", ib->name);	irc_send(irc, buf);	g_free(buf);}static const char *irc_blist_icon(PurpleAccount *a, PurpleBuddy *b){	return "irc";}static GList *irc_status_types(PurpleAccount *account){	PurpleStatusType *type;	GList *types = NULL;	type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE);	types = g_list_append(types, type);	type = purple_status_type_new_with_attrs(		PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE,		"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),		NULL);	types = g_list_append(types, type);	type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE);	types = g_list_append(types, type);	return types;}static GList *irc_actions(PurplePlugin *plugin, gpointer context){	GList *list = NULL;	PurplePluginAction *act = NULL;	act = purple_plugin_action_new(_("View MOTD"), irc_view_motd);	list = g_list_append(list, act);	return list;}static GList *irc_chat_join_info(PurpleConnection *gc){	GList *m = NULL;	struct proto_chat_entry *pce;	pce = g_new0(struct proto_chat_entry, 1);	pce->label = _("_Channel:");	pce->identifier = "channel";	pce->required = TRUE;	m = g_list_append(m, pce);	pce = g_new0(struct proto_chat_entry, 1);	pce->label = _("_Password:");	pce->identifier = "password";	pce->secret = TRUE;	m = g_list_append(m, pce);	return m;}static GHashTable *irc_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 void irc_login(PurpleAccount *account){	PurpleConnection *gc;	struct irc_conn *irc;	char **userparts;	const char *username = purple_account_get_username(account);	gc = purple_account_get_connection(account);	gc->flags |= PURPLE_CONNECTION_NO_NEWLINES;	if (strpbrk(username, " \t\v\r\n") != NULL) {		purple_connection_error(gc, _("IRC nicks may not contain whitespace"));		return;	}	gc->proto_data = irc = g_new0(struct irc_conn, 1);	irc->fd = -1;	irc->account = account;	irc->outbuf = purple_circ_buffer_new(512);	userparts = g_strsplit(username, "@", 2);	purple_connection_set_display_name(gc, userparts[0]);	irc->server = g_strdup(userparts[1]);	g_strfreev(userparts);	irc->buddies = g_hash_table_new_full((GHashFunc)irc_nick_hash, (GEqualFunc)irc_nick_equal,					     NULL, (GDestroyNotify)irc_buddy_free);	irc->cmds = g_hash_table_new(g_str_hash, g_str_equal);	irc_cmd_table_build(irc);	irc->msgs = g_hash_table_new(g_str_hash, g_str_equal);	irc_msg_table_build(irc);	purple_connection_update_progress(gc, _("Connecting"), 1, 2);	if (purple_account_get_bool(account, "ssl", FALSE)) {		if (purple_ssl_is_supported()) {			irc->gsc = purple_ssl_connect(account, irc->server,					purple_account_get_int(account, "port", IRC_DEFAULT_SSL_PORT),					irc_login_cb_ssl, irc_ssl_connect_failure, gc);		} else {			purple_connection_error(gc, _("SSL support unavailable"));			return;		}	}	if (!irc->gsc) {		if (purple_proxy_connect(gc, account, irc->server,				 purple_account_get_int(account, "port", IRC_DEFAULT_PORT),				 irc_login_cb, gc) == NULL)		{			purple_connection_error(gc, _("Couldn't create socket"));			return;		}	}}static gboolean do_login(PurpleConnection *gc) {	char *buf, *tmp = NULL;	char hostname[256];	const char *username, *realname;	struct irc_conn *irc = gc->proto_data;	const char *pass = purple_connection_get_password(gc);	if (pass && *pass) {		buf = irc_format(irc, "vv", "PASS", pass);		if (irc_send(irc, buf) < 0) {/*			purple_connection_error(gc, "Error sending password"); */			g_free(buf);			return FALSE;		}		g_free(buf);	}	gethostname(hostname, sizeof(hostname));	hostname[sizeof(hostname) - 1] = '\0';	realname = purple_account_get_string(irc->account, "realname", "");	username = purple_account_get_string(irc->account, "username", "");	if (username == NULL || *username == '\0') {		username = g_get_user_name();	}	if (username != NULL && strchr(username, ' ') != NULL) {		tmp = g_strdup(username);		while ((buf = strchr(tmp, ' ')) != NULL) {			*buf = '_';		}	}	buf = irc_format(irc, "vvvv:", "USER", tmp ? tmp : username, hostname, irc->server,			      strlen(realname) ? realname : IRC_DEFAULT_ALIAS);	g_free(tmp);	if (irc_send(irc, buf) < 0) {/*		purple_connection_error(gc, "Error registering with server");*/		g_free(buf);		return FALSE;	}	g_free(buf);	buf = irc_format(irc, "vn", "NICK", purple_connection_get_display_name(gc));	if (irc_send(irc, buf) < 0) {/*		purple_connection_error(gc, "Error sending nickname");*/		g_free(buf);		return FALSE;	}	g_free(buf);	irc->recv_time = time(NULL);	return TRUE;}static void irc_login_cb_ssl(gpointer data, PurpleSslConnection *gsc,	PurpleInputCondition cond){	PurpleConnection *gc = data;	if (do_login(gc)) {		purple_ssl_input_add(gsc, irc_input_cb_ssl, gc);	}}static void irc_login_cb(gpointer data, gint source, const gchar *error_message){	PurpleConnection *gc = data;	struct irc_conn *irc = gc->proto_data;	if (source < 0) {		purple_connection_error(gc, _("Couldn't connect to host"));		return;	}	irc->fd = source;	if (do_login(gc)) {		gc->inpa = purple_input_add(irc->fd, PURPLE_INPUT_READ, irc_input_cb, gc);	}}static voidirc_ssl_connect_failure(PurpleSslConnection *gsc, PurpleSslErrorType error,		gpointer data){	PurpleConnection *gc = data;	struct irc_conn *irc = gc->proto_data;	irc->gsc = NULL;	switch(error) {		case PURPLE_SSL_CONNECT_FAILED:			purple_connection_error(gc, _("Connection Failed"));			break;		case PURPLE_SSL_HANDSHAKE_FAILED:			purple_connection_error(gc, _("SSL Handshake Failed"));			break;	}}static void irc_close(PurpleConnection *gc){	struct irc_conn *irc = gc->proto_data;	if (irc == NULL)		return;	if (irc->gsc || (irc->fd >= 0))		irc_cmd_quit(irc, "quit", NULL, NULL);	if (gc->inpa)		purple_input_remove(gc->inpa);	g_free(irc->inbuf);	if (irc->gsc) {		purple_ssl_close(irc->gsc);	} else if (irc->fd >= 0) {		close(irc->fd);	}	if (irc->timer)		purple_timeout_remove(irc->timer);	g_hash_table_destroy(irc->cmds);	g_hash_table_destroy(irc->msgs);	g_hash_table_destroy(irc->buddies);	if (irc->motd)		g_string_free(irc->motd, TRUE);	g_free(irc->server);	if (irc->writeh)		purple_input_remove(irc->writeh);	purple_circ_buffer_destroy(irc->outbuf);	g_free(irc->mode_chars);	g_free(irc);}static int irc_im_send(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags){	struct irc_conn *irc = gc->proto_data;	char *plain;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -