2 * Purple's oscar protocol plugin
3 * This file is the legal property of its developers.
4 * Please see the AUTHORS file distributed alongside this file.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 * Displaying various information about buddies.
29 oscar_caps_to_string(guint64 caps
)
35 str
= g_string_new("");
39 } else while (bit
<= OSCAR_CAPABILITY_LAST
) {
42 case OSCAR_CAPABILITY_BUDDYICON
:
43 tmp
= _("Buddy Icon");
45 case OSCAR_CAPABILITY_TALK
:
48 case OSCAR_CAPABILITY_DIRECTIM
:
49 tmp
= _("AIM Direct IM");
51 case OSCAR_CAPABILITY_CHAT
:
54 case OSCAR_CAPABILITY_GETFILE
:
57 case OSCAR_CAPABILITY_SENDFILE
:
60 case OSCAR_CAPABILITY_GAMES
:
61 case OSCAR_CAPABILITY_GAMES2
:
64 case OSCAR_CAPABILITY_XTRAZ
:
65 case OSCAR_CAPABILITY_NEWCAPS
:
68 case OSCAR_CAPABILITY_ADDINS
:
71 case OSCAR_CAPABILITY_SENDBUDDYLIST
:
72 tmp
= _("Send Buddy List");
74 case OSCAR_CAPABILITY_ICQ_DIRECT
:
75 tmp
= _("ICQ Direct Connect");
77 case OSCAR_CAPABILITY_APINFO
:
80 case OSCAR_CAPABILITY_ICQRTF
:
83 case OSCAR_CAPABILITY_EMPTY
:
86 case OSCAR_CAPABILITY_ICQSERVERRELAY
:
87 tmp
= _("ICQ Server Relay");
89 case OSCAR_CAPABILITY_UNICODEOLD
:
90 tmp
= _("Old ICQ UTF8");
92 case OSCAR_CAPABILITY_TRILLIANCRYPT
:
93 tmp
= _("Trillian Encryption");
95 case OSCAR_CAPABILITY_UNICODE
:
98 case OSCAR_CAPABILITY_HIPTOP
:
101 case OSCAR_CAPABILITY_SECUREIM
:
102 tmp
= _("Security Enabled");
104 case OSCAR_CAPABILITY_VIDEO
:
105 tmp
= _("Video Chat");
107 /* Not actually sure about this one... WinAIM doesn't show anything */
108 case OSCAR_CAPABILITY_ICHATAV
:
111 case OSCAR_CAPABILITY_LIVEVIDEO
:
112 tmp
= _("Live Video");
114 case OSCAR_CAPABILITY_CAMERA
:
117 case OSCAR_CAPABILITY_ICHAT_SCREENSHARE
:
118 tmp
= _("Screen Sharing");
125 g_string_append_printf(str
, "%s%s", (*(str
->str
) == '\0' ? "" : ", "), tmp
);
130 return g_string_free(str
, FALSE
);
134 oscar_user_info_convert_and_add(PurpleAccount
*account
, OscarData
*od
, PurpleNotifyUserInfo
*user_info
,
135 const char *name
, const char *value
)
139 if (value
&& value
[0] && (utf8
= oscar_utf8_try_convert(account
, od
, value
))) {
140 /* TODO: Check whether it's correct to call add_pair_html,
141 or if we should be using add_pair_plaintext. Will
142 need to check callers of this function. */
143 purple_notify_user_info_add_pair_html(user_info
, name
, utf8
);
149 oscar_user_info_convert_and_add_hyperlink(PurpleAccount
*account
, OscarData
*od
, PurpleNotifyUserInfo
*user_info
,
150 const char *name
, const char *value
, const char *url_prefix
)
154 if (value
&& value
[0] && (utf8
= oscar_utf8_try_convert(account
, od
, value
))) {
155 gchar
*tmp
= g_strdup_printf("<a href=\"%s%s\">%s</a>", url_prefix
, utf8
, utf8
);
156 /* TODO: Check whether it's correct to call add_pair_html,
157 or if we should be using add_pair_plaintext. Will
158 need to check callers of this function. */
159 purple_notify_user_info_add_pair_html(user_info
, name
, tmp
);
166 * @brief Append the status information to a user_info struct
168 * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML.
170 * @param gc The PurpleConnection
171 * @param user_info A PurpleNotifyUserInfo object to which status information will be added
172 * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status().
173 * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status().
174 * @param use_html_status If TRUE, prefer HTML-formatted away message over plaintext available message.
177 oscar_user_info_append_status(PurpleConnection
*gc
, PurpleNotifyUserInfo
*user_info
, PurpleBuddy
*b
, aim_userinfo_t
*userinfo
, gboolean use_html_status
)
179 PurpleAccount
*account
= purple_connection_get_account(gc
);
181 PurplePresence
*presence
= NULL
;
182 PurpleStatus
*status
= NULL
;
183 gchar
*message
= NULL
, *itmsurl
= NULL
, *tmp
;
184 gboolean escaping_needed
= TRUE
;
186 od
= purple_connection_get_protocol_data(gc
);
188 if (b
== NULL
&& userinfo
== NULL
)
192 b
= purple_blist_find_buddy(purple_connection_get_account(gc
), userinfo
->bn
);
194 userinfo
= aim_locate_finduserinfo(od
, purple_buddy_get_name(b
));
197 presence
= purple_buddy_get_presence(b
);
198 status
= purple_presence_get_active_status(presence
);
201 /* If we have both b and userinfo we favor userinfo, because if we're
202 viewing someone's profile then we want the HTML away message, and
203 the "message" attribute of the status contains only the plaintext
206 if ((userinfo
->flags
& AIM_FLAG_AWAY
) && use_html_status
&& userinfo
->away_len
> 0 && userinfo
->away
!= NULL
&& userinfo
->away_encoding
!= NULL
) {
208 message
= oscar_encoding_to_utf8(userinfo
->away_encoding
, userinfo
->away
, userinfo
->away_len
);
209 escaping_needed
= FALSE
;
212 * Available message or non-HTML away message (because that's
213 * all we have right now.
215 if ((userinfo
->status
!= NULL
) && userinfo
->status
[0] != '\0') {
216 message
= oscar_encoding_to_utf8(userinfo
->status_encoding
, userinfo
->status
, userinfo
->status_len
);
218 #if defined (_WIN32) || defined (__APPLE__)
219 if (userinfo
->itmsurl
&& (userinfo
->itmsurl
[0] != '\0')) {
220 itmsurl
= oscar_encoding_to_utf8(userinfo
->itmsurl_encoding
, userinfo
->itmsurl
, userinfo
->itmsurl_len
);
225 message
= g_strdup(purple_status_get_attr_string(status
, "message"));
226 itmsurl
= g_strdup(purple_status_get_attr_string(status
, "itmsurl"));
230 tmp
= oscar_util_format_string(message
, purple_account_get_username(account
));
233 if (escaping_needed
) {
234 tmp
= purple_markup_escape_text(message
, -1);
240 if (use_html_status
&& itmsurl
) {
241 tmp
= g_strdup_printf("<a href=\"%s\">%s</a>", itmsurl
, message
);
247 if (purple_presence_is_online(presence
)) {
248 gboolean is_away
= ((status
&& !purple_status_is_available(status
)) || (userinfo
&& (userinfo
->flags
& AIM_FLAG_AWAY
)));
249 if (oscar_util_valid_name_icq(purple_buddy_get_name(b
)) || is_away
|| !message
|| !(*message
)) {
250 /* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message.
251 * If the status name and the message are the same, only show one. */
252 const char *status_name
= purple_status_get_name(status
);
253 if (status_name
&& message
&& purple_strequal(status_name
, message
))
256 tmp
= g_strdup_printf("%s%s%s",
257 status_name
? status_name
: "",
258 ((status_name
&& message
) && *message
) ? ": " : "",
259 (message
&& *message
) ? message
: "");
264 } else if (aim_ssi_waitingforauth(&od
->ssi
.local
,
265 aim_ssi_itemlist_findparentname(&od
->ssi
.local
, purple_buddy_get_name(b
)),
266 purple_buddy_get_name(b
)))
268 /* Note if an offline buddy is not authorized */
269 tmp
= g_strdup_printf("%s%s%s",
271 (message
&& *message
) ? ": " : "",
272 (message
&& *message
) ? message
: "");
277 message
= g_strdup(_("Offline"));
285 status
= purple_presence_get_status(presence
, "mood");
286 mood
= icq_get_custom_icon_description(purple_status_get_attr_string(status
, PURPLE_MOOD_NAME
));
288 comment
= purple_status_get_attr_string(status
, PURPLE_MOOD_COMMENT
);
290 char *escaped_comment
= purple_markup_escape_text(comment
, -1);
291 description
= g_strdup_printf("%s (%s)", _(mood
), escaped_comment
);
292 g_free(escaped_comment
);
294 description
= g_strdup(_(mood
));
296 purple_notify_user_info_add_pair_html(user_info
, _("Mood"), description
);
301 purple_notify_user_info_add_pair_html(user_info
, _("Status"), message
);
306 oscar_user_info_append_extra_info(PurpleConnection
*gc
, PurpleNotifyUserInfo
*user_info
, PurpleBuddy
*b
, aim_userinfo_t
*userinfo
)
309 PurpleAccount
*account
;
310 PurpleGroup
*g
= NULL
;
311 struct buddyinfo
*bi
= NULL
;
313 const char *bname
= NULL
, *gname
= NULL
;
315 od
= purple_connection_get_protocol_data(gc
);
316 account
= purple_connection_get_account(gc
);
318 if ((user_info
== NULL
) || ((b
== NULL
) && (userinfo
== NULL
)))
321 if (userinfo
== NULL
)
322 userinfo
= aim_locate_finduserinfo(od
, purple_buddy_get_name(b
));
325 b
= purple_blist_find_buddy(account
, userinfo
->bn
);
328 bname
= purple_buddy_get_name(b
);
329 g
= purple_buddy_get_group(b
);
330 gname
= purple_group_get_name(g
);
333 if (userinfo
!= NULL
)
334 bi
= g_hash_table_lookup(od
->buddyinfo
, purple_normalize(account
, userinfo
->bn
));
336 if ((bi
!= NULL
) && (bi
->ipaddr
!= 0)) {
338 sprintf(tmp2
, "%u.%u.%u.%u",
339 0xFF & ((bi
->ipaddr
& 0xff000000) >> 24),
340 0xFF & ((bi
->ipaddr
& 0x00ff0000) >> 16),
341 0xFF & ((bi
->ipaddr
& 0x0000ff00) >> 8),
342 0xFF & (bi
->ipaddr
& 0x000000ff));
343 purple_notify_user_info_add_pair_plaintext(user_info
, _("IP Address"), tmp2
);
346 if ((userinfo
!= NULL
) && (userinfo
->warnlevel
!= 0)) {
348 sprintf(tmp2
, "%d", (int)(userinfo
->warnlevel
/10.0 + .5));
349 purple_notify_user_info_add_pair_plaintext(user_info
, _("Warning Level"), tmp2
);
352 if ((b
!= NULL
) && (bname
!= NULL
) && (g
!= NULL
) && (gname
!= NULL
)) {
353 tmp
= aim_ssi_getcomment(&od
->ssi
.local
, gname
, bname
);
355 char *tmp2
= g_markup_escape_text(tmp
, strlen(tmp
));
358 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Buddy Comment"), tmp2
);
365 oscar_user_info_display_error(OscarData
*od
, guint16 error_reason
, gchar
*buddy
)
367 PurpleNotifyUserInfo
*user_info
= purple_notify_user_info_new();
368 gchar
*buf
= g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(error_reason
));
369 purple_notify_user_info_add_pair_plaintext(user_info
, NULL
, buf
);
370 purple_notify_userinfo(od
->gc
, buddy
, user_info
, NULL
, NULL
);
371 purple_notify_user_info_destroy(user_info
);
372 if (!purple_conversation_present_error(buddy
,
373 purple_connection_get_account(od
->gc
), buf
))
375 purple_notify_error(od
->gc
, NULL
, buf
, NULL
,
376 purple_request_cpar_from_connection(od
->gc
));
382 oscar_user_info_display_icq(OscarData
*od
, struct aim_icq_info
*info
)
384 PurpleConnection
*gc
= od
->gc
;
385 PurpleAccount
*account
= purple_connection_get_account(gc
);
387 struct buddyinfo
*bi
;
389 PurpleNotifyUserInfo
*user_info
;
394 user_info
= purple_notify_user_info_new();
396 g_snprintf(who
, sizeof(who
), "%u", info
->uin
);
397 buddy
= purple_blist_find_buddy(account
, who
);
399 bi
= g_hash_table_lookup(od
->buddyinfo
, purple_normalize(account
, purple_buddy_get_name(buddy
)));
403 purple_notify_user_info_add_pair_plaintext(user_info
, _("UIN"), who
);
404 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Nick"), info
->nick
);
405 if ((bi
!= NULL
) && (bi
->ipaddr
!= 0)) {
407 sprintf(tstr
, "%u.%u.%u.%u",
408 0xFF & ((bi
->ipaddr
& 0xff000000) >> 24),
409 0xFF & ((bi
->ipaddr
& 0x00ff0000) >> 16),
410 0xFF & ((bi
->ipaddr
& 0x0000ff00) >> 8),
411 0xFF & (bi
->ipaddr
& 0x000000ff));
412 purple_notify_user_info_add_pair_plaintext(user_info
, _("IP Address"), tstr
);
414 oscar_user_info_convert_and_add(account
, od
, user_info
, _("First Name"), info
->first
);
415 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Last Name"), info
->last
);
416 oscar_user_info_convert_and_add_hyperlink(account
, od
, user_info
, _("Email Address"), info
->email
, "mailto:");
417 if (info
->numaddresses
&& info
->email2
) {
419 for (i
= 0; i
< info
->numaddresses
; i
++) {
420 oscar_user_info_convert_and_add_hyperlink(account
, od
, user_info
, _("Email Address"), info
->email2
[i
], "mailto:");
423 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Mobile Phone"), info
->mobile
);
425 if (info
->gender
!= 0)
426 purple_notify_user_info_add_pair_plaintext(user_info
, _("Gender"), (info
->gender
== 1 ? _("Female") : _("Male")));
428 if ((info
->birthyear
> 1900) && (info
->birthmonth
> 0) && (info
->birthday
> 0)) {
429 /* Initialize the struct properly or strftime() will crash
430 * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */
431 time_t t
= time(NULL
);
432 struct tm
*tm
= localtime(&t
);
434 tm
->tm_mday
= (int)info
->birthday
;
435 tm
->tm_mon
= (int)info
->birthmonth
- 1;
436 tm
->tm_year
= (int)info
->birthyear
- 1900;
438 /* Ignore dst setting of today to avoid timezone shift between
439 * dates in summer and winter time. */
442 /* To be 100% sure that the fields are re-normalized.
443 * If you're sure strftime() ALWAYS does this EVERYWHERE,
444 * feel free to remove it. --rlaager */
447 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Birthday"), purple_date_format_short(tm
));
449 if ((info
->age
> 0) && (info
->age
< 255)) {
451 snprintf(age
, sizeof(age
), "%hhd", info
->age
);
452 purple_notify_user_info_add_pair_plaintext(user_info
, _("Age"), age
);
454 /* TODO: Is it correct to pass info->email here...? */
455 oscar_user_info_convert_and_add_hyperlink(account
, od
, user_info
, _("Personal Web Page"), info
->email
, "");
457 oscar_user_info_append_status(gc
, user_info
, buddy
, /* aim_userinfo_t */ NULL
, /* use_html_status */ TRUE
);
459 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Additional Information"), info
->info
);
460 purple_notify_user_info_add_section_break(user_info
);
462 if ((info
->homeaddr
&& (info
->homeaddr
[0])) || (info
->homecity
&& info
->homecity
[0]) || (info
->homestate
&& info
->homestate
[0]) || (info
->homezip
&& info
->homezip
[0])) {
463 purple_notify_user_info_add_section_header(user_info
, _("Home Address"));
465 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Address"), info
->homeaddr
);
466 oscar_user_info_convert_and_add(account
, od
, user_info
, _("City"), info
->homecity
);
467 oscar_user_info_convert_and_add(account
, od
, user_info
, _("State"), info
->homestate
);
468 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Zip Code"), info
->homezip
);
470 if ((info
->workaddr
&& info
->workaddr
[0]) || (info
->workcity
&& info
->workcity
[0]) || (info
->workstate
&& info
->workstate
[0]) || (info
->workzip
&& info
->workzip
[0])) {
471 purple_notify_user_info_add_section_header(user_info
, _("Work Address"));
473 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Address"), info
->workaddr
);
474 oscar_user_info_convert_and_add(account
, od
, user_info
, _("City"), info
->workcity
);
475 oscar_user_info_convert_and_add(account
, od
, user_info
, _("State"), info
->workstate
);
476 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Zip Code"), info
->workzip
);
478 if ((info
->workcompany
&& info
->workcompany
[0]) || (info
->workdivision
&& info
->workdivision
[0]) || (info
->workposition
&& info
->workposition
[0]) || (info
->workwebpage
&& info
->workwebpage
[0])) {
479 purple_notify_user_info_add_section_header(user_info
, _("Work Information"));
481 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Company"), info
->workcompany
);
482 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Division"), info
->workdivision
);
483 oscar_user_info_convert_and_add(account
, od
, user_info
, _("Position"), info
->workposition
);
484 /* TODO: Is it correct to pass info->email here...? */
485 oscar_user_info_convert_and_add_hyperlink(account
, od
, user_info
, _("Web Page"), info
->email
, "");
488 purple_notify_userinfo(gc
, who
, user_info
, NULL
, NULL
);
489 purple_notify_user_info_destroy(user_info
);
493 oscar_user_info_display_aim(OscarData
*od
, aim_userinfo_t
*userinfo
)
495 PurpleConnection
*gc
= od
->gc
;
496 PurpleAccount
*account
= purple_connection_get_account(gc
);
497 PurpleNotifyUserInfo
*user_info
= purple_notify_user_info_new();
498 gchar
*tmp
= NULL
, *info_utf8
= NULL
, *base_profile_url
= NULL
;
500 oscar_user_info_append_status(gc
, user_info
, /* PurpleBuddy */ NULL
, userinfo
, /* use_html_status */ TRUE
);
502 if ((userinfo
->present
& AIM_USERINFO_PRESENT_IDLE
) && userinfo
->idletime
!= 0) {
503 tmp
= purple_str_seconds_to_string(userinfo
->idletime
*60);
504 purple_notify_user_info_add_pair_plaintext(user_info
, _("Idle"), tmp
);
508 oscar_user_info_append_extra_info(gc
, user_info
, NULL
, userinfo
);
510 if ((userinfo
->present
& AIM_USERINFO_PRESENT_ONLINESINCE
) && !oscar_util_valid_name_sms(userinfo
->bn
)) {
511 /* An SMS contact is always online; its Online Since value is not useful */
512 time_t t
= userinfo
->onlinesince
;
513 purple_notify_user_info_add_pair_plaintext(user_info
, _("Online Since"), purple_date_format_full(localtime(&t
)));
516 if (userinfo
->present
& AIM_USERINFO_PRESENT_MEMBERSINCE
) {
517 time_t t
= userinfo
->membersince
;
518 purple_notify_user_info_add_pair_plaintext(user_info
, _("Member Since"), purple_date_format_full(localtime(&t
)));
521 if (userinfo
->capabilities
!= 0) {
522 tmp
= oscar_caps_to_string(userinfo
->capabilities
);
524 purple_notify_user_info_add_pair_plaintext(user_info
, _("Capabilities"), tmp
);
529 if ((userinfo
->info_len
> 0) && (userinfo
->info
!= NULL
) && (userinfo
->info_encoding
!= NULL
)) {
530 info_utf8
= oscar_encoding_to_utf8(userinfo
->info_encoding
, userinfo
->info
, userinfo
->info_len
);
531 tmp
= oscar_util_format_string(info_utf8
, purple_account_get_username(account
));
532 purple_notify_user_info_add_section_break(user_info
);
534 /* TODO: Check whether it's correct to call add_pair_html,
535 or if we should be using add_pair_plaintext */
536 purple_notify_user_info_add_pair_html(user_info
, _("Profile"), tmp
);
542 purple_notify_user_info_add_section_break(user_info
);
543 base_profile_url
= oscar_util_valid_name_icq(userinfo
->bn
) ? "http://www.icq.com/people" : "http://profiles.aim.com";
544 tmp
= g_strdup_printf("<a href=\"%s/%s\">%s</a>",
545 base_profile_url
, purple_normalize(account
, userinfo
->bn
), _("View web profile"));
546 purple_notify_user_info_add_pair_html(user_info
, NULL
, tmp
);
549 purple_notify_userinfo(gc
, userinfo
->bn
, user_info
, NULL
, NULL
);
550 purple_notify_user_info_destroy(user_info
);