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