libgaim/protocols/yahoo/yahoo_profile.c

branch
gaim
changeset 20470
77693555855f
parent 12970
c2f3b4dcf711
parent 15215
3b4c0490b8b0
child 20471
1966704b3e42
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgaim/protocols/yahoo/yahoo_profile.c	Sun May 20 06:19:49 2007 +0000
@@ -0,0 +1,1264 @@
+/*
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define PHOTO_SUPPORT 1
+
+#include "internal.h"
+#include "debug.h"
+#include "notify.h"
+#include "util.h"
+#if PHOTO_SUPPORT
+#include "imgstore.h"
+#endif
+
+#include "yahoo.h"
+#include "yahoo_friend.h"
+
+typedef struct {
+	GaimConnection *gc;
+	char *name;
+} YahooGetInfoData;
+
+typedef enum profile_lang_id {
+	XX, DA, DE, EL, 
+	EN, EN_GB, 
+	ES_AR, ES_ES, ES_MX, ES_US,
+	FR_CA, FR_FR, 
+	IT, JA, KO, NO, PT, SV, 
+	ZH_CN, ZH_HK, ZH_TW, ZH_US
+} profile_lang_id_t;
+
+typedef struct profile_lang_node {
+	profile_lang_id_t lang;
+	char *last_updated_string;
+	char *det;
+} profile_lang_node_t;
+
+typedef struct profile_strings_node {
+	profile_lang_id_t lang;
+	char *lang_string;                   /* Only to make debugging output saner */
+	char *charset;
+	char *yahoo_id_string;
+	char *private_string;
+	char *no_answer_string;
+	char *my_email_string;
+	char *realname_string;
+	char *location_string;
+	char *age_string;
+	char *maritalstatus_string;
+	char *gender_string;
+	char *occupation_string;
+	char *hobbies_string;
+	char *latest_news_string;
+	char *favorite_quote_string;
+	char *links_string;
+	char *no_home_page_specified_string;
+	char *home_page_string;
+	char *no_cool_link_specified_string;
+	char *cool_link_1_string;
+	char *cool_link_2_string;
+	char *cool_link_3_string;
+	char *dummy;
+} profile_strings_node_t;
+
+typedef enum profile_state {
+	PROFILE_STATE_DEFAULT,
+	PROFILE_STATE_NOT_FOUND,
+	PROFILE_STATE_UNKNOWN_LANGUAGE
+} profile_state_t;
+
+typedef struct {
+	YahooGetInfoData *info_data;
+	GaimNotifyUserInfo *user_info;
+	char *url_buffer;
+	char *photo_url_text;
+	char *profile_url_text;
+	const profile_strings_node_t *strings;
+	const char *last_updated_string;
+	const char *title;
+	profile_state_t profile_state;
+} YahooGetInfoStepTwoData;
+
+/* Strings to determine the profile "language" (more accurately "locale").
+ * Strings in this list must be in the original charset in the profile.
+ * The "Last Updated" string is used, but sometimes is not sufficient to
+ * distinguish 2 locales with this (e.g., ES_ES from ES_US, or FR_CA from
+ * FR_FR, or EL from EN_GB), in which case a second string is added and
+ * such special cases must be placed before the more general case.
+ */
+static const profile_lang_node_t profile_langs[] = {
+	{ DA,    "Opdateret sidste gang ",                          NULL },
+	{ DE,    "Letzter Update ",                                 NULL },
+	{ EL,    "Last Updated:",              "http://gr.profiles.yahoo.com" },
+	{ EN_GB, "Last Update ",                      "Favourite Quote" },
+	{ EN,    "Last Update:",                                        NULL },
+	{ EN,    "Last Update ",                                   NULL },
+	{ ES_AR, "\332ltima actualizaci\363n ",                     NULL },
+	{ ES_ES, "Actualizada el ",       "http://es.profiles.yahoo.com" },
+	{ ES_MX, "Actualizada el  ",      "http://mx.profiles.yahoo.com" },
+	{ ES_US, "Actualizada el  ",                                NULL },
+	{ FR_CA, "Derni\xe8re mise \xe0 jour", "http://cf.profiles.yahoo.com" },
+	{ FR_FR, "Derni\xe8re mise \xe0 jour",                           NULL },
+	{ IT,    "Ultimo aggiornamento:",                                NULL },
+	{ JA,    "\xba\xc7\xbd\xaa\xb9\xb9\xbf\xb7\xc6\xfc\xa1\xa7",     NULL },
+	{ KO,    "\xb0\xbb\xbd\xc5\x20\xb3\xaf\xc2\xa5 ",           NULL },
+	{ NO,    "Sist oppdatert ",                                 NULL },
+	{ PT,    "\332ltima atualiza\347\343o ",                    NULL },
+	{ SV,    "Senast uppdaterad ",                              NULL },
+	{ ZH_CN, "\xd7\xee\xba\xf3\xd0\xde\xb8\xc4\xc8\xd5\xc6\xda",     NULL },
+	{ ZH_HK, "\xb3\xcc\xaa\xf1\xa7\xf3\xb7\x73\xae\xc9\xb6\xa1",     NULL },
+	{ ZH_US, "\xb3\xcc\xab\xe1\xad\xd7\xa7\xef\xa4\xe9\xb4\xc1", "http://chinese.profiles.yahoo.com" },
+	{ ZH_TW, "\xb3\xcc\xab\xe1\xad\xd7\xa7\xef\xa4\xe9\xb4\xc1",     NULL },
+	{ XX,     NULL,                                                  NULL }
+};
+
+/* Strings in this list must be in UTF-8;  's should be specified as spaces. */
+static const profile_strings_node_t profile_strings[] = {
+	{ DA, "da", "ISO-8859-1",
+		"Yahoo! ID:",
+		"Privat",
+		"Intet svar",
+		"Min Email",
+		"Rigtige navn:",
+		"Opholdssted:",
+		"Alder:",
+		"Ægteskabelig status:",
+		"Køn:",
+		"Erhverv:",
+		"Hobbyer:",
+		"Sidste nyt:",
+		"Favoritcitat",
+		"Links",
+		"Ingen hjemmeside specificeret",
+		"Forside:",
+		"Intet cool link specificeret",
+		"Cool link 1:",
+		"Cool link 2:",
+		"Cool link 3:",
+		NULL
+	},
+	{ DE, "de", "ISO-8859-1",
+		"Yahoo!-ID:",
+		"Privat",
+		"Keine Antwort",
+		"Meine E-Mail",
+		"Realer Name:",
+		"Ort:",
+		"Alter:",
+		"Familienstand:",
+		"Geschlecht:",
+		"Beruf:",
+		"Hobbys:",
+		"Neuste Nachrichten:",
+		"Mein Lieblingsspruch",
+		"Links",
+		"Keine Homepage angegeben",
+		"Homepage:",
+		"Keinen coolen Link angegeben",
+		"Cooler Link 1:",
+		"Cooler Link 2:",
+		"Cooler Link 3:",
+		NULL
+	},
+	{ EL, "el", "ISO-8859-7", /* EL is identical to EN, except no_answer_string */
+		"Yahoo! ID:",
+		"Private",
+		"Καμία απάντηση",
+		"My Email",
+		"Real Name:",
+		"Location:",
+		"Age:",
+		"Marital Status:",
+		"Gender:",
+		"Occupation:",
+		"Hobbies:",
+		"Latest News",
+		"Favorite Quote",
+		"Links",
+		"No home page specified",
+		"Home Page:",
+		"No cool link specified",
+		"Cool Link 1:",
+		"Cool Link 2:",
+		"Cool Link 3:",
+		NULL
+	},
+	{ EN, "en", "ISO-8859-1",
+		"Yahoo! ID:",
+		"Private",
+		"No Answer",
+		"My Email:",
+		"Real Name:",
+		"Location:",
+		"Age:",
+		"Marital Status:",
+		"Sex:",
+		"Occupation:",
+		"Hobbies",
+		"Latest News",
+		"Favorite Quote",
+		"Links",
+		"No home page specified",
+		"Home Page:",
+		"No cool link specified",
+		"Cool Link 1",
+		"Cool Link 2",
+		"Cool Link 3",
+		NULL
+	},
+	{ EN_GB, "en_GB", "ISO-8859-1", /* Same as EN except spelling of "Favourite" */
+		"Yahoo! ID:",
+		"Private",
+		"No Answer",
+		"My Email:",
+		"Real Name:",
+		"Location:",
+		"Age:",
+		"Marital Status:",
+		"Sex:",
+		"Occupation:",
+		"Hobbies",
+		"Latest News",
+		"Favourite Quote",
+		"Links",
+		"No home page specified",
+		"Home Page:",
+		"No cool link specified",
+		"Cool Link 1",
+		"Cool Link 2",
+		"Cool Link 3",
+		NULL
+	},
+	{ ES_AR, "es_AR", "ISO-8859-1",
+		"Usuario de Yahoo!:",
+		"Privado",
+		"No introdujiste una respuesta",
+		"Mi dirección de correo electrónico",
+		"Nombre real:",
+		"Ubicación:",
+		"Edad:",
+		"Estado civil:",
+		"Sexo:",
+		"Ocupación:",
+		"Pasatiempos:",
+		"Últimas noticias:",
+		"Tu cita favorita",
+		"Enlaces",
+		"Ninguna página de inicio especificada",
+		"Página de inicio:",
+		"Ningún enlace preferido",
+		"Enlace genial 1:",
+		"Enlace genial 2:",
+		"Enlace genial 3:",
+		NULL
+	},
+	{ ES_ES, "es_ES", "ISO-8859-1",
+		"ID de Yahoo!:",
+		"Privado",
+		"Sin respuesta",
+		"Mi correo-e",
+		"Nombre verdadero:",
+		"Lugar:",
+		"Edad:",
+		"Estado civil:",
+		"Sexo:",
+		"Ocupación:",
+		"Aficiones:",
+		"Ultimas Noticias:",
+		"Tu cita Favorita",
+		"Enlace",
+		"Ninguna página personal especificada",
+		"Página de Inicio:",
+		"Ningún enlace preferido",
+		"Enlaces Preferidos 1:",
+		"Enlaces Preferidos 2:",
+		"Enlaces Preferidos 3:",
+		NULL
+	},
+	{ ES_MX, "es_MX", "ISO-8859-1",
+		"ID de Yahoo!:",
+		"Privado",
+		"Sin responder",
+		"Mi Dirección de correo-e",
+		"Nombre real:",
+		"Ubicación:",
+		"Edad:",
+		"Estado civil:",
+		"Sexo:",
+		"Ocupación:",
+		"Pasatiempos:",
+		"Ultimas Noticias:",
+		"Su cita favorita",
+		"Enlaces",
+		"Ninguna Página predefinida",
+		"Página web:",
+		"Ningún Enlace preferido",
+		"Enlaces Preferidos 1:",
+		"Enlaces Preferidos 2:",
+		"Enlaces Preferidos 3:",
+		NULL
+	},
+	{ ES_US, "es_US", "ISO-8859-1",
+		"ID de Yahoo!:",
+		"Privado",
+		"No introdujo una respuesta",
+		"Mi Dirección de correo-e",
+		"Nombre real:",
+		"Localidad:",
+		"Edad:",
+		"Estado civil:",
+		"Sexo:",
+		"Ocupación:",
+		"Pasatiempos:",
+		"Ultimas Noticias:",
+		"Su cita Favorita",
+		"Enlaces",
+		"Ninguna Página de inicio predefinida",
+		"Página de inicio:",
+		"Ningún Enlace preferido",
+		"Enlaces Preferidos 1:",
+		"Enlaces Preferidos 2:",
+		"Enlaces Preferidos 3:",
+		NULL
+	},
+	{ FR_CA, "fr_CA", "ISO-8859-1",
+		"Compte Yahoo!:",
+		"Privé",
+		"Sans réponse",
+		"Mon courriel",
+		"Nom réel:",
+		"Lieu:",
+		"Âge:",
+		"État civil:",
+		"Sexe:",
+		"Profession:",
+		"Passe-temps:",
+		"Actualités:",
+		"Citation préférée",
+		"Liens",
+		"Pas de mention d'une page personnelle",
+		"Page personnelle:",
+		"Pas de mention d'un lien favori",
+		"Lien préféré 1:",
+		"Lien préféré 2:",
+		"Lien préféré 3:",
+		NULL
+	},
+	{ FR_FR, "fr_FR", "ISO-8859-1",
+		"Compte Yahoo!:",
+		"Privé",
+		"Sans réponse",
+		"Mon E-mail",
+		"Nom réel:",
+		"Lieu:",
+		"Âge:",
+		"Situation de famille:",
+		"Sexe:",
+		"Profession:",
+		"Centres d'intérêts:",
+		"Actualités:",
+		"Citation préférée",
+		"Liens",
+		"Pas de mention d'une page perso",
+		"Page perso:",
+		"Pas de mention d'un lien favori",
+		"Lien préféré 1:",
+		"Lien préféré 2:",
+		"Lien préféré 3:",
+		NULL
+	},
+	{ IT, "it", "ISO-8859-1",
+		"Yahoo! ID:",
+		"Non pubblica",
+		"Nessuna risposta",
+		"La mia e-mail:",
+		"Nome vero:",
+		"Località:",
+		"Età:",
+		"Stato civile:",
+		"Sesso:",
+		"Occupazione:",
+		"Hobby",
+		"Ultime notizie",
+		"Citazione preferita",
+		"Link",
+		"Nessuna home page specificata",
+		"Inizio:",
+		"Nessun link specificato",
+		"Cool Link 1",
+		"Cool Link 2",
+		"Cool Link 3",
+		NULL
+	},
+	{ JA, "ja", "EUC-JP",
+		"Yahoo! JAPAN ID:",
+		"非公開",
+		"無回答",
+		"メール:",
+		"名前:",
+		"住所:",
+		"年齢:",
+		"未婚/既婚:",
+		"性別:",
+		"職業:",
+		"趣味:",
+		"最近の出来事:",
+		NULL,
+#if 0
+		"おすすめサイト",
+#else
+		"自己PR", /* "Self description" comes before "Links" for yahoo.co.jp */
+#endif
+		NULL,
+		NULL,
+		NULL,
+		"おすすめサイト1:",
+		"おすすめサイト2:",
+		"おすすめサイト3:",
+		NULL
+	},
+	{ KO, "ko", "EUC-KR",
+		"야후! ID:",
+		"비공개",
+		"비공개",
+		"My Email",
+		"실명:",
+		"거주지:",
+		"나이:",
+		"결혼 여부:",
+		"성별:",
+		"직업:",
+		"취미:",
+		"자기 소개:",
+		"좋아하는 명언",
+		"링크",
+		"홈페이지를 지정하지 않았습니다.",
+		"홈페이지:",
+		"추천 사이트가 없습니다.",
+		"추천 사이트 1:",
+		"추천 사이트 2:",
+		"추천 사이트 3:",
+		NULL
+	},
+	{ NO, "no", "ISO-8859-1",
+		"Yahoo! ID:",
+		"Privat",
+		"Ikke noe svar",
+		"Min e-post",
+		"Virkelig navn:",
+		"Sted:",
+		"Alder:",
+		"Sivilstatus:",
+		"Kjønn:",
+		"Yrke:",
+		"Hobbyer:",
+		"Siste nytt:",
+		"Yndlingssitat",
+		"Lenker",
+		"Ingen hjemmeside angitt",
+		"Hjemmeside:",
+		"No cool link specified",
+		"Bra lenke 1:",
+		"Bra lenke 2:",
+		"Bra lenke 3:",
+		NULL
+	},
+	{ PT, "pt", "ISO-8859-1",
+		"ID Yahoo!:",
+		"Particular",
+		"Sem resposta",
+		"Meu e-mail",
+		"Nome verdadeiro:",
+		"Local:",
+		"Idade:",
+		"Estado civil:",
+		"Sexo:",
+		"Ocupação:",
+		"Hobbies:",
+		"Últimas notícias:",
+		"Frase favorita",
+		"Links",
+		"Nenhuma página pessoal especificada",
+		"Página pessoal:",
+		"Nenhum site legal especificado",
+		"Site legal 1:",
+		"Site legal 2:",
+		"Site legal 3:",
+		NULL
+	},
+	{ SV, "sv", "ISO-8859-1",
+		"Yahoo!-ID:",
+		"Privat",
+		"Inget svar",
+		"Min mail",
+		"Riktigt namn:",
+		"Plats:",
+		"Ålder:",
+		"Civilstånd:",
+		"Kön:",
+		"Yrke:",
+		"Hobby:",
+		"Senaste nytt:",
+		"Favoritcitat",
+		"Länkar",
+		"Ingen hemsida specificerad",
+		"Hemsida:",
+		"Ingen cool länk specificerad",
+		"Coola länkar 1:",
+		"Coola länkar 2:",
+		"Coola länkar 3:",
+		NULL
+	},
+	{ ZH_CN, "zh_CN", "GB2312",
+		"Yahoo! ID:",
+		"没有提供",
+		"没有回答",
+		"个人电邮地址",
+		"真实姓名:",
+		"所在地点:",
+		"年龄:",
+		"婚姻状况:",
+		"性别:",
+		"职业:",
+		"业余爱好:",
+		"个人近况:",
+		"喜欢的引言",
+		"链接",
+		"没有个人主页",
+		"个人主页:",
+		"没有推荐网站链接",
+		"推荐网站链接 1:",
+		"推荐网站链接 2:",
+		"推荐网站链接 3:",
+		NULL
+	},
+	{ ZH_HK, "zh_HK", "Big5",
+		"Yahoo! ID:",
+		"私人的",
+		"沒有回答",
+		"電子信箱",
+		"真實姓名:",
+		"地點:",
+		"年齡:",
+		"婚姻狀況:",
+		"性別:",
+		"職業:",
+		"嗜好:",
+		"最新消息:",
+		"最喜愛的股票叫價", /* [sic] Yahoo!'s translators don't check context */
+		"連結",
+		"沒有注明個人網頁", /* [sic] */
+		"個人網頁:",
+		"沒有注明 Cool 連結", /* [sic] */
+		"Cool 連結 1:", /* TODO */
+		"Cool 連結 2:", /* TODO */
+		"Cool 連結 3:", /* TODO */
+		NULL
+	},
+	{ ZH_TW, "zh_TW", "Big5",
+		"帳 號:",
+		"沒有提供",
+		"沒有回應",
+		"電子信箱",
+		"姓名:",
+		"地點:",
+		"年齡:",
+		"婚姻狀態:",
+		"性別:",
+		"職業:",
+		"興趣:",
+		"個人近況:",
+		"喜歡的名句",
+		"連結",
+		"沒有個人網頁",
+		"個人網頁:",
+		"沒有推薦網站連結",
+		"推薦網站連結 1:",
+		"推薦網站連結 2:",
+		"推薦網站連結 3:",
+		NULL
+	},
+	{ ZH_US, "zh_US", "Big5", /* ZH_US is like ZH_TW, but also a bit like ZH_HK */
+		"Yahoo! ID:",
+		"沒有提供",
+		"沒有回答",
+		"個人Email地址",
+		"真實姓名:",
+		"地點:",
+		"年齡:",
+		"婚姻狀態:",
+		"性別:",
+		"職業:",
+		"嗜好:",
+		"個人近況:",
+		"喜歡的名句",
+		"連結",
+		"沒有個人網頁",
+		"個人網頁:",
+		"沒有推薦網站連結",
+		"推薦網站連結 1:", /* TODO */
+		"推薦網站連結 2:", /* TODO */
+		"推薦網站連結 3:", /* TODO */
+		NULL
+	},
+	{ XX, NULL, NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL
+	},
+};
+
+static char *yahoo_info_date_reformat(const char *field, size_t len)
+{
+	char *tmp = g_strndup(field, len);
+	time_t t = gaim_str_to_time(tmp, FALSE, NULL, NULL, NULL);
+
+	g_free(tmp);
+	return g_strdup(gaim_date_format_short(localtime(&t)));
+}
+
+static char *yahoo_remove_nonbreaking_spaces(char *str)
+{
+	char *p;
+	while ((p = strstr(str, " ")) != NULL) {
+		*p = ' '; /* Turn  's into ordinary blanks */
+		p += 1;
+		memmove(p, p + 5, strlen(p + 5));
+		str[strlen(str) - 5] = '\0';
+	}
+	return str;
+}
+
+static void yahoo_extract_user_info_text(GaimNotifyUserInfo *user_info, YahooGetInfoData *info_data) {
+	GaimBuddy *b;
+	YahooFriend *f;
+
+	b = gaim_find_buddy(gaim_connection_get_account(info_data->gc),
+			info_data->name);
+
+	if (b) {
+		if(b->alias && b->alias[0]) {
+			char *aliastext = g_markup_escape_text(b->alias, -1);
+			gaim_notify_user_info_add_pair(user_info, _("Alias"), aliastext); 
+			g_free(aliastext);
+		}
+		#if 0
+		if (b->idle > 0) {
+			char *idletime = gaim_str_seconds_to_string(time(NULL) - b->idle);
+			gaim_notify_user_info_add_pair(user_info, _("Idle"), idletime);
+			g_free(idletime);
+		}
+		#endif
+
+		/* Add the normal tooltip pairs */
+		yahoo_tooltip_text(b, user_info, TRUE);
+
+		if ((f = yahoo_friend_find(info_data->gc, b->name))) {
+			const char *ip;
+			if ((ip = yahoo_friend_get_ip(f)))
+				gaim_notify_user_info_add_pair(user_info, _("IP Address"), ip);
+		}
+	}
+}
+
+#if PHOTO_SUPPORT
+
+static char *yahoo_get_photo_url(const char *url_text, const char *name) {
+	GString *s = g_string_sized_new(strlen(name) + 8);
+	char *p;
+	char *it = NULL;
+
+	/*g_string_printf(s, " alt=\"%s\">", name);*/
+	/* Y! newformat */
+	g_string_printf(s, " alt=%s>", name);
+	p = strstr(url_text, s->str);
+
+	if (p) {
+		/* Search backwards for "http://". This is stupid, but it works. */
+		for (; !it && p > url_text; p -= 1) {
+			/*if (strncmp(p, "\"http://", 8) == 0) {*/
+			/* Y! newformat*/
+			if (strncmp(p, "=http://", 8) == 0) {
+				char *q;
+				p += 1; /* skip only the ' ' */
+				q = strchr(p, ' ');
+				if (q) {
+					it = g_strndup(p, q - p);
+				}
+			}
+		}
+	}
+
+	g_string_free(s, TRUE);
+	return it;
+}
+
+static void
+yahoo_got_photo(GaimUtilFetchUrlData *url_data, gpointer data,
+		const gchar *url_text, size_t len, const gchar *error_message);
+
+#endif /* PHOTO_SUPPORT */
+
+static void yahoo_got_info(GaimUtilFetchUrlData *url_data, gpointer user_data,
+		const gchar *url_text, size_t len, const gchar *error_message)
+{
+	YahooGetInfoData *info_data = (YahooGetInfoData *)user_data;
+	GaimNotifyUserInfo *user_info;
+	char *p;
+#if PHOTO_SUPPORT
+	YahooGetInfoStepTwoData *info2_data;
+	char *photo_url_text = NULL;
+#else
+	gboolean found = FALSE;
+	char *stripped;
+	int stripped_len;
+	char *last_updated_utf8_string = NULL;
+#endif
+	const char *last_updated_string = NULL;
+	char *url_buffer;
+	GString *s;
+	char *tmp;
+	char *profile_url_text = NULL;
+	int lang, strid;
+	struct yahoo_data *yd;
+	const profile_strings_node_t *strings = NULL;
+	const char *title;
+	profile_state_t profile_state = PROFILE_STATE_DEFAULT;
+
+	gaim_debug_info("yahoo", "In yahoo_got_info\n");
+
+	yd = info_data->gc->proto_data;
+	yd->url_datas = g_slist_remove(yd->url_datas, url_data);
+
+	user_info = gaim_notify_user_info_new();
+
+	title = yd->jp ? _("Yahoo! Japan Profile") :
+					 _("Yahoo! Profile");
+
+	/* Get the tooltip info string */
+	yahoo_extract_user_info_text(user_info, info_data);
+
+	/* We failed to grab the profile URL.  This is not expected to actually
+	 * happen except under unusual error conditions, as Yahoo is observed
+	 * to send back HTML, with a 200 status code.
+	 */
+	if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0) {
+		gaim_notify_user_info_add_pair(user_info, _("Error retrieving profile"), NULL);
+		gaim_notify_userinfo(info_data->gc, info_data->name, 
+			user_info, NULL, NULL);
+		gaim_notify_user_info_destroy(user_info);
+		g_free(profile_url_text);
+		g_free(info_data->name);
+		g_free(info_data);
+		return;
+	}
+
+	/* Construct the correct profile URL */
+	s = g_string_sized_new(80); /* wild guess */
+	g_string_printf(s, "%s%s", (yd->jp? YAHOOJP_PROFILE_URL: YAHOO_PROFILE_URL),
+		info_data->name);
+	profile_url_text = g_string_free(s, FALSE);
+	s = NULL;
+
+	/* We don't yet support the multiple link level of the warning page for
+	 * 'adult' profiles, not to mention the fact that yahoo wants you to be
+	 * logged in (on the website) to be able to view an 'adult' profile.  For
+	 * now, just tell them that we can't help them, and provide a link to the
+	 * profile if they want to do the web browser thing.
+	 */
+	p = strstr(url_text, "Adult Profiles Warning Message");
+	if (!p) {
+		p = strstr(url_text, "Adult Content Warning"); /* TITLE element */
+	}
+	if (p) {
+		tmp = g_strdup_printf("<b>%s</b><br><br>"
+							  "%s<br><a href=\"%s\">%s</a>",
+						_("Sorry, profiles marked as containing adult content "
+						"are not supported at this time."),
+						 _("If you wish to view this profile, "
+						"you will need to visit this link in your web browser:"),
+						 profile_url_text, profile_url_text);
+		gaim_notify_user_info_add_pair(user_info, NULL, tmp);		
+		g_free(tmp);
+
+		gaim_notify_userinfo(info_data->gc, info_data->name, 
+				user_info, NULL, NULL);
+
+		g_free(profile_url_text);
+		gaim_notify_user_info_destroy(user_info);
+		g_free(info_data->name);
+		g_free(info_data);
+		return;
+	}
+
+	/* Check whether the profile is written in a supported language */
+	for (lang = 0;; lang += 1) {
+		last_updated_string = profile_langs[lang].last_updated_string;
+		if (!last_updated_string)
+			break;
+
+		p = strstr(url_text, last_updated_string);
+
+		if (p) {
+			if (profile_langs[lang].det && !strstr(url_text, profile_langs[lang].det))
+				p = NULL;
+			else
+				break;
+		}
+	}
+
+	if (p) {
+		for (strid = 0; profile_strings[strid].lang != XX; strid += 1) {
+			if (profile_strings[strid].lang == profile_langs[lang].lang) break;
+		}
+		strings = profile_strings + strid;
+		gaim_debug_info("yahoo", "detected profile lang = %s (%d)\n", profile_strings[strid].lang_string, lang);
+	}
+
+	/* Every user may choose his/her own profile language, and this language
+	 * has nothing to do with the preferences of the user which looks at the
+	 * profile. We try to support all languages, but nothing is guaranteed.
+	 * If we cannot determine the language, it means either (1) the profile
+	 * is written in an unsupported language, (2) our language support is
+	 * out of date, or (3) the user is not found, or (4) Y! have changed their
+	 * webpage layout
+	 */
+	if (!p || strings->lang == XX) {
+		if (!strstr(url_text, "Yahoo! Member Directory - User not found")
+				&& !strstr(url_text, "was not found on this server.")
+				&& !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")) {
+			profile_state = PROFILE_STATE_UNKNOWN_LANGUAGE;
+		} else {
+			profile_state = PROFILE_STATE_NOT_FOUND;
+		}
+	}
+
+#if PHOTO_SUPPORT
+	photo_url_text = yahoo_get_photo_url(url_text, info_data->name);
+#endif
+
+	url_buffer = g_strdup(url_text);
+
+	/*
+	 * gaim_markup_strip_html() doesn't strip out character entities like &nbsp;
+	 * and &#183;
+	*/
+	yahoo_remove_nonbreaking_spaces(url_buffer);
+#if 1
+	while ((p = strstr(url_buffer, "&#183;")) != NULL) {
+		memmove(p, p + 6, strlen(p + 6));
+		url_buffer[strlen(url_buffer) - 6] = '\0';
+	}
+#endif
+
+	/* nuke the nasty \r's */
+	gaim_str_strip_char(url_buffer, '\r');
+
+#if PHOTO_SUPPORT
+	/* Marshall the existing state */
+	info2_data = g_malloc(sizeof(YahooGetInfoStepTwoData));
+	info2_data->info_data = info_data;
+	info2_data->url_buffer = url_buffer;
+	info2_data->photo_url_text = photo_url_text;
+	info2_data->profile_url_text = profile_url_text;
+	info2_data->strings = strings;
+	info2_data->last_updated_string = last_updated_string;
+	info2_data->title = title;
+	info2_data->profile_state = profile_state;
+	info2_data->user_info = user_info;
+
+	/* Try to put the photo in there too, if there's one */
+	if (photo_url_text) {
+		GaimUtilFetchUrlData *url_data;
+		/* User-uploaded photos use a different server that requires the Host
+		 * header, but Yahoo Japan will use the "chunked" content encoding if
+		 * we specify HTTP 1.1. So we have to specify 1.0 & fix gaim_util_fetch_url
+		 */
+		url_data = gaim_util_fetch_url(photo_url_text, FALSE, NULL,
+				FALSE, yahoo_got_photo, info2_data);
+		if (url_data != NULL)
+			yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
+		else {
+			g_free(info2_data->info_data->name);
+			g_free(info2_data->info_data);
+			g_free(info2_data);
+		}
+	} else {
+		/* Emulate a callback */
+		yahoo_got_photo(NULL, info2_data, NULL, 0, NULL);
+	}
+}
+
+static void
+yahoo_got_photo(GaimUtilFetchUrlData *url_data, gpointer data,
+		const gchar *url_text, size_t len, const gchar *error_message)
+{
+	YahooGetInfoStepTwoData *info2_data = (YahooGetInfoStepTwoData *)data;
+	struct yahoo_data *yd;
+	gboolean found = FALSE;
+	int id = -1;
+
+	/* Temporary variables */
+	char *p = NULL;
+	char *stripped;
+	int stripped_len;
+	char *last_updated_utf8_string = NULL;
+	char *tmp;
+
+	/* Unmarshall the saved state */
+	YahooGetInfoData *info_data = info2_data->info_data;
+	char *url_buffer = info2_data->url_buffer;
+	GaimNotifyUserInfo *user_info = info2_data->user_info;
+	char *photo_url_text = info2_data->photo_url_text;
+	char *profile_url_text = info2_data->profile_url_text;
+	const profile_strings_node_t *strings = info2_data->strings;
+	const char *last_updated_string = info2_data->last_updated_string;
+	profile_state_t profile_state = info2_data->profile_state;
+
+	/* We continue here from yahoo_got_info, as if nothing has happened */
+#endif /* PHOTO_SUPPORT */
+
+	/* Jun 29 05 Bleeter: Y! changed their profile pages. Terminators now seem to be */
+	/* </dd> and not \n. The prpl's need to be audited before it can be moved */
+	/* in to gaim_markup_strip_html*/
+	char *fudged_buffer;
+
+	yd = info_data->gc->proto_data;
+	yd->url_datas = g_slist_remove(yd->url_datas, url_data);
+
+	fudged_buffer = gaim_strcasereplace(url_buffer, "</dd>", "</dd><br>");
+	/* nuke the html, it's easier than trying to parse the horrid stuff */
+	stripped = gaim_markup_strip_html(fudged_buffer);
+	stripped_len = strlen(stripped);
+
+	gaim_debug_misc("yahoo", "stripped = %p\n", stripped);
+	gaim_debug_misc("yahoo", "url_buffer = %p\n", url_buffer);
+
+	/* convert to utf8 */
+	if (strings && strings->charset != XX) {
+		p = g_convert(stripped, -1, "utf-8", strings->charset,
+				NULL, NULL, NULL);
+		if (!p) {
+			p = g_locale_to_utf8(stripped, -1, NULL, NULL, NULL);
+			if (!p) {
+				p = g_convert(stripped, -1, "utf-8", "windows-1252",
+						NULL, NULL, NULL);
+			}
+		}
+		if (p) {
+			g_free(stripped);
+			stripped = gaim_utf8_ncr_decode(p);
+			stripped_len = strlen(stripped);
+			g_free(p);
+		}
+	}
+	p = NULL;
+
+	/* "Last updated" should also be converted to utf8 and with &nbsp; killed */
+	if (strings && strings->charset != XX) {
+		last_updated_utf8_string = g_convert(last_updated_string, -1, "utf-8",
+				strings->charset, NULL, NULL, NULL);
+		yahoo_remove_nonbreaking_spaces(last_updated_utf8_string);
+
+		gaim_debug_misc("yahoo", "after utf8 conversion: stripped = (%s)\n", stripped);
+	}
+
+	if (profile_state == PROFILE_STATE_DEFAULT) {
+#if 0
+	/* extract their Yahoo! ID and put it in. Don't bother marking has_info as
+	 * true, since the Yahoo! ID will always be there */
+	if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->yahoo_id_string, 10, "\n", 0,
+			NULL, _("Yahoo! ID"), 0, NULL, NULL))
+		;
+#endif
+
+#if PHOTO_SUPPORT
+	/* Try to put the photo in there too, if there's one and is readable */
+	if (data && url_text && len != 0) {
+		if (strstr(url_text, "400 Bad Request")
+				|| strstr(url_text, "403 Forbidden")
+				|| strstr(url_text, "404 Not Found")) {
+
+			gaim_debug_info("yahoo", "Error getting %s: %s\n",
+					photo_url_text, url_text);
+		} else {
+			gaim_debug_info("yahoo", "%s is %d bytes\n", photo_url_text, len);
+			id = gaim_imgstore_add(url_text, len, NULL);
+			
+			tmp = g_strdup_printf("<img id=\"%d\"><br>", id);
+			gaim_notify_user_info_add_pair(user_info, NULL, tmp);
+			g_free(tmp);
+		}
+	}
+#endif /* PHOTO_SUPPORT */
+
+	/* extract their Email address and put it in */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->my_email_string, 1, " ", 0,
+			strings->private_string, _("E-Mail"), 0, NULL, NULL);
+
+	/* extract the Nickname if it exists */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			"Nickname:", 1, "\n", '\n',
+			NULL, _("Nickname"), 0, NULL, NULL);
+
+	/* extract their RealName and put it in */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->realname_string, 1, "\n", '\n',
+			NULL, _("Real Name"), 0, NULL, NULL);
+
+	/* extract their Location and put it in */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->location_string, 2, "\n", '\n',
+			NULL, _("Location"), 0, NULL, NULL);
+
+	/* extract their Age and put it in */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->age_string, 3, "\n", '\n',
+			NULL, _("Age"), 0, NULL, NULL);
+
+	/* extract their MaritalStatus and put it in */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->maritalstatus_string, 3, "\n", '\n',
+			strings->no_answer_string, _("Marital Status"), 0, NULL, NULL);
+
+	/* extract their Gender and put it in */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->gender_string, 3, "\n", '\n',
+			strings->no_answer_string, _("Gender"), 0, NULL, NULL);
+
+	/* extract their Occupation and put it in */
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->occupation_string, 2, "\n", '\n',
+			NULL, _("Occupation"), 0, NULL, NULL);
+
+	/* Hobbies, Latest News, and Favorite Quote are a bit different, since
+	 * the values can contain embedded newlines... but any or all of them
+	 * can also not appear.  The way we delimit them is to successively
+	 * look for the next one that _could_ appear, and if all else fails,
+	 * we end the section by looking for the 'Links' heading, which is the
+	 * next thing to follow this bunch.  (For Yahoo Japan, we check for
+	 * the "Description" ("Self PR") heading instead of "Links".)
+	 */
+
+	if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->hobbies_string, 1, strings->latest_news_string,
+			'\n', "\n", _("Hobbies"), 0, NULL, NULL))
+	{
+		if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+				strings->hobbies_string, 1, strings->favorite_quote_string,
+				'\n', "\n", _("Hobbies"), 0, NULL, NULL))
+		{
+			found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+					strings->hobbies_string, 1, strings->links_string,
+					'\n', "\n", _("Hobbies"), 0, NULL, NULL);
+		}
+		else
+			found = TRUE;
+	}
+	else
+		found = TRUE;
+
+	if (!gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->latest_news_string, 1, strings->favorite_quote_string,
+			'\n', "\n", _("Latest News"), 0, NULL, NULL))
+	{
+		found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+				strings->latest_news_string, 1, strings->links_string,
+				'\n', "\n", _("Latest News"), 0, NULL, NULL);
+	}
+	else
+		found = TRUE;
+
+	found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+			strings->favorite_quote_string, 1, strings->links_string,
+			'\n', "\n", _("Favorite Quote"), 0, NULL, NULL);
+
+	/* Home Page will either be "No home page specified",
+	 * or "Home Page: " and a link.
+	 * For Yahoo! Japan, if there is no home page specified,
+	 * neither "No home page specified" nor "Home Page:" is shown.
+	 */
+	if (strings->home_page_string) {
+		p = !strings->no_home_page_specified_string? NULL:
+			strstr(stripped, strings->no_home_page_specified_string);
+		if(!p)
+		{
+			found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+					strings->home_page_string, 1, "\n", 0, NULL,
+					_("Home Page"), 1, NULL, NULL);
+		}
+	}
+
+	/* Cool Link {1,2,3} is also different.  If "No cool link specified"
+	 * exists, then we have none.  If we have one however, we'll need to
+	 * check and see if we have a second one.  If we have a second one,
+	 * we have to check to see if we have a third one.
+	 */
+	p = !strings->no_cool_link_specified_string? NULL:
+		strstr(stripped,strings->no_cool_link_specified_string);
+	if (!p)
+	{
+		if (gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+				strings->cool_link_1_string, 1, "\n", 0, NULL,
+				_("Cool Link 1"), 1, NULL, NULL))
+		{
+			found = TRUE;
+			if (gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+					strings->cool_link_2_string, 1, "\n", 0, NULL,
+					_("Cool Link 2"), 1, NULL, NULL))
+			{
+				gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+						strings->cool_link_3_string, 1, "\n", 0, NULL,
+						_("Cool Link 3"), 1, NULL, NULL);
+			}
+		}
+	}
+
+	if (last_updated_utf8_string != NULL) {
+		/* see if Member Since is there, and if so, extract it. */
+		found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+				"Member Since:", 1, last_updated_utf8_string,
+				'\n', NULL, _("Member Since"), 0, NULL, yahoo_info_date_reformat);
+
+		/* extract the Last Updated date and put it in */
+		found |= gaim_markup_extract_info_field(stripped, stripped_len, user_info,
+				last_updated_utf8_string, 1, " ", '\n', NULL,
+				_("Last Update"), 0, NULL, yahoo_info_date_reformat);
+	}
+	} /* if (profile_state == PROFILE_STATE_DEFAULT) */
+
+	if(!found)
+	{
+		GString *str = g_string_new("");
+
+		g_string_append_printf(str, "<br><b>");
+		g_string_append_printf(str, _("User information for %s unavailable"),
+				info_data->name);
+		g_string_append_printf(str, "</b><br>");
+
+		if (profile_state == PROFILE_STATE_UNKNOWN_LANGUAGE) {
+			g_string_append_printf(str, "%s<br><br>",
+					_("Sorry, this profile seems to be in a language "
+					  "or format that is not supported at this time."));
+
+		} else if (profile_state == PROFILE_STATE_NOT_FOUND) {
+			GaimBuddy *b = gaim_find_buddy
+					(gaim_connection_get_account(info_data->gc),
+							info_data->name);
+			YahooFriend *f = NULL;
+			if (b) {
+				/* Someone on the buddy list can be "not on server list",
+				 * in which case the user may or may not actually exist.
+				 * Hence this extra step.
+				 */
+				f = yahoo_friend_find(b->account->gc, b->name);
+			}
+			g_string_append_printf(str, "%s<br><br>",
+				f?  _("Could not retrieve the user's profile. "
+					  "This most likely is a temporary server-side problem. "
+					  "Please try again later."):
+					_("Could not retrieve the user's profile. "
+					  "This most likely means that the user does not exist; "
+					  "however, Yahoo! sometimes does fail to find a user's "
+					  "profile. If you know that the user exists, "
+					  "please try again later."));
+		} else {
+			g_string_append_printf(str, "%s<br><br>",
+					_("The user's profile is empty."));
+		}
+		
+		gaim_notify_user_info_add_pair(user_info, NULL, str->str);
+		g_string_free(str, TRUE);
+	}
+
+	/* put a link to the actual profile URL */
+	tmp = g_strdup_printf("<a href=\"%s\">%s</a>", profile_url_text, profile_url_text);
+	gaim_notify_user_info_add_pair(user_info, _("Profile URL"), tmp);
+	g_free(tmp);
+
+	g_free(stripped);
+
+	/* show it to the user */
+	gaim_notify_userinfo(info_data->gc, info_data->name,
+						  user_info, NULL, NULL);
+	gaim_notify_user_info_destroy(user_info);
+
+	g_free(last_updated_utf8_string);
+	g_free(url_buffer);
+	g_free(fudged_buffer);
+	g_free(profile_url_text);
+	g_free(info_data->name);
+	g_free(info_data);
+
+#if PHOTO_SUPPORT
+	g_free(photo_url_text);
+	g_free(info2_data);
+	if (id != -1)
+		gaim_imgstore_unref(id);
+#endif
+}
+
+void yahoo_get_info(GaimConnection *gc, const char *name)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	YahooGetInfoData *data;
+	char *url;
+	GaimUtilFetchUrlData *url_data;
+
+	data       = g_new0(YahooGetInfoData, 1);
+	data->gc   = gc;
+	data->name = g_strdup(name);
+
+	url = g_strdup_printf("%s%s",
+			(yd->jp ? YAHOOJP_PROFILE_URL : YAHOO_PROFILE_URL), name);
+
+	url_data = gaim_util_fetch_url(url, TRUE, NULL, FALSE, yahoo_got_info, data);
+	if (url_data != NULL)
+		yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
+	else {
+		g_free(data->name);
+		g_free(data);
+	}
+
+	g_free(url);
+}

mercurial