5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 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.
21 #include "clientincludes.h"
23 /* Prints a message with three star (*) sign before the actual message
24 on the current output window. This is used to print command outputs
25 and error messages. */
27 void silc_say(SilcClient client, SilcClientConnection conn,
32 SilcClientInternal app = (SilcClientInternal)client->application;
34 memset(message, 0, sizeof(message));
35 strncat(message, "\n*** ", 5);
38 vsprintf(message + 5, msg, vp);
41 /* Print the message */
42 silc_print_to_window(app->screen->output_win[0], message);
45 /* Message for a channel. The `sender' is the nickname of the sender
46 received in the packet. The `channel_name' is the name of the channel. */
48 void silc_channel_message(SilcClient client, SilcClientConnection conn,
49 SilcClientEntry sender, SilcChannelEntry channel
52 /* Message from client */
53 if (conn && !strcmp(conn->current_channel->channel_name,
54 channel->channel_name))
55 silc_print(client, "<%s> %s", sender ? sender->nickname : "[<unknown>]",
58 silc_print(client, "<%s:%s> %s", sender ? sender->nickname : "[<unknown>]",
59 channel->channel_name, msg);
62 /* Private message to the client. The `sender' is the nickname of the
63 sender received in the packet. */
65 void silc_private_message(SilcClient client, SilcClientConnection conn,
66 SilcClientEntry sender, char *msg)
68 silc_print(client, "*%s* %s", sender->nickname, msg);
72 /* Notify message to the client. The notify arguments are sent in the
73 same order as servers sends them. The arguments are same as received
74 from the server except for ID's. If ID is received application receives
75 the corresponding entry to the ID. For example, if Client ID is received
76 application receives SilcClientEntry. Also, if the notify type is
77 for channel the channel entry is sent to application (even if server
80 void silc_notify(SilcClient client, SilcClientConnection conn,
81 SilcNotifyType type, ...)
83 SilcClientInternal app = (SilcClientInternal)client->application;
86 SilcClientEntry client_entry, client_entry2;
87 SilcChannelEntry channel_entry;
93 memset(message, 0, sizeof(message));
95 /* Get arguments (defined by protocol in silc-pp-01 -draft) */
97 case SILC_NOTIFY_TYPE_NONE:
98 tmp = va_arg(vp, char *);
101 strcpy(message, tmp);
104 case SILC_NOTIFY_TYPE_INVITE:
105 (void)va_arg(vp, SilcChannelEntry);
106 tmp = va_arg(vp, char *);
107 client_entry = va_arg(vp, SilcClientEntry);
108 snprintf(message, sizeof(message), "%s invites you to channel %s",
109 client_entry->nickname, tmp);
112 case SILC_NOTIFY_TYPE_JOIN:
113 client_entry = va_arg(vp, SilcClientEntry);
114 channel_entry = va_arg(vp, SilcChannelEntry);
115 snprintf(message, sizeof(message), "%s (%s) has joined channel %s",
116 client_entry->nickname, client_entry->username,
117 channel_entry->channel_name);
118 if (client_entry == conn->local_entry) {
121 silc_list_start(channel_entry->clients);
122 while ((chu = silc_list_get(channel_entry->clients)) != SILC_LIST_END) {
123 if (chu->client == client_entry) {
124 if (app->screen->bottom_line->mode)
125 silc_free(app->screen->bottom_line->mode);
126 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
127 silc_screen_print_bottom_line(app->screen, 0);
134 case SILC_NOTIFY_TYPE_LEAVE:
135 client_entry = va_arg(vp, SilcClientEntry);
136 channel_entry = va_arg(vp, SilcChannelEntry);
137 if (client_entry->server)
138 snprintf(message, sizeof(message), "%s@%s has left channel %s",
139 client_entry->nickname, client_entry->server,
140 channel_entry->channel_name);
142 snprintf(message, sizeof(message), "%s has left channel %s",
143 client_entry->nickname, channel_entry->channel_name);
146 case SILC_NOTIFY_TYPE_SIGNOFF:
147 client_entry = va_arg(vp, SilcClientEntry);
148 tmp = va_arg(vp, char *);
149 if (client_entry->server)
150 snprintf(message, sizeof(message), "Signoff: %s@%s %s%s%s",
151 client_entry->nickname, client_entry->server,
152 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
154 snprintf(message, sizeof(message), "Signoff: %s %s%s%s",
155 client_entry->nickname,
156 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
159 case SILC_NOTIFY_TYPE_TOPIC_SET:
160 client_entry = va_arg(vp, SilcClientEntry);
161 tmp = va_arg(vp, char *);
162 channel_entry = va_arg(vp, SilcChannelEntry);
163 if (client_entry->server)
164 snprintf(message, sizeof(message), "%s@%s set topic on %s: %s",
165 client_entry->nickname, client_entry->server,
166 channel_entry->channel_name, tmp);
168 snprintf(message, sizeof(message), "%s set topic on %s: %s",
169 client_entry->nickname, channel_entry->channel_name, tmp);
172 case SILC_NOTIFY_TYPE_NICK_CHANGE:
173 client_entry = va_arg(vp, SilcClientEntry);
174 client_entry2 = va_arg(vp, SilcClientEntry);
175 if (client_entry->server && client_entry2->server)
176 snprintf(message, sizeof(message), "%s@%s is known as %s@%s",
177 client_entry->nickname, client_entry->server,
178 client_entry2->nickname, client_entry2->server);
180 snprintf(message, sizeof(message), "%s is known as %s",
181 client_entry->nickname, client_entry2->nickname);
184 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
185 client_entry = va_arg(vp, SilcClientEntry);
186 tmp = silc_client_chmode(va_arg(vp, unsigned int));
187 channel_entry = va_arg(vp, SilcChannelEntry);
189 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
190 client_entry->nickname, tmp);
192 snprintf(message, sizeof(message), "%s removed all channel modes",
193 client_entry->nickname);
194 if (app->screen->bottom_line->channel_mode)
195 silc_free(app->screen->bottom_line->channel_mode);
196 app->screen->bottom_line->channel_mode = tmp;
197 silc_screen_print_bottom_line(app->screen, 0);
200 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
201 client_entry = va_arg(vp, SilcClientEntry);
202 tmp_int = va_arg(vp, unsigned int);
203 tmp = silc_client_chumode(tmp_int);
204 client_entry2 = va_arg(vp, SilcClientEntry);
205 channel_entry = va_arg(vp, SilcChannelEntry);
207 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
208 client_entry->nickname, client_entry2->nickname, tmp);
210 snprintf(message, sizeof(message), "%s removed %s's modes",
211 client_entry->nickname, client_entry2->nickname);
212 if (client_entry2 == conn->local_entry) {
213 if (app->screen->bottom_line->mode)
214 silc_free(app->screen->bottom_line->mode);
215 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
216 silc_screen_print_bottom_line(app->screen, 0);
221 case SILC_NOTIFY_TYPE_MOTD:
225 tmp = va_arg(vp, unsigned char *);
229 if (tmp[i++] == '\n') {
230 memset(line, 0, sizeof(line));
231 strncat(line, tmp, i - 1);
234 silc_say(client, conn, "%s", line);
244 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
247 case SILC_NOTIFY_TYPE_KICKED:
248 client_entry = va_arg(vp, SilcClientEntry);
249 tmp = va_arg(vp, char *);
250 channel_entry = va_arg(vp, SilcChannelEntry);
252 if (client_entry == conn->local_entry) {
253 snprintf(message, sizeof(message),
254 "You have been kicked off channel %s %s%s%s",
255 conn->current_channel->channel_name,
256 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
258 snprintf(message, sizeof(message),
259 "%s%s%s has been kicked off channel %s %s%s%s",
260 client_entry->nickname,
261 client_entry->server ? "@" : "",
262 client_entry->server ? client_entry->server : "",
263 conn->current_channel->channel_name,
264 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
268 case SILC_NOTIFY_TYPE_KILLED:
269 client_entry = va_arg(vp, SilcClientEntry);
270 tmp = va_arg(vp, char *);
271 channel_entry = va_arg(vp, SilcChannelEntry);
273 if (client_entry == conn->local_entry) {
274 snprintf(message, sizeof(message),
275 "You have been killed from the SILC Network %s%s%s",
276 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
278 snprintf(message, sizeof(message),
279 "%s%s%s has been killed from the SILC Network %s%s%s",
280 client_entry->nickname,
281 client_entry->server ? "@" : "",
282 client_entry->server ? client_entry->server : "",
283 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
291 silc_print(client, "*** %s", message);
294 /* Command handler. This function is called always in the command function.
295 If error occurs it will be called as well. `conn' is the associated
296 client connection. `cmd_context' is the command context that was
297 originally sent to the command. `success' is FALSE if error occured
298 during command. `command' is the command being processed. It must be
299 noted that this is not reply from server. This is merely called just
300 after application has called the command. Just to tell application
301 that the command really was processed. */
303 void silc_command(SilcClient client, SilcClientConnection conn,
304 SilcClientCommandContext cmd_context, int success,
307 SilcClientInternal app = (SilcClientInternal)client->application;
315 case SILC_COMMAND_QUIT:
316 app->screen->bottom_line->channel = NULL;
317 silc_screen_print_bottom_line(app->screen, 0);
320 case SILC_COMMAND_LEAVE:
322 if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
323 app->screen->bottom_line->channel = NULL;
324 silc_screen_print_bottom_line(app->screen, 0);
332 /* We've resolved all clients we don't know about, now just print the
333 users from the channel on the screen. */
335 void silc_client_show_users(SilcClient client,
336 SilcClientConnection conn,
337 SilcClientEntry *clients,
338 unsigned int clients_count,
341 SilcChannelEntry channel = (SilcChannelEntry)context;
343 int k = 0, len1 = 0, len2 = 0;
344 char *name_list = NULL;
349 silc_list_start(channel->clients);
350 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
351 char *m, *n = chu->client->nickname;
358 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
360 m = silc_client_chumode_char(chu->mode);
362 memcpy(name_list + (len1 - len2), m, strlen(m));
367 memcpy(name_list + (len1 - len2), n, len2);
370 if (k == silc_list_count(channel->clients) - 1)
372 memcpy(name_list + len1, " ", 1);
377 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
379 silc_free(name_list);
382 /* Command reply handler. This function is called always in the command reply
383 function. If error occurs it will be called as well. Normal scenario
384 is that it will be called after the received command data has been parsed
385 and processed. The function is used to pass the received command data to
388 `conn' is the associated client connection. `cmd_payload' is the command
389 payload data received from server and it can be ignored. It is provided
390 if the application would like to re-parse the received command data,
391 however, it must be noted that the data is parsed already by the library
392 thus the payload can be ignored. `success' is FALSE if error occured.
393 In this case arguments are not sent to the application. `command' is the
394 command reply being processed. The function has variable argument list
395 and each command defines the number and type of arguments it passes to the
396 application (on error they are not sent). */
398 void silc_command_reply(SilcClient client, SilcClientConnection conn,
399 SilcCommandPayload cmd_payload, int success,
400 SilcCommand command, SilcCommandStatus status, ...)
402 SilcClientInternal app = (SilcClientInternal)client->application;
406 va_start(vp, status);
410 case SILC_COMMAND_WHOIS:
412 char buf[1024], *nickname, *username, *realname;
414 unsigned int idle, mode;
417 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
418 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
420 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
423 client->ops->say(client, conn, "%s: %s", tmp,
424 silc_client_command_status_message(status));
426 client->ops->say(client, conn, "%s",
427 silc_client_command_status_message(status));
434 (void)va_arg(vp, SilcClientEntry);
435 nickname = va_arg(vp, char *);
436 username = va_arg(vp, char *);
437 realname = va_arg(vp, char *);
438 channels = va_arg(vp, SilcBuffer);
439 mode = va_arg(vp, unsigned int);
440 idle = va_arg(vp, unsigned int);
442 memset(buf, 0, sizeof(buf));
445 len = strlen(nickname);
446 strncat(buf, nickname, len);
447 strncat(buf, " is ", 4);
451 strncat(buf, username, strlen(username));
455 strncat(buf, " (", 2);
456 strncat(buf, realname, strlen(realname));
457 strncat(buf, ")", 1);
460 client->ops->say(client, conn, "%s", buf);
463 SilcDList list = silc_channel_payload_parse_list(channels);
465 SilcChannelPayload entry;
467 memset(buf, 0, sizeof(buf));
468 strcat(buf, "on channels: ");
470 silc_dlist_start(list);
471 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
472 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
473 unsigned int name_len;
474 char *name = silc_channel_get_name(entry, &name_len);
477 strncat(buf, m, strlen(m));
478 strncat(buf, name, name_len);
479 strncat(buf, " ", 1);
483 client->ops->say(client, conn, "%s", buf);
484 silc_channel_payload_list_free(list);
489 client->ops->say(client, conn, "%s is %s", nickname,
490 (mode & SILC_UMODE_SERVER_OPERATOR) ?
492 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
493 "SILC Operator" : "[Unknown mode]");
495 if (idle && nickname)
496 client->ops->say(client, conn, "%s has been idle %d %s",
498 idle > 60 ? (idle / 60) : idle,
499 idle > 60 ? "minutes" : "seconds");
503 case SILC_COMMAND_WHOWAS:
505 char buf[1024], *nickname, *username, *realname;
508 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
509 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
511 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
514 client->ops->say(client, conn, "%s: %s", tmp,
515 silc_client_command_status_message(status));
517 client->ops->say(client, conn, "%s",
518 silc_client_command_status_message(status));
525 (void)va_arg(vp, SilcClientEntry);
526 nickname = va_arg(vp, char *);
527 username = va_arg(vp, char *);
528 realname = va_arg(vp, char *);
530 memset(buf, 0, sizeof(buf));
533 len = strlen(nickname);
534 strncat(buf, nickname, len);
535 strncat(buf, " was ", 5);
539 strncat(buf, username, strlen(nickname));
543 strncat(buf, " (", 2);
544 strncat(buf, realname, strlen(realname));
545 strncat(buf, ")", 1);
548 client->ops->say(client, conn, "%s", buf);
552 case SILC_COMMAND_INVITE:
554 SilcChannelEntry channel;
560 channel = va_arg(vp, SilcChannelEntry);
561 invite_list = va_arg(vp, char *);
564 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
567 silc_say(client, conn, "%s invite list not set",
568 channel->channel_name);
572 case SILC_COMMAND_JOIN:
576 SilcBuffer client_id_list;
577 unsigned int list_count;
578 SilcChannelEntry channel;
583 app->screen->bottom_line->channel = va_arg(vp, char *);
584 channel = va_arg(vp, SilcChannelEntry);
585 mode = va_arg(vp, unsigned int);
586 (void)va_arg(vp, unsigned int);
587 (void)va_arg(vp, unsigned char *);
588 (void)va_arg(vp, unsigned char *);
589 (void)va_arg(vp, unsigned char *);
590 topic = va_arg(vp, char *);
591 (void)va_arg(vp, unsigned char *);
592 list_count = va_arg(vp, unsigned int);
593 client_id_list = va_arg(vp, SilcBuffer);
596 client->ops->say(client, conn, "Topic for %s: %s",
597 app->screen->bottom_line->channel, topic);
599 app->screen->bottom_line->channel_mode = silc_client_chmode(mode);
600 silc_screen_print_bottom_line(app->screen, 0);
602 /* Resolve the client information */
603 silc_client_get_clients_by_list(client, conn, list_count,
605 silc_client_show_users, channel);
609 case SILC_COMMAND_NICK:
611 SilcClientEntry entry;
616 entry = va_arg(vp, SilcClientEntry);
617 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
618 app->screen->bottom_line->nickname = entry->nickname;
619 silc_screen_print_bottom_line(app->screen, 0);
623 case SILC_COMMAND_LIST:
626 unsigned int usercount;
627 unsigned char buf[256], tmp[16];
633 (void)va_arg(vp, SilcChannelEntry);
634 name = va_arg(vp, char *);
635 topic = va_arg(vp, char *);
636 usercount = va_arg(vp, unsigned int);
638 if (status == SILC_STATUS_LIST_START ||
639 status == SILC_STATUS_OK)
640 silc_say(client, conn,
641 " Channel Users Topic");
643 memset(buf, 0, sizeof(buf));
644 strncat(buf, " ", 2);
646 strncat(buf, name, len > 40 ? 40 : len);
648 for (i = 0; i < 40 - len; i++)
652 memset(tmp, 0, sizeof(tmp));
654 snprintf(tmp, sizeof(tmp), "%d", usercount);
659 for (i = 0; i < 10 - len; i++)
665 strncat(buf, topic, len);
668 silc_say(client, conn, "%s", buf);
672 case SILC_COMMAND_UMODE:
679 mode = va_arg(vp, unsigned int);
681 if (!mode && app->screen->bottom_line->umode) {
682 silc_free(app->screen->bottom_line->umode);
683 app->screen->bottom_line->umode = NULL;
686 if (mode & SILC_UMODE_SERVER_OPERATOR) {
687 if (app->screen->bottom_line->umode)
688 silc_free(app->screen->bottom_line->umode);
689 app->screen->bottom_line->umode = strdup("Server Operator");;
692 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
693 if (app->screen->bottom_line->umode)
694 silc_free(app->screen->bottom_line->umode);
695 app->screen->bottom_line->umode = strdup("SILC Operator");;
698 silc_screen_print_bottom_line(app->screen, 0);
702 case SILC_COMMAND_OPER:
703 if (status == SILC_STATUS_OK) {
704 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
705 if (app->screen->bottom_line->umode)
706 silc_free(app->screen->bottom_line->umode);
707 app->screen->bottom_line->umode = strdup("Server Operator");;
708 silc_screen_print_bottom_line(app->screen, 0);
712 case SILC_COMMAND_SILCOPER:
713 if (status == SILC_STATUS_OK) {
714 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
715 if (app->screen->bottom_line->umode)
716 silc_free(app->screen->bottom_line->umode);
717 app->screen->bottom_line->umode = strdup("SILC Operator");;
718 silc_screen_print_bottom_line(app->screen, 0);
722 case SILC_COMMAND_USERS:
726 silc_list_start(conn->current_channel->clients);
727 while ((chu = silc_list_get(conn->current_channel->clients))
729 if (chu->client == conn->local_entry) {
730 if (app->screen->bottom_line->mode)
731 silc_free(app->screen->bottom_line->mode);
732 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
733 silc_screen_print_bottom_line(app->screen, 0);
739 case SILC_COMMAND_BAN:
741 SilcChannelEntry channel;
747 channel = va_arg(vp, SilcChannelEntry);
748 ban_list = va_arg(vp, char *);
751 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
754 silc_say(client, conn, "%s ban list not set", channel->channel_name);
763 /* Called to indicate that connection was either successfully established
764 or connecting failed. This is also the first time application receives
765 the SilcClientConnection objecet which it should save somewhere. */
767 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
769 SilcClientInternal app = (SilcClientInternal)client->application;
772 app->screen->bottom_line->connection = conn->remote_host;
773 silc_screen_print_bottom_line(app->screen, 0);
778 /* Called to indicate that connection was disconnected to the server. */
780 void silc_disconnect(SilcClient client, SilcClientConnection conn)
782 SilcClientInternal app = (SilcClientInternal)client->application;
784 app->screen->bottom_line->connection = NULL;
785 silc_screen_print_bottom_line(app->screen, 0);
789 /* Asks passphrase from user on the input line. */
791 unsigned char *silc_ask_passphrase(SilcClient client,
792 SilcClientConnection conn)
794 SilcClientInternal app = (SilcClientInternal)conn->client->application;
795 char pass1[256], pass2[256];
802 wattroff(app->screen->input_win, A_INVIS);
803 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
804 wattron(app->screen->input_win, A_INVIS);
807 memset(pass1, 0, sizeof(pass1));
808 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
810 /* Print retype prompt */
811 wattroff(app->screen->input_win, A_INVIS);
812 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
813 wattron(app->screen->input_win, A_INVIS);
816 memset(pass2, 0, sizeof(pass2));
817 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
819 if (!strncmp(pass1, pass2, strlen(pass2)))
825 ret = silc_calloc(strlen(pass1), sizeof(char));
826 memcpy(ret, pass1, strlen(pass1));
828 memset(pass1, 0, sizeof(pass1));
829 memset(pass2, 0, sizeof(pass2));
831 wattroff(app->screen->input_win, A_INVIS);
832 silc_screen_input_reset(app->screen);
837 /* Verifies received public key. If user decides to trust the key it is
838 saved as trusted server key for later use. If user does not trust the
839 key this returns FALSE. */
841 int silc_verify_server_key(SilcClient client,
842 SilcClientConnection conn,
843 unsigned char *pk, unsigned int pk_len,
844 SilcSKEPKType pk_type)
846 SilcSocketConnection sock = conn->sock;
849 char *hostname, *fingerprint;
853 hostname = sock->hostname ? sock->hostname : sock->ip;
855 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
856 silc_say(client, conn, "We don't support server %s key type", hostname);
860 pw = getpwuid(getuid());
864 memset(filename, 0, sizeof(filename));
865 memset(file, 0, sizeof(file));
866 snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", hostname,
868 snprintf(filename, sizeof(filename) - 1, "%s/.silc/serverkeys/%s",
871 /* Check wheter this key already exists */
872 if (stat(filename, &st) < 0) {
874 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
875 silc_say(client, conn, "Received server %s public key", hostname);
876 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
877 silc_say(client, conn, "%s", fingerprint);
878 silc_free(fingerprint);
880 /* Ask user to verify the key and save it */
881 if (silc_client_ask_yes_no(client,
882 "Would you like to accept the key (y/n)? "))
884 /* Save the key for future checking */
885 silc_pkcs_save_public_key_data(filename, pk, pk_len,
890 /* The key already exists, verify it. */
891 SilcPublicKey public_key;
892 unsigned char *encpk;
893 unsigned int encpk_len;
895 /* Load the key file */
896 if (!silc_pkcs_load_public_key(filename, &public_key,
898 if (!silc_pkcs_load_public_key(filename, &public_key,
899 SILC_PKCS_FILE_BIN)) {
900 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
901 silc_say(client, conn, "Received server %s public key", hostname);
902 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
903 silc_say(client, conn, "%s", fingerprint);
904 silc_free(fingerprint);
905 silc_say(client, conn, "Could not load your local copy of the server %s key",
907 if (silc_client_ask_yes_no(client,
908 "Would you like to accept the key anyway (y/n)? "))
910 /* Save the key for future checking */
912 silc_pkcs_save_public_key_data(filename, pk, pk_len,
920 /* Encode the key data */
921 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
923 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
924 silc_say(client, conn, "Received server %s public key", hostname);
925 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
926 silc_say(client, conn, "%s", fingerprint);
927 silc_free(fingerprint);
928 silc_say(client, conn, "Your local copy of the server %s key is malformed",
930 if (silc_client_ask_yes_no(client,
931 "Would you like to accept the key anyway (y/n)? "))
933 /* Save the key for future checking */
935 silc_pkcs_save_public_key_data(filename, pk, pk_len,
943 if (memcmp(encpk, pk, encpk_len)) {
944 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
945 silc_say(client, conn, "Received server %s public key", hostname);
946 silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
947 silc_say(client, conn, "%s", fingerprint);
948 silc_free(fingerprint);
949 silc_say(client, conn, "Server %s key does not match with your local copy",
951 silc_say(client, conn, "It is possible that the key has expired or changed");
952 silc_say(client, conn, "It is also possible that some one is performing "
953 "man-in-the-middle attack");
955 /* Ask user to verify the key and save it */
956 if (silc_client_ask_yes_no(client,
957 "Would you like to accept the key anyway (y/n)? "))
959 /* Save the key for future checking */
961 silc_pkcs_save_public_key_data(filename, pk, pk_len,
966 silc_say(client, conn, "Will not accept server %s key", hostname);
970 /* Local copy matched */
974 silc_say(client, conn, "Will not accept server %s key", hostname);
978 /* Find authentication method and authentication data by hostname and
979 port. The hostname may be IP address as well. The found authentication
980 method and authentication data is returned to `auth_meth', `auth_data'
981 and `auth_data_len'. The function returns TRUE if authentication method
982 is found and FALSE if not. `conn' may be NULL. */
984 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
985 char *hostname, unsigned short port,
986 SilcProtocolAuthMeth *auth_meth,
987 unsigned char **auth_data,
988 unsigned int *auth_data_len)
990 SilcClientInternal app = (SilcClientInternal)client->application;
992 if (app->config->conns) {
993 SilcClientConfigSectionConnection *conn = NULL;
995 /* Check if we find a match from user configured connections */
996 conn = silc_client_config_find_connection(app->config,
1000 /* Match found. Use the configured authentication method */
1001 *auth_meth = conn->auth_meth;
1003 if (conn->auth_data) {
1004 *auth_data = strdup(conn->auth_data);
1005 *auth_data_len = strlen(conn->auth_data);
1015 /* Notifies application that failure packet was received. This is called
1016 if there is some protocol active in the client. The `protocol' is the
1017 protocol context. The `failure' is opaque pointer to the failure
1018 indication. Note, that the `failure' is protocol dependant and application
1019 must explicitly cast it to correct type. Usually `failure' is 32 bit
1020 failure type (see protocol specs for all protocol failure types). */
1022 void silc_failure(SilcClient client, SilcClientConnection conn,
1023 SilcProtocol protocol, void *failure)
1028 /* Asks whether the user would like to perform the key agreement protocol.
1029 This is called after we have received an key agreement packet or an
1030 reply to our key agreement packet. This returns TRUE if the user wants
1031 the library to perform the key agreement protocol and FALSE if it is not
1032 desired (application may start it later by calling the function
1033 silc_client_perform_key_agreement). */
1035 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1036 SilcClientEntry client_entry, char *hostname,
1038 SilcKeyAgreementCallback *completion,
1045 /* SILC client operations */
1046 SilcClientOperations ops = {
1048 channel_message: silc_channel_message,
1049 private_message: silc_private_message,
1050 notify: silc_notify,
1051 command: silc_command,
1052 command_reply: silc_command_reply,
1053 connect: silc_connect,
1054 disconnect: silc_disconnect,
1055 get_auth_method: silc_get_auth_method,
1056 verify_server_key: silc_verify_server_key,
1057 ask_passphrase: silc_ask_passphrase,
1058 failure: silc_failure,
1059 key_agreement: silc_key_agreement,