| |
1 /** |
| |
2 * The QQ2003C protocol plugin |
| |
3 * |
| |
4 * for gaim |
| |
5 * |
| |
6 * Copyright (C) 2004 Puzzlebird |
| |
7 * |
| |
8 * This program is free software; you can redistribute it and/or modify |
| |
9 * it under the terms of the GNU General Public License as published by |
| |
10 * the Free Software Foundation; either version 2 of the License, or |
| |
11 * (at your option) any later version. |
| |
12 * |
| |
13 * This program is distributed in the hope that it will be useful, |
| |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
16 * GNU General Public License for more details. |
| |
17 * |
| |
18 * You should have received a copy of the GNU General Public License |
| |
19 * along with this program; if not, write to the Free Software |
| |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
21 */ |
| |
22 |
| |
23 #include "debug.h" |
| |
24 #include "internal.h" |
| |
25 #include "notify.h" |
| |
26 #include "request.h" |
| |
27 |
| |
28 #include "buddy_info.h" |
| |
29 #include "buddy_list.h" |
| |
30 #include "buddy_opt.h" |
| |
31 #include "char_conv.h" |
| |
32 #include "crypt.h" |
| |
33 #include "header_info.h" |
| |
34 #include "packet_parse.h" |
| |
35 #include "qq.h" |
| |
36 #include "send_core.h" |
| |
37 #include "sys_msg.h" |
| |
38 #include "utils.h" |
| |
39 |
| |
40 enum { |
| |
41 QQ_MSG_SYS_BEING_ADDED = 0x01, |
| |
42 QQ_MSG_SYS_ADD_CONTACT_REQUEST = 0x02, |
| |
43 QQ_MSG_SYS_ADD_CONTACT_APPROVED = 0x03, |
| |
44 QQ_MSG_SYS_ADD_CONTACT_REJECTED = 0x04, |
| |
45 QQ_MSG_SYS_NEW_VERSION = 0x09 |
| |
46 }; |
| |
47 |
| |
48 /* Henry: private function for reading/writing of system log */ |
| |
49 static void _qq_sys_msg_log_write(GaimConnection *gc, gchar *msg, gchar *from) |
| |
50 { |
| |
51 GaimLog *log; |
| |
52 GaimAccount *account; |
| |
53 |
| |
54 account = gaim_connection_get_account(gc); |
| |
55 g_return_if_fail(gc != NULL && gc->proto_data != NULL); |
| |
56 |
| |
57 log = gaim_log_new(GAIM_LOG_IM, |
| |
58 "systemim", |
| |
59 account, |
| |
60 NULL, |
| |
61 time(NULL), |
| |
62 NULL |
| |
63 ); |
| |
64 gaim_log_write(log, GAIM_MESSAGE_SYSTEM, from, |
| |
65 time(NULL), msg); |
| |
66 gaim_log_free(log); |
| |
67 } |
| |
68 |
| |
69 /* suggested by rakescar@linuxsir, can still approve after search */ |
| |
70 static void _qq_search_before_auth_with_gc_and_uid(gc_and_uid *g) |
| |
71 { |
| |
72 GaimConnection *gc; |
| |
73 guint32 uid; |
| |
74 |
| |
75 g_return_if_fail(g != NULL); |
| |
76 |
| |
77 gc = g->gc; |
| |
78 uid = g->uid; |
| |
79 g_return_if_fail(gc != 0 && uid != 0); |
| |
80 |
| |
81 qq_send_packet_get_info(gc, uid, TRUE); /* we wanna see window */ |
| |
82 gaim_request_action |
| |
83 (gc, NULL, _("Do you wanna approve the request?"), "", 2, g, 2, |
| |
84 _("Reject"), |
| |
85 G_CALLBACK(qq_reject_add_request_with_gc_and_uid), |
| |
86 _("Approve"), G_CALLBACK(qq_approve_add_request_with_gc_and_uid)); |
| |
87 } |
| |
88 |
| |
89 static void _qq_search_before_add_with_gc_and_uid(gc_and_uid *g) |
| |
90 { |
| |
91 GaimConnection *gc; |
| |
92 guint32 uid; |
| |
93 |
| |
94 g_return_if_fail(g != NULL); |
| |
95 |
| |
96 gc = g->gc; |
| |
97 uid = g->uid; |
| |
98 g_return_if_fail(gc != 0 && uid != 0); |
| |
99 |
| |
100 qq_send_packet_get_info(gc, uid, TRUE); /* we wanna see window */ |
| |
101 gaim_request_action |
| |
102 (gc, NULL, _("Do you wanna add this buddy?"), "", 2, g, 2, |
| |
103 _("Cancel"), NULL, _("Add"), G_CALLBACK(qq_add_buddy_with_gc_and_uid)); |
| |
104 } |
| |
105 |
| |
106 /* Send ACK if the sys message needs an ACK */ |
| |
107 static void _qq_send_packet_ack_msg_sys(GaimConnection *gc, guint8 code, guint32 from, guint16 seq) |
| |
108 { |
| |
109 guint8 bar, *ack, *cursor; |
| |
110 gchar *str; |
| |
111 gint ack_len, bytes; |
| |
112 |
| |
113 str = g_strdup_printf("%d", from); |
| |
114 bar = 0x1e; |
| |
115 ack_len = 1 + 1 + strlen(str) + 1 + 2; |
| |
116 ack = g_newa(guint8, ack_len); |
| |
117 cursor = ack; |
| |
118 bytes = 0; |
| |
119 |
| |
120 bytes += create_packet_b(ack, &cursor, code); |
| |
121 bytes += create_packet_b(ack, &cursor, bar); |
| |
122 bytes += create_packet_data(ack, &cursor, (guint8 *) str, strlen(str)); |
| |
123 bytes += create_packet_b(ack, &cursor, bar); |
| |
124 bytes += create_packet_w(ack, &cursor, seq); |
| |
125 |
| |
126 g_free(str); |
| |
127 |
| |
128 if (bytes == ack_len) /* creation OK */ |
| |
129 qq_send_cmd(gc, QQ_CMD_ACK_SYS_MSG, TRUE, 0, FALSE, ack, ack_len); |
| |
130 else |
| |
131 gaim_debug(GAIM_DEBUG_ERROR, "QQ", |
| |
132 "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); |
| |
133 } |
| |
134 |
| |
135 /* when you are added by a person, QQ server will send sys message */ |
| |
136 static void _qq_process_msg_sys_being_added(GaimConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) |
| |
137 { |
| |
138 gchar *message; |
| |
139 GaimBuddy *b; |
| |
140 guint32 uid; |
| |
141 gc_and_uid *g; |
| |
142 gchar *name; |
| |
143 |
| |
144 g_return_if_fail(gc != NULL && from != NULL && to != NULL); |
| |
145 |
| |
146 uid = strtol(from, NULL, 10); |
| |
147 name = uid_to_gaim_name(uid); |
| |
148 b = gaim_find_buddy(gc->account, name); |
| |
149 g_free(name); |
| |
150 if (b == NULL) { /* the person is not in my list */ |
| |
151 g = g_new0(gc_and_uid, 1); |
| |
152 g->gc = gc; |
| |
153 g->uid = uid; /* only need to get value */ |
| |
154 message = g_strdup_printf(_("You have been added by %s"), from); |
| |
155 _qq_sys_msg_log_write(gc, message, from); |
| |
156 gaim_request_action(gc, NULL, message, |
| |
157 _("Would like to add him?"), 2, g, 3, |
| |
158 _("Cancel"), NULL, _("Add"), |
| |
159 G_CALLBACK |
| |
160 (qq_add_buddy_with_gc_and_uid), |
| |
161 _("Search"), G_CALLBACK(_qq_search_before_add_with_gc_and_uid)); |
| |
162 } else { |
| |
163 message = g_strdup_printf(_("%s has added you [%s]"), from, to); |
| |
164 _qq_sys_msg_log_write(gc, message, from); |
| |
165 gaim_notify_info(gc, NULL, message, NULL); |
| |
166 } |
| |
167 |
| |
168 g_free(message); |
| |
169 } |
| |
170 |
| |
171 /* you are rejected by the person */ |
| |
172 static void _qq_process_msg_sys_add_contact_rejected(GaimConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) |
| |
173 { |
| |
174 gchar *message, *reason; |
| |
175 |
| |
176 g_return_if_fail(gc != NULL && from != NULL && to != NULL); |
| |
177 |
| |
178 message = g_strdup_printf(_("User %s rejected your request"), from); |
| |
179 reason = g_strdup_printf(_("Reason: %s"), msg_utf8); |
| |
180 _qq_sys_msg_log_write(gc, message, from); |
| |
181 |
| |
182 gaim_notify_info(gc, NULL, message, reason); |
| |
183 g_free(message); |
| |
184 g_free(reason); |
| |
185 } |
| |
186 |
| |
187 /* the buddy approves your request of adding him/her as your friend */ |
| |
188 static void _qq_process_msg_sys_add_contact_approved(GaimConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) |
| |
189 { |
| |
190 gchar *message; |
| |
191 qq_data *qd; |
| |
192 |
| |
193 g_return_if_fail(gc != NULL && from != NULL && to != NULL); |
| |
194 |
| |
195 qd = (qq_data *) gc->proto_data; |
| |
196 qq_add_buddy_by_recv_packet(gc, strtol(from, NULL, 10), TRUE, TRUE); |
| |
197 |
| |
198 message = g_strdup_printf(_("Use %s has approved your request"), from); |
| |
199 _qq_sys_msg_log_write(gc, message, from); |
| |
200 gaim_notify_info(gc, NULL, message, NULL); |
| |
201 |
| |
202 g_free(message); |
| |
203 } |
| |
204 |
| |
205 /* someone wants to add you to his buddy list */ |
| |
206 static void _qq_process_msg_sys_add_contact_request(GaimConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) |
| |
207 { |
| |
208 gchar *message, *reason; |
| |
209 guint32 uid; |
| |
210 gc_and_uid *g, *g2; |
| |
211 GaimBuddy *b; |
| |
212 gchar *name; |
| |
213 |
| |
214 g_return_if_fail(gc != NULL && from != NULL && to != NULL); |
| |
215 |
| |
216 uid = strtol(from, NULL, 10); |
| |
217 g = g_new0(gc_and_uid, 1); |
| |
218 g->gc = gc; |
| |
219 g->uid = uid; |
| |
220 |
| |
221 message = g_strdup_printf(_("%s wanna add you [%s] as friends"), from, to); |
| |
222 reason = g_strdup_printf(_("Message: %s"), msg_utf8); |
| |
223 _qq_sys_msg_log_write(gc, message, from); |
| |
224 |
| |
225 gaim_request_action |
| |
226 (gc, NULL, message, reason, 2, g, 3, |
| |
227 _("Reject"), |
| |
228 G_CALLBACK(qq_reject_add_request_with_gc_and_uid), |
| |
229 _("Approve"), |
| |
230 G_CALLBACK(qq_approve_add_request_with_gc_and_uid), |
| |
231 _("Search"), G_CALLBACK(_qq_search_before_auth_with_gc_and_uid)); |
| |
232 |
| |
233 g_free(message); |
| |
234 g_free(reason); |
| |
235 |
| |
236 name = uid_to_gaim_name(uid); |
| |
237 b = gaim_find_buddy(gc->account, name); |
| |
238 g_free(name); |
| |
239 if (b == NULL) { /* the person is not in my list */ |
| |
240 g2 = g_new0(gc_and_uid, 1); |
| |
241 g2->gc = gc; |
| |
242 g2->uid = strtol(from, NULL, 10); |
| |
243 message = g_strdup_printf(_("%s is not in your buddy list"), from); |
| |
244 gaim_request_action(gc, NULL, message, |
| |
245 _("Would you like to add him?"), 2, g2, |
| |
246 3, _("Cancel"), NULL, _("Add"), |
| |
247 G_CALLBACK |
| |
248 (qq_add_buddy_with_gc_and_uid), |
| |
249 _("Search"), G_CALLBACK(_qq_search_before_add_with_gc_and_uid)); |
| |
250 g_free(message); |
| |
251 } |
| |
252 } |
| |
253 |
| |
254 void qq_process_msg_sys(guint8 *buf, gint buf_len, guint16 seq, GaimConnection *gc) |
| |
255 { |
| |
256 qq_data *qd; |
| |
257 gint len; |
| |
258 guint8 *data; |
| |
259 gchar **segments, *code, *from, *to, *msg, *msg_utf8; |
| |
260 |
| |
261 g_return_if_fail(gc != NULL && gc->proto_data != NULL); |
| |
262 g_return_if_fail(buf != NULL && buf_len != 0); |
| |
263 |
| |
264 qd = (qq_data *) gc->proto_data; |
| |
265 len = buf_len; |
| |
266 data = g_newa(guint8, len); |
| |
267 |
| |
268 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { |
| |
269 if (NULL == (segments = split_data(data, len, "\x1f", 4))) |
| |
270 return; |
| |
271 code = segments[0]; |
| |
272 from = segments[1]; |
| |
273 to = segments[2]; |
| |
274 msg = segments[3]; |
| |
275 |
| |
276 _qq_send_packet_ack_msg_sys(gc, code[0], strtol(from, NULL, 10), seq); |
| |
277 |
| |
278 if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ |
| |
279 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Recv sys msg to [%s], not me!, discard\n", to); |
| |
280 g_strfreev(segments); |
| |
281 return; |
| |
282 } |
| |
283 |
| |
284 msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); |
| |
285 switch (strtol(code, NULL, 10)) { |
| |
286 case QQ_MSG_SYS_BEING_ADDED: |
| |
287 _qq_process_msg_sys_being_added(gc, from, to, msg_utf8); |
| |
288 break; |
| |
289 case QQ_MSG_SYS_ADD_CONTACT_REQUEST: |
| |
290 _qq_process_msg_sys_add_contact_request(gc, from, to, msg_utf8); |
| |
291 break; |
| |
292 case QQ_MSG_SYS_ADD_CONTACT_APPROVED: |
| |
293 _qq_process_msg_sys_add_contact_approved(gc, from, to, msg_utf8); |
| |
294 break; |
| |
295 case QQ_MSG_SYS_ADD_CONTACT_REJECTED: |
| |
296 _qq_process_msg_sys_add_contact_rejected(gc, from, to, msg_utf8); |
| |
297 break; |
| |
298 case QQ_MSG_SYS_NEW_VERSION: |
| |
299 gaim_debug(GAIM_DEBUG_WARNING, "QQ", |
| |
300 "QQ server says there is newer version than %s\n", qq_get_source_str(QQ_CLIENT)); |
| |
301 break; |
| |
302 default: |
| |
303 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Recv unknown sys msg code: %s\n", code); |
| |
304 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "the msg is : %s\n", msg_utf8); |
| |
305 } |
| |
306 g_free(msg_utf8); |
| |
307 g_strfreev(segments); |
| |
308 |
| |
309 } else { |
| |
310 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt recv msg sys\n"); |
| |
311 } |
| |
312 } |