| 119 bytes_expected = qd->use_tcp ? QQ_TCP_HEADER_LENGTH : QQ_UDP_HEADER_LENGTH; |
118 bytes_expected = qd->use_tcp ? QQ_TCP_HEADER_LENGTH : QQ_UDP_HEADER_LENGTH; |
| 120 |
119 |
| 121 if (buf_len < bytes_expected) { |
120 if (buf_len < bytes_expected) { |
| 122 gchar *hex_dump = hex_dump_to_str(buf, buf_len); |
121 gchar *hex_dump = hex_dump_to_str(buf, buf_len); |
| 123 purple_debug(PURPLE_DEBUG_ERROR, |
122 purple_debug(PURPLE_DEBUG_ERROR, |
| 124 "QQ", "Received packet is too short, dump and drop\n%s", hex_dump); |
123 "QQ", "Received packet is too short, dump and drop\n%s", hex_dump); |
| 125 g_free(hex_dump); |
124 g_free(hex_dump); |
| 126 return; |
125 return; |
| 127 } |
126 } |
| |
127 |
| 128 /* initialize */ |
128 /* initialize */ |
| 129 cursor = buf; |
129 bytes = 0; |
| 130 bytes_read = 0; |
|
| 131 |
|
| 132 /* QQ TCP packet returns first 2 bytes the length of this packet */ |
130 /* QQ TCP packet returns first 2 bytes the length of this packet */ |
| 133 if (qd->use_tcp) { |
131 if (qd->use_tcp) { |
| 134 bytes_read += read_packet_w(buf, &cursor, buf_len, &buf_len_read); |
132 bytes += qq_get16(&buf_len_read, buf + bytes); |
| 135 if (buf_len_read != buf_len) { /* wrong */ |
133 if (buf_len_read != buf_len) { /* wrong */ |
| 136 purple_debug |
134 purple_debug |
| 137 (PURPLE_DEBUG_ERROR, |
135 (PURPLE_DEBUG_ERROR, |
| 138 "QQ", |
136 "QQ", |
| 139 "TCP read %d bytes, header says %d bytes, use header anyway\n", buf_len, buf_len_read); |
137 "TCP read %d bytes, header says %d bytes, use header anyway\n", buf_len, buf_len_read); |
| 140 buf_len = buf_len_read; /* we believe header is more accurate */ |
138 buf_len = buf_len_read; /* we believe header is more accurate */ |
| 141 } |
139 } |
| 142 } |
140 } |
| 143 |
141 |
| 144 /* now goes the normal QQ packet as UDP packet */ |
142 /* now goes the normal QQ packet as UDP packet */ |
| 145 bytes_read += read_packet_b(buf, &cursor, buf_len, &header.header_tag); |
143 bytes += qq_get8(&header.header_tag, buf + bytes); |
| 146 bytes_read += read_packet_w(buf, &cursor, buf_len, &header.source_tag); |
144 bytes += qq_get16(&header.source_tag, buf + bytes); |
| 147 bytes_read += read_packet_w(buf, &cursor, buf_len, &header.cmd); |
145 bytes += qq_get16(&header.cmd, buf + bytes); |
| 148 bytes_read += read_packet_w(buf, &cursor, buf_len, &header.seq); |
146 bytes += qq_get16(&header.seq, buf + bytes); |
| 149 |
147 |
| 150 if (bytes_read != bytes_expected) { /* read error */ |
148 if (bytes != bytes_expected) { /* read error */ |
| 151 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
149 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
| 152 "Fail reading packet header, expect %d bytes, read %d bytes\n", |
150 "Fail reading packet header, expect %d bytes, read %d bytes\n", |
| 153 bytes_expected, bytes_read); |
151 bytes_expected, bytes); |
| 154 return; |
152 return; |
| 155 } |
153 } |
| 156 |
154 |
| 157 if ((buf[buf_len - 1] != QQ_PACKET_TAIL) || (header.header_tag != QQ_PACKET_TAG)) { |
155 if ((buf[buf_len - 1] != QQ_PACKET_TAIL) || (header.header_tag != QQ_PACKET_TAG)) { |
| 158 gchar *hex_dump = hex_dump_to_str(buf, buf_len); |
156 gchar *hex_dump = hex_dump_to_str(buf, buf_len); |
| 159 purple_debug(PURPLE_DEBUG_ERROR, |
157 purple_debug(PURPLE_DEBUG_ERROR, |
| 160 "QQ", "Unknown QQ proctocol, dump and drop\n%s", hex_dump); |
158 "QQ", "Unknown QQ proctocol, dump and drop\n%s", hex_dump); |
| 161 g_free(hex_dump); |
159 g_free(hex_dump); |
| 162 return; |
160 return; |
| 163 } |
161 } |
| 164 |
162 |
| 165 if (QQ_DEBUG) |
163 if (QQ_DEBUG) |
| 166 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
164 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
| 167 "==> [%05d] %s, from (%s)\n", |
165 "==> [%05d] %s, from (%s)\n", |
| 168 header.seq, qq_get_cmd_desc(header.cmd), qq_get_source_str(header.source_tag)); |
166 header.seq, qq_get_cmd_desc(header.cmd), qq_get_source_str(header.source_tag)); |
| 169 |
167 |
| 170 if (header.cmd != QQ_CMD_LOGIN && header.cmd != QQ_CMD_REQUEST_LOGIN_TOKEN) { |
168 if (header.cmd != QQ_CMD_LOGIN && header.cmd != QQ_CMD_REQUEST_LOGIN_TOKEN) { |
| 171 if (!qd->logged_in) { /* packets before login */ |
169 if (!qd->logged_in) { /* packets before login */ |
| 172 b4_packet = g_new0(packet_before_login, 1); |
170 b4_packet = g_new0(packet_before_login, 1); |
| 173 /* must duplicate, buffer will be freed after exiting this function */ |
171 /* must duplicate, buffer will be freed after exiting this function */ |
| 178 g_queue_push_head(qd->before_login_packets, b4_packet); |
176 g_queue_push_head(qd->before_login_packets, b4_packet); |
| 179 return; /* do not process it now */ |
177 return; /* do not process it now */ |
| 180 } else if (!g_queue_is_empty(qd->before_login_packets)) { |
178 } else if (!g_queue_is_empty(qd->before_login_packets)) { |
| 181 /* logged_in, but we have packets before login */ |
179 /* logged_in, but we have packets before login */ |
| 182 b4_packet = (packet_before_login *) |
180 b4_packet = (packet_before_login *) |
| 183 g_queue_pop_head(qd->before_login_packets); |
181 g_queue_pop_head(qd->before_login_packets); |
| 184 _qq_packet_process(b4_packet->buf, b4_packet->len, gc); |
182 _qq_packet_process(b4_packet->buf, b4_packet->len, gc); |
| 185 /* in fact this is a recursive call, |
183 /* in fact this is a recursive call, |
| 186 * all packets before login will be processed before goes on */ |
184 * all packets before login will be processed before goes on */ |
| 187 g_free(b4_packet->buf); /* the buf is duplicated, need to be freed */ |
185 g_free(b4_packet->buf); /* the buf is duplicated, need to be freed */ |
| 188 g_free(b4_packet); |
186 g_free(b4_packet); |
| 189 } |
187 } |
| 190 } |
188 } |
| 191 |
189 |
| 192 /* this is the length of all the encrypted data (also remove tail tag */ |
190 /* this is the length of all the encrypted data (also remove tail tag */ |
| 193 len = buf_len - (bytes_read) - 1; |
191 bytes_notread = buf_len - bytes - 1; |
| 194 |
192 |
| 195 /* whether it is an ack */ |
193 /* whether it is an ack */ |
| 196 switch (header.cmd) { |
194 switch (header.cmd) { |
| 197 case QQ_CMD_RECV_IM: |
195 case QQ_CMD_RECV_IM: |
| 198 case QQ_CMD_RECV_MSG_SYS: |
196 case QQ_CMD_RECV_MSG_SYS: |
| 199 case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: |
197 case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: |
| 200 /* server intiated packet, we need to send ack and check duplicaion |
198 /* server intiated packet, we need to send ack and check duplicaion |
| 201 * this must be put after processing b4_packet |
199 * this must be put after processing b4_packet |
| 202 * as these packets will be passed in twice */ |
200 * as these packets will be passed in twice */ |
| 203 if (_qq_check_packet_set_window(header.seq, gc)) { |
201 if (_qq_check_packet_set_window(header.seq, gc)) { |
| 204 purple_debug(PURPLE_DEBUG_WARNING, |
202 purple_debug(PURPLE_DEBUG_WARNING, |
| 205 "QQ", "dup [%05d] %s, discard...\n", header.seq, qq_get_cmd_desc(header.cmd)); |
203 "QQ", "dup [%05d] %s, discard...\n", header.seq, qq_get_cmd_desc(header.cmd)); |
| 206 return; |
204 return; |
| 207 } |
205 } |
| 208 break; |
206 break; |
| 209 default:{ /* ack packet, we need to update sendqueue */ |
207 default:{ /* ack packet, we need to update sendqueue */ |
| 210 /* we do not check duplication for server ack */ |
208 /* we do not check duplication for server ack */ |
| 211 qq_sendqueue_remove(qd, header.seq); |
209 qq_sendqueue_remove(qd, header.seq); |
| 212 if (QQ_DEBUG) |
210 if (QQ_DEBUG) |
| 213 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
211 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
| 214 "ack [%05d] %s, remove from sendqueue\n", |
212 "ack [%05d] %s, remove from sendqueue\n", |
| 215 header.seq, qq_get_cmd_desc(header.cmd)); |
213 header.seq, qq_get_cmd_desc(header.cmd)); |
| 216 } |
214 } |
| 217 } |
215 } |
| 218 |
216 |
| 219 /* now process the packet */ |
217 /* now process the packet */ |
| 220 switch (header.cmd) { |
218 switch (header.cmd) { |
| 221 case QQ_CMD_KEEP_ALIVE: |
219 case QQ_CMD_KEEP_ALIVE: |
| 222 qq_process_keep_alive_reply(cursor, len, gc); |
220 qq_process_keep_alive_reply(buf + bytes, bytes_notread, gc); |
| 223 break; |
221 break; |
| 224 case QQ_CMD_UPDATE_INFO: |
222 case QQ_CMD_UPDATE_INFO: |
| 225 qq_process_modify_info_reply(cursor, len, gc); |
223 qq_process_modify_info_reply(buf + bytes, bytes_notread, gc); |
| 226 break; |
224 break; |
| 227 case QQ_CMD_ADD_FRIEND_WO_AUTH: |
225 case QQ_CMD_ADD_FRIEND_WO_AUTH: |
| 228 qq_process_add_buddy_reply(cursor, len, header.seq, gc); |
226 qq_process_add_buddy_reply(buf + bytes, bytes_notread, header.seq, gc); |
| 229 break; |
227 break; |
| 230 case QQ_CMD_DEL_FRIEND: |
228 case QQ_CMD_DEL_FRIEND: |
| 231 qq_process_remove_buddy_reply(cursor, len, gc); |
229 qq_process_remove_buddy_reply(buf + bytes, bytes_notread, gc); |
| 232 break; |
230 break; |
| 233 case QQ_CMD_REMOVE_SELF: |
231 case QQ_CMD_REMOVE_SELF: |
| 234 qq_process_remove_self_reply(cursor, len, gc); |
232 qq_process_remove_self_reply(buf + bytes, bytes_notread, gc); |
| 235 break; |
233 break; |
| 236 case QQ_CMD_BUDDY_AUTH: |
234 case QQ_CMD_BUDDY_AUTH: |
| 237 qq_process_add_buddy_auth_reply(cursor, len, gc); |
235 qq_process_add_buddy_auth_reply(buf + bytes, bytes_notread, gc); |
| 238 break; |
236 break; |
| 239 case QQ_CMD_GET_USER_INFO: |
237 case QQ_CMD_GET_USER_INFO: |
| 240 qq_process_get_info_reply(cursor, len, gc); |
238 qq_process_get_info_reply(buf + bytes, bytes_notread, gc); |
| 241 break; |
239 break; |
| 242 case QQ_CMD_CHANGE_ONLINE_STATUS: |
240 case QQ_CMD_CHANGE_ONLINE_STATUS: |
| 243 qq_process_change_status_reply(cursor, len, gc); |
241 qq_process_change_status_reply(buf + bytes, bytes_notread, gc); |
| 244 break; |
242 break; |
| 245 case QQ_CMD_SEND_IM: |
243 case QQ_CMD_SEND_IM: |
| 246 qq_process_send_im_reply(cursor, len, gc); |
244 qq_process_send_im_reply(buf + bytes, bytes_notread, gc); |
| 247 break; |
245 break; |
| 248 case QQ_CMD_RECV_IM: |
246 case QQ_CMD_RECV_IM: |
| 249 qq_process_recv_im(cursor, len, header.seq, gc); |
247 qq_process_recv_im(buf + bytes, bytes_notread, header.seq, gc); |
| 250 break; |
248 break; |
| 251 case QQ_CMD_LOGIN: |
249 case QQ_CMD_LOGIN: |
| 252 qq_process_login_reply(cursor, len, gc); |
250 qq_process_login_reply(buf + bytes, bytes_notread, gc); |
| 253 break; |
251 break; |
| 254 case QQ_CMD_GET_FRIENDS_LIST: |
252 case QQ_CMD_GET_FRIENDS_LIST: |
| 255 qq_process_get_buddies_list_reply(cursor, len, gc); |
253 qq_process_get_buddies_list_reply(buf + bytes, bytes_notread, gc); |
| 256 break; |
254 break; |
| 257 case QQ_CMD_GET_FRIENDS_ONLINE: |
255 case QQ_CMD_GET_FRIENDS_ONLINE: |
| 258 qq_process_get_buddies_online_reply(cursor, len, gc); |
256 qq_process_get_buddies_online_reply(buf + bytes, bytes_notread, gc); |
| 259 break; |
257 break; |
| 260 case QQ_CMD_GROUP_CMD: |
258 case QQ_CMD_GROUP_CMD: |
| 261 qq_process_group_cmd_reply(cursor, len, header.seq, gc); |
259 qq_process_group_cmd_reply(buf + bytes, bytes_notread, header.seq, gc); |
| 262 break; |
260 break; |
| 263 case QQ_CMD_GET_ALL_LIST_WITH_GROUP: |
261 case QQ_CMD_GET_ALL_LIST_WITH_GROUP: |
| 264 qq_process_get_all_list_with_group_reply(cursor, len, gc); |
262 qq_process_get_all_list_with_group_reply(buf + bytes, bytes_notread, gc); |
| 265 break; |
263 break; |
| 266 case QQ_CMD_GET_LEVEL: |
264 case QQ_CMD_GET_LEVEL: |
| 267 qq_process_get_level_reply(cursor, len, gc); |
265 qq_process_get_level_reply(buf + bytes, bytes_notread, gc); |
| 268 break; |
266 break; |
| 269 case QQ_CMD_REQUEST_LOGIN_TOKEN: |
267 case QQ_CMD_REQUEST_LOGIN_TOKEN: |
| 270 qq_process_request_login_token_reply(cursor, len, gc); |
268 qq_process_request_login_token_reply(buf + bytes, bytes_notread, gc); |
| 271 break; |
269 break; |
| 272 case QQ_CMD_RECV_MSG_SYS: |
270 case QQ_CMD_RECV_MSG_SYS: |
| 273 qq_process_msg_sys(cursor, len, header.seq, gc); |
271 qq_process_msg_sys(buf + bytes, bytes_notread, header.seq, gc); |
| 274 break; |
272 break; |
| 275 case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: |
273 case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: |
| 276 qq_process_friend_change_status(cursor, len, gc); |
274 qq_process_friend_change_status(buf + bytes, bytes_notread, gc); |
| 277 break; |
275 break; |
| 278 default: |
276 default: |
| 279 _qq_process_packet_default(cursor, len, header.cmd, header.seq, gc); |
277 _qq_process_packet_default(buf + bytes, bytes_notread, header.cmd, header.seq, gc); |
| 280 break; |
278 break; |
| 281 } |
279 } |
| 282 } |
280 } |
| 283 |
281 |
| 284 /* clean up the packets before login */ |
282 /* clean up the packets before login */ |
| 285 void qq_b4_packets_free(qq_data *qd) |
283 void qq_b4_packets_free(qq_data *qd) |