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 void silc_say(SilcClient client, SilcClientConnection conn,
185 SilcClientInternal app = (SilcClientInternal)client->application;
187 memset(message, 0, sizeof(message));
188 strncat(message, "\n*** ", 5);
191 vsprintf(message + 5, msg, vp);
194 /* Print the message */
195 silc_print_to_window(app->screen->output_win[0], message);
198 /* Prints a message with three star (*) sign before the actual message
199 on the current output window. This is used to print command outputs
200 and error messages. */
202 void silc_op_say(SilcClient client, SilcClientConnection conn,
203 SilcClientMessageType type, char *msg, ...)
207 SilcClientInternal app = (SilcClientInternal)client->application;
209 memset(message, 0, sizeof(message));
210 strncat(message, "\n*** ", 5);
213 vsprintf(message + 5, msg, vp);
216 /* Print the message */
217 silc_print_to_window(app->screen->output_win[0], message);
220 /* Message for a channel. The `sender' is the nickname of the sender
221 received in the packet. The `channel_name' is the name of the channel. */
223 void silc_channel_message(SilcClient client, SilcClientConnection conn,
224 SilcClientEntry sender, SilcChannelEntry channel,
225 SilcMessageFlags flags, char *msg)
227 /* Message from client */
228 if (conn && !strcmp(conn->current_channel->channel_name,
229 channel->channel_name))
230 if (flags & SILC_MESSAGE_FLAG_ACTION)
231 silc_print(client, "* %s %s", sender ? sender->nickname : "[<unknown>]",
233 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
234 silc_print(client, "- %s %s", sender ? sender->nickname : "[<unknown>]",
237 silc_print(client, "<%s> %s", sender ? sender->nickname : "[<unknown>]",
240 if (flags & SILC_MESSAGE_FLAG_ACTION)
241 silc_print(client, "* %s:%s %s", sender ? sender->nickname :
243 channel->channel_name, msg);
244 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
245 silc_print(client, "- %s:%s %s", sender ? sender->nickname :
247 channel->channel_name, msg);
249 silc_print(client, "<%s:%s> %s", sender ? sender->nickname :
251 channel->channel_name, msg);
254 /* Private message to the client. The `sender' is the nickname of the
255 sender received in the packet. */
257 void silc_private_message(SilcClient client, SilcClientConnection conn,
258 SilcClientEntry sender, SilcMessageFlags flags,
261 silc_print(client, "*%s* %s", sender->nickname, msg);
265 /* Notify message to the client. The notify arguments are sent in the
266 same order as servers sends them. The arguments are same as received
267 from the server except for ID's. If ID is received application receives
268 the corresponding entry to the ID. For example, if Client ID is received
269 application receives SilcClientEntry. Also, if the notify type is
270 for channel the channel entry is sent to application (even if server
271 does not send it). */
273 void silc_notify(SilcClient client, SilcClientConnection conn,
274 SilcNotifyType type, ...)
276 SilcClientInternal app = (SilcClientInternal)client->application;
279 SilcClientEntry client_entry, client_entry2;
280 SilcChannelEntry channel_entry;
286 memset(message, 0, sizeof(message));
288 /* Get arguments (defined by protocol in silc-pp-01 -draft) */
290 case SILC_NOTIFY_TYPE_NONE:
291 tmp = va_arg(vp, char *);
294 strcpy(message, tmp);
297 case SILC_NOTIFY_TYPE_INVITE:
298 (void)va_arg(vp, SilcChannelEntry);
299 tmp = va_arg(vp, char *);
300 client_entry = va_arg(vp, SilcClientEntry);
301 snprintf(message, sizeof(message), "%s invites you to channel %s",
302 client_entry->nickname, tmp);
305 case SILC_NOTIFY_TYPE_JOIN:
306 client_entry = va_arg(vp, SilcClientEntry);
307 channel_entry = va_arg(vp, SilcChannelEntry);
308 snprintf(message, sizeof(message), "%s (%s) has joined channel %s",
309 client_entry->nickname, client_entry->username,
310 channel_entry->channel_name);
311 if (client_entry == conn->local_entry) {
314 silc_list_start(channel_entry->clients);
315 while ((chu = silc_list_get(channel_entry->clients)) != SILC_LIST_END) {
316 if (chu->client == client_entry) {
317 if (app->screen->bottom_line->mode)
318 silc_free(app->screen->bottom_line->mode);
319 app->screen->bottom_line->mode = silc_client_chumode_char(chu->mode);
320 silc_screen_print_bottom_line(app->screen, 0);
327 case SILC_NOTIFY_TYPE_LEAVE:
328 client_entry = va_arg(vp, SilcClientEntry);
329 channel_entry = va_arg(vp, SilcChannelEntry);
330 if (client_entry->server)
331 snprintf(message, sizeof(message), "%s@%s has left channel %s",
332 client_entry->nickname, client_entry->server,
333 channel_entry->channel_name);
335 snprintf(message, sizeof(message), "%s has left channel %s",
336 client_entry->nickname, channel_entry->channel_name);
339 case SILC_NOTIFY_TYPE_SIGNOFF:
340 client_entry = va_arg(vp, SilcClientEntry);
341 tmp = va_arg(vp, char *);
342 if (client_entry->server)
343 snprintf(message, sizeof(message), "Signoff: %s@%s %s%s%s",
344 client_entry->nickname, client_entry->server,
345 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
347 snprintf(message, sizeof(message), "Signoff: %s %s%s%s",
348 client_entry->nickname,
349 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
352 case SILC_NOTIFY_TYPE_TOPIC_SET:
353 client_entry = va_arg(vp, SilcClientEntry);
354 tmp = va_arg(vp, char *);
355 channel_entry = va_arg(vp, SilcChannelEntry);
356 if (client_entry->server)
357 snprintf(message, sizeof(message), "%s@%s set topic on %s: %s",
358 client_entry->nickname, client_entry->server,
359 channel_entry->channel_name, tmp);
361 snprintf(message, sizeof(message), "%s set topic on %s: %s",
362 client_entry->nickname, channel_entry->channel_name, tmp);
365 case SILC_NOTIFY_TYPE_NICK_CHANGE:
366 client_entry = va_arg(vp, SilcClientEntry);
367 client_entry2 = va_arg(vp, SilcClientEntry);
368 if (client_entry->server && client_entry2->server)
369 snprintf(message, sizeof(message), "%s@%s is known as %s@%s",
370 client_entry->nickname, client_entry->server,
371 client_entry2->nickname, client_entry2->server);
373 snprintf(message, sizeof(message), "%s is known as %s",
374 client_entry->nickname, client_entry2->nickname);
377 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
378 client_entry = va_arg(vp, SilcClientEntry);
379 tmp_int = va_arg(vp, uint32);
380 (void)va_arg(vp, char *);
381 (void)va_arg(vp, char *);
382 channel_entry = va_arg(vp, SilcChannelEntry);
384 tmp = silc_client_chmode(tmp_int,
385 channel_entry->channel_key->cipher->name,
386 channel_entry->hmac->hmac->name);
390 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
391 client_entry->nickname, tmp);
393 snprintf(message, sizeof(message),
394 "channel mode was changed to +%s (forced by router)",
399 snprintf(message, sizeof(message), "%s removed all channel modes",
400 client_entry->nickname);
402 snprintf(message, sizeof(message),
403 "Removed all channel modes (forced by router)");
407 if (app->screen->bottom_line->channel_mode)
408 silc_free(app->screen->bottom_line->channel_mode);
409 app->screen->bottom_line->channel_mode = tmp;
410 silc_screen_print_bottom_line(app->screen, 0);
413 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
414 client_entry = va_arg(vp, SilcClientEntry);
415 tmp_int = va_arg(vp, uint32);
416 tmp = silc_client_chumode(tmp_int);
417 client_entry2 = va_arg(vp, SilcClientEntry);
418 channel_entry = va_arg(vp, SilcChannelEntry);
420 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
421 client_entry->nickname, client_entry2->nickname, tmp);
423 snprintf(message, sizeof(message), "%s removed %s's modes",
424 client_entry->nickname, client_entry2->nickname);
425 if (client_entry2 == conn->local_entry) {
426 if (app->screen->bottom_line->mode)
427 silc_free(app->screen->bottom_line->mode);
428 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
429 silc_screen_print_bottom_line(app->screen, 0);
434 case SILC_NOTIFY_TYPE_MOTD:
438 tmp = va_arg(vp, unsigned char *);
442 if (tmp[i++] == '\n') {
443 memset(line, 0, sizeof(line));
444 strncat(line, tmp, i - 1);
447 silc_say(client, conn, "%s", line);
457 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
461 case SILC_NOTIFY_TYPE_KICKED:
462 client_entry = va_arg(vp, SilcClientEntry);
463 tmp = va_arg(vp, char *);
464 channel_entry = va_arg(vp, SilcChannelEntry);
466 if (client_entry == conn->local_entry) {
467 snprintf(message, sizeof(message),
468 "You have been kicked off channel %s %s%s%s",
469 conn->current_channel->channel_name,
470 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
472 snprintf(message, sizeof(message),
473 "%s%s%s has been kicked off channel %s %s%s%s",
474 client_entry->nickname,
475 client_entry->server ? "@" : "",
476 client_entry->server ? client_entry->server : "",
477 conn->current_channel->channel_name,
478 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
482 case SILC_NOTIFY_TYPE_KILLED:
483 client_entry = va_arg(vp, SilcClientEntry);
484 tmp = va_arg(vp, char *);
485 channel_entry = va_arg(vp, SilcChannelEntry);
487 if (client_entry == conn->local_entry) {
488 snprintf(message, sizeof(message),
489 "You have been killed from the SILC Network %s%s%s",
490 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
492 snprintf(message, sizeof(message),
493 "%s%s%s has been killed from the SILC Network %s%s%s",
494 client_entry->nickname,
495 client_entry->server ? "@" : "",
496 client_entry->server ? client_entry->server : "",
497 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
501 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
503 SilcClientEntry *clients;
504 uint32 clients_count;
507 (void)va_arg(vp, void *);
508 clients = va_arg(vp, SilcClientEntry *);
509 clients_count = va_arg(vp, uint32);
511 for (i = 0; i < clients_count; i++) {
512 if (clients[i]->server)
513 snprintf(message, sizeof(message), "Server signoff: %s@%s %s%s%s",
514 clients[i]->nickname, clients[i]->server,
515 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
517 snprintf(message, sizeof(message), "Server signoff: %s %s%s%s",
518 clients[i]->nickname,
519 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
520 silc_print(client, "*** %s", message);
521 memset(message, 0, sizeof(message));
530 silc_print(client, "*** %s", message);
533 /* Command handler. This function is called always in the command function.
534 If error occurs it will be called as well. `conn' is the associated
535 client connection. `cmd_context' is the command context that was
536 originally sent to the command. `success' is FALSE if error occured
537 during command. `command' is the command being processed. It must be
538 noted that this is not reply from server. This is merely called just
539 after application has called the command. Just to tell application
540 that the command really was processed. */
542 void silc_command(SilcClient client, SilcClientConnection conn,
543 SilcClientCommandContext cmd_context, int success,
546 SilcClientInternal app = (SilcClientInternal)client->application;
554 case SILC_COMMAND_QUIT:
555 app->screen->bottom_line->channel = NULL;
556 silc_screen_print_bottom_line(app->screen, 0);
559 case SILC_COMMAND_LEAVE:
560 /* We won't talk anymore on this channel */
561 silc_say(client, conn, "You have left channel %s",
562 conn->current_channel->channel_name);
568 /* We've resolved all clients we don't know about, now just print the
569 users from the channel on the screen. */
571 void silc_client_show_users(SilcClient client,
572 SilcClientConnection conn,
573 SilcClientEntry *clients,
574 uint32 clients_count,
577 SilcChannelEntry channel = (SilcChannelEntry)context;
579 int k = 0, len1 = 0, len2 = 0;
580 char *name_list = NULL;
585 silc_list_start(channel->clients);
586 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
587 char *m, *n = chu->client->nickname;
594 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
596 m = silc_client_chumode_char(chu->mode);
598 memcpy(name_list + (len1 - len2), m, strlen(m));
603 memcpy(name_list + (len1 - len2), n, len2);
606 if (k == silc_list_count(channel->clients) - 1)
608 memcpy(name_list + len1, " ", 1);
613 silc_say(client, conn, "Users on %s: %s", channel->channel_name,
615 silc_free(name_list);
618 /* Command reply handler. This function is called always in the command reply
619 function. If error occurs it will be called as well. Normal scenario
620 is that it will be called after the received command data has been parsed
621 and processed. The function is used to pass the received command data to
624 `conn' is the associated client connection. `cmd_payload' is the command
625 payload data received from server and it can be ignored. It is provided
626 if the application would like to re-parse the received command data,
627 however, it must be noted that the data is parsed already by the library
628 thus the payload can be ignored. `success' is FALSE if error occured.
629 In this case arguments are not sent to the application. `command' is the
630 command reply being processed. The function has variable argument list
631 and each command defines the number and type of arguments it passes to the
632 application (on error they are not sent). */
634 void silc_command_reply(SilcClient client, SilcClientConnection conn,
635 SilcCommandPayload cmd_payload, int success,
636 SilcCommand command, SilcCommandStatus status, ...)
638 SilcClientInternal app = (SilcClientInternal)client->application;
642 va_start(vp, status);
646 case SILC_COMMAND_WHOIS:
648 char buf[1024], *nickname, *username, *realname;
653 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
654 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
656 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
659 silc_say(client, conn, "%s: %s", tmp,
660 silc_client_command_status_message(status));
662 silc_say(client, conn, "%s",
663 silc_client_command_status_message(status));
670 (void)va_arg(vp, SilcClientEntry);
671 nickname = va_arg(vp, char *);
672 username = va_arg(vp, char *);
673 realname = va_arg(vp, char *);
674 channels = va_arg(vp, SilcBuffer);
675 mode = va_arg(vp, uint32);
676 idle = va_arg(vp, uint32);
678 memset(buf, 0, sizeof(buf));
681 len = strlen(nickname);
682 strncat(buf, nickname, len);
683 strncat(buf, " is ", 4);
687 strncat(buf, username, strlen(username));
691 strncat(buf, " (", 2);
692 strncat(buf, realname, strlen(realname));
693 strncat(buf, ")", 1);
696 silc_say(client, conn, "%s", buf);
699 SilcDList list = silc_channel_payload_parse_list(channels);
701 SilcChannelPayload entry;
703 memset(buf, 0, sizeof(buf));
704 strcat(buf, "on channels: ");
706 silc_dlist_start(list);
707 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
708 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
710 char *name = silc_channel_get_name(entry, &name_len);
713 strncat(buf, m, strlen(m));
714 strncat(buf, name, name_len);
715 strncat(buf, " ", 1);
719 silc_say(client, conn, "%s", buf);
720 silc_channel_payload_list_free(list);
725 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
726 (mode & SILC_UMODE_ROUTER_OPERATOR))
727 silc_say(client, conn, "%s is %s", nickname,
728 (mode & SILC_UMODE_SERVER_OPERATOR) ?
730 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
731 "SILC Operator" : "[Unknown mode]");
733 if (mode & SILC_UMODE_GONE)
734 silc_say(client, conn, "%s is gone", nickname);
737 if (idle && nickname)
738 silc_say(client, conn, "%s has been idle %d %s",
740 idle > 60 ? (idle / 60) : idle,
741 idle > 60 ? "minutes" : "seconds");
745 case SILC_COMMAND_WHOWAS:
747 char buf[1024], *nickname, *username, *realname;
750 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
751 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
753 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
756 silc_say(client, conn, "%s: %s", tmp,
757 silc_client_command_status_message(status));
759 silc_say(client, conn, "%s",
760 silc_client_command_status_message(status));
767 (void)va_arg(vp, SilcClientEntry);
768 nickname = va_arg(vp, char *);
769 username = va_arg(vp, char *);
770 realname = va_arg(vp, char *);
772 memset(buf, 0, sizeof(buf));
775 len = strlen(nickname);
776 strncat(buf, nickname, len);
777 strncat(buf, " was ", 5);
781 strncat(buf, username, strlen(nickname));
785 strncat(buf, " (", 2);
786 strncat(buf, realname, strlen(realname));
787 strncat(buf, ")", 1);
790 silc_say(client, conn, "%s", buf);
794 case SILC_COMMAND_INVITE:
796 SilcChannelEntry channel;
802 channel = va_arg(vp, SilcChannelEntry);
803 invite_list = va_arg(vp, char *);
806 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
809 silc_say(client, conn, "%s invite list not set",
810 channel->channel_name);
814 case SILC_COMMAND_JOIN:
818 SilcBuffer client_id_list;
820 SilcChannelEntry channel;
825 app->screen->bottom_line->channel = va_arg(vp, char *);
826 channel = va_arg(vp, SilcChannelEntry);
827 mode = va_arg(vp, uint32);
828 (void)va_arg(vp, uint32);
829 (void)va_arg(vp, unsigned char *);
830 (void)va_arg(vp, unsigned char *);
831 (void)va_arg(vp, unsigned char *);
832 topic = va_arg(vp, char *);
833 (void)va_arg(vp, unsigned char *);
834 list_count = va_arg(vp, uint32);
835 client_id_list = va_arg(vp, SilcBuffer);
838 silc_say(client, conn, "Topic for %s: %s",
839 app->screen->bottom_line->channel, topic);
841 app->screen->bottom_line->channel_mode =
842 silc_client_chmode(mode,
843 channel->channel_key->cipher->name,
844 channel->hmac->hmac->name);
845 silc_screen_print_bottom_line(app->screen, 0);
847 /* Resolve the client information */
848 silc_client_get_clients_by_list(client, conn, list_count,
850 silc_client_show_users, channel);
854 case SILC_COMMAND_NICK:
856 SilcClientEntry entry;
861 entry = va_arg(vp, SilcClientEntry);
862 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
863 app->screen->bottom_line->nickname = entry->nickname;
864 silc_screen_print_bottom_line(app->screen, 0);
868 case SILC_COMMAND_LIST:
872 unsigned char buf[256], tmp[16];
878 (void)va_arg(vp, SilcChannelEntry);
879 name = va_arg(vp, char *);
880 topic = va_arg(vp, char *);
881 usercount = va_arg(vp, int);
883 if (status == SILC_STATUS_LIST_START ||
884 status == SILC_STATUS_OK)
885 silc_say(client, conn,
886 " Channel Users Topic");
888 memset(buf, 0, sizeof(buf));
889 strncat(buf, " ", 2);
891 strncat(buf, name, len > 40 ? 40 : len);
893 for (i = 0; i < 40 - len; i++)
897 memset(tmp, 0, sizeof(tmp));
899 snprintf(tmp, sizeof(tmp), "%d", usercount);
904 for (i = 0; i < 10 - len; i++)
910 strncat(buf, topic, len);
913 silc_say(client, conn, "%s", buf);
917 case SILC_COMMAND_UMODE:
924 mode = va_arg(vp, uint32);
926 if (!mode && app->screen->bottom_line->umode) {
927 silc_free(app->screen->bottom_line->umode);
928 app->screen->bottom_line->umode = NULL;
931 if (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");;
937 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
938 if (app->screen->bottom_line->umode)
939 silc_free(app->screen->bottom_line->umode);
940 app->screen->bottom_line->umode = strdup("SILC Operator");;
943 silc_screen_print_bottom_line(app->screen, 0);
947 case SILC_COMMAND_OPER:
948 if (status == SILC_STATUS_OK) {
949 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
950 if (app->screen->bottom_line->umode)
951 silc_free(app->screen->bottom_line->umode);
952 app->screen->bottom_line->umode = strdup("Server Operator");;
953 silc_screen_print_bottom_line(app->screen, 0);
957 case SILC_COMMAND_SILCOPER:
958 if (status == SILC_STATUS_OK) {
959 conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
960 if (app->screen->bottom_line->umode)
961 silc_free(app->screen->bottom_line->umode);
962 app->screen->bottom_line->umode = strdup("SILC Operator");;
963 silc_screen_print_bottom_line(app->screen, 0);
967 case SILC_COMMAND_USERS:
969 SilcChannelEntry channel;
976 channel = va_arg(vp, SilcChannelEntry);
978 /* There are two ways to do this, either parse the list (that
979 the command_reply sends (just take it with va_arg()) or just
980 traverse the channel's client list. I'll do the latter. See
981 JOIN command reply for example for the list. */
983 silc_say(client, conn, "Users on %s", channel->channel_name);
985 line = silc_calloc(1024, sizeof(*line));
987 silc_list_start(channel->clients);
988 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
989 SilcClientEntry e = chu->client;
993 memset(line, 0, line_len);
995 if (chu->client == conn->local_entry) {
996 /* Update status line */
997 if (app->screen->bottom_line->mode)
998 silc_free(app->screen->bottom_line->mode);
999 app->screen->bottom_line->mode =
1000 silc_client_chumode_char(chu->mode);
1001 silc_screen_print_bottom_line(app->screen, 0);
1004 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1006 line_len += strlen(e->nickname) + strlen(e->server) + 100;
1007 line = silc_calloc(line_len, sizeof(*line));
1010 memset(tmp, 0, sizeof(tmp));
1011 m = silc_client_chumode_char(chu->mode);
1013 strncat(line, " ", 1);
1014 strncat(line, e->nickname, strlen(e->nickname));
1015 strncat(line, e->server ? "@" : "", 1);
1019 len1 = strlen(e->server);
1020 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1022 len1 = strlen(line);
1024 memset(&line[29], 0, len1 - 29);
1026 for (i = 0; i < 30 - len1 - 1; i++)
1030 if (e->mode & SILC_UMODE_GONE)
1034 strcat(tmp, m ? m : "");
1035 strncat(line, tmp, strlen(tmp));
1037 if (strlen(tmp) < 5)
1038 for (i = 0; i < 5 - strlen(tmp); i++)
1041 strcat(line, e->username ? e->username : "");
1043 silc_say(client, conn, "%s", line);
1053 case SILC_COMMAND_BAN:
1055 SilcChannelEntry channel;
1061 channel = va_arg(vp, SilcChannelEntry);
1062 ban_list = va_arg(vp, char *);
1065 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
1068 silc_say(client, conn, "%s ban list not set", channel->channel_name);
1072 case SILC_COMMAND_GETKEY:
1076 SilcPublicKey public_key;
1080 id_type = va_arg(vp, uint32);
1081 entry = va_arg(vp, void *);
1082 public_key = va_arg(vp, SilcPublicKey);
1084 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1086 if (id_type == SILC_ID_CLIENT) {
1087 silc_verify_public_key_internal(client, conn,
1088 SILC_SOCKET_TYPE_CLIENT,
1089 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
1095 case SILC_COMMAND_TOPIC:
1097 SilcChannelEntry channel;
1103 channel = va_arg(vp, SilcChannelEntry);
1104 topic = va_arg(vp, char *);
1107 silc_say(client, conn,
1108 "Topic on channel %s: %s", channel->channel_name,
1118 /* Called to indicate that connection was either successfully established
1119 or connecting failed. This is also the first time application receives
1120 the SilcClientConnection objecet which it should save somewhere. */
1122 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
1124 SilcClientInternal app = (SilcClientInternal)client->application;
1127 app->screen->bottom_line->connection = conn->remote_host;
1128 silc_screen_print_bottom_line(app->screen, 0);
1133 /* Called to indicate that connection was disconnected to the server. */
1135 void silc_disconnect(SilcClient client, SilcClientConnection conn)
1137 SilcClientInternal app = (SilcClientInternal)client->application;
1139 app->screen->bottom_line->connection = NULL;
1140 silc_screen_print_bottom_line(app->screen, 0);
1144 /* Asks passphrase from user on the input line. */
1146 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1147 SilcAskPassphrase completion, void *context)
1149 SilcClientInternal app = (SilcClientInternal)conn->client->application;
1150 char pass1[256], pass2[256];
1156 wattroff(app->screen->input_win, A_INVIS);
1157 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
1158 wattron(app->screen->input_win, A_INVIS);
1161 memset(pass1, 0, sizeof(pass1));
1162 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
1164 /* Print retype prompt */
1165 wattroff(app->screen->input_win, A_INVIS);
1166 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
1167 wattron(app->screen->input_win, A_INVIS);
1170 memset(pass2, 0, sizeof(pass2));
1171 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
1173 if (!strncmp(pass1, pass2, strlen(pass2)))
1179 wattroff(app->screen->input_win, A_INVIS);
1180 silc_screen_input_reset(app->screen);
1182 /* Deliver the passphrase to the library */
1183 completion(pass1, strlen(pass1), context);
1185 memset(pass1, 0, sizeof(pass1));
1186 memset(pass2, 0, sizeof(pass2));
1189 /* Verifies received public key. The `conn_type' indicates which entity
1190 (server, client etc.) has sent the public key. If user decides to trust
1191 the key may be saved as trusted public key for later use. The
1192 `completion' must be called after the public key has been verified. */
1194 void silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1195 SilcSocketType conn_type, unsigned char *pk,
1196 uint32 pk_len, SilcSKEPKType pk_type,
1197 SilcVerifyPublicKey completion, void *context)
1199 if (silc_verify_public_key_internal(client, conn, conn_type, pk,
1201 completion(TRUE, context);
1205 completion(FALSE, context);
1208 /* Find authentication method and authentication data by hostname and
1209 port. The hostname may be IP address as well. The found authentication
1210 method and authentication data is returned to `auth_meth', `auth_data'
1211 and `auth_data_len'. The function returns TRUE if authentication method
1212 is found and FALSE if not. `conn' may be NULL. */
1214 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1215 char *hostname, uint16 port,
1216 SilcProtocolAuthMeth *auth_meth,
1217 unsigned char **auth_data,
1218 uint32 *auth_data_len)
1220 SilcClientInternal app = (SilcClientInternal)client->application;
1222 if (app->config && app->config->conns) {
1223 SilcClientConfigSectionConnection *conn = NULL;
1225 /* Check if we find a match from user configured connections */
1226 conn = silc_client_config_find_connection(app->config,
1230 /* Match found. Use the configured authentication method */
1231 *auth_meth = conn->auth_meth;
1233 if (conn->auth_data) {
1234 *auth_data = strdup(conn->auth_data);
1235 *auth_data_len = strlen(conn->auth_data);
1242 *auth_meth = SILC_AUTH_NONE;
1249 /* Notifies application that failure packet was received. This is called
1250 if there is some protocol active in the client. The `protocol' is the
1251 protocol context. The `failure' is opaque pointer to the failure
1252 indication. Note, that the `failure' is protocol dependant and application
1253 must explicitly cast it to correct type. Usually `failure' is 32 bit
1254 failure type (see protocol specs for all protocol failure types). */
1256 void silc_failure(SilcClient client, SilcClientConnection conn,
1257 SilcProtocol protocol, void *failure)
1259 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1260 SilcSKEStatus status = (SilcSKEStatus)failure;
1262 if (status == SILC_SKE_STATUS_BAD_VERSION)
1263 silc_say(client, conn,
1264 "You are running incompatible client version (it may be "
1265 "too old or too new)");
1266 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1267 silc_say(client, conn, "Server does not support your public key type");
1268 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1269 silc_say(client, conn,
1270 "Server does not support one of your proposed KE group");
1271 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1272 silc_say(client, conn,
1273 "Server does not support one of your proposed cipher");
1274 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1275 silc_say(client, conn,
1276 "Server does not support one of your proposed PKCS");
1277 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1278 silc_say(client, conn,
1279 "Server does not support one of your proposed hash function");
1280 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1281 silc_say(client, conn,
1282 "Server does not support one of your proposed HMAC");
1283 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1284 silc_say(client, conn, "Incorrect signature");
1287 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1288 uint32 err = (uint32)failure;
1290 if (err == SILC_AUTH_FAILED)
1291 silc_say(client, conn, "Authentication failed");
1295 /* Asks whether the user would like to perform the key agreement protocol.
1296 This is called after we have received an key agreement packet or an
1297 reply to our key agreement packet. This returns TRUE if the user wants
1298 the library to perform the key agreement protocol and FALSE if it is not
1299 desired (application may start it later by calling the function
1300 silc_client_perform_key_agreement). */
1302 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1303 SilcClientEntry client_entry, char *hostname,
1305 SilcKeyAgreementCallback *completion,
1310 /* We will just display the info on the screen and return FALSE and user
1311 will have to start the key agreement with a command. */
1314 memset(host, 0, sizeof(host));
1315 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1318 silc_say(client, conn, "%s wants to perform key agreement %s",
1319 client_entry->nickname, hostname ? host : "");
1327 /* SILC client operations */
1328 SilcClientOperations ops = {
1330 silc_channel_message,
1331 silc_private_message,
1337 silc_get_auth_method,
1338 silc_verify_public_key,
1339 silc_ask_passphrase,