pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Clean up a some formatting
2019-11-15, Gary Kramlich
ee5349aa57ac
Clean up a some formatting
/* 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
"internal.h"
#include
"account.h"
#include
"action.h"
#include
"blistnode.h"
#include
"buddy.h"
#include
"buddyicon.h"
#include
"buddylist.h"
#include
"cmds.h"
#include
"connection.h"
#include
"conversation.h"
#include
"conversations.h"
#include
"conversationtypes.h"
#include
"image.h"
#include
"image-store.h"
#include
"message.h"
#include
"notify.h"
#include
"plugins.h"
#include
"presence.h"
#include
"protocol.h"
#include
"protocols.h"
#include
"purpleaccountoption.h"
#include
"request.h"
#include
"roomlist.h"
#include
"server.h"
#include
"signals.h"
#include
"sslconn.h"
#include
"status.h"
#include
"util.h"
#include
"version.h"
#include
"api.h"
#include
"data.h"
#include
"facebook.h"
#include
"http.h"
#include
"util.h"
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
*
1000
;
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
;
PurpleChatConversation
*
chat
;
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
);
for
(
l
=
events
;
l
!=
NULL
;
l
=
l
->
next
)
{
event
=
l
->
data
;
FB_ID_TO_STR
(
event
->
tid
,
tid
);
chat
=
purple_conversations_find_chat_with_account
(
tid
,
acct
);
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
(
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
(
chat
,
uid
,
NULL
,
0
,
TRUE
);
break
;
case
FB_API_EVENT_TYPE_THREAD_USER_REMOVED
:
purple_chat_conversation_remove_user
(
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
;
PurpleChatConversation
*
chat
;
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
);
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_conversations_find_chat_with_account
(
tid
,
acct
);
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
(
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
*
press
,
gpointer
data
)
{
const
gchar
*
statid
;
FbApiPresence
*
pres
;
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
=
press
;
l
!=
NULL
;
l
=
l
->
next
)
{
pres
=
l
->
data
;
if
(
pres
->
active
)
{
pstat
=
PURPLE_STATUS_AVAILABLE
;
}
else
{
pstat
=
PURPLE_STATUS_OFFLINE
;
}
FB_ID_TO_STR
(
pres
->
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
;
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
);
chat
=
purple_conversations_find_chat_with_account
(
tid
,
acct
);
if
((
chat
==
NULL
)
||
purple_chat_conversation_has_left
(
chat
))
{
chat
=
purple_serv_got_joined_chat
(
gc
,
id
,
tid
);
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.
*/
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
;
PurpleChatConversation
*
chat
;
FB_ID_TO_STR
(
thrd
->
tid
,
tid
);
gc
=
fb_data_get_connection
(
fata
);
acct
=
purple_connection_get_account
(
gc
);
chat
=
purple_conversations_find_chat_with_account
(
tid
,
acct
);
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
(
PURPLE_CONVERSATION
(
chat
),
_
(
"You have been removed from this chat"
),
0
);
purple_serv_got_chat_left
(
gc
,
purple_chat_conversation_get_id
(
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
,
1
,
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_memdup
(
&
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
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_g_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
(
PurpleBuddy
*
buddy
,
PurpleNotifyUserInfo
*
info
,
gboolean
full
)
{
const
gchar
*
name
;
PurplePresence
*
pres
;
PurpleStatus
*
status
;
pres
=
purple_buddy_get_presence
(
buddy
);
status
=
purple_presence_get_active_status
(
pres
);
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
(
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
(
const
PurpleBuddy
*
buddy
)
{
return
TRUE
;
}
static
void
fb_server_set_status
(
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
(
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
(
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
()
{
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
(
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
(
PurpleConnection
*
gc
,
GHashTable
*
data
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
gint
id
;
PurpleChatConversation
*
chat
;
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
);
chat
=
purple_conversations_find_chat
(
gc
,
id
);
if
((
chat
!=
NULL
)
&&
!
purple_chat_conversation_has_left
(
chat
))
{
purple_conversation_present
(
PURPLE_CONVERSATION
(
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
(
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
(
PurpleConnection
*
gc
,
gint
id
,
const
gchar
*
msg
,
const
gchar
*
who
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
FbId
uid
;
PurpleChatConversation
*
chat
;
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
);
chat
=
purple_conversations_find_chat
(
gc
,
id
);
name
=
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
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
(
PurpleConnection
*
gc
,
gint
id
,
PurpleMessage
*
msg
)
{
const
gchar
*
name
;
const
gchar
*
text
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
gchar
*
sext
;
PurpleAccount
*
acct
;
PurpleChatConversation
*
chat
;
acct
=
purple_connection_get_account
(
gc
);
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
chat
=
purple_conversations_find_chat
(
gc
,
id
);
name
=
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
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
(
PurpleConnection
*
gc
,
gint
id
,
const
gchar
*
topic
)
{
const
gchar
*
name
;
FbApi
*
api
;
FbData
*
fata
;
FbId
tid
;
PurpleChatConversation
*
chat
;
fata
=
purple_connection_get_protocol_data
(
gc
);
api
=
fb_data_get_api
(
fata
);
chat
=
purple_conversations_find_chat
(
gc
,
id
);
name
=
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
chat
));
tid
=
FB_ID_FROM_STR
(
name
);
fb_api_thread_topic
(
api
,
tid
,
topic
);
}
static
PurpleRoomlist
*
fb_roomlist_get_list
(
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
(
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
)
{
PurpleProtocol
*
protocol
=
PURPLE_PROTOCOL
(
self
);
GList
*
opts
=
NULL
;
PurpleAccountOption
*
opt
;
protocol
->
id
=
FB_PROTOCOL_ID
;
protocol
->
name
=
"Facebook"
;
protocol
->
options
=
OPT_PROTO_CHAT_TOPIC
;
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
);
protocol
->
account_options
=
g_list_reverse
(
opts
);
}
static
void
facebook_protocol_class_init
(
FacebookProtocolClass
*
klass
)
{
PurpleProtocolClass
*
protocol_class
=
PURPLE_PROTOCOL_CLASS
(
klass
);
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_iface_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_iface_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
PurplePluginInfo
*
plugin_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
plugin_load
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
facebook_protocol_register_type
(
G_TYPE_MODULE
(
plugin
));
fb_protocol
=
purple_protocols_add
(
FACEBOOK_TYPE_PROTOCOL
,
error
);
if
(
fb_protocol
==
NULL
)
{
return
FALSE
;
}
fb_cmds_register
();
return
TRUE
;
}
static
gboolean
plugin_unload
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
fb_cmds_unregister
();
return
purple_protocols_remove
(
fb_protocol
,
error
);
}
PURPLE_PLUGIN_INIT
(
facebook
,
plugin_query
,
plugin_load
,
plugin_unload
);