Mercurial > pidgin
diff libpurple/protocols/qq/buddy_list.c @ 24148:1bdf7b602684
2008.10.07 - ccpaging <ccpaging(at)gmail.com>
* Update qun conversation
* Drop group_conv.c and group_conv.h
author | SHiNE CsyFeK <csyfek@gmail.com> |
---|---|
date | Wed, 22 Oct 2008 14:58:32 +0000 |
parents | ce94189f15ad |
children | 818ab62006f5 |
line wrap: on
line diff
--- a/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:55:09 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:58:32 2008 +0000 @@ -82,7 +82,7 @@ /* position starts with 0x0000, * server may return a position tag if list is too long for one packet */ -void qq_request_get_buddies_list(PurpleConnection *gc, guint16 position, gint update_class) +void qq_request_get_buddies(PurpleConnection *gc, guint16 position, gint update_class) { qq_data *qd; guint8 raw_data[16] = {0}; @@ -158,16 +158,24 @@ } /* process the reply packet for get_buddies_online packet */ -guint8 qq_process_get_buddies_online_reply(guint8 *data, gint data_len, PurpleConnection *gc) +guint8 qq_process_get_buddies_online(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gint bytes, bytes_start; gint count; guint8 position; qq_buddy *buddy; - qq_buddy_online bo; int entry_len = 38; + qq_buddy_status bs; + struct { + guint16 unknown1; + guint8 ext_flag; + guint8 comm_flag; + guint16 unknown2; + guint8 ending; /* 0x00 */ + } packet; + g_return_val_if_fail(data != NULL && data_len != 0, -1); qd = (qq_data *) gc->proto_data; @@ -185,41 +193,42 @@ (data_len - bytes), entry_len); break; } - memset(&bo, 0 ,sizeof(bo)); + memset(&bs, 0 ,sizeof(bs)); + memset(&packet, 0 ,sizeof(packet)); /* set flag */ bytes_start = bytes; /* based on one online buddy entry */ /* 000-030 qq_buddy_status */ - bytes += get_buddy_status(&(bo.bs), data + bytes); + bytes += get_buddy_status(&bs, data + bytes); /* 031-032: */ - bytes += qq_get16(&bo.unknown1, data + bytes); + bytes += qq_get16(&packet.unknown1, data + bytes); /* 033-033: ext_flag */ - bytes += qq_get8(&bo.ext_flag, data + bytes); + bytes += qq_get8(&packet.ext_flag, data + bytes); /* 034-034: comm_flag */ - bytes += qq_get8(&bo.comm_flag, data + bytes); + bytes += qq_get8(&packet.comm_flag, data + bytes); /* 035-036: */ - bytes += qq_get16(&bo.unknown2, data + bytes); + bytes += qq_get16(&packet.unknown2, data + bytes); /* 037-037: */ - bytes += qq_get8(&bo.ending, data + bytes); /* 0x00 */ + bytes += qq_get8(&packet.ending, data + bytes); /* 0x00 */ /* skip 4 bytes in qq2007 */ if (qd->client_version >= 2007) bytes += 4; - if (bo.bs.uid == 0 || (bytes - bytes_start) != entry_len) { + if (bs.uid == 0 || (bytes - bytes_start) != entry_len) { purple_debug_error("QQ", "uid=0 or entry complete len(%d) != %d", (bytes - bytes_start), entry_len); continue; } /* check if it is a valid entry */ - if (bo.bs.uid == qd->uid) { - purple_debug_warning("QQ", "I am in online list %d\n", bo.bs.uid); + if (bs.uid == qd->uid) { + purple_debug_warning("QQ", "I am in online list %d\n", bs.uid); } /* update buddy information */ - buddy = qq_get_buddy(gc, bo.bs.uid); + buddy = qq_buddy_find(gc, bs.uid); if (buddy == NULL) { purple_debug_error("QQ", - "Got an online buddy %d, but not in my buddy list\n", bo.bs.uid); + "Got an online buddy %d, but not in my buddy list\n", bs.uid); continue; } /* we find one and update qq_buddy */ @@ -227,18 +236,18 @@ if(0 != fe->s->client_tag) q_bud->client_tag = fe->s->client_tag; */ - buddy->ip.s_addr = bo.bs.ip.s_addr; - buddy->port = bo.bs.port; - buddy->status = bo.bs.status; - buddy->ext_flag = bo.ext_flag; - buddy->comm_flag = bo.comm_flag; - qq_update_buddy_contact(gc, buddy); + buddy->ip.s_addr = bs.ip.s_addr; + buddy->port = bs.port; + buddy->status = bs.status; + buddy->ext_flag = packet.ext_flag; + buddy->comm_flag = packet.comm_flag; + qq_update_buddy_status(gc, bs.uid, bs.status, packet.comm_flag); count++; } if(bytes > data_len) { purple_debug_error("QQ", - "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); + "qq_process_get_buddies_online: Dangerous error! maybe protocol changed, notify developers!\n"); } purple_debug_info("QQ", "Received %d online buddies, nextposition=%u\n", @@ -248,16 +257,15 @@ /* process reply for get_buddies_list */ -guint16 qq_process_get_buddies_list_reply(guint8 *data, gint data_len, PurpleConnection *gc) +guint16 qq_process_get_buddies(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - qq_buddy *buddy; + qq_buddy bd; gint bytes_expected, count; gint bytes, buddy_bytes; gint nickname_len; guint16 position, unknown; - gchar *purple_name; - PurpleBuddy *purple_buddy; + PurpleBuddy *buddy; g_return_val_if_fail(data != NULL && data_len != 0, -1); @@ -273,26 +281,26 @@ /* the following data is buddy list in this packet */ count = 0; while (bytes < data_len) { - buddy = g_new0(qq_buddy, 1); + memset(&bd, 0, sizeof(bd)); /* set flag */ buddy_bytes = bytes; /* 000-003: uid */ - bytes += qq_get32(&buddy->uid, data + bytes); + bytes += qq_get32(&bd.uid, data + bytes); /* 004-005: icon index (1-255) */ - bytes += qq_get16(&buddy->face, data + bytes); + bytes += qq_get16(&bd.face, data + bytes); /* 006-006: age */ - bytes += qq_get8(&buddy->age, data + bytes); + bytes += qq_get8(&bd.age, data + bytes); /* 007-007: gender */ - bytes += qq_get8(&buddy->gender, data + bytes); + bytes += qq_get8(&bd.gender, data + bytes); - nickname_len = qq_get_vstr(&buddy->nickname, QQ_CHARSET_DEFAULT, data + bytes); + nickname_len = qq_get_vstr(&bd.nickname, QQ_CHARSET_DEFAULT, data + bytes); bytes += nickname_len; - qq_filter_str(buddy->nickname); + qq_filter_str(bd.nickname); /* Fixme: merge following as 32bit flag */ bytes += qq_get16(&unknown, data + bytes); - bytes += qq_get8(&buddy->ext_flag, data + bytes); - bytes += qq_get8(&buddy->comm_flag, data + bytes); + bytes += qq_get8(&bd.ext_flag, data + bytes); + bytes += qq_get8(&bd.comm_flag, data + bytes); if (qd->client_version >= 2007) { bytes += 4; /* skip 4 bytes */ @@ -301,11 +309,10 @@ bytes_expected = 12 + nickname_len; } - if (buddy->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { + if (bd.uid == 0 || (bytes - buddy_bytes) != bytes_expected) { purple_debug_info("QQ", "Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes - buddy_bytes); - g_free(buddy->nickname); - g_free(buddy); + g_free(bd.nickname); continue; } else { count++; @@ -313,25 +320,27 @@ #if 1 purple_debug_info("QQ", "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", - buddy->uid, buddy->ext_flag, buddy->comm_flag, buddy->nickname); + bd.uid, bd.ext_flag, bd.comm_flag, bd.nickname); #endif - purple_name = uid_to_purple_name(buddy->uid); - purple_buddy = purple_find_buddy(gc->account, purple_name); - g_free(purple_name); + buddy = qq_buddy_find_or_new(gc, bd.uid); + if (buddy == NULL || buddy->proto_data == NULL) { + g_free(bd.nickname); + continue; + } + bd.last_update = time(NULL); + purple_blist_server_alias_buddy(buddy, bd.nickname); + qq_update_buddy_status(gc, bd.uid, bd.status, bd.comm_flag); - if (purple_buddy == NULL) { - purple_buddy = qq_create_buddy(gc, buddy->uid, TRUE, FALSE); - } - - purple_buddy->proto_data = buddy; - qd->buddies = g_list_append(qd->buddies, buddy); - qq_update_buddy_contact(gc, buddy); + g_memmove(buddy->proto_data, &bd, sizeof(qq_buddy)); + /* nickname has been copy to buddy_data do not free + g_free(bd.nickname); + */ } if(bytes > data_len) { purple_debug_error("QQ", - "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); + "qq_process_get_buddies: Dangerous error! maybe protocol changed, notify developers!"); } purple_debug_info("QQ", "Received %d buddies, nextposition=%u\n", @@ -385,7 +394,7 @@ } if(0x1 == type) { /* a buddy */ /* don't do anything but count - buddies are handled by - * qq_request_get_buddies_list */ + * qq_request_get_buddies */ ++i; } else { /* a group */ group = qq_room_search_id(gc, uid); @@ -421,21 +430,6 @@ * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy, * using different accounts to get info. */ -/* check if status means online or offline */ -gboolean is_online(guint8 status) -{ - switch(status) { - case QQ_BUDDY_ONLINE_NORMAL: - case QQ_BUDDY_ONLINE_AWAY: - case QQ_BUDDY_ONLINE_INVISIBLE: - case QQ_BUDDY_ONLINE_BUSY: - return TRUE; - case QQ_BUDDY_CHANGE_TO_OFFLINE: - return FALSE; - } - return FALSE; -} - /* Help calculate the correct icon index to tell the server. */ gint get_icon_offset(PurpleConnection *gc) { @@ -515,7 +509,7 @@ } /* parse the reply packet for change_status */ -void qq_process_change_status_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_change_status(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gint bytes; @@ -534,7 +528,7 @@ } /* purple_debug_info("QQ", "Change status OK\n"); */ - buddy = qq_get_buddy(gc, qd->uid); + buddy = qq_buddy_find(gc, qd->uid); if (buddy != NULL) { qq_update_buddy_contact(gc, buddy); } @@ -567,7 +561,7 @@ * QQ_BUDDY_ONLINE_INVISIBLE */ bytes += qq_get32(&my_uid, data + bytes); - buddy = qq_get_buddy(gc, bs.uid); + buddy = qq_buddy_find(gc, bs.uid); if (buddy == NULL) { purple_debug_warning("QQ", "Get status of unknown buddy %d\n", bs.uid); return; @@ -590,6 +584,55 @@ } /*TODO: maybe this should be qq_update_buddy_status() ?*/ +void qq_update_buddy_status(PurpleConnection *gc, guint32 uid, guint8 status, guint8 flag) +{ + gchar *who; + gchar *status_id; + + g_return_if_fail(uid != 0); + + who = uid_to_purple_name(uid); + + /* purple supports signon and idle time + * but it is not much use for QQ, I do not use them */ + /* serv_got_update(gc, name, online, 0, q_bud->signon, q_bud->idle, bud->uc); */ + status_id = "available"; + switch(status) { + case QQ_BUDDY_OFFLINE: + status_id = "offline"; + break; + case QQ_BUDDY_ONLINE_NORMAL: + status_id = "available"; + break; + case QQ_BUDDY_CHANGE_TO_OFFLINE: + status_id = "offline"; + break; + case QQ_BUDDY_ONLINE_AWAY: + status_id = "away"; + break; + case QQ_BUDDY_ONLINE_INVISIBLE: + status_id = "invisible"; + break; + case QQ_BUDDY_ONLINE_BUSY: + status_id = "busy"; + break; + default: + status_id = "invisible"; + purple_debug_error("QQ", "unknown status: %x\n", status); + break; + } + purple_debug_info("QQ", "Update buddy %s status as %s\n", who, status_id); + purple_prpl_got_user_status(gc->account, who, status_id, NULL); + + if (flag & QQ_COMM_FLAG_MOBILE && status != QQ_BUDDY_OFFLINE) + purple_prpl_got_user_status(gc->account, who, "mobile", NULL); + else + purple_prpl_got_user_status_deactive(gc->account, who, "mobile"); + + g_free(who); +} + +/*TODO: maybe this should be qq_update_buddy_status() ?*/ void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *buddy) { gchar *purple_name; @@ -655,24 +698,58 @@ /* refresh all buddies online/offline, * after receiving reply for get_buddies_online packet */ -void qq_refresh_all_buddy_status(PurpleConnection *gc) +void qq_update_buddyies_status(PurpleConnection *gc) { - time_t now; - GList *list; qq_data *qd; - qq_buddy *q_bud; + PurpleBuddy *buddy; + qq_buddy *bd; + GSList *buddies, *it; + time_t tm_limit = time(NULL); qd = (qq_data *) (gc->proto_data); - now = time(NULL); - list = qd->buddies; + + tm_limit -= QQ_UPDATE_ONLINE_INTERVAL; - while (list != NULL) { - q_bud = (qq_buddy *) list->data; - if (q_bud != NULL && now > q_bud->last_update + QQ_UPDATE_ONLINE_INTERVAL - && q_bud->status != QQ_BUDDY_ONLINE_INVISIBLE) { - q_bud->status = QQ_BUDDY_CHANGE_TO_OFFLINE; - qq_update_buddy_contact(gc, q_bud); - } - list = list->next; + buddies = purple_find_buddies(purple_connection_get_account(gc), NULL); + for (it = buddies; it; it = it->next) { + buddy = it->data; + if (buddy == NULL) continue; + if (buddy->proto_data == NULL) continue; + + bd = (qq_buddy *)buddy->proto_data; + if (bd->uid == 0) continue; + if (bd->uid == qd->uid) continue; /* my status is always online in my buddy list */ + if (tm_limit < bd->last_update) continue; + if (bd->status == QQ_BUDDY_ONLINE_INVISIBLE) continue; + + bd->status = QQ_BUDDY_CHANGE_TO_OFFLINE; + qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag); } } + +void qq_buddy_data_free_all(PurpleConnection *gc) +{ + qq_data *qd; + PurpleBuddy *buddy; + GSList *buddies, *it; + gint count = 0; + + qd = (qq_data *) (gc->proto_data); + + buddies = purple_find_buddies(purple_connection_get_account(gc), NULL); + for (it = buddies; it; it = it->next) { + buddy = it->data; + if (buddy == NULL) continue; + if (buddy->proto_data == NULL) continue; + + qq_buddy_data_free(buddy->proto_data); + buddy->proto_data = NULL; + + count++; + } + + if (count > 0) { + purple_debug_info("QQ", "%d buddies' data are freed\n", count); + } +} +