?? qq.c
字號:
/** * @file qq.c * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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"#ifdef _WIN32#define random rand#endif#include "accountopt.h"#include "debug.h"#include "notify.h"#include "prefs.h"#include "prpl.h"#include "request.h"#include "roomlist.h"#include "server.h"#include "util.h"#include "buddy_info.h"#include "buddy_opt.h"#include "buddy_status.h"#include "char_conv.h"#include "crypt.h"#include "group.h"#include "group_find.h"#include "group_im.h"#include "group_info.h"#include "group_join.h"#include "group_opt.h"#include "header_info.h"#include "im.h"#include "keep_alive.h"#include "login_logout.h"#include "packet_parse.h"#include "qq.h"#include "qq_proxy.h"#include "send_core.h"#include "send_file.h"#include "utils.h"#include "version.h"#define OPENQ_AUTHOR "Puzzlebird"#define OPENQ_WEBSITE "http://openq.sourceforge.net"#define QQ_TCP_QUERY_PORT "8000"#define QQ_UDP_PORT "8000"const gchar *udp_server_list[] = { "sz.tencent.com", "sz2.tencent.com", "sz3.tencent.com", "sz4.tencent.com", "sz5.tencent.com", "sz6.tencent.com", "sz7.tencent.com", "sz8.tencent.com", "sz9.tencent.com"};const gint udp_server_amount = (sizeof(udp_server_list) / sizeof(udp_server_list[0]));const gchar *tcp_server_list[] = { "tcpconn.tencent.com", "tcpconn2.tencent.com", "tcpconn3.tencent.com", "tcpconn4.tencent.com", "tcpconn5.tencent.com", "tcpconn6.tencent.com"};const gint tcp_server_amount = (sizeof(tcp_server_list) / sizeof(tcp_server_list[0]));static void _qq_login(PurpleAccount *account){ const gchar *qq_server, *qq_port; qq_data *qd; PurpleConnection *gc; PurplePresence *presence; gboolean use_tcp; g_return_if_fail(account != NULL); gc = purple_account_get_connection(account); g_return_if_fail(gc != NULL); gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_AUTO_RESP; qd = g_new0(qq_data, 1); qd->gc = gc; gc->proto_data = qd; qq_server = purple_account_get_string(account, "server", NULL); qq_port = purple_account_get_string(account, "port", NULL); use_tcp = purple_account_get_bool(account, "use_tcp", FALSE); presence = purple_account_get_presence(account); qd->use_tcp = use_tcp; if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) { qd->login_mode = QQ_LOGIN_MODE_HIDDEN; } else if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY) || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY)) { qd->login_mode = QQ_LOGIN_MODE_AWAY; } else { qd->login_mode = QQ_LOGIN_MODE_NORMAL; } if (qq_server == NULL || strlen(qq_server) == 0) qq_server = use_tcp ? tcp_server_list[random() % tcp_server_amount] : udp_server_list[random() % udp_server_amount]; if (qq_port == NULL || strtol(qq_port, NULL, 10) == 0) qq_port = use_tcp ? QQ_TCP_QUERY_PORT : QQ_UDP_PORT; purple_connection_update_progress(gc, _("Connecting"), 0, QQ_CONNECT_STEPS); if (qq_connect(account, qq_server, strtol(qq_port, NULL, 10), use_tcp, FALSE) < 0) purple_connection_error(gc, _("Unable to connect."));}/* directly goes for qq_disconnect */static void _qq_close(PurpleConnection *gc){ g_return_if_fail(gc != NULL); qq_disconnect(gc);}/* returns the icon name for a buddy or protocol */static const gchar *_qq_list_icon(PurpleAccount *a, PurpleBuddy *b){ return "qq";}/* a short status text beside buddy icon*/static gchar *_qq_status_text(PurpleBuddy *b){ qq_buddy *q_bud; GString *status; q_bud = (qq_buddy *) b->proto_data; if (q_bud == NULL) return NULL; status = g_string_new(""); switch(q_bud->status) { case QQ_BUDDY_OFFLINE: g_string_append(status, _("Offline")); break; case QQ_BUDDY_ONLINE_NORMAL: return NULL; break; /* TODO What does this status mean? Labelling it as offline... */ case QQ_BUDDY_ONLINE_OFFLINE: g_string_append(status, _("Offline")); break; case QQ_BUDDY_ONLINE_AWAY: g_string_append(status, _("Away")); break; case QQ_BUDDY_ONLINE_INVISIBLE: g_string_append(status, _("Invisible")); break; default: g_string_printf(status, _("Unknown-%d"), q_bud->status); } return g_string_free(status, FALSE);}/* a floating text when mouse is on the icon, show connection status here */static void _qq_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full){ qq_buddy *q_bud; gchar *ip_str; char *tmp, *tmp2; g_return_if_fail(b != NULL); q_bud = (qq_buddy *) b->proto_data; g_return_if_fail(q_bud != NULL); if (PURPLE_BUDDY_IS_ONLINE(b) && q_bud != NULL) { ip_str = gen_ip_str(q_bud->ip); if (strlen(ip_str) != 0) { tmp = g_strdup_printf(_("%s Address"), ((q_bud->comm_flag & QQ_COMM_FLAG_TCP_MODE) ? "TCP" : "UDP")); tmp2 = g_strdup_printf("%s:%d", ip_str, q_bud->port); purple_notify_user_info_add_pair(user_info, tmp, tmp2); g_free(tmp2); g_free(tmp); } g_free(ip_str); tmp = g_strdup_printf("%d", q_bud->age); purple_notify_user_info_add_pair(user_info, _("Age"), tmp); g_free(tmp); switch (q_bud->gender) { case QQ_BUDDY_GENDER_GG: purple_notify_user_info_add_pair(user_info, _("Gender"), _("Male")); break; case QQ_BUDDY_GENDER_MM: purple_notify_user_info_add_pair(user_info, _("Gender"), _("Female")); break; case QQ_BUDDY_GENDER_UNKNOWN: purple_notify_user_info_add_pair(user_info, _("Gender"), _("Unknown")); break; default: tmp = g_strdup_printf("Error (%d)", q_bud->gender); purple_notify_user_info_add_pair(user_info, _("Gender"), tmp); g_free(tmp); } if (q_bud->level) { tmp = g_strdup_printf("%d", q_bud->level); purple_notify_user_info_add_pair(user_info, _("Level"), tmp); g_free(tmp); } /* For debugging */ /* g_string_append_printf(tooltip, "\n<b>Flag:</b> %01x", q_bud->flag1); g_string_append_printf(tooltip, "\n<b>CommFlag:</b> %01x", q_bud->comm_flag); g_string_append_printf(tooltip, "\n<b>Client:</b> %04x", q_bud->client_version); */ }}/* we can show tiny icons on the four corners of buddy icon, */static const char *_qq_list_emblem(PurpleBuddy *b){ /* each char** are refering to a filename in pixmaps/purple/status/default/ */ qq_buddy *q_bud = b->proto_data; if (q_bud) { if (q_bud->comm_flag & QQ_COMM_FLAG_QQ_MEMBER) return "qq_member"; /* if (q_bud->comm_flag & QQ_COMM_FLAG_VIDEO) return "video"; */ } return NULL;}/* QQ away status (used to initiate QQ away packet) */static GList *_qq_away_states(PurpleAccount *ga){ PurpleStatusType *status; GList *types = NULL; status = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, "available", _("QQ: Available"), FALSE, TRUE, FALSE); types = g_list_append(types, status); status = purple_status_type_new_full(PURPLE_STATUS_AWAY, "away", _("QQ: Away"), FALSE, TRUE, FALSE); types = g_list_append(types, status); status = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, "invisible", _("QQ: Invisible"), FALSE, TRUE, FALSE); types = g_list_append(types, status); status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, "offline", _("QQ: Offline"), FALSE, TRUE, FALSE); types = g_list_append(types, status); status = purple_status_type_new_full(PURPLE_STATUS_MOBILE, "mobile", NULL, FALSE, FALSE, TRUE); types = g_list_append(types, status); return types;}/* initiate QQ away with proper change_status packet */static void _qq_set_away(PurpleAccount *account, PurpleStatus *status){ PurpleConnection *gc = purple_account_get_connection(account); qq_send_packet_change_status(gc);}/* IMPORTANT: PurpleConvImFlags -> PurpleMessageFlags *//* send an instant msg to a buddy */static gint _qq_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, PurpleMessageFlags flags){ gint type, to_uid; gchar *msg, *msg_with_qq_smiley; qq_data *qd; g_return_val_if_fail(who != NULL, -1); qd = (qq_data *) gc->proto_data; g_return_val_if_fail(strlen(message) <= QQ_MSG_IM_MAX, -E2BIG); type = (flags == PURPLE_MESSAGE_AUTO_RESP ? QQ_IM_AUTO_REPLY : QQ_IM_TEXT); to_uid = purple_name_to_uid(who); /* if msg is to myself, bypass the network */ if (to_uid == qd->uid) { serv_got_im(gc, who, message, flags, time(NULL)); } else { msg = utf8_to_qq(message, QQ_CHARSET_DEFAULT); msg_with_qq_smiley = purple_smiley_to_qq(msg); qq_send_packet_im(gc, to_uid, msg_with_qq_smiley, type); g_free(msg); g_free(msg_with_qq_smiley); } return 1;}/* send a chat msg to a QQ Qun */static int _qq_chat_send(PurpleConnection *gc, int channel, const char *message, PurpleMessageFlags flags){ gchar *msg, *msg_with_qq_smiley; qq_group *group; g_return_val_if_fail(message != NULL, -1); g_return_val_if_fail(strlen(message) <= QQ_MSG_IM_MAX, -E2BIG); group = qq_group_find_by_channel(gc, channel); g_return_val_if_fail(group != NULL, -1); msg = utf8_to_qq(message, QQ_CHARSET_DEFAULT); msg_with_qq_smiley = purple_smiley_to_qq(msg); qq_send_packet_group_im(gc, group, msg_with_qq_smiley); g_free(msg); g_free(msg_with_qq_smiley); return 1;}/* send packet to get who's detailed information */static void _qq_get_info(PurpleConnection *gc, const gchar *who){ guint32 uid; qq_data *qd; qd = gc->proto_data; uid = purple_name_to_uid(who); if (uid <= 0) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not valid QQid: %s\n", who); purple_notify_error(gc, NULL, _("Invalid name"), NULL); return; } qq_send_packet_get_level(gc, uid); qq_send_packet_get_info(gc, uid, TRUE);}/* get my own information */static void _qq_menu_modify_my_info(PurplePluginAction *action){ PurpleConnection *gc = (PurpleConnection *) action->context; qq_data *qd; qd = (qq_data *) gc->proto_data; qq_prepare_modify_info(gc);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -