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 bool opt_create_keypair = FALSE;
43 static bool opt_debug = FALSE;
44 static char *opt_pkcs = NULL;
45 static char *opt_keyfile = NULL;
46 static int opt_bits = 0;
50 SilcClient silc_client = NULL;
51 SilcClientConfig silc_config = NULL;
52 extern SilcClientOperations ops;
53 extern int silc_debug;
55 /* SIM (SILC Module) table */
56 SilcSimContext **sims = NULL;
57 uint32 sims_count = 0;
60 static void silc_say(SilcClient client, SilcClientConnection conn,
63 silc_channel_message(SilcClient client, SilcClientConnection conn,
64 SilcClientEntry sender, SilcChannelEntry channel,
65 SilcMessageFlags flags, char *msg);
67 silc_private_message(SilcClient client, SilcClientConnection conn,
68 SilcClientEntry sender, SilcMessageFlags flags,
70 static void silc_notify(SilcClient client, SilcClientConnection conn,
71 SilcNotifyType type, ...);
73 silc_connect(SilcClient client, SilcClientConnection conn, int success);
75 silc_disconnect(SilcClient client, SilcClientConnection conn);
77 silc_command(SilcClient client, SilcClientConnection conn,
78 SilcClientCommandContext cmd_context, int success,
81 silc_command_reply(SilcClient client, SilcClientConnection conn,
82 SilcCommandPayload cmd_payload, int success,
83 SilcCommand command, SilcCommandStatus status, ...);
85 static int silc_verify_public_key(SilcClient client,
86 SilcClientConnection conn,
87 SilcSocketType conn_type,
88 unsigned char *pk, uint32 pk_len,
89 SilcSKEPKType pk_type);
90 static unsigned char *silc_ask_passphrase(SilcClient client,
91 SilcClientConnection conn);
93 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
94 char *hostname, uint16 port,
95 SilcProtocolAuthMeth *auth_meth,
96 unsigned char **auth_data,
97 uint32 *auth_data_len);
99 silc_failure(SilcClient client, SilcClientConnection conn,
100 SilcProtocol protocol, void *failure);
102 silc_key_agreement(SilcClient client, SilcClientConnection conn,
103 SilcClientEntry client_entry, char *hostname,
105 SilcKeyAgreementCallback *completion,
108 static void silc_say(SilcClient client, SilcClientConnection conn,
111 SILC_SERVER_REC *server;
115 server = conn == NULL ? NULL : conn->context;
118 str = g_strdup_vprintf(msg, va);
119 printtext(server, "#silc", MSGLEVEL_CRAP, "%s", str);
124 static void silc_say_error(char *msg, ...)
130 str = g_strdup_vprintf(msg, va);
131 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
137 /* Message for a channel. The `sender' is the nickname of the sender
138 received in the packet. The `channel_name' is the name of the channel. */
141 silc_channel_message(SilcClient client, SilcClientConnection conn,
142 SilcClientEntry sender, SilcChannelEntry channel,
143 SilcMessageFlags flags, char *msg)
145 SILC_SERVER_REC *server;
147 SILC_CHANNEL_REC *chanrec;
149 server = conn == NULL ? NULL : conn->context;
150 chanrec = silc_channel_find_entry(server, channel);
152 nick = silc_nicklist_find(chanrec, sender);
154 if (flags & SILC_MESSAGE_FLAG_ACTION)
156 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
159 signal_emit("message public", 6, server, msg,
160 nick == NULL ? "[<unknown>]" : nick->nick,
161 nick == NULL ? NULL : nick->host,
162 chanrec->name, nick);
165 /* Private message to the client. The `sender' is the nickname of the
166 sender received in the packet. */
169 silc_private_message(SilcClient client, SilcClientConnection conn,
170 SilcClientEntry sender, SilcMessageFlags flags,
173 SILC_SERVER_REC *server;
175 server = conn == NULL ? NULL : conn->context;
176 signal_emit("message private", 4, server, msg,
177 sender->nickname ? sender->nickname : "[<unknown>]",
178 sender->username ? sender->username : NULL);
181 /* Notify message to the client. The notify arguments are sent in the
182 same order as servers sends them. The arguments are same as received
183 from the server except for ID's. If ID is received application receives
184 the corresponding entry to the ID. For example, if Client ID is received
185 application receives SilcClientEntry. Also, if the notify type is
186 for channel the channel entry is sent to application (even if server
187 does not send it). */
194 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
195 static NOTIFY_REC notifies[] = {
196 { SILC_NOTIFY_TYPE_NONE, NULL },
197 { SILC_NOTIFY_TYPE_INVITE, "invite" },
198 { SILC_NOTIFY_TYPE_JOIN, "join" },
199 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
200 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
201 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
202 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
203 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
204 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
205 { SILC_NOTIFY_TYPE_MOTD, "motd" },
206 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
207 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
208 { SILC_NOTIFY_TYPE_KICKED, "kick" },
209 { SILC_NOTIFY_TYPE_KILLED, "kill" },
210 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
211 { SILC_NOTIFY_TYPE_BAN, "ban" },
214 static void silc_notify(SilcClient client, SilcClientConnection conn,
215 SilcNotifyType type, ...)
217 SILC_SERVER_REC *server;
220 server = conn == NULL ? NULL : conn->context;
223 if (type == SILC_NOTIFY_TYPE_NONE) {
224 /* Some generic notice from server */
225 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
226 } else if (type < MAX_NOTIFY) {
227 /* Send signal about the notify event */
229 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
230 signal_emit(signal, 2, server, va);
233 printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type);
239 /* Called to indicate that connection was either successfully established
240 or connecting failed. This is also the first time application receives
241 the SilcClientConnection objecet which it should save somewhere. */
244 silc_connect(SilcClient client, SilcClientConnection conn, int success)
246 SILC_SERVER_REC *server = conn->context;
249 server->connected = TRUE;
250 signal_emit("event connected", 1, server);
252 server->connection_lost = TRUE;
253 server->conn->context = NULL;
254 server_disconnect(SERVER(server));
258 /* Called to indicate that connection was disconnected to the server. */
261 silc_disconnect(SilcClient client, SilcClientConnection conn)
263 SILC_SERVER_REC *server = conn->context;
265 server->conn->context = NULL;
267 server->connection_lost = TRUE;
268 server_disconnect(SERVER(server));
271 /* Command handler. This function is called always in the command function.
272 If error occurs it will be called as well. `conn' is the associated
273 client connection. `cmd_context' is the command context that was
274 originally sent to the command. `success' is FALSE if error occured
275 during command. `command' is the command being processed. It must be
276 noted that this is not reply from server. This is merely called just
277 after application has called the command. Just to tell application
278 that the command really was processed. */
281 silc_command(SilcClient client, SilcClientConnection conn,
282 SilcClientCommandContext cmd_context, int success,
287 /* Client info resolving callback when JOIN command reply is received.
288 This will cache all users on the channel. */
290 void silc_client_join_get_users(SilcClient client,
291 SilcClientConnection conn,
292 SilcClientEntry *clients,
293 uint32 clients_count,
296 SilcChannelEntry channel = (SilcChannelEntry)context;
298 SILC_SERVER_REC *server = conn->context;
299 SILC_CHANNEL_REC *chanrec;
305 chanrec = silc_channel_find_entry(server, channel);
309 silc_list_start(channel->clients);
310 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END)
311 silc_nicklist_insert(chanrec, chu, FALSE);
313 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
314 nicklist_set_own(CHANNEL(chanrec), ownnick);
315 signal_emit("channel joined", 1, chanrec);
316 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
319 /* Command reply handler. This function is called always in the command reply
320 function. If error occurs it will be called as well. Normal scenario
321 is that it will be called after the received command data has been parsed
322 and processed. The function is used to pass the received command data to
325 `conn' is the associated client connection. `cmd_payload' is the command
326 payload data received from server and it can be ignored. It is provided
327 if the application would like to re-parse the received command data,
328 however, it must be noted that the data is parsed already by the library
329 thus the payload can be ignored. `success' is FALSE if error occured.
330 In this case arguments are not sent to the application. `command' is the
331 command reply being processed. The function has variable argument list
332 and each command defines the number and type of arguments it passes to the
333 application (on error they are not sent). */
336 silc_command_reply(SilcClient client, SilcClientConnection conn,
337 SilcCommandPayload cmd_payload, int success,
338 SilcCommand command, SilcCommandStatus status, ...)
341 SILC_SERVER_REC *server = conn->context;
342 SILC_CHANNEL_REC *chanrec;
345 va_start(vp, status);
348 case SILC_COMMAND_WHOIS:
350 char buf[1024], *nickname, *username, *realname;
355 /* XXX should use irssi routines */
357 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
358 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
360 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
363 client->ops->say(client, conn, "%s: %s", tmp,
364 silc_client_command_status_message(status));
366 client->ops->say(client, conn, "%s",
367 silc_client_command_status_message(status));
374 (void)va_arg(vp, SilcClientEntry);
375 nickname = va_arg(vp, char *);
376 username = va_arg(vp, char *);
377 realname = va_arg(vp, char *);
378 channels = va_arg(vp, SilcBuffer);
379 mode = va_arg(vp, uint32);
380 idle = va_arg(vp, uint32);
382 memset(buf, 0, sizeof(buf));
385 len = strlen(nickname);
386 strncat(buf, nickname, len);
387 strncat(buf, " is ", 4);
391 strncat(buf, username, strlen(username));
395 strncat(buf, " (", 2);
396 strncat(buf, realname, strlen(realname));
397 strncat(buf, ")", 1);
400 client->ops->say(client, conn, "%s", buf);
403 SilcDList list = silc_channel_payload_parse_list(channels);
405 SilcChannelPayload entry;
407 memset(buf, 0, sizeof(buf));
408 strcat(buf, "on channels: ");
410 silc_dlist_start(list);
411 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
412 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
414 char *name = silc_channel_get_name(entry, &name_len);
417 strncat(buf, m, strlen(m));
418 strncat(buf, name, name_len);
419 strncat(buf, " ", 1);
423 client->ops->say(client, conn, "%s", buf);
424 silc_channel_payload_list_free(list);
429 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
430 (mode & SILC_UMODE_ROUTER_OPERATOR))
431 client->ops->say(client, conn, "%s is %s", nickname,
432 (mode & SILC_UMODE_SERVER_OPERATOR) ?
434 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
435 "SILC Operator" : "[Unknown mode]");
437 if (mode & SILC_UMODE_GONE)
438 client->ops->say(client, conn, "%s is gone", nickname);
441 if (idle && nickname)
442 client->ops->say(client, conn, "%s has been idle %d %s",
444 idle > 60 ? (idle / 60) : idle,
445 idle > 60 ? "minutes" : "seconds");
449 case SILC_COMMAND_WHOWAS:
451 char buf[1024], *nickname, *username, *realname;
454 /* XXX should use irssi routines */
456 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
457 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
459 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
462 client->ops->say(client, conn, "%s: %s", tmp,
463 silc_client_command_status_message(status));
465 client->ops->say(client, conn, "%s",
466 silc_client_command_status_message(status));
473 (void)va_arg(vp, SilcClientEntry);
474 nickname = va_arg(vp, char *);
475 username = va_arg(vp, char *);
476 realname = va_arg(vp, char *);
478 memset(buf, 0, sizeof(buf));
481 len = strlen(nickname);
482 strncat(buf, nickname, len);
483 strncat(buf, " was ", 5);
487 strncat(buf, username, strlen(nickname));
491 strncat(buf, " (", 2);
492 strncat(buf, realname, strlen(realname));
493 strncat(buf, ")", 1);
496 client->ops->say(client, conn, "%s", buf);
500 case SILC_COMMAND_INVITE:
502 SilcChannelEntry channel;
508 /* XXX should use irssi routines */
510 channel = va_arg(vp, SilcChannelEntry);
511 invite_list = va_arg(vp, char *);
514 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
517 silc_say(client, conn, "%s invite list not set",
518 channel->channel_name);
522 case SILC_COMMAND_JOIN:
524 char *channel, *mode, *topic;
526 SilcChannelEntry channel_entry;
527 SilcBuffer client_id_list;
530 channel = va_arg(vp, char *);
531 channel_entry = va_arg(vp, SilcChannelEntry);
532 modei = va_arg(vp, uint32);
533 (void)va_arg(vp, uint32);
534 (void)va_arg(vp, unsigned char *);
535 (void)va_arg(vp, unsigned char *);
536 (void)va_arg(vp, unsigned char *);
537 topic = va_arg(vp, char *);
538 (void)va_arg(vp, unsigned char *);
539 list_count = va_arg(vp, uint32);
540 client_id_list = va_arg(vp, SilcBuffer);
545 chanrec = silc_channel_find(server, channel);
546 if (chanrec != NULL && !success)
547 channel_destroy(CHANNEL(chanrec));
548 else if (chanrec == NULL && success)
549 chanrec = silc_channel_create(server, channel, TRUE);
552 g_free_not_null(chanrec->topic);
553 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
554 signal_emit("channel topic changed", 1, chanrec);
555 silc_say(client, conn, "Topic for %s: %s", channel, topic);
558 mode = silc_client_chmode(modei, channel_entry);
559 g_free_not_null(chanrec->mode);
560 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
561 signal_emit("channel mode changed", 1, chanrec);
563 /* Resolve the client information */
564 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
565 silc_client_join_get_users,
570 case SILC_COMMAND_NICK:
572 SilcClientEntry client = va_arg(vp, SilcClientEntry);
578 old = g_strdup(server->nick);
579 server_change_nick(SERVER(server), client->nickname);
580 nicklist_rename_unique(SERVER(server),
581 server->conn->local_entry, server->nick,
582 client, client->nickname);
584 signal_emit("message own_nick", 4, server, server->nick, old, "");
589 case SILC_COMMAND_LIST:
593 unsigned char buf[256], tmp[16];
599 /* XXX should use irssi routines */
601 (void)va_arg(vp, SilcChannelEntry);
602 name = va_arg(vp, char *);
603 topic = va_arg(vp, char *);
604 usercount = va_arg(vp, int);
606 if (status == SILC_STATUS_LIST_START ||
607 status == SILC_STATUS_OK)
608 silc_say(client, conn,
609 " Channel Users Topic");
611 memset(buf, 0, sizeof(buf));
612 strncat(buf, " ", 2);
614 strncat(buf, name, len > 40 ? 40 : len);
616 for (i = 0; i < 40 - len; i++)
620 memset(tmp, 0, sizeof(tmp));
622 snprintf(tmp, sizeof(tmp), "%d", usercount);
627 for (i = 0; i < 10 - len; i++)
633 strncat(buf, topic, len);
636 silc_say(client, conn, "%s", buf);
640 case SILC_COMMAND_UMODE:
647 mode = va_arg(vp, uint32);
653 case SILC_COMMAND_OPER:
655 if (status == SILC_STATUS_OK) {
656 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
657 if (app->screen->bottom_line->umode)
658 silc_free(app->screen->bottom_line->umode);
659 app->screen->bottom_line->umode = strdup("Server Operator");;
660 silc_screen_print_bottom_line(app->screen, 0);
665 case SILC_COMMAND_SILCOPER:
667 if (status == SILC_STATUS_OK) {
668 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
669 if (app->screen->bottom_line->umode)
670 silc_free(app->screen->bottom_line->umode);
671 app->screen->bottom_line->umode = strdup("SILC Operator");;
672 silc_screen_print_bottom_line(app->screen, 0);
677 case SILC_COMMAND_USERS:
679 SilcChannelEntry channel;
687 channel = va_arg(vp, SilcChannelEntry);
689 /* There are two ways to do this, either parse the list (that
690 the command_reply sends (just take it with va_arg()) or just
691 traverse the channel's client list. I'll do the latter. See
692 JOIN command reply for example for the list. */
694 silc_say(client, conn, "Users on %s", channel->channel_name);
696 line = silc_calloc(1024, sizeof(*line));
698 silc_list_start(channel->clients);
699 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
700 SilcClientEntry e = chu->client;
704 memset(line, 0, line_len);
706 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
708 line_len += strlen(e->nickname) + strlen(e->server) + 100;
709 line = silc_calloc(line_len, sizeof(*line));
712 memset(tmp, 0, sizeof(tmp));
713 m = silc_client_chumode_char(chu->mode);
715 strncat(line, " ", 1);
716 strncat(line, e->nickname, strlen(e->nickname));
717 strncat(line, e->server ? "@" : "", 1);
721 len1 = strlen(e->server);
722 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
726 memset(&line[29], 0, len1 - 29);
728 for (i = 0; i < 30 - len1 - 1; i++)
732 if (e->mode & SILC_UMODE_GONE)
736 strcat(tmp, m ? m : "");
737 strncat(line, tmp, strlen(tmp));
740 for (i = 0; i < 5 - strlen(tmp); i++)
743 strcat(line, e->username ? e->username : "");
745 silc_say(client, conn, "%s", line);
755 case SILC_COMMAND_BAN:
757 SilcChannelEntry channel;
763 /* XXX should use irssi routines */
765 channel = va_arg(vp, SilcChannelEntry);
766 ban_list = va_arg(vp, char *);
769 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
772 silc_say(client, conn, "%s ban list not set", channel->channel_name);
776 case SILC_COMMAND_GETKEY:
780 SilcPublicKey public_key;
784 id_type = va_arg(vp, uint32);
785 entry = va_arg(vp, void *);
786 public_key = va_arg(vp, SilcPublicKey);
788 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
790 if (id_type == SILC_ID_CLIENT) {
791 silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
792 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
798 case SILC_COMMAND_TOPIC:
800 SilcChannelEntry channel;
806 channel = va_arg(vp, SilcChannelEntry);
807 topic = va_arg(vp, char *);
809 /* XXX should use irssi routines */
812 silc_say(client, conn,
813 "Topic on channel %s: %s", channel->channel_name,
822 /* Verifies received public key. If user decides to trust the key it is
823 saved as public server key for later use. If user does not trust the
824 key this returns FALSE. */
826 static int silc_verify_public_key(SilcClient client,
827 SilcClientConnection conn,
828 SilcSocketType conn_type,
829 unsigned char *pk, uint32 pk_len,
830 SilcSKEPKType pk_type)
835 /* Asks passphrase from user on the input line. */
837 static unsigned char *silc_ask_passphrase(SilcClient client,
838 SilcClientConnection conn)
843 /* Find authentication method and authentication data by hostname and
844 port. The hostname may be IP address as well. The found authentication
845 method and authentication data is returned to `auth_meth', `auth_data'
846 and `auth_data_len'. The function returns TRUE if authentication method
847 is found and FALSE if not. `conn' may be NULL. */
850 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
851 char *hostname, uint16 port,
852 SilcProtocolAuthMeth *auth_meth,
853 unsigned char **auth_data,
854 uint32 *auth_data_len)
857 /* XXX must resolve from configuration whether this connection has
858 any specific authentication data */
860 *auth_meth = SILC_AUTH_NONE;
867 /* Notifies application that failure packet was received. This is called
868 if there is some protocol active in the client. The `protocol' is the
869 protocol context. The `failure' is opaque pointer to the failure
870 indication. Note, that the `failure' is protocol dependant and application
871 must explicitly cast it to correct type. Usually `failure' is 32 bit
872 failure type (see protocol specs for all protocol failure types). */
875 silc_failure(SilcClient client, SilcClientConnection conn,
876 SilcProtocol protocol, void *failure)
878 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
879 SilcSKEStatus status = (SilcSKEStatus)failure;
881 if (status == SILC_SKE_STATUS_BAD_VERSION)
882 silc_say_error("You are running incompatible client version (it may be "
883 "too old or too new)");
884 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
885 silc_say_error("Server does not support your public key type");
886 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
887 silc_say_error("Server does not support one of your proposed KE group");
888 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
889 silc_say_error("Server does not support one of your proposed cipher");
890 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
891 silc_say_error("Server does not support one of your proposed PKCS");
892 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
893 silc_say_error("Server does not support one of your proposed "
895 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
896 silc_say_error("Server does not support one of your proposed HMAC");
897 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
898 silc_say_error("Incorrect signature");
901 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
902 uint32 err = (uint32)failure;
904 if (err == SILC_AUTH_FAILED)
905 silc_say(client, conn, "Authentication failed");
909 /* Asks whether the user would like to perform the key agreement protocol.
910 This is called after we have received an key agreement packet or an
911 reply to our key agreement packet. This returns TRUE if the user wants
912 the library to perform the key agreement protocol and FALSE if it is not
913 desired (application may start it later by calling the function
914 silc_client_perform_key_agreement). */
917 silc_key_agreement(SilcClient client, SilcClientConnection conn,
918 SilcClientEntry client_entry, char *hostname,
920 SilcKeyAgreementCallback *completion,
925 /* We will just display the info on the screen and return FALSE and user
926 will have to start the key agreement with a command. */
929 memset(host, 0, sizeof(host));
930 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
933 silc_say(client, conn, "%s wants to perform key agreement %s",
934 client_entry->nickname, hostname ? host : "");
942 /* SILC client operations */
943 SilcClientOperations ops = {
945 silc_channel_message,
946 silc_private_message,
952 silc_get_auth_method,
953 silc_verify_public_key,
959 static int my_silc_scheduler(void)
961 silc_schedule_one(0);
965 static CHATNET_REC *create_chatnet(void)
967 return g_malloc0(sizeof(CHATNET_REC));
970 static SERVER_SETUP_REC *create_server_setup(void)
972 return g_malloc0(sizeof(SERVER_SETUP_REC));
975 static CHANNEL_SETUP_REC *create_channel_setup(void)
977 return g_malloc0(sizeof(CHANNEL_SETUP_REC));
980 static SERVER_CONNECT_REC *create_server_connect(void)
982 return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC));
985 /* Checks user information and saves them to the config file it they
986 do not exist there already. */
988 static void silc_init_userinfo(void)
990 const char *set, *nick, *user_name;
993 /* check if nick/username/realname wasn't read from setup.. */
994 set = settings_get_str("real_name");
995 if (set == NULL || *set == '\0') {
996 str = g_getenv("SILCNAME");
998 str = g_getenv("IRCNAME");
999 settings_set_str("real_name",
1000 str != NULL ? str : g_get_real_name());
1004 user_name = settings_get_str("user_name");
1005 if (user_name == NULL || *user_name == '\0') {
1006 str = g_getenv("SILCUSER");
1008 str = g_getenv("IRCUSER");
1009 settings_set_str("user_name",
1010 str != NULL ? str : g_get_user_name());
1012 user_name = settings_get_str("user_name");
1016 nick = settings_get_str("nick");
1017 if (nick == NULL || *nick == '\0') {
1018 str = g_getenv("SILCNICK");
1020 str = g_getenv("IRCNICK");
1021 settings_set_str("nick", str != NULL ? str : user_name);
1023 nick = settings_get_str("nick");
1026 /* alternate nick */
1027 set = settings_get_str("alternate_nick");
1028 if (set == NULL || *set == '\0') {
1029 if (strlen(nick) < 9)
1030 str = g_strconcat(nick, "_", NULL);
1032 str = g_strdup(nick);
1033 str[strlen(str)-1] = '_';
1035 settings_set_str("alternate_nick", str);
1040 set = settings_get_str("hostname");
1041 if (set == NULL || *set == '\0') {
1042 str = g_getenv("SILCHOST");
1044 str = g_getenv("IRCHOST");
1046 settings_set_str("hostname", str);
1052 static void silc_log_info(char *message)
1054 fprintf(stderr, "%s\n", message);
1057 static void silc_log_warning(char *message)
1059 fprintf(stderr, "%s\n", message);
1062 static void silc_log_error(char *message)
1064 fprintf(stderr, "%s\n", message);
1067 /* Init SILC. Called from src/fe-text/silc.c */
1069 void silc_core_init(void)
1071 static struct poptOption options[] = {
1072 { "create-key-pair", 'C', POPT_ARG_NONE, &opt_create_keypair, 0,
1073 "Create new public key pair", NULL },
1074 { "pkcs", 0, POPT_ARG_STRING, &opt_pkcs, 0,
1075 "Set the PKCS of the public key pair", "PKCS" },
1076 { "bits", 0, POPT_ARG_INT, &opt_bits, 0,
1077 "Set the length of the public key pair", "VALUE" },
1078 { "show-key", 'S', POPT_ARG_STRING, &opt_keyfile, 0,
1079 "Show the contents of the public key", "FILE" },
1080 { "debug", 'd', POPT_ARG_NONE, &opt_debug, 0,
1081 "Enable debugging", NULL },
1082 { NULL, '\0', 0, NULL }
1085 args_register(options);
1088 /* Finalize init. Called from src/fe-text/silc.c */
1090 void silc_core_init_finish(void)
1092 CHAT_PROTOCOL_REC *rec;
1094 if (opt_create_keypair == TRUE) {
1095 /* Create new key pair and exit */
1096 silc_cipher_register_default();
1097 silc_pkcs_register_default();
1098 silc_hash_register_default();
1099 silc_hmac_register_default();
1100 silc_client_create_key_pair(opt_pkcs, opt_bits,
1101 NULL, NULL, NULL, NULL, NULL);
1107 silc_cipher_register_default();
1108 silc_pkcs_register_default();
1109 silc_hash_register_default();
1110 silc_hmac_register_default();
1111 silc_client_show_key(opt_keyfile);
1115 silc_debug = opt_debug;
1116 silc_log_set_callbacks(silc_log_info, silc_log_warning,
1117 silc_log_error, NULL);
1119 silc_init_userinfo();
1121 /* Allocate SILC client */
1122 silc_client = silc_client_alloc(&ops, NULL);
1124 /* Load local config file */
1125 silc_config = silc_client_config_alloc(SILC_CLIENT_HOME_CONFIG_FILE);
1127 /* Get user information */
1128 silc_client->username = g_strdup(settings_get_str("user_name"));
1129 silc_client->hostname = silc_net_localhost();
1130 silc_client->realname = g_strdup(settings_get_str("real_name"));
1132 /* Register all configured ciphers, PKCS and hash functions. */
1134 silc_config->client = silc_client;
1135 if (!silc_client_config_register_ciphers(silc_config))
1136 silc_cipher_register_default();
1137 if (!silc_client_config_register_pkcs(silc_config))
1138 silc_pkcs_register_default();
1139 if (!silc_client_config_register_hashfuncs(silc_config))
1140 silc_hash_register_default();
1141 if (!silc_client_config_register_hmacs(silc_config))
1142 silc_hmac_register_default();
1144 /* Register default ciphers, pkcs, hash funtions and hmacs. */
1145 silc_cipher_register_default();
1146 silc_pkcs_register_default();
1147 silc_hash_register_default();
1148 silc_hmac_register_default();
1151 /* Check ~/.silc directory and public and private keys */
1152 if (silc_client_check_silc_dir() == FALSE) {
1157 /* Load public and private key */
1158 if (silc_client_load_keys(silc_client) == FALSE) {
1163 /* Initialize the SILC client */
1164 if (!silc_client_init(silc_client)) {
1169 /* Register SILC to the irssi */
1170 rec = g_new0(CHAT_PROTOCOL_REC, 1);
1172 rec->fullname = "Secure Internet Live Conferencing";
1173 rec->chatnet = "silcnet";
1174 rec->create_chatnet = create_chatnet;
1175 rec->create_server_setup = create_server_setup;
1176 rec->create_channel_setup = create_channel_setup;
1177 rec->create_server_connect = create_server_connect;
1178 rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *))
1179 silc_server_connect;
1180 rec->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, int))
1181 silc_channel_create;
1182 rec->query_create = (QUERY_REC *(*) (const char *, const char *, int))
1185 chat_protocol_register(rec);
1189 silc_channels_init();
1190 silc_queries_init();
1192 idletag = g_timeout_add(50, (GSourceFunc) my_silc_scheduler, NULL);
1195 /* Deinit SILC. Called from src/fe-text/silc.c */
1197 void silc_core_deinit(void)
1199 if (idletag != -1) {
1200 signal_emit("chat protocol deinit", 1,
1201 chat_protocol_find("SILC"));
1203 silc_server_deinit();
1204 silc_channels_deinit();
1205 silc_queries_deinit();
1207 chat_protocol_unregister("SILC");
1209 g_source_remove(idletag);
1212 g_free(silc_client->username);
1213 g_free(silc_client->realname);
1214 silc_client_free(silc_client);