5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 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.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
44 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
45 const char *name, SilcSocketType conn_type,
46 unsigned char *pk, SilcUInt32 pk_len,
47 SilcSKEPKType pk_type,
48 SilcVerifyPublicKey completion, void *context);
50 void silc_say(SilcClient client, SilcClientConnection conn,
51 SilcClientMessageType type, char *msg, ...)
53 SILC_SERVER_REC *server;
57 server = conn == NULL ? NULL : conn->context;
60 str = g_strdup_vprintf(msg, va);
61 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
66 void silc_say_error(char *msg, ...)
72 str = g_strdup_vprintf(msg, va);
73 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
79 /* Message for a channel. The `sender' is the nickname of the sender
80 received in the packet. The `channel_name' is the name of the channel. */
82 void silc_channel_message(SilcClient client, SilcClientConnection conn,
83 SilcClientEntry sender, SilcChannelEntry channel,
84 SilcMessageFlags flags, char *msg)
86 SILC_SERVER_REC *server;
88 SILC_CHANNEL_REC *chanrec;
90 SILC_LOG_DEBUG(("Start"));
95 server = conn == NULL ? NULL : conn->context;
96 chanrec = silc_channel_find_entry(server, channel);
100 nick = silc_nicklist_find(chanrec, sender);
102 /* We didn't find client but it clearly exists, add it. */
103 SilcChannelUser chu = silc_client_on_channel(channel, sender);
105 nick = silc_nicklist_insert(chanrec, chu, FALSE);
108 if (flags & SILC_MESSAGE_FLAG_ACTION)
109 printformat_module("fe-common/silc", server, channel->channel_name,
110 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
111 nick == NULL ? "[<unknown>]" : nick->nick, msg);
112 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
113 printformat_module("fe-common/silc", server, channel->channel_name,
114 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
115 nick == NULL ? "[<unknown>]" : nick->nick, msg);
117 signal_emit("message public", 6, server, msg,
118 nick == NULL ? "[<unknown>]" : nick->nick,
119 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
120 chanrec->name, nick);
123 /* Private message to the client. The `sender' is the nickname of the
124 sender received in the packet. */
126 void silc_private_message(SilcClient client, SilcClientConnection conn,
127 SilcClientEntry sender, SilcMessageFlags flags,
130 SILC_SERVER_REC *server;
133 SILC_LOG_DEBUG(("Start"));
135 server = conn == NULL ? NULL : conn->context;
136 memset(userhost, 0, sizeof(userhost));
137 if (sender->username)
138 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
139 sender->username, sender->hostname);
140 signal_emit("message private", 4, server, msg,
141 sender->nickname ? sender->nickname : "[<unknown>]",
142 sender->username ? userhost : NULL);
145 /* Notify message to the client. The notify arguments are sent in the
146 same order as servers sends them. The arguments are same as received
147 from the server except for ID's. If ID is received application receives
148 the corresponding entry to the ID. For example, if Client ID is received
149 application receives SilcClientEntry. Also, if the notify type is
150 for channel the channel entry is sent to application (even if server
151 does not send it). */
153 void silc_notify(SilcClient client, SilcClientConnection conn,
154 SilcNotifyType type, ...)
157 SILC_SERVER_REC *server;
158 SILC_CHANNEL_REC *chanrec;
159 SILC_NICK_REC *nickrec;
160 SilcClientEntry client_entry, client_entry2;
161 SilcChannelEntry channel;
162 SilcServerEntry server_entry;
168 GSList *list1, *list_tmp;
170 SILC_LOG_DEBUG(("Start"));
174 server = conn == NULL ? NULL : conn->context;
177 case SILC_NOTIFY_TYPE_NONE:
178 /* Some generic notice from server */
179 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
182 case SILC_NOTIFY_TYPE_INVITE:
184 * Invited or modified invite list.
187 SILC_LOG_DEBUG(("Notify: INVITE"));
189 channel = va_arg(va, SilcChannelEntry);
190 name = va_arg(va, char *);
191 client_entry = va_arg(va, SilcClientEntry);
193 memset(userhost, 0, sizeof(userhost));
194 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
195 client_entry->username, client_entry->hostname);
196 signal_emit("message invite", 4, server, channel ? channel->channel_name :
197 name, client_entry->nickname, userhost);
200 case SILC_NOTIFY_TYPE_JOIN:
205 SILC_LOG_DEBUG(("Notify: JOIN"));
207 client_entry = va_arg(va, SilcClientEntry);
208 channel = va_arg(va, SilcChannelEntry);
210 if (client_entry == server->conn->local_entry) {
211 /* You joined to channel */
212 chanrec = silc_channel_find(server, channel->channel_name);
213 if (chanrec != NULL && !chanrec->joined)
214 chanrec->entry = channel;
216 chanrec = silc_channel_find_entry(server, channel);
217 if (chanrec != NULL) {
218 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
220 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
224 memset(userhost, 0, sizeof(userhost));
225 if (client_entry->username)
226 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
227 client_entry->username, client_entry->hostname);
228 signal_emit("message join", 4, server, channel->channel_name,
229 client_entry->nickname,
230 client_entry->username == NULL ? "" : userhost);
233 case SILC_NOTIFY_TYPE_LEAVE:
238 SILC_LOG_DEBUG(("Notify: LEAVE"));
240 client_entry = va_arg(va, SilcClientEntry);
241 channel = va_arg(va, SilcChannelEntry);
243 memset(userhost, 0, sizeof(userhost));
244 if (client_entry->username)
245 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
246 client_entry->username, client_entry->hostname);
247 signal_emit("message part", 5, server, channel->channel_name,
248 client_entry->nickname, client_entry->username ?
249 userhost : "", client_entry->nickname);
251 chanrec = silc_channel_find_entry(server, channel);
252 if (chanrec != NULL) {
253 nickrec = silc_nicklist_find(chanrec, client_entry);
255 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
259 case SILC_NOTIFY_TYPE_SIGNOFF:
264 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
266 client_entry = va_arg(va, SilcClientEntry);
267 tmp = va_arg(va, char *);
269 silc_server_free_ftp(server, client_entry);
271 memset(userhost, 0, sizeof(userhost));
272 if (client_entry->username)
273 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
274 client_entry->username, client_entry->hostname);
275 signal_emit("message quit", 4, server, client_entry->nickname,
276 client_entry->username ? userhost : "",
279 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
280 for (list_tmp = list1; list_tmp != NULL; list_tmp =
281 list_tmp->next->next) {
282 CHANNEL_REC *channel = list_tmp->data;
283 NICK_REC *nickrec = list_tmp->next->data;
285 nicklist_remove(channel, nickrec);
289 case SILC_NOTIFY_TYPE_TOPIC_SET:
294 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
296 idtype = va_arg(va, int);
297 entry = va_arg(va, void *);
298 tmp = va_arg(va, char *);
299 channel = va_arg(va, SilcChannelEntry);
301 chanrec = silc_channel_find_entry(server, channel);
302 if (chanrec != NULL) {
303 g_free_not_null(chanrec->topic);
304 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
305 signal_emit("channel topic changed", 1, chanrec);
308 if (idtype == SILC_ID_CLIENT) {
309 client_entry = (SilcClientEntry)entry;
310 memset(userhost, 0, sizeof(userhost));
311 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
312 client_entry->username, client_entry->hostname);
313 signal_emit("message topic", 5, server, channel->channel_name,
314 tmp, client_entry->nickname, userhost);
315 } else if (idtype == SILC_ID_SERVER) {
316 server_entry = (SilcServerEntry)entry;
317 signal_emit("message topic", 5, server, channel->channel_name,
318 tmp, server_entry->server_name,
319 server_entry->server_name);
321 channel = (SilcChannelEntry)entry;
322 signal_emit("message topic", 5, server, channel->channel_name,
323 tmp, channel->channel_name, channel->channel_name);
327 case SILC_NOTIFY_TYPE_NICK_CHANGE:
332 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
334 client_entry = va_arg(va, SilcClientEntry);
335 client_entry2 = va_arg(va, SilcClientEntry);
337 memset(userhost, 0, sizeof(userhost));
338 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
339 client_entry2->username, client_entry2->hostname);
340 nicklist_rename_unique(SERVER(server),
341 client_entry, client_entry->nickname,
342 client_entry2, client_entry2->nickname);
343 signal_emit("message nick", 4, server, client_entry2->nickname,
344 client_entry->nickname, userhost);
347 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
349 * Changed channel mode.
352 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
354 idtype = va_arg(va, int);
355 entry = va_arg(va, void *);
356 mode = va_arg(va, SilcUInt32);
357 (void)va_arg(va, char *);
358 (void)va_arg(va, char *);
359 channel = va_arg(va, SilcChannelEntry);
361 tmp = silc_client_chmode(mode,
362 channel->channel_key ?
363 channel->channel_key->cipher->name : "",
365 silc_hmac_get_name(channel->hmac) : "");
367 chanrec = silc_channel_find_entry(server, channel);
368 if (chanrec != NULL) {
369 g_free_not_null(chanrec->mode);
370 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
371 signal_emit("channel mode changed", 1, chanrec);
374 if (idtype == SILC_ID_CLIENT) {
375 client_entry = (SilcClientEntry)entry;
376 printformat_module("fe-common/silc", server, channel->channel_name,
377 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
378 channel->channel_name, tmp ? tmp : "removed all",
379 client_entry->nickname);
380 } else if (idtype == SILC_ID_SERVER) {
381 server_entry = (SilcServerEntry)entry;
382 printformat_module("fe-common/silc", server, channel->channel_name,
383 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
384 channel->channel_name, tmp ? tmp : "removed all",
385 server_entry->server_name);
391 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
393 * Changed user's mode on channel.
396 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
398 client_entry = va_arg(va, SilcClientEntry);
399 mode = va_arg(va, SilcUInt32);
400 client_entry2 = va_arg(va, SilcClientEntry);
401 channel = va_arg(va, SilcChannelEntry);
403 tmp = silc_client_chumode(mode);
404 chanrec = silc_channel_find_entry(server, channel);
405 if (chanrec != NULL) {
408 if (client_entry2 == server->conn->local_entry)
409 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
411 nick = silc_nicklist_find(chanrec, client_entry2);
413 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
414 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
415 signal_emit("nick mode changed", 2, chanrec, nick);
419 printformat_module("fe-common/silc", server, channel->channel_name,
420 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
421 channel->channel_name, client_entry2->nickname,
422 tmp ? tmp : "removed all",
423 client_entry->nickname);
425 if (mode & SILC_CHANNEL_UMODE_CHANFO)
426 printformat_module("fe-common/silc",
427 server, channel->channel_name, MSGLEVEL_CRAP,
428 SILCTXT_CHANNEL_FOUNDER,
429 channel->channel_name, client_entry2->nickname);
434 case SILC_NOTIFY_TYPE_MOTD:
439 SILC_LOG_DEBUG(("Notify: MOTD"));
441 tmp = va_arg(va, char *);
443 if (!settings_get_bool("skip_motd"))
444 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
447 case SILC_NOTIFY_TYPE_KICKED:
449 * Someone was kicked from channel.
452 SILC_LOG_DEBUG(("Notify: KICKED"));
454 client_entry = va_arg(va, SilcClientEntry);
455 tmp = va_arg(va, char *);
456 client_entry2 = va_arg(va, SilcClientEntry);
457 channel = va_arg(va, SilcChannelEntry);
459 chanrec = silc_channel_find_entry(server, channel);
461 if (client_entry == conn->local_entry) {
462 printformat_module("fe-common/silc", server, channel->channel_name,
463 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
464 channel->channel_name,
465 client_entry ? client_entry2->nickname : "",
468 chanrec->kicked = TRUE;
469 channel_destroy((CHANNEL_REC *)chanrec);
472 printformat_module("fe-common/silc", server, channel->channel_name,
473 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
474 client_entry->nickname, channel->channel_name,
475 client_entry2 ? client_entry2->nickname : "",
479 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
481 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
486 case SILC_NOTIFY_TYPE_KILLED:
488 * Someone was killed from the network.
491 SILC_LOG_DEBUG(("Notify: KILLED"));
493 client_entry = va_arg(va, SilcClientEntry);
494 tmp = va_arg(va, char *);
496 if (client_entry == conn->local_entry) {
497 printformat_module("fe-common/silc", server, NULL,
498 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
501 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
502 for (list_tmp = list1; list_tmp != NULL; list_tmp =
503 list_tmp->next->next) {
504 CHANNEL_REC *channel = list_tmp->data;
505 NICK_REC *nickrec = list_tmp->next->data;
506 nicklist_remove(channel, nickrec);
509 printformat_module("fe-common/silc", server, NULL,
510 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
511 client_entry->nickname,
516 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
519 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
522 * Server has quit the network.
525 SilcClientEntry *clients;
526 SilcUInt32 clients_count;
528 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
530 (void)va_arg(va, void *);
531 clients = va_arg(va, SilcClientEntry *);
532 clients_count = va_arg(va, SilcUInt32);
534 for (i = 0; i < clients_count; i++) {
535 memset(userhost, 0, sizeof(userhost));
536 if (clients[i]->username)
537 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
538 clients[i]->username, clients[i]->hostname);
539 signal_emit("message quit", 4, server, clients[i]->nickname,
540 clients[i]->username ? userhost : "",
543 silc_server_free_ftp(server, clients[i]);
545 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
546 for (list_tmp = list1; list_tmp != NULL; list_tmp =
547 list_tmp->next->next) {
548 CHANNEL_REC *channel = list_tmp->data;
549 NICK_REC *nickrec = list_tmp->next->data;
550 nicklist_remove(channel, nickrec);
558 printformat_module("fe-common/silc", server, NULL,
559 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
566 /* Called to indicate that connection was either successfully established
567 or connecting failed. This is also the first time application receives
568 the SilcClientConnection object which it should save somewhere. */
570 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
572 SILC_SERVER_REC *server = conn->context;
574 if (!server && !success) {
575 silc_client_close_connection(client, NULL, conn);
580 server->connected = TRUE;
581 signal_emit("event connected", 1, server);
583 server->connection_lost = TRUE;
585 server->conn->context = NULL;
586 server_disconnect(SERVER(server));
590 /* Called to indicate that connection was disconnected to the server. */
592 void silc_disconnect(SilcClient client, SilcClientConnection conn)
594 SILC_SERVER_REC *server = conn->context;
596 SILC_LOG_DEBUG(("Start"));
598 if (server->conn && server->conn->local_entry) {
599 nicklist_rename_unique(SERVER(server),
600 server->conn->local_entry, server->nick,
601 server->conn->local_entry,
602 silc_client->username);
603 silc_change_nick(server, silc_client->username);
606 server->conn->context = NULL;
608 server->connection_lost = TRUE;
609 server_disconnect(SERVER(server));
612 /* Command handler. This function is called always in the command function.
613 If error occurs it will be called as well. `conn' is the associated
614 client connection. `cmd_context' is the command context that was
615 originally sent to the command. `success' is FALSE if error occured
616 during command. `command' is the command being processed. It must be
617 noted that this is not reply from server. This is merely called just
618 after application has called the command. Just to tell application
619 that the command really was processed. */
621 void silc_command(SilcClient client, SilcClientConnection conn,
622 SilcClientCommandContext cmd_context, int success,
625 SILC_SERVER_REC *server = conn->context;
627 SILC_LOG_DEBUG(("Start"));
633 case SILC_COMMAND_INVITE:
634 printformat_module("fe-common/silc", server, NULL,
635 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
636 cmd_context->argv[2],
637 (cmd_context->argv[1][0] == '*' ?
638 (char *)conn->current_channel->channel_name :
639 (char *)cmd_context->argv[1]));
646 /* Client info resolving callback when JOIN command reply is received.
647 This will cache all users on the channel. */
649 static void silc_client_join_get_users(SilcClient client,
650 SilcClientConnection conn,
651 SilcClientEntry *clients,
652 SilcUInt32 clients_count,
655 SilcChannelEntry channel = (SilcChannelEntry)context;
656 SilcHashTableList htl;
658 SILC_SERVER_REC *server = conn->context;
659 SILC_CHANNEL_REC *chanrec;
660 SilcClientEntry founder = NULL;
666 chanrec = silc_channel_find(server, channel->channel_name);
670 silc_hash_table_list(channel->user_list, &htl);
671 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
672 if (!chu->client->nickname)
674 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
675 founder = chu->client;
676 silc_nicklist_insert(chanrec, chu, FALSE);
678 silc_hash_table_list_reset(&htl);
680 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
681 nicklist_set_own(CHANNEL(chanrec), ownnick);
682 signal_emit("channel joined", 1, chanrec);
685 printformat_module("fe-common/silc", server, channel->channel_name,
686 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
687 channel->channel_name, chanrec->topic);
689 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
692 if (founder == conn->local_entry)
693 printformat_module("fe-common/silc",
694 server, channel->channel_name, MSGLEVEL_CRAP,
695 SILCTXT_CHANNEL_FOUNDER_YOU,
696 channel->channel_name);
698 printformat_module("fe-common/silc",
699 server, channel->channel_name, MSGLEVEL_CRAP,
700 SILCTXT_CHANNEL_FOUNDER,
701 channel->channel_name, founder->nickname);
707 SilcClientConnection conn;
713 void silc_getkey_cb(bool success, void *context)
715 GetkeyContext getkey = (GetkeyContext)context;
716 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
717 char *name = (getkey->id_type == SILC_ID_CLIENT ?
718 ((SilcClientEntry)getkey->entry)->nickname :
719 ((SilcServerEntry)getkey->entry)->server_name);
722 printformat_module("fe-common/silc", NULL, NULL,
723 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
725 printformat_module("fe-common/silc", NULL, NULL,
726 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
729 silc_free(getkey->fingerprint);
733 /* Command reply handler. This function is called always in the command reply
734 function. If error occurs it will be called as well. Normal scenario
735 is that it will be called after the received command data has been parsed
736 and processed. The function is used to pass the received command data to
739 `conn' is the associated client connection. `cmd_payload' is the command
740 payload data received from server and it can be ignored. It is provided
741 if the application would like to re-parse the received command data,
742 however, it must be noted that the data is parsed already by the library
743 thus the payload can be ignored. `success' is FALSE if error occured.
744 In this case arguments are not sent to the application. `command' is the
745 command reply being processed. The function has variable argument list
746 and each command defines the number and type of arguments it passes to the
747 application (on error they are not sent). */
750 silc_command_reply(SilcClient client, SilcClientConnection conn,
751 SilcCommandPayload cmd_payload, int success,
752 SilcCommand command, SilcCommandStatus status, ...)
755 SILC_SERVER_REC *server = conn->context;
756 SILC_CHANNEL_REC *chanrec;
759 va_start(vp, status);
761 SILC_LOG_DEBUG(("Start"));
764 case SILC_COMMAND_WHOIS:
766 char buf[1024], *nickname, *username, *realname, *nick;
767 unsigned char *fingerprint;
768 SilcUInt32 idle, mode;
770 SilcClientEntry client_entry;
772 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
773 /* Print the unknown nick for user */
775 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
778 silc_say_error("%s: %s", tmp,
779 silc_client_command_status_message(status));
781 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
782 /* Try to find the entry for the unknown client ID, since we
783 might have, and print the nickname of it for user. */
786 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
789 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
791 client_entry = silc_client_get_client_by_id(client, conn,
793 if (client_entry && client_entry->nickname)
794 silc_say_error("%s: %s", client_entry->nickname,
795 silc_client_command_status_message(status));
796 silc_free(client_id);
805 client_entry = va_arg(vp, SilcClientEntry);
806 nickname = va_arg(vp, char *);
807 username = va_arg(vp, char *);
808 realname = va_arg(vp, char *);
809 channels = va_arg(vp, SilcBuffer);
810 mode = va_arg(vp, SilcUInt32);
811 idle = va_arg(vp, SilcUInt32);
812 fingerprint = va_arg(vp, unsigned char *);
814 silc_parse_userfqdn(nickname, &nick, NULL);
815 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
816 SILCTXT_WHOIS_USERINFO, nickname,
817 client_entry->username, client_entry->hostname,
818 nick, client_entry->nickname);
819 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
820 SILCTXT_WHOIS_REALNAME, realname);
824 SilcDList list = silc_channel_payload_parse_list(channels->data,
827 SilcChannelPayload entry;
828 memset(buf, 0, sizeof(buf));
829 silc_dlist_start(list);
830 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
831 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
833 char *name = silc_channel_get_name(entry, &name_len);
836 strncat(buf, m, strlen(m));
837 strncat(buf, name, name_len);
838 strncat(buf, " ", 1);
842 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
843 SILCTXT_WHOIS_CHANNELS, buf);
844 silc_channel_payload_list_free(list);
849 memset(buf, 0, sizeof(buf));
851 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
852 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
853 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
855 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
856 "SILC Operator " : "[Unknown mode] ");
858 if (mode & SILC_UMODE_GONE)
861 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
862 SILCTXT_WHOIS_MODES, buf);
865 if (idle && nickname) {
866 memset(buf, 0, sizeof(buf));
867 snprintf(buf, sizeof(buf) - 1, "%lu %s",
868 idle > 60 ? (idle / 60) : idle,
869 idle > 60 ? "minutes" : "seconds");
871 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
872 SILCTXT_WHOIS_IDLE, buf);
876 fingerprint = silc_fingerprint(fingerprint, 20);
877 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
878 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
879 silc_free(fingerprint);
884 case SILC_COMMAND_IDENTIFY:
886 SilcClientEntry client_entry;
888 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
889 /* Print the unknown nick for user */
891 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
894 silc_say_error("%s: %s", tmp,
895 silc_client_command_status_message(status));
897 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
898 /* Try to find the entry for the unknown client ID, since we
899 might have, and print the nickname of it for user. */
902 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
905 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
907 client_entry = silc_client_get_client_by_id(client, conn,
909 if (client_entry && client_entry->nickname)
910 silc_say_error("%s: %s", client_entry->nickname,
911 silc_client_command_status_message(status));
912 silc_free(client_id);
921 case SILC_COMMAND_WHOWAS:
923 char *nickname, *username, *realname;
925 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
926 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
928 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
931 silc_say_error("%s: %s", tmp,
932 silc_client_command_status_message(status));
939 (void)va_arg(vp, SilcClientEntry);
940 nickname = va_arg(vp, char *);
941 username = va_arg(vp, char *);
942 realname = va_arg(vp, char *);
944 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
945 SILCTXT_WHOWAS_USERINFO, nickname, username,
946 realname ? realname : "");
950 case SILC_COMMAND_INVITE:
952 SilcChannelEntry channel;
954 SilcArgumentPayload args;
960 channel = va_arg(vp, SilcChannelEntry);
961 invite_list = va_arg(vp, char *);
963 args = silc_command_get_args(cmd_payload);
965 argc = silc_argument_get_arg_num(args);
968 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
969 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
972 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
973 SILCTXT_CHANNEL_NO_INVITE_LIST,
974 channel->channel_name);
978 case SILC_COMMAND_JOIN:
980 char *channel, *mode, *topic;
982 SilcChannelEntry channel_entry;
983 SilcBuffer client_id_list;
984 SilcUInt32 list_count;
989 channel = va_arg(vp, char *);
990 channel_entry = va_arg(vp, SilcChannelEntry);
991 modei = va_arg(vp, SilcUInt32);
992 (void)va_arg(vp, SilcUInt32);
993 (void)va_arg(vp, unsigned char *);
994 (void)va_arg(vp, unsigned char *);
995 (void)va_arg(vp, unsigned char *);
996 topic = va_arg(vp, char *);
997 (void)va_arg(vp, unsigned char *);
998 list_count = va_arg(vp, SilcUInt32);
999 client_id_list = va_arg(vp, SilcBuffer);
1001 chanrec = silc_channel_find(server, channel);
1003 chanrec = silc_channel_create(server, channel, TRUE);
1006 g_free_not_null(chanrec->topic);
1007 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1008 signal_emit("channel topic changed", 1, chanrec);
1011 mode = silc_client_chmode(modei,
1012 channel_entry->channel_key ?
1013 channel_entry->channel_key->cipher->name : "",
1014 channel_entry->hmac ?
1015 silc_hmac_get_name(channel_entry->hmac) : "");
1016 g_free_not_null(chanrec->mode);
1017 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1018 signal_emit("channel mode changed", 1, chanrec);
1020 /* Resolve the client information */
1021 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1022 silc_client_join_get_users,
1028 case SILC_COMMAND_NICK:
1030 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1036 old = g_strdup(server->nick);
1037 server_change_nick(SERVER(server), client->nickname);
1038 nicklist_rename_unique(SERVER(server),
1039 server->conn->local_entry, server->nick,
1040 client, client->nickname);
1041 signal_emit("message own_nick", 4, server, server->nick, old, "");
1046 case SILC_COMMAND_LIST:
1055 (void)va_arg(vp, SilcChannelEntry);
1056 name = va_arg(vp, char *);
1057 topic = va_arg(vp, char *);
1058 usercount = va_arg(vp, int);
1060 if (status == SILC_STATUS_LIST_START ||
1061 status == SILC_STATUS_OK)
1062 printformat_module("fe-common/silc", server, NULL,
1063 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1066 snprintf(users, sizeof(users) - 1, "N/A");
1068 snprintf(users, sizeof(users) - 1, "%d", usercount);
1069 printformat_module("fe-common/silc", server, NULL,
1070 MSGLEVEL_CRAP, SILCTXT_LIST,
1071 name, users, topic ? topic : "");
1075 case SILC_COMMAND_UMODE:
1082 mode = va_arg(vp, SilcUInt32);
1084 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1085 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1086 printformat_module("fe-common/silc", server, NULL,
1087 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1089 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1090 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1091 printformat_module("fe-common/silc", server, NULL,
1092 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1094 server->umode = mode;
1095 signal_emit("user mode changed", 2, server, NULL);
1099 case SILC_COMMAND_OPER:
1103 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1104 signal_emit("user mode changed", 2, server, NULL);
1106 printformat_module("fe-common/silc", server, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1110 case SILC_COMMAND_SILCOPER:
1114 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1115 signal_emit("user mode changed", 2, server, NULL);
1117 printformat_module("fe-common/silc", server, NULL,
1118 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1121 case SILC_COMMAND_USERS:
1123 SilcHashTableList htl;
1124 SilcChannelEntry channel;
1125 SilcChannelUser chu;
1130 channel = va_arg(vp, SilcChannelEntry);
1132 printformat_module("fe-common/silc", server, channel->channel_name,
1133 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1134 channel->channel_name);
1136 silc_hash_table_list(channel->user_list, &htl);
1137 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1138 SilcClientEntry e = chu->client;
1139 char stat[5], *mode;
1144 memset(stat, 0, sizeof(stat));
1145 mode = silc_client_chumode_char(chu->mode);
1146 if (e->mode & SILC_UMODE_GONE)
1153 printformat_module("fe-common/silc", server, channel->channel_name,
1154 MSGLEVEL_CRAP, SILCTXT_USERS,
1156 e->username ? e->username : "",
1157 e->hostname ? e->hostname : "",
1158 e->realname ? e->realname : "");
1162 silc_hash_table_list_reset(&htl);
1166 case SILC_COMMAND_BAN:
1168 SilcChannelEntry channel;
1174 channel = va_arg(vp, SilcChannelEntry);
1175 ban_list = va_arg(vp, char *);
1178 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1179 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1182 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1183 SILCTXT_CHANNEL_NO_BAN_LIST,
1184 channel->channel_name);
1188 case SILC_COMMAND_GETKEY:
1192 SilcPublicKey public_key;
1195 GetkeyContext getkey;
1201 id_type = va_arg(vp, SilcUInt32);
1202 entry = va_arg(vp, void *);
1203 public_key = va_arg(vp, SilcPublicKey);
1206 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1208 getkey = silc_calloc(1, sizeof(*getkey));
1209 getkey->entry = entry;
1210 getkey->id_type = id_type;
1211 getkey->client = client;
1212 getkey->conn = conn;
1213 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1215 name = (id_type == SILC_ID_CLIENT ?
1216 ((SilcClientEntry)entry)->nickname :
1217 ((SilcServerEntry)entry)->server_name);
1219 silc_verify_public_key_internal(client, conn, name,
1220 (id_type == SILC_ID_CLIENT ?
1221 SILC_SOCKET_TYPE_CLIENT :
1222 SILC_SOCKET_TYPE_SERVER),
1223 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1224 silc_getkey_cb, getkey);
1227 printformat_module("fe-common/silc", server, NULL,
1228 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1233 case SILC_COMMAND_INFO:
1235 SilcServerEntry server_entry;
1242 server_entry = va_arg(vp, SilcServerEntry);
1243 server_name = va_arg(vp, char *);
1244 server_info = va_arg(vp, char *);
1246 if (server_name && server_info )
1248 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1249 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1254 case SILC_COMMAND_TOPIC:
1256 SilcChannelEntry channel;
1262 channel = va_arg(vp, SilcChannelEntry);
1263 topic = va_arg(vp, char *);
1266 chanrec = silc_channel_find_entry(server, channel);
1268 g_free_not_null(chanrec->topic);
1269 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1270 signal_emit("channel topic changed", 1, chanrec);
1272 printformat_module("fe-common/silc", server, channel->channel_name,
1273 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1274 channel->channel_name, topic);
1276 printformat_module("fe-common/silc", server, channel->channel_name,
1277 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1278 channel->channel_name);
1290 SilcClientConnection conn;
1296 SilcSKEPKType pk_type;
1297 SilcVerifyPublicKey completion;
1301 static void verify_public_key_completion(const char *line, void *context)
1303 PublicKeyVerify verify = (PublicKeyVerify)context;
1305 if (line[0] == 'Y' || line[0] == 'y') {
1306 /* Call the completion */
1307 if (verify->completion)
1308 verify->completion(TRUE, verify->context);
1310 /* Save the key for future checking */
1311 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1312 verify->pk_len, SILC_PKCS_FILE_PEM);
1314 /* Call the completion */
1315 if (verify->completion)
1316 verify->completion(FALSE, verify->context);
1318 printformat_module("fe-common/silc", NULL, NULL,
1319 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1320 verify->entity_name ? verify->entity_name :
1324 silc_free(verify->filename);
1325 silc_free(verify->entity);
1326 silc_free(verify->entity_name);
1327 silc_free(verify->pk);
1331 /* Internal routine to verify public key. If the `completion' is provided
1332 it will be called to indicate whether public was verified or not. For
1333 server/router public key this will check for filename that includes the
1334 remote host's IP address and remote host's hostname. */
1337 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1338 const char *name, SilcSocketType conn_type,
1339 unsigned char *pk, SilcUInt32 pk_len,
1340 SilcSKEPKType pk_type,
1341 SilcVerifyPublicKey completion, void *context)
1344 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1345 char *fingerprint, *babbleprint, *format;
1348 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1349 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1350 "server" : "client");
1351 PublicKeyVerify verify;
1353 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1354 printformat_module("fe-common/silc", NULL, NULL,
1355 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1358 completion(FALSE, context);
1362 pw = getpwuid(getuid());
1365 completion(FALSE, context);
1369 memset(filename, 0, sizeof(filename));
1370 memset(filename2, 0, sizeof(filename2));
1371 memset(file, 0, sizeof(file));
1373 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1374 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1376 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1377 conn->sock->ip, conn->sock->port);
1378 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1379 get_irssi_dir(), entity, file);
1381 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1382 conn->sock->hostname, conn->sock->port);
1383 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1384 get_irssi_dir(), entity, file);
1389 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1390 name, conn->sock->port);
1391 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1392 get_irssi_dir(), entity, file);
1397 /* Replace all whitespaces with `_'. */
1398 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1399 for (i = 0; i < strlen(fingerprint); i++)
1400 if (fingerprint[i] == ' ')
1401 fingerprint[i] = '_';
1403 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1404 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1405 get_irssi_dir(), entity, file);
1406 silc_free(fingerprint);
1411 /* Take fingerprint of the public key */
1412 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1413 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1415 verify = silc_calloc(1, sizeof(*verify));
1416 verify->client = client;
1417 verify->conn = conn;
1418 verify->filename = strdup(ipf);
1419 verify->entity = strdup(entity);
1420 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1421 (name ? strdup(name) : strdup(conn->sock->hostname))
1423 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1424 memcpy(verify->pk, pk, pk_len);
1425 verify->pk_len = pk_len;
1426 verify->pk_type = pk_type;
1427 verify->completion = completion;
1428 verify->context = context;
1430 /* Check whether this key already exists */
1431 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1432 /* Key does not exist, ask user to verify the key and save it */
1434 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1435 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1436 verify->entity_name : entity);
1437 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1438 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1439 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1440 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1441 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1442 SILCTXT_PUBKEY_ACCEPT);
1443 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1446 silc_free(fingerprint);
1449 /* The key already exists, verify it. */
1450 SilcPublicKey public_key;
1451 unsigned char *encpk;
1452 SilcUInt32 encpk_len;
1454 /* Load the key file, try for both IP filename and hostname filename */
1455 if (!silc_pkcs_load_public_key(ipf, &public_key,
1456 SILC_PKCS_FILE_PEM) &&
1457 !silc_pkcs_load_public_key(ipf, &public_key,
1458 SILC_PKCS_FILE_BIN) &&
1459 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1460 SILC_PKCS_FILE_PEM) &&
1461 !silc_pkcs_load_public_key(hostf, &public_key,
1462 SILC_PKCS_FILE_BIN)))) {
1463 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1464 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1465 verify->entity_name : entity);
1466 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1467 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1468 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1469 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1470 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1471 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1472 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1473 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1474 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1477 silc_free(fingerprint);
1481 /* Encode the key data */
1482 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1484 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1485 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1486 verify->entity_name : entity);
1487 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1488 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1489 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1490 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1491 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1492 SILCTXT_PUBKEY_MALFORMED, entity);
1493 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1494 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1495 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1498 silc_free(fingerprint);
1502 /* Compare the keys */
1503 if (memcmp(encpk, pk, encpk_len)) {
1504 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1505 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1506 verify->entity_name : entity);
1507 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1508 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1509 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1510 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1511 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1512 SILCTXT_PUBKEY_NO_MATCH, entity);
1513 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1514 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1515 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1516 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1518 /* Ask user to verify the key and save it */
1519 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1520 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1521 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1524 silc_free(fingerprint);
1528 /* Local copy matched */
1530 completion(TRUE, context);
1531 silc_free(fingerprint);
1535 /* Verifies received public key. The `conn_type' indicates which entity
1536 (server, client etc.) has sent the public key. If user decides to trust
1537 the key may be saved as trusted public key for later use. The
1538 `completion' must be called after the public key has been verified. */
1541 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1542 SilcSocketType conn_type, unsigned char *pk,
1543 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1544 SilcVerifyPublicKey completion, void *context)
1546 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1548 completion, context);
1551 /* Asks passphrase from user on the input line. */
1554 SilcAskPassphrase completion;
1558 void ask_passphrase_completion(const char *passphrase, void *context)
1560 AskPassphrase p = (AskPassphrase)context;
1561 p->completion((unsigned char *)passphrase,
1562 passphrase ? strlen(passphrase) : 0, p->context);
1566 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1567 SilcAskPassphrase completion, void *context)
1569 AskPassphrase p = silc_calloc(1, sizeof(*p));
1570 p->completion = completion;
1571 p->context = context;
1573 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1574 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1578 SilcGetAuthMeth completion;
1580 } *InternalGetAuthMethod;
1582 /* Callback called when we've received the authentication method information
1583 from the server after we've requested it. This will get the authentication
1584 data from the user if needed. */
1586 static void silc_get_auth_method_callback(SilcClient client,
1587 SilcClientConnection conn,
1588 SilcAuthMethod auth_meth,
1591 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1593 SILC_LOG_DEBUG(("Start"));
1595 switch (auth_meth) {
1596 case SILC_AUTH_NONE:
1597 /* No authentication required. */
1598 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1600 case SILC_AUTH_PASSWORD:
1601 /* Do not ask the passphrase from user, the library will ask it if
1602 we do not provide it here. */
1603 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1605 case SILC_AUTH_PUBLIC_KEY:
1606 /* Do not get the authentication data now, the library will generate
1607 it using our default key, if we do not provide it here. */
1608 /* XXX In the future when we support multiple local keys and multiple
1609 local certificates we will need to ask from user which one to use. */
1610 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1614 silc_free(internal);
1617 /* Find authentication method and authentication data by hostname and
1618 port. The hostname may be IP address as well. The found authentication
1619 method and authentication data is returned to `auth_meth', `auth_data'
1620 and `auth_data_len'. The function returns TRUE if authentication method
1621 is found and FALSE if not. `conn' may be NULL. */
1623 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1624 char *hostname, SilcUInt16 port,
1625 SilcGetAuthMeth completion, void *context)
1627 InternalGetAuthMethod internal;
1629 SILC_LOG_DEBUG(("Start"));
1631 /* XXX must resolve from configuration whether this connection has
1632 any specific authentication data */
1634 /* If we do not have this connection configured by the user in a
1635 configuration file then resolve the authentication method from the
1636 server for this session. */
1637 internal = silc_calloc(1, sizeof(*internal));
1638 internal->completion = completion;
1639 internal->context = context;
1641 silc_client_request_authentication_method(client, conn,
1642 silc_get_auth_method_callback,
1646 /* Notifies application that failure packet was received. This is called
1647 if there is some protocol active in the client. The `protocol' is the
1648 protocol context. The `failure' is opaque pointer to the failure
1649 indication. Note, that the `failure' is protocol dependant and application
1650 must explicitly cast it to correct type. Usually `failure' is 32 bit
1651 failure type (see protocol specs for all protocol failure types). */
1653 void silc_failure(SilcClient client, SilcClientConnection conn,
1654 SilcProtocol protocol, void *failure)
1656 SILC_LOG_DEBUG(("Start"));
1658 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1659 SilcSKEStatus status = (SilcSKEStatus)failure;
1661 if (status == SILC_SKE_STATUS_BAD_VERSION)
1662 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1663 SILCTXT_KE_BAD_VERSION);
1664 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1665 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1666 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1667 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1668 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1669 SILCTXT_KE_UNKNOWN_GROUP);
1670 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1671 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1672 SILCTXT_KE_UNKNOWN_CIPHER);
1673 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1674 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1675 SILCTXT_KE_UNKNOWN_PKCS);
1676 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1677 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1678 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1679 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1680 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1681 SILCTXT_KE_UNKNOWN_HMAC);
1682 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1683 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1684 SILCTXT_KE_INCORRECT_SIGNATURE);
1685 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1686 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1687 SILCTXT_KE_INVALID_COOKIE);
1690 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1691 SilcUInt32 err = (SilcUInt32)failure;
1693 if (err == SILC_AUTH_FAILED)
1694 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1695 SILCTXT_AUTH_FAILED);
1699 /* Asks whether the user would like to perform the key agreement protocol.
1700 This is called after we have received an key agreement packet or an
1701 reply to our key agreement packet. This returns TRUE if the user wants
1702 the library to perform the key agreement protocol and FALSE if it is not
1703 desired (application may start it later by calling the function
1704 silc_client_perform_key_agreement). */
1706 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1707 SilcClientEntry client_entry, const char *hostname,
1708 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1713 SILC_LOG_DEBUG(("Start"));
1715 /* We will just display the info on the screen and return FALSE and user
1716 will have to start the key agreement with a command. */
1719 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1722 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1723 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1725 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1726 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1727 client_entry->nickname, hostname, portstr);
1735 void silc_ftp(SilcClient client, SilcClientConnection conn,
1736 SilcClientEntry client_entry, SilcUInt32 session_id,
1737 const char *hostname, SilcUInt16 port)
1739 SILC_SERVER_REC *server;
1741 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1743 SILC_LOG_DEBUG(("Start"));
1745 server = conn->context;
1747 ftp->client_entry = client_entry;
1748 ftp->session_id = session_id;
1751 silc_dlist_add(server->ftp_sessions, ftp);
1752 server->current_session = ftp;
1755 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1758 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1759 SILCTXT_FILE_REQUEST, client_entry->nickname);
1761 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1762 SILCTXT_FILE_REQUEST_HOST,
1763 client_entry->nickname, hostname, portstr);
1766 /* SILC client operations */
1767 SilcClientOperations ops = {
1769 silc_channel_message,
1770 silc_private_message,
1776 silc_get_auth_method,
1777 silc_verify_public_key,
1778 silc_ask_passphrase,