5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2004 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 PURPLE_BEGIN_IGNORE_CAST_ALIGN
24 PURPLE_END_IGNORE_CAST_ALIGN
25 #include "silcclient.h"
26 #include "silcpurple.h"
31 extern SilcClientOperations ops
;
33 static PurpleProtocol
*my_protocol
= NULL
;
34 static GSList
*cmds
= NULL
;
36 /* Error log message callback */
38 static SilcBool
silcpurple_log_error(SilcLogType type
, char *message
,
41 silc_say(NULL
, NULL
, SILC_CLIENT_MESSAGE_ERROR
, message
);
46 silcpurple_list_icon(PurpleAccount
*a
, PurpleBuddy
*b
)
48 return (const char *)"silc";
52 silcpurple_away_states(PurpleAccount
*account
)
54 PurpleStatusType
*type
;
57 type
= purple_status_type_new_full(PURPLE_STATUS_AVAILABLE
, SILCPURPLE_STATUS_ID_AVAILABLE
, NULL
, TRUE
, TRUE
, FALSE
);
58 types
= g_list_append(types
, type
);
59 type
= purple_status_type_new_full(PURPLE_STATUS_AVAILABLE
, SILCPURPLE_STATUS_ID_HYPER
, _("Hyper Active"), TRUE
, TRUE
, FALSE
);
60 types
= g_list_append(types
, type
);
61 type
= purple_status_type_new_full(PURPLE_STATUS_AWAY
, SILCPURPLE_STATUS_ID_AWAY
, NULL
, TRUE
, TRUE
, FALSE
);
62 types
= g_list_append(types
, type
);
63 type
= purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE
, SILCPURPLE_STATUS_ID_BUSY
, _("Busy"), TRUE
, TRUE
, FALSE
);
64 types
= g_list_append(types
, type
);
65 type
= purple_status_type_new_full(PURPLE_STATUS_AWAY
, SILCPURPLE_STATUS_ID_INDISPOSED
, _("Indisposed"), TRUE
, TRUE
, FALSE
);
66 types
= g_list_append(types
, type
);
67 type
= purple_status_type_new_full(PURPLE_STATUS_AWAY
, SILCPURPLE_STATUS_ID_PAGE
, _("Wake Me Up"), TRUE
, TRUE
, FALSE
);
68 types
= g_list_append(types
, type
);
69 type
= purple_status_type_new_full(PURPLE_STATUS_OFFLINE
, SILCPURPLE_STATUS_ID_OFFLINE
, NULL
, TRUE
, TRUE
, FALSE
);
70 types
= g_list_append(types
, type
);
76 silcpurple_set_status(PurpleAccount
*account
, PurpleStatus
*status
)
78 PurpleConnection
*gc
= purple_account_get_connection(account
);
86 sg
= purple_connection_get_protocol_data(gc
);
91 state
= purple_status_get_id(status
);
96 if ((sg
== NULL
) || (sg
->conn
== NULL
))
99 mode
= sg
->conn
->local_entry
->mode
;
100 mode
&= ~(SILC_UMODE_GONE
|
103 SILC_UMODE_INDISPOSED
|
106 if (purple_strequal(state
, "hyper"))
107 mode
|= SILC_UMODE_HYPER
;
108 else if (purple_strequal(state
, "away"))
109 mode
|= SILC_UMODE_GONE
;
110 else if (purple_strequal(state
, "busy"))
111 mode
|= SILC_UMODE_BUSY
;
112 else if (purple_strequal(state
, "indisposed"))
113 mode
|= SILC_UMODE_INDISPOSED
;
114 else if (purple_strequal(state
, "page"))
115 mode
|= SILC_UMODE_PAGE
;
118 idp
= silc_id_payload_encode(sg
->conn
->local_id
, SILC_ID_CLIENT
);
119 SILC_PUT32_MSB(mode
, mb
);
120 silc_client_command_send(sg
->client
, sg
->conn
, SILC_COMMAND_UMODE
,
121 silcpurple_command_reply
, NULL
, 2,
122 1, idp
->data
, silc_buffer_len(idp
),
124 silc_buffer_free(idp
);
128 /*************************** Connection Routines *****************************/
131 silcpurple_keepalive(PurpleConnection
*gc
)
133 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
134 silc_packet_send(sg
->conn
->stream
, SILC_PACKET_HEARTBEAT
, 0,
138 #if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
140 silcpurple_scheduler(gpointer
*context
)
142 SilcClient client
= (SilcClient
)context
;
143 silc_client_run_one(client
);
153 /* A timeout occurred. Call SILC scheduler. */
156 silcpurple_scheduler_timeout(gpointer context
)
158 SilcPurpleTask task
= (SilcPurpleTask
)context
;
159 silc_client_run_one(task
->sg
->client
);
160 silc_dlist_del(task
->sg
->tasks
, task
);
165 /* An fd task event occurred. Call SILC scheduler. */
168 silcpurple_scheduler_fd(gpointer data
, gint fd
, PurpleInputCondition cond
)
170 SilcClient client
= (SilcClient
)data
;
171 silc_client_run_one(client
);
174 /* SILC Scheduler notify callback. This is called whenever task is added to
175 or deleted from SILC scheduler. It's also called when fd task events
176 change. Here we add same tasks to glib's main loop. */
179 silcpurple_scheduler(SilcSchedule schedule
,
180 SilcBool added
, SilcTask task
,
181 SilcBool fd_task
, SilcUInt32 fd
,
183 long seconds
, long useconds
,
186 SilcClient client
= (SilcClient
)context
;
187 PurpleConnection
*gc
= client
->application
;
188 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
189 SilcPurpleTask ptask
= NULL
;
193 /* Add fd or change fd events */
194 PurpleInputCondition e
= 0;
196 silc_dlist_start(sg
->tasks
);
197 while ((ptask
= silc_dlist_get(sg
->tasks
)))
198 if (ptask
->fd
== fd
) {
199 purple_input_remove(ptask
->tag
);
203 if (event
& SILC_TASK_READ
)
204 e
|= PURPLE_INPUT_READ
;
205 if (event
& SILC_TASK_WRITE
)
206 e
|= PURPLE_INPUT_WRITE
;
210 ptask
= silc_calloc(1, sizeof(*ptask
));
212 silc_dlist_add(sg
->tasks
, ptask
);
214 ptask
->tag
= purple_input_add(fd
, e
, silcpurple_scheduler_fd
,
217 silc_dlist_del(sg
->tasks
, ptask
);
222 ptask
= silc_calloc(1, sizeof(*ptask
));
224 ptask
->tag
= g_timeout_add((seconds
* 1000) +
226 silcpurple_scheduler_timeout
,
228 silc_dlist_add(sg
->tasks
, ptask
);
233 silc_dlist_start(sg
->tasks
);
234 while ((ptask
= silc_dlist_get(sg
->tasks
)))
235 if (ptask
->fd
== fd
) {
236 purple_input_remove(ptask
->tag
);
237 silc_dlist_del(sg
->tasks
, ptask
);
244 #endif /* __SILC_TOOLKIT_VERSION */
247 silcpurple_connect_cb(SilcClient client
, SilcClientConnection conn
,
248 SilcClientConnectionStatus status
, SilcStatus error
,
249 const char *message
, void *context
)
251 PurpleConnection
*gc
= context
;
256 #ifdef HAVE_SYS_UTSNAME_H
260 sg
= purple_connection_get_protocol_data(gc
);
263 case SILC_CLIENT_CONN_SUCCESS
:
264 case SILC_CLIENT_CONN_SUCCESS_RESUME
:
267 /* Connection created successfully */
268 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTED
);
270 /* Send the server our buddy list */
271 silcpurple_send_buddylist(gc
);
273 g_unlink(silcpurple_session_file(purple_account_get_username(sg
->account
)));
275 /* Send any UMODEs configured for account */
276 if (purple_account_get_bool(sg
->account
, "block-ims", FALSE
)) {
277 silc_client_command_call(sg
->client
, sg
->conn
, NULL
,
278 "UMODE", "+P", NULL
);
281 /* Set default attributes */
282 mask
= SILC_ATTRIBUTE_MOOD_NORMAL
;
283 silc_client_attribute_add(client
, conn
,
284 SILC_ATTRIBUTE_STATUS_MOOD
,
285 SILC_32_TO_PTR(mask
),
287 mask
= SILC_ATTRIBUTE_CONTACT_CHAT
;
288 silc_client_attribute_add(client
, conn
,
289 SILC_ATTRIBUTE_PREFERRED_CONTACT
,
290 SILC_32_TO_PTR(mask
),
292 #ifdef HAVE_SYS_UTSNAME_H
294 SilcAttributeObjDevice dev
;
295 memset(&dev
, 0, sizeof(dev
));
296 dev
.type
= SILC_ATTRIBUTE_DEVICE_COMPUTER
;
297 dev
.version
= u
.release
;
298 dev
.model
= u
.sysname
;
299 silc_client_attribute_add(client
, conn
,
300 SILC_ATTRIBUTE_DEVICE_INFO
,
301 (void *)&dev
, sizeof(dev
));
304 silc_timezone(tz
, sizeof(tz
));
305 silc_client_attribute_add(client
, conn
,
306 SILC_ATTRIBUTE_TIMEZONE
,
307 (void *)tz
, strlen(tz
));
309 /* Set our buddy icon */
310 img
= purple_buddy_icons_find_account_icon(sg
->account
);
311 silcpurple_buddy_set_icon(gc
, img
);
317 case SILC_CLIENT_CONN_DISCONNECTED
:
319 if (sg
->resuming
&& !sg
->detaching
)
320 g_unlink(silcpurple_session_file(purple_account_get_username(sg
->account
)));
322 /* Close the connection */
324 purple_connection_error(gc
,
325 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
326 _("Disconnected by server"));
328 /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */
329 purple_account_disconnect(purple_connection_get_account(gc
));
332 case SILC_CLIENT_CONN_ERROR
:
333 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
334 _("Error connecting to SILC Server"));
335 g_unlink(silcpurple_session_file(purple_account_get_username(sg
->account
)));
338 case SILC_CLIENT_CONN_ERROR_KE
:
339 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
,
340 _("Key Exchange failed"));
343 case SILC_CLIENT_CONN_ERROR_AUTH
:
344 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
345 _("Authentication failed"));
348 case SILC_CLIENT_CONN_ERROR_RESUME
:
349 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
350 _("Resuming detached session failed. "
351 "Press Reconnect to create new connection."));
352 g_unlink(silcpurple_session_file(purple_account_get_username(sg
->account
)));
355 case SILC_CLIENT_CONN_ERROR_TIMEOUT
:
356 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
357 _("Connection timed out"));
366 silcpurple_stream_created(SilcSocketStreamStatus status
, SilcStream stream
,
369 PurpleConnection
*gc
= context
;
372 SilcClientConnectionParams params
;
375 sg
= purple_connection_get_protocol_data(gc
);
377 if (status
!= SILC_SOCKET_OK
) {
378 purple_connection_error(gc
,
379 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
380 _("Connection failed"));
381 silc_pkcs_public_key_free(sg
->public_key
);
382 silc_pkcs_private_key_free(sg
->private_key
);
384 purple_connection_set_protocol_data(gc
, NULL
);
390 /* Get session detachment data, if available */
391 memset(¶ms
, 0, sizeof(params
));
392 dfile
= silcpurple_session_file(purple_account_get_username(sg
->account
));
393 params
.detach_data
= (unsigned char *)silc_file_readfile(dfile
, ¶ms
.detach_data_len
);
394 if (params
.detach_data
)
395 params
.detach_data
[params
.detach_data_len
] = 0;
396 params
.ignore_requested_attributes
= FALSE
;
397 params
.pfs
= purple_account_get_bool(sg
->account
, "pfs", FALSE
);
400 if (params
.detach_data
) {
401 purple_connection_update_progress(gc
, _("Resuming session"), 2, 5);
404 purple_connection_update_progress(gc
, _("Performing key exchange"), 2, 5);
407 /* Perform SILC Key Exchange. */
408 silc_client_key_exchange(client
, ¶ms
, sg
->public_key
,
409 sg
->private_key
, stream
, SILC_CONN_SERVER
,
410 silcpurple_connect_cb
, gc
);
412 silc_free(params
.detach_data
);
416 silcpurple_login_connected(gpointer data
, gint source
, const gchar
*error_message
)
418 PurpleConnection
*gc
= data
;
421 g_return_if_fail(gc
!= NULL
);
423 sg
= purple_connection_get_protocol_data(gc
);
426 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
427 _("Connection failed"));
428 silc_pkcs_public_key_free(sg
->public_key
);
429 silc_pkcs_private_key_free(sg
->private_key
);
431 purple_connection_set_protocol_data(gc
, NULL
);
435 silc_hash_alloc((unsigned char *)"sha1", &sg
->sha1hash
);
437 /* Wrap socket to TCP stream */
438 silc_socket_tcp_stream_create(source
, TRUE
, FALSE
,
439 sg
->client
->schedule
,
440 silcpurple_stream_created
, gc
);
443 static void silcpurple_continue_running(SilcPurple sg
)
445 PurpleConnection
*gc
= sg
->gc
;
446 PurpleAccount
*account
= purple_connection_get_account(gc
);
448 /* Connect to the SILC server */
449 if (purple_proxy_connect(gc
, account
,
450 purple_account_get_string(account
, "server",
452 purple_account_get_int(account
, "port", 706),
453 silcpurple_login_connected
, gc
) == NULL
)
455 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
456 _("Unable to connect"));
457 purple_connection_set_protocol_data(gc
, NULL
);
463 static void silcpurple_got_password_cb(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
465 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
466 PurpleAccount
*account
= purple_connection_get_account(gc
);
467 char pkd
[256], prd
[256];
468 const char *password
;
471 /* TODO: the password prompt dialog doesn't get disposed if the account disconnects */
472 PURPLE_ASSERT_CONNECTION_IS_VALID(gc
);
474 password
= purple_request_fields_get_string(fields
, "password");
475 remember
= purple_request_fields_get_bool(fields
, "remember");
477 if (!password
|| !*password
)
479 purple_notify_error(gc
, NULL
,
480 _("Password is required to sign on."), NULL
,
481 purple_request_cpar_from_connection(gc
));
482 purple_connection_set_protocol_data(gc
, NULL
);
488 purple_account_set_remember_password(account
, TRUE
);
490 purple_account_set_password(account
, password
, NULL
, NULL
);
492 /* Load SILC key pair */
493 g_snprintf(pkd
, sizeof(pkd
), "%s" G_DIR_SEPARATOR_S
"public_key.pub", silcpurple_silcdir());
494 g_snprintf(prd
, sizeof(prd
), "%s" G_DIR_SEPARATOR_S
"private_key.prv", silcpurple_silcdir());
495 if (!silc_load_key_pair((char *)purple_account_get_string(account
, "public-key", pkd
),
496 (char *)purple_account_get_string(account
, "private-key", prd
),
498 &sg
->public_key
, &sg
->private_key
)) {
499 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
500 _("Unable to load SILC key pair"));
501 purple_connection_set_protocol_data(gc
, NULL
);
505 silcpurple_continue_running(sg
);
508 static void silcpurple_no_password_cb(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
512 /* TODO: the password prompt dialog doesn't get disposed if the account disconnects */
513 PURPLE_ASSERT_CONNECTION_IS_VALID(gc
);
515 sg
= purple_connection_get_protocol_data(gc
);
516 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
517 _("Unable to load SILC key pair"));
518 purple_connection_set_protocol_data(gc
, NULL
);
522 static void silcpurple_running(SilcClient client
, void *context
)
524 SilcPurple sg
= context
;
525 PurpleConnection
*gc
= sg
->gc
;
526 PurpleAccount
*account
= purple_connection_get_account(gc
);
527 char pkd
[256], prd
[256];
531 purple_connection_update_progress(gc
, _("Connecting to SILC Server"), 1, 5);
533 /* Load SILC key pair */
534 g_snprintf(pkd
, sizeof(pkd
), "%s" G_DIR_SEPARATOR_S
"public_key.pub", silcpurple_silcdir());
535 g_snprintf(prd
, sizeof(prd
), "%s" G_DIR_SEPARATOR_S
"private_key.prv", silcpurple_silcdir());
536 if (!silc_load_key_pair((char *)purple_account_get_string(account
, "public-key", pkd
),
537 (char *)purple_account_get_string(account
, "private-key", prd
),
538 (purple_connection_get_password(gc
) == NULL
) ? "" : purple_connection_get_password(gc
),
539 &sg
->public_key
, &sg
->private_key
)) {
540 if (!purple_connection_get_password(gc
)) {
541 purple_account_request_password(account
, G_CALLBACK(silcpurple_got_password_cb
),
542 G_CALLBACK(silcpurple_no_password_cb
), gc
);
545 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
546 _("Unable to load SILC key pair"));
547 purple_connection_set_protocol_data(gc
, NULL
);
551 silcpurple_continue_running(sg
);
555 silcpurple_login(PurpleAccount
*account
)
558 PurpleConnection
*gc
;
560 SilcClientParams params
;
561 const char *cipher
, *hmac
;
562 char *username
, *hostname
, *realname
, **up
;
565 gc
= purple_account_get_connection(account
);
568 purple_connection_set_protocol_data(gc
, NULL
);
570 memset(¶ms
, 0, sizeof(params
));
571 strcat(params
.nickname_format
, "%n#a");
573 /* Allocate SILC client */
574 client
= silc_client_alloc(&ops
, ¶ms
, gc
, NULL
);
576 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
581 /* Get username, real name and local hostname for SILC library */
582 if (!purple_account_get_username(account
))
583 purple_account_set_username(account
, silc_get_username());
585 username
= (char *)purple_account_get_username(account
);
586 up
= g_strsplit(username
, "@", 2);
587 username
= g_strdup(up
[0]);
590 if (!purple_account_get_user_info(account
)) {
591 purple_account_set_user_info(account
, silc_get_real_name());
592 if (!purple_account_get_user_info(account
))
593 purple_account_set_user_info(account
,
596 realname
= (char *)purple_account_get_user_info(account
);
597 hostname
= silc_net_localhost();
599 purple_connection_set_display_name(gc
, username
);
601 /* Register requested cipher and HMAC */
602 cipher
= purple_account_get_string(account
, "cipher",
603 SILC_DEFAULT_CIPHER
);
604 for (i
= 0; silc_default_ciphers
[i
].name
; i
++)
605 if (purple_strequal(silc_default_ciphers
[i
].name
, cipher
)) {
606 silc_cipher_register(&(silc_default_ciphers
[i
]));
609 hmac
= purple_account_get_string(account
, "hmac", SILC_DEFAULT_HMAC
);
610 for (i
= 0; silc_default_hmacs
[i
].name
; i
++)
611 if (purple_strequal(silc_default_hmacs
[i
].name
, hmac
)) {
612 silc_hmac_register(&(silc_default_hmacs
[i
]));
616 sg
= silc_calloc(1, sizeof(*sg
));
621 sg
->account
= account
;
622 purple_connection_set_protocol_data(gc
, sg
);
624 /* Init SILC client */
625 if (!silc_client_init(client
, username
, hostname
, realname
,
626 silcpurple_running
, sg
)) {
627 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
628 _("Unable to initialize SILC protocol"));
629 purple_connection_set_protocol_data(gc
, NULL
);
638 /* Check the ~/.silc dir and create it, and new key pair if necessary. */
639 if (!silcpurple_check_silc_dir(gc
)) {
640 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
641 _("Error loading SILC key pair"));
642 purple_connection_set_protocol_data(gc
, NULL
);
647 #if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
648 /* Schedule SILC using Glib's event loop */
649 sg
->scheduler
= g_timeout_add(300, (GSourceFunc
)silcpurple_scheduler
, client
);
651 /* Run SILC scheduler */
652 sg
->tasks
= silc_dlist_init();
653 silc_schedule_set_notify(client
->schedule
, silcpurple_scheduler
,
655 silc_client_run_one(client
);
656 #endif /* __SILC_TOOLKIT_VERSION */
660 silcpurple_close_final(gpointer
*context
)
662 SilcPurple sg
= (SilcPurple
)context
;
664 purple_debug_info("silc", "Finalizing SilcPurple %p\n", sg
);
666 silc_client_stop(sg
->client
, NULL
, NULL
);
667 silc_client_free(sg
->client
);
669 silc_hash_free(sg
->sha1hash
);
671 silc_mime_assembler_free(sg
->mimeass
);
677 silcpurple_close(PurpleConnection
*gc
)
679 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
680 #if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
682 #endif /* __SILC_TOOLKIT_VERSION */
684 const char *ui_name
= NULL
, *ui_website
= NULL
;
687 g_return_if_fail(sg
!= NULL
);
689 ui_info
= purple_core_get_ui_info();
692 ui_name
= g_hash_table_lookup(ui_info
, "name");
693 ui_website
= g_hash_table_lookup(ui_info
, "website");
696 if(!ui_name
|| !ui_website
) {
698 ui_website
= PURPLE_WEBSITE
;
700 quit_msg
= g_strdup_printf(_("Download %s: %s"),
701 ui_name
, ui_website
);
704 silc_client_command_call(sg
->client
, sg
->conn
, NULL
,
710 silc_client_close_connection(sg
->client
, sg
->conn
);
712 #if __SILC_TOOLKIT_VERSION >= SILC_VERSION(1,1,1)
714 silc_client_run_one(sg
->client
);
715 silc_schedule_set_notify(sg
->client
->schedule
, NULL
, NULL
);
717 silc_dlist_start(sg
->tasks
);
718 while ((task
= silc_dlist_get(sg
->tasks
))) {
719 purple_input_remove(task
->tag
);
722 silc_dlist_uninit(sg
->tasks
);
723 #endif /* __SILC_TOOLKIT_VERSION */
726 g_source_remove(sg
->scheduler
);
728 purple_debug_info("silc", "Scheduling destruction of SilcPurple %p\n", sg
);
729 g_timeout_add(1, (GSourceFunc
)silcpurple_close_final
, sg
);
733 /****************************** Protocol Actions *****************************/
736 silcpurple_attrs_cancel(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
742 silcpurple_attrs_cb(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
744 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
745 SilcClient client
= sg
->client
;
746 SilcClientConnection conn
= sg
->conn
;
747 PurpleRequestField
*f
;
749 SilcUInt32 tmp_len
, mask
;
750 SilcAttributeObjService service
;
751 SilcAttributeObjDevice dev
;
752 SilcVCardStruct vcard
;
755 sg
= purple_connection_get_protocol_data(gc
);
759 memset(&service
, 0, sizeof(service
));
760 memset(&dev
, 0, sizeof(dev
));
761 memset(&vcard
, 0, sizeof(vcard
));
763 silc_client_attribute_del(client
, conn
,
764 SILC_ATTRIBUTE_USER_INFO
, NULL
);
765 silc_client_attribute_del(client
, conn
,
766 SILC_ATTRIBUTE_SERVICE
, NULL
);
767 silc_client_attribute_del(client
, conn
,
768 SILC_ATTRIBUTE_STATUS_MOOD
, NULL
);
769 silc_client_attribute_del(client
, conn
,
770 SILC_ATTRIBUTE_STATUS_FREETEXT
, NULL
);
771 silc_client_attribute_del(client
, conn
,
772 SILC_ATTRIBUTE_STATUS_MESSAGE
, NULL
);
773 silc_client_attribute_del(client
, conn
,
774 SILC_ATTRIBUTE_PREFERRED_LANGUAGE
, NULL
);
775 silc_client_attribute_del(client
, conn
,
776 SILC_ATTRIBUTE_PREFERRED_CONTACT
, NULL
);
777 silc_client_attribute_del(client
, conn
,
778 SILC_ATTRIBUTE_TIMEZONE
, NULL
);
779 silc_client_attribute_del(client
, conn
,
780 SILC_ATTRIBUTE_GEOLOCATION
, NULL
);
781 silc_client_attribute_del(client
, conn
,
782 SILC_ATTRIBUTE_DEVICE_INFO
, NULL
);
786 f
= purple_request_fields_get_field(fields
, "mood_normal");
787 if (f
&& purple_request_field_bool_get_value(f
))
788 mask
|= SILC_ATTRIBUTE_MOOD_NORMAL
;
789 f
= purple_request_fields_get_field(fields
, "mood_happy");
790 if (f
&& purple_request_field_bool_get_value(f
))
791 mask
|= SILC_ATTRIBUTE_MOOD_HAPPY
;
792 f
= purple_request_fields_get_field(fields
, "mood_sad");
793 if (f
&& purple_request_field_bool_get_value(f
))
794 mask
|= SILC_ATTRIBUTE_MOOD_SAD
;
795 f
= purple_request_fields_get_field(fields
, "mood_angry");
796 if (f
&& purple_request_field_bool_get_value(f
))
797 mask
|= SILC_ATTRIBUTE_MOOD_ANGRY
;
798 f
= purple_request_fields_get_field(fields
, "mood_jealous");
799 if (f
&& purple_request_field_bool_get_value(f
))
800 mask
|= SILC_ATTRIBUTE_MOOD_JEALOUS
;
801 f
= purple_request_fields_get_field(fields
, "mood_ashamed");
802 if (f
&& purple_request_field_bool_get_value(f
))
803 mask
|= SILC_ATTRIBUTE_MOOD_ASHAMED
;
804 f
= purple_request_fields_get_field(fields
, "mood_invincible");
805 if (f
&& purple_request_field_bool_get_value(f
))
806 mask
|= SILC_ATTRIBUTE_MOOD_INVINCIBLE
;
807 f
= purple_request_fields_get_field(fields
, "mood_inlove");
808 if (f
&& purple_request_field_bool_get_value(f
))
809 mask
|= SILC_ATTRIBUTE_MOOD_INLOVE
;
810 f
= purple_request_fields_get_field(fields
, "mood_sleepy");
811 if (f
&& purple_request_field_bool_get_value(f
))
812 mask
|= SILC_ATTRIBUTE_MOOD_SLEEPY
;
813 f
= purple_request_fields_get_field(fields
, "mood_bored");
814 if (f
&& purple_request_field_bool_get_value(f
))
815 mask
|= SILC_ATTRIBUTE_MOOD_BORED
;
816 f
= purple_request_fields_get_field(fields
, "mood_excited");
817 if (f
&& purple_request_field_bool_get_value(f
))
818 mask
|= SILC_ATTRIBUTE_MOOD_EXCITED
;
819 f
= purple_request_fields_get_field(fields
, "mood_anxious");
820 if (f
&& purple_request_field_bool_get_value(f
))
821 mask
|= SILC_ATTRIBUTE_MOOD_ANXIOUS
;
822 silc_client_attribute_add(client
, conn
,
823 SILC_ATTRIBUTE_STATUS_MOOD
,
824 SILC_32_TO_PTR(mask
),
827 /* Set preferred contact */
829 f
= purple_request_fields_get_field(fields
, "contact_chat");
830 if (f
&& purple_request_field_bool_get_value(f
))
831 mask
|= SILC_ATTRIBUTE_CONTACT_CHAT
;
832 f
= purple_request_fields_get_field(fields
, "contact_email");
833 if (f
&& purple_request_field_bool_get_value(f
))
834 mask
|= SILC_ATTRIBUTE_CONTACT_EMAIL
;
835 f
= purple_request_fields_get_field(fields
, "contact_call");
836 if (f
&& purple_request_field_bool_get_value(f
))
837 mask
|= SILC_ATTRIBUTE_CONTACT_CALL
;
838 f
= purple_request_fields_get_field(fields
, "contact_sms");
839 if (f
&& purple_request_field_bool_get_value(f
))
840 mask
|= SILC_ATTRIBUTE_CONTACT_SMS
;
841 f
= purple_request_fields_get_field(fields
, "contact_mms");
842 if (f
&& purple_request_field_bool_get_value(f
))
843 mask
|= SILC_ATTRIBUTE_CONTACT_MMS
;
844 f
= purple_request_fields_get_field(fields
, "contact_video");
845 if (f
&& purple_request_field_bool_get_value(f
))
846 mask
|= SILC_ATTRIBUTE_CONTACT_VIDEO
;
848 silc_client_attribute_add(client
, conn
,
849 SILC_ATTRIBUTE_PREFERRED_CONTACT
,
850 SILC_32_TO_PTR(mask
),
853 /* Set status text */
855 f
= purple_request_fields_get_field(fields
, "status_text");
857 val
= purple_request_field_string_get_value(f
);
859 silc_client_attribute_add(client
, conn
,
860 SILC_ATTRIBUTE_STATUS_FREETEXT
,
861 (void *)val
, strlen(val
));
865 f
= purple_request_fields_get_field(fields
, "vcard");
867 val
= purple_request_field_string_get_value(f
);
869 purple_account_set_string(sg
->account
, "vcard", val
);
870 tmp
= silc_file_readfile(val
, &tmp_len
);
873 if (silc_vcard_decode((unsigned char *)tmp
, tmp_len
, &vcard
))
874 silc_client_attribute_add(client
, conn
,
875 SILC_ATTRIBUTE_USER_INFO
,
879 silc_vcard_free(&vcard
);
882 purple_account_set_string(sg
->account
, "vcard", "");
885 #ifdef HAVE_SYS_UTSNAME_H
886 /* Set device info */
887 f
= purple_request_fields_get_field(fields
, "device");
888 if (f
&& purple_request_field_bool_get_value(f
)) {
891 dev
.type
= SILC_ATTRIBUTE_DEVICE_COMPUTER
;
892 dev
.version
= u
.release
;
893 dev
.model
= u
.sysname
;
894 silc_client_attribute_add(client
, conn
,
895 SILC_ATTRIBUTE_DEVICE_INFO
,
896 (void *)&dev
, sizeof(dev
));
903 f
= purple_request_fields_get_field(fields
, "timezone");
905 val
= purple_request_field_string_get_value(f
);
907 silc_client_attribute_add(client
, conn
,
908 SILC_ATTRIBUTE_TIMEZONE
,
909 (void *)val
, strlen(val
));
913 silcpurple_attrs(PurpleProtocolAction
*action
)
915 PurpleConnection
*gc
= action
->connection
;
916 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
917 SilcClient client
= sg
->client
;
918 SilcClientConnection conn
= sg
->conn
;
919 PurpleRequestFields
*fields
;
920 PurpleRequestFieldGroup
*g
;
921 PurpleRequestField
*f
;
923 SilcAttributePayload attr
;
924 gboolean mnormal
= TRUE
, mhappy
= FALSE
, msad
= FALSE
,
925 mangry
= FALSE
, mjealous
= FALSE
, mashamed
= FALSE
,
926 minvincible
= FALSE
, minlove
= FALSE
, msleepy
= FALSE
,
927 mbored
= FALSE
, mexcited
= FALSE
, manxious
= FALSE
;
928 gboolean cemail
= FALSE
, ccall
= FALSE
, csms
= FALSE
,
929 cmms
= FALSE
, cchat
= TRUE
, cvideo
= FALSE
;
930 #ifdef HAVE_SYS_UTSNAME_H
931 gboolean device
= TRUE
;
933 char status
[1024], tz
[16];
935 sg
= purple_connection_get_protocol_data(gc
);
939 memset(status
, 0, sizeof(status
));
941 attrs
= silc_client_attributes_get(client
, conn
);
943 if (silc_hash_table_find(attrs
,
944 SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_MOOD
),
945 NULL
, (void *)&attr
)) {
947 silc_attribute_get_object(attr
, &mood
, sizeof(mood
));
949 mhappy
= (mood
& SILC_ATTRIBUTE_MOOD_HAPPY
);
950 msad
= (mood
& SILC_ATTRIBUTE_MOOD_SAD
);
951 mangry
= (mood
& SILC_ATTRIBUTE_MOOD_ANGRY
);
952 mjealous
= (mood
& SILC_ATTRIBUTE_MOOD_JEALOUS
);
953 mashamed
= (mood
& SILC_ATTRIBUTE_MOOD_ASHAMED
);
954 minvincible
= (mood
& SILC_ATTRIBUTE_MOOD_INVINCIBLE
);
955 minlove
= (mood
& SILC_ATTRIBUTE_MOOD_INLOVE
);
956 msleepy
= (mood
& SILC_ATTRIBUTE_MOOD_SLEEPY
);
957 mbored
= (mood
& SILC_ATTRIBUTE_MOOD_BORED
);
958 mexcited
= (mood
& SILC_ATTRIBUTE_MOOD_EXCITED
);
959 manxious
= (mood
& SILC_ATTRIBUTE_MOOD_ANXIOUS
);
962 if (silc_hash_table_find(attrs
,
963 SILC_32_TO_PTR(SILC_ATTRIBUTE_PREFERRED_CONTACT
),
964 NULL
, (void *)&attr
)) {
965 SilcUInt32 contact
= 0;
966 silc_attribute_get_object(attr
, &contact
, sizeof(contact
));
967 cemail
= (contact
& SILC_ATTRIBUTE_CONTACT_EMAIL
);
968 ccall
= (contact
& SILC_ATTRIBUTE_CONTACT_CALL
);
969 csms
= (contact
& SILC_ATTRIBUTE_CONTACT_SMS
);
970 cmms
= (contact
& SILC_ATTRIBUTE_CONTACT_MMS
);
971 cchat
= (contact
& SILC_ATTRIBUTE_CONTACT_CHAT
);
972 cvideo
= (contact
& SILC_ATTRIBUTE_CONTACT_VIDEO
);
975 if (silc_hash_table_find(attrs
,
976 SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_FREETEXT
),
977 NULL
, (void *)&attr
))
978 silc_attribute_get_object(attr
, &status
, sizeof(status
));
980 #ifdef HAVE_SYS_UTSNAME_H
981 if (!silc_hash_table_find(attrs
,
982 SILC_32_TO_PTR(SILC_ATTRIBUTE_DEVICE_INFO
),
983 NULL
, (void *)&attr
))
988 fields
= purple_request_fields_new();
990 g
= purple_request_field_group_new(NULL
);
991 f
= purple_request_field_label_new("l3", _("Your Current Mood"));
992 purple_request_field_group_add_field(g
, f
);
993 f
= purple_request_field_bool_new("mood_normal", _("Normal"), mnormal
);
994 purple_request_field_group_add_field(g
, f
);
995 f
= purple_request_field_bool_new("mood_happy", _("Happy"), mhappy
);
996 purple_request_field_group_add_field(g
, f
);
997 f
= purple_request_field_bool_new("mood_sad", _("Sad"), msad
);
998 purple_request_field_group_add_field(g
, f
);
999 f
= purple_request_field_bool_new("mood_angry", _("Angry"), mangry
);
1000 purple_request_field_group_add_field(g
, f
);
1001 f
= purple_request_field_bool_new("mood_jealous", _("Jealous"), mjealous
);
1002 purple_request_field_group_add_field(g
, f
);
1003 f
= purple_request_field_bool_new("mood_ashamed", _("Ashamed"), mashamed
);
1004 purple_request_field_group_add_field(g
, f
);
1005 f
= purple_request_field_bool_new("mood_invincible", _("Invincible"), minvincible
);
1006 purple_request_field_group_add_field(g
, f
);
1007 f
= purple_request_field_bool_new("mood_inlove", _("In love"), minlove
);
1008 purple_request_field_group_add_field(g
, f
);
1009 f
= purple_request_field_bool_new("mood_sleepy", _("Sleepy"), msleepy
);
1010 purple_request_field_group_add_field(g
, f
);
1011 f
= purple_request_field_bool_new("mood_bored", _("Bored"), mbored
);
1012 purple_request_field_group_add_field(g
, f
);
1013 f
= purple_request_field_bool_new("mood_excited", _("Excited"), mexcited
);
1014 purple_request_field_group_add_field(g
, f
);
1015 f
= purple_request_field_bool_new("mood_anxious", _("Anxious"), manxious
);
1016 purple_request_field_group_add_field(g
, f
);
1018 f
= purple_request_field_label_new("l4", _("\nYour Preferred Contact Methods"));
1019 purple_request_field_group_add_field(g
, f
);
1020 f
= purple_request_field_bool_new("contact_chat", _("Chat"), cchat
);
1021 purple_request_field_group_add_field(g
, f
);
1022 f
= purple_request_field_bool_new("contact_email", _("Email"), cemail
);
1023 purple_request_field_group_add_field(g
, f
);
1024 f
= purple_request_field_bool_new("contact_call", _("Phone"), ccall
);
1025 purple_request_field_group_add_field(g
, f
);
1026 f
= purple_request_field_bool_new("contact_sms", _("SMS"), csms
);
1027 purple_request_field_group_add_field(g
, f
);
1028 f
= purple_request_field_bool_new("contact_mms", _("MMS"), cmms
);
1029 purple_request_field_group_add_field(g
, f
);
1030 f
= purple_request_field_bool_new("contact_video", _("Video conferencing"), cvideo
);
1031 purple_request_field_group_add_field(g
, f
);
1032 purple_request_fields_add_group(fields
, g
);
1034 g
= purple_request_field_group_new(NULL
);
1035 f
= purple_request_field_string_new("status_text", _("Your Current Status"),
1036 status
[0] ? status
: NULL
, TRUE
);
1037 purple_request_field_group_add_field(g
, f
);
1038 purple_request_fields_add_group(fields
, g
);
1040 g
= purple_request_field_group_new(NULL
);
1041 #ifdef HAVE_SYS_UTSNAME_H
1042 f
= purple_request_field_bool_new("device",
1043 _("Let others see what computer you are using"),
1045 purple_request_field_group_add_field(g
, f
);
1047 purple_request_fields_add_group(fields
, g
);
1049 g
= purple_request_field_group_new(NULL
);
1050 f
= purple_request_field_string_new("vcard", _("Your VCard File"),
1051 purple_account_get_string(sg
->account
, "vcard", ""),
1053 purple_request_field_group_add_field(g
, f
);
1055 silc_timezone(tz
, sizeof(tz
));
1056 f
= purple_request_field_string_new("timezone", _("Timezone (UTC)"), tz
, FALSE
);
1057 purple_request_field_group_add_field(g
, f
);
1058 purple_request_fields_add_group(fields
, g
);
1060 purple_request_fields(gc
, _("User Online Status Attributes"),
1061 _("User Online Status Attributes"),
1062 _("You can let other users see your online status information "
1063 "and your personal information. Please fill the information "
1064 "you would like other users to see about yourself."),
1066 _("OK"), G_CALLBACK(silcpurple_attrs_cb
),
1067 _("Cancel"), G_CALLBACK(silcpurple_attrs_cancel
),
1068 purple_request_cpar_from_connection(gc
), gc
);
1072 silcpurple_detach(PurpleProtocolAction
*action
)
1074 PurpleConnection
*gc
= action
->connection
;
1079 sg
= purple_connection_get_protocol_data(gc
);
1084 silc_client_command_call(sg
->client
, sg
->conn
, "DETACH");
1085 sg
->detaching
= TRUE
;
1089 silcpurple_view_motd(PurpleProtocolAction
*action
)
1091 PurpleConnection
*gc
= action
->connection
;
1097 sg
= purple_connection_get_protocol_data(gc
);
1102 purple_notify_error(gc
, _("Message of the Day"), _("No Message "
1103 "of the Day available"), _("There is no Message of the "
1104 "Day associated with this connection"),
1105 purple_request_cpar_from_connection(gc
));
1109 tmp
= g_markup_escape_text(sg
->motd
, -1);
1110 purple_notify_formatted(gc
, NULL
, _("Message of the Day"), NULL
,
1116 silcpurple_create_keypair_cancel(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
1122 silcpurple_create_keypair_cb(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
1125 PurpleRequestField
*f
;
1126 const char *val
, *pkfile
= NULL
, *prfile
= NULL
;
1127 const char *pass1
= NULL
, *pass2
= NULL
, *un
= NULL
, *hn
= NULL
;
1128 const char *rn
= NULL
, *e
= NULL
, *o
= NULL
, *c
= NULL
;
1130 int keylen
= SILCPURPLE_DEF_PKCS_LEN
;
1131 SilcPublicKey public_key
;
1133 sg
= purple_connection_get_protocol_data(gc
);
1138 f
= purple_request_fields_get_field(fields
, "pass1");
1140 val
= purple_request_field_string_get_value(f
);
1146 f
= purple_request_fields_get_field(fields
, "pass2");
1148 val
= purple_request_field_string_get_value(f
);
1154 if (!purple_strequal(pass1
, pass2
)) {
1155 purple_notify_error(gc
, _("Create New SILC Key Pair"),
1156 _("Passphrases do not match"), NULL
,
1157 purple_request_cpar_from_connection(gc
));
1162 f
= purple_request_fields_get_field(fields
, "key");
1164 val
= purple_request_field_string_get_value(f
);
1167 f
= purple_request_fields_get_field(fields
, "pkfile");
1169 pkfile
= purple_request_field_string_get_value(f
);
1170 f
= purple_request_fields_get_field(fields
, "prfile");
1172 prfile
= purple_request_field_string_get_value(f
);
1174 f
= purple_request_fields_get_field(fields
, "un");
1176 un
= purple_request_field_string_get_value(f
);
1177 f
= purple_request_fields_get_field(fields
, "hn");
1179 hn
= purple_request_field_string_get_value(f
);
1180 f
= purple_request_fields_get_field(fields
, "rn");
1182 rn
= purple_request_field_string_get_value(f
);
1183 f
= purple_request_fields_get_field(fields
, "e");
1185 e
= purple_request_field_string_get_value(f
);
1186 f
= purple_request_fields_get_field(fields
, "o");
1188 o
= purple_request_field_string_get_value(f
);
1189 f
= purple_request_fields_get_field(fields
, "c");
1191 c
= purple_request_field_string_get_value(f
);
1193 identifier
= silc_pkcs_silc_encode_identifier((char *)un
, (char *)hn
,
1194 (char *)rn
, (char *)e
,
1195 (char *)o
, (char *)c
,
1198 /* Create the key pair */
1199 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS
, keylen
, pkfile
, prfile
,
1200 identifier
, pass1
, &public_key
, NULL
,
1202 purple_notify_error(gc
, _("Create New SILC Key Pair"),
1203 _("Key Pair Generation failed"), NULL
,
1204 purple_request_cpar_from_connection(gc
));
1208 silcpurple_show_public_key(sg
, NULL
, public_key
, NULL
, NULL
);
1210 silc_pkcs_public_key_free(public_key
);
1211 silc_free(identifier
);
1215 silcpurple_create_keypair(PurpleProtocolAction
*action
)
1217 PurpleConnection
*gc
= action
->connection
;
1218 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
1219 PurpleRequestFields
*fields
;
1220 PurpleRequestFieldGroup
*g
;
1221 PurpleRequestField
*f
;
1222 const char *username
, *realname
;
1223 char *hostname
, **u
;
1224 char tmp
[256], pkd
[256], pkd2
[256], prd
[256], prd2
[256];
1226 username
= purple_account_get_username(sg
->account
);
1227 u
= g_strsplit(username
, "@", 2);
1229 realname
= purple_account_get_user_info(sg
->account
);
1230 hostname
= silc_net_localhost();
1231 g_snprintf(tmp
, sizeof(tmp
), "%s@%s", username
, hostname
);
1233 g_snprintf(pkd2
, sizeof(pkd2
), "%s" G_DIR_SEPARATOR_S
"public_key.pub", silcpurple_silcdir());
1234 g_snprintf(prd2
, sizeof(prd2
), "%s" G_DIR_SEPARATOR_S
"private_key.prv", silcpurple_silcdir());
1235 g_snprintf(pkd
, sizeof(pkd
) - 1, "%s",
1236 purple_account_get_string(purple_connection_get_account(gc
), "public-key", pkd2
));
1237 g_snprintf(prd
, sizeof(prd
) - 1, "%s",
1238 purple_account_get_string(purple_connection_get_account(gc
), "private-key", prd2
));
1240 fields
= purple_request_fields_new();
1242 g
= purple_request_field_group_new(NULL
);
1243 f
= purple_request_field_string_new("key", _("Key length"), "2048", FALSE
);
1244 purple_request_field_group_add_field(g
, f
);
1245 f
= purple_request_field_string_new("pkfile", _("Public key file"), pkd
, FALSE
);
1246 purple_request_field_group_add_field(g
, f
);
1247 f
= purple_request_field_string_new("prfile", _("Private key file"), prd
, FALSE
);
1248 purple_request_field_group_add_field(g
, f
);
1249 purple_request_fields_add_group(fields
, g
);
1251 g
= purple_request_field_group_new(NULL
);
1252 f
= purple_request_field_string_new("un", _("Username"), username
? username
: "", FALSE
);
1253 purple_request_field_group_add_field(g
, f
);
1254 f
= purple_request_field_string_new("hn", _("Hostname"), hostname
? hostname
: "", FALSE
);
1255 purple_request_field_group_add_field(g
, f
);
1256 f
= purple_request_field_string_new("rn", _("Real name"), realname
? realname
: "", FALSE
);
1257 purple_request_field_group_add_field(g
, f
);
1258 f
= purple_request_field_string_new("e", _("Email"), tmp
, FALSE
);
1259 purple_request_field_group_add_field(g
, f
);
1260 f
= purple_request_field_string_new("o", _("Organization"), "", FALSE
);
1261 purple_request_field_group_add_field(g
, f
);
1262 f
= purple_request_field_string_new("c", _("Country"), "", FALSE
);
1263 purple_request_field_group_add_field(g
, f
);
1264 purple_request_fields_add_group(fields
, g
);
1266 g
= purple_request_field_group_new(NULL
);
1267 f
= purple_request_field_string_new("pass1", _("Passphrase"), "", FALSE
);
1268 purple_request_field_string_set_masked(f
, TRUE
);
1269 purple_request_field_group_add_field(g
, f
);
1270 f
= purple_request_field_string_new("pass2", _("Passphrase (retype)"), "", FALSE
);
1271 purple_request_field_string_set_masked(f
, TRUE
);
1272 purple_request_field_group_add_field(g
, f
);
1273 purple_request_fields_add_group(fields
, g
);
1275 purple_request_fields(gc
, _("Create New SILC Key Pair"),
1276 _("Create New SILC Key Pair"), NULL
, fields
,
1277 _("Generate Key Pair"), G_CALLBACK(silcpurple_create_keypair_cb
),
1278 _("Cancel"), G_CALLBACK(silcpurple_create_keypair_cancel
),
1279 purple_request_cpar_from_connection(gc
), gc
);
1282 silc_free(hostname
);
1286 silcpurple_change_pass(PurpleProtocolAction
*action
)
1288 PurpleConnection
*gc
= action
->connection
;
1289 purple_account_request_change_password(purple_connection_get_account(gc
));
1293 silcpurple_change_passwd(PurpleConnection
*gc
, const char *old
, const char *new)
1296 g_snprintf(prd
, sizeof(prd
), "%s" G_DIR_SEPARATOR_S
"private_key.pub", silcpurple_silcdir());
1297 silc_change_private_key_passphrase(purple_account_get_string(purple_connection_get_account(gc
),
1299 prd
), old
? old
: "", new ? new : "");
1303 silcpurple_show_set_info(PurpleProtocolAction
*action
)
1305 PurpleConnection
*gc
= action
->connection
;
1306 purple_account_request_change_user_info(purple_connection_get_account(gc
));
1310 silcpurple_set_info(PurpleConnection
*gc
, const char *text
)
1315 silcpurple_get_actions(PurpleConnection
*gc
)
1318 PurpleProtocolAction
*act
;
1320 act
= purple_protocol_action_new(_("Online Status"),
1322 list
= g_list_append(list
, act
);
1324 act
= purple_protocol_action_new(_("Detach From Server"),
1326 list
= g_list_append(list
, act
);
1328 act
= purple_protocol_action_new(_("View Message of the Day"),
1329 silcpurple_view_motd
);
1330 list
= g_list_append(list
, act
);
1332 act
= purple_protocol_action_new(_("Create SILC Key Pair..."),
1333 silcpurple_create_keypair
);
1334 list
= g_list_append(list
, act
);
1336 act
= purple_protocol_action_new(_("Change Password..."),
1337 silcpurple_change_pass
);
1338 list
= g_list_append(list
, act
);
1340 act
= purple_protocol_action_new(_("Set User Info..."),
1341 silcpurple_show_set_info
);
1342 list
= g_list_append(list
, act
);
1348 /******************************* IM Routines *********************************/
1353 SilcUInt32 message_len
;
1354 SilcMessageFlags flags
;
1355 PurpleMessageFlags gflags
;
1359 silcpurple_send_im_resolved(SilcClient client
,
1360 SilcClientConnection conn
,
1365 PurpleConnection
*gc
= client
->application
;
1366 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
1367 SilcPurpleIM im
= context
;
1368 PurpleIMConversation
*convo
;
1370 SilcClientEntry client_entry
;
1372 gboolean free_list
= FALSE
;
1374 convo
= purple_conversations_find_im_with_account(im
->nick
,
1382 if (silc_dlist_count(clients
) > 1) {
1383 /* Find the correct one. The im->nick might be a formatted nick
1384 so this will find the correct one. */
1385 clients
= silc_client_get_clients_local(client
, conn
,
1393 silc_dlist_start(clients
);
1394 client_entry
= silc_dlist_get(clients
);
1396 /* Check for images */
1397 if (im
->gflags
& PURPLE_MESSAGE_IMAGES
) {
1398 list
= silcpurple_image_message(im
->message
, &im
->flags
);
1400 /* Send one or more MIME message. If more than one, they
1401 are MIME fragments due to over large message */
1404 silc_dlist_start(list
);
1405 while ((buf
= silc_dlist_get(list
)) != SILC_LIST_END
)
1406 silc_client_send_private_message(client
, conn
,
1407 client_entry
, im
->flags
, sg
->sha1hash
,
1409 silc_buffer_len(buf
));
1410 silc_mime_partial_free(list
);
1411 purple_conversation_write_message(PURPLE_CONVERSATION(convo
),
1412 purple_message_new_outgoing(
1413 conn
->local_entry
->nickname
, im
->message
, 0));
1418 /* Send the message */
1419 silc_client_send_private_message(client
, conn
, client_entry
, im
->flags
,
1420 sg
->sha1hash
, (unsigned char *)im
->message
, im
->message_len
);
1421 purple_conversation_write_message(PURPLE_CONVERSATION(convo
),
1422 purple_message_new_outgoing(conn
->local_entry
->nickname
, im
->message
, 0));
1426 g_snprintf(tmp
, sizeof(tmp
),
1427 _("User <I>%s</I> is not present in the network"), im
->nick
);
1428 purple_conversation_write_system_message(
1429 PURPLE_CONVERSATION(convo
), tmp
, 0);
1433 silc_client_list_free(client
, conn
, clients
);
1436 g_free(im
->message
);
1441 silcpurple_send_im(PurpleConnection
*gc
, PurpleMessage
*pmsg
)
1443 SilcPurple sg
= purple_connection_get_protocol_data(gc
);
1444 SilcClient client
= sg
->client
;
1445 SilcClientConnection conn
= sg
->conn
;
1447 SilcClientEntry client_entry
;
1448 SilcMessageFlags mflags
;
1451 gboolean sign
= purple_account_get_bool(sg
->account
, "sign-verify", FALSE
);
1453 const gchar
*rcpt
= purple_message_get_recipient(pmsg
);
1454 const gchar
*message
= purple_message_get_contents(pmsg
);
1455 PurpleMessageFlags flags
= purple_message_get_flags(pmsg
);
1457 if (!rcpt
|| purple_message_is_empty(pmsg
))
1460 mflags
= SILC_MESSAGE_FLAG_UTF8
;
1462 tmp
= msg
= purple_unescape_html(message
);
1464 if (!g_ascii_strncasecmp(msg
, "/me ", 4)) {
1470 mflags
|= SILC_MESSAGE_FLAG_ACTION
;
1471 } else if (strlen(msg
) > 1 && msg
[0] == '/') {
1472 if (!silc_client_command_call(client
, conn
, msg
+ 1))
1473 purple_notify_error(gc
, _("Call Command"),
1474 _("Cannot call command"),
1475 _("Unknown command"),
1476 purple_request_cpar_from_connection(gc
));
1482 mflags
|= SILC_MESSAGE_FLAG_SIGNED
;
1484 /* Find client entry */
1485 clients
= silc_client_get_clients_local(client
, conn
, rcpt
, FALSE
);
1487 /* Resolve unknown user */
1488 SilcPurpleIM im
= silc_calloc(1, sizeof(*im
));
1493 im
->nick
= g_strdup(rcpt
);
1494 im
->message
= g_strdup(message
);
1495 im
->message_len
= strlen(im
->message
);
1498 silc_client_get_clients(client
, conn
, rcpt
, NULL
,
1499 silcpurple_send_im_resolved
, im
);
1503 silc_dlist_start(clients
);
1504 client_entry
= silc_dlist_get(clients
);
1506 /* Check for images */
1507 if (flags
& PURPLE_MESSAGE_IMAGES
) {
1508 list
= silcpurple_image_message(message
, &mflags
);
1510 /* Send one or more MIME message. If more than one, they
1511 are MIME fragments due to over large message */
1514 silc_dlist_start(list
);
1515 while ((buf
= silc_dlist_get(list
)) != SILC_LIST_END
)
1517 silc_client_send_private_message(client
, conn
,
1518 client_entry
, mflags
, sg
->sha1hash
,
1520 silc_buffer_len(buf
));
1521 silc_mime_partial_free(list
);
1523 silc_client_list_free(client
, conn
, clients
);
1528 /* Send private message directly */
1529 ret
= silc_client_send_private_message(client
, conn
, client_entry
,
1530 mflags
, sg
->sha1hash
,
1531 (unsigned char *)msg
,
1535 silc_client_list_free(client
, conn
, clients
);
1540 static GList
*silcpurple_blist_node_menu(PurpleBlistNode
*node
) {
1541 /* split this single menu building function back into the two
1542 original: one for buddies and one for chats */
1543 if(PURPLE_IS_CHAT(node
)) {
1544 return silcpurple_chat_menu((PurpleChat
*) node
);
1545 } else if(PURPLE_IS_BUDDY(node
)) {
1546 return silcpurple_buddy_menu((PurpleBuddy
*) node
);
1548 g_return_val_if_reached(NULL
);
1552 /********************************* Commands **********************************/
1554 static PurpleCmdRet
silcpurple_cmd_chat_part(PurpleConversation
*conv
,
1555 const char *cmd
, char **args
, char **error
, void *data
)
1557 PurpleConnection
*gc
;
1558 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(conv
);
1561 gc
= purple_conversation_get_connection(conv
);
1564 return PURPLE_CMD_RET_FAILED
;
1567 chat
= purple_conversations_find_chat_with_account(args
[0],
1568 purple_connection_get_account(gc
));
1571 id
= purple_chat_conversation_get_id(chat
);
1574 return PURPLE_CMD_RET_FAILED
;
1576 silcpurple_chat_leave(gc
, id
);
1578 return PURPLE_CMD_RET_OK
;
1582 static PurpleCmdRet
silcpurple_cmd_chat_topic(PurpleConversation
*conv
,
1583 const char *cmd
, char **args
, char **error
, void *data
)
1585 PurpleConnection
*gc
;
1587 char *buf
, *tmp
, *tmp2
;
1590 gc
= purple_conversation_get_connection(conv
);
1591 id
= purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(conv
));
1593 if (gc
== NULL
|| id
== 0)
1594 return PURPLE_CMD_RET_FAILED
;
1596 if (!args
|| !args
[0]) {
1597 topic
= purple_chat_conversation_get_topic(PURPLE_CHAT_CONVERSATION(conv
));
1599 tmp
= g_markup_escape_text(topic
, -1);
1600 tmp2
= purple_markup_linkify(tmp
);
1601 buf
= g_strdup_printf(_("current topic is: %s"), tmp2
);
1605 buf
= g_strdup(_("No topic is set"));
1606 purple_conversation_write_system_message(conv
,
1607 buf
, PURPLE_MESSAGE_NO_LOG
);
1612 if (args
&& args
[0] && (strlen(args
[0]) > 255)) {
1613 *error
= g_strdup(_("Topic too long"));
1614 return PURPLE_CMD_RET_FAILED
;
1617 silcpurple_chat_set_topic(gc
, id
, args
? args
[0] : NULL
);
1619 return PURPLE_CMD_RET_OK
;
1622 static PurpleCmdRet
silcpurple_cmd_chat_join(PurpleConversation
*conv
,
1623 const char *cmd
, char **args
, char **error
, void *data
)
1627 if(!args
|| !args
[0])
1628 return PURPLE_CMD_RET_FAILED
;
1630 comp
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, NULL
);
1632 g_hash_table_replace(comp
, "channel", args
[0]);
1634 g_hash_table_replace(comp
, "passphrase", args
[1]);
1636 silcpurple_chat_join(purple_conversation_get_connection(conv
), comp
);
1638 g_hash_table_destroy(comp
);
1639 return PURPLE_CMD_RET_OK
;
1642 static PurpleCmdRet
silcpurple_cmd_chat_list(PurpleConversation
*conv
,
1643 const char *cmd
, char **args
, char **error
, void *data
)
1645 PurpleConnection
*gc
;
1646 gc
= purple_conversation_get_connection(conv
);
1647 purple_roomlist_show_with_account(purple_connection_get_account(gc
));
1648 return PURPLE_CMD_RET_OK
;
1651 static PurpleCmdRet
silcpurple_cmd_whois(PurpleConversation
*conv
,
1652 const char *cmd
, char **args
, char **error
, void *data
)
1654 PurpleConnection
*gc
;
1656 gc
= purple_conversation_get_connection(conv
);
1659 return PURPLE_CMD_RET_FAILED
;
1661 silcpurple_get_info(gc
, args
[0]);
1663 return PURPLE_CMD_RET_OK
;
1666 static PurpleCmdRet
silcpurple_cmd_msg(PurpleConversation
*conv
,
1667 const char *cmd
, char **args
, char **error
, void *data
)
1670 PurpleConnection
*gc
;
1672 gc
= purple_conversation_get_connection(conv
);
1675 return PURPLE_CMD_RET_FAILED
;
1677 ret
= silcpurple_send_im(gc
,
1678 purple_message_new_outgoing(args
[0], args
[1], 0));
1681 return PURPLE_CMD_RET_OK
;
1683 return PURPLE_CMD_RET_FAILED
;
1686 static PurpleCmdRet
silcpurple_cmd_query(PurpleConversation
*conv
,
1687 const char *cmd
, char **args
, char **error
, void *data
)
1690 PurpleIMConversation
*im
;
1691 PurpleConnection
*gc
;
1692 PurpleAccount
*account
;
1694 if (!args
|| !args
[0]) {
1695 *error
= g_strdup(_("You must specify a nick"));
1696 return PURPLE_CMD_RET_FAILED
;
1699 gc
= purple_conversation_get_connection(conv
);
1702 return PURPLE_CMD_RET_FAILED
;
1704 account
= purple_connection_get_account(gc
);
1706 im
= purple_im_conversation_new(account
, args
[0]);
1709 PurpleMessage
*msg
= purple_message_new_outgoing(
1710 args
[0], args
[1], 0);
1712 ret
= silcpurple_send_im(gc
, msg
);
1713 purple_conversation_write_message(PURPLE_CONVERSATION(im
), msg
);
1717 return PURPLE_CMD_RET_OK
;
1719 return PURPLE_CMD_RET_FAILED
;
1722 static PurpleCmdRet
silcpurple_cmd_motd(PurpleConversation
*conv
,
1723 const char *cmd
, char **args
, char **error
, void *data
)
1725 PurpleConnection
*gc
;
1729 gc
= purple_conversation_get_connection(conv
);
1732 return PURPLE_CMD_RET_FAILED
;
1734 sg
= purple_connection_get_protocol_data(gc
);
1737 return PURPLE_CMD_RET_FAILED
;
1740 *error
= g_strdup(_("There is no Message of the Day associated with this connection"));
1741 return PURPLE_CMD_RET_FAILED
;
1744 tmp
= g_markup_escape_text(sg
->motd
, -1);
1745 purple_notify_formatted(gc
, NULL
, _("Message of the Day"), NULL
,
1749 return PURPLE_CMD_RET_OK
;
1752 static PurpleCmdRet
silcpurple_cmd_detach(PurpleConversation
*conv
,
1753 const char *cmd
, char **args
, char **error
, void *data
)
1755 PurpleConnection
*gc
;
1758 gc
= purple_conversation_get_connection(conv
);
1761 return PURPLE_CMD_RET_FAILED
;
1763 sg
= purple_connection_get_protocol_data(gc
);
1766 return PURPLE_CMD_RET_FAILED
;
1768 silc_client_command_call(sg
->client
, sg
->conn
, "DETACH");
1769 sg
->detaching
= TRUE
;
1771 return PURPLE_CMD_RET_OK
;
1774 static PurpleCmdRet
silcpurple_cmd_cmode(PurpleConversation
*conv
,
1775 const char *cmd
, char **args
, char **error
, void *data
)
1777 PurpleConnection
*gc
;
1779 SilcChannelEntry channel
;
1780 char *silccmd
, *silcargs
, *msg
, tmp
[256];
1783 gc
= purple_conversation_get_connection(conv
);
1785 if (gc
== NULL
|| !args
|| purple_connection_get_protocol_data(gc
) == NULL
)
1786 return PURPLE_CMD_RET_FAILED
;
1788 sg
= purple_connection_get_protocol_data(gc
);
1793 chname
= purple_conversation_get_name(conv
);
1796 channel
= silc_client_get_channel(sg
->client
, sg
->conn
,
1799 *error
= g_strdup_printf(_("channel %s not found"), chname
);
1800 return PURPLE_CMD_RET_FAILED
;
1802 if (channel
->mode
) {
1803 silcpurple_get_chmode_string(channel
->mode
, tmp
, sizeof(tmp
));
1804 msg
= g_strdup_printf(_("channel modes for %s: %s"), chname
, tmp
);
1806 msg
= g_strdup_printf(_("no channel modes are set on %s"), chname
);
1808 purple_conversation_write_system_message(conv
, msg
, PURPLE_MESSAGE_NO_LOG
);
1810 return PURPLE_CMD_RET_OK
;
1813 silcargs
= g_strjoinv(" ", args
);
1814 silccmd
= g_strconcat(cmd
, " ", silcargs
, NULL
);
1816 if (!silc_client_command_call(sg
->client
, sg
->conn
, silccmd
)) {
1818 *error
= g_strdup_printf(_("Failed to set cmodes for %s"), args
[0]);
1819 return PURPLE_CMD_RET_FAILED
;
1823 return PURPLE_CMD_RET_OK
;
1826 static PurpleCmdRet
silcpurple_cmd_generic(PurpleConversation
*conv
,
1827 const char *cmd
, char **args
, char **error
, void *data
)
1829 PurpleConnection
*gc
;
1831 char *silccmd
, *silcargs
;
1833 gc
= purple_conversation_get_connection(conv
);
1836 return PURPLE_CMD_RET_FAILED
;
1838 sg
= purple_connection_get_protocol_data(gc
);
1841 return PURPLE_CMD_RET_FAILED
;
1843 silcargs
= g_strjoinv(" ", args
);
1844 silccmd
= g_strconcat(cmd
, " ", args
? silcargs
: NULL
, NULL
);
1846 if (!silc_client_command_call(sg
->client
, sg
->conn
, silccmd
)) {
1848 *error
= g_strdup_printf(_("Unknown command: %s, (may be a client bug)"), cmd
);
1849 return PURPLE_CMD_RET_FAILED
;
1853 return PURPLE_CMD_RET_OK
;
1856 static PurpleCmdRet
silcpurple_cmd_quit(PurpleConversation
*conv
,
1857 const char *cmd
, char **args
, char **error
, void *data
)
1859 PurpleConnection
*gc
;
1861 GHashTable
*ui_info
;
1862 const char *ui_name
= NULL
, *ui_website
= NULL
;
1865 gc
= purple_conversation_get_connection(conv
);
1868 return PURPLE_CMD_RET_FAILED
;
1870 sg
= purple_connection_get_protocol_data(gc
);
1873 return PURPLE_CMD_RET_FAILED
;
1875 ui_info
= purple_core_get_ui_info();
1878 ui_name
= g_hash_table_lookup(ui_info
, "name");
1879 ui_website
= g_hash_table_lookup(ui_info
, "website");
1882 if(!ui_name
|| !ui_website
) {
1884 ui_website
= PURPLE_WEBSITE
;
1886 quit_msg
= g_strdup_printf(_("Download %s: %s"),
1887 ui_name
, ui_website
);
1889 silc_client_command_call(sg
->client
, sg
->conn
, NULL
,
1890 "QUIT", (args
&& args
[0]) ? args
[0] : quit_msg
, NULL
);
1893 return PURPLE_CMD_RET_OK
;
1896 static PurpleCmdRet
silcpurple_cmd_call(PurpleConversation
*conv
,
1897 const char *cmd
, char **args
, char **error
, void *data
)
1899 PurpleConnection
*gc
;
1902 gc
= purple_conversation_get_connection(conv
);
1905 return PURPLE_CMD_RET_FAILED
;
1907 sg
= purple_connection_get_protocol_data(gc
);
1910 return PURPLE_CMD_RET_FAILED
;
1912 if (!silc_client_command_call(sg
->client
, sg
->conn
, args
[0])) {
1913 *error
= g_strdup_printf(_("Unknown command: %s"), args
[0]);
1914 return PURPLE_CMD_RET_FAILED
;
1917 return PURPLE_CMD_RET_OK
;
1921 /************************** Plugin Initialization ****************************/
1924 silcpurple_register_commands(void)
1928 id
= purple_cmd_register("part", "w", PURPLE_CMD_P_PROTOCOL
,
1929 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
|
1930 PURPLE_CMD_FLAG_PROTOCOL_ONLY
| PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
1931 "prpl-silc", silcpurple_cmd_chat_part
, _("part [channel]: Leave the chat"), NULL
);
1932 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1934 id
= purple_cmd_register("leave", "w", PURPLE_CMD_P_PROTOCOL
,
1935 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
|
1936 PURPLE_CMD_FLAG_PROTOCOL_ONLY
| PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
1937 "prpl-silc", silcpurple_cmd_chat_part
, _("leave [channel]: Leave the chat"), NULL
);
1938 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1940 id
= purple_cmd_register("topic", "s", PURPLE_CMD_P_PROTOCOL
,
1941 PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
1942 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc",
1943 silcpurple_cmd_chat_topic
, _("topic [<new topic>]: View or change the topic"), NULL
);
1944 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1946 id
= purple_cmd_register("join", "ws", PURPLE_CMD_P_PROTOCOL
,
1947 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
|
1948 PURPLE_CMD_FLAG_PROTOCOL_ONLY
| PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
,
1949 "prpl-silc", silcpurple_cmd_chat_join
,
1950 _("join <channel> [<password>]: Join a chat on this network"), NULL
);
1951 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1953 id
= purple_cmd_register("list", "", PURPLE_CMD_P_PROTOCOL
,
1954 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
1955 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc",
1956 silcpurple_cmd_chat_list
, _("list: List channels on this network"), NULL
);
1957 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1959 id
= purple_cmd_register("whois", "w", PURPLE_CMD_P_PROTOCOL
,
1960 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
1962 silcpurple_cmd_whois
, _("whois <nick>: View nick's information"), NULL
);
1963 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1965 id
= purple_cmd_register("msg", "ws", PURPLE_CMD_P_PROTOCOL
,
1966 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
1967 "prpl-silc", silcpurple_cmd_msg
,
1968 _("msg <nick> <message>: Send a private message to a user"), NULL
);
1969 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1971 id
= purple_cmd_register("query", "ws", PURPLE_CMD_P_PROTOCOL
,
1972 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
1973 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_query
,
1974 _("query <nick> [<message>]: Send a private message to a user"), NULL
);
1975 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1977 id
= purple_cmd_register("motd", "", PURPLE_CMD_P_PROTOCOL
,
1978 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
1979 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_motd
,
1980 _("motd: View the server's Message Of The Day"), NULL
);
1981 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1983 id
= purple_cmd_register("detach", "", PURPLE_CMD_P_PROTOCOL
,
1984 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
1985 "prpl-silc", silcpurple_cmd_detach
,
1986 _("detach: Detach this session"), NULL
);
1987 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1989 id
= purple_cmd_register("quit", "s", PURPLE_CMD_P_PROTOCOL
,
1990 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
1991 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_quit
,
1992 _("quit [message]: Disconnect from the server, with an optional message"), NULL
);
1993 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
1995 id
= purple_cmd_register("call", "s", PURPLE_CMD_P_PROTOCOL
,
1996 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
1997 "prpl-silc", silcpurple_cmd_call
,
1998 _("call <command>: Call any silc client command"), NULL
);
1999 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2001 /* These below just get passed through for the silc client library to deal
2003 id
= purple_cmd_register("kill", "ws", PURPLE_CMD_P_PROTOCOL
,
2004 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2005 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_generic
,
2006 _("kill <nick> [-pubkey|<reason>]: Kill nick"), NULL
);
2007 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2009 id
= purple_cmd_register("nick", "w", PURPLE_CMD_P_PROTOCOL
,
2010 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
2011 "prpl-silc", silcpurple_cmd_generic
,
2012 _("nick <newnick>: Change your nickname"), NULL
);
2013 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2015 id
= purple_cmd_register("whowas", "ww", PURPLE_CMD_P_PROTOCOL
,
2016 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2017 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_generic
,
2018 _("whowas <nick>: View nick's information"), NULL
);
2019 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2021 id
= purple_cmd_register("cmode", "wws", PURPLE_CMD_P_PROTOCOL
,
2022 PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2023 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_cmode
,
2024 _("cmode <channel> [+|-<modes>] [arguments]: Change or display channel modes"), NULL
);
2025 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2027 id
= purple_cmd_register("cumode", "wws", PURPLE_CMD_P_PROTOCOL
,
2028 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2029 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_generic
,
2030 _("cumode <channel> +|-<modes> <nick>: Change nick's modes on channel"), NULL
);
2031 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2033 id
= purple_cmd_register("umode", "w", PURPLE_CMD_P_PROTOCOL
,
2034 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
2035 "prpl-silc", silcpurple_cmd_generic
,
2036 _("umode <usermodes>: Set your modes in the network"), NULL
);
2037 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2039 id
= purple_cmd_register("oper", "s", PURPLE_CMD_P_PROTOCOL
,
2040 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
2041 "prpl-silc", silcpurple_cmd_generic
,
2042 _("oper <nick> [-pubkey]: Get server operator privileges"), NULL
);
2043 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2045 id
= purple_cmd_register("invite", "ws", PURPLE_CMD_P_PROTOCOL
,
2046 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2047 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_generic
,
2048 _("invite <channel> [-|+]<nick>: invite nick or add/remove from channel invite list"), NULL
);
2049 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2051 id
= purple_cmd_register("kick", "wws", PURPLE_CMD_P_PROTOCOL
,
2052 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2053 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_generic
,
2054 _("kick <channel> <nick> [comment]: Kick client from channel"), NULL
);
2055 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2057 id
= purple_cmd_register("info", "w", PURPLE_CMD_P_PROTOCOL
,
2058 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2059 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_generic
,
2060 _("info [server]: View server administrative details"), NULL
);
2061 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2063 id
= purple_cmd_register("ban", "ww", PURPLE_CMD_P_PROTOCOL
,
2064 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
|
2065 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
, "prpl-silc", silcpurple_cmd_generic
,
2066 _("ban [<channel> +|-<nick>]: Ban client from channel"), NULL
);
2067 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2069 id
= purple_cmd_register("getkey", "w", PURPLE_CMD_P_PROTOCOL
,
2070 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
2071 "prpl-silc", silcpurple_cmd_generic
,
2072 _("getkey <nick|server>: Retrieve client's or server's public key"), NULL
);
2073 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2075 id
= purple_cmd_register("stats", "", PURPLE_CMD_P_PROTOCOL
,
2076 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
2077 "prpl-silc", silcpurple_cmd_generic
,
2078 _("stats: View server and network statistics"), NULL
);
2079 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2081 id
= purple_cmd_register("ping", "", PURPLE_CMD_P_PROTOCOL
,
2082 PURPLE_CMD_FLAG_IM
| PURPLE_CMD_FLAG_CHAT
| PURPLE_CMD_FLAG_PROTOCOL_ONLY
,
2083 "prpl-silc", silcpurple_cmd_generic
,
2084 _("ping: Send PING to the connected server"), NULL
);
2085 cmds
= g_slist_prepend(cmds
, GUINT_TO_POINTER(id
));
2089 silcpurple_unregister_commands(void)
2092 PurpleCmdId id
= GPOINTER_TO_UINT(cmds
->data
);
2093 purple_cmd_unregister(id
);
2094 cmds
= g_slist_delete_link(cmds
, cmds
);
2098 static PurpleWhiteboardOps silcpurple_wb_ops
=
2100 silcpurple_wb_start
,
2102 silcpurple_wb_get_dimensions
,
2103 silcpurple_wb_set_dimensions
,
2104 silcpurple_wb_get_brush
,
2105 silcpurple_wb_set_brush
,
2107 silcpurple_wb_clear
,
2118 silcpurple_protocol_init(PurpleProtocol
*protocol
)
2120 PurpleAccountOption
*option
;
2121 PurpleAccountUserSplit
*split
;
2124 PurpleKeyValuePair
*kvp
;
2127 protocol
->id
= "prpl-silc";
2128 protocol
->name
= "SILC";
2129 protocol
->options
= OPT_PROTO_CHAT_TOPIC
| OPT_PROTO_UNIQUE_CHATNAME
|
2130 OPT_PROTO_PASSWORD_OPTIONAL
|
2131 OPT_PROTO_SLASH_COMMANDS_NATIVE
;
2132 protocol
->icon_spec
= purple_buddy_icon_spec_new("jpeg,gif,png,bmp",
2134 PURPLE_ICON_SCALE_DISPLAY
);
2136 protocol
->whiteboard_ops
= &silcpurple_wb_ops
;
2138 split
= purple_account_user_split_new(_("Network"), "silcnet.org", '@');
2139 protocol
->user_splits
= g_list_append(protocol
->user_splits
, split
);
2141 /* Account options */
2142 option
= purple_account_option_string_new(_("Connect server"),
2144 "silc.silcnet.org");
2145 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2146 option
= purple_account_option_int_new(_("Port"), "port", 706);
2147 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2148 g_snprintf(tmp
, sizeof(tmp
), "%s" G_DIR_SEPARATOR_S
"public_key.pub", silcpurple_silcdir());
2149 option
= purple_account_option_string_new(_("Public Key file"),
2151 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2152 g_snprintf(tmp
, sizeof(tmp
), "%s" G_DIR_SEPARATOR_S
"private_key.prv", silcpurple_silcdir());
2153 option
= purple_account_option_string_new(_("Private Key file"),
2154 "private-key", tmp
);
2155 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2157 for (i
= 0; silc_default_ciphers
[i
].name
; i
++) {
2158 kvp
= g_new0(PurpleKeyValuePair
, 1);
2159 kvp
->key
= g_strdup(silc_default_ciphers
[i
].name
);
2160 kvp
->value
= g_strdup(silc_default_ciphers
[i
].name
);
2161 list
= g_list_append(list
, kvp
);
2163 option
= purple_account_option_list_new(_("Cipher"), "cipher", list
);
2164 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2167 for (i
= 0; silc_default_hmacs
[i
].name
; i
++) {
2168 kvp
= g_new0(PurpleKeyValuePair
, 1);
2169 kvp
->key
= g_strdup(silc_default_hmacs
[i
].name
);
2170 kvp
->value
= g_strdup(silc_default_hmacs
[i
].name
);
2171 list
= g_list_append(list
, kvp
);
2173 option
= purple_account_option_list_new(_("HMAC"), "hmac", list
);
2174 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2176 option
= purple_account_option_bool_new(_("Use Perfect Forward Secrecy"),
2178 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2180 option
= purple_account_option_bool_new(_("Public key authentication"),
2181 "pubkey-auth", FALSE
);
2182 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2183 option
= purple_account_option_bool_new(_("Block IMs without Key Exchange"),
2184 "block-ims", FALSE
);
2185 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2186 option
= purple_account_option_bool_new(_("Block messages to whiteboard"),
2188 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2189 option
= purple_account_option_bool_new(_("Automatically open whiteboard"),
2191 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2192 option
= purple_account_option_bool_new(_("Digitally sign and verify all messages"),
2193 "sign-verify", FALSE
);
2194 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
2198 silcpurple_protocol_class_init(PurpleProtocolClass
*klass
)
2200 klass
->login
= silcpurple_login
;
2201 klass
->close
= silcpurple_close
;
2202 klass
->status_types
= silcpurple_away_states
;
2203 klass
->list_icon
= silcpurple_list_icon
;
2207 silcpurple_protocol_client_iface_init(PurpleProtocolClientInterface
*client_iface
)
2209 client_iface
->get_actions
= silcpurple_get_actions
;
2210 client_iface
->status_text
= silcpurple_status_text
;
2211 client_iface
->tooltip_text
= silcpurple_tooltip_text
;
2212 client_iface
->blist_node_menu
= silcpurple_blist_node_menu
;
2216 silcpurple_protocol_server_iface_init(PurpleProtocolServerInterface
*server_iface
)
2218 server_iface
->set_info
= silcpurple_set_info
;
2219 server_iface
->get_info
= silcpurple_get_info
;
2220 server_iface
->set_status
= silcpurple_set_status
;
2221 server_iface
->set_idle
= silcpurple_idle_set
;
2222 server_iface
->change_passwd
= silcpurple_change_passwd
;
2223 server_iface
->add_buddy
= silcpurple_add_buddy
;
2224 server_iface
->remove_buddy
= silcpurple_remove_buddy
;
2225 server_iface
->keepalive
= silcpurple_keepalive
;
2226 server_iface
->set_buddy_icon
= silcpurple_buddy_set_icon
;
2230 silcpurple_protocol_im_iface_init(PurpleProtocolIMInterface
*im_iface
)
2232 im_iface
->send
= silcpurple_send_im
;
2236 silcpurple_protocol_chat_iface_init(PurpleProtocolChatInterface
*chat_iface
)
2238 chat_iface
->info
= silcpurple_chat_info
;
2239 chat_iface
->info_defaults
= silcpurple_chat_info_defaults
;
2240 chat_iface
->join
= silcpurple_chat_join
;
2241 chat_iface
->get_name
= silcpurple_get_chat_name
;
2242 chat_iface
->invite
= silcpurple_chat_invite
;
2243 chat_iface
->leave
= silcpurple_chat_leave
;
2244 chat_iface
->send
= silcpurple_chat_send
;
2245 chat_iface
->set_topic
= silcpurple_chat_set_topic
;
2249 silcpurple_protocol_roomlist_iface_init(PurpleProtocolRoomlistInterface
*roomlist_iface
)
2251 roomlist_iface
->get_list
= silcpurple_roomlist_get_list
;
2252 roomlist_iface
->cancel
= silcpurple_roomlist_cancel
;
2256 silcpurple_protocol_xfer_iface_init(PurpleProtocolXferInterface
*xfer_iface
)
2258 xfer_iface
->send_file
= silcpurple_ftp_send_file
;
2259 xfer_iface
->new_xfer
= silcpurple_ftp_new_xfer
;
2262 PURPLE_DEFINE_TYPE_EXTENDED(
2263 SilcProtocol
, silcpurple_protocol
, PURPLE_TYPE_PROTOCOL
, 0,
2265 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CLIENT
,
2266 silcpurple_protocol_client_iface_init
)
2268 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_SERVER
,
2269 silcpurple_protocol_server_iface_init
)
2271 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_IM
,
2272 silcpurple_protocol_im_iface_init
)
2274 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CHAT
,
2275 silcpurple_protocol_chat_iface_init
)
2277 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_ROOMLIST
,
2278 silcpurple_protocol_roomlist_iface_init
)
2280 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_XFER
,
2281 silcpurple_protocol_xfer_iface_init
)
2284 static PurplePluginInfo
*
2285 plugin_query(GError
**error
)
2287 const gchar
* const authors
[] = {
2292 return purple_plugin_info_new(
2294 "name", "SILC Protocol",
2296 "category", N_("Protocol"),
2297 "summary", N_("SILC Protocol Plugin"),
2298 "description", N_("Secure Internet Live Conferencing (SILC) Protocol"),
2300 "website", "http://silcnet.org/",
2301 "abi-version", PURPLE_ABI_VERSION
,
2302 "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
2303 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
2309 plugin_load(PurplePlugin
*plugin
, GError
**error
)
2311 silcpurple_protocol_register_type(plugin
);
2313 my_protocol
= purple_protocols_add(SILCPURPLE_TYPE_PROTOCOL
, error
);
2317 purple_prefs_remove("/plugins/prpl/silc");
2319 silc_log_set_callback(SILC_LOG_ERROR
, silcpurple_log_error
, NULL
);
2320 silcpurple_register_commands();
2326 plugin_unload(PurplePlugin
*plugin
, GError
**error
)
2328 silcpurple_unregister_commands();
2330 if (!purple_protocols_remove(my_protocol
, error
))
2336 PURPLE_PLUGIN_INIT(silc
, plugin_query
, plugin_load
, plugin_unload
);