Mercurial > pidgin
comparison libgaim/protocols/qq/buddy_info.c @ 14192:60b1bc8dbf37
[gaim-migrate @ 16863]
Renamed 'core' to 'libgaim'
committer: Tailor Script <tailor@pidgin.im>
author | Evan Schoenberg <evan.s@dreskin.net> |
---|---|
date | Sat, 19 Aug 2006 01:50:10 +0000 |
parents | |
children | 584cbd1628d0 |
comparison
equal
deleted
inserted
replaced
14191:009db0b357b5 | 14192:60b1bc8dbf37 |
---|---|
1 /** | |
2 * The QQ2003C protocol plugin | |
3 * | |
4 * for gaim | |
5 * | |
6 * Copyright (C) 2004 Puzzlebird | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
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 | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 | |
23 #include "internal.h" | |
24 #include "debug.h" | |
25 #include "notify.h" | |
26 #include "request.h" | |
27 | |
28 #include "utils.h" | |
29 #include "packet_parse.h" | |
30 #include "buddy_info.h" | |
31 #include "char_conv.h" | |
32 #include "crypt.h" | |
33 #include "header_info.h" | |
34 #include "keep_alive.h" | |
35 #include "send_core.h" | |
36 | |
37 /* Below is all of the information necessary to reconstruct the various | |
38 * information fields that one can set in the official client. When we need | |
39 * to know about a specific field (e.g., should "city" be a choice | |
40 * or text field?), we can simply look it up from the template. Note that | |
41 * there are a number of unidentified fields. */ | |
42 typedef struct _info_field { | |
43 gchar *title; | |
44 gchar *id; /* used by gaim_request fields */ | |
45 gint pos; | |
46 gchar *group; | |
47 gint group_pos; /* for display order in the UI */ | |
48 gint choice; /* indicates which character array contains the choices */ | |
49 gboolean customizable; /* whether a user can enter any text as a value, regardless of choice arrays */ | |
50 gchar *value; | |
51 } info_field; | |
52 | |
53 static const info_field info_template_data[] = { | |
54 { N_("User ID"), "uid", 0, QQ_MAIN_INFO, 0, QQ_NO_CHOICE, TRUE, NULL }, | |
55 { N_("Nickname"), "nick", 1, QQ_MAIN_INFO, 1, QQ_NO_CHOICE, TRUE, NULL }, | |
56 { N_("Country/Region"), "country", 2, QQ_MAIN_INFO, 5, QQ_COUNTRY, TRUE, NULL }, | |
57 { N_("Province/State"), "province", 3, QQ_MAIN_INFO, 6, QQ_PROVINCE, TRUE, NULL }, | |
58 { N_("Zipcode"), "zipcode", 4, QQ_EXTRA_INFO, 7, QQ_NO_CHOICE, TRUE, NULL }, | |
59 { N_("Address"), "address", 5, QQ_EXTRA_INFO, 6, QQ_NO_CHOICE, TRUE, NULL }, | |
60 { N_("Phone Number"), "tel", 6, QQ_EXTRA_INFO, 9, QQ_NO_CHOICE, TRUE, NULL }, | |
61 { N_("Age"), "age", 7, QQ_MAIN_INFO, 3, QQ_NO_CHOICE, TRUE, NULL }, | |
62 { N_("Gender"), "gender", 8, QQ_MAIN_INFO, 4, QQ_GENDER, FALSE, NULL }, | |
63 { N_("Name"), "name", 9, QQ_MAIN_INFO, 2, QQ_NO_CHOICE, TRUE, NULL }, | |
64 { N_("Email"), "email", 10, QQ_EXTRA_INFO, 5, QQ_NO_CHOICE, TRUE, NULL }, | |
65 { "pager_sn", "pager_sn", 11, QQ_MISC, 0, QQ_NO_CHOICE, TRUE, NULL }, | |
66 { "pager_num", "pager_num", 12, QQ_MISC, 1, QQ_NO_CHOICE, TRUE, NULL }, | |
67 { "pager_sp", "pager_sp", 13, QQ_MISC, 2, QQ_NO_CHOICE, TRUE, NULL }, | |
68 { "pager_base_num", "pager_base_num", 14, QQ_MISC, 3, QQ_NO_CHOICE, TRUE, NULL }, | |
69 { "pager_type", "pager_type", 15, QQ_MISC, 4, QQ_NO_CHOICE, TRUE, NULL }, | |
70 { N_("Occupation"), "occupation", 16, QQ_EXTRA_INFO, 1, QQ_OCCUPATION, TRUE, NULL }, | |
71 { N_("Homepage"), "homepage", 17, QQ_EXTRA_INFO, 10, QQ_NO_CHOICE, TRUE, NULL }, | |
72 { "auth_type", "auth_type", 18, QQ_MISC, 5, QQ_NO_CHOICE, TRUE, NULL }, | |
73 { "unknown1", "unknown1", 19, QQ_MISC, 6, QQ_NO_CHOICE, TRUE, NULL }, | |
74 { "unknown2", "unknown2", 20, QQ_MISC, 7, QQ_NO_CHOICE, TRUE, NULL }, | |
75 { "face", "face", 21, QQ_MISC, 8, QQ_NO_CHOICE, TRUE, NULL }, | |
76 { N_("Cellphone Number"), "hp_num", 22, QQ_EXTRA_INFO, 8, QQ_NO_CHOICE, TRUE, NULL }, | |
77 { "hp_type", "hp_type", 23, QQ_MISC, 9, QQ_NO_CHOICE, TRUE, NULL }, | |
78 { N_("Personal Introduction"), "intro", 24, QQ_PERSONAL_INTRO, 0, QQ_NO_CHOICE, TRUE, NULL }, | |
79 { N_("City"), "city", 25, QQ_MAIN_INFO, 7, QQ_NO_CHOICE, TRUE, NULL }, | |
80 { "unknown3", "unknown3", 26, QQ_MISC, 10, QQ_NO_CHOICE, TRUE, NULL }, | |
81 { "unknown4", "unknown4", 27, QQ_MISC, 11, QQ_NO_CHOICE, TRUE, NULL }, | |
82 { "unknown5", "unknown5", 28, QQ_MISC, 12, QQ_NO_CHOICE, TRUE, NULL }, | |
83 { "is_open_hp", "is_open_hp", 29, QQ_MISC, 13, QQ_NO_CHOICE, TRUE, NULL }, | |
84 { "is_open_contact", "is_open_contact", 30, QQ_MISC, 14, QQ_NO_CHOICE, TRUE, NULL }, | |
85 { N_("College"), "college", 31, QQ_EXTRA_INFO, 4, QQ_NO_CHOICE, TRUE, NULL }, | |
86 { N_("Horoscope Symbol"), "horoscope", 32, QQ_EXTRA_INFO, 0, QQ_HOROSCOPE, FALSE, NULL }, | |
87 { N_("Zodiac Symbol"), "zodiac", 33, QQ_EXTRA_INFO, 2, QQ_ZODIAC, FALSE, NULL }, | |
88 { N_("Blood Type"), "blood", 34, QQ_EXTRA_INFO, 3, QQ_BLOOD, FALSE, NULL }, | |
89 { "qq_show", "qq_show", 35, QQ_MISC, 15, QQ_NO_CHOICE, TRUE, NULL }, | |
90 { "unknown6", "unknown6", 36, QQ_MISC, 16, QQ_NO_CHOICE, TRUE, NULL }, | |
91 { NULL, NULL, 0, NULL, 0, 0, 0, NULL } | |
92 }; | |
93 | |
94 /* TODO: translate these arrays to their English equivalents | |
95 * and move these characters to the zh_CN po file */ | |
96 static const gchar *horoscope_names[] = { | |
97 "-", "水瓶座", "双鱼座", "牡羊座", "金牛座", | |
98 "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", | |
99 "天蝎座", "射手座", "魔羯座", NULL | |
100 }; | |
101 | |
102 static const gchar *zodiac_names[] = { | |
103 "-", "鼠", "牛", "虎", "兔", | |
104 "龙", "蛇", "马", "羊", "猴", | |
105 "鸡", "狗", "猪", NULL | |
106 }; | |
107 | |
108 static const gchar *blood_types[] = { | |
109 "-", N_("A"), N_("B"), N_("O"), N_("AB"), N_("Other"), NULL | |
110 }; | |
111 | |
112 static const gchar *genders[] = { | |
113 N_("Male"), | |
114 N_("Female"), | |
115 NULL | |
116 }; | |
117 | |
118 static const gchar *country_names[] = { | |
119 "中国", "中国香港", "中国澳门", "中国台湾", | |
120 "新加坡", "马来西亚", "美国", NULL | |
121 }; | |
122 | |
123 static const gchar *province_names[] = { | |
124 "北京", "天津", "上海", "重庆", "香港", | |
125 "河北", "山西", "内蒙古", "辽宁", "吉林", | |
126 "黑龙江", "江西", "浙江", "江苏", "安徽", | |
127 "福建", "山东", "河南", "湖北", "湖南", | |
128 "广东", "广西", "海南", "四川", "贵州", | |
129 "云南", "西藏", "陕西", "甘肃", "宁夏", | |
130 "青海", "新疆", "台湾", "澳门", NULL | |
131 }; | |
132 | |
133 static const gchar *occupation_names[] = { | |
134 "全职", "兼职", "制造业", "商业", "失业中", | |
135 "学生", "工程师", "政府部门", "教育业", "服务行业", | |
136 "老板", "计算机业", "退休", "金融业", | |
137 "销售/广告/市场", NULL | |
138 }; | |
139 | |
140 static const gint choice_sizes[] = { 0, 13, 13, 6, 2, 7, 34, 15 }; | |
141 | |
142 | |
143 static const gchar *info_group_headers[] = { | |
144 QQ_MAIN_INFO, | |
145 QQ_EXTRA_INFO, | |
146 QQ_PERSONAL_INTRO, | |
147 QQ_MISC | |
148 }; | |
149 | |
150 static const gchar **choices[] = { | |
151 NULL, | |
152 horoscope_names, | |
153 zodiac_names, | |
154 blood_types, | |
155 genders, | |
156 country_names, | |
157 province_names, | |
158 occupation_names | |
159 }; | |
160 | |
161 /************************ info and info_field methods ************************/ | |
162 | |
163 /* Given an id, return the template for that field. | |
164 * Returns NULL if the id is not found. */ | |
165 static const info_field *info_field_get_template(const gchar *id) | |
166 { | |
167 const info_field *cur_field; | |
168 const gchar *cur_id; | |
169 | |
170 cur_field = info_template_data; | |
171 cur_id = cur_field->id; | |
172 while(cur_id != NULL) { | |
173 if (g_ascii_strcasecmp(cur_id, id) == 0) | |
174 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) | |
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(group, entry, info_field_compare); | |
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 the 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])) | |
229 return FALSE; | |
230 i = atoi(value); | |
231 if (i < 0 || i >= choice_sizes[choice]) | |
232 return FALSE; | |
233 return TRUE; | |
234 } | |
235 | |
236 /* formats a field for printing */ | |
237 static void append_field_to_str(gpointer field, gpointer str) | |
238 { | |
239 info_field *f; | |
240 gint choice; | |
241 gboolean valid_index; | |
242 gchar *value; | |
243 | |
244 f = (info_field *) field; | |
245 choice = f->choice; | |
246 valid_index = is_valid_index(f->value, choice); | |
247 if (choice && valid_index) value = g_strdup(choices[choice][atoi(f->value)]); | |
248 else value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT); | |
249 g_string_append_printf((GString *) str, "<b>%s:</b> %s<br />", | |
250 f->title, value); | |
251 g_free(value); | |
252 info_field_free(f); | |
253 } | |
254 | |
255 /* formats a group of information for printing */ | |
256 static void append_group_to_str(GString *str, const gchar *group_name, const gchar **info) | |
257 { | |
258 GList *group; | |
259 | |
260 group = info_get_group(info, group_name); | |
261 g_string_append_printf(str, "<b>%s</b><br /><br />", (*(info_field *) group->data).group); | |
262 g_list_foreach(group, append_field_to_str, str); | |
263 g_list_free(group); | |
264 g_string_append_printf(str, "<br />"); | |
265 } | |
266 | |
267 /* Takes a contact_info struct and outputs the appropriate fields in | |
268 * a printable format for our upcoming call to gaim_notify_userinfo. */ | |
269 static GString *info_to_str(const gchar **info) | |
270 { | |
271 GString *info_text; | |
272 | |
273 info_text = g_string_new(""); | |
274 append_group_to_str(info_text, QQ_MAIN_INFO, info); | |
275 append_group_to_str(info_text, QQ_EXTRA_INFO, info); | |
276 append_group_to_str(info_text, QQ_PERSONAL_INTRO, info); | |
277 /* append_group_to_str(info_text, QQ_MISC, info); */ | |
278 | |
279 return info_text; | |
280 } | |
281 | |
282 /************************ packets and UI management **************************/ | |
283 | |
284 /* send a packet to get detailed information of uid */ | |
285 void qq_send_packet_get_info(GaimConnection * gc, guint32 uid, gboolean show_window) | |
286 { | |
287 qq_data *qd; | |
288 gchar *uid_str; | |
289 qq_info_query *query; | |
290 | |
291 g_return_if_fail(gc != NULL && gc->proto_data != NULL && uid != 0); | |
292 | |
293 qd = (qq_data *) gc->proto_data; | |
294 uid_str = g_strdup_printf("%d", uid); | |
295 qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, (guint8 *) uid_str, strlen(uid_str)); | |
296 | |
297 query = g_new0(qq_info_query, 1); | |
298 query->uid = uid; | |
299 query->show_window = show_window; | |
300 query->modify_info = FALSE; | |
301 qd->info_query = g_list_append(qd->info_query, query); | |
302 | |
303 g_free(uid_str); | |
304 } | |
305 | |
306 /* set up the fields requesting personal information and send a get_info packet | |
307 * for myself */ | |
308 void qq_prepare_modify_info(GaimConnection *gc) | |
309 { | |
310 qq_data *qd; | |
311 GList *ql; | |
312 qq_info_query *query; | |
313 | |
314 qd = (qq_data *) gc->proto_data; | |
315 qq_send_packet_get_info(gc, qd->uid, FALSE); | |
316 /* traverse backwards so we get the most recent info_query */ | |
317 for (ql = g_list_last(qd->info_query); ql != NULL; ql = g_list_previous(ql)) { | |
318 query = ql->data; | |
319 if (query->uid == qd->uid) | |
320 query->modify_info = TRUE; | |
321 } | |
322 } | |
323 | |
324 /* send packet to modify personal information */ | |
325 void qq_send_packet_modify_info(GaimConnection *gc, contact_info *info) | |
326 { | |
327 gchar *info_field[QQ_CONTACT_FIELDS]; | |
328 gint i; | |
329 guint8 *raw_data, *cursor, bar; | |
330 | |
331 g_return_if_fail(gc != NULL && info != NULL); | |
332 | |
333 bar = 0x1f; | |
334 raw_data = g_newa(guint8, MAX_PACKET_SIZE - 128); | |
335 cursor = raw_data; | |
336 | |
337 g_memmove(info_field, info, sizeof(gchar *) * QQ_CONTACT_FIELDS); | |
338 | |
339 create_packet_b(raw_data, &cursor, bar); | |
340 | |
341 /* important!, skip the first uid entry */ | |
342 for (i = 1; i < QQ_CONTACT_FIELDS; i++) { | |
343 create_packet_b(raw_data, &cursor, bar); | |
344 create_packet_data(raw_data, &cursor, (guint8 *) info_field[i], strlen(info_field[i])); | |
345 } | |
346 create_packet_b(raw_data, &cursor, bar); | |
347 | |
348 qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, TRUE, 0, TRUE, raw_data, cursor - raw_data); | |
349 | |
350 } | |
351 | |
352 static void modify_info_cancel_cb(modify_info_data *mid) | |
353 { | |
354 qq_data *qd; | |
355 | |
356 qd = (qq_data *) mid->gc->proto_data; | |
357 qd->modifying_info = FALSE; | |
358 | |
359 g_list_free(mid->misc); | |
360 g_free(mid); | |
361 } | |
362 | |
363 /* Runs through all of the fields in the modify info UI and puts | |
364 * their values into the outgoing packet. */ | |
365 static void parse_field(gpointer field, gpointer outgoing_info) | |
366 { | |
367 GaimRequestField *f; | |
368 gchar **segments, *value; | |
369 const info_field *ft; | |
370 const gchar *id; | |
371 | |
372 f = (GaimRequestField *) field; | |
373 segments = (gchar **) outgoing_info; | |
374 id = gaim_request_field_get_id(f); | |
375 ft = info_field_get_template(id); | |
376 if (ft->choice && !ft->customizable) { | |
377 value = g_strdup_printf("%d", gaim_request_field_choice_get_value(f)); | |
378 } else { | |
379 value = (gchar *) gaim_request_field_string_get_value(f); | |
380 if (value == NULL) | |
381 value = g_strdup("-"); | |
382 else | |
383 value = utf8_to_qq(value, QQ_CHARSET_DEFAULT); | |
384 } | |
385 segments[ft->pos] = value; | |
386 } | |
387 | |
388 /* dumps the uneditable information straight into the outgoing packet */ | |
389 static void parse_misc_field(gpointer field, gpointer outgoing_info) | |
390 { | |
391 info_field *f; | |
392 gchar **segments; | |
393 | |
394 f = (info_field *) field; | |
395 segments = (gchar **) outgoing_info; | |
396 segments[f->pos] = g_strdup(f->value); | |
397 info_field_free(f); | |
398 } | |
399 | |
400 /* Runs through all of the information fields and copies them into an | |
401 * outgoing packet, then sends that packet. */ | |
402 static void modify_info_ok_cb(modify_info_data *mid, GaimRequestFields *fields) | |
403 { | |
404 GaimConnection *gc; | |
405 qq_data *qd; | |
406 GList *list, *groups, *group_node; | |
407 gchar *info_field[QQ_CONTACT_FIELDS]; | |
408 contact_info *info; | |
409 gint i; | |
410 | |
411 gc = mid->gc; | |
412 qd = (qq_data *) gc->proto_data; | |
413 qd->modifying_info = FALSE; | |
414 list = mid->misc; | |
415 g_list_foreach(list, parse_misc_field, info_field); | |
416 g_list_free(list); | |
417 groups = gaim_request_fields_get_groups(fields); | |
418 while(groups) { | |
419 group_node = groups; | |
420 list = gaim_request_field_group_get_fields(group_node->data); | |
421 g_list_foreach(list, parse_field, info_field); | |
422 groups = g_list_remove_link(groups, group_node); | |
423 } | |
424 info = (contact_info *) info_field; | |
425 | |
426 qq_send_packet_modify_info(gc, info); | |
427 g_free(mid); | |
428 for (i = 0; i < QQ_CONTACT_FIELDS; i++) | |
429 g_free(info_field[i]); | |
430 } | |
431 | |
432 /* Sets up the display for one group of information. This includes | |
433 * managing which fields in the UI should be textfields and | |
434 * which choices, and also mapping ints to choice values when appropriate. */ | |
435 static void setup_group(gpointer field, gpointer group) | |
436 { | |
437 info_field *f; | |
438 GaimRequestFieldGroup *g; | |
439 GaimRequestField *rf; | |
440 gint choice, index, j; | |
441 gboolean customizable, valid_index, multiline; | |
442 gchar *id, *value; | |
443 | |
444 f = (info_field *) field; | |
445 g = (GaimRequestFieldGroup *) group; | |
446 choice = f->choice; | |
447 customizable = f->customizable; | |
448 id = f->id; | |
449 valid_index = TRUE; | |
450 | |
451 if (!choice || customizable) { | |
452 valid_index = is_valid_index(f->value, choice); | |
453 multiline = id == "intro"; | |
454 if (valid_index) { | |
455 index = atoi(f->value); | |
456 value = (gchar *) choices[choice][index]; | |
457 } else { | |
458 value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT); | |
459 } | |
460 rf = gaim_request_field_string_new(id, f->title, value, multiline); | |
461 } else { | |
462 index = atoi(f->value); | |
463 value = (gchar *) choices[choice][index]; | |
464 rf = gaim_request_field_choice_new(id, f->title, index); | |
465 j = 0; | |
466 while(choices[choice][j] != NULL) | |
467 gaim_request_field_choice_add(rf, choices[choice][j++]); | |
468 } | |
469 gaim_request_field_group_add_field(g, rf); | |
470 if (!valid_index) | |
471 g_free(value); | |
472 info_field_free(f); | |
473 } | |
474 | |
475 /* Takes the info returned by a get_info packet for the user and sets up | |
476 * a form using those values and the info_template. */ | |
477 static void create_modify_info_dialogue(GaimConnection *gc, const gchar **info) | |
478 { | |
479 qq_data *qd; | |
480 GaimRequestFields *fields; | |
481 GaimRequestFieldGroup *group; | |
482 GaimRequestField *field; | |
483 GList *group_list; | |
484 modify_info_data *mid; | |
485 gint i; | |
486 | |
487 /* so we only have one dialog open at a time */ | |
488 qd = (qq_data *) gc->proto_data; | |
489 if (!qd->modifying_info) { | |
490 qd->modifying_info = TRUE; | |
491 | |
492 fields = gaim_request_fields_new(); | |
493 | |
494 /* we only care about the first 3 groups, not the miscellaneous stuff */ | |
495 for (i = 0; i < 3; i++) { | |
496 group = gaim_request_field_group_new(info_group_headers[i]); | |
497 gaim_request_fields_add_group(fields, group); | |
498 group_list = info_get_group(info, info_group_headers[i]); | |
499 g_list_foreach(group_list, setup_group, group); | |
500 g_list_free(group_list); | |
501 } | |
502 | |
503 field = gaim_request_fields_get_field(fields, "uid"); | |
504 gaim_request_field_string_set_editable(field, FALSE); | |
505 | |
506 mid = g_new0(modify_info_data, 1); | |
507 mid->gc = gc; | |
508 mid->misc = info_get_group(info, info_group_headers[3]); | |
509 | |
510 gaim_request_fields(gc, _("Modify my information"), | |
511 _("Modify my information"), NULL, fields, | |
512 _("Update my information"), G_CALLBACK(modify_info_ok_cb), | |
513 _("Cancel"), G_CALLBACK(modify_info_cancel_cb), | |
514 mid); | |
515 } | |
516 } | |
517 | |
518 /* process the reply of modify_info packet */ | |
519 void qq_process_modify_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc) | |
520 { | |
521 qq_data *qd; | |
522 gint len; | |
523 guint8 *data; | |
524 | |
525 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
526 g_return_if_fail(buf != NULL && buf_len != 0); | |
527 | |
528 qd = (qq_data *) gc->proto_data; | |
529 len = buf_len; | |
530 data = g_newa(guint8, len); | |
531 | |
532 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { | |
533 data[len] = '\0'; | |
534 if (qd->uid == atoi((gchar *) data)) { /* return should be my uid */ | |
535 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Update info ACK OK\n"); | |
536 gaim_notify_info(gc, NULL, _("Your information has been updated"), NULL); | |
537 } | |
538 } else { | |
539 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt modify info reply\n"); | |
540 } | |
541 } | |
542 | |
543 /* after getting info or modify myself, refresh the buddy list accordingly */ | |
544 void qq_refresh_buddy_and_myself(contact_info *info, GaimConnection *gc) | |
545 { | |
546 GaimBuddy *b; | |
547 qq_data *qd; | |
548 qq_buddy *q_bud; | |
549 gchar *alias_utf8; | |
550 | |
551 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
552 qd = (qq_data *) gc->proto_data; | |
553 | |
554 alias_utf8 = qq_to_utf8(info->nick, QQ_CHARSET_DEFAULT); | |
555 if (qd->uid == strtol(info->uid, NULL, 10)) { /* it is me */ | |
556 qd->my_icon = strtol(info->face, NULL, 10); | |
557 if (alias_utf8 != NULL) | |
558 gaim_account_set_alias(gc->account, alias_utf8); | |
559 } | |
560 /* update buddy list (including myself, if myself is the buddy) */ | |
561 b = gaim_find_buddy(gc->account, uid_to_gaim_name(strtol(info->uid, NULL, 10))); | |
562 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; | |
563 if (q_bud != NULL) { /* I have this buddy */ | |
564 q_bud->age = strtol(info->age, NULL, 10); | |
565 q_bud->gender = strtol(info->gender, NULL, 10); | |
566 q_bud->icon = strtol(info->face, NULL, 10); | |
567 if (alias_utf8 != NULL) | |
568 q_bud->nickname = g_strdup(alias_utf8); | |
569 qq_update_buddy_contact(gc, q_bud); | |
570 } | |
571 g_free(alias_utf8); | |
572 } | |
573 | |
574 /* process reply to get_info packet */ | |
575 void qq_process_get_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc) | |
576 { | |
577 gint len; | |
578 guint8 *data; | |
579 gchar **segments; | |
580 qq_info_query *query; | |
581 qq_data *qd; | |
582 contact_info *info; | |
583 GList *list, *query_list; | |
584 GString *info_text; | |
585 | |
586 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
587 g_return_if_fail(buf != NULL && buf_len != 0); | |
588 | |
589 qd = (qq_data *) gc->proto_data; | |
590 list = query_list = NULL; | |
591 len = buf_len; | |
592 data = g_newa(guint8, len); | |
593 info = NULL; | |
594 | |
595 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { | |
596 if (NULL == (segments = split_data(data, len, "\x1e", QQ_CONTACT_FIELDS))) | |
597 return; | |
598 | |
599 info = (contact_info *) segments; | |
600 qq_refresh_buddy_and_myself(info, gc); | |
601 | |
602 query_list = qd->info_query; | |
603 /* ensure we're processing the right query */ | |
604 while (query_list) { | |
605 query = (qq_info_query *) query_list->data; | |
606 if (query->uid == atoi(info->uid)) { | |
607 if (query->show_window) { | |
608 info_text = info_to_str((const gchar **) segments); | |
609 gaim_notify_userinfo(gc, info->uid, info_text->str, NULL, NULL); | |
610 g_string_free(info_text, TRUE); | |
611 } else if (query->modify_info) { | |
612 create_modify_info_dialogue(gc, (const gchar **) segments); | |
613 } | |
614 qd->info_query = g_list_remove(qd->info_query, qd->info_query->data); | |
615 g_free(query); | |
616 break; | |
617 } | |
618 query_list = query_list->next; | |
619 } | |
620 | |
621 g_strfreev(segments); | |
622 } else { | |
623 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt get info reply\n"); | |
624 } | |
625 } | |
626 | |
627 void qq_info_query_free(qq_data *qd) | |
628 { | |
629 gint i; | |
630 qq_info_query *p; | |
631 | |
632 g_return_if_fail(qd != NULL); | |
633 | |
634 i = 0; | |
635 while (qd->info_query != NULL) { | |
636 p = (qq_info_query *) (qd->info_query->data); | |
637 qd->info_query = g_list_remove(qd->info_query, p); | |
638 g_free(p); | |
639 i++; | |
640 } | |
641 gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d info queries are freed!\n", i); | |
642 } |