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);
162 if (flags & SILC_MESSAGE_FLAG_ACTION)
164 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
167 signal_emit("message public", 6, server, msg,
168 nick == NULL ? "[<unknown>]" : nick->nick,
169 nick == NULL ? NULL : nick->host,
170 chanrec->name, nick);
173 /* Private message to the client. The `sender' is the nickname of the
174 sender received in the packet. */
177 silc_private_message(SilcClient client, SilcClientConnection conn,
178 SilcClientEntry sender, SilcMessageFlags flags,
181 SILC_SERVER_REC *server;
183 server = conn == NULL ? NULL : conn->context;
184 signal_emit("message private", 4, server, msg,
185 sender->nickname ? sender->nickname : "[<unknown>]",
186 sender->username ? sender->username : NULL);
189 /* Notify message to the client. The notify arguments are sent in the
190 same order as servers sends them. The arguments are same as received
191 from the server except for ID's. If ID is received application receives
192 the corresponding entry to the ID. For example, if Client ID is received
193 application receives SilcClientEntry. Also, if the notify type is
194 for channel the channel entry is sent to application (even if server
195 does not send it). */
202 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
203 static NOTIFY_REC notifies[] = {
204 { SILC_NOTIFY_TYPE_NONE, NULL },
205 { SILC_NOTIFY_TYPE_INVITE, "invite" },
206 { SILC_NOTIFY_TYPE_JOIN, "join" },
207 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
208 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
209 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
210 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
211 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
212 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
213 { SILC_NOTIFY_TYPE_MOTD, "motd" },
214 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
215 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
216 { SILC_NOTIFY_TYPE_KICKED, "kick" },
217 { SILC_NOTIFY_TYPE_KILLED, "kill" },
218 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
219 { SILC_NOTIFY_TYPE_BAN, "ban" },
222 static void silc_notify(SilcClient client, SilcClientConnection conn,
223 SilcNotifyType type, ...)
225 SILC_SERVER_REC *server;
228 server = conn == NULL ? NULL : conn->context;
231 if (type == SILC_NOTIFY_TYPE_NONE) {
232 /* Some generic notice from server */
233 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
234 } else if (type < MAX_NOTIFY) {
235 /* Send signal about the notify event */
237 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
238 signal_emit(signal, 2, server, va);
241 printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type);
247 /* Called to indicate that connection was either successfully established
248 or connecting failed. This is also the first time application receives
249 the SilcClientConnection objecet which it should save somewhere. */
252 silc_connect(SilcClient client, SilcClientConnection conn, int success)
254 SILC_SERVER_REC *server = conn->context;
257 server->connected = TRUE;
258 signal_emit("event connected", 1, server);
260 server->connection_lost = TRUE;
261 server->conn->context = NULL;
262 server_disconnect(SERVER(server));
266 /* Called to indicate that connection was disconnected to the server. */
269 silc_disconnect(SilcClient client, SilcClientConnection conn)
271 SILC_SERVER_REC *server = conn->context;
273 server->conn->context = NULL;
275 server->connection_lost = TRUE;
276 server_disconnect(SERVER(server));
279 /* Command handler. This function is called always in the command function.
280 If error occurs it will be called as well. `conn' is the associated
281 client connection. `cmd_context' is the command context that was
282 originally sent to the command. `success' is FALSE if error occured
283 during command. `command' is the command being processed. It must be
284 noted that this is not reply from server. This is merely called just
285 after application has called the command. Just to tell application
286 that the command really was processed. */
289 silc_command(SilcClient client, SilcClientConnection conn,
290 SilcClientCommandContext cmd_context, int success,
295 /* Client info resolving callback when JOIN command reply is received.
296 This will cache all users on the channel. */
298 void silc_client_join_get_users(SilcClient client,
299 SilcClientConnection conn,
300 SilcClientEntry *clients,
301 uint32 clients_count,
304 SilcChannelEntry channel = (SilcChannelEntry)context;
306 SILC_SERVER_REC *server = conn->context;
307 SILC_CHANNEL_REC *chanrec;
313 chanrec = silc_channel_find_entry(server, channel);
317 silc_list_start(channel->clients);
318 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END)
319 silc_nicklist_insert(chanrec, chu, FALSE);
321 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
322 nicklist_set_own(CHANNEL(chanrec), ownnick);
323 signal_emit("channel joined", 1, chanrec);
324 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
327 /* Command reply handler. This function is called always in the command reply
328 function. If error occurs it will be called as well. Normal scenario
329 is that it will be called after the received command data has been parsed
330 and processed. The function is used to pass the received command data to
333 `conn' is the associated client connection. `cmd_payload' is the command
334 payload data received from server and it can be ignored. It is provided
335 if the application would like to re-parse the received command data,
336 however, it must be noted that the data is parsed already by the library
337 thus the payload can be ignored. `success' is FALSE if error occured.
338 In this case arguments are not sent to the application. `command' is the
339 command reply being processed. The function has variable argument list
340 and each command defines the number and type of arguments it passes to the
341 application (on error they are not sent). */
344 silc_command_reply(SilcClient client, SilcClientConnection conn,
345 SilcCommandPayload cmd_payload, int success,
346 SilcCommand command, SilcCommandStatus status, ...)
349 SILC_SERVER_REC *server = conn->context;
350 SILC_CHANNEL_REC *chanrec;
353 va_start(vp, status);
356 case SILC_COMMAND_WHOIS:
358 char buf[1024], *nickname, *username, *realname;
363 /* XXX should use irssi routines */
365 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
366 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
368 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
371 client->ops->say(client, conn, "%s: %s", tmp,
372 silc_client_command_status_message(status));
374 client->ops->say(client, conn, "%s",
375 silc_client_command_status_message(status));
382 (void)va_arg(vp, SilcClientEntry);
383 nickname = va_arg(vp, char *);
384 username = va_arg(vp, char *);
385 realname = va_arg(vp, char *);
386 channels = va_arg(vp, SilcBuffer);
387 mode = va_arg(vp, uint32);
388 idle = va_arg(vp, uint32);
390 memset(buf, 0, sizeof(buf));
393 len = strlen(nickname);
394 strncat(buf, nickname, len);
395 strncat(buf, " is ", 4);
399 strncat(buf, username, strlen(username));
403 strncat(buf, " (", 2);
404 strncat(buf, realname, strlen(realname));
405 strncat(buf, ")", 1);
408 client->ops->say(client, conn, "%s", buf);
411 SilcDList list = silc_channel_payload_parse_list(channels);
413 SilcChannelPayload entry;
415 memset(buf, 0, sizeof(buf));
416 strcat(buf, "on channels: ");
418 silc_dlist_start(list);
419 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
420 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
422 char *name = silc_channel_get_name(entry, &name_len);
425 strncat(buf, m, strlen(m));
426 strncat(buf, name, name_len);
427 strncat(buf, " ", 1);
431 client->ops->say(client, conn, "%s", buf);
432 silc_channel_payload_list_free(list);
437 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
438 (mode & SILC_UMODE_ROUTER_OPERATOR))
439 client->ops->say(client, conn, "%s is %s", nickname,
440 (mode & SILC_UMODE_SERVER_OPERATOR) ?
442 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
443 "SILC Operator" : "[Unknown mode]");
445 if (mode & SILC_UMODE_GONE)
446 client->ops->say(client, conn, "%s is gone", nickname);
449 if (idle && nickname)
450 client->ops->say(client, conn, "%s has been idle %d %s",
452 idle > 60 ? (idle / 60) : idle,
453 idle > 60 ? "minutes" : "seconds");
457 case SILC_COMMAND_WHOWAS:
459 char buf[1024], *nickname, *username, *realname;
462 /* XXX should use irssi routines */
464 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
465 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
467 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
470 client->ops->say(client, conn, "%s: %s", tmp,
471 silc_client_command_status_message(status));
473 client->ops->say(client, conn, "%s",
474 silc_client_command_status_message(status));
481 (void)va_arg(vp, SilcClientEntry);
482 nickname = va_arg(vp, char *);
483 username = va_arg(vp, char *);
484 realname = va_arg(vp, char *);
486 memset(buf, 0, sizeof(buf));
489 len = strlen(nickname);
490 strncat(buf, nickname, len);
491 strncat(buf, " was ", 5);
495 strncat(buf, username, strlen(nickname));
499 strncat(buf, " (", 2);
500 strncat(buf, realname, strlen(realname));
501 strncat(buf, ")", 1);
504 client->ops->say(client, conn, "%s", buf);
508 case SILC_COMMAND_INVITE:
510 SilcChannelEntry channel;
516 /* XXX should use irssi routines */
518 channel = va_arg(vp, SilcChannelEntry);
519 invite_list = va_arg(vp, char *);
522 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
525 silc_say(client, conn, "%s invite list not set",
526 channel->channel_name);
530 case SILC_COMMAND_JOIN:
532 char *channel, *mode, *topic;
534 SilcChannelEntry channel_entry;
535 SilcBuffer client_id_list;
538 channel = va_arg(vp, char *);
539 channel_entry = va_arg(vp, SilcChannelEntry);
540 modei = va_arg(vp, uint32);
541 (void)va_arg(vp, uint32);
542 (void)va_arg(vp, unsigned char *);
543 (void)va_arg(vp, unsigned char *);
544 (void)va_arg(vp, unsigned char *);
545 topic = va_arg(vp, char *);
546 (void)va_arg(vp, unsigned char *);
547 list_count = va_arg(vp, uint32);
548 client_id_list = va_arg(vp, SilcBuffer);
550 /* XXX what an earth do I do with the topic??? */
555 chanrec = silc_channel_find(server, channel);
556 if (chanrec != NULL && !success)
557 channel_destroy(CHANNEL(chanrec));
558 else if (chanrec == NULL && success)
559 chanrec = silc_channel_create(server, channel, TRUE);
561 mode = silc_client_chmode(modei, channel_entry);
562 g_free_not_null(chanrec->mode);
563 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
564 signal_emit("channel mode changed", 1, chanrec);
566 /* Resolve the client information */
567 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
568 silc_client_join_get_users,
573 case SILC_COMMAND_NICK:
575 SilcClientEntry client = va_arg(vp, SilcClientEntry);
581 old = g_strdup(server->nick);
582 server_change_nick(SERVER(server), client->nickname);
583 nicklist_rename_unique(SERVER(server),
584 server->conn->local_entry, server->nick,
585 client, client->nickname);
587 signal_emit("message own_nick", 4, server, server->nick, old, "");
592 case SILC_COMMAND_LIST:
596 unsigned char buf[256], tmp[16];
602 /* XXX should use irssi routines */
604 (void)va_arg(vp, SilcChannelEntry);
605 name = va_arg(vp, char *);
606 topic = va_arg(vp, char *);
607 usercount = va_arg(vp, int);
609 if (status == SILC_STATUS_LIST_START ||
610 status == SILC_STATUS_OK)
611 silc_say(client, conn,
612 " Channel Users Topic");
614 memset(buf, 0, sizeof(buf));
615 strncat(buf, " ", 2);
617 strncat(buf, name, len > 40 ? 40 : len);
619 for (i = 0; i < 40 - len; i++)
623 memset(tmp, 0, sizeof(tmp));
625 snprintf(tmp, sizeof(tmp), "%d", usercount);
630 for (i = 0; i < 10 - len; i++)
636 strncat(buf, topic, len);
639 silc_say(client, conn, "%s", buf);
643 case SILC_COMMAND_UMODE:
650 mode = va_arg(vp, uint32);
656 case SILC_COMMAND_OPER:
658 if (status == SILC_STATUS_OK) {
659 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
660 if (app->screen->bottom_line->umode)
661 silc_free(app->screen->bottom_line->umode);
662 app->screen->bottom_line->umode = strdup("Server Operator");;
663 silc_screen_print_bottom_line(app->screen, 0);
668 case SILC_COMMAND_SILCOPER:
670 if (status == SILC_STATUS_OK) {
671 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
672 if (app->screen->bottom_line->umode)
673 silc_free(app->screen->bottom_line->umode);
674 app->screen->bottom_line->umode = strdup("SILC Operator");;
675 silc_screen_print_bottom_line(app->screen, 0);
680 case SILC_COMMAND_USERS:
682 SilcChannelEntry channel;
690 channel = va_arg(vp, SilcChannelEntry);
692 /* There are two ways to do this, either parse the list (that
693 the command_reply sends (just take it with va_arg()) or just
694 traverse the channel's client list. I'll do the latter. See
695 JOIN command reply for example for the list. */
697 silc_say(client, conn, "Users on %s", channel->channel_name);
699 line = silc_calloc(1024, sizeof(*line));
701 silc_list_start(channel->clients);
702 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
703 SilcClientEntry e = chu->client;
707 memset(line, 0, line_len);
709 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
711 line_len += strlen(e->nickname) + strlen(e->server) + 100;
712 line = silc_calloc(line_len, sizeof(*line));
715 memset(tmp, 0, sizeof(tmp));
716 m = silc_client_chumode_char(chu->mode);
718 strncat(line, " ", 1);
719 strncat(line, e->nickname, strlen(e->nickname));
720 strncat(line, e->server ? "@" : "", 1);
724 len1 = strlen(e->server);
725 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
729 memset(&line[29], 0, len1 - 29);
731 for (i = 0; i < 30 - len1 - 1; i++)
735 if (e->mode & SILC_UMODE_GONE)
739 strcat(tmp, m ? m : "");
740 strncat(line, tmp, strlen(tmp));
743 for (i = 0; i < 5 - strlen(tmp); i++)
746 strcat(line, e->username ? e->username : "");
748 silc_say(client, conn, "%s", line);
758 case SILC_COMMAND_BAN:
760 SilcChannelEntry channel;
766 /* XXX should use irssi routines */
768 channel = va_arg(vp, SilcChannelEntry);
769 ban_list = va_arg(vp, char *);
772 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
775 silc_say(client, conn, "%s ban list not set", channel->channel_name);
779 case SILC_COMMAND_GETKEY:
783 SilcPublicKey public_key;
787 id_type = va_arg(vp, uint32);
788 entry = va_arg(vp, void *);
789 public_key = va_arg(vp, SilcPublicKey);
791 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
793 if (id_type == SILC_ID_CLIENT) {
794 silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
795 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
801 case SILC_COMMAND_TOPIC:
803 SilcChannelEntry channel;
809 channel = va_arg(vp, SilcChannelEntry);
810 topic = va_arg(vp, char *);
812 /* XXX should use irssi routines */
815 silc_say(client, conn,
816 "Topic on channel %s: %s", channel->channel_name,
825 /* Verifies received public key. If user decides to trust the key it is
826 saved as public server key for later use. If user does not trust the
827 key this returns FALSE. */
829 static int silc_verify_public_key(SilcClient client,
830 SilcClientConnection conn,
831 SilcSocketType conn_type,
832 unsigned char *pk, uint32 pk_len,
833 SilcSKEPKType pk_type)
838 /* Asks passphrase from user on the input line. */
840 static unsigned char *silc_ask_passphrase(SilcClient client,
841 SilcClientConnection conn)
846 /* Find authentication method and authentication data by hostname and
847 port. The hostname may be IP address as well. The found authentication
848 method and authentication data is returned to `auth_meth', `auth_data'
849 and `auth_data_len'. The function returns TRUE if authentication method
850 is found and FALSE if not. `conn' may be NULL. */
853 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
854 char *hostname, uint16 port,
855 SilcProtocolAuthMeth *auth_meth,
856 unsigned char **auth_data,
857 uint32 *auth_data_len)
860 /* XXX must resolve from configuration whether this connection has
861 any specific authentication data */
863 *auth_meth = SILC_AUTH_NONE;
870 /* Notifies application that failure packet was received. This is called
871 if there is some protocol active in the client. The `protocol' is the
872 protocol context. The `failure' is opaque pointer to the failure
873 indication. Note, that the `failure' is protocol dependant and application
874 must explicitly cast it to correct type. Usually `failure' is 32 bit
875 failure type (see protocol specs for all protocol failure types). */
878 silc_failure(SilcClient client, SilcClientConnection conn,
879 SilcProtocol protocol, void *failure)
881 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
882 SilcSKEStatus status = (SilcSKEStatus)failure;
884 if (status == SILC_SKE_STATUS_BAD_VERSION)
885 silc_say_error("You are running incompatible client version (it may be "
886 "too old or too new)");
887 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
888 silc_say_error("Server does not support your public key type");
889 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
890 silc_say_error("Server does not support one of your proposed KE group");
891 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
892 silc_say_error("Server does not support one of your proposed cipher");
893 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
894 silc_say_error("Server does not support one of your proposed PKCS");
895 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
896 silc_say_error("Server does not support one of your proposed "
898 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
899 silc_say_error("Server does not support one of your proposed HMAC");
900 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
901 silc_say_error("Incorrect signature");
904 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
905 uint32 err = (uint32)failure;
907 if (err == SILC_AUTH_FAILED)
908 silc_say(client, conn, "Authentication failed");
912 /* Asks whether the user would like to perform the key agreement protocol.
913 This is called after we have received an key agreement packet or an
914 reply to our key agreement packet. This returns TRUE if the user wants
915 the library to perform the key agreement protocol and FALSE if it is not
916 desired (application may start it later by calling the function
917 silc_client_perform_key_agreement). */
920 silc_key_agreement(SilcClient client, SilcClientConnection conn,
921 SilcClientEntry client_entry, char *hostname,
923 SilcKeyAgreementCallback *completion,
928 /* We will just display the info on the screen and return FALSE and user
929 will have to start the key agreement with a command. */
932 memset(host, 0, sizeof(host));
933 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
936 silc_say(client, conn, "%s wants to perform key agreement %s",
937 client_entry->nickname, hostname ? host : "");
945 /* SILC client operations */
946 SilcClientOperations ops = {
948 silc_channel_message,
949 silc_private_message,
955 silc_get_auth_method,
956 silc_verify_public_key,
962 static int my_silc_scheduler(void)
964 silc_schedule_one(0);
968 static CHATNET_REC *create_chatnet(void)
970 return g_malloc0(sizeof(CHATNET_REC));
973 static SERVER_SETUP_REC *create_server_setup(void)
975 return g_malloc0(sizeof(SERVER_SETUP_REC));
978 static CHANNEL_SETUP_REC *create_channel_setup(void)
980 return g_malloc0(sizeof(CHANNEL_SETUP_REC));
983 static SERVER_CONNECT_REC *create_server_connect(void)
985 return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC));
988 /* Checks user information and saves them to the config file it they
989 do not exist there already. */
991 static void silc_init_userinfo(void)
993 const char *set, *nick, *user_name;
996 /* check if nick/username/realname wasn't read from setup.. */
997 set = settings_get_str("real_name");
998 if (set == NULL || *set == '\0') {
999 str = g_getenv("SILCNAME");
1001 str = g_getenv("IRCNAME");
1002 settings_set_str("real_name",
1003 str != NULL ? str : g_get_real_name());
1007 user_name = settings_get_str("user_name");
1008 if (user_name == NULL || *user_name == '\0') {
1009 str = g_getenv("SILCUSER");
1011 str = g_getenv("IRCUSER");
1012 settings_set_str("user_name",
1013 str != NULL ? str : g_get_user_name());
1015 user_name = settings_get_str("user_name");
1019 nick = settings_get_str("nick");
1020 if (nick == NULL || *nick == '\0') {
1021 str = g_getenv("SILCNICK");
1023 str = g_getenv("IRCNICK");
1024 settings_set_str("nick", str != NULL ? str : user_name);
1026 nick = settings_get_str("nick");
1029 /* alternate nick */
1030 set = settings_get_str("alternate_nick");
1031 if (set == NULL || *set == '\0') {
1032 if (strlen(nick) < 9)
1033 str = g_strconcat(nick, "_", NULL);
1035 str = g_strdup(nick);
1036 str[strlen(str)-1] = '_';
1038 settings_set_str("alternate_nick", str);
1043 set = settings_get_str("hostname");
1044 if (set == NULL || *set == '\0') {
1045 str = g_getenv("SILCHOST");
1047 str = g_getenv("IRCHOST");
1049 settings_set_str("hostname", str);
1053 /* Init SILC. Called from src/fe-text/silc.c */
1055 void silc_core_init(void)
1057 static struct poptOption options[] = {
1058 { "create-key-pair", 'C', POPT_ARG_NONE, &opt_create_keypair, 0,
1059 "Create new public key pair", NULL },
1060 { "pkcs", 0, POPT_ARG_STRING, &opt_pkcs, 0,
1061 "Set the PKCS of the public key pair", "PKCS" },
1062 { "bits", 0, POPT_ARG_INT, &opt_bits, 0,
1063 "Set the length of the public key pair", "VALUE" },
1064 { "show-key", 'S', POPT_ARG_STRING, &opt_keyfile, 0,
1065 "Show the contents of the public key", "FILE" },
1066 { NULL, '\0', 0, NULL }
1069 args_register(options);
1072 /* Finalize init. Called from src/fe-text/silc.c */
1074 void silc_core_init_finish(void)
1076 CHAT_PROTOCOL_REC *rec;
1078 if (opt_create_keypair == TRUE) {
1079 /* Create new key pair and exit */
1080 silc_cipher_register_default();
1081 silc_pkcs_register_default();
1082 silc_hash_register_default();
1083 silc_hmac_register_default();
1084 silc_client_create_key_pair(opt_pkcs, opt_bits,
1085 NULL, NULL, NULL, NULL, NULL);
1091 silc_cipher_register_default();
1092 silc_pkcs_register_default();
1093 silc_hash_register_default();
1094 silc_hmac_register_default();
1095 silc_client_show_key(opt_keyfile);
1099 silc_init_userinfo();
1101 /* Allocate SILC client */
1102 silc_client = silc_client_alloc(&ops, NULL);
1104 /* Load local config file */
1105 silc_config = silc_client_config_alloc(SILC_CLIENT_HOME_CONFIG_FILE);
1107 /* Get user information */
1108 silc_client->username = g_strdup(settings_get_str("user_name"));
1109 silc_client->hostname = silc_net_localhost();
1110 silc_client->realname = g_strdup(settings_get_str("real_name"));
1112 /* Register all configured ciphers, PKCS and hash functions. */
1114 silc_config->client = silc_client;
1115 if (!silc_client_config_register_ciphers(silc_config))
1116 silc_cipher_register_default();
1117 if (!silc_client_config_register_pkcs(silc_config))
1118 silc_pkcs_register_default();
1119 if (!silc_client_config_register_hashfuncs(silc_config))
1120 silc_hash_register_default();
1121 if (!silc_client_config_register_hmacs(silc_config))
1122 silc_hmac_register_default();
1124 /* Register default ciphers, pkcs, hash funtions and hmacs. */
1125 silc_cipher_register_default();
1126 silc_pkcs_register_default();
1127 silc_hash_register_default();
1128 silc_hmac_register_default();
1131 /* Check ~/.silc directory and public and private keys */
1132 if (silc_client_check_silc_dir() == FALSE) {
1137 /* Load public and private key */
1138 if (silc_client_load_keys(silc_client) == FALSE) {
1143 /* Initialize the SILC client */
1144 if (!silc_client_init(silc_client)) {
1149 /* Register SILC to the irssi */
1150 rec = g_new0(CHAT_PROTOCOL_REC, 1);
1152 rec->fullname = "Secure Internet Live Conferencing";
1153 rec->chatnet = "silcnet";
1154 rec->create_chatnet = create_chatnet;
1155 rec->create_server_setup = create_server_setup;
1156 rec->create_channel_setup = create_channel_setup;
1157 rec->create_server_connect = create_server_connect;
1158 rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *))
1159 silc_server_connect;
1160 rec->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, int))
1161 silc_channel_create;
1162 rec->query_create = (QUERY_REC *(*) (const char *, const char *, int))
1165 chat_protocol_register(rec);
1169 silc_channels_init();
1170 silc_queries_init();
1172 idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL);
1175 /* Deinit SILC. Called from src/fe-text/silc.c */
1177 void silc_core_deinit(void)
1179 if (idletag != -1) {
1180 signal_emit("chat protocol deinit", 1,
1181 chat_protocol_find("SILC"));
1183 silc_server_deinit();
1184 silc_channels_deinit();
1185 silc_queries_deinit();
1187 chat_protocol_unregister("SILC");
1189 g_source_remove(idletag);
1192 g_free(silc_client->username);
1193 g_free(silc_client->realname);
1194 silc_client_free(silc_client);