comparison libpurple/protocols/yahoo/yahoo_profile.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 2c33e35a5084
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
1 /*
2 * gaim
3 *
4 * Gaim is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
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
24 #define PHOTO_SUPPORT 1
25
26 #include "internal.h"
27 #include "debug.h"
28 #include "notify.h"
29 #include "util.h"
30 #if PHOTO_SUPPORT
31 #include "imgstore.h"
32 #endif
33
34 #include "yahoo.h"
35 #include "yahoo_friend.h"
36
37 typedef struct {
38 GaimConnection *gc;
39 char *name;
40 } YahooGetInfoData;
41
42 typedef enum profile_lang_id {
43 XX, DA, DE, EL,
44 EN, EN_GB,
45 ES_AR, ES_ES, ES_MX, ES_US,
46 FR_CA, FR_FR,
47 IT, JA, KO, NO, PT, SV,
48 ZH_CN, ZH_HK, ZH_TW, ZH_US
49 } profile_lang_id_t;
50
51 typedef struct profile_lang_node {
52 profile_lang_id_t lang;
53 char *last_updated_string;
54 char *det;
55 } profile_lang_node_t;
56
57 typedef struct profile_strings_node {
58 profile_lang_id_t lang;
59 char *lang_string; /* Only to make debugging output saner */
60 char *charset;
61 char *yahoo_id_string;
62 char *private_string;
63 char *no_answer_string;
64 char *my_email_string;
65 char *realname_string;
66 char *location_string;
67 char *age_string;
68 char *maritalstatus_string;
69 char *gender_string;
70 char *occupation_string;
71 char *hobbies_string;
72 char *latest_news_string;
73 char *favorite_quote_string;
74 char *links_string;
75 char *no_home_page_specified_string;
76 char *home_page_string;
77 char *no_cool_link_specified_string;
78 char *cool_link_1_string;
79 char *cool_link_2_string;
80 char *cool_link_3_string;
81 char *dummy;
82 } profile_strings_node_t;
83
84 typedef enum profile_state {
85 PROFILE_STATE_DEFAULT,
86 PROFILE_STATE_NOT_FOUND,
87 PROFILE_STATE_UNKNOWN_LANGUAGE
88 } profile_state_t;
89
90 typedef struct {
91 YahooGetInfoData *info_data;
92 GaimNotifyUserInfo *user_info;
93 char *url_buffer;
94 char *photo_url_text;
95 char *profile_url_text;
96 const profile_strings_node_t *strings;
97 const char *last_updated_string;
98 const char *title;
99 profile_state_t profile_state;
100 } YahooGetInfoStepTwoData;
101
102 /* Strings to determine the profile "language" (more accurately "locale").
103 * Strings in this list must be in the original charset in the profile.
104 * The "Last Updated" string is used, but sometimes is not sufficient to
105 * distinguish 2 locales with this (e.g., ES_ES from ES_US, or FR_CA from
106 * FR_FR, or EL from EN_GB), in which case a second string is added and
107 * such special cases must be placed before the more general case.
108 */
109 static const profile_lang_node_t profile_langs[] = {
110 { DA, "Opdateret sidste gang&nbsp;", NULL },
111 { DE, "Letzter Update&nbsp;", NULL },
112 { EL, "Last Updated:", "http://gr.profiles.yahoo.com" },
113 { EN_GB, "Last Update&nbsp;", "Favourite Quote" },
114 { EN, "Last Update:", NULL },
115 { EN, "Last Update&nbsp;", NULL },
116 { ES_AR, "\332ltima actualizaci\363n&nbsp;", NULL },
117 { ES_ES, "Actualizada el&nbsp;", "http://es.profiles.yahoo.com" },
118 { ES_MX, "Actualizada el &nbsp;", "http://mx.profiles.yahoo.com" },
119 { ES_US, "Actualizada el &nbsp;", NULL },
120 { FR_CA, "Derni\xe8re mise \xe0 jour", "http://cf.profiles.yahoo.com" },
121 { FR_FR, "Derni\xe8re mise \xe0 jour", NULL },
122 { IT, "Ultimo aggiornamento:", NULL },
123 { JA, "\xba\xc7\xbd\xaa\xb9\xb9\xbf\xb7\xc6\xfc\xa1\xa7", NULL },
124 { KO, "\xb0\xbb\xbd\xc5\x20\xb3\xaf\xc2\xa5&nbsp;", NULL },
125 { NO, "Sist oppdatert&nbsp;", NULL },
126 { PT, "\332ltima atualiza\347\343o&nbsp;", NULL },
127 { SV, "Senast uppdaterad&nbsp;", NULL },
128 { ZH_CN, "\xd7\xee\xba\xf3\xd0\xde\xb8\xc4\xc8\xd5\xc6\xda", NULL },
129 { ZH_HK, "\xb3\xcc\xaa\xf1\xa7\xf3\xb7\x73\xae\xc9\xb6\xa1", NULL },
130 { ZH_US, "\xb3\xcc\xab\xe1\xad\xd7\xa7\xef\xa4\xe9\xb4\xc1", "http://chinese.profiles.yahoo.com" },
131 { ZH_TW, "\xb3\xcc\xab\xe1\xad\xd7\xa7\xef\xa4\xe9\xb4\xc1", NULL },
132 { XX, NULL, NULL }
133 };
134
135 /* Strings in this list must be in UTF-8; &nbsp;'s should be specified as spaces. */
136 static const profile_strings_node_t profile_strings[] = {
137 { DA, "da", "ISO-8859-1",
138 "Yahoo! ID:",
139 "Privat",
140 "Intet svar",
141 "Min Email",
142 "Rigtige navn:",
143 "Opholdssted:",
144 "Alder:",
145 "Ægteskabelig status:",
146 "Køn:",
147 "Erhverv:",
148 "Hobbyer:",
149 "Sidste nyt:",
150 "Favoritcitat",
151 "Links",
152 "Ingen hjemmeside specificeret",
153 "Forside:",
154 "Intet cool link specificeret",
155 "Cool link 1:",
156 "Cool link 2:",
157 "Cool link 3:",
158 NULL
159 },
160 { DE, "de", "ISO-8859-1",
161 "Yahoo!-ID:",
162 "Privat",
163 "Keine Antwort",
164 "Meine E-Mail",
165 "Realer Name:",
166 "Ort:",
167 "Alter:",
168 "Familienstand:",
169 "Geschlecht:",
170 "Beruf:",
171 "Hobbys:",
172 "Neuste Nachrichten:",
173 "Mein Lieblingsspruch",
174 "Links",
175 "Keine Homepage angegeben",
176 "Homepage:",
177 "Keinen coolen Link angegeben",
178 "Cooler Link 1:",
179 "Cooler Link 2:",
180 "Cooler Link 3:",
181 NULL
182 },
183 { EL, "el", "ISO-8859-7", /* EL is identical to EN, except no_answer_string */
184 "Yahoo! ID:",
185 "Private",
186 "Καμία απάντηση",
187 "My Email",
188 "Real Name:",
189 "Location:",
190 "Age:",
191 "Marital Status:",
192 "Gender:",
193 "Occupation:",
194 "Hobbies:",
195 "Latest News",
196 "Favorite Quote",
197 "Links",
198 "No home page specified",
199 "Home Page:",
200 "No cool link specified",
201 "Cool Link 1:",
202 "Cool Link 2:",
203 "Cool Link 3:",
204 NULL
205 },
206 { EN, "en", "ISO-8859-1",
207 "Yahoo! ID:",
208 "Private",
209 "No Answer",
210 "My Email:",
211 "Real Name:",
212 "Location:",
213 "Age:",
214 "Marital Status:",
215 "Sex:",
216 "Occupation:",
217 "Hobbies",
218 "Latest News",
219 "Favorite Quote",
220 "Links",
221 "No home page specified",
222 "Home Page:",
223 "No cool link specified",
224 "Cool Link 1",
225 "Cool Link 2",
226 "Cool Link 3",
227 NULL
228 },
229 { EN_GB, "en_GB", "ISO-8859-1", /* Same as EN except spelling of "Favourite" */
230 "Yahoo! ID:",
231 "Private",
232 "No Answer",
233 "My Email:",
234 "Real Name:",
235 "Location:",
236 "Age:",
237 "Marital Status:",
238 "Sex:",
239 "Occupation:",
240 "Hobbies",
241 "Latest News",
242 "Favourite Quote",
243 "Links",
244 "No home page specified",
245 "Home Page:",
246 "No cool link specified",
247 "Cool Link 1",
248 "Cool Link 2",
249 "Cool Link 3",
250 NULL
251 },
252 { ES_AR, "es_AR", "ISO-8859-1",
253 "Usuario de Yahoo!:",
254 "Privado",
255 "No introdujiste una respuesta",
256 "Mi dirección de correo electrónico",
257 "Nombre real:",
258 "Ubicación:",
259 "Edad:",
260 "Estado civil:",
261 "Sexo:",
262 "Ocupación:",
263 "Pasatiempos:",
264 "Últimas noticias:",
265 "Tu cita favorita",
266 "Enlaces",
267 "Ninguna página de inicio especificada",
268 "Página de inicio:",
269 "Ningún enlace preferido",
270 "Enlace genial 1:",
271 "Enlace genial 2:",
272 "Enlace genial 3:",
273 NULL
274 },
275 { ES_ES, "es_ES", "ISO-8859-1",
276 "ID de Yahoo!:",
277 "Privado",
278 "Sin respuesta",
279 "Mi correo-e",
280 "Nombre verdadero:",
281 "Lugar:",
282 "Edad:",
283 "Estado civil:",
284 "Sexo:",
285 "Ocupación:",
286 "Aficiones:",
287 "Ultimas Noticias:",
288 "Tu cita Favorita",
289 "Enlace",
290 "Ninguna página personal especificada",
291 "Página de Inicio:",
292 "Ningún enlace preferido",
293 "Enlaces Preferidos 1:",
294 "Enlaces Preferidos 2:",
295 "Enlaces Preferidos 3:",
296 NULL
297 },
298 { ES_MX, "es_MX", "ISO-8859-1",
299 "ID de Yahoo!:",
300 "Privado",
301 "Sin responder",
302 "Mi Dirección de correo-e",
303 "Nombre real:",
304 "Ubicación:",
305 "Edad:",
306 "Estado civil:",
307 "Sexo:",
308 "Ocupación:",
309 "Pasatiempos:",
310 "Ultimas Noticias:",
311 "Su cita favorita",
312 "Enlaces",
313 "Ninguna Página predefinida",
314 "Página web:",
315 "Ningún Enlace preferido",
316 "Enlaces Preferidos 1:",
317 "Enlaces Preferidos 2:",
318 "Enlaces Preferidos 3:",
319 NULL
320 },
321 { ES_US, "es_US", "ISO-8859-1",
322 "ID de Yahoo!:",
323 "Privado",
324 "No introdujo una respuesta",
325 "Mi Dirección de correo-e",
326 "Nombre real:",
327 "Localidad:",
328 "Edad:",
329 "Estado civil:",
330 "Sexo:",
331 "Ocupación:",
332 "Pasatiempos:",
333 "Ultimas Noticias:",
334 "Su cita Favorita",
335 "Enlaces",
336 "Ninguna Página de inicio predefinida",
337 "Página de inicio:",
338 "Ningún Enlace preferido",
339 "Enlaces Preferidos 1:",
340 "Enlaces Preferidos 2:",
341 "Enlaces Preferidos 3:",
342 NULL
343 },
344 { FR_CA, "fr_CA", "ISO-8859-1",
345 "Compte Yahoo!:",
346 "Privé",
347 "Sans réponse",
348 "Mon courriel",
349 "Nom réel:",
350 "Lieu:",
351 "Âge:",
352 "État civil:",
353 "Sexe:",
354 "Profession:",
355 "Passe-temps:",
356 "Actualités:",
357 "Citation préférée",
358 "Liens",
359 "Pas de mention d'une page personnelle",
360 "Page personnelle:",
361 "Pas de mention d'un lien favori",
362 "Lien préféré 1:",
363 "Lien préféré 2:",
364 "Lien préféré 3:",
365 NULL
366 },
367 { FR_FR, "fr_FR", "ISO-8859-1",
368 "Compte Yahoo!:",
369 "Privé",
370 "Sans réponse",
371 "Mon E-mail",
372 "Nom réel:",
373 "Lieu:",
374 "Âge:",
375 "Situation de famille:",
376 "Sexe:",
377 "Profession:",
378 "Centres d'intérêts:",
379 "Actualités:",
380 "Citation préférée",
381 "Liens",
382 "Pas de mention d'une page perso",
383 "Page perso:",
384 "Pas de mention d'un lien favori",
385 "Lien préféré 1:",
386 "Lien préféré 2:",
387 "Lien préféré 3:",
388 NULL
389 },
390 { IT, "it", "ISO-8859-1",
391 "Yahoo! ID:",
392 "Non pubblica",
393 "Nessuna risposta",
394 "La mia e-mail:",
395 "Nome vero:",
396 "Località:",
397 "Età:",
398 "Stato civile:",
399 "Sesso:",
400 "Occupazione:",
401 "Hobby",
402 "Ultime notizie",
403 "Citazione preferita",
404 "Link",
405 "Nessuna home page specificata",
406 "Inizio:",
407 "Nessun link specificato",
408 "Cool Link 1",
409 "Cool Link 2",
410 "Cool Link 3",
411 NULL
412 },
413 { JA, "ja", "EUC-JP",
414 "Yahoo! JAPAN ID:",
415 "非公開",
416 "無回答",
417 "メール:",
418 "名前:",
419 "住所:",
420 "年齢:",
421 "未婚/既婚:",
422 "性別:",
423 "職業:",
424 "趣味:",
425 "最近の出来事:",
426 NULL,
427 #if 0
428 "おすすめサイト",
429 #else
430 "自己PR", /* "Self description" comes before "Links" for yahoo.co.jp */
431 #endif
432 NULL,
433 NULL,
434 NULL,
435 "おすすめサイト1:",
436 "おすすめサイト2:",
437 "おすすめサイト3:",
438 NULL
439 },
440 { KO, "ko", "EUC-KR",
441 "야후! ID:",
442 "비공개",
443 "비공개",
444 "My Email",
445 "실명:",
446 "거주지:",
447 "나이:",
448 "결혼 여부:",
449 "성별:",
450 "직업:",
451 "취미:",
452 "자기 소개:",
453 "좋아하는 명언",
454 "링크",
455 "홈페이지를 지정하지 않았습니다.",
456 "홈페이지:",
457 "추천 사이트가 없습니다.",
458 "추천 사이트 1:",
459 "추천 사이트 2:",
460 "추천 사이트 3:",
461 NULL
462 },
463 { NO, "no", "ISO-8859-1",
464 "Yahoo! ID:",
465 "Privat",
466 "Ikke noe svar",
467 "Min e-post",
468 "Virkelig navn:",
469 "Sted:",
470 "Alder:",
471 "Sivilstatus:",
472 "Kjønn:",
473 "Yrke:",
474 "Hobbyer:",
475 "Siste nytt:",
476 "Yndlingssitat",
477 "Lenker",
478 "Ingen hjemmeside angitt",
479 "Hjemmeside:",
480 "No cool link specified",
481 "Bra lenke 1:",
482 "Bra lenke 2:",
483 "Bra lenke 3:",
484 NULL
485 },
486 { PT, "pt", "ISO-8859-1",
487 "ID Yahoo!:",
488 "Particular",
489 "Sem resposta",
490 "Meu e-mail",
491 "Nome verdadeiro:",
492 "Local:",
493 "Idade:",
494 "Estado civil:",
495 "Sexo:",
496 "Ocupação:",
497 "Hobbies:",
498 "Últimas notícias:",
499 "Frase favorita",
500 "Links",
501 "Nenhuma página pessoal especificada",
502 "Página pessoal:",
503 "Nenhum site legal especificado",
504 "Site legal 1:",
505 "Site legal 2:",
506 "Site legal 3:",
507 NULL
508 },
509 { SV, "sv", "ISO-8859-1",
510 "Yahoo!-ID:",
511 "Privat",
512 "Inget svar",
513 "Min mail",
514 "Riktigt namn:",
515 "Plats:",
516 "Ålder:",
517 "Civilstånd:",
518 "Kön:",
519 "Yrke:",
520 "Hobby:",
521 "Senaste nytt:",
522 "Favoritcitat",
523 "Länkar",
524 "Ingen hemsida specificerad",
525 "Hemsida:",
526 "Ingen cool länk specificerad",
527 "Coola länkar 1:",
528 "Coola länkar 2:",
529 "Coola länkar 3:",
530 NULL
531 },
532 { ZH_CN, "zh_CN", "GB2312",
533 "Yahoo! ID:",
534 "没有提供",
535 "没有回答",
536 "个人电邮地址",
537 "真实姓名:",
538 "所在地点:",
539 "年龄:",
540 "婚姻状况:",
541 "性别:",
542 "职业:",
543 "业余爱好:",
544 "个人近况:",
545 "喜欢的引言",
546 "链接",
547 "没有个人主页",
548 "个人主页:",
549 "没有推荐网站链接",
550 "推荐网站链接 1:",
551 "推荐网站链接 2:",
552 "推荐网站链接 3:",
553 NULL
554 },
555 { ZH_HK, "zh_HK", "Big5",
556 "Yahoo! ID:",
557 "私人的",
558 "沒有回答",
559 "電子信箱",
560 "真實姓名:",
561 "地點:",
562 "年齡:",
563 "婚姻狀況:",
564 "性別:",
565 "職業:",
566 "嗜好:",
567 "最新消息:",
568 "最喜愛的股票叫價", /* [sic] Yahoo!'s translators don't check context */
569 "連結",
570 "沒有注明個人網頁", /* [sic] */
571 "個人網頁:",
572 "沒有注明 Cool 連結", /* [sic] */
573 "Cool 連結 1:", /* TODO */
574 "Cool 連結 2:", /* TODO */
575 "Cool 連結 3:", /* TODO */
576 NULL
577 },
578 { ZH_TW, "zh_TW", "Big5",
579 "帳 號:",
580 "沒有提供",
581 "沒有回應",
582 "電子信箱",
583 "姓名:",
584 "地點:",
585 "年齡:",
586 "婚姻狀態:",
587 "性別:",
588 "職業:",
589 "興趣:",
590 "個人近況:",
591 "喜歡的名句",
592 "連結",
593 "沒有個人網頁",
594 "個人網頁:",
595 "沒有推薦網站連結",
596 "推薦網站連結 1:",
597 "推薦網站連結 2:",
598 "推薦網站連結 3:",
599 NULL
600 },
601 { ZH_US, "zh_US", "Big5", /* ZH_US is like ZH_TW, but also a bit like ZH_HK */
602 "Yahoo! ID:",
603 "沒有提供",
604 "沒有回答",
605 "個人Email地址",
606 "真實姓名:",
607 "地點:",
608 "年齡:",
609 "婚姻狀態:",
610 "性別:",
611 "職業:",
612 "嗜好:",
613 "個人近況:",
614 "喜歡的名句",
615 "連結",
616 "沒有個人網頁",
617 "個人網頁:",
618 "沒有推薦網站連結",
619 "推薦網站連結 1:", /* TODO */
620 "推薦網站連結 2:", /* TODO */
621 "推薦網站連結 3:", /* TODO */
622 NULL
623 },
624 { XX, NULL, NULL,
625 NULL,
626 NULL,
627 NULL,
628 NULL,
629 NULL,
630 NULL,
631 NULL,
632 NULL,
633 NULL,
634 NULL,
635 NULL,
636 NULL,
637 NULL,
638 NULL,
639 NULL,
640 NULL,
641 NULL,
642 NULL,
643 NULL,
644 NULL,
645 NULL
646 },
647 };
648
649 static char *yahoo_info_date_reformat(const char *field, size_t len)
650 {
651 char *tmp = g_strndup(field, len);
652 time_t t = gaim_str_to_time(tmp, FALSE, NULL, NULL, NULL);
653
654 g_free(tmp);
655 return g_strdup(gaim_date_format_short(localtime(&t)));
656 }
657
658 static char *yahoo_remove_nonbreaking_spaces(char *str)
659 {
660 char *p;
661 while ((p = strstr(str, "&nbsp;")) != NULL) {
662 *p = ' '; /* Turn &nbsp;'s into ordinary blanks */
663 p += 1;
664 memmove(p, p + 5, strlen(p + 5));
665 str[strlen(str) - 5] = '\0';
666 }
667 return str;
668 }
669
670 static void yahoo_extract_user_info_text(GaimNotifyUserInfo *user_info, YahooGetInfoData *info_data) {
671 GaimBuddy *b;
672 YahooFriend *f;
673
674 b = gaim_find_buddy(gaim_connection_get_account(info_data->gc),
675 info_data->name);
676
677 if (b) {
678 if(b->alias && b->alias[0]) {
679 char *aliastext = g_markup_escape_text(b->alias, -1);
680 gaim_notify_user_info_add_pair(user_info, _("Alias"), aliastext);
681 g_free(aliastext);
682 }
683 #if 0
684 if (b->idle > 0) {
685 char *idletime = gaim_str_seconds_to_string(time(NULL) - b->idle);
686 gaim_notify_user_info_add_pair(user_info, _("Idle"), idletime);
687 g_free(idletime);
688 }
689 #endif
690
691 /* Add the normal tooltip pairs */
692 yahoo_tooltip_text(b, user_info, TRUE);
693
694 if ((f = yahoo_friend_find(info_data->gc, b->name))) {
695 const char *ip;
696 if ((ip = yahoo_friend_get_ip(f)))
697 gaim_notify_user_info_add_pair(user_info, _("IP Address"), ip);
698 }
699 }
700 }
701
702 #if PHOTO_SUPPORT
703
704 static char *yahoo_get_photo_url(const char *url_text, const char *name) {
705 GString *s = g_string_sized_new(strlen(name) + 8);
706 char *p;
707 char *it = NULL;
708
709 /*g_string_printf(s, " alt=\"%s\">", name);*/
710 /* Y! newformat */
711 g_string_printf(s, " alt=%s>", name);
712 p = strstr(url_text, s->str);
713
714 if (p) {
715 /* Search backwards for "http://". This is stupid, but it works. */
716 for (; !it && p > url_text; p -= 1) {
717 /*if (strncmp(p, "\"http://", 8) == 0) {*/
718 /* Y! newformat*/
719 if (strncmp(p, "=http://", 8) == 0) {
720 char *q;
721 p += 1; /* skip only the ' ' */
722 q = strchr(p, ' ');
723 if (q) {
724 it = g_strndup(p, q - p);
725 }
726 }
727 }
728 }
729
730 g_string_free(s, TRUE);
731 return it;
732 }
733
734 static void
735 yahoo_got_photo(GaimUtilFetchUrlData *url_data, gpointer data,
736 const gchar *url_text, size_t len, const gchar *error_message);
737
738 #endif /* PHOTO_SUPPORT */
739
740 static void yahoo_got_info(GaimUtilFetchUrlData *url_data, gpointer user_data,
741 const gchar *url_text, size_t len, const gchar *error_message)
742 {
743 YahooGetInfoData *info_data = (YahooGetInfoData *)user_data;
744 GaimNotifyUserInfo *user_info;
745 char *p;
746 #if PHOTO_SUPPORT
747 YahooGetInfoStepTwoData *info2_data;
748 char *photo_url_text = NULL;
749 #else
750 gboolean found = FALSE;
751 char *stripped;
752 int stripped_len;
753 char *last_updated_utf8_string = NULL;
754 #endif
755 const char *last_updated_string = NULL;
756 char *url_buffer;
757 GString *s;
758 char *tmp;
759 char *profile_url_text = NULL;
760 int lang, strid;
761 struct yahoo_data *yd;
762 const profile_strings_node_t *strings = NULL;
763 const char *title;
764 profile_state_t profile_state = PROFILE_STATE_DEFAULT;
765
766 gaim_debug_info("yahoo", "In yahoo_got_info\n");
767
768 yd = info_data->gc->proto_data;
769 yd->url_datas = g_slist_remove(yd->url_datas, url_data);
770
771 user_info = gaim_notify_user_info_new();
772
773 title = yd->jp ? _("Yahoo! Japan Profile") :
774 _("Yahoo! Profile");
775
776 /* Get the tooltip info string */
777 yahoo_extract_user_info_text(user_info, info_data);
778
779 /* We failed to grab the profile URL. This is not expected to actually
780 * happen except under unusual error conditions, as Yahoo is observed
781 * to send back HTML, with a 200 status code.
782 */
783 if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0) {
784 gaim_notify_user_info_add_pair(user_info, _("Error retrieving profile"), NULL);
785 gaim_notify_userinfo(info_data->gc, info_data->name,
786 user_info, NULL, NULL);
787 gaim_notify_user_info_destroy(user_info);
788 g_free(profile_url_text);
789 g_free(info_data->name);
790 g_free(info_data);
791 return;
792 }
793
794 /* Construct the correct profile URL */
795 s = g_string_sized_new(80); /* wild guess */
796 g_string_printf(s, "%s%s", (yd->jp? YAHOOJP_PROFILE_URL: YAHOO_PROFILE_URL),
797 info_data->name);
798 profile_url_text = g_string_free(s, FALSE);
799 s = NULL;
800
801 /* We don't yet support the multiple link level of the warning page for
802 * 'adult' profiles, not to mention the fact that yahoo wants you to be
803 * logged in (on the website) to be able to view an 'adult' profile. For
804 * now, just tell them that we can't help them, and provide a link to the
805 * profile if they want to do the web browser thing.
806 */
807 p = strstr(url_text, "Adult Profiles Warning Message");
808 if (!p) {
809 p = strstr(url_text, "Adult Content Warning"); /* TITLE element */
810 }
811 if (p) {
812 tmp = g_strdup_printf("<b>%s</b><br><br>"
813 "%s<br><a href=\"%s\">%s</a>",
814 _("Sorry, profiles marked as containing adult content "
815 "are not supported at this time."),
816 _("If you wish to view this profile, "
817 "you will need to visit this link in your web browser:"),
818 profile_url_text, profile_url_text);
819 gaim_notify_user_info_add_pair(user_info, NULL, tmp);
820 g_free(tmp);
821
822 gaim_notify_userinfo(info_data->gc, info_data->name,
823 user_info, NULL, NULL);
824
825 g_free(profile_url_text);
826 gaim_notify_user_info_destroy(user_info);
827 g_free(info_data->name);
828 g_free(info_data);
829 return;
830 }
831
832 /* Check whether the profile is written in a supported language */
833 for (lang = 0;; lang += 1) {
834 last_updated_string = profile_langs[lang].last_updated_string;
835 if (!last_updated_string)
836 break;
837
838 p = strstr(url_text, last_updated_string);
839
840 if (p) {
841 if (profile_langs[lang].det && !strstr(url_text, profile_langs[lang].det))
842 p = NULL;
843 else
844 break;
845 }
846 }
847
848 if (p) {
849 for (strid = 0; profile_strings[strid].lang != XX; strid += 1) {
850 if (profile_strings[strid].lang == profile_langs[lang].lang) break;
851 }
852 strings = profile_strings + strid;
853 gaim_debug_info("yahoo", "detected profile lang = %s (%d)\n", profile_strings[strid].lang_string, lang);
854 }
855
856 /* Every user may choose his/her own profile language, and this language
857 * has nothing to do with the preferences of the user which looks at the
858 * profile. We try to support all languages, but nothing is guaranteed.
859 * If we cannot determine the language, it means either (1) the profile
860 * is written in an unsupported language, (2) our language support is
861 * out of date, or (3) the user is not found, or (4) Y! have changed their
862 * webpage layout
863 */
864 if (!p || strings->lang == XX) {
865 if (!strstr(url_text, "Yahoo! Member Directory - User not found")
866 && !strstr(url_text, "was not found on this server.")
867 && !strstr(url_text, "\xb8\xf8\xb3\xab\xa5\xd7\xa5\xed\xa5\xd5\xa5\xa3\xa1\xbc\xa5\xeb\xa4\xac\xb8\xab\xa4\xc4\xa4\xab\xa4\xea\xa4\xde\xa4\xbb\xa4\xf3")) {
868 profile_state = PROFILE_STATE_UNKNOWN_LANGUAGE;
869 } else {
870 profile_state = PROFILE_STATE_NOT_FOUND;
871 }
872 }
873
874 #if PHOTO_SUPPORT
875 photo_url_text = yahoo_get_photo_url(url_text, info_data->name);
876 #endif
877
878 url_buffer = g_strdup(url_text);
879
880 /*
881 * gaim_markup_strip_html() doesn't strip out character entities like &nbsp;
882 * and &#183;
883 */
884 yahoo_remove_nonbreaking_spaces(url_buffer);
885 #if 1
886 while ((p = strstr(url_buffer, "&#183;")) != NULL) {
887 memmove(p, p + 6, strlen(p + 6));
888 url_buffer[strlen(url_buffer) - 6] = '\0';
889 }
890 #endif
891
892 /* nuke the nasty \r's */
893 gaim_str_strip_char(url_buffer, '\r');
894
895 #if PHOTO_SUPPORT
896 /* Marshall the existing state */
897 info2_data = g_malloc(sizeof(YahooGetInfoStepTwoData));
898 info2_data->info_data = info_data;
899 info2_data->url_buffer = url_buffer;
900 info2_data->photo_url_text = photo_url_text;
901 info2_data->profile_url_text = profile_url_text;
902 info2_data->strings = strings;
903 info2_data->last_updated_string = last_updated_string;
904 info2_data->title = title;
905 info2_data->profile_state = profile_state;
906 info2_data->user_info = user_info;
907
908 /* Try to put the photo in there too, if there's one */
909 if (photo_url_text) {
910 GaimUtilFetchUrlData *url_data;
911 /* User-uploaded photos use a different server that requires the Host
912 * header, but Yahoo Japan will use the "chunked" content encoding if
913 * we specify HTTP 1.1. So we have to specify 1.0 & fix gaim_util_fetch_url
914 */
915 url_data = gaim_util_fetch_url(photo_url_text, FALSE, NULL,
916 FALSE, yahoo_got_photo, info2_data);
917 if (url_data != NULL)
918 yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
919 else {
920 g_free(info2_data->info_data->name);
921 g_free(info2_data->info_data);
922 g_free(info2_data);
923 }
924 } else {
925 /* Emulate a callback */
926 yahoo_got_photo(NULL, info2_data, NULL, 0, NULL);
927 }
928 }
929
930 static void
931 yahoo_got_photo(GaimUtilFetchUrlData *url_data, gpointer data,
932 const gchar *url_text, size_t len, const gchar *error_message)
933 {
934 YahooGetInfoStepTwoData *info2_data = (YahooGetInfoStepTwoData *)data;
935 struct yahoo_data *yd;
936 gboolean found = FALSE;
937 int id = -1;
938
939 /* Temporary variables */
940 char *p = NULL;
941 char *stripped;
942 int stripped_len;
943 char *last_updated_utf8_string = NULL;
944 char *tmp;
945
946 /* Unmarshall the saved state */
947 YahooGetInfoData *info_data = info2_data->info_data;
948 char *url_buffer = info2_data->url_buffer;
949 GaimNotifyUserInfo *user_info = info2_data->user_info;
950 char *photo_url_text = info2_data->photo_url_text;
951 char *profile_url_text = info2_data->profile_url_text;
952 const profile_strings_node_t *strings = info2_data->strings;
953 const char *last_updated_string = info2_data->last_updated_string;
954 profile_state_t profile_state = info2_data->profile_state;
955
956 /* We continue here from yahoo_got_info, as if nothing has happened */
957 #endif /* PHOTO_SUPPORT */
958
959 /* Jun 29 05 Bleeter: Y! changed their profile pages. Terminators now seem to be */
960 /* </dd> and not \n. The prpl's need to be audited before it can be moved */
961 /* in to gaim_markup_strip_html*/
962 char *fudged_buffer;
963
964 yd = info_data->gc->proto_data;
965 yd->url_datas = g_slist_remove(yd->url_datas, url_data);
966
967 fudged_buffer = gaim_strcasereplace(url_buffer, "</dd>", "</dd><br>");
968 /* nuke the html, it's easier than trying to parse the horrid stuff */
969 stripped = gaim_markup_strip_html(fudged_buffer);
970 stripped_len = strlen(stripped);
971
972 gaim_debug_misc("yahoo", "stripped = %p\n", stripped);
973 gaim_debug_misc("yahoo", "url_buffer = %p\n", url_buffer);
974
975 /* convert to utf8 */
976 if (strings && strings->charset != XX) {
977 p = g_convert(stripped, -1, "utf-8", strings->charset,
978 NULL, NULL, NULL);
979 if (!p) {
980 p = g_locale_to_utf8(stripped, -1, NULL, NULL, NULL);
981 if (!p) {
982 p = g_convert(stripped, -1, "utf-8", "windows-1252",
983 NULL, NULL, NULL);
984 }
985 }
986 if (p) {
987 g_free(stripped);
988 stripped = gaim_utf8_ncr_decode(p);
989 stripped_len = strlen(stripped);
990 g_free(p);
991 }
992 }
993 p = NULL;
994
995 /* "Last updated" should also be converted to utf8 and with &nbsp; killed */
996 if (strings && strings->charset != XX) {
997 last_updated_utf8_string = g_convert(last_updated_string, -1, "utf-8",
998 strings->charset, NULL, NULL, NULL);
999 yahoo_remove_nonbreaking_spaces(last_updated_utf8_string);
1000
1001 gaim_debug_misc("yahoo", "after utf8 conversion: stripped = (%s)\n", stripped);
1002 }
1003
1004 if (profile_state == PROFILE_STATE_DEFAULT) {
1005 #if 0
1006 /* extract their Yahoo! ID and put it in. Don't bother marking has_info as
1007 * true, since the Yahoo! ID will always be there */
1008 if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1009 strings->yahoo_id_string, 10, "\n", 0,
1010 NULL, _("Yahoo! ID"), 0, NULL, NULL))
1011 ;
1012 #endif
1013
1014 #if PHOTO_SUPPORT
1015 /* Try to put the photo in there too, if there's one and is readable */
1016 if (data && url_text && len != 0) {
1017 if (strstr(url_text, "400 Bad Request")
1018 || strstr(url_text, "403 Forbidden")
1019 || strstr(url_text, "404 Not Found")) {
1020
1021 gaim_debug_info("yahoo", "Error getting %s: %s\n",
1022 photo_url_text, url_text);
1023 } else {
1024 gaim_debug_info("yahoo", "%s is %d bytes\n", photo_url_text, len);
1025 id = gaim_imgstore_add(url_text, len, NULL);
1026
1027 tmp = g_strdup_printf("<img id=\"%d\"><br>", id);
1028 gaim_notify_user_info_add_pair(user_info, NULL, tmp);
1029 g_free(tmp);
1030 }
1031 }
1032 #endif /* PHOTO_SUPPORT */
1033
1034 /* extract their Email address and put it in */
1035 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1036 strings->my_email_string, 1, " ", 0,
1037 strings->private_string, _("E-Mail"), 0, NULL, NULL);
1038
1039 /* extract the Nickname if it exists */
1040 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1041 "Nickname:", 1, "\n", '\n',
1042 NULL, _("Nickname"), 0, NULL, NULL);
1043
1044 /* extract their RealName and put it in */
1045 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1046 strings->realname_string, 1, "\n", '\n',
1047 NULL, _("Real Name"), 0, NULL, NULL);
1048
1049 /* extract their Location and put it in */
1050 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1051 strings->location_string, 2, "\n", '\n',
1052 NULL, _("Location"), 0, NULL, NULL);
1053
1054 /* extract their Age and put it in */
1055 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1056 strings->age_string, 3, "\n", '\n',
1057 NULL, _("Age"), 0, NULL, NULL);
1058
1059 /* extract their MaritalStatus and put it in */
1060 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1061 strings->maritalstatus_string, 3, "\n", '\n',
1062 strings->no_answer_string, _("Marital Status"), 0, NULL, NULL);
1063
1064 /* extract their Gender and put it in */
1065 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1066 strings->gender_string, 3, "\n", '\n',
1067 strings->no_answer_string, _("Gender"), 0, NULL, NULL);
1068
1069 /* extract their Occupation and put it in */
1070 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1071 strings->occupation_string, 2, "\n", '\n',
1072 NULL, _("Occupation"), 0, NULL, NULL);
1073
1074 /* Hobbies, Latest News, and Favorite Quote are a bit different, since
1075 * the values can contain embedded newlines... but any or all of them
1076 * can also not appear. The way we delimit them is to successively
1077 * look for the next one that _could_ appear, and if all else fails,
1078 * we end the section by looking for the 'Links' heading, which is the
1079 * next thing to follow this bunch. (For Yahoo Japan, we check for
1080 * the "Description" ("Self PR") heading instead of "Links".)
1081 */
1082
1083 if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1084 strings->hobbies_string, 1, strings->latest_news_string,
1085 '\n', "\n", _("Hobbies"), 0, NULL, NULL))
1086 {
1087 if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1088 strings->hobbies_string, 1, strings->favorite_quote_string,
1089 '\n', "\n", _("Hobbies"), 0, NULL, NULL))
1090 {
1091 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1092 strings->hobbies_string, 1, strings->links_string,
1093 '\n', "\n", _("Hobbies"), 0, NULL, NULL);
1094 }
1095 else
1096 found = TRUE;
1097 }
1098 else
1099 found = TRUE;
1100
1101 if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1102 strings->latest_news_string, 1, strings->favorite_quote_string,
1103 '\n', "\n", _("Latest News"), 0, NULL, NULL))
1104 {
1105 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1106 strings->latest_news_string, 1, strings->links_string,
1107 '\n', "\n", _("Latest News"), 0, NULL, NULL);
1108 }
1109 else
1110 found = TRUE;
1111
1112 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1113 strings->favorite_quote_string, 1, strings->links_string,
1114 '\n', "\n", _("Favorite Quote"), 0, NULL, NULL);
1115
1116 /* Home Page will either be "No home page specified",
1117 * or "Home Page: " and a link.
1118 * For Yahoo! Japan, if there is no home page specified,
1119 * neither "No home page specified" nor "Home Page:" is shown.
1120 */
1121 if (strings->home_page_string) {
1122 p = !strings->no_home_page_specified_string? NULL:
1123 strstr(stripped, strings->no_home_page_specified_string);
1124 if(!p)
1125 {
1126 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1127 strings->home_page_string, 1, "\n", 0, NULL,
1128 _("Home Page"), 1, NULL, NULL);
1129 }
1130 }
1131
1132 /* Cool Link {1,2,3} is also different. If "No cool link specified"
1133 * exists, then we have none. If we have one however, we'll need to
1134 * check and see if we have a second one. If we have a second one,
1135 * we have to check to see if we have a third one.
1136 */
1137 p = !strings->no_cool_link_specified_string? NULL:
1138 strstr(stripped,strings->no_cool_link_specified_string);
1139 if (!p)
1140 {
1141 if (gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1142 strings->cool_link_1_string, 1, "\n", 0, NULL,
1143 _("Cool Link 1"), 1, NULL, NULL))
1144 {
1145 found = TRUE;
1146 if (gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1147 strings->cool_link_2_string, 1, "\n", 0, NULL,
1148 _("Cool Link 2"), 1, NULL, NULL))
1149 {
1150 gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1151 strings->cool_link_3_string, 1, "\n", 0, NULL,
1152 _("Cool Link 3"), 1, NULL, NULL);
1153 }
1154 }
1155 }
1156
1157 if (last_updated_utf8_string != NULL) {
1158 /* see if Member Since is there, and if so, extract it. */
1159 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1160 "Member Since:", 1, last_updated_utf8_string,
1161 '\n', NULL, _("Member Since"), 0, NULL, yahoo_info_date_reformat);
1162
1163 /* extract the Last Updated date and put it in */
1164 found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
1165 last_updated_utf8_string, 1, " ", '\n', NULL,
1166 _("Last Update"), 0, NULL, yahoo_info_date_reformat);
1167 }
1168 } /* if (profile_state == PROFILE_STATE_DEFAULT) */
1169
1170 if(!found)
1171 {
1172 GString *str = g_string_new("");
1173
1174 g_string_append_printf(str, "<br><b>");
1175 g_string_append_printf(str, _("User information for %s unavailable"),
1176 info_data->name);
1177 g_string_append_printf(str, "</b><br>");
1178
1179 if (profile_state == PROFILE_STATE_UNKNOWN_LANGUAGE) {
1180 g_string_append_printf(str, "%s<br><br>",
1181 _("Sorry, this profile seems to be in a language "
1182 "or format that is not supported at this time."));
1183
1184 } else if (profile_state == PROFILE_STATE_NOT_FOUND) {
1185 GaimBuddy *b = gaim_find_buddy
1186 (gaim_connection_get_account(info_data->gc),
1187 info_data->name);
1188 YahooFriend *f = NULL;
1189 if (b) {
1190 /* Someone on the buddy list can be "not on server list",
1191 * in which case the user may or may not actually exist.
1192 * Hence this extra step.
1193 */
1194 f = yahoo_friend_find(b->account->gc, b->name);
1195 }
1196 g_string_append_printf(str, "%s<br><br>",
1197 f? _("Could not retrieve the user's profile. "
1198 "This most likely is a temporary server-side problem. "
1199 "Please try again later."):
1200 _("Could not retrieve the user's profile. "
1201 "This most likely means that the user does not exist; "
1202 "however, Yahoo! sometimes does fail to find a user's "
1203 "profile. If you know that the user exists, "
1204 "please try again later."));
1205 } else {
1206 g_string_append_printf(str, "%s<br><br>",
1207 _("The user's profile is empty."));
1208 }
1209
1210 gaim_notify_user_info_add_pair(user_info, NULL, str->str);
1211 g_string_free(str, TRUE);
1212 }
1213
1214 /* put a link to the actual profile URL */
1215 tmp = g_strdup_printf("<a href=\"%s\">%s</a>", profile_url_text, profile_url_text);
1216 gaim_notify_user_info_add_pair(user_info, _("Profile URL"), tmp);
1217 g_free(tmp);
1218
1219 g_free(stripped);
1220
1221 /* show it to the user */
1222 gaim_notify_userinfo(info_data->gc, info_data->name,
1223 user_info, NULL, NULL);
1224 gaim_notify_user_info_destroy(user_info);
1225
1226 g_free(last_updated_utf8_string);
1227 g_free(url_buffer);
1228 g_free(fudged_buffer);
1229 g_free(profile_url_text);
1230 g_free(info_data->name);
1231 g_free(info_data);
1232
1233 #if PHOTO_SUPPORT
1234 g_free(photo_url_text);
1235 g_free(info2_data);
1236 if (id != -1)
1237 gaim_imgstore_unref(id);
1238 #endif
1239 }
1240
1241 void yahoo_get_info(GaimConnection *gc, const char *name)
1242 {
1243 struct yahoo_data *yd = gc->proto_data;
1244 YahooGetInfoData *data;
1245 char *url;
1246 GaimUtilFetchUrlData *url_data;
1247
1248 data = g_new0(YahooGetInfoData, 1);
1249 data->gc = gc;
1250 data->name = g_strdup(name);
1251
1252 url = g_strdup_printf("%s%s",
1253 (yd->jp ? YAHOOJP_PROFILE_URL : YAHOO_PROFILE_URL), name);
1254
1255 url_data = gaim_util_fetch_url(url, TRUE, NULL, FALSE, yahoo_got_info, data);
1256 if (url_data != NULL)
1257 yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
1258 else {
1259 g_free(data->name);
1260 g_free(data);
1261 }
1262
1263 g_free(url);
1264 }