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;
684 channel = va_arg(vp, SilcChannelEntry);
686 /* There are two ways to do this, either parse the list (that
687 the command_reply sends (just take it with va_arg()) or just
688 traverse the channel's client list. I'll do the latter. See
689 JOIN command reply for example for the list. */
691 silc_say(client, conn, "Users on %s", channel->channel_name);
693 line = silc_calloc(1024, sizeof(*line));
695 silc_list_start(channel->clients);
696 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
697 SilcClientEntry e = chu->client;
701 memset(line, 0, line_len);
703 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
705 line_len += strlen(e->nickname) + strlen(e->server) + 100;
706 line = silc_calloc(line_len, sizeof(*line));
709 memset(tmp, 0, sizeof(tmp));
710 m = silc_client_chumode_char(chu->mode);
712 strncat(line, " ", 1);
713 strncat(line, e->nickname, strlen(e->nickname));
714 strncat(line, e->server ? "@" : "", 1);
718 len1 = strlen(e->server);
719 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
723 memset(&line[29], 0, len1 - 29);
725 for (i = 0; i < 30 - len1 - 1; i++)
729 if (e->mode & SILC_UMODE_GONE)
733 strcat(tmp, m ? m : "");
734 strncat(line, tmp, strlen(tmp));
737 for (i = 0; i < 5 - strlen(tmp); i++)
740 strcat(line, e->username ? e->username : "");
742 silc_say(client, conn, "%s", line);
752 case SILC_COMMAND_BAN:
754 SilcChannelEntry channel;
760 /* XXX should use irssi routines */
762 channel = va_arg(vp, SilcChannelEntry);
763 ban_list = va_arg(vp, char *);
766 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
769 silc_say(client, conn, "%s ban list not set", channel->channel_name);
773 case SILC_COMMAND_GETKEY:
777 SilcPublicKey public_key;
781 id_type = va_arg(vp, uint32);
782 entry = va_arg(vp, void *);
783 public_key = va_arg(vp, SilcPublicKey);
785 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
787 if (id_type == SILC_ID_CLIENT) {
788 silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
789 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
795 case SILC_COMMAND_TOPIC:
797 SilcChannelEntry channel;
803 channel = va_arg(vp, SilcChannelEntry);
804 topic = va_arg(vp, char *);
806 /* XXX should use irssi routines */
809 silc_say(client, conn,
810 "Topic on channel %s: %s", channel->channel_name,
819 /* Verifies received public key. If user decides to trust the key it is
820 saved as public server key for later use. If user does not trust the
821 key this returns FALSE. */
823 static int silc_verify_public_key(SilcClient client,
824 SilcClientConnection conn,
825 SilcSocketType conn_type,
826 unsigned char *pk, uint32 pk_len,
827 SilcSKEPKType pk_type)
832 /* Asks passphrase from user on the input line. */
834 static unsigned char *silc_ask_passphrase(SilcClient client,
835 SilcClientConnection conn)
840 /* Find authentication method and authentication data by hostname and
841 port. The hostname may be IP address as well. The found authentication
842 method and authentication data is returned to `auth_meth', `auth_data'
843 and `auth_data_len'. The function returns TRUE if authentication method
844 is found and FALSE if not. `conn' may be NULL. */
847 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
848 char *hostname, uint16 port,
849 SilcProtocolAuthMeth *auth_meth,
850 unsigned char **auth_data,
851 uint32 *auth_data_len)
854 /* XXX must resolve from configuration whether this connection has
855 any specific authentication data */
857 *auth_meth = SILC_AUTH_NONE;
864 /* Notifies application that failure packet was received. This is called
865 if there is some protocol active in the client. The `protocol' is the
866 protocol context. The `failure' is opaque pointer to the failure
867 indication. Note, that the `failure' is protocol dependant and application
868 must explicitly cast it to correct type. Usually `failure' is 32 bit
869 failure type (see protocol specs for all protocol failure types). */
872 silc_failure(SilcClient client, SilcClientConnection conn,
873 SilcProtocol protocol, void *failure)
875 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
876 SilcSKEStatus status = (SilcSKEStatus)failure;
878 if (status == SILC_SKE_STATUS_BAD_VERSION)
879 silc_say_error("You are running incompatible client version (it may be "
880 "too old or too new)");
881 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
882 silc_say_error("Server does not support your public key type");
883 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
884 silc_say_error("Server does not support one of your proposed KE group");
885 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
886 silc_say_error("Server does not support one of your proposed cipher");
887 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
888 silc_say_error("Server does not support one of your proposed PKCS");
889 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
890 silc_say_error("Server does not support one of your proposed "
892 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
893 silc_say_error("Server does not support one of your proposed HMAC");
894 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
895 silc_say_error("Incorrect signature");
898 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
899 uint32 err = (uint32)failure;
901 if (err == SILC_AUTH_FAILED)
902 silc_say(client, conn, "Authentication failed");
906 /* Asks whether the user would like to perform the key agreement protocol.
907 This is called after we have received an key agreement packet or an
908 reply to our key agreement packet. This returns TRUE if the user wants
909 the library to perform the key agreement protocol and FALSE if it is not
910 desired (application may start it later by calling the function
911 silc_client_perform_key_agreement). */
914 silc_key_agreement(SilcClient client, SilcClientConnection conn,
915 SilcClientEntry client_entry, char *hostname,
917 SilcKeyAgreementCallback *completion,
922 /* We will just display the info on the screen and return FALSE and user
923 will have to start the key agreement with a command. */
926 memset(host, 0, sizeof(host));
927 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
930 silc_say(client, conn, "%s wants to perform key agreement %s",
931 client_entry->nickname, hostname ? host : "");
939 /* SILC client operations */
940 SilcClientOperations ops = {
942 silc_channel_message,
943 silc_private_message,
949 silc_get_auth_method,
950 silc_verify_public_key,
956 static int my_silc_scheduler(void)
958 silc_schedule_one(0);
962 static CHATNET_REC *create_chatnet(void)
964 return g_malloc0(sizeof(CHATNET_REC));
967 static SERVER_SETUP_REC *create_server_setup(void)
969 return g_malloc0(sizeof(SERVER_SETUP_REC));
972 static CHANNEL_SETUP_REC *create_channel_setup(void)
974 return g_malloc0(sizeof(CHANNEL_SETUP_REC));
977 static SERVER_CONNECT_REC *create_server_connect(void)
979 return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC));
982 /* Checks user information and saves them to the config file it they
983 do not exist there already. */
985 static void silc_init_userinfo(void)
987 const char *set, *nick, *user_name;
990 /* check if nick/username/realname wasn't read from setup.. */
991 set = settings_get_str("real_name");
992 if (set == NULL || *set == '\0') {
993 str = g_getenv("SILCNAME");
995 str = g_getenv("IRCNAME");
996 settings_set_str("real_name",
997 str != NULL ? str : g_get_real_name());
1001 user_name = settings_get_str("user_name");
1002 if (user_name == NULL || *user_name == '\0') {
1003 str = g_getenv("SILCUSER");
1005 str = g_getenv("IRCUSER");
1006 settings_set_str("user_name",
1007 str != NULL ? str : g_get_user_name());
1009 user_name = settings_get_str("user_name");
1013 nick = settings_get_str("nick");
1014 if (nick == NULL || *nick == '\0') {
1015 str = g_getenv("SILCNICK");
1017 str = g_getenv("IRCNICK");
1018 settings_set_str("nick", str != NULL ? str : user_name);
1020 nick = settings_get_str("nick");
1023 /* alternate nick */
1024 set = settings_get_str("alternate_nick");
1025 if (set == NULL || *set == '\0') {
1026 if (strlen(nick) < 9)
1027 str = g_strconcat(nick, "_", NULL);
1029 str = g_strdup(nick);
1030 str[strlen(str)-1] = '_';
1032 settings_set_str("alternate_nick", str);
1037 set = settings_get_str("hostname");
1038 if (set == NULL || *set == '\0') {
1039 str = g_getenv("SILCHOST");
1041 str = g_getenv("IRCHOST");
1043 settings_set_str("hostname", str);
1047 /* Init SILC. Called from src/fe-text/silc.c */
1049 void silc_core_init(void)
1051 static struct poptOption options[] = {
1052 { "create-key-pair", 'C', POPT_ARG_NONE, &opt_create_keypair, 0,
1053 "Create new public key pair", NULL },
1054 { "pkcs", 0, POPT_ARG_STRING, &opt_pkcs, 0,
1055 "Set the PKCS of the public key pair", "PKCS" },
1056 { "bits", 0, POPT_ARG_INT, &opt_bits, 0,
1057 "Set the length of the public key pair", "VALUE" },
1058 { "show-key", 'S', POPT_ARG_STRING, &opt_keyfile, 0,
1059 "Show the contents of the public key", "FILE" },
1060 { NULL, '\0', 0, NULL }
1063 args_register(options);
1066 /* Finalize init. Called from src/fe-text/silc.c */
1068 void silc_core_init_finish(void)
1070 CHAT_PROTOCOL_REC *rec;
1072 if (opt_create_keypair == TRUE) {
1073 /* Create new key pair and exit */
1074 silc_cipher_register_default();
1075 silc_pkcs_register_default();
1076 silc_hash_register_default();
1077 silc_hmac_register_default();
1078 silc_client_create_key_pair(opt_pkcs, opt_bits,
1079 NULL, NULL, NULL, NULL, NULL);
1085 silc_cipher_register_default();
1086 silc_pkcs_register_default();
1087 silc_hash_register_default();
1088 silc_hmac_register_default();
1089 silc_client_show_key(opt_keyfile);
1093 silc_init_userinfo();
1095 /* Allocate SILC client */
1096 silc_client = silc_client_alloc(&ops, NULL);
1098 /* Load local config file */
1099 silc_config = silc_client_config_alloc(SILC_CLIENT_HOME_CONFIG_FILE);
1101 /* Get user information */
1102 silc_client->username = g_strdup(settings_get_str("user_name"));
1103 silc_client->hostname = silc_net_localhost();
1104 silc_client->realname = g_strdup(settings_get_str("real_name"));
1106 /* Register all configured ciphers, PKCS and hash functions. */
1108 silc_config->client = silc_client;
1109 if (!silc_client_config_register_ciphers(silc_config))
1110 silc_cipher_register_default();
1111 if (!silc_client_config_register_pkcs(silc_config))
1112 silc_pkcs_register_default();
1113 if (!silc_client_config_register_hashfuncs(silc_config))
1114 silc_hash_register_default();
1115 if (!silc_client_config_register_hmacs(silc_config))
1116 silc_hmac_register_default();
1118 /* Register default ciphers, pkcs, hash funtions and hmacs. */
1119 silc_cipher_register_default();
1120 silc_pkcs_register_default();
1121 silc_hash_register_default();
1122 silc_hmac_register_default();
1125 /* Check ~/.silc directory and public and private keys */
1126 if (silc_client_check_silc_dir() == FALSE) {
1131 /* Load public and private key */
1132 if (silc_client_load_keys(silc_client) == FALSE) {
1137 /* Initialize the SILC client */
1138 if (!silc_client_init(silc_client)) {
1143 /* Register SILC to the irssi */
1144 rec = g_new0(CHAT_PROTOCOL_REC, 1);
1146 rec->fullname = "Secure Internet Live Conferencing";
1147 rec->chatnet = "silcnet";
1148 rec->create_chatnet = create_chatnet;
1149 rec->create_server_setup = create_server_setup;
1150 rec->create_channel_setup = create_channel_setup;
1151 rec->create_server_connect = create_server_connect;
1152 rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *))
1153 silc_server_connect;
1154 rec->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, int))
1155 silc_channel_create;
1156 rec->query_create = (QUERY_REC *(*) (const char *, const char *, int))
1159 chat_protocol_register(rec);
1163 silc_channels_init();
1164 silc_queries_init();
1166 idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL);
1169 /* Deinit SILC. Called from src/fe-text/silc.c */
1171 void silc_core_deinit(void)
1173 if (idletag != -1) {
1174 signal_emit("chat protocol deinit", 1,
1175 chat_protocol_find("SILC"));
1177 silc_server_deinit();
1178 silc_channels_deinit();
1179 silc_queries_deinit();
1181 chat_protocol_unregister("SILC");
1183 g_source_remove(idletag);
1186 g_free(silc_client->username);
1187 g_free(silc_client->realname);
1188 silc_client_free(silc_client);