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:
560 printformat_module("fe-common/silc", server, NULL,
561 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
564 case SILC_COMMAND_SILCOPER:
565 printformat_module("fe-common/silc", server, NULL,
566 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
569 case SILC_COMMAND_USERS:
571 SilcChannelEntry channel;
577 channel = va_arg(vp, SilcChannelEntry);
579 printformat_module("fe-common/silc", server, channel->channel_name,
580 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
581 channel->channel_name);
583 silc_list_start(channel->clients);
584 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
585 SilcClientEntry e = chu->client;
588 memset(stat, 0, sizeof(stat));
589 mode = silc_client_chumode_char(chu->mode);
590 if (e->mode & SILC_UMODE_GONE)
597 printformat_module("fe-common/silc", server, channel->channel_name,
598 MSGLEVEL_CRAP, SILCTXT_USERS,
599 e->nickname, stat, e->username,
600 e->realname ? e->realname : "");
607 case SILC_COMMAND_BAN:
609 SilcChannelEntry channel;
615 channel = va_arg(vp, SilcChannelEntry);
616 ban_list = va_arg(vp, char *);
619 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
620 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
623 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
624 SILCTXT_CHANNEL_NO_BAN_LIST,
625 channel->channel_name);
629 case SILC_COMMAND_GETKEY:
633 SilcPublicKey public_key;
637 id_type = va_arg(vp, uint32);
638 entry = va_arg(vp, void *);
639 public_key = va_arg(vp, SilcPublicKey);
641 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
643 if (id_type == SILC_ID_CLIENT)
644 silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT,
645 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
650 case SILC_COMMAND_TOPIC:
652 SilcChannelEntry channel;
658 channel = va_arg(vp, SilcChannelEntry);
659 topic = va_arg(vp, char *);
662 chanrec = silc_channel_find_entry(server, channel);
664 g_free_not_null(chanrec->topic);
665 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
666 signal_emit("channel topic changed", 1, chanrec);
668 printformat_module("fe-common/silc", server, channel->channel_name,
669 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
670 channel->channel_name, topic);
680 /* Internal routine to verify public key. If the `completion' is provided
681 it will be called to indicate whether public was verified or not. */
685 SilcClientConnection conn;
690 SilcSKEPKType pk_type;
691 SilcVerifyPublicKey completion;
695 static void verify_public_key_completion(const char *line, void *context)
697 PublicKeyVerify verify = (PublicKeyVerify)context;
699 if (line[0] == 'Y' || line[0] == 'y') {
700 /* Call the completion */
701 if (verify->completion)
702 verify->completion(TRUE, verify->context);
704 /* Save the key for future checking */
705 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
706 verify->pk_len, SILC_PKCS_FILE_PEM);
708 /* Call the completion */
709 if (verify->completion)
710 verify->completion(FALSE, verify->context);
712 printformat_module("fe-common/silc", NULL, NULL,
713 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
716 silc_free(verify->filename);
717 silc_free(verify->entity);
718 silc_free(verify->pk);
723 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
724 SilcSocketType conn_type, unsigned char *pk,
725 uint32 pk_len, SilcSKEPKType pk_type,
726 SilcVerifyPublicKey completion, void *context)
729 char file[256], filename[256], *fingerprint, *format;
732 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
733 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
734 "server" : "client");
735 PublicKeyVerify verify;
737 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
738 printformat_module("fe-common/silc", NULL, NULL,
739 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
742 completion(FALSE, context);
746 pw = getpwuid(getuid());
749 completion(FALSE, context);
753 memset(filename, 0, sizeof(filename));
754 memset(file, 0, sizeof(file));
756 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
757 conn_type == SILC_SOCKET_TYPE_ROUTER) {
758 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
759 conn->sock->hostname, conn->sock->port);
760 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
761 pw->pw_dir, entity, file);
763 /* Replace all whitespaces with `_'. */
764 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
765 for (i = 0; i < strlen(fingerprint); i++)
766 if (fingerprint[i] == ' ')
767 fingerprint[i] = '_';
769 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
770 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
771 pw->pw_dir, entity, file);
772 silc_free(fingerprint);
775 /* Take fingerprint of the public key */
776 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
778 verify = silc_calloc(1, sizeof(*verify));
779 verify->client = client;
781 verify->filename = strdup(filename);
782 verify->entity = strdup(entity);
783 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
784 memcpy(verify->pk, pk, pk_len);
785 verify->pk_len = pk_len;
786 verify->pk_type = pk_type;
787 verify->completion = completion;
788 verify->context = context;
790 /* Check whether this key already exists */
791 if (stat(filename, &st) < 0) {
792 /* Key does not exist, ask user to verify the key and save it */
794 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
795 SILCTXT_PUBKEY_RECEIVED, entity);
796 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
797 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
798 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
799 SILCTXT_PUBKEY_ACCEPT);
800 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
803 silc_free(fingerprint);
806 /* The key already exists, verify it. */
807 SilcPublicKey public_key;
808 unsigned char *encpk;
811 /* Load the key file */
812 if (!silc_pkcs_load_public_key(filename, &public_key,
814 if (!silc_pkcs_load_public_key(filename, &public_key,
815 SILC_PKCS_FILE_BIN)) {
816 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
817 SILCTXT_PUBKEY_RECEIVED, entity);
818 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
819 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
820 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
821 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
822 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
823 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
824 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
827 silc_free(fingerprint);
831 /* Encode the key data */
832 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
834 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
835 SILCTXT_PUBKEY_RECEIVED, entity);
836 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
837 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
838 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
839 SILCTXT_PUBKEY_MALFORMED, entity);
840 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
841 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
842 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
845 silc_free(fingerprint);
849 /* Compare the keys */
850 if (memcmp(encpk, pk, encpk_len)) {
851 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
852 SILCTXT_PUBKEY_RECEIVED, entity);
853 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
854 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
855 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
856 SILCTXT_PUBKEY_NO_MATCH, entity);
857 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
858 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
859 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
860 SILCTXT_PUBKEY_MITM_ATTACK, entity);
862 /* Ask user to verify the key and save it */
863 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
864 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
865 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
868 silc_free(fingerprint);
872 /* Local copy matched */
874 completion(TRUE, context);
875 silc_free(fingerprint);
879 /* Verifies received public key. The `conn_type' indicates which entity
880 (server, client etc.) has sent the public key. If user decides to trust
881 the key may be saved as trusted public key for later use. The
882 `completion' must be called after the public key has been verified. */
885 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
886 SilcSocketType conn_type, unsigned char *pk,
887 uint32 pk_len, SilcSKEPKType pk_type,
888 SilcVerifyPublicKey completion, void *context)
890 silc_verify_public_key_internal(client, conn, conn_type, pk,
892 completion, context);
895 /* Asks passphrase from user on the input line. */
898 SilcAskPassphrase completion;
902 void ask_passphrase_completion(const char *passphrase, void *context)
904 AskPassphrase p = (AskPassphrase)context;
905 p->completion((unsigned char *)passphrase,
906 passphrase ? strlen(passphrase) : 0, p->context);
910 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
911 SilcAskPassphrase completion, void *context)
913 AskPassphrase p = silc_calloc(1, sizeof(*p));
914 p->completion = completion;
915 p->context = context;
917 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
918 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
921 /* Find authentication method and authentication data by hostname and
922 port. The hostname may be IP address as well. The found authentication
923 method and authentication data is returned to `auth_meth', `auth_data'
924 and `auth_data_len'. The function returns TRUE if authentication method
925 is found and FALSE if not. `conn' may be NULL. */
927 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
928 char *hostname, uint16 port,
929 SilcProtocolAuthMeth *auth_meth,
930 unsigned char **auth_data,
931 uint32 *auth_data_len)
934 /* XXX must resolve from configuration whether this connection has
935 any specific authentication data */
937 *auth_meth = SILC_AUTH_NONE;
944 /* Notifies application that failure packet was received. This is called
945 if there is some protocol active in the client. The `protocol' is the
946 protocol context. The `failure' is opaque pointer to the failure
947 indication. Note, that the `failure' is protocol dependant and application
948 must explicitly cast it to correct type. Usually `failure' is 32 bit
949 failure type (see protocol specs for all protocol failure types). */
951 void silc_failure(SilcClient client, SilcClientConnection conn,
952 SilcProtocol protocol, void *failure)
954 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
955 SilcSKEStatus status = (SilcSKEStatus)failure;
957 if (status == SILC_SKE_STATUS_BAD_VERSION)
958 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
959 SILCTXT_KE_BAD_VERSION);
960 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
961 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
962 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
963 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
964 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
965 SILCTXT_KE_UNKNOWN_GROUP);
966 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
967 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
968 SILCTXT_KE_UNKNOWN_CIPHER);
969 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
970 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
971 SILCTXT_KE_UNKNOWN_PKCS);
972 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
973 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
974 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
975 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
976 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
977 SILCTXT_KE_UNKNOWN_HMAC);
978 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
979 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
980 SILCTXT_KE_INCORRECT_SIGNATURE);
983 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
984 uint32 err = (uint32)failure;
986 if (err == SILC_AUTH_FAILED)
987 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
988 SILCTXT_AUTH_FAILED);
992 /* Asks whether the user would like to perform the key agreement protocol.
993 This is called after we have received an key agreement packet or an
994 reply to our key agreement packet. This returns TRUE if the user wants
995 the library to perform the key agreement protocol and FALSE if it is not
996 desired (application may start it later by calling the function
997 silc_client_perform_key_agreement). */
999 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1000 SilcClientEntry client_entry, char *hostname,
1002 SilcKeyAgreementCallback *completion,
1007 /* We will just display the info on the screen and return FALSE and user
1008 will have to start the key agreement with a command. */
1011 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1014 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1015 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1017 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1018 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1019 client_entry->nickname, hostname, portstr);
1027 /* SILC client operations */
1028 SilcClientOperations ops = {
1030 silc_channel_message,
1031 silc_private_message,
1037 silc_get_auth_method,
1038 silc_verify_public_key,
1039 silc_ask_passphrase,