pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
closing merged branch
memory-leaks
2020-02-03, Gary Kramlich
208e387899a5
closing merged branch
/* 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.
*
* Rewritten from scratch during Google Summer of Code 2012
* by Tomek Wasilczyk (http://www.wasilczyk.pl).
*
* Previously implemented by:
* - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
* - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
* - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
*
* 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
"status.h"
#include
<libgadu.h>
#include
<debug.h>
#include
<request.h>
#include
"gg.h"
#include
"utils.h"
struct
_ggp_status_session_data
{
gboolean
status_broadcasting
;
gchar
*
current_description
;
};
static
inline
ggp_status_session_data
*
ggp_status_get_ssdata
(
PurpleConnection
*
gc
);
static
gchar
*
ggp_status_validate_description
(
const
gchar
*
msg
);
static
inline
ggp_status_session_data
*
ggp_status_get_ssdata
(
PurpleConnection
*
gc
)
{
GGPInfo
*
accdata
=
purple_connection_get_protocol_data
(
gc
);
return
accdata
->
status_data
;
}
void
ggp_status_setup
(
PurpleConnection
*
gc
)
{
GGPInfo
*
accdata
=
purple_connection_get_protocol_data
(
gc
);
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
ggp_status_session_data
*
ssdata
=
g_new0
(
ggp_status_session_data
,
1
);
accdata
->
status_data
=
ssdata
;
ssdata
->
status_broadcasting
=
purple_account_get_bool
(
account
,
"status_broadcasting"
,
TRUE
);
}
void
ggp_status_cleanup
(
PurpleConnection
*
gc
)
{
ggp_status_session_data
*
ssdata
=
ggp_status_get_ssdata
(
gc
);
g_free
(
ssdata
->
current_description
);
g_free
(
ssdata
);
}
static
gchar
*
ggp_status_validate_description
(
const
gchar
*
msg
)
{
if
(
msg
==
NULL
||
msg
[
0
]
==
'\0'
)
return
NULL
;
return
ggp_utf8_strndup
(
msg
,
GG_STATUS_DESCR_MAXSIZE
);
}
GList
*
ggp_status_types
(
PurpleAccount
*
account
)
{
GList
*
types
=
NULL
;
types
=
g_list_append
(
types
,
purple_status_type_new_with_attrs
(
PURPLE_STATUS_AVAILABLE
,
NULL
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
));
types
=
g_list_append
(
types
,
purple_status_type_new_with_attrs
(
PURPLE_STATUS_AVAILABLE
,
"freeforchat"
,
_
(
"Chatty"
),
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
));
types
=
g_list_append
(
types
,
purple_status_type_new_with_attrs
(
PURPLE_STATUS_AWAY
,
NULL
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
));
types
=
g_list_append
(
types
,
purple_status_type_new_with_attrs
(
PURPLE_STATUS_UNAVAILABLE
,
NULL
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
));
types
=
g_list_append
(
types
,
purple_status_type_new_with_attrs
(
PURPLE_STATUS_INVISIBLE
,
NULL
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
));
types
=
g_list_append
(
types
,
purple_status_type_new_with_attrs
(
PURPLE_STATUS_OFFLINE
,
NULL
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
));
return
types
;
}
int
ggp_status_from_purplestatus
(
PurpleStatus
*
status
,
gchar
**
message
)
{
const
char
*
status_id
=
purple_status_get_id
(
status
);
const
char
*
status_message
=
purple_status_get_attr_string
(
status
,
"message"
);
g_return_val_if_fail
(
message
!=
NULL
,
0
);
*
message
=
NULL
;
if
(
status_message
)
{
gchar
*
stripped
=
purple_markup_strip_html
(
status_message
);
g_strstrip
(
stripped
);
*
message
=
ggp_status_validate_description
(
stripped
);
g_free
(
stripped
);
}
if
(
0
==
strcmp
(
status_id
,
"available"
))
return
status_message
?
GG_STATUS_AVAIL_DESCR
:
GG_STATUS_AVAIL
;
if
(
0
==
strcmp
(
status_id
,
"freeforchat"
))
return
status_message
?
GG_STATUS_FFC_DESCR
:
GG_STATUS_FFC
;
if
(
0
==
strcmp
(
status_id
,
"away"
))
return
status_message
?
GG_STATUS_BUSY_DESCR
:
GG_STATUS_BUSY
;
if
(
0
==
strcmp
(
status_id
,
"unavailable"
))
return
status_message
?
GG_STATUS_DND_DESCR
:
GG_STATUS_DND
;
if
(
0
==
strcmp
(
status_id
,
"invisible"
))
return
status_message
?
GG_STATUS_INVISIBLE_DESCR
:
GG_STATUS_INVISIBLE
;
if
(
0
==
strcmp
(
status_id
,
"offline"
))
return
status_message
?
GG_STATUS_NOT_AVAIL_DESCR
:
GG_STATUS_NOT_AVAIL
;
purple_debug_error
(
"gg"
,
"ggp_status_from_purplestatus: "
"unknown status requested (%s)
\n
"
,
status_id
);
return
status_message
?
GG_STATUS_AVAIL_DESCR
:
GG_STATUS_AVAIL
;
}
const
gchar
*
ggp_status_to_purplestatus
(
int
status
)
{
switch
(
status
)
{
case
GG_STATUS_NOT_AVAIL
:
case
GG_STATUS_NOT_AVAIL_DESCR
:
case
GG_STATUS_BLOCKED
:
case
GG_STATUS_UNKNOWN
:
return
purple_primitive_get_id_from_type
(
PURPLE_STATUS_OFFLINE
);
case
GG_STATUS_FFC
:
case
GG_STATUS_FFC_DESCR
:
return
"freeforchat"
;
case
GG_STATUS_AVAIL
:
case
GG_STATUS_AVAIL_DESCR
:
return
purple_primitive_get_id_from_type
(
PURPLE_STATUS_AVAILABLE
);
case
GG_STATUS_BUSY
:
case
GG_STATUS_BUSY_DESCR
:
return
purple_primitive_get_id_from_type
(
PURPLE_STATUS_AWAY
);
case
GG_STATUS_INVISIBLE
:
case
GG_STATUS_INVISIBLE_DESCR
:
return
purple_primitive_get_id_from_type
(
PURPLE_STATUS_INVISIBLE
);
case
GG_STATUS_DND
:
case
GG_STATUS_DND_DESCR
:
return
purple_primitive_get_id_from_type
(
PURPLE_STATUS_UNAVAILABLE
);
default
:
purple_debug_warning
(
"gg"
,
"ggp_status_to_purplestatus: unknown status %#02x
\n
"
,
status
);
return
purple_primitive_get_id_from_type
(
PURPLE_STATUS_AVAILABLE
);
}
}
const
gchar
*
ggp_status_get_name
(
const
gchar
*
purple_status
)
{
if
(
g_strcmp0
(
purple_status
,
"freeforchat"
)
==
0
)
return
_
(
"Chatty"
);
return
purple_primitive_get_name_from_type
(
purple_primitive_get_type_from_id
(
purple_status
));
}
/*******************************************************************************
* Own status.
******************************************************************************/
static
void
ggp_status_broadcasting_dialog_ok
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
);
/******************************************************************************/
void
ggp_status_set_initial
(
PurpleConnection
*
gc
,
struct
gg_login_params
*
glp
)
{
ggp_status_session_data
*
ssdata
=
ggp_status_get_ssdata
(
gc
);
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
glp
->
status
=
ggp_status_from_purplestatus
(
purple_account_get_active_status
(
account
),
&
glp
->
status_descr
);
if
(
!
ggp_status_get_status_broadcasting
(
gc
))
glp
->
status
|=
GG_STATUS_FRIENDS_MASK
;
ssdata
->
current_description
=
g_strdup
(
glp
->
status_descr
);
}
gboolean
ggp_status_set
(
PurpleAccount
*
account
,
int
status
,
const
gchar
*
msg
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
ggp_status_session_data
*
ssdata
=
ggp_status_get_ssdata
(
gc
);
GGPInfo
*
accdata
=
purple_connection_get_protocol_data
(
gc
);
gchar
*
new_description
=
ggp_status_validate_description
(
msg
);
if
(
!
ssdata
->
status_broadcasting
)
status
|=
GG_STATUS_FRIENDS_MASK
;
if
((
status
==
GG_STATUS_NOT_AVAIL
||
status
==
GG_STATUS_NOT_AVAIL_DESCR
)
&&
0
==
g_strcmp0
(
ssdata
->
current_description
,
new_description
))
{
purple_debug_info
(
"gg"
,
"ggp_status_set: new status doesn't "
"differ when closing connection - ignore
\n
"
);
g_free
(
new_description
);
return
FALSE
;
}
g_free
(
ssdata
->
current_description
);
ssdata
->
current_description
=
new_description
;
if
(
msg
==
NULL
)
gg_change_status
(
accdata
->
session
,
status
);
else
gg_change_status_descr
(
accdata
->
session
,
status
,
new_description
);
return
TRUE
;
}
void
ggp_status_set_purplestatus
(
PurpleAccount
*
account
,
PurpleStatus
*
status
)
{
int
status_gg
;
gchar
*
msg
=
NULL
;
if
(
!
purple_status_is_active
(
status
))
return
;
status_gg
=
ggp_status_from_purplestatus
(
status
,
&
msg
);
ggp_status_set
(
account
,
status_gg
,
msg
);
g_free
(
msg
);
}
void
ggp_status_set_disconnected
(
PurpleAccount
*
account
)
{
gchar
*
msg
=
NULL
;
ggp_status_from_purplestatus
(
purple_account_get_active_status
(
account
),
&
msg
);
if
(
!
ggp_status_set
(
account
,
msg
?
GG_STATUS_NOT_AVAIL_DESCR
:
GG_STATUS_NOT_AVAIL
,
msg
))
{
g_free
(
msg
);
return
;
}
/*
struct gg_event *ev;
guint64 wait_start = ggp_microtime(), now;
int sleep_time = 5000;
while ((ev = gg_watch_fd(info->session)) != NULL)
{
if (ev->type == GG_EVENT_DISCONNECT_ACK)
break;
now = ggp_microtime();
if (now - wait_start + sleep_time >= 100000)
break;
usleep(sleep_time);
sleep_time *= 2;
}
*/
g_usleep
(
100000
);
g_free
(
msg
);
}
void
ggp_status_fake_to_self
(
PurpleConnection
*
gc
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
PurpleStatus
*
status
=
purple_presence_get_active_status
(
purple_account_get_presence
(
account
));
const
char
*
status_msg
=
purple_status_get_attr_string
(
status
,
"message"
);
gchar
*
status_msg_gg
=
NULL
;
if
(
status_msg
!=
NULL
&&
status_msg
[
0
]
!=
'\0'
)
{
status_msg_gg
=
g_new0
(
gchar
,
GG_STATUS_DESCR_MAXSIZE
+
1
);
g_utf8_strncpy
(
status_msg_gg
,
status_msg
,
GG_STATUS_DESCR_MAXSIZE
);
}
purple_protocol_got_user_status
(
account
,
purple_account_get_username
(
account
),
purple_status_get_id
(
status
),
status_msg_gg
?
"message"
:
NULL
,
status_msg_gg
,
NULL
);
g_free
(
status_msg_gg
);
}
gboolean
ggp_status_get_status_broadcasting
(
PurpleConnection
*
gc
)
{
return
ggp_status_get_ssdata
(
gc
)
->
status_broadcasting
;
}
void
ggp_status_set_status_broadcasting
(
PurpleConnection
*
gc
,
gboolean
broadcasting
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
ggp_status_get_ssdata
(
gc
)
->
status_broadcasting
=
broadcasting
;
purple_account_set_bool
(
account
,
"status_broadcasting"
,
broadcasting
);
ggp_status_set_purplestatus
(
account
,
purple_account_get_active_status
(
account
));
}
void
ggp_status_broadcasting_dialog
(
PurpleConnection
*
gc
)
{
PurpleRequestFields
*
fields
;
PurpleRequestFieldGroup
*
group
;
PurpleRequestField
*
field
;
fields
=
purple_request_fields_new
();
group
=
purple_request_field_group_new
(
NULL
);
purple_request_fields_add_group
(
fields
,
group
);
field
=
purple_request_field_bool_new
(
"buddies_only"
,
_
(
"Show status only for buddies"
),
!
ggp_status_get_status_broadcasting
(
gc
));
purple_request_field_group_add_field
(
group
,
field
);
purple_request_fields
(
gc
,
_
(
"Change status broadcasting"
),
_
(
"Please, select who can see your status"
),
NULL
,
fields
,
_
(
"OK"
),
G_CALLBACK
(
ggp_status_broadcasting_dialog_ok
),
_
(
"Cancel"
),
NULL
,
purple_request_cpar_from_connection
(
gc
),
gc
);
}
static
void
ggp_status_broadcasting_dialog_ok
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
)
{
ggp_status_set_status_broadcasting
(
gc
,
!
purple_request_fields_get_bool
(
fields
,
"buddies_only"
));
}
/*******************************************************************************
* Buddy status.
******************************************************************************/
void
ggp_status_got_others_buddy
(
PurpleConnection
*
gc
,
uin_t
uin
,
int
status
,
const
char
*
descr
);
/******************************************************************************/
void
ggp_status_got_others
(
PurpleConnection
*
gc
,
struct
gg_event
*
ev
)
{
if
(
ev
->
type
==
GG_EVENT_NOTIFY60
)
{
struct
gg_event_notify60
*
notify
=
ev
->
event
.
notify60
;
int
i
;
for
(
i
=
0
;
notify
[
i
].
uin
;
i
++
)
ggp_status_got_others_buddy
(
gc
,
notify
[
i
].
uin
,
GG_S
(
notify
[
i
].
status
),
notify
[
i
].
descr
);
}
else
if
(
ev
->
type
==
GG_EVENT_STATUS60
)
{
struct
gg_event_status60
*
notify
=
&
ev
->
event
.
status60
;
ggp_status_got_others_buddy
(
gc
,
notify
->
uin
,
GG_S
(
notify
->
status
),
notify
->
descr
);
}
else
purple_debug_fatal
(
"gg"
,
"ggp_status_got_others: "
"unexpected event %d
\n
"
,
ev
->
type
);
}
void
ggp_status_got_others_buddy
(
PurpleConnection
*
gc
,
uin_t
uin
,
int
status
,
const
char
*
descr
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
PurpleBuddy
*
buddy
=
purple_blist_find_buddy
(
account
,
ggp_uin_to_str
(
uin
));
const
gchar
*
purple_status
=
ggp_status_to_purplestatus
(
status
);
gchar
*
status_message
=
NULL
;
gboolean
is_own
;
is_own
=
(
!
g_strcmp0
(
ggp_uin_to_str
(
uin
),
purple_account_get_username
(
account
)));
if
(
!
buddy
)
{
if
(
!
is_own
)
{
purple_debug_warning
(
"gg"
,
"ggp_status_got_others_buddy: "
"buddy %u not found
\n
"
,
uin
);
}
return
;
}
ggp_buddy_get_data
(
buddy
)
->
blocked
=
(
status
==
GG_STATUS_BLOCKED
);
ggp_buddy_get_data
(
buddy
)
->
not_a_friend
=
(
status
==
GG_STATUS_UNKNOWN
);
if
(
descr
!=
NULL
)
{
status_message
=
g_strdup
(
descr
);
g_strstrip
(
status_message
);
if
(
status_message
[
0
]
==
'\0'
)
{
g_free
(
status_message
);
status_message
=
NULL
;
}
}
if
(
uin
==
ggp_str_to_uin
(
purple_account_get_username
(
account
)))
{
purple_debug_info
(
"gg"
,
"ggp_status_got_others_buddy: "
"own status changed to %s [%s]
\n
"
,
purple_status
,
status_message
?
status_message
:
""
);
}
else
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"gg"
,
"ggp_status_got_others_buddy: "
"status of %u changed to %s [%s]
\n
"
,
uin
,
purple_status
,
status_message
?
status_message
:
""
);
}
if
(
status_message
)
{
purple_protocol_got_user_status
(
account
,
ggp_uin_to_str
(
uin
),
purple_status
,
"message"
,
status_message
,
NULL
);
}
else
{
purple_protocol_got_user_status
(
account
,
ggp_uin_to_str
(
uin
),
purple_status
,
NULL
);
}
g_free
(
status_message
);
}
char
*
ggp_status_buddy_text
(
PurpleBuddy
*
buddy
)
{
ggp_buddy_data
*
buddy_data
=
ggp_buddy_get_data
(
buddy
);
const
gchar
*
purple_message
;
if
(
buddy_data
->
blocked
)
return
g_strdup
(
_
(
"Blocked"
));
if
(
buddy_data
->
not_a_friend
)
return
g_strdup
(
_
(
"Not a buddy"
));
purple_message
=
purple_status_get_attr_string
(
purple_presence_get_active_status
(
purple_buddy_get_presence
(
buddy
)),
"message"
);
if
(
!
purple_message
)
return
NULL
;
return
g_markup_escape_text
(
purple_message
,
-1
);
}