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"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
42 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
43 SilcSocketType conn_type, unsigned char *pk,
44 uint32 pk_len, SilcSKEPKType pk_type,
45 SilcVerifyPublicKey completion, void *context);
47 void silc_say(SilcClient client, SilcClientConnection conn,
50 SILC_SERVER_REC *server;
54 server = conn == NULL ? NULL : conn->context;
57 str = g_strdup_vprintf(msg, va);
58 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
63 void silc_say_error(char *msg, ...)
69 str = g_strdup_vprintf(msg, va);
70 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
76 /* Message for a channel. The `sender' is the nickname of the sender
77 received in the packet. The `channel_name' is the name of the channel. */
79 void silc_channel_message(SilcClient client, SilcClientConnection conn,
80 SilcClientEntry sender, SilcChannelEntry channel,
81 SilcMessageFlags flags, char *msg)
83 SILC_SERVER_REC *server;
85 SILC_CHANNEL_REC *chanrec;
87 server = conn == NULL ? NULL : conn->context;
88 chanrec = silc_channel_find_entry(server, channel);
90 nick = silc_nicklist_find(chanrec, sender);
92 if (flags & SILC_MESSAGE_FLAG_ACTION)
93 printformat_module("fe-common/silc", server, channel->channel_name,
94 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, msg);
95 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
96 printformat_module("fe-common/silc", server, channel->channel_name,
97 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, msg);
99 signal_emit("message public", 6, server, msg,
100 nick == NULL ? "[<unknown>]" : nick->nick,
101 nick == NULL ? NULL : nick->host,
102 chanrec->name, nick);
105 /* Private message to the client. The `sender' is the nickname of the
106 sender received in the packet. */
108 void silc_private_message(SilcClient client, SilcClientConnection conn,
109 SilcClientEntry sender, SilcMessageFlags flags,
112 SILC_SERVER_REC *server;
114 server = conn == NULL ? NULL : conn->context;
115 signal_emit("message private", 4, server, msg,
116 sender->nickname ? sender->nickname : "[<unknown>]",
117 sender->username ? sender->username : NULL);
120 /* Notify message to the client. The notify arguments are sent in the
121 same order as servers sends them. The arguments are same as received
122 from the server except for ID's. If ID is received application receives
123 the corresponding entry to the ID. For example, if Client ID is received
124 application receives SilcClientEntry. Also, if the notify type is
125 for channel the channel entry is sent to application (even if server
126 does not send it). */
133 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
134 static NOTIFY_REC notifies[] = {
135 { SILC_NOTIFY_TYPE_NONE, NULL },
136 { SILC_NOTIFY_TYPE_INVITE, "invite" },
137 { SILC_NOTIFY_TYPE_JOIN, "join" },
138 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
139 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
140 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
141 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
142 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
143 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
144 { SILC_NOTIFY_TYPE_MOTD, "motd" },
145 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
146 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
147 { SILC_NOTIFY_TYPE_KICKED, "kick" },
148 { SILC_NOTIFY_TYPE_KILLED, "kill" },
149 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
150 { SILC_NOTIFY_TYPE_BAN, "ban" },
153 void silc_notify(SilcClient client, SilcClientConnection conn,
154 SilcNotifyType type, ...)
156 SILC_SERVER_REC *server;
159 server = conn == NULL ? NULL : conn->context;
162 if (type == SILC_NOTIFY_TYPE_NONE) {
163 /* Some generic notice from server */
164 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
165 } else if (type < MAX_NOTIFY) {
166 /* Send signal about the notify event */
168 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
169 signal_emit(signal, 2, server, va);
172 printformat_module("fe-common/silc", server, NULL,
173 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
179 /* Called to indicate that connection was either successfully established
180 or connecting failed. This is also the first time application receives
181 the SilcClientConnection objecet which it should save somewhere. */
183 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
185 SILC_SERVER_REC *server = conn->context;
188 server->connected = TRUE;
189 signal_emit("event connected", 1, server);
191 server->connection_lost = TRUE;
192 server->conn->context = NULL;
193 server_disconnect(SERVER(server));
197 /* Called to indicate that connection was disconnected to the server. */
199 void silc_disconnect(SilcClient client, SilcClientConnection conn)
201 SILC_SERVER_REC *server = conn->context;
203 server->conn->context = NULL;
205 server->connection_lost = TRUE;
206 server_disconnect(SERVER(server));
209 /* Command handler. This function is called always in the command function.
210 If error occurs it will be called as well. `conn' is the associated
211 client connection. `cmd_context' is the command context that was
212 originally sent to the command. `success' is FALSE if error occured
213 during command. `command' is the command being processed. It must be
214 noted that this is not reply from server. This is merely called just
215 after application has called the command. Just to tell application
216 that the command really was processed. */
218 void silc_command(SilcClient client, SilcClientConnection conn,
219 SilcClientCommandContext cmd_context, int success,
224 /* Client info resolving callback when JOIN command reply is received.
225 This will cache all users on the channel. */
227 static void silc_client_join_get_users(SilcClient client,
228 SilcClientConnection conn,
229 SilcClientEntry *clients,
230 uint32 clients_count,
233 SilcChannelEntry channel = (SilcChannelEntry)context;
235 SILC_SERVER_REC *server = conn->context;
236 SILC_CHANNEL_REC *chanrec;
237 SilcClientEntry founder = NULL;
243 chanrec = silc_channel_find(server, channel->channel_name);
247 silc_list_start(channel->clients);
248 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
249 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
250 founder = chu->client;
251 silc_nicklist_insert(chanrec, chu, FALSE);
254 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
255 nicklist_set_own(CHANNEL(chanrec), ownnick);
256 signal_emit("channel joined", 1, chanrec);
259 printformat_module("fe-common/silc", server, channel->channel_name,
260 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
261 channel->channel_name, chanrec->topic);
263 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
266 if (founder == conn->local_entry)
267 printformat_module("fe-common/silc",
268 server, channel->channel_name, MSGLEVEL_CRAP,
269 SILCTXT_CHANNEL_FOUNDER_YOU,
270 channel->channel_name);
272 printformat_module("fe-common/silc",
273 server, channel->channel_name, MSGLEVEL_CRAP,
274 SILCTXT_CHANNEL_FOUNDER,
275 channel->channel_name, founder->nickname);
279 /* Command reply handler. This function is called always in the command reply
280 function. If error occurs it will be called as well. Normal scenario
281 is that it will be called after the received command data has been parsed
282 and processed. The function is used to pass the received command data to
285 `conn' is the associated client connection. `cmd_payload' is the command
286 payload data received from server and it can be ignored. It is provided
287 if the application would like to re-parse the received command data,
288 however, it must be noted that the data is parsed already by the library
289 thus the payload can be ignored. `success' is FALSE if error occured.
290 In this case arguments are not sent to the application. `command' is the
291 command reply being processed. The function has variable argument list
292 and each command defines the number and type of arguments it passes to the
293 application (on error they are not sent). */
296 silc_command_reply(SilcClient client, SilcClientConnection conn,
297 SilcCommandPayload cmd_payload, int success,
298 SilcCommand command, SilcCommandStatus status, ...)
301 SILC_SERVER_REC *server = conn->context;
302 SILC_CHANNEL_REC *chanrec;
305 va_start(vp, status);
308 case SILC_COMMAND_WHOIS:
310 char buf[1024], *nickname, *username, *realname;
314 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
315 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
317 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
320 silc_say_error("%s: %s", tmp,
321 silc_client_command_status_message(status));
323 silc_say_error("%s", silc_client_command_status_message(status));
330 (void)va_arg(vp, SilcClientEntry);
331 nickname = va_arg(vp, char *);
332 username = va_arg(vp, char *);
333 realname = va_arg(vp, char *);
334 channels = va_arg(vp, SilcBuffer);
335 mode = va_arg(vp, uint32);
336 idle = va_arg(vp, uint32);
338 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
339 SILCTXT_WHOIS_USERINFO, nickname, username,
343 SilcDList list = silc_channel_payload_parse_list(channels);
345 SilcChannelPayload entry;
346 memset(buf, 0, sizeof(buf));
347 silc_dlist_start(list);
348 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
349 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
351 char *name = silc_channel_get_name(entry, &name_len);
354 strncat(buf, m, strlen(m));
355 strncat(buf, name, name_len);
356 strncat(buf, " ", 1);
360 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
361 SILCTXT_WHOIS_CHANNELS, buf);
362 silc_channel_payload_list_free(list);
367 memset(buf, 0, sizeof(buf));
369 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
370 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
371 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
373 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
374 "SILC Operator " : "[Unknown mode] ");
376 if (mode & SILC_UMODE_GONE)
379 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
380 SILCTXT_WHOIS_MODES, buf);
383 if (idle && nickname) {
384 memset(buf, 0, sizeof(buf));
385 snprintf(buf, sizeof(buf) - 1, "%lu %s",
386 idle > 60 ? (idle / 60) : idle,
387 idle > 60 ? "minutes" : "seconds");
389 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
390 SILCTXT_WHOIS_IDLE, buf);
395 case SILC_COMMAND_WHOWAS:
397 char *nickname, *username, *realname;
399 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
400 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
402 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
405 silc_say_error("%s: %s", tmp,
406 silc_client_command_status_message(status));
408 silc_say_error("%s", silc_client_command_status_message(status));
415 (void)va_arg(vp, SilcClientEntry);
416 nickname = va_arg(vp, char *);
417 username = va_arg(vp, char *);
418 realname = va_arg(vp, char *);
420 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
421 SILCTXT_WHOWAS_USERINFO, nickname, username,
422 realname ? realname : "");
426 case SILC_COMMAND_INVITE:
428 SilcChannelEntry channel;
434 channel = va_arg(vp, SilcChannelEntry);
435 invite_list = va_arg(vp, char *);
438 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
439 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
442 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
443 SILCTXT_CHANNEL_NO_INVITE_LIST,
444 channel->channel_name);
448 case SILC_COMMAND_JOIN:
450 char *channel, *mode, *topic;
452 SilcChannelEntry channel_entry;
453 SilcBuffer client_id_list;
456 channel = va_arg(vp, char *);
457 channel_entry = va_arg(vp, SilcChannelEntry);
458 modei = va_arg(vp, uint32);
459 (void)va_arg(vp, uint32);
460 (void)va_arg(vp, unsigned char *);
461 (void)va_arg(vp, unsigned char *);
462 (void)va_arg(vp, unsigned char *);
463 topic = va_arg(vp, char *);
464 (void)va_arg(vp, unsigned char *);
465 list_count = va_arg(vp, uint32);
466 client_id_list = va_arg(vp, SilcBuffer);
471 chanrec = silc_channel_find(server, channel);
472 if (chanrec != NULL && !success)
473 channel_destroy(CHANNEL(chanrec));
474 else if (chanrec == NULL && success)
475 chanrec = silc_channel_create(server, channel, TRUE);
478 g_free_not_null(chanrec->topic);
479 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
480 signal_emit("channel topic changed", 1, chanrec);
483 mode = silc_client_chmode(modei, channel_entry);
484 g_free_not_null(chanrec->mode);
485 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
486 signal_emit("channel mode changed", 1, chanrec);
488 /* Resolve the client information */
489 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
490 silc_client_join_get_users,
495 case SILC_COMMAND_NICK:
497 SilcClientEntry client = va_arg(vp, SilcClientEntry);
503 old = g_strdup(server->nick);
504 server_change_nick(SERVER(server), client->nickname);
505 nicklist_rename_unique(SERVER(server),
506 server->conn->local_entry, server->nick,
507 client, client->nickname);
509 signal_emit("message own_nick", 4, server, server->nick, old, "");
514 case SILC_COMMAND_LIST:
523 (void)va_arg(vp, SilcChannelEntry);
524 name = va_arg(vp, char *);
525 topic = va_arg(vp, char *);
526 usercount = va_arg(vp, int);
528 if (status == SILC_STATUS_LIST_START ||
529 status == SILC_STATUS_OK)
530 printformat_module("fe-common/silc", server, NULL,
531 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
533 snprintf(users, sizeof(users) - 1, "%d", usercount);
534 printformat_module("fe-common/silc", server, NULL,
535 MSGLEVEL_CRAP, SILCTXT_LIST,
536 name, users, topic ? topic : "");
540 case SILC_COMMAND_UMODE:
547 mode = va_arg(vp, uint32);
549 if (mode & SILC_UMODE_SERVER_OPERATOR)
550 printformat_module("fe-common/silc", server, NULL,
551 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
553 if (mode & SILC_UMODE_ROUTER_OPERATOR)
554 printformat_module("fe-common/silc", server, NULL,
555 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
559 case SILC_COMMAND_OPER:
563 printformat_module("fe-common/silc", server, NULL,
564 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
567 case SILC_COMMAND_SILCOPER:
571 printformat_module("fe-common/silc", server, NULL,
572 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
575 case SILC_COMMAND_USERS:
577 SilcChannelEntry channel;
583 channel = va_arg(vp, SilcChannelEntry);
585 printformat_module("fe-common/silc", server, channel->channel_name,
586 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
587 channel->channel_name);
589 silc_list_start(channel->clients);
590 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
591 SilcClientEntry e = chu->client;
594 memset(stat, 0, sizeof(stat));
595 mode = silc_client_chumode_char(chu->mode);
596 if (e->mode & SILC_UMODE_GONE)
603 printformat_module("fe-common/silc", server, channel->channel_name,
604 MSGLEVEL_CRAP, SILCTXT_USERS,
605 e->nickname, stat, e->username,
606 e->realname ? e->realname : "");
613 case SILC_COMMAND_BAN:
615 SilcChannelEntry channel;
621 channel = va_arg(vp, SilcChannelEntry);
622 ban_list = va_arg(vp, char *);
625 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
626 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
629 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
630 SILCTXT_CHANNEL_NO_BAN_LIST,
631 channel->channel_name);
635 case SILC_COMMAND_GETKEY:
639 SilcPublicKey public_key;
643 id_type = va_arg(vp, uint32);
644 entry = va_arg(vp, void *);
645 public_key = va_arg(vp, SilcPublicKey);
647 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
649 if (id_type == SILC_ID_CLIENT)
650 silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT,
651 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
656 case SILC_COMMAND_TOPIC:
658 SilcChannelEntry channel;
664 channel = va_arg(vp, SilcChannelEntry);
665 topic = va_arg(vp, char *);
668 chanrec = silc_channel_find_entry(server, channel);
670 g_free_not_null(chanrec->topic);
671 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
672 signal_emit("channel topic changed", 1, chanrec);
674 printformat_module("fe-common/silc", server, channel->channel_name,
675 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
676 channel->channel_name, topic);
686 /* Internal routine to verify public key. If the `completion' is provided
687 it will be called to indicate whether public was verified or not. */
691 SilcClientConnection conn;
696 SilcSKEPKType pk_type;
697 SilcVerifyPublicKey completion;
701 static void verify_public_key_completion(const char *line, void *context)
703 PublicKeyVerify verify = (PublicKeyVerify)context;
705 if (line[0] == 'Y' || line[0] == 'y') {
706 /* Call the completion */
707 if (verify->completion)
708 verify->completion(TRUE, verify->context);
710 /* Save the key for future checking */
711 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
712 verify->pk_len, SILC_PKCS_FILE_PEM);
714 /* Call the completion */
715 if (verify->completion)
716 verify->completion(FALSE, verify->context);
718 printformat_module("fe-common/silc", NULL, NULL,
719 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
722 silc_free(verify->filename);
723 silc_free(verify->entity);
724 silc_free(verify->pk);
729 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
730 SilcSocketType conn_type, unsigned char *pk,
731 uint32 pk_len, SilcSKEPKType pk_type,
732 SilcVerifyPublicKey completion, void *context)
735 char file[256], filename[256], *fingerprint, *format;
738 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
739 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
740 "server" : "client");
741 PublicKeyVerify verify;
743 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
744 printformat_module("fe-common/silc", NULL, NULL,
745 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
748 completion(FALSE, context);
752 pw = getpwuid(getuid());
755 completion(FALSE, context);
759 memset(filename, 0, sizeof(filename));
760 memset(file, 0, sizeof(file));
762 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
763 conn_type == SILC_SOCKET_TYPE_ROUTER) {
764 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
765 conn->sock->hostname, conn->sock->port);
766 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
767 pw->pw_dir, entity, file);
769 /* Replace all whitespaces with `_'. */
770 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
771 for (i = 0; i < strlen(fingerprint); i++)
772 if (fingerprint[i] == ' ')
773 fingerprint[i] = '_';
775 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
776 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
777 pw->pw_dir, entity, file);
778 silc_free(fingerprint);
781 /* Take fingerprint of the public key */
782 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
784 verify = silc_calloc(1, sizeof(*verify));
785 verify->client = client;
787 verify->filename = strdup(filename);
788 verify->entity = strdup(entity);
789 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
790 memcpy(verify->pk, pk, pk_len);
791 verify->pk_len = pk_len;
792 verify->pk_type = pk_type;
793 verify->completion = completion;
794 verify->context = context;
796 /* Check whether this key already exists */
797 if (stat(filename, &st) < 0) {
798 /* Key does not exist, ask user to verify the key and save it */
800 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
801 SILCTXT_PUBKEY_RECEIVED, entity);
802 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
803 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
804 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
805 SILCTXT_PUBKEY_ACCEPT);
806 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
809 silc_free(fingerprint);
812 /* The key already exists, verify it. */
813 SilcPublicKey public_key;
814 unsigned char *encpk;
817 /* Load the key file */
818 if (!silc_pkcs_load_public_key(filename, &public_key,
820 if (!silc_pkcs_load_public_key(filename, &public_key,
821 SILC_PKCS_FILE_BIN)) {
822 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
823 SILCTXT_PUBKEY_RECEIVED, entity);
824 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
825 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
826 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
827 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
828 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
829 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
830 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
833 silc_free(fingerprint);
837 /* Encode the key data */
838 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
840 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
841 SILCTXT_PUBKEY_RECEIVED, entity);
842 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
843 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
844 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
845 SILCTXT_PUBKEY_MALFORMED, entity);
846 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
847 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
848 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
851 silc_free(fingerprint);
855 /* Compare the keys */
856 if (memcmp(encpk, pk, encpk_len)) {
857 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
858 SILCTXT_PUBKEY_RECEIVED, entity);
859 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
860 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
861 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
862 SILCTXT_PUBKEY_NO_MATCH, entity);
863 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
864 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
865 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
866 SILCTXT_PUBKEY_MITM_ATTACK, entity);
868 /* Ask user to verify the key and save it */
869 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
870 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
871 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
874 silc_free(fingerprint);
878 /* Local copy matched */
880 completion(TRUE, context);
881 silc_free(fingerprint);
885 /* Verifies received public key. The `conn_type' indicates which entity
886 (server, client etc.) has sent the public key. If user decides to trust
887 the key may be saved as trusted public key for later use. The
888 `completion' must be called after the public key has been verified. */
891 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
892 SilcSocketType conn_type, unsigned char *pk,
893 uint32 pk_len, SilcSKEPKType pk_type,
894 SilcVerifyPublicKey completion, void *context)
896 silc_verify_public_key_internal(client, conn, conn_type, pk,
898 completion, context);
901 /* Asks passphrase from user on the input line. */
904 SilcAskPassphrase completion;
908 void ask_passphrase_completion(const char *passphrase, void *context)
910 AskPassphrase p = (AskPassphrase)context;
911 p->completion((unsigned char *)passphrase,
912 passphrase ? strlen(passphrase) : 0, p->context);
916 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
917 SilcAskPassphrase completion, void *context)
919 AskPassphrase p = silc_calloc(1, sizeof(*p));
920 p->completion = completion;
921 p->context = context;
923 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
924 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
927 /* Find authentication method and authentication data by hostname and
928 port. The hostname may be IP address as well. The found authentication
929 method and authentication data is returned to `auth_meth', `auth_data'
930 and `auth_data_len'. The function returns TRUE if authentication method
931 is found and FALSE if not. `conn' may be NULL. */
933 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
934 char *hostname, uint16 port,
935 SilcProtocolAuthMeth *auth_meth,
936 unsigned char **auth_data,
937 uint32 *auth_data_len)
940 SILC_SERVER_REC *server = conn ? conn->context : NULL;
942 /* XXX must resolve from configuration whether this connection has
943 any specific authentication data */
945 *auth_meth = SILC_AUTH_NONE;
950 printformat_module("fe-common/silc", server, NULL,
951 MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED);
957 /* Notifies application that failure packet was received. This is called
958 if there is some protocol active in the client. The `protocol' is the
959 protocol context. The `failure' is opaque pointer to the failure
960 indication. Note, that the `failure' is protocol dependant and application
961 must explicitly cast it to correct type. Usually `failure' is 32 bit
962 failure type (see protocol specs for all protocol failure types). */
964 void silc_failure(SilcClient client, SilcClientConnection conn,
965 SilcProtocol protocol, void *failure)
967 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
968 SilcSKEStatus status = (SilcSKEStatus)failure;
970 if (status == SILC_SKE_STATUS_BAD_VERSION)
971 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
972 SILCTXT_KE_BAD_VERSION);
973 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
974 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
975 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
976 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
977 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
978 SILCTXT_KE_UNKNOWN_GROUP);
979 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
980 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
981 SILCTXT_KE_UNKNOWN_CIPHER);
982 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
983 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
984 SILCTXT_KE_UNKNOWN_PKCS);
985 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
986 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
987 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
988 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
989 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
990 SILCTXT_KE_UNKNOWN_HMAC);
991 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
992 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
993 SILCTXT_KE_INCORRECT_SIGNATURE);
996 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
997 uint32 err = (uint32)failure;
999 if (err == SILC_AUTH_FAILED)
1000 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1001 SILCTXT_AUTH_FAILED);
1005 /* Asks whether the user would like to perform the key agreement protocol.
1006 This is called after we have received an key agreement packet or an
1007 reply to our key agreement packet. This returns TRUE if the user wants
1008 the library to perform the key agreement protocol and FALSE if it is not
1009 desired (application may start it later by calling the function
1010 silc_client_perform_key_agreement). */
1012 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1013 SilcClientEntry client_entry, char *hostname,
1015 SilcKeyAgreementCallback *completion,
1020 /* We will just display the info on the screen and return FALSE and user
1021 will have to start the key agreement with a command. */
1024 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1027 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1028 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1030 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1031 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1032 client_entry->nickname, hostname, portstr);
1040 /* SILC client operations */
1041 SilcClientOperations ops = {
1043 silc_channel_message,
1044 silc_private_message,
1050 silc_get_auth_method,
1051 silc_verify_public_key,
1052 silc_ask_passphrase,