00001
00023
00024
00025 #include <string.h>
00026 #include "debug.h"
00027 #include "prefs.h"
00028
00029 #include "utils.h"
00030 #include "packet_parse.h"
00031 #include "buddy_status.h"
00032 #include "crypt.h"
00033 #include "header_info.h"
00034 #include "keep_alive.h"
00035 #include "send_core.h"
00036
00037 #define QQ_MISC_STATUS_HAVING_VIIDEO 0x00000001
00038
00039 #define QQ_ICON_SUFFIX_DEFAULT QQ_ICON_SUFFIX_OFFLINE
00040 #define QQ_CHANGE_ONLINE_STATUS_REPLY_OK 0x30 // ASCii value of "0"
00041
00042 enum {
00043 QQ_ICON_SUFFIX_NORMAL = 1,
00044 QQ_ICON_SUFFIX_OFFLINE = 2,
00045 QQ_ICON_SUFFIX_AWAY = 3,
00046 };
00047
00048
00049 void _qq_buddy_status_dump_unclear(qq_buddy_status * s)
00050 {
00051 GString *dump;
00052
00053 g_return_if_fail(s != NULL);
00054
00055 dump = g_string_new("");
00056 g_string_append_printf(dump, "unclear fields for [%d]:\n", s->uid);
00057 g_string_append_printf(dump, "004: %02x (unknown)\n", s->unknown1);
00058 g_string_append_printf(dump, "011: %02x (unknown)\n", s->unknown2);
00059
00060 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Buddy status entry, %s", dump->str);
00061 g_string_free(dump, TRUE);
00062 }
00063
00064
00065
00066 gint _qq_buddy_status_read(guint8 * data, guint8 ** cursor, gint len, qq_buddy_status * s) {
00067 gint bytes;
00068
00069 g_return_val_if_fail(data != NULL && *cursor != NULL && s != NULL, -1);
00070
00071 bytes = 0;
00072
00073
00074 bytes += read_packet_dw(data, cursor, len, &s->uid);
00075
00076 bytes += read_packet_b(data, cursor, len, &s->unknown1);
00077
00078 s->ip = g_new0(guint8, 4);
00079 bytes += read_packet_data(data, cursor, len, s->ip, 4);
00080
00081 bytes += read_packet_w(data, cursor, len, &s->port);
00082
00083 bytes += read_packet_b(data, cursor, len, &s->unknown2);
00084
00085 bytes += read_packet_b(data, cursor, len, &s->status);
00086
00087 bytes += read_packet_w(data, cursor, len, &s->client_version);
00088
00089 s->unknown_key = g_new0(guint8, QQ_KEY_LENGTH);
00090 bytes += read_packet_data(data, cursor, len, s->unknown_key, QQ_KEY_LENGTH);
00091
00092 if (s->uid == 0 || bytes != 31)
00093 return -1;
00094
00095 return bytes;
00096
00097 }
00098
00099
00100
00101 gboolean is_online(guint8 status)
00102 {
00103 return (status == QQ_BUDDY_ONLINE_NORMAL ? TRUE : (status == QQ_BUDDY_ONLINE_AWAY ? TRUE : FALSE));
00104 }
00105
00106
00107
00108
00109 gchar get_suffix_from_status(guint8 status)
00110 {
00111 switch (status) {
00112 case QQ_BUDDY_ONLINE_NORMAL:
00113 return QQ_ICON_SUFFIX_NORMAL;
00114 case QQ_BUDDY_ONLINE_AWAY:
00115 return QQ_ICON_SUFFIX_AWAY;
00116 case QQ_BUDDY_ONLINE_INVISIBLE:
00117 case QQ_BUDDY_ONLINE_OFFLINE:
00118 return QQ_ICON_SUFFIX_OFFLINE;
00119 default:
00120 return QQ_ICON_SUFFIX_DEFAULT;
00121 }
00122 }
00123
00124
00125
00126 void qq_send_packet_change_status(GaimConnection * gc)
00127 {
00128 qq_data *qd;
00129 guint8 *raw_data, *cursor, away_cmd;
00130 guint32 misc_status;
00131 gboolean fake_video;
00132
00133 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00134
00135 qd = (qq_data *) gc->proto_data;
00136 if (!qd->logged_in)
00137 return;
00138
00139 switch (qd->status) {
00140 case QQ_SELF_STATUS_AVAILABLE:
00141 away_cmd = QQ_BUDDY_ONLINE_NORMAL;
00142 break;
00143 case QQ_SELF_STATUS_INVISIBLE:
00144 away_cmd = QQ_BUDDY_ONLINE_INVISIBLE;
00145 break;
00146 case QQ_SELF_STATUS_AWAY:
00147 case QQ_SELF_STATUS_IDLE:
00148 case QQ_SELF_STATUS_CUSTOM:
00149 away_cmd = QQ_BUDDY_ONLINE_AWAY;
00150 break;
00151 default:
00152 away_cmd = QQ_BUDDY_ONLINE_NORMAL;
00153 }
00154
00155 raw_data = g_new0(guint8, 5);
00156 cursor = raw_data;
00157 misc_status = 0x00000000;
00158
00159 fake_video = gaim_prefs_get_bool("/plugins/prpl/qq/show_fake_video");
00160 if (fake_video)
00161 misc_status |= QQ_MISC_STATUS_HAVING_VIIDEO;
00162
00163 create_packet_b(raw_data, &cursor, away_cmd);
00164 create_packet_dw(raw_data, &cursor, misc_status);
00165
00166 qq_send_cmd(gc, QQ_CMD_CHANGE_ONLINE_STATUS, TRUE, 0, TRUE, raw_data, 5);
00167
00168 g_free(raw_data);
00169 }
00170
00171
00172
00173 void qq_process_change_status_reply(guint8 * buf, gint buf_len, GaimConnection * gc) {
00174 qq_data *qd;
00175 gint len;
00176 guint8 *data, *cursor, reply;
00177
00178 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00179 g_return_if_fail(buf != NULL && buf_len != 0);
00180
00181 qd = (qq_data *) gc->proto_data;
00182 len = buf_len;
00183 data = g_newa(guint8, len);
00184
00185 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00186 cursor = data;
00187 read_packet_b(data, &cursor, len, &reply);
00188 if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) {
00189 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Change status fail\n");
00190 } else
00191 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Change status OK\n");
00192 } else
00193 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n");
00194
00195 }
00196
00197
00198
00199
00200 void qq_process_friend_change_status(guint8 * buf, gint buf_len, GaimConnection * gc) {
00201 qq_data *qd;
00202 gint len, bytes;
00203 guint32 my_uid;
00204 guint8 *data, *cursor;
00205 GaimBuddy *b;
00206 qq_buddy *q_bud;
00207 qq_buddy_status *s;
00208 gchar *name;
00209
00210 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00211 g_return_if_fail(buf != NULL && buf_len != 0);
00212
00213 qd = (qq_data *) gc->proto_data;
00214 len = buf_len;
00215 data = g_newa(guint8, len);
00216 cursor = data;
00217
00218 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00219 s = g_new0(qq_buddy_status, 1);
00220 bytes = 0;
00221
00222 bytes += _qq_buddy_status_read(data, &cursor, len, s);
00223
00224 bytes += read_packet_dw(data, &cursor, len, &my_uid);
00225
00226 if (my_uid == 0 || bytes != 35) {
00227 g_free(s->ip);
00228 g_free(s->unknown_key);
00229 g_free(s);
00230 return;
00231 }
00232 if (QQ_DEBUG)
00233 _qq_buddy_status_dump_unclear(s);
00234
00235 name = uid_to_gaim_name(s->uid);
00236 b = gaim_find_buddy(gc->account, name);
00237 g_free(name);
00238 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
00239 if (q_bud) {
00240 gaim_debug(GAIM_DEBUG_INFO, "QQ", "s->uid = %d, q_bud->uid = %d\n", s->uid , q_bud->uid);
00241 if(0 != *((guint32 *)s->ip)) {
00242 g_memmove(q_bud->ip, s->ip, 4);
00243 q_bud->port = s->port;
00244 }
00245 q_bud->status = s->status;
00246 if(0 != s->client_version)
00247 q_bud->client_version = s->client_version;
00248 qq_update_buddy_contact(gc, q_bud);
00249 }
00250 g_free(s->ip);
00251 g_free(s->unknown_key);
00252 g_free(s);
00253 } else
00254 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt buddy status change packet\n");
00255
00256 }
00257
00258
00259