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);
92 nick = silc_nicklist_find(chanrec, sender);
94 if (flags & SILC_MESSAGE_FLAG_ACTION)
95 printformat_module("fe-common/silc", server, channel->channel_name,
96 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, msg);
97 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
98 printformat_module("fe-common/silc", server, channel->channel_name,
99 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, msg);
101 signal_emit("message public", 6, server, msg,
102 nick == NULL ? "[<unknown>]" : nick->nick,
103 nick == NULL ? NULL : nick->host,
104 chanrec->name, nick);
107 /* Private message to the client. The `sender' is the nickname of the
108 sender received in the packet. */
110 void silc_private_message(SilcClient client, SilcClientConnection conn,
111 SilcClientEntry sender, SilcMessageFlags flags,
114 SILC_SERVER_REC *server;
116 server = conn == NULL ? NULL : conn->context;
117 signal_emit("message private", 4, server, msg,
118 sender->nickname ? sender->nickname : "[<unknown>]",
119 sender->username ? sender->username : NULL);
122 /* Notify message to the client. The notify arguments are sent in the
123 same order as servers sends them. The arguments are same as received
124 from the server except for ID's. If ID is received application receives
125 the corresponding entry to the ID. For example, if Client ID is received
126 application receives SilcClientEntry. Also, if the notify type is
127 for channel the channel entry is sent to application (even if server
128 does not send it). */
135 #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
136 static NOTIFY_REC notifies[] = {
137 { SILC_NOTIFY_TYPE_NONE, NULL },
138 { SILC_NOTIFY_TYPE_INVITE, "invite" },
139 { SILC_NOTIFY_TYPE_JOIN, "join" },
140 { SILC_NOTIFY_TYPE_LEAVE, "leave" },
141 { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
142 { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
143 { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
144 { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
145 { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
146 { SILC_NOTIFY_TYPE_MOTD, "motd" },
147 { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
148 { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
149 { SILC_NOTIFY_TYPE_KICKED, "kick" },
150 { SILC_NOTIFY_TYPE_KILLED, "kill" },
151 { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
152 { SILC_NOTIFY_TYPE_BAN, "ban" },
155 void silc_notify(SilcClient client, SilcClientConnection conn,
156 SilcNotifyType type, ...)
158 SILC_SERVER_REC *server;
161 server = conn == NULL ? NULL : conn->context;
164 if (type == SILC_NOTIFY_TYPE_NONE) {
165 /* Some generic notice from server */
166 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
167 } else if (type < MAX_NOTIFY) {
168 /* Send signal about the notify event */
170 g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
171 signal_emit(signal, 2, server, va);
174 printformat_module("fe-common/silc", server, NULL,
175 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
181 /* Called to indicate that connection was either successfully established
182 or connecting failed. This is also the first time application receives
183 the SilcClientConnection objecet which it should save somewhere. */
185 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
187 SILC_SERVER_REC *server = conn->context;
190 server->connected = TRUE;
191 signal_emit("event connected", 1, server);
193 server->connection_lost = TRUE;
194 server->conn->context = NULL;
195 server_disconnect(SERVER(server));
199 /* Called to indicate that connection was disconnected to the server. */
201 void silc_disconnect(SilcClient client, SilcClientConnection conn)
203 SILC_SERVER_REC *server = conn->context;
205 server->conn->context = NULL;
207 server->connection_lost = TRUE;
208 server_disconnect(SERVER(server));
211 /* Command handler. This function is called always in the command function.
212 If error occurs it will be called as well. `conn' is the associated
213 client connection. `cmd_context' is the command context that was
214 originally sent to the command. `success' is FALSE if error occured
215 during command. `command' is the command being processed. It must be
216 noted that this is not reply from server. This is merely called just
217 after application has called the command. Just to tell application
218 that the command really was processed. */
220 void silc_command(SilcClient client, SilcClientConnection conn,
221 SilcClientCommandContext cmd_context, int success,
226 /* Client info resolving callback when JOIN command reply is received.
227 This will cache all users on the channel. */
229 static void silc_client_join_get_users(SilcClient client,
230 SilcClientConnection conn,
231 SilcClientEntry *clients,
232 uint32 clients_count,
235 SilcChannelEntry channel = (SilcChannelEntry)context;
237 SILC_SERVER_REC *server = conn->context;
238 SILC_CHANNEL_REC *chanrec;
239 SilcClientEntry founder = NULL;
245 chanrec = silc_channel_find(server, channel->channel_name);
249 silc_list_start(channel->clients);
250 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
251 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
252 founder = chu->client;
253 silc_nicklist_insert(chanrec, chu, FALSE);
256 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
257 nicklist_set_own(CHANNEL(chanrec), ownnick);
258 signal_emit("channel joined", 1, chanrec);
261 printformat_module("fe-common/silc", server, channel->channel_name,
262 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
263 channel->channel_name, chanrec->topic);
265 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
268 if (founder == conn->local_entry)
269 printformat_module("fe-common/silc",
270 server, channel->channel_name, MSGLEVEL_CRAP,
271 SILCTXT_CHANNEL_FOUNDER_YOU,
272 channel->channel_name);
274 printformat_module("fe-common/silc",
275 server, channel->channel_name, MSGLEVEL_CRAP,
276 SILCTXT_CHANNEL_FOUNDER,
277 channel->channel_name, founder->nickname);
281 /* Command reply handler. This function is called always in the command reply
282 function. If error occurs it will be called as well. Normal scenario
283 is that it will be called after the received command data has been parsed
284 and processed. The function is used to pass the received command data to
287 `conn' is the associated client connection. `cmd_payload' is the command
288 payload data received from server and it can be ignored. It is provided
289 if the application would like to re-parse the received command data,
290 however, it must be noted that the data is parsed already by the library
291 thus the payload can be ignored. `success' is FALSE if error occured.
292 In this case arguments are not sent to the application. `command' is the
293 command reply being processed. The function has variable argument list
294 and each command defines the number and type of arguments it passes to the
295 application (on error they are not sent). */
298 silc_command_reply(SilcClient client, SilcClientConnection conn,
299 SilcCommandPayload cmd_payload, int success,
300 SilcCommand command, SilcCommandStatus status, ...)
303 SILC_SERVER_REC *server = conn->context;
304 SILC_CHANNEL_REC *chanrec;
307 va_start(vp, status);
310 case SILC_COMMAND_WHOIS:
312 char buf[1024], *nickname, *username, *realname;
316 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
317 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
319 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
322 silc_say_error("%s: %s", tmp,
323 silc_client_command_status_message(status));
325 silc_say_error("%s", silc_client_command_status_message(status));
332 (void)va_arg(vp, SilcClientEntry);
333 nickname = va_arg(vp, char *);
334 username = va_arg(vp, char *);
335 realname = va_arg(vp, char *);
336 channels = va_arg(vp, SilcBuffer);
337 mode = va_arg(vp, uint32);
338 idle = va_arg(vp, uint32);
340 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
341 SILCTXT_WHOIS_USERINFO, nickname, username,
345 SilcDList list = silc_channel_payload_parse_list(channels);
347 SilcChannelPayload entry;
348 memset(buf, 0, sizeof(buf));
349 silc_dlist_start(list);
350 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
351 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
353 char *name = silc_channel_get_name(entry, &name_len);
356 strncat(buf, m, strlen(m));
357 strncat(buf, name, name_len);
358 strncat(buf, " ", 1);
362 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
363 SILCTXT_WHOIS_CHANNELS, buf);
364 silc_channel_payload_list_free(list);
369 memset(buf, 0, sizeof(buf));
371 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
372 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
373 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
375 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
376 "SILC Operator " : "[Unknown mode] ");
378 if (mode & SILC_UMODE_GONE)
381 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
382 SILCTXT_WHOIS_MODES, buf);
385 if (idle && nickname) {
386 memset(buf, 0, sizeof(buf));
387 snprintf(buf, sizeof(buf) - 1, "%lu %s",
388 idle > 60 ? (idle / 60) : idle,
389 idle > 60 ? "minutes" : "seconds");
391 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
392 SILCTXT_WHOIS_IDLE, buf);
397 case SILC_COMMAND_WHOWAS:
399 char *nickname, *username, *realname;
401 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
402 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
404 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
407 silc_say_error("%s: %s", tmp,
408 silc_client_command_status_message(status));
410 silc_say_error("%s", silc_client_command_status_message(status));
417 (void)va_arg(vp, SilcClientEntry);
418 nickname = va_arg(vp, char *);
419 username = va_arg(vp, char *);
420 realname = va_arg(vp, char *);
422 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
423 SILCTXT_WHOWAS_USERINFO, nickname, username,
424 realname ? realname : "");
428 case SILC_COMMAND_INVITE:
430 SilcChannelEntry channel;
436 channel = va_arg(vp, SilcChannelEntry);
437 invite_list = va_arg(vp, char *);
440 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
441 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
444 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
445 SILCTXT_CHANNEL_NO_INVITE_LIST,
446 channel->channel_name);
450 case SILC_COMMAND_JOIN:
452 char *channel, *mode, *topic;
454 SilcChannelEntry channel_entry;
455 SilcBuffer client_id_list;
458 channel = va_arg(vp, char *);
459 channel_entry = va_arg(vp, SilcChannelEntry);
460 modei = va_arg(vp, uint32);
461 (void)va_arg(vp, uint32);
462 (void)va_arg(vp, unsigned char *);
463 (void)va_arg(vp, unsigned char *);
464 (void)va_arg(vp, unsigned char *);
465 topic = va_arg(vp, char *);
466 (void)va_arg(vp, unsigned char *);
467 list_count = va_arg(vp, uint32);
468 client_id_list = va_arg(vp, SilcBuffer);
473 chanrec = silc_channel_find(server, channel);
474 if (chanrec != NULL && !success)
475 channel_destroy(CHANNEL(chanrec));
476 else if (chanrec == NULL && success)
477 chanrec = silc_channel_create(server, channel, TRUE);
480 g_free_not_null(chanrec->topic);
481 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
482 signal_emit("channel topic changed", 1, chanrec);
485 mode = silc_client_chmode(modei, channel_entry);
486 g_free_not_null(chanrec->mode);
487 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
488 signal_emit("channel mode changed", 1, chanrec);
490 /* Resolve the client information */
491 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
492 silc_client_join_get_users,
497 case SILC_COMMAND_NICK:
499 SilcClientEntry client = va_arg(vp, SilcClientEntry);
505 old = g_strdup(server->nick);
506 server_change_nick(SERVER(server), client->nickname);
507 nicklist_rename_unique(SERVER(server),
508 server->conn->local_entry, server->nick,
509 client, client->nickname);
511 signal_emit("message own_nick", 4, server, server->nick, old, "");
516 case SILC_COMMAND_LIST:
525 (void)va_arg(vp, SilcChannelEntry);
526 name = va_arg(vp, char *);
527 topic = va_arg(vp, char *);
528 usercount = va_arg(vp, int);
530 if (status == SILC_STATUS_LIST_START ||
531 status == SILC_STATUS_OK)
532 printformat_module("fe-common/silc", server, NULL,
533 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
535 snprintf(users, sizeof(users) - 1, "%d", usercount);
536 printformat_module("fe-common/silc", server, NULL,
537 MSGLEVEL_CRAP, SILCTXT_LIST,
538 name, users, topic ? topic : "");
542 case SILC_COMMAND_UMODE:
549 mode = va_arg(vp, uint32);
551 if (mode & SILC_UMODE_SERVER_OPERATOR)
552 printformat_module("fe-common/silc", server, NULL,
553 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
555 if (mode & SILC_UMODE_ROUTER_OPERATOR)
556 printformat_module("fe-common/silc", server, NULL,
557 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
561 case SILC_COMMAND_OPER:
565 printformat_module("fe-common/silc", server, NULL,
566 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
569 case SILC_COMMAND_SILCOPER:
573 printformat_module("fe-common/silc", server, NULL,
574 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
577 case SILC_COMMAND_USERS:
579 SilcChannelEntry channel;
585 channel = va_arg(vp, SilcChannelEntry);
587 printformat_module("fe-common/silc", server, channel->channel_name,
588 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
589 channel->channel_name);
591 silc_list_start(channel->clients);
592 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
593 SilcClientEntry e = chu->client;
596 memset(stat, 0, sizeof(stat));
597 mode = silc_client_chumode_char(chu->mode);
598 if (e->mode & SILC_UMODE_GONE)
605 printformat_module("fe-common/silc", server, channel->channel_name,
606 MSGLEVEL_CRAP, SILCTXT_USERS,
607 e->nickname, stat, e->username,
608 e->realname ? e->realname : "");
615 case SILC_COMMAND_BAN:
617 SilcChannelEntry channel;
623 channel = va_arg(vp, SilcChannelEntry);
624 ban_list = va_arg(vp, char *);
627 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
628 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
631 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
632 SILCTXT_CHANNEL_NO_BAN_LIST,
633 channel->channel_name);
637 case SILC_COMMAND_GETKEY:
641 SilcPublicKey public_key;
645 id_type = va_arg(vp, uint32);
646 entry = va_arg(vp, void *);
647 public_key = va_arg(vp, SilcPublicKey);
649 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
651 if (id_type == SILC_ID_CLIENT)
652 silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT,
653 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
658 case SILC_COMMAND_TOPIC:
660 SilcChannelEntry channel;
666 channel = va_arg(vp, SilcChannelEntry);
667 topic = va_arg(vp, char *);
670 chanrec = silc_channel_find_entry(server, channel);
672 g_free_not_null(chanrec->topic);
673 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
674 signal_emit("channel topic changed", 1, chanrec);
676 printformat_module("fe-common/silc", server, channel->channel_name,
677 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
678 channel->channel_name, topic);
688 /* Internal routine to verify public key. If the `completion' is provided
689 it will be called to indicate whether public was verified or not. */
693 SilcClientConnection conn;
698 SilcSKEPKType pk_type;
699 SilcVerifyPublicKey completion;
703 static void verify_public_key_completion(const char *line, void *context)
705 PublicKeyVerify verify = (PublicKeyVerify)context;
707 if (line[0] == 'Y' || line[0] == 'y') {
708 /* Call the completion */
709 if (verify->completion)
710 verify->completion(TRUE, verify->context);
712 /* Save the key for future checking */
713 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
714 verify->pk_len, SILC_PKCS_FILE_PEM);
716 /* Call the completion */
717 if (verify->completion)
718 verify->completion(FALSE, verify->context);
720 printformat_module("fe-common/silc", NULL, NULL,
721 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
724 silc_free(verify->filename);
725 silc_free(verify->entity);
726 silc_free(verify->pk);
731 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
732 SilcSocketType conn_type, unsigned char *pk,
733 uint32 pk_len, SilcSKEPKType pk_type,
734 SilcVerifyPublicKey completion, void *context)
737 char file[256], filename[256], *fingerprint, *format;
740 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
741 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
742 "server" : "client");
743 PublicKeyVerify verify;
745 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
746 printformat_module("fe-common/silc", NULL, NULL,
747 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
750 completion(FALSE, context);
754 pw = getpwuid(getuid());
757 completion(FALSE, context);
761 memset(filename, 0, sizeof(filename));
762 memset(file, 0, sizeof(file));
764 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
765 conn_type == SILC_SOCKET_TYPE_ROUTER) {
766 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
767 conn->sock->hostname, conn->sock->port);
768 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
769 pw->pw_dir, entity, file);
771 /* Replace all whitespaces with `_'. */
772 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
773 for (i = 0; i < strlen(fingerprint); i++)
774 if (fingerprint[i] == ' ')
775 fingerprint[i] = '_';
777 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
778 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
779 pw->pw_dir, entity, file);
780 silc_free(fingerprint);
783 /* Take fingerprint of the public key */
784 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
786 verify = silc_calloc(1, sizeof(*verify));
787 verify->client = client;
789 verify->filename = strdup(filename);
790 verify->entity = strdup(entity);
791 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
792 memcpy(verify->pk, pk, pk_len);
793 verify->pk_len = pk_len;
794 verify->pk_type = pk_type;
795 verify->completion = completion;
796 verify->context = context;
798 /* Check whether this key already exists */
799 if (stat(filename, &st) < 0) {
800 /* Key does not exist, ask user to verify the key and save it */
802 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
803 SILCTXT_PUBKEY_RECEIVED, entity);
804 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
805 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
806 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
807 SILCTXT_PUBKEY_ACCEPT);
808 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
811 silc_free(fingerprint);
814 /* The key already exists, verify it. */
815 SilcPublicKey public_key;
816 unsigned char *encpk;
819 /* Load the key file */
820 if (!silc_pkcs_load_public_key(filename, &public_key,
822 if (!silc_pkcs_load_public_key(filename, &public_key,
823 SILC_PKCS_FILE_BIN)) {
824 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
825 SILCTXT_PUBKEY_RECEIVED, entity);
826 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
827 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
828 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
829 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
830 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
831 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
832 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
835 silc_free(fingerprint);
839 /* Encode the key data */
840 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
842 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
843 SILCTXT_PUBKEY_RECEIVED, entity);
844 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
845 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
846 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
847 SILCTXT_PUBKEY_MALFORMED, entity);
848 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
849 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
850 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
853 silc_free(fingerprint);
857 /* Compare the keys */
858 if (memcmp(encpk, pk, encpk_len)) {
859 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
860 SILCTXT_PUBKEY_RECEIVED, entity);
861 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
862 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
863 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
864 SILCTXT_PUBKEY_NO_MATCH, entity);
865 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
866 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
867 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
868 SILCTXT_PUBKEY_MITM_ATTACK, entity);
870 /* Ask user to verify the key and save it */
871 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
872 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
873 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
876 silc_free(fingerprint);
880 /* Local copy matched */
882 completion(TRUE, context);
883 silc_free(fingerprint);
887 /* Verifies received public key. The `conn_type' indicates which entity
888 (server, client etc.) has sent the public key. If user decides to trust
889 the key may be saved as trusted public key for later use. The
890 `completion' must be called after the public key has been verified. */
893 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
894 SilcSocketType conn_type, unsigned char *pk,
895 uint32 pk_len, SilcSKEPKType pk_type,
896 SilcVerifyPublicKey completion, void *context)
898 silc_verify_public_key_internal(client, conn, conn_type, pk,
900 completion, context);
903 /* Asks passphrase from user on the input line. */
906 SilcAskPassphrase completion;
910 void ask_passphrase_completion(const char *passphrase, void *context)
912 AskPassphrase p = (AskPassphrase)context;
913 p->completion((unsigned char *)passphrase,
914 passphrase ? strlen(passphrase) : 0, p->context);
918 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
919 SilcAskPassphrase completion, void *context)
921 AskPassphrase p = silc_calloc(1, sizeof(*p));
922 p->completion = completion;
923 p->context = context;
925 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
926 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
929 /* Find authentication method and authentication data by hostname and
930 port. The hostname may be IP address as well. The found authentication
931 method and authentication data is returned to `auth_meth', `auth_data'
932 and `auth_data_len'. The function returns TRUE if authentication method
933 is found and FALSE if not. `conn' may be NULL. */
935 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
936 char *hostname, uint16 port,
937 SilcProtocolAuthMeth *auth_meth,
938 unsigned char **auth_data,
939 uint32 *auth_data_len)
942 SILC_SERVER_REC *server = conn ? conn->context : NULL;
944 /* XXX must resolve from configuration whether this connection has
945 any specific authentication data */
947 *auth_meth = SILC_AUTH_NONE;
952 printformat_module("fe-common/silc", server, NULL,
953 MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED);
959 /* Notifies application that failure packet was received. This is called
960 if there is some protocol active in the client. The `protocol' is the
961 protocol context. The `failure' is opaque pointer to the failure
962 indication. Note, that the `failure' is protocol dependant and application
963 must explicitly cast it to correct type. Usually `failure' is 32 bit
964 failure type (see protocol specs for all protocol failure types). */
966 void silc_failure(SilcClient client, SilcClientConnection conn,
967 SilcProtocol protocol, void *failure)
969 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
970 SilcSKEStatus status = (SilcSKEStatus)failure;
972 if (status == SILC_SKE_STATUS_BAD_VERSION)
973 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
974 SILCTXT_KE_BAD_VERSION);
975 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
976 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
977 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
978 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
979 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
980 SILCTXT_KE_UNKNOWN_GROUP);
981 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
982 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
983 SILCTXT_KE_UNKNOWN_CIPHER);
984 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
985 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
986 SILCTXT_KE_UNKNOWN_PKCS);
987 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
988 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
989 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
990 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
991 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
992 SILCTXT_KE_UNKNOWN_HMAC);
993 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
994 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
995 SILCTXT_KE_INCORRECT_SIGNATURE);
998 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
999 uint32 err = (uint32)failure;
1001 if (err == SILC_AUTH_FAILED)
1002 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1003 SILCTXT_AUTH_FAILED);
1007 /* Asks whether the user would like to perform the key agreement protocol.
1008 This is called after we have received an key agreement packet or an
1009 reply to our key agreement packet. This returns TRUE if the user wants
1010 the library to perform the key agreement protocol and FALSE if it is not
1011 desired (application may start it later by calling the function
1012 silc_client_perform_key_agreement). */
1014 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1015 SilcClientEntry client_entry, char *hostname,
1017 SilcKeyAgreementCallback *completion,
1022 /* We will just display the info on the screen and return FALSE and user
1023 will have to start the key agreement with a command. */
1026 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1029 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1030 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1032 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
1033 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1034 client_entry->nickname, hostname, portstr);
1042 /* SILC client operations */
1043 SilcClientOperations ops = {
1045 silc_channel_message,
1046 silc_private_message,
1052 silc_get_auth_method,
1053 silc_verify_public_key,
1054 silc_ask_passphrase,