qulogic/pidgin
Clone
Summary
Browse
Changes
Graph
Merge 5b5516d9a5dbbd6e534eba231284bbd1c4c16f57 to fix package_version.h
next.minor
2012-06-13, Hg Conversion
53986e2d3f2e
Merge 5b5516d9a5dbbd6e534eba231284bbd1c4c16f57 to fix package_version.h
/**
* @file session.c MSN session functions
*
* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
"internal.h"
#include
"debug.h"
#include
"error.h"
#include
"msnutils.h"
#include
"session.h"
#include
"notification.h"
#include
"oim.h"
MsnSession
*
msn_session_new
(
PurpleAccount
*
account
)
{
MsnSession
*
session
;
g_return_val_if_fail
(
account
!=
NULL
,
NULL
);
session
=
g_new0
(
MsnSession
,
1
);
session
->
account
=
account
;
session
->
notification
=
msn_notification_new
(
session
);
session
->
userlist
=
msn_userlist_new
(
session
);
session
->
user
=
msn_user_new
(
session
->
userlist
,
purple_account_get_username
(
account
),
NULL
);
msn_userlist_add_user
(
session
->
userlist
,
session
->
user
);
session
->
oim
=
msn_oim_new
(
session
);
session
->
protocol_ver
=
0
;
session
->
enable_mpop
=
TRUE
;
/* Default only */
session
->
guid
=
rand_guid
();
return
session
;
}
void
msn_session_destroy
(
MsnSession
*
session
)
{
g_return_if_fail
(
session
!=
NULL
);
session
->
destroying
=
TRUE
;
while
(
session
->
url_datas
)
{
purple_util_fetch_url_cancel
(
session
->
url_datas
->
data
);
session
->
url_datas
=
g_slist_delete_link
(
session
->
url_datas
,
session
->
url_datas
);
}
if
(
session
->
connected
)
msn_session_disconnect
(
session
);
if
(
session
->
soap_cleanup_handle
)
purple_timeout_remove
(
session
->
soap_cleanup_handle
);
if
(
session
->
soap_table
!=
NULL
)
g_hash_table_destroy
(
session
->
soap_table
);
while
(
session
->
slplinks
!=
NULL
)
msn_slplink_unref
(
session
->
slplinks
->
data
);
while
(
session
->
switches
!=
NULL
)
msn_switchboard_destroy
(
session
->
switches
->
data
);
if
(
session
->
oim
!=
NULL
)
msn_oim_destroy
(
session
->
oim
);
if
(
session
->
nexus
!=
NULL
)
msn_nexus_destroy
(
session
->
nexus
);
if
(
session
->
user
!=
NULL
)
msn_user_unref
(
session
->
user
);
if
(
session
->
notification
!=
NULL
)
msn_notification_destroy
(
session
->
notification
);
msn_userlist_destroy
(
session
->
userlist
);
g_free
(
session
->
psm
);
g_free
(
session
->
guid
);
g_free
(
session
->
abch_cachekey
);
#if 0
g_free(session->blocked_text);
#endif
g_free
(
session
->
passport_info
.
sid
);
g_free
(
session
->
passport_info
.
mspauth
);
g_free
(
session
->
passport_info
.
client_ip
);
g_free
(
session
->
passport_info
.
mail_url
);
g_free
(
session
);
}
gboolean
msn_session_connect
(
MsnSession
*
session
,
const
char
*
host
,
int
port
,
gboolean
http_method
)
{
g_return_val_if_fail
(
session
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
!
session
->
connected
,
TRUE
);
session
->
connected
=
TRUE
;
session
->
http_method
=
http_method
;
if
(
session
->
notification
==
NULL
)
{
purple_debug_error
(
"msn"
,
"This shouldn't happen
\n
"
);
g_return_val_if_reached
(
FALSE
);
}
return
msn_notification_connect
(
session
->
notification
,
host
,
port
);
}
void
msn_session_disconnect
(
MsnSession
*
session
)
{
g_return_if_fail
(
session
!=
NULL
);
if
(
!
session
->
connected
)
return
;
if
(
session
->
login_timeout
)
{
purple_timeout_remove
(
session
->
login_timeout
);
session
->
login_timeout
=
0
;
}
session
->
connected
=
FALSE
;
while
(
session
->
switches
!=
NULL
)
msn_switchboard_close
(
session
->
switches
->
data
);
if
(
session
->
notification
!=
NULL
)
msn_notification_close
(
session
->
notification
);
}
/* TODO: This must go away when conversation is redesigned */
MsnSwitchBoard
*
msn_session_find_swboard
(
MsnSession
*
session
,
const
char
*
username
)
{
GList
*
l
;
g_return_val_if_fail
(
session
!=
NULL
,
NULL
);
g_return_val_if_fail
(
username
!=
NULL
,
NULL
);
for
(
l
=
session
->
switches
;
l
!=
NULL
;
l
=
l
->
next
)
{
MsnSwitchBoard
*
swboard
;
swboard
=
l
->
data
;
if
((
swboard
->
im_user
!=
NULL
)
&&
!
strcmp
(
username
,
swboard
->
im_user
))
return
swboard
;
}
return
NULL
;
}
static
PurpleConversation
*
msn_session_get_conv
(
MsnSession
*
session
,
const
char
*
passport
)
{
PurpleAccount
*
account
;
PurpleConversation
*
conv
;
g_return_val_if_fail
(
session
!=
NULL
,
NULL
);
account
=
session
->
account
;
conv
=
purple_find_conversation_with_account
(
PURPLE_CONV_TYPE_IM
,
passport
,
account
);
if
(
conv
==
NULL
){
conv
=
purple_conversation_new
(
PURPLE_CONV_TYPE_IM
,
account
,
passport
);
}
return
conv
;
}
/* put Message to User Conversation
*
* passport - the one want to talk to you
*/
void
msn_session_report_user
(
MsnSession
*
session
,
const
char
*
passport
,
const
char
*
msg
,
PurpleMessageFlags
flags
)
{
PurpleConversation
*
conv
;
if
((
conv
=
msn_session_get_conv
(
session
,
passport
))
!=
NULL
){
purple_conversation_write
(
conv
,
NULL
,
msg
,
flags
,
time
(
NULL
));
}
}
MsnSwitchBoard
*
msn_session_find_swboard_with_conv
(
MsnSession
*
session
,
PurpleConversation
*
conv
)
{
GList
*
l
;
g_return_val_if_fail
(
session
!=
NULL
,
NULL
);
g_return_val_if_fail
(
conv
!=
NULL
,
NULL
);
for
(
l
=
session
->
switches
;
l
!=
NULL
;
l
=
l
->
next
)
{
MsnSwitchBoard
*
swboard
;
swboard
=
l
->
data
;
if
(
swboard
->
conv
==
conv
)
return
swboard
;
}
return
NULL
;
}
MsnSwitchBoard
*
msn_session_find_swboard_with_id
(
const
MsnSession
*
session
,
int
chat_id
)
{
GList
*
l
;
g_return_val_if_fail
(
session
!=
NULL
,
NULL
);
g_return_val_if_fail
(
chat_id
>=
0
,
NULL
);
for
(
l
=
session
->
switches
;
l
!=
NULL
;
l
=
l
->
next
)
{
MsnSwitchBoard
*
swboard
;
swboard
=
l
->
data
;
if
(
swboard
->
chat_id
==
chat_id
)
return
swboard
;
}
return
NULL
;
}
MsnSwitchBoard
*
msn_session_get_swboard
(
MsnSession
*
session
,
const
char
*
username
,
MsnSBFlag
flag
)
{
MsnSwitchBoard
*
swboard
;
g_return_val_if_fail
(
session
!=
NULL
,
NULL
);
swboard
=
msn_session_find_swboard
(
session
,
username
);
if
(
swboard
==
NULL
)
{
swboard
=
msn_switchboard_new
(
session
);
swboard
->
im_user
=
g_strdup
(
username
);
msn_switchboard_request
(
swboard
);
msn_switchboard_request_add_user
(
swboard
,
username
);
}
swboard
->
flag
|=
flag
;
return
swboard
;
}
static
gboolean
msn_login_timeout_cb
(
gpointer
data
)
{
MsnSession
*
session
=
data
;
/* This forces the login process to finish, even though we haven't heard
a response for our FQY requests yet. We'll at least end up online to the
people we've already added. The rest will follow later. */
msn_session_finish_login
(
session
);
session
->
login_timeout
=
0
;
return
FALSE
;
}
void
msn_session_activate_login_timeout
(
MsnSession
*
session
)
{
if
(
!
session
->
logged_in
&&
session
->
connected
)
{
session
->
login_timeout
=
purple_timeout_add_seconds
(
MSN_LOGIN_FQY_TIMEOUT
,
msn_login_timeout_cb
,
session
);
}
}
static
void
msn_session_sync_users
(
MsnSession
*
session
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
session
->
account
);
GList
*
to_remove
=
NULL
;
GSList
*
buddies
;
g_return_if_fail
(
gc
!=
NULL
);
/* The core used to use msn_add_buddy to add all buddies before
* being logged in. This no longer happens, so we manually iterate
* over the whole buddy list to identify sync issues.
*/
for
(
buddies
=
purple_find_buddies
(
session
->
account
,
NULL
);
buddies
;
buddies
=
g_slist_delete_link
(
buddies
,
buddies
))
{
PurpleBuddy
*
buddy
=
buddies
->
data
;
const
gchar
*
buddy_name
=
purple_buddy_get_name
(
buddy
);
const
gchar
*
group_name
=
purple_group_get_name
(
purple_buddy_get_group
(
buddy
));
MsnUser
*
remote_user
;
gboolean
found
=
FALSE
;
remote_user
=
msn_userlist_find_user
(
session
->
userlist
,
buddy_name
);
if
(
remote_user
&&
remote_user
->
list_op
&
MSN_LIST_FL_OP
)
{
GList
*
l
;
for
(
l
=
remote_user
->
group_ids
;
l
;
l
=
l
->
next
)
{
const
char
*
name
=
msn_userlist_find_group_name
(
remote_user
->
userlist
,
l
->
data
);
if
(
name
&&
!
g_ascii_strcasecmp
(
group_name
,
name
))
{
found
=
TRUE
;
break
;
}
}
/* We don't care if they're in a different group, as long as they're on the
* list somewhere. If we check for the group, we cause pain, agony and
* suffering for people who decide to re-arrange their buddy list elsewhere.
*/
if
(
!
found
)
{
if
((
remote_user
==
NULL
)
||
!
(
remote_user
->
list_op
&
MSN_LIST_FL_OP
))
{
/* The user is not on the server list */
msn_error_sync_issue
(
session
,
buddy_name
,
group_name
);
}
else
{
/* The user is not in that group on the server list */
to_remove
=
g_list_prepend
(
to_remove
,
buddy
);
}
}
}
}
if
(
to_remove
!=
NULL
)
{
g_list_foreach
(
to_remove
,
(
GFunc
)
purple_blist_remove_buddy
,
NULL
);
g_list_free
(
to_remove
);
}
}
void
msn_session_set_error
(
MsnSession
*
session
,
MsnErrorType
error
,
const
char
*
info
)
{
PurpleConnection
*
gc
;
PurpleConnectionError
reason
;
char
*
msg
;
if
(
session
->
destroying
)
return
;
gc
=
purple_account_get_connection
(
session
->
account
);
switch
(
error
)
{
case
MSN_ERROR_SERVCONN
:
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
msg
=
g_strdup
(
info
);
break
;
case
MSN_ERROR_UNSUPPORTED_PROTOCOL
:
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
msg
=
g_strdup
(
_
(
"Our protocol is not supported by the "
"server"
));
break
;
case
MSN_ERROR_HTTP_MALFORMED
:
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
msg
=
g_strdup
(
_
(
"Error parsing HTTP"
));
break
;
case
MSN_ERROR_SIGN_OTHER
:
reason
=
PURPLE_CONNECTION_ERROR_NAME_IN_USE
;
msg
=
g_strdup
(
_
(
"You have signed on from another location"
));
if
(
!
purple_account_get_remember_password
(
session
->
account
))
purple_account_set_password
(
session
->
account
,
NULL
);
break
;
case
MSN_ERROR_SERV_UNAVAILABLE
:
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
msg
=
g_strdup
(
_
(
"The MSN servers are temporarily "
"unavailable. Please wait and try "
"again."
));
break
;
case
MSN_ERROR_SERV_DOWN
:
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
msg
=
g_strdup
(
_
(
"The MSN servers are going down "
"temporarily"
));
break
;
case
MSN_ERROR_AUTH
:
reason
=
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
;
msg
=
g_strdup_printf
(
_
(
"Unable to authenticate: %s"
),
(
info
==
NULL
)
?
_
(
"Unknown error"
)
:
info
);
/* Clear the password if it isn't being saved */
if
(
!
purple_account_get_remember_password
(
session
->
account
))
purple_account_set_password
(
session
->
account
,
NULL
);
break
;
case
MSN_ERROR_BAD_BLIST
:
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
msg
=
g_strdup
(
_
(
"Your MSN buddy list is temporarily "
"unavailable. Please wait and try "
"again."
));
break
;
default
:
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
msg
=
g_strdup
(
_
(
"Unknown error"
));
break
;
}
msn_session_disconnect
(
session
);
purple_connection_error_reason
(
gc
,
reason
,
msg
);
g_free
(
msg
);
}
static
const
char
*
get_login_step_text
(
MsnSession
*
session
)
{
const
char
*
steps_text
[]
=
{
_
(
"Connecting"
),
_
(
"Handshaking"
),
_
(
"Transferring"
),
_
(
"Handshaking"
),
_
(
"Starting authentication"
),
_
(
"Getting cookie"
),
_
(
"Authenticating"
),
_
(
"Sending cookie"
),
_
(
"Retrieving buddy list"
)
};
return
steps_text
[
session
->
login_step
];
}
void
msn_session_set_login_step
(
MsnSession
*
session
,
MsnLoginStep
step
)
{
PurpleConnection
*
gc
;
/* Prevent the connection progress going backwards, eg. if we get
* transferred several times during login */
if
(
session
->
login_step
>=
step
)
return
;
/* If we're already logged in, we're probably here because of a
* mid-session XFR from the notification server, so we don't want to
* popup the connection progress dialog */
if
(
session
->
logged_in
)
return
;
gc
=
session
->
account
->
gc
;
session
->
login_step
=
step
;
purple_connection_update_progress
(
gc
,
get_login_step_text
(
session
),
step
,
MSN_LOGIN_STEPS
);
}
void
msn_session_finish_login
(
MsnSession
*
session
)
{
PurpleAccount
*
account
;
PurpleConnection
*
gc
;
PurpleStoredImage
*
img
;
if
(
!
session
->
logged_in
)
{
account
=
session
->
account
;
gc
=
purple_account_get_connection
(
account
);
img
=
purple_buddy_icons_find_account_icon
(
session
->
account
);
/* TODO: Do we really want to call this if img is NULL? */
msn_user_set_buddy_icon
(
session
->
user
,
img
);
if
(
img
!=
NULL
)
purple_imgstore_unref
(
img
);
session
->
logged_in
=
TRUE
;
purple_connection_set_state
(
gc
,
PURPLE_CONNECTED
);
/* Sync users */
msn_session_sync_users
(
session
);
}
if
(
session
->
protocol_ver
>=
16
)
{
/* TODO: Send this when updating status instead? */
msn_notification_send_uux_endpointdata
(
session
);
msn_notification_send_uux_private_endpointdata
(
session
);
}
msn_change_status
(
session
);
}