src/protocols/yahoo/yahoo_profile.c

branch
cpw.khc.msnp14
changeset 20472
6a6d2ef151e6
parent 13912
463b4fa9f067
parent 20469
b2836a24d81e
child 20473
91e1b3a49d10
equal deleted inserted replaced
13912:463b4fa9f067 20472:6a6d2ef151e6
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 char *url_buffer;
93 GString *s;
94 char *photo_url_text;
95 char *profile_url_text;
96 char *tooltip_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;
102
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.
109 */
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 { 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 }
134 };
135
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
160 },
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
183 },
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
206 },
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
229 },
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
252 },
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
275 },
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
298 },
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
321 },
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
344 },
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
367 },
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
390 },
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
413 },
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
440 },
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
463 },
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
486 },
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
509 },
510 { SV, "sv", "ISO-8859-1",
511 "Yahoo!-ID:",
512 "Privat",
513 "Inget svar",
514 "Min mail",
515 "Riktigt namn:",
516 "Plats:",
517 "Ålder:",
518 "Civilstånd:",
519 "Kön:",
520 "Yrke:",
521 "Hobby:",
522 "Senaste nytt:",
523 "Favoritcitat",
524 "Länkar",
525 "Ingen hemsida specificerad",
526 "Hemsida:",
527 "Ingen cool länk specificerad",
528 "Coola länkar 1:",
529 "Coola länkar 2:",
530 "Coola länkar 3:",
531 NULL
532 },
533 { ZH_CN, "zh_CN", "GB2312",
534 "Yahoo! ID:",
535 "没有提供",
536 "没有回答",
537 "个人电邮地址",
538 "真实姓名:",
539 "所在地点:",
540 "年龄:",
541 "婚姻状况:",
542 "性别:",
543 "职业:",
544 "业余爱好:",
545 "个人近况:",
546 "喜欢的引言",
547 "链接",
548 "没有个人主页",
549 "个人主页:",
550 "没有推荐网站链接",
551 "推荐网站链接 1:",
552 "推荐网站链接 2:",
553 "推荐网站链接 3:",
554 NULL
555 },
556 { ZH_HK, "zh_HK", "Big5",
557 "Yahoo! ID:",
558 "私人的",
559 "沒有回答",
560 "電子信箱",
561 "真實姓名:",
562 "地點:",
563 "年齡:",
564 "婚姻狀況:",
565 "性別:",
566 "職業:",
567 "嗜好:",
568 "最新消息:",
569 "最喜愛的股票叫價", /* [sic] Yahoo!'s translators don't check context */
570 "連結",
571 "沒有注明個人網頁", /* [sic] */
572 "個人網頁:",
573 "沒有注明 Cool 連結", /* [sic] */
574 "Cool 連結 1:", /* TODO */
575 "Cool 連結 2:", /* TODO */
576 "Cool 連結 3:", /* TODO */
577 NULL
578 },
579 { ZH_TW, "zh_TW", "Big5",
580 "帳 號:",
581 "沒有提供",
582 "沒有回應",
583 "電子信箱",
584 "姓名:",
585 "地點:",
586 "年齡:",
587 "婚姻狀態:",
588 "性別:",
589 "職業:",
590 "興趣:",
591 "個人近況:",
592 "喜歡的名句",
593 "連結",
594 "沒有個人網頁",
595 "個人網頁:",
596 "沒有推薦網站連結",
597 "推薦網站連結 1:",
598 "推薦網站連結 2:",
599 "推薦網站連結 3:",
600 NULL
601 },
602 { ZH_US, "zh_US", "Big5", /* ZH_US is like ZH_TW, but also a bit like ZH_HK */
603 "Yahoo! ID:",
604 "沒有提供",
605 "沒有回答",
606 "個人Email地址",
607 "真實姓名:",
608 "地點:",
609 "年齡:",
610 "婚姻狀態:",
611 "性別:",
612 "職業:",
613 "嗜好:",
614 "個人近況:",
615 "喜歡的名句",
616 "連結",
617 "沒有個人網頁",
618 "個人網頁:",
619 "沒有推薦網站連結",
620 "推薦網站連結 1:", /* TODO */
621 "推薦網站連結 2:", /* TODO */
622 "推薦網站連結 3:", /* TODO */
623 NULL
624 },
625 { XX, NULL, 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 NULL
647 },
648 };
649
650 static char *yahoo_info_date_reformat(const char *field, size_t len)
651 {
652 char *tmp = g_strndup(field, len);
653 time_t t = gaim_str_to_time(tmp, FALSE, NULL, NULL, NULL);
654
655 g_free(tmp);
656 return g_strdup(gaim_date_format_short(localtime(&t)));
657 }
658
659 static char *yahoo_remove_nonbreaking_spaces(char *str)
660 {
661 char *p;
662 while ((p = strstr(str, " ")) != NULL) {
663 *p = ' '; /* Turn  's into ordinary blanks */
664 p += 1;
665 memmove(p, p + 5, strlen(p + 5));
666 str[strlen(str) - 5] = '\0';
667 }
668 return str;
669 }
670
671 static char *yahoo_tooltip_info_text(YahooGetInfoData *info_data) {
672 GString *s = g_string_sized_new(80); /* wild guess */
673 GaimBuddy *b;
674 YahooFriend *f;
675
676 b = gaim_find_buddy(gaim_connection_get_account(info_data->gc),
677 info_data->name);
678
679 if (b) {
680 GString *str = g_string_new("");
681 char *tmp;
682
683 if(b->alias && b->alias[0]) {
684 char *aliastext = g_markup_escape_text(b->alias, -1);
685 g_string_append_printf(s, _("<b>Alias:</b> %s<br>"), aliastext);
686 g_free(aliastext);
687 }
688 #if 0
689 if (b->idle > 0) {
690 char *idletime = gaim_str_seconds_to_string(time(NULL) - b->idle);
691 g_string_append_printf(s, _("<b>%s:</b> %s<br>"), _("Idle"),
692 idletime);
693 g_free(idletime);
694 }
695 #endif
696
697 yahoo_tooltip_text(b, str, TRUE);
698 tmp = gaim_strreplace((*str->str == '\n' ? str->str + 1 : str->str),
699 "\n", "<br>");
700 g_string_free(str, TRUE);
701 g_string_append_printf(s, "%s<br>", tmp);
702 g_free(tmp);
703
704 if ((f = yahoo_friend_find(info_data->gc, b->name))) {
705 const char *ip;
706 if ((ip = yahoo_friend_get_ip(f)))
707 g_string_append_printf(s, _("<b>IP Address:</b> %s<br>"), ip);
708 }
709 }
710 return g_string_free(s, FALSE);
711 }
712
713 #if PHOTO_SUPPORT
714
715 static char *yahoo_get_photo_url(const char *url_text, const char *name) {
716 GString *s = g_string_sized_new(strlen(name) + 8);
717 char *p;
718 char *it = NULL;
719
720 /*g_string_printf(s, " alt=\"%s\">", name);*/
721 /* Y! newformat */
722 g_string_printf(s, " alt=%s>", name);
723 p = strstr(url_text, s->str);
724
725 if (p) {
726 /* Search backwards for "http://". This is stupid, but it works. */
727 for (; !it && p > url_text; p -= 1) {
728 /*if (strncmp(p, "\"http://", 8) == 0) {*/
729 /* Y! newformat*/
730 if (strncmp(p, "=http://", 8) == 0) {
731 char *q;
732 p += 1; /* skip only the ' ' */
733 q = strchr(p, ' ');
734 if (q) {
735 it = g_strndup(p, q - p);
736 }
737 }
738 }
739 }
740
741 g_string_free(s, TRUE);
742 return it;
743 }
744
745 static void yahoo_got_photo(void *data, const char *url_text, size_t len);
746
747 #endif /* PHOTO_SUPPORT */
748
749 static void yahoo_got_info(void *data, const char *url_text, size_t len)
750 {
751 YahooGetInfoData *info_data = (YahooGetInfoData *)data;
752 char *p;
753 char buf[1024];
754 #if PHOTO_SUPPORT
755 YahooGetInfoStepTwoData *info2_data;
756 char *photo_url_text = NULL;
757 #else
758 gboolean found = FALSE;
759 char *stripped;
760 int stripped_len;
761 char *last_updated_utf8_string = NULL;
762 #endif
763 const char *last_updated_string = NULL;
764 char *url_buffer;
765 GString *s;
766 char *tooltip_text = NULL;
767 char *profile_url_text = NULL;
768 int lang, strid;
769 struct yahoo_data *yd;
770 const profile_strings_node_t *strings = NULL;
771 const char *title;
772 profile_state_t profile_state = PROFILE_STATE_DEFAULT;
773
774 if (!GAIM_CONNECTION_IS_VALID(info_data->gc)) {
775 g_free(info_data->name);
776 g_free(info_data);
777 return;
778 }
779
780 gaim_debug_info("yahoo", "In yahoo_got_info\n");
781
782 yd = info_data->gc->proto_data;
783 title = (yd->jp? _("Yahoo! Japan Profile") :
784 _("Yahoo! Profile"));
785
786 /* Get the tooltip info string */
787 tooltip_text = yahoo_tooltip_info_text(info_data);
788
789 /* We failed to grab the profile URL. This is not expected to actually
790 * happen except under unusual error conditions, as Yahoo is observed
791 * to send back HTML, with a 200 status code.
792 */
793 if (url_text == NULL || strcmp(url_text, "") == 0) {
794 g_snprintf(buf, 1024, "<html><body>%s<b>%s</b></body></html>",
795 tooltip_text, _("Error retrieving profile"));
796
797 gaim_notify_userinfo(info_data->gc, info_data->name,
798 buf, NULL, NULL);
799
800 g_free(profile_url_text);
801 g_free(tooltip_text);
802 g_free(info_data->name);
803 g_free(info_data);
804 return;
805 }
806
807 /* Construct the correct profile URL */
808 s = g_string_sized_new(80); /* wild guess */
809 g_string_printf(s, "%s%s", (yd->jp? YAHOOJP_PROFILE_URL: YAHOO_PROFILE_URL),
810 info_data->name);
811 profile_url_text = g_string_free(s, FALSE);
812 s = NULL;
813
814 /* We don't yet support the multiple link level of the warning page for
815 * 'adult' profiles, not to mention the fact that yahoo wants you to be
816 * logged in (on the website) to be able to view an 'adult' profile. For
817 * now, just tell them that we can't help them, and provide a link to the
818 * profile if they want to do the web browser thing.
819 */
820 p = strstr(url_text, "Adult Profiles Warning Message");
821 if (!p) {
822 p = strstr(url_text, "Adult Content Warning"); /* TITLE element */
823 }
824 if (p) {
825 g_snprintf(buf, 1024, "<html><body>%s<b>%s</b><br><br>"
826 "%s<br><a href=\"%s\">%s</a></body></html>",
827 tooltip_text,
828 _("Sorry, profiles marked as containing adult content "
829 "are not supported at this time."),
830 _("If you wish to view this profile, "
831 "you will need to visit this link in your web browser"),
832 profile_url_text, profile_url_text);
833
834 gaim_notify_userinfo(info_data->gc, info_data->name,
835 buf, NULL, NULL);
836
837 g_free(profile_url_text);
838 g_free(tooltip_text);
839 g_free(info_data->name);
840 g_free(info_data);
841 return;
842 }
843
844 /* Check whether the profile is written in a supported language */
845 for (lang = 0;; lang += 1) {
846 last_updated_string = profile_langs[lang].last_updated_string;
847 if (!last_updated_string)
848 break;
849
850 p = strstr(url_text, last_updated_string);
851
852 if (p) {
853 if (profile_langs[lang].det && !strstr(url_text, profile_langs[lang].det))
854 p = NULL;
855 else
856 break;
857 }
858 }
859
860 if (p) {
861 for (strid = 0; profile_strings[strid].lang != XX; strid += 1) {
862 if (profile_strings[strid].lang == profile_langs[lang].lang) break;
863 }
864 strings = profile_strings + strid;
865 gaim_debug_info("yahoo", "detected profile lang = %s (%d)\n", profile_strings[strid].lang_string, lang);
866 }
867
868 /* Every user may choose his/her own profile language, and this language
869 * has nothing to do with the preferences of the user which looks at the
870 * profile. We try to support all languages, but nothing is guaranteed.
871 * If we cannot determine the language, it means either (1) the profile
872 * is written in an unsupported language, (2) our language support is
873 * out of date, or (3) the user is not found, or (4) Y! have changed their
874 * webpage layout
875 */
876 if (!p || strings->lang == XX) {
877 if (!strstr(url_text, "Yahoo! Member Directory - User not found")
878 && !strstr(url_text, "was not found on this server.")
879 && !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")) {
880 profile_state = PROFILE_STATE_UNKNOWN_LANGUAGE;
881 } else {
882 profile_state = PROFILE_STATE_NOT_FOUND;
883 }
884 }
885
886 #if PHOTO_SUPPORT
887 photo_url_text = yahoo_get_photo_url(url_text, info_data->name);
888 #endif
889
890 url_buffer = g_strdup(url_text);
891
892 /*
893 * gaim_markup_strip_html() doesn't strip out character entities like &nbsp;
894 * and &#183;
895 */
896 yahoo_remove_nonbreaking_spaces(url_buffer);
897 #if 1
898 while ((p = strstr(url_buffer, "&#183;")) != NULL) {
899 memmove(p, p + 6, strlen(p + 6));
900 url_buffer[strlen(url_buffer) - 6] = '\0';
901 }
902 #endif
903
904 /* nuke the nasty \r's */
905 gaim_str_strip_char(url_buffer, '\r');
906
907 #if PHOTO_SUPPORT
908 /* Marshall the existing state */
909 info2_data = g_malloc(sizeof(YahooGetInfoStepTwoData));
910 info2_data->info_data = info_data;
911 info2_data->url_buffer = url_buffer;
912 info2_data->s = s;
913 info2_data->photo_url_text = photo_url_text;
914 info2_data->profile_url_text = profile_url_text;
915 info2_data->tooltip_text = tooltip_text;
916 info2_data->strings = strings;
917 info2_data->last_updated_string = last_updated_string;
918 info2_data->title = title;
919 info2_data->profile_state = profile_state;
920
921 /* Try to put the photo in there too, if there's one */
922 if (photo_url_text) {
923 /* User-uploaded photos use a different server that requires the Host
924 * header, but Yahoo Japan will use the "chunked" content encoding if
925 * we specify HTTP 1.1. So we have to specify 1.0 & fix gaim_url_fetch
926 */
927 gaim_url_fetch(photo_url_text, FALSE, NULL, FALSE, yahoo_got_photo,
928 info2_data);
929 } else {
930 /* Emulate a callback */
931 yahoo_got_photo(info2_data, NULL, 0);
932 }
933 }
934
935 static void yahoo_got_photo(void *data, const char *url_text, size_t len)
936 {
937 YahooGetInfoStepTwoData *info2_data = (YahooGetInfoStepTwoData *)data;
938 gboolean found = FALSE;
939 int id = -1;
940
941 /* Temporary variables */
942 char *p = NULL;
943 char *stripped;
944 int stripped_len;
945 char *last_updated_utf8_string = NULL;
946
947 /* Unmarshall the saved state */
948 YahooGetInfoData *info_data = info2_data->info_data;
949 char *url_buffer = info2_data->url_buffer;
950 GString *s = info2_data->s;
951 char *photo_url_text = info2_data->photo_url_text;
952 char *profile_url_text = info2_data->profile_url_text;
953 char *tooltip_text = info2_data->tooltip_text;
954 const profile_strings_node_t *strings = info2_data->strings;
955 const char *last_updated_string = info2_data->last_updated_string;
956 profile_state_t profile_state = info2_data->profile_state;
957
958 /* We continue here from yahoo_got_info, as if nothing has happened */
959 #endif /* PHOTO_SUPPORT */
960
961 /* Jun 29 05 Bleeter: Y! changed their profile pages. Terminators now seem to be */
962 /* </dd> and not \n. The prpl's need to be audited before it can be moved */
963 /* in to gaim_markup_strip_html*/
964 char *fudged_buffer;
965 fudged_buffer = gaim_strcasereplace(url_buffer, "</dd>", "</dd><br>");
966 /* nuke the html, it's easier than trying to parse the horrid stuff */
967 stripped = gaim_markup_strip_html(fudged_buffer);
968 stripped_len = strlen(stripped);
969
970 gaim_debug_misc("yahoo", "stripped = %p\n", stripped);
971 gaim_debug_misc("yahoo", "url_buffer = %p\n", url_buffer);
972
973 /* convert to utf8 */
974 if (strings && strings->charset != XX) {
975 p = g_convert(stripped, -1, "utf-8", strings->charset,
976 NULL, NULL, NULL);
977 if (!p) {
978 p = g_locale_to_utf8(stripped, -1, NULL, NULL, NULL);
979 if (!p) {
980 p = g_convert(stripped, -1, "utf-8", "windows-1252",
981 NULL, NULL, NULL);
982 }
983 }
984 if (p) {
985 g_free(stripped);
986 stripped = gaim_utf8_ncr_decode(p);
987 stripped_len = strlen(stripped);
988 g_free(p);
989 }
990 }
991 p = NULL;
992
993 /* "Last updated" should also be converted to utf8 and with &nbsp; killed */
994 if (strings && strings->charset != XX) {
995 last_updated_utf8_string = g_convert(last_updated_string, -1, "utf-8",
996 strings->charset, NULL, NULL, NULL);
997 yahoo_remove_nonbreaking_spaces(last_updated_utf8_string);
998
999 gaim_debug_misc("yahoo", "after utf8 conversion: stripped = (%s)\n", stripped);
1000 }
1001
1002 /* gonna re-use the memory we've already got for url_buffer */
1003 /* no we're not */
1004 s = g_string_sized_new(strlen(url_buffer));
1005
1006 if (profile_state == PROFILE_STATE_DEFAULT) {
1007 #if 0
1008 /* extract their Yahoo! ID and put it in. Don't bother marking has_info as
1009 * true, since the Yahoo! ID will always be there */
1010 if (!gaim_markup_extract_info_field(stripped, stripped_len, s,
1011 strings->yahoo_id_string, 10, "\n", 0,
1012 NULL, _("Yahoo! ID"), 0, NULL, NULL))
1013 ;
1014 #endif
1015
1016 #if PHOTO_SUPPORT
1017 /* Try to put the photo in there too, if there's one and is readable */
1018 if (data && url_text && len != 0) {
1019 if (strstr(url_text, "400 Bad Request")
1020 || strstr(url_text, "403 Forbidden")
1021 || strstr(url_text, "404 Not Found")) {
1022
1023 gaim_debug_info("yahoo", "Error getting %s: %s\n",
1024 photo_url_text, url_text);
1025 } else {
1026 gaim_debug_info("yahoo", "%s is %d bytes\n", photo_url_text, len);
1027 id = gaim_imgstore_add(url_text, len, NULL);
1028 g_string_append_printf(s, "<img id=\"%d\"><br>", id);
1029 }
1030 }
1031 #endif /* PHOTO_SUPPORT */
1032
1033 /* extract their Email address and put it in */
1034 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1035 strings->my_email_string, 1, " ", 0,
1036 strings->private_string, _("E-Mail"), 0, NULL, NULL);
1037
1038 /* extract the Nickname if it exists */
1039 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1040 "Nickname:", 1, "\n", '\n',
1041 NULL, _("Nickname"), 0, NULL, NULL);
1042
1043 /* extract their RealName and put it in */
1044 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1045 strings->realname_string, 1, "\n", '\n',
1046 NULL, _("Real Name"), 0, NULL, NULL);
1047
1048 /* extract their Location and put it in */
1049 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1050 strings->location_string, 2, "\n", '\n',
1051 NULL, _("Location"), 0, NULL, NULL);
1052
1053 /* extract their Age and put it in */
1054 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1055 strings->age_string, 3, "\n", '\n',
1056 NULL, _("Age"), 0, NULL, NULL);
1057
1058 /* extract their MaritalStatus and put it in */
1059 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1060 strings->maritalstatus_string, 3, "\n", '\n',
1061 strings->no_answer_string, _("Marital Status"), 0, NULL, NULL);
1062
1063 /* extract their Gender and put it in */
1064 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1065 strings->gender_string, 3, "\n", '\n',
1066 strings->no_answer_string, _("Gender"), 0, NULL, NULL);
1067
1068 /* extract their Occupation and put it in */
1069 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1070 strings->occupation_string, 2, "\n", '\n',
1071 NULL, _("Occupation"), 0, NULL, NULL);
1072
1073 /* Hobbies, Latest News, and Favorite Quote are a bit different, since
1074 * the values can contain embedded newlines... but any or all of them
1075 * can also not appear. The way we delimit them is to successively
1076 * look for the next one that _could_ appear, and if all else fails,
1077 * we end the section by looking for the 'Links' heading, which is the
1078 * next thing to follow this bunch. (For Yahoo Japan, we check for
1079 * the "Description" ("Self PR") heading instead of "Links".)
1080 */
1081
1082 if (!gaim_markup_extract_info_field(stripped, stripped_len, s,
1083 strings->hobbies_string, 1, strings->latest_news_string,
1084 '\n', "\n", _("Hobbies"), 0, NULL, NULL))
1085 {
1086 if (!gaim_markup_extract_info_field(stripped, stripped_len, s,
1087 strings->hobbies_string, 1, strings->favorite_quote_string,
1088 '\n', "\n", _("Hobbies"), 0, NULL, NULL))
1089 {
1090 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1091 strings->hobbies_string, 1, strings->links_string,
1092 '\n', "\n", _("Hobbies"), 0, NULL, NULL);
1093 }
1094 else
1095 found = TRUE;
1096 }
1097 else
1098 found = TRUE;
1099
1100 if (!gaim_markup_extract_info_field(stripped, stripped_len, s,
1101 strings->latest_news_string, 1, strings->favorite_quote_string,
1102 '\n', "\n", _("Latest News"), 0, NULL, NULL))
1103 {
1104 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1105 strings->latest_news_string, 1, strings->links_string,
1106 '\n', "\n", _("Latest News"), 0, NULL, NULL);
1107 }
1108 else
1109 found = TRUE;
1110
1111 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1112 strings->favorite_quote_string, 1, strings->links_string,
1113 '\n', "\n", _("Favorite Quote"), 0, NULL, NULL);
1114
1115 /* Home Page will either be "No home page specified",
1116 * or "Home Page: " and a link.
1117 * For Yahoo! Japan, if there is no home page specified,
1118 * neither "No home page specified" nor "Home Page:" is shown.
1119 */
1120 if (strings->home_page_string) {
1121 p = !strings->no_home_page_specified_string? NULL:
1122 strstr(stripped, strings->no_home_page_specified_string);
1123 if(!p)
1124 {
1125 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1126 strings->home_page_string, 1, "\n", 0, NULL,
1127 _("Home Page"), 1, NULL, NULL);
1128 }
1129 }
1130
1131 /* Cool Link {1,2,3} is also different. If "No cool link specified"
1132 * exists, then we have none. If we have one however, we'll need to
1133 * check and see if we have a second one. If we have a second one,
1134 * we have to check to see if we have a third one.
1135 */
1136 p = !strings->no_cool_link_specified_string? NULL:
1137 strstr(stripped,strings->no_cool_link_specified_string);
1138 if (!p)
1139 {
1140 if (gaim_markup_extract_info_field(stripped, stripped_len, s,
1141 strings->cool_link_1_string, 1, "\n", 0, NULL,
1142 _("Cool Link 1"), 1, NULL, NULL))
1143 {
1144 found = TRUE;
1145 if (gaim_markup_extract_info_field(stripped, stripped_len, s,
1146 strings->cool_link_2_string, 1, "\n", 0, NULL,
1147 _("Cool Link 2"), 1, NULL, NULL))
1148 {
1149 gaim_markup_extract_info_field(stripped, stripped_len, s,
1150 strings->cool_link_3_string, 1, "\n", 0, NULL,
1151 _("Cool Link 3"), 1, NULL, NULL);
1152 }
1153 }
1154 }
1155
1156 /* see if Member Since is there, and if so, extract it. */
1157 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1158 "Member Since:", 1, last_updated_utf8_string,
1159 '\n', NULL, _("Member Since"), 0, NULL, yahoo_info_date_reformat);
1160
1161 /* extract the Last Updated date and put it in */
1162 found |= gaim_markup_extract_info_field(stripped, stripped_len, s,
1163 last_updated_utf8_string, 1, " ", '\n', NULL,
1164 _("Last Update"), 0, NULL, yahoo_info_date_reformat);
1165 } /* if (profile_state == PROFILE_STATE_DEFAULT) */
1166
1167 if(!found)
1168 {
1169 g_string_append_printf(s, "<br><b>");
1170 g_string_append_printf(s, _("User information for %s unavailable"),
1171 info_data->name);
1172 g_string_append_printf(s, "</b><br>");
1173
1174 if (profile_state == PROFILE_STATE_UNKNOWN_LANGUAGE) {
1175 g_string_append_printf(s, "%s<br><br>",
1176 _("Sorry, this profile seems to be in a language "
1177 "or format that is not supported at this time."));
1178
1179 } else if (profile_state == PROFILE_STATE_NOT_FOUND) {
1180 GaimBuddy *b = gaim_find_buddy
1181 (gaim_connection_get_account(info_data->gc),
1182 info_data->name);
1183 YahooFriend *f = NULL;
1184 if (b) {
1185 /* Someone on the buddy list can be "not on server list",
1186 * in which case the user may or may not actually exist.
1187 * Hence this extra step.
1188 */
1189 f = yahoo_friend_find(b->account->gc, b->name);
1190 }
1191 g_string_append_printf(s, "%s<br><br>",
1192 f? _("Could not retrieve the user's profile. "
1193 "This most likely is a temporary server-side problem. "
1194 "Please try again later."):
1195 _("Could not retrieve the user's profile. "
1196 "This most likely means that the user does not exist; "
1197 "however, Yahoo! sometimes does fail to find a user's "
1198 "profile. If you know that the user exists, "
1199 "please try again later."));
1200
1201 } else {
1202 g_string_append_printf(s, "%s<br><br>",
1203 _("The user's profile is empty."));
1204 }
1205 }
1206
1207 /* put a link to the actual profile URL */
1208 g_string_append_printf(s, _("<b>%s:</b> "), _("Profile URL"));
1209 g_string_append_printf(s, "<br><a href=\"%s\">%s</a><br>",
1210 profile_url_text, profile_url_text);
1211
1212 /* finish off the html at the end */
1213 g_string_append(s, "</body></html>");
1214 g_free(stripped);
1215
1216 /* Put the Yahoo! ID, nickname, idle time, and status message in */
1217 g_string_prepend(s, tooltip_text);
1218
1219 /* finish off the html at the beginning */
1220 g_string_prepend(s, "<html><body>");
1221
1222 /* show it to the user */
1223 gaim_notify_userinfo(info_data->gc, info_data->name,
1224 s->str, NULL, NULL);
1225
1226 g_free(last_updated_utf8_string);
1227 g_free(url_buffer);
1228 g_free(fudged_buffer);
1229 g_string_free(s, TRUE);
1230 g_free(profile_url_text);
1231 g_free(tooltip_text);
1232 g_free(info_data->name);
1233 g_free(info_data);
1234
1235 #if PHOTO_SUPPORT
1236 g_free(photo_url_text);
1237 g_free(info2_data);
1238 if (id != -1)
1239 gaim_imgstore_unref(id);
1240 #endif
1241 }
1242
1243 void yahoo_get_info(GaimConnection *gc, const char *name)
1244 {
1245 struct yahoo_data *yd = gc->proto_data;
1246 YahooGetInfoData *data;
1247 char *url;
1248
1249 data = g_new0(YahooGetInfoData, 1);
1250 data->gc = gc;
1251 data->name = g_strdup(name);
1252
1253 url = g_strdup_printf("%s%s",
1254 (yd->jp? YAHOOJP_PROFILE_URL: YAHOO_PROFILE_URL), name);
1255
1256 gaim_url_fetch(url, TRUE, NULL, FALSE, yahoo_got_info, data);
1257
1258 g_free(url);
1259 }

mercurial