pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
merge of '77693555855fe9cd3215414f79964dba346cc5fa'
gaim
2008-11-12, Richard Laager
1966704b3e42
merge of '77693555855fe9cd3215414f79964dba346cc5fa'
and '19a87e98e5857ad0289f2c760d460f7f1dbbb42d'
/*
* 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
,
"
\332
ltima actualizaci
\363
n "
,
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
\xe8
re mise
\xe0
jour"
,
"http://cf.profiles.yahoo.com"
},
{
FR_FR
,
"Derni
\xe8
re 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
,
"
\332
ltima atualiza
\347\343
o "
,
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
* and ·
*/
yahoo_remove_nonbreaking_spaces
(
url_buffer
);
#if 1
while
((
p
=
strstr
(
url_buffer
,
"·"
))
!=
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 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
);
}