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/
/**
* @file gg.c Gadu-Gadu protocol plugin
*
* purple
*
* Copyright (C) 2005 Bartosz Oler <bartosz@bzimage.us>
*
* Some parts of the code are adapted or taken from the previous implementation
* of this plugin written by Arkadiusz Miskiewicz <misiek@pld.org.pl>
* Some parts Copyright (C) 2009 Krzysztof Klinikowski <grommasher@gmail.com>
*
* Thanks to Google's Summer of Code Program.
*
* 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
"gg.h"
#include
"chat.h"
#include
"search.h"
#include
"blist.h"
#include
"utils.h"
#include
"resolver-purple.h"
#include
"purplew.h"
#include
"libgadu-events.h"
#include
"multilogon.h"
#include
"status.h"
#include
"servconn.h"
#include
"tcpsocket.h"
#include
"pubdir-prpl.h"
#include
"message-prpl.h"
#include
"html.h"
#include
"libgaduw.h"
struct
_GGPProtocol
{
PurpleProtocol
parent
;
};
/* ---------------------------------------------------------------------- */
static
PurpleProtocol
*
my_protocol
=
NULL
;
/* ---------------------------------------------------------------------- */
ggp_buddy_data
*
ggp_buddy_get_data
(
PurpleBuddy
*
buddy
)
{
ggp_buddy_data
*
buddy_data
=
purple_buddy_get_protocol_data
(
buddy
);
if
(
buddy_data
)
return
buddy_data
;
buddy_data
=
g_new0
(
ggp_buddy_data
,
1
);
/* TODO: leak */
purple_buddy_set_protocol_data
(
buddy
,
buddy_data
);
return
buddy_data
;
}
static
void
ggp_buddy_free
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
)
{
ggp_buddy_data
*
buddy_data
=
purple_buddy_get_protocol_data
(
buddy
);
if
(
!
buddy_data
)
{
return
;
}
g_free
(
buddy_data
);
purple_buddy_set_protocol_data
(
buddy
,
NULL
);
}
const
gchar
*
ggp_get_imtoken
(
PurpleConnection
*
gc
)
{
GGPInfo
*
accdata
=
purple_connection_get_protocol_data
(
gc
);
if
(
accdata
->
imtoken
)
return
accdata
->
imtoken
;
if
(
accdata
->
imtoken_warned
)
return
NULL
;
accdata
->
imtoken_warned
=
TRUE
;
purple_notify_error
(
gc
,
_
(
"Authentication failed"
),
_
(
"IMToken value has not been received."
),
_
(
"Some features will be disabled. "
"You may try again after a while."
),
purple_request_cpar_from_connection
(
gc
));
return
NULL
;
}
uin_t
ggp_own_uin
(
PurpleConnection
*
gc
)
{
return
ggp_str_to_uin
(
purple_account_get_username
(
purple_connection_get_account
(
gc
)));
}
/* ---------------------------------------------------------------------- */
/* buddy list import/export from/to file */
static
void
ggp_callback_buddylist_save_ok
(
PurpleConnection
*
gc
,
const
char
*
filename
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
char
*
buddylist
=
ggp_buddylist_dump
(
account
);
purple_debug_info
(
"gg"
,
"Saving...
\n
"
);
purple_debug_info
(
"gg"
,
"file = %s
\n
"
,
filename
);
if
(
buddylist
==
NULL
)
{
purple_notify_info
(
account
,
_
(
"Save Buddylist..."
),
_
(
"Your "
"buddylist is empty, nothing was written to the file."
),
NULL
,
purple_request_cpar_from_connection
(
gc
));
return
;
}
if
(
g_file_set_contents
(
filename
,
buddylist
,
-1
,
NULL
))
{
purple_notify_info
(
account
,
_
(
"Save Buddylist..."
),
_
(
"Buddylist saved successfully!"
),
NULL
,
purple_request_cpar_from_connection
(
gc
));
}
else
{
gchar
*
primary
=
g_strdup_printf
(
_
(
"Couldn't write buddy list for %s to %s"
),
purple_account_get_username
(
account
),
filename
);
purple_notify_error
(
account
,
_
(
"Save Buddylist..."
),
primary
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
primary
);
}
g_free
(
buddylist
);
}
static
void
ggp_callback_buddylist_load_ok
(
PurpleConnection
*
gc
,
gchar
*
file
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
GError
*
error
=
NULL
;
char
*
buddylist
=
NULL
;
gsize
length
;
purple_debug_info
(
"gg"
,
"file_name = %s
\n
"
,
file
);
if
(
!
g_file_get_contents
(
file
,
&
buddylist
,
&
length
,
&
error
))
{
purple_notify_error
(
account
,
_
(
"Couldn't load buddylist"
),
_
(
"Couldn't load buddylist"
),
error
->
message
,
purple_request_cpar_from_connection
(
gc
));
purple_debug_error
(
"gg"
,
"Couldn't load buddylist. file = %s; error = %s
\n
"
,
file
,
error
->
message
);
g_error_free
(
error
);
return
;
}
ggp_buddylist_load
(
gc
,
buddylist
);
g_free
(
buddylist
);
purple_notify_info
(
account
,
_
(
"Load Buddylist..."
),
_
(
"Buddylist loaded successfully!"
),
NULL
,
purple_request_cpar_from_connection
(
gc
));
}
/* }}} */
/*
*/
/* static void ggp_action_buddylist_save(PurpleProtocolAction *action) {{{ */
static
void
ggp_action_buddylist_save
(
PurpleProtocolAction
*
action
)
{
PurpleConnection
*
gc
=
action
->
connection
;
purple_request_file
(
action
,
_
(
"Save buddylist..."
),
NULL
,
TRUE
,
G_CALLBACK
(
ggp_callback_buddylist_save_ok
),
NULL
,
purple_request_cpar_from_connection
(
gc
),
gc
);
}
static
void
ggp_action_buddylist_load
(
PurpleProtocolAction
*
action
)
{
PurpleConnection
*
gc
=
action
->
connection
;
purple_request_file
(
action
,
_
(
"Load buddylist from file..."
),
NULL
,
FALSE
,
G_CALLBACK
(
ggp_callback_buddylist_load_ok
),
NULL
,
purple_request_cpar_from_connection
(
gc
),
gc
);
}
/* ----- BLOCK BUDDIES -------------------------------------------------- */
static
void
ggp_add_deny
(
PurpleProtocolPrivacy
*
privacy
,
PurpleConnection
*
gc
,
const
char
*
who
)
{
GGPInfo
*
info
=
purple_connection_get_protocol_data
(
gc
);
uin_t
uin
=
ggp_str_to_uin
(
who
);
purple_debug_info
(
"gg"
,
"ggp_add_deny: %u
\n
"
,
uin
);
gg_remove_notify_ex
(
info
->
session
,
uin
,
GG_USER_NORMAL
);
gg_add_notify_ex
(
info
->
session
,
uin
,
GG_USER_BLOCKED
);
}
static
void
ggp_remove_deny
(
PurpleProtocolPrivacy
*
privacy
,
PurpleConnection
*
gc
,
const
char
*
who
)
{
GGPInfo
*
info
=
purple_connection_get_protocol_data
(
gc
);
uin_t
uin
=
ggp_str_to_uin
(
who
);
purple_debug_info
(
"gg"
,
"ggp_rem_deny: %u
\n
"
,
uin
);
gg_remove_notify_ex
(
info
->
session
,
uin
,
GG_USER_BLOCKED
);
gg_add_notify_ex
(
info
->
session
,
uin
,
GG_USER_NORMAL
);
}
/* ---------------------------------------------------------------------- */
/* ----- INTERNAL CALLBACKS --------------------------------------------- */
/* ---------------------------------------------------------------------- */
static
void
ggp_typing_notification_handler
(
PurpleConnection
*
gc
,
uin_t
uin
,
int
length
)
{
gchar
*
from
;
from
=
g_strdup_printf
(
"%u"
,
uin
);
if
(
length
)
purple_serv_got_typing
(
gc
,
from
,
0
,
PURPLE_IM_TYPING
);
else
purple_serv_got_typing_stopped
(
gc
,
from
);
g_free
(
from
);
}
/**
* Handling of XML events.
*
* @param gc PurpleConnection.
* @param data Raw XML contents.
*
* @see http://toxygen.net/libgadu/protocol/#ch1.13
* @todo: this may not be necessary anymore
*/
static
void
ggp_xml_event_handler
(
PurpleConnection
*
gc
,
char
*
data
)
{
PurpleXmlNode
*
xml
=
NULL
;
PurpleXmlNode
*
xmlnode_next_event
;
xml
=
purple_xmlnode_from_str
(
data
,
-1
);
if
(
xml
==
NULL
)
{
purple_debug_error
(
"gg"
,
"ggp_xml_event_handler: "
"invalid xml: [%s]
\n
"
,
data
);
goto
out
;
}
xmlnode_next_event
=
purple_xmlnode_get_child
(
xml
,
"event"
);
while
(
xmlnode_next_event
!=
NULL
)
{
PurpleXmlNode
*
xmlnode_current_event
=
xmlnode_next_event
;
PurpleXmlNode
*
xmlnode_type
;
char
*
event_type_raw
;
int
event_type
=
0
;
PurpleXmlNode
*
xmlnode_sender
;
char
*
event_sender_raw
;
uin_t
event_sender
=
0
;
xmlnode_next_event
=
purple_xmlnode_get_next_twin
(
xmlnode_next_event
);
xmlnode_type
=
purple_xmlnode_get_child
(
xmlnode_current_event
,
"type"
);
if
(
xmlnode_type
==
NULL
)
continue
;
event_type_raw
=
purple_xmlnode_get_data
(
xmlnode_type
);
if
(
event_type_raw
!=
NULL
)
event_type
=
atoi
(
event_type_raw
);
g_free
(
event_type_raw
);
xmlnode_sender
=
purple_xmlnode_get_child
(
xmlnode_current_event
,
"sender"
);
if
(
xmlnode_sender
!=
NULL
)
{
event_sender_raw
=
purple_xmlnode_get_data
(
xmlnode_sender
);
if
(
event_sender_raw
!=
NULL
)
event_sender
=
ggp_str_to_uin
(
event_sender_raw
);
g_free
(
event_sender_raw
);
}
switch
(
event_type
)
{
case
28
:
/* avatar update */
purple_debug_info
(
"gg"
,
"ggp_xml_event_handler: avatar updated (uid: %u)
\n
"
,
event_sender
);
break
;
default
:
purple_debug_error
(
"gg"
,
"ggp_xml_event_handler: unsupported event type=%d from=%u
\n
"
,
event_type
,
event_sender
);
}
}
out
:
if
(
xml
)
purple_xmlnode_free
(
xml
);
}
static
void
ggp_callback_recv
(
gpointer
_gc
,
gint
fd
,
PurpleInputCondition
cond
)
{
PurpleConnection
*
gc
=
_gc
;
GGPInfo
*
info
=
purple_connection_get_protocol_data
(
gc
);
struct
gg_event
*
ev
;
if
(
!
(
ev
=
gg_watch_fd
(
info
->
session
)))
{
purple_debug_error
(
"gg"
,
"ggp_callback_recv: gg_watch_fd failed -- CRITICAL!
\n
"
);
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Unable to read from socket"
));
return
;
}
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"gg"
,
"ggp_callback_recv: got event %s"
,
gg_debug_event
(
ev
->
type
));
}
purple_input_remove
(
info
->
inpa
);
info
->
inpa
=
purple_input_add
(
info
->
session
->
fd
,
ggp_tcpsocket_inputcond_gg_to_purple
(
info
->
session
->
check
),
ggp_callback_recv
,
gc
);
switch
(
ev
->
type
)
{
case
GG_EVENT_NONE
:
/* Nothing happened. */
break
;
case
GG_EVENT_CONN_FAILED
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Server disconnected"
));
break
;
case
GG_EVENT_MSG
:
ggp_message_got
(
gc
,
&
ev
->
event
.
msg
);
break
;
case
GG_EVENT_ACK
:
case
GG_EVENT_ACK110
:
break
;
case
GG_EVENT_IMAGE_REPLY
:
ggp_image_recv
(
gc
,
&
ev
->
event
.
image_reply
);
break
;
case
GG_EVENT_IMAGE_REQUEST
:
ggp_image_send
(
gc
,
&
ev
->
event
.
image_request
);
break
;
case
GG_EVENT_NOTIFY60
:
case
GG_EVENT_STATUS60
:
ggp_status_got_others
(
gc
,
ev
);
break
;
case
GG_EVENT_TYPING_NOTIFICATION
:
ggp_typing_notification_handler
(
gc
,
ev
->
event
.
typing_notification
.
uin
,
ev
->
event
.
typing_notification
.
length
);
break
;
case
GG_EVENT_XML_EVENT
:
purple_debug_info
(
"gg"
,
"GG_EVENT_XML_EVENT
\n
"
);
ggp_xml_event_handler
(
gc
,
ev
->
event
.
xml_event
.
data
);
break
;
case
GG_EVENT_USER_DATA
:
ggp_events_user_data
(
gc
,
&
ev
->
event
.
user_data
);
break
;
case
GG_EVENT_JSON_EVENT
:
ggp_events_json
(
gc
,
&
ev
->
event
.
json_event
);
break
;
case
GG_EVENT_USERLIST100_VERSION
:
ggp_roster_version
(
gc
,
&
ev
->
event
.
userlist100_version
);
break
;
case
GG_EVENT_USERLIST100_REPLY
:
ggp_roster_reply
(
gc
,
&
ev
->
event
.
userlist100_reply
);
break
;
case
GG_EVENT_MULTILOGON_MSG
:
ggp_message_got_multilogon
(
gc
,
&
ev
->
event
.
multilogon_msg
);
break
;
case
GG_EVENT_MULTILOGON_INFO
:
ggp_multilogon_info
(
gc
,
&
ev
->
event
.
multilogon_info
);
break
;
case
GG_EVENT_IMTOKEN
:
purple_debug_info
(
"gg"
,
"gg11: got IMTOKEN
\n
"
);
g_free
(
info
->
imtoken
);
info
->
imtoken
=
g_strdup
(
ev
->
event
.
imtoken
.
imtoken
);
break
;
case
GG_EVENT_PONG110
:
purple_debug_info
(
"gg"
,
"gg11: got PONG110 %lu
\n
"
,
(
long
unsigned
)
ev
->
event
.
pong110
.
time
);
break
;
case
GG_EVENT_CHAT_INFO
:
case
GG_EVENT_CHAT_INFO_GOT_ALL
:
case
GG_EVENT_CHAT_INFO_UPDATE
:
case
GG_EVENT_CHAT_CREATED
:
case
GG_EVENT_CHAT_INVITE_ACK
:
ggp_chat_got_event
(
gc
,
ev
);
break
;
case
GG_EVENT_DISCONNECT
:
ggp_servconn_remote_disconnect
(
gc
);
break
;
default
:
purple_debug_warning
(
"gg"
,
"unsupported event type=%d
\n
"
,
ev
->
type
);
break
;
}
gg_free_event
(
ev
);
}
void
ggp_async_login_handler
(
gpointer
_gc
,
gint
fd
,
PurpleInputCondition
cond
)
{
PurpleConnection
*
gc
=
_gc
;
GGPInfo
*
info
;
struct
gg_event
*
ev
;
PURPLE_ASSERT_CONNECTION_IS_VALID
(
gc
);
info
=
purple_connection_get_protocol_data
(
gc
);
purple_debug_info
(
"gg"
,
"login_handler: session: check = %d; state = %d;
\n
"
,
info
->
session
->
check
,
info
->
session
->
state
);
switch
(
info
->
session
->
state
)
{
case
GG_STATE_ERROR
:
purple_debug_info
(
"gg"
,
"GG_STATE_ERROR
\n
"
);
break
;
case
GG_STATE_RESOLVING
:
purple_debug_info
(
"gg"
,
"GG_STATE_RESOLVING
\n
"
);
break
;
case
GG_STATE_RESOLVING_GG
:
purple_debug_info
(
"gg"
,
"GG_STATE_RESOLVING_GG
\n
"
);
break
;
case
GG_STATE_CONNECTING_HUB
:
purple_debug_info
(
"gg"
,
"GG_STATE_CONNECTING_HUB
\n
"
);
break
;
case
GG_STATE_READING_DATA
:
purple_debug_info
(
"gg"
,
"GG_STATE_READING_DATA
\n
"
);
break
;
case
GG_STATE_CONNECTING_GG
:
purple_debug_info
(
"gg"
,
"GG_STATE_CONNECTING_GG
\n
"
);
break
;
case
GG_STATE_READING_KEY
:
purple_debug_info
(
"gg"
,
"GG_STATE_READING_KEY
\n
"
);
break
;
case
GG_STATE_READING_REPLY
:
purple_debug_info
(
"gg"
,
"GG_STATE_READING_REPLY
\n
"
);
break
;
case
GG_STATE_TLS_NEGOTIATION
:
purple_debug_info
(
"gg"
,
"GG_STATE_TLS_NEGOTIATION
\n
"
);
break
;
case
GG_STATE_RESOLVING_HUB
:
purple_debug_info
(
"gg"
,
"GG_STATE_RESOLVING_HUB
\n
"
);
break
;
case
GG_STATE_READING_HUB
:
purple_debug_info
(
"gg"
,
"GG_STATE_READING_HUB
\n
"
);
break
;
default
:
purple_debug_error
(
"gg"
,
"unknown state = %d
\n
"
,
info
->
session
->
state
);
break
;
}
if
(
!
(
ev
=
gg_watch_fd
(
info
->
session
)))
{
purple_debug_error
(
"gg"
,
"login_handler: gg_watch_fd failed!
\n
"
);
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Unable to read from socket"
));
return
;
}
purple_debug_info
(
"gg"
,
"login_handler: session->fd = %d
\n
"
,
info
->
session
->
fd
);
purple_debug_info
(
"gg"
,
"login_handler: session: check = %d; state = %d;
\n
"
,
info
->
session
->
check
,
info
->
session
->
state
);
purple_input_remove
(
info
->
inpa
);
info
->
inpa
=
0
;
/** XXX I think that this shouldn't be done if ev->type is GG_EVENT_CONN_FAILED or GG_EVENT_CONN_SUCCESS -datallah */
if
(
info
->
session
->
fd
>=
0
)
info
->
inpa
=
purple_input_add
(
info
->
session
->
fd
,
(
info
->
session
->
check
==
1
)
?
PURPLE_INPUT_WRITE
:
PURPLE_INPUT_READ
,
ggp_async_login_handler
,
gc
);
switch
(
ev
->
type
)
{
case
GG_EVENT_NONE
:
/* Nothing happened. */
purple_debug_info
(
"gg"
,
"GG_EVENT_NONE
\n
"
);
break
;
case
GG_EVENT_CONN_SUCCESS
:
{
purple_debug_info
(
"gg"
,
"GG_EVENT_CONN_SUCCESS:"
" successfully connected to %s
\n
"
,
info
->
session
->
connect_host
);
ggp_servconn_add_server
(
info
->
session
->
connect_host
);
purple_input_remove
(
info
->
inpa
);
info
->
inpa
=
purple_input_add
(
info
->
session
->
fd
,
PURPLE_INPUT_READ
,
ggp_callback_recv
,
gc
);
purple_connection_update_progress
(
gc
,
_
(
"Connected"
),
1
,
2
);
purple_connection_set_state
(
gc
,
PURPLE_CONNECTION_CONNECTED
);
ggp_buddylist_send
(
gc
);
ggp_roster_request_update
(
gc
);
}
break
;
case
GG_EVENT_CONN_FAILED
:
if
(
info
->
inpa
>
0
)
{
purple_input_remove
(
info
->
inpa
);
info
->
inpa
=
0
;
}
purple_debug_info
(
"gg"
,
"Connection failure: %d
\n
"
,
ev
->
event
.
failure
);
switch
(
ev
->
event
.
failure
)
{
case
GG_FAILURE_RESOLVING
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Unable to resolve "
"hostname"
));
break
;
case
GG_FAILURE_PASSWORD
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
_
(
"Incorrect password"
));
break
;
case
GG_FAILURE_TLS
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
,
_
(
"SSL Connection Failed"
));
break
;
case
GG_FAILURE_INTRUDER
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
_
(
"Your account has been "
"disabled because too many "
"incorrect passwords were "
"entered"
));
break
;
case
GG_FAILURE_UNAVAILABLE
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Service temporarily "
"unavailable"
));
break
;
case
GG_FAILURE_PROXY
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Error connecting to proxy "
"server"
));
break
;
case
GG_FAILURE_HUB
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Error connecting to master "
"server"
));
break
;
case
GG_FAILURE_INTERNAL
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Internal error"
));
break
;
default
:
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Connection failed"
));
}
break
;
case
GG_EVENT_MSG
:
if
(
ev
->
event
.
msg
.
sender
==
0
)
{
if
(
ev
->
event
.
msg
.
message
==
NULL
)
break
;
/* system messages are mostly ads */
purple_debug_info
(
"gg"
,
"System message:
\n
%s
\n
"
,
ev
->
event
.
msg
.
message
);
}
else
{
purple_debug_warning
(
"gg"
,
"GG_EVENT_MSG: message from user %u "
"unexpected while connecting:
\n
%s
\n
"
,
ev
->
event
.
msg
.
sender
,
ev
->
event
.
msg
.
message
);
}
break
;
default
:
purple_debug_error
(
"gg"
,
"strange event: %d
\n
"
,
ev
->
type
);
break
;
}
gg_free_event
(
ev
);
}
static
gint
gg_uri_handler_find_account
(
PurpleAccount
*
account
,
G_GNUC_UNUSED
gconstpointer
data
)
{
const
gchar
*
protocol_id
;
protocol_id
=
purple_account_get_protocol_id
(
account
);
if
(
purple_strequal
(
protocol_id
,
"prpl-gg"
)
&&
purple_account_is_connected
(
account
))
{
return
0
;
}
else
{
return
-1
;
}
}
static
gboolean
gg_uri_handler
(
const
gchar
*
scheme
,
const
gchar
*
screenname
,
GHashTable
*
params
)
{
GList
*
accounts
;
GList
*
account_node
;
PurpleConversation
*
im
;
g_return_val_if_fail
(
screenname
!=
NULL
,
FALSE
);
if
(
!
purple_strequal
(
scheme
,
"gg"
))
{
return
FALSE
;
}
if
(
screenname
[
0
]
==
'\0'
)
{
purple_debug_warning
(
"gg"
,
"Invalid empty screenname in URI"
);
return
FALSE
;
}
/* Find online Gadu-Gadu account */
accounts
=
purple_accounts_get_all
();
account_node
=
g_list_find_custom
(
accounts
,
NULL
,
(
GCompareFunc
)
gg_uri_handler_find_account
);
if
(
account_node
==
NULL
)
{
return
FALSE
;
}
im
=
purple_im_conversation_new
(
account_node
->
data
,
screenname
);
purple_conversation_present
(
im
);
return
TRUE
;
}
/* ---------------------------------------------------------------------- */
/* ----- PurpleProtocol ----------------------------------------- */
/* ---------------------------------------------------------------------- */
static
const
char
*
ggp_list_icon
(
PurpleAccount
*
account
,
PurpleBuddy
*
buddy
)
{
return
"gadu-gadu"
;
}
static
PurpleBuddyIconSpec
*
ggp_protocol_get_buddy_icon_spec
(
PurpleProtocol
*
protocol
)
{
return
purple_buddy_icon_spec_new
(
"png"
,
1
,
1
,
200
,
200
,
0
,
PURPLE_ICON_SCALE_DISPLAY
|
PURPLE_ICON_SCALE_SEND
);
}
static
GList
*
ggp_protocol_get_account_options
(
PurpleProtocol
*
protocol
)
{
PurpleAccountOption
*
option
=
NULL
;
PurpleKeyValuePair
*
kvp
=
NULL
;
GList
*
encryption_options
=
NULL
;
GList
*
protocol_version
=
NULL
;
GList
*
opts
=
NULL
;
option
=
purple_account_option_string_new
(
_
(
"GG server"
),
"gg_server"
,
""
);
opts
=
g_list_append
(
opts
,
option
);
/* setup encryption options */
kvp
=
purple_key_value_pair_new
(
_
(
"Use encryption if available"
),
"opportunistic_tls"
);
encryption_options
=
g_list_append
(
encryption_options
,
kvp
);
kvp
=
purple_key_value_pair_new
(
_
(
"Require encryption"
),
"require_tls"
);
encryption_options
=
g_list_append
(
encryption_options
,
kvp
);
kvp
=
purple_key_value_pair_new
(
_
(
"Don't use encryption"
),
"none"
);
encryption_options
=
g_list_append
(
encryption_options
,
kvp
);
option
=
purple_account_option_list_new
(
_
(
"Connection security"
),
"encryption"
,
encryption_options
);
opts
=
g_list_append
(
opts
,
option
);
/* setup the protocol version */
kvp
=
purple_key_value_pair_new
(
_
(
"Default"
),
"default"
);
protocol_version
=
g_list_append
(
protocol_version
,
kvp
);
kvp
=
purple_key_value_pair_new
(
"GG 10"
,
"gg10"
);
protocol_version
=
g_list_append
(
protocol_version
,
kvp
);
kvp
=
purple_key_value_pair_new
(
"GG 11"
,
"gg11"
);
protocol_version
=
g_list_append
(
protocol_version
,
kvp
);
option
=
purple_account_option_list_new
(
_
(
"Protocol version"
),
"protocol_version"
,
protocol_version
);
opts
=
g_list_append
(
opts
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Show links from strangers"
),
"show_links_from_strangers"
,
1
);
opts
=
g_list_append
(
opts
,
option
);
return
opts
;
}
static
const
char
*
ggp_normalize
(
PurpleProtocolClient
*
client
,
PurpleAccount
*
account
,
const
char
*
who
)
{
static
char
normalized
[
21
];
/* maximum unsigned long long int size */
uin_t
uin
=
ggp_str_to_uin
(
who
);
if
(
uin
<=
0
)
{
return
NULL
;
}
g_snprintf
(
normalized
,
sizeof
(
normalized
),
"%u"
,
uin
);
return
normalized
;
}
/* TODO:
* - move to status.c ?
* - add information about not adding to his buddy list (not_a_friend)
*/
static
void
ggp_tooltip_text
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
b
,
PurpleNotifyUserInfo
*
user_info
,
gboolean
full
)
{
PurpleStatus
*
status
;
char
*
tmp
;
const
char
*
name
,
*
alias
;
gchar
*
msg
;
g_return_if_fail
(
b
!=
NULL
);
status
=
purple_presence_get_active_status
(
purple_buddy_get_presence
(
b
));
name
=
purple_status_get_name
(
status
);
alias
=
purple_buddy_get_alias
(
b
);
ggp_status_from_purplestatus
(
status
,
&
msg
);
purple_notify_user_info_add_pair_plaintext
(
user_info
,
_
(
"Alias"
),
alias
);
if
(
msg
!=
NULL
)
{
if
(
PURPLE_BUDDY_IS_ONLINE
(
b
))
{
tmp
=
g_strdup_printf
(
"%s: %s"
,
name
,
msg
);
purple_notify_user_info_add_pair_plaintext
(
user_info
,
_
(
"Status"
),
tmp
);
g_free
(
tmp
);
}
else
{
purple_notify_user_info_add_pair_plaintext
(
user_info
,
_
(
"Message"
),
msg
);
}
g_free
(
msg
);
/* We don't want to duplicate 'Status: Offline'. */
}
else
if
(
PURPLE_BUDDY_IS_ONLINE
(
b
))
{
purple_notify_user_info_add_pair_plaintext
(
user_info
,
_
(
"Status"
),
name
);
}
}
static
void
ggp_login
(
PurpleAccount
*
account
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
struct
gg_login_params
*
glp
;
GGPInfo
*
info
;
const
char
*
address
;
const
gchar
*
encryption_type
,
*
protocol_version
;
GProxyResolver
*
resolver
;
GError
*
error
;
purple_connection_set_flags
(
gc
,
PURPLE_CONNECTION_FLAG_HTML
|
PURPLE_CONNECTION_FLAG_NO_URLDESC
);
resolver
=
purple_proxy_get_proxy_resolver
(
account
,
&
error
);
if
(
resolver
==
NULL
)
{
purple_debug_error
(
"gg"
,
"Unable to get account proxy resolver: %s"
,
error
->
message
);
purple_connection_take_error
(
gc
,
error
);
return
;
}
glp
=
g_new0
(
struct
gg_login_params
,
1
);
glp
->
struct_size
=
sizeof
(
struct
gg_login_params
);
info
=
g_new0
(
GGPInfo
,
1
);
purple_connection_set_protocol_data
(
gc
,
info
);
info
->
http
=
soup_session_new_with_options
(
"proxy-resolver"
,
resolver
,
NULL
);
ggp_tcpsocket_setup
(
gc
,
glp
);
ggp_image_setup
(
gc
);
ggp_avatar_setup
(
gc
);
ggp_roster_setup
(
gc
);
ggp_multilogon_setup
(
gc
);
ggp_status_setup
(
gc
);
ggp_chat_setup
(
gc
);
ggp_message_setup
(
gc
);
ggp_edisc_setup
(
gc
,
resolver
);
g_object_unref
(
resolver
);
glp
->
uin
=
ggp_str_to_uin
(
purple_account_get_username
(
account
));
glp
->
password
=
ggp_convert_to_cp1250
(
purple_connection_get_password
(
gc
));
if
(
glp
->
uin
==
0
)
{
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_INVALID_USERNAME
,
_
(
"The username specified is invalid."
));
purple_str_wipe
(
glp
->
password
);
g_free
(
glp
);
return
;
}
glp
->
image_size
=
255
;
glp
->
status_flags
=
GG_STATUS_FLAG_UNKNOWN
;
if
(
purple_account_get_bool
(
account
,
"show_links_from_strangers"
,
1
))
glp
->
status_flags
|=
GG_STATUS_FLAG_SPAM
;
glp
->
encoding
=
GG_ENCODING_UTF8
;
glp
->
protocol_features
=
(
GG_FEATURE_DND_FFC
|
GG_FEATURE_TYPING_NOTIFICATION
|
GG_FEATURE_MULTILOGON
|
GG_FEATURE_USER_DATA
);
glp
->
async
=
1
;
encryption_type
=
purple_account_get_string
(
account
,
"encryption"
,
"opportunistic_tls"
);
purple_debug_info
(
"gg"
,
"Requested encryption type: %s
\n
"
,
encryption_type
);
if
(
purple_strequal
(
encryption_type
,
"opportunistic_tls"
))
glp
->
tls
=
GG_SSL_ENABLED
;
else
if
(
purple_strequal
(
encryption_type
,
"require_tls"
))
{
if
(
gg_libgadu_check_feature
(
GG_LIBGADU_FEATURE_SSL
))
glp
->
tls
=
GG_SSL_REQUIRED
;
else
{
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
,
_
(
"SSL support unavailable"
));
purple_str_wipe
(
glp
->
password
);
g_free
(
glp
);
return
;
}
}
else
/* encryption_type == "none" */
glp
->
tls
=
GG_SSL_DISABLED
;
purple_debug_misc
(
"gg"
,
"TLS mode: %d
\n
"
,
glp
->
tls
);
protocol_version
=
purple_account_get_string
(
account
,
"protocol_version"
,
"default"
);
purple_debug_info
(
"gg"
,
"Requested protocol version: %s
\n
"
,
protocol_version
);
if
(
purple_strequal
(
protocol_version
,
"gg10"
))
glp
->
protocol_version
=
GG_PROTOCOL_VERSION_100
;
else
if
(
purple_strequal
(
protocol_version
,
"gg11"
))
glp
->
protocol_version
=
GG_PROTOCOL_VERSION_110
;
glp
->
compatibility
=
GG_COMPAT_1_12_0
;
ggp_status_set_initial
(
gc
,
glp
);
address
=
purple_account_get_string
(
account
,
"gg_server"
,
""
);
if
(
address
&&
*
address
)
glp
->
connect_host
=
g_strdup
(
address
);
info
->
session
=
gg_login
(
glp
);
g_free
(
glp
->
connect_host
);
purple_str_wipe
(
glp
->
password
);
g_free
(
glp
);
purple_connection_update_progress
(
gc
,
_
(
"Connecting"
),
0
,
2
);
if
(
info
->
session
==
NULL
)
{
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Connection failed"
));
return
;
}
if
(
info
->
session
->
fd
>
0
)
{
info
->
inpa
=
purple_input_add
(
info
->
session
->
fd
,
PURPLE_INPUT_READ
,
ggp_async_login_handler
,
gc
);
}
}
static
void
ggp_close
(
PurpleConnection
*
gc
)
{
PurpleAccount
*
account
;
GGPInfo
*
info
;;
g_return_if_fail
(
gc
!=
NULL
);
account
=
purple_connection_get_account
(
gc
);
info
=
purple_connection_get_protocol_data
(
gc
);
purple_notify_close_with_handle
(
gc
);
if
(
info
)
{
if
(
info
->
session
!=
NULL
)
{
ggp_status_set_disconnected
(
account
);
gg_logoff
(
info
->
session
);
gg_free_session
(
info
->
session
);
}
ggp_image_cleanup
(
gc
);
ggp_avatar_cleanup
(
gc
);
ggp_roster_cleanup
(
gc
);
ggp_multilogon_cleanup
(
gc
);
ggp_status_cleanup
(
gc
);
ggp_chat_cleanup
(
gc
);
ggp_message_cleanup
(
gc
);
ggp_edisc_cleanup
(
gc
);
if
(
info
->
inpa
>
0
)
purple_input_remove
(
info
->
inpa
);
g_free
(
info
->
imtoken
);
if
(
info
->
http
)
{
soup_session_abort
(
info
->
http
);
g_object_unref
(
info
->
http
);
}
purple_connection_set_protocol_data
(
gc
,
NULL
);
g_free
(
info
);
}
purple_debug_info
(
"gg"
,
"Connection closed.
\n
"
);
}
static
unsigned
int
ggp_send_typing
(
PurpleProtocolIM
*
im
,
PurpleConnection
*
gc
,
const
char
*
name
,
PurpleIMTypingState
state
)
{
GGPInfo
*
info
=
purple_connection_get_protocol_data
(
gc
);
int
dummy_length
;
/* we don't send real length of typed message */
if
(
state
==
PURPLE_IM_TYPED
)
/* not supported */
return
1
;
if
(
state
==
PURPLE_IM_TYPING
)
dummy_length
=
(
int
)
g_random_int
();
else
/* PURPLE_IM_NOT_TYPING */
dummy_length
=
0
;
gg_typing_notification
(
info
->
session
,
ggp_str_to_uin
(
name
),
dummy_length
);
return
1
;
/* wait 1 second before another notification */
}
static
void
ggp_add_buddy
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
,
const
gchar
*
message
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
GGPInfo
*
info
=
purple_connection_get_protocol_data
(
gc
);
const
gchar
*
name
=
purple_buddy_get_name
(
buddy
);
gg_add_notify
(
info
->
session
,
ggp_str_to_uin
(
name
));
/* gg server won't tell us our status here */
if
(
purple_strequal
(
purple_account_get_username
(
account
),
name
))
ggp_status_fake_to_self
(
gc
);
ggp_roster_add_buddy
(
protocol_server
,
gc
,
buddy
,
group
,
message
);
ggp_pubdir_request_buddy_alias
(
gc
,
buddy
);
}
static
void
ggp_remove_buddy
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
)
{
GGPInfo
*
info
=
purple_connection_get_protocol_data
(
gc
);
gg_remove_notify
(
info
->
session
,
ggp_str_to_uin
(
purple_buddy_get_name
(
buddy
)));
ggp_roster_remove_buddy
(
protocol_server
,
gc
,
buddy
,
group
);
}
static
void
ggp_keepalive
(
PurpleProtocolServer
*
protocol_server
,
PurpleConnection
*
gc
)
{
GGPInfo
*
info
=
purple_connection_get_protocol_data
(
gc
);
/* purple_debug_info("gg", "Keeping connection alive....\n"); */
if
(
gg_ping
(
info
->
session
)
<
0
)
{
purple_debug_info
(
"gg"
,
"Not connected to the server "
"or gg_session is not correct
\n
"
);
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Not connected to the server"
));
}
}
static
void
ggp_action_multilogon
(
PurpleProtocolAction
*
action
)
{
ggp_multilogon_dialog
(
action
->
connection
);
}
static
void
ggp_action_status_broadcasting
(
PurpleProtocolAction
*
action
)
{
ggp_status_broadcasting_dialog
(
action
->
connection
);
}
static
void
ggp_action_search
(
PurpleProtocolAction
*
action
)
{
ggp_pubdir_search
(
action
->
connection
,
NULL
);
}
static
void
ggp_action_set_info
(
PurpleProtocolAction
*
action
)
{
ggp_pubdir_set_info
(
action
->
connection
);
}
static
GList
*
ggp_get_actions
(
PurpleProtocolClient
*
client
,
PurpleConnection
*
gc
)
{
GList
*
m
=
NULL
;
PurpleProtocolAction
*
act
;
act
=
purple_protocol_action_new
(
_
(
"Show other sessions"
),
ggp_action_multilogon
);
m
=
g_list_append
(
m
,
act
);
act
=
purple_protocol_action_new
(
_
(
"Show status only for buddies"
),
ggp_action_status_broadcasting
);
m
=
g_list_append
(
m
,
act
);
m
=
g_list_append
(
m
,
NULL
);
act
=
purple_protocol_action_new
(
_
(
"Find buddies..."
),
ggp_action_search
);
m
=
g_list_append
(
m
,
act
);
act
=
purple_protocol_action_new
(
_
(
"Set User Info"
),
ggp_action_set_info
);
m
=
g_list_append
(
m
,
act
);
m
=
g_list_append
(
m
,
NULL
);
act
=
purple_protocol_action_new
(
_
(
"Save buddylist to file..."
),
ggp_action_buddylist_save
);
m
=
g_list_append
(
m
,
act
);
act
=
purple_protocol_action_new
(
_
(
"Load buddylist from file..."
),
ggp_action_buddylist_load
);
m
=
g_list_append
(
m
,
act
);
return
m
;
}
static
const
char
*
ggp_list_emblem
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
)
{
ggp_buddy_data
*
buddy_data
=
ggp_buddy_get_data
(
buddy
);
if
(
buddy_data
->
blocked
)
return
"not-authorized"
;
if
(
buddy_data
->
not_a_friend
)
return
"unavailable"
;
return
NULL
;
}
static
gboolean
ggp_offline_message
(
PurpleProtocolClient
*
client
,
PurpleBuddy
*
buddy
)
{
return
TRUE
;
}
static
GHashTable
*
ggp_get_account_text_table
(
PurpleProtocolClient
*
client
,
PurpleAccount
*
account
)
{
GHashTable
*
table
;
table
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
g_hash_table_insert
(
table
,
"login_label"
,
(
gpointer
)
_
(
"GG number..."
));
return
table
;
}
static
gssize
ggp_get_max_message_size
(
PurpleProtocolClient
*
client
,
PurpleConversation
*
conv
)
{
/* TODO: it may depend on protocol version or other factors */
return
1200
;
/* no more than 1232 */
}
static
void
ggp_protocol_init
(
GGPProtocol
*
self
)
{
}
static
void
ggp_protocol_class_init
(
GGPProtocolClass
*
klass
)
{
PurpleProtocolClass
*
protocol_class
=
PURPLE_PROTOCOL_CLASS
(
klass
);
protocol_class
->
login
=
ggp_login
;
protocol_class
->
close
=
ggp_close
;
protocol_class
->
status_types
=
ggp_status_types
;
protocol_class
->
list_icon
=
ggp_list_icon
;
protocol_class
->
get_account_options
=
ggp_protocol_get_account_options
;
protocol_class
->
get_buddy_icon_spec
=
ggp_protocol_get_buddy_icon_spec
;
}
static
void
ggp_protocol_class_finalize
(
G_GNUC_UNUSED
GGPProtocolClass
*
klass
)
{
}
static
void
ggp_protocol_client_iface_init
(
PurpleProtocolClientInterface
*
client_iface
)
{
client_iface
->
get_actions
=
ggp_get_actions
;
client_iface
->
list_emblem
=
ggp_list_emblem
;
client_iface
->
status_text
=
ggp_status_buddy_text
;
client_iface
->
tooltip_text
=
ggp_tooltip_text
;
client_iface
->
buddy_free
=
ggp_buddy_free
;
client_iface
->
normalize
=
ggp_normalize
;
client_iface
->
offline_message
=
ggp_offline_message
;
client_iface
->
get_account_text_table
=
ggp_get_account_text_table
;
client_iface
->
get_max_message_size
=
ggp_get_max_message_size
;
}
static
void
ggp_protocol_server_iface_init
(
PurpleProtocolServerInterface
*
server_iface
)
{
server_iface
->
get_info
=
ggp_pubdir_get_info_protocol
;
server_iface
->
set_status
=
ggp_status_set_purplestatus
;
server_iface
->
add_buddy
=
ggp_add_buddy
;
server_iface
->
remove_buddy
=
ggp_remove_buddy
;
server_iface
->
keepalive
=
ggp_keepalive
;
server_iface
->
alias_buddy
=
ggp_roster_alias_buddy
;
server_iface
->
group_buddy
=
ggp_roster_group_buddy
;
server_iface
->
rename_group
=
ggp_roster_rename_group
;
server_iface
->
set_buddy_icon
=
ggp_avatar_own_set
;
}
static
void
ggp_protocol_im_iface_init
(
PurpleProtocolIMInterface
*
im_iface
)
{
im_iface
->
send
=
ggp_message_send_im
;
im_iface
->
send_typing
=
ggp_send_typing
;
}
static
void
ggp_protocol_chat_iface_init
(
PurpleProtocolChatInterface
*
chat_iface
)
{
chat_iface
->
info
=
ggp_chat_info
;
chat_iface
->
info_defaults
=
ggp_chat_info_defaults
;
chat_iface
->
join
=
ggp_chat_join
;
chat_iface
->
get_name
=
ggp_chat_get_name
;
chat_iface
->
invite
=
ggp_chat_invite
;
chat_iface
->
leave
=
ggp_chat_leave
;
chat_iface
->
send
=
ggp_chat_send
;
chat_iface
->
reject
=
NULL
;
/* TODO */
}
static
void
ggp_protocol_roomlist_iface_init
(
PurpleProtocolRoomlistInterface
*
roomlist_iface
)
{
roomlist_iface
->
get_list
=
ggp_chat_roomlist_get_list
;
}
static
void
ggp_protocol_privacy_iface_init
(
PurpleProtocolPrivacyInterface
*
privacy_iface
)
{
privacy_iface
->
add_deny
=
ggp_add_deny
;
privacy_iface
->
remove_deny
=
ggp_remove_deny
;
}
static
void
ggp_protocol_xfer_iface_init
(
PurpleProtocolXferInterface
*
xfer_iface
)
{
xfer_iface
->
can_receive
=
ggp_edisc_xfer_can_receive_file
;
xfer_iface
->
send_file
=
ggp_edisc_xfer_send_file
;
xfer_iface
->
new_xfer
=
ggp_edisc_xfer_send_new
;
}
G_DEFINE_DYNAMIC_TYPE_EXTENDED
(
GGPProtocol
,
ggp_protocol
,
PURPLE_TYPE_PROTOCOL
,
0
,
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CLIENT
,
ggp_protocol_client_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_SERVER
,
ggp_protocol_server_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_IM
,
ggp_protocol_im_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CHAT
,
ggp_protocol_chat_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_ROOMLIST
,
ggp_protocol_roomlist_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_PRIVACY
,
ggp_protocol_privacy_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_XFER
,
ggp_protocol_xfer_iface_init
));
static
PurpleProtocol
*
ggp_protocol_new
(
void
)
{
return
PURPLE_PROTOCOL
(
g_object_new
(
GGP_TYPE_PROTOCOL
,
"id"
,
"prpl-gg"
,
"name"
,
"Gadu-Gadu"
,
"description"
,
"Gadu-Gadu is a Polish instant messaging client"
,
"icon-name"
,
"im-gadu-gadu"
,
"icon-resource-path"
,
"/im/pidgin/libpurple/gg/icons"
,
NULL
));
}
static
gchar
*
plugin_extra
(
PurplePlugin
*
plugin
)
{
return
g_strdup_printf
(
"Using libgadu version %s"
,
gg_libgadu_version
());
}
static
GPluginPluginInfo
*
gg_query
(
GError
**
error
)
{
const
gchar
*
const
authors
[]
=
{
"boler@sourceforge.net"
,
NULL
};
return
purple_plugin_info_new
(
"id"
,
"prpl-gg"
,
"name"
,
"Gadu-Gadu Protocol"
,
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Protocol"
),
"summary"
,
N_
(
"Gadu-Gadu Protocol Plugin"
),
"description"
,
N_
(
"Polish popular IM"
),
"authors"
,
authors
,
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"extra-cb"
,
plugin_extra
,
"flags"
,
PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
NULL
);
}
static
gboolean
gg_load
(
GPluginPlugin
*
plugin
,
GError
**
error
)
{
PurpleProtocolManager
*
manager
=
purple_protocol_manager_get_default
();
ggp_protocol_register_type
(
G_TYPE_MODULE
(
plugin
));
ggp_xfer_register
(
G_TYPE_MODULE
(
plugin
));
my_protocol
=
ggp_protocol_new
();
if
(
!
purple_protocol_manager_register
(
manager
,
my_protocol
,
error
))
{
g_clear_object
(
&
my_protocol
);
return
FALSE
;
}
purple_prefs_add_none
(
"/plugins/prpl/gg"
);
purple_debug_info
(
"gg"
,
"Loading Gadu-Gadu protocol plugin with "
"libgadu %s...
\n
"
,
gg_libgadu_version
());
ggp_libgaduw_setup
();
ggp_resolver_purple_setup
();
ggp_servconn_setup
(
NULL
);
ggp_html_setup
();
ggp_message_setup_global
();
purple_signal_connect
(
purple_get_core
(),
"uri-handler"
,
plugin
,
PURPLE_CALLBACK
(
gg_uri_handler
),
NULL
);
return
TRUE
;
}
static
gboolean
gg_unload
(
GPluginPlugin
*
plugin
,
gboolean
shutdown
,
GError
**
error
)
{
PurpleProtocolManager
*
manager
=
purple_protocol_manager_get_default
();
if
(
!
purple_protocol_manager_unregister
(
manager
,
my_protocol
,
error
))
{
return
FALSE
;
}
purple_signal_disconnect
(
purple_get_core
(),
"uri-handler"
,
plugin
,
PURPLE_CALLBACK
(
gg_uri_handler
));
ggp_servconn_cleanup
();
ggp_html_cleanup
();
ggp_message_cleanup_global
();
ggp_libgaduw_cleanup
();
g_clear_object
(
&
my_protocol
);
return
TRUE
;
}
GPLUGIN_NATIVE_PLUGIN_DECLARE
(
gg
)
/* vim: set ts=8 sts=0 sw=8 noet: */