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);
679 /* Internal routine to verify public key. If the `completion' is provided
680 it will be called to indicate whether public was verified or not. */
684 SilcClientConnection conn;
689 SilcSKEPKType pk_type;
690 SilcVerifyPublicKey completion;
694 static void verify_public_key_completion(const char *line, void *context)
696 PublicKeyVerify verify = (PublicKeyVerify)context;
698 if (line[0] == 'Y' || line[0] == 'y') {
699 /* Call the completion */
700 if (verify->completion)
701 verify->completion(TRUE, verify->context);
703 /* Save the key for future checking */
704 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
705 verify->pk_len, SILC_PKCS_FILE_PEM);
707 /* Call the completion */
708 if (verify->completion)
709 verify->completion(FALSE, verify->context);
711 printformat_module("fe-common/silc", NULL, NULL,
712 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
715 silc_free(verify->filename);
716 silc_free(verify->entity);
717 silc_free(verify->pk);
722 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
723 SilcSocketType conn_type, unsigned char *pk,
724 uint32 pk_len, SilcSKEPKType pk_type,
725 SilcVerifyPublicKey completion, void *context)
728 char file[256], filename[256], *fingerprint, *format;
731 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
732 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
733 "server" : "client");
734 PublicKeyVerify verify;
736 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
737 printformat_module("fe-common/silc", NULL, NULL,
738 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
741 completion(FALSE, context);
745 pw = getpwuid(getuid());
748 completion(FALSE, context);
752 memset(filename, 0, sizeof(filename));
753 memset(file, 0, sizeof(file));
755 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
756 conn_type == SILC_SOCKET_TYPE_ROUTER) {
757 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
758 conn->sock->hostname, conn->sock->port);
759 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
760 pw->pw_dir, entity, file);
762 /* Replace all whitespaces with `_'. */
763 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
764 for (i = 0; i < strlen(fingerprint); i++)
765 if (fingerprint[i] == ' ')
766 fingerprint[i] = '_';
768 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
769 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
770 pw->pw_dir, entity, file);
771 silc_free(fingerprint);
774 /* Take fingerprint of the public key */
775 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
777 verify = silc_calloc(1, sizeof(*verify));
778 verify->client = client;
780 verify->filename = strdup(filename);
781 verify->entity = strdup(entity);
782 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
783 memcpy(verify->pk, pk, pk_len);
784 verify->pk_len = pk_len;
785 verify->pk_type = pk_type;
786 verify->completion = completion;
787 verify->context = context;
789 /* Check whether this key already exists */
790 if (stat(filename, &st) < 0) {
791 /* Key does not exist, ask user to verify the key and save it */
793 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
794 SILCTXT_PUBKEY_RECEIVED, entity);
795 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
796 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
797 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
798 SILCTXT_PUBKEY_ACCEPT);
799 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
802 silc_free(fingerprint);
805 /* The key already exists, verify it. */
806 SilcPublicKey public_key;
807 unsigned char *encpk;
810 /* Load the key file */
811 if (!silc_pkcs_load_public_key(filename, &public_key,
813 if (!silc_pkcs_load_public_key(filename, &public_key,
814 SILC_PKCS_FILE_BIN)) {
815 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
816 SILCTXT_PUBKEY_RECEIVED, entity);
817 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
818 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
819 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
820 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
821 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
822 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
823 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
826 silc_free(fingerprint);
830 /* Encode the key data */
831 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
833 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
834 SILCTXT_PUBKEY_RECEIVED, entity);
835 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
836 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
837 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
838 SILCTXT_PUBKEY_MALFORMED, entity);
839 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
840 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
841 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
844 silc_free(fingerprint);
848 /* Compare the keys */
849 if (memcmp(encpk, pk, encpk_len)) {
850 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
851 SILCTXT_PUBKEY_RECEIVED, entity);
852 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
853 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
854 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
855 SILCTXT_PUBKEY_NO_MATCH, entity);
856 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
857 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
858 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
859 SILCTXT_PUBKEY_MITM_ATTACK, entity);
861 /* Ask user to verify the key and save it */
862 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
863 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
864 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
867 silc_free(fingerprint);
871 /* Local copy matched */
873 completion(TRUE, context);
874 silc_free(fingerprint);
878 /* Verifies received public key. The `conn_type' indicates which entity
879 (server, client etc.) has sent the public key. If user decides to trust
880 the key may be saved as trusted public key for later use. The
881 `completion' must be called after the public key has been verified. */
884 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
885 SilcSocketType conn_type, unsigned char *pk,
886 uint32 pk_len, SilcSKEPKType pk_type,
887 SilcVerifyPublicKey completion, void *context)
889 silc_verify_public_key_internal(client, conn, conn_type, pk,
891 completion, context);
894 /* Asks passphrase from user on the input line. */
897 SilcAskPassphrase completion;
901 void ask_passphrase_completion(const char *passphrase, void *context)
903 AskPassphrase p = (AskPassphrase)context;
904 p->completion((unsigned char *)passphrase,
905 passphrase ? strlen(passphrase) : 0, p->context);
909 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
910 SilcAskPassphrase completion, void *context)
912 AskPassphrase p = silc_calloc(1, sizeof(*p));
913 p->completion = completion;
914 p->context = context;
916 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
917 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
920 /* Find authentication method and authentication data by hostname and
921 port. The hostname may be IP address as well. The found authentication
922 method and authentication data is returned to `auth_meth', `auth_data'
923 and `auth_data_len'. The function returns TRUE if authentication method
924 is found and FALSE if not. `conn' may be NULL. */
926 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
927 char *hostname, uint16 port,
928 SilcProtocolAuthMeth *auth_meth,
929 unsigned char **auth_data,
930 uint32 *auth_data_len)
933 /* XXX must resolve from configuration whether this connection has
934 any specific authentication data */
936 *auth_meth = SILC_AUTH_NONE;
943 /* Notifies application that failure packet was received. This is called
944 if there is some protocol active in the client. The `protocol' is the
945 protocol context. The `failure' is opaque pointer to the failure
946 indication. Note, that the `failure' is protocol dependant and application
947 must explicitly cast it to correct type. Usually `failure' is 32 bit
948 failure type (see protocol specs for all protocol failure types). */
950 void silc_failure(SilcClient client, SilcClientConnection conn,
951 SilcProtocol protocol, void *failure)
953 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
954 SilcSKEStatus status = (SilcSKEStatus)failure;
956 if (status == SILC_SKE_STATUS_BAD_VERSION)
957 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
958 SILCTXT_KE_BAD_VERSION);
959 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
960 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
961 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
962 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
963 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
964 SILCTXT_KE_UNKNOWN_GROUP);
965 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
966 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
967 SILCTXT_KE_UNKNOWN_CIPHER);
968 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
969 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
970 SILCTXT_KE_UNKNOWN_PKCS);
971 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
972 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
973 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
974 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
975 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
976 SILCTXT_KE_UNKNOWN_HMAC);
977 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
978 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
979 SILCTXT_KE_INCORRECT_SIGNATURE);
982 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
983 uint32 err = (uint32)failure;
985 if (err == SILC_AUTH_FAILED)
986 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
987 SILCTXT_AUTH_FAILED);
991 /* Asks whether the user would like to perform the key agreement protocol.
992 This is called after we have received an key agreement packet or an
993 reply to our key agreement packet. This returns TRUE if the user wants
994 the library to perform the key agreement protocol and FALSE if it is not
995 desired (application may start it later by calling the function
996 silc_client_perform_key_agreement). */
998 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
999 SilcClientEntry client_entry, char *hostname,
1001 SilcKeyAgreementCallback *completion,
1006 /* We will just display the info on the screen and return FALSE and user
1007 will have to start the key agreement with a command. */
1010 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1013 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1014 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1016 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1017 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1018 client_entry->nickname, hostname, portstr);
1026 /* SILC client operations */
1027 SilcClientOperations ops = {
1029 silc_channel_message,
1030 silc_private_message,
1036 silc_get_auth_method,
1037 silc_verify_public_key,
1038 silc_ask_passphrase,