# HG changeset patch # User Mark Huetsch # Date 1158944634 0 # Node ID 000b8c0631213b0d925f09db6ebcc08902f71722 # Parent 473b225e73520db6514cffcca42b97e8f84790a8 [gaim-migrate @ 17339] My previous implementation was a bit awkward. This requires less overhead. Also, let's only show those info fields that a buddy has actually filled out. committer: Tailor Script diff -r 473b225e7352 -r 000b8c063121 libgaim/protocols/qq/buddy_info.c --- a/libgaim/protocols/qq/buddy_info.c Fri Sep 22 16:05:09 2006 +0000 +++ b/libgaim/protocols/qq/buddy_info.c Fri Sep 22 17:03:54 2006 +0000 @@ -34,253 +34,200 @@ #include "keep_alive.h" #include "send_core.h" -/* Below is all of the information necessary to reconstruct the various - * information fields that one can set in the official client. When we need - * to know about a specific field (e.g., should "city" be a choice - * or text field?), we can simply look it up from the template. Note that - * there are a number of unidentified fields. */ -typedef struct _info_field { - gchar *title; - gchar *id; /* used by gaim_request fields */ - gint pos; - gchar *group; - gint group_pos; /* for display order in the UI */ - gint choice; /* indicates which character array contains the choices */ - gboolean customizable; /* whether a user can enter any text as a value, regardless of choice arrays */ - gchar *value; -} info_field; +#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") -static const info_field info_template_data[] = { - { N_("User ID"), "uid", 0, QQ_MAIN_INFO, 0, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Nickname"), "nick", 1, QQ_MAIN_INFO, 1, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Country/Region"), "country", 2, QQ_MAIN_INFO, 5, QQ_COUNTRY, TRUE, NULL }, - { N_("Province/State"), "province", 3, QQ_MAIN_INFO, 6, QQ_PROVINCE, TRUE, NULL }, - { N_("Zipcode"), "zipcode", 4, QQ_EXTRA_INFO, 7, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Address"), "address", 5, QQ_EXTRA_INFO, 6, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Phone Number"), "tel", 6, QQ_EXTRA_INFO, 9, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Age"), "age", 7, QQ_MAIN_INFO, 3, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Gender"), "gender", 8, QQ_MAIN_INFO, 4, QQ_GENDER, FALSE, NULL }, - { N_("Name"), "name", 9, QQ_MAIN_INFO, 2, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Email"), "email", 10, QQ_EXTRA_INFO, 5, QQ_NO_CHOICE, TRUE, NULL }, - { "pager_sn", "pager_sn", 11, QQ_MISC, 0, QQ_NO_CHOICE, TRUE, NULL }, - { "pager_num", "pager_num", 12, QQ_MISC, 1, QQ_NO_CHOICE, TRUE, NULL }, - { "pager_sp", "pager_sp", 13, QQ_MISC, 2, QQ_NO_CHOICE, TRUE, NULL }, - { "pager_base_num", "pager_base_num", 14, QQ_MISC, 3, QQ_NO_CHOICE, TRUE, NULL }, - { "pager_type", "pager_type", 15, QQ_MISC, 4, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Occupation"), "occupation", 16, QQ_EXTRA_INFO, 1, QQ_OCCUPATION, TRUE, NULL }, - { N_("Homepage"), "homepage", 17, QQ_EXTRA_INFO, 10, QQ_NO_CHOICE, TRUE, NULL }, - { "auth_type", "auth_type", 18, QQ_MISC, 5, QQ_NO_CHOICE, TRUE, NULL }, - { "unknown1", "unknown1", 19, QQ_MISC, 6, QQ_NO_CHOICE, TRUE, NULL }, - { "unknown2", "unknown2", 20, QQ_MISC, 7, QQ_NO_CHOICE, TRUE, NULL }, - { "face", "face", 21, QQ_MISC, 8, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Cellphone Number"), "hp_num", 22, QQ_EXTRA_INFO, 8, QQ_NO_CHOICE, TRUE, NULL }, - { "hp_type", "hp_type", 23, QQ_MISC, 9, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Personal Introduction"), "intro", 24, QQ_PERSONAL_INTRO, 0, QQ_NO_CHOICE, TRUE, NULL }, - { N_("City"), "city", 25, QQ_MAIN_INFO, 7, QQ_NO_CHOICE, TRUE, NULL }, - { "unknown3", "unknown3", 26, QQ_MISC, 10, QQ_NO_CHOICE, TRUE, NULL }, - { "unknown4", "unknown4", 27, QQ_MISC, 11, QQ_NO_CHOICE, TRUE, NULL }, - { "unknown5", "unknown5", 28, QQ_MISC, 12, QQ_NO_CHOICE, TRUE, NULL }, - { "is_open_hp", "is_open_hp", 29, QQ_MISC, 13, QQ_NO_CHOICE, TRUE, NULL }, - { "is_open_contact", "is_open_contact", 30, QQ_MISC, 14, QQ_NO_CHOICE, TRUE, NULL }, - { N_("College"), "college", 31, QQ_EXTRA_INFO, 4, QQ_NO_CHOICE, TRUE, NULL }, - { N_("Horoscope Symbol"), "horoscope", 32, QQ_EXTRA_INFO, 0, QQ_HOROSCOPE, FALSE, NULL }, - { N_("Zodiac Symbol"), "zodiac", 33, QQ_EXTRA_INFO, 2, QQ_ZODIAC, FALSE, NULL }, - { N_("Blood Type"), "blood", 34, QQ_EXTRA_INFO, 3, QQ_BLOOD, FALSE, NULL }, - { "qq_show", "qq_show", 35, QQ_MISC, 15, QQ_NO_CHOICE, TRUE, NULL }, - { "unknown6", "unknown6", 36, QQ_MISC, 16, QQ_NO_CHOICE, TRUE, NULL }, - { NULL, NULL, 0, NULL, 0, 0, 0, NULL } -}; - -/* TODO: translate these arrays to their English equivalents - * and move these characters to the zh_CN po file */ +#define QQ_HOROSCOPE_SIZE 13 static const gchar *horoscope_names[] = { - "-", "水瓶座", "双鱼座", "牡羊座", "金牛座", - "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", - "天蝎座", "射手座", "魔羯座", NULL -}; - -static const gchar *zodiac_names[] = { - "-", "鼠", "牛", "虎", "兔", - "龙", "蛇", "马", "羊", "猴", - "鸡", "狗", "猪", NULL -}; - -static const gchar *blood_types[] = { - "-", N_("A"), N_("B"), N_("O"), N_("AB"), N_("Other"), NULL -}; - -static const gchar *genders[] = { - N_("Male"), - N_("Female"), - NULL -}; - -static const gchar *country_names[] = { - "中国", "中国香港", "中国澳门", "中国台湾", - "新加坡", "马来西亚", "美国", NULL + "-", N_("Aquarius"), N_("Pisces"), N_("Aries"), N_("Taurus"), + N_("Gemini"), N_("Cancer"), N_("Leo"), N_("Virgo"), N_("Libra"), + N_("Scorpio"), N_("Sagittarius"), N_("Capricorn") }; -static const gchar *province_names[] = { - "北京", "天津", "上海", "重庆", "香港", - "河北", "山西", "内蒙古", "辽宁", "吉林", - "黑龙江", "江西", "浙江", "江苏", "安徽", - "福建", "山东", "河南", "湖北", "湖南", - "广东", "广西", "海南", "四川", "贵州", - "云南", "西藏", "陕西", "甘肃", "宁夏", - "青海", "新疆", "台湾", "澳门", NULL -}; - -static const gchar *occupation_names[] = { - "全职", "兼职", "制造业", "商业", "失业中", - "学生", "工程师", "政府部门", "教育业", "服务行业", - "老板", "计算机业", "退休", "金融业", - "销售/广告/市场", NULL +#define QQ_ZODIAC_SIZE 13 +static const gchar *zodiac_names[] = { + "-", N_("Rat"), N_("Ox"), N_("Tiger"), N_("Rabbit"), + N_("Dragon"), N_("Snake"), N_("Horse"), N_("Goat"), N_("Monkey"), + N_("Rooster"), N_("Dog"), N_("Pig") }; -static const gint choice_sizes[] = { 0, 13, 13, 6, 2, 7, 34, 15 }; - - -static const gchar *info_group_headers[] = { - QQ_MAIN_INFO, - QQ_EXTRA_INFO, - QQ_PERSONAL_INTRO, - QQ_MISC +#define QQ_BLOOD_SIZE 6 +static const gchar *blood_types[] = { + "-", "A", "B", "O", "AB", N_("Other") }; -static const gchar **choices[] = { - NULL, - horoscope_names, - zodiac_names, - blood_types, - genders, - country_names, - province_names, - occupation_names +#define QQ_GENDER_SIZE 2 +static const gchar *genders[] = { + N_("Male"), + N_("Female") }; -/************************ info and info_field methods ************************/ +#define QQ_CONTACT_FIELDS 37 -/* Given an id, return the template for that field. - * Returns NULL if the id is not found. */ -static const info_field *info_field_get_template(const gchar *id) -{ - const info_field *cur_field; - const gchar *cur_id; - - cur_field = info_template_data; - cur_id = cur_field->id; - while(cur_id != NULL) { - if (g_ascii_strcasecmp(cur_id, id) == 0) - return cur_field; - cur_field++; - cur_id = cur_field->id; - } - gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Info field with id %s not found!", id); - return NULL; -} - -/* info_fields are compared by their group positions */ -static gint info_field_compare(gconstpointer a, gconstpointer b) -{ - return ((info_field *) a)->group_pos - ((info_field *) b)->group_pos; -} +/* 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; -static void info_field_free(info_field *i) -{ - g_free(i->value); - g_free(i); -} - -/* Parses the info_template_data above and returns a newly-allocated list - * containing the desired fields from segments. This list is ordered by - * group_pos. */ -static GList *info_get_group(const gchar **info, const gchar *group_name) -{ - const info_field *cur; - info_field *entry; - GList *group = NULL; +/* 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 { + GaimConnection *gc; + contact_info *info; +} modify_info_data; - cur = info_template_data; - while (cur->id != NULL) { - if (g_ascii_strcasecmp(group_name, cur->group) == 0) { - entry = g_memdup(cur, sizeof(info_field)); - entry->value = g_strdup(info[entry->pos]); - group = g_list_insert_sorted(group, entry, info_field_compare); - } - cur++; - } - - return group; -} - -/* Determines if the given text value and choice group require - * a lookup from the choice arrays. */ -static gboolean is_valid_index(gchar *value, gint choice) +/* return -1 as a sentinel */ +static gint choice_index(const gchar *value, const gchar **choice, gint choice_size) { gint len, i; - if (choice == 0) return FALSE; len = strlen(value); - /* the server sends us an ascii index and none of the arrays has more than 99 - * elements */ - if (len > 3 || len == 0) return FALSE; - for (i = 0; i < len; i++) + if (len > 3 || len == 0) return -1; + for (i = 0; i < len; i++) { if (!g_ascii_isdigit(value[i])) - return FALSE; - i = atoi(value); - if (i < 0 || i >= choice_sizes[choice]) - return FALSE; - return TRUE; + return -1; + } + i = strtol(value, NULL, 10); + if (i >= choice_size) + return -1; + + return i; +} + +/* return should be freed */ +static gchar *field_value(const gchar *field, const gchar **choice, gint choice_size) +{ + gint index, len; + + 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; + } + } else { + if (strcmp(field, "-") != 0) { + return qq_to_utf8(field, QQ_CHARSET_DEFAULT); + } else { + return NULL; + } + } +} + +static void append_field_value(GString *info_text, const gchar *field, + const gchar *title, const gchar **choice, gint choice_size) +{ + gchar *value = field_value(field, choice, choice_size); + + if (value != NULL) { + g_string_append_printf(info_text, "
%s: %s", title, value); + g_free(value); + } } -/* formats a field for printing */ -static void append_field_to_str(gpointer field, gpointer str) +static GString *info_to_str(const contact_info *info) { - info_field *f; - gint choice; - gboolean valid_index; - gchar *value; - - f = (info_field *) field; - choice = f->choice; - valid_index = is_valid_index(f->value, choice); - if (choice && valid_index) value = g_strdup(choices[choice][atoi(f->value)]); - else value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT); - g_string_append_printf((GString *) str, "%s: %s
", - f->title, value); - g_free(value); - info_field_free(f); -} - -/* formats a group of information for printing */ -static void append_group_to_str(GString *str, const gchar *group_name, const gchar **info) -{ - GList *group; - - group = info_get_group(info, group_name); - g_string_append_printf(str, "%s

", (*(info_field *) group->data).group); - g_list_foreach(group, append_field_to_str, str); - g_list_free(group); - g_string_append_printf(str, "
"); -} - -/* Takes a contact_info struct and outputs the appropriate fields in - * a printable format for our upcoming call to gaim_notify_userinfo. */ -static GString *info_to_str(const gchar **info) -{ - GString *info_text; + GString *info_text, *extra_info; + const gchar *intro; + gint len; info_text = g_string_new(""); - append_group_to_str(info_text, QQ_MAIN_INFO, info); - append_group_to_str(info_text, QQ_EXTRA_INFO, info); - append_group_to_str(info_text, QQ_PERSONAL_INTRO, info); - /* append_group_to_str(info_text, QQ_MISC, info); */ + g_string_append_printf(info_text, "%s

", QQ_PRIMARY_INFORMATION); + g_string_append_printf(info_text, "%s: %s", QQ_NUMBER, info->uid); + append_field_value(info_text, info->nick, QQ_NICKNAME, NULL, 0); + append_field_value(info_text, info->name, QQ_NAME, NULL, 0); + append_field_value(info_text, info->age, QQ_AGE, NULL, 0); + append_field_value(info_text, info->gender, QQ_GENDER, genders, QQ_GENDER_SIZE); + append_field_value(info_text, info->country, QQ_COUNTRY, NULL, 0); + append_field_value(info_text, info->province, QQ_PROVINCE, NULL, 0); + append_field_value(info_text, info->city, QQ_CITY, NULL, 0); + + extra_info = g_string_new(""); + g_string_append_printf(extra_info, "

%s
", QQ_ADDITIONAL_INFORMATION); + len = extra_info->len; + append_field_value(extra_info, info->horoscope, QQ_HOROSCOPE, horoscope_names, QQ_HOROSCOPE_SIZE); + append_field_value(extra_info, info->occupation, QQ_OCCUPATION, NULL, 0); + append_field_value(extra_info, info->zodiac, QQ_ZODIAC, zodiac_names, QQ_ZODIAC_SIZE); + append_field_value(extra_info, info->blood, QQ_BLOOD, blood_types, QQ_BLOOD_SIZE); + append_field_value(extra_info, info->college, QQ_COLLEGE, NULL, 0); + append_field_value(extra_info, info->email, QQ_EMAIL, NULL, 0); + append_field_value(extra_info, info->address, QQ_ADDRESS, NULL, 0); + append_field_value(extra_info, info->zipcode, QQ_ZIPCODE, NULL, 0); + append_field_value(extra_info, info->hp_num, QQ_CELL, NULL, 0); + append_field_value(extra_info, info->tel, QQ_TELEPHONE, NULL, 0); + append_field_value(extra_info, info->homepage, QQ_HOMEPAGE, NULL, 0); + if (len != extra_info->len) + g_string_append(info_text, extra_info->str); + g_string_free(extra_info, TRUE); + + intro = field_value(info->intro, NULL, 0); + if (intro) { + g_string_append_printf(info_text, "

%s

", QQ_INTRO); + g_string_append(info_text, 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 info_text; } -/************************ packets and UI management **************************/ - /* send a packet to get detailed information of uid */ void qq_send_packet_get_info(GaimConnection *gc, guint32 uid, gboolean show_window) { @@ -320,26 +267,23 @@ } /* send packet to modify personal information */ -void qq_send_packet_modify_info(GaimConnection *gc, contact_info *info) +static void qq_send_packet_modify_info(GaimConnection *gc, gchar **segments) { - gchar *info_field[QQ_CONTACT_FIELDS]; gint i; guint8 *raw_data, *cursor, bar; - g_return_if_fail(gc != NULL && info != NULL); + g_return_if_fail(gc != NULL && segments != NULL); bar = 0x1f; raw_data = g_newa(guint8, MAX_PACKET_SIZE - 128); cursor = raw_data; - g_memmove(info_field, info, sizeof(gchar *) * QQ_CONTACT_FIELDS); - create_packet_b(raw_data, &cursor, bar); - /* important!, skip the first uid entry */ + /* 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 *) info_field[i], strlen(info_field[i])); + create_packet_data(raw_data, &cursor, (guint8 *) segments[i], strlen(segments[i])); } create_packet_b(raw_data, &cursor, bar); @@ -354,133 +298,122 @@ qd = (qq_data *) mid->gc->proto_data; qd->modifying_info = FALSE; - g_list_free(mid->misc); + g_strfreev((gchar **) mid->info); g_free(mid); } -/* Runs through all of the fields in the modify info UI and puts - * their values into the outgoing packet. */ -static void parse_field(gpointer field, gpointer outgoing_info) +static gchar *parse_field(GList **list, gboolean choice) { - GaimRequestField *f; - gchar **segments, *value; - const info_field *ft; - const gchar *id; + gchar *value; + GaimRequestField *field; - f = (GaimRequestField *) field; - segments = (gchar **) outgoing_info; - id = gaim_request_field_get_id(f); - ft = info_field_get_template(id); - if (ft->choice && !ft->customizable) { - value = g_strdup_printf("%d", gaim_request_field_choice_get_value(f)); + field = (GaimRequestField *) (*list)->data; + if (choice) { + value = g_strdup_printf("%d", gaim_request_field_choice_get_value(field)); } else { - value = (gchar *) gaim_request_field_string_get_value(f); + value = (gchar *) gaim_request_field_string_get_value(field); if (value == NULL) value = g_strdup("-"); else value = utf8_to_qq(value, QQ_CHARSET_DEFAULT); } - segments[ft->pos] = value; + *list = g_list_remove_link(*list, *list); + + return value; } -/* dumps the uneditable information straight into the outgoing packet */ -static void parse_misc_field(gpointer field, gpointer outgoing_info) -{ - info_field *f; - gchar **segments; - - f = (info_field *) field; - segments = (gchar **) outgoing_info; - segments[f->pos] = g_strdup(f->value); - info_field_free(f); -} - -/* Runs through all of the information fields and copies them into an - * outgoing packet, then sends that packet. */ +/* parse fields and send info packet */ static void modify_info_ok_cb(modify_info_data *mid, GaimRequestFields *fields) { GaimConnection *gc; qq_data *qd; - GList *list, *groups, *group_node; - gchar *info_field[QQ_CONTACT_FIELDS]; + GList *list, *groups; contact_info *info; - gint i; gc = mid->gc; qd = (qq_data *) gc->proto_data; qd->modifying_info = FALSE; - list = mid->misc; - g_list_foreach(list, parse_misc_field, info_field); - g_list_free(list); + + info = mid->info; + groups = gaim_request_fields_get_groups(fields); - while(groups) { - group_node = groups; - list = gaim_request_field_group_get_fields(group_node->data); - g_list_foreach(list, parse_field, info_field); - groups = g_list_remove_link(groups, group_node); - } - info = (contact_info *) info_field; + list = gaim_request_field_group_get_fields(groups->data); + info->uid = parse_field(&list, FALSE); + info->nick = parse_field(&list, FALSE); + info->name = parse_field(&list, FALSE); + info->age = parse_field(&list, FALSE); + info->gender = parse_field(&list, TRUE); + info->country = parse_field(&list, FALSE); + info->province = parse_field(&list, FALSE); + info->city = parse_field(&list, FALSE); + groups = g_list_remove_link(groups, groups); + list = gaim_request_field_group_get_fields(groups->data); + info->horoscope = parse_field(&list, TRUE); + info->occupation = parse_field(&list, FALSE); + info->zodiac = parse_field(&list, TRUE); + info->blood = parse_field(&list, TRUE); + info->college = parse_field(&list, FALSE); + info->email = parse_field(&list, FALSE); + info->address = parse_field(&list, FALSE); + info->zipcode = parse_field(&list, FALSE); + info->hp_num = parse_field(&list, FALSE); + info->tel = parse_field(&list, FALSE); + info->homepage = parse_field(&list, FALSE); + groups = g_list_remove_link(groups, groups); + list = gaim_request_field_group_get_fields(groups->data); + info->intro = parse_field(&list, FALSE); + groups = g_list_remove_link(groups, groups); - qq_send_packet_modify_info(gc, info); + qq_send_packet_modify_info(gc, (gchar **) info); + + g_strfreev((gchar **) mid->info); g_free(mid); - for (i = 0; i < QQ_CONTACT_FIELDS; i++) - g_free(info_field[i]); } -/* Sets up the display for one group of information. This includes - * managing which fields in the UI should be textfields and - * which choices, and also mapping ints to choice values when appropriate. */ -static void setup_group(gpointer field, gpointer group) +static GaimRequestFieldGroup *setup_field_group(GaimRequestFields *fields, const gchar *title) { - info_field *f; - GaimRequestFieldGroup *g; - GaimRequestField *rf; - gint choice, index, j; - gboolean customizable, valid_index, multiline; - gchar *id, *value; + GaimRequestFieldGroup *group; - f = (info_field *) field; - g = (GaimRequestFieldGroup *) group; - choice = f->choice; - customizable = f->customizable; - id = f->id; - valid_index = TRUE; + group = gaim_request_field_group_new(title); + gaim_request_fields_add_group(fields, group); + + return group; +} - if (!choice || customizable) { - valid_index = is_valid_index(f->value, choice); - multiline = id == "intro"; - if (valid_index) { - index = atoi(f->value); - value = (gchar *) choices[choice][index]; - } else { - value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT); - } - rf = gaim_request_field_string_new(id, f->title, value, multiline); - } else { - index = atoi(f->value); - value = (gchar *) choices[choice][index]; - rf = gaim_request_field_choice_new(id, f->title, index); - j = 0; - while(choices[choice][j] != NULL) - gaim_request_field_choice_add(rf, choices[choice][j++]); - } - gaim_request_field_group_add_field(g, rf); - if (!valid_index) - g_free(value); - info_field_free(f); +static void add_string_field_to_group(GaimRequestFieldGroup *group, + const gchar *id, const gchar *title, const gchar *value) +{ + GaimRequestField *field; + gchar *utf8_value; + + utf8_value = qq_to_utf8(value, QQ_CHARSET_DEFAULT); + field = gaim_request_field_string_new(id, title, utf8_value, FALSE); + gaim_request_field_group_add_field(group, field); + g_free(utf8_value); } -/* Takes the info returned by a get_info packet for the user and sets up - * a form using those values and the info_template. */ -static void create_modify_info_dialogue(GaimConnection *gc, const gchar **info) +static void add_choice_field_to_group(GaimRequestFieldGroup *group, + const gchar *id, const gchar *title, const gchar *value, + const gchar **choice, gint choice_size) +{ + GaimRequestField *field; + gint i, index; + + index = choice_index(value, choice, choice_size); + field = gaim_request_field_choice_new(id, title, index); + for (i = 0; i < choice_size; i++) + gaim_request_field_choice_add(field, choice[i]); + gaim_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(GaimConnection *gc, const contact_info *info) { qq_data *qd; + GaimRequestFieldGroup *group; GaimRequestFields *fields; - GaimRequestFieldGroup *group; GaimRequestField *field; - GList *group_list; modify_info_data *mid; - gint i; /* so we only have one dialog open at a time */ qd = (qq_data *) gc->proto_data; @@ -488,22 +421,58 @@ qd->modifying_info = TRUE; fields = gaim_request_fields_new(); - - /* we only care about the first 3 groups, not the miscellaneous stuff */ - for (i = 0; i < 3; i++) { - group = gaim_request_field_group_new(info_group_headers[i]); - gaim_request_fields_add_group(fields, group); - group_list = info_get_group(info, info_group_headers[i]); - g_list_foreach(group_list, setup_group, group); - g_list_free(group_list); - } - field = gaim_request_fields_get_field(fields, "uid"); + group = setup_field_group(fields, QQ_PRIMARY_INFORMATION); + field = gaim_request_field_string_new("uid", QQ_NUMBER, info->uid, FALSE); + gaim_request_field_group_add_field(group, field); gaim_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); + 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); + group = setup_field_group(fields, QQ_INTRO); + field = gaim_request_field_string_new("intro", QQ_INTRO, info->intro, TRUE); + gaim_request_field_group_add_field(group, field); + + /* prepare unmodifiable info */ mid = g_new0(modify_info_data, 1); mid->gc = gc; - mid->misc = info_get_group(info, info_group_headers[3]); + /* 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); gaim_request_fields(gc, _("Modify my information"), _("Modify my information"), NULL, fields, @@ -599,7 +568,7 @@ gchar *icon = g_strdup_printf("%i", qd->my_icon); qd->modifying_face = FALSE; memcpy(info->face, icon, 2); - qq_send_packet_modify_info(gc, info); + qq_send_packet_modify_info(gc, segments); g_free(icon); } @@ -611,11 +580,11 @@ query = (qq_info_query *) query_list->data; if (query->uid == atoi(info->uid)) { if (query->show_window) { - info_text = info_to_str((const gchar **) segments); + info_text = info_to_str(info); gaim_notify_userinfo(gc, info->uid, info_text->str, NULL, NULL); g_string_free(info_text, TRUE); } else if (query->modify_info) { - create_modify_info_dialogue(gc, (const gchar **) segments); + create_modify_info_dialogue(gc, info); } qd->info_query = g_list_remove(qd->info_query, qd->info_query->data); g_free(query); diff -r 473b225e7352 -r 000b8c063121 libgaim/protocols/qq/buddy_info.h --- a/libgaim/protocols/qq/buddy_info.h Fri Sep 22 16:05:09 2006 +0000 +++ b/libgaim/protocols/qq/buddy_info.h Fri Sep 22 17:03:54 2006 +0000 @@ -25,6 +25,7 @@ #include #include "connection.h" + #include "buddy_opt.h" #include "qq.h" @@ -39,80 +40,47 @@ #define QQ_BUDDY_GENDER_UNKNOWN 0xff 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 */ + 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; -/* 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; - -/* We get an info packet on ourselves before we modify our information. - * Even though not all of the information is currently modifiable, it still - * all needs to be there when we send out the modify info packet */ -typedef struct _modify_info_data { - GaimConnection *gc; - GList *misc, *node; -} modify_info_data; - -#define QQ_CONTACT_FIELDS 37 - -#define QQ_MAIN_INFO "Primary Information" -#define QQ_EXTRA_INFO "Detailed Information" -#define QQ_PERSONAL_INTRO "Personal Introduction" -#define QQ_MISC "Miscellaneous" - -#define QQ_NO_CHOICE 0 -#define QQ_HOROSCOPE 1 -#define QQ_ZODIAC 2 -#define QQ_BLOOD 3 -#define QQ_GENDER 4 -#define QQ_COUNTRY 5 -#define QQ_PROVINCE 6 -#define QQ_OCCUPATION 7 - void qq_refresh_buddy_and_myself(contact_info *info, GaimConnection *gc); void qq_send_packet_get_info(GaimConnection *gc, guint32 uid, gboolean show_window); -void qq_send_packet_modify_info(GaimConnection *gc, contact_info *info); void qq_prepare_modify_info(GaimConnection *gc); void qq_process_modify_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc); void qq_process_get_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc);