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"
24 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
25 SilcSocketType conn_type, unsigned char *pk,
26 uint32 pk_len, SilcSKEPKType pk_type)
29 char file[256], filename[256], *fingerprint;
32 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
33 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
36 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
37 silc_say(client, conn, "We don't support %s public key type %d",
42 pw = getpwuid(getuid());
46 memset(filename, 0, sizeof(filename));
47 memset(file, 0, sizeof(file));
49 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
50 conn_type == SILC_SOCKET_TYPE_ROUTER) {
51 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
52 conn->sock->hostname, conn->sock->port);
53 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
54 pw->pw_dir, entity, file);
56 /* Replace all whitespaces with `_'. */
57 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
58 for (i = 0; i < strlen(fingerprint); i++)
59 if (fingerprint[i] == ' ')
62 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
63 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
64 pw->pw_dir, entity, file);
65 silc_free(fingerprint);
68 /* Take fingerprint of the public key */
69 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
71 /* Check whether this key already exists */
72 if (stat(filename, &st) < 0) {
74 silc_say(client, conn, "Received %s public key", entity);
75 silc_say(client, conn, "Fingerprint for the %s key is", entity);
76 silc_say(client, conn, "%s", fingerprint);
78 /* Ask user to verify the key and save it */
79 if (silc_client_ask_yes_no(client,
80 "Would you like to accept the key (y/n)? "))
82 /* Save the key for future checking */
83 silc_pkcs_save_public_key_data(filename, pk, pk_len,
85 silc_free(fingerprint);
89 /* The key already exists, verify it. */
90 SilcPublicKey public_key;
94 /* Load the key file */
95 if (!silc_pkcs_load_public_key(filename, &public_key,
97 if (!silc_pkcs_load_public_key(filename, &public_key,
98 SILC_PKCS_FILE_BIN)) {
99 silc_say(client, conn, "Received %s public key", entity);
100 silc_say(client, conn, "Fingerprint for the %s key is", entity);
101 silc_say(client, conn, "%s", fingerprint);
102 silc_say(client, conn, "Could not load your local copy of the %s key",
104 if (silc_client_ask_yes_no(client,
105 "Would you like to accept the key anyway (y/n)? "))
107 /* Save the key for future checking */
109 silc_pkcs_save_public_key_data(filename, pk, pk_len,
111 silc_free(fingerprint);
115 silc_free(fingerprint);
119 /* Encode the key data */
120 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
122 silc_say(client, conn, "Received %s public key", entity);
123 silc_say(client, conn, "Fingerprint for the %s key is", entity);
124 silc_say(client, conn, "%s", fingerprint);
125 silc_say(client, conn, "Your local copy of the %s key is malformed",
127 if (silc_client_ask_yes_no(client,
128 "Would you like to accept the key anyway (y/n)? "))
130 /* Save the key for future checking */
132 silc_pkcs_save_public_key_data(filename, pk, pk_len,
134 silc_free(fingerprint);
138 silc_free(fingerprint);
142 if (memcmp(encpk, pk, encpk_len)) {
143 silc_say(client, conn, "Received %s public key", entity);
144 silc_say(client, conn, "Fingerprint for the %s key is", entity);
145 silc_say(client, conn, "%s", fingerprint);
146 silc_say(client, conn, "%s key does not match with your local copy",
148 silc_say(client, conn,
149 "It is possible that the key has expired or changed");
150 silc_say(client, conn, "It is also possible that some one is performing "
151 "man-in-the-middle attack");
153 /* Ask user to verify the key and save it */
154 if (silc_client_ask_yes_no(client,
155 "Would you like to accept the key anyway (y/n)? "))
157 /* Save the key for future checking */
159 silc_pkcs_save_public_key_data(filename, pk, pk_len,
161 silc_free(fingerprint);
165 silc_say(client, conn, "Will not accept the %s key", entity);
166 silc_free(fingerprint);
170 /* Local copy matched */
171 silc_free(fingerprint);
175 silc_say(client, conn, "Will not accept the %s key", entity);
176 silc_free(fingerprint);
180 /* Prints a message with three star (*) sign before the actual message
181 on the current output window. This is used to print command outputs
182 and error messages. */
184 void silc_say(SilcClient client, SilcClientConnection conn,
189 SilcClientInternal app = (SilcClientInternal)client->application;
191 memset(message, 0, sizeof(message));
192 strncat(message, "\n*** ", 5);
195 vsprintf(message + 5, msg, vp);
198 /* Print the message */
199 silc_print_to_window(app->screen->output_win[0], message);
202 /* Message for a channel. The `sender' is the nickname of the sender
203 received in the packet. The `channel_name' is the name of the channel. */
205 void silc_channel_message(SilcClient client, SilcClientConnection conn,
206 SilcClientEntry sender, SilcChannelEntry channel,
207 SilcMessageFlags flags, char *msg)
209 /* Message from client */
210 if (conn && !strcmp(conn->current_channel->channel_name,
211 channel->channel_name))
212 if (flags & SILC_MESSAGE_FLAG_ACTION)
213 silc_print(client, "* %s %s", sender ? sender->nickname : "[<unknown>]",
215 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
216 silc_print(client, "- %s %s", sender ? sender->nickname : "[<unknown>]",
219 silc_print(client, "<%s> %s", sender ? sender->nickname : "[<unknown>]",
222 if (flags & SILC_MESSAGE_FLAG_ACTION)
223 silc_print(client, "* %s:%s %s", sender ? sender->nickname :
225 channel->channel_name, msg);
226 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
227 silc_print(client, "- %s:%s %s", sender ? sender->nickname :
229 channel->channel_name, msg);
231 silc_print(client, "<%s:%s> %s", sender ? sender->nickname :
233 channel->channel_name, msg);
236 /* Private message to the client. The `sender' is the nickname of the
237 sender received in the packet. */
239 void silc_private_message(SilcClient client, SilcClientConnection conn,
240 SilcClientEntry sender, SilcMessageFlags flags,
243 silc_print(client, "*%s* %s", sender->nickname, msg);
247 /* Notify message to the client. The notify arguments are sent in the
248 same order as servers sends them. The arguments are same as received
249 from the server except for ID's. If ID is received application receives
250 the corresponding entry to the ID. For example, if Client ID is received
251 application receives SilcClientEntry. Also, if the notify type is
252 for channel the channel entry is sent to application (even if server
253 does not send it). */
255 void silc_notify(SilcClient client, SilcClientConnection conn,
256 SilcNotifyType type, ...)
258 SilcClientInternal app = (SilcClientInternal)client->application;
261 SilcClientEntry client_entry, client_entry2;
262 SilcChannelEntry channel_entry;
268 memset(message, 0, sizeof(message));
270 /* Get arguments (defined by protocol in silc-pp-01 -draft) */
272 case SILC_NOTIFY_TYPE_NONE:
273 tmp = va_arg(vp, char *);
276 strcpy(message, tmp);
279 case SILC_NOTIFY_TYPE_INVITE:
280 (void)va_arg(vp, SilcChannelEntry);
281 tmp = va_arg(vp, char *);
282 client_entry = va_arg(vp, SilcClientEntry);
283 snprintf(message, sizeof(message), "%s invites you to channel %s",
284 client_entry->nickname, tmp);
287 case SILC_NOTIFY_TYPE_JOIN:
288 client_entry = va_arg(vp, SilcClientEntry);
289 channel_entry = va_arg(vp, SilcChannelEntry);
290 snprintf(message, sizeof(message), "%s (%s) has joined channel %s",
291 client_entry->nickname, client_entry->username,
292 channel_entry->channel_name);
293 if (client_entry == conn->local_entry) {
296 silc_list_start(channel_entry->clients);
297 while ((chu = silc_list_get(channel_entry->clients)) != SILC_LIST_END) {
298 if (chu->client == client_entry) {
299 if (app->screen->bottom_line->mode)
300 silc_free(app->screen->bottom_line->mode);
301 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
302 silc_screen_print_bottom_line(app->screen, 0);
309 case SILC_NOTIFY_TYPE_LEAVE:
310 client_entry = va_arg(vp, SilcClientEntry);
311 channel_entry = va_arg(vp, SilcChannelEntry);
312 if (client_entry->server)
313 snprintf(message, sizeof(message), "%s@%s has left channel %s",
314 client_entry->nickname, client_entry->server,
315 channel_entry->channel_name);
317 snprintf(message, sizeof(message), "%s has left channel %s",
318 client_entry->nickname, channel_entry->channel_name);
321 case SILC_NOTIFY_TYPE_SIGNOFF:
322 client_entry = va_arg(vp, SilcClientEntry);
323 tmp = va_arg(vp, char *);
324 if (client_entry->server)
325 snprintf(message, sizeof(message), "Signoff: %s@%s %s%s%s",
326 client_entry->nickname, client_entry->server,
327 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
329 snprintf(message, sizeof(message), "Signoff: %s %s%s%s",
330 client_entry->nickname,
331 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
334 case SILC_NOTIFY_TYPE_TOPIC_SET:
335 client_entry = va_arg(vp, SilcClientEntry);
336 tmp = va_arg(vp, char *);
337 channel_entry = va_arg(vp, SilcChannelEntry);
338 if (client_entry->server)
339 snprintf(message, sizeof(message), "%s@%s set topic on %s: %s",
340 client_entry->nickname, client_entry->server,
341 channel_entry->channel_name, tmp);
343 snprintf(message, sizeof(message), "%s set topic on %s: %s",
344 client_entry->nickname, channel_entry->channel_name, tmp);
347 case SILC_NOTIFY_TYPE_NICK_CHANGE:
348 client_entry = va_arg(vp, SilcClientEntry);
349 client_entry2 = va_arg(vp, SilcClientEntry);
350 if (client_entry->server && client_entry2->server)
351 snprintf(message, sizeof(message), "%s@%s is known as %s@%s",
352 client_entry->nickname, client_entry->server,
353 client_entry2->nickname, client_entry2->server);
355 snprintf(message, sizeof(message), "%s is known as %s",
356 client_entry->nickname, client_entry2->nickname);
359 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
360 client_entry = va_arg(vp, SilcClientEntry);
361 tmp_int = va_arg(vp, uint32);
362 (void)va_arg(vp, char *);
363 (void)va_arg(vp, char *);
364 channel_entry = va_arg(vp, SilcChannelEntry);
366 tmp = silc_client_chmode(tmp_int,
367 channel_entry->channel_key->cipher->name,
368 channel_entry->hmac->hmac->name);
372 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
373 client_entry->nickname, tmp);
375 snprintf(message, sizeof(message),
376 "channel mode was changed to +%s (forced by router)",
381 snprintf(message, sizeof(message), "%s removed all channel modes",
382 client_entry->nickname);
384 snprintf(message, sizeof(message),
385 "Removed all channel modes (forced by router)");
389 if (app->screen->bottom_line->channel_mode)
390 silc_free(app->screen->bottom_line->channel_mode);
391 app->screen->bottom_line->channel_mode = tmp;
392 silc_screen_print_bottom_line(app->screen, 0);
395 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
396 client_entry = va_arg(vp, SilcClientEntry);
397 tmp_int = va_arg(vp, uint32);
398 tmp = silc_client_chumode(tmp_int);
399 client_entry2 = va_arg(vp, SilcClientEntry);
400 channel_entry = va_arg(vp, SilcChannelEntry);
402 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
403 client_entry->nickname, client_entry2->nickname, tmp);
405 snprintf(message, sizeof(message), "%s removed %s's modes",
406 client_entry->nickname, client_entry2->nickname);
407 if (client_entry2 == conn->local_entry) {
408 if (app->screen->bottom_line->mode)
409 silc_free(app->screen->bottom_line->mode);
410 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
411 silc_screen_print_bottom_line(app->screen, 0);
416 case SILC_NOTIFY_TYPE_MOTD:
420 tmp = va_arg(vp, unsigned char *);
424 if (tmp[i++] == '\n') {
425 memset(line, 0, sizeof(line));
426 strncat(line, tmp, i - 1);
429 silc_say(client, conn, "%s", line);
439 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
443 case SILC_NOTIFY_TYPE_KICKED:
444 client_entry = va_arg(vp, SilcClientEntry);
445 tmp = va_arg(vp, char *);
446 channel_entry = va_arg(vp, SilcChannelEntry);
448 if (client_entry == conn->local_entry) {
449 snprintf(message, sizeof(message),
450 "You have been kicked off channel %s %s%s%s",
451 conn->current_channel->channel_name,
452 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
454 snprintf(message, sizeof(message),
455 "%s%s%s has been kicked off channel %s %s%s%s",
456 client_entry->nickname,
457 client_entry->server ? "@" : "",
458 client_entry->server ? client_entry->server : "",
459 conn->current_channel->channel_name,
460 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
464 case SILC_NOTIFY_TYPE_KILLED:
465 client_entry = va_arg(vp, SilcClientEntry);
466 tmp = va_arg(vp, char *);
467 channel_entry = va_arg(vp, SilcChannelEntry);
469 if (client_entry == conn->local_entry) {
470 snprintf(message, sizeof(message),
471 "You have been killed from the SILC Network %s%s%s",
472 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
474 snprintf(message, sizeof(message),
475 "%s%s%s has been killed from the SILC Network %s%s%s",
476 client_entry->nickname,
477 client_entry->server ? "@" : "",
478 client_entry->server ? client_entry->server : "",
479 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
483 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
485 SilcClientEntry *clients;
486 uint32 clients_count;
489 (void)va_arg(vp, void *);
490 clients = va_arg(vp, SilcClientEntry *);
491 clients_count = va_arg(vp, uint32);
493 for (i = 0; i < clients_count; i++) {
494 if (clients[i]->server)
495 snprintf(message, sizeof(message), "Server signoff: %s@%s %s%s%s",
496 clients[i]->nickname, clients[i]->server,
497 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
499 snprintf(message, sizeof(message), "Server signoff: %s %s%s%s",
500 clients[i]->nickname,
501 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
502 silc_print(client, "*** %s", message);
503 memset(message, 0, sizeof(message));
512 silc_print(client, "*** %s", message);
515 /* Command handler. This function is called always in the command function.
516 If error occurs it will be called as well. `conn' is the associated
517 client connection. `cmd_context' is the command context that was
518 originally sent to the command. `success' is FALSE if error occured
519 during command. `command' is the command being processed. It must be
520 noted that this is not reply from server. This is merely called just
521 after application has called the command. Just to tell application
522 that the command really was processed. */
524 void silc_command(SilcClient client, SilcClientConnection conn,
525 SilcClientCommandContext cmd_context, int success,
528 SilcClientInternal app = (SilcClientInternal)client->application;
536 case SILC_COMMAND_QUIT:
537 app->screen->bottom_line->channel = NULL;
538 silc_screen_print_bottom_line(app->screen, 0);
541 case SILC_COMMAND_LEAVE:
542 /* We won't talk anymore on this channel */
543 silc_say(client, conn, "You have left channel %s",
544 conn->current_channel->channel_name);
550 /* We've resolved all clients we don't know about, now just print the
551 users from the channel on the screen. */
553 void silc_client_show_users(SilcClient client,
554 SilcClientConnection conn,
555 SilcClientEntry *clients,
556 uint32 clients_count,
559 SilcChannelEntry channel = (SilcChannelEntry)context;
561 int k = 0, len1 = 0, len2 = 0;
562 char *name_list = NULL;
567 silc_list_start(channel->clients);
568 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
569 char *m, *n = chu->client->nickname;
576 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
578 m = silc_client_chumode_char(chu->mode);
580 memcpy(name_list + (len1 - len2), m, strlen(m));
585 memcpy(name_list + (len1 - len2), n, len2);
588 if (k == silc_list_count(channel->clients) - 1)
590 memcpy(name_list + len1, " ", 1);
595 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
597 silc_free(name_list);
600 /* Command reply handler. This function is called always in the command reply
601 function. If error occurs it will be called as well. Normal scenario
602 is that it will be called after the received command data has been parsed
603 and processed. The function is used to pass the received command data to
606 `conn' is the associated client connection. `cmd_payload' is the command
607 payload data received from server and it can be ignored. It is provided
608 if the application would like to re-parse the received command data,
609 however, it must be noted that the data is parsed already by the library
610 thus the payload can be ignored. `success' is FALSE if error occured.
611 In this case arguments are not sent to the application. `command' is the
612 command reply being processed. The function has variable argument list
613 and each command defines the number and type of arguments it passes to the
614 application (on error they are not sent). */
616 void silc_command_reply(SilcClient client, SilcClientConnection conn,
617 SilcCommandPayload cmd_payload, int success,
618 SilcCommand command, SilcCommandStatus status, ...)
620 SilcClientInternal app = (SilcClientInternal)client->application;
624 va_start(vp, status);
628 case SILC_COMMAND_WHOIS:
630 char buf[1024], *nickname, *username, *realname;
635 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
636 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
638 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
641 client->ops->say(client, conn, "%s: %s", tmp,
642 silc_client_command_status_message(status));
644 client->ops->say(client, conn, "%s",
645 silc_client_command_status_message(status));
652 (void)va_arg(vp, SilcClientEntry);
653 nickname = va_arg(vp, char *);
654 username = va_arg(vp, char *);
655 realname = va_arg(vp, char *);
656 channels = va_arg(vp, SilcBuffer);
657 mode = va_arg(vp, uint32);
658 idle = va_arg(vp, uint32);
660 memset(buf, 0, sizeof(buf));
663 len = strlen(nickname);
664 strncat(buf, nickname, len);
665 strncat(buf, " is ", 4);
669 strncat(buf, username, strlen(username));
673 strncat(buf, " (", 2);
674 strncat(buf, realname, strlen(realname));
675 strncat(buf, ")", 1);
678 client->ops->say(client, conn, "%s", buf);
681 SilcDList list = silc_channel_payload_parse_list(channels);
683 SilcChannelPayload entry;
685 memset(buf, 0, sizeof(buf));
686 strcat(buf, "on channels: ");
688 silc_dlist_start(list);
689 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
690 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
692 char *name = silc_channel_get_name(entry, &name_len);
695 strncat(buf, m, strlen(m));
696 strncat(buf, name, name_len);
697 strncat(buf, " ", 1);
701 client->ops->say(client, conn, "%s", buf);
702 silc_channel_payload_list_free(list);
707 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
708 (mode & SILC_UMODE_ROUTER_OPERATOR))
709 client->ops->say(client, conn, "%s is %s", nickname,
710 (mode & SILC_UMODE_SERVER_OPERATOR) ?
712 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
713 "SILC Operator" : "[Unknown mode]");
715 if (mode & SILC_UMODE_GONE)
716 client->ops->say(client, conn, "%s is gone", nickname);
719 if (idle && nickname)
720 client->ops->say(client, conn, "%s has been idle %d %s",
722 idle > 60 ? (idle / 60) : idle,
723 idle > 60 ? "minutes" : "seconds");
727 case SILC_COMMAND_WHOWAS:
729 char buf[1024], *nickname, *username, *realname;
732 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
733 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
735 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
738 client->ops->say(client, conn, "%s: %s", tmp,
739 silc_client_command_status_message(status));
741 client->ops->say(client, conn, "%s",
742 silc_client_command_status_message(status));
749 (void)va_arg(vp, SilcClientEntry);
750 nickname = va_arg(vp, char *);
751 username = va_arg(vp, char *);
752 realname = va_arg(vp, char *);
754 memset(buf, 0, sizeof(buf));
757 len = strlen(nickname);
758 strncat(buf, nickname, len);
759 strncat(buf, " was ", 5);
763 strncat(buf, username, strlen(nickname));
767 strncat(buf, " (", 2);
768 strncat(buf, realname, strlen(realname));
769 strncat(buf, ")", 1);
772 client->ops->say(client, conn, "%s", buf);
776 case SILC_COMMAND_INVITE:
778 SilcChannelEntry channel;
784 channel = va_arg(vp, SilcChannelEntry);
785 invite_list = va_arg(vp, char *);
788 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
791 silc_say(client, conn, "%s invite list not set",
792 channel->channel_name);
796 case SILC_COMMAND_JOIN:
800 SilcBuffer client_id_list;
802 SilcChannelEntry channel;
807 app->screen->bottom_line->channel = va_arg(vp, char *);
808 channel = va_arg(vp, SilcChannelEntry);
809 mode = va_arg(vp, uint32);
810 (void)va_arg(vp, uint32);
811 (void)va_arg(vp, unsigned char *);
812 (void)va_arg(vp, unsigned char *);
813 (void)va_arg(vp, unsigned char *);
814 topic = va_arg(vp, char *);
815 (void)va_arg(vp, unsigned char *);
816 list_count = va_arg(vp, uint32);
817 client_id_list = va_arg(vp, SilcBuffer);
820 client->ops->say(client, conn, "Topic for %s: %s",
821 app->screen->bottom_line->channel, topic);
823 app->screen->bottom_line->channel_mode =
824 silc_client_chmode(mode,
825 channel->channel_key->cipher->name,
826 channel->hmac->hmac->name);
827 silc_screen_print_bottom_line(app->screen, 0);
829 /* Resolve the client information */
830 silc_client_get_clients_by_list(client, conn, list_count,
832 silc_client_show_users, channel);
836 case SILC_COMMAND_NICK:
838 SilcClientEntry entry;
843 entry = va_arg(vp, SilcClientEntry);
844 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
845 app->screen->bottom_line->nickname = entry->nickname;
846 silc_screen_print_bottom_line(app->screen, 0);
850 case SILC_COMMAND_LIST:
854 unsigned char buf[256], tmp[16];
860 (void)va_arg(vp, SilcChannelEntry);
861 name = va_arg(vp, char *);
862 topic = va_arg(vp, char *);
863 usercount = va_arg(vp, int);
865 if (status == SILC_STATUS_LIST_START ||
866 status == SILC_STATUS_OK)
867 silc_say(client, conn,
868 " Channel Users Topic");
870 memset(buf, 0, sizeof(buf));
871 strncat(buf, " ", 2);
873 strncat(buf, name, len > 40 ? 40 : len);
875 for (i = 0; i < 40 - len; i++)
879 memset(tmp, 0, sizeof(tmp));
881 snprintf(tmp, sizeof(tmp), "%d", usercount);
886 for (i = 0; i < 10 - len; i++)
892 strncat(buf, topic, len);
895 silc_say(client, conn, "%s", buf);
899 case SILC_COMMAND_UMODE:
906 mode = va_arg(vp, uint32);
908 if (!mode && app->screen->bottom_line->umode) {
909 silc_free(app->screen->bottom_line->umode);
910 app->screen->bottom_line->umode = NULL;
913 if (mode & SILC_UMODE_SERVER_OPERATOR) {
914 if (app->screen->bottom_line->umode)
915 silc_free(app->screen->bottom_line->umode);
916 app->screen->bottom_line->umode = strdup("Server Operator");;
919 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
920 if (app->screen->bottom_line->umode)
921 silc_free(app->screen->bottom_line->umode);
922 app->screen->bottom_line->umode = strdup("SILC Operator");;
925 silc_screen_print_bottom_line(app->screen, 0);
929 case SILC_COMMAND_OPER:
930 if (status == SILC_STATUS_OK) {
931 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
932 if (app->screen->bottom_line->umode)
933 silc_free(app->screen->bottom_line->umode);
934 app->screen->bottom_line->umode = strdup("Server Operator");;
935 silc_screen_print_bottom_line(app->screen, 0);
939 case SILC_COMMAND_SILCOPER:
940 if (status == SILC_STATUS_OK) {
941 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
942 if (app->screen->bottom_line->umode)
943 silc_free(app->screen->bottom_line->umode);
944 app->screen->bottom_line->umode = strdup("SILC Operator");;
945 silc_screen_print_bottom_line(app->screen, 0);
949 case SILC_COMMAND_USERS:
951 SilcChannelEntry channel;
958 channel = va_arg(vp, SilcChannelEntry);
960 /* There are two ways to do this, either parse the list (that
961 the command_reply sends (just take it with va_arg()) or just
962 traverse the channel's client list. I'll do the latter. See
963 JOIN command reply for example for the list. */
965 silc_say(client, conn, "Users on %s", channel->channel_name);
967 line = silc_calloc(1024, sizeof(*line));
969 silc_list_start(channel->clients);
970 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
971 SilcClientEntry e = chu->client;
975 memset(line, 0, line_len);
977 if (chu->client == conn->local_entry) {
978 /* Update status line */
979 if (app->screen->bottom_line->mode)
980 silc_free(app->screen->bottom_line->mode);
981 app->screen->bottom_line->mode =
982 silc_client_chumode_char(chu->mode);
983 silc_screen_print_bottom_line(app->screen, 0);
986 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
988 line_len += strlen(e->nickname) + strlen(e->server) + 100;
989 line = silc_calloc(line_len, sizeof(*line));
992 memset(tmp, 0, sizeof(tmp));
993 m = silc_client_chumode_char(chu->mode);
995 strncat(line, " ", 1);
996 strncat(line, e->nickname, strlen(e->nickname));
997 strncat(line, e->server ? "@" : "", 1);
1001 len1 = strlen(e->server);
1002 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1004 len1 = strlen(line);
1006 memset(&line[29], 0, len1 - 29);
1008 for (i = 0; i < 30 - len1 - 1; i++)
1012 if (e->mode & SILC_UMODE_GONE)
1016 strcat(tmp, m ? m : "");
1017 strncat(line, tmp, strlen(tmp));
1019 if (strlen(tmp) < 5)
1020 for (i = 0; i < 5 - strlen(tmp); i++)
1023 strcat(line, e->username ? e->username : "");
1025 silc_say(client, conn, "%s", line);
1035 case SILC_COMMAND_BAN:
1037 SilcChannelEntry channel;
1043 channel = va_arg(vp, SilcChannelEntry);
1044 ban_list = va_arg(vp, char *);
1047 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
1050 silc_say(client, conn, "%s ban list not set", channel->channel_name);
1054 case SILC_COMMAND_GETKEY:
1058 SilcPublicKey public_key;
1062 id_type = va_arg(vp, uint32);
1063 entry = va_arg(vp, void *);
1064 public_key = va_arg(vp, SilcPublicKey);
1066 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1068 if (id_type == SILC_ID_CLIENT) {
1069 silc_verify_public_key_internal(client, conn,
1070 SILC_SOCKET_TYPE_CLIENT,
1071 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
1077 case SILC_COMMAND_TOPIC:
1079 SilcChannelEntry channel;
1085 channel = va_arg(vp, SilcChannelEntry);
1086 topic = va_arg(vp, char *);
1089 silc_say(client, conn,
1090 "Topic on channel %s: %s", channel->channel_name,
1100 /* Called to indicate that connection was either successfully established
1101 or connecting failed. This is also the first time application receives
1102 the SilcClientConnection objecet which it should save somewhere. */
1104 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
1106 SilcClientInternal app = (SilcClientInternal)client->application;
1109 app->screen->bottom_line->connection = conn->remote_host;
1110 silc_screen_print_bottom_line(app->screen, 0);
1115 /* Called to indicate that connection was disconnected to the server. */
1117 void silc_disconnect(SilcClient client, SilcClientConnection conn)
1119 SilcClientInternal app = (SilcClientInternal)client->application;
1121 app->screen->bottom_line->connection = NULL;
1122 silc_screen_print_bottom_line(app->screen, 0);
1126 /* Asks passphrase from user on the input line. */
1128 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1129 SilcAskPassphrase completion, void *context)
1131 SilcClientInternal app = (SilcClientInternal)conn->client->application;
1132 char pass1[256], pass2[256];
1138 wattroff(app->screen->input_win, A_INVIS);
1139 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
1140 wattron(app->screen->input_win, A_INVIS);
1143 memset(pass1, 0, sizeof(pass1));
1144 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
1146 /* Print retype prompt */
1147 wattroff(app->screen->input_win, A_INVIS);
1148 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
1149 wattron(app->screen->input_win, A_INVIS);
1152 memset(pass2, 0, sizeof(pass2));
1153 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
1155 if (!strncmp(pass1, pass2, strlen(pass2)))
1161 wattroff(app->screen->input_win, A_INVIS);
1162 silc_screen_input_reset(app->screen);
1164 /* Deliver the passphrase to the library */
1165 completion(pass1, strlen(pass1), context);
1167 memset(pass1, 0, sizeof(pass1));
1168 memset(pass2, 0, sizeof(pass2));
1171 /* Verifies received public key. The `conn_type' indicates which entity
1172 (server, client etc.) has sent the public key. If user decides to trust
1173 the key may be saved as trusted public key for later use. The
1174 `completion' must be called after the public key has been verified. */
1176 void silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1177 SilcSocketType conn_type, unsigned char *pk,
1178 uint32 pk_len, SilcSKEPKType pk_type,
1179 SilcVerifyPublicKey completion, void *context)
1181 if (silc_verify_public_key_internal(client, conn, conn_type, pk,
1183 completion(TRUE, context);
1187 completion(FALSE, context);
1190 /* Find authentication method and authentication data by hostname and
1191 port. The hostname may be IP address as well. The found authentication
1192 method and authentication data is returned to `auth_meth', `auth_data'
1193 and `auth_data_len'. The function returns TRUE if authentication method
1194 is found and FALSE if not. `conn' may be NULL. */
1196 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1197 char *hostname, uint16 port,
1198 SilcProtocolAuthMeth *auth_meth,
1199 unsigned char **auth_data,
1200 uint32 *auth_data_len)
1202 SilcClientInternal app = (SilcClientInternal)client->application;
1204 if (app->config && app->config->conns) {
1205 SilcClientConfigSectionConnection *conn = NULL;
1207 /* Check if we find a match from user configured connections */
1208 conn = silc_client_config_find_connection(app->config,
1212 /* Match found. Use the configured authentication method */
1213 *auth_meth = conn->auth_meth;
1215 if (conn->auth_data) {
1216 *auth_data = strdup(conn->auth_data);
1217 *auth_data_len = strlen(conn->auth_data);
1224 *auth_meth = SILC_AUTH_NONE;
1231 /* Notifies application that failure packet was received. This is called
1232 if there is some protocol active in the client. The `protocol' is the
1233 protocol context. The `failure' is opaque pointer to the failure
1234 indication. Note, that the `failure' is protocol dependant and application
1235 must explicitly cast it to correct type. Usually `failure' is 32 bit
1236 failure type (see protocol specs for all protocol failure types). */
1238 void silc_failure(SilcClient client, SilcClientConnection conn,
1239 SilcProtocol protocol, void *failure)
1241 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1242 SilcSKEStatus status = (SilcSKEStatus)failure;
1244 if (status == SILC_SKE_STATUS_BAD_VERSION)
1245 silc_say(client, conn,
1246 "You are running incompatible client version (it may be "
1247 "too old or too new)");
1248 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1249 silc_say(client, conn, "Server does not support your public key type");
1250 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1251 silc_say(client, conn,
1252 "Server does not support one of your proposed KE group");
1253 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1254 silc_say(client, conn,
1255 "Server does not support one of your proposed cipher");
1256 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1257 silc_say(client, conn,
1258 "Server does not support one of your proposed PKCS");
1259 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1260 silc_say(client, conn,
1261 "Server does not support one of your proposed hash function");
1262 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1263 silc_say(client, conn,
1264 "Server does not support one of your proposed HMAC");
1265 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1266 silc_say(client, conn, "Incorrect signature");
1269 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1270 uint32 err = (uint32)failure;
1272 if (err == SILC_AUTH_FAILED)
1273 silc_say(client, conn, "Authentication failed");
1277 /* Asks whether the user would like to perform the key agreement protocol.
1278 This is called after we have received an key agreement packet or an
1279 reply to our key agreement packet. This returns TRUE if the user wants
1280 the library to perform the key agreement protocol and FALSE if it is not
1281 desired (application may start it later by calling the function
1282 silc_client_perform_key_agreement). */
1284 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1285 SilcClientEntry client_entry, char *hostname,
1287 SilcKeyAgreementCallback *completion,
1292 /* We will just display the info on the screen and return FALSE and user
1293 will have to start the key agreement with a command. */
1296 memset(host, 0, sizeof(host));
1297 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1300 silc_say(client, conn, "%s wants to perform key agreement %s",
1301 client_entry->nickname, hostname ? host : "");
1309 /* SILC client operations */
1310 SilcClientOperations ops = {
1312 silc_channel_message,
1313 silc_private_message,
1319 silc_get_auth_method,
1320 silc_verify_public_key,
1321 silc_ask_passphrase,