pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Add the real CVE number
release-2.x.y
2017-03-08, Gary Kramlich
f40dfcb98ba1
Add the real CVE number
/*
silcpurple.c
Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 2004 - 2007 Pekka Riikonen
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.
*/
#include
"internal.h"
#include
"silc.h"
#include
"silcclient.h"
#include
"silcpurple.h"
#include
"version.h"
#include
"wb.h"
#include
"core.h"
extern
SilcClientOperations
ops
;
static
PurplePlugin
*
silc_plugin
=
NULL
;
/* Error log message callback */
static
SilcBool
silcpurple_log_error
(
SilcLogType
type
,
char
*
message
,
void
*
context
)
{
silc_say
(
NULL
,
NULL
,
SILC_CLIENT_MESSAGE_ERROR
,
message
);
return
TRUE
;
}
static
const
char
*
silcpurple_list_icon
(
PurpleAccount
*
a
,
PurpleBuddy
*
b
)
{
return
(
const
char
*
)
"silc"
;
}
static
GList
*
silcpurple_away_states
(
PurpleAccount
*
account
)
{
PurpleStatusType
*
type
;
GList
*
types
=
NULL
;
type
=
purple_status_type_new_full
(
PURPLE_STATUS_AVAILABLE
,
SILCPURPLE_STATUS_ID_AVAILABLE
,
NULL
,
TRUE
,
TRUE
,
FALSE
);
types
=
g_list_append
(
types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_AVAILABLE
,
SILCPURPLE_STATUS_ID_HYPER
,
_
(
"Hyper Active"
),
TRUE
,
TRUE
,
FALSE
);
types
=
g_list_append
(
types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_AWAY
,
SILCPURPLE_STATUS_ID_AWAY
,
NULL
,
TRUE
,
TRUE
,
FALSE
);
types
=
g_list_append
(
types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_UNAVAILABLE
,
SILCPURPLE_STATUS_ID_BUSY
,
_
(
"Busy"
),
TRUE
,
TRUE
,
FALSE
);
types
=
g_list_append
(
types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_AWAY
,
SILCPURPLE_STATUS_ID_INDISPOSED
,
_
(
"Indisposed"
),
TRUE
,
TRUE
,
FALSE
);
types
=
g_list_append
(
types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_AWAY
,
SILCPURPLE_STATUS_ID_PAGE
,
_
(
"Wake Me Up"
),
TRUE
,
TRUE
,
FALSE
);
types
=
g_list_append
(
types
,
type
);
type
=
purple_status_type_new_full
(
PURPLE_STATUS_OFFLINE
,
SILCPURPLE_STATUS_ID_OFFLINE
,
NULL
,
TRUE
,
TRUE
,
FALSE
);
types
=
g_list_append
(
types
,
type
);
return
types
;
}
static
void
silcpurple_set_status
(
PurpleAccount
*
account
,
PurpleStatus
*
status
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
SilcPurple
sg
=
NULL
;
SilcUInt32
mode
;
SilcBuffer
idp
;
unsigned
char
mb
[
4
];
const
char
*
state
;
if
(
gc
!=
NULL
)
sg
=
gc
->
proto_data
;
if
(
status
==
NULL
)
return
;
state
=
purple_status_get_id
(
status
);
if
(
state
==
NULL
)
return
;
if
((
sg
==
NULL
)
||
(
sg
->
conn
==
NULL
))
return
;
mode
=
sg
->
conn
->
local_entry
->
mode
;
mode
&=
~
(
SILC_UMODE_GONE
|
SILC_UMODE_HYPER
|
SILC_UMODE_BUSY
|
SILC_UMODE_INDISPOSED
|
SILC_UMODE_PAGE
);
if
(
!
strcmp
(
state
,
"hyper"
))
mode
|=
SILC_UMODE_HYPER
;
else
if
(
!
strcmp
(
state
,
"away"
))
mode
|=
SILC_UMODE_GONE
;
else
if
(
!
strcmp
(
state
,
"busy"
))
mode
|=
SILC_UMODE_BUSY
;
else
if
(
!
strcmp
(
state
,
"indisposed"
))
mode
|=
SILC_UMODE_INDISPOSED
;
else
if
(
!
strcmp
(
state
,
"page"
))
mode
|=
SILC_UMODE_PAGE
;
/* Send UMODE */
idp
=
silc_id_payload_encode
(
sg
->
conn
->
local_id
,
SILC_ID_CLIENT
);
SILC_PUT32_MSB
(
mode
,
mb
);
silc_client_command_send
(
sg
->
client
,
sg
->
conn
,
SILC_COMMAND_UMODE
,
silcpurple_command_reply
,
NULL
,
2
,
1
,
idp
->
data
,
silc_buffer_len
(
idp
),
2
,
mb
,
sizeof
(
mb
));
silc_buffer_free
(
idp
);
}
/*************************** Connection Routines *****************************/
static
void
silcpurple_keepalive
(
PurpleConnection
*
gc
)
{
SilcPurple
sg
=
gc
->
proto_data
;
silc_packet_send
(
sg
->
conn
->
stream
,
SILC_PACKET_HEARTBEAT
,
0
,
NULL
,
0
);
}
#if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
static
gboolean
silcpurple_scheduler
(
gpointer
*
context
)
{
SilcClient
client
=
(
SilcClient
)
context
;
silc_client_run_one
(
client
);
return
TRUE
;
}
#else
typedef
struct
{
SilcPurple
sg
;
SilcUInt32
fd
;
guint
tag
;
}
*
SilcPurpleTask
;
/* A timeout occurred. Call SILC scheduler. */
static
gboolean
silcpurple_scheduler_timeout
(
gpointer
context
)
{
SilcPurpleTask
task
=
(
SilcPurpleTask
)
context
;
silc_client_run_one
(
task
->
sg
->
client
);
silc_dlist_del
(
task
->
sg
->
tasks
,
task
);
silc_free
(
task
);
return
FALSE
;
}
/* An fd task event occurred. Call SILC scheduler. */
static
void
silcpurple_scheduler_fd
(
gpointer
data
,
gint
fd
,
PurpleInputCondition
cond
)
{
SilcClient
client
=
(
SilcClient
)
data
;
silc_client_run_one
(
client
);
}
/* SILC Scheduler notify callback. This is called whenever task is added to
or deleted from SILC scheduler. It's also called when fd task events
change. Here we add same tasks to glib's main loop. */
static
void
silcpurple_scheduler
(
SilcSchedule
schedule
,
SilcBool
added
,
SilcTask
task
,
SilcBool
fd_task
,
SilcUInt32
fd
,
SilcTaskEvent
event
,
long
seconds
,
long
useconds
,
void
*
context
)
{
SilcClient
client
=
(
SilcClient
)
context
;
PurpleConnection
*
gc
=
client
->
application
;
SilcPurple
sg
=
gc
->
proto_data
;
SilcPurpleTask
ptask
=
NULL
;
if
(
added
)
{
if
(
fd_task
)
{
/* Add fd or change fd events */
PurpleInputCondition
e
=
0
;
silc_dlist_start
(
sg
->
tasks
);
while
((
ptask
=
silc_dlist_get
(
sg
->
tasks
)))
if
(
ptask
->
fd
==
fd
)
{
purple_input_remove
(
ptask
->
tag
);
break
;
}
if
(
event
&
SILC_TASK_READ
)
e
|=
PURPLE_INPUT_READ
;
if
(
event
&
SILC_TASK_WRITE
)
e
|=
PURPLE_INPUT_WRITE
;
if
(
e
)
{
if
(
!
ptask
)
{
ptask
=
silc_calloc
(
1
,
sizeof
(
*
ptask
));
ptask
->
fd
=
fd
;
silc_dlist_add
(
sg
->
tasks
,
ptask
);
}
ptask
->
tag
=
purple_input_add
(
fd
,
e
,
silcpurple_scheduler_fd
,
client
);
}
else
if
(
ptask
)
{
silc_dlist_del
(
sg
->
tasks
,
ptask
);
silc_free
(
ptask
);
}
}
else
{
/* Add timeout */
ptask
=
silc_calloc
(
1
,
sizeof
(
*
ptask
));
ptask
->
sg
=
sg
;
ptask
->
tag
=
purple_timeout_add
((
seconds
*
1000
)
+
(
useconds
/
1000
),
silcpurple_scheduler_timeout
,
ptask
);
silc_dlist_add
(
sg
->
tasks
,
ptask
);
}
}
else
{
if
(
fd_task
)
{
/* Remove fd */
silc_dlist_start
(
sg
->
tasks
);
while
((
ptask
=
silc_dlist_get
(
sg
->
tasks
)))
if
(
ptask
->
fd
==
fd
)
{
purple_input_remove
(
ptask
->
tag
);
silc_dlist_del
(
sg
->
tasks
,
ptask
);
silc_free
(
ptask
);
break
;
}
}
}
}
#endif
/* __SILC_TOOLKIT_VERSION */
static
void
silcpurple_connect_cb
(
SilcClient
client
,
SilcClientConnection
conn
,
SilcClientConnectionStatus
status
,
SilcStatus
error
,
const
char
*
message
,
void
*
context
)
{
PurpleConnection
*
gc
=
context
;
SilcPurple
sg
;
SilcUInt32
mask
;
char
tz
[
16
];
PurpleStoredImage
*
img
;
#ifdef HAVE_SYS_UTSNAME_H
struct
utsname
u
;
#endif
sg
=
gc
->
proto_data
;
switch
(
status
)
{
case
SILC_CLIENT_CONN_SUCCESS
:
case
SILC_CLIENT_CONN_SUCCESS_RESUME
:
sg
->
conn
=
conn
;
/* Connection created successfully */
purple_connection_set_state
(
gc
,
PURPLE_CONNECTED
);
/* Send the server our buddy list */
silcpurple_send_buddylist
(
gc
);
g_unlink
(
silcpurple_session_file
(
purple_account_get_username
(
sg
->
account
)));
/* Send any UMODEs configured for account */
if
(
purple_account_get_bool
(
sg
->
account
,
"block-ims"
,
FALSE
))
{
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
NULL
,
"UMODE"
,
"+P"
,
NULL
);
}
/* Set default attributes */
mask
=
SILC_ATTRIBUTE_MOOD_NORMAL
;
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_STATUS_MOOD
,
SILC_32_TO_PTR
(
mask
),
sizeof
(
SilcUInt32
));
mask
=
SILC_ATTRIBUTE_CONTACT_CHAT
;
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_PREFERRED_CONTACT
,
SILC_32_TO_PTR
(
mask
),
sizeof
(
SilcUInt32
));
#ifdef HAVE_SYS_UTSNAME_H
if
(
!
uname
(
&
u
))
{
SilcAttributeObjDevice
dev
;
memset
(
&
dev
,
0
,
sizeof
(
dev
));
dev
.
type
=
SILC_ATTRIBUTE_DEVICE_COMPUTER
;
dev
.
version
=
u
.
release
;
dev
.
model
=
u
.
sysname
;
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_DEVICE_INFO
,
(
void
*
)
&
dev
,
sizeof
(
dev
));
}
#endif
silc_timezone
(
tz
,
sizeof
(
tz
));
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_TIMEZONE
,
(
void
*
)
tz
,
strlen
(
tz
));
/* Set our buddy icon */
img
=
purple_buddy_icons_find_account_icon
(
sg
->
account
);
silcpurple_buddy_set_icon
(
gc
,
img
);
purple_imgstore_unref
(
img
);
return
;
break
;
case
SILC_CLIENT_CONN_DISCONNECTED
:
/* Disconnected */
if
(
sg
->
resuming
&&
!
sg
->
detaching
)
g_unlink
(
silcpurple_session_file
(
purple_account_get_username
(
sg
->
account
)));
/* Close the connection */
if
(
!
sg
->
detaching
)
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Disconnected by server"
));
else
/* TODO: Does this work correctly? Maybe we need to set wants_to_die? */
purple_account_disconnect
(
purple_connection_get_account
(
gc
));
break
;
case
SILC_CLIENT_CONN_ERROR
:
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Error connecting to SILC Server"
));
g_unlink
(
silcpurple_session_file
(
purple_account_get_username
(
sg
->
account
)));
break
;
case
SILC_CLIENT_CONN_ERROR_KE
:
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
,
_
(
"Key Exchange failed"
));
break
;
case
SILC_CLIENT_CONN_ERROR_AUTH
:
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
_
(
"Authentication failed"
));
break
;
case
SILC_CLIENT_CONN_ERROR_RESUME
:
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Resuming detached session failed. "
"Press Reconnect to create new connection."
));
g_unlink
(
silcpurple_session_file
(
purple_account_get_username
(
sg
->
account
)));
break
;
case
SILC_CLIENT_CONN_ERROR_TIMEOUT
:
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Connection timed out"
));
break
;
}
/* Error */
sg
->
conn
=
NULL
;
}
static
void
silcpurple_stream_created
(
SilcSocketStreamStatus
status
,
SilcStream
stream
,
void
*
context
)
{
PurpleConnection
*
gc
=
context
;
SilcPurple
sg
;
SilcClient
client
;
SilcClientConnectionParams
params
;
const
char
*
dfile
;
sg
=
gc
->
proto_data
;
if
(
status
!=
SILC_SOCKET_OK
)
{
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Connection failed"
));
silc_pkcs_public_key_free
(
sg
->
public_key
);
silc_pkcs_private_key_free
(
sg
->
private_key
);
silc_free
(
sg
);
gc
->
proto_data
=
NULL
;
return
;
}
client
=
sg
->
client
;
/* Get session detachment data, if available */
memset
(
&
params
,
0
,
sizeof
(
params
));
dfile
=
silcpurple_session_file
(
purple_account_get_username
(
sg
->
account
));
params
.
detach_data
=
(
unsigned
char
*
)
silc_file_readfile
(
dfile
,
&
params
.
detach_data_len
);
if
(
params
.
detach_data
)
params
.
detach_data
[
params
.
detach_data_len
]
=
0
;
params
.
ignore_requested_attributes
=
FALSE
;
params
.
pfs
=
purple_account_get_bool
(
sg
->
account
,
"pfs"
,
FALSE
);
/* Progress */
if
(
params
.
detach_data
)
{
purple_connection_update_progress
(
gc
,
_
(
"Resuming session"
),
2
,
5
);
sg
->
resuming
=
TRUE
;
}
else
{
purple_connection_update_progress
(
gc
,
_
(
"Performing key exchange"
),
2
,
5
);
}
/* Perform SILC Key Exchange. */
silc_client_key_exchange
(
client
,
&
params
,
sg
->
public_key
,
sg
->
private_key
,
stream
,
SILC_CONN_SERVER
,
silcpurple_connect_cb
,
gc
);
silc_free
(
params
.
detach_data
);
}
static
void
silcpurple_login_connected
(
gpointer
data
,
gint
source
,
const
gchar
*
error_message
)
{
PurpleConnection
*
gc
=
data
;
SilcPurple
sg
;
g_return_if_fail
(
gc
!=
NULL
);
sg
=
gc
->
proto_data
;
if
(
source
<
0
)
{
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Connection failed"
));
silc_pkcs_public_key_free
(
sg
->
public_key
);
silc_pkcs_private_key_free
(
sg
->
private_key
);
silc_free
(
sg
);
gc
->
proto_data
=
NULL
;
return
;
}
silc_hash_alloc
((
unsigned
char
*
)
"sha1"
,
&
sg
->
sha1hash
);
/* Wrap socket to TCP stream */
silc_socket_tcp_stream_create
(
source
,
TRUE
,
FALSE
,
sg
->
client
->
schedule
,
silcpurple_stream_created
,
gc
);
}
static
void
silcpurple_continue_running
(
SilcPurple
sg
)
{
PurpleConnection
*
gc
=
sg
->
gc
;
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
/* Connect to the SILC server */
if
(
purple_proxy_connect
(
gc
,
account
,
purple_account_get_string
(
account
,
"server"
,
"silc.silcnet.org"
),
purple_account_get_int
(
account
,
"port"
,
706
),
silcpurple_login_connected
,
gc
)
==
NULL
)
{
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
_
(
"Unable to connect"
));
gc
->
proto_data
=
NULL
;
silc_free
(
sg
);
return
;
}
}
static
void
silcpurple_got_password_cb
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
)
{
SilcPurple
sg
=
(
SilcPurple
)
gc
->
proto_data
;
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
char
pkd
[
256
],
prd
[
256
];
const
char
*
password
;
gboolean
remember
;
/* The password prompt dialog doesn't get disposed if the account disconnects */
if
(
!
PURPLE_CONNECTION_IS_VALID
(
gc
))
return
;
password
=
purple_request_fields_get_string
(
fields
,
"password"
);
remember
=
purple_request_fields_get_bool
(
fields
,
"remember"
);
if
(
!
password
||
!*
password
)
{
purple_notify_error
(
gc
,
NULL
,
_
(
"Password is required to sign on."
),
NULL
);
gc
->
proto_data
=
NULL
;
silc_free
(
sg
);
return
;
}
if
(
remember
)
purple_account_set_remember_password
(
account
,
TRUE
);
purple_account_set_password
(
account
,
password
);
/* Load SILC key pair */
g_snprintf
(
pkd
,
sizeof
(
pkd
),
"%s"
G_DIR_SEPARATOR_S
"public_key.pub"
,
silcpurple_silcdir
());
g_snprintf
(
prd
,
sizeof
(
prd
),
"%s"
G_DIR_SEPARATOR_S
"private_key.prv"
,
silcpurple_silcdir
());
if
(
!
silc_load_key_pair
((
char
*
)
purple_account_get_string
(
account
,
"public-key"
,
pkd
),
(
char
*
)
purple_account_get_string
(
account
,
"private-key"
,
prd
),
password
,
&
sg
->
public_key
,
&
sg
->
private_key
))
{
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Unable to load SILC key pair"
));
gc
->
proto_data
=
NULL
;
silc_free
(
sg
);
return
;
}
silcpurple_continue_running
(
sg
);
}
static
void
silcpurple_no_password_cb
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
)
{
SilcPurple
sg
;
/* The password prompt dialog doesn't get disposed if the account disconnects */
if
(
!
PURPLE_CONNECTION_IS_VALID
(
gc
))
return
;
sg
=
gc
->
proto_data
;
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Unable to load SILC key pair"
));
gc
->
proto_data
=
NULL
;
silc_free
(
sg
);
}
static
void
silcpurple_running
(
SilcClient
client
,
void
*
context
)
{
SilcPurple
sg
=
context
;
PurpleConnection
*
gc
=
sg
->
gc
;
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
char
pkd
[
256
],
prd
[
256
];
/* Progress */
purple_connection_update_progress
(
gc
,
_
(
"Connecting to SILC Server"
),
1
,
5
);
/* Load SILC key pair */
g_snprintf
(
pkd
,
sizeof
(
pkd
),
"%s"
G_DIR_SEPARATOR_S
"public_key.pub"
,
silcpurple_silcdir
());
g_snprintf
(
prd
,
sizeof
(
prd
),
"%s"
G_DIR_SEPARATOR_S
"private_key.prv"
,
silcpurple_silcdir
());
if
(
!
silc_load_key_pair
((
char
*
)
purple_account_get_string
(
account
,
"public-key"
,
pkd
),
(
char
*
)
purple_account_get_string
(
account
,
"private-key"
,
prd
),
(
gc
->
password
==
NULL
)
?
""
:
gc
->
password
,
&
sg
->
public_key
,
&
sg
->
private_key
))
{
if
(
!
purple_account_get_password
(
account
))
{
purple_account_request_password
(
account
,
G_CALLBACK
(
silcpurple_got_password_cb
),
G_CALLBACK
(
silcpurple_no_password_cb
),
gc
);
return
;
}
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Unable to load SILC key pair"
));
gc
->
proto_data
=
NULL
;
silc_free
(
sg
);
return
;
}
silcpurple_continue_running
(
sg
);
}
static
void
silcpurple_login
(
PurpleAccount
*
account
)
{
SilcClient
client
;
PurpleConnection
*
gc
;
SilcPurple
sg
;
SilcClientParams
params
;
const
char
*
cipher
,
*
hmac
;
char
*
username
,
*
hostname
,
*
realname
,
**
up
;
int
i
;
gc
=
account
->
gc
;
if
(
!
gc
)
return
;
gc
->
proto_data
=
NULL
;
memset
(
&
params
,
0
,
sizeof
(
params
));
strcat
(
params
.
nickname_format
,
"%n#a"
);
/* Allocate SILC client */
client
=
silc_client_alloc
(
&
ops
,
&
params
,
gc
,
NULL
);
if
(
!
client
)
{
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Out of memory"
));
return
;
}
/* Get username, real name and local hostname for SILC library */
if
(
!
purple_account_get_username
(
account
))
purple_account_set_username
(
account
,
silc_get_username
());
username
=
(
char
*
)
purple_account_get_username
(
account
);
up
=
g_strsplit
(
username
,
"@"
,
2
);
username
=
g_strdup
(
up
[
0
]);
g_strfreev
(
up
);
if
(
!
purple_account_get_user_info
(
account
))
{
purple_account_set_user_info
(
account
,
silc_get_real_name
());
if
(
!
purple_account_get_user_info
(
account
))
purple_account_set_user_info
(
account
,
"John T. Noname"
);
}
realname
=
(
char
*
)
purple_account_get_user_info
(
account
);
hostname
=
silc_net_localhost
();
purple_connection_set_display_name
(
gc
,
username
);
/* Register requested cipher and HMAC */
cipher
=
purple_account_get_string
(
account
,
"cipher"
,
SILC_DEFAULT_CIPHER
);
for
(
i
=
0
;
silc_default_ciphers
[
i
].
name
;
i
++
)
if
(
!
strcmp
(
silc_default_ciphers
[
i
].
name
,
cipher
))
{
silc_cipher_register
(
&
(
silc_default_ciphers
[
i
]));
break
;
}
hmac
=
purple_account_get_string
(
account
,
"hmac"
,
SILC_DEFAULT_HMAC
);
for
(
i
=
0
;
silc_default_hmacs
[
i
].
name
;
i
++
)
if
(
!
strcmp
(
silc_default_hmacs
[
i
].
name
,
hmac
))
{
silc_hmac_register
(
&
(
silc_default_hmacs
[
i
]));
break
;
}
sg
=
silc_calloc
(
1
,
sizeof
(
*
sg
));
if
(
!
sg
)
return
;
sg
->
client
=
client
;
sg
->
gc
=
gc
;
sg
->
account
=
account
;
gc
->
proto_data
=
sg
;
/* Init SILC client */
if
(
!
silc_client_init
(
client
,
username
,
hostname
,
realname
,
silcpurple_running
,
sg
))
{
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Unable to initialize SILC protocol"
));
gc
->
proto_data
=
NULL
;
silc_free
(
sg
);
silc_free
(
hostname
);
g_free
(
username
);
return
;
}
silc_free
(
hostname
);
g_free
(
username
);
/* Check the ~/.silc dir and create it, and new key pair if necessary. */
if
(
!
silcpurple_check_silc_dir
(
gc
))
{
purple_connection_error_reason
(
gc
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
_
(
"Error loading SILC key pair"
));
gc
->
proto_data
=
NULL
;
silc_free
(
sg
);
return
;
}
#if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
/* Schedule SILC using Glib's event loop */
sg
->
scheduler
=
purple_timeout_add
(
300
,
(
GSourceFunc
)
silcpurple_scheduler
,
client
);
#else
/* Run SILC scheduler */
sg
->
tasks
=
silc_dlist_init
();
silc_schedule_set_notify
(
client
->
schedule
,
silcpurple_scheduler
,
client
);
silc_client_run_one
(
client
);
#endif
/* __SILC_TOOLKIT_VERSION */
}
static
int
silcpurple_close_final
(
gpointer
*
context
)
{
SilcPurple
sg
=
(
SilcPurple
)
context
;
purple_debug_info
(
"silc"
,
"Finalizing SilcPurple %p
\n
"
,
sg
);
silc_client_stop
(
sg
->
client
,
NULL
,
NULL
);
silc_client_free
(
sg
->
client
);
if
(
sg
->
sha1hash
)
silc_hash_free
(
sg
->
sha1hash
);
if
(
sg
->
mimeass
)
silc_mime_assembler_free
(
sg
->
mimeass
);
silc_free
(
sg
);
return
0
;
}
static
void
silcpurple_close
(
PurpleConnection
*
gc
)
{
SilcPurple
sg
=
gc
->
proto_data
;
#if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
SilcPurpleTask
task
;
#endif
/* __SILC_TOOLKIT_VERSION */
GHashTable
*
ui_info
;
const
char
*
ui_name
=
NULL
,
*
ui_website
=
NULL
;
char
*
quit_msg
;
g_return_if_fail
(
sg
!=
NULL
);
ui_info
=
purple_core_get_ui_info
();
if
(
ui_info
)
{
ui_name
=
g_hash_table_lookup
(
ui_info
,
"name"
);
ui_website
=
g_hash_table_lookup
(
ui_info
,
"website"
);
}
if
(
!
ui_name
||
!
ui_website
)
{
ui_name
=
"Pidgin"
;
ui_website
=
PURPLE_WEBSITE
;
}
quit_msg
=
g_strdup_printf
(
_
(
"Download %s: %s"
),
ui_name
,
ui_website
);
/* Send QUIT */
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
NULL
,
"QUIT"
,
quit_msg
,
NULL
);
g_free
(
quit_msg
);
if
(
sg
->
conn
)
silc_client_close_connection
(
sg
->
client
,
sg
->
conn
);
#if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
if
(
sg
->
conn
)
silc_client_run_one
(
sg
->
client
);
silc_schedule_set_notify
(
sg
->
client
->
schedule
,
NULL
,
NULL
);
silc_dlist_start
(
sg
->
tasks
);
while
((
task
=
silc_dlist_get
(
sg
->
tasks
)))
{
purple_input_remove
(
task
->
tag
);
silc_free
(
task
);
}
silc_dlist_uninit
(
sg
->
tasks
);
#endif
/* __SILC_TOOLKIT_VERSION */
purple_timeout_remove
(
sg
->
scheduler
);
purple_debug_info
(
"silc"
,
"Scheduling destruction of SilcPurple %p
\n
"
,
sg
);
purple_timeout_add
(
1
,
(
GSourceFunc
)
silcpurple_close_final
,
sg
);
}
/****************************** Protocol Actions *****************************/
static
void
silcpurple_attrs_cancel
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
)
{
/* Nothing */
}
static
void
silcpurple_attrs_cb
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
)
{
SilcPurple
sg
=
gc
->
proto_data
;
SilcClient
client
=
sg
->
client
;
SilcClientConnection
conn
=
sg
->
conn
;
PurpleRequestField
*
f
;
char
*
tmp
;
SilcUInt32
tmp_len
,
mask
;
SilcAttributeObjService
service
;
SilcAttributeObjDevice
dev
;
SilcVCardStruct
vcard
;
const
char
*
val
;
sg
=
gc
->
proto_data
;
if
(
!
sg
)
return
;
memset
(
&
service
,
0
,
sizeof
(
service
));
memset
(
&
dev
,
0
,
sizeof
(
dev
));
memset
(
&
vcard
,
0
,
sizeof
(
vcard
));
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_USER_INFO
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_SERVICE
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_STATUS_MOOD
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_STATUS_FREETEXT
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_STATUS_MESSAGE
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_PREFERRED_LANGUAGE
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_PREFERRED_CONTACT
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_TIMEZONE
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_GEOLOCATION
,
NULL
);
silc_client_attribute_del
(
client
,
conn
,
SILC_ATTRIBUTE_DEVICE_INFO
,
NULL
);
/* Set mood */
mask
=
0
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_normal"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_NORMAL
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_happy"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_HAPPY
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_sad"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_SAD
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_angry"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_ANGRY
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_jealous"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_JEALOUS
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_ashamed"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_ASHAMED
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_invincible"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_INVINCIBLE
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_inlove"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_INLOVE
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_sleepy"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_SLEEPY
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_bored"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_BORED
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_excited"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_EXCITED
;
f
=
purple_request_fields_get_field
(
fields
,
"mood_anxious"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_MOOD_ANXIOUS
;
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_STATUS_MOOD
,
SILC_32_TO_PTR
(
mask
),
sizeof
(
SilcUInt32
));
/* Set preferred contact */
mask
=
0
;
f
=
purple_request_fields_get_field
(
fields
,
"contact_chat"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_CONTACT_CHAT
;
f
=
purple_request_fields_get_field
(
fields
,
"contact_email"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_CONTACT_EMAIL
;
f
=
purple_request_fields_get_field
(
fields
,
"contact_call"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_CONTACT_CALL
;
f
=
purple_request_fields_get_field
(
fields
,
"contact_sms"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_CONTACT_SMS
;
f
=
purple_request_fields_get_field
(
fields
,
"contact_mms"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_CONTACT_MMS
;
f
=
purple_request_fields_get_field
(
fields
,
"contact_video"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
mask
|=
SILC_ATTRIBUTE_CONTACT_VIDEO
;
if
(
mask
)
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_PREFERRED_CONTACT
,
SILC_32_TO_PTR
(
mask
),
sizeof
(
SilcUInt32
));
/* Set status text */
val
=
NULL
;
f
=
purple_request_fields_get_field
(
fields
,
"status_text"
);
if
(
f
)
val
=
purple_request_field_string_get_value
(
f
);
if
(
val
&&
*
val
)
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_STATUS_FREETEXT
,
(
void
*
)
val
,
strlen
(
val
));
/* Set vcard */
val
=
NULL
;
f
=
purple_request_fields_get_field
(
fields
,
"vcard"
);
if
(
f
)
val
=
purple_request_field_string_get_value
(
f
);
if
(
val
&&
*
val
)
{
purple_account_set_string
(
sg
->
account
,
"vcard"
,
val
);
tmp
=
silc_file_readfile
(
val
,
&
tmp_len
);
if
(
tmp
)
{
tmp
[
tmp_len
]
=
0
;
if
(
silc_vcard_decode
((
unsigned
char
*
)
tmp
,
tmp_len
,
&
vcard
))
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_USER_INFO
,
(
void
*
)
&
vcard
,
sizeof
(
vcard
));
}
silc_vcard_free
(
&
vcard
);
silc_free
(
tmp
);
}
else
{
purple_account_set_string
(
sg
->
account
,
"vcard"
,
""
);
}
#ifdef HAVE_SYS_UTSNAME_H
/* Set device info */
f
=
purple_request_fields_get_field
(
fields
,
"device"
);
if
(
f
&&
purple_request_field_bool_get_value
(
f
))
{
struct
utsname
u
;
if
(
!
uname
(
&
u
))
{
dev
.
type
=
SILC_ATTRIBUTE_DEVICE_COMPUTER
;
dev
.
version
=
u
.
release
;
dev
.
model
=
u
.
sysname
;
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_DEVICE_INFO
,
(
void
*
)
&
dev
,
sizeof
(
dev
));
}
}
#endif
/* Set timezone */
val
=
NULL
;
f
=
purple_request_fields_get_field
(
fields
,
"timezone"
);
if
(
f
)
val
=
purple_request_field_string_get_value
(
f
);
if
(
val
&&
*
val
)
silc_client_attribute_add
(
client
,
conn
,
SILC_ATTRIBUTE_TIMEZONE
,
(
void
*
)
val
,
strlen
(
val
));
}
static
void
silcpurple_attrs
(
PurplePluginAction
*
action
)
{
PurpleConnection
*
gc
=
(
PurpleConnection
*
)
action
->
context
;
SilcPurple
sg
=
gc
->
proto_data
;
SilcClient
client
=
sg
->
client
;
SilcClientConnection
conn
=
sg
->
conn
;
PurpleRequestFields
*
fields
;
PurpleRequestFieldGroup
*
g
;
PurpleRequestField
*
f
;
SilcHashTable
attrs
;
SilcAttributePayload
attr
;
gboolean
mnormal
=
TRUE
,
mhappy
=
FALSE
,
msad
=
FALSE
,
mangry
=
FALSE
,
mjealous
=
FALSE
,
mashamed
=
FALSE
,
minvincible
=
FALSE
,
minlove
=
FALSE
,
msleepy
=
FALSE
,
mbored
=
FALSE
,
mexcited
=
FALSE
,
manxious
=
FALSE
;
gboolean
cemail
=
FALSE
,
ccall
=
FALSE
,
csms
=
FALSE
,
cmms
=
FALSE
,
cchat
=
TRUE
,
cvideo
=
FALSE
;
gboolean
device
=
TRUE
;
char
status
[
1024
],
tz
[
16
];
sg
=
gc
->
proto_data
;
if
(
!
sg
)
return
;
memset
(
status
,
0
,
sizeof
(
status
));
attrs
=
silc_client_attributes_get
(
client
,
conn
);
if
(
attrs
)
{
if
(
silc_hash_table_find
(
attrs
,
SILC_32_TO_PTR
(
SILC_ATTRIBUTE_STATUS_MOOD
),
NULL
,
(
void
*
)
&
attr
))
{
SilcUInt32
mood
=
0
;
silc_attribute_get_object
(
attr
,
&
mood
,
sizeof
(
mood
));
mnormal
=
!
mood
;
mhappy
=
(
mood
&
SILC_ATTRIBUTE_MOOD_HAPPY
);
msad
=
(
mood
&
SILC_ATTRIBUTE_MOOD_SAD
);
mangry
=
(
mood
&
SILC_ATTRIBUTE_MOOD_ANGRY
);
mjealous
=
(
mood
&
SILC_ATTRIBUTE_MOOD_JEALOUS
);
mashamed
=
(
mood
&
SILC_ATTRIBUTE_MOOD_ASHAMED
);
minvincible
=
(
mood
&
SILC_ATTRIBUTE_MOOD_INVINCIBLE
);
minlove
=
(
mood
&
SILC_ATTRIBUTE_MOOD_INLOVE
);
msleepy
=
(
mood
&
SILC_ATTRIBUTE_MOOD_SLEEPY
);
mbored
=
(
mood
&
SILC_ATTRIBUTE_MOOD_BORED
);
mexcited
=
(
mood
&
SILC_ATTRIBUTE_MOOD_EXCITED
);
manxious
=
(
mood
&
SILC_ATTRIBUTE_MOOD_ANXIOUS
);
}
if
(
silc_hash_table_find
(
attrs
,
SILC_32_TO_PTR
(
SILC_ATTRIBUTE_PREFERRED_CONTACT
),
NULL
,
(
void
*
)
&
attr
))
{
SilcUInt32
contact
=
0
;
silc_attribute_get_object
(
attr
,
&
contact
,
sizeof
(
contact
));
cemail
=
(
contact
&
SILC_ATTRIBUTE_CONTACT_EMAIL
);
ccall
=
(
contact
&
SILC_ATTRIBUTE_CONTACT_CALL
);
csms
=
(
contact
&
SILC_ATTRIBUTE_CONTACT_SMS
);
cmms
=
(
contact
&
SILC_ATTRIBUTE_CONTACT_MMS
);
cchat
=
(
contact
&
SILC_ATTRIBUTE_CONTACT_CHAT
);
cvideo
=
(
contact
&
SILC_ATTRIBUTE_CONTACT_VIDEO
);
}
if
(
silc_hash_table_find
(
attrs
,
SILC_32_TO_PTR
(
SILC_ATTRIBUTE_STATUS_FREETEXT
),
NULL
,
(
void
*
)
&
attr
))
silc_attribute_get_object
(
attr
,
&
status
,
sizeof
(
status
));
if
(
!
silc_hash_table_find
(
attrs
,
SILC_32_TO_PTR
(
SILC_ATTRIBUTE_DEVICE_INFO
),
NULL
,
(
void
*
)
&
attr
))
device
=
FALSE
;
}
fields
=
purple_request_fields_new
();
g
=
purple_request_field_group_new
(
NULL
);
f
=
purple_request_field_label_new
(
"l3"
,
_
(
"Your Current Mood"
));
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_normal"
,
_
(
"Normal"
),
mnormal
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_happy"
,
_
(
"Happy"
),
mhappy
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_sad"
,
_
(
"Sad"
),
msad
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_angry"
,
_
(
"Angry"
),
mangry
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_jealous"
,
_
(
"Jealous"
),
mjealous
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_ashamed"
,
_
(
"Ashamed"
),
mashamed
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_invincible"
,
_
(
"Invincible"
),
minvincible
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_inlove"
,
_
(
"In love"
),
minlove
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_sleepy"
,
_
(
"Sleepy"
),
msleepy
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_bored"
,
_
(
"Bored"
),
mbored
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_excited"
,
_
(
"Excited"
),
mexcited
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"mood_anxious"
,
_
(
"Anxious"
),
manxious
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_label_new
(
"l4"
,
_
(
"
\n
Your Preferred Contact Methods"
));
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"contact_chat"
,
_
(
"Chat"
),
cchat
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"contact_email"
,
_
(
"Email"
),
cemail
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"contact_call"
,
_
(
"Phone"
),
ccall
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"contact_sms"
,
_
(
"SMS"
),
csms
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"contact_mms"
,
_
(
"MMS"
),
cmms
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_bool_new
(
"contact_video"
,
_
(
"Video conferencing"
),
cvideo
);
purple_request_field_group_add_field
(
g
,
f
);
purple_request_fields_add_group
(
fields
,
g
);
g
=
purple_request_field_group_new
(
NULL
);
f
=
purple_request_field_string_new
(
"status_text"
,
_
(
"Your Current Status"
),
status
[
0
]
?
status
:
NULL
,
TRUE
);
purple_request_field_group_add_field
(
g
,
f
);
purple_request_fields_add_group
(
fields
,
g
);
g
=
purple_request_field_group_new
(
NULL
);
#if 0
f = purple_request_field_label_new("l2", _("Online Services"));
purple_request_field_group_add_field(g, f);
f = purple_request_field_bool_new("services",
_("Let others see what services you are using"),
TRUE);
purple_request_field_group_add_field(g, f);
#endif
#ifdef HAVE_SYS_UTSNAME_H
f
=
purple_request_field_bool_new
(
"device"
,
_
(
"Let others see what computer you are using"
),
device
);
purple_request_field_group_add_field
(
g
,
f
);
#endif
purple_request_fields_add_group
(
fields
,
g
);
g
=
purple_request_field_group_new
(
NULL
);
f
=
purple_request_field_string_new
(
"vcard"
,
_
(
"Your VCard File"
),
purple_account_get_string
(
sg
->
account
,
"vcard"
,
""
),
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
silc_timezone
(
tz
,
sizeof
(
tz
));
f
=
purple_request_field_string_new
(
"timezone"
,
_
(
"Timezone (UTC)"
),
tz
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
purple_request_fields_add_group
(
fields
,
g
);
purple_request_fields
(
gc
,
_
(
"User Online Status Attributes"
),
_
(
"User Online Status Attributes"
),
_
(
"You can let other users see your online status information "
"and your personal information. Please fill the information "
"you would like other users to see about yourself."
),
fields
,
_
(
"OK"
),
G_CALLBACK
(
silcpurple_attrs_cb
),
_
(
"Cancel"
),
G_CALLBACK
(
silcpurple_attrs_cancel
),
gc
->
account
,
NULL
,
NULL
,
gc
);
}
static
void
silcpurple_detach
(
PurplePluginAction
*
action
)
{
PurpleConnection
*
gc
=
(
PurpleConnection
*
)
action
->
context
;
SilcPurple
sg
;
if
(
!
gc
)
return
;
sg
=
gc
->
proto_data
;
if
(
!
sg
)
return
;
/* Call DETACH */
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
"DETACH"
);
sg
->
detaching
=
TRUE
;
}
static
void
silcpurple_view_motd
(
PurplePluginAction
*
action
)
{
PurpleConnection
*
gc
=
(
PurpleConnection
*
)
action
->
context
;
SilcPurple
sg
;
char
*
tmp
;
if
(
!
gc
)
return
;
sg
=
gc
->
proto_data
;
if
(
!
sg
)
return
;
if
(
!
sg
->
motd
)
{
purple_notify_error
(
gc
,
_
(
"Message of the Day"
),
_
(
"No Message of the Day available"
),
_
(
"There is no Message of the Day associated with this connection"
));
return
;
}
tmp
=
g_markup_escape_text
(
sg
->
motd
,
-1
);
purple_notify_formatted
(
gc
,
NULL
,
_
(
"Message of the Day"
),
NULL
,
tmp
,
NULL
,
NULL
);
g_free
(
tmp
);
}
static
void
silcpurple_create_keypair_cancel
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
)
{
/* Nothing */
}
static
void
silcpurple_create_keypair_cb
(
PurpleConnection
*
gc
,
PurpleRequestFields
*
fields
)
{
SilcPurple
sg
;
PurpleRequestField
*
f
;
const
char
*
val
,
*
pkfile
=
NULL
,
*
prfile
=
NULL
;
const
char
*
pass1
=
NULL
,
*
pass2
=
NULL
,
*
un
=
NULL
,
*
hn
=
NULL
;
const
char
*
rn
=
NULL
,
*
e
=
NULL
,
*
o
=
NULL
,
*
c
=
NULL
;
char
*
identifier
;
int
keylen
=
SILCPURPLE_DEF_PKCS_LEN
;
SilcPublicKey
public_key
;
sg
=
gc
->
proto_data
;
if
(
!
sg
)
return
;
val
=
NULL
;
f
=
purple_request_fields_get_field
(
fields
,
"pass1"
);
if
(
f
)
val
=
purple_request_field_string_get_value
(
f
);
if
(
val
&&
*
val
)
pass1
=
val
;
else
pass1
=
""
;
val
=
NULL
;
f
=
purple_request_fields_get_field
(
fields
,
"pass2"
);
if
(
f
)
val
=
purple_request_field_string_get_value
(
f
);
if
(
val
&&
*
val
)
pass2
=
val
;
else
pass2
=
""
;
if
(
strcmp
(
pass1
,
pass2
))
{
purple_notify_error
(
gc
,
_
(
"Create New SILC Key Pair"
),
_
(
"Passphrases do not match"
),
NULL
);
return
;
}
val
=
NULL
;
f
=
purple_request_fields_get_field
(
fields
,
"key"
);
if
(
f
)
val
=
purple_request_field_string_get_value
(
f
);
if
(
val
&&
*
val
)
keylen
=
atoi
(
val
);
f
=
purple_request_fields_get_field
(
fields
,
"pkfile"
);
if
(
f
)
pkfile
=
purple_request_field_string_get_value
(
f
);
f
=
purple_request_fields_get_field
(
fields
,
"prfile"
);
if
(
f
)
prfile
=
purple_request_field_string_get_value
(
f
);
f
=
purple_request_fields_get_field
(
fields
,
"un"
);
if
(
f
)
un
=
purple_request_field_string_get_value
(
f
);
f
=
purple_request_fields_get_field
(
fields
,
"hn"
);
if
(
f
)
hn
=
purple_request_field_string_get_value
(
f
);
f
=
purple_request_fields_get_field
(
fields
,
"rn"
);
if
(
f
)
rn
=
purple_request_field_string_get_value
(
f
);
f
=
purple_request_fields_get_field
(
fields
,
"e"
);
if
(
f
)
e
=
purple_request_field_string_get_value
(
f
);
f
=
purple_request_fields_get_field
(
fields
,
"o"
);
if
(
f
)
o
=
purple_request_field_string_get_value
(
f
);
f
=
purple_request_fields_get_field
(
fields
,
"c"
);
if
(
f
)
c
=
purple_request_field_string_get_value
(
f
);
identifier
=
silc_pkcs_silc_encode_identifier
((
char
*
)
un
,
(
char
*
)
hn
,
(
char
*
)
rn
,
(
char
*
)
e
,
(
char
*
)
o
,
(
char
*
)
c
,
NULL
);
/* Create the key pair */
if
(
!
silc_create_key_pair
(
SILCPURPLE_DEF_PKCS
,
keylen
,
pkfile
,
prfile
,
identifier
,
pass1
,
&
public_key
,
NULL
,
FALSE
))
{
purple_notify_error
(
gc
,
_
(
"Create New SILC Key Pair"
),
_
(
"Key Pair Generation failed"
),
NULL
);
return
;
}
silcpurple_show_public_key
(
sg
,
NULL
,
public_key
,
NULL
,
NULL
);
silc_pkcs_public_key_free
(
public_key
);
silc_free
(
identifier
);
}
static
void
silcpurple_create_keypair
(
PurplePluginAction
*
action
)
{
PurpleConnection
*
gc
=
(
PurpleConnection
*
)
action
->
context
;
SilcPurple
sg
=
gc
->
proto_data
;
PurpleRequestFields
*
fields
;
PurpleRequestFieldGroup
*
g
;
PurpleRequestField
*
f
;
const
char
*
username
,
*
realname
;
char
*
hostname
,
**
u
;
char
tmp
[
256
],
pkd
[
256
],
pkd2
[
256
],
prd
[
256
],
prd2
[
256
];
username
=
purple_account_get_username
(
sg
->
account
);
u
=
g_strsplit
(
username
,
"@"
,
2
);
username
=
u
[
0
];
realname
=
purple_account_get_user_info
(
sg
->
account
);
hostname
=
silc_net_localhost
();
g_snprintf
(
tmp
,
sizeof
(
tmp
),
"%s@%s"
,
username
,
hostname
);
g_snprintf
(
pkd2
,
sizeof
(
pkd2
),
"%s"
G_DIR_SEPARATOR_S
"public_key.pub"
,
silcpurple_silcdir
());
g_snprintf
(
prd2
,
sizeof
(
prd2
),
"%s"
G_DIR_SEPARATOR_S
"private_key.prv"
,
silcpurple_silcdir
());
g_snprintf
(
pkd
,
sizeof
(
pkd
)
-
1
,
"%s"
,
purple_account_get_string
(
gc
->
account
,
"public-key"
,
pkd2
));
g_snprintf
(
prd
,
sizeof
(
prd
)
-
1
,
"%s"
,
purple_account_get_string
(
gc
->
account
,
"private-key"
,
prd2
));
fields
=
purple_request_fields_new
();
g
=
purple_request_field_group_new
(
NULL
);
f
=
purple_request_field_string_new
(
"key"
,
_
(
"Key length"
),
"2048"
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"pkfile"
,
_
(
"Public key file"
),
pkd
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"prfile"
,
_
(
"Private key file"
),
prd
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
purple_request_fields_add_group
(
fields
,
g
);
g
=
purple_request_field_group_new
(
NULL
);
f
=
purple_request_field_string_new
(
"un"
,
_
(
"Username"
),
username
?
username
:
""
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"hn"
,
_
(
"Hostname"
),
hostname
?
hostname
:
""
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"rn"
,
_
(
"Real name"
),
realname
?
realname
:
""
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"e"
,
_
(
"Email"
),
tmp
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"o"
,
_
(
"Organization"
),
""
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"c"
,
_
(
"Country"
),
""
,
FALSE
);
purple_request_field_group_add_field
(
g
,
f
);
purple_request_fields_add_group
(
fields
,
g
);
g
=
purple_request_field_group_new
(
NULL
);
f
=
purple_request_field_string_new
(
"pass1"
,
_
(
"Passphrase"
),
""
,
FALSE
);
purple_request_field_string_set_masked
(
f
,
TRUE
);
purple_request_field_group_add_field
(
g
,
f
);
f
=
purple_request_field_string_new
(
"pass2"
,
_
(
"Passphrase (retype)"
),
""
,
FALSE
);
purple_request_field_string_set_masked
(
f
,
TRUE
);
purple_request_field_group_add_field
(
g
,
f
);
purple_request_fields_add_group
(
fields
,
g
);
purple_request_fields
(
gc
,
_
(
"Create New SILC Key Pair"
),
_
(
"Create New SILC Key Pair"
),
NULL
,
fields
,
_
(
"Generate Key Pair"
),
G_CALLBACK
(
silcpurple_create_keypair_cb
),
_
(
"Cancel"
),
G_CALLBACK
(
silcpurple_create_keypair_cancel
),
gc
->
account
,
NULL
,
NULL
,
gc
);
g_strfreev
(
u
);
silc_free
(
hostname
);
}
static
void
silcpurple_change_pass
(
PurplePluginAction
*
action
)
{
PurpleConnection
*
gc
=
(
PurpleConnection
*
)
action
->
context
;
purple_account_request_change_password
(
purple_connection_get_account
(
gc
));
}
static
void
silcpurple_change_passwd
(
PurpleConnection
*
gc
,
const
char
*
old
,
const
char
*
new
)
{
char
prd
[
256
];
g_snprintf
(
prd
,
sizeof
(
prd
),
"%s"
G_DIR_SEPARATOR_S
"private_key.pub"
,
silcpurple_silcdir
());
silc_change_private_key_passphrase
(
purple_account_get_string
(
gc
->
account
,
"private-key"
,
prd
),
old
?
old
:
""
,
new
?
new
:
""
);
}
static
void
silcpurple_show_set_info
(
PurplePluginAction
*
action
)
{
PurpleConnection
*
gc
=
(
PurpleConnection
*
)
action
->
context
;
purple_account_request_change_user_info
(
purple_connection_get_account
(
gc
));
}
static
void
silcpurple_set_info
(
PurpleConnection
*
gc
,
const
char
*
text
)
{
}
static
GList
*
silcpurple_actions
(
PurplePlugin
*
plugin
,
gpointer
context
)
{
GList
*
list
=
NULL
;
PurplePluginAction
*
act
;
act
=
purple_plugin_action_new
(
_
(
"Online Status"
),
silcpurple_attrs
);
list
=
g_list_append
(
list
,
act
);
act
=
purple_plugin_action_new
(
_
(
"Detach From Server"
),
silcpurple_detach
);
list
=
g_list_append
(
list
,
act
);
act
=
purple_plugin_action_new
(
_
(
"View Message of the Day"
),
silcpurple_view_motd
);
list
=
g_list_append
(
list
,
act
);
act
=
purple_plugin_action_new
(
_
(
"Create SILC Key Pair..."
),
silcpurple_create_keypair
);
list
=
g_list_append
(
list
,
act
);
act
=
purple_plugin_action_new
(
_
(
"Change Password..."
),
silcpurple_change_pass
);
list
=
g_list_append
(
list
,
act
);
act
=
purple_plugin_action_new
(
_
(
"Set User Info..."
),
silcpurple_show_set_info
);
list
=
g_list_append
(
list
,
act
);
return
list
;
}
/******************************* IM Routines *********************************/
typedef
struct
{
char
*
nick
;
char
*
message
;
SilcUInt32
message_len
;
SilcMessageFlags
flags
;
PurpleMessageFlags
gflags
;
}
*
SilcPurpleIM
;
static
void
silcpurple_send_im_resolved
(
SilcClient
client
,
SilcClientConnection
conn
,
SilcStatus
status
,
SilcDList
clients
,
void
*
context
)
{
PurpleConnection
*
gc
=
client
->
application
;
SilcPurple
sg
=
gc
->
proto_data
;
SilcPurpleIM
im
=
context
;
PurpleConversation
*
convo
;
char
tmp
[
256
];
SilcClientEntry
client_entry
;
SilcDList
list
;
gboolean
free_list
=
FALSE
;
convo
=
purple_find_conversation_with_account
(
PURPLE_CONV_TYPE_IM
,
im
->
nick
,
sg
->
account
);
if
(
!
convo
)
return
;
if
(
!
clients
)
goto
err
;
if
(
silc_dlist_count
(
clients
)
>
1
)
{
/* Find the correct one. The im->nick might be a formatted nick
so this will find the correct one. */
clients
=
silc_client_get_clients_local
(
client
,
conn
,
im
->
nick
,
FALSE
);
if
(
!
clients
)
goto
err
;
free_list
=
TRUE
;
}
silc_dlist_start
(
clients
);
client_entry
=
silc_dlist_get
(
clients
);
/* Check for images */
if
(
im
->
gflags
&
PURPLE_MESSAGE_IMAGES
)
{
list
=
silcpurple_image_message
(
im
->
message
,
&
im
->
flags
);
if
(
list
)
{
/* Send one or more MIME message. If more than one, they
are MIME fragments due to over large message */
SilcBuffer
buf
;
silc_dlist_start
(
list
);
while
((
buf
=
silc_dlist_get
(
list
))
!=
SILC_LIST_END
)
silc_client_send_private_message
(
client
,
conn
,
client_entry
,
im
->
flags
,
sg
->
sha1hash
,
buf
->
data
,
silc_buffer_len
(
buf
));
silc_mime_partial_free
(
list
);
purple_conv_im_write
(
PURPLE_CONV_IM
(
convo
),
conn
->
local_entry
->
nickname
,
im
->
message
,
0
,
time
(
NULL
));
goto
out
;
}
}
/* Send the message */
silc_client_send_private_message
(
client
,
conn
,
client_entry
,
im
->
flags
,
sg
->
sha1hash
,
(
unsigned
char
*
)
im
->
message
,
im
->
message_len
);
purple_conv_im_write
(
PURPLE_CONV_IM
(
convo
),
conn
->
local_entry
->
nickname
,
im
->
message
,
0
,
time
(
NULL
));
goto
out
;
err
:
g_snprintf
(
tmp
,
sizeof
(
tmp
),
_
(
"User <I>%s</I> is not present in the network"
),
im
->
nick
);
purple_conversation_write
(
convo
,
NULL
,
tmp
,
PURPLE_MESSAGE_SYSTEM
,
time
(
NULL
));
out
:
if
(
free_list
)
{
silc_client_list_free
(
client
,
conn
,
clients
);
}
g_free
(
im
->
nick
);
g_free
(
im
->
message
);
silc_free
(
im
);
}
static
int
silcpurple_send_im
(
PurpleConnection
*
gc
,
const
char
*
who
,
const
char
*
message
,
PurpleMessageFlags
flags
)
{
SilcPurple
sg
=
gc
->
proto_data
;
SilcClient
client
=
sg
->
client
;
SilcClientConnection
conn
=
sg
->
conn
;
SilcDList
clients
;
SilcClientEntry
client_entry
;
SilcMessageFlags
mflags
;
char
*
msg
,
*
tmp
;
int
ret
=
0
;
gboolean
sign
=
purple_account_get_bool
(
sg
->
account
,
"sign-verify"
,
FALSE
);
SilcDList
list
;
if
(
!
who
||
!
message
)
return
0
;
mflags
=
SILC_MESSAGE_FLAG_UTF8
;
tmp
=
msg
=
purple_unescape_html
(
message
);
if
(
!
g_ascii_strncasecmp
(
msg
,
"/me "
,
4
))
{
msg
+=
4
;
if
(
!*
msg
)
{
g_free
(
tmp
);
return
0
;
}
mflags
|=
SILC_MESSAGE_FLAG_ACTION
;
}
else
if
(
strlen
(
msg
)
>
1
&&
msg
[
0
]
==
'/'
)
{
if
(
!
silc_client_command_call
(
client
,
conn
,
msg
+
1
))
purple_notify_error
(
gc
,
_
(
"Call Command"
),
_
(
"Cannot call command"
),
_
(
"Unknown command"
));
g_free
(
tmp
);
return
0
;
}
if
(
sign
)
mflags
|=
SILC_MESSAGE_FLAG_SIGNED
;
/* Find client entry */
clients
=
silc_client_get_clients_local
(
client
,
conn
,
who
,
FALSE
);
if
(
!
clients
)
{
/* Resolve unknown user */
SilcPurpleIM
im
=
silc_calloc
(
1
,
sizeof
(
*
im
));
if
(
!
im
)
{
g_free
(
tmp
);
return
0
;
}
im
->
nick
=
g_strdup
(
who
);
im
->
message
=
g_strdup
(
message
);
im
->
message_len
=
strlen
(
im
->
message
);
im
->
flags
=
mflags
;
im
->
gflags
=
flags
;
silc_client_get_clients
(
client
,
conn
,
who
,
NULL
,
silcpurple_send_im_resolved
,
im
);
g_free
(
tmp
);
return
0
;
}
silc_dlist_start
(
clients
);
client_entry
=
silc_dlist_get
(
clients
);
/* Check for images */
if
(
flags
&
PURPLE_MESSAGE_IMAGES
)
{
list
=
silcpurple_image_message
(
message
,
&
mflags
);
if
(
list
)
{
/* Send one or more MIME message. If more than one, they
are MIME fragments due to over large message */
SilcBuffer
buf
;
silc_dlist_start
(
list
);
while
((
buf
=
silc_dlist_get
(
list
))
!=
SILC_LIST_END
)
ret
=
silc_client_send_private_message
(
client
,
conn
,
client_entry
,
mflags
,
sg
->
sha1hash
,
buf
->
data
,
silc_buffer_len
(
buf
));
silc_mime_partial_free
(
list
);
g_free
(
tmp
);
silc_client_list_free
(
client
,
conn
,
clients
);
return
ret
;
}
}
/* Send private message directly */
ret
=
silc_client_send_private_message
(
client
,
conn
,
client_entry
,
mflags
,
sg
->
sha1hash
,
(
unsigned
char
*
)
msg
,
strlen
(
msg
));
g_free
(
tmp
);
silc_client_list_free
(
client
,
conn
,
clients
);
return
ret
;
}
static
GList
*
silcpurple_blist_node_menu
(
PurpleBlistNode
*
node
)
{
/* split this single menu building function back into the two
original: one for buddies and one for chats */
if
(
PURPLE_BLIST_NODE_IS_CHAT
(
node
))
{
return
silcpurple_chat_menu
((
PurpleChat
*
)
node
);
}
else
if
(
PURPLE_BLIST_NODE_IS_BUDDY
(
node
))
{
return
silcpurple_buddy_menu
((
PurpleBuddy
*
)
node
);
}
else
{
g_return_val_if_reached
(
NULL
);
}
}
/********************************* Commands **********************************/
static
PurpleCmdRet
silcpurple_cmd_chat_part
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
PurpleConversation
*
convo
=
conv
;
int
id
=
0
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
if
(
args
&&
args
[
0
])
convo
=
purple_find_conversation_with_account
(
PURPLE_CONV_TYPE_CHAT
,
args
[
0
],
gc
->
account
);
if
(
convo
!=
NULL
)
id
=
purple_conv_chat_get_id
(
PURPLE_CONV_CHAT
(
convo
));
if
(
id
==
0
)
return
PURPLE_CMD_RET_FAILED
;
silcpurple_chat_leave
(
gc
,
id
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_chat_topic
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
int
id
=
0
;
char
*
buf
,
*
tmp
,
*
tmp2
;
const
char
*
topic
;
gc
=
purple_conversation_get_gc
(
conv
);
id
=
purple_conv_chat_get_id
(
PURPLE_CONV_CHAT
(
conv
));
if
(
gc
==
NULL
||
id
==
0
)
return
PURPLE_CMD_RET_FAILED
;
if
(
!
args
||
!
args
[
0
])
{
topic
=
purple_conv_chat_get_topic
(
PURPLE_CONV_CHAT
(
conv
));
if
(
topic
)
{
tmp
=
g_markup_escape_text
(
topic
,
-1
);
tmp2
=
purple_markup_linkify
(
tmp
);
buf
=
g_strdup_printf
(
_
(
"current topic is: %s"
),
tmp2
);
g_free
(
tmp
);
g_free
(
tmp2
);
}
else
buf
=
g_strdup
(
_
(
"No topic is set"
));
purple_conv_chat_write
(
PURPLE_CONV_CHAT
(
conv
),
gc
->
account
->
username
,
buf
,
PURPLE_MESSAGE_SYSTEM
|
PURPLE_MESSAGE_NO_LOG
,
time
(
NULL
));
g_free
(
buf
);
}
if
(
args
&&
args
[
0
]
&&
(
strlen
(
args
[
0
])
>
255
))
{
*
error
=
g_strdup
(
_
(
"Topic too long"
));
return
PURPLE_CMD_RET_FAILED
;
}
silcpurple_chat_set_topic
(
gc
,
id
,
args
?
args
[
0
]
:
NULL
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_chat_join
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
GHashTable
*
comp
;
if
(
!
args
||
!
args
[
0
])
return
PURPLE_CMD_RET_FAILED
;
comp
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
NULL
,
NULL
);
g_hash_table_replace
(
comp
,
"channel"
,
args
[
0
]);
if
(
args
[
1
])
g_hash_table_replace
(
comp
,
"passphrase"
,
args
[
1
]);
silcpurple_chat_join
(
purple_conversation_get_gc
(
conv
),
comp
);
g_hash_table_destroy
(
comp
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_chat_list
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
gc
=
purple_conversation_get_gc
(
conv
);
purple_roomlist_show_with_account
(
purple_connection_get_account
(
gc
));
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_whois
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
silcpurple_get_info
(
gc
,
args
[
0
]);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_msg
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
int
ret
;
PurpleConnection
*
gc
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
ret
=
silcpurple_send_im
(
gc
,
args
[
0
],
args
[
1
],
PURPLE_MESSAGE_SEND
);
if
(
ret
)
return
PURPLE_CMD_RET_OK
;
else
return
PURPLE_CMD_RET_FAILED
;
}
static
PurpleCmdRet
silcpurple_cmd_query
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
int
ret
=
1
;
PurpleConversation
*
convo
;
PurpleConnection
*
gc
;
PurpleAccount
*
account
;
if
(
!
args
||
!
args
[
0
])
{
*
error
=
g_strdup
(
_
(
"You must specify a nick"
));
return
PURPLE_CMD_RET_FAILED
;
}
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
account
=
purple_connection_get_account
(
gc
);
convo
=
purple_conversation_new
(
PURPLE_CONV_TYPE_IM
,
account
,
args
[
0
]);
if
(
args
[
1
])
{
ret
=
silcpurple_send_im
(
gc
,
args
[
0
],
args
[
1
],
PURPLE_MESSAGE_SEND
);
purple_conv_im_write
(
PURPLE_CONV_IM
(
convo
),
purple_connection_get_display_name
(
gc
),
args
[
1
],
PURPLE_MESSAGE_SEND
,
time
(
NULL
));
}
if
(
ret
)
return
PURPLE_CMD_RET_OK
;
else
return
PURPLE_CMD_RET_FAILED
;
}
static
PurpleCmdRet
silcpurple_cmd_motd
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
SilcPurple
sg
;
char
*
tmp
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
sg
=
gc
->
proto_data
;
if
(
sg
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
if
(
!
sg
->
motd
)
{
*
error
=
g_strdup
(
_
(
"There is no Message of the Day associated with this connection"
));
return
PURPLE_CMD_RET_FAILED
;
}
tmp
=
g_markup_escape_text
(
sg
->
motd
,
-1
);
purple_notify_formatted
(
gc
,
NULL
,
_
(
"Message of the Day"
),
NULL
,
tmp
,
NULL
,
NULL
);
g_free
(
tmp
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_detach
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
SilcPurple
sg
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
sg
=
gc
->
proto_data
;
if
(
sg
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
"DETACH"
);
sg
->
detaching
=
TRUE
;
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_cmode
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
SilcPurple
sg
;
SilcChannelEntry
channel
;
char
*
silccmd
,
*
silcargs
,
*
msg
,
tmp
[
256
];
const
char
*
chname
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
||
!
args
||
gc
->
proto_data
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
sg
=
gc
->
proto_data
;
if
(
args
[
0
])
chname
=
args
[
0
];
else
chname
=
purple_conversation_get_name
(
conv
);
if
(
!
args
[
1
])
{
channel
=
silc_client_get_channel
(
sg
->
client
,
sg
->
conn
,
(
char
*
)
chname
);
if
(
!
channel
)
{
*
error
=
g_strdup_printf
(
_
(
"channel %s not found"
),
chname
);
return
PURPLE_CMD_RET_FAILED
;
}
if
(
channel
->
mode
)
{
silcpurple_get_chmode_string
(
channel
->
mode
,
tmp
,
sizeof
(
tmp
));
msg
=
g_strdup_printf
(
_
(
"channel modes for %s: %s"
),
chname
,
tmp
);
}
else
{
msg
=
g_strdup_printf
(
_
(
"no channel modes are set on %s"
),
chname
);
}
purple_conv_chat_write
(
PURPLE_CONV_CHAT
(
conv
),
""
,
msg
,
PURPLE_MESSAGE_SYSTEM
|
PURPLE_MESSAGE_NO_LOG
,
time
(
NULL
));
g_free
(
msg
);
return
PURPLE_CMD_RET_OK
;
}
silcargs
=
g_strjoinv
(
" "
,
args
);
silccmd
=
g_strconcat
(
cmd
,
" "
,
silcargs
,
NULL
);
g_free
(
silcargs
);
if
(
!
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
silccmd
))
{
g_free
(
silccmd
);
*
error
=
g_strdup_printf
(
_
(
"Failed to set cmodes for %s"
),
args
[
0
]);
return
PURPLE_CMD_RET_FAILED
;
}
g_free
(
silccmd
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_generic
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
SilcPurple
sg
;
char
*
silccmd
,
*
silcargs
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
sg
=
gc
->
proto_data
;
if
(
sg
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
silcargs
=
g_strjoinv
(
" "
,
args
);
silccmd
=
g_strconcat
(
cmd
,
" "
,
args
?
silcargs
:
NULL
,
NULL
);
g_free
(
silcargs
);
if
(
!
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
silccmd
))
{
g_free
(
silccmd
);
*
error
=
g_strdup_printf
(
_
(
"Unknown command: %s, (may be a client bug)"
),
cmd
);
return
PURPLE_CMD_RET_FAILED
;
}
g_free
(
silccmd
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_quit
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
SilcPurple
sg
;
GHashTable
*
ui_info
;
const
char
*
ui_name
=
NULL
,
*
ui_website
=
NULL
;
char
*
quit_msg
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
sg
=
gc
->
proto_data
;
if
(
sg
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
ui_info
=
purple_core_get_ui_info
();
if
(
ui_info
)
{
ui_name
=
g_hash_table_lookup
(
ui_info
,
"name"
);
ui_website
=
g_hash_table_lookup
(
ui_info
,
"website"
);
}
if
(
!
ui_name
||
!
ui_website
)
{
ui_name
=
"Pidgin"
;
ui_website
=
PURPLE_WEBSITE
;
}
quit_msg
=
g_strdup_printf
(
_
(
"Download %s: %s"
),
ui_name
,
ui_website
);
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
NULL
,
"QUIT"
,
(
args
&&
args
[
0
])
?
args
[
0
]
:
quit_msg
,
NULL
);
g_free
(
quit_msg
);
return
PURPLE_CMD_RET_OK
;
}
static
PurpleCmdRet
silcpurple_cmd_call
(
PurpleConversation
*
conv
,
const
char
*
cmd
,
char
**
args
,
char
**
error
,
void
*
data
)
{
PurpleConnection
*
gc
;
SilcPurple
sg
;
gc
=
purple_conversation_get_gc
(
conv
);
if
(
gc
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
sg
=
gc
->
proto_data
;
if
(
sg
==
NULL
)
return
PURPLE_CMD_RET_FAILED
;
if
(
!
silc_client_command_call
(
sg
->
client
,
sg
->
conn
,
args
[
0
]))
{
*
error
=
g_strdup_printf
(
_
(
"Unknown command: %s"
),
args
[
0
]);
return
PURPLE_CMD_RET_FAILED
;
}
return
PURPLE_CMD_RET_OK
;
}
/************************** Plugin Initialization ****************************/
static
void
silcpurple_register_commands
(
void
)
{
purple_cmd_register
(
"part"
,
"w"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_chat_part
,
_
(
"part [channel]: Leave the chat"
),
NULL
);
purple_cmd_register
(
"leave"
,
"w"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_chat_part
,
_
(
"leave [channel]: Leave the chat"
),
NULL
);
purple_cmd_register
(
"topic"
,
"s"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_chat_topic
,
_
(
"topic [<new topic>]: View or change the topic"
),
NULL
);
purple_cmd_register
(
"join"
,
"ws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_chat_join
,
_
(
"join <channel> [<password>]: Join a chat on this network"
),
NULL
);
purple_cmd_register
(
"list"
,
""
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_chat_list
,
_
(
"list: List channels on this network"
),
NULL
);
purple_cmd_register
(
"whois"
,
"w"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_whois
,
_
(
"whois <nick>: View nick's information"
),
NULL
);
purple_cmd_register
(
"msg"
,
"ws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_msg
,
_
(
"msg <nick> <message>: Send a private message to a user"
),
NULL
);
purple_cmd_register
(
"query"
,
"ws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_query
,
_
(
"query <nick> [<message>]: Send a private message to a user"
),
NULL
);
purple_cmd_register
(
"motd"
,
""
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_motd
,
_
(
"motd: View the server's Message Of The Day"
),
NULL
);
purple_cmd_register
(
"detach"
,
""
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_detach
,
_
(
"detach: Detach this session"
),
NULL
);
purple_cmd_register
(
"quit"
,
"s"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_quit
,
_
(
"quit [message]: Disconnect from the server, with an optional message"
),
NULL
);
purple_cmd_register
(
"call"
,
"s"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_call
,
_
(
"call <command>: Call any silc client command"
),
NULL
);
/* These below just get passed through for the silc client library to deal
* with */
purple_cmd_register
(
"kill"
,
"ws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"kill <nick> [-pubkey|<reason>]: Kill nick"
),
NULL
);
purple_cmd_register
(
"nick"
,
"w"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"nick <newnick>: Change your nickname"
),
NULL
);
purple_cmd_register
(
"whowas"
,
"ww"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"whowas <nick>: View nick's information"
),
NULL
);
purple_cmd_register
(
"cmode"
,
"wws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_cmode
,
_
(
"cmode <channel> [+|-<modes>] [arguments]: Change or display channel modes"
),
NULL
);
purple_cmd_register
(
"cumode"
,
"wws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"cumode <channel> +|-<modes> <nick>: Change nick's modes on channel"
),
NULL
);
purple_cmd_register
(
"umode"
,
"w"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"umode <usermodes>: Set your modes in the network"
),
NULL
);
purple_cmd_register
(
"oper"
,
"s"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"oper <nick> [-pubkey]: Get server operator privileges"
),
NULL
);
purple_cmd_register
(
"invite"
,
"ws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"invite <channel> [-|+]<nick>: invite nick or add/remove from channel invite list"
),
NULL
);
purple_cmd_register
(
"kick"
,
"wws"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"kick <channel> <nick> [comment]: Kick client from channel"
),
NULL
);
purple_cmd_register
(
"info"
,
"w"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"info [server]: View server administrative details"
),
NULL
);
purple_cmd_register
(
"ban"
,
"ww"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
|
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"ban [<channel> +|-<nick>]: Ban client from channel"
),
NULL
);
purple_cmd_register
(
"getkey"
,
"w"
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"getkey <nick|server>: Retrieve client's or server's public key"
),
NULL
);
purple_cmd_register
(
"stats"
,
""
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"stats: View server and network statistics"
),
NULL
);
purple_cmd_register
(
"ping"
,
""
,
PURPLE_CMD_P_PRPL
,
PURPLE_CMD_FLAG_IM
|
PURPLE_CMD_FLAG_CHAT
|
PURPLE_CMD_FLAG_PRPL_ONLY
,
"prpl-silc"
,
silcpurple_cmd_generic
,
_
(
"ping: Send PING to the connected server"
),
NULL
);
#if 0
/* Purple doesn't handle these yet */
purple_cmd_register("users", "w", PURPLE_CMD_P_PRPL,
PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY,
"prpl-silc", silcpurple_cmd_users,
_("users <channel>: List users in channel"));
purple_cmd_register("names", "ww", PURPLE_CMD_P_PRPL,
PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_names,
_("names [-count|-ops|-halfops|-voices|-normal] <channel(s)>: List specific users in channel(s)"));
#endif
}
static
PurpleWhiteboardPrplOps
silcpurple_wb_ops
=
{
silcpurple_wb_start
,
silcpurple_wb_end
,
silcpurple_wb_get_dimensions
,
silcpurple_wb_set_dimensions
,
silcpurple_wb_get_brush
,
silcpurple_wb_set_brush
,
silcpurple_wb_send
,
silcpurple_wb_clear
,
/* padding */
NULL
,
NULL
,
NULL
,
NULL
};
static
PurplePluginProtocolInfo
prpl_info
=
{
OPT_PROTO_CHAT_TOPIC
|
OPT_PROTO_UNIQUE_CHATNAME
|
OPT_PROTO_PASSWORD_OPTIONAL
|
OPT_PROTO_IM_IMAGE
|
OPT_PROTO_SLASH_COMMANDS_NATIVE
,
NULL
,
/* user_splits */
NULL
,
/* protocol_options */
{
"jpeg,gif,png,bmp"
,
0
,
0
,
96
,
96
,
0
,
PURPLE_ICON_SCALE_DISPLAY
},
/* icon_spec */
silcpurple_list_icon
,
/* list_icon */
NULL
,
/* list_emblems */
silcpurple_status_text
,
/* status_text */
silcpurple_tooltip_text
,
/* tooltip_text */
silcpurple_away_states
,
/* away_states */
silcpurple_blist_node_menu
,
/* blist_node_menu */
silcpurple_chat_info
,
/* chat_info */
silcpurple_chat_info_defaults
,
/* chat_info_defaults */
silcpurple_login
,
/* login */
silcpurple_close
,
/* close */
silcpurple_send_im
,
/* send_im */
silcpurple_set_info
,
/* set_info */
NULL
,
/* send_typing */
silcpurple_get_info
,
/* get_info */
silcpurple_set_status
,
/* set_status */
silcpurple_idle_set
,
/* set_idle */
silcpurple_change_passwd
,
/* change_passwd */
silcpurple_add_buddy
,
/* add_buddy */
NULL
,
/* add_buddies */
silcpurple_remove_buddy
,
/* remove_buddy */
NULL
,
/* remove_buddies */
NULL
,
/* add_permit */
NULL
,
/* add_deny */
NULL
,
/* rem_permit */
NULL
,
/* rem_deny */
NULL
,
/* set_permit_deny */
silcpurple_chat_join
,
/* join_chat */
NULL
,
/* reject_chat */
silcpurple_get_chat_name
,
/* get_chat_name */
silcpurple_chat_invite
,
/* chat_invite */
silcpurple_chat_leave
,
/* chat_leave */
NULL
,
/* chat_whisper */
silcpurple_chat_send
,
/* chat_send */
silcpurple_keepalive
,
/* keepalive */
NULL
,
/* register_user */
NULL
,
/* get_cb_info */
NULL
,
/* get_cb_away */
NULL
,
/* alias_buddy */
NULL
,
/* group_buddy */
NULL
,
/* rename_group */
NULL
,
/* buddy_free */
NULL
,
/* convo_closed */
NULL
,
/* normalize */
silcpurple_buddy_set_icon
,
/* set_buddy_icon */
NULL
,
/* remove_group */
NULL
,
/* get_cb_real_name */
silcpurple_chat_set_topic
,
/* set_chat_topic */
NULL
,
/* find_blist_chat */
silcpurple_roomlist_get_list
,
/* roomlist_get_list */
silcpurple_roomlist_cancel
,
/* roomlist_cancel */
NULL
,
/* roomlist_expand_category */
NULL
,
/* can_receive_file */
silcpurple_ftp_send_file
,
/* send_file */
silcpurple_ftp_new_xfer
,
/* new_xfer */
NULL
,
/* offline_message */
&
silcpurple_wb_ops
,
/* whiteboard_prpl_ops */
NULL
,
/* send_raw */
NULL
,
/* roomlist_room_serialize */
NULL
,
/* unregister_user */
NULL
,
/* send_attention */
NULL
,
/* get_attention_types */
sizeof
(
PurplePluginProtocolInfo
),
/* struct_size */
NULL
,
/* get_account_text_table */
NULL
,
/* initiate_media */
NULL
,
/* get_media_caps */
NULL
,
/* get_moods */
NULL
,
/* set_public_alias */
NULL
,
/* get_public_alias */
NULL
,
/* add_buddy_with_invite */
NULL
/* add_buddies_with_invite */
};
static
PurplePluginInfo
info
=
{
PURPLE_PLUGIN_MAGIC
,
PURPLE_MAJOR_VERSION
,
PURPLE_MINOR_VERSION
,
PURPLE_PLUGIN_PROTOCOL
,
/**< type */
NULL
,
/**< ui_requirement */
0
,
/**< flags */
NULL
,
/**< dependencies */
PURPLE_PRIORITY_DEFAULT
,
/**< priority */
"prpl-silc"
,
/**< id */
"SILC"
,
/**< name */
"1.1"
,
/**< version */
/** summary */
N_
(
"SILC Protocol Plugin"
),
/** description */
N_
(
"Secure Internet Live Conferencing (SILC) Protocol"
),
"Pekka Riikonen"
,
/**< author */
"http://silcnet.org/"
,
/**< homepage */
NULL
,
/**< load */
NULL
,
/**< unload */
NULL
,
/**< destroy */
NULL
,
/**< ui_info */
&
prpl_info
,
/**< extra_info */
NULL
,
/**< prefs_info */
silcpurple_actions
,
/* padding */
NULL
,
NULL
,
NULL
,
NULL
};
#if 0
static SilcBool silcpurple_debug_cb(char *file, char *function, int line,
char *message, void *context)
{
purple_debug_info("SILC", "%s:%d:%s - %s\n", file ? file : "(null)", line, function ? function : "(null)", message ? message : "(null)");
return TRUE;
}
#endif
static
void
init_plugin
(
PurplePlugin
*
plugin
)
{
PurpleAccountOption
*
option
;
PurpleAccountUserSplit
*
split
;
char
tmp
[
256
];
int
i
;
PurpleKeyValuePair
*
kvp
;
GList
*
list
=
NULL
;
silc_plugin
=
plugin
;
split
=
purple_account_user_split_new
(
_
(
"Network"
),
"silcnet.org"
,
'@'
);
prpl_info
.
user_splits
=
g_list_append
(
prpl_info
.
user_splits
,
split
);
/* Account options */
option
=
purple_account_option_string_new
(
_
(
"Connect server"
),
"server"
,
"silc.silcnet.org"
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
option
=
purple_account_option_int_new
(
_
(
"Port"
),
"port"
,
706
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
g_snprintf
(
tmp
,
sizeof
(
tmp
),
"%s"
G_DIR_SEPARATOR_S
"public_key.pub"
,
silcpurple_silcdir
());
option
=
purple_account_option_string_new
(
_
(
"Public Key file"
),
"public-key"
,
tmp
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
g_snprintf
(
tmp
,
sizeof
(
tmp
),
"%s"
G_DIR_SEPARATOR_S
"private_key.prv"
,
silcpurple_silcdir
());
option
=
purple_account_option_string_new
(
_
(
"Private Key file"
),
"private-key"
,
tmp
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
for
(
i
=
0
;
silc_default_ciphers
[
i
].
name
;
i
++
)
{
kvp
=
g_new0
(
PurpleKeyValuePair
,
1
);
kvp
->
key
=
g_strdup
(
silc_default_ciphers
[
i
].
name
);
kvp
->
value
=
g_strdup
(
silc_default_ciphers
[
i
].
name
);
list
=
g_list_append
(
list
,
kvp
);
}
option
=
purple_account_option_list_new
(
_
(
"Cipher"
),
"cipher"
,
list
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
list
=
NULL
;
for
(
i
=
0
;
silc_default_hmacs
[
i
].
name
;
i
++
)
{
kvp
=
g_new0
(
PurpleKeyValuePair
,
1
);
kvp
->
key
=
g_strdup
(
silc_default_hmacs
[
i
].
name
);
kvp
->
value
=
g_strdup
(
silc_default_hmacs
[
i
].
name
);
list
=
g_list_append
(
list
,
kvp
);
}
option
=
purple_account_option_list_new
(
_
(
"HMAC"
),
"hmac"
,
list
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Use Perfect Forward Secrecy"
),
"pfs"
,
FALSE
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Public key authentication"
),
"pubkey-auth"
,
FALSE
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Block IMs without Key Exchange"
),
"block-ims"
,
FALSE
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Block messages to whiteboard"
),
"block-wb"
,
FALSE
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Automatically open whiteboard"
),
"open-wb"
,
FALSE
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Digitally sign and verify all messages"
),
"sign-verify"
,
FALSE
);
prpl_info
.
protocol_options
=
g_list_append
(
prpl_info
.
protocol_options
,
option
);
purple_prefs_remove
(
"/plugins/prpl/silc"
);
silc_log_set_callback
(
SILC_LOG_ERROR
,
silcpurple_log_error
,
NULL
);
silcpurple_register_commands
();
#if 0
silc_log_debug(TRUE);
silc_log_set_debug_string("*client*");
silc_log_quick(TRUE);
silc_log_set_debug_callbacks(silcpurple_debug_cb, NULL, NULL, NULL);
#endif
}
PURPLE_INIT_PLUGIN
(
silc
,
init_plugin
,
info
);