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_int = va_arg(vp, unsigned int);
187 (void)va_arg(vp, char *);
188 (void)va_arg(vp, char *);
189 channel_entry = va_arg(vp, SilcChannelEntry);
191 tmp = silc_client_chmode(tmp_int, channel_entry);
194 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
195 client_entry->nickname, tmp);
197 snprintf(message, sizeof(message), "%s removed all channel modes",
198 client_entry->nickname);
199 if (app->screen->bottom_line->channel_mode)
200 silc_free(app->screen->bottom_line->channel_mode);
201 app->screen->bottom_line->channel_mode = tmp;
202 silc_screen_print_bottom_line(app->screen, 0);
205 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
206 client_entry = va_arg(vp, SilcClientEntry);
207 tmp_int = va_arg(vp, unsigned int);
208 tmp = silc_client_chumode(tmp_int);
209 client_entry2 = va_arg(vp, SilcClientEntry);
210 channel_entry = va_arg(vp, SilcChannelEntry);
212 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
213 client_entry->nickname, client_entry2->nickname, tmp);
215 snprintf(message, sizeof(message), "%s removed %s's modes",
216 client_entry->nickname, client_entry2->nickname);
217 if (client_entry2 == conn->local_entry) {
218 if (app->screen->bottom_line->mode)
219 silc_free(app->screen->bottom_line->mode);
220 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
221 silc_screen_print_bottom_line(app->screen, 0);
226 case SILC_NOTIFY_TYPE_MOTD:
230 tmp = va_arg(vp, unsigned char *);
234 if (tmp[i++] == '\n') {
235 memset(line, 0, sizeof(line));
236 strncat(line, tmp, i - 1);
239 silc_say(client, conn, "%s", line);
249 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
252 case SILC_NOTIFY_TYPE_KICKED:
253 client_entry = va_arg(vp, SilcClientEntry);
254 tmp = va_arg(vp, char *);
255 channel_entry = va_arg(vp, SilcChannelEntry);
257 if (client_entry == conn->local_entry) {
258 snprintf(message, sizeof(message),
259 "You have been kicked off channel %s %s%s%s",
260 conn->current_channel->channel_name,
261 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
263 snprintf(message, sizeof(message),
264 "%s%s%s has been kicked off channel %s %s%s%s",
265 client_entry->nickname,
266 client_entry->server ? "@" : "",
267 client_entry->server ? client_entry->server : "",
268 conn->current_channel->channel_name,
269 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
273 case SILC_NOTIFY_TYPE_KILLED:
274 client_entry = va_arg(vp, SilcClientEntry);
275 tmp = va_arg(vp, char *);
276 channel_entry = va_arg(vp, SilcChannelEntry);
278 if (client_entry == conn->local_entry) {
279 snprintf(message, sizeof(message),
280 "You have been killed from the SILC Network %s%s%s",
281 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
283 snprintf(message, sizeof(message),
284 "%s%s%s has been killed from the SILC Network %s%s%s",
285 client_entry->nickname,
286 client_entry->server ? "@" : "",
287 client_entry->server ? client_entry->server : "",
288 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
296 silc_print(client, "*** %s", message);
299 /* Command handler. This function is called always in the command function.
300 If error occurs it will be called as well. `conn' is the associated
301 client connection. `cmd_context' is the command context that was
302 originally sent to the command. `success' is FALSE if error occured
303 during command. `command' is the command being processed. It must be
304 noted that this is not reply from server. This is merely called just
305 after application has called the command. Just to tell application
306 that the command really was processed. */
308 void silc_command(SilcClient client, SilcClientConnection conn,
309 SilcClientCommandContext cmd_context, int success,
312 SilcClientInternal app = (SilcClientInternal)client->application;
320 case SILC_COMMAND_QUIT:
321 app->screen->bottom_line->channel = NULL;
322 silc_screen_print_bottom_line(app->screen, 0);
325 case SILC_COMMAND_LEAVE:
327 if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
328 app->screen->bottom_line->channel = NULL;
329 silc_screen_print_bottom_line(app->screen, 0);
337 /* We've resolved all clients we don't know about, now just print the
338 users from the channel on the screen. */
340 void silc_client_show_users(SilcClient client,
341 SilcClientConnection conn,
342 SilcClientEntry *clients,
343 unsigned int clients_count,
346 SilcChannelEntry channel = (SilcChannelEntry)context;
348 int k = 0, len1 = 0, len2 = 0;
349 char *name_list = NULL;
354 silc_list_start(channel->clients);
355 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
356 char *m, *n = chu->client->nickname;
363 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
365 m = silc_client_chumode_char(chu->mode);
367 memcpy(name_list + (len1 - len2), m, strlen(m));
372 memcpy(name_list + (len1 - len2), n, len2);
375 if (k == silc_list_count(channel->clients) - 1)
377 memcpy(name_list + len1, " ", 1);
382 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
384 silc_free(name_list);
387 /* Command reply handler. This function is called always in the command reply
388 function. If error occurs it will be called as well. Normal scenario
389 is that it will be called after the received command data has been parsed
390 and processed. The function is used to pass the received command data to
393 `conn' is the associated client connection. `cmd_payload' is the command
394 payload data received from server and it can be ignored. It is provided
395 if the application would like to re-parse the received command data,
396 however, it must be noted that the data is parsed already by the library
397 thus the payload can be ignored. `success' is FALSE if error occured.
398 In this case arguments are not sent to the application. `command' is the
399 command reply being processed. The function has variable argument list
400 and each command defines the number and type of arguments it passes to the
401 application (on error they are not sent). */
403 void silc_command_reply(SilcClient client, SilcClientConnection conn,
404 SilcCommandPayload cmd_payload, int success,
405 SilcCommand command, SilcCommandStatus status, ...)
407 SilcClientInternal app = (SilcClientInternal)client->application;
411 va_start(vp, status);
415 case SILC_COMMAND_WHOIS:
417 char buf[1024], *nickname, *username, *realname;
419 unsigned int idle, mode;
422 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
423 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
425 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
428 client->ops->say(client, conn, "%s: %s", tmp,
429 silc_client_command_status_message(status));
431 client->ops->say(client, conn, "%s",
432 silc_client_command_status_message(status));
439 (void)va_arg(vp, SilcClientEntry);
440 nickname = va_arg(vp, char *);
441 username = va_arg(vp, char *);
442 realname = va_arg(vp, char *);
443 channels = va_arg(vp, SilcBuffer);
444 mode = va_arg(vp, unsigned int);
445 idle = va_arg(vp, unsigned int);
447 memset(buf, 0, sizeof(buf));
450 len = strlen(nickname);
451 strncat(buf, nickname, len);
452 strncat(buf, " is ", 4);
456 strncat(buf, username, strlen(username));
460 strncat(buf, " (", 2);
461 strncat(buf, realname, strlen(realname));
462 strncat(buf, ")", 1);
465 client->ops->say(client, conn, "%s", buf);
468 SilcDList list = silc_channel_payload_parse_list(channels);
470 SilcChannelPayload entry;
472 memset(buf, 0, sizeof(buf));
473 strcat(buf, "on channels: ");
475 silc_dlist_start(list);
476 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
477 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
478 unsigned int name_len;
479 char *name = silc_channel_get_name(entry, &name_len);
482 strncat(buf, m, strlen(m));
483 strncat(buf, name, name_len);
484 strncat(buf, " ", 1);
488 client->ops->say(client, conn, "%s", buf);
489 silc_channel_payload_list_free(list);
494 client->ops->say(client, conn, "%s is %s", nickname,
495 (mode & SILC_UMODE_SERVER_OPERATOR) ?
497 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
498 "SILC Operator" : "[Unknown mode]");
500 if (idle && nickname)
501 client->ops->say(client, conn, "%s has been idle %d %s",
503 idle > 60 ? (idle / 60) : idle,
504 idle > 60 ? "minutes" : "seconds");
508 case SILC_COMMAND_WHOWAS:
510 char buf[1024], *nickname, *username, *realname;
513 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
514 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
516 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
519 client->ops->say(client, conn, "%s: %s", tmp,
520 silc_client_command_status_message(status));
522 client->ops->say(client, conn, "%s",
523 silc_client_command_status_message(status));
530 (void)va_arg(vp, SilcClientEntry);
531 nickname = va_arg(vp, char *);
532 username = va_arg(vp, char *);
533 realname = va_arg(vp, char *);
535 memset(buf, 0, sizeof(buf));
538 len = strlen(nickname);
539 strncat(buf, nickname, len);
540 strncat(buf, " was ", 5);
544 strncat(buf, username, strlen(nickname));
548 strncat(buf, " (", 2);
549 strncat(buf, realname, strlen(realname));
550 strncat(buf, ")", 1);
553 client->ops->say(client, conn, "%s", buf);
557 case SILC_COMMAND_INVITE:
559 SilcChannelEntry channel;
565 channel = va_arg(vp, SilcChannelEntry);
566 invite_list = va_arg(vp, char *);
569 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
572 silc_say(client, conn, "%s invite list not set",
573 channel->channel_name);
577 case SILC_COMMAND_JOIN:
581 SilcBuffer client_id_list;
582 unsigned int list_count;
583 SilcChannelEntry channel;
588 app->screen->bottom_line->channel = va_arg(vp, char *);
589 channel = va_arg(vp, SilcChannelEntry);
590 mode = va_arg(vp, unsigned int);
591 (void)va_arg(vp, unsigned int);
592 (void)va_arg(vp, unsigned char *);
593 (void)va_arg(vp, unsigned char *);
594 (void)va_arg(vp, unsigned char *);
595 topic = va_arg(vp, char *);
596 (void)va_arg(vp, unsigned char *);
597 list_count = va_arg(vp, unsigned int);
598 client_id_list = va_arg(vp, SilcBuffer);
601 client->ops->say(client, conn, "Topic for %s: %s",
602 app->screen->bottom_line->channel, topic);
604 app->screen->bottom_line->channel_mode =
605 silc_client_chmode(mode, channel);
606 silc_screen_print_bottom_line(app->screen, 0);
608 /* Resolve the client information */
609 silc_client_get_clients_by_list(client, conn, list_count,
611 silc_client_show_users, channel);
615 case SILC_COMMAND_NICK:
617 SilcClientEntry entry;
622 entry = va_arg(vp, SilcClientEntry);
623 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
624 app->screen->bottom_line->nickname = entry->nickname;
625 silc_screen_print_bottom_line(app->screen, 0);
629 case SILC_COMMAND_LIST:
632 unsigned int usercount;
633 unsigned char buf[256], tmp[16];
639 (void)va_arg(vp, SilcChannelEntry);
640 name = va_arg(vp, char *);
641 topic = va_arg(vp, char *);
642 usercount = va_arg(vp, unsigned int);
644 if (status == SILC_STATUS_LIST_START ||
645 status == SILC_STATUS_OK)
646 silc_say(client, conn,
647 " Channel Users Topic");
649 memset(buf, 0, sizeof(buf));
650 strncat(buf, " ", 2);
652 strncat(buf, name, len > 40 ? 40 : len);
654 for (i = 0; i < 40 - len; i++)
658 memset(tmp, 0, sizeof(tmp));
660 snprintf(tmp, sizeof(tmp), "%d", usercount);
665 for (i = 0; i < 10 - len; i++)
671 strncat(buf, topic, len);
674 silc_say(client, conn, "%s", buf);
678 case SILC_COMMAND_UMODE:
685 mode = va_arg(vp, unsigned int);
687 if (!mode && app->screen->bottom_line->umode) {
688 silc_free(app->screen->bottom_line->umode);
689 app->screen->bottom_line->umode = NULL;
692 if (mode & SILC_UMODE_SERVER_OPERATOR) {
693 if (app->screen->bottom_line->umode)
694 silc_free(app->screen->bottom_line->umode);
695 app->screen->bottom_line->umode = strdup("Server Operator");;
698 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
699 if (app->screen->bottom_line->umode)
700 silc_free(app->screen->bottom_line->umode);
701 app->screen->bottom_line->umode = strdup("SILC Operator");;
704 silc_screen_print_bottom_line(app->screen, 0);
708 case SILC_COMMAND_OPER:
709 if (status == SILC_STATUS_OK) {
710 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
711 if (app->screen->bottom_line->umode)
712 silc_free(app->screen->bottom_line->umode);
713 app->screen->bottom_line->umode = strdup("Server Operator");;
714 silc_screen_print_bottom_line(app->screen, 0);
718 case SILC_COMMAND_SILCOPER:
719 if (status == SILC_STATUS_OK) {
720 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
721 if (app->screen->bottom_line->umode)
722 silc_free(app->screen->bottom_line->umode);
723 app->screen->bottom_line->umode = strdup("SILC Operator");;
724 silc_screen_print_bottom_line(app->screen, 0);
728 case SILC_COMMAND_USERS:
732 silc_list_start(conn->current_channel->clients);
733 while ((chu = silc_list_get(conn->current_channel->clients))
735 if (chu->client == conn->local_entry) {
736 if (app->screen->bottom_line->mode)
737 silc_free(app->screen->bottom_line->mode);
738 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
739 silc_screen_print_bottom_line(app->screen, 0);
745 case SILC_COMMAND_BAN:
747 SilcChannelEntry channel;
753 channel = va_arg(vp, SilcChannelEntry);
754 ban_list = va_arg(vp, char *);
757 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
760 silc_say(client, conn, "%s ban list not set", channel->channel_name);
769 /* Called to indicate that connection was either successfully established
770 or connecting failed. This is also the first time application receives
771 the SilcClientConnection objecet which it should save somewhere. */
773 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
775 SilcClientInternal app = (SilcClientInternal)client->application;
778 app->screen->bottom_line->connection = conn->remote_host;
779 silc_screen_print_bottom_line(app->screen, 0);
784 /* Called to indicate that connection was disconnected to the server. */
786 void silc_disconnect(SilcClient client, SilcClientConnection conn)
788 SilcClientInternal app = (SilcClientInternal)client->application;
790 app->screen->bottom_line->connection = NULL;
791 silc_screen_print_bottom_line(app->screen, 0);
795 /* Asks passphrase from user on the input line. */
797 unsigned char *silc_ask_passphrase(SilcClient client,
798 SilcClientConnection conn)
800 SilcClientInternal app = (SilcClientInternal)conn->client->application;
801 char pass1[256], pass2[256];
808 wattroff(app->screen->input_win, A_INVIS);
809 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
810 wattron(app->screen->input_win, A_INVIS);
813 memset(pass1, 0, sizeof(pass1));
814 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
816 /* Print retype prompt */
817 wattroff(app->screen->input_win, A_INVIS);
818 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
819 wattron(app->screen->input_win, A_INVIS);
822 memset(pass2, 0, sizeof(pass2));
823 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
825 if (!strncmp(pass1, pass2, strlen(pass2)))
831 ret = silc_calloc(strlen(pass1), sizeof(char));
832 memcpy(ret, pass1, strlen(pass1));
834 memset(pass1, 0, sizeof(pass1));
835 memset(pass2, 0, sizeof(pass2));
837 wattroff(app->screen->input_win, A_INVIS);
838 silc_screen_input_reset(app->screen);
843 /* Verifies received public key. If user decides to trust the key it is
844 saved as public server key for later use. If user does not trust the
845 key this returns FALSE. */
847 int silc_verify_public_key(SilcClient client,
848 SilcClientConnection conn,
849 SilcSocketType conn_type,
850 unsigned char *pk, unsigned int pk_len,
851 SilcSKEPKType pk_type)
853 SilcSocketConnection sock = conn->sock;
856 char *hostname, *fingerprint;
859 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
860 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
861 "server" : "client");
863 hostname = sock->hostname ? sock->hostname : sock->ip;
865 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
866 silc_say(client, conn, "We don't support %s %s key type",
871 pw = getpwuid(getuid());
875 memset(filename, 0, sizeof(filename));
876 memset(file, 0, sizeof(file));
877 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, hostname,
879 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
880 pw->pw_dir, entity, file);
882 /* Check wheter this key already exists */
883 if (stat(filename, &st) < 0) {
885 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
886 silc_say(client, conn, "Received %s %s public key", entity, hostname);
887 silc_say(client, conn, "Fingerprint for the %s %s key is", entity,
889 silc_say(client, conn, "%s", fingerprint);
890 silc_free(fingerprint);
892 /* Ask user to verify the key and save it */
893 if (silc_client_ask_yes_no(client,
894 "Would you like to accept the key (y/n)? "))
896 /* Save the key for future checking */
897 silc_pkcs_save_public_key_data(filename, pk, pk_len,
902 /* The key already exists, verify it. */
903 SilcPublicKey public_key;
904 unsigned char *encpk;
905 unsigned int encpk_len;
907 /* Load the key file */
908 if (!silc_pkcs_load_public_key(filename, &public_key,
910 if (!silc_pkcs_load_public_key(filename, &public_key,
911 SILC_PKCS_FILE_BIN)) {
912 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
913 silc_say(client, conn, "Received %s %s public key", entity, hostname);
914 silc_say(client, conn, "Fingerprint for the %s %s key is",
916 silc_say(client, conn, "%s", fingerprint);
917 silc_free(fingerprint);
918 silc_say(client, conn, "Could not load your local copy of the %s %s key",
920 if (silc_client_ask_yes_no(client,
921 "Would you like to accept the key anyway (y/n)? "))
923 /* Save the key for future checking */
925 silc_pkcs_save_public_key_data(filename, pk, pk_len,
933 /* Encode the key data */
934 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
936 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
937 silc_say(client, conn, "Received %s %s public key", entity, hostname);
938 silc_say(client, conn, "Fingerprint for the %s %s key is",
940 silc_say(client, conn, "%s", fingerprint);
941 silc_free(fingerprint);
942 silc_say(client, conn, "Your local copy of the %s %s key is malformed",
944 if (silc_client_ask_yes_no(client,
945 "Would you like to accept the key anyway (y/n)? "))
947 /* Save the key for future checking */
949 silc_pkcs_save_public_key_data(filename, pk, pk_len,
957 if (memcmp(encpk, pk, encpk_len)) {
958 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
959 silc_say(client, conn, "Received %s %s public key", entity, hostname);
960 silc_say(client, conn, "Fingerprint for the %s %s key is",
962 silc_say(client, conn, "%s", fingerprint);
963 silc_free(fingerprint);
964 silc_say(client, conn, "%s %s key does not match with your local copy",
966 silc_say(client, conn, "It is possible that the key has expired or changed");
967 silc_say(client, conn, "It is also possible that some one is performing "
968 "man-in-the-middle attack");
970 /* Ask user to verify the key and save it */
971 if (silc_client_ask_yes_no(client,
972 "Would you like to accept the key anyway (y/n)? "))
974 /* Save the key for future checking */
976 silc_pkcs_save_public_key_data(filename, pk, pk_len,
981 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
985 /* Local copy matched */
989 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
993 /* Find authentication method and authentication data by hostname and
994 port. The hostname may be IP address as well. The found authentication
995 method and authentication data is returned to `auth_meth', `auth_data'
996 and `auth_data_len'. The function returns TRUE if authentication method
997 is found and FALSE if not. `conn' may be NULL. */
999 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1000 char *hostname, unsigned short port,
1001 SilcProtocolAuthMeth *auth_meth,
1002 unsigned char **auth_data,
1003 unsigned int *auth_data_len)
1005 SilcClientInternal app = (SilcClientInternal)client->application;
1007 if (app->config->conns) {
1008 SilcClientConfigSectionConnection *conn = NULL;
1010 /* Check if we find a match from user configured connections */
1011 conn = silc_client_config_find_connection(app->config,
1015 /* Match found. Use the configured authentication method */
1016 *auth_meth = conn->auth_meth;
1018 if (conn->auth_data) {
1019 *auth_data = strdup(conn->auth_data);
1020 *auth_data_len = strlen(conn->auth_data);
1027 *auth_meth = SILC_AUTH_NONE;
1034 /* Notifies application that failure packet was received. This is called
1035 if there is some protocol active in the client. The `protocol' is the
1036 protocol context. The `failure' is opaque pointer to the failure
1037 indication. Note, that the `failure' is protocol dependant and application
1038 must explicitly cast it to correct type. Usually `failure' is 32 bit
1039 failure type (see protocol specs for all protocol failure types). */
1041 void silc_failure(SilcClient client, SilcClientConnection conn,
1042 SilcProtocol protocol, void *failure)
1047 /* Asks whether the user would like to perform the key agreement protocol.
1048 This is called after we have received an key agreement packet or an
1049 reply to our key agreement packet. This returns TRUE if the user wants
1050 the library to perform the key agreement protocol and FALSE if it is not
1051 desired (application may start it later by calling the function
1052 silc_client_perform_key_agreement). */
1054 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1055 SilcClientEntry client_entry, char *hostname,
1057 SilcKeyAgreementCallback *completion,
1062 /* We will just display the info on the screen and return FALSE and user
1063 will have to start the key agreement with a command. */
1066 memset(host, 0, sizeof(host));
1067 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1070 silc_say(client, conn, "%s wants to perform key agreement %s",
1071 client_entry->nickname, hostname ? host : "");
1079 /* SILC client operations */
1080 SilcClientOperations ops = {
1082 channel_message: silc_channel_message,
1083 private_message: silc_private_message,
1084 notify: silc_notify,
1085 command: silc_command,
1086 command_reply: silc_command_reply,
1087 connect: silc_connect,
1088 disconnect: silc_disconnect,
1089 get_auth_method: silc_get_auth_method,
1090 verify_public_key: silc_verify_public_key,
1091 ask_passphrase: silc_ask_passphrase,
1092 failure: silc_failure,
1093 key_agreement: silc_key_agreement,