pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
closing merged branch
memory-leaks
2020-02-03, Gary Kramlich
208e387899a5
closing merged branch
/*
* novell.c
*
* Copyright (c) 2004 Novell, Inc. All Rights Reserved.
*
* 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; version 2 of the License.
*
* 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
"action.h"
#include
"debug.h"
#include
"plugins.h"
#include
"server.h"
#include
"nmuser.h"
#include
"notify.h"
#include
"novell.h"
#include
"purple-gio.h"
#include
"purpleaccountoption.h"
#include
"util.h"
#include
"request.h"
#include
"network.h"
#include
"status.h"
#include
"version.h"
#define DEFAULT_PORT 8300
#define NOVELL_CONNECT_STEPS 4
#define NM_ROOT_FOLDER_NAME "GroupWise Messenger"
#define NOVELL_STATUS_TYPE_AVAILABLE "available"
#define NOVELL_STATUS_TYPE_AWAY "away"
#define NOVELL_STATUS_TYPE_BUSY "busy"
#define NOVELL_STATUS_TYPE_OFFLINE "offline"
#define NOVELL_STATUS_TYPE_IDLE "idle"
#define NOVELL_STATUS_TYPE_APPEAR_OFFLINE "appearoffline"
static
PurpleProtocol
*
my_protocol
=
NULL
;
static
gboolean
_is_disconnect_error
(
NMERR_T
err
);
static
gboolean
_check_for_disconnect
(
NMUser
*
user
,
NMERR_T
err
);
static
void
_send_message
(
NMUser
*
user
,
NMMessage
*
message
);
static
void
_update_buddy_status
(
NMUser
*
user
,
PurpleBuddy
*
buddy
,
int
status
,
int
gmt
);
static
void
_remove_purple_buddies
(
NMUser
*
user
);
static
void
_add_contacts_to_purple_blist
(
NMUser
*
user
,
NMFolder
*
folder
);
static
void
_add_purple_buddies
(
NMUser
*
user
);
static
void
_sync_contact_list
(
NMUser
*
user
);
static
void
_sync_privacy_lists
(
NMUser
*
user
);
static
void
_show_info
(
PurpleConnection
*
gc
,
NMUserRecord
*
user_record
,
char
*
name
);
const
char
*
_get_conference_name
(
int
id
);
/*******************************************************************************
* Response callbacks
*******************************************************************************/
/* Handle login response */
static
void
_login_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
const
char
*
alias
;
NMERR_T
rc
;
if
(
user
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
if
(
gc
==
NULL
)
return
;
if
(
ret_code
==
NM_OK
)
{
/* Set alias for user if not set (use Full Name) */
alias
=
purple_account_get_private_alias
(
user
->
client_data
);
if
(
alias
==
NULL
||
*
alias
==
'\0'
)
{
alias
=
nm_user_record_get_full_name
(
user
->
user_record
);
if
(
alias
)
purple_account_set_private_alias
(
user
->
client_data
,
alias
);
}
/* Tell Purple that we are connected */
purple_connection_set_state
(
gc
,
PURPLE_CONNECTION_CONNECTED
);
_sync_contact_list
(
user
);
rc
=
nm_send_set_status
(
user
,
NM_STATUS_AVAILABLE
,
NULL
,
NULL
,
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
else
{
PurpleConnectionError
reason
;
char
*
err
=
g_strdup_printf
(
_
(
"Unable to login: %s"
),
nm_error_to_string
(
ret_code
));
switch
(
ret_code
)
{
case
NMERR_AUTHENTICATION_FAILED
:
case
NMERR_CREDENTIALS_MISSING
:
case
NMERR_PASSWORD_INVALID
:
/* Don't attempt to auto-reconnect if our
* password was invalid.
*/
if
(
!
purple_account_get_remember_password
(
purple_connection_get_account
(
gc
)))
purple_account_set_password
(
purple_connection_get_account
(
gc
),
NULL
,
NULL
,
NULL
);
reason
=
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
;
break
;
default
:
/* FIXME: There are other reasons login could fail */
reason
=
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
}
purple_connection_error
(
gc
,
reason
,
err
);
g_free
(
err
);
}
}
/* Handle getstatus response*/
static
void
_get_status_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleBuddy
*
buddy
;
GSList
*
buddies
;
GSList
*
bnode
;
NMUserRecord
*
user_record
=
(
NMUserRecord
*
)
resp_data
;
int
status
;
if
(
user
==
NULL
||
user_record
==
NULL
)
return
;
if
(
ret_code
==
NM_OK
)
{
/* Find all Purple buddies and update their statuses */
const
char
*
name
=
nm_user_record_get_display_id
(
user_record
);
if
(
name
)
{
buddies
=
purple_blist_find_buddies
((
PurpleAccount
*
)
user
->
client_data
,
name
);
for
(
bnode
=
buddies
;
bnode
;
bnode
=
bnode
->
next
)
{
buddy
=
(
PurpleBuddy
*
)
bnode
->
data
;
if
(
buddy
)
{
status
=
nm_user_record_get_status
(
user_record
);
_update_buddy_status
(
user
,
buddy
,
status
,
time
(
0
));
}
}
g_slist_free
(
buddies
);
}
}
else
{
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_get_status_resp_cb(): rc = 0x%X
\n
"
,
ret_code
);
}
}
/* Show an error if the rename failed */
static
void
_rename_contact_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
if
(
ret_code
!=
NM_OK
)
{
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_rename_contact_resp_cb(): rc = 0x%X
\n
"
,
ret_code
);
}
}
/* Handle the getdetails response and send the message */
static
void
_get_details_resp_send_msg
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConversation
*
gconv
;
PurpleConnection
*
gc
;
NMUserRecord
*
user_record
=
NULL
;
NMContact
*
cntct
=
NULL
;
NMConference
*
conf
;
NMMessage
*
msg
=
user_data
;
const
char
*
dn
=
NULL
;
const
char
*
name
;
if
(
user
==
NULL
||
msg
==
NULL
)
return
;
if
(
ret_code
==
NM_OK
)
{
user_record
=
(
NMUserRecord
*
)
resp_data
;
if
(
user_record
)
{
/* Set the title for the conversation */
/* XXX - Should this be find_im_with_account? */
gconv
=
purple_conversations_find_with_account
(
nm_user_record_get_display_id
(
user_record
),
(
PurpleAccount
*
)
user
->
client_data
);
if
(
gconv
)
{
dn
=
nm_user_record_get_dn
(
user_record
);
if
(
dn
)
{
cntct
=
nm_find_contact
(
user
,
dn
);
}
if
(
cntct
)
{
purple_conversation_set_title
(
gconv
,
nm_contact_get_display_name
(
cntct
));
}
else
{
/* Not in the contact list, try to user full name */
name
=
(
char
*
)
nm_user_record_get_full_name
(
user_record
);
if
(
name
)
purple_conversation_set_title
(
gconv
,
name
);
}
}
/* Add the user record to particpant list */
conf
=
nm_message_get_conference
(
msg
);
if
(
conf
)
{
nm_conference_add_participant
(
conf
,
user_record
);
_send_message
(
user
,
msg
);
}
}
}
else
{
gc
=
purple_account_get_connection
(
user
->
client_data
);
if
(
gc
!=
NULL
)
{
char
*
err
=
g_strdup_printf
(
_
(
"Unable to send message."
" Could not get details for user (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
nm_release_message
(
msg
);
}
}
/* Set up the new PurpleBuddy based on the response from getdetails */
static
void
_get_details_resp_setup_buddy
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMUserRecord
*
user_record
;
NMContact
*
contact
;
PurpleBuddy
*
buddy
;
const
char
*
alias
;
NMERR_T
rc
=
NM_OK
;
if
(
user
==
NULL
||
resp_data
==
NULL
||
user_data
==
NULL
)
return
;
contact
=
user_data
;
if
(
ret_code
==
NM_OK
)
{
user_record
=
resp_data
;
buddy
=
nm_contact_get_data
(
contact
);
nm_contact_set_user_record
(
contact
,
user_record
);
/* Set the display id */
purple_buddy_set_name
(
buddy
,
nm_user_record_get_display_id
(
user_record
));
alias
=
purple_buddy_get_alias
(
buddy
);
if
(
alias
==
NULL
||
*
alias
==
'\0'
||
purple_strequal
(
alias
,
purple_buddy_get_name
(
buddy
)))
{
purple_buddy_set_local_alias
(
buddy
,
nm_user_record_get_full_name
(
user_record
));
/* Tell the server about the new display name */
rc
=
nm_send_rename_contact
(
user
,
contact
,
nm_user_record_get_full_name
(
user_record
),
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
/* Get initial status for the buddy */
rc
=
nm_send_get_status
(
user
,
resp_data
,
_get_status_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
/* nm_release_contact(contact);*/
}
nm_release_contact
(
contact
);
}
/* Add the new contact into the PurpleBuddy list */
static
void
_create_contact_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMContact
*
tmp_contact
=
(
NMContact
*
)
user_data
;
NMContact
*
new_contact
=
NULL
;
NMFolder
*
folder
=
NULL
;
PurpleGroup
*
group
;
PurpleBuddy
*
buddy
;
const
char
*
folder_name
=
NULL
;
NMERR_T
rc
=
NM_OK
;
if
(
user
==
NULL
)
return
;
if
(
ret_code
==
NM_OK
)
{
new_contact
=
(
NMContact
*
)
resp_data
;
if
(
new_contact
==
NULL
||
tmp_contact
==
NULL
)
return
;
/* Get the userid and folder name for the new contact */
folder
=
nm_find_folder_by_id
(
user
,
nm_contact_get_parent_id
(
new_contact
));
if
(
folder
)
{
folder_name
=
nm_folder_get_name
(
folder
);
}
if
(
folder_name
==
NULL
||
*
folder_name
==
'\0'
)
folder_name
=
NM_ROOT_FOLDER_NAME
;
/* Re-add the buddy now that we got the okay from the server */
group
=
purple_blist_find_group
(
folder_name
);
if
(
group
)
{
const
char
*
alias
=
nm_contact_get_display_name
(
tmp_contact
);
const
char
*
display_id
=
nm_contact_get_display_id
(
new_contact
);
if
(
display_id
==
NULL
)
display_id
=
nm_contact_get_dn
(
new_contact
);
if
(
alias
&&
!
purple_strequal
(
alias
,
display_id
))
{
/* The user requested an alias, tell the server about it. */
rc
=
nm_send_rename_contact
(
user
,
new_contact
,
alias
,
_rename_contact_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
else
{
alias
=
""
;
}
/* Add it to the purple buddy list if it is not there */
buddy
=
purple_blist_find_buddy_in_group
(
user
->
client_data
,
display_id
,
group
);
if
(
buddy
==
NULL
)
{
buddy
=
purple_buddy_new
(
user
->
client_data
,
display_id
,
alias
);
purple_blist_add_buddy
(
buddy
,
NULL
,
group
,
NULL
);
}
/* Save the new buddy as part of the contact object */
nm_contact_set_data
(
new_contact
,
(
gpointer
)
buddy
);
/* We need details for the user before we can setup the
* new Purple buddy. We always call this because the
* 'createcontact' response fields do not always contain
* everything that we need.
*/
nm_contact_add_ref
(
new_contact
);
rc
=
nm_send_get_details
(
user
,
nm_contact_get_dn
(
new_contact
),
_get_details_resp_setup_buddy
,
new_contact
);
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
user
->
client_data
);
const
char
*
name
=
nm_contact_get_dn
(
tmp_contact
);
char
*
err
;
err
=
g_strdup_printf
(
_
(
"Unable to add %s to your buddy list (%s)."
),
name
,
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
if
(
tmp_contact
)
nm_release_contact
(
tmp_contact
);
}
/* Show an error if we failed to send the message */
static
void
_send_message_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
char
*
err
=
NULL
;
if
(
user
==
NULL
)
return
;
if
(
ret_code
!=
NM_OK
)
{
gc
=
purple_account_get_connection
(
user
->
client_data
);
/* TODO: Improve this! message to who or for what conference? */
err
=
g_strdup_printf
(
_
(
"Unable to send message (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
}
/* Show an error if the remove failed */
static
void
_remove_contact_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
if
(
ret_code
!=
NM_OK
)
{
/* TODO: Display an error? */
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_remove_contact_resp_cb(): rc = 0x%x
\n
"
,
ret_code
);
}
}
/* Show an error if the remove failed */
static
void
_remove_folder_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
if
(
ret_code
!=
NM_OK
)
{
/* TODO: Display an error? */
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_remove_folder_resp_cb(): rc = 0x%x
\n
"
,
ret_code
);
}
}
/* Show an error if the move failed */
static
void
_move_contact_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
if
(
ret_code
!=
NM_OK
)
{
/* TODO: Display an error? */
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_move_contact_resp_cb(): rc = 0x%x
\n
"
,
ret_code
);
}
}
/* Show an error if the rename failed */
static
void
_rename_folder_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
if
(
ret_code
!=
NM_OK
)
{
/* TODO: Display an error? */
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_rename_folder_resp_cb(): rc = 0x%x
\n
"
,
ret_code
);
}
}
static
void
_sendinvite_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
char
*
err
;
PurpleConnection
*
gc
;
if
(
user
==
NULL
)
return
;
if
(
ret_code
!=
NM_OK
)
{
gc
=
purple_account_get_connection
(
user
->
client_data
);
err
=
g_strdup_printf
(
_
(
"Unable to invite user (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_sendinvite_resp_cb(): rc = 0x%x
\n
"
,
ret_code
);
}
}
/* If the createconf was successful attempt to send the message,
* otherwise display an error message to the user.
*/
static
void
_createconf_resp_send_msg
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMConference
*
conf
;
NMMessage
*
msg
=
user_data
;
if
(
user
==
NULL
||
msg
==
NULL
)
return
;
if
(
ret_code
==
NM_OK
)
{
_send_message
(
user
,
msg
);
}
else
{
if
((
conf
=
nm_message_get_conference
(
msg
)))
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
user
->
client_data
);
const
char
*
name
=
NULL
;
char
*
err
;
NMUserRecord
*
ur
;
ur
=
nm_conference_get_participant
(
conf
,
0
);
if
(
ur
)
name
=
nm_user_record_get_userid
(
ur
);
if
(
name
)
err
=
g_strdup_printf
(
_
(
"Unable to send message to %s."
" Could not create the conference (%s)."
),
name
,
nm_error_to_string
(
ret_code
));
else
err
=
g_strdup_printf
(
_
(
"Unable to send message."
" Could not create the conference (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
nm_release_message
(
msg
);
}
}
/* Move contact to newly created folder */
static
void
_create_folder_resp_move_contact
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMContact
*
contact
=
user_data
;
NMFolder
*
new_folder
;
char
*
folder_name
=
resp_data
;
NMERR_T
rc
=
NM_OK
;
if
(
user
==
NULL
||
folder_name
==
NULL
||
contact
==
NULL
)
{
g_free
(
folder_name
);
return
;
}
if
(
ret_code
==
NM_OK
||
ret_code
==
NMERR_DUPLICATE_FOLDER
)
{
new_folder
=
nm_find_folder
(
user
,
folder_name
);
if
(
new_folder
)
{
/* Tell the server to move the contact to the new folder */
/* rc = nm_send_move_contact(user, contact, new_folder,
_move_contact_resp_cb, NULL); */
rc
=
nm_send_create_contact
(
user
,
new_folder
,
contact
,
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
user
->
client_data
);
char
*
err
=
g_strdup_printf
(
_
(
"Unable to move user %s"
" to folder %s in the server side list."
" Error while creating folder (%s)."
),
nm_contact_get_dn
(
contact
),
folder_name
,
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
g_free
(
folder_name
);
}
/* Add contact to newly create folder */
static
void
_create_folder_resp_add_contact
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMContact
*
contact
=
(
NMContact
*
)
user_data
;
NMFolder
*
folder
;
char
*
folder_name
=
(
char
*
)
resp_data
;
NMERR_T
rc
=
NM_OK
;
if
(
user
==
NULL
||
folder_name
==
NULL
||
contact
==
NULL
)
{
if
(
contact
)
nm_release_contact
(
contact
);
g_free
(
folder_name
);
return
;
}
if
(
ret_code
==
NM_OK
||
ret_code
==
NMERR_DUPLICATE_FOLDER
)
{
folder
=
nm_find_folder
(
user
,
folder_name
);
if
(
folder
)
{
rc
=
nm_send_create_contact
(
user
,
folder
,
contact
,
_create_contact_resp_cb
,
contact
);
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
user
->
client_data
);
const
char
*
name
=
nm_contact_get_dn
(
contact
);
char
*
err
=
g_strdup_printf
(
_
(
"Unable to add %s to your buddy list."
" Error creating folder in server side list (%s)."
),
name
,
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
nm_release_contact
(
contact
);
g_free
(
err
);
}
g_free
(
folder_name
);
}
static
void
_join_conf_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleChatConversation
*
chat
;
PurpleConnection
*
gc
;
NMUserRecord
*
ur
;
NMConference
*
conference
=
user_data
;
const
char
*
name
,
*
conf_name
;
int
i
,
count
;
if
(
user
==
NULL
||
conference
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
if
(
ret_code
==
NM_OK
)
{
conf_name
=
_get_conference_name
(
++
user
->
conference_count
);
chat
=
purple_serv_got_joined_chat
(
gc
,
user
->
conference_count
,
conf_name
);
if
(
chat
)
{
nm_conference_set_data
(
conference
,
(
gpointer
)
chat
);
count
=
nm_conference_get_participant_count
(
conference
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
ur
=
nm_conference_get_participant
(
conference
,
i
);
if
(
ur
)
{
name
=
nm_user_record_get_display_id
(
ur
);
purple_chat_conversation_add_user
(
chat
,
name
,
NULL
,
PURPLE_CHAT_USER_NONE
,
TRUE
);
}
}
}
}
}
/* Show info returned by getdetails */
static
void
_get_details_resp_show_info
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
NMUserRecord
*
user_record
;
char
*
name
;
char
*
err
;
if
(
user
==
NULL
)
return
;
name
=
user_data
;
if
(
ret_code
==
NM_OK
)
{
user_record
=
(
NMUserRecord
*
)
resp_data
;
if
(
user_record
)
{
_show_info
(
purple_account_get_connection
(
user
->
client_data
),
user_record
,
g_strdup
(
name
));
}
}
else
{
gc
=
purple_account_get_connection
(
user
->
client_data
);
err
=
g_strdup_printf
(
_
(
"Could not get details for user %s (%s)."
),
name
,
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
g_free
(
name
);
}
/* Handle get details response add to privacy list */
static
void
_get_details_resp_add_privacy_item
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
PurpleAccount
*
account
;
NMUserRecord
*
user_record
=
resp_data
;
char
*
err
;
gboolean
allowed
=
GPOINTER_TO_INT
(
user_data
);
const
char
*
display_id
;
if
(
user
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
display_id
=
nm_user_record_get_display_id
(
user_record
);
account
=
purple_connection_get_account
(
gc
);
if
(
ret_code
==
NM_OK
)
{
if
(
allowed
)
{
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_denied
(
account
),
display_id
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_permit_add
(
account
,
display_id
,
TRUE
);
}
}
else
{
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_denied
(
account
),
display_id
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_deny_add
(
account
,
display_id
,
TRUE
);
}
}
}
else
{
err
=
g_strdup_printf
(
_
(
"Unable to add user to privacy list (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
}
/* Handle response to create privacy item request */
static
void
_create_privacy_item_deny_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
PurpleAccount
*
account
;
NMUserRecord
*
user_record
;
char
*
who
=
user_data
;
char
*
err
;
NMERR_T
rc
=
NM_OK
;
const
char
*
display_id
=
NULL
;
if
(
user
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
account
=
purple_connection_get_account
(
gc
);
if
(
ret_code
==
NM_OK
)
{
user_record
=
nm_find_user_record
(
user
,
who
);
if
(
user_record
)
display_id
=
nm_user_record_get_display_id
(
user_record
);
if
(
display_id
)
{
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_denied
(
account
),
display_id
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_deny_add
(
account
,
display_id
,
TRUE
);
}
}
else
{
rc
=
nm_send_get_details
(
user
,
who
,
_get_details_resp_add_privacy_item
,
GINT_TO_POINTER
(
FALSE
));
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
err
=
g_strdup_printf
(
_
(
"Unable to add %s to deny list (%s)."
),
who
,
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
g_free
(
who
);
}
/* Handle response to create privacy item request */
static
void
_create_privacy_item_permit_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
PurpleAccount
*
account
;
NMUserRecord
*
user_record
;
char
*
who
=
user_data
;
char
*
err
;
NMERR_T
rc
=
NM_OK
;
const
char
*
display_id
=
NULL
;
if
(
user
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
account
=
purple_connection_get_account
(
gc
);
if
(
ret_code
==
NM_OK
)
{
user_record
=
nm_find_user_record
(
user
,
who
);
if
(
user_record
)
display_id
=
nm_user_record_get_display_id
(
user_record
);
if
(
display_id
)
{
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_permitted
(
account
),
display_id
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_permit_add
(
account
,
display_id
,
TRUE
);
}
}
else
{
rc
=
nm_send_get_details
(
user
,
who
,
_get_details_resp_add_privacy_item
,
GINT_TO_POINTER
(
TRUE
));
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
err
=
g_strdup_printf
(
_
(
"Unable to add %s to permit list (%s)."
),
who
,
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
g_free
(
who
);
}
static
void
_get_details_send_privacy_create
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMERR_T
rc
=
NM_OK
;
PurpleConnection
*
gc
;
NMUserRecord
*
user_record
=
resp_data
;
char
*
err
;
gboolean
allowed
=
GPOINTER_TO_INT
(
user_data
);
const
char
*
dn
,
*
display_id
;
if
(
user
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
dn
=
nm_user_record_get_dn
(
user_record
);
display_id
=
nm_user_record_get_display_id
(
user_record
);
if
(
ret_code
==
NM_OK
)
{
if
(
allowed
)
{
rc
=
nm_send_create_privacy_item
(
user
,
dn
,
TRUE
,
_create_privacy_item_permit_resp_cb
,
g_strdup
(
display_id
));
_check_for_disconnect
(
user
,
rc
);
}
else
{
rc
=
nm_send_create_privacy_item
(
user
,
dn
,
FALSE
,
_create_privacy_item_deny_resp_cb
,
g_strdup
(
display_id
));
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
err
=
g_strdup_printf
(
_
(
"Unable to add user to privacy list (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
}
static
void
_remove_privacy_item_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
char
*
who
=
user_data
;
char
*
err
;
if
(
user
==
NULL
)
return
;
if
(
ret_code
!=
NM_OK
)
{
gc
=
purple_account_get_connection
(
user
->
client_data
);
err
=
g_strdup_printf
(
_
(
"Unable to remove %s from privacy list (%s)."
),
who
,
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
g_free
(
who
);
}
static
void
_set_privacy_default_resp_cb
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
PurpleConnection
*
gc
;
char
*
err
;
if
(
user
==
NULL
)
return
;
if
(
ret_code
!=
NM_OK
)
{
gc
=
purple_account_get_connection
(
user
->
client_data
);
err
=
g_strdup_printf
(
_
(
"Unable to change server side privacy settings (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
}
/* Handle get details response add to privacy list */
static
void
_get_details_resp_send_invite
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMERR_T
rc
=
NM_OK
;
PurpleConnection
*
gc
;
NMUserRecord
*
user_record
=
resp_data
;
char
*
err
;
GSList
*
cnode
;
NMConference
*
conference
;
gpointer
chat
;
int
id
=
GPOINTER_TO_INT
(
user_data
);
if
(
user
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
if
(
ret_code
==
NM_OK
)
{
for
(
cnode
=
user
->
conferences
;
cnode
!=
NULL
;
cnode
=
cnode
->
next
)
{
conference
=
cnode
->
data
;
if
(
conference
&&
(
chat
=
nm_conference_get_data
(
conference
)))
{
if
(
purple_chat_conversation_get_id
(
PURPLE_CHAT_CONVERSATION
(
chat
))
==
id
)
{
rc
=
nm_send_conference_invite
(
user
,
conference
,
user_record
,
NULL
,
_sendinvite_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
break
;
}
}
}
}
else
{
err
=
g_strdup_printf
(
_
(
"Unable to invite user (%s)."
),
nm_error_to_string
(
ret_code
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
}
static
void
_createconf_resp_send_invite
(
NMUser
*
user
,
NMERR_T
ret_code
,
gpointer
resp_data
,
gpointer
user_data
)
{
NMERR_T
rc
=
NM_OK
;
NMConference
*
conference
=
resp_data
;
NMUserRecord
*
user_record
=
user_data
;
PurpleConnection
*
gc
;
char
*
err
;
if
(
user
==
NULL
)
return
;
if
(
ret_code
==
NM_OK
)
{
rc
=
nm_send_conference_invite
(
user
,
conference
,
user_record
,
NULL
,
_sendinvite_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
else
{
err
=
g_strdup_printf
(
_
(
"Unable to create conference (%s)."
),
nm_error_to_string
(
ret_code
));
gc
=
purple_account_get_connection
(
user
->
client_data
);
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
}
/*******************************************************************************
* Helper functions
******************************************************************************/
static
char
*
_user_agent_string
(
void
)
{
#if !defined(_WIN32)
const
char
*
sysname
=
""
;
const
char
*
release
=
""
;
struct
utsname
u
;
if
(
uname
(
&
u
)
==
0
)
{
sysname
=
u
.
sysname
;
release
=
u
.
release
;
}
else
{
sysname
=
"Linux"
;
release
=
"Unknown"
;
}
return
g_strdup_printf
(
"Purple/%s (%s; %s)"
,
VERSION
,
sysname
,
release
);
#else
const
char
*
sysname
=
""
;
OSVERSIONINFO
os_info
;
SYSTEM_INFO
sys_info
;
os_info
.
dwOSVersionInfoSize
=
sizeof
(
OSVERSIONINFO
);
GetVersionEx
(
&
os_info
);
GetSystemInfo
(
&
sys_info
);
if
(
os_info
.
dwPlatformId
==
VER_PLATFORM_WIN32_NT
)
{
switch
(
os_info
.
dwMajorVersion
)
{
case
3
:
case
4
:
sysname
=
"Windows NT"
;
break
;
case
5
:
switch
(
os_info
.
dwMinorVersion
)
{
case
0
:
sysname
=
"Windows 2000"
;
break
;
case
1
:
sysname
=
"Windows XP"
;
break
;
case
2
:
sysname
=
"Windows Server 2003"
;
break
;
default
:
sysname
=
"Windows"
;
break
;
}
break
;
default
:
sysname
=
"Windows"
;
break
;
}
}
else
if
(
os_info
.
dwPlatformId
==
VER_PLATFORM_WIN32_WINDOWS
)
{
switch
(
os_info
.
dwMinorVersion
)
{
case
0
:
sysname
=
"Windows 95"
;
break
;
case
10
:
sysname
=
"Windows 98"
;
break
;
case
90
:
sysname
=
"Windows ME"
;
break
;
default
:
sysname
=
"Windows"
;
break
;
}
}
else
{
sysname
=
"Windows"
;
}
return
g_strdup_printf
(
"Purple/%s (%s; %ld.%ld)"
,
VERSION
,
sysname
,
os_info
.
dwMajorVersion
,
os_info
.
dwMinorVersion
);
#endif
}
static
gboolean
_is_disconnect_error
(
NMERR_T
err
)
{
return
(
err
==
NMERR_TCP_WRITE
||
err
==
NMERR_TCP_READ
||
err
==
NMERR_PROTOCOL
);
}
static
gboolean
_check_for_disconnect
(
NMUser
*
user
,
NMERR_T
err
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
user
->
client_data
);
if
(
_is_disconnect_error
(
err
))
{
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Error communicating with server. Closing connection."
));
return
TRUE
;
}
return
FALSE
;
}
/* Check to see if the conference is instantiated, if so send the message.
* If not send the create conference -- the response handler for the createconf
* will call this function again.
*/
static
void
_send_message
(
NMUser
*
user
,
NMMessage
*
message
)
{
NMConference
*
conf
;
NMERR_T
rc
=
NM_OK
;
conf
=
nm_message_get_conference
(
message
);
if
(
conf
)
{
/* We have a conference make sure that the
server knows about it already. */
if
(
nm_conference_is_instantiated
(
conf
))
{
/* We have everything that we need...finally! */
rc
=
nm_send_message
(
user
,
message
,
_send_message_resp_cb
);
_check_for_disconnect
(
user
,
rc
);
nm_release_message
(
message
);
}
else
{
rc
=
nm_send_create_conference
(
user
,
conf
,
_createconf_resp_send_msg
,
message
);
_check_for_disconnect
(
user
,
rc
);
}
}
}
/*
* Update the status of the given buddy in the Purple buddy list
*/
static
void
_update_buddy_status
(
NMUser
*
user
,
PurpleBuddy
*
buddy
,
int
novellstatus
,
int
gmt
)
{
PurpleAccount
*
account
;
const
char
*
status_id
;
const
char
*
text
=
NULL
;
const
char
*
dn
;
const
char
*
name
;
int
idle
=
0
;
account
=
purple_buddy_get_account
(
buddy
);
name
=
purple_buddy_get_name
(
buddy
);
switch
(
novellstatus
)
{
case
NM_STATUS_AVAILABLE
:
status_id
=
NOVELL_STATUS_TYPE_AVAILABLE
;
break
;
case
NM_STATUS_AWAY
:
status_id
=
NOVELL_STATUS_TYPE_AWAY
;
break
;
case
NM_STATUS_BUSY
:
status_id
=
NOVELL_STATUS_TYPE_BUSY
;
break
;
case
NM_STATUS_OFFLINE
:
status_id
=
NOVELL_STATUS_TYPE_OFFLINE
;
break
;
case
NM_STATUS_AWAY_IDLE
:
status_id
=
NOVELL_STATUS_TYPE_AWAY
;
idle
=
gmt
;
break
;
default
:
status_id
=
NOVELL_STATUS_TYPE_OFFLINE
;
break
;
}
/* Get status text for the user */
dn
=
nm_lookup_dn
(
user
,
name
);
if
(
dn
)
{
NMUserRecord
*
user_record
=
nm_find_user_record
(
user
,
dn
);
if
(
user_record
)
{
text
=
nm_user_record_get_status_text
(
user_record
);
}
}
purple_protocol_got_user_status
(
account
,
name
,
status_id
,
"message"
,
text
,
NULL
);
purple_protocol_got_user_idle
(
account
,
name
,
(
novellstatus
==
NM_STATUS_AWAY_IDLE
),
idle
);
}
/* Iterate through the cached Purple buddy list and remove buddies
* that are not in the server side list.
*/
static
void
_remove_purple_buddies
(
NMUser
*
user
)
{
PurpleBlistNode
*
gnode
;
PurpleBlistNode
*
cnode
;
PurpleBlistNode
*
bnode
;
PurpleGroup
*
group
;
PurpleBuddy
*
buddy
;
GSList
*
rem_list
=
NULL
;
NMFolder
*
folder
=
NULL
;
const
char
*
gname
=
NULL
;
for
(
gnode
=
purple_blist_get_default_root
();
gnode
;
gnode
=
purple_blist_node_get_sibling_next
(
gnode
))
{
if
(
!
PURPLE_IS_GROUP
(
gnode
))
continue
;
group
=
(
PurpleGroup
*
)
gnode
;
gname
=
purple_group_get_name
(
group
);
for
(
cnode
=
purple_blist_node_get_first_child
(
gnode
);
cnode
;
cnode
=
purple_blist_node_get_sibling_next
(
cnode
))
{
if
(
!
PURPLE_IS_CONTACT
(
cnode
))
continue
;
for
(
bnode
=
purple_blist_node_get_first_child
(
cnode
);
bnode
;
bnode
=
purple_blist_node_get_sibling_next
(
bnode
))
{
if
(
!
PURPLE_IS_BUDDY
(
bnode
))
continue
;
buddy
=
(
PurpleBuddy
*
)
bnode
;
if
(
purple_buddy_get_account
(
buddy
)
==
user
->
client_data
)
{
if
(
purple_strequal
(
gname
,
NM_ROOT_FOLDER_NAME
))
gname
=
""
;
folder
=
nm_find_folder
(
user
,
gname
);
if
(
folder
==
NULL
||
!
nm_folder_find_contact_by_display_id
(
folder
,
purple_buddy_get_name
(
buddy
)))
{
rem_list
=
g_slist_append
(
rem_list
,
buddy
);
}
}
}
}
}
g_slist_free_full
(
rem_list
,
(
GDestroyNotify
)
purple_blist_remove_buddy
);
}
/* Add all of the contacts in the given folder to the Purple buddy list */
static
void
_add_contacts_to_purple_blist
(
NMUser
*
user
,
NMFolder
*
folder
)
{
NMUserRecord
*
user_record
=
NULL
;
NMContact
*
contact
=
NULL
;
PurpleBuddy
*
buddy
=
NULL
;
PurpleGroup
*
group
;
NMERR_T
cnt
=
0
,
i
;
const
char
*
name
=
NULL
;
const
char
*
fname
=
NULL
;
int
status
=
0
;
/* If this is the root folder give it a name. Purple does not have the concept of
* a root folder.
*/
fname
=
nm_folder_get_name
(
folder
);
if
(
fname
==
NULL
||
*
fname
==
'\0'
)
{
fname
=
NM_ROOT_FOLDER_NAME
;
}
/* Does the Purple group exist already? */
group
=
purple_blist_find_group
(
fname
);
if
(
group
==
NULL
)
{
group
=
purple_group_new
(
fname
);
purple_blist_add_group
(
group
,
NULL
);
}
/* Get each contact for this folder */
cnt
=
nm_folder_get_contact_count
(
folder
);
for
(
i
=
0
;
i
<
cnt
;
i
++
)
{
contact
=
nm_folder_get_contact
(
folder
,
i
);
if
(
contact
)
{
name
=
nm_contact_get_display_id
(
contact
);
if
(
name
)
{
buddy
=
purple_blist_find_buddy_in_group
(
user
->
client_data
,
name
,
group
);
if
(
buddy
==
NULL
)
{
/* Add it to the purple buddy list */
buddy
=
purple_buddy_new
(
user
->
client_data
,
name
,
nm_contact_get_display_name
(
contact
));
purple_blist_add_buddy
(
buddy
,
NULL
,
group
,
NULL
);
}
/* Set the initial status for the buddy */
user_record
=
nm_contact_get_user_record
(
contact
);
if
(
user_record
)
{
status
=
nm_user_record_get_status
(
user_record
);
}
_update_buddy_status
(
user
,
buddy
,
status
,
time
(
0
));
/* Save the new buddy as part of the contact object */
nm_contact_set_data
(
contact
,
(
gpointer
)
buddy
);
}
}
else
{
/* NULL contact. This should not happen, but
* let's break out of the loop.
*/
break
;
}
}
}
/* Add all of the server side contacts to the Purple buddy list. */
static
void
_add_purple_buddies
(
NMUser
*
user
)
{
int
cnt
=
0
,
i
;
NMFolder
*
root_folder
=
NULL
;
NMFolder
*
folder
=
NULL
;
root_folder
=
nm_get_root_folder
(
user
);
if
(
root_folder
)
{
/* Add sub-folders and contacts to sub-folders...
* iterate throught the sub-folders in reverse order
* because Purple adds the folders to the front -- so we
* want to add the first folder last
*/
cnt
=
nm_folder_get_subfolder_count
(
root_folder
);
for
(
i
=
cnt
-1
;
i
>=
0
;
i
--
)
{
folder
=
nm_folder_get_subfolder
(
root_folder
,
i
);
if
(
folder
)
{
_add_contacts_to_purple_blist
(
user
,
folder
);
}
}
/* Add contacts for the root folder */
_add_contacts_to_purple_blist
(
user
,
root_folder
);
}
}
static
void
_sync_contact_list
(
NMUser
*
user
)
{
/* Remove all buddies from the local list that are
* not in the server side list and add all buddies
* from the server side list that are not in
* the local list
*/
_remove_purple_buddies
(
user
);
_add_purple_buddies
(
user
);
user
->
clist_synched
=
TRUE
;
}
static
void
_sync_privacy_lists
(
NMUser
*
user
)
{
GSList
*
node
=
NULL
,
*
rem_list
=
NULL
;
PurpleConnection
*
gc
;
PurpleAccount
*
account
;
const
char
*
name
,
*
dn
;
NMUserRecord
*
user_record
;
if
(
user
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
if
(
gc
==
NULL
)
return
;
account
=
purple_connection_get_account
(
gc
);
/* Set the Purple privacy setting */
if
(
user
->
default_deny
)
{
if
(
user
->
allow_list
==
NULL
)
{
purple_account_set_privacy_type
(
account
,
PURPLE_ACCOUNT_PRIVACY_DENY_ALL
);
}
else
{
purple_account_set_privacy_type
(
account
,
PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS
);
}
}
else
{
if
(
user
->
deny_list
==
NULL
)
{
purple_account_set_privacy_type
(
account
,
PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL
);
}
else
{
purple_account_set_privacy_type
(
account
,
PURPLE_ACCOUNT_PRIVACY_DENY_USERS
);
}
}
/* Add stuff */
for
(
node
=
user
->
allow_list
;
node
;
node
=
node
->
next
)
{
user_record
=
nm_find_user_record
(
user
,
(
char
*
)
node
->
data
);
if
(
user_record
)
name
=
nm_user_record_get_display_id
(
user_record
);
else
name
=
(
char
*
)
node
->
data
;
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_permitted
(
account
),
name
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_permit_add
(
account
,
name
,
TRUE
);
}
}
for
(
node
=
user
->
deny_list
;
node
;
node
=
node
->
next
)
{
user_record
=
nm_find_user_record
(
user
,
(
char
*
)
node
->
data
);
if
(
user_record
)
name
=
nm_user_record_get_display_id
(
user_record
);
else
name
=
(
char
*
)
node
->
data
;
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_denied
(
account
),
name
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_deny_add
(
account
,
name
,
TRUE
);
}
}
/* Remove stuff */
for
(
node
=
purple_account_privacy_get_permitted
(
account
);
node
;
node
=
node
->
next
)
{
dn
=
nm_lookup_dn
(
user
,
(
char
*
)
node
->
data
);
if
(
dn
!=
NULL
&&
!
g_slist_find_custom
(
user
->
allow_list
,
dn
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
rem_list
=
g_slist_append
(
rem_list
,
node
->
data
);
}
}
if
(
rem_list
)
{
for
(
node
=
rem_list
;
node
;
node
=
node
->
next
)
{
purple_account_privacy_permit_remove
(
account
,
(
char
*
)
node
->
data
,
TRUE
);
}
g_slist_free
(
rem_list
);
rem_list
=
NULL
;
}
for
(
node
=
purple_account_privacy_get_denied
(
account
);
node
;
node
=
node
->
next
)
{
dn
=
nm_lookup_dn
(
user
,
(
char
*
)
node
->
data
);
if
(
dn
!=
NULL
&&
!
g_slist_find_custom
(
user
->
deny_list
,
dn
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
rem_list
=
g_slist_append
(
rem_list
,
node
->
data
);
}
}
if
(
rem_list
)
{
for
(
node
=
rem_list
;
node
;
node
=
node
->
next
)
{
purple_account_privacy_deny_remove
(
account
,
(
char
*
)
node
->
data
,
TRUE
);
}
g_slist_free
(
rem_list
);
}
}
/* Map known property tags to user-friendly strings */
static
const
char
*
_map_property_tag
(
const
char
*
tag
)
{
if
(
tag
==
NULL
)
return
NULL
;
if
(
purple_strequal
(
tag
,
"telephoneNumber"
))
return
_
(
"Telephone Number"
);
else
if
(
purple_strequal
(
tag
,
"L"
))
return
_
(
"Location"
);
else
if
(
purple_strequal
(
tag
,
"OU"
))
return
_
(
"Department"
);
else
if
(
purple_strequal
(
tag
,
"personalTitle"
))
return
_
(
"Personal Title"
);
else
if
(
purple_strequal
(
tag
,
"Title"
))
return
_
(
"Job Title"
);
else
if
(
purple_strequal
(
tag
,
"mailstop"
))
return
_
(
"Mailstop"
);
else
if
(
purple_strequal
(
tag
,
"Internet EMail Address"
))
return
_
(
"Email Address"
);
else
return
tag
;
}
/* Display a dialog box showing the properties for the given user record */
static
void
_show_info
(
PurpleConnection
*
gc
,
NMUserRecord
*
user_record
,
char
*
name
)
{
PurpleNotifyUserInfo
*
user_info
=
purple_notify_user_info_new
();
int
count
,
i
;
NMProperty
*
property
;
const
char
*
tag
,
*
value
;
tag
=
_
(
"User ID"
);
value
=
nm_user_record_get_userid
(
user_record
);
if
(
value
)
{
/* 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
(
user_info
,
tag
,
value
);
}
tag
=
_
(
"Full name"
);
value
=
nm_user_record_get_full_name
(
user_record
);
if
(
value
)
{
/* 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
(
user_info
,
tag
,
value
);
}
count
=
nm_user_record_get_property_count
(
user_record
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
property
=
nm_user_record_get_property
(
user_record
,
i
);
if
(
property
)
{
tag
=
_map_property_tag
(
nm_property_get_tag
(
property
));
value
=
nm_property_get_value
(
property
);
if
(
tag
&&
value
)
{
/* 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
(
user_info
,
tag
,
value
);
}
nm_release_property
(
property
);
}
}
purple_notify_userinfo
(
gc
,
name
,
user_info
,
NULL
,
NULL
);
purple_notify_user_info_destroy
(
user_info
);
g_free
(
name
);
}
/* Send a join conference, the first item in the parms list is the
* NMUser object and the second item is the conference to join.
* This callback is passed to purple_request_action when we ask the
* user if they want to join the conference.
*/
static
void
_join_conference_cb
(
GSList
*
parms
)
{
NMUser
*
user
;
NMConference
*
conference
;
NMERR_T
rc
=
NM_OK
;
if
(
parms
==
NULL
||
g_slist_length
(
parms
)
!=
2
)
return
;
user
=
g_slist_nth_data
(
parms
,
0
);
conference
=
g_slist_nth_data
(
parms
,
1
);
if
(
user
&&
conference
)
{
rc
=
nm_send_join_conference
(
user
,
conference
,
_join_conf_resp_cb
,
conference
);
_check_for_disconnect
(
user
,
rc
);
}
g_slist_free
(
parms
);
}
/* Send a reject conference, the first item in the parms list is the
* NMUser object and the second item is the conference to reject.
* This callback is passed to purple_request_action when we ask the
* user if they want to joing the conference.
*/
static
void
_reject_conference_cb
(
GSList
*
parms
)
{
NMUser
*
user
;
NMConference
*
conference
;
NMERR_T
rc
=
NM_OK
;
if
(
parms
==
NULL
||
g_slist_length
(
parms
)
!=
2
)
return
;
user
=
g_slist_nth_data
(
parms
,
0
);
conference
=
g_slist_nth_data
(
parms
,
1
);
if
(
user
&&
conference
)
{
rc
=
nm_send_reject_conference
(
user
,
conference
,
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
g_slist_free
(
parms
);
}
static
void
_initiate_conference_cb
(
PurpleBlistNode
*
node
,
gpointer
ignored
)
{
PurpleBuddy
*
buddy
;
PurpleConnection
*
gc
;
NMUser
*
user
;
const
char
*
conf_name
;
PurpleChatConversation
*
chat
=
NULL
;
NMUserRecord
*
user_record
;
NMConference
*
conference
;
g_return_if_fail
(
PURPLE_IS_BUDDY
(
node
));
buddy
=
(
PurpleBuddy
*
)
node
;
gc
=
purple_account_get_connection
(
purple_buddy_get_account
(
buddy
));
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
/* We should already have a userrecord for the buddy */
user_record
=
nm_find_user_record
(
user
,
purple_buddy_get_name
(
buddy
));
if
(
user_record
==
NULL
)
return
;
conf_name
=
_get_conference_name
(
++
user
->
conference_count
);
chat
=
purple_serv_got_joined_chat
(
gc
,
user
->
conference_count
,
conf_name
);
if
(
chat
)
{
conference
=
nm_create_conference
(
NULL
);
nm_conference_set_data
(
conference
,
(
gpointer
)
chat
);
nm_send_create_conference
(
user
,
conference
,
_createconf_resp_send_invite
,
user_record
);
nm_release_conference
(
conference
);
}
}
const
char
*
_get_conference_name
(
int
id
)
{
static
char
*
name
=
NULL
;
g_free
(
name
);
name
=
g_strdup_printf
(
_
(
"GroupWise Conference %d"
),
id
);
return
name
;
}
static
void
_show_privacy_locked_error
(
PurpleConnection
*
gc
,
NMUser
*
user
)
{
char
*
err
;
err
=
g_strdup_printf
(
_
(
"Unable to change server side privacy settings (%s)."
),
nm_error_to_string
(
NMERR_ADMIN_LOCKED
));
purple_notify_error
(
gc
,
NULL
,
err
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
err
);
}
/*******************************************************************************
* Connect and recv callbacks
******************************************************************************/
static
void
novell_ssl_recv_cb
(
GObject
*
stream
,
gpointer
data
)
{
PurpleConnection
*
gc
=
data
;
NMUser
*
user
;
NMERR_T
rc
;
if
(
gc
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
rc
=
nm_process_new_data
(
user
);
if
(
rc
!=
NM_OK
)
{
if
(
_is_disconnect_error
(
rc
))
{
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Error communicating with server. Closing connection."
));
}
else
{
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"Error processing event or response (%d).
\n
"
,
rc
);
}
}
}
static
void
novell_login_callback
(
GObject
*
source_object
,
GAsyncResult
*
res
,
gpointer
data
)
{
GSocketClient
*
client
=
G_SOCKET_CLIENT
(
source_object
);
PurpleConnection
*
gc
=
data
;
GSocketConnection
*
sockconn
;
NMUser
*
user
;
NMConn
*
conn
;
NMERR_T
rc
=
0
;
const
char
*
pwd
=
NULL
;
gchar
*
my_addr
=
NULL
;
char
*
ua
=
NULL
;
GError
*
error
=
NULL
;
sockconn
=
g_socket_client_connect_to_host_finish
(
client
,
res
,
&
error
);
if
(
sockconn
==
NULL
)
{
if
(
g_error_matches
(
error
,
G_IO_ERROR
,
G_IO_ERROR_CANCELLED
))
{
g_error_free
(
error
);
}
else
{
purple_connection_take_error
(
gc
,
error
);
}
return
;
}
user
=
purple_connection_get_protocol_data
(
gc
);
if
((
user
==
NULL
)
||
(
conn
=
user
->
conn
)
==
NULL
)
return
;
purple_connection_update_progress
(
gc
,
_
(
"Authenticating..."
),
2
,
NOVELL_CONNECT_STEPS
);
conn
->
stream
=
G_IO_STREAM
(
sockconn
);
conn
->
input
=
g_data_input_stream_new
(
g_io_stream_get_input_stream
(
conn
->
stream
));
conn
->
output
=
g_io_stream_get_output_stream
(
conn
->
stream
);
g_data_input_stream_set_byte_order
(
conn
->
input
,
G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN
);
g_data_input_stream_set_newline_type
(
conn
->
input
,
G_DATA_STREAM_NEWLINE_TYPE_LF
);
my_addr
=
purple_network_get_my_ip_from_gio
(
sockconn
);
pwd
=
purple_connection_get_password
(
gc
);
ua
=
_user_agent_string
();
rc
=
nm_send_login
(
user
,
pwd
,
my_addr
,
ua
,
_login_resp_cb
,
NULL
);
if
(
rc
==
NM_OK
)
{
GSource
*
source
;
source
=
g_pollable_input_stream_create_source
(
G_POLLABLE_INPUT_STREAM
(
conn
->
input
),
user
->
cancellable
);
g_source_set_callback
(
source
,
(
GSourceFunc
)
novell_ssl_recv_cb
,
gc
,
NULL
);
}
else
{
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Unable to connect"
));
}
purple_connection_update_progress
(
gc
,
_
(
"Waiting for response..."
),
3
,
NOVELL_CONNECT_STEPS
);
g_free
(
ua
);
g_free
(
my_addr
);
}
/*******************************************************************************
* Event callback and event handlers
******************************************************************************/
static
void
_evt_receive_message
(
NMUser
*
user
,
NMEvent
*
event
)
{
NMUserRecord
*
user_record
=
NULL
;
NMContact
*
contact
=
NULL
;
PurpleIMConversation
*
im
;
NMConference
*
conference
;
PurpleMessageFlags
flags
;
char
*
text
=
NULL
;
text
=
g_markup_escape_text
(
nm_event_get_text
(
event
),
-1
);
conference
=
nm_event_get_conference
(
event
);
if
(
conference
)
{
PurpleChatConversation
*
chat
=
nm_conference_get_data
(
conference
);
/* Is this a single person 'conversation' or a conference? */
if
(
chat
==
NULL
&&
nm_conference_get_participant_count
(
conference
)
==
1
)
{
user_record
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
user_record
)
{
flags
=
0
;
if
(
nm_event_get_type
(
event
)
==
NMEVT_RECEIVE_AUTOREPLY
)
flags
|=
PURPLE_MESSAGE_AUTO_RESP
;
purple_serv_got_im
(
purple_account_get_connection
(
user
->
client_data
),
nm_user_record_get_display_id
(
user_record
),
text
,
flags
,
nm_event_get_gmt
(
event
));
im
=
purple_conversations_find_im_with_account
(
nm_user_record_get_display_id
(
user_record
),
(
PurpleAccount
*
)
user
->
client_data
);
if
(
im
)
{
contact
=
nm_find_contact
(
user
,
nm_event_get_source
(
event
));
if
(
contact
)
{
purple_conversation_set_title
(
PURPLE_CONVERSATION
(
im
),
nm_contact_get_display_name
(
contact
));
}
else
{
const
char
*
name
=
nm_user_record_get_full_name
(
user_record
);
if
(
name
==
NULL
)
name
=
nm_user_record_get_userid
(
user_record
);
purple_conversation_set_title
(
PURPLE_CONVERSATION
(
im
),
name
);
}
}
}
else
{
/* this should not happen, see the event code.
* the event code will get the contact details from
* the server if it does not have them before calling
* the event callback.
*/
}
}
else
if
(
chat
)
{
/* get the contact for send if we have one */
NMContact
*
contact
=
nm_find_contact
(
user
,
nm_event_get_source
(
event
));
/* get the user record for the sender */
user_record
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
user_record
)
{
const
char
*
name
=
nm_contact_get_display_name
(
contact
);
if
(
name
==
NULL
)
{
name
=
nm_user_record_get_full_name
(
user_record
);
if
(
name
==
NULL
)
name
=
nm_user_record_get_display_id
(
user_record
);
}
purple_serv_got_chat_in
(
purple_account_get_connection
(
user
->
client_data
),
purple_chat_conversation_get_id
(
chat
),
name
,
PURPLE_MESSAGE_RECV
,
text
,
nm_event_get_gmt
(
event
));
}
}
}
g_free
(
text
);
}
static
void
_evt_conference_left
(
NMUser
*
user
,
NMEvent
*
event
)
{
PurpleChatConversation
*
chat
;
NMConference
*
conference
;
conference
=
nm_event_get_conference
(
event
);
if
(
conference
)
{
chat
=
nm_conference_get_data
(
conference
);
if
(
chat
)
{
NMUserRecord
*
ur
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
ur
)
purple_chat_conversation_remove_user
(
chat
,
nm_user_record_get_display_id
(
ur
),
NULL
);
}
}
}
static
void
_evt_conference_invite_notify
(
NMUser
*
user
,
NMEvent
*
event
)
{
PurpleConversation
*
gconv
;
NMConference
*
conference
;
NMUserRecord
*
user_record
=
NULL
;
char
*
str
=
NULL
;
user_record
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
conference
=
nm_event_get_conference
(
event
);
if
(
user_record
&&
conference
)
{
gconv
=
nm_conference_get_data
(
conference
);
str
=
g_strdup_printf
(
_
(
"%s has been invited to this conversation."
),
nm_user_record_get_display_id
(
user_record
));
purple_conversation_write_system_message
(
gconv
,
str
,
0
);
g_free
(
str
);
}
}
static
void
_evt_conference_invite
(
NMUser
*
user
,
NMEvent
*
event
)
{
NMUserRecord
*
ur
;
PurpleConnection
*
gc
;
GSList
*
parms
=
NULL
;
const
char
*
title
=
NULL
;
const
char
*
secondary
=
NULL
;
const
char
*
name
=
NULL
;
char
*
primary
=
NULL
;
time_t
gmt
;
ur
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
ur
)
name
=
nm_user_record_get_full_name
(
ur
);
if
(
name
==
NULL
)
name
=
nm_event_get_source
(
event
);
gmt
=
nm_event_get_gmt
(
event
);
title
=
_
(
"Invitation to Conversation"
);
primary
=
g_strdup_printf
(
_
(
"Invitation from: %s
\n\n
Sent: %s"
),
name
,
purple_date_format_full
(
localtime
(
&
gmt
)));
secondary
=
_
(
"Would you like to join the conversation?"
);
/* Set up parms list for the callbacks
* We need to send the NMUser object and
* the NMConference object to the callbacks
*/
parms
=
NULL
;
parms
=
g_slist_append
(
parms
,
user
);
parms
=
g_slist_append
(
parms
,
nm_event_get_conference
(
event
));
/* Prompt the user */
/* TODO: Would it be better to use purple_serv_got_chat_invite() here? */
gc
=
purple_account_get_connection
(
user
->
client_data
);
purple_request_action
(
gc
,
title
,
primary
,
secondary
,
PURPLE_DEFAULT_ACTION_NONE
,
purple_request_cpar_from_connection
(
gc
),
parms
,
2
,
_
(
"Yes"
),
G_CALLBACK
(
_join_conference_cb
),
_
(
"No"
),
G_CALLBACK
(
_reject_conference_cb
));
g_free
(
primary
);
}
static
void
_evt_conference_joined
(
NMUser
*
user
,
NMEvent
*
event
)
{
PurpleChatConversation
*
chat
=
NULL
;
PurpleConnection
*
gc
;
NMConference
*
conference
=
NULL
;
NMUserRecord
*
ur
=
NULL
;
const
char
*
name
;
const
char
*
conf_name
;
gc
=
purple_account_get_connection
(
user
->
client_data
);
if
(
gc
==
NULL
)
return
;
conference
=
nm_event_get_conference
(
event
);
if
(
conference
)
{
chat
=
nm_conference_get_data
(
conference
);
if
(
nm_conference_get_participant_count
(
conference
)
==
2
&&
chat
==
NULL
)
{
ur
=
nm_conference_get_participant
(
conference
,
0
);
if
(
ur
)
{
conf_name
=
_get_conference_name
(
++
user
->
conference_count
);
chat
=
purple_serv_got_joined_chat
(
gc
,
user
->
conference_count
,
conf_name
);
if
(
chat
)
{
nm_conference_set_data
(
conference
,
(
gpointer
)
chat
);
name
=
nm_user_record_get_display_id
(
ur
);
purple_chat_conversation_add_user
(
chat
,
name
,
NULL
,
PURPLE_CHAT_USER_NONE
,
TRUE
);
}
}
}
if
(
chat
!=
NULL
)
{
ur
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
ur
)
{
name
=
nm_user_record_get_display_id
(
ur
);
if
(
!
purple_chat_conversation_has_user
(
chat
,
name
))
{
purple_chat_conversation_add_user
(
chat
,
name
,
NULL
,
PURPLE_CHAT_USER_NONE
,
TRUE
);
}
}
}
}
}
static
void
_evt_status_change
(
NMUser
*
user
,
NMEvent
*
event
)
{
PurpleBuddy
*
buddy
=
NULL
;
GSList
*
buddies
;
GSList
*
bnode
;
NMUserRecord
*
user_record
;
const
char
*
display_id
;
int
status
;
user_record
=
nm_event_get_user_record
(
event
);
if
(
user_record
)
{
/* Retrieve new status */
status
=
nm_user_record_get_status
(
user_record
);
/* Update status for buddy in all folders */
display_id
=
nm_user_record_get_display_id
(
user_record
);
buddies
=
purple_blist_find_buddies
(
user
->
client_data
,
display_id
);
for
(
bnode
=
buddies
;
bnode
;
bnode
=
bnode
->
next
)
{
buddy
=
(
PurpleBuddy
*
)
bnode
->
data
;
if
(
buddy
)
{
_update_buddy_status
(
user
,
buddy
,
status
,
nm_event_get_gmt
(
event
));
}
}
g_slist_free
(
buddies
);
}
}
static
void
_evt_user_disconnect
(
NMUser
*
user
,
NMEvent
*
event
)
{
PurpleConnection
*
gc
;
PurpleAccount
*
account
=
user
->
client_data
;
gc
=
purple_account_get_connection
(
account
);
if
(
gc
)
{
if
(
!
purple_account_get_remember_password
(
account
))
purple_account_set_password
(
account
,
NULL
,
NULL
,
NULL
);
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_NAME_IN_USE
,
_
(
"You have signed on from another location"
));
}
}
static
void
_evt_user_typing
(
NMUser
*
user
,
NMEvent
*
event
)
{
PurpleConnection
*
gc
;
NMUserRecord
*
user_record
=
NULL
;
gc
=
purple_account_get_connection
((
PurpleAccount
*
)
user
->
client_data
);
if
(
gc
)
{
user_record
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
user_record
)
{
purple_serv_got_typing
(
gc
,
nm_user_record_get_display_id
(
user_record
),
30
,
PURPLE_IM_TYPING
);
}
}
}
static
void
_evt_user_not_typing
(
NMUser
*
user
,
NMEvent
*
event
)
{
PurpleConnection
*
gc
;
NMUserRecord
*
user_record
;
gc
=
purple_account_get_connection
((
PurpleAccount
*
)
user
->
client_data
);
if
(
gc
)
{
user_record
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
user_record
)
{
purple_serv_got_typing_stopped
(
gc
,
nm_user_record_get_display_id
(
user_record
));
}
}
}
static
void
_evt_undeliverable_status
(
NMUser
*
user
,
NMEvent
*
event
)
{
NMUserRecord
*
ur
;
PurpleConversation
*
gconv
;
char
*
str
;
ur
=
nm_find_user_record
(
user
,
nm_event_get_source
(
event
));
if
(
ur
)
{
/* XXX - Should this be PURPLE_CONV_TYPE_IM? */
gconv
=
purple_conversations_find_with_account
(
nm_user_record_get_display_id
(
ur
),
user
->
client_data
);
if
(
gconv
)
{
const
char
*
name
=
nm_user_record_get_full_name
(
ur
);
if
(
name
==
NULL
)
{
name
=
nm_user_record_get_display_id
(
ur
);
}
str
=
g_strdup_printf
(
_
(
"%s appears to be offline and did not receive"
" the message that you just sent."
),
name
);
purple_conversation_write_system_message
(
gconv
,
str
,
0
);
g_free
(
str
);
}
}
}
static
void
_event_callback
(
NMUser
*
user
,
NMEvent
*
event
)
{
if
(
user
==
NULL
||
event
==
NULL
)
return
;
switch
(
nm_event_get_type
(
event
))
{
case
NMEVT_STATUS_CHANGE
:
_evt_status_change
(
user
,
event
);
break
;
case
NMEVT_RECEIVE_AUTOREPLY
:
case
NMEVT_RECEIVE_MESSAGE
:
_evt_receive_message
(
user
,
event
);
break
;
case
NMEVT_USER_DISCONNECT
:
_evt_user_disconnect
(
user
,
event
);
break
;
case
NMEVT_USER_TYPING
:
_evt_user_typing
(
user
,
event
);
break
;
case
NMEVT_USER_NOT_TYPING
:
_evt_user_not_typing
(
user
,
event
);
break
;
case
NMEVT_SERVER_DISCONNECT
:
/* Nothing to do? */
break
;
case
NMEVT_INVALID_RECIPIENT
:
break
;
case
NMEVT_UNDELIVERABLE_STATUS
:
_evt_undeliverable_status
(
user
,
event
);
break
;
case
NMEVT_CONFERENCE_INVITE_NOTIFY
:
/* Someone else has been invited to join a
* conference that we are currently a part of
*/
_evt_conference_invite_notify
(
user
,
event
);
break
;
case
NMEVT_CONFERENCE_INVITE
:
/* We have been invited to join a conference */
_evt_conference_invite
(
user
,
event
);
break
;
case
NMEVT_CONFERENCE_JOINED
:
/* Some one has joined a conference that we
* are a part of
*/
_evt_conference_joined
(
user
,
event
);
break
;
case
NMEVT_CONFERENCE_LEFT
:
/* Someone else has left a conference that we
* are currently a part of
*/
_evt_conference_left
(
user
,
event
);
break
;
default
:
purple_debug
(
PURPLE_DEBUG_INFO
,
"novell"
,
"_event_callback(): unhandled event, %d
\n
"
,
nm_event_get_type
(
event
));
break
;
}
}
/*******************************************************************************
* Protocol Ops
******************************************************************************/
static
void
novell_login
(
PurpleAccount
*
account
)
{
PurpleConnection
*
gc
;
NMUser
*
user
=
NULL
;
const
char
*
server
;
const
char
*
name
;
int
port
;
GError
*
error
=
NULL
;
if
(
account
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
account
);
if
(
gc
==
NULL
)
return
;
purple_connection_set_flags
(
gc
,
PURPLE_CONNECTION_FLAG_NO_IMAGES
);
server
=
purple_account_get_string
(
account
,
"server"
,
NULL
);
if
(
server
==
NULL
||
*
server
==
'\0'
)
{
/* TODO: Would be nice to prompt if not set!
* purple_request_fields(gc, _("Server Address"),...);
*/
/* ...but for now just error out with a nice message. */
purple_connection_error
(
gc
,
PURPLE_CONNECTION_ERROR_INVALID_SETTINGS
,
_
(
"Unable to connect to server. Please enter the "
"address of the server to which you wish to connect."
));
return
;
}
port
=
purple_account_get_int
(
account
,
"port"
,
DEFAULT_PORT
);
name
=
purple_account_get_username
(
account
);
user
=
nm_initialize_user
(
name
,
server
,
port
,
account
,
_event_callback
);
if
(
user
&&
user
->
conn
)
{
/* save user */
purple_connection_set_protocol_data
(
gc
,
user
);
/* connect to the server */
purple_connection_update_progress
(
gc
,
_
(
"Connecting"
),
1
,
NOVELL_CONNECT_STEPS
);
user
->
conn
->
client
=
purple_gio_socket_client_new
(
account
,
&
error
);
if
(
user
->
conn
->
client
==
NULL
)
{
purple_connection_take_error
(
gc
,
error
);
return
;
}
g_socket_client_set_tls
(
user
->
conn
->
client
,
TRUE
);
g_socket_client_connect_to_host_async
(
user
->
conn
->
client
,
user
->
conn
->
addr
,
user
->
conn
->
port
,
user
->
cancellable
,
novell_login_callback
,
gc
);
}
}
static
void
novell_close
(
PurpleConnection
*
gc
)
{
NMUser
*
user
;
NMConn
*
conn
;
if
(
gc
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
)
{
conn
=
user
->
conn
;
if
(
conn
)
{
nm_release_conn
(
conn
);
}
nm_deinitialize_user
(
user
);
}
purple_connection_set_protocol_data
(
gc
,
NULL
);
}
static
int
novell_send_im
(
PurpleConnection
*
gc
,
PurpleMessage
*
msg
)
{
NMUserRecord
*
user_record
=
NULL
;
NMConference
*
conf
=
NULL
;
NMMessage
*
message
;
NMUser
*
user
;
const
char
*
dn
=
NULL
;
char
*
plain
;
gboolean
done
=
TRUE
,
created_conf
=
FALSE
;
NMERR_T
rc
=
NM_OK
;
const
gchar
*
name
=
purple_message_get_recipient
(
msg
);
if
(
gc
==
NULL
||
name
==
NULL
||
purple_message_is_empty
(
msg
))
return
0
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
0
;
/* Create a new message */
plain
=
purple_unescape_html
(
purple_message_get_contents
(
msg
));
message
=
nm_create_message
(
plain
);
g_free
(
plain
);
/* Need to get the DN for the buddy so we can look up the convo */
dn
=
nm_lookup_dn
(
user
,
name
);
/* Do we already know about the sender? */
user_record
=
nm_find_user_record
(
user
,
dn
);
if
(
user_record
)
{
/* Do we already have an instantiated conference? */
conf
=
nm_find_conversation
(
user
,
dn
);
if
(
conf
==
NULL
)
{
/* If not, create a blank conference */
conf
=
nm_create_conference
(
NULL
);
created_conf
=
TRUE
;
nm_conference_add_participant
(
conf
,
user_record
);
}
nm_message_set_conference
(
message
,
conf
);
/* Make sure conference is instantiated */
if
(
!
nm_conference_is_instantiated
(
conf
))
{
/* It is not, so send the createconf. We will
* have to finish sending the message when we
* get the response with the new conference guid.
*/
rc
=
nm_send_create_conference
(
user
,
conf
,
_createconf_resp_send_msg
,
message
);
_check_for_disconnect
(
user
,
rc
);
done
=
FALSE
;
}
}
else
{
/* If we don't have details for the user, then we don't have
* a conference yet. So create one and send the getdetails
* to the server. We will have to finish sending the message
* when we get the response from the server.
*/
conf
=
nm_create_conference
(
NULL
);
created_conf
=
TRUE
;
nm_message_set_conference
(
message
,
conf
);
rc
=
nm_send_get_details
(
user
,
name
,
_get_details_resp_send_msg
,
message
);
_check_for_disconnect
(
user
,
rc
);
done
=
FALSE
;
}
if
(
done
)
{
/* Did we find everything we needed? */
rc
=
nm_send_message
(
user
,
message
,
_send_message_resp_cb
);
_check_for_disconnect
(
user
,
rc
);
nm_release_message
(
message
);
}
if
(
created_conf
&&
conf
)
nm_release_conference
(
conf
);
return
1
;
}
static
unsigned
int
novell_send_typing
(
PurpleConnection
*
gc
,
const
char
*
name
,
PurpleIMTypingState
state
)
{
NMConference
*
conf
=
NULL
;
NMUser
*
user
;
const
char
*
dn
=
NULL
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
||
name
==
NULL
)
return
0
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
0
;
/* Need to get the DN for the buddy so we can look up the convo */
dn
=
nm_lookup_dn
(
user
,
name
);
if
(
dn
)
{
/* Now find the conference in our list */
conf
=
nm_find_conversation
(
user
,
dn
);
if
(
conf
)
{
rc
=
nm_send_typing
(
user
,
conf
,
((
state
==
PURPLE_IM_TYPING
)
?
TRUE
:
FALSE
),
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
}
return
0
;
}
static
void
novell_convo_closed
(
PurpleConnection
*
gc
,
const
char
*
who
)
{
NMUser
*
user
;
NMConference
*
conf
;
const
char
*
dn
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
||
who
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
&&
(
dn
=
nm_lookup_dn
(
user
,
who
)))
{
conf
=
nm_find_conversation
(
user
,
dn
);
if
(
conf
)
{
rc
=
nm_send_leave_conference
(
user
,
conf
,
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
}
}
static
void
novell_chat_leave
(
PurpleConnection
*
gc
,
int
id
)
{
NMConference
*
conference
;
NMUser
*
user
;
PurpleChatConversation
*
chat
;
GSList
*
cnode
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
for
(
cnode
=
user
->
conferences
;
cnode
!=
NULL
;
cnode
=
cnode
->
next
)
{
conference
=
cnode
->
data
;
if
(
conference
&&
(
chat
=
nm_conference_get_data
(
conference
)))
{
if
(
purple_chat_conversation_get_id
(
chat
)
==
id
)
{
rc
=
nm_send_leave_conference
(
user
,
conference
,
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
break
;
}
}
}
purple_serv_got_chat_left
(
gc
,
id
);
}
static
void
novell_chat_invite
(
PurpleConnection
*
gc
,
int
id
,
const
char
*
message
,
const
char
*
who
)
{
NMConference
*
conference
;
NMUser
*
user
;
PurpleChatConversation
*
chat
;
GSList
*
cnode
;
NMERR_T
rc
=
NM_OK
;
NMUserRecord
*
user_record
=
NULL
;
if
(
gc
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
user_record
=
nm_find_user_record
(
user
,
who
);
if
(
user_record
==
NULL
)
{
rc
=
nm_send_get_details
(
user
,
who
,
_get_details_resp_send_invite
,
GINT_TO_POINTER
(
id
));
_check_for_disconnect
(
user
,
rc
);
return
;
}
for
(
cnode
=
user
->
conferences
;
cnode
!=
NULL
;
cnode
=
cnode
->
next
)
{
conference
=
cnode
->
data
;
if
(
conference
&&
(
chat
=
nm_conference_get_data
(
conference
)))
{
if
(
purple_chat_conversation_get_id
(
chat
)
==
id
)
{
rc
=
nm_send_conference_invite
(
user
,
conference
,
user_record
,
message
,
_sendinvite_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
break
;
}
}
}
}
static
int
novell_chat_send
(
PurpleConnection
*
gc
,
int
id
,
PurpleMessage
*
msg
)
{
NMConference
*
conference
;
PurpleChatConversation
*
chat
;
GSList
*
cnode
;
NMMessage
*
message
;
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
const
char
*
name
;
char
*
str
,
*
plain
;
if
(
gc
==
NULL
||
purple_message_is_empty
(
msg
))
return
-1
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
-1
;
plain
=
purple_unescape_html
(
purple_message_get_contents
(
msg
));
message
=
nm_create_message
(
plain
);
g_free
(
plain
);
for
(
cnode
=
user
->
conferences
;
cnode
!=
NULL
;
cnode
=
cnode
->
next
)
{
conference
=
cnode
->
data
;
if
(
conference
&&
(
chat
=
nm_conference_get_data
(
conference
)))
{
if
(
purple_chat_conversation_get_id
(
chat
)
==
id
)
{
nm_message_set_conference
(
message
,
conference
);
/* check to see if the conference is instatiated yet */
if
(
!
nm_conference_is_instantiated
(
conference
))
{
nm_message_add_ref
(
message
);
nm_send_create_conference
(
user
,
conference
,
_createconf_resp_send_msg
,
message
);
}
else
{
rc
=
nm_send_message
(
user
,
message
,
_send_message_resp_cb
);
}
nm_release_message
(
message
);
if
(
!
_check_for_disconnect
(
user
,
rc
))
{
/* Use the account alias if it is set */
name
=
purple_account_get_private_alias
(
user
->
client_data
);
if
(
name
==
NULL
||
*
name
==
'\0'
)
{
/* If there is no account alias, try full name */
name
=
nm_user_record_get_full_name
(
user
->
user_record
);
if
(
name
==
NULL
||
*
name
==
'\0'
)
{
/* Fall back to the username that we are signed in with */
name
=
purple_account_get_username
(
user
->
client_data
);
}
}
purple_serv_got_chat_in
(
gc
,
id
,
name
,
purple_message_get_flags
(
msg
),
purple_message_get_contents
(
msg
),
time
(
NULL
));
return
0
;
}
else
return
-1
;
}
}
}
/* The conference was not found, must be closed */
chat
=
purple_conversations_find_chat
(
gc
,
id
);
if
(
chat
)
{
str
=
g_strdup
(
_
(
"This conference has been closed."
" No more messages can be sent."
));
purple_conversation_write_system_message
(
PURPLE_CONVERSATION
(
chat
),
str
,
0
);
g_free
(
str
);
}
if
(
message
)
nm_release_message
(
message
);
return
-1
;
}
static
void
novell_add_buddy
(
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
,
const
char
*
message
)
{
NMFolder
*
folder
=
NULL
;
NMContact
*
contact
;
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
const
char
*
alias
,
*
gname
,
*
bname
;
if
(
gc
==
NULL
||
buddy
==
NULL
||
group
==
NULL
)
return
;
user
=
(
NMUser
*
)
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
/* If we haven't synched the contact list yet, ignore
* the add_buddy calls. Server side list is the master.
*/
if
(
!
user
->
clist_synched
)
return
;
/* Don't re-add a buddy that is already on our contact list */
if
(
nm_find_user_record
(
user
,
purple_buddy_get_name
(
buddy
))
!=
NULL
)
return
;
contact
=
nm_create_contact
();
nm_contact_set_dn
(
contact
,
purple_buddy_get_name
(
buddy
));
/* Remove the PurpleBuddy (we will add it back after adding it
* to the server side list). Save the alias if there is one.
*/
alias
=
purple_buddy_get_alias
(
buddy
);
bname
=
purple_buddy_get_name
(
buddy
);
if
(
alias
&&
!
purple_strequal
(
alias
,
bname
))
nm_contact_set_display_name
(
contact
,
alias
);
purple_blist_remove_buddy
(
buddy
);
buddy
=
NULL
;
gname
=
purple_group_get_name
(
group
);
if
(
purple_strequal
(
gname
,
NM_ROOT_FOLDER_NAME
))
{
gname
=
""
;
}
folder
=
nm_find_folder
(
user
,
gname
);
if
(
folder
)
{
/* We have everything that we need, so send the createcontact */
rc
=
nm_send_create_contact
(
user
,
folder
,
contact
,
_create_contact_resp_cb
,
contact
);
}
else
{
/* Need to create the folder before we can add the contact */
rc
=
nm_send_create_folder
(
user
,
gname
,
_create_folder_resp_add_contact
,
contact
);
}
_check_for_disconnect
(
user
,
rc
);
}
static
void
novell_remove_buddy
(
PurpleConnection
*
gc
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
)
{
NMContact
*
contact
;
NMFolder
*
folder
;
NMUser
*
user
;
const
char
*
dn
,
*
gname
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
||
buddy
==
NULL
||
group
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
&&
(
dn
=
nm_lookup_dn
(
user
,
purple_buddy_get_name
(
buddy
))))
{
gname
=
purple_group_get_name
(
group
);
if
(
purple_strequal
(
gname
,
NM_ROOT_FOLDER_NAME
))
{
gname
=
""
;
}
folder
=
nm_find_folder
(
user
,
gname
);
if
(
folder
)
{
contact
=
nm_folder_find_contact
(
folder
,
dn
);
if
(
contact
)
{
/* Remove the buddy from the contact */
nm_contact_set_data
(
contact
,
NULL
);
/* Tell the server to remove the contact */
rc
=
nm_send_remove_contact
(
user
,
folder
,
contact
,
_remove_contact_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
}
}
}
static
void
novell_remove_group
(
PurpleConnection
*
gc
,
PurpleGroup
*
group
)
{
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
||
group
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
)
{
NMFolder
*
folder
=
nm_find_folder
(
user
,
purple_group_get_name
(
group
));
if
(
folder
)
{
rc
=
nm_send_remove_folder
(
user
,
folder
,
_remove_folder_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
}
}
static
void
novell_alias_buddy
(
PurpleConnection
*
gc
,
const
char
*
name
,
const
char
*
alias
)
{
NMContact
*
contact
;
NMUser
*
user
;
GList
*
contacts
=
NULL
;
GList
*
cnode
=
NULL
;
const
char
*
dn
=
NULL
,
*
fname
=
NULL
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
||
name
==
NULL
||
alias
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
&&
(
dn
=
nm_lookup_dn
(
user
,
name
)))
{
/* Alias all of instances of the contact */
contacts
=
nm_find_contacts
(
user
,
dn
);
for
(
cnode
=
contacts
;
cnode
!=
NULL
;
cnode
=
cnode
->
next
)
{
contact
=
(
NMContact
*
)
cnode
->
data
;
if
(
contact
)
{
PurpleGroup
*
group
=
NULL
;
PurpleBuddy
*
buddy
;
NMFolder
*
folder
;
/* Alias the Purple buddy? */
folder
=
nm_find_folder_by_id
(
user
,
nm_contact_get_parent_id
(
contact
));
if
(
folder
)
{
fname
=
nm_folder_get_name
(
folder
);
if
(
*
fname
==
'\0'
)
{
fname
=
NM_ROOT_FOLDER_NAME
;
}
group
=
purple_blist_find_group
(
fname
);
}
if
(
group
)
{
const
char
*
balias
;
buddy
=
purple_blist_find_buddy_in_group
(
user
->
client_data
,
name
,
group
);
balias
=
buddy
?
purple_buddy_get_local_alias
(
buddy
)
:
NULL
;
if
(
balias
&&
!
purple_strequal
(
balias
,
alias
))
purple_buddy_set_local_alias
(
buddy
,
alias
);
}
/* Tell the server to alias the contact */
rc
=
nm_send_rename_contact
(
user
,
contact
,
alias
,
_rename_contact_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
}
if
(
contacts
)
g_list_free
(
contacts
);
}
}
static
void
novell_group_buddy
(
PurpleConnection
*
gc
,
const
char
*
name
,
const
char
*
old_group_name
,
const
char
*
new_group_name
)
{
NMFolder
*
old_folder
;
NMFolder
*
new_folder
;
NMContact
*
contact
;
NMUser
*
user
;
const
char
*
dn
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
||
name
==
NULL
||
old_group_name
==
NULL
||
new_group_name
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
&&
(
dn
=
nm_lookup_dn
(
user
,
name
)))
{
/* Find the old folder */
if
(
purple_strequal
(
old_group_name
,
NM_ROOT_FOLDER_NAME
))
{
old_folder
=
nm_get_root_folder
(
user
);
if
(
nm_folder_find_contact
(
old_folder
,
dn
)
==
NULL
)
old_folder
=
nm_find_folder
(
user
,
old_group_name
);
}
else
{
old_folder
=
nm_find_folder
(
user
,
old_group_name
);
}
if
(
old_folder
&&
(
contact
=
nm_folder_find_contact
(
old_folder
,
dn
)))
{
/* Find the new folder */
new_folder
=
nm_find_folder
(
user
,
new_group_name
);
if
(
new_folder
==
NULL
)
{
if
(
purple_strequal
(
new_group_name
,
NM_ROOT_FOLDER_NAME
))
new_folder
=
nm_get_root_folder
(
user
);
}
if
(
new_folder
)
{
/* Tell the server to move the contact to the new folder */
rc
=
nm_send_move_contact
(
user
,
contact
,
new_folder
,
_move_contact_resp_cb
,
NULL
);
}
else
{
nm_contact_add_ref
(
contact
);
/* Remove the old contact first */
nm_send_remove_contact
(
user
,
old_folder
,
contact
,
_remove_contact_resp_cb
,
NULL
);
/* New folder does not exist yet, so create it */
rc
=
nm_send_create_folder
(
user
,
new_group_name
,
_create_folder_resp_move_contact
,
contact
);
}
_check_for_disconnect
(
user
,
rc
);
}
}
}
static
void
novell_rename_group
(
PurpleConnection
*
gc
,
const
char
*
old_name
,
PurpleGroup
*
group
,
GList
*
moved_buddies
)
{
NMERR_T
rc
=
NM_OK
;
NMFolder
*
folder
;
NMUser
*
user
;
if
(
gc
==
NULL
||
old_name
==
NULL
||
group
==
NULL
||
moved_buddies
==
NULL
)
{
return
;
}
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
)
{
const
char
*
gname
=
purple_group_get_name
(
group
);
/* Does new folder exist already? */
if
(
nm_find_folder
(
user
,
gname
))
{
/* purple_group_set_name() adds the buddies
* to the new group and removes the old group...
* so there is nothing more to do here.
*/
return
;
}
if
(
purple_strequal
(
old_name
,
NM_ROOT_FOLDER_NAME
))
{
/* Can't rename the root folder ... need to revisit this */
return
;
}
folder
=
nm_find_folder
(
user
,
old_name
);
if
(
folder
)
{
rc
=
nm_send_rename_folder
(
user
,
folder
,
gname
,
_rename_folder_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
}
}
static
const
char
*
novell_list_icon
(
PurpleAccount
*
account
,
PurpleBuddy
*
buddy
)
{
return
"novell"
;
}
static
void
novell_tooltip_text
(
PurpleBuddy
*
buddy
,
PurpleNotifyUserInfo
*
user_info
,
gboolean
full
)
{
NMUserRecord
*
user_record
=
NULL
;
PurpleConnection
*
gc
;
NMUser
*
user
;
int
status
=
0
;
const
char
*
status_str
=
NULL
;
const
char
*
text
=
NULL
;
if
(
buddy
==
NULL
)
return
;
gc
=
purple_account_get_connection
(
purple_buddy_get_account
(
buddy
));
if
(
gc
==
NULL
||
(
user
=
purple_connection_get_protocol_data
(
gc
))
==
NULL
)
return
;
if
(
PURPLE_BUDDY_IS_ONLINE
(
buddy
))
{
user_record
=
nm_find_user_record
(
user
,
purple_buddy_get_name
(
buddy
));
if
(
user_record
)
{
status
=
nm_user_record_get_status
(
user_record
);
text
=
nm_user_record_get_status_text
(
user_record
);
/* No custom text, so default it ... */
switch
(
status
)
{
case
NM_STATUS_AVAILABLE
:
status_str
=
_
(
"Available"
);
break
;
case
NM_STATUS_AWAY
:
status_str
=
_
(
"Away"
);
break
;
case
NM_STATUS_BUSY
:
status_str
=
_
(
"Busy"
);
break
;
case
NM_STATUS_AWAY_IDLE
:
status_str
=
_
(
"Idle"
);
break
;
case
NM_STATUS_OFFLINE
:
status_str
=
_
(
"Offline"
);
break
;
default
:
status_str
=
_
(
"Unknown"
);
break
;
}
purple_notify_user_info_add_pair_plaintext
(
user_info
,
_
(
"Status"
),
status_str
);
if
(
text
)
{
/* 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
(
user_info
,
_
(
"Message"
),
text
);
}
}
}
}
static
void
novell_set_idle
(
PurpleConnection
*
gc
,
int
time
)
{
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
const
char
*
id
=
NULL
;
PurpleStatus
*
status
=
NULL
;
if
(
gc
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
status
=
purple_account_get_active_status
(
purple_connection_get_account
(
gc
));
id
=
purple_status_get_id
(
status
);
/* Only go idle if active status is available */
if
(
purple_strequal
(
id
,
NOVELL_STATUS_TYPE_AVAILABLE
))
{
if
(
time
>
0
)
{
rc
=
nm_send_set_status
(
user
,
NM_STATUS_AWAY_IDLE
,
NULL
,
NULL
,
NULL
,
NULL
);
}
else
{
rc
=
nm_send_set_status
(
user
,
NM_STATUS_AVAILABLE
,
NULL
,
NULL
,
NULL
,
NULL
);
}
}
_check_for_disconnect
(
user
,
rc
);
}
static
void
novell_get_info
(
PurpleConnection
*
gc
,
const
char
*
name
)
{
NMUserRecord
*
user_record
;
NMUser
*
user
;
NMERR_T
rc
;
if
(
gc
==
NULL
||
name
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
)
{
user_record
=
nm_find_user_record
(
user
,
name
);
if
(
user_record
)
{
_show_info
(
gc
,
user_record
,
g_strdup
(
name
));
}
else
{
rc
=
nm_send_get_details
(
user
,
name
,
_get_details_resp_show_info
,
g_strdup
(
name
));
_check_for_disconnect
(
user
,
rc
);
}
}
}
static
char
*
novell_status_text
(
PurpleBuddy
*
buddy
)
{
const
char
*
text
=
NULL
;
const
char
*
dn
=
NULL
;
PurpleAccount
*
account
;
account
=
buddy
?
purple_buddy_get_account
(
buddy
)
:
NULL
;
if
(
buddy
&&
account
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
if
(
gc
)
{
NMUser
*
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
)
{
dn
=
nm_lookup_dn
(
user
,
purple_buddy_get_name
(
buddy
));
if
(
dn
)
{
NMUserRecord
*
user_record
=
nm_find_user_record
(
user
,
dn
);
if
(
user_record
)
{
text
=
nm_user_record_get_status_text
(
user_record
);
if
(
text
)
return
g_strdup
(
text
);
}
}
}
}
}
return
NULL
;
}
static
GList
*
novell_status_types
(
PurpleAccount
*
account
)
{
GList
*
status_types
=
NULL
;
PurpleStatusType
*
type
;
g_return_val_if_fail
(
account
!=
NULL
,
NULL
);
type
=
purple_status_type_new_with_attrs
(
PURPLE_STATUS_AVAILABLE
,
NOVELL_STATUS_TYPE_AVAILABLE
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
);
status_types
=
g_list_append
(
status_types
,
type
);
type
=
purple_status_type_new_with_attrs
(
PURPLE_STATUS_AWAY
,
NOVELL_STATUS_TYPE_AWAY
,
NULL
,
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
);
status_types
=
g_list_append
(
status_types
,
type
);
type
=
purple_status_type_new_with_attrs
(
PURPLE_STATUS_UNAVAILABLE
,
NOVELL_STATUS_TYPE_BUSY
,
_
(
"Busy"
),
TRUE
,
TRUE
,
FALSE
,
"message"
,
_
(
"Message"
),
purple_value_new
(
G_TYPE_STRING
),
NULL
);
status_types
=
g_list_append
(
status_types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_INVISIBLE
,
NOVELL_STATUS_TYPE_APPEAR_OFFLINE
,
NULL
,
TRUE
,
TRUE
,
FALSE
);
status_types
=
g_list_append
(
status_types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_OFFLINE
,
NULL
,
NULL
,
TRUE
,
TRUE
,
FALSE
);
status_types
=
g_list_append
(
status_types
,
type
);
return
status_types
;
}
static
void
novell_set_status
(
PurpleAccount
*
account
,
PurpleStatus
*
status
)
{
PurpleConnection
*
gc
;
gboolean
connected
;
PurplePresence
*
presence
;
PurpleStatusType
*
type
;
PurpleStatusPrimitive
primitive
;
NMUser
*
user
;
NMSTATUS_T
novellstatus
=
NM_STATUS_AVAILABLE
;
NMERR_T
rc
=
NM_OK
;
const
char
*
msg
=
NULL
;
char
*
text
=
NULL
;
connected
=
purple_account_is_connected
(
account
);
presence
=
purple_status_get_presence
(
status
);
type
=
purple_status_get_status_type
(
status
);
primitive
=
purple_status_type_get_primitive
(
type
);
/*
* We don't have any independent statuses, so we don't need to
* do anything when a status is deactivated (because another
* status is about to be activated).
*/
if
(
!
purple_status_is_active
(
status
))
return
;
if
(
!
connected
)
return
;
gc
=
purple_account_get_connection
(
account
);
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
if
(
primitive
==
PURPLE_STATUS_AVAILABLE
)
{
novellstatus
=
NM_STATUS_AVAILABLE
;
}
else
if
(
primitive
==
PURPLE_STATUS_AWAY
)
{
novellstatus
=
NM_STATUS_AWAY
;
}
else
if
(
primitive
==
PURPLE_STATUS_UNAVAILABLE
)
{
novellstatus
=
NM_STATUS_BUSY
;
}
else
if
(
primitive
==
PURPLE_STATUS_INVISIBLE
)
{
novellstatus
=
NM_STATUS_OFFLINE
;
}
else
if
(
purple_presence_is_idle
(
presence
))
{
novellstatus
=
NM_STATUS_AWAY_IDLE
;
}
else
{
novellstatus
=
NM_STATUS_AVAILABLE
;
}
if
(
primitive
==
PURPLE_STATUS_AWAY
||
primitive
==
PURPLE_STATUS_AVAILABLE
||
primitive
==
PURPLE_STATUS_UNAVAILABLE
)
{
msg
=
purple_status_get_attr_string
(
status
,
"message"
);
text
=
g_strdup
(
msg
);
if
(
primitive
==
PURPLE_STATUS_AVAILABLE
)
msg
=
NULL
;
/* no auto replies for online status */
/* Don't want newlines in status text */
purple_util_chrreplace
(
text
,
'\n'
,
' '
);
}
rc
=
nm_send_set_status
(
user
,
novellstatus
,
text
,
msg
,
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
g_free
(
text
);
}
static
void
novell_add_permit
(
PurpleConnection
*
gc
,
const
char
*
who
)
{
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
const
char
*
name
=
who
;
if
(
gc
==
NULL
||
who
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
/* Remove first -- we will add it back in when we get
* the okay from the server
*/
purple_account_privacy_permit_remove
(
purple_connection_get_account
(
gc
),
who
,
TRUE
);
if
(
nm_user_is_privacy_locked
(
user
))
{
_show_privacy_locked_error
(
gc
,
user
);
_sync_privacy_lists
(
user
);
return
;
}
/* Work around for problem with un-typed, dotted contexts */
if
(
strchr
(
who
,
'.'
))
{
const
char
*
dn
=
nm_lookup_dn
(
user
,
who
);
if
(
dn
==
NULL
)
{
rc
=
nm_send_get_details
(
user
,
who
,
_get_details_send_privacy_create
,
GINT_TO_POINTER
(
TRUE
));
_check_for_disconnect
(
user
,
rc
);
return
;
}
else
{
name
=
dn
;
}
}
rc
=
nm_send_create_privacy_item
(
user
,
name
,
TRUE
,
_create_privacy_item_permit_resp_cb
,
g_strdup
(
who
));
_check_for_disconnect
(
user
,
rc
);
}
static
void
novell_add_deny
(
PurpleConnection
*
gc
,
const
char
*
who
)
{
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
const
char
*
name
=
who
;
if
(
gc
==
NULL
||
who
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
/* Remove first -- we will add it back in when we get
* the okay from the server
*/
purple_account_privacy_deny_remove
(
purple_connection_get_account
(
gc
),
who
,
TRUE
);
if
(
nm_user_is_privacy_locked
(
user
))
{
_show_privacy_locked_error
(
gc
,
user
);
_sync_privacy_lists
(
user
);
return
;
}
/* Work around for problem with un-typed, dotted contexts */
if
(
strchr
(
who
,
'.'
))
{
const
char
*
dn
=
nm_lookup_dn
(
user
,
who
);
if
(
dn
==
NULL
)
{
rc
=
nm_send_get_details
(
user
,
who
,
_get_details_send_privacy_create
,
GINT_TO_POINTER
(
FALSE
));
_check_for_disconnect
(
user
,
rc
);
return
;
}
else
{
name
=
dn
;
}
}
rc
=
nm_send_create_privacy_item
(
user
,
name
,
FALSE
,
_create_privacy_item_deny_resp_cb
,
g_strdup
(
who
));
_check_for_disconnect
(
user
,
rc
);
}
static
void
novell_rem_permit
(
PurpleConnection
*
gc
,
const
char
*
who
)
{
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
const
char
*
dn
=
NULL
;
if
(
gc
==
NULL
||
who
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
if
(
nm_user_is_privacy_locked
(
user
))
{
_show_privacy_locked_error
(
gc
,
user
);
_sync_privacy_lists
(
user
);
return
;
}
dn
=
nm_lookup_dn
(
user
,
who
);
if
(
dn
==
NULL
)
dn
=
who
;
rc
=
nm_send_remove_privacy_item
(
user
,
dn
,
TRUE
,
_remove_privacy_item_resp_cb
,
g_strdup
(
who
));
_check_for_disconnect
(
user
,
rc
);
}
static
void
novell_rem_deny
(
PurpleConnection
*
gc
,
const
char
*
who
)
{
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
const
char
*
dn
=
NULL
;
if
(
gc
==
NULL
||
who
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
if
(
nm_user_is_privacy_locked
(
user
))
{
_show_privacy_locked_error
(
gc
,
user
);
_sync_privacy_lists
(
user
);
return
;
}
dn
=
nm_lookup_dn
(
user
,
who
);
if
(
dn
==
NULL
)
dn
=
who
;
rc
=
nm_send_remove_privacy_item
(
user
,
dn
,
FALSE
,
_remove_privacy_item_resp_cb
,
g_strdup
(
who
));
_check_for_disconnect
(
user
,
rc
);
}
static
void
novell_set_permit_deny
(
PurpleConnection
*
gc
)
{
NMERR_T
rc
=
NM_OK
;
const
char
*
dn
,
*
name
=
NULL
;
NMUserRecord
*
user_record
=
NULL
;
GSList
*
node
=
NULL
,
*
copy
=
NULL
;
NMUser
*
user
;
int
i
,
j
,
num_contacts
,
num_folders
;
NMContact
*
contact
;
NMFolder
*
folder
=
NULL
;
PurpleAccount
*
account
;
if
(
gc
==
NULL
)
return
;
account
=
purple_connection_get_account
(
gc
);
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
if
(
user
->
privacy_synched
==
FALSE
)
{
_sync_privacy_lists
(
user
);
user
->
privacy_synched
=
TRUE
;
return
;
}
if
(
nm_user_is_privacy_locked
(
user
))
{
_show_privacy_locked_error
(
gc
,
user
);
_sync_privacy_lists
(
user
);
return
;
}
switch
(
purple_account_get_privacy_type
(
account
))
{
case
PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL
:
rc
=
nm_send_set_privacy_default
(
user
,
FALSE
,
_set_privacy_default_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
/* clear server side deny list */
if
(
rc
==
NM_OK
)
{
copy
=
g_slist_copy
(
user
->
deny_list
);
for
(
node
=
copy
;
node
&&
node
->
data
;
node
=
node
->
next
)
{
rc
=
nm_send_remove_privacy_item
(
user
,
(
const
char
*
)
node
->
data
,
FALSE
,
NULL
,
NULL
);
if
(
_check_for_disconnect
(
user
,
rc
))
break
;
}
g_slist_free
(
copy
);
g_slist_free
(
user
->
deny_list
);
user
->
deny_list
=
NULL
;
}
break
;
case
PURPLE_ACCOUNT_PRIVACY_DENY_ALL
:
rc
=
nm_send_set_privacy_default
(
user
,
TRUE
,
_set_privacy_default_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
/* clear server side allow list */
if
(
rc
==
NM_OK
)
{
copy
=
g_slist_copy
(
user
->
allow_list
);
for
(
node
=
copy
;
node
&&
node
->
data
;
node
=
node
->
next
)
{
rc
=
nm_send_remove_privacy_item
(
user
,
(
const
char
*
)
node
->
data
,
TRUE
,
NULL
,
NULL
);
if
(
_check_for_disconnect
(
user
,
rc
))
break
;
}
g_slist_free
(
copy
);
g_slist_free
(
user
->
allow_list
);
user
->
allow_list
=
NULL
;
}
break
;
case
PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS
:
rc
=
nm_send_set_privacy_default
(
user
,
TRUE
,
_set_privacy_default_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
/* sync allow lists */
if
(
rc
==
NM_OK
)
{
for
(
node
=
user
->
allow_list
;
node
;
node
=
node
->
next
)
{
user_record
=
nm_find_user_record
(
user
,
(
char
*
)
node
->
data
);
if
(
user_record
)
{
name
=
nm_user_record_get_display_id
(
user_record
);
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_permitted
(
account
),
name
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_permit_add
(
account
,
name
,
TRUE
);
}
}
}
for
(
node
=
purple_account_privacy_get_permitted
(
account
);
node
;
node
=
node
->
next
)
{
dn
=
nm_lookup_dn
(
user
,
(
char
*
)
node
->
data
);
if
(
dn
)
{
if
(
!
g_slist_find_custom
(
user
->
allow_list
,
dn
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
rc
=
nm_send_create_privacy_item
(
user
,
dn
,
TRUE
,
_create_privacy_item_deny_resp_cb
,
g_strdup
(
dn
));
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
purple_account_privacy_permit_remove
(
account
,
(
char
*
)
node
->
data
,
TRUE
);
}
}
}
break
;
case
PURPLE_ACCOUNT_PRIVACY_DENY_USERS
:
/* set to default allow */
rc
=
nm_send_set_privacy_default
(
user
,
FALSE
,
_set_privacy_default_resp_cb
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
/* sync deny lists */
if
(
rc
==
NM_OK
)
{
for
(
node
=
user
->
deny_list
;
node
;
node
=
node
->
next
)
{
user_record
=
nm_find_user_record
(
user
,
(
char
*
)
node
->
data
);
if
(
user_record
)
{
name
=
nm_user_record_get_display_id
(
user_record
);
if
(
!
g_slist_find_custom
(
purple_account_privacy_get_denied
(
account
),
name
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
purple_account_privacy_deny_add
(
account
,
name
,
TRUE
);
}
}
}
for
(
node
=
purple_account_privacy_get_denied
(
account
);
node
;
node
=
node
->
next
)
{
name
=
NULL
;
dn
=
nm_lookup_dn
(
user
,
(
char
*
)
node
->
data
);
if
(
dn
)
{
user_record
=
nm_find_user_record
(
user
,
dn
);
name
=
nm_user_record_get_display_id
(
user_record
);
if
(
!
g_slist_find_custom
(
user
->
deny_list
,
dn
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
rc
=
nm_send_create_privacy_item
(
user
,
dn
,
FALSE
,
_create_privacy_item_deny_resp_cb
,
g_strdup
(
name
));
_check_for_disconnect
(
user
,
rc
);
}
}
else
{
purple_account_privacy_deny_remove
(
account
,
(
char
*
)
node
->
data
,
TRUE
);
}
}
}
break
;
case
PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST
:
/* remove users from allow list that are not in buddy list */
copy
=
g_slist_copy
(
user
->
allow_list
);
for
(
node
=
copy
;
node
&&
node
->
data
;
node
=
node
->
next
)
{
if
(
!
nm_find_contacts
(
user
,
node
->
data
))
{
rc
=
nm_send_remove_privacy_item
(
user
,
(
const
char
*
)
node
->
data
,
TRUE
,
NULL
,
NULL
);
if
(
_check_for_disconnect
(
user
,
rc
))
return
;
}
}
g_slist_free
(
copy
);
/* add all buddies to allow list */
num_contacts
=
nm_folder_get_contact_count
(
user
->
root_folder
);
for
(
i
=
0
;
i
<
num_contacts
;
i
++
)
{
contact
=
nm_folder_get_contact
(
user
->
root_folder
,
i
);
dn
=
nm_contact_get_dn
(
contact
);
if
(
dn
&&
!
g_slist_find_custom
(
user
->
allow_list
,
dn
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
rc
=
nm_send_create_privacy_item
(
user
,
dn
,
TRUE
,
_create_privacy_item_deny_resp_cb
,
g_strdup
(
dn
));
if
(
_check_for_disconnect
(
user
,
rc
))
return
;
}
}
num_folders
=
nm_folder_get_subfolder_count
(
user
->
root_folder
);
for
(
i
=
0
;
i
<
num_folders
;
i
++
)
{
folder
=
nm_folder_get_subfolder
(
user
->
root_folder
,
i
);
num_contacts
=
nm_folder_get_contact_count
(
folder
);
for
(
j
=
0
;
j
<
num_contacts
;
j
++
)
{
contact
=
nm_folder_get_contact
(
folder
,
j
);
dn
=
nm_contact_get_dn
(
contact
);
if
(
dn
&&
!
g_slist_find_custom
(
user
->
allow_list
,
dn
,
(
GCompareFunc
)
purple_utf8_strcasecmp
))
{
rc
=
nm_send_create_privacy_item
(
user
,
dn
,
TRUE
,
_create_privacy_item_deny_resp_cb
,
g_strdup
(
dn
));
if
(
_check_for_disconnect
(
user
,
rc
))
return
;
}
}
}
/* set to default deny */
rc
=
nm_send_set_privacy_default
(
user
,
TRUE
,
_set_privacy_default_resp_cb
,
NULL
);
if
(
_check_for_disconnect
(
user
,
rc
))
break
;
break
;
}
}
static
GList
*
novell_blist_node_menu
(
PurpleBlistNode
*
node
)
{
GList
*
list
=
NULL
;
PurpleActionMenu
*
act
;
if
(
PURPLE_IS_BUDDY
(
node
))
{
act
=
purple_action_menu_new
(
_
(
"Initiate _Chat"
),
PURPLE_CALLBACK
(
_initiate_conference_cb
),
NULL
,
NULL
);
list
=
g_list_append
(
list
,
act
);
}
return
list
;
}
static
void
novell_keepalive
(
PurpleConnection
*
gc
)
{
NMUser
*
user
;
NMERR_T
rc
=
NM_OK
;
if
(
gc
==
NULL
)
return
;
user
=
purple_connection_get_protocol_data
(
gc
);
if
(
user
==
NULL
)
return
;
rc
=
nm_send_keepalive
(
user
,
NULL
,
NULL
);
_check_for_disconnect
(
user
,
rc
);
}
static
gssize
novell_get_max_message_size
(
PurpleConversation
*
conv
)
{
/* XXX: got from pidgin-otr - verify and document it */
return
1792
;
}
static
void
novell_protocol_init
(
NovellProtocol
*
self
)
{
PurpleProtocol
*
protocol
=
PURPLE_PROTOCOL
(
self
);
PurpleAccountOption
*
option
;
protocol
->
id
=
"prpl-novell"
;
protocol
->
name
=
"GroupWise"
;
option
=
purple_account_option_string_new
(
_
(
"Server address"
),
"server"
,
NULL
);
protocol
->
account_options
=
g_list_append
(
protocol
->
account_options
,
option
);
option
=
purple_account_option_int_new
(
_
(
"Server port"
),
"port"
,
DEFAULT_PORT
);
protocol
->
account_options
=
g_list_append
(
protocol
->
account_options
,
option
);
}
static
void
novell_protocol_class_init
(
NovellProtocolClass
*
klass
)
{
PurpleProtocolClass
*
protocol_class
=
PURPLE_PROTOCOL_CLASS
(
klass
);
protocol_class
->
login
=
novell_login
;
protocol_class
->
close
=
novell_close
;
protocol_class
->
status_types
=
novell_status_types
;
protocol_class
->
list_icon
=
novell_list_icon
;
}
static
void
novell_protocol_class_finalize
(
G_GNUC_UNUSED
NovellProtocolClass
*
klass
)
{
}
static
void
novell_protocol_client_iface_init
(
PurpleProtocolClientInterface
*
client_iface
)
{
client_iface
->
status_text
=
novell_status_text
;
client_iface
->
tooltip_text
=
novell_tooltip_text
;
client_iface
->
blist_node_menu
=
novell_blist_node_menu
;
client_iface
->
convo_closed
=
novell_convo_closed
;
client_iface
->
normalize
=
purple_normalize_nocase
;
client_iface
->
get_max_message_size
=
novell_get_max_message_size
;
}
static
void
novell_protocol_server_iface_init
(
PurpleProtocolServerInterface
*
server_iface
)
{
server_iface
->
get_info
=
novell_get_info
;
server_iface
->
set_status
=
novell_set_status
;
server_iface
->
set_idle
=
novell_set_idle
;
server_iface
->
add_buddy
=
novell_add_buddy
;
server_iface
->
remove_buddy
=
novell_remove_buddy
;
server_iface
->
keepalive
=
novell_keepalive
;
server_iface
->
alias_buddy
=
novell_alias_buddy
;
server_iface
->
group_buddy
=
novell_group_buddy
;
server_iface
->
rename_group
=
novell_rename_group
;
server_iface
->
remove_group
=
novell_remove_group
;
}
static
void
novell_protocol_im_iface_init
(
PurpleProtocolIMInterface
*
im_iface
)
{
im_iface
->
send
=
novell_send_im
;
im_iface
->
send_typing
=
novell_send_typing
;
}
static
void
novell_protocol_chat_iface_init
(
PurpleProtocolChatInterface
*
chat_iface
)
{
chat_iface
->
invite
=
novell_chat_invite
;
chat_iface
->
leave
=
novell_chat_leave
;
chat_iface
->
send
=
novell_chat_send
;
}
static
void
novell_protocol_privacy_iface_init
(
PurpleProtocolPrivacyInterface
*
privacy_iface
)
{
privacy_iface
->
add_permit
=
novell_add_permit
;
privacy_iface
->
add_deny
=
novell_add_deny
;
privacy_iface
->
rem_permit
=
novell_rem_permit
;
privacy_iface
->
rem_deny
=
novell_rem_deny
;
privacy_iface
->
set_permit_deny
=
novell_set_permit_deny
;
}
G_DEFINE_DYNAMIC_TYPE_EXTENDED
(
NovellProtocol
,
novell_protocol
,
PURPLE_TYPE_PROTOCOL
,
0
,
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CLIENT
,
novell_protocol_client_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_SERVER
,
novell_protocol_server_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_IM
,
novell_protocol_im_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CHAT
,
novell_protocol_chat_iface_init
)
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_PRIVACY
,
novell_protocol_privacy_iface_init
));
static
PurplePluginInfo
*
plugin_query
(
GError
**
error
)
{
return
purple_plugin_info_new
(
"id"
,
"prpl-novell"
,
"name"
,
"Novell GroupWise Protocol"
,
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Protocol"
),
"summary"
,
N_
(
"Novell GroupWise Messenger Protocol Plugin"
),
"description"
,
N_
(
"Novell GroupWise Messenger Protocol Plugin"
),
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"flags"
,
PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
NULL
);
}
static
gboolean
plugin_load
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
novell_protocol_register_type
(
G_TYPE_MODULE
(
plugin
));
my_protocol
=
purple_protocols_add
(
NOVELL_TYPE_PROTOCOL
,
error
);
if
(
!
my_protocol
)
return
FALSE
;
return
TRUE
;
}
static
gboolean
plugin_unload
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
if
(
!
purple_protocols_remove
(
my_protocol
,
error
))
return
FALSE
;
return
TRUE
;
}
PURPLE_PLUGIN_INIT
(
novell
,
plugin_query
,
plugin_load
,
plugin_unload
);