| 64 /* TODO: figure out what's going on with the IP region. Sometimes I get valid IP addresses, |
64 /* TODO: figure out what's going on with the IP region. Sometimes I get valid IP addresses, |
| 65 * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy, |
65 * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy, |
| 66 * using different accounts to get info. */ |
66 * using different accounts to get info. */ |
| 67 |
67 |
| 68 /* parse the data into qq_buddy_status */ |
68 /* parse the data into qq_buddy_status */ |
| 69 gint qq_buddy_status_read(guint8 *data, guint8 **cursor, gint len, qq_buddy_status *s) |
69 gint qq_buddy_status_read(qq_buddy_status *s, guint8 *data) |
| 70 { |
70 { |
| 71 gint bytes; |
71 gint bytes = 0; |
| 72 |
72 |
| 73 g_return_val_if_fail(data != NULL && *cursor != NULL && s != NULL, -1); |
73 g_return_val_if_fail(data != NULL && s != NULL, -1); |
| 74 |
|
| 75 bytes = 0; |
|
| 76 |
74 |
| 77 /* 000-003: uid */ |
75 /* 000-003: uid */ |
| 78 bytes += read_packet_dw(data, cursor, len, &s->uid); |
76 bytes += qq_get32(&s->uid, data + bytes); |
| 79 /* 004-004: 0x01 */ |
77 /* 004-004: 0x01 */ |
| 80 bytes += read_packet_b(data, cursor, len, &s->unknown1); |
78 bytes += qq_get8(&s->unknown1, data + bytes); |
| 81 /* this is no longer the IP, it seems QQ (as of 2006) no longer sends |
79 /* this is no longer the IP, it seems QQ (as of 2006) no longer sends |
| 82 * the buddy's IP in this packet. all 0s */ |
80 * the buddy's IP in this packet. all 0s */ |
| 83 /* 005-008: ip */ |
81 /* 005-008: ip */ |
| 84 s->ip = g_new0(guint8, 4); |
82 s->ip = g_new0(guint8, 4); |
| 85 bytes += read_packet_data(data, cursor, len, s->ip, 4); |
83 bytes += qq_getdata(s->ip, 4, data + bytes); |
| 86 /* port info is no longer here either */ |
84 /* port info is no longer here either */ |
| 87 /* 009-010: port */ |
85 /* 009-010: port */ |
| 88 bytes += read_packet_w(data, cursor, len, &s->port); |
86 bytes += qq_get16(&s->port, data + bytes); |
| 89 /* 011-011: 0x00 */ |
87 /* 011-011: 0x00 */ |
| 90 bytes += read_packet_b(data, cursor, len, &s->unknown2); |
88 bytes += qq_get8(&s->unknown2, data + bytes); |
| 91 /* 012-012: status */ |
89 /* 012-012: status */ |
| 92 bytes += read_packet_b(data, cursor, len, &s->status); |
90 bytes += qq_get8(&s->status, data + bytes); |
| 93 /* 013-014: client_version */ |
91 /* 013-014: client_version */ |
| 94 bytes += read_packet_w(data, cursor, len, &s->client_version); |
92 bytes += qq_get16(&s->client_version, data + bytes); |
| 95 /* 015-030: unknown key */ |
93 /* 015-030: unknown key */ |
| 96 s->unknown_key = g_new0(guint8, QQ_KEY_LENGTH); |
94 s->unknown_key = g_new0(guint8, QQ_KEY_LENGTH); |
| 97 bytes += read_packet_data(data, cursor, len, s->unknown_key, QQ_KEY_LENGTH); |
95 bytes += qq_getdata(s->unknown_key, QQ_KEY_LENGTH, data + bytes); |
| 98 |
96 |
| 99 if (s->uid == 0 || bytes != 31) |
97 if (s->uid == 0 || bytes != 31) |
| 100 return -1; |
98 return -1; |
| 101 |
99 |
| 102 return bytes; |
100 return bytes; |
| 161 away_cmd = QQ_BUDDY_ONLINE_AWAY; |
161 away_cmd = QQ_BUDDY_ONLINE_AWAY; |
| 162 } else { |
162 } else { |
| 163 away_cmd = QQ_BUDDY_ONLINE_NORMAL; |
163 away_cmd = QQ_BUDDY_ONLINE_NORMAL; |
| 164 } |
164 } |
| 165 |
165 |
| 166 raw_data = g_new0(guint8, 5); |
|
| 167 cursor = raw_data; |
|
| 168 misc_status = 0x00000000; |
166 misc_status = 0x00000000; |
| 169 |
|
| 170 fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video"); |
167 fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video"); |
| 171 if (fake_video) |
168 if (fake_video) |
| 172 misc_status |= QQ_MISC_STATUS_HAVING_VIIDEO; |
169 misc_status |= QQ_MISC_STATUS_HAVING_VIIDEO; |
| 173 |
170 |
| 174 create_packet_b(raw_data, &cursor, away_cmd); |
171 bytes = 0; |
| 175 create_packet_dw(raw_data, &cursor, misc_status); |
172 bytes += qq_put8(raw_data + bytes, away_cmd); |
| 176 |
173 bytes += qq_put32(raw_data + bytes, misc_status); |
| 177 qq_send_cmd(gc, QQ_CMD_CHANGE_ONLINE_STATUS, TRUE, 0, TRUE, raw_data, 5); |
174 |
| 178 |
175 qq_send_cmd(gc, QQ_CMD_CHANGE_ONLINE_STATUS, TRUE, 0, TRUE, raw_data, bytes); |
| 179 g_free(raw_data); |
|
| 180 } |
176 } |
| 181 |
177 |
| 182 /* parse the reply packet for change_status */ |
178 /* parse the reply packet for change_status */ |
| 183 void qq_process_change_status_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) |
179 void qq_process_change_status_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) |
| 184 { |
180 { |
| 185 qq_data *qd; |
181 qq_data *qd; |
| 186 gint len; |
182 gint len, bytes; |
| 187 guint8 *data, *cursor, reply; |
183 guint8 *data, reply; |
| 188 PurpleBuddy *b; |
184 PurpleBuddy *b; |
| 189 qq_buddy *q_bud; |
185 qq_buddy *q_bud; |
| 190 gchar *name; |
186 gchar *name; |
| 191 |
187 |
| 192 g_return_if_fail(buf != NULL && buf_len != 0); |
188 g_return_if_fail(buf != NULL && buf_len != 0); |
| 193 |
189 |
| 194 qd = (qq_data *) gc->proto_data; |
190 qd = (qq_data *) gc->proto_data; |
| 195 len = buf_len; |
191 len = buf_len; |
| 196 data = g_newa(guint8, len); |
192 data = g_newa(guint8, len); |
| 197 |
193 |
| 198 if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { |
194 if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { |
| 199 cursor = data; |
|
| 200 read_packet_b(data, &cursor, len, &reply); |
|
| 201 if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) { |
|
| 202 purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Change status fail\n"); |
|
| 203 } else { |
|
| 204 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Change status OK\n"); |
|
| 205 name = uid_to_purple_name(qd->uid); |
|
| 206 b = purple_find_buddy(gc->account, name); |
|
| 207 g_free(name); |
|
| 208 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; |
|
| 209 qq_update_buddy_contact(gc, q_bud); |
|
| 210 } |
|
| 211 } else { |
|
| 212 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n"); |
195 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n"); |
| |
196 return; |
| |
197 } |
| |
198 |
| |
199 bytes = 0; |
| |
200 bytes = qq_get8(&reply, data + bytes); |
| |
201 if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) { |
| |
202 purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Change status fail\n"); |
| |
203 } else { |
| |
204 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Change status OK\n"); |
| |
205 name = uid_to_purple_name(qd->uid); |
| |
206 b = purple_find_buddy(gc->account, name); |
| |
207 g_free(name); |
| |
208 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; |
| |
209 qq_update_buddy_contact(gc, q_bud); |
| 213 } |
210 } |
| 214 } |
211 } |
| 215 |
212 |
| 216 /* it is a server message indicating that one of my buddies has changed its status */ |
213 /* it is a server message indicating that one of my buddies has changed its status */ |
| 217 void qq_process_friend_change_status(guint8 *buf, gint buf_len, PurpleConnection *gc) |
214 void qq_process_friend_change_status(guint8 *buf, gint buf_len, PurpleConnection *gc) |
| 218 { |
215 { |
| 219 qq_data *qd; |
216 qq_data *qd; |
| 220 gint len, bytes; |
217 gint len, bytes; |
| 221 guint32 my_uid; |
218 guint32 my_uid; |
| 222 guint8 *data, *cursor; |
219 guint8 *data; |
| 223 PurpleBuddy *b; |
220 PurpleBuddy *b; |
| 224 qq_buddy *q_bud; |
221 qq_buddy *q_bud; |
| 225 qq_buddy_status *s; |
222 qq_buddy_status *s; |
| 226 gchar *name; |
223 gchar *name; |
| 227 |
224 |
| 228 g_return_if_fail(buf != NULL && buf_len != 0); |
225 g_return_if_fail(buf != NULL && buf_len != 0); |
| 229 |
226 |
| 230 qd = (qq_data *) gc->proto_data; |
227 qd = (qq_data *) gc->proto_data; |
| 231 len = buf_len; |
228 len = buf_len; |
| 232 data = g_newa(guint8, len); |
229 data = g_newa(guint8, len); |
| 233 cursor = data; |
230 |
| 234 |
231 if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { |
| 235 if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { |
232 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddy status change packet\n"); |
| 236 s = g_new0(qq_buddy_status, 1); |
233 return; |
| 237 bytes = 0; |
234 } |
| 238 /* 000-030: qq_buddy_status */ |
235 |
| 239 bytes += qq_buddy_status_read(data, &cursor, len, s); |
236 s = g_new0(qq_buddy_status, 1); |
| 240 /* 031-034: my uid */ |
237 bytes = 0; |
| 241 /* This has a value of 0 when we've changed our status to |
238 /* 000-030: qq_buddy_status */ |
| 242 * QQ_BUDDY_ONLINE_INVISIBLE */ |
239 bytes += qq_buddy_status_read(s, data + bytes); |
| 243 bytes += read_packet_dw(data, &cursor, len, &my_uid); |
240 /* 031-034: my uid */ |
| 244 |
241 /* This has a value of 0 when we've changed our status to |
| 245 if (bytes != 35) { |
242 * QQ_BUDDY_ONLINE_INVISIBLE */ |
| 246 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "bytes(%d) != 35\n", bytes); |
243 bytes += qq_get32(&my_uid, data + bytes); |
| 247 g_free(s->ip); |
244 |
| 248 g_free(s->unknown_key); |
245 if (bytes != 35) { |
| 249 g_free(s); |
246 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "bytes(%d) != 35\n", bytes); |
| 250 return; |
|
| 251 } |
|
| 252 |
|
| 253 name = uid_to_purple_name(s->uid); |
|
| 254 b = purple_find_buddy(gc->account, name); |
|
| 255 g_free(name); |
|
| 256 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; |
|
| 257 if (q_bud) { |
|
| 258 purple_debug(PURPLE_DEBUG_INFO, "QQ", "s->uid = %d, q_bud->uid = %d\n", s->uid , q_bud->uid); |
|
| 259 if(0 != *((guint32 *)s->ip)) { |
|
| 260 g_memmove(q_bud->ip, s->ip, 4); |
|
| 261 q_bud->port = s->port; |
|
| 262 } |
|
| 263 q_bud->status = s->status; |
|
| 264 if(0 != s->client_version) |
|
| 265 q_bud->client_version = s->client_version; |
|
| 266 if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL) |
|
| 267 qq_send_packet_get_level(gc, q_bud->uid); |
|
| 268 qq_update_buddy_contact(gc, q_bud); |
|
| 269 } else { |
|
| 270 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
|
| 271 "got information of unknown buddy %d\n", s->uid); |
|
| 272 } |
|
| 273 |
|
| 274 g_free(s->ip); |
247 g_free(s->ip); |
| 275 g_free(s->unknown_key); |
248 g_free(s->unknown_key); |
| 276 g_free(s); |
249 g_free(s); |
| 277 } else { |
250 return; |
| 278 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddy status change packet\n"); |
251 } |
| 279 } |
252 |
| 280 } |
253 name = uid_to_purple_name(s->uid); |
| |
254 b = purple_find_buddy(gc->account, name); |
| |
255 g_free(name); |
| |
256 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; |
| |
257 if (q_bud) { |
| |
258 purple_debug(PURPLE_DEBUG_INFO, "QQ", "s->uid = %d, q_bud->uid = %d\n", s->uid , q_bud->uid); |
| |
259 if(0 != *((guint32 *)s->ip)) { |
| |
260 g_memmove(q_bud->ip, s->ip, 4); |
| |
261 q_bud->port = s->port; |
| |
262 } |
| |
263 q_bud->status = s->status; |
| |
264 if(0 != s->client_version) { |
| |
265 q_bud->client_version = s->client_version; |
| |
266 } |
| |
267 if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL) { |
| |
268 qq_send_packet_get_level(gc, q_bud->uid); |
| |
269 } |
| |
270 qq_update_buddy_contact(gc, q_bud); |
| |
271 } else { |
| |
272 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
| |
273 "got information of unknown buddy %d\n", s->uid); |
| |
274 } |
| |
275 |
| |
276 g_free(s->ip); |
| |
277 g_free(s->unknown_key); |
| |
278 g_free(s); |
| |
279 } |