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 char *opt_pkcs = NULL;
44 static char *opt_keyfile = NULL;
45 static int opt_bits = 0;
49 SilcClient silc_client = NULL;
50 SilcClientConfig silc_config = NULL;
51 extern SilcClientOperations ops;
53 /* SIM (SILC Module) table */
54 SilcSimContext **sims = NULL;
55 uint32 sims_count = 0;
58 static void silc_say(SilcClient client, SilcClientConnection conn,
61 silc_channel_message(SilcClient client, SilcClientConnection conn,
62 SilcClientEntry sender, SilcChannelEntry channel,
63 SilcMessageFlags flags, char *msg);
65 silc_private_message(SilcClient client, SilcClientConnection conn,
66 SilcClientEntry sender, SilcMessageFlags flags,
68 static void silc_notify(SilcClient client, SilcClientConnection conn,
69 SilcNotifyType type, ...);
71 silc_connect(SilcClient client, SilcClientConnection conn, int success);
73 silc_disconnect(SilcClient client, SilcClientConnection conn);
75 silc_command(SilcClient client, SilcClientConnection conn,
76 SilcClientCommandContext cmd_context, int success,
79 silc_command_reply(SilcClient client, SilcClientConnection conn,
80 SilcCommandPayload cmd_payload, int success,
81 SilcCommand command, SilcCommandStatus status, ...);
83 static int silc_verify_public_key(SilcClient client,
84 SilcClientConnection conn,
85 SilcSocketType conn_type,
86 unsigned char *pk, uint32 pk_len,
87 SilcSKEPKType pk_type);
88 static unsigned char *silc_ask_passphrase(SilcClient client,
89 SilcClientConnection conn);
91 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
92 char *hostname, uint16 port,
93 SilcProtocolAuthMeth *auth_meth,
94 unsigned char **auth_data,
95 uint32 *auth_data_len);
97 silc_failure(SilcClient client, SilcClientConnection conn,
98 SilcProtocol protocol, void *failure);
100 silc_key_agreement(SilcClient client, SilcClientConnection conn,
101 SilcClientEntry client_entry, char *hostname,
103 SilcKeyAgreementCallback *completion,
106 static void silc_say(SilcClient client, SilcClientConnection conn,
109 SILC_SERVER_REC *server;
113 server = conn == NULL ? NULL : conn->context;
116 str = g_strdup_vprintf(msg, va);
117 printtext(server, "#silc", MSGLEVEL_CRAP, "%s", str);
122 static void silc_say_error(char *msg, ...)
128 str = g_strdup_vprintf(msg, va);
129 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
135 /* Message for a channel. The `sender' is the nickname of the sender
136 received in the packet. The `channel_name' is the name of the channel. */
139 silc_channel_message(SilcClient client, SilcClientConnection conn,
140 SilcClientEntry sender, SilcChannelEntry channel,
141 SilcMessageFlags flags, char *msg)
143 SILC_SERVER_REC *server;
145 SILC_CHANNEL_REC *chanrec;
147 server = conn == NULL ? NULL : conn->context;
148 chanrec = silc_channel_find_entry(server, channel);
150 nick = silc_nicklist_find(chanrec, sender);
152 if (flags & SILC_MESSAGE_FLAG_ACTION)
154 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
157 signal_emit("message public", 6, server, msg,
158 nick == NULL ? "[<unknown>]" : nick->nick,
159 nick == NULL ? NULL : nick->host,
160 chanrec->name, nick);
163 /* Private message to the client. The `sender' is the nickname of the
164 sender received in the packet. */
167 silc_private_message(SilcClient client, SilcClientConnection conn,
168 SilcClientEntry sender, SilcMessageFlags flags,
171 SILC_SERVER_REC *server;
173 server = conn == NULL ? NULL : conn->context;
174 signal_emit("message private", 4, server, msg,
175 sender->nickname ? sender->nickname : "[<unknown>]",
176 sender->username ? sender->username : NULL);
179 /* Notify message to the client. The notify arguments are sent in the
180 same order as servers sends them. The arguments are same as received
181 from the server except for ID's. If ID is received application receives
182 the corresponding entry to the ID. For example, if Client ID is received
183 application receives SilcClientEntry. Also, if the notify type is
184 for channel the channel entry is sent to application (even if server
185 does not send it). */
192 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
193 static NOTIFY_REC notifies[] = {
194 { SILC_NOTIFY_TYPE_NONE, NULL },
195 { SILC_NOTIFY_TYPE_INVITE, "invite" },
196 { SILC_NOTIFY_TYPE_JOIN, "join" },
197 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
198 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
199 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
200 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
201 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
202 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
203 { SILC_NOTIFY_TYPE_MOTD, "motd" },
204 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
205 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
206 { SILC_NOTIFY_TYPE_KICKED, "kick" },
207 { SILC_NOTIFY_TYPE_KILLED, "kill" },
208 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
209 { SILC_NOTIFY_TYPE_BAN, "ban" },
212 static void silc_notify(SilcClient client, SilcClientConnection conn,
213 SilcNotifyType type, ...)
215 SILC_SERVER_REC *server;
218 server = conn == NULL ? NULL : conn->context;
221 if (type == SILC_NOTIFY_TYPE_NONE) {
222 /* Some generic notice from server */
223 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
224 } else if (type < MAX_NOTIFY) {
225 /* Send signal about the notify event */
227 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
228 signal_emit(signal, 2, server, va);
231 printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type);
237 /* Called to indicate that connection was either successfully established
238 or connecting failed. This is also the first time application receives
239 the SilcClientConnection objecet which it should save somewhere. */
242 silc_connect(SilcClient client, SilcClientConnection conn, int success)
244 SILC_SERVER_REC *server = conn->context;
247 server->connected = TRUE;
248 signal_emit("event connected", 1, server);
250 server->connection_lost = TRUE;
251 server->conn->context = NULL;
252 server_disconnect(SERVER(server));
256 /* Called to indicate that connection was disconnected to the server. */
259 silc_disconnect(SilcClient client, SilcClientConnection conn)
261 SILC_SERVER_REC *server = conn->context;
263 server->conn->context = NULL;
265 server->connection_lost = TRUE;
266 server_disconnect(SERVER(server));
269 /* Command handler. This function is called always in the command function.
270 If error occurs it will be called as well. `conn' is the associated
271 client connection. `cmd_context' is the command context that was
272 originally sent to the command. `success' is FALSE if error occured
273 during command. `command' is the command being processed. It must be
274 noted that this is not reply from server. This is merely called just
275 after application has called the command. Just to tell application
276 that the command really was processed. */
279 silc_command(SilcClient client, SilcClientConnection conn,
280 SilcClientCommandContext cmd_context, int success,
285 /* Client info resolving callback when JOIN command reply is received.
286 This will cache all users on the channel. */
288 void silc_client_join_get_users(SilcClient client,
289 SilcClientConnection conn,
290 SilcClientEntry *clients,
291 uint32 clients_count,
294 SilcChannelEntry channel = (SilcChannelEntry)context;
296 SILC_SERVER_REC *server = conn->context;
297 SILC_CHANNEL_REC *chanrec;
303 chanrec = silc_channel_find_entry(server, channel);
307 silc_list_start(channel->clients);
308 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END)
309 silc_nicklist_insert(chanrec, chu, FALSE);
311 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
312 nicklist_set_own(CHANNEL(chanrec), ownnick);
313 signal_emit("channel joined", 1, chanrec);
314 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
317 /* Command reply handler. This function is called always in the command reply
318 function. If error occurs it will be called as well. Normal scenario
319 is that it will be called after the received command data has been parsed
320 and processed. The function is used to pass the received command data to
323 `conn' is the associated client connection. `cmd_payload' is the command
324 payload data received from server and it can be ignored. It is provided
325 if the application would like to re-parse the received command data,
326 however, it must be noted that the data is parsed already by the library
327 thus the payload can be ignored. `success' is FALSE if error occured.
328 In this case arguments are not sent to the application. `command' is the
329 command reply being processed. The function has variable argument list
330 and each command defines the number and type of arguments it passes to the
331 application (on error they are not sent). */
334 silc_command_reply(SilcClient client, SilcClientConnection conn,
335 SilcCommandPayload cmd_payload, int success,
336 SilcCommand command, SilcCommandStatus status, ...)
339 SILC_SERVER_REC *server = conn->context;
340 SILC_CHANNEL_REC *chanrec;
343 va_start(vp, status);
346 case SILC_COMMAND_WHOIS:
348 char buf[1024], *nickname, *username, *realname;
353 /* XXX should use irssi routines */
355 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
356 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
358 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
361 client->ops->say(client, conn, "%s: %s", tmp,
362 silc_client_command_status_message(status));
364 client->ops->say(client, conn, "%s",
365 silc_client_command_status_message(status));
372 (void)va_arg(vp, SilcClientEntry);
373 nickname = va_arg(vp, char *);
374 username = va_arg(vp, char *);
375 realname = va_arg(vp, char *);
376 channels = va_arg(vp, SilcBuffer);
377 mode = va_arg(vp, uint32);
378 idle = va_arg(vp, uint32);
380 memset(buf, 0, sizeof(buf));
383 len = strlen(nickname);
384 strncat(buf, nickname, len);
385 strncat(buf, " is ", 4);
389 strncat(buf, username, strlen(username));
393 strncat(buf, " (", 2);
394 strncat(buf, realname, strlen(realname));
395 strncat(buf, ")", 1);
398 client->ops->say(client, conn, "%s", buf);
401 SilcDList list = silc_channel_payload_parse_list(channels);
403 SilcChannelPayload entry;
405 memset(buf, 0, sizeof(buf));
406 strcat(buf, "on channels: ");
408 silc_dlist_start(list);
409 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
410 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
412 char *name = silc_channel_get_name(entry, &name_len);
415 strncat(buf, m, strlen(m));
416 strncat(buf, name, name_len);
417 strncat(buf, " ", 1);
421 client->ops->say(client, conn, "%s", buf);
422 silc_channel_payload_list_free(list);
427 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
428 (mode & SILC_UMODE_ROUTER_OPERATOR))
429 client->ops->say(client, conn, "%s is %s", nickname,
430 (mode & SILC_UMODE_SERVER_OPERATOR) ?
432 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
433 "SILC Operator" : "[Unknown mode]");
435 if (mode & SILC_UMODE_GONE)
436 client->ops->say(client, conn, "%s is gone", nickname);
439 if (idle && nickname)
440 client->ops->say(client, conn, "%s has been idle %d %s",
442 idle > 60 ? (idle / 60) : idle,
443 idle > 60 ? "minutes" : "seconds");
447 case SILC_COMMAND_WHOWAS:
449 char buf[1024], *nickname, *username, *realname;
452 /* XXX should use irssi routines */
454 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
455 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
457 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
460 client->ops->say(client, conn, "%s: %s", tmp,
461 silc_client_command_status_message(status));
463 client->ops->say(client, conn, "%s",
464 silc_client_command_status_message(status));
471 (void)va_arg(vp, SilcClientEntry);
472 nickname = va_arg(vp, char *);
473 username = va_arg(vp, char *);
474 realname = va_arg(vp, char *);
476 memset(buf, 0, sizeof(buf));
479 len = strlen(nickname);
480 strncat(buf, nickname, len);
481 strncat(buf, " was ", 5);
485 strncat(buf, username, strlen(nickname));
489 strncat(buf, " (", 2);
490 strncat(buf, realname, strlen(realname));
491 strncat(buf, ")", 1);
494 client->ops->say(client, conn, "%s", buf);
498 case SILC_COMMAND_INVITE:
500 SilcChannelEntry channel;
506 /* XXX should use irssi routines */
508 channel = va_arg(vp, SilcChannelEntry);
509 invite_list = va_arg(vp, char *);
512 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
515 silc_say(client, conn, "%s invite list not set",
516 channel->channel_name);
520 case SILC_COMMAND_JOIN:
522 char *channel, *mode, *topic;
524 SilcChannelEntry channel_entry;
525 SilcBuffer client_id_list;
528 channel = va_arg(vp, char *);
529 channel_entry = va_arg(vp, SilcChannelEntry);
530 modei = va_arg(vp, uint32);
531 (void)va_arg(vp, uint32);
532 (void)va_arg(vp, unsigned char *);
533 (void)va_arg(vp, unsigned char *);
534 (void)va_arg(vp, unsigned char *);
535 topic = va_arg(vp, char *);
536 (void)va_arg(vp, unsigned char *);
537 list_count = va_arg(vp, uint32);
538 client_id_list = va_arg(vp, SilcBuffer);
543 chanrec = silc_channel_find(server, channel);
544 if (chanrec != NULL && !success)
545 channel_destroy(CHANNEL(chanrec));
546 else if (chanrec == NULL && success)
547 chanrec = silc_channel_create(server, channel, TRUE);
550 g_free_not_null(chanrec->topic);
551 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
552 signal_emit("channel topic changed", 1, chanrec);
553 silc_say(client, conn, "Topic for %s: %s", channel, topic);
556 mode = silc_client_chmode(modei, channel_entry);
557 g_free_not_null(chanrec->mode);
558 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
559 signal_emit("channel mode changed", 1, chanrec);
561 /* Resolve the client information */
562 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
563 silc_client_join_get_users,
568 case SILC_COMMAND_NICK:
570 SilcClientEntry client = va_arg(vp, SilcClientEntry);
576 old = g_strdup(server->nick);
577 server_change_nick(SERVER(server), client->nickname);
578 nicklist_rename_unique(SERVER(server),
579 server->conn->local_entry, server->nick,
580 client, client->nickname);
582 signal_emit("message own_nick", 4, server, server->nick, old, "");
587 case SILC_COMMAND_LIST:
591 unsigned char buf[256], tmp[16];
597 /* XXX should use irssi routines */
599 (void)va_arg(vp, SilcChannelEntry);
600 name = va_arg(vp, char *);
601 topic = va_arg(vp, char *);
602 usercount = va_arg(vp, int);
604 if (status == SILC_STATUS_LIST_START ||
605 status == SILC_STATUS_OK)
606 silc_say(client, conn,
607 " Channel Users Topic");
609 memset(buf, 0, sizeof(buf));
610 strncat(buf, " ", 2);
612 strncat(buf, name, len > 40 ? 40 : len);
614 for (i = 0; i < 40 - len; i++)
618 memset(tmp, 0, sizeof(tmp));
620 snprintf(tmp, sizeof(tmp), "%d", usercount);
625 for (i = 0; i < 10 - len; i++)
631 strncat(buf, topic, len);
634 silc_say(client, conn, "%s", buf);
638 case SILC_COMMAND_UMODE:
645 mode = va_arg(vp, uint32);
651 case SILC_COMMAND_OPER:
653 if (status == SILC_STATUS_OK) {
654 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
655 if (app->screen->bottom_line->umode)
656 silc_free(app->screen->bottom_line->umode);
657 app->screen->bottom_line->umode = strdup("Server Operator");;
658 silc_screen_print_bottom_line(app->screen, 0);
663 case SILC_COMMAND_SILCOPER:
665 if (status == SILC_STATUS_OK) {
666 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
667 if (app->screen->bottom_line->umode)
668 silc_free(app->screen->bottom_line->umode);
669 app->screen->bottom_line->umode = strdup("SILC Operator");;
670 silc_screen_print_bottom_line(app->screen, 0);
675 case SILC_COMMAND_USERS:
677 SilcChannelEntry channel;
685 channel = va_arg(vp, SilcChannelEntry);
687 /* There are two ways to do this, either parse the list (that
688 the command_reply sends (just take it with va_arg()) or just
689 traverse the channel's client list. I'll do the latter. See
690 JOIN command reply for example for the list. */
692 silc_say(client, conn, "Users on %s", channel->channel_name);
694 line = silc_calloc(1024, sizeof(*line));
696 silc_list_start(channel->clients);
697 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
698 SilcClientEntry e = chu->client;
702 memset(line, 0, line_len);
704 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
706 line_len += strlen(e->nickname) + strlen(e->server) + 100;
707 line = silc_calloc(line_len, sizeof(*line));
710 memset(tmp, 0, sizeof(tmp));
711 m = silc_client_chumode_char(chu->mode);
713 strncat(line, " ", 1);
714 strncat(line, e->nickname, strlen(e->nickname));
715 strncat(line, e->server ? "@" : "", 1);
719 len1 = strlen(e->server);
720 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
724 memset(&line[29], 0, len1 - 29);
726 for (i = 0; i < 30 - len1 - 1; i++)
730 if (e->mode & SILC_UMODE_GONE)
734 strcat(tmp, m ? m : "");
735 strncat(line, tmp, strlen(tmp));
738 for (i = 0; i < 5 - strlen(tmp); i++)
741 strcat(line, e->username ? e->username : "");
743 silc_say(client, conn, "%s", line);
753 case SILC_COMMAND_BAN:
755 SilcChannelEntry channel;
761 /* XXX should use irssi routines */
763 channel = va_arg(vp, SilcChannelEntry);
764 ban_list = va_arg(vp, char *);
767 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
770 silc_say(client, conn, "%s ban list not set", channel->channel_name);
774 case SILC_COMMAND_GETKEY:
778 SilcPublicKey public_key;
782 id_type = va_arg(vp, uint32);
783 entry = va_arg(vp, void *);
784 public_key = va_arg(vp, SilcPublicKey);
786 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
788 if (id_type == SILC_ID_CLIENT) {
789 silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
790 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
796 case SILC_COMMAND_TOPIC:
798 SilcChannelEntry channel;
804 channel = va_arg(vp, SilcChannelEntry);
805 topic = va_arg(vp, char *);
807 /* XXX should use irssi routines */
810 silc_say(client, conn,
811 "Topic on channel %s: %s", channel->channel_name,
820 /* Verifies received public key. If user decides to trust the key it is
821 saved as public server key for later use. If user does not trust the
822 key this returns FALSE. */
824 static int silc_verify_public_key(SilcClient client,
825 SilcClientConnection conn,
826 SilcSocketType conn_type,
827 unsigned char *pk, uint32 pk_len,
828 SilcSKEPKType pk_type)
833 /* Asks passphrase from user on the input line. */
835 static unsigned char *silc_ask_passphrase(SilcClient client,
836 SilcClientConnection conn)
841 /* Find authentication method and authentication data by hostname and
842 port. The hostname may be IP address as well. The found authentication
843 method and authentication data is returned to `auth_meth', `auth_data'
844 and `auth_data_len'. The function returns TRUE if authentication method
845 is found and FALSE if not. `conn' may be NULL. */
848 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
849 char *hostname, uint16 port,
850 SilcProtocolAuthMeth *auth_meth,
851 unsigned char **auth_data,
852 uint32 *auth_data_len)
855 /* XXX must resolve from configuration whether this connection has
856 any specific authentication data */
858 *auth_meth = SILC_AUTH_NONE;
865 /* Notifies application that failure packet was received. This is called
866 if there is some protocol active in the client. The `protocol' is the
867 protocol context. The `failure' is opaque pointer to the failure
868 indication. Note, that the `failure' is protocol dependant and application
869 must explicitly cast it to correct type. Usually `failure' is 32 bit
870 failure type (see protocol specs for all protocol failure types). */
873 silc_failure(SilcClient client, SilcClientConnection conn,
874 SilcProtocol protocol, void *failure)
876 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
877 SilcSKEStatus status = (SilcSKEStatus)failure;
879 if (status == SILC_SKE_STATUS_BAD_VERSION)
880 silc_say_error("You are running incompatible client version (it may be "
881 "too old or too new)");
882 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
883 silc_say_error("Server does not support your public key type");
884 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
885 silc_say_error("Server does not support one of your proposed KE group");
886 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
887 silc_say_error("Server does not support one of your proposed cipher");
888 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
889 silc_say_error("Server does not support one of your proposed PKCS");
890 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
891 silc_say_error("Server does not support one of your proposed "
893 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
894 silc_say_error("Server does not support one of your proposed HMAC");
895 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
896 silc_say_error("Incorrect signature");
899 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
900 uint32 err = (uint32)failure;
902 if (err == SILC_AUTH_FAILED)
903 silc_say(client, conn, "Authentication failed");
907 /* Asks whether the user would like to perform the key agreement protocol.
908 This is called after we have received an key agreement packet or an
909 reply to our key agreement packet. This returns TRUE if the user wants
910 the library to perform the key agreement protocol and FALSE if it is not
911 desired (application may start it later by calling the function
912 silc_client_perform_key_agreement). */
915 silc_key_agreement(SilcClient client, SilcClientConnection conn,
916 SilcClientEntry client_entry, char *hostname,
918 SilcKeyAgreementCallback *completion,
923 /* We will just display the info on the screen and return FALSE and user
924 will have to start the key agreement with a command. */
927 memset(host, 0, sizeof(host));
928 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
931 silc_say(client, conn, "%s wants to perform key agreement %s",
932 client_entry->nickname, hostname ? host : "");
940 /* SILC client operations */
941 SilcClientOperations ops = {
943 silc_channel_message,
944 silc_private_message,
950 silc_get_auth_method,
951 silc_verify_public_key,
957 static int my_silc_scheduler(void)
959 silc_schedule_one(0);
963 static CHATNET_REC *create_chatnet(void)
965 return g_malloc0(sizeof(CHATNET_REC));
968 static SERVER_SETUP_REC *create_server_setup(void)
970 return g_malloc0(sizeof(SERVER_SETUP_REC));
973 static CHANNEL_SETUP_REC *create_channel_setup(void)
975 return g_malloc0(sizeof(CHANNEL_SETUP_REC));
978 static SERVER_CONNECT_REC *create_server_connect(void)
980 return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC));
983 /* Checks user information and saves them to the config file it they
984 do not exist there already. */
986 static void silc_init_userinfo(void)
988 const char *set, *nick, *user_name;
991 /* check if nick/username/realname wasn't read from setup.. */
992 set = settings_get_str("real_name");
993 if (set == NULL || *set == '\0') {
994 str = g_getenv("SILCNAME");
996 str = g_getenv("IRCNAME");
997 settings_set_str("real_name",
998 str != NULL ? str : g_get_real_name());
1002 user_name = settings_get_str("user_name");
1003 if (user_name == NULL || *user_name == '\0') {
1004 str = g_getenv("SILCUSER");
1006 str = g_getenv("IRCUSER");
1007 settings_set_str("user_name",
1008 str != NULL ? str : g_get_user_name());
1010 user_name = settings_get_str("user_name");
1014 nick = settings_get_str("nick");
1015 if (nick == NULL || *nick == '\0') {
1016 str = g_getenv("SILCNICK");
1018 str = g_getenv("IRCNICK");
1019 settings_set_str("nick", str != NULL ? str : user_name);
1021 nick = settings_get_str("nick");
1024 /* alternate nick */
1025 set = settings_get_str("alternate_nick");
1026 if (set == NULL || *set == '\0') {
1027 if (strlen(nick) < 9)
1028 str = g_strconcat(nick, "_", NULL);
1030 str = g_strdup(nick);
1031 str[strlen(str)-1] = '_';
1033 settings_set_str("alternate_nick", str);
1038 set = settings_get_str("hostname");
1039 if (set == NULL || *set == '\0') {
1040 str = g_getenv("SILCHOST");
1042 str = g_getenv("IRCHOST");
1044 settings_set_str("hostname", str);
1048 /* Init SILC. Called from src/fe-text/silc.c */
1050 void silc_core_init(void)
1052 static struct poptOption options[] = {
1053 { "create-key-pair", 'C', POPT_ARG_NONE, &opt_create_keypair, 0,
1054 "Create new public key pair", NULL },
1055 { "pkcs", 0, POPT_ARG_STRING, &opt_pkcs, 0,
1056 "Set the PKCS of the public key pair", "PKCS" },
1057 { "bits", 0, POPT_ARG_INT, &opt_bits, 0,
1058 "Set the length of the public key pair", "VALUE" },
1059 { "show-key", 'S', POPT_ARG_STRING, &opt_keyfile, 0,
1060 "Show the contents of the public key", "FILE" },
1061 { NULL, '\0', 0, NULL }
1064 args_register(options);
1067 /* Finalize init. Called from src/fe-text/silc.c */
1069 void silc_core_init_finish(void)
1071 CHAT_PROTOCOL_REC *rec;
1073 if (opt_create_keypair == TRUE) {
1074 /* Create new key pair and exit */
1075 silc_cipher_register_default();
1076 silc_pkcs_register_default();
1077 silc_hash_register_default();
1078 silc_hmac_register_default();
1079 silc_client_create_key_pair(opt_pkcs, opt_bits,
1080 NULL, NULL, NULL, NULL, NULL);
1086 silc_cipher_register_default();
1087 silc_pkcs_register_default();
1088 silc_hash_register_default();
1089 silc_hmac_register_default();
1090 silc_client_show_key(opt_keyfile);
1094 silc_init_userinfo();
1096 /* Allocate SILC client */
1097 silc_client = silc_client_alloc(&ops, NULL);
1099 /* Load local config file */
1100 silc_config = silc_client_config_alloc(SILC_CLIENT_HOME_CONFIG_FILE);
1102 /* Get user information */
1103 silc_client->username = g_strdup(settings_get_str("user_name"));
1104 silc_client->hostname = silc_net_localhost();
1105 silc_client->realname = g_strdup(settings_get_str("real_name"));
1107 /* Register all configured ciphers, PKCS and hash functions. */
1109 silc_config->client = silc_client;
1110 if (!silc_client_config_register_ciphers(silc_config))
1111 silc_cipher_register_default();
1112 if (!silc_client_config_register_pkcs(silc_config))
1113 silc_pkcs_register_default();
1114 if (!silc_client_config_register_hashfuncs(silc_config))
1115 silc_hash_register_default();
1116 if (!silc_client_config_register_hmacs(silc_config))
1117 silc_hmac_register_default();
1119 /* Register default ciphers, pkcs, hash funtions and hmacs. */
1120 silc_cipher_register_default();
1121 silc_pkcs_register_default();
1122 silc_hash_register_default();
1123 silc_hmac_register_default();
1126 /* Check ~/.silc directory and public and private keys */
1127 if (silc_client_check_silc_dir() == FALSE) {
1132 /* Load public and private key */
1133 if (silc_client_load_keys(silc_client) == FALSE) {
1138 /* Initialize the SILC client */
1139 if (!silc_client_init(silc_client)) {
1144 /* Register SILC to the irssi */
1145 rec = g_new0(CHAT_PROTOCOL_REC, 1);
1147 rec->fullname = "Secure Internet Live Conferencing";
1148 rec->chatnet = "silcnet";
1149 rec->create_chatnet = create_chatnet;
1150 rec->create_server_setup = create_server_setup;
1151 rec->create_channel_setup = create_channel_setup;
1152 rec->create_server_connect = create_server_connect;
1153 rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *))
1154 silc_server_connect;
1155 rec->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, int))
1156 silc_channel_create;
1157 rec->query_create = (QUERY_REC *(*) (const char *, const char *, int))
1160 chat_protocol_register(rec);
1164 silc_channels_init();
1165 silc_queries_init();
1167 idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL);
1170 /* Deinit SILC. Called from src/fe-text/silc.c */
1172 void silc_core_deinit(void)
1174 if (idletag != -1) {
1175 signal_emit("chat protocol deinit", 1,
1176 chat_protocol_find("SILC"));
1178 silc_server_deinit();
1179 silc_channels_deinit();
1180 silc_queries_deinit();
1182 chat_protocol_unregister("SILC");
1184 g_source_remove(idletag);
1187 g_free(silc_client->username);
1188 g_free(silc_client->realname);
1189 silc_client_free(silc_client);