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>]",
58 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
59 silc_print(client, "- %s %s", sender ? sender->nickname : "[<unknown>]",
62 silc_print(client, "<%s> %s", sender ? sender->nickname : "[<unknown>]",
65 if (flags & SILC_MESSAGE_FLAG_ACTION)
66 silc_print(client, "* %s:%s %s", sender ? sender->nickname :
68 channel->channel_name, msg);
69 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
70 silc_print(client, "- %s:%s %s", sender ? sender->nickname :
72 channel->channel_name, msg);
74 silc_print(client, "<%s:%s> %s", sender ? sender->nickname :
76 channel->channel_name, msg);
79 /* Private message to the client. The `sender' is the nickname of the
80 sender received in the packet. */
82 void silc_private_message(SilcClient client, SilcClientConnection conn,
83 SilcClientEntry sender, SilcMessageFlags flags,
86 silc_print(client, "*%s* %s", sender->nickname, msg);
90 /* Notify message to the client. The notify arguments are sent in the
91 same order as servers sends them. The arguments are same as received
92 from the server except for ID's. If ID is received application receives
93 the corresponding entry to the ID. For example, if Client ID is received
94 application receives SilcClientEntry. Also, if the notify type is
95 for channel the channel entry is sent to application (even if server
98 void silc_notify(SilcClient client, SilcClientConnection conn,
99 SilcNotifyType type, ...)
101 SilcClientInternal app = (SilcClientInternal)client->application;
104 SilcClientEntry client_entry, client_entry2;
105 SilcChannelEntry channel_entry;
107 unsigned int tmp_int;
111 memset(message, 0, sizeof(message));
113 /* Get arguments (defined by protocol in silc-pp-01 -draft) */
115 case SILC_NOTIFY_TYPE_NONE:
116 tmp = va_arg(vp, char *);
119 strcpy(message, tmp);
122 case SILC_NOTIFY_TYPE_INVITE:
123 (void)va_arg(vp, SilcChannelEntry);
124 tmp = va_arg(vp, char *);
125 client_entry = va_arg(vp, SilcClientEntry);
126 snprintf(message, sizeof(message), "%s invites you to channel %s",
127 client_entry->nickname, tmp);
130 case SILC_NOTIFY_TYPE_JOIN:
131 client_entry = va_arg(vp, SilcClientEntry);
132 channel_entry = va_arg(vp, SilcChannelEntry);
133 snprintf(message, sizeof(message), "%s (%s) has joined channel %s",
134 client_entry->nickname, client_entry->username,
135 channel_entry->channel_name);
136 if (client_entry == conn->local_entry) {
139 silc_list_start(channel_entry->clients);
140 while ((chu = silc_list_get(channel_entry->clients)) != SILC_LIST_END) {
141 if (chu->client == client_entry) {
142 if (app->screen->bottom_line->mode)
143 silc_free(app->screen->bottom_line->mode);
144 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
145 silc_screen_print_bottom_line(app->screen, 0);
152 case SILC_NOTIFY_TYPE_LEAVE:
153 client_entry = va_arg(vp, SilcClientEntry);
154 channel_entry = va_arg(vp, SilcChannelEntry);
155 if (client_entry->server)
156 snprintf(message, sizeof(message), "%s@%s has left channel %s",
157 client_entry->nickname, client_entry->server,
158 channel_entry->channel_name);
160 snprintf(message, sizeof(message), "%s has left channel %s",
161 client_entry->nickname, channel_entry->channel_name);
164 case SILC_NOTIFY_TYPE_SIGNOFF:
165 client_entry = va_arg(vp, SilcClientEntry);
166 tmp = va_arg(vp, char *);
167 if (client_entry->server)
168 snprintf(message, sizeof(message), "Signoff: %s@%s %s%s%s",
169 client_entry->nickname, client_entry->server,
170 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
172 snprintf(message, sizeof(message), "Signoff: %s %s%s%s",
173 client_entry->nickname,
174 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
177 case SILC_NOTIFY_TYPE_TOPIC_SET:
178 client_entry = va_arg(vp, SilcClientEntry);
179 tmp = va_arg(vp, char *);
180 channel_entry = va_arg(vp, SilcChannelEntry);
181 if (client_entry->server)
182 snprintf(message, sizeof(message), "%s@%s set topic on %s: %s",
183 client_entry->nickname, client_entry->server,
184 channel_entry->channel_name, tmp);
186 snprintf(message, sizeof(message), "%s set topic on %s: %s",
187 client_entry->nickname, channel_entry->channel_name, tmp);
190 case SILC_NOTIFY_TYPE_NICK_CHANGE:
191 client_entry = va_arg(vp, SilcClientEntry);
192 client_entry2 = va_arg(vp, SilcClientEntry);
193 if (client_entry->server && client_entry2->server)
194 snprintf(message, sizeof(message), "%s@%s is known as %s@%s",
195 client_entry->nickname, client_entry->server,
196 client_entry2->nickname, client_entry2->server);
198 snprintf(message, sizeof(message), "%s is known as %s",
199 client_entry->nickname, client_entry2->nickname);
202 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
203 client_entry = va_arg(vp, SilcClientEntry);
204 tmp_int = va_arg(vp, unsigned int);
205 (void)va_arg(vp, char *);
206 (void)va_arg(vp, char *);
207 channel_entry = va_arg(vp, SilcChannelEntry);
209 tmp = silc_client_chmode(tmp_int, channel_entry);
212 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
213 client_entry->nickname, tmp);
215 snprintf(message, sizeof(message), "%s removed all channel modes",
216 client_entry->nickname);
217 if (app->screen->bottom_line->channel_mode)
218 silc_free(app->screen->bottom_line->channel_mode);
219 app->screen->bottom_line->channel_mode = tmp;
220 silc_screen_print_bottom_line(app->screen, 0);
223 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
224 client_entry = va_arg(vp, SilcClientEntry);
225 tmp_int = va_arg(vp, unsigned int);
226 tmp = silc_client_chumode(tmp_int);
227 client_entry2 = va_arg(vp, SilcClientEntry);
228 channel_entry = va_arg(vp, SilcChannelEntry);
230 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
231 client_entry->nickname, client_entry2->nickname, tmp);
233 snprintf(message, sizeof(message), "%s removed %s's modes",
234 client_entry->nickname, client_entry2->nickname);
235 if (client_entry2 == conn->local_entry) {
236 if (app->screen->bottom_line->mode)
237 silc_free(app->screen->bottom_line->mode);
238 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
239 silc_screen_print_bottom_line(app->screen, 0);
244 case SILC_NOTIFY_TYPE_MOTD:
248 tmp = va_arg(vp, unsigned char *);
252 if (tmp[i++] == '\n') {
253 memset(line, 0, sizeof(line));
254 strncat(line, tmp, i - 1);
257 silc_say(client, conn, "%s", line);
267 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
270 case SILC_NOTIFY_TYPE_KICKED:
271 client_entry = va_arg(vp, SilcClientEntry);
272 tmp = va_arg(vp, char *);
273 channel_entry = va_arg(vp, SilcChannelEntry);
275 if (client_entry == conn->local_entry) {
276 snprintf(message, sizeof(message),
277 "You have been kicked off channel %s %s%s%s",
278 conn->current_channel->channel_name,
279 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
281 snprintf(message, sizeof(message),
282 "%s%s%s has been kicked off channel %s %s%s%s",
283 client_entry->nickname,
284 client_entry->server ? "@" : "",
285 client_entry->server ? client_entry->server : "",
286 conn->current_channel->channel_name,
287 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
291 case SILC_NOTIFY_TYPE_KILLED:
292 client_entry = va_arg(vp, SilcClientEntry);
293 tmp = va_arg(vp, char *);
294 channel_entry = va_arg(vp, SilcChannelEntry);
296 if (client_entry == conn->local_entry) {
297 snprintf(message, sizeof(message),
298 "You have been killed from the SILC Network %s%s%s",
299 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
301 snprintf(message, sizeof(message),
302 "%s%s%s has been killed from the SILC Network %s%s%s",
303 client_entry->nickname,
304 client_entry->server ? "@" : "",
305 client_entry->server ? client_entry->server : "",
306 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
314 silc_print(client, "*** %s", message);
317 /* Command handler. This function is called always in the command function.
318 If error occurs it will be called as well. `conn' is the associated
319 client connection. `cmd_context' is the command context that was
320 originally sent to the command. `success' is FALSE if error occured
321 during command. `command' is the command being processed. It must be
322 noted that this is not reply from server. This is merely called just
323 after application has called the command. Just to tell application
324 that the command really was processed. */
326 void silc_command(SilcClient client, SilcClientConnection conn,
327 SilcClientCommandContext cmd_context, int success,
330 SilcClientInternal app = (SilcClientInternal)client->application;
338 case SILC_COMMAND_QUIT:
339 app->screen->bottom_line->channel = NULL;
340 silc_screen_print_bottom_line(app->screen, 0);
343 case SILC_COMMAND_LEAVE:
345 if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
346 app->screen->bottom_line->channel = NULL;
347 silc_screen_print_bottom_line(app->screen, 0);
355 /* We've resolved all clients we don't know about, now just print the
356 users from the channel on the screen. */
358 void silc_client_show_users(SilcClient client,
359 SilcClientConnection conn,
360 SilcClientEntry *clients,
361 unsigned int clients_count,
364 SilcChannelEntry channel = (SilcChannelEntry)context;
366 int k = 0, len1 = 0, len2 = 0;
367 char *name_list = NULL;
372 silc_list_start(channel->clients);
373 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
374 char *m, *n = chu->client->nickname;
381 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
383 m = silc_client_chumode_char(chu->mode);
385 memcpy(name_list + (len1 - len2), m, strlen(m));
390 memcpy(name_list + (len1 - len2), n, len2);
393 if (k == silc_list_count(channel->clients) - 1)
395 memcpy(name_list + len1, " ", 1);
400 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
402 silc_free(name_list);
405 /* Command reply handler. This function is called always in the command reply
406 function. If error occurs it will be called as well. Normal scenario
407 is that it will be called after the received command data has been parsed
408 and processed. The function is used to pass the received command data to
411 `conn' is the associated client connection. `cmd_payload' is the command
412 payload data received from server and it can be ignored. It is provided
413 if the application would like to re-parse the received command data,
414 however, it must be noted that the data is parsed already by the library
415 thus the payload can be ignored. `success' is FALSE if error occured.
416 In this case arguments are not sent to the application. `command' is the
417 command reply being processed. The function has variable argument list
418 and each command defines the number and type of arguments it passes to the
419 application (on error they are not sent). */
421 void silc_command_reply(SilcClient client, SilcClientConnection conn,
422 SilcCommandPayload cmd_payload, int success,
423 SilcCommand command, SilcCommandStatus status, ...)
425 SilcClientInternal app = (SilcClientInternal)client->application;
429 va_start(vp, status);
433 case SILC_COMMAND_WHOIS:
435 char buf[1024], *nickname, *username, *realname;
437 unsigned int idle, mode;
440 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
441 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
443 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
446 client->ops->say(client, conn, "%s: %s", tmp,
447 silc_client_command_status_message(status));
449 client->ops->say(client, conn, "%s",
450 silc_client_command_status_message(status));
457 (void)va_arg(vp, SilcClientEntry);
458 nickname = va_arg(vp, char *);
459 username = va_arg(vp, char *);
460 realname = va_arg(vp, char *);
461 channels = va_arg(vp, SilcBuffer);
462 mode = va_arg(vp, unsigned int);
463 idle = va_arg(vp, unsigned int);
465 memset(buf, 0, sizeof(buf));
468 len = strlen(nickname);
469 strncat(buf, nickname, len);
470 strncat(buf, " is ", 4);
474 strncat(buf, username, strlen(username));
478 strncat(buf, " (", 2);
479 strncat(buf, realname, strlen(realname));
480 strncat(buf, ")", 1);
483 client->ops->say(client, conn, "%s", buf);
486 SilcDList list = silc_channel_payload_parse_list(channels);
488 SilcChannelPayload entry;
490 memset(buf, 0, sizeof(buf));
491 strcat(buf, "on channels: ");
493 silc_dlist_start(list);
494 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
495 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
496 unsigned int name_len;
497 char *name = silc_channel_get_name(entry, &name_len);
500 strncat(buf, m, strlen(m));
501 strncat(buf, name, name_len);
502 strncat(buf, " ", 1);
506 client->ops->say(client, conn, "%s", buf);
507 silc_channel_payload_list_free(list);
512 client->ops->say(client, conn, "%s is %s", nickname,
513 (mode & SILC_UMODE_SERVER_OPERATOR) ?
515 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
516 "SILC Operator" : "[Unknown mode]");
518 if (idle && nickname)
519 client->ops->say(client, conn, "%s has been idle %d %s",
521 idle > 60 ? (idle / 60) : idle,
522 idle > 60 ? "minutes" : "seconds");
526 case SILC_COMMAND_WHOWAS:
528 char buf[1024], *nickname, *username, *realname;
531 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
532 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
534 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
537 client->ops->say(client, conn, "%s: %s", tmp,
538 silc_client_command_status_message(status));
540 client->ops->say(client, conn, "%s",
541 silc_client_command_status_message(status));
548 (void)va_arg(vp, SilcClientEntry);
549 nickname = va_arg(vp, char *);
550 username = va_arg(vp, char *);
551 realname = va_arg(vp, char *);
553 memset(buf, 0, sizeof(buf));
556 len = strlen(nickname);
557 strncat(buf, nickname, len);
558 strncat(buf, " was ", 5);
562 strncat(buf, username, strlen(nickname));
566 strncat(buf, " (", 2);
567 strncat(buf, realname, strlen(realname));
568 strncat(buf, ")", 1);
571 client->ops->say(client, conn, "%s", buf);
575 case SILC_COMMAND_INVITE:
577 SilcChannelEntry channel;
583 channel = va_arg(vp, SilcChannelEntry);
584 invite_list = va_arg(vp, char *);
587 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
590 silc_say(client, conn, "%s invite list not set",
591 channel->channel_name);
595 case SILC_COMMAND_JOIN:
599 SilcBuffer client_id_list;
600 unsigned int list_count;
601 SilcChannelEntry channel;
606 app->screen->bottom_line->channel = va_arg(vp, char *);
607 channel = va_arg(vp, SilcChannelEntry);
608 mode = va_arg(vp, unsigned int);
609 (void)va_arg(vp, unsigned int);
610 (void)va_arg(vp, unsigned char *);
611 (void)va_arg(vp, unsigned char *);
612 (void)va_arg(vp, unsigned char *);
613 topic = va_arg(vp, char *);
614 (void)va_arg(vp, unsigned char *);
615 list_count = va_arg(vp, unsigned int);
616 client_id_list = va_arg(vp, SilcBuffer);
619 client->ops->say(client, conn, "Topic for %s: %s",
620 app->screen->bottom_line->channel, topic);
622 app->screen->bottom_line->channel_mode =
623 silc_client_chmode(mode, channel);
624 silc_screen_print_bottom_line(app->screen, 0);
626 /* Resolve the client information */
627 silc_client_get_clients_by_list(client, conn, list_count,
629 silc_client_show_users, channel);
633 case SILC_COMMAND_NICK:
635 SilcClientEntry entry;
640 entry = va_arg(vp, SilcClientEntry);
641 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
642 app->screen->bottom_line->nickname = entry->nickname;
643 silc_screen_print_bottom_line(app->screen, 0);
647 case SILC_COMMAND_LIST:
650 unsigned int usercount;
651 unsigned char buf[256], tmp[16];
657 (void)va_arg(vp, SilcChannelEntry);
658 name = va_arg(vp, char *);
659 topic = va_arg(vp, char *);
660 usercount = va_arg(vp, unsigned int);
662 if (status == SILC_STATUS_LIST_START ||
663 status == SILC_STATUS_OK)
664 silc_say(client, conn,
665 " Channel Users Topic");
667 memset(buf, 0, sizeof(buf));
668 strncat(buf, " ", 2);
670 strncat(buf, name, len > 40 ? 40 : len);
672 for (i = 0; i < 40 - len; i++)
676 memset(tmp, 0, sizeof(tmp));
678 snprintf(tmp, sizeof(tmp), "%d", usercount);
683 for (i = 0; i < 10 - len; i++)
689 strncat(buf, topic, len);
692 silc_say(client, conn, "%s", buf);
696 case SILC_COMMAND_UMODE:
703 mode = va_arg(vp, unsigned int);
705 if (!mode && app->screen->bottom_line->umode) {
706 silc_free(app->screen->bottom_line->umode);
707 app->screen->bottom_line->umode = NULL;
710 if (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");;
716 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
717 if (app->screen->bottom_line->umode)
718 silc_free(app->screen->bottom_line->umode);
719 app->screen->bottom_line->umode = strdup("SILC Operator");;
722 silc_screen_print_bottom_line(app->screen, 0);
726 case SILC_COMMAND_OPER:
727 if (status == SILC_STATUS_OK) {
728 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
729 if (app->screen->bottom_line->umode)
730 silc_free(app->screen->bottom_line->umode);
731 app->screen->bottom_line->umode = strdup("Server Operator");;
732 silc_screen_print_bottom_line(app->screen, 0);
736 case SILC_COMMAND_SILCOPER:
737 if (status == SILC_STATUS_OK) {
738 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
739 if (app->screen->bottom_line->umode)
740 silc_free(app->screen->bottom_line->umode);
741 app->screen->bottom_line->umode = strdup("SILC Operator");;
742 silc_screen_print_bottom_line(app->screen, 0);
746 case SILC_COMMAND_USERS:
750 silc_list_start(conn->current_channel->clients);
751 while ((chu = silc_list_get(conn->current_channel->clients))
753 if (chu->client == conn->local_entry) {
754 if (app->screen->bottom_line->mode)
755 silc_free(app->screen->bottom_line->mode);
756 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
757 silc_screen_print_bottom_line(app->screen, 0);
763 case SILC_COMMAND_BAN:
765 SilcChannelEntry channel;
771 channel = va_arg(vp, SilcChannelEntry);
772 ban_list = va_arg(vp, char *);
775 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
778 silc_say(client, conn, "%s ban list not set", channel->channel_name);
787 /* Called to indicate that connection was either successfully established
788 or connecting failed. This is also the first time application receives
789 the SilcClientConnection objecet which it should save somewhere. */
791 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
793 SilcClientInternal app = (SilcClientInternal)client->application;
796 app->screen->bottom_line->connection = conn->remote_host;
797 silc_screen_print_bottom_line(app->screen, 0);
802 /* Called to indicate that connection was disconnected to the server. */
804 void silc_disconnect(SilcClient client, SilcClientConnection conn)
806 SilcClientInternal app = (SilcClientInternal)client->application;
808 app->screen->bottom_line->connection = NULL;
809 silc_screen_print_bottom_line(app->screen, 0);
813 /* Asks passphrase from user on the input line. */
815 unsigned char *silc_ask_passphrase(SilcClient client,
816 SilcClientConnection conn)
818 SilcClientInternal app = (SilcClientInternal)conn->client->application;
819 char pass1[256], pass2[256];
826 wattroff(app->screen->input_win, A_INVIS);
827 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
828 wattron(app->screen->input_win, A_INVIS);
831 memset(pass1, 0, sizeof(pass1));
832 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
834 /* Print retype prompt */
835 wattroff(app->screen->input_win, A_INVIS);
836 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
837 wattron(app->screen->input_win, A_INVIS);
840 memset(pass2, 0, sizeof(pass2));
841 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
843 if (!strncmp(pass1, pass2, strlen(pass2)))
849 ret = silc_calloc(strlen(pass1), sizeof(char));
850 memcpy(ret, pass1, strlen(pass1));
852 memset(pass1, 0, sizeof(pass1));
853 memset(pass2, 0, sizeof(pass2));
855 wattroff(app->screen->input_win, A_INVIS);
856 silc_screen_input_reset(app->screen);
861 /* Verifies received public key. If user decides to trust the key it is
862 saved as public server key for later use. If user does not trust the
863 key this returns FALSE. */
865 int silc_verify_public_key(SilcClient client,
866 SilcClientConnection conn,
867 SilcSocketType conn_type,
868 unsigned char *pk, unsigned int pk_len,
869 SilcSKEPKType pk_type)
871 SilcSocketConnection sock = conn->sock;
874 char *hostname, *fingerprint;
877 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
878 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
879 "server" : "client");
881 hostname = sock->hostname ? sock->hostname : sock->ip;
883 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
884 silc_say(client, conn, "We don't support %s %s key type",
889 pw = getpwuid(getuid());
893 memset(filename, 0, sizeof(filename));
894 memset(file, 0, sizeof(file));
895 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, hostname,
897 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
898 pw->pw_dir, entity, file);
900 /* Check wheter this key already exists */
901 if (stat(filename, &st) < 0) {
903 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
904 silc_say(client, conn, "Received %s %s public key", entity, hostname);
905 silc_say(client, conn, "Fingerprint for the %s %s key is", entity,
907 silc_say(client, conn, "%s", fingerprint);
908 silc_free(fingerprint);
910 /* Ask user to verify the key and save it */
911 if (silc_client_ask_yes_no(client,
912 "Would you like to accept the key (y/n)? "))
914 /* Save the key for future checking */
915 silc_pkcs_save_public_key_data(filename, pk, pk_len,
920 /* The key already exists, verify it. */
921 SilcPublicKey public_key;
922 unsigned char *encpk;
923 unsigned int encpk_len;
925 /* Load the key file */
926 if (!silc_pkcs_load_public_key(filename, &public_key,
928 if (!silc_pkcs_load_public_key(filename, &public_key,
929 SILC_PKCS_FILE_BIN)) {
930 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
931 silc_say(client, conn, "Received %s %s public key", entity, hostname);
932 silc_say(client, conn, "Fingerprint for the %s %s key is",
934 silc_say(client, conn, "%s", fingerprint);
935 silc_free(fingerprint);
936 silc_say(client, conn, "Could not load your local copy of the %s %s key",
938 if (silc_client_ask_yes_no(client,
939 "Would you like to accept the key anyway (y/n)? "))
941 /* Save the key for future checking */
943 silc_pkcs_save_public_key_data(filename, pk, pk_len,
951 /* Encode the key data */
952 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
954 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
955 silc_say(client, conn, "Received %s %s public key", entity, hostname);
956 silc_say(client, conn, "Fingerprint for the %s %s key is",
958 silc_say(client, conn, "%s", fingerprint);
959 silc_free(fingerprint);
960 silc_say(client, conn, "Your local copy of the %s %s key is malformed",
962 if (silc_client_ask_yes_no(client,
963 "Would you like to accept the key anyway (y/n)? "))
965 /* Save the key for future checking */
967 silc_pkcs_save_public_key_data(filename, pk, pk_len,
975 if (memcmp(encpk, pk, encpk_len)) {
976 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
977 silc_say(client, conn, "Received %s %s public key", entity, hostname);
978 silc_say(client, conn, "Fingerprint for the %s %s key is",
980 silc_say(client, conn, "%s", fingerprint);
981 silc_free(fingerprint);
982 silc_say(client, conn, "%s %s key does not match with your local copy",
984 silc_say(client, conn, "It is possible that the key has expired or changed");
985 silc_say(client, conn, "It is also possible that some one is performing "
986 "man-in-the-middle attack");
988 /* Ask user to verify the key and save it */
989 if (silc_client_ask_yes_no(client,
990 "Would you like to accept the key anyway (y/n)? "))
992 /* Save the key for future checking */
994 silc_pkcs_save_public_key_data(filename, pk, pk_len,
999 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
1003 /* Local copy matched */
1007 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
1011 /* Find authentication method and authentication data by hostname and
1012 port. The hostname may be IP address as well. The found authentication
1013 method and authentication data is returned to `auth_meth', `auth_data'
1014 and `auth_data_len'. The function returns TRUE if authentication method
1015 is found and FALSE if not. `conn' may be NULL. */
1017 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1018 char *hostname, unsigned short port,
1019 SilcProtocolAuthMeth *auth_meth,
1020 unsigned char **auth_data,
1021 unsigned int *auth_data_len)
1023 SilcClientInternal app = (SilcClientInternal)client->application;
1025 if (app->config->conns) {
1026 SilcClientConfigSectionConnection *conn = NULL;
1028 /* Check if we find a match from user configured connections */
1029 conn = silc_client_config_find_connection(app->config,
1033 /* Match found. Use the configured authentication method */
1034 *auth_meth = conn->auth_meth;
1036 if (conn->auth_data) {
1037 *auth_data = strdup(conn->auth_data);
1038 *auth_data_len = strlen(conn->auth_data);
1045 *auth_meth = SILC_AUTH_NONE;
1052 /* Notifies application that failure packet was received. This is called
1053 if there is some protocol active in the client. The `protocol' is the
1054 protocol context. The `failure' is opaque pointer to the failure
1055 indication. Note, that the `failure' is protocol dependant and application
1056 must explicitly cast it to correct type. Usually `failure' is 32 bit
1057 failure type (see protocol specs for all protocol failure types). */
1059 void silc_failure(SilcClient client, SilcClientConnection conn,
1060 SilcProtocol protocol, void *failure)
1065 /* Asks whether the user would like to perform the key agreement protocol.
1066 This is called after we have received an key agreement packet or an
1067 reply to our key agreement packet. This returns TRUE if the user wants
1068 the library to perform the key agreement protocol and FALSE if it is not
1069 desired (application may start it later by calling the function
1070 silc_client_perform_key_agreement). */
1072 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1073 SilcClientEntry client_entry, char *hostname,
1075 SilcKeyAgreementCallback *completion,
1080 /* We will just display the info on the screen and return FALSE and user
1081 will have to start the key agreement with a command. */
1084 memset(host, 0, sizeof(host));
1085 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1088 silc_say(client, conn, "%s wants to perform key agreement %s",
1089 client_entry->nickname, hostname ? host : "");
1097 /* SILC client operations */
1098 SilcClientOperations ops = {
1100 channel_message: silc_channel_message,
1101 private_message: silc_private_message,
1102 notify: silc_notify,
1103 command: silc_command,
1104 command_reply: silc_command_reply,
1105 connect: silc_connect,
1106 disconnect: silc_disconnect,
1107 get_auth_method: silc_get_auth_method,
1108 verify_public_key: silc_verify_public_key,
1109 ask_passphrase: silc_ask_passphrase,
1110 failure: silc_failure,
1111 key_agreement: silc_key_agreement,