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