Mercurial > pidgin
comparison src/protocols/qq/buddy_info.c @ 13989:16102b9c5c4a
[gaim-migrate @ 16562]
*Eliminated all Gtk-related code from the prpl. Notably, this included the group ("Qun") administrative dialog and a dialog for setting and viewing personal information. Code for the latter now uses the gaim UI, while the former is currently disabled.
*Disabled a few non-functional/non-essential menu actions. These included: IP lookup, system logging, about dialog, and qq_buddy_menu.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Huetsch <markhuetsch> |
---|---|
date | Mon, 24 Jul 2006 13:39:12 +0000 |
parents | 983fd420e86b |
children | e6977f9435a1 |
comparison
equal
deleted
inserted
replaced
13988:4d5cc9e4cb12 | 13989:16102b9c5c4a |
---|---|
18 * You should have received a copy of the GNU General Public License | 18 * You should have received a copy of the GNU General Public License |
19 * along with this program; if not, write to the Free Software | 19 * along with this program; if not, write to the Free Software |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 */ | 21 */ |
22 | 22 |
23 // START OF FILE | |
24 /*****************************************************************************/ | |
25 #include "internal.h" // strlen, _("get_text) | 23 #include "internal.h" // strlen, _("get_text) |
26 #include "debug.h" // gaim_debug | 24 #include "debug.h" // gaim_debug |
27 #include "notify.h" // gaim_notify | 25 #include "notify.h" // gaim_notify |
26 #include "request.h" // gaim_request_fields_new | |
28 | 27 |
29 #include "utils.h" // uid_to_gaim_name | 28 #include "utils.h" // uid_to_gaim_name |
30 #include "packet_parse.h" // MAX_PACKET_SIZE | 29 #include "packet_parse.h" // MAX_PACKET_SIZE |
31 #include "buddy_info.h" // | 30 #include "buddy_info.h" // |
32 #include "char_conv.h" // qq_to_utf8 | 31 #include "char_conv.h" // qq_to_utf8 |
33 #include "crypt.h" // qq_crypt | 32 #include "crypt.h" // qq_crypt |
34 #include "header_info.h" // cmd alias | 33 #include "header_info.h" // cmd alias |
35 #include "infodlg.h" // info_window | |
36 #include "keep_alive.h" // qq_update_buddy_contact | 34 #include "keep_alive.h" // qq_update_buddy_contact |
37 #include "send_core.h" // qq_send_cmd | 35 #include "send_core.h" // qq_send_cmd |
38 | 36 |
39 // amount of fiedls in user info | 37 // Below is all of the information necessary to reconstruct the various |
40 #define QQ_CONTACT_FIELDS 37 | 38 // information fields that one can set in the official client. When we need |
41 | 39 // to know about a specific field (e.g., should "city" be a choice |
42 // There is no user id stored in the reply packet for information query | 40 // or text field?), we can simply look it up from the template. Note that |
43 // we have to manually store the query, so that we know the query source | 41 // there are a number of unidentified fields. |
44 typedef struct _qq_info_query { | 42 |
45 guint32 uid; | 43 typedef struct _info_field { |
46 gboolean show_window; | 44 gchar *title; |
47 contact_info *ret_info; | 45 gchar *id; // used by gaim_request fields |
48 } qq_info_query; | 46 gint pos; |
49 | 47 gchar *group; |
50 /*****************************************************************************/ | 48 gint group_pos; // for display order in the UI |
51 // send a packet to get detailed information of uid, | 49 gint choice; // indicates which character array contains the choices |
52 // if show_window, a info window will be display upon receiving a reply | 50 gboolean customizable; // whether a user can enter any text as a value, regardless of choice arrays |
51 gchar *value; | |
52 } info_field; | |
53 | |
54 static const info_field info_template_data[] = { | |
55 { N_("User ID"), "uid", 0, QQ_MAIN_INFO, 0, QQ_NO_CHOICE, TRUE, NULL }, | |
56 { N_("Nickname"), "nick", 1, QQ_MAIN_INFO, 1, QQ_NO_CHOICE, TRUE, NULL }, | |
57 { N_("Country/Region"), "country", 2, QQ_MAIN_INFO, 5, QQ_COUNTRY, TRUE, NULL }, | |
58 { N_("Province/State"), "province", 3, QQ_MAIN_INFO, 6, QQ_PROVINCE, TRUE, NULL }, | |
59 { N_("Zipcode"), "zipcode", 4, QQ_EXTRA_INFO, 7, QQ_NO_CHOICE, TRUE, NULL }, | |
60 { N_("Address"), "address", 5, QQ_EXTRA_INFO, 6, QQ_NO_CHOICE, TRUE, NULL }, | |
61 { N_("Phone Number"), "tel", 6, QQ_EXTRA_INFO, 9, QQ_NO_CHOICE, TRUE, NULL }, | |
62 { N_("Age"), "age", 7, QQ_MAIN_INFO, 3, QQ_NO_CHOICE, TRUE, NULL }, | |
63 { N_("Gender"), "gender", 8, QQ_MAIN_INFO, 4, QQ_GENDER, FALSE, NULL }, | |
64 { N_("Name"), "name", 9, QQ_MAIN_INFO, 2, QQ_NO_CHOICE, TRUE, NULL }, | |
65 { N_("Email"), "email", 10, QQ_EXTRA_INFO, 5, QQ_NO_CHOICE, TRUE, NULL }, | |
66 { "pager_sn", "pager_sn", 11, QQ_MISC, 0, QQ_NO_CHOICE, TRUE, NULL }, | |
67 { "pager_num", "pager_num", 12, QQ_MISC, 1, QQ_NO_CHOICE, TRUE, NULL }, | |
68 { "pager_sp", "pager_sp", 13, QQ_MISC, 2, QQ_NO_CHOICE, TRUE, NULL }, | |
69 { "pager_base_num", "pager_base_num", 14, QQ_MISC, 3, QQ_NO_CHOICE, TRUE, NULL }, | |
70 { "pager_type", "pager_type", 15, QQ_MISC, 4, QQ_NO_CHOICE, TRUE, NULL }, | |
71 { N_("Occupation"), "occupation", 16, QQ_EXTRA_INFO, 1, QQ_OCCUPATION, TRUE, NULL }, | |
72 { N_("Homepage"), "homepage", 17, QQ_EXTRA_INFO, 10, QQ_NO_CHOICE, TRUE, NULL }, | |
73 { "auth_type", "auth_type", 18, QQ_MISC, 5, QQ_NO_CHOICE, TRUE, NULL }, | |
74 { "unknown1", "unknown1", 19, QQ_MISC, 6, QQ_NO_CHOICE, TRUE, NULL }, | |
75 { "unknown2", "unknown2", 20, QQ_MISC, 7, QQ_NO_CHOICE, TRUE, NULL }, | |
76 { "face", "face", 21, QQ_MISC, 8, QQ_NO_CHOICE, TRUE, NULL }, | |
77 { N_("Cellphone Number"), "hp_num", 22, QQ_EXTRA_INFO, 8, QQ_NO_CHOICE, TRUE, NULL }, | |
78 { "hp_type", "hp_type", 23, QQ_MISC, 9, QQ_NO_CHOICE, TRUE, NULL }, | |
79 { N_("Personal Introduction"), "intro", 24, QQ_PERSONAL_INTRO, 0, QQ_NO_CHOICE, TRUE, NULL }, | |
80 { N_("City"), "city", 25, QQ_MAIN_INFO, 7, QQ_NO_CHOICE, TRUE, NULL }, | |
81 { "unknown3", "unknown3", 26, QQ_MISC, 10, QQ_NO_CHOICE, TRUE, NULL }, | |
82 { "unknown4", "unknown4", 27, QQ_MISC, 11, QQ_NO_CHOICE, TRUE, NULL }, | |
83 { "unknown5", "unknown5", 28, QQ_MISC, 12, QQ_NO_CHOICE, TRUE, NULL }, | |
84 { "is_open_hp", "is_open_hp", 29, QQ_MISC, 13, QQ_NO_CHOICE, TRUE, NULL }, | |
85 { "is_open_contact", "is_open_contact", 30, QQ_MISC, 14, QQ_NO_CHOICE, TRUE, NULL }, | |
86 { N_("College"), "college", 31, QQ_EXTRA_INFO, 4, QQ_NO_CHOICE, TRUE, NULL }, | |
87 { N_("Horoscope Symbol"), "horoscope", 32, QQ_EXTRA_INFO, 0, QQ_HOROSCOPE, FALSE, NULL }, | |
88 { N_("Zodiac Symbol"), "zodiac", 33, QQ_EXTRA_INFO, 2, QQ_ZODIAC, FALSE, NULL }, | |
89 { N_("Blood Type"), "blood", 34, QQ_EXTRA_INFO, 3, QQ_BLOOD, FALSE, NULL }, | |
90 { "qq_show", "qq_show", 35, QQ_MISC, 15, QQ_NO_CHOICE, TRUE, NULL }, | |
91 { "unknown6", "unknown6", 36, QQ_MISC, 16, QQ_NO_CHOICE, TRUE, NULL }, | |
92 { NULL, NULL, 0, NULL, 0, 0, 0, NULL } //NULL termination | |
93 }; | |
94 | |
95 //TODO: translate these arrays to their English equivalents | |
96 // and move these characters to the zh_CN po file | |
97 static const gchar *horoscope_names[] = { | |
98 "-", "水瓶座", "双鱼座", "牡羊座", "金牛座", | |
99 "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", | |
100 "天蝎座", "射手座", "魔羯座", NULL | |
101 }; | |
102 | |
103 static const gchar *zodiac_names[] = { | |
104 "-", "鼠", "牛", "虎", "兔", | |
105 "龙", "蛇", "马", "羊", "猴", | |
106 "鸡", "狗", "猪", NULL | |
107 }; | |
108 | |
109 static const gchar *blood_types[] = { | |
110 "其它", "A型", "B型", "O型", "AB型", NULL | |
111 }; | |
112 | |
113 static const gchar *genders[] = { | |
114 N_("Male"), | |
115 N_("Female"), | |
116 NULL | |
117 }; | |
118 | |
119 static const gchar *country_names[] = { | |
120 "中国", "中国香港", "中国澳门", "中国台湾", | |
121 "新加坡", "马来西亚", "美国", NULL | |
122 }; | |
123 | |
124 static const gchar *province_names[] = { | |
125 "北京", "天津", "上海", "重庆", "香港", | |
126 "河北", "山西", "内蒙古", "辽宁", "吉林", | |
127 "黑龙江", "江西", "浙江", "江苏", "安徽", | |
128 "福建", "山东", "河南", "湖北", "湖南", | |
129 "广东", "广西", "海南", "四川", "贵州", | |
130 "云南", "西藏", "陕西", "甘肃", "宁夏", | |
131 "青海", "新疆", "台湾", "澳门", NULL | |
132 }; | |
133 | |
134 static const gchar *occupation_names[] = { | |
135 "全职", "兼职", "制造业", "商业", "失业中", | |
136 "学生", "工程师", "政府部门", "教育业", "服务行业", | |
137 "老板", "计算机业", "退休", "金融业", | |
138 "销售/广告/市场", NULL | |
139 }; | |
140 | |
141 static const gint choice_sizes[] = { 0, 13, 13, 5, 2, 7, 34, 15 }; | |
142 | |
143 | |
144 static const gchar *info_group_headers[] = { | |
145 QQ_MAIN_INFO, | |
146 QQ_EXTRA_INFO, | |
147 QQ_PERSONAL_INTRO, | |
148 QQ_MISC | |
149 }; | |
150 | |
151 static const gchar **choices[] = { | |
152 NULL, | |
153 horoscope_names, | |
154 zodiac_names, | |
155 blood_types, | |
156 genders, | |
157 country_names, | |
158 province_names, | |
159 occupation_names | |
160 }; | |
161 | |
162 /*************** info and info_field methods *****************/ | |
163 | |
164 // Given an id, return the template for that field. | |
165 // Returns NULL if the id is not found. | |
166 static const info_field *info_field_get_template(const gchar *id) | |
167 { | |
168 const info_field *cur_field; | |
169 const gchar *cur_id; | |
170 | |
171 cur_field = info_template_data; | |
172 cur_id = cur_field->id; | |
173 while(cur_id != NULL) { | |
174 if (g_ascii_strcasecmp(cur_id, id) == 0) return cur_field; | |
175 cur_field++; | |
176 cur_id = cur_field->id; | |
177 } | |
178 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Info field with id %s not found!", id); | |
179 return NULL; | |
180 } | |
181 | |
182 // info_fields are compared by their group positions | |
183 static gint info_field_compare(gconstpointer a, gconstpointer b, gpointer unused) | |
184 { | |
185 return ((info_field *) a)->group_pos - ((info_field *) b)->group_pos; | |
186 } | |
187 | |
188 static void info_field_free(info_field *i) | |
189 { | |
190 g_free(i->value); | |
191 g_free(i); | |
192 } | |
193 | |
194 // Parses the info_template_data above and returns a newly-allocated list | |
195 // containing the desired fields from segments. This list is ordered by | |
196 // group_pos. | |
197 static GList *info_get_group(const gchar **info, const gchar *group_name) | |
198 { | |
199 const info_field *cur; | |
200 info_field *entry; | |
201 GList *group = NULL; | |
202 | |
203 cur = info_template_data; | |
204 while (cur->id != NULL) { | |
205 if (g_ascii_strcasecmp(group_name, cur->group) == 0) { | |
206 entry = g_memdup(cur, sizeof(info_field)); | |
207 entry->value = g_strdup(info[entry->pos]); | |
208 group = g_list_insert_sorted_with_data(group, entry, info_field_compare, NULL); | |
209 } | |
210 cur++; | |
211 } | |
212 | |
213 return group; | |
214 } | |
215 | |
216 // determines if the given text value and choice group require | |
217 // a lookup from the choice arrays | |
218 static gboolean is_valid_index(gchar *value, gint choice) | |
219 { | |
220 gint len, i; | |
221 | |
222 if (choice == 0) return FALSE; | |
223 len = strlen(value); | |
224 // the server sends us an ascii index and none of arrays has more than 99 | |
225 // elements | |
226 if (len > 3 || len == 0) return FALSE; | |
227 for (i = 0; i < len; i++) | |
228 if (!g_ascii_isdigit(value[i])) return FALSE; | |
229 i = atoi(value); | |
230 if (i < 0 || i >= choice_sizes[choice]) return FALSE; | |
231 return TRUE; | |
232 } | |
233 | |
234 // formats a field for printing | |
235 static void append_field_to_str(gpointer field, gpointer str) | |
236 { | |
237 info_field *f; | |
238 gint choice; | |
239 gboolean valid_index; | |
240 gchar *value; | |
241 | |
242 f = (info_field *) field; | |
243 choice = f->choice; | |
244 valid_index = is_valid_index(f->value, choice); | |
245 if (choice && valid_index) value = g_strdup(choices[choice][atoi(f->value)]); | |
246 else value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT); | |
247 g_string_append_printf((GString *) str, "<b>%s:</b> %s<br />", | |
248 f->title, value); | |
249 g_free(value); | |
250 info_field_free(f); | |
251 } | |
252 | |
253 // formats a group of information for printing | |
254 static void append_group_to_str(GString *str, const gchar *group_name, const gchar **info) | |
255 { | |
256 GList *group; | |
257 | |
258 group = info_get_group(info, group_name); | |
259 g_string_append_printf(str, "<b>%s</b><br /><br />", (*(info_field *) group->data).group); | |
260 g_list_foreach(group, append_field_to_str, str); | |
261 g_list_free(group); | |
262 g_string_append_printf(str, "<br />"); | |
263 } | |
264 | |
265 // takes a contact_info struct and outputs the appropriate fields in | |
266 // a printable format for our upcoming call to gaim_notify_userinfo | |
267 static GString *info_to_str(const gchar **info) | |
268 { | |
269 GString *info_text; | |
270 | |
271 info_text = g_string_new(""); | |
272 append_group_to_str(info_text, QQ_MAIN_INFO, info); | |
273 append_group_to_str(info_text, QQ_EXTRA_INFO, info); | |
274 append_group_to_str(info_text, QQ_PERSONAL_INTRO, info); | |
275 //if (QQ_DEBUG) append_group_to_str(info_text, QQ_MISC, info); | |
276 | |
277 return info_text; | |
278 } | |
279 | |
280 /*************** packets and UI management *****************/ | |
281 | |
282 // send a packet to get detailed information of uid | |
53 void qq_send_packet_get_info(GaimConnection * gc, guint32 uid, gboolean show_window) | 283 void qq_send_packet_get_info(GaimConnection * gc, guint32 uid, gboolean show_window) |
54 { | 284 { |
55 qq_data *qd; | 285 qq_data *qd; |
56 gchar *uid_str; | 286 gchar *uid_str; |
57 GList *list; | |
58 qq_info_query *query; | 287 qq_info_query *query; |
59 gboolean is_exist; | |
60 contact_info_window *info_window; | |
61 | 288 |
62 g_return_if_fail(gc != NULL && gc->proto_data != NULL && uid != 0); | 289 g_return_if_fail(gc != NULL && gc->proto_data != NULL && uid != 0); |
63 | 290 |
64 qd = (qq_data *) gc->proto_data; | 291 qd = (qq_data *) gc->proto_data; |
65 uid_str = g_strdup_printf("%d", uid); | 292 uid_str = g_strdup_printf("%d", uid); |
66 qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, uid_str, strlen(uid_str)); | 293 qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, (guint8 *) uid_str, strlen(uid_str)); |
67 | |
68 if (show_window) { // prepare the window | |
69 is_exist = FALSE; // see if there is already a window for this uid | |
70 list = qd->contact_info_window; | |
71 while (list != NULL) { | |
72 info_window = (contact_info_window *) list->data; | |
73 if (uid == info_window->uid) { | |
74 is_exist = TRUE; | |
75 break; | |
76 } else | |
77 list = list->next; | |
78 } // while list | |
79 if (!is_exist) { // create a new one | |
80 info_window = g_new0(contact_info_window, 1); | |
81 info_window->uid = uid; | |
82 qd->contact_info_window = g_list_append(qd->contact_info_window, info_window); | |
83 } // if !is_exist | |
84 } // if show_window | |
85 | 294 |
86 query = g_new0(qq_info_query, 1); | 295 query = g_new0(qq_info_query, 1); |
87 query->uid = uid; | 296 query->uid = uid; |
88 query->show_window = show_window; | 297 query->show_window = show_window; |
298 query->modify_info = FALSE; | |
89 qd->info_query = g_list_append(qd->info_query, query); | 299 qd->info_query = g_list_append(qd->info_query, query); |
90 | 300 |
91 g_free(uid_str); | 301 g_free(uid_str); |
92 } // qq_send_packet_get_info | 302 } |
93 | 303 |
94 /*****************************************************************************/ | 304 // set up the fields requesting personal information and send a get_info packet |
305 // for myself | |
306 void qq_prepare_modify_info(GaimConnection *gc) | |
307 { | |
308 qq_data *qd; | |
309 GList *ql; | |
310 qq_info_query *query; | |
311 | |
312 qd = (qq_data *) gc->proto_data; | |
313 qq_send_packet_get_info(gc, qd->uid, FALSE); | |
314 // traverse backwards so we get the most recent info_query | |
315 for (ql = g_list_last(qd->info_query); ql != NULL; ql = g_list_previous(ql)) { | |
316 query = ql->data; | |
317 if (query->uid == qd->uid) query->modify_info = TRUE; | |
318 } | |
319 } | |
320 | |
95 // send packet to modify personal information, and/or change password | 321 // send packet to modify personal information, and/or change password |
96 void qq_send_packet_modify_info(GaimConnection * gc, contact_info * info, gchar * new_passwd) | 322 void qq_send_packet_modify_info(GaimConnection *gc, contact_info *info, gchar *new_passwd) |
97 { | 323 { |
98 GaimAccount *a; | 324 GaimAccount *a; |
99 gchar *old_passwd, *info_field[QQ_CONTACT_FIELDS]; | 325 gchar *old_passwd, *info_field[QQ_CONTACT_FIELDS]; |
100 gint i; | 326 gint i; |
101 guint8 *raw_data, *cursor, bar; | 327 guint8 *raw_data, *cursor, bar; |
110 | 336 |
111 g_memmove(info_field, info, sizeof(gchar *) * QQ_CONTACT_FIELDS); | 337 g_memmove(info_field, info, sizeof(gchar *) * QQ_CONTACT_FIELDS); |
112 | 338 |
113 if (new_passwd == NULL || strlen(new_passwd) == 0) | 339 if (new_passwd == NULL || strlen(new_passwd) == 0) |
114 create_packet_b(raw_data, &cursor, bar); | 340 create_packet_b(raw_data, &cursor, bar); |
115 else { // we gonna change passwd | 341 else { // we're gonna change passwd |
116 create_packet_data(raw_data, &cursor, old_passwd, strlen(old_passwd)); | 342 create_packet_data(raw_data, &cursor, (guint8 *) old_passwd, strlen(old_passwd)); |
117 create_packet_b(raw_data, &cursor, bar); | 343 create_packet_b(raw_data, &cursor, bar); |
118 create_packet_data(raw_data, &cursor, new_passwd, strlen(new_passwd)); | 344 create_packet_data(raw_data, &cursor, (guint8 *) new_passwd, strlen(new_passwd)); |
119 } | 345 } |
120 | 346 |
121 // important!, skip the first uid entry | 347 // important!, skip the first uid entry |
122 for (i = 1; i < QQ_CONTACT_FIELDS; i++) { | 348 for (i = 1; i < QQ_CONTACT_FIELDS; i++) { |
123 create_packet_b(raw_data, &cursor, bar); | 349 create_packet_b(raw_data, &cursor, bar); |
124 create_packet_data(raw_data, &cursor, info_field[i], strlen(info_field[i])); | 350 create_packet_data(raw_data, &cursor, (guint8 *) info_field[i], strlen(info_field[i])); |
125 } | 351 } |
126 create_packet_b(raw_data, &cursor, bar); | 352 create_packet_b(raw_data, &cursor, bar); |
127 | 353 |
128 qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, TRUE, 0, TRUE, raw_data, cursor - raw_data); | 354 qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, TRUE, 0, TRUE, raw_data, cursor - raw_data); |
129 | 355 |
130 } // qq_send_packet_modify_info | 356 } |
131 | 357 |
132 /*****************************************************************************/ | 358 static void modify_info_cancel_cb(modify_info_data *mid) |
133 // process the reply of modidy_info packet | 359 { |
134 void qq_process_modify_info_reply(guint8 * buf, gint buf_len, GaimConnection * gc) | 360 g_list_free(mid->misc); |
361 g_free(mid); | |
362 } | |
363 | |
364 // runs through all of the fields in the modify info UI and put | |
365 // their values into the outgoing packet | |
366 static void parse_field(gpointer field, gpointer outgoing_info) | |
367 { | |
368 GaimRequestField *f; | |
369 gchar **segments, *value; | |
370 const info_field *ft; | |
371 const gchar *id; | |
372 | |
373 f = (GaimRequestField *) field; | |
374 segments = (gchar **) outgoing_info; | |
375 id = gaim_request_field_get_id(f); | |
376 ft = info_field_get_template(id); | |
377 if (ft->choice && !ft->customizable) | |
378 value = g_strdup_printf("%d", gaim_request_field_choice_get_value(f)); | |
379 else { | |
380 value = (gchar *) gaim_request_field_string_get_value(f); | |
381 if (value == NULL) value = g_strdup(""); | |
382 else value = utf8_to_qq(value, QQ_CHARSET_DEFAULT); | |
383 } | |
384 segments[ft->pos] = value; | |
385 } | |
386 | |
387 // dumps the uneditable information straight into the outgoing packet | |
388 static void parse_misc_field(gpointer field, gpointer outgoing_info) | |
389 { | |
390 info_field *f; | |
391 gchar **segments; | |
392 | |
393 f = (info_field *) field; | |
394 segments = (gchar **) outgoing_info; | |
395 segments[f->pos] = g_strdup(f->value); | |
396 info_field_free(f); | |
397 } | |
398 | |
399 // runs through all of the information fields and copies them into an | |
400 // outgoing packet, then sends that packet | |
401 static void modify_info_ok_cb(modify_info_data *mid, GaimRequestFields *fields) | |
402 { | |
403 GaimConnection *gc; | |
404 GList *list, *groups, *group_node; | |
405 gchar *info_field[QQ_CONTACT_FIELDS]; | |
406 contact_info *info; | |
407 gint i; | |
408 | |
409 gc = mid->gc; | |
410 list = mid->misc; | |
411 g_list_foreach(list, parse_misc_field, info_field); | |
412 g_list_free(list); | |
413 groups = gaim_request_fields_get_groups(fields); | |
414 while(groups) { | |
415 group_node = groups; | |
416 list = gaim_request_field_group_get_fields(group_node->data); | |
417 g_list_foreach(list, parse_field, info_field); | |
418 groups = g_list_remove_link(groups, group_node); | |
419 } | |
420 info = (contact_info *) info_field; | |
421 | |
422 qq_send_packet_modify_info(gc, info, NULL); | |
423 g_free(mid); | |
424 for (i = 0; i < QQ_CONTACT_FIELDS; i++) | |
425 g_free(info_field[i]); | |
426 } | |
427 | |
428 // Sets up the display for one group of information. This includes | |
429 // managing which fields in the UI should be textfields and | |
430 // which choices, and also mapping ints to choice values when appropriate. | |
431 static void setup_group(gpointer field, gpointer group) | |
432 { | |
433 info_field *f; | |
434 GaimRequestFieldGroup *g; | |
435 GaimRequestField *rf; | |
436 gint choice, index, j; | |
437 gboolean customizable, valid_index, multiline; | |
438 gchar *id, *value; | |
439 | |
440 f = (info_field *) field; | |
441 g = (GaimRequestFieldGroup *) group; | |
442 choice = f->choice; | |
443 customizable = f->customizable; | |
444 id = f->id; | |
445 valid_index = TRUE; | |
446 | |
447 if (!choice || customizable) { | |
448 valid_index = is_valid_index(f->value, choice); | |
449 multiline = id == "intro"; | |
450 if (valid_index) { | |
451 index = atoi(f->value); | |
452 value = (gchar *) choices[choice][index]; | |
453 } else value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT); | |
454 rf = gaim_request_field_string_new(id, f->title, value, multiline); | |
455 } else { | |
456 index = atoi(f->value); | |
457 value = (gchar *) choices[choice][index]; | |
458 rf = gaim_request_field_choice_new(id, f->title, index); | |
459 j = 0; | |
460 while(choices[choice][j] != NULL) | |
461 gaim_request_field_choice_add(rf, choices[choice][j++]); | |
462 } | |
463 gaim_request_field_group_add_field(g, rf); | |
464 if (!valid_index) g_free(value); | |
465 info_field_free(f); | |
466 } | |
467 | |
468 // Takes the info returned by a get_info packet for the user and sets up | |
469 // a form using those values and the info_template. | |
470 static void create_modify_info_dialogue(GaimConnection *gc, const gchar **info) | |
471 { | |
472 GaimRequestFields *fields; | |
473 GaimRequestFieldGroup *group; | |
474 GaimRequestField *field; | |
475 GList *group_list; | |
476 modify_info_data *mid; | |
477 gint i; | |
478 | |
479 fields = gaim_request_fields_new(); | |
480 | |
481 // we only care about the first 3 groups, not the miscellaneous stuff | |
482 for (i = 0; i < 3; i++) { | |
483 group = gaim_request_field_group_new(info_group_headers[i]); | |
484 gaim_request_fields_add_group(fields, group); | |
485 group_list = info_get_group(info, info_group_headers[i]); | |
486 g_list_foreach(group_list, setup_group, group); | |
487 g_list_free(group_list); | |
488 } | |
489 | |
490 //set this manually here instead of generating a new template column | |
491 field = gaim_request_fields_get_field(fields, "uid"); | |
492 gaim_request_field_string_set_editable(field, FALSE); | |
493 | |
494 //we need to pass the info that doesn't get modified as aux data | |
495 //because we'll still need it when we send the modify_info packet | |
496 mid = g_new0(modify_info_data, 1); | |
497 mid->gc = gc; | |
498 mid->misc = info_get_group(info, info_group_headers[3]); | |
499 | |
500 gaim_request_fields(gc, _("Modify my information"), | |
501 _("Modify my information"), NULL, fields, | |
502 _("Update my information"), G_CALLBACK(modify_info_ok_cb), | |
503 _("Cancel"), G_CALLBACK(modify_info_cancel_cb), | |
504 mid); | |
505 } | |
506 | |
507 // process the reply of modify_info packet | |
508 void qq_process_modify_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc) | |
135 { | 509 { |
136 qq_data *qd; | 510 qq_data *qd; |
137 gint len; | 511 gint len; |
138 guint8 *data; | 512 guint8 *data; |
139 | 513 |
143 qd = (qq_data *) gc->proto_data; | 517 qd = (qq_data *) gc->proto_data; |
144 len = buf_len; | 518 len = buf_len; |
145 data = g_newa(guint8, len); | 519 data = g_newa(guint8, len); |
146 | 520 |
147 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { | 521 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { |
148 if (qd->uid == atoi(data)) { // return should be my uid | 522 if (qd->uid == atoi((gchar *) data)) { // return should be my uid |
149 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Update info ACK OK\n"); | 523 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Update info ACK OK\n"); |
150 gaim_notify_info(gc, NULL, _("You information have been updated"), NULL); | 524 gaim_notify_info(gc, NULL, _("Your information has been updated"), NULL); |
151 } | 525 } |
152 } else | 526 } else |
153 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt modify info reply\n"); | 527 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt modify info reply\n"); |
154 | 528 |
155 } // qq_process_modify_info_reply | 529 } |
156 | 530 |
157 /*****************************************************************************/ | |
158 // after getting info or modify myself, refresh the buddy list accordingly | 531 // after getting info or modify myself, refresh the buddy list accordingly |
159 void qq_refresh_buddy_and_myself(contact_info * info, GaimConnection * gc) | 532 void qq_refresh_buddy_and_myself(contact_info *info, GaimConnection *gc) |
160 { | 533 { |
161 GaimBuddy *b; | 534 GaimBuddy *b; |
162 qq_data *qd; | 535 qq_data *qd; |
163 qq_buddy *q_bud; | 536 qq_buddy *q_bud; |
164 gchar *alias_utf8; | 537 gchar *alias_utf8; |
180 q_bud->gender = strtol(info->gender, NULL, 10); | 553 q_bud->gender = strtol(info->gender, NULL, 10); |
181 q_bud->icon = strtol(info->face, NULL, 10); | 554 q_bud->icon = strtol(info->face, NULL, 10); |
182 if (alias_utf8 != NULL) | 555 if (alias_utf8 != NULL) |
183 q_bud->nickname = g_strdup(alias_utf8); | 556 q_bud->nickname = g_strdup(alias_utf8); |
184 qq_update_buddy_contact(gc, q_bud); | 557 qq_update_buddy_contact(gc, q_bud); |
185 } // if q_bud | 558 } |
186 g_free(alias_utf8); | 559 g_free(alias_utf8); |
187 } // qq_refresh_buddy_and_myself | 560 } |
188 | 561 |
189 /*****************************************************************************/ | 562 // XXX When we don't have any immediate response, we send duplicate get info packets |
563 // to the server. If the server ends up responding to multiple packets, we get multiple | |
564 // modify info dialogues, which is annoying. Fix this. | |
565 | |
190 // process reply to get_info packet | 566 // process reply to get_info packet |
191 void qq_process_get_info_reply(guint8 * buf, gint buf_len, GaimConnection * gc) | 567 void qq_process_get_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc) |
192 { | 568 { |
193 gint len; | 569 gint len; |
194 guint8 *data; | 570 guint8 *data; |
195 gchar **segments; | 571 gchar **segments; |
196 qq_info_query *query; | 572 qq_info_query *query; |
197 qq_data *qd; | 573 qq_data *qd; |
198 contact_info *info; | 574 contact_info *info; |
199 contact_info_window *info_window; | |
200 gboolean show_window; | |
201 GList *list, *query_list; | 575 GList *list, *query_list; |
576 GString *info_text; | |
202 | 577 |
203 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | 578 g_return_if_fail(gc != NULL && gc->proto_data != NULL); |
204 g_return_if_fail(buf != NULL && buf_len != 0); | 579 g_return_if_fail(buf != NULL && buf_len != 0); |
205 | 580 |
206 qd = (qq_data *) gc->proto_data; | 581 qd = (qq_data *) gc->proto_data; |
215 | 590 |
216 info = (contact_info *) segments; | 591 info = (contact_info *) segments; |
217 qq_refresh_buddy_and_myself(info, gc); | 592 qq_refresh_buddy_and_myself(info, gc); |
218 | 593 |
219 query_list = qd->info_query; | 594 query_list = qd->info_query; |
220 show_window = FALSE; | 595 // ensure we're processing the right query |
221 while (query_list != NULL) { | 596 while (query_list) { |
222 query = (qq_info_query *) query_list->data; | 597 query = (qq_info_query *) query_list->data; |
223 if (query->uid == atoi(info->uid)) { | 598 if (query->uid == atoi(info->uid)) { |
224 show_window = query->show_window; | 599 if (query->show_window) { |
600 info_text = info_to_str((const gchar **) segments); | |
601 gaim_notify_userinfo(gc, info->uid, info_text->str, NULL, NULL); | |
602 g_string_free(info_text, TRUE); | |
603 } else if (query->modify_info) { | |
604 create_modify_info_dialogue(gc, (const gchar **) segments); | |
605 } | |
225 qd->info_query = g_list_remove(qd->info_query, qd->info_query->data); | 606 qd->info_query = g_list_remove(qd->info_query, qd->info_query->data); |
226 g_free(query); | 607 g_free(query); |
227 break; | 608 break; |
228 } | 609 } |
229 query_list = query_list->next; | 610 query_list = query_list->next; |
230 } // while query_list | |
231 | |
232 if (!show_window) { | |
233 g_strfreev(segments); | |
234 return; | |
235 } | 611 } |
236 // if not show_window, we can not find the window here either | 612 |
237 list = qd->contact_info_window; | |
238 while (list != NULL) { | |
239 info_window = (contact_info_window *) (list->data); | |
240 if (info_window->uid == atoi(info->uid)) { | |
241 if (info_window->window) | |
242 qq_refresh_contact_info_dialog(info, gc, info_window); | |
243 else | |
244 qq_show_contact_info_dialog(info, gc, info_window); | |
245 break; | |
246 } else | |
247 list = list->next; | |
248 } // while list | |
249 g_strfreev(segments); | 613 g_strfreev(segments); |
250 } else | 614 } else |
251 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt get info reply\n"); | 615 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt get info reply\n"); |
252 | 616 |
253 } // qq_process_get_info_reply | 617 } |
254 | 618 |
255 /*****************************************************************************/ | |
256 void qq_info_query_free(qq_data * qd) | 619 void qq_info_query_free(qq_data * qd) |
257 { | 620 { |
258 gint i; | 621 gint i; |
259 qq_info_query *p; | 622 qq_info_query *p; |
260 | 623 |
266 qd->info_query = g_list_remove(qd->info_query, p); | 629 qd->info_query = g_list_remove(qd->info_query, p); |
267 g_free(p); | 630 g_free(p); |
268 i++; | 631 i++; |
269 } | 632 } |
270 gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d info queries are freed!\n", i); | 633 gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d info queries are freed!\n", i); |
271 } // qq_add_buddy_request_free | 634 } |
272 | |
273 /*****************************************************************************/ | |
274 // END OF FILE |