pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Remove the deprecated keyring API.
2021-04-21, Gary Kramlich
32c1f097d4e8
Remove the deprecated keyring API.
I've disable the building of the internal keyring for now but left it so it
can be referenced when it is ported to the CredentialProvider API.
Testing Done:
Ran Pidgin and verified the preferences window worked.
Bugs closed: PIDGIN-17486
Reviewed at https://reviews.imfreedom.org/r/624/
/**
* 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.
*
* Nullprpl is a mock protocol plugin for Pidgin and libpurple. You can create
* accounts with it, sign on and off, add buddies, and send and receive IMs,
* all without connecting to a server!
*
* Beyond that basic functionality, nullprpl supports presence and
* away/available messages, offline messages, user info, typing notification,
* privacy allow/block lists, chat rooms, room lists, and protocol
* icons and emblems. Notable missing features are file transfer and account
* registration and authentication.
*
* Nullprpl is intended as an example of how to write a libpurple protocol
* plugin. It doesn't contain networking code or an event loop, but it does
* demonstrate how to use the libpurple API to do pretty much everything a
* protocol might need to do.
*
* Nullprpl is also a useful tool for hacking on Pidgin, Finch, and other
* libpurple clients. It's a full-featured protocol plugin, but doesn't depend
* on an external server, so it's a quick and easy way to exercise test new
* code. It also allows you to work while you're disconnected.
*
* 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
<stdarg.h>
#include
<string.h>
#include
<time.h>
#include
<glib.h>
#include
<glib/gi18n-lib.h>
#include
<purple.h>
#include
"nullprpl.h"
/*
* reference to the protocol instance, used for registering signals, prefs,
* etc. it is set when the protocol is added in plugin_load and is required
* for removing the protocol in plugin_unload.
*/
static
PurpleProtocol
*
my_protocol
=
NULL
;
#define NULL_STATUS_ONLINE "online"
#define NULL_STATUS_AWAY "away"
#define NULL_STATUS_OFFLINE "offline"
typedef
void
(
*
GcFunc
)(
PurpleConnection
*
from
,
PurpleConnection
*
to
,
gpointer
userdata
);
typedef
struct
{
GcFunc
fn
;
PurpleConnection
*
from
;
gpointer
userdata
;
}
GcFuncData
;
/*
* stores offline messages that haven't been delivered yet. maps username
* (char *) to GList * of GOfflineMessages. initialized in plugin_load.
*/
GHashTable
*
goffline_messages
=
NULL
;
typedef
struct
{
char
*
from
;
char
*
message
;
time_t
mtime
;
PurpleMessageFlags
flags
;
}
GOfflineMessage
;
/*
* helpers
*/
static
PurpleConnection
*
get_null_gc
(
const
char
*
username
)
{
PurpleAccount
*
acct
=
purple_accounts_find
(
username
,
"null"
);
if
(
acct
&&
purple_account_is_connected
(
acct
))
return
purple_account_get_connection
(
acct
);
else
return
NULL
;
}
static
void
call_if_nullprotocol
(
gpointer
data
,
gpointer
userdata
)
{
PurpleConnection
*
gc
=
(
PurpleConnection
*
)(
data
);
GcFuncData
*
gcfdata
=
(
GcFuncData
*
)
userdata
;
if
(
purple_strequal
(
purple_account_get_protocol_id
(
purple_connection_get_account
(
gc
)),
"null"
))
gcfdata
->
fn
(
gcfdata
->
from
,
gc
,
gcfdata
->
userdata
);
}
static
void
foreach_null_gc
(
GcFunc
fn
,
PurpleConnection
*
from
,
gpointer
userdata
)
{
GcFuncData
gcfdata
=
{
fn
,
from
,
userdata
};
g_list_foreach
(
purple_connections_get_all
(),
call_if_nullprotocol
,
&
gcfdata
);
}
typedef
void
(
*
ChatFunc
)(
PurpleChatConversation
*
from
,
PurpleChatConversation
*
to
,
int
id
,
const
char
*
room
,
gpointer
userdata
);
typedef
struct
{
ChatFunc
fn
;
PurpleChatConversation
*
from_chat
;
gpointer
userdata
;
}
ChatFuncData
;
static
void
call_chat_func
(
gpointer
data
,
gpointer
userdata
)
{
PurpleConnection
*
to
=
(
PurpleConnection
*
)
data
;
ChatFuncData
*
cfdata
=
(
ChatFuncData
*
)
userdata
;
int
id
=
purple_chat_conversation_get_id
(
cfdata
->
from_chat
);
PurpleChatConversation
*
chat
=
purple_conversations_find_chat
(
to
,
id
);
if
(
chat
)
cfdata
->
fn
(
cfdata
->
from_chat
,
chat
,
id
,
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
chat
)),
cfdata
->
userdata
);
}
static
void
foreach_gc_in_chat
(
ChatFunc
fn
,
PurpleConnection
*
from
,
int
id
,
gpointer
userdata
)
{
PurpleChatConversation
*
chat
=
purple_conversations_find_chat
(
from
,
id
);
ChatFuncData
cfdata
=
{
fn
,
chat
,
userdata
};
g_list_foreach
(
purple_connections_get_all
(),
call_chat_func
,
&
cfdata
);
}
static
void
discover_status
(
PurpleConnection
*
from
,
PurpleConnection
*
to
,
gpointer
userdata
)
{
const
char
*
from_username
=
purple_account_get_username
(
purple_connection_get_account
(
from
));
const
char
*
to_username
=
purple_account_get_username
(
purple_connection_get_account
(
to
));
if
(
purple_blist_find_buddy
(
purple_connection_get_account
(
from
),
to_username
))
{
PurpleStatus
*
status
=
purple_account_get_active_status
(
purple_connection_get_account
(
to
));
const
char
*
status_id
=
purple_status_get_id
(
status
);
const
char
*
message
=
purple_status_get_attr_string
(
status
,
"message"
);
if
(
purple_strequal
(
status_id
,
NULL_STATUS_ONLINE
)
||
purple_strequal
(
status_id
,
NULL_STATUS_AWAY
)
||
purple_strequal
(
status_id
,
NULL_STATUS_OFFLINE
))
{
purple_debug_info
(
"nullprpl"
,
"%s sees that %s is %s: %s
\n
"
,
from_username
,
to_username
,
status_id
,
message
);
purple_protocol_got_user_status
(
purple_connection_get_account
(
from
),
to_username
,
status_id
,
(
message
)
?
"message"
:
NULL
,
message
,
NULL
);
}
else
{
purple_debug_error
(
"nullprpl"
,
"%s's buddy %s has an unknown status: %s, %s"
,
from_username
,
to_username
,
status_id
,
message
);
}
}
}
static
void
report_status_change
(
PurpleConnection
*
from
,
PurpleConnection
*
to
,
gpointer
userdata
)
{
purple_debug_info
(
"nullprpl"
,
"notifying %s that %s changed status
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
to
)),
purple_account_get_username
(
purple_connection_get_account
(
from
)));
discover_status
(
to
,
from
,
NULL
);
}
/*
* UI callbacks
*/
static
void
null_input_user_info
(
PurpleProtocolAction
*
action
)
{
PurpleConnection
*
gc
=
action
->
connection
;
PurpleAccount
*
acct
=
purple_connection_get_account
(
gc
);
purple_debug_info
(
"nullprpl"
,
"showing 'Set User Info' dialog for %s
\n
"
,
purple_account_get_username
(
acct
));
purple_account_request_change_user_info
(
acct
);
}
/*
* Protocol functions
*/
static
GList
*
null_get_actions
(
PurpleProtocolClient
*
client
,
PurpleConnection
*
gc
)
{
PurpleProtocolAction
*
action
=
purple_protocol_action_new
(
_
(
"Set User Info..."
),
null_input_user_info
);
return
g_list_append
(
NULL
,
action
);
}
static
const
char
*
null_list_icon
(
PurpleAccount
*
acct
,
PurpleBuddy
*
buddy
)
{
return
"null"
;
}
static
GList
*
null_protocol_get_account_options
(
PurpleProtocol
*
protocol
)
{
PurpleAccountOption
*
option
;
option
=
purple_account_option_string_new
(
_
(
"Example option"
),
/* text shown to user */
"example"
,
/* pref name */
"default"
);
/* default value */
return
g_list_append
(
NULL
,
option
);
}
static
PurpleBuddyIconSpec
*
null_protocol_get_buddy_icon_spec
(
PurpleProtocol
*
protocol
)
{
return
purple_buddy_icon_spec_new
(
"png,jpg,gif"
,
/* format */
0
,
/* min_width */
0
,
/* min_height */
128
,
/* max_width */
128
,
/* max_height */
10000
,
/* max_filesize */
PURPLE_ICON_SCALE_DISPLAY
/* scale_rules */
);
}
static
GList
*
null_protocol_get_user_splits
(
PurpleProtocol
*
protocol
)
{
PurpleAccountUserSplit
*
split
;
split
=
purple_account_user_split_new
(
_
(
"Example user split"
),
/* text shown to user */
"default"
,
/* default value */
'@'
);
/* field separator */
return
g_list_append
(
NULL
,
split
);
}
static
char
*
null_status_text
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
)
{
purple_debug_info
(
"nullprpl"
,
"getting %s's status text for %s
\n
"
,
purple_buddy_get_name
(
buddy
),
purple_account_get_username
(
purple_buddy_get_account
(
buddy
)));
if
(
purple_blist_find_buddy
(
purple_buddy_get_account
(
buddy
),
purple_buddy_get_name
(
buddy
)))
{
PurplePresence
*
presence
=
purple_buddy_get_presence
(
buddy
);
PurpleStatus
*
status
=
purple_presence_get_active_status
(
presence
);
const
char
*
name
=
purple_status_get_name
(
status
);
const
char
*
message
=
purple_status_get_attr_string
(
status
,
"message"
);
char
*
text
;
if
(
message
&&
*
message
)
text
=
g_strdup_printf
(
"%s: %s"
,
name
,
message
);
else
text
=
g_strdup
(
name
);
purple_debug_info
(
"nullprpl"
,
"%s's status text is %s
\n
"
,
purple_buddy_get_name
(
buddy
),
text
);
return
text
;
}
else
{
purple_debug_info
(
"nullprpl"
,
"...but %s is not logged in
\n
"
,
purple_buddy_get_name
(
buddy
));
return
g_strdup
(
"Not logged in"
);
}
}
static
void
null_tooltip_text
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
,
PurpleNotifyUserInfo
*
info
,
gboolean
full
)
{
PurpleConnection
*
gc
=
get_null_gc
(
purple_buddy_get_name
(
buddy
));
if
(
gc
)
{
/* they're logged in */
PurplePresence
*
presence
=
purple_buddy_get_presence
(
buddy
);
PurpleStatus
*
status
=
purple_presence_get_active_status
(
presence
);
char
*
msg
=
null_status_text
(
client
,
buddy
);
/* TODO: Check whether it's correct to call add_pair_html,
or if we should be using add_pair_plaintext */
purple_notify_user_info_add_pair_html
(
info
,
purple_status_get_name
(
status
),
msg
);
g_free
(
msg
);
if
(
full
)
{
const
char
*
user_info
=
purple_account_get_user_info
(
purple_connection_get_account
(
gc
));
if
(
user_info
)
/* TODO: Check whether it's correct to call add_pair_html,
or if we should be using add_pair_plaintext */
purple_notify_user_info_add_pair_html
(
info
,
_
(
"User info"
),
user_info
);
}
}
else
{
/* they're not logged in */
purple_notify_user_info_add_pair_plaintext
(
info
,
_
(
"User info"
),
_
(
"not logged in"
));
}
purple_debug_info
(
"nullprpl"
,
"showing %s tooltip for %s
\n
"
,
(
full
)
?
"full"
:
"short"
,
purple_buddy_get_name
(
buddy
));
}
static
GList
*
null_status_types
(
PurpleAccount
*
acct
)
{
GList
*
types
=
NULL
;
PurpleStatusType
*
type
;
purple_debug_info
(
"nullprpl"
,
"returning status types for %s: %s, %s, %s
\n
"
,
purple_account_get_username
(
acct
),
NULL_STATUS_ONLINE
,
NULL_STATUS_AWAY
,
NULL_STATUS_OFFLINE
);
type
=
purple_status_type_new_with_attrs
(
PURPLE_STATUS_AVAILABLE
,
NULL_STATUS_ONLINE
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
);
types
=
g_list_prepend
(
types
,
type
);
type
=
purple_status_type_new_with_attrs
(
PURPLE_STATUS_AWAY
,
NULL_STATUS_AWAY
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
);
types
=
g_list_prepend
(
types
,
type
);
type
=
purple_status_type_new_with_attrs
(
PURPLE_STATUS_OFFLINE
,
NULL_STATUS_OFFLINE
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
);
types
=
g_list_prepend
(
types
,
type
);
return
g_list_reverse
(
types
);
}
static
void
blist_example_menu_item
(
PurpleBlistNode
*
node
,
gpointer
userdata
)
{
purple_debug_info
(
"nullprpl"
,
"example menu item clicked on user %s
\n
"
,
purple_buddy_get_name
(
PURPLE_BUDDY
(
node
)));
purple_notify_info
(
NULL
,
/* plugin handle or PurpleConnection */
_
(
"Primary title"
),
_
(
"Secondary title"
),
_
(
"This is the callback for the NullProtocol menu item."
),
NULL
);
}
static
GList
*
null_blist_node_menu
(
PurpleProtocolClient
*
client
,
PurpleBlistNode
*
node
)
{
purple_debug_info
(
"nullprpl"
,
"providing buddy list context menu item
\n
"
);
if
(
PURPLE_IS_BUDDY
(
node
))
{
PurpleActionMenu
*
action
=
purple_action_menu_new
(
_
(
"NullProtocol example menu item"
),
PURPLE_CALLBACK
(
blist_example_menu_item
),
NULL
,
/* userdata passed to the callback */
NULL
);
/* child menu items */
return
g_list_append
(
NULL
,
action
);
}
else
{
return
NULL
;
}
}
static
GList
*
null_chat_info
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
)
{
PurpleProtocolChatEntry
*
pce
;
/* defined in protocols.h */
purple_debug_info
(
"nullprpl"
,
"returning chat setting 'room'
\n
"
);
pce
=
g_new0
(
PurpleProtocolChatEntry
,
1
);
pce
->
label
=
_
(
"Chat room"
);
pce
->
identifier
=
"room"
;
pce
->
required
=
TRUE
;
return
g_list_append
(
NULL
,
pce
);
}
static
GHashTable
*
null_chat_info_defaults
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
const
gchar
*
room
)
{
GHashTable
*
defaults
;
purple_debug_info
(
"nullprpl"
,
"returning chat default setting "
"'room' = 'default'
\n
"
);
defaults
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
NULL
,
g_free
);
g_hash_table_insert
(
defaults
,
"room"
,
g_strdup
(
"default"
));
return
defaults
;
}
static
void
null_login
(
PurpleAccount
*
acct
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
acct
);
GList
*
offline_messages
;
GList
*
all_offline_messages
;
purple_debug_info
(
"nullprpl"
,
"logging in %s
\n
"
,
purple_account_get_username
(
acct
));
purple_connection_set_flags
(
gc
,
PURPLE_CONNECTION_FLAG_NO_IMAGES
);
purple_connection_update_progress
(
gc
,
_
(
"Connecting"
),
0
,
/* which connection step this is */
2
);
/* total number of steps */
purple_connection_update_progress
(
gc
,
_
(
"Connected"
),
1
,
/* which connection step this is */
2
);
/* total number of steps */
purple_connection_set_state
(
gc
,
PURPLE_CONNECTION_CONNECTED
);
/* tell purple about everyone on our buddy list who's connected */
foreach_null_gc
(
discover_status
,
gc
,
NULL
);
/* notify other nullprotocol accounts */
foreach_null_gc
(
report_status_change
,
gc
,
NULL
);
/* fetch stored offline messages */
purple_debug_info
(
"nullprpl"
,
"checking for offline messages for %s
\n
"
,
purple_account_get_username
(
acct
));
all_offline_messages
=
offline_messages
=
g_hash_table_lookup
(
goffline_messages
,
purple_account_get_username
(
acct
));
while
(
offline_messages
)
{
GOfflineMessage
*
message
=
(
GOfflineMessage
*
)
offline_messages
->
data
;
purple_debug_info
(
"nullprpl"
,
"delivering offline message to %s: %s
\n
"
,
purple_account_get_username
(
acct
),
message
->
message
);
purple_serv_got_im
(
gc
,
message
->
from
,
message
->
message
,
message
->
flags
,
message
->
mtime
);
offline_messages
=
g_list_next
(
offline_messages
);
g_free
(
message
->
from
);
g_free
(
message
->
message
);
g_free
(
message
);
}
g_hash_table_remove
(
goffline_messages
,
purple_account_get_username
(
acct
));
g_list_free
(
all_offline_messages
);
}
static
void
null_close
(
PurpleConnection
*
gc
)
{
/* notify other nullprotocol accounts */
foreach_null_gc
(
report_status_change
,
gc
,
NULL
);
}
static
int
null_send_im
(
PurpleProtocolIM
*
im
,
PurpleConnection
*
gc
,
PurpleMessage
*
msg
)
{
const
char
*
from_username
=
purple_account_get_username
(
purple_connection_get_account
(
gc
));
const
gchar
*
who
=
purple_message_get_recipient
(
msg
);
PurpleMessageFlags
receive_flags
;
PurpleAccount
*
to_acct
=
purple_accounts_find
(
who
,
"null"
);
PurpleConnection
*
to
;
const
gchar
*
message
=
purple_message_get_contents
(
msg
);
receive_flags
=
((
purple_message_get_flags
(
msg
)
&
~
PURPLE_MESSAGE_SEND
)
|
PURPLE_MESSAGE_RECV
);
purple_debug_info
(
"nullprpl"
,
"sending message from %s to %s: %s
\n
"
,
from_username
,
who
,
message
);
/* is the sender blocked by the recipient's privacy settings? */
if
(
to_acct
&&
!
purple_account_privacy_check
(
to_acct
,
purple_account_get_username
(
purple_connection_get_account
(
gc
))))
{
char
*
msg
=
g_strdup_printf
(
_
(
"Your message was blocked by %s's privacy settings."
),
who
);
purple_debug_info
(
"nullprpl"
,
"discarding; %s is blocked by %s's privacy settings
\n
"
,
from_username
,
who
);
purple_conversation_present_error
(
who
,
purple_connection_get_account
(
gc
),
msg
);
g_free
(
msg
);
return
0
;
}
/* is the recipient online? */
to
=
get_null_gc
(
who
);
if
(
to
)
{
/* yes, send */
purple_serv_got_im
(
to
,
from_username
,
message
,
receive_flags
,
time
(
NULL
));
}
else
{
/* nope, store as an offline message */
GOfflineMessage
*
offline_message
;
GList
*
messages
;
purple_debug_info
(
"nullprpl"
,
"%s is offline, sending as offline message
\n
"
,
who
);
offline_message
=
g_new0
(
GOfflineMessage
,
1
);
offline_message
->
from
=
g_strdup
(
from_username
);
offline_message
->
message
=
g_strdup
(
message
);
offline_message
->
mtime
=
time
(
NULL
);
offline_message
->
flags
=
receive_flags
;
messages
=
g_hash_table_lookup
(
goffline_messages
,
who
);
messages
=
g_list_append
(
messages
,
offline_message
);
g_hash_table_insert
(
goffline_messages
,
g_strdup
(
who
),
messages
);
}
return
1
;
}
static
void
null_set_info
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
const
gchar
*
info
)
{
purple_debug_info
(
"nullprpl"
,
"setting %s's user info to %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
info
);
}
static
const
char
*
typing_state_to_string
(
PurpleIMTypingState
typing
)
{
switch
(
typing
)
{
case
PURPLE_IM_NOT_TYPING
:
return
"is not typing"
;
case
PURPLE_IM_TYPING
:
return
"is typing"
;
case
PURPLE_IM_TYPED
:
return
"stopped typing momentarily"
;
default
:
return
"unknown typing state"
;
}
}
static
void
notify_typing
(
PurpleConnection
*
from
,
PurpleConnection
*
to
,
gpointer
typing
)
{
const
char
*
from_username
=
purple_account_get_username
(
purple_connection_get_account
(
from
));
const
char
*
action
=
typing_state_to_string
((
PurpleIMTypingState
)
typing
);
purple_debug_info
(
"nullprpl"
,
"notifying %s that %s %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
to
)),
from_username
,
action
);
purple_serv_got_typing
(
to
,
from_username
,
0
,
/* if non-zero, a timeout in seconds after which to
* reset the typing status to PURPLE_IM_NOT_TYPING */
(
PurpleIMTypingState
)
typing
);
}
static
unsigned
int
null_send_typing
(
PurpleProtocolIM
*
im
,
PurpleConnection
*
gc
,
const
char
*
name
,
PurpleIMTypingState
typing
)
{
purple_debug_info
(
"nullprpl"
,
"%s %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
typing_state_to_string
(
typing
));
foreach_null_gc
(
notify_typing
,
gc
,
(
gpointer
)
typing
);
return
0
;
}
static
void
null_get_info
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
const
gchar
*
username
)
{
const
char
*
body
;
PurpleNotifyUserInfo
*
info
=
purple_notify_user_info_new
();
PurpleAccount
*
acct
;
purple_debug_info
(
"nullprpl"
,
"Fetching %s's user info for %s
\n
"
,
username
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)));
acct
=
purple_accounts_find
(
username
,
"null"
);
if
(
!
get_null_gc
(
username
))
{
char
*
msg
=
g_strdup_printf
(
_
(
"%s is not logged in."
),
username
);
purple_notify_error
(
gc
,
_
(
"User Info"
),
_
(
"User info not available. "
),
msg
,
purple_request_cpar_from_account
(
acct
));
g_free
(
msg
);
}
if
(
acct
)
body
=
purple_account_get_user_info
(
acct
);
else
body
=
_
(
"No user info."
);
/* TODO: Check whether it's correct to call add_pair_html,
or if we should be using add_pair_plaintext */
purple_notify_user_info_add_pair_html
(
info
,
"Info"
,
body
);
/* show a buddy's user info in a nice dialog box */
purple_notify_userinfo
(
gc
,
/* connection the buddy info came through */
username
,
/* buddy's username */
info
,
/* body */
NULL
,
/* callback called when dialog closed */
NULL
);
/* userdata for callback */
}
static
void
null_set_status
(
PurpleProtocolServer
*
protocol_server
,
PurpleAccount
*
acct
,
PurpleStatus
*
status
)
{
const
char
*
msg
=
purple_status_get_attr_string
(
status
,
"message"
);
purple_debug_info
(
"nullprpl"
,
"setting %s's status to %s: %s
\n
"
,
purple_account_get_username
(
acct
),
purple_status_get_name
(
status
),
msg
);
foreach_null_gc
(
report_status_change
,
get_null_gc
(
purple_account_get_username
(
acct
)),
NULL
);
}
static
void
null_set_idle
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
gint
idletime
)
{
purple_debug_info
(
"nullprpl"
,
"purple reports that %s has been idle for %d seconds
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
idletime
);
}
static
void
null_change_passwd
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
const
gchar
*
old_pass
,
const
gchar
*
new_pass
)
{
purple_debug_info
(
"nullprpl"
,
"%s wants to change their password
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)));
}
static
void
null_add_buddy
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
,
const
gchar
*
message
)
{
const
char
*
username
=
purple_account_get_username
(
purple_connection_get_account
(
gc
));
PurpleConnection
*
buddy_gc
=
get_null_gc
(
purple_buddy_get_name
(
buddy
));
purple_debug_info
(
"nullprpl"
,
"adding %s to %s's buddy list
\n
"
,
purple_buddy_get_name
(
buddy
),
username
);
if
(
buddy_gc
)
{
PurpleAccount
*
buddy_acct
=
purple_connection_get_account
(
buddy_gc
);
discover_status
(
gc
,
buddy_gc
,
NULL
);
if
(
purple_blist_find_buddy
(
buddy_acct
,
username
))
{
purple_debug_info
(
"nullprpl"
,
"%s is already on %s's buddy list
\n
"
,
username
,
purple_buddy_get_name
(
buddy
));
}
else
{
purple_debug_info
(
"nullprpl"
,
"asking %s if they want to add %s
\n
"
,
purple_buddy_get_name
(
buddy
),
username
);
purple_account_request_add
(
buddy_acct
,
username
,
NULL
,
/* local account id (rarely used) */
NULL
,
/* alias */
message
);
/* message */
}
}
}
static
void
null_add_buddies
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
GList
*
buddies
,
GList
*
groups
,
const
gchar
*
message
)
{
GList
*
buddy
=
buddies
;
GList
*
group
=
groups
;
purple_debug_info
(
"nullprpl"
,
"adding multiple buddies
\n
"
);
while
(
buddy
&&
group
)
{
null_add_buddy
(
protocol_server
,
gc
,
PURPLE_BUDDY
(
buddy
->
data
),
PURPLE_GROUP
(
group
->
data
),
message
);
buddy
=
g_list_next
(
buddy
);
group
=
g_list_next
(
group
);
}
}
static
void
null_remove_buddy
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
)
{
purple_debug_info
(
"nullprpl"
,
"removing %s from %s's buddy list
\n
"
,
purple_buddy_get_name
(
buddy
),
purple_account_get_username
(
purple_connection_get_account
(
gc
)));
}
static
void
null_remove_buddies
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
GList
*
buddies
,
GList
*
groups
)
{
GList
*
buddy
=
buddies
;
GList
*
group
=
groups
;
purple_debug_info
(
"nullprpl"
,
"removing multiple buddies
\n
"
);
while
(
buddy
&&
group
)
{
null_remove_buddy
(
protocol_server
,
gc
,
PURPLE_BUDDY
(
buddy
->
data
),
PURPLE_GROUP
(
group
->
data
));
buddy
=
g_list_next
(
buddy
);
group
=
g_list_next
(
group
);
}
}
/*
* nullprotocol uses purple's local whitelist and blacklist, stored in blist.xml, as
* its authoritative privacy settings, and uses purple's logic (specifically
* purple_privacy_check(), from privacy.h), to determine whether messages are
* allowed or blocked.
*/
static
void
null_add_permit
(
PurpleProtocolPrivacy
*
privacy
,
PurpleConnection
*
gc
,
const
char
*
name
)
{
purple_debug_info
(
"nullprpl"
,
"%s adds %s to their allowed list
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
name
);
}
static
void
null_add_deny
(
PurpleProtocolPrivacy
*
privacy
,
PurpleConnection
*
gc
,
const
char
*
name
)
{
purple_debug_info
(
"nullprpl"
,
"%s adds %s to their blocked list
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
name
);
}
static
void
null_remove_permit
(
PurpleProtocolPrivacy
*
privacy
,
PurpleConnection
*
gc
,
const
char
*
name
)
{
purple_debug_info
(
"nullprpl"
,
"%s removes %s from their allowed list
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
name
);
}
static
void
null_remove_deny
(
PurpleProtocolPrivacy
*
privacy
,
PurpleConnection
*
gc
,
const
char
*
name
)
{
purple_debug_info
(
"nullprpl"
,
"%s removes %s from their blocked list
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
name
);
}
static
void
null_set_permit_deny
(
PurpleProtocolPrivacy
*
privacy
,
PurpleConnection
*
gc
)
{
/* this is for synchronizing the local black/whitelist with the server.
* for nullprotocol, it's a noop.
*/
}
static
void
joined_chat
(
PurpleChatConversation
*
from
,
PurpleChatConversation
*
to
,
int
id
,
const
char
*
room
,
gpointer
userdata
)
{
/* tell their chat window that we joined */
purple_debug_info
(
"nullprpl"
,
"%s sees that %s joined chat room %s
\n
"
,
purple_chat_conversation_get_nick
(
to
),
purple_chat_conversation_get_nick
(
from
),
room
);
purple_chat_conversation_add_user
(
to
,
purple_chat_conversation_get_nick
(
from
),
NULL
,
/* user-provided join message, IRC style */
PURPLE_CHAT_USER_NONE
,
TRUE
);
/* show a join message */
if
(
from
!=
to
)
{
/* add them to our chat window */
purple_debug_info
(
"nullprpl"
,
"%s sees that %s is in chat room %s
\n
"
,
purple_chat_conversation_get_nick
(
from
),
purple_chat_conversation_get_nick
(
to
),
room
);
purple_chat_conversation_add_user
(
from
,
purple_chat_conversation_get_nick
(
to
),
NULL
,
/* user-provided join message, IRC style */
PURPLE_CHAT_USER_NONE
,
FALSE
);
/* show a join message */
}
}
static
void
null_join_chat
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
GHashTable
*
components
)
{
const
char
*
username
=
purple_account_get_username
(
purple_connection_get_account
(
gc
));
const
char
*
room
=
g_hash_table_lookup
(
components
,
"room"
);
int
chat_id
=
g_str_hash
(
room
);
purple_debug_info
(
"nullprpl"
,
"%s is joining chat room %s
\n
"
,
username
,
room
);
if
(
!
purple_conversations_find_chat
(
gc
,
chat_id
))
{
purple_serv_got_joined_chat
(
gc
,
chat_id
,
room
);
/* tell everyone that we joined, and add them if they're already there */
foreach_gc_in_chat
(
joined_chat
,
gc
,
chat_id
,
NULL
);
}
else
{
char
*
tmp
=
g_strdup_printf
(
_
(
"%s is already in chat room %s."
),
username
,
room
);
purple_debug_info
(
"nullprpl"
,
"%s is already in chat room %s
\n
"
,
username
,
room
);
purple_notify_info
(
gc
,
_
(
"Join chat"
),
_
(
"Join chat"
),
tmp
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
tmp
);
}
}
static
void
null_reject_chat
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
GHashTable
*
components
)
{
const
char
*
invited_by
=
g_hash_table_lookup
(
components
,
"invited_by"
);
const
char
*
room
=
g_hash_table_lookup
(
components
,
"room"
);
const
char
*
username
=
purple_account_get_username
(
purple_connection_get_account
(
gc
));
PurpleConnection
*
invited_by_gc
=
get_null_gc
(
invited_by
);
char
*
message
=
g_strdup_printf
(
"%s %s %s."
,
username
,
_
(
"has rejected your invitation to join the chat room"
),
room
);
purple_debug_info
(
"nullprpl"
,
"%s has rejected %s's invitation to join chat room %s
\n
"
,
username
,
invited_by
,
room
);
purple_notify_info
(
invited_by_gc
,
_
(
"Chat invitation rejected"
),
_
(
"Chat invitation rejected"
),
message
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
message
);
}
static
gchar
*
null_get_chat_name
(
PurpleProtocolChat
*
protocol_chat
,
GHashTable
*
components
)
{
const
char
*
room
=
g_hash_table_lookup
(
components
,
"room"
);
purple_debug_info
(
"nullprpl"
,
"reporting chat room name '%s'
\n
"
,
room
);
return
g_strdup
(
room
);
}
static
void
null_chat_invite
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
gint
id
,
const
gchar
*
message
,
const
gchar
*
who
)
{
const
char
*
username
=
purple_account_get_username
(
purple_connection_get_account
(
gc
));
PurpleChatConversation
*
chat
=
purple_conversations_find_chat
(
gc
,
id
);
const
char
*
room
=
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
chat
));
PurpleAccount
*
to_acct
=
purple_accounts_find
(
who
,
"null"
);
purple_debug_info
(
"nullprpl"
,
"%s is inviting %s to join chat room %s
\n
"
,
username
,
who
,
room
);
if
(
to_acct
)
{
PurpleChatConversation
*
to_conv
=
purple_conversations_find_chat
(
purple_account_get_connection
(
to_acct
),
id
);
if
(
to_conv
)
{
char
*
tmp
=
g_strdup_printf
(
"%s is already in chat room %s."
,
who
,
room
);
purple_debug_info
(
"nullprpl"
,
"%s is already in chat room %s; "
"ignoring invitation from %s
\n
"
,
who
,
room
,
username
);
purple_notify_info
(
gc
,
_
(
"Chat invitation"
),
_
(
"Chat invitation"
),
tmp
,
purple_request_cpar_from_conversation
(
PURPLE_CONVERSATION
(
to_conv
)));
g_free
(
tmp
);
}
else
{
GHashTable
*
components
;
components
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
NULL
,
g_free
);
g_hash_table_replace
(
components
,
"room"
,
g_strdup
(
room
));
g_hash_table_replace
(
components
,
"invited_by"
,
g_strdup
(
username
));
purple_serv_got_chat_invite
(
purple_account_get_connection
(
to_acct
),
room
,
username
,
message
,
components
);
}
}
}
static
void
left_chat_room
(
PurpleChatConversation
*
from
,
PurpleChatConversation
*
to
,
int
id
,
const
char
*
room
,
gpointer
userdata
)
{
if
(
from
!=
to
)
{
/* tell their chat window that we left */
purple_debug_info
(
"nullprpl"
,
"%s sees that %s left chat room %s
\n
"
,
purple_chat_conversation_get_nick
(
to
),
purple_chat_conversation_get_nick
(
from
),
room
);
purple_chat_conversation_remove_user
(
to
,
purple_chat_conversation_get_nick
(
from
),
NULL
);
/* user-provided message, IRC style */
}
}
static
void
null_chat_leave
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
gint
id
)
{
PurpleChatConversation
*
chat
=
purple_conversations_find_chat
(
gc
,
id
);
purple_debug_info
(
"nullprpl"
,
"%s is leaving chat room %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
chat
)));
/* tell everyone that we left */
foreach_gc_in_chat
(
left_chat_room
,
gc
,
id
,
NULL
);
}
static
void
receive_chat_message
(
PurpleChatConversation
*
from
,
PurpleChatConversation
*
to
,
int
id
,
const
char
*
room
,
gpointer
userdata
)
{
const
char
*
message
=
(
const
char
*
)
userdata
;
PurpleConnection
*
to_gc
=
get_null_gc
(
purple_chat_conversation_get_nick
(
to
));
purple_debug_info
(
"nullprpl"
,
"%s receives message from %s in chat room %s: %s
\n
"
,
purple_chat_conversation_get_nick
(
to
),
purple_chat_conversation_get_nick
(
from
),
room
,
message
);
purple_serv_got_chat_in
(
to_gc
,
id
,
purple_chat_conversation_get_nick
(
from
),
PURPLE_MESSAGE_RECV
,
message
,
time
(
NULL
));
}
static
gint
null_chat_send
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
gint
id
,
PurpleMessage
*
msg
)
{
const
char
*
username
=
purple_account_get_username
(
purple_connection_get_account
(
gc
));
PurpleChatConversation
*
chat
=
purple_conversations_find_chat
(
gc
,
id
);
const
gchar
*
message
=
purple_message_get_contents
(
msg
);
if
(
chat
)
{
purple_debug_info
(
"nullprpl"
,
"%s is sending message to chat room %s: %s
\n
"
,
username
,
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
chat
)),
message
);
/* send message to everyone in the chat room */
foreach_gc_in_chat
(
receive_chat_message
,
gc
,
id
,
(
gpointer
)
message
);
return
0
;
}
else
{
purple_debug_info
(
"nullprpl"
,
"tried to send message from %s to chat room #%d: %s
\n
"
"but couldn't find chat room"
,
username
,
id
,
message
);
return
-1
;
}
}
static
void
null_register_user
(
PurpleProtocolServer
*
protocol_server
,
PurpleAccount
*
acct
)
{
purple_debug_info
(
"nullprpl"
,
"registering account for %s
\n
"
,
purple_account_get_username
(
acct
));
}
static
void
null_alias_buddy
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
const
gchar
*
who
,
const
gchar
*
alias
)
{
purple_debug_info
(
"nullprpl"
,
"%s sets %s's alias to %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
who
,
alias
);
}
static
void
null_group_buddy
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
const
gchar
*
who
,
const
gchar
*
old_group
,
const
gchar
*
new_group
)
{
purple_debug_info
(
"nullprpl"
,
"%s has moved %s from group %s to group %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
who
,
old_group
,
new_group
);
}
static
void
null_rename_group
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
const
gchar
*
old_name
,
PurpleGroup
*
group
,
GList
*
moved_buddies
)
{
purple_debug_info
(
"nullprpl"
,
"%s has renamed group %s to %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
old_name
,
purple_group_get_name
(
group
));
}
static
void
null_convo_closed
(
PurpleProtocolClient
*
client
,
PurpleConnection
*
gc
,
const
char
*
who
)
{
purple_debug_info
(
"nullprpl"
,
"%s's conversation with %s was closed
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
who
);
}
/* normalize a username (e.g. remove whitespace, add default domain, etc.)
* for nullprotocol, this is a noop.
*/
static
const
char
*
null_normalize
(
PurpleProtocolClient
*
client
,
PurpleAccount
*
acct
,
const
char
*
input
)
{
return
input
;
}
static
void
null_set_buddy_icon
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
PurpleImage
*
img
)
{
purple_debug_info
(
"nullprpl"
,
"setting %s's buddy icon to %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
img
?
purple_image_get_path
(
img
)
:
"(null)"
);
}
static
void
null_remove_group
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
PurpleGroup
*
group
)
{
purple_debug_info
(
"nullprpl"
,
"%s has removed group %s
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
purple_group_get_name
(
group
));
}
static
void
set_chat_topic_fn
(
PurpleChatConversation
*
from
,
PurpleChatConversation
*
to
,
int
id
,
const
char
*
room
,
gpointer
userdata
)
{
const
char
*
topic
=
(
const
char
*
)
userdata
;
const
char
*
username
=
purple_account_get_username
(
purple_conversation_get_account
(
PURPLE_CONVERSATION
(
from
)));
char
*
msg
;
purple_chat_conversation_set_topic
(
to
,
username
,
topic
);
if
(
topic
&&
*
topic
)
msg
=
g_strdup_printf
(
_
(
"%s sets topic to: %s"
),
username
,
topic
);
else
msg
=
g_strdup_printf
(
_
(
"%s clears topic"
),
username
);
purple_conversation_write_system_message
(
PURPLE_CONVERSATION
(
to
),
msg
,
PURPLE_MESSAGE_NO_LOG
);
g_free
(
msg
);
}
static
void
null_set_chat_topic
(
PurpleProtocolChat
*
protocol_chat
,
PurpleConnection
*
gc
,
gint
id
,
const
gchar
*
topic
)
{
PurpleChatConversation
*
chat
=
purple_conversations_find_chat
(
gc
,
id
);
const
char
*
last_topic
;
if
(
!
chat
)
return
;
purple_debug_info
(
"nullprpl"
,
"%s sets topic of chat room '%s' to '%s'
\n
"
,
purple_account_get_username
(
purple_connection_get_account
(
gc
)),
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
chat
)),
topic
);
last_topic
=
purple_chat_conversation_get_topic
(
chat
);
if
(
purple_strequal
(
topic
,
last_topic
))
return
;
/* topic is unchanged, this is a noop */
foreach_gc_in_chat
(
set_chat_topic_fn
,
gc
,
id
,
(
gpointer
)
topic
);
}
static
gboolean
null_finish_get_roomlist
(
gpointer
roomlist
)
{
purple_roomlist_set_in_progress
(
PURPLE_ROOMLIST
(
roomlist
),
FALSE
);
g_object_unref
(
roomlist
);
return
FALSE
;
}
static
PurpleRoomlist
*
null_roomlist_get_list
(
PurpleConnection
*
gc
)
{
const
char
*
username
=
purple_account_get_username
(
purple_connection_get_account
(
gc
));
PurpleRoomlist
*
roomlist
=
purple_roomlist_new
(
purple_connection_get_account
(
gc
));
GList
*
fields
=
NULL
;
PurpleRoomlistField
*
field
;
GList
*
chats
;
GList
*
seen_ids
=
NULL
;
purple_debug_info
(
"nullprpl"
,
"%s asks for room list; returning:
\n
"
,
username
);
/* set up the room list */
field
=
purple_roomlist_field_new
(
PURPLE_ROOMLIST_FIELD_STRING
,
"room"
,
"room"
,
TRUE
/* hidden */
);
fields
=
g_list_append
(
fields
,
field
);
field
=
purple_roomlist_field_new
(
PURPLE_ROOMLIST_FIELD_INT
,
"Id"
,
"Id"
,
FALSE
);
fields
=
g_list_append
(
fields
,
field
);
purple_roomlist_set_fields
(
roomlist
,
fields
);
/* add each chat room. the chat ids are cached in seen_ids so that each room
* is only returned once, even if multiple users are in it. */
for
(
chats
=
purple_conversations_get_chats
();
chats
;
chats
=
g_list_next
(
chats
))
{
PurpleChatConversation
*
chat
=
PURPLE_CHAT_CONVERSATION
(
chats
->
data
);
PurpleRoomlistRoom
*
room
;
const
char
*
name
=
purple_conversation_get_name
(
PURPLE_CONVERSATION
(
chat
));
int
id
=
purple_chat_conversation_get_id
(
chat
);
/* have we already added this room? */
if
(
g_list_find_custom
(
seen_ids
,
name
,
(
GCompareFunc
)
strcmp
))
continue
;
/* yes! try the next one. */
/* This cast is OK because this list is only staying around for the life
* of this function and none of the conversations are being deleted
* in that timespan. */
seen_ids
=
g_list_prepend
(
seen_ids
,
(
char
*
)
name
);
/* no, it's new. */
purple_debug_info
(
"nullprpl"
,
"%s (%d), "
,
name
,
id
);
room
=
purple_roomlist_room_new
(
PURPLE_ROOMLIST_ROOMTYPE_ROOM
,
name
,
NULL
);
purple_roomlist_room_add_field
(
roomlist
,
room
,
name
);
purple_roomlist_room_add_field
(
roomlist
,
room
,
&
id
);
purple_roomlist_room_add
(
roomlist
,
room
);
}
g_list_free
(
seen_ids
);
g_timeout_add
(
1
/* ms */
,
null_finish_get_roomlist
,
g_object_ref
(
roomlist
));
return
roomlist
;
}
static
void
null_roomlist_cancel
(
PurpleRoomlist
*
list
)
{
PurpleAccount
*
account
=
purple_roomlist_get_account
(
list
);
purple_debug_info
(
"nullprpl"
,
"%s asked to cancel room list request
\n
"
,
purple_account_get_username
(
account
));
}
static
void
null_roomlist_expand_category
(
PurpleRoomlist
*
list
,
PurpleRoomlistRoom
*
category
)
{
PurpleAccount
*
account
=
purple_roomlist_get_account
(
list
);
purple_debug_info
(
"nullprpl"
,
"%s asked to expand room list category %s
\n
"
,
purple_account_get_username
(
account
),
purple_roomlist_room_get_name
(
category
));
}
static
gboolean
null_offline_message
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
)
{
purple_debug_info
(
"nullprpl"
,
"reporting that offline messages are supported for %s
\n
"
,
purple_buddy_get_name
(
buddy
));
return
TRUE
;
}
/*
* Initialize the protocol instance. see protocol.h for more information.
*/
static
void
null_protocol_init
(
NullProtocol
*
self
)
{
}
/*
* Initialize the protocol class and interfaces.
* see protocol.h for more information.
*/
static
void
null_protocol_class_init
(
NullProtocolClass
*
klass
)
{
PurpleProtocolClass
*
protocol_class
=
PURPLE_PROTOCOL_CLASS
(
klass
);
protocol_class
->
login
=
null_login
;
protocol_class
->
close
=
null_close
;
protocol_class
->
status_types
=
null_status_types
;
protocol_class
->
list_icon
=
null_list_icon
;
protocol_class
->
get_account_options
=
null_protocol_get_account_options
;
protocol_class
->
get_buddy_icon_spec
=
null_protocol_get_buddy_icon_spec
;
protocol_class
->
get_user_splits
=
null_protocol_get_user_splits
;
}
static
void
null_protocol_class_finalize
(
G_GNUC_UNUSED
NullProtocolClass
*
klass
)
{
}
static
void
null_protocol_client_iface_init
(
PurpleProtocolClientInterface
*
client_iface
)
{
client_iface
->
get_actions
=
null_get_actions
;
client_iface
->
status_text
=
null_status_text
;
client_iface
->
tooltip_text
=
null_tooltip_text
;
client_iface
->
blist_node_menu
=
null_blist_node_menu
;
client_iface
->
convo_closed
=
null_convo_closed
;
client_iface
->
normalize
=
null_normalize
;
client_iface
->
offline_message
=
null_offline_message
;
}
static
void
null_protocol_server_iface_init
(
PurpleProtocolServerInterface
*
server_iface
)
{
server_iface
->
register_user
=
null_register_user
;
server_iface
->
set_info
=
null_set_info
;
server_iface
->
get_info
=
null_get_info
;
server_iface
->
set_status
=
null_set_status
;
server_iface
->
set_idle
=
null_set_idle
;
server_iface
->
change_passwd
=
null_change_passwd
;
server_iface
->
add_buddy
=
null_add_buddy
;
server_iface
->
add_buddies
=
null_add_buddies
;
server_iface
->
remove_buddy
=
null_remove_buddy
;
server_iface
->
remove_buddies
=
null_remove_buddies
;
server_iface
->
alias_buddy
=
null_alias_buddy
;
server_iface
->
group_buddy
=
null_group_buddy
;
server_iface
->
rename_group
=
null_rename_group
;
server_iface
->
set_buddy_icon
=
null_set_buddy_icon
;
server_iface
->
remove_group
=
null_remove_group
;
}
static
void
null_protocol_im_iface_init
(
PurpleProtocolIMInterface
*
im_iface
)
{
im_iface
->
send
=
null_send_im
;
im_iface
->
send_typing
=
null_send_typing
;
}
static
void
null_protocol_chat_iface_init
(
PurpleProtocolChatInterface
*
chat_iface
)
{
chat_iface
->
info
=
null_chat_info
;
chat_iface
->
info_defaults
=
null_chat_info_defaults
;
chat_iface
->
join
=
null_join_chat
;
chat_iface
->
reject
=
null_reject_chat
;
chat_iface
->
get_name
=
null_get_chat_name
;
chat_iface
->
invite
=
null_chat_invite
;
chat_iface
->
leave
=
null_chat_leave
;
chat_iface
->
send
=
null_chat_send
;
chat_iface
->
set_topic
=
null_set_chat_topic
;
}
static
void
null_protocol_privacy_iface_init
(
PurpleProtocolPrivacyInterface
*
privacy_iface
)
{
privacy_iface
->
add_permit
=
null_add_permit
;
privacy_iface
->
add_deny
=
null_add_deny
;
privacy_iface
->
remove_permit
=
null_remove_permit
;
privacy_iface
->
remove_deny
=
null_remove_deny
;
privacy_iface
->
set_permit_deny
=
null_set_permit_deny
;
}
static
void
null_protocol_roomlist_iface_init
(
PurpleProtocolRoomlistInterface
*
roomlist_iface
)
{
roomlist_iface
->
get_list
=
null_roomlist_get_list
;
roomlist_iface
->
cancel
=
null_roomlist_cancel
;
roomlist_iface
->
expand_category
=
null_roomlist_expand_category
;
}
/*
* define the null protocol type. this macro defines
* null_protocol_register_type(PurplePlugin *) which is called in plugin_load()
* to register this type with the type system, and null_protocol_get_type()
* which returns the registered GType.
*/
G_DEFINE_DYNAMIC_TYPE_EXTENDED
(
NullProtocol
,
null_protocol
,
PURPLE_TYPE_PROTOCOL
,
0
,
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CLIENT
,
null_protocol_client_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_SERVER
,
null_protocol_server_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_IM
,
null_protocol_im_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CHAT
,
null_protocol_chat_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_PRIVACY
,
null_protocol_privacy_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_ROOMLIST
,
null_protocol_roomlist_iface_init
));
static
PurpleProtocol
*
null_protocol_new
(
void
)
{
return
PURPLE_PROTOCOL
(
g_object_new
(
NULL_TYPE_PROTOCOL
,
"id"
,
"prpl-null"
,
"name"
,
"Null - Testing Protocol"
,
"options"
,
OPT_PROTO_NO_PASSWORD
|
OPT_PROTO_CHAT_TOPIC
,
NULL
));
}
static
PurplePluginInfo
*
plugin_query
(
GError
**
error
)
{
return
purple_plugin_info_new
(
"id"
,
"prpl-null"
,
"name"
,
"Null Protocol"
,
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Protocol"
),
"summary"
,
N_
(
"Null Protocol Plugin"
),
"description"
,
N_
(
"Null Protocol Plugin"
),
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
/* If you're using this protocol plugin as the basis of a plugin that will
* be distributed separately from libpurple, do not include these flags. */
"flags"
,
PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
NULL
);
}
static
gboolean
plugin_load
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
PurpleProtocolManager
*
manager
=
purple_protocol_manager_get_default
();
/* register the NULL_TYPE_PROTOCOL type in the type system. this function
* is defined by G_DEFINE_DYNAMIC_TYPE_EXTENDED. */
null_protocol_register_type
(
G_TYPE_MODULE
(
plugin
));
/* add the protocol to the core */
my_protocol
=
null_protocol_new
();
if
(
!
purple_protocol_manager_register
(
manager
,
my_protocol
,
error
))
{
g_clear_object
(
&
my_protocol
);
return
FALSE
;
}
purple_debug_info
(
"nullprpl"
,
"starting up
\n
"
);
/* get ready to store offline messages */
goffline_messages
=
g_hash_table_new_full
(
g_str_hash
,
/* hash fn */
g_str_equal
,
/* key comparison fn */
g_free
,
/* key free fn */
NULL
);
/* value free fn */
return
TRUE
;
}
static
gboolean
plugin_unload
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
PurpleProtocolManager
*
manager
=
purple_protocol_manager_get_default
();
purple_debug_info
(
"nullprpl"
,
"shutting down
\n
"
);
/* remove the protocol from the core */
if
(
!
purple_protocol_manager_unregister
(
manager
,
my_protocol
,
error
))
{
return
FALSE
;
}
g_clear_object
(
&
my_protocol
);
return
TRUE
;
}
/* initialize the plugin */
PURPLE_PLUGIN_INIT
(
null
,
plugin_query
,
plugin_load
,
plugin_unload
);