comparison libpurple/protocols/qq/group_im.c @ 24640:2cfdcaf6b5f3

Support long qun im
author Hu Yong <ccpaging@gmail.com>
date Wed, 19 Nov 2008 08:31:45 +0000
parents 2df8b8f3c3f6
children 2df1d0449ba6
comparison
equal deleted inserted replaced
24639:9f2149adcac2 24640:2cfdcaf6b5f3
203 /* recv an IM from a group chat */ 203 /* recv an IM from a group chat */
204 void qq_process_room_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type) 204 void qq_process_room_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type)
205 { 205 {
206 qq_data *qd; 206 qq_data *qd;
207 gchar *msg_smiley, *msg_fmt, *msg_utf8; 207 gchar *msg_smiley, *msg_fmt, *msg_utf8;
208 gint skip_len; 208 gint bytes, tail_len;
209 gint bytes ;
210 struct { 209 struct {
211 guint32 ext_id; 210 guint32 ext_id;
212 guint8 type8; 211 guint8 type8;
213 guint32 member_uid; 212 guint32 member_uid;
214 guint16 unknown; 213 guint16 unknown;
215 guint16 msg_seq; 214 guint16 msg_seq;
216 time_t send_time; 215 time_t send_time;
217 guint32 unknown4; 216 guint32 version;
218 guint16 msg_len; 217 guint16 msg_len;
219 gchar *msg; 218 gchar *msg;
220 guint8 *font_attr;
221 gint font_attr_len;
222 } im_text; 219 } im_text;
223 220 guint32 temp_id;
224 g_return_if_fail(data != NULL && data_len > 0); 221 guint16 content_type;
225 222 guint8 frag_count, frag_index;
226 /* FIXME: check length here */ 223 guint16 msg_id;
227 224 qq_im_format *fmt = NULL;
225
226 /* at least include im_text.msg_len */
227 g_return_if_fail(data != NULL && data_len > 23);
228 qd = (qq_data *) gc->proto_data; 228 qd = (qq_data *) gc->proto_data;
229 229
230 /* qq_show_packet("ROOM_IM", data, data_len); */ 230 /* qq_show_packet("ROOM_IM", data, data_len); */
231
232 memset(&im_text, 0, sizeof(im_text)); 231 memset(&im_text, 0, sizeof(im_text));
233 bytes = 0; 232 bytes = 0;
234 bytes += qq_get32(&(im_text.ext_id), data + bytes); 233 bytes += qq_get32(&(im_text.ext_id), data + bytes);
235 bytes += qq_get8(&(im_text.type8), data + bytes); 234 bytes += qq_get8(&(im_text.type8), data + bytes);
236 235
237 if(QQ_MSG_TEMP_QUN_IM == msg_type) { 236 if(QQ_MSG_TEMP_QUN_IM == msg_type) {
238 bytes += qq_get32(&(id), data + bytes); 237 bytes += qq_get32(&temp_id, data + bytes);
239 } 238 }
240 239
241 bytes += qq_get32(&(im_text.member_uid), bytes + data); 240 bytes += qq_get32(&(im_text.member_uid), bytes + data);
242 bytes += qq_get16(&im_text.unknown, data + bytes); /* 0x0001? */ 241 bytes += qq_get16(&im_text.unknown, data + bytes); /* 0x0001? */
243 bytes += qq_get16(&(im_text.msg_seq), data + bytes); 242 bytes += qq_get16(&(im_text.msg_seq), data + bytes);
244 bytes += qq_getime(&im_text.send_time, data + bytes); 243 bytes += qq_getime(&im_text.send_time, data + bytes);
245 bytes += qq_get32(&im_text.unknown4, data + bytes); /* versionID */ 244 bytes += qq_get32(&im_text.version, data + bytes);
246 /*
247 * length includes font_attr
248 * this msg_len includes msg and font_attr
249 **** the format is ****
250 * length of all
251 * 1. unknown 10 bytes
252 * 2. 0-ended string
253 * 3. font_attr
254 */
255
256 bytes += qq_get16(&(im_text.msg_len), data + bytes); 245 bytes += qq_get16(&(im_text.msg_len), data + bytes);
246 purple_debug_info("QQ", "Room IM, ext id %u, seq %u, version 0x%04X, len %u\n",
247 im_text.ext_id, im_text.msg_seq, im_text.version, im_text.msg_len);
248
249 if (im_text.msg_len != data_len - bytes) {
250 purple_debug_warning("QQ", "Room IM length %d should be %d\n",
251 im_text.msg_len, data_len - bytes);
252 im_text.msg_len = data_len - bytes;
253 }
254
255 g_return_if_fail(im_text.msg_len > 0 && bytes + im_text.msg_len <= data_len);
256 if(msg_type != QQ_MSG_QUN_IM_UNKNOWN) {
257 g_return_if_fail(im_text.msg_len >= 10);
258
259 bytes += qq_get16(&content_type, data + bytes);
260 bytes += qq_get8(&frag_count, data + bytes);
261 bytes += qq_get8(&frag_index, data + bytes);
262 bytes += qq_get16(&msg_id, data + bytes);
263 bytes += 4; /* skip 0x(00 00 00 00) */
264 purple_debug_info("QQ", "Room IM, content %d, frag %d-%d, msg id %u\n",
265 content_type, frag_count, frag_index, msg_id);
266 im_text.msg_len -= 10;
267 }
257 g_return_if_fail(im_text.msg_len > 0); 268 g_return_if_fail(im_text.msg_len > 0);
258 /*
259 * 10 bytes from lumaqq
260 * contentType = buf.getChar();
261 * totalFragments = buf.get() & 255;
262 * fragmentSequence = buf.get() & 255;
263 * messageId = buf.getChar();
264 * buf.getInt();
265 */
266
267 if(msg_type != QQ_MSG_UNKNOWN_QUN_IM)
268 skip_len = 10;
269 else
270 skip_len = 0;
271 bytes += skip_len;
272 269
273 /* qq_show_packet("Message", data + bytes, data_len - bytes); */ 270 /* qq_show_packet("Message", data + bytes, data_len - bytes); */
274 271 if (frag_count <= 1 || frag_count == frag_index + 1) {
275 im_text.msg = g_strdup((gchar *) data + bytes); 272 fmt = qq_im_fmt_new();
276 bytes += strlen(im_text.msg) + 1; 273 tail_len = qq_get_im_tail(fmt, data + bytes, data_len - bytes);
277 /* there might not be any font_attr, check it */ 274 im_text.msg = g_strndup((gchar *)(data + bytes), data_len - tail_len);
278 im_text.font_attr_len = data_len - bytes;
279 if (im_text.font_attr_len > 0) {
280 im_text.font_attr = g_memdup(data + bytes, im_text.font_attr_len);
281 /* qq_show_packet("font_attr", packet.font_attr, packet.font_attr_len); */
282 } else { 275 } else {
283 im_text.font_attr = NULL; 276 im_text.msg = g_strndup((gchar *)(data + bytes), data_len - bytes);
284 } 277 }
285 278
286 /* group im_group has no flag to indicate whether it has font_attr or not */ 279 /* group im_group has no flag to indicate whether it has font_attr or not */
287 msg_smiley = qq_emoticon_to_purple(im_text.msg); 280 msg_smiley = qq_emoticon_to_purple(im_text.msg);
288 if (im_text.font_attr != NULL) { 281 if (fmt != NULL) {
289 msg_fmt = qq_format_to_purple(im_text.font_attr, im_text.font_attr_len, 282 msg_fmt = qq_im_fmt_to_purple(fmt, msg_smiley);
290 msg_smiley);
291 msg_utf8 = qq_to_utf8(msg_fmt, QQ_CHARSET_DEFAULT); 283 msg_utf8 = qq_to_utf8(msg_fmt, QQ_CHARSET_DEFAULT);
292 g_free(msg_fmt); 284 g_free(msg_fmt);
285 qq_im_fmt_free(fmt);
293 } else { 286 } else {
294 msg_utf8 = qq_to_utf8(msg_smiley, QQ_CHARSET_DEFAULT); 287 msg_utf8 = qq_to_utf8(msg_smiley, QQ_CHARSET_DEFAULT);
295 } 288 }
296 g_free(msg_smiley); 289 g_free(msg_smiley);
297 290
298 291 purple_debug_info("QQ", "Room (%u) IM from %u: %s\n",
292 im_text.ext_id, im_text.member_uid, msg_utf8);
299 qq_room_got_chat_in(gc, id, im_text.member_uid, msg_utf8, im_text.send_time); 293 qq_room_got_chat_in(gc, id, im_text.member_uid, msg_utf8, im_text.send_time);
300 294
301 g_free(msg_utf8); 295 g_free(msg_utf8);
302 g_free(im_text.msg); 296 g_free(im_text.msg);
303 if (im_text.font_attr) g_free(im_text.font_attr);
304 } 297 }
305 298
306 /* send IM to a group */ 299 /* send IM to a group */
307 static void request_room_send_im(PurpleConnection *gc, guint32 room_id, qq_im_format *fmt, const gchar *msg) 300 static void request_room_send_im(PurpleConnection *gc, guint32 room_id, qq_im_format *fmt, const gchar *msg)
308 { 301 {
312 g_return_if_fail(room_id != 0 && msg != NULL); 305 g_return_if_fail(room_id != 0 && msg != NULL);
313 306
314 bytes = 0; 307 bytes = 0;
315 bytes += qq_put16(raw_data + bytes, 0); 308 bytes += qq_put16(raw_data + bytes, 0);
316 bytes += qq_putdata(raw_data + bytes, (guint8 *)msg, strlen(msg)); 309 bytes += qq_putdata(raw_data + bytes, (guint8 *)msg, strlen(msg));
317 bytes += qq_put8(raw_data + bytes, 0);
318 bytes += qq_put_im_tail(raw_data + bytes, fmt); 310 bytes += qq_put_im_tail(raw_data + bytes, fmt);
311 bytes += qq_put32(raw_data + bytes, 0); /* unknown 4 bytes */
319 312
320 /* reset first two bytes */ 313 /* reset first two bytes */
321 qq_put16(raw_data, bytes - 2); 314 qq_put16(raw_data, bytes - 2);
322 315
323 qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_MSG, room_id, raw_data, bytes); 316 qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_IM, room_id, raw_data, bytes);
324 } 317 }
325 318
326 /* this is the ACK */ 319 /* this is the ACK */
327 void qq_process_room_send_im(PurpleConnection *gc, guint8 *data, gint len) 320 void qq_process_room_send_im(PurpleConnection *gc, guint8 *data, gint len)
328 { 321 {
329 /* return should be the internal group id 322 /* return should be the internal group id
330 * but we have nothing to do with it */ 323 * but we have nothing to do with it */
331 return; 324 return;
325 }
326
327 void qq_process_room_send_im_ex(PurpleConnection *gc, guint8 *data, gint len)
328 {
329 /* return should be the internal group id
330 * but we have nothing to do with it */
331 return;
332 }
333
334 static void request_room_send_im_ex(PurpleConnection *gc, guint32 room_id,
335 qq_im_format *fmt, gchar *msg, guint16 msg_id, guint8 frag_count, guint8 frag_index)
336 {
337 guint8 raw_data[MAX_PACKET_SIZE - 16];
338 gint bytes;
339
340
341 g_return_if_fail(room_id != 0 && msg != NULL);
342
343 bytes = 0;
344 bytes += qq_put16(raw_data + bytes, 0); /* packet len */
345 /* type 0x0001, text only; 0x0002, with custom emoticon */
346 bytes += qq_put16(raw_data + bytes, 0x0001);
347 bytes += qq_put8(raw_data + bytes, frag_count);
348 bytes += qq_put8(raw_data + bytes, frag_index);
349 bytes += qq_put16(raw_data + bytes, msg_id);
350 bytes += qq_put32(raw_data + bytes, 0); /* unknow 4 bytes */
351 bytes += qq_putdata(raw_data + bytes, (guint8 *)msg, strlen(msg));
352 if (frag_count == frag_index + 1) {
353 bytes += qq_put8(raw_data + bytes, 0x20); /* add extra SPACE */
354 bytes += qq_put_im_tail(raw_data + bytes, fmt);
355 }
356
357 /* reset first two bytes as length */
358 qq_put16(raw_data, bytes - 2);
359
360 /*qq_show_packet("QQ_ROOM_CMD_SEND_IM_EX", raw_data, bytes); */
361 qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_IM_EX, room_id, raw_data, bytes);
332 } 362 }
333 363
334 /* send a chat msg to a QQ Qun 364 /* send a chat msg to a QQ Qun
335 * called by purple */ 365 * called by purple */
336 int qq_chat_send(PurpleConnection *gc, int id, const char *what, PurpleMessageFlags flags) 366 int qq_chat_send(PurpleConnection *gc, int id, const char *what, PurpleMessageFlags flags)
340 gchar *msg_stripped, *tmp; 370 gchar *msg_stripped, *tmp;
341 GSList *segments, *it; 371 GSList *segments, *it;
342 gint msg_len; 372 gint msg_len;
343 const gchar *start_invalid; 373 const gchar *start_invalid;
344 gboolean is_smiley_none; 374 gboolean is_smiley_none;
375 guint8 frag_count, frag_index;
345 376
346 g_return_val_if_fail(NULL != gc && NULL != gc->proto_data, -1); 377 g_return_val_if_fail(NULL != gc && NULL != gc->proto_data, -1);
347 g_return_val_if_fail(id != 0 && what != NULL, -1); 378 g_return_val_if_fail(id != 0 && what != NULL, -1);
348 379
349 qd = (qq_data *) gc->proto_data; 380 qd = (qq_data *) gc->proto_data;
378 409
379 if (segments == NULL) { 410 if (segments == NULL) {
380 return -1; 411 return -1;
381 } 412 }
382 413
414 qd->send_im_id++;
383 fmt = qq_im_fmt_new_by_purple(what); 415 fmt = qq_im_fmt_new_by_purple(what);
384 for (it = segments; it; it = it->next) { 416 frag_count = g_slist_length(segments);
385 request_room_send_im(gc, id, fmt, (gchar *)it->data); 417 frag_index = 0;
386 g_free(it->data); 418 /*
387 } 419 if (frag_count <= 1) {
420 */
421 for (it = segments; it; it = it->next) {
422 request_room_send_im(gc, id, fmt, (gchar *)it->data);
423 g_free(it->data);
424 }
425 /*
426 } else {
427 for (it = segments; it; it = it->next) {
428 request_room_send_im_ex(gc, id, fmt, (gchar *)it->data,
429 qd->send_im_id, frag_count, frag_index);
430 g_free(it->data);
431 frag_index++;
432 }
433 }
434 */
388 qq_im_fmt_free(fmt); 435 qq_im_fmt_free(fmt);
389 g_slist_free(segments); 436 g_slist_free(segments);
390 return 1; 437 return 1;
391 } 438 }