5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
32 #include "version_internal.h"
38 #include "fe-common/core/printtext.h"
39 #include "fe-common/core/fe-channels.h"
41 /* Command line option variables */
42 static char *opt_server = NULL;
43 static int opt_port = 0;
44 static char *opt_nickname = NULL;
45 static char *opt_channel = NULL;
46 static char *opt_cipher = NULL;
47 static char *opt_public_key = NULL;
48 static char *opt_private_key = NULL;
49 static char *opt_config_file = NULL;
50 static bool opt_no_silcrc = FALSE;
52 static bool opt_create_keypair = FALSE;
53 static char *opt_pkcs = NULL;
54 static char *opt_keyfile = NULL;
55 static int opt_bits = 0;
59 SilcClient silc_client = NULL;
60 SilcClientConfig silc_config = NULL;
61 extern SilcClientOperations ops;
63 /* SIM (SILC Module) table */
64 SilcSimContext **sims = NULL;
65 uint32 sims_count = 0;
68 static void silc_say(SilcClient client, SilcClientConnection conn,
71 silc_channel_message(SilcClient client, SilcClientConnection conn,
72 SilcClientEntry sender, SilcChannelEntry channel,
73 SilcMessageFlags flags, char *msg);
75 silc_private_message(SilcClient client, SilcClientConnection conn,
76 SilcClientEntry sender, SilcMessageFlags flags,
78 static void silc_notify(SilcClient client, SilcClientConnection conn,
79 SilcNotifyType type, ...);
81 silc_connect(SilcClient client, SilcClientConnection conn, int success);
83 silc_disconnect(SilcClient client, SilcClientConnection conn);
85 silc_command(SilcClient client, SilcClientConnection conn,
86 SilcClientCommandContext cmd_context, int success,
89 silc_command_reply(SilcClient client, SilcClientConnection conn,
90 SilcCommandPayload cmd_payload, int success,
91 SilcCommand command, SilcCommandStatus status, ...);
93 static int silc_verify_public_key(SilcClient client,
94 SilcClientConnection conn,
95 SilcSocketType conn_type,
96 unsigned char *pk, uint32 pk_len,
97 SilcSKEPKType pk_type);
98 static unsigned char *silc_ask_passphrase(SilcClient client,
99 SilcClientConnection conn);
101 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
102 char *hostname, uint16 port,
103 SilcProtocolAuthMeth *auth_meth,
104 unsigned char **auth_data,
105 uint32 *auth_data_len);
107 silc_failure(SilcClient client, SilcClientConnection conn,
108 SilcProtocol protocol, void *failure);
110 silc_key_agreement(SilcClient client, SilcClientConnection conn,
111 SilcClientEntry client_entry, char *hostname,
113 SilcKeyAgreementCallback *completion,
116 static void silc_say(SilcClient client, SilcClientConnection conn,
119 SILC_SERVER_REC *server;
123 server = conn == NULL ? NULL : conn->context;
126 str = g_strdup_vprintf(msg, va);
127 printtext(server, "#silc", MSGLEVEL_CRAP, "%s", str);
132 static void silc_say_error(char *msg, ...)
138 str = g_strdup_vprintf(msg, va);
139 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
145 /* Message for a channel. The `sender' is the nickname of the sender
146 received in the packet. The `channel_name' is the name of the channel. */
149 silc_channel_message(SilcClient client, SilcClientConnection conn,
150 SilcClientEntry sender, SilcChannelEntry channel,
151 SilcMessageFlags flags, char *msg)
153 SILC_SERVER_REC *server;
155 SILC_CHANNEL_REC *chanrec;
157 server = conn == NULL ? NULL : conn->context;
158 chanrec = silc_channel_find_entry(server, channel);
160 nick = silc_nicklist_find(chanrec, sender);
161 signal_emit("message public", 6, server, msg,
162 nick == NULL ? "[<unknown>]" : nick->nick,
163 nick == NULL ? NULL : nick->host,
164 chanrec->name, nick);
167 /* Private message to the client. The `sender' is the nickname of the
168 sender received in the packet. */
171 silc_private_message(SilcClient client, SilcClientConnection conn,
172 SilcClientEntry sender, SilcMessageFlags flags,
175 SILC_SERVER_REC *server;
177 server = conn == NULL ? NULL : conn->context;
178 signal_emit("message private", 4, server, msg,
179 sender->nickname ? sender->nickname : "[<unknown>]",
180 sender->username ? sender->username : NULL);
183 /* Notify message to the client. The notify arguments are sent in the
184 same order as servers sends them. The arguments are same as received
185 from the server except for ID's. If ID is received application receives
186 the corresponding entry to the ID. For example, if Client ID is received
187 application receives SilcClientEntry. Also, if the notify type is
188 for channel the channel entry is sent to application (even if server
189 does not send it). */
196 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
197 static NOTIFY_REC notifies[] = {
198 { SILC_NOTIFY_TYPE_NONE, NULL },
199 { SILC_NOTIFY_TYPE_INVITE, "invite" },
200 { SILC_NOTIFY_TYPE_JOIN, "join" },
201 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
202 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
203 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
204 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
205 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
206 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
207 { SILC_NOTIFY_TYPE_MOTD, "motd" },
208 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
209 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
210 { SILC_NOTIFY_TYPE_KICKED, "kick" },
211 { SILC_NOTIFY_TYPE_KILLED, "kill" },
212 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
213 { SILC_NOTIFY_TYPE_BAN, "ban" },
216 static void silc_notify(SilcClient client, SilcClientConnection conn,
217 SilcNotifyType type, ...)
219 SILC_SERVER_REC *server;
222 server = conn == NULL ? NULL : conn->context;
225 if (type == SILC_NOTIFY_TYPE_NONE) {
226 /* Some generic notice from server */
227 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
228 } else if (type < MAX_NOTIFY) {
229 /* Send signal about the notify event */
231 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
232 signal_emit(signal, 2, server, va);
235 printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type);
241 /* Called to indicate that connection was either successfully established
242 or connecting failed. This is also the first time application receives
243 the SilcClientConnection objecet which it should save somewhere. */
246 silc_connect(SilcClient client, SilcClientConnection conn, int success)
248 SILC_SERVER_REC *server = conn->context;
251 server->connected = TRUE;
252 signal_emit("event connected", 1, server);
254 server->connection_lost = TRUE;
255 server->conn->context = NULL;
256 server_disconnect(SERVER(server));
260 /* Called to indicate that connection was disconnected to the server. */
263 silc_disconnect(SilcClient client, SilcClientConnection conn)
265 SILC_SERVER_REC *server = conn->context;
267 server->conn->context = NULL;
269 server->connection_lost = TRUE;
270 server_disconnect(SERVER(server));
273 /* Command handler. This function is called always in the command function.
274 If error occurs it will be called as well. `conn' is the associated
275 client connection. `cmd_context' is the command context that was
276 originally sent to the command. `success' is FALSE if error occured
277 during command. `command' is the command being processed. It must be
278 noted that this is not reply from server. This is merely called just
279 after application has called the command. Just to tell application
280 that the command really was processed. */
283 silc_command(SilcClient client, SilcClientConnection conn,
284 SilcClientCommandContext cmd_context, int success,
289 /* Client info resolving callback when JOIN command reply is received.
290 This will cache all users on the channel. */
292 void silc_client_join_get_users(SilcClient client,
293 SilcClientConnection conn,
294 SilcClientEntry *clients,
295 uint32 clients_count,
298 SilcChannelEntry channel = (SilcChannelEntry)context;
300 SILC_SERVER_REC *server = conn->context;
301 SILC_CHANNEL_REC *chanrec;
307 chanrec = silc_channel_find_entry(server, channel);
311 silc_list_start(channel->clients);
312 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END)
313 silc_nicklist_insert(chanrec, chu, FALSE);
315 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
316 nicklist_set_own(CHANNEL(chanrec), ownnick);
317 signal_emit("channel joined", 1, chanrec);
318 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
321 /* Command reply handler. This function is called always in the command reply
322 function. If error occurs it will be called as well. Normal scenario
323 is that it will be called after the received command data has been parsed
324 and processed. The function is used to pass the received command data to
327 `conn' is the associated client connection. `cmd_payload' is the command
328 payload data received from server and it can be ignored. It is provided
329 if the application would like to re-parse the received command data,
330 however, it must be noted that the data is parsed already by the library
331 thus the payload can be ignored. `success' is FALSE if error occured.
332 In this case arguments are not sent to the application. `command' is the
333 command reply being processed. The function has variable argument list
334 and each command defines the number and type of arguments it passes to the
335 application (on error they are not sent). */
338 silc_command_reply(SilcClient client, SilcClientConnection conn,
339 SilcCommandPayload cmd_payload, int success,
340 SilcCommand command, SilcCommandStatus status, ...)
343 SILC_SERVER_REC *server = conn->context;
344 SILC_CHANNEL_REC *chanrec;
347 va_start(vp, status);
350 case SILC_COMMAND_WHOIS:
352 char buf[1024], *nickname, *username, *realname;
357 /* XXX should use irssi routines */
359 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
360 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
362 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
365 client->ops->say(client, conn, "%s: %s", tmp,
366 silc_client_command_status_message(status));
368 client->ops->say(client, conn, "%s",
369 silc_client_command_status_message(status));
376 (void)va_arg(vp, SilcClientEntry);
377 nickname = va_arg(vp, char *);
378 username = va_arg(vp, char *);
379 realname = va_arg(vp, char *);
380 channels = va_arg(vp, SilcBuffer);
381 mode = va_arg(vp, uint32);
382 idle = va_arg(vp, uint32);
384 memset(buf, 0, sizeof(buf));
387 len = strlen(nickname);
388 strncat(buf, nickname, len);
389 strncat(buf, " is ", 4);
393 strncat(buf, username, strlen(username));
397 strncat(buf, " (", 2);
398 strncat(buf, realname, strlen(realname));
399 strncat(buf, ")", 1);
402 client->ops->say(client, conn, "%s", buf);
405 SilcDList list = silc_channel_payload_parse_list(channels);
407 SilcChannelPayload entry;
409 memset(buf, 0, sizeof(buf));
410 strcat(buf, "on channels: ");
412 silc_dlist_start(list);
413 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
414 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
416 char *name = silc_channel_get_name(entry, &name_len);
419 strncat(buf, m, strlen(m));
420 strncat(buf, name, name_len);
421 strncat(buf, " ", 1);
425 client->ops->say(client, conn, "%s", buf);
426 silc_channel_payload_list_free(list);
431 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
432 (mode & SILC_UMODE_ROUTER_OPERATOR))
433 client->ops->say(client, conn, "%s is %s", nickname,
434 (mode & SILC_UMODE_SERVER_OPERATOR) ?
436 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
437 "SILC Operator" : "[Unknown mode]");
439 if (mode & SILC_UMODE_GONE)
440 client->ops->say(client, conn, "%s is gone", nickname);
443 if (idle && nickname)
444 client->ops->say(client, conn, "%s has been idle %d %s",
446 idle > 60 ? (idle / 60) : idle,
447 idle > 60 ? "minutes" : "seconds");
451 case SILC_COMMAND_WHOWAS:
453 char buf[1024], *nickname, *username, *realname;
456 /* XXX should use irssi routines */
458 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
459 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
461 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
464 client->ops->say(client, conn, "%s: %s", tmp,
465 silc_client_command_status_message(status));
467 client->ops->say(client, conn, "%s",
468 silc_client_command_status_message(status));
475 (void)va_arg(vp, SilcClientEntry);
476 nickname = va_arg(vp, char *);
477 username = va_arg(vp, char *);
478 realname = va_arg(vp, char *);
480 memset(buf, 0, sizeof(buf));
483 len = strlen(nickname);
484 strncat(buf, nickname, len);
485 strncat(buf, " was ", 5);
489 strncat(buf, username, strlen(nickname));
493 strncat(buf, " (", 2);
494 strncat(buf, realname, strlen(realname));
495 strncat(buf, ")", 1);
498 client->ops->say(client, conn, "%s", buf);
502 case SILC_COMMAND_INVITE:
504 SilcChannelEntry channel;
510 /* XXX should use irssi routines */
512 channel = va_arg(vp, SilcChannelEntry);
513 invite_list = va_arg(vp, char *);
516 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
519 silc_say(client, conn, "%s invite list not set",
520 channel->channel_name);
524 case SILC_COMMAND_JOIN:
526 char *channel, *mode, *topic;
528 SilcChannelEntry channel_entry;
529 SilcBuffer client_id_list;
532 channel = va_arg(vp, char *);
533 channel_entry = va_arg(vp, SilcChannelEntry);
534 modei = va_arg(vp, uint32);
535 (void)va_arg(vp, uint32);
536 (void)va_arg(vp, unsigned char *);
537 (void)va_arg(vp, unsigned char *);
538 (void)va_arg(vp, unsigned char *);
539 topic = va_arg(vp, char *);
540 (void)va_arg(vp, unsigned char *);
541 list_count = va_arg(vp, uint32);
542 client_id_list = va_arg(vp, SilcBuffer);
544 /* XXX what an earth do I do with the topic??? */
549 chanrec = silc_channel_find(server, channel);
550 if (chanrec != NULL && !success)
551 channel_destroy(CHANNEL(chanrec));
552 else if (chanrec == NULL && success)
553 chanrec = silc_channel_create(server, channel, TRUE);
555 mode = silc_client_chmode(modei, channel_entry);
556 g_free_not_null(chanrec->mode);
557 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
558 signal_emit("channel mode changed", 1, chanrec);
560 /* Resolve the client information */
561 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
562 silc_client_join_get_users,
567 case SILC_COMMAND_NICK:
569 SilcClientEntry client = va_arg(vp, SilcClientEntry);
575 old = g_strdup(server->nick);
576 server_change_nick(SERVER(server), client->nickname);
577 nicklist_rename_unique(SERVER(server),
578 server->conn->local_entry, server->nick,
579 client, client->nickname);
581 signal_emit("message own_nick", 4, server, server->nick, old, "");
586 case SILC_COMMAND_LIST:
590 unsigned char buf[256], tmp[16];
596 /* XXX should use irssi routines */
598 (void)va_arg(vp, SilcChannelEntry);
599 name = va_arg(vp, char *);
600 topic = va_arg(vp, char *);
601 usercount = va_arg(vp, int);
603 if (status == SILC_STATUS_LIST_START ||
604 status == SILC_STATUS_OK)
605 silc_say(client, conn,
606 " Channel Users Topic");
608 memset(buf, 0, sizeof(buf));
609 strncat(buf, " ", 2);
611 strncat(buf, name, len > 40 ? 40 : len);
613 for (i = 0; i < 40 - len; i++)
617 memset(tmp, 0, sizeof(tmp));
619 snprintf(tmp, sizeof(tmp), "%d", usercount);
624 for (i = 0; i < 10 - len; i++)
630 strncat(buf, topic, len);
633 silc_say(client, conn, "%s", buf);
637 case SILC_COMMAND_UMODE:
644 mode = va_arg(vp, uint32);
650 case SILC_COMMAND_OPER:
652 if (status == SILC_STATUS_OK) {
653 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
654 if (app->screen->bottom_line->umode)
655 silc_free(app->screen->bottom_line->umode);
656 app->screen->bottom_line->umode = strdup("Server Operator");;
657 silc_screen_print_bottom_line(app->screen, 0);
662 case SILC_COMMAND_SILCOPER:
664 if (status == SILC_STATUS_OK) {
665 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
666 if (app->screen->bottom_line->umode)
667 silc_free(app->screen->bottom_line->umode);
668 app->screen->bottom_line->umode = strdup("SILC Operator");;
669 silc_screen_print_bottom_line(app->screen, 0);
674 case SILC_COMMAND_USERS:
676 SilcChannelEntry channel;
677 SilcChannelUser user;
683 channel = va_arg(vp, SilcChannelEntry);
684 chanrec = silc_channel_find_entry(server, channel);
688 silc_list_start(channel->clients);
689 while ((user = silc_list_get(channel->clients)) != NULL)
690 silc_nicklist_insert(chanrec, user, FALSE);
692 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
693 nicklist_set_own(CHANNEL(chanrec), ownnick);
694 signal_emit("channel joined", 1, chanrec);
695 fe_channels_nicklist(CHANNEL(chanrec),
696 CHANNEL_NICKLIST_FLAG_ALL);
700 case SILC_COMMAND_BAN:
702 SilcChannelEntry channel;
708 /* XXX should use irssi routines */
711 channel = va_arg(vp, SilcChannelEntry);
712 ban_list = va_arg(vp, char *);
715 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
718 silc_say(client, conn, "%s ban list not set", channel->channel_name);
722 case SILC_COMMAND_GETKEY:
726 SilcPublicKey public_key;
730 id_type = va_arg(vp, uint32);
731 entry = va_arg(vp, void *);
732 public_key = va_arg(vp, SilcPublicKey);
734 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
736 if (id_type == SILC_ID_CLIENT) {
737 silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
738 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
744 case SILC_COMMAND_TOPIC:
746 SilcChannelEntry channel;
752 channel = va_arg(vp, SilcChannelEntry);
753 topic = va_arg(vp, char *);
755 /* XXX should use irssi routines */
758 silc_say(client, conn,
759 "Topic on channel %s: %s", channel->channel_name,
768 /* Verifies received public key. If user decides to trust the key it is
769 saved as public server key for later use. If user does not trust the
770 key this returns FALSE. */
772 static int silc_verify_public_key(SilcClient client,
773 SilcClientConnection conn,
774 SilcSocketType conn_type,
775 unsigned char *pk, uint32 pk_len,
776 SilcSKEPKType pk_type)
781 /* Asks passphrase from user on the input line. */
783 static unsigned char *silc_ask_passphrase(SilcClient client,
784 SilcClientConnection conn)
789 /* Find authentication method and authentication data by hostname and
790 port. The hostname may be IP address as well. The found authentication
791 method and authentication data is returned to `auth_meth', `auth_data'
792 and `auth_data_len'. The function returns TRUE if authentication method
793 is found and FALSE if not. `conn' may be NULL. */
796 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
797 char *hostname, uint16 port,
798 SilcProtocolAuthMeth *auth_meth,
799 unsigned char **auth_data,
800 uint32 *auth_data_len)
803 /* XXX must resolve from configuration whether this connection has
804 any specific authentication data */
806 *auth_meth = SILC_AUTH_NONE;
813 /* Notifies application that failure packet was received. This is called
814 if there is some protocol active in the client. The `protocol' is the
815 protocol context. The `failure' is opaque pointer to the failure
816 indication. Note, that the `failure' is protocol dependant and application
817 must explicitly cast it to correct type. Usually `failure' is 32 bit
818 failure type (see protocol specs for all protocol failure types). */
821 silc_failure(SilcClient client, SilcClientConnection conn,
822 SilcProtocol protocol, void *failure)
824 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
825 SilcSKEStatus status = (SilcSKEStatus)failure;
827 if (status == SILC_SKE_STATUS_BAD_VERSION)
828 silc_say_error("You are running incompatible client version (it may be "
829 "too old or too new)");
830 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
831 silc_say_error("Server does not support your public key type");
832 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
833 silc_say_error("Server does not support one of your proposed KE group");
834 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
835 silc_say_error("Server does not support one of your proposed cipher");
836 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
837 silc_say_error("Server does not support one of your proposed PKCS");
838 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
839 silc_say_error("Server does not support one of your proposed "
841 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
842 silc_say_error("Server does not support one of your proposed HMAC");
843 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
844 silc_say_error("Incorrect signature");
847 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
848 uint32 err = (uint32)failure;
850 if (err == SILC_AUTH_FAILED)
851 silc_say(client, conn, "Authentication failed");
855 /* Asks whether the user would like to perform the key agreement protocol.
856 This is called after we have received an key agreement packet or an
857 reply to our key agreement packet. This returns TRUE if the user wants
858 the library to perform the key agreement protocol and FALSE if it is not
859 desired (application may start it later by calling the function
860 silc_client_perform_key_agreement). */
863 silc_key_agreement(SilcClient client, SilcClientConnection conn,
864 SilcClientEntry client_entry, char *hostname,
866 SilcKeyAgreementCallback *completion,
871 /* We will just display the info on the screen and return FALSE and user
872 will have to start the key agreement with a command. */
875 memset(host, 0, sizeof(host));
876 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
879 silc_say(client, conn, "%s wants to perform key agreement %s",
880 client_entry->nickname, hostname ? host : "");
888 /* SILC client operations */
889 SilcClientOperations ops = {
891 silc_channel_message,
892 silc_private_message,
898 silc_get_auth_method,
899 silc_verify_public_key,
905 static int my_silc_scheduler(void)
907 silc_schedule_one(0);
911 static CHATNET_REC *create_chatnet(void)
913 return g_malloc0(sizeof(CHATNET_REC));
916 static SERVER_SETUP_REC *create_server_setup(void)
918 return g_malloc0(sizeof(SERVER_SETUP_REC));
921 static CHANNEL_SETUP_REC *create_channel_setup(void)
923 return g_malloc0(sizeof(CHANNEL_SETUP_REC));
926 static SERVER_CONNECT_REC *create_server_connect(void)
928 return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC));
931 /* Checks user information and saves them to the config file it they
932 do not exist there already. */
934 static void silc_init_userinfo(void)
936 const char *set, *nick, *user_name;
939 /* check if nick/username/realname wasn't read from setup.. */
940 set = settings_get_str("real_name");
941 if (set == NULL || *set == '\0') {
942 str = g_getenv("SILCNAME");
944 str = g_getenv("IRCNAME");
945 settings_set_str("real_name",
946 str != NULL ? str : g_get_real_name());
950 user_name = settings_get_str("user_name");
951 if (user_name == NULL || *user_name == '\0') {
952 str = g_getenv("SILCUSER");
954 str = g_getenv("IRCUSER");
955 settings_set_str("user_name",
956 str != NULL ? str : g_get_user_name());
958 user_name = settings_get_str("user_name");
962 nick = settings_get_str("nick");
963 if (nick == NULL || *nick == '\0') {
964 str = g_getenv("SILCNICK");
966 str = g_getenv("IRCNICK");
967 settings_set_str("nick", str != NULL ? str : user_name);
969 nick = settings_get_str("nick");
973 set = settings_get_str("alternate_nick");
974 if (set == NULL || *set == '\0') {
975 if (strlen(nick) < 9)
976 str = g_strconcat(nick, "_", NULL);
978 str = g_strdup(nick);
979 str[strlen(str)-1] = '_';
981 settings_set_str("alternate_nick", str);
986 set = settings_get_str("hostname");
987 if (set == NULL || *set == '\0') {
988 str = g_getenv("SILCHOST");
990 str = g_getenv("IRCHOST");
992 settings_set_str("hostname", str);
996 /* Init SILC. Called from src/fe-text/silc.c */
998 void silc_core_init(void)
1000 static struct poptOption options[] = {
1001 { "create-key-pair", 'C', POPT_ARG_NONE, &opt_create_keypair, 0,
1002 "Create new public key pair", NULL },
1003 { "pkcs", 0, POPT_ARG_STRING, &opt_pkcs, 0,
1004 "Set the PKCS of the public key pair", "PKCS" },
1005 { "bits", 0, POPT_ARG_INT, &opt_bits, 0,
1006 "Set the length of the public key pair", "VALUE" },
1007 { "show-key", 'S', POPT_ARG_STRING, &opt_keyfile, 0,
1008 "Show the contents of the public key", "FILE" },
1009 { NULL, '\0', 0, NULL }
1012 args_register(options);
1015 /* Finalize init. Called from src/fe-text/silc.c */
1017 void silc_core_init_finish(void)
1019 CHAT_PROTOCOL_REC *rec;
1021 if (opt_create_keypair == TRUE) {
1022 /* Create new key pair and exit */
1023 silc_cipher_register_default();
1024 silc_pkcs_register_default();
1025 silc_hash_register_default();
1026 silc_hmac_register_default();
1027 silc_client_create_key_pair(opt_pkcs, opt_bits,
1028 NULL, NULL, NULL, NULL, NULL);
1034 silc_cipher_register_default();
1035 silc_pkcs_register_default();
1036 silc_hash_register_default();
1037 silc_hmac_register_default();
1038 silc_client_show_key(opt_keyfile);
1042 /* Allocate SILC client */
1043 silc_client = silc_client_alloc(&ops, NULL);
1045 /* Load local config file */
1046 silc_config = silc_client_config_alloc(SILC_CLIENT_HOME_CONFIG_FILE);
1048 /* Get user information */
1049 silc_client->username = g_strdup(settings_get_str("user_name"));
1050 silc_client->hostname = silc_net_localhost();
1051 silc_client->realname = g_strdup(settings_get_str("real_name"));
1053 /* Register all configured ciphers, PKCS and hash functions. */
1055 silc_config->client = silc_client;
1056 if (!silc_client_config_register_ciphers(silc_config))
1057 silc_cipher_register_default();
1058 if (!silc_client_config_register_pkcs(silc_config))
1059 silc_pkcs_register_default();
1060 if (!silc_client_config_register_hashfuncs(silc_config))
1061 silc_hash_register_default();
1062 if (!silc_client_config_register_hmacs(silc_config))
1063 silc_hmac_register_default();
1065 /* Register default ciphers, pkcs, hash funtions and hmacs. */
1066 silc_cipher_register_default();
1067 silc_pkcs_register_default();
1068 silc_hash_register_default();
1069 silc_hmac_register_default();
1072 /* Check ~/.silc directory and public and private keys */
1073 if (silc_client_check_silc_dir() == FALSE) {
1078 /* Load public and private key */
1079 if (silc_client_load_keys(silc_client) == FALSE) {
1084 /* Initialize the SILC client */
1085 if (!silc_client_init(silc_client)) {
1090 /* Register SILC to the irssi */
1091 rec = g_new0(CHAT_PROTOCOL_REC, 1);
1093 rec->fullname = "Secure Internet Live Conferencing";
1094 rec->chatnet = "silcnet";
1095 rec->create_chatnet = create_chatnet;
1096 rec->create_server_setup = create_server_setup;
1097 rec->create_channel_setup = create_channel_setup;
1098 rec->create_server_connect = create_server_connect;
1099 rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *))
1100 silc_server_connect;
1101 rec->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, int))
1102 silc_channel_create;
1103 rec->query_create = (QUERY_REC *(*) (const char *, const char *, int))
1106 chat_protocol_register(rec);
1109 silc_init_userinfo();
1111 silc_channels_init();
1112 silc_queries_init();
1114 idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL);
1117 /* Deinit SILC. Called from src/fe-text/silc.c */
1119 void silc_core_deinit(void)
1121 if (idletag != -1) {
1122 signal_emit("chat protocol deinit", 1,
1123 chat_protocol_find("SILC"));
1125 silc_server_deinit();
1126 silc_channels_deinit();
1127 silc_queries_deinit();
1129 chat_protocol_unregister("SILC");
1131 g_source_remove(idletag);
1134 g_free(silc_client->username);
1135 g_free(silc_client->realname);
1136 silc_client_free(silc_client);