# HG changeset patch # User SHiNE CsyFeK # Date 1221835601 0 # Node ID d57928c9dd8f52eb70108d0c85d0c9cf4682c7f7 # Parent b72816d1a131f537f2890fa1312a09d9150b5ecd 2008.09.19 - ccpaging * Rewrite buddy modify info, there is a ticket for this problem * Use ship32 to trans action code between request packet and reply packet process diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/ChangeLog --- a/libpurple/protocols/qq/ChangeLog Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/ChangeLog Fri Sep 19 14:46:41 2008 +0000 @@ -1,3 +1,7 @@ +2008.09.19 - ccpaging + * Rewrite buddy modify info, there is a ticket for this problem + * Use ship32 to trans action code between request packet and reply packet process + 2008.09.15 - csyfek * im.pidgin.pidgin.openq branch diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/Makefile.am --- a/libpurple/protocols/qq/Makefile.am Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/Makefile.am Fri Sep 19 14:46:41 2008 +0000 @@ -54,8 +54,6 @@ send_file.h \ qq_trans.c \ qq_trans.h \ - sys_msg.c \ - sys_msg.h \ utils.c \ utils.h diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/Makefile.mingw --- a/libpurple/protocols/qq/Makefile.mingw Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/Makefile.mingw Fri Sep 19 14:46:41 2008 +0000 @@ -64,7 +64,6 @@ qq_process.c \ qq_trans.c \ send_file.c \ - sys_msg.c \ utils.c OBJECTS = $(C_SRC:%.c=%.o) diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Fri Sep 19 14:46:41 2008 +0000 @@ -36,29 +36,6 @@ #include "qq_base.h" #include "qq_network.h" -#define QQ_PRIMARY_INFORMATION _("Primary Information") -#define QQ_ADDITIONAL_INFORMATION _("Additional Information") -#define QQ_INTRO _("Personal Introduction") -#define QQ_NUMBER _("QQ Number") -#define QQ_NICKNAME _("Nickname") -#define QQ_NAME _("Name") -#define QQ_AGE _("Age") -#define QQ_GENDER _("Gender") -#define QQ_COUNTRY _("Country/Region") -#define QQ_PROVINCE _("Province/State") -#define QQ_CITY _("City") -#define QQ_HOROSCOPE _("Horoscope Symbol") -#define QQ_OCCUPATION _("Occupation") -#define QQ_ZODIAC _("Zodiac Sign") -#define QQ_BLOOD _("Blood Type") -#define QQ_COLLEGE _("College") -#define QQ_EMAIL _("Email") -#define QQ_ADDRESS _("Address") -#define QQ_ZIPCODE _("Zipcode") -#define QQ_CELL _("Cellphone Number") -#define QQ_TELEPHONE _("Phone Number") -#define QQ_HOMEPAGE _("Homepage") - #define QQ_HOROSCOPE_SIZE 13 static const gchar *horoscope_names[] = { "-", N_("Aquarius"), N_("Pisces"), N_("Aries"), N_("Taurus"), @@ -78,223 +55,166 @@ "-", "A", "B", "O", "AB", N_("Other") }; -#define QQ_GENDER_SIZE 2 -static const gchar *genders[] = { - N_("Male"), - N_("Female") +#define QQ_PUBLISH_SIZE 3 +static const gchar *publish_types[] = { + N_("Visible"), N_("Firend Only"), N_("Private") }; -#define QQ_CONTACT_FIELDS 37 +#define QQ_GENDER_SIZE 3 +static const gchar *genders[] = { + N_("Private"), + N_("Male"), + N_("Female"), +}; + +static const gchar *genders_zh[] = { + N_("-"), + N_("\xc4\xd0"), + N_("\xc5\xae"), +}; + #define QQ_FACES 100 -/* There is no user id stored in the reply packet for information query - * we have to manually store the query, so that we know the query source */ -typedef struct _qq_info_query { - guint32 uid; - gboolean show_window; - gboolean modify_info; -} qq_info_query; +enum { + QQ_INFO_UID = 0, QQ_INFO_NICK, QQ_INFO_COUNTRY, QQ_INFO_PROVINCE, QQ_INFO_ZIPCODE, + QQ_INFO_ADDR, QQ_INFO_TEL, QQ_INFO_AGE, QQ_INFO_GENDER, QQ_INFO_NAME, QQ_INFO_EMAIL, + QQ_INFO_PG_SN, QQ_INFO_PG_NUM, QQ_INFO_PG_SP, QQ_INFO_PG_BASE_NUM, QQ_INFO_PG_TYPE, + QQ_INFO_OCCU, QQ_INFO_HOME_PAGE, QQ_INFO_AUTH_TYPE, QQ_INFO_UNKNOW1, QQ_INFO_UNKNOW2, + QQ_INFO_FACE, QQ_INFO_MOBILE, QQ_INFO_MOBILE_TYPE, QQ_INFO_INTRO, QQ_INFO_CITY, + QQ_INFO_UNKNOW3, QQ_INFO_UNKNOW4, QQ_INFO_UNKNOW5, + QQ_INFO_IS_PUB_MOBILE, QQ_INFO_IS_PUB_CONTACT, QQ_INFO_COLLEGE, QQ_INFO_HOROSCOPE, + QQ_INFO_ZODIAC, QQ_INFO_BLOOD, QQ_INFO_SHOW, QQ_INFO_UNKNOW6, + QQ_INFO_LAST, +}; -typedef struct _contact_info { - gchar *uid; - gchar *nick; - gchar *country; - gchar *province; - gchar *zipcode; - gchar *address; - gchar *tel; - gchar *age; - gchar *gender; - gchar *name; - gchar *email; - gchar *pager_sn; - gchar *pager_num; - gchar *pager_sp; - gchar *pager_base_num; - gchar *pager_type; - gchar *occupation; - gchar *homepage; - gchar *auth_type; - gchar *unknown1; - gchar *unknown2; - gchar *face; - gchar *hp_num; - gchar *hp_type; - gchar *intro; - gchar *city; - gchar *unknown3; - gchar *unknown4; - gchar *unknown5; - gchar *is_open_hp; - gchar *is_open_contact; - gchar *college; - gchar *horoscope; - gchar *zodiac; - gchar *blood; - gchar *qq_show; - gchar *unknown6; /* always 0x2D */ -} contact_info; +enum { + QQ_FIELD_UNUSED = 0, QQ_FIELD_BASE, QQ_FIELD_EXT, QQ_FIELD_CONTACT, QQ_FIELD_ADDR +}; + +enum { + QQ_FIELD_LABEL = 0, QQ_FIELD_STRING, QQ_FIELD_MULTI, QQ_FIELD_BOOL, QQ_FIELD_CHOICE, +}; + +typedef struct { + int iclass; + int type; + char *id; + char *text; + const gchar **choice; + int choice_size; +} QQ_FIELD_INFO; -/* We get an info packet on ourselves before we modify our information. - * Even though not all of the information is modifiable, it still - * all needs to be there when we send out the modify info packet */ -typedef struct _modify_info_data { - PurpleConnection *gc; - contact_info *info; -} modify_info_data; - -/* return -1 as a sentinel */ -static gint choice_index(const gchar *value, const gchar **choice, gint choice_size) -{ - gint len, i; +static const QQ_FIELD_INFO field_infos[] = { + { QQ_FIELD_BASE, QQ_FIELD_STRING, "uid", N_("QQ Number"), NULL, 0 }, + { QQ_FIELD_BASE, QQ_FIELD_STRING, "nick", N_("Nickname"), NULL, 0 }, + { QQ_FIELD_ADDR, QQ_FIELD_STRING, "country", N_("Country/Region"), NULL, 0 }, + { QQ_FIELD_ADDR, QQ_FIELD_STRING, "province", N_("Province/State"), NULL, 0 }, + { QQ_FIELD_ADDR, QQ_FIELD_STRING, "zipcode", N_("Zipcode"), NULL, 0 }, + { QQ_FIELD_ADDR, QQ_FIELD_STRING, "address", N_("Address"), NULL, 0 }, + { QQ_FIELD_CONTACT, QQ_FIELD_STRING, "tel", N_("Phone Number"), NULL, 0 }, + { QQ_FIELD_BASE, QQ_FIELD_STRING, "age", N_("Age"), NULL, 0 }, + { QQ_FIELD_BASE, QQ_FIELD_CHOICE, "gender", N_("Gender"), genders, QQ_GENDER_SIZE }, + { QQ_FIELD_BASE, QQ_FIELD_STRING, "name", N_("Name"), NULL, 0 }, + { QQ_FIELD_CONTACT, QQ_FIELD_STRING, "email", N_("Email"), NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "pg_sn", "Pager Serial Num", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "pg_num", "Pager Num", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "pg_sp", "Pager Serivce Provider", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "pg_sta", "Pager Station Num", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "pg_type", "Pager Type", NULL, 0 }, + { QQ_FIELD_BASE, QQ_FIELD_STRING, "occupation", N_("Occupation"), NULL, 0 }, + { QQ_FIELD_CONTACT, QQ_FIELD_STRING, "homepage", N_("Homepage"), NULL, 0 }, + { QQ_FIELD_BASE, QQ_FIELD_BOOL, "auth", N_("Authorize adding"), NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow1", "Unknow1", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow2", "Unknow2", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "face", "Face", NULL, 0 }, + { QQ_FIELD_CONTACT, QQ_FIELD_STRING, "mobile", N_("Cellphone Number"), NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "mobile_type","Cellphone Type", NULL, 0 }, + { QQ_FIELD_BASE, QQ_FIELD_MULTI, "intro", N_("Personal Introduction"), NULL, 0 }, + { QQ_FIELD_ADDR, QQ_FIELD_STRING, "city", N_("City/Area"), NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow3", "Unknow3", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow4", "Unknow4", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow5", "Unknow5", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_CHOICE, "pub_mobile", N_("Publish Mobile"), publish_types, QQ_PUBLISH_SIZE }, + { QQ_FIELD_CONTACT, QQ_FIELD_CHOICE, "pub_contact", N_("Publish Contact"), publish_types, QQ_PUBLISH_SIZE }, + { QQ_FIELD_EXT, QQ_FIELD_STRING, "college", N_("College"), NULL, 0 }, + { QQ_FIELD_EXT, QQ_FIELD_CHOICE, "horoscope", N_("Horoscope"), horoscope_names, QQ_HOROSCOPE_SIZE }, + { QQ_FIELD_EXT, QQ_FIELD_CHOICE, "zodiac", N_("Zodiac"), zodiac_names, QQ_ZODIAC_SIZE }, + { QQ_FIELD_EXT, QQ_FIELD_CHOICE, "blood", N_("Blood"), blood_types, QQ_BLOOD_SIZE }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "qq_show", "QQ Show", NULL, 0 }, + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow6", "Unknow6", NULL, 0 } +}; - len = strlen(value); - if (len > 3 || len == 0) return -1; - for (i = 0; i < len; i++) { - if (!g_ascii_isdigit(value[i])) - return -1; - } - i = strtol(value, NULL, 10); - if (i >= choice_size) - return -1; - - return i; -} +typedef struct _modify_info_request { + PurpleConnection *gc; + int iclass; + gchar **segments; +} modify_info_request; -/* return should be freed */ -static gchar *field_value(const gchar *field, const gchar **choice, gint choice_size) +#ifdef DEBUG +static void info_debug(gchar **segments) { - gint index, len; + int index; + gchar *utf8_str; + for (index = 0; segments[index] != NULL && index < QQ_INFO_LAST; index++) { + if (field_infos[index].type == QQ_FIELD_STRING + || field_infos[index].type == QQ_FIELD_LABEL + || field_infos[index].type == QQ_FIELD_MULTI + || index == QQ_INFO_GENDER) { + utf8_str = qq_to_utf8(segments[index], QQ_CHARSET_DEFAULT); + purple_debug_info("QQ_BUDDY_INFO", "%s: %s\n", field_infos[index]. text, utf8_str); + g_free(utf8_str); + continue; + } + purple_debug_info("QQ_BUDDY_INFO", "%s: %s\n", field_infos[index]. text, segments[index]); + } +} +#endif + +static void info_display_only(PurpleConnection *gc, gchar **segments) +{ + PurpleNotifyUserInfo *user_info; + gchar *utf8_value; + int index; + int choice_num; - len = strlen(field); - if (len == 0) { - return NULL; - } else if (choice != NULL) { - /* some choice fields are also customizable */ - index = choice_index(field, choice, choice_size); - if (index == -1) { - if (strcmp(field, "-") != 0) { - return qq_to_utf8(field, QQ_CHARSET_DEFAULT); - } else { - return NULL; - } - /* else ASCIIized index */ - } else { - if (strcmp(choice[index], "-") != 0) - return g_strdup(choice[index]); - else - return NULL; + user_info = purple_notify_user_info_new(); + + for (index = 1; segments[index] != NULL && index < QQ_INFO_LAST; index++) { + if (field_infos[index].iclass == QQ_FIELD_UNUSED) { + continue; } - } else { - if (strcmp(field, "-") != 0) { - return qq_to_utf8(field, QQ_CHARSET_DEFAULT); - } else { - return NULL; + switch (field_infos[index].type) { + case QQ_FIELD_BOOL: + purple_notify_user_info_add_pair(user_info, field_infos[index].text, + strtol(segments[index], NULL, 10) ? _("True") : _("False")); + break; + case QQ_FIELD_CHOICE: + choice_num = strtol(segments[index], NULL, 10); + if (choice_num < 0 || choice_num >= field_infos[index].choice_size) choice_num = 0; + + purple_notify_user_info_add_pair(user_info, field_infos[index].text, field_infos[index].choice[choice_num]); + break; + case QQ_FIELD_LABEL: + case QQ_FIELD_STRING: + case QQ_FIELD_MULTI: + default: + if (strlen(segments[index]) != 0) { + utf8_value = qq_to_utf8(segments[index], QQ_CHARSET_DEFAULT); + purple_notify_user_info_add_pair(user_info, field_infos[index].text, utf8_value); + g_free(utf8_value); + } + break; } } -} -static gboolean append_field_value(PurpleNotifyUserInfo *user_info, const gchar *field, - const gchar *title, const gchar **choice, gint choice_size) -{ - gchar *value = field_value(field, choice, choice_size); - - if (value != NULL) { - purple_notify_user_info_add_pair(user_info, title, value); - g_free(value); - - return TRUE; - } - - return FALSE; -} - -static PurpleNotifyUserInfo * - info_to_notify_user_info(const contact_info *info) -{ - PurpleNotifyUserInfo *user_info = purple_notify_user_info_new(); - const gchar *intro; - gboolean has_extra_info = FALSE; - - purple_notify_user_info_add_pair(user_info, QQ_NUMBER, info->uid); - - append_field_value(user_info, info->nick, QQ_NICKNAME, NULL, 0); - append_field_value(user_info, info->name, QQ_NAME, NULL, 0); - append_field_value(user_info, info->age, QQ_AGE, NULL, 0); - append_field_value(user_info, info->gender, QQ_GENDER, genders, QQ_GENDER_SIZE); - append_field_value(user_info, info->country, QQ_COUNTRY, NULL, 0); - append_field_value(user_info, info->province, QQ_PROVINCE, NULL, 0); - append_field_value(user_info, info->city, QQ_CITY, NULL, 0); - - purple_notify_user_info_add_section_header(user_info, QQ_ADDITIONAL_INFORMATION); - - has_extra_info |= append_field_value(user_info, info->horoscope, QQ_HOROSCOPE, horoscope_names, QQ_HOROSCOPE_SIZE); - has_extra_info |= append_field_value(user_info, info->occupation, QQ_OCCUPATION, NULL, 0); - has_extra_info |= append_field_value(user_info, info->zodiac, QQ_ZODIAC, zodiac_names, QQ_ZODIAC_SIZE); - has_extra_info |= append_field_value(user_info, info->blood, QQ_BLOOD, blood_types, QQ_BLOOD_SIZE); - has_extra_info |= append_field_value(user_info, info->college, QQ_COLLEGE, NULL, 0); - has_extra_info |= append_field_value(user_info, info->email, QQ_EMAIL, NULL, 0); - has_extra_info |= append_field_value(user_info, info->address, QQ_ADDRESS, NULL, 0); - has_extra_info |= append_field_value(user_info, info->zipcode, QQ_ZIPCODE, NULL, 0); - has_extra_info |= append_field_value(user_info, info->hp_num, QQ_CELL, NULL, 0); - has_extra_info |= append_field_value(user_info, info->tel, QQ_TELEPHONE, NULL, 0); - has_extra_info |= append_field_value(user_info, info->homepage, QQ_HOMEPAGE, NULL, 0); + purple_notify_userinfo(gc, segments[0], user_info, NULL, NULL); - if (!has_extra_info) - purple_notify_user_info_remove_last_item(user_info); - - intro = field_value(info->intro, NULL, 0); - if (intro) { - purple_notify_user_info_add_pair(user_info, QQ_INTRO, intro); - } - - /* for debugging */ - /* - g_string_append_printf(info_text, "

%s
", "Miscellaneous"); - append_field_value(info_text, info->pager_sn, "pager_sn", NULL, 0); - append_field_value(info_text, info->pager_num, "pager_num", NULL, 0); - append_field_value(info_text, info->pager_sp, "pager_sp", NULL, 0); - append_field_value(info_text, info->pager_base_num, "pager_base_num", NULL, 0); - append_field_value(info_text, info->pager_type, "pager_type", NULL, 0); - append_field_value(info_text, info->auth_type, "auth_type", NULL, 0); - append_field_value(info_text, info->unknown1, "unknown1", NULL, 0); - append_field_value(info_text, info->unknown2, "unknown2", NULL, 0); - append_field_value(info_text, info->face, "face", NULL, 0); - append_field_value(info_text, info->hp_type, "hp_type", NULL, 0); - append_field_value(info_text, info->unknown3, "unknown3", NULL, 0); - append_field_value(info_text, info->unknown4, "unknown4", NULL, 0); - append_field_value(info_text, info->unknown5, "unknown5", NULL, 0); - append_field_value(info_text, info->is_open_hp, "is_open_hp", NULL, 0); - append_field_value(info_text, info->is_open_contact, "is_open_contact", NULL, 0); - append_field_value(info_text, info->qq_show, "qq_show", NULL, 0); - append_field_value(info_text, info->unknown6, "unknown6", NULL, 0); - */ - - return user_info; -} - -/* send a packet to get detailed information of uid */ -void qq_send_packet_get_info(PurpleConnection *gc, guint32 uid, gboolean show_window) -{ - qq_data *qd; - gchar uid_str[11]; - qq_info_query *query; - - g_return_if_fail(uid != 0); - - qd = (qq_data *) gc->proto_data; - g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) uid_str, strlen(uid_str)); - - query = g_new0(qq_info_query, 1); - query->uid = uid; - query->show_window = show_window; - query->modify_info = FALSE; - qd->info_query = g_list_append(qd->info_query, query); + purple_notify_user_info_destroy(user_info); + g_strfreev(segments); } void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, - gint update_class, guint32 ship32) + gint update_class, int action) { qq_data *qd; gchar raw_data[16] = {0}; @@ -304,399 +224,216 @@ qd = (qq_data *) gc->proto_data; g_snprintf(raw_data, sizeof(raw_data), "%d", uid); qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) raw_data, strlen(raw_data), - update_class, ship32); -} - -/* set up the fields requesting personal information and send a get_info packet - * for myself */ -void qq_prepare_modify_info(PurpleConnection *gc) -{ - qq_data *qd; - GList *ql; - qq_info_query *query; - - qd = (qq_data *) gc->proto_data; - qq_send_packet_get_info(gc, qd->uid, FALSE); - /* traverse backwards so we get the most recent info_query */ - for (ql = g_list_last(qd->info_query); ql != NULL; ql = g_list_previous(ql)) { - query = ql->data; - if (query->uid == qd->uid) - query->modify_info = TRUE; - } + update_class, action); } /* send packet to modify personal information */ -static void qq_send_packet_modify_info(PurpleConnection *gc, contact_info *info) +static void request_modify_info(PurpleConnection *gc, gchar **segments) { gint bytes = 0; guint8 raw_data[MAX_PACKET_SIZE - 128] = {0}; guint8 bar; + gchar *join; - g_return_if_fail(info != NULL); + g_return_if_fail(segments != NULL); bar = 0x1f; bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_put8(raw_data + bytes, bar); /* important! skip the first uid entry */ - /* - for (i = 1; i < QQ_CONTACT_FIELDS; i++) { - create_packet_b(raw_data, &cursor, bar); - create_packet_data(raw_data, &cursor, (guint8 *) segments[i], strlen(segments[i])); - } - */ - /* uid */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->uid, strlen(info->uid)); - /* nick */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->nick, strlen(info->nick)); - /* country */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->country, strlen(info->country)); - /* province */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->province, strlen(info->province)); - /* zipcode */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->zipcode, strlen(info->zipcode)); - /* address */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->address, strlen(info->address)); - /* tel */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->tel, strlen(info->tel)); - /* age */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->age, strlen(info->age)); - /* gender */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->gender, strlen(info->gender)); - /* name */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->name, strlen(info->name)); - /* email */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->email, strlen(info->email)); - /* pager_sn */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_sn, strlen(info->pager_sn)); - /* pager_num */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_num, strlen(info->pager_num)); - /* pager_sp */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_sp, strlen(info->pager_sp)); - /* pager_base_num */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_base_num, strlen(info->pager_base_num)); - /* pager_type */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_type, strlen(info->pager_type)); - /* occupation */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->occupation, strlen(info->occupation)); - /* homepage */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->homepage, strlen(info->homepage)); - /* auth_type */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->auth_type, strlen(info->auth_type)); - /* unknown1 */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown1, strlen(info->unknown1)); - /* unknown2 */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown2, strlen(info->unknown2)); - /* face */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->face, strlen(info->face)); - /* hp_num */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->hp_num, strlen(info->hp_num)); - /* hp_type */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->hp_type, strlen(info->hp_type)); - /* intro */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->intro, strlen(info->intro)); - /* city */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->city, strlen(info->city)); - /* unknown3 */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown3, strlen(info->unknown3)); - /* unknown4 */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown4, strlen(info->unknown4)); - /* unknown5 */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown5, strlen(info->unknown5)); - /* is_open_hp */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->is_open_hp, strlen(info->is_open_hp)); - /* is_open_contact */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->is_open_contact, strlen(info->is_open_contact)); - /* college */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->college, strlen(info->college)); - /* horoscope */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->horoscope, strlen(info->horoscope)); - /* zodiac */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->zodiac, strlen(info->zodiac)); - /* blood */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->blood, strlen(info->blood)); - /* qq_show */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->qq_show, strlen(info->qq_show)); - /* unknown6 */ - bytes += qq_put8(raw_data + bytes, bar); - bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown6, strlen(info->unknown6)); + join = g_strjoinv("\x1f", segments +1); + bytes += qq_putdata(raw_data + bytes, (guint8 *)join, strlen(join)); + g_free(join); bytes += qq_put8(raw_data + bytes, bar); + /* qq_show_packet("request_modify_info", raw_data, bytes); */ qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, raw_data, bytes); - -} - -static void modify_info_cancel_cb(modify_info_data *mid) -{ - qq_data *qd; - - qd = (qq_data *) mid->gc->proto_data; - qd->modifying_info = FALSE; - - g_strfreev((gchar **) mid->info); - g_free(mid); } -static gchar *parse_field(PurpleRequestField *field, gboolean choice) +static void info_modify_cancel_cb(modify_info_request *info_request) { - gchar *value; - - if (choice) { - value = g_strdup_printf("%d", purple_request_field_choice_get_value(field)); - } else { - value = (gchar *) purple_request_field_string_get_value(field); - if (value == NULL) - value = g_strdup("-"); - else - value = utf8_to_qq(value, QQ_CHARSET_DEFAULT); - } - - return value; + g_strfreev(info_request->segments); + g_free(info_request); } /* parse fields and send info packet */ -static void modify_info_ok_cb(modify_info_data *mid, PurpleRequestFields *fields) +static void info_modify_ok_cb(modify_info_request *info_request, PurpleRequestFields *fields) { PurpleConnection *gc; qq_data *qd; - GList *groups; - contact_info *info; - - gc = mid->gc; - qd = (qq_data *) gc->proto_data; - qd->modifying_info = FALSE; - - info = mid->info; + gchar **segments; + int index; + const char *utf8_str; + gchar *value; + int choice_num; - groups = purple_request_fields_get_groups(fields); - while (groups != NULL) { - PurpleRequestFieldGroup *group = groups->data; - const char *g_name = purple_request_field_group_get_title(group); - GList *fields = purple_request_field_group_get_fields(group); - - if (g_name == NULL) - continue; + gc = info_request->gc; + g_return_if_fail(gc != NULL && info_request->gc); + qd = (qq_data *) gc->proto_data; + segments = info_request->segments; + g_return_if_fail(segments != NULL); - while (fields != NULL) { - PurpleRequestField *field = fields->data; - const char *f_id = purple_request_field_get_id(field); - - if (!strcmp(QQ_PRIMARY_INFORMATION, g_name)) { - - if (!strcmp(f_id, "uid")) - info->uid = parse_field(field, FALSE); - else if (!strcmp(f_id, "nick")) - info->nick = parse_field(field, FALSE); - else if (!strcmp(f_id, "name")) - info->name = parse_field(field, FALSE); - else if (!strcmp(f_id, "age")) - info->age = parse_field(field, FALSE); - else if (!strcmp(f_id, "gender")) - info->gender = parse_field(field, TRUE); - else if (!strcmp(f_id, "country")) - info->country = parse_field(field, FALSE); - else if (!strcmp(f_id, "province")) - info->province = parse_field(field, FALSE); - else if (!strcmp(f_id, "city")) - info->city = parse_field(field, FALSE); - - } else if (!strcmp(QQ_ADDITIONAL_INFORMATION, g_name)) { + for (index = 1; segments[index] != NULL && index < QQ_INFO_LAST; index++) { + if (field_infos[index].iclass == QQ_FIELD_UNUSED) { + continue; + } + if (!purple_request_fields_exists(fields, field_infos[index].id)) { + continue; + } + switch (field_infos[index].type) { + case QQ_FIELD_BOOL: + value = purple_request_fields_get_bool(fields, field_infos[index].id) + ? g_strdup("1") : g_strdup("0"); + g_free(segments[index]); + segments[index] = value; + break; + case QQ_FIELD_CHOICE: + choice_num = purple_request_fields_get_choice(fields, field_infos[index].id); + if (choice_num < 0 || choice_num >= field_infos[index].choice_size) choice_num = 0; - if (!strcmp(f_id, "horoscope")) - info->horoscope = parse_field(field, TRUE); - else if (!strcmp(f_id, "occupation")) - info->occupation = parse_field(field, FALSE); - else if (!strcmp(f_id, "zodiac")) - info->zodiac = parse_field(field, TRUE); - else if (!strcmp(f_id, "blood")) - info->blood = parse_field(field, TRUE); - else if (!strcmp(f_id, "college")) - info->college = parse_field(field, FALSE); - else if (!strcmp(f_id, "email")) - info->email = parse_field(field, FALSE); - else if (!strcmp(f_id, "address")) - info->address = parse_field(field, FALSE); - else if (!strcmp(f_id, "zipcode")) - info->zipcode = parse_field(field, FALSE); - else if (!strcmp(f_id, "hp_num")) - info->hp_num = parse_field(field, FALSE); - else if (!strcmp(f_id, "tel")) - info->tel = parse_field(field, FALSE); - else if (!strcmp(f_id, "homepage")) - info->homepage = parse_field(field, FALSE); + if (index == QQ_INFO_GENDER) { + /* QQ Server only recept gender in Chinese */ + value = g_strdup(genders_zh[choice_num]); + } else { + value = g_strdup_printf("%d", choice_num); + } + g_free(segments[index]); + segments[index] = value; + break; + case QQ_FIELD_LABEL: + case QQ_FIELD_STRING: + case QQ_FIELD_MULTI: + default: + utf8_str = purple_request_fields_get_string(fields, field_infos[index].id); + if (utf8_str == NULL) { + value = g_strdup("-"); + } else { + value = utf8_to_qq(utf8_str, QQ_CHARSET_DEFAULT); + if (value == NULL) value = g_strdup("-"); + } + g_free(segments[index]); + segments[index] = value; + break; + } + } + request_modify_info(gc, segments); - } else if (!strcmp(QQ_INTRO, g_name)) { - - if (!strcmp(f_id, "intro")) - info->intro = parse_field(field, FALSE); - - } - - fields = fields->next; - } - - groups = groups->next; - } - - /* This casting looks like a horrible idea to me -DAA - * yes, rewritten -s3e - * qq_send_packet_modify_info(gc, (gchar **) info); - */ - qq_send_packet_modify_info(gc, info); - - g_strfreev((gchar **) mid->info); - g_free(mid); + g_strfreev(segments); + g_free(info_request); } -static PurpleRequestFieldGroup *setup_field_group(PurpleRequestFields *fields, const gchar *title) -{ - PurpleRequestFieldGroup *group; - - group = purple_request_field_group_new(title); - purple_request_fields_add_group(fields, group); - - return group; -} - -static void add_string_field_to_group(PurpleRequestFieldGroup *group, - const gchar *id, const gchar *title, const gchar *value) +static void field_request_new(PurpleRequestFieldGroup *group, gint index, gchar **segments) { PurpleRequestField *field; gchar *utf8_value; + int choice_num; + int i; - utf8_value = qq_to_utf8(value, QQ_CHARSET_DEFAULT); - field = purple_request_field_string_new(id, title, utf8_value, FALSE); - purple_request_field_group_add_field(group, field); - g_free(utf8_value); + g_return_if_fail(index >=0 && segments[index] != NULL && index < QQ_INFO_LAST); + + switch (field_infos[index].type) { + case QQ_FIELD_STRING: + case QQ_FIELD_MULTI: + utf8_value = qq_to_utf8(segments[index], QQ_CHARSET_DEFAULT); + if (field_infos[index].type == QQ_FIELD_STRING) { + field = purple_request_field_string_new( + field_infos[index].id, field_infos[index].text, utf8_value, FALSE); + } else { + field = purple_request_field_string_new( + field_infos[index].id, field_infos[index].text, utf8_value, TRUE); + } + purple_request_field_group_add_field(group, field); + g_free(utf8_value); + break; + case QQ_FIELD_BOOL: + field = purple_request_field_bool_new( + field_infos[index].id, field_infos[index].text, + strtol(segments[index], NULL, 10) ? TRUE : FALSE); + purple_request_field_group_add_field(group, field); + break; + case QQ_FIELD_CHOICE: + choice_num = strtol(segments[index], NULL, 10); + if (choice_num < 0 || choice_num >= field_infos[index].choice_size) choice_num = 0; + + if (index == QQ_INFO_GENDER && strlen(segments[index]) != 0) { + for (i = 0; i < QQ_GENDER_SIZE; i++) { + if (strcmp(segments[index], genders_zh[i]) == 0) { + choice_num = i; + } + } + } + field = purple_request_field_choice_new( + field_infos[index].id, field_infos[index].text, choice_num); + for (i = 0; i < field_infos[index].choice_size; i++) { + purple_request_field_choice_add(field, field_infos[index].choice[i]); + } + purple_request_field_group_add_field(group, field); + break; + case QQ_FIELD_LABEL: + default: + field = purple_request_field_label_new(field_infos[index].id, segments[index]); + purple_request_field_group_add_field(group, field); + break; + } } -static void add_choice_field_to_group(PurpleRequestFieldGroup *group, - const gchar *id, const gchar *title, const gchar *value, - const gchar **choice, gint choice_size) -{ - PurpleRequestField *field; - gint i, index; - - index = choice_index(value, choice, choice_size); - field = purple_request_field_choice_new(id, title, index); - for (i = 0; i < choice_size; i++) - purple_request_field_choice_add(field, choice[i]); - purple_request_field_group_add_field(group, field); -} - -/* take the info returned by a get_info packet for myself and set up a request form */ -static void create_modify_info_dialogue(PurpleConnection *gc, const contact_info *info) +static void info_modify_dialogue(PurpleConnection *gc, gchar **segments, int iclass) { qq_data *qd; PurpleRequestFieldGroup *group; PurpleRequestFields *fields; - PurpleRequestField *field; - modify_info_data *mid; + modify_info_request *info_request; + gchar *utf8_title, *utf8_prim; + int index; - /* so we only have one dialog open at a time */ qd = (qq_data *) gc->proto_data; - if (!qd->modifying_info) { - qd->modifying_info = TRUE; - - fields = purple_request_fields_new(); + /* Keep one dialog once a time */ + purple_request_close_with_handle(gc); - group = setup_field_group(fields, QQ_PRIMARY_INFORMATION); - field = purple_request_field_string_new("uid", QQ_NUMBER, info->uid, FALSE); - purple_request_field_group_add_field(group, field); - purple_request_field_string_set_editable(field, FALSE); - add_string_field_to_group(group, "nick", QQ_NICKNAME, info->nick); - add_string_field_to_group(group, "name", QQ_NAME, info->name); - add_string_field_to_group(group, "age", QQ_AGE, info->age); - add_choice_field_to_group(group, "gender", QQ_GENDER, info->gender, genders, QQ_GENDER_SIZE); - add_string_field_to_group(group, "country", QQ_COUNTRY, info->country); - add_string_field_to_group(group, "province", QQ_PROVINCE, info->province); - add_string_field_to_group(group, "city", QQ_CITY, info->city); + fields = purple_request_fields_new(); + group = purple_request_field_group_new(NULL); + purple_request_fields_add_group(fields, group); - group = setup_field_group(fields, QQ_ADDITIONAL_INFORMATION); - add_choice_field_to_group(group, "horoscope", QQ_HOROSCOPE, info->horoscope, horoscope_names, QQ_HOROSCOPE_SIZE); - add_string_field_to_group(group, "occupation", QQ_OCCUPATION, info->occupation); - add_choice_field_to_group(group, "zodiac", QQ_ZODIAC, info->zodiac, zodiac_names, QQ_ZODIAC_SIZE); - add_choice_field_to_group(group, "blood", QQ_BLOOD, info->blood, blood_types, QQ_BLOOD_SIZE); - add_string_field_to_group(group, "college", QQ_COLLEGE, info->college); - add_string_field_to_group(group, "email", QQ_EMAIL, info->email); - add_string_field_to_group(group, "address", QQ_ADDRESS, info->address); - add_string_field_to_group(group, "zipcode", QQ_ZIPCODE, info->zipcode); - add_string_field_to_group(group, "hp_num", QQ_CELL, info->hp_num); - add_string_field_to_group(group, "tel", QQ_TELEPHONE, info->tel); - add_string_field_to_group(group, "homepage", QQ_HOMEPAGE, info->homepage); + for (index = 1; segments[index] != NULL && index < QQ_INFO_LAST; index++) { + if (field_infos[index].iclass != iclass) { + continue; + } + field_request_new(group, index, segments); + } - group = setup_field_group(fields, QQ_INTRO); - field = purple_request_field_string_new("intro", QQ_INTRO, info->intro, TRUE); - purple_request_field_group_add_field(group, field); + switch (iclass) { + case QQ_FIELD_CONTACT: + utf8_title = g_strdup(_("Modify Contact")); + utf8_prim = g_strdup_printf("%s for %s", _("Modify Contact"), segments[0]); + case QQ_FIELD_ADDR: + utf8_title = g_strdup(_("Modify Address")); + utf8_prim = g_strdup_printf("%s for %s", _("Modify Address"), segments[0]); + case QQ_FIELD_EXT: + utf8_title = g_strdup(_("Modify Extend Information")); + utf8_prim = g_strdup_printf("%s for %s", _("Modify Extend Information"), segments[0]); + break; + case QQ_FIELD_BASE: + default: + utf8_title = g_strdup(_("Modify Information")); + utf8_prim = g_strdup_printf("%s for %s", _("Modify Information"), segments[0]); + } - /* prepare unmodifiable info */ - mid = g_new0(modify_info_data, 1); - mid->gc = gc; - /* QQ_CONTACT_FIELDS+1 so that the array is NULL-terminated and can be g_strfreev()'ed later */ - mid->info = (contact_info *) g_new0(gchar *, QQ_CONTACT_FIELDS+1); - mid->info->pager_sn = g_strdup(info->pager_sn); - mid->info->pager_num = g_strdup(info->pager_num); - mid->info->pager_sp = g_strdup(info->pager_sp); - mid->info->pager_base_num = g_strdup(info->pager_base_num); - mid->info->pager_type = g_strdup(info->pager_type); - mid->info->auth_type = g_strdup(info->auth_type); - mid->info->unknown1 = g_strdup(info->unknown1); - mid->info->unknown2 = g_strdup(info->unknown2); - mid->info->face = g_strdup(info->face); - mid->info->hp_type = g_strdup(info->hp_type); - mid->info->unknown3 = g_strdup(info->unknown3); - mid->info->unknown4 = g_strdup(info->unknown4); - mid->info->unknown5 = g_strdup(info->unknown5); - /* TODO stop hiding these 2 */ - mid->info->is_open_hp = g_strdup(info->is_open_hp); - mid->info->is_open_contact = g_strdup(info->is_open_contact); - mid->info->qq_show = g_strdup(info->qq_show); - mid->info->unknown6 = g_strdup(info->unknown6); + info_request = g_new0(modify_info_request, 1); + info_request->gc = gc; + info_request->iclass = iclass; + info_request->segments = segments; - purple_request_fields(gc, _("Modify information"), - _("Modify information"), NULL, fields, - _("Update information"), G_CALLBACK(modify_info_ok_cb), - _("Cancel"), G_CALLBACK(modify_info_cancel_cb), - purple_connection_get_account(gc), NULL, NULL, - mid); - } + purple_request_fields(gc, utf8_title, utf8_prim, NULL, fields, + _("Update"), G_CALLBACK(info_modify_ok_cb), + _("Cancel"), G_CALLBACK(info_modify_cancel_cb), + purple_connection_get_account(gc), NULL, NULL, + info_request); + + g_free(utf8_title); + g_free(utf8_prim); } /* process the reply of modify_info packet */ @@ -715,7 +452,7 @@ } } -static void _qq_send_packet_modify_face(PurpleConnection *gc, gint face_num) +static void request_set_buddy_icon(PurpleConnection *gc, gint face_num) { PurpleAccount *account = purple_connection_get_account(gc); PurplePresence *presence = purple_account_get_presence(account); @@ -732,11 +469,10 @@ } qd->my_icon = 3 * (face_num - 1) + offset; - qd->modifying_face = TRUE; - qq_send_packet_get_info(gc, qd->uid, FALSE); + qq_request_buddy_info(gc, qd->uid, 0, QQ_BUDDY_INFO_SET_ICON); } -void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile) +static void buddy_local_icon_set(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile) { gchar *data; gsize len; @@ -749,7 +485,7 @@ } /* TODO: custom faces for QQ members and users with level >= 16 */ -void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) +void qq_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) { gchar *icon; gint icon_num; @@ -796,13 +532,13 @@ } g_free(errmsg); /* tell server my icon changed */ - _qq_send_packet_modify_face(gc, icon_num); + request_set_buddy_icon(gc, icon_num); /* display in blist */ - qq_set_buddy_icon_for_user(account, account->username, icon, icon_path); + buddy_local_icon_set(account, account->username, icon, icon_path); } -static void _qq_update_buddy_icon(PurpleAccount *account, const gchar *name, gint face) +static void buddy_local_icon_upate(PurpleAccount *account, const gchar *name, gint face) { PurpleBuddy *buddy; gchar *icon_num_str = face_to_icon_str(face); @@ -820,14 +556,14 @@ QQ_ICON_PREFIX, icon_num_str, QQ_ICON_SUFFIX, NULL); - qq_set_buddy_icon_for_user(account, name, icon_num_str, icon_path); + buddy_local_icon_set(account, name, icon_num_str, icon_path); g_free(icon_path); } g_free(icon_num_str); } /* after getting info or modify myself, refresh the buddy list accordingly */ -static void qq_refresh_buddy_and_myself(contact_info *info, PurpleConnection *gc) +static void qq_refresh_buddy_and_myself(gchar **segments, PurpleConnection *gc) { PurpleBuddy *b; qq_data *qd; @@ -837,11 +573,11 @@ PurpleAccount *account = purple_connection_get_account(gc); qd = (qq_data *) gc->proto_data; - purple_name = uid_to_purple_name(strtol(info->uid, NULL, 10)); + purple_name = uid_to_purple_name(strtol(segments[QQ_INFO_UID], NULL, 10)); - alias_utf8 = qq_to_utf8(info->nick, QQ_CHARSET_DEFAULT); - if (qd->uid == strtol(info->uid, NULL, 10)) { /* it is me */ - qd->my_icon = strtol(info->face, NULL, 10); + alias_utf8 = qq_to_utf8(segments[QQ_INFO_NICK], QQ_CHARSET_DEFAULT); + if (qd->uid == strtol(segments[QQ_INFO_UID], NULL, 10)) { /* it is me */ + qd->my_icon = strtol(segments[QQ_INFO_FACE], NULL, 10); if (alias_utf8 != NULL) purple_account_set_alias(account, alias_utf8); } @@ -849,87 +585,73 @@ b = purple_find_buddy(gc->account, purple_name); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud != NULL) { /* I have this buddy */ - q_bud->age = strtol(info->age, NULL, 10); - q_bud->gender = strtol(info->gender, NULL, 10); - q_bud->face = strtol(info->face, NULL, 10); + q_bud->age = strtol(segments[QQ_INFO_AGE], NULL, 10); + q_bud->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10); + q_bud->face = strtol(segments[QQ_INFO_FACE], NULL, 10); if (alias_utf8 != NULL) q_bud->nickname = g_strdup(alias_utf8); qq_update_buddy_contact(gc, q_bud); - _qq_update_buddy_icon(gc->account, purple_name, q_bud->face); + buddy_local_icon_upate(gc->account, purple_name, q_bud->face); } g_free(purple_name); g_free(alias_utf8); } /* process reply to get_info packet */ -void qq_process_get_buddy_info(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_get_buddy_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc) { + qq_data *qd; gchar **segments; - qq_info_query *query; - qq_data *qd; - contact_info *info; - GList *list, *query_list; - PurpleNotifyUserInfo *user_info; g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - list = query_list = NULL; - info = NULL; - if (NULL == (segments = split_data(data, data_len, "\x1e", QQ_CONTACT_FIELDS))) + if (NULL == (segments = split_data(data, data_len, "\x1e", QQ_INFO_LAST))) return; - info = (contact_info *) segments; - if (qd->modifying_face && strtol(info->face, NULL, 10) != qd->my_icon) { - gchar *icon = g_strdup_printf("%d", qd->my_icon); - qd->modifying_face = FALSE; - g_free(info->face); - info->face = icon; - qq_send_packet_modify_info(gc, (contact_info *)segments); +#ifdef DEBUG + info_debug(segments); +#endif + + if (action == QQ_BUDDY_INFO_SET_ICON) { + if (strtol(segments[QQ_INFO_FACE], NULL, 10) != qd->my_icon) { + gchar *icon = g_strdup_printf("%d", qd->my_icon); + + g_free(segments[QQ_INFO_FACE]); + segments[QQ_INFO_FACE] = icon; + + request_modify_info(gc, segments); + qq_refresh_buddy_and_myself(segments, gc); + } + g_strfreev(segments); + return; } - qq_refresh_buddy_and_myself(info, gc); - - query_list = qd->info_query; - /* ensure we're processing the right query */ - while (query_list) { - query = (qq_info_query *) query_list->data; - if (query->uid == atoi(info->uid)) { - if (query->show_window) { - user_info = info_to_notify_user_info(info); - purple_notify_userinfo(gc, info->uid, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - } else if (query->modify_info) { - create_modify_info_dialogue(gc, info); - } - qd->info_query = g_list_remove(qd->info_query, qd->info_query->data); - g_free(query); + qq_refresh_buddy_and_myself(segments, gc); + switch (action) { + case QQ_BUDDY_INFO_DISPLAY: + info_display_only(gc, segments); + break; + case QQ_BUDDY_INFO_SET_ICON: + break; + case QQ_BUDDY_INFO_MODIFY_BASE: + info_modify_dialogue(gc, segments, QQ_FIELD_BASE); break; - } - query_list = query_list->next; + case QQ_BUDDY_INFO_MODIFY_EXT: + info_modify_dialogue(gc, segments, QQ_FIELD_EXT); + break; + case QQ_BUDDY_INFO_MODIFY_ADDR: + info_modify_dialogue(gc, segments, QQ_FIELD_ADDR); + break; + case QQ_BUDDY_INFO_MODIFY_CONTACT: + info_modify_dialogue(gc, segments, QQ_FIELD_CONTACT); + break; + default: + g_strfreev(segments); + break; } - - g_strfreev(segments); -} - -void qq_info_query_free(qq_data *qd) -{ - gint count; - qq_info_query *p; - - g_return_if_fail(qd != NULL); - - count = 0; - while (qd->info_query != NULL) { - p = (qq_info_query *) (qd->info_query->data); - qd->info_query = g_list_remove(qd->info_query, p); - g_free(p); - count++; - } - if (count > 0) { - purple_debug_info("QQ", "%d info queries are freed!\n", count); - } + return; } void qq_request_get_level(PurpleConnection *gc, guint32 uid) diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/buddy_info.h --- a/libpurple/protocols/qq/buddy_info.h Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Fri Sep 19 14:46:41 2008 +0000 @@ -70,18 +70,19 @@ enum { QQ_BUDDY_INFO_UPDATE_ONLY = 0, QQ_BUDDY_INFO_DISPLAY, - QQ_BUDDY_INFO_MODIFY, + QQ_BUDDY_INFO_SET_ICON, + QQ_BUDDY_INFO_MODIFY_BASE, + QQ_BUDDY_INFO_MODIFY_EXT, + QQ_BUDDY_INFO_MODIFY_ADDR, + QQ_BUDDY_INFO_MODIFY_CONTACT, }; -void qq_send_packet_get_info(PurpleConnection *gc, guint32 uid, gboolean show_window); void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, - gint update_class, guint32 ship32); -void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); -void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile); -void qq_prepare_modify_info(PurpleConnection *gc); + gint update_class, int action); +void qq_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); void qq_process_modify_info_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_process_get_buddy_info(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_info_query_free(qq_data *qd); +void qq_process_get_buddy_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc); + void qq_request_get_level(PurpleConnection *gc, guint32 uid); void qq_request_get_buddies_level(PurpleConnection *gc, gint update_class); void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Fri Sep 19 14:46:41 2008 +0000 @@ -311,8 +311,7 @@ } #if 1 - purple_debug_info("QQ", - "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", + purple_debug_info("QQ", "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", q_bud->uid, q_bud->ext_flag, q_bud->comm_flag, q_bud->nickname); #endif @@ -321,7 +320,7 @@ g_free(name); if (b == NULL) { - b = qq_add_buddy_by_recv_packet(gc, q_bud->uid, TRUE, FALSE); + b = qq_create_buddy(gc, q_bud->uid, TRUE, FALSE); } b->proto_data = q_bud; diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/buddy_opt.c --- a/libpurple/protocols/qq/buddy_opt.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Fri Sep 19 14:46:41 2008 +0000 @@ -26,6 +26,7 @@ #include "internal.h" #include "notify.h" #include "request.h" +#include "privacy.h" #include "buddy_info.h" #include "buddy_list.h" @@ -52,24 +53,19 @@ QQ_MY_AUTH_REQUEST = 0x32, /* ASCII value of "2" */ }; -typedef struct _qq_add_buddy_request { - guint32 uid; - guint16 seq; -} qq_add_buddy_request; - /* send packet to remove a buddy from my buddy list */ -static void _qq_send_packet_remove_buddy(PurpleConnection *gc, guint32 uid) +static void request_buddy_remove(PurpleConnection *gc, guint32 uid) { gchar uid_str[11]; g_return_if_fail(uid > 0); g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(gc, QQ_CMD_DEL_BUDDY, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_BUDDY_REMOVE, (guint8 *) uid_str, strlen(uid_str)); } /* try to remove myself from someone's buddy list */ -static void _qq_send_packet_remove_self_from(PurpleConnection *gc, guint32 uid) +static void request_buddy_remove_me(PurpleConnection *gc, guint32 uid) { guint8 raw_data[16] = {0}; gint bytes = 0; @@ -78,31 +74,24 @@ bytes += qq_put32(raw_data + bytes, uid); - qq_send_cmd(gc, QQ_CMD_REMOVE_SELF, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_REMOVE_ME, raw_data, bytes); } /* try to add a buddy without authentication */ -static void _qq_send_packet_add_buddy(PurpleConnection *gc, guint32 uid) +static void request_buddy_add_no_auth(PurpleConnection *gc, guint32 uid) { - qq_data *qd = (qq_data *) gc->proto_data; - qq_add_buddy_request *req; gchar uid_str[11]; g_return_if_fail(uid > 0); /* we need to send the ascii code of this uid to qq server */ g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_WO_AUTH, (guint8 *) uid_str, strlen(uid_str)); - - /* must be set after sending packet to get the correct send_seq */ - req = g_new0(qq_add_buddy_request, 1); - req->seq = qd->send_seq; - req->uid = uid; - qd->add_buddy_request = g_list_append(qd->add_buddy_request, req); + qq_send_cmd_mess(gc, QQ_CMD_BUDDY_ADD_NO_AUTH, + (guint8 *) uid_str, strlen(uid_str), 0, uid); } /* this buddy needs authentication, text conversion is done at lowest level */ -static void _qq_send_packet_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text) +static void request_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text) { gchar *text_qq, uid_str[11]; guint8 bar, *raw_data; @@ -125,130 +114,256 @@ g_free(text_qq); } - qq_send_cmd(gc, QQ_CMD_BUDDY_AUTH, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_BUDDY_ADD_AUTH, raw_data, bytes); } -static void _qq_send_packet_add_buddy_auth_with_gc_and_uid(gc_and_uid *g, const gchar *text) +static void request_buddy_add_auth_cb(qq_add_request *add_req, const gchar *text) { - PurpleConnection *gc; - guint32 uid; - g_return_if_fail(g != NULL); + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } - gc = g->gc; - uid = g->uid; - g_return_if_fail(uid != 0); - - _qq_send_packet_buddy_auth(gc, uid, QQ_MY_AUTH_REQUEST, text); - g_free(g); + request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_REQUEST, text); + g_free(add_req); } /* the real packet to reject and request is sent from here */ -static void _qq_reject_add_request_real(gc_and_uid *g, const gchar *reason) +static void buddy_add_deny_reason_cb(qq_add_request *add_req, const gchar *reason) { - gint uid; - PurpleConnection *gc; - - g_return_if_fail(g != NULL); + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } - gc = g->gc; - uid = g->uid; - g_return_if_fail(uid != 0); - - _qq_send_packet_buddy_auth(gc, uid, QQ_MY_AUTH_REJECT, reason); - g_free(g); + request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_REJECT, reason); + g_free(add_req); } /* we approve other's request of adding me as friend */ -void qq_approve_add_request_with_gc_and_uid(gc_and_uid *g) +static void buddy_add_authorize_cb(qq_add_request *add_req) { - gint uid; - PurpleConnection *gc; - - g_return_if_fail(g != NULL); + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid != 0) { + g_free(add_req); + return; + } - gc = g->gc; - uid = g->uid; - g_return_if_fail(uid != 0); - - _qq_send_packet_buddy_auth(gc, uid, QQ_MY_AUTH_APPROVE, NULL); - g_free(g); -} - -void qq_do_nothing_with_gc_and_uid(gc_and_uid *g, const gchar *msg) -{ - g_free(g); + request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_APPROVE, NULL); + g_free(add_req); } /* we reject other's request of adding me as friend */ -void qq_reject_add_request_with_gc_and_uid(gc_and_uid *g) +static void buddy_add_deny_cb(qq_add_request *add_req) { gint uid; gchar *msg1, *msg2; PurpleConnection *gc; - gc_and_uid *g2; - gchar *nombre; - - g_return_if_fail(g != NULL); + gchar *purple_name; - gc = g->gc; - uid = g->uid; - g_return_if_fail(uid != 0); + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } - g_free(g); - - g2 = g_new0(gc_and_uid, 1); - g2->gc = gc; - g2->uid = uid; + gc = add_req->gc; + uid = add_req->uid; msg1 = g_strdup_printf(_("You rejected %d's request"), uid); msg2 = g_strdup(_("Message:")); - nombre = uid_to_purple_name(uid); + purple_name = uid_to_purple_name(uid); purple_request_input(gc, _("Reject request"), msg1, msg2, _("Sorry, you are not my style..."), TRUE, FALSE, - NULL, _("Reject"), G_CALLBACK(_qq_reject_add_request_real), _("Cancel"), NULL, - purple_connection_get_account(gc), nombre, NULL, - g2); - g_free(nombre); + NULL, _("Reject"), G_CALLBACK(buddy_add_deny_reason_cb), _("Cancel"), NULL, + purple_connection_get_account(gc), purple_name, NULL, + add_req); + g_free(purple_name); +} + +/* suggested by rakescar@linuxsir, can still approve after search */ +static void buddy_add_check_info_cb(qq_add_request *add_req) +{ + PurpleConnection *gc; + guint32 uid; + gchar *purple_name; + + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } + + gc = add_req->gc; + uid = add_req->uid; + + qq_request_buddy_info(gc, uid, 0, QQ_BUDDY_INFO_DISPLAY); + + purple_name = uid_to_purple_name(uid); + purple_request_action + (gc, NULL, _("Do you approve the requestion?"), "", + PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(gc), purple_name, NULL, + add_req, 2, + _("Reject"), G_CALLBACK(buddy_add_deny_cb), + _("Approve"), G_CALLBACK(buddy_add_authorize_cb)); + g_free(purple_name); } -void qq_add_buddy_with_gc_and_uid(gc_and_uid *g) +/* add a buddy and send packet to QQ server + * note that when purple load local cached buddy list into its blist + * it also calls this funtion, so we have to + * define qd->is_login=TRUE AFTER serv_finish_login(gc) */ +void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) +{ + qq_data *qd; + guint32 uid; + PurpleBuddy *b; + + qd = (qq_data *) gc->proto_data; + if (!qd->is_login) + return; /* IMPORTANT ! */ + + uid = purple_name_to_uid(buddy->name); + if (uid > 0) { + request_buddy_add_no_auth(gc, uid); + return; + } + + b = purple_find_buddy(gc->account, buddy->name); + if (b != NULL) { + purple_blist_remove_buddy(b); + } + purple_notify_error(gc, NULL, _("QQ Number Error"), _("Invalid QQ Number")); +} + +void qq_change_buddys_group(PurpleConnection *gc, const char *who, + const char *old_group, const char *new_group) { gint uid; - PurpleConnection *gc; + g_return_if_fail(who != NULL); - g_return_if_fail(g != NULL); + if (strcmp(new_group, PURPLE_GROUP_QQ_UNKNOWN) == 0) { + if (purple_privacy_check(gc->account, who)) { + purple_privacy_deny(gc->account, who, TRUE, FALSE); + } else { + purple_privacy_deny_add(gc->account, who, TRUE); + } + return; + } - gc = g->gc; - uid = g->uid; + if (strcmp(old_group, PURPLE_GROUP_QQ_UNKNOWN) != 0) { + return; + } + + uid = purple_name_to_uid(who); g_return_if_fail(uid != 0); - _qq_send_packet_add_buddy(gc, uid); - g_free(g); + purple_privacy_deny_remove(gc->account, who, TRUE); + + purple_debug_info("QQ", "Add unknow buddy %d\n", uid); + request_buddy_add_no_auth(gc, uid); +} + +static void buddy_cancel_cb(qq_add_request *add_req, const gchar *msg) +{ + g_return_if_fail(add_req != NULL); + g_free(add_req); +} + +static void buddy_add_no_auth_cb(qq_add_request *add_req) +{ + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } + + request_buddy_add_no_auth(add_req->gc, add_req->uid); + g_free(add_req); } -void qq_block_buddy_with_gc_and_uid(gc_and_uid *g) +static void buddy_remove_both_cb(qq_add_request *add_req) { - guint32 uid; PurpleConnection *gc; - PurpleBuddy buddy; - PurpleGroup group; + qq_data *qd; + gchar *purple_name; + PurpleBuddy *buddy; + qq_buddy *q_buddy; + + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } + + gc = add_req->gc; + qd = (qq_data *) gc->proto_data; + + request_buddy_remove(gc, add_req->uid); + request_buddy_remove_me(gc, add_req->uid); + + purple_name = uid_to_purple_name(add_req->uid); + buddy = purple_find_buddy(gc->account, purple_name); + if (buddy == NULL) { + g_free(add_req); + return; + } - g_return_if_fail(g != NULL); + q_buddy = (qq_buddy *) buddy->proto_data; + if (q_buddy != NULL) + qd->buddies = g_list_remove(qd->buddies, q_buddy); + else + purple_debug_warning("QQ", "We have no qq_buddy record for %s\n", buddy->name); + + purple_blist_remove_buddy(buddy); + g_free(add_req); +} - gc = g->gc; - uid = g->uid; +/* remove a buddy from my list and remove myself from his list */ +/* TODO: re-enable this */ +void qq_remove_buddy_and_me(PurpleBlistNode * node) +{ + PurpleConnection *gc; + qq_data *qd; + guint32 uid; + qq_add_request *add_req; + PurpleBuddy *buddy; + const gchar *who; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = (PurpleBuddy *) node; + gc = purple_account_get_connection(buddy->account); + qd = (qq_data *) gc->proto_data; + if (!qd->is_login) + return; + + who = buddy->name; + g_return_if_fail(who != NULL); + + uid = purple_name_to_uid(who); g_return_if_fail(uid > 0); - buddy.name = uid_to_purple_name(uid); - group.name = PURPLE_GROUP_QQ_BLOCKED; + add_req = g_new0(qq_add_request, 1); + add_req->gc = gc; + add_req->uid = uid; - qq_remove_buddy(gc, &buddy, &group); - _qq_send_packet_remove_self_from(gc, uid); + purple_request_action(gc, _("Block Buddy"), + "Are you sure you want to block this buddy?", + NULL, + 1, + purple_connection_get_account(gc), NULL, NULL, + add_req, 2, + _("Cancel"), G_CALLBACK(buddy_cancel_cb), + _("Block"), G_CALLBACK(buddy_remove_both_cb)); } /* process reply to add_buddy_auth request */ -void qq_process_add_buddy_auth_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_buddy_add_auth(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gchar **segments, *msg_utf8; @@ -271,7 +386,7 @@ } /* process the server reply for my request to remove a buddy */ -void qq_process_remove_buddy_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_buddy_remove(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; @@ -291,7 +406,7 @@ } /* process the server reply for my request to remove myself from a buddy */ -void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_buddy_remove_me(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; @@ -302,91 +417,75 @@ if (data[0] != QQ_REMOVE_SELF_REPLY_OK) { /* there is no reason return from server */ purple_debug_warning("QQ", "Remove self fails\n"); - purple_notify_info(gc, _("QQ Buddy"), _("Failed:"), _("Remove from other's buddy list")); + purple_notify_info(gc, _("QQ Buddy"), _("Failed:"), _("Remove me from other's buddy list")); } else { /* if reply */ purple_debug_info("QQ", "Remove from a buddy OK\n"); - /* TODO: Does the user really need to be notified about this? */ +#if 0 purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), _("Remove from other's buddy list")); +#endif } } -void qq_process_add_buddy_reply(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) +void qq_process_buddy_add_no_auth(guint8 *data, gint data_len, guint32 uid, PurpleConnection *gc) { qq_data *qd; - gint for_uid; - gchar *msg, **segments, *uid, *reply; - GList *list; + gchar *msg, **segments, *dest_uid, *reply; PurpleBuddy *b; - gc_and_uid *g; - qq_add_buddy_request *req; + qq_add_request *add_req; gchar *nombre; g_return_if_fail(data != NULL && data_len != 0); - for_uid = 0; qd = (qq_data *) gc->proto_data; - list = qd->add_buddy_request; - while (list != NULL) { - req = (qq_add_buddy_request *) list->data; - if (req->seq == seq) { /* reply to this */ - for_uid = req->uid; - qd->add_buddy_request = g_list_remove(qd->add_buddy_request, qd->add_buddy_request->data); - g_free(req); - break; - } - list = list->next; - } - - if (for_uid == 0) { /* we have no record for this */ - purple_debug_error("QQ", "We have no record for add buddy reply [%d], discard\n", seq); + if (uid == 0) { /* we have no record for this */ + purple_debug_error("QQ", "Process buddy add, unknow id\n"); return; } else { - purple_debug_info("QQ", "Add buddy reply [%d] is for id [%d]\n", seq, for_uid); + purple_debug_info("QQ", "Process buddy add for id [%d]\n", uid); } if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) return; - uid = segments[0]; + dest_uid = segments[0]; reply = segments[1]; - if (strtol(uid, NULL, 10) != qd->uid) { /* should not happen */ - purple_debug_error("QQ", "Add buddy reply is to [%s], not me!", uid); + if (strtol(dest_uid, NULL, 10) != qd->uid) { /* should not happen */ + purple_debug_error("QQ", "Add buddy reply is to [%s], not me!", dest_uid); g_strfreev(segments); return; } if (strtol(reply, NULL, 10) > 0) { /* need auth */ purple_debug_warning("QQ", "Add buddy attempt fails, need authentication\n"); - nombre = uid_to_purple_name(for_uid); + nombre = uid_to_purple_name(uid); b = purple_find_buddy(gc->account, nombre); if (b != NULL) purple_blist_remove_buddy(b); - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = for_uid; - msg = g_strdup_printf(_("%d needs authentication"), for_uid); + add_req = g_new0(qq_add_request, 1); + add_req->gc = gc; + add_req->uid = uid; + msg = g_strdup_printf(_("%d needs authentication"), uid); purple_request_input(gc, NULL, msg, _("Input request here"), /* TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands */ _("Would you be my friend?"), TRUE, FALSE, NULL, _("Send"), - G_CALLBACK - (_qq_send_packet_add_buddy_auth_with_gc_and_uid), - _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), + G_CALLBACK(request_buddy_add_auth_cb), + _("Cancel"), G_CALLBACK(buddy_cancel_cb), purple_connection_get_account(gc), nombre, NULL, - g); + add_req); g_free(msg); g_free(nombre); } else { /* add OK */ - qq_add_buddy_by_recv_packet(gc, for_uid, TRUE, TRUE); - msg = g_strdup_printf(_("Add into %d's buddy list"), for_uid); + qq_create_buddy(gc, uid, TRUE, TRUE); + msg = g_strdup_printf(_("Add into %d's buddy list"), uid); purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), msg); g_free(msg); } g_strfreev(segments); } -PurpleGroup *qq_get_purple_group(const gchar *group_name) +PurpleGroup *qq_create_group(const gchar *group_name) { PurpleGroup *g; @@ -404,131 +503,93 @@ /* we add new buddy, if the received packet is from someone not in my list * return the PurpleBuddy that is just created */ -PurpleBuddy *qq_add_buddy_by_recv_packet(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create) +PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create) { - PurpleAccount *a; - PurpleBuddy *b; - PurpleGroup *g; + PurpleBuddy *buddy; + PurpleGroup *group; qq_data *qd; qq_buddy *q_bud; - gchar *name, *group_name; + gchar *buddy_name, *group_name; - a = gc->account; + g_return_val_if_fail(gc->account != NULL && uid != 0, NULL); qd = (qq_data *) gc->proto_data; - g_return_val_if_fail(a != NULL && uid != 0, NULL); - group_name = is_known ? - g_strdup_printf(PURPLE_GROUP_QQ_FORMAT, purple_account_get_username(a)) : g_strdup(PURPLE_GROUP_QQ_UNKNOWN); + if (is_known) { + group_name = g_strdup_printf(PURPLE_GROUP_QQ_FORMAT, + purple_account_get_username(gc->account)); + } else { + group_name = g_strdup(PURPLE_GROUP_QQ_UNKNOWN); + } - g = qq_get_purple_group(group_name); + group = qq_create_group(group_name); - name = uid_to_purple_name(uid); - b = purple_find_buddy(gc->account, name); + buddy_name = uid_to_purple_name(uid); + buddy = purple_find_buddy(gc->account, buddy_name); /* remove old, we can not simply return here * because there might be old local copy of this buddy */ - if (b != NULL) - purple_blist_remove_buddy(b); + if (buddy != NULL) + purple_blist_remove_buddy(buddy); - b = purple_buddy_new(a, name, NULL); + buddy = purple_buddy_new(gc->account, buddy_name, NULL); + if ( !is_known ) { + if (purple_privacy_check(gc->account, buddy_name)) { + purple_privacy_deny(gc->account, buddy_name, TRUE, FALSE); + } else { + purple_privacy_deny_add(gc->account, buddy_name, TRUE); + } + } if (!create) - b->proto_data = NULL; + buddy->proto_data = NULL; else { q_bud = g_new0(qq_buddy, 1); q_bud->uid = uid; - b->proto_data = q_bud; + buddy->proto_data = q_bud; qd->buddies = g_list_append(qd->buddies, q_bud); - qq_send_packet_get_info(gc, q_bud->uid, FALSE); + qq_request_buddy_info(gc, qd->uid, 0, 0); qq_request_get_buddies_online(gc, 0, 0); + qq_request_get_level(gc, qd->uid); } - purple_blist_add_buddy(b, NULL, g, NULL); - purple_debug_warning("QQ", "Add new buddy: [%s]\n", name); + purple_blist_add_buddy(buddy, NULL, group, NULL); + purple_debug_warning("QQ", "Add new buddy: [%s]\n", buddy_name); - g_free(name); + g_free(buddy_name); g_free(group_name); - return b; -} - -/* add a buddy and send packet to QQ server - * note that when purple load local cached buddy list into its blist - * it also calls this funtion, so we have to - * define qd->is_login=TRUE AFTER serv_finish_login(gc) */ -void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) -{ - qq_data *qd; - guint32 uid; - PurpleBuddy *b; - - qd = (qq_data *) gc->proto_data; - if (!qd->is_login) - return; /* IMPORTANT ! */ - - uid = purple_name_to_uid(buddy->name); - if (uid > 0) - _qq_send_packet_add_buddy(gc, uid); - else { - b = purple_find_buddy(gc->account, buddy->name); - if (b != NULL) - purple_blist_remove_buddy(b); - purple_notify_error(gc, NULL, - _("QQ Number Error"), - _("Invalid QQ Number")); - } + return buddy; } /* remove a buddy and send packet to QQ server accordingly */ void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { qq_data *qd; - PurpleBuddy *b; qq_buddy *q_bud; guint32 uid; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + g_return_if_fail(buddy != NULL); qd = (qq_data *) gc->proto_data; + uid = purple_name_to_uid(buddy->name); - if (!qd->is_login) return; - if (uid > 0) - _qq_send_packet_remove_buddy(gc, uid); + if (uid > 0) { + request_buddy_remove(gc, uid); + } - b = purple_find_buddy(gc->account, buddy->name); - if (b != NULL) { - q_bud = (qq_buddy *) b->proto_data; - if (q_bud != NULL) - qd->buddies = g_list_remove(qd->buddies, q_bud); - else - purple_debug_warning("QQ", "We have no qq_buddy record for %s\n", buddy->name); - /* remove buddy on blist, this does not trigger qq_remove_buddy again - * do this only if the request comes from block request, - * otherwise purple segmentation fault */ - if (g_ascii_strcasecmp(group->name, PURPLE_GROUP_QQ_BLOCKED) == 0) - purple_blist_remove_buddy(b); - } + q_bud = (qq_buddy *) buddy->proto_data; + if (q_bud != NULL) + qd->buddies = g_list_remove(qd->buddies, q_bud); + else + purple_debug_warning("QQ", "We have no qq_buddy record for %s\n", buddy->name); + + /* Do not call purple_blist_remove_buddy, + * otherwise purple segmentation fault */ } -/* free add buddy request queue */ -void qq_add_buddy_request_free(qq_data *qd) -{ - gint count; - qq_add_buddy_request *p; - - count = 0; - while (qd->add_buddy_request != NULL) { - p = (qq_add_buddy_request *) (qd->add_buddy_request->data); - qd->add_buddy_request = g_list_remove(qd->add_buddy_request, p); - g_free(p); - count++; - } - if (count > 0) { - purple_debug_info("QQ", "%d add buddy requests are freed!\n", count); - } -} - -/* free up all qq_buddy */ +/* free all qq_buddy */ void qq_buddies_list_free(PurpleAccount *account, qq_data *qd) { gint count; @@ -555,3 +616,149 @@ purple_debug_info("QQ", "%d qq_buddy structures are freed!\n", count); } } + +/* someone wants to add you to his buddy list */ +static void server_buddy_add_request(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) +{ + gchar *message, *reason; + guint32 uid; + qq_add_request *g, *g2; + PurpleBuddy *b; + gchar *name; + + g_return_if_fail(from != NULL && to != NULL); + + uid = strtol(from, NULL, 10); + g = g_new0(qq_add_request, 1); + g->gc = gc; + g->uid = uid; + + name = uid_to_purple_name(uid); + + /* TODO: this should go through purple_account_request_authorization() */ + message = g_strdup_printf(_("%s wants to add you [%s] as a friend"), from, to); + reason = g_strdup_printf(_("Message: %s"), msg_utf8); + + purple_request_action + (gc, NULL, message, reason, PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(gc), name, NULL, + g, 3, + _("Reject"), + G_CALLBACK(buddy_add_deny_cb), + _("Approve"), + G_CALLBACK(buddy_add_authorize_cb), + _("Search"), G_CALLBACK(buddy_add_check_info_cb)); + + g_free(message); + g_free(reason); + + /* XXX: Is this needed once the above goes through purple_account_request_authorization()? */ + b = purple_find_buddy(gc->account, name); + if (b == NULL) { /* the person is not in my list */ + g2 = g_new0(qq_add_request, 1); + g2->gc = gc; + g2->uid = strtol(from, NULL, 10); + message = g_strdup_printf(_("%s is not in buddy list"), from); + purple_request_action(gc, NULL, message, + _("Would you add?"), PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(gc), name, NULL, + g2, 3, + _("Cancel"), NULL, + _("Add"), G_CALLBACK(buddy_add_no_auth_cb), + _("Search"), G_CALLBACK(buddy_add_check_info_cb)); + g_free(message); + } + + g_free(name); +} + +/* when you are added by a person, QQ server will send sys message */ +static void server_buddy_added(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) +{ + gchar *message; + PurpleBuddy *b; + guint32 uid; + qq_add_request *add_req; + gchar *name; + + g_return_if_fail(from != NULL && to != NULL); + + uid = strtol(from, NULL, 10); + name = uid_to_purple_name(uid); + b = purple_find_buddy(gc->account, name); + + if (b == NULL) { /* the person is not in my list */ + add_req = g_new0(qq_add_request, 1); + add_req->gc = gc; + add_req->uid = uid; /* only need to get value */ + message = g_strdup_printf(_("You have been added by %s"), from); + purple_request_action(gc, NULL, message, + _("Would you like to add him?"), + PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(gc), name, NULL, + add_req, 3, + _("Cancel"), G_CALLBACK(buddy_cancel_cb), + _("Add"), G_CALLBACK(buddy_add_no_auth_cb), + _("Search"), G_CALLBACK(buddy_add_check_info_cb)); + } else { + message = g_strdup_printf(_("%s added you [%s] to buddy list"), from, to); + purple_notify_info(gc, _("QQ Budy"), _("Successed:"), message); + } + + g_free(name); + g_free(message); +} + +/* the buddy approves your request of adding him/her as your friend */ +static void server_buddy_added_me(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) +{ + gchar *message; + qq_data *qd; + + g_return_if_fail(from != NULL && to != NULL); + + qd = (qq_data *) gc->proto_data; + qq_create_buddy(gc, strtol(from, NULL, 10), TRUE, TRUE); + + message = g_strdup_printf(_("Requestion approved by %s"), from); + purple_notify_info(gc, _("QQ Buddy"), _("Notice:"), message); + + g_free(message); +} + +/* you are rejected by the person */ +static void server_buddy_rejected_me(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) +{ + gchar *message, *reason; + + g_return_if_fail(from != NULL && to != NULL); + + message = g_strdup_printf(_("Requestion rejected by %s"), from); + reason = g_strdup_printf(_("Message: %s"), msg_utf8); + + purple_notify_info(gc, _("QQ Buddy"), message, reason); + g_free(message); + g_free(reason); +} + +void qq_process_buddy_from_server(PurpleConnection *gc, int funct, + gchar *from, gchar *to, gchar *msg_utf8) +{ + switch (funct) { + case QQ_SERVER_BUDDY_ADDED: + server_buddy_added(gc, from, to, msg_utf8); + break; + case QQ_SERVER_BUDDY_ADD_REQUEST: + server_buddy_add_request(gc, from, to, msg_utf8); + break; + case QQ_SERVER_BUDDY_ADDED_ME: + server_buddy_added_me(gc, from, to, msg_utf8); + break; + case QQ_SERVER_BUDDY_REJECTED_ME: + server_buddy_rejected_me(gc, from, to, msg_utf8); + break; + default: + purple_debug_warning("QQ", "Unknow buddy operate (%d) from server\n", funct); + break; + } +} diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/buddy_opt.h --- a/libpurple/protocols/qq/buddy_opt.h Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.h Fri Sep 19 14:46:41 2008 +0000 @@ -30,33 +30,21 @@ #include "qq.h" -typedef struct _gc_and_uid gc_and_uid; - -struct _gc_and_uid { - guint32 uid; - PurpleConnection *gc; -}; - -void qq_approve_add_request_with_gc_and_uid(gc_and_uid *g); -void qq_reject_add_request_with_gc_and_uid(gc_and_uid *g); - -void qq_add_buddy_with_gc_and_uid(gc_and_uid *g); -void qq_block_buddy_with_gc_and_uid(gc_and_uid *g); - -void qq_do_nothing_with_gc_and_uid(gc_and_uid *g, const gchar *msg); - -void qq_process_remove_buddy_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); -void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_process_add_buddy_reply(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc); -void qq_process_add_buddy_auth_reply(guint8 *data, gint data_len, PurpleConnection *gc); -PurpleBuddy *qq_add_buddy_by_recv_packet(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create); void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); - -PurpleGroup *qq_get_purple_group(const gchar *group_name); - +void qq_change_buddys_group(PurpleConnection *gc, const char *who, + const char *old_group, const char *new_group); +void qq_remove_buddy_and_me(PurpleBlistNode * node); void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); -void qq_add_buddy_request_free(qq_data *qd); - +PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create); void qq_buddies_list_free(PurpleAccount *account, qq_data *qd); +void qq_process_buddy_remove(guint8 *buf, gint buf_len, PurpleConnection *gc); +void qq_process_buddy_remove_me(guint8 *data, gint data_len, PurpleConnection *gc); +void qq_process_buddy_add_no_auth(guint8 *data, gint data_len, guint32 uid, PurpleConnection *gc); +void qq_process_buddy_add_auth(guint8 *data, gint data_len, PurpleConnection *gc); +void qq_process_buddy_from_server(PurpleConnection *gc, int funct, + gchar *from, gchar *to, gchar *msg_utf8); + +PurpleGroup *qq_create_group(const gchar *group_name); + #endif diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/group.c --- a/libpurple/protocols/qq/group.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/group.c Fri Sep 19 14:46:41 2008 +0000 @@ -34,7 +34,7 @@ #include "utils.h" #include "qq_network.h" #include "header_info.h" -#include "group.h" +#include "group_free.h" static void _qq_group_search_callback(PurpleConnection *gc, const gchar *input) { diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/group_internal.c --- a/libpurple/protocols/qq/group_internal.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.c Fri Sep 19 14:46:41 2008 +0000 @@ -63,7 +63,7 @@ PurpleChat *chat; components = qq_group_to_hashtable(group); chat = purple_chat_new(purple_connection_get_account(gc), group->title_utf8, components); - g = qq_get_purple_group(PURPLE_GROUP_QQ_QUN); + g = qq_create_group(PURPLE_GROUP_QQ_QUN); purple_blist_add_chat(chat, g, NULL); purple_debug_info("QQ", "You have added group \"%s\" to blist locally\n", group->title_utf8); } diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/group_join.c --- a/libpurple/protocols/qq/group_join.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/group_join.c Fri Sep 19 14:46:41 2008 +0000 @@ -29,11 +29,9 @@ #include "request.h" #include "server.h" -#include "buddy_opt.h" #include "char_conv.h" #include "group_conv.h" #include "group_find.h" -#include "group_free.h" #include "group_internal.h" #include "group_info.h" #include "group_join.h" @@ -51,19 +49,28 @@ QQ_ROOM_JOIN_DENIED = 0x03, }; -static void _qq_group_exit_with_gc_and_id(gc_and_uid *g) +static void group_quit_cb(qq_add_request *add_req) { PurpleConnection *gc; guint32 id; qq_group *group; - gc = g->gc; - id = g->uid; + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } + + gc = add_req->gc; + id = add_req->uid; group = qq_room_search_id(gc, id); - g_return_if_fail(group != NULL); + if (group == NULL) { + g_free(add_req); + return; + } qq_send_room_cmd_only(gc, QQ_ROOM_CMD_QUIT, group->id); + g_free(add_req); } /* send packet to join a group without auth */ @@ -95,44 +102,53 @@ qq_send_room_cmd_only(gc, QQ_ROOM_CMD_JOIN, group->id); } -static void _qq_group_join_auth_with_gc_and_id(gc_and_uid *g, const gchar *reason_utf8) +static void group_join_cb(qq_add_request *add_req, const gchar *reason_utf8) { - PurpleConnection *gc; qq_group *group; - guint32 id; + + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } - gc = g->gc; - id = g->uid; - - group = qq_room_search_id(gc, id); + group = qq_room_search_id(add_req->gc, add_req->uid); if (group == NULL) { - purple_debug_error("QQ", "Can not find qq_group by internal_id: %d\n", id); + purple_debug_error("QQ", "Can not find qq_group by internal_id: %d\n", add_req->uid); + g_free(add_req); return; - } else { /* everything is OK */ - qq_send_cmd_group_auth(gc, group, QQ_ROOM_AUTH_REQUEST_APPLY, 0, reason_utf8); } + + qq_send_cmd_group_auth(add_req->gc, group, QQ_ROOM_AUTH_REQUEST_APPLY, 0, reason_utf8); + g_free(add_req); +} + +void qq_group_cancel_cb(qq_add_request *add_req, const gchar *msg) +{ + g_return_if_fail(add_req != NULL); + g_free(add_req); } static void _qq_group_join_auth(PurpleConnection *gc, qq_group *group) { gchar *msg; - gc_and_uid *g; + qq_add_request *add_req; g_return_if_fail(group != NULL); purple_debug_info("QQ", "Group (internal id: %d) needs authentication\n", group->id); msg = g_strdup_printf("Group \"%s\" needs authentication\n", group->title_utf8); - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = group->id; + add_req = g_new0(qq_add_request, 1); + add_req->gc = gc; + add_req->uid = group->id; purple_request_input(gc, NULL, msg, _("Input request here"), _("Would you be my friend?"), TRUE, FALSE, NULL, _("Send"), - G_CALLBACK(_qq_group_join_auth_with_gc_and_id), - _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), + G_CALLBACK(group_join_cb), + _("Cancel"), G_CALLBACK(qq_group_cancel_cb), purple_connection_get_account(gc), group->title_utf8, NULL, - g); + add_req); g_free(msg); } @@ -308,7 +324,7 @@ { gchar *id_ptr; guint32 id; - gc_and_uid *g; + qq_add_request *add_req; g_return_if_fail(data != NULL); @@ -317,16 +333,16 @@ g_return_if_fail(id > 0); - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = id; + add_req = g_new0(qq_add_request, 1); + add_req->gc = gc; + add_req->uid = id; purple_request_action(gc, _("QQ Qun Operation"), _("Are you sure you want to leave this Qun?"), _("Note, if you are the creator, \nthis operation will eventually remove this Qun."), 1, purple_connection_get_account(gc), NULL, NULL, - g, 2, _("Cancel"), - G_CALLBACK(qq_do_nothing_with_gc_and_uid), - _("Continue"), G_CALLBACK(_qq_group_exit_with_gc_and_id)); + add_req, 2, _("Cancel"), + G_CALLBACK(qq_group_cancel_cb), + _("Continue"), G_CALLBACK(group_quit_cb)); } diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/group_join.h --- a/libpurple/protocols/qq/group_join.h Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/group_join.h Fri Sep 19 14:46:41 2008 +0000 @@ -49,4 +49,5 @@ void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc); void qq_process_group_cmd_join_group(guint8 *data, gint len, PurpleConnection *gc); +void qq_group_cancel_cb(qq_add_request *add_req, const gchar *msg); #endif diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/group_opt.c --- a/libpurple/protocols/qq/group_opt.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.c Fri Sep 19 14:46:41 2008 +0000 @@ -97,7 +97,7 @@ { g_return_if_fail(g != NULL && g->gc != NULL && g->member > 0); - qq_send_packet_get_info(g->gc, g->member, TRUE); /* we want to see window */ + qq_request_buddy_info(g->gc, g->member, 0, QQ_BUDDY_INFO_DISPLAY); purple_request_action(g->gc, NULL, _("Do you want to approve the request?"), "", PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(g->gc), NULL, NULL, @@ -322,17 +322,24 @@ qq_send_room_cmd_noid(gc, QQ_ROOM_CMD_CREATE, data, bytes); } -static void qq_group_setup_with_gc_and_uid(gc_and_uid *g) +static void qq_group_setup_cb(qq_add_request *add_req) { qq_group *group; - g_return_if_fail(g != NULL && g->gc != NULL && g->uid > 0); + g_return_if_fail(add_req != NULL); + if (add_req->gc == NULL || add_req->uid == 0) { + g_free(add_req); + return; + } - group = qq_room_search_id(g->gc, g->uid); - g_return_if_fail(group != NULL); + group = qq_room_search_id(add_req->gc, add_req->uid); + if (group == NULL) { + g_free(add_req); + return; + } /* TODO insert UI code here */ /* qq_group_detail_window_show(g->gc, group); */ - g_free(g); + g_free(add_req); } void qq_group_process_create_group_reply(guint8 *data, gint len, PurpleConnection *gc) @@ -340,7 +347,7 @@ gint bytes; guint32 id, ext_id; qq_group *group; - gc_and_uid *g; + qq_add_request *add_req; qq_data *qd; g_return_if_fail(data != NULL); @@ -362,19 +369,18 @@ purple_debug_info("QQ", "Succeed in create Qun, external ID %d\n", group->ext_id); - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = id; + add_req = g_new0(qq_add_request, 1); + add_req->gc = gc; + add_req->uid = id; purple_request_action(gc, _("QQ Qun Operation"), _("You have successfully created a Qun"), - _ - ("Would you like to set up the detail information now?"), + _("Would you like to set up the detail information now?"), 1, purple_connection_get_account(gc), NULL, NULL, - g, 2, - _("Setup"), G_CALLBACK(qq_group_setup_with_gc_and_uid), - _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid)); + add_req, 2, + _("Setup"), G_CALLBACK(qq_group_setup_cb), + _("Cancel"), G_CALLBACK(qq_group_cancel_cb)); } void qq_group_process_activate_group_reply(guint8 *data, gint len, PurpleConnection *gc) diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/header_info.c --- a/libpurple/protocols/qq/header_info.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/header_info.c Fri Sep 19 14:46:41 2008 +0000 @@ -140,12 +140,12 @@ return "QQ_CMD_SEARCH_USER"; case QQ_CMD_GET_BUDDY_INFO: return "QQ_CMD_GET_BUDDY_INFO"; - case QQ_CMD_ADD_BUDDY_WO_AUTH: - return "QQ_CMD_ADD_BUDDY_WO_AUTH"; - case QQ_CMD_DEL_BUDDY: - return "QQ_CMD_DEL_BUDDY"; - case QQ_CMD_BUDDY_AUTH: - return "QQ_CMD_BUDDY_AUTH"; + case QQ_CMD_BUDDY_ADD_NO_AUTH: + return "QQ_CMD_BUDDY_ADD_NO_AUTH"; + case QQ_CMD_BUDDY_REMOVE: + return "QQ_CMD_BUDDY_REMOVE"; + case QQ_CMD_BUDDY_ADD_AUTH: + return "QQ_CMD_BUDDY_ADD_AUTH"; case QQ_CMD_CHANGE_STATUS: return "QQ_CMD_CHANGE_STATUS"; case QQ_CMD_ACK_SYS_MSG: @@ -154,8 +154,8 @@ return "QQ_CMD_SEND_IM"; case QQ_CMD_RECV_IM: return "QQ_CMD_RECV_IM"; - case QQ_CMD_REMOVE_SELF: - return "QQ_CMD_REMOVE_SELF"; + case QQ_CMD_REMOVE_ME: + return "QQ_CMD_REMOVE_ME"; case QQ_CMD_LOGIN: return "QQ_CMD_LOGIN"; case QQ_CMD_GET_BUDDIES_LIST: diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/header_info.h --- a/libpurple/protocols/qq/header_info.h Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/header_info.h Fri Sep 19 14:46:41 2008 +0000 @@ -44,14 +44,14 @@ QQ_CMD_UPDATE_INFO = 0x0004, /* update information */ QQ_CMD_SEARCH_USER = 0x0005, /* search for user */ QQ_CMD_GET_BUDDY_INFO = 0x0006, /* get user information */ - QQ_CMD_ADD_BUDDY_WO_AUTH = 0x0009, /* add buddy without auth */ - QQ_CMD_DEL_BUDDY = 0x000a, /* delete a buddy */ - QQ_CMD_BUDDY_AUTH = 0x000b, /* buddy authentication */ + QQ_CMD_BUDDY_ADD_NO_AUTH = 0x0009, /* add buddy without auth */ + QQ_CMD_BUDDY_REMOVE = 0x000a, /* delete a buddy */ + QQ_CMD_BUDDY_ADD_AUTH = 0x000b, /* buddy authentication */ QQ_CMD_CHANGE_STATUS = 0x000d, /* change my online status */ QQ_CMD_ACK_SYS_MSG = 0x0012, /* ack system message */ QQ_CMD_SEND_IM = 0x0016, /* send message */ QQ_CMD_RECV_IM = 0x0017, /* receive message */ - QQ_CMD_REMOVE_SELF = 0x001c, /* remove self */ + QQ_CMD_REMOVE_ME = 0x001c, /* remove self */ QQ_CMD_REQUEST_KEY = 0x001d, /* request key for file transfer */ QQ_CMD_CELL_PHONE_1 = 0x0021, /* cell phone 1 */ QQ_CMD_LOGIN = 0x0022, /* login */ @@ -98,4 +98,12 @@ const gchar *qq_get_room_cmd_desc(gint room_cmd); +enum { + QQ_SERVER_BUDDY_ADDED = 0x01, + QQ_SERVER_BUDDY_ADD_REQUEST = 0x02, + QQ_SERVER_BUDDY_ADDED_ME = 0x03, + QQ_SERVER_BUDDY_REJECTED_ME = 0x04, + QQ_SERVER_NOTICE= 0x06, + QQ_SERVER_NEW_CLIENT = 0x09 +}; #endif diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/im.c --- a/libpurple/protocols/qq/im.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/im.c Fri Sep 19 14:46:41 2008 +0000 @@ -355,7 +355,7 @@ name = uid_to_purple_name(common->sender_uid); b = purple_find_buddy(gc->account, name); if (b == NULL) { - qq_add_buddy_by_recv_packet(gc, common->sender_uid, FALSE, TRUE); + qq_create_buddy(gc, common->sender_uid, FALSE, TRUE); b = purple_find_buddy(gc->account, name); } qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/packet_parse.c --- a/libpurple/protocols/qq/packet_parse.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.c Fri Sep 19 14:46:41 2008 +0000 @@ -38,7 +38,7 @@ #define PARSER_DEBUG #endif -/* read one byte from buf, +/* read one byte from buf, * return the number of bytes read if succeeds, otherwise return -1 */ gint qq_get8(guint8 *b, guint8 *buf) { @@ -53,7 +53,7 @@ } -/* read two bytes as "guint16" from buf, +/* read two bytes as "guint16" from buf, * return the number of bytes read if succeeds, otherwise return -1 */ gint qq_get16(guint16 *w, guint8 *buf) { @@ -67,7 +67,7 @@ return sizeof(w_dest); } -/* read four bytes as "guint32" from buf, +/* read four bytes as "guint32" from buf, * return the number of bytes read if succeeds, otherwise return -1 */ gint qq_get32(guint32 *dw, guint8 *buf) { @@ -87,7 +87,7 @@ return sizeof(struct in_addr); } -/* read datalen bytes from buf, +/* read datalen bytes from buf, * return the number of bytes read if succeeds, otherwise return -1 */ gint qq_getdata(guint8 *data, gint datalen, guint8 *buf) { @@ -171,7 +171,7 @@ * return the number of bytes packed, otherwise return -1 */ gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen) { - memcpy(buf, data, datalen); + memcpy(buf, data, datalen); #ifdef PARSER_DEBUG purple_debug_info("QQ", "[DBG][putdata] buf %p\n", (void *)buf); #endif diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Fri Sep 19 14:46:41 2008 +0000 @@ -456,7 +456,7 @@ } /* send packet to get who's detailed information */ -static void _qq_get_info(PurpleConnection *gc, const gchar *who) +static void qq_show_buddy_info(PurpleConnection *gc, const gchar *who) { guint32 uid; qq_data *qd; @@ -471,59 +471,65 @@ } qq_request_get_level(gc, uid); - qq_send_packet_get_info(gc, uid, TRUE); + qq_request_buddy_info(gc, uid, 0, QQ_BUDDY_INFO_DISPLAY); } -/* get my own information */ -static void _qq_menu_modify_my_info(PurplePluginAction *action) +static void action_update_all_rooms(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + qq_data *qd; + qd = (qq_data *) gc->proto_data; + + if ( !qd->is_login ) { + return; + } + + qq_update_all_rooms(gc, 0, 0); +} + +static void action_modify_info_base(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *) action->context; qq_data *qd; qd = (qq_data *) gc->proto_data; - qq_prepare_modify_info(gc); + qq_request_buddy_info(gc, qd->uid, 0, QQ_BUDDY_INFO_MODIFY_BASE); +} + +static void action_modify_info_ext(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + qq_data *qd; + + qd = (qq_data *) gc->proto_data; + qq_request_buddy_info(gc, qd->uid, 0, QQ_BUDDY_INFO_MODIFY_EXT); } -static void _qq_menu_change_password(PurplePluginAction *action) +static void action_modify_info_addr(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + qq_data *qd; + + qd = (qq_data *) gc->proto_data; + qq_request_buddy_info(gc, qd->uid, 0, QQ_BUDDY_INFO_MODIFY_ADDR); +} + +static void action_modify_info_contact(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + qq_data *qd; + + qd = (qq_data *) gc->proto_data; + qq_request_buddy_info(gc, qd->uid, 0, QQ_BUDDY_INFO_MODIFY_CONTACT); +} + +static void action_change_password(PurplePluginAction *action) { purple_notify_uri(NULL, "https://password.qq.com"); } -/* remove a buddy from my list and remove myself from his list */ -/* TODO: re-enable this -static void _qq_menu_block_buddy(PurpleBlistNode * node) -{ - guint32 uid; - gc_and_uid *g; - PurpleBuddy *buddy; - PurpleConnection *gc; - const gchar *who; - - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); - - buddy = (PurpleBuddy *) node; - gc = purple_account_get_connection(buddy->account); - who = buddy->name; - g_return_if_fail(who != NULL); - - uid = purple_name_to_uid(who); - g_return_if_fail(uid > 0); - - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = uid; - - purple_request_action(gc, _("Block Buddy"), - _("Are you sure you want to block this buddy?"), NULL, - 1, g, 2, - _("Cancel"), - G_CALLBACK(qq_do_nothing_with_gc_and_uid), - _("Block"), G_CALLBACK(qq_block_buddy_with_gc_and_uid)); -} -*/ - /* show a brief summary of what we get from login packet */ -static void _qq_menu_account_info(PurplePluginAction *action) +static void action_show_account_info(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *) action->context; qq_data *qd; @@ -628,19 +634,31 @@ #endif /* protocol related menus */ -static GList *_qq_actions(PurplePlugin *plugin, gpointer context) +static GList *qq_actions(PurplePlugin *plugin, gpointer context) { GList *m; PurplePluginAction *act; m = NULL; - act = purple_plugin_action_new(_("Set My Information"), _qq_menu_modify_my_info); + act = purple_plugin_action_new(_("Modify Information"), action_modify_info_base); + m = g_list_append(m, act); + + act = purple_plugin_action_new(_("Modify Extend Information"), action_modify_info_ext); + m = g_list_append(m, act); + + act = purple_plugin_action_new(_("Modify Address"), action_modify_info_addr); m = g_list_append(m, act); - act = purple_plugin_action_new(_("Change Password"), _qq_menu_change_password); + act = purple_plugin_action_new(_("Modify Contact"), action_modify_info_contact); m = g_list_append(m, act); - act = purple_plugin_action_new(_("Account Information"), _qq_menu_account_info); + act = purple_plugin_action_new(_("Change Password"), action_change_password); + m = g_list_append(m, act); + + act = purple_plugin_action_new(_("Account Information"), action_show_account_info); + m = g_list_append(m, act); + + act = purple_plugin_action_new(_("Update all QQ Quns"), action_update_all_rooms); m = g_list_append(m, act); /* @@ -676,17 +694,18 @@ static GList *_qq_buddy_menu(PurpleBlistNode * node) { GList *m; + PurpleMenuAction *act; if(PURPLE_BLIST_NODE_IS_CHAT(node)) return _qq_chat_menu(node); m = NULL; + act = purple_menu_action_new(_("Remove both side"), PURPLE_CALLBACK(qq_remove_buddy_and_me), NULL, NULL); /* add NULL by gfhuang */ + m = g_list_append(m, act); + /* TODO : not working, temp commented out by gfhuang */ #if 0 - - act = purple_menu_action_new(_("Block this buddy"), PURPLE_CALLBACK(_qq_menu_block_buddy), NULL, NULL); /* add NULL by gfhuang */ - m = g_list_append(m, act); /* if (q_bud && is_online(q_bud->status)) { */ act = purple_menu_action_new(_("Send File"), PURPLE_CALLBACK(_qq_menu_send_file), NULL, NULL); /* add NULL by gfhuang */ m = g_list_append(m, act); @@ -705,7 +724,7 @@ purple_name = chat_name_to_purple_name(who); if (purple_name != NULL) - _qq_get_info(gc, purple_name); + qq_show_buddy_info(gc, purple_name); } /* convert chat nickname to qq-uid to invite individual IM to buddy */ @@ -735,7 +754,7 @@ _qq_send_im, /* send_im */ NULL, /* set_info */ NULL, /* send_typing */ - _qq_get_info, /* get_info */ + qq_show_buddy_info, /* get_info */ _qq_change_status, /* change status */ NULL, /* set_idle */ NULL, /* change_passwd */ @@ -760,12 +779,12 @@ _qq_get_chat_buddy_info, /* get_cb_info */ NULL, /* get_cb_away */ NULL, /* alias_buddy */ - NULL, /* group_buddy */ + qq_change_buddys_group, /* group_buddy */ NULL, /* rename_group */ NULL, /* buddy_free */ NULL, /* convo_closed */ NULL, /* normalize */ - qq_set_my_buddy_icon, /* set_buddy_icon */ + qq_set_buddy_icon, /* set_buddy_icon */ NULL, /* remove_group */ _qq_get_chat_buddy_real_name, /* get_cb_real_name */ NULL, /* set_chat_topic */ @@ -815,7 +834,7 @@ NULL, /**< ui_info */ &prpl_info, /**< extra_info */ NULL, /**< prefs_info */ - _qq_actions, + qq_actions, /* padding */ NULL, @@ -878,7 +897,7 @@ purple_prefs_add_bool("/plugins/prpl/qq/show_fake_video", FALSE); purple_prefs_add_bool("/plugins/prpl/qq/show_room_when_newin", TRUE); purple_prefs_add_int("/plugins/prpl/qq/resend_interval", 3); - purple_prefs_add_int("/plugins/prpl/qq/resend_times", 4); + purple_prefs_add_int("/plugins/prpl/qq/resend_times", 10); } PURPLE_INIT_PLUGIN(qq, init_plugin, info); diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/qq.h --- a/libpurple/protocols/qq/qq.h Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/qq.h Fri Sep 19 14:46:41 2008 +0000 @@ -40,6 +40,12 @@ typedef struct _qq_buddy qq_buddy; typedef struct _qq_interval qq_interval; typedef struct _qq_net_stat qq_net_stat; +typedef struct _qq_add_request qq_add_request; + +struct _qq_add_request { + guint32 uid; + PurpleConnection *gc; +}; struct _qq_interval { gint resend; @@ -151,14 +157,7 @@ GSList *joining_groups; GSList *adding_groups_from_server; /* internal ids of groups the server wants in my blist */ GList *buddies; - GList *contact_info_window; GList *group_info_window; - GList *info_query; - GList *add_buddy_request; - - /* TODO pass qq_send_packet_get_info() a callback and use signals to get rid of these */ - gboolean modifying_info; - gboolean modifying_face; gboolean is_show_notice; gboolean is_show_news; diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/qq_network.c --- a/libpurple/protocols/qq/qq_network.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.c Fri Sep 19 14:46:41 2008 +0000 @@ -285,6 +285,10 @@ update_class = qq_trans_get_class(trans); ship32 = qq_trans_get_ship(trans); + if (update_class != 0 || ship32 != 0) { + purple_debug_info("QQ", "Process in Update class %d, ship32 %d\n", + update_class, ship32); + } switch (cmd) { case QQ_CMD_TOKEN: @@ -998,8 +1002,6 @@ qd->my_ip.s_addr = 0; qq_group_free_all(qd); - qq_add_buddy_request_free(qd); - qq_info_query_free(qd); qq_buddies_list_free(gc->account, qd); } diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Fri Sep 19 14:46:41 2008 +0000 @@ -30,10 +30,10 @@ #include "buddy_list.h" #include "buddy_opt.h" #include "group_info.h" -#include "group_free.h" #include "char_conv.h" #include "qq_crypt.h" +#include "group_search.h" #include "group_conv.h" #include "group_find.h" #include "group_internal.h" @@ -41,7 +41,6 @@ #include "group_info.h" #include "group_join.h" #include "group_opt.h" -#include "group_search.h" #include "header_info.h" #include "qq_base.h" @@ -50,7 +49,6 @@ #include "packet_parse.h" #include "qq_network.h" #include "qq_trans.h" -#include "sys_msg.h" #include "utils.h" enum { @@ -83,6 +81,111 @@ } } +/* Send ACK if the sys message needs an ACK */ +static void _qq_send_packet_ack_msg_sys(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) +{ + qq_data *qd; + guint8 bar, *ack; + gchar *str; + gint ack_len, bytes; + + qd = (qq_data *) gc->proto_data; + + str = g_strdup_printf("%d", from); + bar = 0x1e; + ack_len = 1 + 1 + strlen(str) + 1 + 2; + ack = g_newa(guint8, ack_len); + + bytes = 0; + bytes += qq_put8(ack + bytes, code); + bytes += qq_put8(ack + bytes, bar); + bytes += qq_putdata(ack + bytes, (guint8 *) str, strlen(str)); + bytes += qq_put8(ack + bytes, bar); + bytes += qq_put16(ack + bytes, seq); + + g_free(str); + + if (bytes == ack_len) /* creation OK */ + qq_send_server_reply(gc, QQ_CMD_ACK_SYS_MSG, 0, ack, ack_len); + else + purple_debug_error("QQ", + "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); +} + +static void _qq_process_msg_sys_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) +{ + qq_data *qd = (qq_data *) gc->proto_data; + gchar *title, *content; + + g_return_if_fail(from != NULL && to != NULL); + + title = g_strdup_printf(_("From %s:"), from); + content = g_strdup_printf(_("%s"), msg_utf8); + + if (qd->is_show_notice) { + purple_notify_info(gc, _("QQ Server Notice"), title, content); + } else { + purple_debug_info("QQ", "QQ Server notice from %s:\n%s", from, msg_utf8); +} + g_free(title); + g_free(content); +} + +static void process_server_msg(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) +{ + qq_data *qd; + gchar **segments, *code, *from, *to, *msg, *msg_utf8; + int funct; + + g_return_if_fail(data != NULL && data_len != 0); + + qd = (qq_data *) gc->proto_data; + + if (NULL == (segments = split_data(data, data_len, "\x1f", 4))) + return; + code = segments[0]; + from = segments[1]; + to = segments[2]; + msg = segments[3]; + + _qq_send_packet_ack_msg_sys(gc, code[0], strtol(from, NULL, 10), seq); + + if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ + purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to); + g_strfreev(segments); + return; + } + + msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + if (from == NULL && msg_utf8) { + purple_debug_error("QQ", "Recv NULL sys msg to [%s], discard\n", to); + g_strfreev(segments); + g_free(msg_utf8); + return; + } + + funct = strtol(code, NULL, 10); + switch (funct) { + case QQ_SERVER_BUDDY_ADDED: + case QQ_SERVER_BUDDY_ADD_REQUEST: + case QQ_SERVER_BUDDY_ADDED_ME: + case QQ_SERVER_BUDDY_REJECTED_ME: + qq_process_buddy_from_server(gc, funct, from, to, msg_utf8); + break; + case QQ_SERVER_NOTICE: + _qq_process_msg_sys_notice(gc, from, to, msg_utf8); + break; + case QQ_SERVER_NEW_CLIENT: + purple_debug_warning("QQ", + "QQ Server has newer client than %s\n", qq_get_ver_desc(QQ_CLIENT)); + break; + default: + purple_debug_warning("QQ", "Recv unknown sys msg code: %s\nMsg: %s\n", code, msg_utf8); + } + g_free(msg_utf8); + g_strfreev(segments); +} + void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) { qq_data *qd; @@ -116,7 +219,7 @@ qq_process_recv_im(data, data_len, seq, gc); break; case QQ_CMD_RECV_MSG_SYS: - qq_process_msg_sys(data, data_len, seq, gc); + process_server_msg(data, data_len, seq, gc); break; case QQ_CMD_BUDDY_CHANGE_STATUS: qq_process_buddy_change_status(data, data_len, gc); @@ -189,7 +292,7 @@ } } -static void update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +void qq_update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) { qq_data *qd; gboolean is_new_turn = FALSE; @@ -244,7 +347,7 @@ switch (cmd) { case 0: - qq_request_buddy_info(gc, qd->uid, QQ_CMD_CLASS_UPDATE_ALL, QQ_BUDDY_INFO_UPDATE_ONLY); + qq_request_buddy_info(gc, qd->uid, QQ_CMD_CLASS_UPDATE_ALL, 0); break; case QQ_CMD_GET_BUDDY_INFO: qq_request_change_status(gc, QQ_CMD_CLASS_UPDATE_ALL); @@ -263,7 +366,7 @@ break; case QQ_CMD_GET_BUDDIES_ONLINE: /* last command */ - update_all_rooms(gc, 0, 0); + qq_update_all_rooms(gc, 0, 0); break; default: break; @@ -451,9 +554,8 @@ if (update_class == QQ_CMD_CLASS_NONE) return; - purple_debug_info("QQ", "Update class %d\n", update_class); if (update_class == QQ_CMD_CLASS_UPDATE_ALL) { - update_all_rooms(gc, room_cmd, room_id); + qq_update_all_rooms(gc, room_cmd, room_id); return; } if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) { @@ -506,9 +608,6 @@ /* now initiate QQ Qun, do it first as it may take longer to finish */ qq_group_init(gc); - /* Now goes on updating my icon/nickname, not showing info_window */ - qd->modifying_face = FALSE; - /* is_login, but we have packets before login */ qq_trans_process_remained(gc); @@ -555,20 +654,20 @@ case QQ_CMD_UPDATE_INFO: qq_process_modify_info_reply(data, data_len, gc); break; - case QQ_CMD_ADD_BUDDY_WO_AUTH: - qq_process_add_buddy_reply(data, data_len, seq, gc); + case QQ_CMD_BUDDY_ADD_NO_AUTH: + qq_process_buddy_add_no_auth(data, data_len, ship32, gc); break; - case QQ_CMD_DEL_BUDDY: - qq_process_remove_buddy_reply(data, data_len, gc); + case QQ_CMD_BUDDY_REMOVE: + qq_process_buddy_remove(data, data_len, gc); break; - case QQ_CMD_REMOVE_SELF: - qq_process_remove_self_reply(data, data_len, gc); + case QQ_CMD_REMOVE_ME: + qq_process_buddy_remove_me(data, data_len, gc); break; - case QQ_CMD_BUDDY_AUTH: - qq_process_add_buddy_auth_reply(data, data_len, gc); + case QQ_CMD_BUDDY_ADD_AUTH: + qq_process_buddy_add_auth(data, data_len, gc); break; case QQ_CMD_GET_BUDDY_INFO: - qq_process_get_buddy_info(data, data_len, gc); + qq_process_get_buddy_info(data, data_len, ship32, gc); break; case QQ_CMD_CHANGE_STATUS: qq_process_change_status_reply(data, data_len, gc); diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/qq_process.h --- a/libpurple/protocols/qq/qq_process.h Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.h Fri Sep 19 14:46:41 2008 +0000 @@ -34,6 +34,7 @@ QQ_CMD_CLASS_NONE = 0, QQ_CMD_CLASS_UPDATE_ALL, QQ_CMD_CLASS_UPDATE_ONLINE, + QQ_CMD_CLASS_UPDATE_BUDDY, QQ_CMD_CLASS_UPDATE_ROOM, }; @@ -49,5 +50,6 @@ void qq_update_all(PurpleConnection *gc, guint16 cmd); void qq_update_online(PurpleConnection *gc, guint16 cmd); void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); +void qq_update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); #endif diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/qq_trans.c --- a/libpurple/protocols/qq/qq_trans.c Mon Sep 15 12:55:33 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Fri Sep 19 14:46:41 2008 +0000 @@ -131,6 +131,7 @@ } trans->update_class = update_class; + trans->ship32 = ship32; return trans; } diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/sys_msg.c --- a/libpurple/protocols/qq/sys_msg.c Mon Sep 15 12:55:33 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +0,0 @@ -/** - * @file sys_msg.c - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "debug.h" -#include "internal.h" -#include "notify.h" -#include "request.h" - -#include "buddy_info.h" -#include "buddy_list.h" -#include "buddy_opt.h" -#include "char_conv.h" -#include "header_info.h" -#include "packet_parse.h" -#include "qq.h" -#include "qq_network.h" -#include "sys_msg.h" -#include "utils.h" - -enum { - QQ_MSG_SYS_BEING_ADDED = 0x01, - QQ_MSG_SYS_ADD_CONTACT_REQUEST = 0x02, - QQ_MSG_SYS_ADD_CONTACT_APPROVED = 0x03, - QQ_MSG_SYS_ADD_CONTACT_REJECTED = 0x04, - QQ_MSG_SYS_NOTICE= 0x06, - QQ_MSG_SYS_NEW_VERSION = 0x09 -}; - -/* Henry: private function for reading/writing of system log */ -static void _qq_sys_msg_log_write(PurpleConnection *gc, gchar *msg, gchar *from) -{ - PurpleLog *log; - PurpleAccount *account; - - account = purple_connection_get_account(gc); - - log = purple_log_new(PURPLE_LOG_IM, - "systemim", - account, - NULL, - time(NULL), - NULL - ); - purple_log_write(log, PURPLE_MESSAGE_SYSTEM, from, - time(NULL), msg); - purple_log_free(log); -} - -/* suggested by rakescar@linuxsir, can still approve after search */ -static void _qq_search_before_auth_with_gc_and_uid(gc_and_uid *g) -{ - PurpleConnection *gc; - guint32 uid; - gchar *nombre; - - g_return_if_fail(g != NULL); - - gc = g->gc; - uid = g->uid; - g_return_if_fail(gc != 0 && uid != 0); - - qq_send_packet_get_info(gc, uid, TRUE); /* we want to see window */ - - nombre = uid_to_purple_name(uid); - purple_request_action - (gc, NULL, _("Do you approve the requestion?"), "", - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), nombre, NULL, - g, 2, - _("Reject"), G_CALLBACK(qq_reject_add_request_with_gc_and_uid), - _("Approve"), G_CALLBACK(qq_approve_add_request_with_gc_and_uid)); - g_free(nombre); -} - -static void _qq_search_before_add_with_gc_and_uid(gc_and_uid *g) -{ - PurpleConnection *gc; - guint32 uid; - gchar *nombre; - - g_return_if_fail(g != NULL); - - gc = g->gc; - uid = g->uid; - g_return_if_fail(gc != 0 && uid != 0); - - qq_send_packet_get_info(gc, uid, TRUE); /* we want to see window */ - nombre = uid_to_purple_name(uid); - purple_request_action - (gc, NULL, _("Do you add the buddy?"), "", - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), nombre, NULL, - g, 2, - _("Cancel"), NULL, - _("Add"), G_CALLBACK(qq_add_buddy_with_gc_and_uid)); - g_free(nombre); -} - -/* Send ACK if the sys message needs an ACK */ -static void _qq_send_packet_ack_msg_sys(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) -{ - qq_data *qd; - guint8 bar, *ack; - gchar *str; - gint ack_len, bytes; - - qd = (qq_data *) gc->proto_data; - - str = g_strdup_printf("%d", from); - bar = 0x1e; - ack_len = 1 + 1 + strlen(str) + 1 + 2; - ack = g_newa(guint8, ack_len); - - bytes = 0; - bytes += qq_put8(ack + bytes, code); - bytes += qq_put8(ack + bytes, bar); - bytes += qq_putdata(ack + bytes, (guint8 *) str, strlen(str)); - bytes += qq_put8(ack + bytes, bar); - bytes += qq_put16(ack + bytes, seq); - - g_free(str); - - if (bytes == ack_len) /* creation OK */ - qq_send_server_reply(gc, QQ_CMD_ACK_SYS_MSG, 0, ack, ack_len); - else - purple_debug_error("QQ", - "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); -} - -/* when you are added by a person, QQ server will send sys message */ -static void _qq_process_msg_sys_being_added(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) -{ - gchar *message; - PurpleBuddy *b; - guint32 uid; - gc_and_uid *g; - gchar *name; - - g_return_if_fail(from != NULL && to != NULL); - - uid = strtol(from, NULL, 10); - name = uid_to_purple_name(uid); - b = purple_find_buddy(gc->account, name); - - if (b == NULL) { /* the person is not in my list */ - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = uid; /* only need to get value */ - message = g_strdup_printf(_("You have been added by %s"), from); - _qq_sys_msg_log_write(gc, message, from); - purple_request_action(gc, NULL, message, - _("Would you like to add him?"), - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), name, NULL, - g, 3, - _("Cancel"), NULL, - _("Add"), G_CALLBACK(qq_add_buddy_with_gc_and_uid), - _("Search"), G_CALLBACK(_qq_search_before_add_with_gc_and_uid)); - } else { - message = g_strdup_printf(_("%s added you [%s] to buddy list"), from, to); - _qq_sys_msg_log_write(gc, message, from); - purple_notify_info(gc, _("QQ Budy"), _("Successed:"), message); - } - - g_free(name); - g_free(message); -} - -/* you are rejected by the person */ -static void _qq_process_msg_sys_add_contact_rejected(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) -{ - gchar *message, *reason; - - g_return_if_fail(from != NULL && to != NULL); - - message = g_strdup_printf(_("Requestion rejected by %s"), from); - reason = g_strdup_printf(_("Message: %s"), msg_utf8); - _qq_sys_msg_log_write(gc, message, from); - - purple_notify_info(gc, _("QQ Buddy"), message, reason); - g_free(message); - g_free(reason); -} - -/* the buddy approves your request of adding him/her as your friend */ -static void _qq_process_msg_sys_add_contact_approved(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) -{ - gchar *message; - qq_data *qd; - - g_return_if_fail(from != NULL && to != NULL); - - qd = (qq_data *) gc->proto_data; - qq_add_buddy_by_recv_packet(gc, strtol(from, NULL, 10), TRUE, TRUE); - - message = g_strdup_printf(_("Requestion approved by %s"), from); - _qq_sys_msg_log_write(gc, message, from); - purple_notify_info(gc, _("QQ Buddy"), _("Notice:"), message); - - g_free(message); -} - -/* someone wants to add you to his buddy list */ -static void _qq_process_msg_sys_add_contact_request(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) -{ - gchar *message, *reason; - guint32 uid; - gc_and_uid *g, *g2; - PurpleBuddy *b; - gchar *name; - - g_return_if_fail(from != NULL && to != NULL); - - uid = strtol(from, NULL, 10); - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = uid; - - name = uid_to_purple_name(uid); - - /* TODO: this should go through purple_account_request_authorization() */ - message = g_strdup_printf(_("%s wants to add you [%s] as a friend"), from, to); - reason = g_strdup_printf(_("Message: %s"), msg_utf8); - _qq_sys_msg_log_write(gc, message, from); - - purple_request_action - (gc, NULL, message, reason, PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), name, NULL, - g, 3, - _("Reject"), - G_CALLBACK(qq_reject_add_request_with_gc_and_uid), - _("Approve"), - G_CALLBACK(qq_approve_add_request_with_gc_and_uid), - _("Search"), G_CALLBACK(_qq_search_before_auth_with_gc_and_uid)); - - g_free(message); - g_free(reason); - - /* XXX: Is this needed once the above goes through purple_account_request_authorization()? */ - b = purple_find_buddy(gc->account, name); - if (b == NULL) { /* the person is not in my list */ - g2 = g_new0(gc_and_uid, 1); - g2->gc = gc; - g2->uid = strtol(from, NULL, 10); - message = g_strdup_printf(_("%s is not in buddy list"), from); - purple_request_action(gc, NULL, message, - _("Would you add?"), PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), name, NULL, - g2, 3, - _("Cancel"), NULL, - _("Add"), G_CALLBACK(qq_add_buddy_with_gc_and_uid), - _("Search"), G_CALLBACK(_qq_search_before_add_with_gc_and_uid)); - g_free(message); - } - - g_free(name); -} - -static void _qq_process_msg_sys_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) -{ - qq_data *qd = (qq_data *) gc->proto_data; - gchar *title, *content; - - g_return_if_fail(from != NULL && to != NULL); - - title = g_strdup_printf(_("From %s:"), from); - content = g_strdup_printf(_("%s"), msg_utf8); - - if (qd->is_show_notice) { - purple_notify_info(gc, _("QQ Server Notice"), title, content); - } else { - purple_debug_info("QQ", "QQ Server notice from %s:\n%s", from, msg_utf8); -} - g_free(title); - g_free(content); -} - -void qq_process_msg_sys(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) -{ - qq_data *qd; - gchar **segments, *code, *from, *to, *msg, *msg_utf8; - - g_return_if_fail(data != NULL && data_len != 0); - - qd = (qq_data *) gc->proto_data; - - if (NULL == (segments = split_data(data, data_len, "\x1f", 4))) - return; - code = segments[0]; - from = segments[1]; - to = segments[2]; - msg = segments[3]; - - _qq_send_packet_ack_msg_sys(gc, code[0], strtol(from, NULL, 10), seq); - - if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ - purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to); - g_strfreev(segments); - return; - } - - msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); - if (from == NULL && msg_utf8) { - purple_debug_error("QQ", "Recv NULL sys msg to [%s], discard\n", to); - g_strfreev(segments); - g_free(msg_utf8); - return; - } - - switch (strtol(code, NULL, 10)) { - case QQ_MSG_SYS_BEING_ADDED: - _qq_process_msg_sys_being_added(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_ADD_CONTACT_REQUEST: - _qq_process_msg_sys_add_contact_request(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_ADD_CONTACT_APPROVED: - _qq_process_msg_sys_add_contact_approved(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_ADD_CONTACT_REJECTED: - _qq_process_msg_sys_add_contact_rejected(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_NOTICE: - _qq_process_msg_sys_notice(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_NEW_VERSION: - purple_debug_warning("QQ", - "QQ server says there is newer version than %s\n", qq_get_ver_desc(QQ_CLIENT)); - break; - default: - purple_debug_warning("QQ", "Recv unknown sys msg code: %s\n", code); - purple_debug_warning("QQ", "the msg is : %s\n", msg_utf8); - } - g_free(msg_utf8); - g_strfreev(segments); -} diff -r b72816d1a131 -r d57928c9dd8f libpurple/protocols/qq/sys_msg.h --- a/libpurple/protocols/qq/sys_msg.h Mon Sep 15 12:55:33 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/** - * @file sys_msg.h - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _QQ_SYS_MSG_H_ -#define _QQ_SYS_MSG_H_ - -#include -#include "connection.h" - -void qq_process_msg_sys(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc); - -#endif