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, channel_entry);
370 snprintf(message, sizeof(message), "%s changed channel mode to +%s",
371 client_entry->nickname, tmp);
373 snprintf(message, sizeof(message),
374 "channel mode was changed to +%s (forced by router)",
379 snprintf(message, sizeof(message), "%s removed all channel modes",
380 client_entry->nickname);
382 snprintf(message, sizeof(message),
383 "Removed all channel modes (forced by router)");
387 if (app->screen->bottom_line->channel_mode)
388 silc_free(app->screen->bottom_line->channel_mode);
389 app->screen->bottom_line->channel_mode = tmp;
390 silc_screen_print_bottom_line(app->screen, 0);
393 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
394 client_entry = va_arg(vp, SilcClientEntry);
395 tmp_int = va_arg(vp, uint32);
396 tmp = silc_client_chumode(tmp_int);
397 client_entry2 = va_arg(vp, SilcClientEntry);
398 channel_entry = va_arg(vp, SilcChannelEntry);
400 snprintf(message, sizeof(message), "%s changed %s's mode to +%s",
401 client_entry->nickname, client_entry2->nickname, tmp);
403 snprintf(message, sizeof(message), "%s removed %s's modes",
404 client_entry->nickname, client_entry2->nickname);
405 if (client_entry2 == conn->local_entry) {
406 if (app->screen->bottom_line->mode)
407 silc_free(app->screen->bottom_line->mode);
408 app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
409 silc_screen_print_bottom_line(app->screen, 0);
414 case SILC_NOTIFY_TYPE_MOTD:
418 tmp = va_arg(vp, unsigned char *);
422 if (tmp[i++] == '\n') {
423 memset(line, 0, sizeof(line));
424 strncat(line, tmp, i - 1);
427 silc_say(client, conn, "%s", line);
437 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
441 case SILC_NOTIFY_TYPE_KICKED:
442 client_entry = va_arg(vp, SilcClientEntry);
443 tmp = va_arg(vp, char *);
444 channel_entry = va_arg(vp, SilcChannelEntry);
446 if (client_entry == conn->local_entry) {
447 snprintf(message, sizeof(message),
448 "You have been kicked off channel %s %s%s%s",
449 conn->current_channel->channel_name,
450 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
452 snprintf(message, sizeof(message),
453 "%s%s%s has been kicked off channel %s %s%s%s",
454 client_entry->nickname,
455 client_entry->server ? "@" : "",
456 client_entry->server ? client_entry->server : "",
457 conn->current_channel->channel_name,
458 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
462 case SILC_NOTIFY_TYPE_KILLED:
463 client_entry = va_arg(vp, SilcClientEntry);
464 tmp = va_arg(vp, char *);
465 channel_entry = va_arg(vp, SilcChannelEntry);
467 if (client_entry == conn->local_entry) {
468 snprintf(message, sizeof(message),
469 "You have been killed from the SILC Network %s%s%s",
470 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
472 snprintf(message, sizeof(message),
473 "%s%s%s has been killed from the SILC Network %s%s%s",
474 client_entry->nickname,
475 client_entry->server ? "@" : "",
476 client_entry->server ? client_entry->server : "",
477 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
481 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
483 SilcClientEntry *clients;
484 uint32 clients_count;
487 (void)va_arg(vp, void *);
488 clients = va_arg(vp, SilcClientEntry *);
489 clients_count = va_arg(vp, uint32);
491 for (i = 0; i < clients_count; i++) {
492 if (clients[i]->server)
493 snprintf(message, sizeof(message), "Server signoff: %s@%s %s%s%s",
494 clients[i]->nickname, clients[i]->server,
495 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
497 snprintf(message, sizeof(message), "Server signoff: %s %s%s%s",
498 clients[i]->nickname,
499 tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
500 silc_print(client, "*** %s", message);
501 memset(message, 0, sizeof(message));
510 silc_print(client, "*** %s", message);
513 /* Command handler. This function is called always in the command function.
514 If error occurs it will be called as well. `conn' is the associated
515 client connection. `cmd_context' is the command context that was
516 originally sent to the command. `success' is FALSE if error occured
517 during command. `command' is the command being processed. It must be
518 noted that this is not reply from server. This is merely called just
519 after application has called the command. Just to tell application
520 that the command really was processed. */
522 void silc_command(SilcClient client, SilcClientConnection conn,
523 SilcClientCommandContext cmd_context, int success,
526 SilcClientInternal app = (SilcClientInternal)client->application;
534 case SILC_COMMAND_QUIT:
535 app->screen->bottom_line->channel = NULL;
536 silc_screen_print_bottom_line(app->screen, 0);
539 case SILC_COMMAND_LEAVE:
540 /* We won't talk anymore on this channel */
541 silc_say(client, conn, "You have left channel %s",
542 conn->current_channel->channel_name);
548 /* We've resolved all clients we don't know about, now just print the
549 users from the channel on the screen. */
551 void silc_client_show_users(SilcClient client,
552 SilcClientConnection conn,
553 SilcClientEntry *clients,
554 uint32 clients_count,
557 SilcChannelEntry channel = (SilcChannelEntry)context;
559 int k = 0, len1 = 0, len2 = 0;
560 char *name_list = NULL;
565 silc_list_start(channel->clients);
566 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
567 char *m, *n = chu->client->nickname;
574 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
576 m = silc_client_chumode_char(chu->mode);
578 memcpy(name_list + (len1 - len2), m, strlen(m));
583 memcpy(name_list + (len1 - len2), n, len2);
586 if (k == silc_list_count(channel->clients) - 1)
588 memcpy(name_list + len1, " ", 1);
593 client->ops->say(client, conn, "Users on %s: %s", channel->channel_name,
595 silc_free(name_list);
598 /* Command reply handler. This function is called always in the command reply
599 function. If error occurs it will be called as well. Normal scenario
600 is that it will be called after the received command data has been parsed
601 and processed. The function is used to pass the received command data to
604 `conn' is the associated client connection. `cmd_payload' is the command
605 payload data received from server and it can be ignored. It is provided
606 if the application would like to re-parse the received command data,
607 however, it must be noted that the data is parsed already by the library
608 thus the payload can be ignored. `success' is FALSE if error occured.
609 In this case arguments are not sent to the application. `command' is the
610 command reply being processed. The function has variable argument list
611 and each command defines the number and type of arguments it passes to the
612 application (on error they are not sent). */
614 void silc_command_reply(SilcClient client, SilcClientConnection conn,
615 SilcCommandPayload cmd_payload, int success,
616 SilcCommand command, SilcCommandStatus status, ...)
618 SilcClientInternal app = (SilcClientInternal)client->application;
622 va_start(vp, status);
626 case SILC_COMMAND_WHOIS:
628 char buf[1024], *nickname, *username, *realname;
633 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
634 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
636 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
639 client->ops->say(client, conn, "%s: %s", tmp,
640 silc_client_command_status_message(status));
642 client->ops->say(client, conn, "%s",
643 silc_client_command_status_message(status));
650 (void)va_arg(vp, SilcClientEntry);
651 nickname = va_arg(vp, char *);
652 username = va_arg(vp, char *);
653 realname = va_arg(vp, char *);
654 channels = va_arg(vp, SilcBuffer);
655 mode = va_arg(vp, uint32);
656 idle = va_arg(vp, uint32);
658 memset(buf, 0, sizeof(buf));
661 len = strlen(nickname);
662 strncat(buf, nickname, len);
663 strncat(buf, " is ", 4);
667 strncat(buf, username, strlen(username));
671 strncat(buf, " (", 2);
672 strncat(buf, realname, strlen(realname));
673 strncat(buf, ")", 1);
676 client->ops->say(client, conn, "%s", buf);
679 SilcDList list = silc_channel_payload_parse_list(channels);
681 SilcChannelPayload entry;
683 memset(buf, 0, sizeof(buf));
684 strcat(buf, "on channels: ");
686 silc_dlist_start(list);
687 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
688 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
690 char *name = silc_channel_get_name(entry, &name_len);
693 strncat(buf, m, strlen(m));
694 strncat(buf, name, name_len);
695 strncat(buf, " ", 1);
699 client->ops->say(client, conn, "%s", buf);
700 silc_channel_payload_list_free(list);
705 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
706 (mode & SILC_UMODE_ROUTER_OPERATOR))
707 client->ops->say(client, conn, "%s is %s", nickname,
708 (mode & SILC_UMODE_SERVER_OPERATOR) ?
710 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
711 "SILC Operator" : "[Unknown mode]");
713 if (mode & SILC_UMODE_GONE)
714 client->ops->say(client, conn, "%s is gone", nickname);
717 if (idle && nickname)
718 client->ops->say(client, conn, "%s has been idle %d %s",
720 idle > 60 ? (idle / 60) : idle,
721 idle > 60 ? "minutes" : "seconds");
725 case SILC_COMMAND_WHOWAS:
727 char buf[1024], *nickname, *username, *realname;
730 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
731 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
733 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
736 client->ops->say(client, conn, "%s: %s", tmp,
737 silc_client_command_status_message(status));
739 client->ops->say(client, conn, "%s",
740 silc_client_command_status_message(status));
747 (void)va_arg(vp, SilcClientEntry);
748 nickname = va_arg(vp, char *);
749 username = va_arg(vp, char *);
750 realname = va_arg(vp, char *);
752 memset(buf, 0, sizeof(buf));
755 len = strlen(nickname);
756 strncat(buf, nickname, len);
757 strncat(buf, " was ", 5);
761 strncat(buf, username, strlen(nickname));
765 strncat(buf, " (", 2);
766 strncat(buf, realname, strlen(realname));
767 strncat(buf, ")", 1);
770 client->ops->say(client, conn, "%s", buf);
774 case SILC_COMMAND_INVITE:
776 SilcChannelEntry channel;
782 channel = va_arg(vp, SilcChannelEntry);
783 invite_list = va_arg(vp, char *);
786 silc_say(client, conn, "%s invite list: %s", channel->channel_name,
789 silc_say(client, conn, "%s invite list not set",
790 channel->channel_name);
794 case SILC_COMMAND_JOIN:
798 SilcBuffer client_id_list;
800 SilcChannelEntry channel;
805 app->screen->bottom_line->channel = va_arg(vp, char *);
806 channel = va_arg(vp, SilcChannelEntry);
807 mode = va_arg(vp, uint32);
808 (void)va_arg(vp, uint32);
809 (void)va_arg(vp, unsigned char *);
810 (void)va_arg(vp, unsigned char *);
811 (void)va_arg(vp, unsigned char *);
812 topic = va_arg(vp, char *);
813 (void)va_arg(vp, unsigned char *);
814 list_count = va_arg(vp, uint32);
815 client_id_list = va_arg(vp, SilcBuffer);
818 client->ops->say(client, conn, "Topic for %s: %s",
819 app->screen->bottom_line->channel, topic);
821 app->screen->bottom_line->channel_mode =
822 silc_client_chmode(mode, channel);
823 silc_screen_print_bottom_line(app->screen, 0);
825 /* Resolve the client information */
826 silc_client_get_clients_by_list(client, conn, list_count,
828 silc_client_show_users, channel);
832 case SILC_COMMAND_NICK:
834 SilcClientEntry entry;
839 entry = va_arg(vp, SilcClientEntry);
840 silc_say(client, conn, "Your current nickname is %s", entry->nickname);
841 app->screen->bottom_line->nickname = entry->nickname;
842 silc_screen_print_bottom_line(app->screen, 0);
846 case SILC_COMMAND_LIST:
850 unsigned char buf[256], tmp[16];
856 (void)va_arg(vp, SilcChannelEntry);
857 name = va_arg(vp, char *);
858 topic = va_arg(vp, char *);
859 usercount = va_arg(vp, int);
861 if (status == SILC_STATUS_LIST_START ||
862 status == SILC_STATUS_OK)
863 silc_say(client, conn,
864 " Channel Users Topic");
866 memset(buf, 0, sizeof(buf));
867 strncat(buf, " ", 2);
869 strncat(buf, name, len > 40 ? 40 : len);
871 for (i = 0; i < 40 - len; i++)
875 memset(tmp, 0, sizeof(tmp));
877 snprintf(tmp, sizeof(tmp), "%d", usercount);
882 for (i = 0; i < 10 - len; i++)
888 strncat(buf, topic, len);
891 silc_say(client, conn, "%s", buf);
895 case SILC_COMMAND_UMODE:
902 mode = va_arg(vp, uint32);
904 if (!mode && app->screen->bottom_line->umode) {
905 silc_free(app->screen->bottom_line->umode);
906 app->screen->bottom_line->umode = NULL;
909 if (mode & SILC_UMODE_SERVER_OPERATOR) {
910 if (app->screen->bottom_line->umode)
911 silc_free(app->screen->bottom_line->umode);
912 app->screen->bottom_line->umode = strdup("Server Operator");;
915 if (mode & SILC_UMODE_ROUTER_OPERATOR) {
916 if (app->screen->bottom_line->umode)
917 silc_free(app->screen->bottom_line->umode);
918 app->screen->bottom_line->umode = strdup("SILC Operator");;
921 silc_screen_print_bottom_line(app->screen, 0);
925 case SILC_COMMAND_OPER:
926 if (status == SILC_STATUS_OK) {
927 conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
928 if (app->screen->bottom_line->umode)
929 silc_free(app->screen->bottom_line->umode);
930 app->screen->bottom_line->umode = strdup("Server Operator");;
931 silc_screen_print_bottom_line(app->screen, 0);
935 case SILC_COMMAND_SILCOPER:
936 if (status == SILC_STATUS_OK) {
937 conn->local_entry->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");;
941 silc_screen_print_bottom_line(app->screen, 0);
945 case SILC_COMMAND_USERS:
947 SilcChannelEntry channel;
954 channel = va_arg(vp, SilcChannelEntry);
956 /* There are two ways to do this, either parse the list (that
957 the command_reply sends (just take it with va_arg()) or just
958 traverse the channel's client list. I'll do the latter. See
959 JOIN command reply for example for the list. */
961 silc_say(client, conn, "Users on %s", channel->channel_name);
963 line = silc_calloc(1024, sizeof(*line));
965 silc_list_start(channel->clients);
966 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
967 SilcClientEntry e = chu->client;
971 memset(line, 0, line_len);
973 if (chu->client == conn->local_entry) {
974 /* Update status line */
975 if (app->screen->bottom_line->mode)
976 silc_free(app->screen->bottom_line->mode);
977 app->screen->bottom_line->mode =
978 silc_client_chumode_char(chu->mode);
979 silc_screen_print_bottom_line(app->screen, 0);
982 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
984 line_len += strlen(e->nickname) + strlen(e->server) + 100;
985 line = silc_calloc(line_len, sizeof(*line));
988 memset(tmp, 0, sizeof(tmp));
989 m = silc_client_chumode_char(chu->mode);
991 strncat(line, " ", 1);
992 strncat(line, e->nickname, strlen(e->nickname));
993 strncat(line, e->server ? "@" : "", 1);
997 len1 = strlen(e->server);
998 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1000 len1 = strlen(line);
1002 memset(&line[29], 0, len1 - 29);
1004 for (i = 0; i < 30 - len1 - 1; i++)
1008 if (e->mode & SILC_UMODE_GONE)
1012 strcat(tmp, m ? m : "");
1013 strncat(line, tmp, strlen(tmp));
1015 if (strlen(tmp) < 5)
1016 for (i = 0; i < 5 - strlen(tmp); i++)
1019 strcat(line, e->username ? e->username : "");
1021 silc_say(client, conn, "%s", line);
1031 case SILC_COMMAND_BAN:
1033 SilcChannelEntry channel;
1039 channel = va_arg(vp, SilcChannelEntry);
1040 ban_list = va_arg(vp, char *);
1043 silc_say(client, conn, "%s ban list: %s", channel->channel_name,
1046 silc_say(client, conn, "%s ban list not set", channel->channel_name);
1050 case SILC_COMMAND_GETKEY:
1054 SilcPublicKey public_key;
1058 id_type = va_arg(vp, uint32);
1059 entry = va_arg(vp, void *);
1060 public_key = va_arg(vp, SilcPublicKey);
1062 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1064 if (id_type == SILC_ID_CLIENT) {
1065 silc_verify_public_key_internal(client, conn,
1066 SILC_SOCKET_TYPE_CLIENT,
1067 pk, pk_len, SILC_SKE_PK_TYPE_SILC);
1073 case SILC_COMMAND_TOPIC:
1075 SilcChannelEntry channel;
1081 channel = va_arg(vp, SilcChannelEntry);
1082 topic = va_arg(vp, char *);
1085 silc_say(client, conn,
1086 "Topic on channel %s: %s", channel->channel_name,
1096 /* Called to indicate that connection was either successfully established
1097 or connecting failed. This is also the first time application receives
1098 the SilcClientConnection objecet which it should save somewhere. */
1100 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
1102 SilcClientInternal app = (SilcClientInternal)client->application;
1105 app->screen->bottom_line->connection = conn->remote_host;
1106 silc_screen_print_bottom_line(app->screen, 0);
1111 /* Called to indicate that connection was disconnected to the server. */
1113 void silc_disconnect(SilcClient client, SilcClientConnection conn)
1115 SilcClientInternal app = (SilcClientInternal)client->application;
1117 app->screen->bottom_line->connection = NULL;
1118 silc_screen_print_bottom_line(app->screen, 0);
1122 /* Asks passphrase from user on the input line. */
1124 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1125 SilcAskPassphrase completion, void *context)
1127 SilcClientInternal app = (SilcClientInternal)conn->client->application;
1128 char pass1[256], pass2[256];
1134 wattroff(app->screen->input_win, A_INVIS);
1135 silc_screen_input_print_prompt(app->screen, "Passphrase: ");
1136 wattron(app->screen->input_win, A_INVIS);
1139 memset(pass1, 0, sizeof(pass1));
1140 wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
1142 /* Print retype prompt */
1143 wattroff(app->screen->input_win, A_INVIS);
1144 silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
1145 wattron(app->screen->input_win, A_INVIS);
1148 memset(pass2, 0, sizeof(pass2));
1149 wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
1151 if (!strncmp(pass1, pass2, strlen(pass2)))
1157 wattroff(app->screen->input_win, A_INVIS);
1158 silc_screen_input_reset(app->screen);
1160 /* Deliver the passphrase to the library */
1161 completion(pass1, strlen(pass1), context);
1163 memset(pass1, 0, sizeof(pass1));
1164 memset(pass2, 0, sizeof(pass2));
1167 /* Verifies received public key. The `conn_type' indicates which entity
1168 (server, client etc.) has sent the public key. If user decides to trust
1169 the key may be saved as trusted public key for later use. The
1170 `completion' must be called after the public key has been verified. */
1172 void silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1173 SilcSocketType conn_type, unsigned char *pk,
1174 uint32 pk_len, SilcSKEPKType pk_type,
1175 SilcVerifyPublicKey completion, void *context)
1177 if (silc_verify_public_key_internal(client, conn, conn_type, pk,
1179 completion(TRUE, context);
1183 completion(FALSE, context);
1186 /* Find authentication method and authentication data by hostname and
1187 port. The hostname may be IP address as well. The found authentication
1188 method and authentication data is returned to `auth_meth', `auth_data'
1189 and `auth_data_len'. The function returns TRUE if authentication method
1190 is found and FALSE if not. `conn' may be NULL. */
1192 int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1193 char *hostname, uint16 port,
1194 SilcProtocolAuthMeth *auth_meth,
1195 unsigned char **auth_data,
1196 uint32 *auth_data_len)
1198 SilcClientInternal app = (SilcClientInternal)client->application;
1200 if (app->config && app->config->conns) {
1201 SilcClientConfigSectionConnection *conn = NULL;
1203 /* Check if we find a match from user configured connections */
1204 conn = silc_client_config_find_connection(app->config,
1208 /* Match found. Use the configured authentication method */
1209 *auth_meth = conn->auth_meth;
1211 if (conn->auth_data) {
1212 *auth_data = strdup(conn->auth_data);
1213 *auth_data_len = strlen(conn->auth_data);
1220 *auth_meth = SILC_AUTH_NONE;
1227 /* Notifies application that failure packet was received. This is called
1228 if there is some protocol active in the client. The `protocol' is the
1229 protocol context. The `failure' is opaque pointer to the failure
1230 indication. Note, that the `failure' is protocol dependant and application
1231 must explicitly cast it to correct type. Usually `failure' is 32 bit
1232 failure type (see protocol specs for all protocol failure types). */
1234 void silc_failure(SilcClient client, SilcClientConnection conn,
1235 SilcProtocol protocol, void *failure)
1237 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1238 SilcSKEStatus status = (SilcSKEStatus)failure;
1240 if (status == SILC_SKE_STATUS_BAD_VERSION)
1241 silc_say(client, conn,
1242 "You are running incompatible client version (it may be "
1243 "too old or too new)");
1244 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1245 silc_say(client, conn, "Server does not support your public key type");
1246 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1247 silc_say(client, conn,
1248 "Server does not support one of your proposed KE group");
1249 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1250 silc_say(client, conn,
1251 "Server does not support one of your proposed cipher");
1252 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1253 silc_say(client, conn,
1254 "Server does not support one of your proposed PKCS");
1255 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1256 silc_say(client, conn,
1257 "Server does not support one of your proposed hash function");
1258 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1259 silc_say(client, conn,
1260 "Server does not support one of your proposed HMAC");
1261 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1262 silc_say(client, conn, "Incorrect signature");
1265 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1266 uint32 err = (uint32)failure;
1268 if (err == SILC_AUTH_FAILED)
1269 silc_say(client, conn, "Authentication failed");
1273 /* Asks whether the user would like to perform the key agreement protocol.
1274 This is called after we have received an key agreement packet or an
1275 reply to our key agreement packet. This returns TRUE if the user wants
1276 the library to perform the key agreement protocol and FALSE if it is not
1277 desired (application may start it later by calling the function
1278 silc_client_perform_key_agreement). */
1280 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1281 SilcClientEntry client_entry, char *hostname,
1283 SilcKeyAgreementCallback *completion,
1288 /* We will just display the info on the screen and return FALSE and user
1289 will have to start the key agreement with a command. */
1292 memset(host, 0, sizeof(host));
1293 snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
1296 silc_say(client, conn, "%s wants to perform key agreement %s",
1297 client_entry->nickname, hostname ? host : "");
1305 /* SILC client operations */
1306 SilcClientOperations ops = {
1308 silc_channel_message,
1309 silc_private_message,
1315 silc_get_auth_method,
1316 silc_verify_public_key,
1317 silc_ask_passphrase,