qulogic/pidgin
Clone
Summary
Browse
Changes
Graph
Add disconnection reasons to oscar.
cpw.resiak.disconnectreason
2007-10-01, Will Thompson
a9fc6198b5c6
Add disconnection reasons to oscar.
/**
* @file buddy_opt.c
*
* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
"debug.h"
#include
"internal.h"
#include
"notify.h"
#include
"request.h"
#include
"buddy_info.h"
#include
"buddy_list.h"
#include
"buddy_opt.h"
#include
"char_conv.h"
#include
"crypt.h"
#include
"header_info.h"
#include
"im.h"
#include
"keep_alive.h"
#include
"packet_parse.h"
#include
"send_core.h"
#include
"utils.h"
#define PURPLE_GROUP_QQ_FORMAT "QQ (%s)"
#define PURPLE_GROUP_QQ_UNKNOWN "QQ Unknown"
#define PURPLE_GROUP_QQ_BLOCKED "QQ Blocked"
#define QQ_REMOVE_BUDDY_REPLY_OK 0x00
#define QQ_REMOVE_SELF_REPLY_OK 0x00
#define QQ_ADD_BUDDY_AUTH_REPLY_OK 0x30
/* ASCII value of "0" */
enum
{
QQ_MY_AUTH_APPROVE
=
0x30
,
/* ASCII value of "0" */
QQ_MY_AUTH_REJECT
=
0x31
,
/* ASCII value of "1" */
QQ_MY_AUTH_REQUEST
=
0x32
,
/* ASCII value of "2" */
};
typedef
struct
_qq_add_buddy_request
{
guint32
uid
;
guint16
seq
;
}
qq_add_buddy_request
;
/* send packet to remove a buddy from my buddy list */
static
void
_qq_send_packet_remove_buddy
(
PurpleConnection
*
gc
,
guint32
uid
)
{
gchar
uid_str
[
11
];
g_return_if_fail
(
uid
>
0
);
g_snprintf
(
uid_str
,
sizeof
(
uid_str
),
"%d"
,
uid
);
qq_send_cmd
(
gc
,
QQ_CMD_DEL_FRIEND
,
TRUE
,
0
,
TRUE
,
(
guint8
*
)
uid_str
,
strlen
(
uid_str
));
}
/* try to remove myself from someone's buddy list */
static
void
_qq_send_packet_remove_self_from
(
PurpleConnection
*
gc
,
guint32
uid
)
{
guint8
*
raw_data
,
*
cursor
;
g_return_if_fail
(
uid
>
0
);
raw_data
=
g_newa
(
guint8
,
4
);
cursor
=
raw_data
;
create_packet_dw
(
raw_data
,
&
cursor
,
uid
);
qq_send_cmd
(
gc
,
QQ_CMD_REMOVE_SELF
,
TRUE
,
0
,
TRUE
,
raw_data
,
4
);
}
/* try to add a buddy without authentication */
static
void
_qq_send_packet_add_buddy
(
PurpleConnection
*
gc
,
guint32
uid
)
{
qq_data
*
qd
;
qq_add_buddy_request
*
req
;
gchar
uid_str
[
11
];
g_return_if_fail
(
uid
>
0
);
/* we need to send the ascii code of this uid to qq server */
g_snprintf
(
uid_str
,
sizeof
(
uid_str
),
"%d"
,
uid
);
qq_send_cmd
(
gc
,
QQ_CMD_ADD_FRIEND_WO_AUTH
,
TRUE
,
0
,
TRUE
,
(
guint8
*
)
uid_str
,
strlen
(
uid_str
));
/* must be set after sending packet to get the correct send_seq */
qd
=
(
qq_data
*
)
gc
->
proto_data
;
req
=
g_new0
(
qq_add_buddy_request
,
1
);
req
->
seq
=
qd
->
send_seq
;
req
->
uid
=
uid
;
qd
->
add_buddy_request
=
g_list_append
(
qd
->
add_buddy_request
,
req
);
}
/* this buddy needs authentication, text conversion is done at lowest level */
static
void
_qq_send_packet_buddy_auth
(
PurpleConnection
*
gc
,
guint32
uid
,
const
gchar
response
,
const
gchar
*
text
)
{
gchar
*
text_qq
,
uid_str
[
11
];
guint8
bar
,
*
cursor
,
*
raw_data
;
g_return_if_fail
(
uid
!=
0
);
g_snprintf
(
uid_str
,
sizeof
(
uid_str
),
"%d"
,
uid
);
bar
=
0x1f
;
raw_data
=
g_newa
(
guint8
,
QQ_MSG_IM_MAX
);
cursor
=
raw_data
;
create_packet_data
(
raw_data
,
&
cursor
,
(
guint8
*
)
uid_str
,
strlen
(
uid_str
));
create_packet_b
(
raw_data
,
&
cursor
,
bar
);
create_packet_b
(
raw_data
,
&
cursor
,
response
);
if
(
text
!=
NULL
)
{
text_qq
=
utf8_to_qq
(
text
,
QQ_CHARSET_DEFAULT
);
create_packet_b
(
raw_data
,
&
cursor
,
bar
);
create_packet_data
(
raw_data
,
&
cursor
,
(
guint8
*
)
text_qq
,
strlen
(
text_qq
));
g_free
(
text_qq
);
}
qq_send_cmd
(
gc
,
QQ_CMD_BUDDY_AUTH
,
TRUE
,
0
,
TRUE
,
raw_data
,
cursor
-
raw_data
);
}
static
void
_qq_send_packet_add_buddy_auth_with_gc_and_uid
(
gc_and_uid
*
g
,
const
gchar
*
text
)
{
PurpleConnection
*
gc
;
guint32
uid
;
g_return_if_fail
(
g
!=
NULL
);
gc
=
g
->
gc
;
uid
=
g
->
uid
;
g_return_if_fail
(
uid
!=
0
);
_qq_send_packet_buddy_auth
(
gc
,
uid
,
QQ_MY_AUTH_REQUEST
,
text
);
g_free
(
g
);
}
/* the real packet to reject and request is sent from here */
static
void
_qq_reject_add_request_real
(
gc_and_uid
*
g
,
const
gchar
*
reason
)
{
gint
uid
;
PurpleConnection
*
gc
;
g_return_if_fail
(
g
!=
NULL
);
gc
=
g
->
gc
;
uid
=
g
->
uid
;
g_return_if_fail
(
uid
!=
0
);
_qq_send_packet_buddy_auth
(
gc
,
uid
,
QQ_MY_AUTH_REJECT
,
reason
);
g_free
(
g
);
}
/* we approve other's request of adding me as friend */
void
qq_approve_add_request_with_gc_and_uid
(
gc_and_uid
*
g
)
{
gint
uid
;
PurpleConnection
*
gc
;
g_return_if_fail
(
g
!=
NULL
);
gc
=
g
->
gc
;
uid
=
g
->
uid
;
g_return_if_fail
(
uid
!=
0
);
_qq_send_packet_buddy_auth
(
gc
,
uid
,
QQ_MY_AUTH_APPROVE
,
NULL
);
g_free
(
g
);
}
void
qq_do_nothing_with_gc_and_uid
(
gc_and_uid
*
g
,
const
gchar
*
msg
)
{
g_free
(
g
);
}
/* we reject other's request of adding me as friend */
void
qq_reject_add_request_with_gc_and_uid
(
gc_and_uid
*
g
)
{
gint
uid
;
gchar
*
msg1
,
*
msg2
;
PurpleConnection
*
gc
;
gc_and_uid
*
g2
;
gchar
*
nombre
;
g_return_if_fail
(
g
!=
NULL
);
gc
=
g
->
gc
;
uid
=
g
->
uid
;
g_return_if_fail
(
uid
!=
0
);
g_free
(
g
);
g2
=
g_new0
(
gc_and_uid
,
1
);
g2
->
gc
=
gc
;
g2
->
uid
=
uid
;
msg1
=
g_strdup_printf
(
_
(
"You rejected %d's request"
),
uid
);
msg2
=
g_strdup
(
_
(
"Input your reason:"
));
nombre
=
uid_to_purple_name
(
uid
);
purple_request_input
(
gc
,
_
(
"Reject request"
),
msg1
,
msg2
,
_
(
"Sorry, you are not my type..."
),
TRUE
,
FALSE
,
NULL
,
_
(
"Reject"
),
G_CALLBACK
(
_qq_reject_add_request_real
),
_
(
"Cancel"
),
NULL
,
purple_connection_get_account
(
gc
),
nombre
,
NULL
,
g2
);
g_free
(
nombre
);
}
void
qq_add_buddy_with_gc_and_uid
(
gc_and_uid
*
g
)
{
gint
uid
;
PurpleConnection
*
gc
;
g_return_if_fail
(
g
!=
NULL
);
gc
=
g
->
gc
;
uid
=
g
->
uid
;
g_return_if_fail
(
uid
!=
0
);
_qq_send_packet_add_buddy
(
gc
,
uid
);
g_free
(
g
);
}
void
qq_block_buddy_with_gc_and_uid
(
gc_and_uid
*
g
)
{
guint32
uid
;
PurpleConnection
*
gc
;
PurpleBuddy
buddy
;
PurpleGroup
group
;
g_return_if_fail
(
g
!=
NULL
);
gc
=
g
->
gc
;
uid
=
g
->
uid
;
g_return_if_fail
(
uid
>
0
);
buddy
.
name
=
uid_to_purple_name
(
uid
);
group
.
name
=
PURPLE_GROUP_QQ_BLOCKED
;
qq_remove_buddy
(
gc
,
&
buddy
,
&
group
);
_qq_send_packet_remove_self_from
(
gc
,
uid
);
}
/* process reply to add_buddy_auth request */
void
qq_process_add_buddy_auth_reply
(
guint8
*
buf
,
gint
buf_len
,
PurpleConnection
*
gc
)
{
qq_data
*
qd
;
gint
len
;
guint8
*
data
,
*
cursor
,
reply
;
gchar
**
segments
,
*
msg_utf8
;
g_return_if_fail
(
buf
!=
NULL
&&
buf_len
!=
0
);
qd
=
(
qq_data
*
)
gc
->
proto_data
;
len
=
buf_len
;
data
=
g_newa
(
guint8
,
len
);
cursor
=
data
;
if
(
qq_crypt
(
DECRYPT
,
buf
,
buf_len
,
qd
->
session_key
,
data
,
&
len
))
{
read_packet_b
(
data
,
&
cursor
,
len
,
&
reply
);
if
(
reply
!=
QQ_ADD_BUDDY_AUTH_REPLY_OK
)
{
purple_debug
(
PURPLE_DEBUG_WARNING
,
"QQ"
,
"Add buddy with auth request failed
\n
"
);
if
(
NULL
==
(
segments
=
split_data
(
data
,
len
,
"
\x1f
"
,
2
)))
return
;
msg_utf8
=
qq_to_utf8
(
segments
[
1
],
QQ_CHARSET_DEFAULT
);
purple_notify_error
(
gc
,
NULL
,
_
(
"Add buddy with auth request failed"
),
msg_utf8
);
g_free
(
msg_utf8
);
}
else
{
purple_debug
(
PURPLE_DEBUG_INFO
,
"QQ"
,
"Add buddy with auth request OK
\n
"
);
}
}
else
{
purple_debug
(
PURPLE_DEBUG_ERROR
,
"QQ"
,
"Error decrypt add buddy with auth reply
\n
"
);
}
}
/* process the server reply for my request to remove a buddy */
void
qq_process_remove_buddy_reply
(
guint8
*
buf
,
gint
buf_len
,
PurpleConnection
*
gc
)
{
qq_data
*
qd
;
gint
len
;
guint8
*
data
,
*
cursor
,
reply
;
g_return_if_fail
(
buf
!=
NULL
&&
buf_len
!=
0
);
qd
=
(
qq_data
*
)
gc
->
proto_data
;
len
=
buf_len
;
data
=
g_newa
(
guint8
,
len
);
if
(
qq_crypt
(
DECRYPT
,
buf
,
buf_len
,
qd
->
session_key
,
data
,
&
len
))
{
cursor
=
data
;
read_packet_b
(
data
,
&
cursor
,
len
,
&
reply
);
if
(
reply
!=
QQ_REMOVE_BUDDY_REPLY_OK
)
{
/* there is no reason return from server */
purple_debug
(
PURPLE_DEBUG_WARNING
,
"QQ"
,
"Remove buddy fails
\n
"
);
}
else
{
/* if reply */
purple_debug
(
PURPLE_DEBUG_INFO
,
"QQ"
,
"Remove buddy OK
\n
"
);
/* TODO: We don't really need to notify the user about this, do we? */
purple_notify_info
(
gc
,
NULL
,
_
(
"You have successfully removed a buddy"
),
NULL
);
}
}
else
{
purple_debug
(
PURPLE_DEBUG_ERROR
,
"QQ"
,
"Error decrypt remove buddy reply
\n
"
);
}
}
/* process the server reply for my request to remove myself from a buddy */
void
qq_process_remove_self_reply
(
guint8
*
buf
,
gint
buf_len
,
PurpleConnection
*
gc
)
{
qq_data
*
qd
;
gint
len
;
guint8
*
data
,
*
cursor
,
reply
;
g_return_if_fail
(
buf
!=
NULL
&&
buf_len
!=
0
);
qd
=
(
qq_data
*
)
gc
->
proto_data
;
len
=
buf_len
;
data
=
g_newa
(
guint8
,
len
);
if
(
qq_crypt
(
DECRYPT
,
buf
,
buf_len
,
qd
->
session_key
,
data
,
&
len
))
{
cursor
=
data
;
read_packet_b
(
data
,
&
cursor
,
len
,
&
reply
);
if
(
reply
!=
QQ_REMOVE_SELF_REPLY_OK
)
/* there is no reason return from server */
purple_debug
(
PURPLE_DEBUG_WARNING
,
"QQ"
,
"Remove self fails
\n
"
);
else
{
/* if reply */
purple_debug
(
PURPLE_DEBUG_INFO
,
"QQ"
,
"Remove self from a buddy OK
\n
"
);
/* TODO: Does the user really need to be notified about this? */
purple_notify_info
(
gc
,
NULL
,
_
(
"You have successfully removed yourself from your friend's buddy list"
),
NULL
);
}
}
else
{
purple_debug
(
PURPLE_DEBUG_ERROR
,
"QQ"
,
"Error decrypt remove self reply
\n
"
);
}
}
void
qq_process_add_buddy_reply
(
guint8
*
buf
,
gint
buf_len
,
guint16
seq
,
PurpleConnection
*
gc
)
{
qq_data
*
qd
;
gint
len
,
for_uid
;
gchar
*
msg
,
**
segments
,
*
uid
,
*
reply
;
guint8
*
data
;
GList
*
list
;
PurpleBuddy
*
b
;
gc_and_uid
*
g
;
qq_add_buddy_request
*
req
;
gchar
*
nombre
;
g_return_if_fail
(
buf
!=
NULL
&&
buf_len
!=
0
);
for_uid
=
0
;
qd
=
(
qq_data
*
)
gc
->
proto_data
;
len
=
buf_len
;
list
=
qd
->
add_buddy_request
;
while
(
list
!=
NULL
)
{
req
=
(
qq_add_buddy_request
*
)
list
->
data
;
if
(
req
->
seq
==
seq
)
{
/* reply to this */
for_uid
=
req
->
uid
;
qd
->
add_buddy_request
=
g_list_remove
(
qd
->
add_buddy_request
,
qd
->
add_buddy_request
->
data
);
g_free
(
req
);
break
;
}
list
=
list
->
next
;
}
if
(
for_uid
==
0
)
{
/* we have no record for this */
purple_debug
(
PURPLE_DEBUG_ERROR
,
"QQ"
,
"We have no record for add buddy reply [%d], discard
\n
"
,
seq
);
return
;
}
else
{
purple_debug
(
PURPLE_DEBUG_INFO
,
"QQ"
,
"Add buddy reply [%d] is for id [%d]
\n
"
,
seq
,
for_uid
);
}
data
=
g_newa
(
guint8
,
len
);
if
(
qq_crypt
(
DECRYPT
,
buf
,
buf_len
,
qd
->
session_key
,
data
,
&
len
))
{
if
(
NULL
==
(
segments
=
split_data
(
data
,
len
,
"
\x1f
"
,
2
)))
return
;
uid
=
segments
[
0
];
reply
=
segments
[
1
];
if
(
strtol
(
uid
,
NULL
,
10
)
!=
qd
->
uid
)
{
/* should not happen */
purple_debug
(
PURPLE_DEBUG_ERROR
,
"QQ"
,
"Add buddy reply is to [%s], not me!"
,
uid
);
g_strfreev
(
segments
);
return
;
}
if
(
strtol
(
reply
,
NULL
,
10
)
>
0
)
{
/* need auth */
purple_debug
(
PURPLE_DEBUG_WARNING
,
"QQ"
,
"Add buddy attempt fails, need authentication
\n
"
);
nombre
=
uid_to_purple_name
(
for_uid
);
b
=
purple_find_buddy
(
gc
->
account
,
nombre
);
if
(
b
!=
NULL
)
purple_blist_remove_buddy
(
b
);
g
=
g_new0
(
gc_and_uid
,
1
);
g
->
gc
=
gc
;
g
->
uid
=
for_uid
;
msg
=
g_strdup_printf
(
_
(
"User %d needs authentication"
),
for_uid
);
purple_request_input
(
gc
,
NULL
,
msg
,
_
(
"Input request here"
),
/* TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands */
_
(
"Would you be my friend?"
),
TRUE
,
FALSE
,
NULL
,
_
(
"Send"
),
G_CALLBACK
(
_qq_send_packet_add_buddy_auth_with_gc_and_uid
),
_
(
"Cancel"
),
G_CALLBACK
(
qq_do_nothing_with_gc_and_uid
),
purple_connection_get_account
(
gc
),
nombre
,
NULL
,
g
);
g_free
(
msg
);
g_free
(
nombre
);
}
else
{
/* add OK */
qq_add_buddy_by_recv_packet
(
gc
,
for_uid
,
TRUE
,
TRUE
);
msg
=
g_strdup_printf
(
_
(
"You have added %d to buddy list"
),
for_uid
);
purple_notify_info
(
gc
,
NULL
,
msg
,
NULL
);
g_free
(
msg
);
}
g_strfreev
(
segments
);
}
else
{
purple_debug
(
PURPLE_DEBUG_ERROR
,
"QQ"
,
"Error decrypt add buddy reply
\n
"
);
}
}
PurpleGroup
*
qq_get_purple_group
(
const
gchar
*
group_name
)
{
PurpleGroup
*
g
;
g_return_val_if_fail
(
group_name
!=
NULL
,
NULL
);
g
=
purple_find_group
(
group_name
);
if
(
g
==
NULL
)
{
g
=
purple_group_new
(
group_name
);
purple_blist_add_group
(
g
,
NULL
);
purple_debug
(
PURPLE_DEBUG_WARNING
,
"QQ"
,
"Add new group: %s
\n
"
,
group_name
);
}
return
g
;
}
/* we add new buddy, if the received packet is from someone not in my list
* return the PurpleBuddy that is just created */
PurpleBuddy
*
qq_add_buddy_by_recv_packet
(
PurpleConnection
*
gc
,
guint32
uid
,
gboolean
is_known
,
gboolean
create
)
{
PurpleAccount
*
a
;
PurpleBuddy
*
b
;
PurpleGroup
*
g
;
qq_data
*
qd
;
qq_buddy
*
q_bud
;
gchar
*
name
,
*
group_name
;
a
=
gc
->
account
;
qd
=
(
qq_data
*
)
gc
->
proto_data
;
g_return_val_if_fail
(
a
!=
NULL
&&
uid
!=
0
,
NULL
);
group_name
=
is_known
?
g_strdup_printf
(
PURPLE_GROUP_QQ_FORMAT
,
purple_account_get_username
(
a
))
:
g_strdup
(
PURPLE_GROUP_QQ_UNKNOWN
);
g
=
qq_get_purple_group
(
group_name
);
name
=
uid_to_purple_name
(
uid
);
b
=
purple_find_buddy
(
gc
->
account
,
name
);
/* remove old, we can not simply return here
* because there might be old local copy of this buddy */
if
(
b
!=
NULL
)
purple_blist_remove_buddy
(
b
);
b
=
purple_buddy_new
(
a
,
name
,
NULL
);
if
(
!
create
)
b
->
proto_data
=
NULL
;
else
{
q_bud
=
g_new0
(
qq_buddy
,
1
);
q_bud
->
uid
=
uid
;
b
->
proto_data
=
q_bud
;
qd
->
buddies
=
g_list_append
(
qd
->
buddies
,
q_bud
);
qq_send_packet_get_info
(
gc
,
q_bud
->
uid
,
FALSE
);
qq_send_packet_get_buddies_online
(
gc
,
QQ_FRIENDS_ONLINE_POSITION_START
);
}
purple_blist_add_buddy
(
b
,
NULL
,
g
,
NULL
);
purple_debug
(
PURPLE_DEBUG_WARNING
,
"QQ"
,
"Add new buddy: [%s]
\n
"
,
name
);
g_free
(
name
);
g_free
(
group_name
);
return
b
;
}
/* add a buddy and send packet to QQ server
* note that when purple load local cached buddy list into its blist
* it also calls this funtion, so we have to
* define qd->logged_in=TRUE AFTER serv_finish_login(gc) */
void
qq_add_buddy
(
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
)
{
qq_data
*
qd
;
guint32
uid
;
PurpleBuddy
*
b
;
qd
=
(
qq_data
*
)
gc
->
proto_data
;
if
(
!
qd
->
logged_in
)
return
;
/* IMPORTANT ! */
uid
=
purple_name_to_uid
(
buddy
->
name
);
if
(
uid
>
0
)
_qq_send_packet_add_buddy
(
gc
,
uid
);
else
{
b
=
purple_find_buddy
(
gc
->
account
,
buddy
->
name
);
if
(
b
!=
NULL
)
purple_blist_remove_buddy
(
b
);
purple_notify_error
(
gc
,
NULL
,
_
(
"QQid Error"
),
_
(
"Invalid QQid"
));
}
}
/* remove a buddy and send packet to QQ server accordingly */
void
qq_remove_buddy
(
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
)
{
qq_data
*
qd
;
PurpleBuddy
*
b
;
qq_buddy
*
q_bud
;
guint32
uid
;
qd
=
(
qq_data
*
)
gc
->
proto_data
;
uid
=
purple_name_to_uid
(
buddy
->
name
);
if
(
!
qd
->
logged_in
)
return
;
if
(
uid
>
0
)
_qq_send_packet_remove_buddy
(
gc
,
uid
);
b
=
purple_find_buddy
(
gc
->
account
,
buddy
->
name
);
if
(
b
!=
NULL
)
{
q_bud
=
(
qq_buddy
*
)
b
->
proto_data
;
if
(
q_bud
!=
NULL
)
qd
->
buddies
=
g_list_remove
(
qd
->
buddies
,
q_bud
);
else
purple_debug
(
PURPLE_DEBUG_WARNING
,
"QQ"
,
"We have no qq_buddy record for %s
\n
"
,
buddy
->
name
);
/* remove buddy on blist, this does not trigger qq_remove_buddy again
* do this only if the request comes from block request,
* otherwise purple segmentation fault */
if
(
g_ascii_strcasecmp
(
group
->
name
,
PURPLE_GROUP_QQ_BLOCKED
)
==
0
)
purple_blist_remove_buddy
(
b
);
}
}
/* free add buddy request queue */
void
qq_add_buddy_request_free
(
qq_data
*
qd
)
{
gint
i
;
qq_add_buddy_request
*
p
;
i
=
0
;
while
(
qd
->
add_buddy_request
)
{
p
=
(
qq_add_buddy_request
*
)
(
qd
->
add_buddy_request
->
data
);
qd
->
add_buddy_request
=
g_list_remove
(
qd
->
add_buddy_request
,
p
);
g_free
(
p
);
i
++
;
}
purple_debug
(
PURPLE_DEBUG_INFO
,
"QQ"
,
"%d add buddy requests are freed!
\n
"
,
i
);
}
/* free up all qq_buddy */
void
qq_buddies_list_free
(
PurpleAccount
*
account
,
qq_data
*
qd
)
{
gint
i
;
qq_buddy
*
p
;
gchar
*
name
;
PurpleBuddy
*
b
;
i
=
0
;
while
(
qd
->
buddies
)
{
p
=
(
qq_buddy
*
)
(
qd
->
buddies
->
data
);
qd
->
buddies
=
g_list_remove
(
qd
->
buddies
,
p
);
name
=
uid_to_purple_name
(
p
->
uid
);
b
=
purple_find_buddy
(
account
,
name
);
if
(
b
!=
NULL
)
b
->
proto_data
=
NULL
;
else
purple_debug
(
PURPLE_DEBUG_INFO
,
"QQ"
,
"qq_buddy %s not found in purple proto_data
\n
"
,
name
);
g_free
(
name
);
g_free
(
p
);
i
++
;
}
purple_debug
(
PURPLE_DEBUG_INFO
,
"QQ"
,
"%d qq_buddy structures are freed!
\n
"
,
i
);
}