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;
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, uint32);
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, uint32);
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 ? ")" : "");
324 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
326 SilcClientEntry *clients;
327 uint32 clients_count;
330 (void)va_arg(vp, void *);
331 clients = va_arg(vp, SilcClientEntry *);
332 clients_count = va_arg(vp, uint32);
334 for (i = 0; i < clients_count; i++) {
335 if (clients[i]->server)
336 snprintf(message, sizeof(message), "Server signoff: %s@%s %s%s%s",
337 clients[i]->nickname, clients[i]->server,
338 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
340 snprintf(message, sizeof(message), "Server signoff: %s %s%s%s",
341 clients[i]->nickname,
342 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
343 silc_print(client, "*** %s", message);
344 memset(message, 0, sizeof(message));
353 silc_print(client, "*** %s", message);
356 /* Command handler. This function is called always in the command function.
357 If error occurs it will be called as well. `conn' is the associated
358 client connection. `cmd_context' is the command context that was
359 originally sent to the command. `success' is FALSE if error occured
360 during command. `command' is the command being processed. It must be
361 noted that this is not reply from server. This is merely called just
362 after application has called the command. Just to tell application
363 that the command really was processed. */
365 void silc_command(SilcClient client, SilcClientConnection conn,
366 SilcClientCommandContext cmd_context, int success,
369 SilcClientInternal app = (SilcClientInternal)client->application;
377 case SILC_COMMAND_QUIT:
378 app->screen->bottom_line->channel = NULL;
379 silc_screen_print_bottom_line(app->screen, 0);
382 case SILC_COMMAND_LEAVE:
384 if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
385 app->screen->bottom_line->channel = NULL;
386 silc_screen_print_bottom_line(app->screen, 0);
394 /* We've resolved all clients we don't know about, now just print the
395 users from the channel on the screen. */
397 void silc_client_show_users(SilcClient client,
398 SilcClientConnection conn,
399 SilcClientEntry *clients,
400 uint32 clients_count,
403 SilcChannelEntry channel = (SilcChannelEntry)context;
405 int k = 0, len1 = 0, len2 = 0;
406 char *name_list = NULL;
411 silc_list_start(channel->clients);
412 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
413 char *m, *n = chu->client->nickname;
420 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
422 m = silc_client_chumode_char(chu->mode);
424 memcpy(name_list + (len1 - len2), m, strlen(m));
429 memcpy(name_list + (len1 - len2), n, len2);
432 if (k == silc_list_count(channel->clients) - 1)
434 memcpy(name_list + len1, " ", 1);
439 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
441 silc_free(name_list);
444 /* Command reply handler. This function is called always in the command reply
445 function. If error occurs it will be called as well. Normal scenario
446 is that it will be called after the received command data has been parsed
447 and processed. The function is used to pass the received command data to
450 `conn' is the associated client connection. `cmd_payload' is the command
451 payload data received from server and it can be ignored. It is provided
452 if the application would like to re-parse the received command data,
453 however, it must be noted that the data is parsed already by the library
454 thus the payload can be ignored. `success' is FALSE if error occured.
455 In this case arguments are not sent to the application. `command' is the
456 command reply being processed. The function has variable argument list
457 and each command defines the number and type of arguments it passes to the
458 application (on error they are not sent). */
460 void silc_command_reply(SilcClient client, SilcClientConnection conn,
461 SilcCommandPayload cmd_payload, int success,
462 SilcCommand command, SilcCommandStatus status, ...)
464 SilcClientInternal app = (SilcClientInternal)client->application;
468 va_start(vp, status);
472 case SILC_COMMAND_WHOIS:
474 char buf[1024], *nickname, *username, *realname;
479 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
480 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
482 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
485 client->ops->say(client, conn, "%s: %s", tmp,
486 silc_client_command_status_message(status));
488 client->ops->say(client, conn, "%s",
489 silc_client_command_status_message(status));
496 (void)va_arg(vp, SilcClientEntry);
497 nickname = va_arg(vp, char *);
498 username = va_arg(vp, char *);
499 realname = va_arg(vp, char *);
500 channels = va_arg(vp, SilcBuffer);
501 mode = va_arg(vp, uint32);
502 idle = va_arg(vp, uint32);
504 memset(buf, 0, sizeof(buf));
507 len = strlen(nickname);
508 strncat(buf, nickname, len);
509 strncat(buf, " is ", 4);
513 strncat(buf, username, strlen(username));
517 strncat(buf, " (", 2);
518 strncat(buf, realname, strlen(realname));
519 strncat(buf, ")", 1);
522 client->ops->say(client, conn, "%s", buf);
525 SilcDList list = silc_channel_payload_parse_list(channels);
527 SilcChannelPayload entry;
529 memset(buf, 0, sizeof(buf));
530 strcat(buf, "on channels: ");
532 silc_dlist_start(list);
533 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
534 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
536 char *name = silc_channel_get_name(entry, &name_len);
539 strncat(buf, m, strlen(m));
540 strncat(buf, name, name_len);
541 strncat(buf, " ", 1);
545 client->ops->say(client, conn, "%s", buf);
546 silc_channel_payload_list_free(list);
551 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
552 (mode & SILC_UMODE_ROUTER_OPERATOR))
553 client->ops->say(client, conn, "%s is %s", nickname,
554 (mode & SILC_UMODE_SERVER_OPERATOR) ?
556 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
557 "SILC Operator" : "[Unknown mode]");
559 if (mode & SILC_UMODE_GONE)
560 client->ops->say(client, conn, "%s is gone", nickname);
563 if (idle && nickname)
564 client->ops->say(client, conn, "%s has been idle %d %s",
566 idle > 60 ? (idle / 60) : idle,
567 idle > 60 ? "minutes" : "seconds");
571 case SILC_COMMAND_WHOWAS:
573 char buf[1024], *nickname, *username, *realname;
576 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
577 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
579 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
582 client->ops->say(client, conn, "%s: %s", tmp,
583 silc_client_command_status_message(status));
585 client->ops->say(client, conn, "%s",
586 silc_client_command_status_message(status));
593 (void)va_arg(vp, SilcClientEntry);
594 nickname = va_arg(vp, char *);
595 username = va_arg(vp, char *);
596 realname = va_arg(vp, char *);
598 memset(buf, 0, sizeof(buf));
601 len = strlen(nickname);
602 strncat(buf, nickname, len);
603 strncat(buf, " was ", 5);
607 strncat(buf, username, strlen(nickname));
611 strncat(buf, " (", 2);
612 strncat(buf, realname, strlen(realname));
613 strncat(buf, ")", 1);
616 client->ops->say(client, conn, "%s", buf);
620 case SILC_COMMAND_INVITE:
622 SilcChannelEntry channel;
628 channel = va_arg(vp, SilcChannelEntry);
629 invite_list = va_arg(vp, char *);
632 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
635 silc_say(client, conn, "%s invite list not set",
636 channel->channel_name);
640 case SILC_COMMAND_JOIN:
644 SilcBuffer client_id_list;
646 SilcChannelEntry channel;
651 app->screen->bottom_line->channel = va_arg(vp, char *);
652 channel = va_arg(vp, SilcChannelEntry);
653 mode = va_arg(vp, uint32);
654 (void)va_arg(vp, uint32);
655 (void)va_arg(vp, unsigned char *);
656 (void)va_arg(vp, unsigned char *);
657 (void)va_arg(vp, unsigned char *);
658 topic = va_arg(vp, char *);
659 (void)va_arg(vp, unsigned char *);
660 list_count = va_arg(vp, uint32);
661 client_id_list = va_arg(vp, SilcBuffer);
664 client->ops->say(client, conn, "Topic for %s: %s",
665 app->screen->bottom_line->channel, topic);
667 app->screen->bottom_line->channel_mode =
668 silc_client_chmode(mode, channel);
669 silc_screen_print_bottom_line(app->screen, 0);
671 /* Resolve the client information */
672 silc_client_get_clients_by_list(client, conn, list_count,
674 silc_client_show_users, channel);
678 case SILC_COMMAND_NICK:
680 SilcClientEntry entry;
685 entry = va_arg(vp, SilcClientEntry);
686 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
687 app->screen->bottom_line->nickname = entry->nickname;
688 silc_screen_print_bottom_line(app->screen, 0);
692 case SILC_COMMAND_LIST:
696 unsigned char buf[256], tmp[16];
702 (void)va_arg(vp, SilcChannelEntry);
703 name = va_arg(vp, char *);
704 topic = va_arg(vp, char *);
705 usercount = va_arg(vp, int);
707 if (status == SILC_STATUS_LIST_START ||
708 status == SILC_STATUS_OK)
709 silc_say(client, conn,
710 " Channel Users Topic");
712 memset(buf, 0, sizeof(buf));
713 strncat(buf, " ", 2);
715 strncat(buf, name, len > 40 ? 40 : len);
717 for (i = 0; i < 40 - len; i++)
721 memset(tmp, 0, sizeof(tmp));
723 snprintf(tmp, sizeof(tmp), "%d", usercount);
728 for (i = 0; i < 10 - len; i++)
734 strncat(buf, topic, len);
737 silc_say(client, conn, "%s", buf);
741 case SILC_COMMAND_UMODE:
748 mode = va_arg(vp, uint32);
750 if (!mode && app->screen->bottom_line->umode) {
751 silc_free(app->screen->bottom_line->umode);
752 app->screen->bottom_line->umode = NULL;
755 if (mode & SILC_UMODE_SERVER_OPERATOR) {
756 if (app->screen->bottom_line->umode)
757 silc_free(app->screen->bottom_line->umode);
758 app->screen->bottom_line->umode = strdup("Server Operator");;
761 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
762 if (app->screen->bottom_line->umode)
763 silc_free(app->screen->bottom_line->umode);
764 app->screen->bottom_line->umode = strdup("SILC Operator");;
767 silc_screen_print_bottom_line(app->screen, 0);
771 case SILC_COMMAND_OPER:
772 if (status == SILC_STATUS_OK) {
773 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
774 if (app->screen->bottom_line->umode)
775 silc_free(app->screen->bottom_line->umode);
776 app->screen->bottom_line->umode = strdup("Server Operator");;
777 silc_screen_print_bottom_line(app->screen, 0);
781 case SILC_COMMAND_SILCOPER:
782 if (status == SILC_STATUS_OK) {
783 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
784 if (app->screen->bottom_line->umode)
785 silc_free(app->screen->bottom_line->umode);
786 app->screen->bottom_line->umode = strdup("SILC Operator");;
787 silc_screen_print_bottom_line(app->screen, 0);
791 case SILC_COMMAND_USERS:
793 SilcChannelEntry channel;
800 channel = va_arg(vp, SilcChannelEntry);
802 /* There are two ways to do this, either parse the list (that
803 the command_reply sends (just take it with va_arg())) or just
804 traverse the channel'c client list. I'll do the latter. See
805 JOIN command reply for example for the list. */
807 silc_say(client, conn, "Users on %s", channel->channel_name);
809 line = silc_calloc(1024, sizeof(*line));
811 silc_list_start(channel->clients);
812 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
813 SilcClientEntry e = chu->client;
817 memset(line, 0, line_len);
819 if (chu->client == conn->local_entry) {
820 /* Update status line */
821 if (app->screen->bottom_line->mode)
822 silc_free(app->screen->bottom_line->mode);
823 app->screen->bottom_line->mode =
824 silc_client_chumode_char(chu->mode);
825 silc_screen_print_bottom_line(app->screen, 0);
828 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
830 line_len += strlen(e->nickname) + strlen(e->server) + 100;
831 line = silc_calloc(line_len, sizeof(*line));
834 memset(tmp, 0, sizeof(tmp));
835 m = silc_client_chumode_char(chu->mode);
837 strncat(line, " ", 1);
838 strncat(line, e->nickname, strlen(e->nickname));
839 strncat(line, e->server ? "@" : "", 1);
843 len1 = strlen(e->server);
844 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
848 memset(&line[29], 0, len1 - 29);
850 for (i = 0; i < 30 - len1 - 1; i++)
854 if (e->mode & SILC_UMODE_GONE)
858 strcat(tmp, m ? m : "");
859 strncat(line, tmp, strlen(tmp));
862 for (i = 0; i < 5 - strlen(tmp); i++)
865 strcat(line, e->username ? e->username : "");
867 silc_say(client, conn, "%s", line);
877 case SILC_COMMAND_BAN:
879 SilcChannelEntry channel;
885 channel = va_arg(vp, SilcChannelEntry);
886 ban_list = va_arg(vp, char *);
889 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
892 silc_say(client, conn, "%s ban list not set", channel->channel_name);
896 case SILC_COMMAND_GETKEY:
900 SilcPublicKey public_key;
904 id_type = va_arg(vp, SilcIdType);
905 entry = va_arg(vp, void *);
906 public_key = va_arg(vp, SilcPublicKey);
908 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
910 if (id_type == SILC_ID_CLIENT) {
911 silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
912 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
923 /* Called to indicate that connection was either successfully established
924 or connecting failed. This is also the first time application receives
925 the SilcClientConnection objecet which it should save somewhere. */
927 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
929 SilcClientInternal app = (SilcClientInternal)client->application;
932 app->screen->bottom_line->connection = conn->remote_host;
933 silc_screen_print_bottom_line(app->screen, 0);
938 /* Called to indicate that connection was disconnected to the server. */
940 void silc_disconnect(SilcClient client, SilcClientConnection conn)
942 SilcClientInternal app = (SilcClientInternal)client->application;
944 app->screen->bottom_line->connection = NULL;
945 silc_screen_print_bottom_line(app->screen, 0);
949 /* Asks passphrase from user on the input line. */
951 unsigned char *silc_ask_passphrase(SilcClient client,
952 SilcClientConnection conn)
954 SilcClientInternal app = (SilcClientInternal)conn->client->application;
955 char pass1[256], pass2[256];
962 wattroff(app->screen->input_win, A_INVIS);
963 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
964 wattron(app->screen->input_win, A_INVIS);
967 memset(pass1, 0, sizeof(pass1));
968 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
970 /* Print retype prompt */
971 wattroff(app->screen->input_win, A_INVIS);
972 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
973 wattron(app->screen->input_win, A_INVIS);
976 memset(pass2, 0, sizeof(pass2));
977 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
979 if (!strncmp(pass1, pass2, strlen(pass2)))
985 ret = silc_calloc(strlen(pass1), sizeof(char));
986 memcpy(ret, pass1, strlen(pass1));
988 memset(pass1, 0, sizeof(pass1));
989 memset(pass2, 0, sizeof(pass2));
991 wattroff(app->screen->input_win, A_INVIS);
992 silc_screen_input_reset(app->screen);
997 /* Verifies received public key. If user decides to trust the key it is
998 saved as public server key for later use. If user does not trust the
999 key this returns FALSE. */
1001 int silc_verify_public_key(SilcClient client,
1002 SilcClientConnection conn,
1003 SilcSocketType conn_type,
1004 unsigned char *pk, uint32 pk_len,
1005 SilcSKEPKType pk_type)
1007 SilcSocketConnection sock = conn->sock;
1010 char *hostname, *fingerprint;
1013 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1014 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1015 "server" : "client");
1017 hostname = sock->hostname ? sock->hostname : sock->ip;
1019 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1020 silc_say(client, conn, "We don't support %s %s key type",
1025 pw = getpwuid(getuid());
1029 memset(filename, 0, sizeof(filename));
1030 memset(file, 0, sizeof(file));
1031 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, hostname,
1033 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1034 pw->pw_dir, entity, file);
1036 /* Check wheter this key already exists */
1037 if (stat(filename, &st) < 0) {
1039 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1040 silc_say(client, conn, "Received %s %s public key", entity, hostname);
1041 silc_say(client, conn, "Fingerprint for the %s %s key is", entity,
1043 silc_say(client, conn, "%s", fingerprint);
1044 silc_free(fingerprint);
1046 /* Ask user to verify the key and save it */
1047 if (silc_client_ask_yes_no(client,
1048 "Would you like to accept the key (y/n)? "))
1050 /* Save the key for future checking */
1051 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1052 SILC_PKCS_FILE_PEM);
1056 /* The key already exists, verify it. */
1057 SilcPublicKey public_key;
1058 unsigned char *encpk;
1061 /* Load the key file */
1062 if (!silc_pkcs_load_public_key(filename, &public_key,
1063 SILC_PKCS_FILE_PEM))
1064 if (!silc_pkcs_load_public_key(filename, &public_key,
1065 SILC_PKCS_FILE_BIN)) {
1066 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1067 silc_say(client, conn, "Received %s %s public key", entity, hostname);
1068 silc_say(client, conn, "Fingerprint for the %s %s key is",
1070 silc_say(client, conn, "%s", fingerprint);
1071 silc_free(fingerprint);
1072 silc_say(client, conn, "Could not load your local copy of the %s %s key",
1074 if (silc_client_ask_yes_no(client,
1075 "Would you like to accept the key anyway (y/n)? "))
1077 /* Save the key for future checking */
1079 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1080 SILC_PKCS_FILE_PEM);
1087 /* Encode the key data */
1088 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1090 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1091 silc_say(client, conn, "Received %s %s public key", entity, hostname);
1092 silc_say(client, conn, "Fingerprint for the %s %s key is",
1094 silc_say(client, conn, "%s", fingerprint);
1095 silc_free(fingerprint);
1096 silc_say(client, conn, "Your local copy of the %s %s key is malformed",
1098 if (silc_client_ask_yes_no(client,
1099 "Would you like to accept the key anyway (y/n)? "))
1101 /* Save the key for future checking */
1103 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1104 SILC_PKCS_FILE_PEM);
1111 if (memcmp(encpk, pk, encpk_len)) {
1112 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1113 silc_say(client, conn, "Received %s %s public key", entity, hostname);
1114 silc_say(client, conn, "Fingerprint for the %s %s key is",
1116 silc_say(client, conn, "%s", fingerprint);
1117 silc_free(fingerprint);
1118 silc_say(client, conn, "%s %s key does not match with your local copy",
1120 silc_say(client, conn, "It is possible that the key has expired or changed");
1121 silc_say(client, conn, "It is also possible that some one is performing "
1122 "man-in-the-middle attack");
1124 /* Ask user to verify the key and save it */
1125 if (silc_client_ask_yes_no(client,
1126 "Would you like to accept the key anyway (y/n)? "))
1128 /* Save the key for future checking */
1130 silc_pkcs_save_public_key_data(filename, pk, pk_len,
1131 SILC_PKCS_FILE_PEM);
1135 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
1139 /* Local copy matched */
1143 silc_say(client, conn, "Will not accept %s %s key", entity, hostname);
1147 /* Find authentication method and authentication data by hostname and
1148 port. The hostname may be IP address as well. The found authentication
1149 method and authentication data is returned to `auth_meth', `auth_data'
1150 and `auth_data_len'. The function returns TRUE if authentication method
1151 is found and FALSE if not. `conn' may be NULL. */
1153 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1154 char *hostname, uint16 port,
1155 SilcProtocolAuthMeth *auth_meth,
1156 unsigned char **auth_data,
1157 uint32 *auth_data_len)
1159 SilcClientInternal app = (SilcClientInternal)client->application;
1161 if (app->config->conns) {
1162 SilcClientConfigSectionConnection *conn = NULL;
1164 /* Check if we find a match from user configured connections */
1165 conn = silc_client_config_find_connection(app->config,
1169 /* Match found. Use the configured authentication method */
1170 *auth_meth = conn->auth_meth;
1172 if (conn->auth_data) {
1173 *auth_data = strdup(conn->auth_data);
1174 *auth_data_len = strlen(conn->auth_data);
1181 *auth_meth = SILC_AUTH_NONE;
1188 /* Notifies application that failure packet was received. This is called
1189 if there is some protocol active in the client. The `protocol' is the
1190 protocol context. The `failure' is opaque pointer to the failure
1191 indication. Note, that the `failure' is protocol dependant and application
1192 must explicitly cast it to correct type. Usually `failure' is 32 bit
1193 failure type (see protocol specs for all protocol failure types). */
1195 void silc_failure(SilcClient client, SilcClientConnection conn,
1196 SilcProtocol protocol, void *failure)
1201 /* Asks whether the user would like to perform the key agreement protocol.
1202 This is called after we have received an key agreement packet or an
1203 reply to our key agreement packet. This returns TRUE if the user wants
1204 the library to perform the key agreement protocol and FALSE if it is not
1205 desired (application may start it later by calling the function
1206 silc_client_perform_key_agreement). */
1208 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1209 SilcClientEntry client_entry, char *hostname,
1211 SilcKeyAgreementCallback *completion,
1216 /* We will just display the info on the screen and return FALSE and user
1217 will have to start the key agreement with a command. */
1220 memset(host, 0, sizeof(host));
1221 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1224 silc_say(client, conn, "%s wants to perform key agreement %s",
1225 client_entry->nickname, hostname ? host : "");
1233 /* SILC client operations */
1234 SilcClientOperations ops = {
1236 channel_message: silc_channel_message,
1237 private_message: silc_private_message,
1238 notify: silc_notify,
1239 command: silc_command,
1240 command_reply: silc_command_reply,
1241 connect: silc_connect,
1242 disconnect: silc_disconnect,
1243 get_auth_method: silc_get_auth_method,
1244 verify_public_key: silc_verify_public_key,
1245 ask_passphrase: silc_ask_passphrase,
1246 failure: silc_failure,
1247 key_agreement: silc_key_agreement,