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
23 #include "conversations.h"
25 static GList
*conversations
= NULL
;
26 static GList
*ims
= NULL
;
27 static GList
*chats
= NULL
;
28 static PurpleConversationUiOps
*default_ops
= NULL
;
31 * A hash table used for efficient lookups of conversations by name.
32 * struct _purple_hconv => PurpleConversation*
34 static GHashTable
*conversation_cache
= NULL
;
36 struct _purple_hconv
{
39 PurpleAccount
*account
;
43 _purple_conversations_hconv_hash(struct _purple_hconv
*hc
)
45 return g_str_hash(hc
->name
) ^ hc
->im
^ g_direct_hash(hc
->account
);
49 _purple_conversations_hconv_equal(struct _purple_hconv
*hc1
, struct _purple_hconv
*hc2
)
51 return (hc1
->im
== hc2
->im
&&
52 hc1
->account
== hc2
->account
&&
53 g_str_equal(hc1
->name
, hc2
->name
));
57 _purple_conversations_hconv_free_key(struct _purple_hconv
*hc
)
64 purple_conversations_add(PurpleConversation
*conv
)
66 PurpleAccount
*account
;
67 struct _purple_hconv
*hc
;
69 g_return_if_fail(conv
!= NULL
);
71 if (g_list_find(conversations
, conv
) != NULL
)
74 conversations
= g_list_prepend(conversations
, conv
);
76 if (PURPLE_IS_IM_CONVERSATION(conv
))
77 ims
= g_list_prepend(ims
, conv
);
79 chats
= g_list_prepend(chats
, conv
);
81 account
= purple_conversation_get_account(conv
);
83 hc
= g_new(struct _purple_hconv
, 1);
84 hc
->name
= g_strdup(purple_normalize(account
,
85 purple_conversation_get_name(conv
)));
86 hc
->account
= account
;
87 hc
->im
= PURPLE_IS_IM_CONVERSATION(conv
);
89 g_hash_table_insert(conversation_cache
, hc
, conv
);
93 purple_conversations_remove(PurpleConversation
*conv
)
95 PurpleAccount
*account
;
96 struct _purple_hconv hc
;
98 g_return_if_fail(conv
!= NULL
);
100 conversations
= g_list_remove(conversations
, conv
);
102 if (PURPLE_IS_IM_CONVERSATION(conv
))
103 ims
= g_list_remove(ims
, conv
);
105 chats
= g_list_remove(chats
, conv
);
107 account
= purple_conversation_get_account(conv
);
109 hc
.name
= (gchar
*)purple_normalize(account
,
110 purple_conversation_get_name(conv
));
111 hc
.account
= account
;
112 hc
.im
= PURPLE_IS_IM_CONVERSATION(conv
);
114 g_hash_table_remove(conversation_cache
, &hc
);
118 _purple_conversations_update_cache(PurpleConversation
*conv
, const char *name
,
119 PurpleAccount
*account
)
121 PurpleAccount
*old_account
;
122 struct _purple_hconv
*hc
;
124 g_return_if_fail(conv
!= NULL
);
125 g_return_if_fail(account
!= NULL
|| name
!= NULL
);
127 old_account
= purple_conversation_get_account(conv
);
129 hc
= g_new(struct _purple_hconv
, 1);
130 hc
->im
= PURPLE_IS_IM_CONVERSATION(conv
);
131 hc
->account
= old_account
;
132 hc
->name
= (gchar
*)purple_normalize(old_account
,
133 purple_conversation_get_name(conv
));
135 g_hash_table_remove(conversation_cache
, hc
);
138 hc
->account
= account
;
140 hc
->name
= g_strdup(purple_normalize(hc
->account
, name
));
142 g_hash_table_insert(conversation_cache
, hc
, conv
);
146 purple_conversations_get_all(void)
148 return conversations
;
152 purple_conversations_get_ims(void)
158 purple_conversations_get_chats(void)
164 purple_conversations_find_with_account(const char *name
,
165 PurpleAccount
*account
)
167 PurpleConversation
*c
= NULL
;
168 struct _purple_hconv hc
;
170 g_return_val_if_fail(name
!= NULL
, NULL
);
172 hc
.name
= (gchar
*)purple_normalize(account
, name
);
173 hc
.account
= account
;
176 c
= g_hash_table_lookup(conversation_cache
, &hc
);
179 c
= g_hash_table_lookup(conversation_cache
, &hc
);
185 PurpleIMConversation
*
186 purple_conversations_find_im_with_account(const char *name
,
187 PurpleAccount
*account
)
189 PurpleIMConversation
*im
= NULL
;
190 struct _purple_hconv hc
;
192 g_return_val_if_fail(name
!= NULL
, NULL
);
194 hc
.name
= (gchar
*)purple_normalize(account
, name
);
195 hc
.account
= account
;
198 im
= g_hash_table_lookup(conversation_cache
, &hc
);
203 PurpleChatConversation
*
204 purple_conversations_find_chat_with_account(const char *name
,
205 PurpleAccount
*account
)
207 PurpleChatConversation
*c
= NULL
;
208 struct _purple_hconv hc
;
210 g_return_val_if_fail(name
!= NULL
, NULL
);
212 hc
.name
= (gchar
*)purple_normalize(account
, name
);
213 hc
.account
= account
;
216 c
= g_hash_table_lookup(conversation_cache
, &hc
);
221 PurpleChatConversation
*
222 purple_conversations_find_chat(const PurpleConnection
*gc
, int id
)
225 PurpleChatConversation
*chat
;
227 for (l
= purple_conversations_get_chats(); l
!= NULL
; l
= l
->next
) {
228 chat
= (PurpleChatConversation
*)l
->data
;
230 if (purple_chat_conversation_get_id(chat
) == id
&&
231 purple_conversation_get_connection(PURPLE_CONVERSATION(chat
)) == gc
)
239 purple_conversations_set_ui_ops(PurpleConversationUiOps
*ops
)
244 PurpleConversationUiOps
*
245 purple_conversations_get_ui_ops(void)
251 purple_conversations_get_handle(void)
259 purple_conversations_init(void)
261 void *handle
= purple_conversations_get_handle();
263 conversation_cache
= g_hash_table_new_full((GHashFunc
)_purple_conversations_hconv_hash
,
264 (GEqualFunc
)_purple_conversations_hconv_equal
,
265 (GDestroyNotify
)_purple_conversations_hconv_free_key
, NULL
);
267 /**********************************************************************
268 * Register preferences
269 **********************************************************************/
272 purple_prefs_add_none("/purple/conversations");
274 /* Conversations -> Chat */
275 purple_prefs_add_none("/purple/conversations/chat");
276 purple_prefs_add_bool("/purple/conversations/chat/show_nick_change", TRUE
);
278 /* Conversations -> IM */
279 purple_prefs_add_none("/purple/conversations/im");
280 purple_prefs_add_bool("/purple/conversations/im/send_typing", TRUE
);
283 /**********************************************************************
285 **********************************************************************/
286 purple_signal_register(handle
, "writing-im-msg",
287 purple_marshal_BOOLEAN__POINTER_POINTER
, G_TYPE_BOOLEAN
, 2,
288 PURPLE_TYPE_IM_CONVERSATION
, PURPLE_TYPE_MESSAGE
);
290 purple_signal_register(handle
, "wrote-im-msg",
291 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2,
292 PURPLE_TYPE_IM_CONVERSATION
, PURPLE_TYPE_MESSAGE
);
294 purple_signal_register(handle
, "sent-attention",
295 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT
,
296 G_TYPE_NONE
, 4, PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
,
297 PURPLE_TYPE_CONVERSATION
, G_TYPE_UINT
);
299 purple_signal_register(handle
, "got-attention",
300 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT
,
301 G_TYPE_NONE
, 4, PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
,
302 PURPLE_TYPE_CONVERSATION
, G_TYPE_UINT
);
304 purple_signal_register(handle
, "sending-im-msg",
305 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
,
306 2, PURPLE_TYPE_ACCOUNT
, PURPLE_TYPE_MESSAGE
);
308 purple_signal_register(handle
, "sent-im-msg",
309 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
,
310 2, PURPLE_TYPE_ACCOUNT
, PURPLE_TYPE_MESSAGE
);
312 purple_signal_register(handle
, "receiving-im-msg",
313 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER
,
314 G_TYPE_BOOLEAN
, 5, PURPLE_TYPE_ACCOUNT
,
315 G_TYPE_POINTER
, /* pointer to a string */
316 G_TYPE_POINTER
, /* pointer to a string */
317 PURPLE_TYPE_IM_CONVERSATION
,
318 G_TYPE_POINTER
); /* pointer to a string */
320 purple_signal_register(handle
, "received-im-msg",
321 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
322 G_TYPE_NONE
, 5, PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
,
323 G_TYPE_STRING
, PURPLE_TYPE_IM_CONVERSATION
, G_TYPE_UINT
);
325 purple_signal_register(handle
, "blocked-im-msg",
326 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT_UINT
,
327 G_TYPE_NONE
, 5, PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
,
328 G_TYPE_STRING
, G_TYPE_UINT
, G_TYPE_UINT
);
330 purple_signal_register(handle
, "writing-chat-msg",
331 purple_marshal_BOOLEAN__POINTER_POINTER
, G_TYPE_BOOLEAN
, 2,
332 PURPLE_TYPE_IM_CONVERSATION
, PURPLE_TYPE_MESSAGE
);
334 purple_signal_register(handle
, "wrote-chat-msg",
335 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2,
336 PURPLE_TYPE_IM_CONVERSATION
, PURPLE_TYPE_MESSAGE
);
338 purple_signal_register(handle
, "sending-chat-msg",
339 purple_marshal_VOID__POINTER_POINTER_UINT
, G_TYPE_NONE
,
340 3, PURPLE_TYPE_ACCOUNT
, PURPLE_TYPE_MESSAGE
, G_TYPE_UINT
);
342 purple_signal_register(handle
, "sent-chat-msg",
343 purple_marshal_VOID__POINTER_POINTER_UINT
, G_TYPE_NONE
,
344 3, PURPLE_TYPE_ACCOUNT
, PURPLE_TYPE_MESSAGE
, G_TYPE_UINT
);
346 purple_signal_register(handle
, "receiving-chat-msg",
347 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER
,
348 G_TYPE_BOOLEAN
, 5, PURPLE_TYPE_ACCOUNT
,
349 G_TYPE_POINTER
, /* pointer to a string */
350 G_TYPE_POINTER
, /* pointer to a string */
351 PURPLE_TYPE_CHAT_CONVERSATION
,
352 G_TYPE_POINTER
); /* pointer to an unsigned int */
354 purple_signal_register(handle
, "received-chat-msg",
355 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
356 G_TYPE_NONE
, 5, PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
,
357 G_TYPE_STRING
, PURPLE_TYPE_CHAT_CONVERSATION
, G_TYPE_UINT
);
359 purple_signal_register(handle
, "conversation-created",
360 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
361 PURPLE_TYPE_CONVERSATION
);
363 purple_signal_register(handle
, "conversation-updated",
364 purple_marshal_VOID__POINTER_UINT
, G_TYPE_NONE
, 2,
365 PURPLE_TYPE_CONVERSATION
, G_TYPE_UINT
);
367 purple_signal_register(handle
, "deleting-conversation",
368 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
369 PURPLE_TYPE_CONVERSATION
);
371 purple_signal_register(handle
, "buddy-typing",
372 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2,
373 PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
);
375 purple_signal_register(handle
, "buddy-typed",
376 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2,
377 PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
);
379 purple_signal_register(handle
, "buddy-typing-stopped",
380 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2,
381 PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
);
383 purple_signal_register(handle
, "chat-user-joining",
384 purple_marshal_BOOLEAN__POINTER_POINTER_UINT
,
385 G_TYPE_BOOLEAN
, 3, PURPLE_TYPE_CHAT_CONVERSATION
,
386 G_TYPE_STRING
, G_TYPE_UINT
);
388 purple_signal_register(handle
, "chat-user-joined",
389 purple_marshal_VOID__POINTER_POINTER_UINT_UINT
,
390 G_TYPE_NONE
, 4, PURPLE_TYPE_CHAT_CONVERSATION
,
391 G_TYPE_STRING
, G_TYPE_UINT
, G_TYPE_BOOLEAN
);
393 purple_signal_register(handle
, "chat-user-flags",
394 purple_marshal_VOID__POINTER_UINT_UINT
, G_TYPE_NONE
, 3,
395 PURPLE_TYPE_CHAT_USER
, G_TYPE_UINT
, G_TYPE_UINT
);
397 purple_signal_register(handle
, "chat-user-leaving",
398 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
399 G_TYPE_BOOLEAN
, 3, PURPLE_TYPE_CHAT_CONVERSATION
,
400 G_TYPE_STRING
, G_TYPE_STRING
);
402 purple_signal_register(handle
, "chat-user-left",
403 purple_marshal_VOID__POINTER_POINTER_POINTER
,
404 G_TYPE_NONE
, 3, PURPLE_TYPE_CHAT_CONVERSATION
,
405 G_TYPE_STRING
, G_TYPE_STRING
);
407 purple_signal_register(handle
, "deleting-chat-user",
408 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
409 PURPLE_TYPE_CHAT_USER
);
411 purple_signal_register(handle
, "chat-inviting-user",
412 purple_marshal_VOID__POINTER_POINTER_POINTER
,
413 G_TYPE_NONE
, 3, PURPLE_TYPE_CHAT_CONVERSATION
,
415 G_TYPE_POINTER
); /* pointer to a string */
417 purple_signal_register(handle
, "chat-invited-user",
418 purple_marshal_VOID__POINTER_POINTER_POINTER
,
419 G_TYPE_NONE
, 3, PURPLE_TYPE_CHAT_CONVERSATION
,
420 G_TYPE_STRING
, G_TYPE_STRING
);
422 purple_signal_register(handle
, "chat-invited",
423 purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER
,
424 G_TYPE_INT
, 5, PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
,
425 G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_POINTER
);
427 purple_signal_register(handle
, "chat-invite-blocked",
428 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_POINTER
,
429 G_TYPE_NONE
, 5, PURPLE_TYPE_ACCOUNT
, G_TYPE_STRING
,
430 G_TYPE_STRING
, G_TYPE_STRING
,
431 G_TYPE_POINTER
); /* (GHashTable *) */
433 purple_signal_register(handle
, "chat-joined",
434 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
435 PURPLE_TYPE_CHAT_CONVERSATION
);
437 purple_signal_register(handle
, "chat-join-failed",
438 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2,
439 PURPLE_TYPE_CONNECTION
, G_TYPE_POINTER
);
441 purple_signal_register(handle
, "chat-left",
442 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
443 PURPLE_TYPE_CHAT_CONVERSATION
);
445 purple_signal_register(handle
, "chat-topic-changed",
446 purple_marshal_VOID__POINTER_POINTER_POINTER
,
447 G_TYPE_NONE
, 3, PURPLE_TYPE_CHAT_CONVERSATION
,
448 G_TYPE_STRING
, G_TYPE_STRING
);
450 purple_signal_register(handle
, "cleared-message-history",
451 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
452 PURPLE_TYPE_CONVERSATION
);
454 purple_signal_register(handle
, "conversation-extended-menu",
455 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2,
456 PURPLE_TYPE_CONVERSATION
,
457 G_TYPE_POINTER
); /* (GList **) */
461 purple_conversations_uninit(void)
463 while (conversations
)
464 g_object_unref(G_OBJECT(conversations
->data
));
466 g_hash_table_destroy(conversation_cache
);
467 purple_signals_unregister_by_instance(purple_conversations_get_handle());