📄 buddy_info.c
字号:
/* 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(); 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); 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 = purple_request_field_string_new("intro", QQ_INTRO, info->intro, TRUE); purple_request_field_group_add_field(group, field); /* 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); purple_request_fields(gc, _("Modify my information"), _("Modify my information"), NULL, fields, _("Update my information"), G_CALLBACK(modify_info_ok_cb), _("Cancel"), G_CALLBACK(modify_info_cancel_cb), purple_connection_get_account(gc), NULL, NULL, mid); }}/* process the reply of modify_info packet */void qq_process_modify_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc){ qq_data *qd; gint len; guint8 *data; g_return_if_fail(buf != NULL && buf_len != 0); qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { data[len] = '\0'; if (qd->uid == atoi((gchar *) data)) { /* return should be my uid */ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Update info ACK OK\n"); purple_notify_info(gc, NULL, _("Your information has been updated"), NULL); } } else { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt modify info reply\n"); }}static void _qq_send_packet_modify_face(PurpleConnection *gc, gint face_num){ PurpleAccount *account = purple_connection_get_account(gc); PurplePresence *presence = purple_account_get_presence(account); qq_data *qd = (qq_data *) gc->proto_data; gint offset; if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) { offset = 2; } else if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY) || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY)) { offset = 1; } else { offset = 0; } qd->my_icon = 3 * (face_num - 1) + offset; qd->modifying_face = TRUE; qq_send_packet_get_info(gc, qd->uid, FALSE);}void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile){ gchar *data; gsize len; if (!g_file_get_contents(iconfile, &data, &len, NULL)) g_return_if_reached(); else { purple_buddy_icons_set_for_user(account, who, data, len, icon_num); }}/* TODO: custom faces for QQ members and users with level >= 16 */void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img){ gchar *icon; gint icon_num; gint icon_len; PurpleAccount *account = purple_connection_get_account(gc); const gchar *icon_path = purple_account_get_buddy_icon_path(account); const gchar *buddy_icon_dir = qq_buddy_icon_dir(); gint prefix_len = strlen(QQ_ICON_PREFIX); gint suffix_len = strlen(QQ_ICON_SUFFIX); gint dir_len = strlen(buddy_icon_dir); gchar *errmsg = g_strdup_printf(_("Setting custom faces is not currently supported. Please choose an image from %s."), buddy_icon_dir); gboolean icon_global = purple_account_get_bool(gc->account, "use-global-buddyicon", TRUE); if (!icon_path) icon_path = ""; icon_len = strlen(icon_path) - dir_len - 1 - prefix_len - suffix_len; /* make sure we're using an appropriate icon */ if (!(g_ascii_strncasecmp(icon_path, buddy_icon_dir, dir_len) == 0 && icon_path[dir_len] == G_DIR_SEPARATOR && g_ascii_strncasecmp(icon_path + dir_len + 1, QQ_ICON_PREFIX, prefix_len) == 0 && g_ascii_strncasecmp(icon_path + dir_len + 1 + prefix_len + icon_len, QQ_ICON_SUFFIX, suffix_len) == 0 && icon_len <= 3)) { if (icon_global) purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", errmsg); else purple_notify_error(gc, _("Invalid QQ Face"), errmsg, NULL); g_free(errmsg); return; } /* strip everything but number */ icon = g_strndup(icon_path + dir_len + 1 + prefix_len, icon_len); icon_num = strtol(icon, NULL, 10); g_free(icon); /* ensure face number in proper range */ if (icon_num > QQ_FACES) { if (icon_global) purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", errmsg); else purple_notify_error(gc, _("Invalid QQ Face"), errmsg, NULL); g_free(errmsg); return; } g_free(errmsg); /* tell server my icon changed */ _qq_send_packet_modify_face(gc, icon_num); /* display in blist */ qq_set_buddy_icon_for_user(account, account->username, icon, icon_path);}static void _qq_update_buddy_icon(PurpleAccount *account, const gchar *name, gint face){ PurpleBuddy *buddy; gchar *icon_num_str = face_to_icon_str(face); const gchar *old_icon_num = NULL; if ((buddy = purple_find_buddy(account, name))) old_icon_num = purple_buddy_icons_get_checksum_for_user(buddy); if (old_icon_num == NULL || strcmp(icon_num_str, old_icon_num)) { gchar *icon_path; icon_path = g_strconcat(qq_buddy_icon_dir(), G_DIR_SEPARATOR_S, QQ_ICON_PREFIX, icon_num_str, QQ_ICON_SUFFIX, NULL); qq_set_buddy_icon_for_user(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 */void qq_refresh_buddy_and_myself(contact_info *info, PurpleConnection *gc){ PurpleBuddy *b; qq_data *qd; qq_buddy *q_bud; gchar *alias_utf8, *purple_name; PurpleAccount *account = purple_connection_get_account(gc); qd = (qq_data *) gc->proto_data; purple_name = uid_to_purple_name(strtol(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); if (alias_utf8 != NULL) purple_account_set_alias(account, alias_utf8); } /* update buddy list (including myself, if myself is the buddy) */ 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); 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); } g_free(purple_name); g_free(alias_utf8);}/* process reply to get_info packet */void qq_process_get_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc){ gint len; guint8 *data; gchar **segments; qq_info_query *query; qq_data *qd; contact_info *info; GList *list, *query_list; PurpleNotifyUserInfo *user_info; g_return_if_fail(buf != NULL && buf_len != 0); qd = (qq_data *) gc->proto_data; list = query_list = NULL; len = buf_len; data = g_newa(guint8, len); info = NULL; if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { if (NULL == (segments = split_data(data, len, "\x1e", QQ_CONTACT_FIELDS))) 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, segments); } 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); break; } query_list = query_list->next; } g_strfreev(segments); } else { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt get info reply\n"); }}void qq_info_query_free(qq_data *qd){ gint i; qq_info_query *p; g_return_if_fail(qd != NULL); i = 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); i++; } purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d info queries are freed!\n", i);}void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid){ guint8 buf[5]; guint32 tmp = g_htonl(uid); buf[0] = 0; memcpy(buf+1, &tmp, 4); qq_send_cmd(gc, QQ_CMD_GET_LEVEL, TRUE, 0, TRUE, buf, 5);}void qq_send_packet_get_buddies_levels(PurpleConnection *gc){ guint8 *buf, *tmp; guint16 size; qq_buddy *q_bud; qq_data *qd = (qq_data *) gc->proto_data; GList *node = qd->buddies; if (qd->buddies) { /* server only sends back levels for online buddies, no point * in asking for anyone else */ size = 4*g_list_length(qd->buddies) + 1; buf = g_new0(guint8, size); tmp = buf + 1; while (node != NULL) { guint32 tmp4; q_bud = (qq_buddy *) node->data; if (q_bud != NULL) { tmp4 = g_htonl(q_bud->uid); memcpy(tmp, &tmp4, 4); tmp += 4; } node = node->next; } qq_send_cmd(gc, QQ_CMD_GET_LEVEL, TRUE, 0, TRUE, buf, size); g_free(buf); }}void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc){ guint32 uid, onlineTime; guint16 level, timeRemainder; gchar *purple_name; PurpleBuddy *b; qq_buddy *q_bud; gint decr_len, i; guint8 *decr_buf, *tmp; PurpleAccount *account = purple_connection_get_account(gc); qq_data *qd = (qq_data *) gc->proto_data; decr_len = buf_len; decr_buf = g_new0(guint8, buf_len); if (!qq_crypt(DECRYPT, buf, buf_len, qd->session_key, decr_buf, &decr_len)) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Couldn't decrypt get level packet\n"); } decr_len--; if (decr_len % 12 != 0) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Get levels list of abnormal length. Truncating last %d bytes.\n", decr_len % 12); decr_len -= (decr_len % 12); } tmp = decr_buf + 1; /* this byte seems random */ /* purple_debug(PURPLE_DEBUG_INFO, "QQ", "Byte one of get_level packet: %d\n", buf[0]); */ for (i = 0; i < decr_len; i += 12) { uid = g_ntohl(*(guint32 *) tmp); tmp += 4; onlineTime = g_ntohl(*(guint32 *) tmp); tmp += 4; level = g_ntohs(*(guint16 *) tmp); tmp += 2; timeRemainder = g_ntohs(*(guint16 *) tmp); tmp += 2; /* purple_debug(PURPLE_DEBUG_INFO, "QQ", "Level packet entry:\nuid: %d\nonlineTime: %d\nlevel: %d\ntimeRemainder: %d\n", uid, onlineTime, level, timeRemainder); */ purple_name = uid_to_purple_name(uid); b = purple_find_buddy(account, purple_name); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud != NULL || uid == qd->uid) { if (q_bud) { q_bud->onlineTime = onlineTime; q_bud->level = level; q_bud->timeRemainder = timeRemainder; } if (uid == qd->uid) { qd->my_level = level; } } else { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Got an online buddy %d, but not in my buddy list\n", uid); } g_free(purple_name); } g_free(decr_buf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -