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);
213 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
214 client_entry->nickname, tmp);
216 snprintf(message, sizeof(message),
217 "channel mode was changed to +%s (forced by router)",
222 snprintf(message, sizeof(message), "%s removed all channel modes",
223 client_entry->nickname);
225 snprintf(message, sizeof(message),
226 "Removed all channel modes (forced by router)");
230 if (app->screen->bottom_line->channel_mode)
231 silc_free(app->screen->bottom_line->channel_mode);
232 app->screen->bottom_line->channel_mode = tmp;
233 silc_screen_print_bottom_line(app->screen, 0);
236 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
237 client_entry = va_arg(vp, SilcClientEntry);
238 tmp_int = va_arg(vp, unsigned int);
239 tmp = silc_client_chumode(tmp_int);
240 client_entry2 = va_arg(vp, SilcClientEntry);
241 channel_entry = va_arg(vp, SilcChannelEntry);
243 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
244 client_entry->nickname, client_entry2->nickname, tmp);
246 snprintf(message, sizeof(message), "%s removed %s's modes",
247 client_entry->nickname, client_entry2->nickname);
248 if (client_entry2 == conn->local_entry) {
249 if (app->screen->bottom_line->mode)
250 silc_free(app->screen->bottom_line->mode);
251 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
252 silc_screen_print_bottom_line(app->screen, 0);
257 case SILC_NOTIFY_TYPE_MOTD:
261 tmp = va_arg(vp, unsigned char *);
265 if (tmp[i++] == '\n') {
266 memset(line, 0, sizeof(line));
267 strncat(line, tmp, i - 1);
270 silc_say(client, conn, "%s", line);
280 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
284 case SILC_NOTIFY_TYPE_KICKED:
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 kicked off channel %s %s%s%s",
292 conn->current_channel->channel_name,
293 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
295 snprintf(message, sizeof(message),
296 "%s%s%s has been kicked off channel %s %s%s%s",
297 client_entry->nickname,
298 client_entry->server ? "@" : "",
299 client_entry->server ? client_entry->server : "",
300 conn->current_channel->channel_name,
301 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
305 case SILC_NOTIFY_TYPE_KILLED:
306 client_entry = va_arg(vp, SilcClientEntry);
307 tmp = va_arg(vp, char *);
308 channel_entry = va_arg(vp, SilcChannelEntry);
310 if (client_entry == conn->local_entry) {
311 snprintf(message, sizeof(message),
312 "You have been killed from the SILC Network %s%s%s",
313 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
315 snprintf(message, sizeof(message),
316 "%s%s%s has been killed from the SILC Network %s%s%s",
317 client_entry->nickname,
318 client_entry->server ? "@" : "",
319 client_entry->server ? client_entry->server : "",
320 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
328 silc_print(client, "*** %s", message);
331 /* Command handler. This function is called always in the command function.
332 If error occurs it will be called as well. `conn' is the associated
333 client connection. `cmd_context' is the command context that was
334 originally sent to the command. `success' is FALSE if error occured
335 during command. `command' is the command being processed. It must be
336 noted that this is not reply from server. This is merely called just
337 after application has called the command. Just to tell application
338 that the command really was processed. */
340 void silc_command(SilcClient client, SilcClientConnection conn,
341 SilcClientCommandContext cmd_context, int success,
344 SilcClientInternal app = (SilcClientInternal)client->application;
352 case SILC_COMMAND_QUIT:
353 app->screen->bottom_line->channel = NULL;
354 silc_screen_print_bottom_line(app->screen, 0);
357 case SILC_COMMAND_LEAVE:
359 if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
360 app->screen->bottom_line->channel = NULL;
361 silc_screen_print_bottom_line(app->screen, 0);
369 /* We've resolved all clients we don't know about, now just print the
370 users from the channel on the screen. */
372 void silc_client_show_users(SilcClient client,
373 SilcClientConnection conn,
374 SilcClientEntry *clients,
375 unsigned int clients_count,
378 SilcChannelEntry channel = (SilcChannelEntry)context;
380 int k = 0, len1 = 0, len2 = 0;
381 char *name_list = NULL;
386 silc_list_start(channel->clients);
387 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
388 char *m, *n = chu->client->nickname;
395 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
397 m = silc_client_chumode_char(chu->mode);
399 memcpy(name_list + (len1 - len2), m, strlen(m));
404 memcpy(name_list + (len1 - len2), n, len2);
407 if (k == silc_list_count(channel->clients) - 1)
409 memcpy(name_list + len1, " ", 1);
414 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
416 silc_free(name_list);
419 /* Command reply handler. This function is called always in the command reply
420 function. If error occurs it will be called as well. Normal scenario
421 is that it will be called after the received command data has been parsed
422 and processed. The function is used to pass the received command data to
425 `conn' is the associated client connection. `cmd_payload' is the command
426 payload data received from server and it can be ignored. It is provided
427 if the application would like to re-parse the received command data,
428 however, it must be noted that the data is parsed already by the library
429 thus the payload can be ignored. `success' is FALSE if error occured.
430 In this case arguments are not sent to the application. `command' is the
431 command reply being processed. The function has variable argument list
432 and each command defines the number and type of arguments it passes to the
433 application (on error they are not sent). */
435 void silc_command_reply(SilcClient client, SilcClientConnection conn,
436 SilcCommandPayload cmd_payload, int success,
437 SilcCommand command, SilcCommandStatus status, ...)
439 SilcClientInternal app = (SilcClientInternal)client->application;
443 va_start(vp, status);
447 case SILC_COMMAND_WHOIS:
449 char buf[1024], *nickname, *username, *realname;
451 unsigned int idle, mode;
454 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
455 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
457 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
460 client->ops->say(client, conn, "%s: %s", tmp,
461 silc_client_command_status_message(status));
463 client->ops->say(client, conn, "%s",
464 silc_client_command_status_message(status));
471 (void)va_arg(vp, SilcClientEntry);
472 nickname = va_arg(vp, char *);
473 username = va_arg(vp, char *);
474 realname = va_arg(vp, char *);
475 channels = va_arg(vp, SilcBuffer);
476 mode = va_arg(vp, unsigned int);
477 idle = va_arg(vp, unsigned int);
479 memset(buf, 0, sizeof(buf));
482 len = strlen(nickname);
483 strncat(buf, nickname, len);
484 strncat(buf, " is ", 4);
488 strncat(buf, username, strlen(username));
492 strncat(buf, " (", 2);
493 strncat(buf, realname, strlen(realname));
494 strncat(buf, ")", 1);
497 client->ops->say(client, conn, "%s", buf);
500 SilcDList list = silc_channel_payload_parse_list(channels);
502 SilcChannelPayload entry;
504 memset(buf, 0, sizeof(buf));
505 strcat(buf, "on channels: ");
507 silc_dlist_start(list);
508 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
509 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
510 unsigned int name_len;
511 char *name = silc_channel_get_name(entry, &name_len);
514 strncat(buf, m, strlen(m));
515 strncat(buf, name, name_len);
516 strncat(buf, " ", 1);
520 client->ops->say(client, conn, "%s", buf);
521 silc_channel_payload_list_free(list);
526 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
527 (mode & SILC_UMODE_ROUTER_OPERATOR))
528 client->ops->say(client, conn, "%s is %s", nickname,
529 (mode & SILC_UMODE_SERVER_OPERATOR) ?
531 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
532 "SILC Operator" : "[Unknown mode]");
534 if (mode & SILC_UMODE_GONE)
535 client->ops->say(client, conn, "%s is gone", nickname);
538 if (idle && nickname)
539 client->ops->say(client, conn, "%s has been idle %d %s",
541 idle > 60 ? (idle / 60) : idle,
542 idle > 60 ? "minutes" : "seconds");
546 case SILC_COMMAND_WHOWAS:
548 char buf[1024], *nickname, *username, *realname;
551 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
552 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
554 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
557 client->ops->say(client, conn, "%s: %s", tmp,
558 silc_client_command_status_message(status));
560 client->ops->say(client, conn, "%s",
561 silc_client_command_status_message(status));
568 (void)va_arg(vp, SilcClientEntry);
569 nickname = va_arg(vp, char *);
570 username = va_arg(vp, char *);
571 realname = va_arg(vp, char *);
573 memset(buf, 0, sizeof(buf));
576 len = strlen(nickname);
577 strncat(buf, nickname, len);
578 strncat(buf, " was ", 5);
582 strncat(buf, username, strlen(nickname));
586 strncat(buf, " (", 2);
587 strncat(buf, realname, strlen(realname));
588 strncat(buf, ")", 1);
591 client->ops->say(client, conn, "%s", buf);
595 case SILC_COMMAND_INVITE:
597 SilcChannelEntry channel;
603 channel = va_arg(vp, SilcChannelEntry);
604 invite_list = va_arg(vp, char *);
607 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
610 silc_say(client, conn, "%s invite list not set",
611 channel->channel_name);
615 case SILC_COMMAND_JOIN:
619 SilcBuffer client_id_list;
620 unsigned int list_count;
621 SilcChannelEntry channel;
626 app->screen->bottom_line->channel = va_arg(vp, char *);
627 channel = va_arg(vp, SilcChannelEntry);
628 mode = va_arg(vp, unsigned int);
629 (void)va_arg(vp, unsigned int);
630 (void)va_arg(vp, unsigned char *);
631 (void)va_arg(vp, unsigned char *);
632 (void)va_arg(vp, unsigned char *);
633 topic = va_arg(vp, char *);
634 (void)va_arg(vp, unsigned char *);
635 list_count = va_arg(vp, unsigned int);
636 client_id_list = va_arg(vp, SilcBuffer);
639 client->ops->say(client, conn, "Topic for %s: %s",
640 app->screen->bottom_line->channel, topic);
642 app->screen->bottom_line->channel_mode =
643 silc_client_chmode(mode, channel);
644 silc_screen_print_bottom_line(app->screen, 0);
646 /* Resolve the client information */
647 silc_client_get_clients_by_list(client, conn, list_count,
649 silc_client_show_users, channel);
653 case SILC_COMMAND_NICK:
655 SilcClientEntry entry;
660 entry = va_arg(vp, SilcClientEntry);
661 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
662 app->screen->bottom_line->nickname = entry->nickname;
663 silc_screen_print_bottom_line(app->screen, 0);
667 case SILC_COMMAND_LIST:
670 unsigned int usercount;
671 unsigned char buf[256], tmp[16];
677 (void)va_arg(vp, SilcChannelEntry);
678 name = va_arg(vp, char *);
679 topic = va_arg(vp, char *);
680 usercount = va_arg(vp, unsigned int);
682 if (status == SILC_STATUS_LIST_START ||
683 status == SILC_STATUS_OK)
684 silc_say(client, conn,
685 " Channel Users Topic");
687 memset(buf, 0, sizeof(buf));
688 strncat(buf, " ", 2);
690 strncat(buf, name, len > 40 ? 40 : len);
692 for (i = 0; i < 40 - len; i++)
696 memset(tmp, 0, sizeof(tmp));
698 snprintf(tmp, sizeof(tmp), "%d", usercount);
703 for (i = 0; i < 10 - len; i++)
709 strncat(buf, topic, len);
712 silc_say(client, conn, "%s", buf);
716 case SILC_COMMAND_UMODE:
723 mode = va_arg(vp, unsigned int);
725 if (!mode && app->screen->bottom_line->umode) {
726 silc_free(app->screen->bottom_line->umode);
727 app->screen->bottom_line->umode = NULL;
730 if (mode & SILC_UMODE_SERVER_OPERATOR) {
731 if (app->screen->bottom_line->umode)
732 silc_free(app->screen->bottom_line->umode);
733 app->screen->bottom_line->umode = strdup("Server Operator");;
736 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
737 if (app->screen->bottom_line->umode)
738 silc_free(app->screen->bottom_line->umode);
739 app->screen->bottom_line->umode = strdup("SILC Operator");;
742 silc_screen_print_bottom_line(app->screen, 0);
746 case SILC_COMMAND_OPER:
747 if (status == SILC_STATUS_OK) {
748 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
749 if (app->screen->bottom_line->umode)
750 silc_free(app->screen->bottom_line->umode);
751 app->screen->bottom_line->umode = strdup("Server Operator");;
752 silc_screen_print_bottom_line(app->screen, 0);
756 case SILC_COMMAND_SILCOPER:
757 if (status == SILC_STATUS_OK) {
758 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
759 if (app->screen->bottom_line->umode)
760 silc_free(app->screen->bottom_line->umode);
761 app->screen->bottom_line->umode = strdup("SILC Operator");;
762 silc_screen_print_bottom_line(app->screen, 0);
766 case SILC_COMMAND_USERS:
768 SilcChannelEntry channel;
775 channel = va_arg(vp, SilcChannelEntry);
777 /* There are two ways to do this, either parse the list (that
778 the command_reply sends (just take it with va_arg())) or just
779 traverse the channel'c client list. I'll do the latter. See
780 JOIN command reply for example for the list. */
782 silc_say(client, conn, "Users on %s", channel->channel_name);
784 line = silc_calloc(1024, sizeof(*line));
786 silc_list_start(channel->clients);
787 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
788 SilcClientEntry e = chu->client;
792 memset(line, 0, line_len);
794 if (chu->client == conn->local_entry) {
795 /* Update status line */
796 if (app->screen->bottom_line->mode)
797 silc_free(app->screen->bottom_line->mode);
798 app->screen->bottom_line->mode =
799 silc_client_chumode_char(chu->mode);
800 silc_screen_print_bottom_line(app->screen, 0);
803 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
805 line_len += strlen(e->nickname) + strlen(e->server) + 100;
806 line = silc_calloc(line_len, sizeof(*line));
809 memset(tmp, 0, sizeof(tmp));
810 m = silc_client_chumode_char(chu->mode);
812 strncat(line, " ", 1);
813 strncat(line, e->nickname, strlen(e->nickname));
814 strncat(line, e->server ? "@" : "", 1);
818 len1 = strlen(e->server);
819 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
823 memset(&line[29], 0, len1 - 29);
825 for (i = 0; i < 30 - len1 - 1; i++)
829 if (e->mode & SILC_UMODE_GONE)
833 strcat(tmp, m ? m : "");
834 strncat(line, tmp, strlen(tmp));
837 for (i = 0; i < 5 - strlen(tmp); i++)
840 strcat(line, e->username ? e->username : "");
842 silc_say(client, conn, "%s", line);
852 case SILC_COMMAND_BAN:
854 SilcChannelEntry channel;
860 channel = va_arg(vp, SilcChannelEntry);
861 ban_list = va_arg(vp, char *);
864 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
867 silc_say(client, conn, "%s ban list not set", channel->channel_name);
876 /* Called to indicate that connection was either successfully established
877 or connecting failed. This is also the first time application receives
878 the SilcClientConnection objecet which it should save somewhere. */
880 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
882 SilcClientInternal app = (SilcClientInternal)client->application;
885 app->screen->bottom_line->connection = conn->remote_host;
886 silc_screen_print_bottom_line(app->screen, 0);
891 /* Called to indicate that connection was disconnected to the server. */
893 void silc_disconnect(SilcClient client, SilcClientConnection conn)
895 SilcClientInternal app = (SilcClientInternal)client->application;
897 app->screen->bottom_line->connection = NULL;
898 silc_screen_print_bottom_line(app->screen, 0);
902 /* Asks passphrase from user on the input line. */
904 unsigned char *silc_ask_passphrase(SilcClient client,
905 SilcClientConnection conn)
907 SilcClientInternal app = (SilcClientInternal)conn->client->application;
908 char pass1[256], pass2[256];
915 wattroff(app->screen->input_win, A_INVIS);
916 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
917 wattron(app->screen->input_win, A_INVIS);
920 memset(pass1, 0, sizeof(pass1));
921 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
923 /* Print retype prompt */
924 wattroff(app->screen->input_win, A_INVIS);
925 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
926 wattron(app->screen->input_win, A_INVIS);
929 memset(pass2, 0, sizeof(pass2));
930 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
932 if (!strncmp(pass1, pass2, strlen(pass2)))
938 ret = silc_calloc(strlen(pass1), sizeof(char));
939 memcpy(ret, pass1, strlen(pass1));
941 memset(pass1, 0, sizeof(pass1));
942 memset(pass2, 0, sizeof(pass2));
944 wattroff(app->screen->input_win, A_INVIS);
945 silc_screen_input_reset(app->screen);
950 /* Verifies received public key. If user decides to trust the key it is
951 saved as public server key for later use. If user does not trust the
952 key this returns FALSE. */
954 int silc_verify_public_key(SilcClient client,
955 SilcClientConnection conn,
956 SilcSocketType conn_type,
957 unsigned char *pk, unsigned int pk_len,
958 SilcSKEPKType pk_type)
960 SilcSocketConnection sock = conn->sock;
963 char *hostname, *fingerprint;
966 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
967 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
968 "server" : "client");
970 hostname = sock->hostname ? sock->hostname : sock->ip;
972 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
973 silc_say(client, conn, "We don't support %s %s key type",
978 pw = getpwuid(getuid());
982 memset(filename, 0, sizeof(filename));
983 memset(file, 0, sizeof(file));
984 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, hostname,
986 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
987 pw->pw_dir, entity, file);
989 /* Check wheter this key already exists */
990 if (stat(filename, &st) < 0) {
992 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
993 silc_say(client, conn, "Received %s %s public key", entity, hostname);
994 silc_say(client, conn, "Fingerprint for the %s %s key is", entity,
996 silc_say(client, conn, "%s", fingerprint);
997 silc_free(fingerprint);
999 /* Ask user to verify the key and save it */
1000 if (silc_client_ask_yes_no(client,
1001 "Would you like to accept the key (y/n)? "))
1003 /* Save the key for future checking */
1004 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1005 SILC_PKCS_FILE_PEM);
1009 /* The key already exists, verify it. */
1010 SilcPublicKey public_key;
1011 unsigned char *encpk;
1012 unsigned int encpk_len;
1014 /* Load the key file */
1015 if (!silc_pkcs_load_public_key(filename, &public_key,
1016 SILC_PKCS_FILE_PEM))
1017 if (!silc_pkcs_load_public_key(filename, &public_key,
1018 SILC_PKCS_FILE_BIN)) {
1019 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1020 silc_say(client, conn, "Received %s %s public key", entity, hostname);
1021 silc_say(client, conn, "Fingerprint for the %s %s key is",
1023 silc_say(client, conn, "%s", fingerprint);
1024 silc_free(fingerprint);
1025 silc_say(client, conn, "Could not load your local copy of the %s %s key",
1027 if (silc_client_ask_yes_no(client,
1028 "Would you like to accept the key anyway (y/n)? "))
1030 /* Save the key for future checking */
1032 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1033 SILC_PKCS_FILE_PEM);
1040 /* Encode the key data */
1041 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1043 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1044 silc_say(client, conn, "Received %s %s public key", entity, hostname);
1045 silc_say(client, conn, "Fingerprint for the %s %s key is",
1047 silc_say(client, conn, "%s", fingerprint);
1048 silc_free(fingerprint);
1049 silc_say(client, conn, "Your local copy of the %s %s key is malformed",
1051 if (silc_client_ask_yes_no(client,
1052 "Would you like to accept the key anyway (y/n)? "))
1054 /* Save the key for future checking */
1056 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1057 SILC_PKCS_FILE_PEM);
1064 if (memcmp(encpk, pk, encpk_len)) {
1065 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1066 silc_say(client, conn, "Received %s %s public key", entity, hostname);
1067 silc_say(client, conn, "Fingerprint for the %s %s key is",
1069 silc_say(client, conn, "%s", fingerprint);
1070 silc_free(fingerprint);
1071 silc_say(client, conn, "%s %s key does not match with your local copy",
1073 silc_say(client, conn, "It is possible that the key has expired or changed");
1074 silc_say(client, conn, "It is also possible that some one is performing "
1075 "man-in-the-middle attack");
1077 /* Ask user to verify the key and save it */
1078 if (silc_client_ask_yes_no(client,
1079 "Would you like to accept the key anyway (y/n)? "))
1081 /* Save the key for future checking */
1083 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1084 SILC_PKCS_FILE_PEM);
1088 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
1092 /* Local copy matched */
1096 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
1100 /* Find authentication method and authentication data by hostname and
1101 port. The hostname may be IP address as well. The found authentication
1102 method and authentication data is returned to `auth_meth', `auth_data'
1103 and `auth_data_len'. The function returns TRUE if authentication method
1104 is found and FALSE if not. `conn' may be NULL. */
1106 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1107 char *hostname, unsigned short port,
1108 SilcProtocolAuthMeth *auth_meth,
1109 unsigned char **auth_data,
1110 unsigned int *auth_data_len)
1112 SilcClientInternal app = (SilcClientInternal)client->application;
1114 if (app->config->conns) {
1115 SilcClientConfigSectionConnection *conn = NULL;
1117 /* Check if we find a match from user configured connections */
1118 conn = silc_client_config_find_connection(app->config,
1122 /* Match found. Use the configured authentication method */
1123 *auth_meth = conn->auth_meth;
1125 if (conn->auth_data) {
1126 *auth_data = strdup(conn->auth_data);
1127 *auth_data_len = strlen(conn->auth_data);
1134 *auth_meth = SILC_AUTH_NONE;
1141 /* Notifies application that failure packet was received. This is called
1142 if there is some protocol active in the client. The `protocol' is the
1143 protocol context. The `failure' is opaque pointer to the failure
1144 indication. Note, that the `failure' is protocol dependant and application
1145 must explicitly cast it to correct type. Usually `failure' is 32 bit
1146 failure type (see protocol specs for all protocol failure types). */
1148 void silc_failure(SilcClient client, SilcClientConnection conn,
1149 SilcProtocol protocol, void *failure)
1154 /* Asks whether the user would like to perform the key agreement protocol.
1155 This is called after we have received an key agreement packet or an
1156 reply to our key agreement packet. This returns TRUE if the user wants
1157 the library to perform the key agreement protocol and FALSE if it is not
1158 desired (application may start it later by calling the function
1159 silc_client_perform_key_agreement). */
1161 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1162 SilcClientEntry client_entry, char *hostname,
1164 SilcKeyAgreementCallback *completion,
1169 /* We will just display the info on the screen and return FALSE and user
1170 will have to start the key agreement with a command. */
1173 memset(host, 0, sizeof(host));
1174 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1177 silc_say(client, conn, "%s wants to perform key agreement %s",
1178 client_entry->nickname, hostname ? host : "");
1186 /* SILC client operations */
1187 SilcClientOperations ops = {
1189 channel_message: silc_channel_message,
1190 private_message: silc_private_message,
1191 notify: silc_notify,
1192 command: silc_command,
1193 command_reply: silc_command_reply,
1194 connect: silc_connect,
1195 disconnect: silc_disconnect,
1196 get_auth_method: silc_get_auth_method,
1197 verify_public_key: silc_verify_public_key,
1198 ask_passphrase: silc_ask_passphrase,
1199 failure: silc_failure,
1200 key_agreement: silc_key_agreement,