pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Route GLib debug logging directly to the Finch debug window
2021-10-18, Elliott Sales de Andrade
1896a80ff8e3
Route GLib debug logging directly to the Finch debug window
Instead of flowing through purple debug, this merges some bits of the existing GLib log handler, and the purple debug printer.
Testing Done:
Open the Debug window an see some `GLib-*` outputs.
Reviewed at https://reviews.imfreedom.org/r/1057/
/* purple
*
* Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
<glib/gi18n-lib.h>
#include
<gplugin.h>
#include
<gplugin-native.h>
#include
<purple.h>
#include
"libpurple/glibcompat.h"
#include
"api.h"
#include
"data.h"
#include
"facebook.h"
#include
"http.h"
#include
"util.h"
struct
_FacebookProtocol
{
PurpleProtocol
parent
;
};
static
GSList
*
fb_cmds
=
NULL
;
static
PurpleProtocol
*
fb_protocol
=
NULL
;
static
void
fb_cb_api_messages
(
FbApi
*
api
,
GSList
*
msgs
,
gpointer
data
);
static
PurpleGroup
*
fb_get_group
(
gboolean
friend
)
{
PurpleBlistNode
*
n
;
PurpleBlistNode
*
node
;
PurpleGroup
*
grp
;
const
gchar
*
title
;
if
(
friend
)
{
title
=
_
(
"Facebook Friends"
);
}
else
{
title
=
_
(
"Facebook Non-Friends"
);
}
grp
=
purple_blist_find_group
(
title
);
if
(
G_UNLIKELY
(
grp
==
NULL
))
{
grp
=
purple_group_new
(
title
);
node
=
NULL
;
for
(
n
=
purple_blist_get_default_root
();
n
!=
NULL
;
n
=
n
->
next
)
{
node
=
n
;
}
/* Append to the end of the buddy list */
purple_blist_add_group
(
grp
,
node
);
if
(
!
friend
)
{
node
=
PURPLE_BLIST_NODE
(
grp
);
purple_blist_node_set_bool
(
node
,
"collapsed"
,
TRUE
);
}
}
return
grp
;
}
static
void
fb_buddy_add_nonfriend
(
PurpleAccount
*
acct
,
FbApiUser
*
user
)
{
gchar
uid
[
FB_ID_STRMAX
];
PurpleBuddy
*
bdy
;
PurpleGroup
*
grp
;
FB_ID_TO_STR
(
user
->
uid
,
uid
);
bdy
=
purple_buddy_new
(
acct
,
uid
,
user
->
name
);
grp
=
fb_get_group
(
FALSE
);
purple_buddy_set_server_alias
(
bdy
,
user
->
name
);
purple_blist_add_buddy
(
bdy
,
NULL
,
grp
,
NULL
);
}
static
void
fb_cb_api_auth
(
FbApi
*
api
,
gpointer
data
)
{
FbData
*
fata
=
data
;
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
purple_connection_update_progress
(
gc
,
_
(
"Fetching contacts"
),
2
,
4
);
fb_data_save
(
fata
);
fb_api_contacts
(
api
);
}
static
void
fb_cb_api_connect
(
FbApi
*
api
,
gpointer
data
)
{
FbData
*
fata
=
data
;
PurpleAccount
*
acct
;
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
fb_data_save
(
fata
);
purple_connection_set_state
(
gc
,
PURPLE_CONNECTION_CONNECTED
);
if
(
purple_account_get_bool
(
acct
,
"show-unread"
,
TRUE
))
{
fb_api_unread
(
api
);
}
}
static
void
fb_cb_api_contact
(
FbApi
*
api
,
FbApiUser
*
user
,
gpointer
data
)
{
FbData
*
fata
=
data
;
gchar
uid
[
FB_ID_STRMAX
];
GSList
*
msgs
;
PurpleAccount
*
acct
;
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
FB_ID_TO_STR
(
user
->
uid
,
uid
);
if
(
purple_blist_find_buddy
(
acct
,
uid
)
==
NULL
)
{
fb_buddy_add_nonfriend
(
acct
,
user
);
}
msgs
=
fb_data_take_messages
(
fata
,
user
->
uid
);
if
(
msgs
!=
NULL
)
{
fb_cb_api_messages
(
api
,
msgs
,
fata
);
g_slist_free_full
(
msgs
,
(
GDestroyNotify
)
fb_api_message_free
);
}
}
static
gboolean
fb_cb_sync_contacts
(
gpointer
data
)
{
FbApi
*
api
;
FbData
*
fata
=
data
;
api
=
fb_data_get_api
(
fata
);
fb_data_clear_timeout
(
fata
,
"sync-contacts"
,
FALSE
);
fb_api_contacts
(
api
);
return
FALSE
;
}
static
void
fb_cb_icon
(
FbDataImage
*
img
,
GError
*
error
)
{
const
gchar
*
csum
;
const
gchar
*
name
;
const
gchar
*
str
;
FbHttpParams
*
params
;
gsize
size
;
guint8
*
image
;
PurpleAccount
*
acct
;
PurpleBuddy
*
bdy
;
bdy
=
fb_data_image_get_data
(
img
);
acct
=
purple_buddy_get_account
(
bdy
);
name
=
purple_buddy_get_name
(
bdy
);
if
(
G_UNLIKELY
(
error
!=
NULL
))
{
fb_util_debug_warning
(
"Failed to retrieve icon for %s: %s"
,
name
,
error
->
message
);
return
;
}
str
=
fb_data_image_get_url
(
img
);
params
=
fb_http_params_new_parse
(
str
,
TRUE
);
csum
=
fb_http_params_get_str
(
params
,
"oh"
,
NULL
);
image
=
fb_data_image_dup_image
(
img
,
&
size
);
purple_buddy_icons_set_for_user
(
acct
,
name
,
image
,
size
,
csum
);
fb_http_params_free
(
params
);
}
static
void
fb_sync_contacts_add_timeout
(
FbData
*
fata
)
{
gint
sync
;
PurpleConnection
*
gc
;
PurpleAccount
*
acct
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
sync
=
purple_account_get_int
(
acct
,
"sync-interval"
,
5
);
if
(
sync
<
1
)
{
purple_account_set_int
(
acct
,
"sync-interval"
,
1
);
sync
=
1
;
}
sync
*=
60
;
fb_data_add_timeout
(
fata
,
"sync-contacts"
,
sync
,
fb_cb_sync_contacts
,
fata
);
}
static
void
fb_cb_api_contacts
(
FbApi
*
api
,
GSList
*
users
,
gboolean
complete
,
gpointer
data
)
{
const
gchar
*
alias
;
const
gchar
*
csum
;
FbApiUser
*
user
;
FbData
*
fata
=
data
;
FbId
muid
;
gchar
uid
[
FB_ID_STRMAX
];
GSList
*
l
;
GValue
val
=
G_VALUE_INIT
;
PurpleAccount
*
acct
;
PurpleBuddy
*
bdy
;
PurpleConnection
*
gc
;
PurpleConnectionState
state
;
PurpleGroup
*
grp
;
PurpleGroup
*
grpn
;
PurpleStatus
*
status
;
PurpleStatusPrimitive
pstat
;
PurpleStatusType
*
type
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
grp
=
fb_get_group
(
TRUE
);
grpn
=
fb_get_group
(
FALSE
);
alias
=
purple_account_get_private_alias
(
acct
);
state
=
purple_connection_get_state
(
gc
);
g_value_init
(
&
val
,
FB_TYPE_ID
);
g_object_get_property
(
G_OBJECT
(
api
),
"uid"
,
&
val
);
muid
=
g_value_get_int64
(
&
val
);
g_value_unset
(
&
val
);
for
(
l
=
users
;
l
!=
NULL
;
l
=
l
->
next
)
{
user
=
l
->
data
;
FB_ID_TO_STR
(
user
->
uid
,
uid
);
if
(
G_UNLIKELY
(
user
->
uid
==
muid
))
{
if
(
G_UNLIKELY
(
alias
!=
NULL
))
{
continue
;
}
purple_account_set_private_alias
(
acct
,
user
->
name
);
continue
;
}
bdy
=
purple_blist_find_buddy
(
acct
,
uid
);
if
((
bdy
!=
NULL
)
&&
(
purple_buddy_get_group
(
bdy
)
==
grpn
))
{
purple_blist_remove_buddy
(
bdy
);
bdy
=
NULL
;
}
if
(
bdy
==
NULL
)
{
bdy
=
purple_buddy_new
(
acct
,
uid
,
NULL
);
purple_blist_add_buddy
(
bdy
,
NULL
,
grp
,
NULL
);
}
purple_buddy_set_server_alias
(
bdy
,
user
->
name
);
csum
=
purple_buddy_icons_get_checksum_for_user
(
bdy
);
if
(
!
purple_strequal
(
csum
,
user
->
csum
))
{
fb_data_image_add
(
fata
,
user
->
icon
,
fb_cb_icon
,
bdy
,
NULL
);
}
}
fb_data_image_queue
(
fata
);
if
(
!
complete
)
{
return
;
}
if
(
state
!=
PURPLE_CONNECTION_CONNECTED
)
{
status
=
purple_account_get_active_status
(
acct
);
type
=
purple_status_get_status_type
(
status
);
pstat
=
purple_status_type_get_primitive
(
type
);
purple_connection_update_progress
(
gc
,
_
(
"Connecting"
),
3
,
4
);
fb_api_connect
(
api
,
pstat
==
PURPLE_STATUS_INVISIBLE
);
}
fb_sync_contacts_add_timeout
(
fata
);
}
static
void
fb_cb_api_contacts_delta
(
FbApi
*
api
,
GSList
*
added
,
GSList
*
removed
,
gpointer
data
)
{
FbApiUser
*
user
;
FbData
*
fata
=
data
;
gchar
uid
[
FB_ID_STRMAX
];
GSList
*
l
;
PurpleAccount
*
acct
;
PurpleBuddy
*
bdy
;
PurpleConnection
*
gc
;
PurpleGroup
*
grp
;
PurpleGroup
*
grpn
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
grp
=
fb_get_group
(
TRUE
);
grpn
=
fb_get_group
(
FALSE
);
for
(
l
=
added
;
l
!=
NULL
;
l
=
l
->
next
)
{
user
=
l
->
data
;
FB_ID_TO_STR
(
user
->
uid
,
uid
);
bdy
=
purple_blist_find_buddy
(
acct
,
uid
);
if
((
bdy
!=
NULL
)
&&
(
purple_buddy_get_group
(
bdy
)
==
grpn
))
{
purple_blist_remove_buddy
(
bdy
);
}
bdy
=
purple_buddy_new
(
acct
,
uid
,
NULL
);
purple_blist_add_buddy
(
bdy
,
NULL
,
grp
,
NULL
);
purple_buddy_set_server_alias
(
bdy
,
user
->
name
);
}
for
(
l
=
removed
;
l
!=
NULL
;
l
=
l
->
next
)
{
bdy
=
purple_blist_find_buddy
(
acct
,
l
->
data
);
if
(
bdy
!=
NULL
)
{
purple_blist_remove_buddy
(
bdy
);
}
}
fb_sync_contacts_add_timeout
(
fata
);
}
static
void
fb_cb_api_error
(
FbApi
*
api
,
GError
*
error
,
gpointer
data
)
{
FbData
*
fata
=
data
;
PurpleConnection
*
gc
;
PurpleConnectionError
errc
;
gc
=
fb_data_get_connection
(
fata
);
if
(
error
->
domain
==
G_IO_ERROR
)
{
purple_connection_g_error
(
gc
,
error
);
return
;
}
if
(
g_error_matches
(
error
,
FB_API_ERROR
,
FB_API_ERROR_QUEUE
))
{
/* Save the reset data */
fb_data_save
(
fata
);
}
if
((
error
->
domain
==
FB_HTTP_ERROR
)
&&
(
error
->
code
>=
400
)
&&
(
error
->
code
<=
500
))
{
errc
=
PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
}
else
if
(
g_error_matches
(
error
,
FB_API_ERROR
,
FB_API_ERROR_AUTH
))
{
errc
=
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
;
}
else
{
errc
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
}
if
(
!
g_error_matches
(
error
,
FB_API_ERROR
,
FB_API_ERROR_NONFATAL
))
{
purple_connection_error
(
gc
,
errc
,
error
->
message
);
}
}
static
void
fb_cb_api_events
(
FbApi
*
api
,
GSList
*
events
,
gpointer
data
)
{
FbData
*
fata
=
data
;
FbApiEvent
*
event
;
gchar
uid
[
FB_ID_STRMAX
];
gchar
tid
[
FB_ID_STRMAX
];
GHashTable
*
fetch
;
GHashTableIter
iter
;
GSList
*
l
;
PurpleAccount
*
acct
;
PurpleConversation
*
chat
;
PurpleConversationManager
*
manager
;
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
fetch
=
g_hash_table_new
(
fb_id_hash
,
fb_id_equal
);
manager
=
purple_conversation_manager_get_default
();
for
(
l
=
events
;
l
!=
NULL
;
l
=
l
->
next
)
{
event
=
l
->
data
;
FB_ID_TO_STR
(
event
->
tid
,
tid
);
chat
=
purple_conversation_manager_find_chat
(
manager
,
acct
,
tid
);
if
(
chat
==
NULL
)
{
continue
;
}
FB_ID_TO_STR
(
event
->
uid
,
uid
);
switch
(
event
->
type
)
{
case
FB_API_EVENT_TYPE_THREAD_TOPIC
:
purple_chat_conversation_set_topic
(
PURPLE_CHAT_CONVERSATION
(
chat
),
uid
,
event
->
text
);
break
;
case
FB_API_EVENT_TYPE_THREAD_USER_ADDED
:
if
(
purple_blist_find_buddy
(
acct
,
uid
)
==
NULL
)
{
if
(
event
->
text
)
{
FbApiUser
*
user
=
fb_api_user_dup
(
NULL
,
FALSE
);
user
->
uid
=
event
->
uid
;
user
->
name
=
g_strdup
(
event
->
text
);
fb_buddy_add_nonfriend
(
acct
,
user
);
fb_api_user_free
(
user
);
}
else
{
g_hash_table_insert
(
fetch
,
&
event
->
tid
,
event
);
break
;
}
}
purple_chat_conversation_add_user
(
PURPLE_CHAT_CONVERSATION
(
chat
),
uid
,
NULL
,
0
,
TRUE
);
break
;
case
FB_API_EVENT_TYPE_THREAD_USER_REMOVED
:
purple_chat_conversation_remove_user
(
PURPLE_CHAT_CONVERSATION
(
chat
),
uid
,
event
->
text
);
break
;
}
}
g_hash_table_iter_init
(
&
iter
,
fetch
);
while
(
g_hash_table_iter_next
(
&
iter
,
NULL
,
(
gpointer
)
&
event
))
{
fb_api_thread
(
api
,
event
->
tid
);
}
g_hash_table_destroy
(
fetch
);
}
static
void
fb_cb_image
(
FbDataImage
*
img
,
GError
*
error
)
{
const
gchar
*
url
;
FbApi
*
api
;
FbApiMessage
*
msg
;
FbData
*
fata
;
gsize
size
;
GSList
*
msgs
=
NULL
;
guint
id
;
guint8
*
image
;
PurpleImage
*
pimg
;
fata
=
fb_data_image_get_fata
(
img
);
msg
=
fb_data_image_get_data
(
img
);
if
(
G_UNLIKELY
(
error
!=
NULL
))
{
url
=
fb_data_image_get_url
(
img
);
fb_util_debug_warning
(
"Failed to retrieve image %s: %s"
,
url
,
error
->
message
);
return
;
}
api
=
fb_data_get_api
(
fata
);
image
=
fb_data_image_dup_image
(
img
,
&
size
);
pimg
=
purple_image_new_from_data
(
image
,
size
);
id
=
purple_image_store_add_weak
(
pimg
);
g_free
(
msg
->
text
);
msg
->
text
=
g_strdup_printf
(
"<img src=
\"
"
PURPLE_IMAGE_STORE_PROTOCOL
"%u
\"
>"
,
id
);
msg
->
flags
|=
FB_API_MESSAGE_FLAG_DONE
;
msgs
=
g_slist_prepend
(
msgs
,
msg
);
fb_cb_api_messages
(
api
,
msgs
,
fata
);
g_slist_free
(
msgs
);
}
static
void
fb_cb_api_messages
(
FbApi
*
api
,
GSList
*
msgs
,
gpointer
data
)
{
const
gchar
*
text
;
FbApiMessage
*
msg
;
FbData
*
fata
=
data
;
gboolean
isself
;
gboolean
mark
;
gboolean
open
;
gboolean
self
;
gchar
*
html
;
gchar
tid
[
FB_ID_STRMAX
];
gchar
uid
[
FB_ID_STRMAX
];
gint
id
;
gint64
tstamp
;
GSList
*
l
;
PurpleAccount
*
acct
;
PurpleConversation
*
chat
;
PurpleConversationManager
*
manager
;
PurpleConnection
*
gc
;
PurpleMessageFlags
flags
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
mark
=
purple_account_get_bool
(
acct
,
"mark-read"
,
TRUE
);
open
=
purple_account_get_bool
(
acct
,
"group-chat-open"
,
TRUE
);
self
=
purple_account_get_bool
(
acct
,
"show-self"
,
TRUE
);
manager
=
purple_conversation_manager_get_default
();
for
(
l
=
msgs
;
l
!=
NULL
;
l
=
l
->
next
)
{
msg
=
l
->
data
;
FB_ID_TO_STR
(
msg
->
uid
,
uid
);
if
(
purple_blist_find_buddy
(
acct
,
uid
)
==
NULL
)
{
msg
=
fb_api_message_dup
(
msg
,
TRUE
);
fb_data_add_message
(
fata
,
msg
);
fb_api_contact
(
api
,
msg
->
uid
);
continue
;
}
isself
=
(
msg
->
flags
&
FB_API_MESSAGE_FLAG_SELF
)
!=
0
;
if
(
isself
&&
!
self
)
{
continue
;
}
flags
=
isself
?
PURPLE_MESSAGE_SEND
:
PURPLE_MESSAGE_RECV
;
tstamp
=
msg
->
tstamp
/
1000
;
if
(
msg
->
flags
&
FB_API_MESSAGE_FLAG_IMAGE
)
{
if
(
!
(
msg
->
flags
&
FB_API_MESSAGE_FLAG_DONE
))
{
msg
=
fb_api_message_dup
(
msg
,
TRUE
);
fb_data_image_add
(
fata
,
msg
->
text
,
fb_cb_image
,
msg
,
(
GDestroyNotify
)
fb_api_message_free
);
fb_data_image_queue
(
fata
);
continue
;
}
flags
|=
PURPLE_MESSAGE_IMAGES
;
text
=
msg
->
text
;
html
=
NULL
;
}
else
{
html
=
purple_markup_escape_text
(
msg
->
text
,
-1
);
text
=
html
;
}
if
(
msg
->
tid
==
0
)
{
if
(
mark
&&
!
isself
)
{
fb_data_set_unread
(
fata
,
msg
->
uid
,
TRUE
);
}
fb_util_serv_got_im
(
gc
,
uid
,
text
,
flags
,
tstamp
);
g_free
(
html
);
continue
;
}
FB_ID_TO_STR
(
msg
->
tid
,
tid
);
chat
=
purple_conversation_manager_find_chat
(
manager
,
acct
,
tid
);
if
(
chat
==
NULL
)
{
if
(
!
open
)
{
g_free
(
html
);
continue
;
}
id
=
fb_id_hash
(
&
msg
->
tid
);
purple_serv_got_joined_chat
(
gc
,
id
,
tid
);
fb_api_thread
(
api
,
msg
->
tid
);
}
else
{
id
=
purple_chat_conversation_get_id
(
PURPLE_CHAT_CONVERSATION
(
chat
));
}
if
(
mark
&&
!
isself
)
{
fb_data_set_unread
(
fata
,
msg
->
tid
,
TRUE
);
}
fb_util_serv_got_chat_in
(
gc
,
id
,
uid
,
text
,
flags
,
tstamp
);
g_free
(
html
);
}
}
static
void
fb_cb_api_presences
(
FbApi
*
api
,
GSList
*
presences
,
gpointer
data
)
{
const
gchar
*
statid
;
FbData
*
fata
=
data
;
gchar
uid
[
FB_ID_STRMAX
];
GSList
*
l
;
PurpleAccount
*
acct
;
PurpleConnection
*
gc
;
PurpleStatusPrimitive
pstat
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
for
(
l
=
presences
;
l
!=
NULL
;
l
=
l
->
next
)
{
FbApiPresence
*
api_presence
=
l
->
data
;
if
(
api_presence
->
active
)
{
pstat
=
PURPLE_STATUS_AVAILABLE
;
}
else
{
pstat
=
PURPLE_STATUS_OFFLINE
;
}
FB_ID_TO_STR
(
api_presence
->
uid
,
uid
);
statid
=
purple_primitive_get_id_from_type
(
pstat
);
purple_protocol_got_user_status
(
acct
,
uid
,
statid
,
NULL
);
}
}
static
void
fb_cb_api_thread
(
FbApi
*
api
,
FbApiThread
*
thrd
,
gpointer
data
)
{
const
gchar
*
name
;
FbApiUser
*
user
;
FbData
*
fata
=
data
;
gboolean
active
;
gchar
tid
[
FB_ID_STRMAX
];
gchar
uid
[
FB_ID_STRMAX
];
gint
id
;
GSList
*
l
;
PurpleAccount
*
acct
;
PurpleConversation
*
conv
;
PurpleConversationManager
*
manager
;
PurpleChatConversation
*
chat
;
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
id
=
fb_id_hash
(
&
thrd
->
tid
);
FB_ID_TO_STR
(
thrd
->
tid
,
tid
);
manager
=
purple_conversation_manager_get_default
();
conv
=
purple_conversation_manager_find_chat
(
manager
,
acct
,
tid
);
if
((
conv
==
NULL
)
||
purple_chat_conversation_has_left
(
PURPLE_CHAT_CONVERSATION
(
conv
)))
{
conv
=
purple_serv_got_joined_chat
(
gc
,
id
,
tid
);
chat
=
PURPLE_CHAT_CONVERSATION
(
conv
);
active
=
FALSE
;
}
else
{
/* If there are no users in the group chat, including
* the local user, then the group chat has yet to be
* setup by this function. As a result, any group chat
* without users is inactive.
*/
chat
=
PURPLE_CHAT_CONVERSATION
(
conv
);
active
=
purple_chat_conversation_get_users_count
(
chat
)
>
0
;
}
if
(
!
active
)
{
name
=
purple_account_get_username
(
acct
);
purple_chat_conversation_add_user
(
chat
,
name
,
NULL
,
0
,
FALSE
);
}
purple_chat_conversation_set_topic
(
chat
,
NULL
,
thrd
->
topic
);
for
(
l
=
thrd
->
users
;
l
!=
NULL
;
l
=
l
->
next
)
{
user
=
l
->
data
;
FB_ID_TO_STR
(
user
->
uid
,
uid
);
if
(
purple_chat_conversation_has_user
(
chat
,
uid
))
{
continue
;
}
if
(
purple_blist_find_buddy
(
acct
,
uid
)
==
NULL
)
{
fb_buddy_add_nonfriend
(
acct
,
user
);
}
purple_chat_conversation_add_user
(
chat
,
uid
,
NULL
,
0
,
active
);
}
}
static
void
fb_cb_api_thread_create
(
FbApi
*
api
,
FbId
tid
,
gpointer
data
)
{
FbData
*
fata
=
data
;
gchar
sid
[
FB_ID_STRMAX
];
GHashTable
*
table
;
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
FB_ID_TO_STR
(
tid
,
sid
);
table
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
NULL
,
g_free
);
g_hash_table_insert
(
table
,
"name"
,
g_strdup
(
sid
));
purple_serv_join_chat
(
gc
,
table
);
g_hash_table_destroy
(
table
);
}
static
void
fb_cb_api_thread_kicked
(
FbApi
*
api
,
FbApiThread
*
thrd
,
gpointer
data
)
{
FbData
*
fata
=
data
;
gchar
tid
[
FB_ID_STRMAX
];
PurpleAccount
*
acct
;
PurpleConnection
*
gc
;
PurpleConversation
*
chat
;
PurpleConversationManager
*
manager
;
FB_ID_TO_STR
(
thrd
->
tid
,
tid
);
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
manager
=
purple_conversation_manager_get_default
();
chat
=
purple_conversation_manager_find_chat
(
manager
,
acct
,
tid
);
if
(
chat
==
NULL
)
{
PurpleRequestCommonParameters
*
cpar
;
cpar
=
purple_request_cpar_from_connection
(
gc
);
purple_notify_error
(
gc
,
_
(
"Join a Chat"
),
_
(
"Failed to Join Chat"
),
_
(
"You have been removed from this chat"
),
cpar
);
return
;
}
purple_conversation_write_system_message
(
chat
,
_
(
"You have been removed from this chat"
),
0
);
purple_serv_got_chat_left
(
gc
,
purple_chat_conversation_get_id
(
PURPLE_CHAT_CONVERSATION
(
chat
)));
}
static
void
fb_cb_api_threads
(
FbApi
*
api
,
GSList
*
thrds
,
gpointer
data
)
{
const
gchar
*
alias
;
FbApiUser
*
user
;
FbData
*
fata
=
data
;
gchar
tid
[
FB_ID_STRMAX
];
gchar
uid
[
FB_ID_STRMAX
];
GSList
*
l
;
GSList
*
m
;
GString
*
gstr
;
FbApiThread
*
thrd
;
PurpleAccount
*
acct
;
PurpleBuddy
*
bdy
;
PurpleConnection
*
gc
;
PurpleRoomlist
*
list
;
PurpleRoomlistRoom
*
room
;
list
=
fb_data_get_roomlist
(
fata
);
if
(
G_UNLIKELY
(
list
==
NULL
))
{
return
;
}
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
gstr
=
g_string_new
(
NULL
);
for
(
l
=
thrds
;
l
!=
NULL
;
l
=
l
->
next
)
{
thrd
=
l
->
data
;
FB_ID_TO_STR
(
thrd
->
tid
,
tid
);
g_string_truncate
(
gstr
,
0
);
for
(
m
=
thrd
->
users
;
m
!=
NULL
;
m
=
m
->
next
)
{
user
=
m
->
data
;
FB_ID_TO_STR
(
user
->
uid
,
uid
);
bdy
=
purple_blist_find_buddy
(
acct
,
uid
);
if
(
bdy
!=
NULL
)
{
alias
=
purple_buddy_get_alias
(
bdy
);
}
else
{
alias
=
user
->
name
;
}
if
(
gstr
->
len
>
0
)
{
g_string_append
(
gstr
,
", "
);
}
g_string_append
(
gstr
,
alias
);
}
room
=
purple_roomlist_room_new
(
PURPLE_ROOMLIST_ROOMTYPE_ROOM
,
tid
,
NULL
);
purple_roomlist_room_add_field
(
list
,
room
,
thrd
->
topic
);
purple_roomlist_room_add_field
(
list
,
room
,
gstr
->
str
);
purple_roomlist_room_add
(
list
,
room
);
}
purple_roomlist_set_in_progress
(
list
,
FALSE
);
fb_data_set_roomlist
(
fata
,
NULL
);
g_string_free
(
gstr
,
TRUE
);
}
static
void
fb_cb_api_typing
(
FbApi
*
api
,
FbApiTyping
*
typg
,
gpointer
data
)
{
FbData
*
fata
=
data
;
gchar
uid
[
FB_ID_STRMAX
];
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
FB_ID_TO_STR
(
typg
->
uid
,
uid
);
if
(
typg
->
state
)
{
purple_serv_got_typing
(
gc
,
uid
,
0
,
PURPLE_IM_TYPING
);
}
else
{
purple_serv_got_typing_stopped
(
gc
,
uid
);
}
}
static
void
fb_mark_read
(
FbData
*
fata
,
FbId
id
,
gboolean
thread
)
{
FbApi
*
api
;
PurpleAccount
*
acct
;
PurpleConnection
*
gc
;
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
api
=
fb_data_get_api
(
fata
);
if
(
!
fb_data_get_unread
(
fata
,
id
)
||
(
purple_account_get_bool
(
acct
,
"mark-read-available"
,
FALSE
)
&&
fb_api_is_invisible
(
api
)))
{
return
;
}
fb_data_set_unread
(
fata
,
id
,
FALSE
);
fb_api_read
(
api
,
id
,
thread
);
}
static
gboolean
fb_cb_conv_read
(
gpointer
data
)
{
const
gchar
*
name
;
FbData
*
fata
;
FbId
id
;
gchar
*
tname
;
PurpleConnection
*
gc
;
PurpleConversation
*
conv
=
data
;
gc
=
purple_conversation_get_connection
(
conv
);
fata
=
purple_connection_get_protocol_data
(
gc
);
name
=
purple_conversation_get_name
(
conv
);
id
=
FB_ID_FROM_STR
(
name
);
tname
=
g_strconcat
(
"conv-read-"
,
name
,
NULL
);
fb_data_clear_timeout
(
fata
,
tname
,
FALSE
);
g_free
(
tname
);
if
(
purple_conversation_has_focus
(
conv
))
{
fb_mark_read
(
fata
,
id
,
PURPLE_IS_CHAT_CONVERSATION
(
conv
));
}
return
FALSE
;
}
static
void
fb_cb_conv_updated
(
PurpleConversation
*
conv
,
PurpleConversationUpdateType
type
,
gpointer
data
)
{
const
gchar
*
name
;
const
gchar
*
pid
;
FbData
*
fata
=
data
;
gchar
*
tname
;
PurpleAccount
*
acct
;
acct
=
purple_conversation_get_account
(
conv
);
pid
=
purple_account_get_protocol_id
(
acct
);
if
((
type
==
PURPLE_CONVERSATION_UPDATE_UNSEEN
)
&&
purple_strequal
(
pid
,
FB_PROTOCOL_ID
)
&&
purple_account_get_bool
(
acct
,
"mark-read"
,
TRUE
))
{
/* Use event loop for purple_conversation_has_focus() */
name
=
purple_conversation_get_name
(
conv
);
tname
=
g_strconcat
(
"conv-read-"
,
name
,
NULL
);
fb_data_add_timeout
(
fata
,
tname
,
0
,
fb_cb_conv_read
,
conv
);
g_free
(
tname
);
}
}
static
void
fb_cb_conv_deleting
(
PurpleConversation
*
conv
,
gpointer
data
)
{
const
gchar
*
name
;
const
gchar
*
pid
;
FbData
*
fata
=
data
;
gchar
*
tname
;
PurpleAccount
*
acct
;
acct
=
purple_conversation_get_account
(
conv
);
pid
=
purple_account_get_protocol_id
(
acct
);
if
(
!
purple_strequal
(
pid
,
FB_PROTOCOL_ID
))
{
return
;
}
name
=
purple_conversation_get_name
(
conv
);
tname
=
g_strconcat
(
"conv-read-"
,
name
,
NULL
);
fb_data_clear_timeout
(
fata
,
tname
,
TRUE
);
g_free
(
tname
);
}
static
void
fb_blist_chat_create
(
GSList
*
buddies
,
gpointer
data
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
=
data
;
FbId
*
did
;
FbId
uid
;
GSList
*
l
;
GSList
*
uids
=
NULL
;
PurpleConnection
*
gc
;
PurpleRequestCommonParameters
*
cpar
;
gc
=
fb_data_get_connection
(
fata
);
api
=
fb_data_get_api
(
fata
);
if
(
g_slist_length
(
buddies
)
<
2
)
{
cpar
=
purple_request_cpar_from_connection
(
gc
);
purple_notify_error
(
gc
,
_
(
"Initiate Chat"
),
_
(
"Failed to Initiate Chat"
),
_
(
"At least two initial chat participants"
" are required."
),
cpar
);
return
;
}
for
(
l
=
buddies
;
l
!=
NULL
;
l
=
l
->
next
)
{
name
=
purple_buddy_get_name
(
l
->
data
);
uid
=
FB_ID_FROM_STR
(
name
);
did
=
g_memdup2
(
&
uid
,
sizeof
uid
);
uids
=
g_slist_prepend
(
uids
,
did
);
}
fb_api_thread_create
(
api
,
uids
);
g_slist_free_full
(
uids
,
g_free
);
}
static
void
fb_blist_chat_init
(
PurpleBlistNode
*
node
,
gpointer
data
)
{
FbData
*
fata
=
data
;
GSList
*
select
=
NULL
;
PurpleConnection
*
gc
;
if
(
!
PURPLE_IS_BUDDY
(
node
))
{
return
;
}
gc
=
fb_data_get_connection
(
fata
);
select
=
g_slist_prepend
(
select
,
PURPLE_BUDDY
(
node
));
fb_util_request_buddy
(
gc
,
_
(
"Initiate Chat"
),
_
(
"Initial Chat Participants"
),
_
(
"Select at least two initial participants."
),
select
,
TRUE
,
G_CALLBACK
(
fb_blist_chat_create
),
NULL
,
fata
);
g_slist_free
(
select
);
}
static
GList
*
fb_get_account_options
(
PurpleProtocol
*
protocol
)
{
GList
*
opts
=
NULL
;
PurpleAccountOption
*
opt
;
opt
=
purple_account_option_int_new
(
_
(
"Buddy list sync interval"
),
"sync-interval"
,
5
);
opts
=
g_list_prepend
(
opts
,
opt
);
opt
=
purple_account_option_bool_new
(
_
(
"Mark messages as read on focus"
),
"mark-read"
,
TRUE
);
opts
=
g_list_prepend
(
opts
,
opt
);
opt
=
purple_account_option_bool_new
(
_
(
"Mark messages as read only when available"
),
"mark-read-available"
,
FALSE
);
opts
=
g_list_prepend
(
opts
,
opt
);
opt
=
purple_account_option_bool_new
(
_
(
"Show self messages"
),
"show-self"
,
TRUE
);
opts
=
g_list_prepend
(
opts
,
opt
);
opt
=
purple_account_option_bool_new
(
_
(
"Show unread messages"
),
"show-unread"
,
TRUE
);
opts
=
g_list_prepend
(
opts
,
opt
);
opt
=
purple_account_option_bool_new
(
_
(
"Open new group chats with "
"incoming messages"
),
"group-chat-open"
,
TRUE
);
opts
=
g_list_prepend
(
opts
,
opt
);
return
g_list_reverse
(
opts
);
}
static
void
fb_login
(
PurpleAccount
*
acct
)
{
const
gchar
*
pass
;
const
gchar
*
user
;
FbApi
*
api
;
FbData
*
fata
;
gpointer
convh
;
PurpleConnection
*
gc
;
GProxyResolver
*
resolver
;
GError
*
error
=
NULL
;
gc
=
purple_account_get_connection
(
acct
);
resolver
=
purple_proxy_get_proxy_resolver
(
acct
,
&
error
);
if
(
resolver
==
NULL
)
{
fb_util_debug_error
(
"Unable to get account proxy resolver: %s"
,
error
->
message
);
purple_connection_take_error
(
gc
,
error
);
return
;
}
fata
=
fb_data_new
(
gc
,
resolver
);
api
=
fb_data_get_api
(
fata
);
convh
=
purple_conversations_get_handle
();
purple_connection_set_protocol_data
(
gc
,
fata
);
g_signal_connect
(
api
,
"auth"
,
G_CALLBACK
(
fb_cb_api_auth
),
fata
);
g_signal_connect
(
api
,
"connect"
,
G_CALLBACK
(
fb_cb_api_connect
),
fata
);
g_signal_connect
(
api
,
"contact"
,
G_CALLBACK
(
fb_cb_api_contact
),
fata
);
g_signal_connect
(
api
,
"contacts"
,
G_CALLBACK
(
fb_cb_api_contacts
),
fata
);
g_signal_connect
(
api
,
"contacts-delta"
,
G_CALLBACK
(
fb_cb_api_contacts_delta
),
fata
);
g_signal_connect
(
api
,
"error"
,
G_CALLBACK
(
fb_cb_api_error
),
fata
);
g_signal_connect
(
api
,
"events"
,
G_CALLBACK
(
fb_cb_api_events
),
fata
);
g_signal_connect
(
api
,
"messages"
,
G_CALLBACK
(
fb_cb_api_messages
),
fata
);
g_signal_connect
(
api
,
"presences"
,
G_CALLBACK
(
fb_cb_api_presences
),
fata
);
g_signal_connect
(
api
,
"thread"
,
G_CALLBACK
(
fb_cb_api_thread
),
fata
);
g_signal_connect
(
api
,
"thread-create"
,
G_CALLBACK
(
fb_cb_api_thread_create
),
fata
);
g_signal_connect
(
api
,
"thread-kicked"
,
G_CALLBACK
(
fb_cb_api_thread_kicked
),
fata
);
g_signal_connect
(
api
,
"threads"
,
G_CALLBACK
(
fb_cb_api_threads
),
fata
);
g_signal_connect
(
api
,
"typing"
,
G_CALLBACK
(
fb_cb_api_typing
),
fata
);
purple_signal_connect
(
convh
,
"conversation-updated"
,
gc
,
G_CALLBACK
(
fb_cb_conv_updated
),
fata
);
purple_signal_connect
(
convh
,
"deleting-conversation"
,
gc
,
G_CALLBACK
(
fb_cb_conv_deleting
),
fata
);
if
(
!
fb_data_load
(
fata
)
||
!
purple_account_get_remember_password
(
acct
))
{
user
=
purple_account_get_username
(
acct
);
pass
=
purple_connection_get_password
(
gc
);
purple_connection_update_progress
(
gc
,
_
(
"Authenticating"
),
1
,
4
);
fb_api_auth
(
api
,
user
,
pass
);
return
;
}
purple_connection_update_progress
(
gc
,
_
(
"Fetching contacts"
),
2
,
4
);
fb_api_contacts
(
api
);
}
static
void
fb_close
(
PurpleConnection
*
gc
)
{
FbApi
*
api
;
FbData
*
fata
;
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
fb_data_save
(
fata
);
fb_api_disconnect
(
api
);
g_object_unref
(
fata
);
purple_connection_set_protocol_data
(
gc
,
NULL
);
purple_signals_disconnect_by_handle
(
gc
);
}
static
GList
*
fb_status_types
(
PurpleAccount
*
acct
)
{
PurpleStatusType
*
type
;
GList
*
types
=
NULL
;
type
=
purple_status_type_new
(
PURPLE_STATUS_AVAILABLE
,
NULL
,
NULL
,
TRUE
);
types
=
g_list_prepend
(
types
,
type
);
/* Just a NULL state (as of now) for compatibility */
type
=
purple_status_type_new
(
PURPLE_STATUS_AWAY
,
NULL
,
NULL
,
TRUE
);
types
=
g_list_prepend
(
types
,
type
);
type
=
purple_status_type_new
(
PURPLE_STATUS_INVISIBLE
,
NULL
,
NULL
,
TRUE
);
types
=
g_list_prepend
(
types
,
type
);
type
=
purple_status_type_new
(
PURPLE_STATUS_OFFLINE
,
NULL
,
NULL
,
TRUE
);
types
=
g_list_prepend
(
types
,
type
);
return
g_list_reverse
(
types
);
}
static
const
char
*
fb_list_icon
(
PurpleAccount
*
account
,
PurpleBuddy
*
buddy
)
{
return
"facebook"
;
}
static
void
fb_client_tooltip_text
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
,
PurpleNotifyUserInfo
*
info
,
gboolean
full
)
{
const
gchar
*
name
;
PurplePresence
*
presence
;
PurpleStatus
*
status
;
presence
=
purple_buddy_get_presence
(
buddy
);
status
=
purple_presence_get_active_status
(
presence
);
if
(
!
PURPLE_BUDDY_IS_ONLINE
(
buddy
))
{
/* Prevent doubles statues for Offline buddies */
/* See: pidgin_get_tooltip_text() in gtkblist.c */
purple_notify_user_info_remove_last_item
(
info
);
}
name
=
purple_status_get_name
(
status
);
purple_notify_user_info_add_pair_plaintext
(
info
,
_
(
"Status"
),
name
);
}
static
GList
*
fb_client_blist_node_menu
(
PurpleProtocolClient
*
client
,
PurpleBlistNode
*
node
)
{
FbData
*
fata
;
GList
*
acts
=
NULL
;
PurpleAccount
*
acct
;
PurpleConnection
*
gc
;
PurpleActionMenu
*
act
;
if
(
!
PURPLE_IS_BUDDY
(
node
))
{
return
NULL
;
}
acct
=
purple_buddy_get_account
(
PURPLE_BUDDY
(
node
));
gc
=
purple_account_get_connection
(
acct
);
fata
=
purple_connection_get_protocol_data
(
gc
);
act
=
purple_action_menu_new
(
_
(
"Initiate _Chat"
),
PURPLE_CALLBACK
(
fb_blist_chat_init
),
fata
,
NULL
);
acts
=
g_list_prepend
(
acts
,
act
);
return
g_list_reverse
(
acts
);
}
static
gboolean
fb_client_offline_message
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
)
{
return
TRUE
;
}
static
void
fb_server_set_status
(
PurpleProtocolServer
*
protocol_server
,
PurpleAccount
*
acct
,
PurpleStatus
*
status
)
{
FbApi
*
api
;
FbData
*
fata
;
gboolean
invis
;
PurpleConnection
*
gc
;
PurpleStatusPrimitive
pstat
;
PurpleStatusType
*
type
;
gc
=
purple_account_get_connection
(
acct
);
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
type
=
purple_status_get_status_type
(
status
);
pstat
=
purple_status_type_get_primitive
(
type
);
invis
=
fb_api_is_invisible
(
api
);
if
((
pstat
==
PURPLE_STATUS_INVISIBLE
)
&&
!
invis
)
{
fb_api_connect
(
api
,
TRUE
);
}
else
if
((
pstat
!=
PURPLE_STATUS_OFFLINE
)
&&
invis
)
{
fb_api_connect
(
api
,
FALSE
);
}
}
static
gint
fb_im_send
(
PurpleProtocolIM
*
im
,
PurpleConnection
*
gc
,
PurpleMessage
*
msg
)
{
const
gchar
*
name
;
const
gchar
*
text
;
FbApi
*
api
;
FbData
*
fata
;
FbId
uid
;
gchar
*
sext
;
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
name
=
purple_message_get_recipient
(
msg
);
uid
=
FB_ID_FROM_STR
(
name
);
text
=
purple_message_get_contents
(
msg
);
sext
=
purple_markup_strip_html
(
text
);
fb_api_message
(
api
,
uid
,
FALSE
,
sext
);
g_free
(
sext
);
return
1
;
}
static
guint
fb_im_send_typing
(
PurpleProtocolIM
*
im
,
PurpleConnection
*
gc
,
const
gchar
*
name
,
PurpleIMTypingState
state
)
{
FbApi
*
api
;
FbData
*
fata
;
FbId
uid
;
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
uid
=
FB_ID_FROM_STR
(
name
);
fb_api_typing
(
api
,
uid
,
state
!=
PURPLE_IM_NOT_TYPING
);
return
0
;
}
static
GList
*
fb_chat_info
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
connection
)
{
GList
*
pces
=
NULL
;
PurpleProtocolChatEntry
*
pce
;
pce
=
g_new0
(
PurpleProtocolChatEntry
,
1
);
pce
->
label
=
_
(
"Chat _Name:"
);
pce
->
identifier
=
"name"
;
pce
->
required
=
TRUE
;
pces
=
g_list_prepend
(
pces
,
pce
);
return
g_list_reverse
(
pces
);
}
static
GHashTable
*
fb_chat_info_defaults
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
const
gchar
*
name
)
{
GHashTable
*
data
;
data
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
NULL
,
g_free
);
g_hash_table_insert
(
data
,
"name"
,
g_strdup
(
name
));
return
data
;
}
static
void
fb_chat_join
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
GHashTable
*
data
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
gint
id
;
PurpleConversation
*
chat
;
PurpleConversationManager
*
manager
;
PurpleRequestCommonParameters
*
cpar
;
name
=
g_hash_table_lookup
(
data
,
"name"
);
g_return_if_fail
(
name
!=
NULL
);
if
(
!
FB_ID_IS_STR
(
name
))
{
cpar
=
purple_request_cpar_from_connection
(
gc
);
purple_notify_error
(
gc
,
_
(
"Join a Chat"
),
_
(
"Failed to Join Chat"
),
_
(
"Invalid Facebook identifier."
),
cpar
);
return
;
}
tid
=
FB_ID_FROM_STR
(
name
);
id
=
fb_id_hash
(
&
tid
);
manager
=
purple_conversation_manager_get_default
();
chat
=
purple_conversation_manager_find_chat_by_id
(
manager
,
purple_connection_get_account
(
gc
),
id
);
if
((
chat
!=
NULL
)
&&
!
purple_chat_conversation_has_left
(
PURPLE_CHAT_CONVERSATION
(
chat
)))
{
purple_conversation_present
(
chat
);
return
;
}
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
fb_api_thread
(
api
,
tid
);
}
static
gchar
*
fb_chat_get_name
(
PurpleProtocolChat
*
protocol_chat
,
GHashTable
*
data
)
{
const
gchar
*
name
;
name
=
g_hash_table_lookup
(
data
,
"name"
);
g_return_val_if_fail
(
name
!=
NULL
,
NULL
);
return
g_strdup
(
name
);
}
static
void
fb_chat_invite
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
gint
id
,
const
gchar
*
msg
,
const
gchar
*
who
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
FbId
uid
;
PurpleConversation
*
chat
;
PurpleConversationManager
*
manager
;
PurpleRequestCommonParameters
*
cpar
;
if
(
!
FB_ID_IS_STR
(
who
))
{
cpar
=
purple_request_cpar_from_connection
(
gc
);
purple_notify_error
(
gc
,
_
(
"Invite Buddy Into Chat Room"
),
_
(
"Failed to Invite User"
),
_
(
"Invalid Facebook identifier."
),
cpar
);
return
;
}
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
manager
=
purple_conversation_manager_get_default
();
chat
=
purple_conversation_manager_find_chat_by_id
(
manager
,
purple_connection_get_account
(
gc
),
id
);
name
=
purple_conversation_get_name
(
chat
);
tid
=
FB_ID_FROM_STR
(
name
);
uid
=
FB_ID_FROM_STR
(
who
);
fb_api_thread_invite
(
api
,
tid
,
uid
);
}
static
gint
fb_chat_send
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
gint
id
,
PurpleMessage
*
msg
)
{
const
gchar
*
name
;
const
gchar
*
text
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
gchar
*
sext
;
PurpleAccount
*
acct
;
PurpleConversation
*
chat
;
PurpleConversationManager
*
manager
;
acct
=
purple_connection_get_account
(
gc
);
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
manager
=
purple_conversation_manager_get_default
();
chat
=
purple_conversation_manager_find_chat_by_id
(
manager
,
acct
,
id
);
name
=
purple_conversation_get_name
(
chat
);
tid
=
FB_ID_FROM_STR
(
name
);
text
=
purple_message_get_contents
(
msg
);
sext
=
purple_markup_strip_html
(
text
);
fb_api_message
(
api
,
tid
,
TRUE
,
sext
);
g_free
(
sext
);
name
=
purple_account_get_username
(
acct
);
purple_serv_got_chat_in
(
gc
,
id
,
name
,
purple_message_get_flags
(
msg
),
purple_message_get_contents
(
msg
),
time
(
NULL
));
return
0
;
}
static
void
fb_chat_set_topic
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
gint
id
,
const
gchar
*
topic
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
PurpleConversation
*
chat
;
PurpleConversationManager
*
manager
;
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
manager
=
purple_conversation_manager_get_default
();
chat
=
purple_conversation_manager_find_chat_by_id
(
manager
,
purple_connection_get_account
(
gc
),
id
);
name
=
purple_conversation_get_name
(
chat
);
tid
=
FB_ID_FROM_STR
(
name
);
fb_api_thread_topic
(
api
,
tid
,
topic
);
}
static
PurpleRoomlist
*
fb_roomlist_get_list
(
PurpleProtocolRoomlist
*
protocol_roomlist
,
PurpleConnection
*
gc
)
{
FbApi
*
api
;
FbData
*
fata
;
GList
*
flds
=
NULL
;
PurpleAccount
*
acct
;
PurpleRoomlist
*
list
;
PurpleRoomlistField
*
fld
;
fata
=
purple_connection_get_protocol_data
(
gc
);
list
=
fb_data_get_roomlist
(
fata
);
g_return_val_if_fail
(
list
==
NULL
,
NULL
);
api
=
fb_data_get_api
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
list
=
purple_roomlist_new
(
acct
);
fb_data_set_roomlist
(
fata
,
list
);
fld
=
purple_roomlist_field_new
(
PURPLE_ROOMLIST_FIELD_STRING
,
_
(
"Topic"
),
"topic"
,
FALSE
);
flds
=
g_list_prepend
(
flds
,
fld
);
fld
=
purple_roomlist_field_new
(
PURPLE_ROOMLIST_FIELD_STRING
,
_
(
"Users"
),
"users"
,
FALSE
);
flds
=
g_list_prepend
(
flds
,
fld
);
flds
=
g_list_reverse
(
flds
);
purple_roomlist_set_fields
(
list
,
flds
);
purple_roomlist_set_in_progress
(
list
,
TRUE
);
fb_api_threads
(
api
);
return
list
;
}
static
void
fb_roomlist_cancel
(
PurpleProtocolRoomlist
*
protocol_roomlist
,
PurpleRoomlist
*
list
)
{
FbData
*
fata
;
PurpleAccount
*
acct
;
PurpleConnection
*
gc
;
PurpleRoomlist
*
cist
;
acct
=
purple_roomlist_get_account
(
list
);
gc
=
purple_account_get_connection
(
acct
);
fata
=
purple_connection_get_protocol_data
(
gc
);
cist
=
fb_data_get_roomlist
(
fata
);
if
(
G_LIKELY
(
cist
==
list
))
{
fb_data_set_roomlist
(
fata
,
NULL
);
}
purple_roomlist_set_in_progress
(
list
,
FALSE
);
g_object_unref
(
list
);
}
static
PurpleCmdRet
fb_cmd_kick
(
PurpleConversation
*
conv
,
const
gchar
*
cmd
,
gchar
**
args
,
gchar
**
error
,
gpointer
data
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
FbId
uid
;
GError
*
err
=
NULL
;
PurpleAccount
*
acct
;
PurpleBuddy
*
bdy
;
PurpleConnection
*
gc
;
PurpleChatConversation
*
chat
;
g_return_val_if_fail
(
PURPLE_IS_CHAT_CONVERSATION
(
conv
),
PURPLE_CMD_RET_FAILED
);
gc
=
purple_conversation_get_connection
(
conv
);
acct
=
purple_connection_get_account
(
gc
);
chat
=
PURPLE_CHAT_CONVERSATION
(
conv
);
bdy
=
fb_util_account_find_buddy
(
acct
,
chat
,
args
[
0
],
&
err
);
if
(
err
!=
NULL
)
{
*
error
=
g_strdup_printf
(
_
(
"%s."
),
err
->
message
);
g_error_free
(
err
);
return
PURPLE_CMD_RET_FAILED
;
}
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
name
=
purple_conversation_get_name
(
conv
);
tid
=
FB_ID_FROM_STR
(
name
);
name
=
purple_buddy_get_name
(
bdy
);
uid
=
FB_ID_FROM_STR
(
name
);
fb_api_thread_remove
(
api
,
tid
,
uid
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
fb_cmd_leave
(
PurpleConversation
*
conv
,
const
gchar
*
cmd
,
gchar
**
args
,
gchar
**
error
,
gpointer
data
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
gint
id
;
PurpleConnection
*
gc
;
PurpleChatConversation
*
chat
;
g_return_val_if_fail
(
PURPLE_IS_CHAT_CONVERSATION
(
conv
),
PURPLE_CMD_RET_FAILED
);
gc
=
purple_conversation_get_connection
(
conv
);
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
chat
=
PURPLE_CHAT_CONVERSATION
(
conv
);
id
=
purple_chat_conversation_get_id
(
chat
);
name
=
purple_conversation_get_name
(
conv
);
tid
=
FB_ID_FROM_STR
(
name
);
purple_serv_got_chat_left
(
gc
,
id
);
fb_api_thread_remove
(
api
,
tid
,
0
);
return
PURPLE_CMD_RET_OK
;
}
static
void
facebook_protocol_init
(
FacebookProtocol
*
self
)
{
}
static
void
facebook_protocol_class_init
(
FacebookProtocolClass
*
klass
)
{
PurpleProtocolClass
*
protocol_class
=
PURPLE_PROTOCOL_CLASS
(
klass
);
protocol_class
->
get_account_options
=
fb_get_account_options
;
protocol_class
->
login
=
fb_login
;
protocol_class
->
close
=
fb_close
;
protocol_class
->
status_types
=
fb_status_types
;
protocol_class
->
list_icon
=
fb_list_icon
;
}
static
void
facebook_protocol_class_finalize
(
G_GNUC_UNUSED
FacebookProtocolClass
*
klass
)
{
}
static
void
facebook_protocol_client_iface_init
(
PurpleProtocolClientInterface
*
iface
)
{
iface
->
tooltip_text
=
fb_client_tooltip_text
;
iface
->
blist_node_menu
=
fb_client_blist_node_menu
;
iface
->
offline_message
=
fb_client_offline_message
;
}
static
void
facebook_protocol_server_init
(
PurpleProtocolServerInterface
*
iface
)
{
iface
->
set_status
=
fb_server_set_status
;
}
static
void
facebook_protocol_im_iface_init
(
PurpleProtocolIMInterface
*
iface
)
{
iface
->
send
=
fb_im_send
;
iface
->
send_typing
=
fb_im_send_typing
;
}
static
void
facebook_protocol_chat_iface_init
(
PurpleProtocolChatInterface
*
iface
)
{
iface
->
info
=
fb_chat_info
;
iface
->
info_defaults
=
fb_chat_info_defaults
;
iface
->
join
=
fb_chat_join
;
iface
->
get_name
=
fb_chat_get_name
;
iface
->
invite
=
fb_chat_invite
;
iface
->
send
=
fb_chat_send
;
iface
->
set_topic
=
fb_chat_set_topic
;
}
static
void
facebook_protocol_roomlist_iface_init
(
PurpleProtocolRoomlistInterface
*
iface
)
{
iface
->
get_list
=
fb_roomlist_get_list
;
iface
->
cancel
=
fb_roomlist_cancel
;
}
G_DEFINE_DYNAMIC_TYPE_EXTENDED
(
FacebookProtocol
,
facebook_protocol
,
PURPLE_TYPE_PROTOCOL
,
0
,
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CLIENT
,
facebook_protocol_client_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_SERVER
,
facebook_protocol_server_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_IM
,
facebook_protocol_im_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CHAT
,
facebook_protocol_chat_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_ROOMLIST
,
facebook_protocol_roomlist_iface_init
));
static
void
fb_cmds_register
(
void
)
{
PurpleCmdId
id
;
static
PurpleCmdFlag
cflags
=
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PROTOCOL_ONLY
;
g_return_if_fail
(
fb_cmds
==
NULL
);
id
=
purple_cmd_register
(
"kick"
,
"s"
,
PURPLE_CMD_P_PROTOCOL
,
cflags
,
FB_PROTOCOL_ID
,
fb_cmd_kick
,
_
(
"kick: Kick someone from the chat"
),
NULL
);
fb_cmds
=
g_slist_prepend
(
fb_cmds
,
GUINT_TO_POINTER
(
id
));
id
=
purple_cmd_register
(
"leave"
,
""
,
PURPLE_CMD_P_PROTOCOL
,
cflags
,
FB_PROTOCOL_ID
,
fb_cmd_leave
,
_
(
"leave: Leave the chat"
),
NULL
);
fb_cmds
=
g_slist_prepend
(
fb_cmds
,
GUINT_TO_POINTER
(
id
));
}
static
void
fb_cmds_unregister_free
(
gpointer
data
)
{
PurpleCmdId
id
=
GPOINTER_TO_UINT
(
data
);
purple_cmd_unregister
(
id
);
}
static
void
fb_cmds_unregister
(
void
)
{
g_slist_free_full
(
fb_cmds
,
fb_cmds_unregister_free
);
}
static
GPluginPluginInfo
*
facebook_query
(
GError
**
error
)
{
return
purple_plugin_info_new
(
"id"
,
FB_PROTOCOL_ID
,
"name"
,
"Facebook Protocol"
,
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Protocol"
),
"summary"
,
N_
(
"Facebook Protocol Plugin"
),
"description"
,
N_
(
"Facebook Protocol Plugin"
),
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"flags"
,
PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
NULL
);
}
static
gboolean
facebook_load
(
GPluginPlugin
*
plugin
,
GError
**
error
)
{
PurpleProtocolManager
*
manager
=
purple_protocol_manager_get_default
();
facebook_protocol_register_type
(
G_TYPE_MODULE
(
plugin
));
fb_protocol
=
g_object_new
(
FACEBOOK_TYPE_PROTOCOL
,
"id"
,
FB_PROTOCOL_ID
,
"name"
,
"Facebook"
,
"description"
,
"Facebook is a chat protocol, developed by Facebook"
,
"icon-name"
,
"im-facebook"
,
"icon-resource-path"
,
"/im/pidgin/libpurple/facebook/icons"
,
"options"
,
OPT_PROTO_CHAT_TOPIC
,
NULL
);
if
(
!
purple_protocol_manager_register
(
manager
,
fb_protocol
,
error
))
{
g_clear_object
(
&
fb_protocol
);
return
FALSE
;
}
fb_cmds_register
();
return
TRUE
;
}
static
gboolean
facebook_unload
(
GPluginPlugin
*
plugin
,
gboolean
shutdown
,
GError
**
error
)
{
PurpleProtocolManager
*
manager
=
purple_protocol_manager_get_default
();
if
(
!
purple_protocol_manager_unregister
(
manager
,
fb_protocol
,
error
))
{
return
FALSE
;
}
fb_cmds_unregister
();
g_clear_object
(
&
fb_protocol
);
return
TRUE
;
}
GPLUGIN_NATIVE_PLUGIN_DECLARE
(
facebook
)