4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
24 #include "conversation.h"
32 /**************************************************************************/
33 /** @name Attention Type API */
34 /**************************************************************************/
36 purple_attention_type_new(const char *ulname
, const char *name
,
37 const char *inc_desc
, const char *out_desc
)
39 PurpleAttentionType
*attn
= g_new0(PurpleAttentionType
, 1);
41 purple_attention_type_set_name(attn
, name
);
42 purple_attention_type_set_incoming_desc(attn
, inc_desc
);
43 purple_attention_type_set_outgoing_desc(attn
, out_desc
);
44 purple_attention_type_set_unlocalized_name(attn
, ulname
);
51 purple_attention_type_set_name(PurpleAttentionType
*type
, const char *name
)
53 g_return_if_fail(type
!= NULL
);
59 purple_attention_type_set_incoming_desc(PurpleAttentionType
*type
, const char *desc
)
61 g_return_if_fail(type
!= NULL
);
63 type
->incoming_description
= desc
;
67 purple_attention_type_set_outgoing_desc(PurpleAttentionType
*type
, const char *desc
)
69 g_return_if_fail(type
!= NULL
);
71 type
->outgoing_description
= desc
;
75 purple_attention_type_set_icon_name(PurpleAttentionType
*type
, const char *name
)
77 g_return_if_fail(type
!= NULL
);
79 type
->icon_name
= name
;
83 purple_attention_type_set_unlocalized_name(PurpleAttentionType
*type
, const char *ulname
)
85 g_return_if_fail(type
!= NULL
);
87 type
->unlocalized_name
= ulname
;
91 purple_attention_type_get_name(const PurpleAttentionType
*type
)
93 g_return_val_if_fail(type
!= NULL
, NULL
);
99 purple_attention_type_get_incoming_desc(const PurpleAttentionType
*type
)
101 g_return_val_if_fail(type
!= NULL
, NULL
);
103 return type
->incoming_description
;
107 purple_attention_type_get_outgoing_desc(const PurpleAttentionType
*type
)
109 g_return_val_if_fail(type
!= NULL
, NULL
);
111 return type
->outgoing_description
;
115 purple_attention_type_get_icon_name(const PurpleAttentionType
*type
)
117 g_return_val_if_fail(type
!= NULL
, NULL
);
119 if(type
->icon_name
== NULL
|| *(type
->icon_name
) == '\0')
122 return type
->icon_name
;
126 purple_attention_type_get_unlocalized_name(const PurpleAttentionType
*type
)
128 g_return_val_if_fail(type
!= NULL
, NULL
);
130 return type
->unlocalized_name
;
133 /**************************************************************************/
134 /** @name Protocol Plugin API */
135 /**************************************************************************/
137 purple_prpl_got_account_idle(PurpleAccount
*account
, gboolean idle
,
140 g_return_if_fail(account
!= NULL
);
141 g_return_if_fail(purple_account_is_connected(account
));
143 purple_presence_set_idle(purple_account_get_presence(account
),
148 purple_prpl_got_account_login_time(PurpleAccount
*account
, time_t login_time
)
150 PurplePresence
*presence
;
152 g_return_if_fail(account
!= NULL
);
153 g_return_if_fail(purple_account_is_connected(account
));
156 login_time
= time(NULL
);
158 presence
= purple_account_get_presence(account
);
160 purple_presence_set_login_time(presence
, login_time
);
164 purple_prpl_got_account_status(PurpleAccount
*account
, const char *status_id
, ...)
166 PurplePresence
*presence
;
167 PurpleStatus
*status
;
170 g_return_if_fail(account
!= NULL
);
171 g_return_if_fail(status_id
!= NULL
);
172 g_return_if_fail(purple_account_is_connected(account
));
174 presence
= purple_account_get_presence(account
);
175 status
= purple_presence_get_status(presence
, status_id
);
177 g_return_if_fail(status
!= NULL
);
179 va_start(args
, status_id
);
180 purple_status_set_active_with_attrs(status
, TRUE
, args
);
185 purple_prpl_got_account_actions(PurpleAccount
*account
)
188 g_return_if_fail(account
!= NULL
);
189 g_return_if_fail(purple_account_is_connected(account
));
191 purple_signal_emit(purple_accounts_get_handle(), "account-actions-changed",
196 purple_prpl_got_user_idle(PurpleAccount
*account
, const char *name
,
197 gboolean idle
, time_t idle_time
)
199 PurplePresence
*presence
;
202 g_return_if_fail(account
!= NULL
);
203 g_return_if_fail(name
!= NULL
);
204 g_return_if_fail(purple_account_is_connected(account
) || purple_account_is_connecting(account
));
206 if ((list
= purple_find_buddies(account
, name
)) == NULL
)
210 presence
= purple_buddy_get_presence(list
->data
);
211 list
= g_slist_delete_link(list
, list
);
212 purple_presence_set_idle(presence
, idle
, idle_time
);
217 purple_prpl_got_user_login_time(PurpleAccount
*account
, const char *name
,
221 PurplePresence
*presence
;
223 g_return_if_fail(account
!= NULL
);
224 g_return_if_fail(name
!= NULL
);
226 if ((list
= purple_find_buddies(account
, name
)) == NULL
)
230 login_time
= time(NULL
);
233 PurpleBuddy
*buddy
= list
->data
;
234 presence
= purple_buddy_get_presence(buddy
);
235 list
= g_slist_delete_link(list
, list
);
237 if (purple_presence_get_login_time(presence
) != login_time
)
239 purple_presence_set_login_time(presence
, login_time
);
241 purple_signal_emit(purple_blist_get_handle(), "buddy-got-login-time", buddy
);
247 purple_prpl_got_user_status(PurpleAccount
*account
, const char *name
,
248 const char *status_id
, ...)
252 PurplePresence
*presence
;
253 PurpleStatus
*status
;
254 PurpleStatus
*old_status
;
257 g_return_if_fail(account
!= NULL
);
258 g_return_if_fail(name
!= NULL
);
259 g_return_if_fail(status_id
!= NULL
);
260 g_return_if_fail(purple_account_is_connected(account
) || purple_account_is_connecting(account
));
262 if((list
= purple_find_buddies(account
, name
)) == NULL
)
265 for(l
= list
; l
!= NULL
; l
= l
->next
) {
268 presence
= purple_buddy_get_presence(buddy
);
269 status
= purple_presence_get_status(presence
, status_id
);
273 * TODO: This should never happen, right? We should call
274 * g_warning() or something.
278 old_status
= purple_presence_get_active_status(presence
);
280 va_start(args
, status_id
);
281 purple_status_set_active_with_attrs(status
, TRUE
, args
);
284 purple_blist_update_buddy_status(buddy
, old_status
);
289 /* The buddy is no longer online, they are therefore by definition not
290 * still typing to us. */
291 if (!purple_status_is_online(status
)) {
292 serv_got_typing_stopped(purple_account_get_connection(account
), name
);
293 purple_prpl_got_media_caps(account
, name
);
297 void purple_prpl_got_user_status_deactive(PurpleAccount
*account
, const char *name
,
298 const char *status_id
)
302 PurplePresence
*presence
;
303 PurpleStatus
*status
;
305 g_return_if_fail(account
!= NULL
);
306 g_return_if_fail(name
!= NULL
);
307 g_return_if_fail(status_id
!= NULL
);
308 g_return_if_fail(purple_account_is_connected(account
) || purple_account_is_connecting(account
));
310 if((list
= purple_find_buddies(account
, name
)) == NULL
)
313 for(l
= list
; l
!= NULL
; l
= l
->next
) {
316 presence
= purple_buddy_get_presence(buddy
);
317 status
= purple_presence_get_status(presence
, status_id
);
322 if (purple_status_is_active(status
)) {
323 purple_status_set_active(status
, FALSE
);
324 purple_blist_update_buddy_status(buddy
, status
);
332 do_prpl_change_account_status(PurpleAccount
*account
,
333 PurpleStatus
*old_status
, PurpleStatus
*new_status
)
336 PurplePluginProtocolInfo
*prpl_info
;
338 if (purple_status_is_online(new_status
) &&
339 purple_account_is_disconnected(account
) &&
340 purple_network_is_available())
342 purple_account_connect(account
);
346 if (!purple_status_is_online(new_status
))
348 if (!purple_account_is_disconnected(account
))
349 purple_account_disconnect(account
);
350 /* Clear out the unsaved password if we're already disconnected and we switch to offline status */
351 else if (!purple_account_get_remember_password(account
))
352 purple_account_set_password(account
, NULL
);
356 if (purple_account_is_connecting(account
))
358 * We don't need to call the set_status PRPL function because
359 * the PRPL will take care of setting its status during the
360 * connection process.
364 prpl
= purple_find_prpl(purple_account_get_protocol_id(account
));
369 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(prpl
);
371 if (!purple_account_is_disconnected(account
) && prpl_info
->set_status
!= NULL
)
373 prpl_info
->set_status(account
, new_status
);
378 purple_prpl_change_account_status(PurpleAccount
*account
,
379 PurpleStatus
*old_status
, PurpleStatus
*new_status
)
381 g_return_if_fail(account
!= NULL
);
382 g_return_if_fail(new_status
!= NULL
);
383 g_return_if_fail(!purple_status_is_exclusive(new_status
) || old_status
!= NULL
);
385 do_prpl_change_account_status(account
, old_status
, new_status
);
387 purple_signal_emit(purple_accounts_get_handle(), "account-status-changed",
388 account
, old_status
, new_status
);
392 purple_prpl_get_statuses(PurpleAccount
*account
, PurplePresence
*presence
)
394 GList
*statuses
= NULL
;
396 PurpleStatus
*status
;
398 g_return_val_if_fail(account
!= NULL
, NULL
);
399 g_return_val_if_fail(presence
!= NULL
, NULL
);
401 for (l
= purple_account_get_status_types(account
); l
!= NULL
; l
= l
->next
)
403 status
= purple_status_new((PurpleStatusType
*)l
->data
, presence
);
404 statuses
= g_list_prepend(statuses
, status
);
407 statuses
= g_list_reverse(statuses
);
413 purple_prpl_attention(PurpleConversation
*conv
, const char *who
,
414 guint type
, PurpleMessageFlags flags
, time_t mtime
)
416 PurpleAccount
*account
= purple_conversation_get_account(conv
);
417 purple_signal_emit(purple_conversations_get_handle(),
418 flags
== PURPLE_MESSAGE_SEND
? "sent-attention" : "got-attention",
419 account
, who
, conv
, type
);
423 purple_prpl_send_attention(PurpleConnection
*gc
, const char *who
, guint type_code
)
425 PurpleAttentionType
*attn
;
426 PurpleMessageFlags flags
;
428 PurpleConversation
*conv
;
429 gboolean (*send_attention
)(PurpleConnection
*, const char *, guint
);
435 g_return_if_fail(gc
!= NULL
);
436 g_return_if_fail(who
!= NULL
);
438 prpl
= purple_find_prpl(purple_account_get_protocol_id(gc
->account
));
439 send_attention
= PURPLE_PLUGIN_PROTOCOL_INFO(prpl
)->send_attention
;
440 g_return_if_fail(send_attention
!= NULL
);
444 attn
= purple_get_attention_type_from_code(gc
->account
, type_code
);
446 if ((buddy
= purple_find_buddy(purple_connection_get_account(gc
), who
)) != NULL
)
447 alias
= purple_buddy_get_contact_alias(buddy
);
451 if (attn
&& purple_attention_type_get_outgoing_desc(attn
)) {
452 description
= g_strdup_printf(purple_attention_type_get_outgoing_desc(attn
), alias
);
454 description
= g_strdup_printf(_("Requesting %s's attention..."), alias
);
457 flags
= PURPLE_MESSAGE_SEND
| PURPLE_MESSAGE_NOTIFY
| PURPLE_MESSAGE_SYSTEM
;
459 purple_debug_info("server", "serv_send_attention: sending '%s' to %s\n",
462 if (!send_attention(gc
, who
, type_code
))
465 conv
= purple_conversation_new(PURPLE_CONV_TYPE_IM
, gc
->account
, who
);
466 purple_conv_im_write(PURPLE_CONV_IM(conv
), NULL
, description
, flags
, mtime
);
467 purple_prpl_attention(conv
, who
, type_code
, PURPLE_MESSAGE_SEND
, time(NULL
));
473 got_attention(PurpleConnection
*gc
, int id
, const char *who
, guint type_code
)
475 PurpleMessageFlags flags
;
476 PurpleAttentionType
*attn
;
484 attn
= purple_get_attention_type_from_code(gc
->account
, type_code
);
486 /* PURPLE_MESSAGE_NOTIFY is for attention messages. */
487 flags
= PURPLE_MESSAGE_SYSTEM
| PURPLE_MESSAGE_NOTIFY
| PURPLE_MESSAGE_RECV
;
489 /* TODO: if (attn->icon_name) is non-null, use it to lookup an emoticon and display
490 * it next to the attention command. And if it is null, display a generic icon. */
492 if ((buddy
= purple_find_buddy(purple_connection_get_account(gc
), who
)) != NULL
)
493 alias
= purple_buddy_get_contact_alias(buddy
);
497 if (attn
&& purple_attention_type_get_incoming_desc(attn
)) {
498 description
= g_strdup_printf(purple_attention_type_get_incoming_desc(attn
), alias
);
500 description
= g_strdup_printf(_("%s has requested your attention!"), alias
);
503 purple_debug_info("server", "got_attention: got '%s' from %s\n",
507 serv_got_im(gc
, who
, description
, flags
, mtime
);
509 serv_got_chat_in(gc
, id
, who
, flags
, description
, mtime
);
511 /* TODO: sounds (depending on PurpleAttentionType), shaking, etc. */
517 purple_prpl_got_attention(PurpleConnection
*gc
, const char *who
, guint type_code
)
519 PurpleConversation
*conv
= NULL
;
520 PurpleAccount
*account
= purple_connection_get_account(gc
);
522 got_attention(gc
, -1, who
, type_code
);
524 purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY
, who
, account
);
526 purple_prpl_attention(conv
, who
, type_code
, PURPLE_MESSAGE_RECV
,
531 purple_prpl_got_attention_in_chat(PurpleConnection
*gc
, int id
, const char *who
, guint type_code
)
533 got_attention(gc
, id
, who
, type_code
);
537 purple_prpl_initiate_media(PurpleAccount
*account
,
539 PurpleMediaSessionType type
)
542 PurpleConnection
*gc
= NULL
;
543 PurplePlugin
*prpl
= NULL
;
544 PurplePluginProtocolInfo
*prpl_info
= NULL
;
547 gc
= purple_account_get_connection(account
);
549 prpl
= purple_connection_get_prpl(gc
);
551 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(prpl
);
553 if (prpl_info
&& PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info
, initiate_media
)) {
554 /* should check that the protocol supports this media type here? */
555 return prpl_info
->initiate_media(account
, who
, type
);
562 purple_prpl_get_media_caps(PurpleAccount
*account
, const char *who
)
565 PurpleConnection
*gc
= NULL
;
566 PurplePlugin
*prpl
= NULL
;
567 PurplePluginProtocolInfo
*prpl_info
= NULL
;
570 gc
= purple_account_get_connection(account
);
572 prpl
= purple_connection_get_prpl(gc
);
574 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(prpl
);
576 if (prpl_info
&& PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info
,
578 return prpl_info
->get_media_caps(account
, who
);
581 return PURPLE_MEDIA_CAPS_NONE
;
585 purple_prpl_got_media_caps(PurpleAccount
*account
, const char *name
)
590 g_return_if_fail(account
!= NULL
);
591 g_return_if_fail(name
!= NULL
);
593 if ((list
= purple_find_buddies(account
, name
)) == NULL
)
597 PurpleBuddy
*buddy
= list
->data
;
598 PurpleMediaCaps oldcaps
= purple_buddy_get_media_caps(buddy
);
599 PurpleMediaCaps newcaps
= 0;
600 const gchar
*bname
= purple_buddy_get_name(buddy
);
601 list
= g_slist_delete_link(list
, list
);
604 newcaps
= purple_prpl_get_media_caps(account
, bname
);
605 purple_buddy_set_media_caps(buddy
, newcaps
);
607 if (oldcaps
== newcaps
)
610 purple_signal_emit(purple_blist_get_handle(),
611 "buddy-caps-changed", buddy
,
617 /**************************************************************************
618 * Protocol Plugin Subsystem API
619 **************************************************************************/
622 purple_find_prpl(const char *id
)
625 PurplePlugin
*plugin
;
627 g_return_val_if_fail(id
!= NULL
, NULL
);
629 for (l
= purple_plugins_get_protocols(); l
!= NULL
; l
= l
->next
) {
630 plugin
= (PurplePlugin
*)l
->data
;
632 if (purple_strequal(plugin
->info
->id
, id
))