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,
50 SilcMessageFlags flags, char *msg)
52 /* Message from client */
53 if (conn && !strcmp(conn->current_channel->channel_name,
54 channel->channel_name))
55 if (flags & SILC_MESSAGE_FLAG_ACTION)
56 silc_print(client, "* %s %s", sender ? sender->nickname : "[<unknown>]",
59 silc_print(client, "<%s> %s", sender ? sender->nickname : "[<unknown>]",
62 if (flags & SILC_MESSAGE_FLAG_ACTION)
63 silc_print(client, "* %s:%s %s", sender ? sender->nickname :
65 channel->channel_name, msg);
67 silc_print(client, "<%s:%s> %s", sender ? sender->nickname :
69 channel->channel_name, msg);
72 /* Private message to the client. The `sender' is the nickname of the
73 sender received in the packet. */
75 void silc_private_message(SilcClient client, SilcClientConnection conn,
76 SilcClientEntry sender, SilcMessageFlags flags,
79 silc_print(client, "*%s* %s", sender->nickname, msg);
83 /* Notify message to the client. The notify arguments are sent in the
84 same order as servers sends them. The arguments are same as received
85 from the server except for ID's. If ID is received application receives
86 the corresponding entry to the ID. For example, if Client ID is received
87 application receives SilcClientEntry. Also, if the notify type is
88 for channel the channel entry is sent to application (even if server
91 void silc_notify(SilcClient client, SilcClientConnection conn,
92 SilcNotifyType type, ...)
94 SilcClientInternal app = (SilcClientInternal)client->application;
97 SilcClientEntry client_entry, client_entry2;
98 SilcChannelEntry channel_entry;
100 unsigned int tmp_int;
104 memset(message, 0, sizeof(message));
106 /* Get arguments (defined by protocol in silc-pp-01 -draft) */
108 case SILC_NOTIFY_TYPE_NONE:
109 tmp = va_arg(vp, char *);
112 strcpy(message, tmp);
115 case SILC_NOTIFY_TYPE_INVITE:
116 (void)va_arg(vp, SilcChannelEntry);
117 tmp = va_arg(vp, char *);
118 client_entry = va_arg(vp, SilcClientEntry);
119 snprintf(message, sizeof(message), "%s invites you to channel %s",
120 client_entry->nickname, tmp);
123 case SILC_NOTIFY_TYPE_JOIN:
124 client_entry = va_arg(vp, SilcClientEntry);
125 channel_entry = va_arg(vp, SilcChannelEntry);
126 snprintf(message, sizeof(message), "%s (%s) has joined channel %s",
127 client_entry->nickname, client_entry->username,
128 channel_entry->channel_name);
129 if (client_entry == conn->local_entry) {
132 silc_list_start(channel_entry->clients);
133 while ((chu = silc_list_get(channel_entry->clients)) != SILC_LIST_END) {
134 if (chu->client == client_entry) {
135 if (app->screen->bottom_line->mode)
136 silc_free(app->screen->bottom_line->mode);
137 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
138 silc_screen_print_bottom_line(app->screen, 0);
145 case SILC_NOTIFY_TYPE_LEAVE:
146 client_entry = va_arg(vp, SilcClientEntry);
147 channel_entry = va_arg(vp, SilcChannelEntry);
148 if (client_entry->server)
149 snprintf(message, sizeof(message), "%s@%s has left channel %s",
150 client_entry->nickname, client_entry->server,
151 channel_entry->channel_name);
153 snprintf(message, sizeof(message), "%s has left channel %s",
154 client_entry->nickname, channel_entry->channel_name);
157 case SILC_NOTIFY_TYPE_SIGNOFF:
158 client_entry = va_arg(vp, SilcClientEntry);
159 tmp = va_arg(vp, char *);
160 if (client_entry->server)
161 snprintf(message, sizeof(message), "Signoff: %s@%s %s%s%s",
162 client_entry->nickname, client_entry->server,
163 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
165 snprintf(message, sizeof(message), "Signoff: %s %s%s%s",
166 client_entry->nickname,
167 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
170 case SILC_NOTIFY_TYPE_TOPIC_SET:
171 client_entry = va_arg(vp, SilcClientEntry);
172 tmp = va_arg(vp, char *);
173 channel_entry = va_arg(vp, SilcChannelEntry);
174 if (client_entry->server)
175 snprintf(message, sizeof(message), "%s@%s set topic on %s: %s",
176 client_entry->nickname, client_entry->server,
177 channel_entry->channel_name, tmp);
179 snprintf(message, sizeof(message), "%s set topic on %s: %s",
180 client_entry->nickname, channel_entry->channel_name, tmp);
183 case SILC_NOTIFY_TYPE_NICK_CHANGE:
184 client_entry = va_arg(vp, SilcClientEntry);
185 client_entry2 = va_arg(vp, SilcClientEntry);
186 if (client_entry->server && client_entry2->server)
187 snprintf(message, sizeof(message), "%s@%s is known as %s@%s",
188 client_entry->nickname, client_entry->server,
189 client_entry2->nickname, client_entry2->server);
191 snprintf(message, sizeof(message), "%s is known as %s",
192 client_entry->nickname, client_entry2->nickname);
195 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
196 client_entry = va_arg(vp, SilcClientEntry);
197 tmp_int = va_arg(vp, unsigned int);
198 (void)va_arg(vp, char *);
199 (void)va_arg(vp, char *);
200 channel_entry = va_arg(vp, SilcChannelEntry);
202 tmp = silc_client_chmode(tmp_int, channel_entry);
205 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
206 client_entry->nickname, tmp);
208 snprintf(message, sizeof(message), "%s removed all channel modes",
209 client_entry->nickname);
210 if (app->screen->bottom_line->channel_mode)
211 silc_free(app->screen->bottom_line->channel_mode);
212 app->screen->bottom_line->channel_mode = tmp;
213 silc_screen_print_bottom_line(app->screen, 0);
216 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
217 client_entry = va_arg(vp, SilcClientEntry);
218 tmp_int = va_arg(vp, unsigned int);
219 tmp = silc_client_chumode(tmp_int);
220 client_entry2 = va_arg(vp, SilcClientEntry);
221 channel_entry = va_arg(vp, SilcChannelEntry);
223 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
224 client_entry->nickname, client_entry2->nickname, tmp);
226 snprintf(message, sizeof(message), "%s removed %s's modes",
227 client_entry->nickname, client_entry2->nickname);
228 if (client_entry2 == conn->local_entry) {
229 if (app->screen->bottom_line->mode)
230 silc_free(app->screen->bottom_line->mode);
231 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
232 silc_screen_print_bottom_line(app->screen, 0);
237 case SILC_NOTIFY_TYPE_MOTD:
241 tmp = va_arg(vp, unsigned char *);
245 if (tmp[i++] == '\n') {
246 memset(line, 0, sizeof(line));
247 strncat(line, tmp, i - 1);
250 silc_say(client, conn, "%s", line);
260 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
263 case SILC_NOTIFY_TYPE_KICKED:
264 client_entry = va_arg(vp, SilcClientEntry);
265 tmp = va_arg(vp, char *);
266 channel_entry = va_arg(vp, SilcChannelEntry);
268 if (client_entry == conn->local_entry) {
269 snprintf(message, sizeof(message),
270 "You have been kicked off channel %s %s%s%s",
271 conn->current_channel->channel_name,
272 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
274 snprintf(message, sizeof(message),
275 "%s%s%s has been kicked off channel %s %s%s%s",
276 client_entry->nickname,
277 client_entry->server ? "@" : "",
278 client_entry->server ? client_entry->server : "",
279 conn->current_channel->channel_name,
280 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
284 case SILC_NOTIFY_TYPE_KILLED:
285 client_entry = va_arg(vp, SilcClientEntry);
286 tmp = va_arg(vp, char *);
287 channel_entry = va_arg(vp, SilcChannelEntry);
289 if (client_entry == conn->local_entry) {
290 snprintf(message, sizeof(message),
291 "You have been killed from the SILC Network %s%s%s",
292 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
294 snprintf(message, sizeof(message),
295 "%s%s%s has been killed from the SILC Network %s%s%s",
296 client_entry->nickname,
297 client_entry->server ? "@" : "",
298 client_entry->server ? client_entry->server : "",
299 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
307 silc_print(client, "*** %s", message);
310 /* Command handler. This function is called always in the command function.
311 If error occurs it will be called as well. `conn' is the associated
312 client connection. `cmd_context' is the command context that was
313 originally sent to the command. `success' is FALSE if error occured
314 during command. `command' is the command being processed. It must be
315 noted that this is not reply from server. This is merely called just
316 after application has called the command. Just to tell application
317 that the command really was processed. */
319 void silc_command(SilcClient client, SilcClientConnection conn,
320 SilcClientCommandContext cmd_context, int success,
323 SilcClientInternal app = (SilcClientInternal)client->application;
331 case SILC_COMMAND_QUIT:
332 app->screen->bottom_line->channel = NULL;
333 silc_screen_print_bottom_line(app->screen, 0);
336 case SILC_COMMAND_LEAVE:
338 if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
339 app->screen->bottom_line->channel = NULL;
340 silc_screen_print_bottom_line(app->screen, 0);
348 /* We've resolved all clients we don't know about, now just print the
349 users from the channel on the screen. */
351 void silc_client_show_users(SilcClient client,
352 SilcClientConnection conn,
353 SilcClientEntry *clients,
354 unsigned int clients_count,
357 SilcChannelEntry channel = (SilcChannelEntry)context;
359 int k = 0, len1 = 0, len2 = 0;
360 char *name_list = NULL;
365 silc_list_start(channel->clients);
366 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
367 char *m, *n = chu->client->nickname;
374 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
376 m = silc_client_chumode_char(chu->mode);
378 memcpy(name_list + (len1 - len2), m, strlen(m));
383 memcpy(name_list + (len1 - len2), n, len2);
386 if (k == silc_list_count(channel->clients) - 1)
388 memcpy(name_list + len1, " ", 1);
393 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
395 silc_free(name_list);
398 /* Command reply handler. This function is called always in the command reply
399 function. If error occurs it will be called as well. Normal scenario
400 is that it will be called after the received command data has been parsed
401 and processed. The function is used to pass the received command data to
404 `conn' is the associated client connection. `cmd_payload' is the command
405 payload data received from server and it can be ignored. It is provided
406 if the application would like to re-parse the received command data,
407 however, it must be noted that the data is parsed already by the library
408 thus the payload can be ignored. `success' is FALSE if error occured.
409 In this case arguments are not sent to the application. `command' is the
410 command reply being processed. The function has variable argument list
411 and each command defines the number and type of arguments it passes to the
412 application (on error they are not sent). */
414 void silc_command_reply(SilcClient client, SilcClientConnection conn,
415 SilcCommandPayload cmd_payload, int success,
416 SilcCommand command, SilcCommandStatus status, ...)
418 SilcClientInternal app = (SilcClientInternal)client->application;
422 va_start(vp, status);
426 case SILC_COMMAND_WHOIS:
428 char buf[1024], *nickname, *username, *realname;
430 unsigned int idle, mode;
433 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
434 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
436 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
439 client->ops->say(client, conn, "%s: %s", tmp,
440 silc_client_command_status_message(status));
442 client->ops->say(client, conn, "%s",
443 silc_client_command_status_message(status));
450 (void)va_arg(vp, SilcClientEntry);
451 nickname = va_arg(vp, char *);
452 username = va_arg(vp, char *);
453 realname = va_arg(vp, char *);
454 channels = va_arg(vp, SilcBuffer);
455 mode = va_arg(vp, unsigned int);
456 idle = va_arg(vp, unsigned int);
458 memset(buf, 0, sizeof(buf));
461 len = strlen(nickname);
462 strncat(buf, nickname, len);
463 strncat(buf, " is ", 4);
467 strncat(buf, username, strlen(username));
471 strncat(buf, " (", 2);
472 strncat(buf, realname, strlen(realname));
473 strncat(buf, ")", 1);
476 client->ops->say(client, conn, "%s", buf);
479 SilcDList list = silc_channel_payload_parse_list(channels);
481 SilcChannelPayload entry;
483 memset(buf, 0, sizeof(buf));
484 strcat(buf, "on channels: ");
486 silc_dlist_start(list);
487 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
488 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
489 unsigned int name_len;
490 char *name = silc_channel_get_name(entry, &name_len);
493 strncat(buf, m, strlen(m));
494 strncat(buf, name, name_len);
495 strncat(buf, " ", 1);
499 client->ops->say(client, conn, "%s", buf);
500 silc_channel_payload_list_free(list);
505 client->ops->say(client, conn, "%s is %s", nickname,
506 (mode & SILC_UMODE_SERVER_OPERATOR) ?
508 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
509 "SILC Operator" : "[Unknown mode]");
511 if (idle && nickname)
512 client->ops->say(client, conn, "%s has been idle %d %s",
514 idle > 60 ? (idle / 60) : idle,
515 idle > 60 ? "minutes" : "seconds");
519 case SILC_COMMAND_WHOWAS:
521 char buf[1024], *nickname, *username, *realname;
524 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
525 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
527 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
530 client->ops->say(client, conn, "%s: %s", tmp,
531 silc_client_command_status_message(status));
533 client->ops->say(client, conn, "%s",
534 silc_client_command_status_message(status));
541 (void)va_arg(vp, SilcClientEntry);
542 nickname = va_arg(vp, char *);
543 username = va_arg(vp, char *);
544 realname = va_arg(vp, char *);
546 memset(buf, 0, sizeof(buf));
549 len = strlen(nickname);
550 strncat(buf, nickname, len);
551 strncat(buf, " was ", 5);
555 strncat(buf, username, strlen(nickname));
559 strncat(buf, " (", 2);
560 strncat(buf, realname, strlen(realname));
561 strncat(buf, ")", 1);
564 client->ops->say(client, conn, "%s", buf);
568 case SILC_COMMAND_INVITE:
570 SilcChannelEntry channel;
576 channel = va_arg(vp, SilcChannelEntry);
577 invite_list = va_arg(vp, char *);
580 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
583 silc_say(client, conn, "%s invite list not set",
584 channel->channel_name);
588 case SILC_COMMAND_JOIN:
592 SilcBuffer client_id_list;
593 unsigned int list_count;
594 SilcChannelEntry channel;
599 app->screen->bottom_line->channel = va_arg(vp, char *);
600 channel = va_arg(vp, SilcChannelEntry);
601 mode = va_arg(vp, unsigned int);
602 (void)va_arg(vp, unsigned int);
603 (void)va_arg(vp, unsigned char *);
604 (void)va_arg(vp, unsigned char *);
605 (void)va_arg(vp, unsigned char *);
606 topic = va_arg(vp, char *);
607 (void)va_arg(vp, unsigned char *);
608 list_count = va_arg(vp, unsigned int);
609 client_id_list = va_arg(vp, SilcBuffer);
612 client->ops->say(client, conn, "Topic for %s: %s",
613 app->screen->bottom_line->channel, topic);
615 app->screen->bottom_line->channel_mode =
616 silc_client_chmode(mode, channel);
617 silc_screen_print_bottom_line(app->screen, 0);
619 /* Resolve the client information */
620 silc_client_get_clients_by_list(client, conn, list_count,
622 silc_client_show_users, channel);
626 case SILC_COMMAND_NICK:
628 SilcClientEntry entry;
633 entry = va_arg(vp, SilcClientEntry);
634 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
635 app->screen->bottom_line->nickname = entry->nickname;
636 silc_screen_print_bottom_line(app->screen, 0);
640 case SILC_COMMAND_LIST:
643 unsigned int usercount;
644 unsigned char buf[256], tmp[16];
650 (void)va_arg(vp, SilcChannelEntry);
651 name = va_arg(vp, char *);
652 topic = va_arg(vp, char *);
653 usercount = va_arg(vp, unsigned int);
655 if (status == SILC_STATUS_LIST_START ||
656 status == SILC_STATUS_OK)
657 silc_say(client, conn,
658 " Channel Users Topic");
660 memset(buf, 0, sizeof(buf));
661 strncat(buf, " ", 2);
663 strncat(buf, name, len > 40 ? 40 : len);
665 for (i = 0; i < 40 - len; i++)
669 memset(tmp, 0, sizeof(tmp));
671 snprintf(tmp, sizeof(tmp), "%d", usercount);
676 for (i = 0; i < 10 - len; i++)
682 strncat(buf, topic, len);
685 silc_say(client, conn, "%s", buf);
689 case SILC_COMMAND_UMODE:
696 mode = va_arg(vp, unsigned int);
698 if (!mode && app->screen->bottom_line->umode) {
699 silc_free(app->screen->bottom_line->umode);
700 app->screen->bottom_line->umode = NULL;
703 if (mode & SILC_UMODE_SERVER_OPERATOR) {
704 if (app->screen->bottom_line->umode)
705 silc_free(app->screen->bottom_line->umode);
706 app->screen->bottom_line->umode = strdup("Server Operator");;
709 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
710 if (app->screen->bottom_line->umode)
711 silc_free(app->screen->bottom_line->umode);
712 app->screen->bottom_line->umode = strdup("SILC Operator");;
715 silc_screen_print_bottom_line(app->screen, 0);
719 case SILC_COMMAND_OPER:
720 if (status == SILC_STATUS_OK) {
721 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
722 if (app->screen->bottom_line->umode)
723 silc_free(app->screen->bottom_line->umode);
724 app->screen->bottom_line->umode = strdup("Server Operator");;
725 silc_screen_print_bottom_line(app->screen, 0);
729 case SILC_COMMAND_SILCOPER:
730 if (status == SILC_STATUS_OK) {
731 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
732 if (app->screen->bottom_line->umode)
733 silc_free(app->screen->bottom_line->umode);
734 app->screen->bottom_line->umode = strdup("SILC Operator");;
735 silc_screen_print_bottom_line(app->screen, 0);
739 case SILC_COMMAND_USERS:
743 silc_list_start(conn->current_channel->clients);
744 while ((chu = silc_list_get(conn->current_channel->clients))
746 if (chu->client == conn->local_entry) {
747 if (app->screen->bottom_line->mode)
748 silc_free(app->screen->bottom_line->mode);
749 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
750 silc_screen_print_bottom_line(app->screen, 0);
756 case SILC_COMMAND_BAN:
758 SilcChannelEntry channel;
764 channel = va_arg(vp, SilcChannelEntry);
765 ban_list = va_arg(vp, char *);
768 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
771 silc_say(client, conn, "%s ban list not set", channel->channel_name);
780 /* Called to indicate that connection was either successfully established
781 or connecting failed. This is also the first time application receives
782 the SilcClientConnection objecet which it should save somewhere. */
784 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
786 SilcClientInternal app = (SilcClientInternal)client->application;
789 app->screen->bottom_line->connection = conn->remote_host;
790 silc_screen_print_bottom_line(app->screen, 0);
795 /* Called to indicate that connection was disconnected to the server. */
797 void silc_disconnect(SilcClient client, SilcClientConnection conn)
799 SilcClientInternal app = (SilcClientInternal)client->application;
801 app->screen->bottom_line->connection = NULL;
802 silc_screen_print_bottom_line(app->screen, 0);
806 /* Asks passphrase from user on the input line. */
808 unsigned char *silc_ask_passphrase(SilcClient client,
809 SilcClientConnection conn)
811 SilcClientInternal app = (SilcClientInternal)conn->client->application;
812 char pass1[256], pass2[256];
819 wattroff(app->screen->input_win, A_INVIS);
820 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
821 wattron(app->screen->input_win, A_INVIS);
824 memset(pass1, 0, sizeof(pass1));
825 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
827 /* Print retype prompt */
828 wattroff(app->screen->input_win, A_INVIS);
829 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
830 wattron(app->screen->input_win, A_INVIS);
833 memset(pass2, 0, sizeof(pass2));
834 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
836 if (!strncmp(pass1, pass2, strlen(pass2)))
842 ret = silc_calloc(strlen(pass1), sizeof(char));
843 memcpy(ret, pass1, strlen(pass1));
845 memset(pass1, 0, sizeof(pass1));
846 memset(pass2, 0, sizeof(pass2));
848 wattroff(app->screen->input_win, A_INVIS);
849 silc_screen_input_reset(app->screen);
854 /* Verifies received public key. If user decides to trust the key it is
855 saved as public server key for later use. If user does not trust the
856 key this returns FALSE. */
858 int silc_verify_public_key(SilcClient client,
859 SilcClientConnection conn,
860 SilcSocketType conn_type,
861 unsigned char *pk, unsigned int pk_len,
862 SilcSKEPKType pk_type)
864 SilcSocketConnection sock = conn->sock;
867 char *hostname, *fingerprint;
870 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
871 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
872 "server" : "client");
874 hostname = sock->hostname ? sock->hostname : sock->ip;
876 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
877 silc_say(client, conn, "We don't support %s %s key type",
882 pw = getpwuid(getuid());
886 memset(filename, 0, sizeof(filename));
887 memset(file, 0, sizeof(file));
888 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, hostname,
890 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
891 pw->pw_dir, entity, file);
893 /* Check wheter this key already exists */
894 if (stat(filename, &st) < 0) {
896 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
897 silc_say(client, conn, "Received %s %s public key", entity, hostname);
898 silc_say(client, conn, "Fingerprint for the %s %s key is", entity,
900 silc_say(client, conn, "%s", fingerprint);
901 silc_free(fingerprint);
903 /* Ask user to verify the key and save it */
904 if (silc_client_ask_yes_no(client,
905 "Would you like to accept the key (y/n)? "))
907 /* Save the key for future checking */
908 silc_pkcs_save_public_key_data(filename, pk, pk_len,
913 /* The key already exists, verify it. */
914 SilcPublicKey public_key;
915 unsigned char *encpk;
916 unsigned int encpk_len;
918 /* Load the key file */
919 if (!silc_pkcs_load_public_key(filename, &public_key,
921 if (!silc_pkcs_load_public_key(filename, &public_key,
922 SILC_PKCS_FILE_BIN)) {
923 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
924 silc_say(client, conn, "Received %s %s public key", entity, hostname);
925 silc_say(client, conn, "Fingerprint for the %s %s key is",
927 silc_say(client, conn, "%s", fingerprint);
928 silc_free(fingerprint);
929 silc_say(client, conn, "Could not load your local copy of the %s %s key",
931 if (silc_client_ask_yes_no(client,
932 "Would you like to accept the key anyway (y/n)? "))
934 /* Save the key for future checking */
936 silc_pkcs_save_public_key_data(filename, pk, pk_len,
944 /* Encode the key data */
945 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
947 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
948 silc_say(client, conn, "Received %s %s public key", entity, hostname);
949 silc_say(client, conn, "Fingerprint for the %s %s key is",
951 silc_say(client, conn, "%s", fingerprint);
952 silc_free(fingerprint);
953 silc_say(client, conn, "Your local copy of the %s %s key is malformed",
955 if (silc_client_ask_yes_no(client,
956 "Would you like to accept the key anyway (y/n)? "))
958 /* Save the key for future checking */
960 silc_pkcs_save_public_key_data(filename, pk, pk_len,
968 if (memcmp(encpk, pk, encpk_len)) {
969 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
970 silc_say(client, conn, "Received %s %s public key", entity, hostname);
971 silc_say(client, conn, "Fingerprint for the %s %s key is",
973 silc_say(client, conn, "%s", fingerprint);
974 silc_free(fingerprint);
975 silc_say(client, conn, "%s %s key does not match with your local copy",
977 silc_say(client, conn, "It is possible that the key has expired or changed");
978 silc_say(client, conn, "It is also possible that some one is performing "
979 "man-in-the-middle attack");
981 /* Ask user to verify the key and save it */
982 if (silc_client_ask_yes_no(client,
983 "Would you like to accept the key anyway (y/n)? "))
985 /* Save the key for future checking */
987 silc_pkcs_save_public_key_data(filename, pk, pk_len,
992 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
996 /* Local copy matched */
1000 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
1004 /* Find authentication method and authentication data by hostname and
1005 port. The hostname may be IP address as well. The found authentication
1006 method and authentication data is returned to `auth_meth', `auth_data'
1007 and `auth_data_len'. The function returns TRUE if authentication method
1008 is found and FALSE if not. `conn' may be NULL. */
1010 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1011 char *hostname, unsigned short port,
1012 SilcProtocolAuthMeth *auth_meth,
1013 unsigned char **auth_data,
1014 unsigned int *auth_data_len)
1016 SilcClientInternal app = (SilcClientInternal)client->application;
1018 if (app->config->conns) {
1019 SilcClientConfigSectionConnection *conn = NULL;
1021 /* Check if we find a match from user configured connections */
1022 conn = silc_client_config_find_connection(app->config,
1026 /* Match found. Use the configured authentication method */
1027 *auth_meth = conn->auth_meth;
1029 if (conn->auth_data) {
1030 *auth_data = strdup(conn->auth_data);
1031 *auth_data_len = strlen(conn->auth_data);
1038 *auth_meth = SILC_AUTH_NONE;
1045 /* Notifies application that failure packet was received. This is called
1046 if there is some protocol active in the client. The `protocol' is the
1047 protocol context. The `failure' is opaque pointer to the failure
1048 indication. Note, that the `failure' is protocol dependant and application
1049 must explicitly cast it to correct type. Usually `failure' is 32 bit
1050 failure type (see protocol specs for all protocol failure types). */
1052 void silc_failure(SilcClient client, SilcClientConnection conn,
1053 SilcProtocol protocol, void *failure)
1058 /* Asks whether the user would like to perform the key agreement protocol.
1059 This is called after we have received an key agreement packet or an
1060 reply to our key agreement packet. This returns TRUE if the user wants
1061 the library to perform the key agreement protocol and FALSE if it is not
1062 desired (application may start it later by calling the function
1063 silc_client_perform_key_agreement). */
1065 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1066 SilcClientEntry client_entry, char *hostname,
1068 SilcKeyAgreementCallback *completion,
1073 /* We will just display the info on the screen and return FALSE and user
1074 will have to start the key agreement with a command. */
1077 memset(host, 0, sizeof(host));
1078 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1081 silc_say(client, conn, "%s wants to perform key agreement %s",
1082 client_entry->nickname, hostname ? host : "");
1090 /* SILC client operations */
1091 SilcClientOperations ops = {
1093 channel_message: silc_channel_message,
1094 private_message: silc_private_message,
1095 notify: silc_notify,
1096 command: silc_command,
1097 command_reply: silc_command_reply,
1098 connect: silc_connect,
1099 disconnect: silc_disconnect,
1100 get_auth_method: silc_get_auth_method,
1101 verify_public_key: silc_verify_public_key,
1102 ask_passphrase: silc_ask_passphrase,
1103 failure: silc_failure,
1104 key_agreement: silc_key_agreement,