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, const unsigned char *message,
85 SilcUInt32 message_len)
87 SILC_SERVER_REC *server;
89 SILC_CHANNEL_REC *chanrec;
91 SILC_LOG_DEBUG(("Start"));
96 server = conn == NULL ? NULL : conn->context;
97 chanrec = silc_channel_find_entry(server, channel);
101 nick = silc_nicklist_find(chanrec, sender);
103 /* We didn't find client but it clearly exists, add it. */
104 SilcChannelUser chu = silc_client_on_channel(channel, sender);
106 nick = silc_nicklist_insert(chanrec, chu, FALSE);
109 if (flags & SILC_MESSAGE_FLAG_ACTION)
110 printformat_module("fe-common/silc", server, channel->channel_name,
111 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
112 nick == NULL ? "[<unknown>]" : nick->nick, message);
113 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
114 printformat_module("fe-common/silc", server, channel->channel_name,
115 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
116 nick == NULL ? "[<unknown>]" : nick->nick, message);
118 signal_emit("message public", 6, server, message,
119 nick == NULL ? "[<unknown>]" : nick->nick,
120 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
121 chanrec->name, nick);
124 /* Private message to the client. The `sender' is the nickname of the
125 sender received in the packet. */
127 void silc_private_message(SilcClient client, SilcClientConnection conn,
128 SilcClientEntry sender, SilcMessageFlags flags,
129 const unsigned char *message,
130 SilcUInt32 message_len)
132 SILC_SERVER_REC *server;
135 SILC_LOG_DEBUG(("Start"));
137 server = conn == NULL ? NULL : conn->context;
138 memset(userhost, 0, sizeof(userhost));
139 if (sender->username)
140 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
141 sender->username, sender->hostname);
142 signal_emit("message private", 4, server, message,
143 sender->nickname ? sender->nickname : "[<unknown>]",
144 sender->username ? userhost : NULL);
147 /* Notify message to the client. The notify arguments are sent in the
148 same order as servers sends them. The arguments are same as received
149 from the server except for ID's. If ID is received application receives
150 the corresponding entry to the ID. For example, if Client ID is received
151 application receives SilcClientEntry. Also, if the notify type is
152 for channel the channel entry is sent to application (even if server
153 does not send it). */
155 void silc_notify(SilcClient client, SilcClientConnection conn,
156 SilcNotifyType type, ...)
159 SILC_SERVER_REC *server;
160 SILC_CHANNEL_REC *chanrec;
161 SILC_NICK_REC *nickrec;
162 SilcClientEntry client_entry, client_entry2;
163 SilcChannelEntry channel, channel2;
164 SilcServerEntry server_entry;
170 GSList *list1, *list_tmp;
172 SILC_LOG_DEBUG(("Start"));
176 server = conn == NULL ? NULL : conn->context;
179 case SILC_NOTIFY_TYPE_NONE:
180 /* Some generic notice from server */
181 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
184 case SILC_NOTIFY_TYPE_INVITE:
186 * Invited or modified invite list.
189 SILC_LOG_DEBUG(("Notify: INVITE"));
191 channel = va_arg(va, SilcChannelEntry);
192 name = va_arg(va, char *);
193 client_entry = va_arg(va, SilcClientEntry);
195 memset(userhost, 0, sizeof(userhost));
196 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
197 client_entry->username, client_entry->hostname);
198 signal_emit("message invite", 4, server, channel ? channel->channel_name :
199 name, client_entry->nickname, userhost);
202 case SILC_NOTIFY_TYPE_JOIN:
207 SILC_LOG_DEBUG(("Notify: JOIN"));
209 client_entry = va_arg(va, SilcClientEntry);
210 channel = va_arg(va, SilcChannelEntry);
212 if (client_entry == server->conn->local_entry) {
213 /* You joined to channel */
214 chanrec = silc_channel_find(server, channel->channel_name);
215 if (chanrec != NULL && !chanrec->joined)
216 chanrec->entry = channel;
218 chanrec = silc_channel_find_entry(server, channel);
219 if (chanrec != NULL) {
220 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
222 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
226 memset(userhost, 0, sizeof(userhost));
227 if (client_entry->username)
228 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
229 client_entry->username, client_entry->hostname);
230 signal_emit("message join", 4, server, channel->channel_name,
231 client_entry->nickname,
232 client_entry->username == NULL ? "" : userhost);
235 case SILC_NOTIFY_TYPE_LEAVE:
240 SILC_LOG_DEBUG(("Notify: LEAVE"));
242 client_entry = va_arg(va, SilcClientEntry);
243 channel = va_arg(va, SilcChannelEntry);
245 memset(userhost, 0, sizeof(userhost));
246 if (client_entry->username)
247 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
248 client_entry->username, client_entry->hostname);
249 signal_emit("message part", 5, server, channel->channel_name,
250 client_entry->nickname, client_entry->username ?
251 userhost : "", client_entry->nickname);
253 chanrec = silc_channel_find_entry(server, channel);
254 if (chanrec != NULL) {
255 nickrec = silc_nicklist_find(chanrec, client_entry);
257 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
261 case SILC_NOTIFY_TYPE_SIGNOFF:
266 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
268 client_entry = va_arg(va, SilcClientEntry);
269 tmp = va_arg(va, char *);
271 silc_server_free_ftp(server, client_entry);
273 memset(userhost, 0, sizeof(userhost));
274 if (client_entry->username)
275 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
276 client_entry->username, client_entry->hostname);
277 signal_emit("message quit", 4, server, client_entry->nickname,
278 client_entry->username ? userhost : "",
281 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
282 for (list_tmp = list1; list_tmp != NULL; list_tmp =
283 list_tmp->next->next) {
284 CHANNEL_REC *channel = list_tmp->data;
285 NICK_REC *nickrec = list_tmp->next->data;
287 nicklist_remove(channel, nickrec);
291 case SILC_NOTIFY_TYPE_TOPIC_SET:
296 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
298 idtype = va_arg(va, int);
299 entry = va_arg(va, void *);
300 tmp = va_arg(va, char *);
301 channel = va_arg(va, SilcChannelEntry);
303 chanrec = silc_channel_find_entry(server, channel);
304 if (chanrec != NULL) {
305 g_free_not_null(chanrec->topic);
306 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
307 signal_emit("channel topic changed", 1, chanrec);
310 if (idtype == SILC_ID_CLIENT) {
311 client_entry = (SilcClientEntry)entry;
312 memset(userhost, 0, sizeof(userhost));
313 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
314 client_entry->username, client_entry->hostname);
315 signal_emit("message topic", 5, server, channel->channel_name,
316 tmp, client_entry->nickname, userhost);
317 } else if (idtype == SILC_ID_SERVER) {
318 server_entry = (SilcServerEntry)entry;
319 signal_emit("message topic", 5, server, channel->channel_name,
320 tmp, server_entry->server_name,
321 server_entry->server_name);
323 channel = (SilcChannelEntry)entry;
324 signal_emit("message topic", 5, server, channel->channel_name,
325 tmp, channel->channel_name, channel->channel_name);
329 case SILC_NOTIFY_TYPE_NICK_CHANGE:
334 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
336 client_entry = va_arg(va, SilcClientEntry);
337 client_entry2 = va_arg(va, SilcClientEntry);
339 memset(userhost, 0, sizeof(userhost));
340 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
341 client_entry2->username, client_entry2->hostname);
342 nicklist_rename_unique(SERVER(server),
343 client_entry, client_entry->nickname,
344 client_entry2, client_entry2->nickname);
345 signal_emit("message nick", 4, server, client_entry2->nickname,
346 client_entry->nickname, userhost);
349 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
351 * Changed channel mode.
354 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
356 idtype = va_arg(va, int);
357 entry = va_arg(va, void *);
358 mode = va_arg(va, SilcUInt32);
359 (void)va_arg(va, char *);
360 (void)va_arg(va, char *);
361 channel = va_arg(va, SilcChannelEntry);
363 tmp = silc_client_chmode(mode,
364 channel->channel_key ?
365 channel->channel_key->cipher->name : "",
367 silc_hmac_get_name(channel->hmac) : "");
369 chanrec = silc_channel_find_entry(server, channel);
370 if (chanrec != NULL) {
371 g_free_not_null(chanrec->mode);
372 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
373 signal_emit("channel mode changed", 1, chanrec);
376 if (idtype == SILC_ID_CLIENT) {
377 client_entry = (SilcClientEntry)entry;
378 printformat_module("fe-common/silc", server, channel->channel_name,
379 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
380 channel->channel_name, tmp ? tmp : "removed all",
381 client_entry->nickname);
382 } else if (idtype == SILC_ID_SERVER) {
383 server_entry = (SilcServerEntry)entry;
384 printformat_module("fe-common/silc", server, channel->channel_name,
385 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
386 channel->channel_name, tmp ? tmp : "removed all",
387 server_entry->server_name);
389 channel2 = (SilcChannelEntry)entry;
390 printformat_module("fe-common/silc", server, channel->channel_name,
391 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
392 channel->channel_name, tmp ? tmp : "removed all",
393 channel2->channel_name);
399 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
401 * Changed user's mode on channel.
404 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
406 idtype = va_arg(va, int);
407 entry = va_arg(va, void *);
408 mode = va_arg(va, SilcUInt32);
409 client_entry2 = va_arg(va, SilcClientEntry);
410 channel = va_arg(va, SilcChannelEntry);
412 tmp = silc_client_chumode(mode);
413 chanrec = silc_channel_find_entry(server, channel);
414 if (chanrec != NULL) {
417 if (client_entry2 == server->conn->local_entry)
418 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
420 nick = silc_nicklist_find(chanrec, client_entry2);
422 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
423 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
424 signal_emit("nick mode changed", 2, chanrec, nick);
428 if (idtype == SILC_ID_CLIENT) {
429 client_entry = (SilcClientEntry)entry;
430 printformat_module("fe-common/silc", server, channel->channel_name,
431 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
432 channel->channel_name, client_entry2->nickname,
433 tmp ? tmp : "removed all",
434 client_entry->nickname);
435 } else if (idtype == SILC_ID_SERVER) {
436 server_entry = (SilcServerEntry)entry;
437 printformat_module("fe-common/silc", server, channel->channel_name,
438 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
439 channel->channel_name, client_entry2->nickname,
440 tmp ? tmp : "removed all",
441 server_entry->server_name);
443 channel2 = (SilcChannelEntry)entry;
444 printformat_module("fe-common/silc", server, channel->channel_name,
445 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
446 channel->channel_name, client_entry2->nickname,
447 tmp ? tmp : "removed all",
448 channel2->channel_name);
451 if (mode & SILC_CHANNEL_UMODE_CHANFO)
452 printformat_module("fe-common/silc",
453 server, channel->channel_name, MSGLEVEL_CRAP,
454 SILCTXT_CHANNEL_FOUNDER,
455 channel->channel_name, client_entry2->nickname);
460 case SILC_NOTIFY_TYPE_MOTD:
465 SILC_LOG_DEBUG(("Notify: MOTD"));
467 tmp = va_arg(va, char *);
469 if (!settings_get_bool("skip_motd"))
470 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
473 case SILC_NOTIFY_TYPE_KICKED:
475 * Someone was kicked from channel.
478 SILC_LOG_DEBUG(("Notify: KICKED"));
480 client_entry = va_arg(va, SilcClientEntry);
481 tmp = va_arg(va, char *);
482 client_entry2 = va_arg(va, SilcClientEntry);
483 channel = va_arg(va, SilcChannelEntry);
485 chanrec = silc_channel_find_entry(server, channel);
487 if (client_entry == conn->local_entry) {
488 printformat_module("fe-common/silc", server, channel->channel_name,
489 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
490 channel->channel_name,
491 client_entry ? client_entry2->nickname : "",
494 chanrec->kicked = TRUE;
495 channel_destroy((CHANNEL_REC *)chanrec);
498 printformat_module("fe-common/silc", server, channel->channel_name,
499 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
500 client_entry->nickname, channel->channel_name,
501 client_entry2 ? client_entry2->nickname : "",
505 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
507 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
512 case SILC_NOTIFY_TYPE_KILLED:
514 * Someone was killed from the network.
517 SILC_LOG_DEBUG(("Notify: KILLED"));
519 client_entry = va_arg(va, SilcClientEntry);
520 tmp = va_arg(va, char *);
521 client_entry2 = va_arg(va, SilcClientEntry);
523 if (client_entry == conn->local_entry) {
524 printformat_module("fe-common/silc", server, NULL,
525 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
526 client_entry2 ? client_entry2->nickname : "",
529 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
530 for (list_tmp = list1; list_tmp != NULL; list_tmp =
531 list_tmp->next->next) {
532 CHANNEL_REC *channel = list_tmp->data;
533 NICK_REC *nickrec = list_tmp->next->data;
534 nicklist_remove(channel, nickrec);
537 printformat_module("fe-common/silc", server, NULL,
538 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
539 client_entry->nickname,
540 client_entry2 ? client_entry2->nickname : "",
545 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
548 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
551 * Server has quit the network.
554 SilcClientEntry *clients;
555 SilcUInt32 clients_count;
557 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
559 (void)va_arg(va, void *);
560 clients = va_arg(va, SilcClientEntry *);
561 clients_count = va_arg(va, SilcUInt32);
563 for (i = 0; i < clients_count; i++) {
564 memset(userhost, 0, sizeof(userhost));
565 if (clients[i]->username)
566 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
567 clients[i]->username, clients[i]->hostname);
568 signal_emit("message quit", 4, server, clients[i]->nickname,
569 clients[i]->username ? userhost : "",
572 silc_server_free_ftp(server, clients[i]);
574 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
575 for (list_tmp = list1; list_tmp != NULL; list_tmp =
576 list_tmp->next->next) {
577 CHANNEL_REC *channel = list_tmp->data;
578 NICK_REC *nickrec = list_tmp->next->data;
579 nicklist_remove(channel, nickrec);
587 printformat_module("fe-common/silc", server, NULL,
588 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
595 /* Called to indicate that connection was either successfully established
596 or connecting failed. This is also the first time application receives
597 the SilcClientConnection object which it should save somewhere. */
599 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
601 SILC_SERVER_REC *server = conn->context;
603 if (!server && !success) {
604 silc_client_close_connection(client, conn);
609 server->connected = TRUE;
610 signal_emit("event connected", 1, server);
612 server->connection_lost = TRUE;
614 server->conn->context = NULL;
615 server_disconnect(SERVER(server));
619 /* Called to indicate that connection was disconnected to the server. */
621 void silc_disconnect(SilcClient client, SilcClientConnection conn)
623 SILC_SERVER_REC *server = conn->context;
625 SILC_LOG_DEBUG(("Start"));
627 if (!server || server->connection_lost)
630 if (server->conn && server->conn->local_entry) {
631 nicklist_rename_unique(SERVER(server),
632 server->conn->local_entry, server->nick,
633 server->conn->local_entry,
634 silc_client->username);
635 silc_change_nick(server, silc_client->username);
638 server->conn->context = NULL;
640 server->connection_lost = TRUE;
641 server_disconnect(SERVER(server));
644 /* Command handler. This function is called always in the command function.
645 If error occurs it will be called as well. `conn' is the associated
646 client connection. `cmd_context' is the command context that was
647 originally sent to the command. `success' is FALSE if error occured
648 during command. `command' is the command being processed. It must be
649 noted that this is not reply from server. This is merely called just
650 after application has called the command. Just to tell application
651 that the command really was processed. */
653 void silc_command(SilcClient client, SilcClientConnection conn,
654 SilcClientCommandContext cmd_context, int success,
657 SILC_SERVER_REC *server = conn->context;
659 SILC_LOG_DEBUG(("Start"));
665 case SILC_COMMAND_INVITE:
666 printformat_module("fe-common/silc", server, NULL,
667 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
668 cmd_context->argv[2],
669 (cmd_context->argv[1][0] == '*' ?
670 (char *)conn->current_channel->channel_name :
671 (char *)cmd_context->argv[1]));
678 /* Client info resolving callback when JOIN command reply is received.
679 This will cache all users on the channel. */
681 static void silc_client_join_get_users(SilcClient client,
682 SilcClientConnection conn,
683 SilcClientEntry *clients,
684 SilcUInt32 clients_count,
687 SilcChannelEntry channel = (SilcChannelEntry)context;
688 SilcHashTableList htl;
690 SILC_SERVER_REC *server = conn->context;
691 SILC_CHANNEL_REC *chanrec;
692 SilcClientEntry founder = NULL;
698 chanrec = silc_channel_find(server, channel->channel_name);
702 silc_hash_table_list(channel->user_list, &htl);
703 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
704 if (!chu->client->nickname)
706 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
707 founder = chu->client;
708 silc_nicklist_insert(chanrec, chu, FALSE);
710 silc_hash_table_list_reset(&htl);
712 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
713 nicklist_set_own(CHANNEL(chanrec), ownnick);
714 signal_emit("channel joined", 1, chanrec);
717 printformat_module("fe-common/silc", server, channel->channel_name,
718 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
719 channel->channel_name, chanrec->topic);
721 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
724 if (founder == conn->local_entry)
725 printformat_module("fe-common/silc",
726 server, channel->channel_name, MSGLEVEL_CRAP,
727 SILCTXT_CHANNEL_FOUNDER_YOU,
728 channel->channel_name);
730 printformat_module("fe-common/silc",
731 server, channel->channel_name, MSGLEVEL_CRAP,
732 SILCTXT_CHANNEL_FOUNDER,
733 channel->channel_name, founder->nickname);
739 SilcClientConnection conn;
745 void silc_getkey_cb(bool success, void *context)
747 GetkeyContext getkey = (GetkeyContext)context;
748 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
749 char *name = (getkey->id_type == SILC_ID_CLIENT ?
750 ((SilcClientEntry)getkey->entry)->nickname :
751 ((SilcServerEntry)getkey->entry)->server_name);
754 printformat_module("fe-common/silc", NULL, NULL,
755 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
757 printformat_module("fe-common/silc", NULL, NULL,
758 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
761 silc_free(getkey->fingerprint);
765 /* Command reply handler. This function is called always in the command reply
766 function. If error occurs it will be called as well. Normal scenario
767 is that it will be called after the received command data has been parsed
768 and processed. The function is used to pass the received command data to
771 `conn' is the associated client connection. `cmd_payload' is the command
772 payload data received from server and it can be ignored. It is provided
773 if the application would like to re-parse the received command data,
774 however, it must be noted that the data is parsed already by the library
775 thus the payload can be ignored. `success' is FALSE if error occured.
776 In this case arguments are not sent to the application. `command' is the
777 command reply being processed. The function has variable argument list
778 and each command defines the number and type of arguments it passes to the
779 application (on error they are not sent). */
782 silc_command_reply(SilcClient client, SilcClientConnection conn,
783 SilcCommandPayload cmd_payload, int success,
784 SilcCommand command, SilcCommandStatus status, ...)
787 SILC_SERVER_REC *server = conn->context;
788 SILC_CHANNEL_REC *chanrec;
791 va_start(vp, status);
793 SILC_LOG_DEBUG(("Start"));
796 case SILC_COMMAND_WHOIS:
798 char buf[1024], *nickname, *username, *realname, *nick;
799 unsigned char *fingerprint;
800 SilcUInt32 idle, mode;
802 SilcClientEntry client_entry;
804 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
805 /* Print the unknown nick for user */
807 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
810 silc_say_error("%s: %s", tmp,
811 silc_client_command_status_message(status));
813 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
814 /* Try to find the entry for the unknown client ID, since we
815 might have, and print the nickname of it for user. */
818 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
821 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
824 client_entry = silc_client_get_client_by_id(client, conn,
826 if (client_entry && client_entry->nickname)
827 silc_say_error("%s: %s", client_entry->nickname,
828 silc_client_command_status_message(status));
829 silc_free(client_id);
838 client_entry = va_arg(vp, SilcClientEntry);
839 nickname = va_arg(vp, char *);
840 username = va_arg(vp, char *);
841 realname = va_arg(vp, char *);
842 channels = va_arg(vp, SilcBuffer);
843 mode = va_arg(vp, SilcUInt32);
844 idle = va_arg(vp, SilcUInt32);
845 fingerprint = va_arg(vp, unsigned char *);
847 silc_parse_userfqdn(nickname, &nick, NULL);
848 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
849 SILCTXT_WHOIS_USERINFO, nickname,
850 client_entry->username, client_entry->hostname,
851 nick, client_entry->nickname);
852 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
853 SILCTXT_WHOIS_REALNAME, realname);
857 SilcDList list = silc_channel_payload_parse_list(channels->data,
860 SilcChannelPayload entry;
861 memset(buf, 0, sizeof(buf));
862 silc_dlist_start(list);
863 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
864 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
866 char *name = silc_channel_get_name(entry, &name_len);
869 strncat(buf, m, strlen(m));
870 strncat(buf, name, name_len);
871 strncat(buf, " ", 1);
875 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
876 SILCTXT_WHOIS_CHANNELS, buf);
877 silc_channel_payload_list_free(list);
882 memset(buf, 0, sizeof(buf));
884 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
885 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
886 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
888 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
889 "SILC Operator" : "[Unknown mode]");
891 if (mode & SILC_UMODE_GONE)
892 strcat(buf, " away");
893 if (mode & SILC_UMODE_INDISPOSED)
894 strcat(buf, " indisposed");
895 if (mode & SILC_UMODE_BUSY)
896 strcat(buf, " busy");
897 if (mode & SILC_UMODE_PAGE)
898 strcat(buf, " page to reach");
899 if (mode & SILC_UMODE_HYPER)
900 strcat(buf, " hyper active");
901 if (mode & SILC_UMODE_ROBOT)
902 strcat(buf, " robot");
904 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
905 SILCTXT_WHOIS_MODES, buf);
908 if (idle && nickname) {
909 memset(buf, 0, sizeof(buf));
910 snprintf(buf, sizeof(buf) - 1, "%lu %s",
911 idle > 60 ? (idle / 60) : idle,
912 idle > 60 ? "minutes" : "seconds");
914 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
915 SILCTXT_WHOIS_IDLE, buf);
919 fingerprint = silc_fingerprint(fingerprint, 20);
920 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
921 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
922 silc_free(fingerprint);
927 case SILC_COMMAND_IDENTIFY:
929 SilcClientEntry client_entry;
931 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
932 /* Print the unknown nick for user */
934 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
937 silc_say_error("%s: %s", tmp,
938 silc_client_command_status_message(status));
940 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
941 /* Try to find the entry for the unknown client ID, since we
942 might have, and print the nickname of it for user. */
945 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
948 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
951 client_entry = silc_client_get_client_by_id(client, conn,
953 if (client_entry && client_entry->nickname)
954 silc_say_error("%s: %s", client_entry->nickname,
955 silc_client_command_status_message(status));
956 silc_free(client_id);
965 case SILC_COMMAND_WHOWAS:
967 char *nickname, *username, *realname;
969 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
970 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
972 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
975 silc_say_error("%s: %s", tmp,
976 silc_client_command_status_message(status));
983 (void)va_arg(vp, SilcClientEntry);
984 nickname = va_arg(vp, char *);
985 username = va_arg(vp, char *);
986 realname = va_arg(vp, char *);
988 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
989 SILCTXT_WHOWAS_USERINFO, nickname, username,
990 realname ? realname : "");
994 case SILC_COMMAND_INVITE:
996 SilcChannelEntry channel;
998 SilcArgumentPayload args;
1004 channel = va_arg(vp, SilcChannelEntry);
1005 invite_list = va_arg(vp, char *);
1007 args = silc_command_get_args(cmd_payload);
1009 argc = silc_argument_get_arg_num(args);
1012 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1013 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1016 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1017 SILCTXT_CHANNEL_NO_INVITE_LIST,
1018 channel->channel_name);
1022 case SILC_COMMAND_JOIN:
1024 char *channel, *mode, *topic;
1026 SilcChannelEntry channel_entry;
1027 SilcBuffer client_id_list;
1028 SilcUInt32 list_count;
1033 channel = va_arg(vp, char *);
1034 channel_entry = va_arg(vp, SilcChannelEntry);
1035 modei = va_arg(vp, SilcUInt32);
1036 (void)va_arg(vp, SilcUInt32);
1037 (void)va_arg(vp, unsigned char *);
1038 (void)va_arg(vp, unsigned char *);
1039 (void)va_arg(vp, unsigned char *);
1040 topic = va_arg(vp, char *);
1041 (void)va_arg(vp, unsigned char *);
1042 list_count = va_arg(vp, SilcUInt32);
1043 client_id_list = va_arg(vp, SilcBuffer);
1045 chanrec = silc_channel_find(server, channel);
1047 chanrec = silc_channel_create(server, channel, TRUE);
1050 g_free_not_null(chanrec->topic);
1051 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1052 signal_emit("channel topic changed", 1, chanrec);
1055 mode = silc_client_chmode(modei,
1056 channel_entry->channel_key ?
1057 channel_entry->channel_key->cipher->name : "",
1058 channel_entry->hmac ?
1059 silc_hmac_get_name(channel_entry->hmac) : "");
1060 g_free_not_null(chanrec->mode);
1061 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1062 signal_emit("channel mode changed", 1, chanrec);
1064 /* Resolve the client information */
1065 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1066 silc_client_join_get_users,
1072 case SILC_COMMAND_NICK:
1074 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1080 old = g_strdup(server->nick);
1081 server_change_nick(SERVER(server), client->nickname);
1082 nicklist_rename_unique(SERVER(server),
1083 server->conn->local_entry, server->nick,
1084 client, client->nickname);
1085 signal_emit("message own_nick", 4, server, server->nick, old, "");
1090 case SILC_COMMAND_LIST:
1099 (void)va_arg(vp, SilcChannelEntry);
1100 name = va_arg(vp, char *);
1101 topic = va_arg(vp, char *);
1102 usercount = va_arg(vp, int);
1104 if (status == SILC_STATUS_LIST_START ||
1105 status == SILC_STATUS_OK)
1106 printformat_module("fe-common/silc", server, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1110 snprintf(users, sizeof(users) - 1, "N/A");
1112 snprintf(users, sizeof(users) - 1, "%d", usercount);
1113 printformat_module("fe-common/silc", server, NULL,
1114 MSGLEVEL_CRAP, SILCTXT_LIST,
1115 name, users, topic ? topic : "");
1119 case SILC_COMMAND_UMODE:
1126 mode = va_arg(vp, SilcUInt32);
1128 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1129 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1130 printformat_module("fe-common/silc", server, NULL,
1131 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1133 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1134 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1135 printformat_module("fe-common/silc", server, NULL,
1136 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1138 server->umode = mode;
1139 signal_emit("user mode changed", 2, server, NULL);
1143 case SILC_COMMAND_OPER:
1147 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1148 signal_emit("user mode changed", 2, server, NULL);
1150 printformat_module("fe-common/silc", server, NULL,
1151 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1154 case SILC_COMMAND_SILCOPER:
1158 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1159 signal_emit("user mode changed", 2, server, NULL);
1161 printformat_module("fe-common/silc", server, NULL,
1162 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1165 case SILC_COMMAND_USERS:
1167 SilcHashTableList htl;
1168 SilcChannelEntry channel;
1169 SilcChannelUser chu;
1174 channel = va_arg(vp, SilcChannelEntry);
1176 printformat_module("fe-common/silc", server, channel->channel_name,
1177 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1178 channel->channel_name);
1180 silc_hash_table_list(channel->user_list, &htl);
1181 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1182 SilcClientEntry e = chu->client;
1183 char stat[5], *mode;
1188 memset(stat, 0, sizeof(stat));
1189 mode = silc_client_chumode_char(chu->mode);
1190 if (e->mode & SILC_UMODE_GONE)
1192 else if (e->mode & SILC_UMODE_INDISPOSED)
1194 else if (e->mode & SILC_UMODE_BUSY)
1196 else if (e->mode & SILC_UMODE_PAGE)
1198 else if (e->mode & SILC_UMODE_HYPER)
1200 else if (e->mode & SILC_UMODE_ROBOT)
1207 printformat_module("fe-common/silc", server, channel->channel_name,
1208 MSGLEVEL_CRAP, SILCTXT_USERS,
1210 e->username ? e->username : "",
1211 e->hostname ? e->hostname : "",
1212 e->realname ? e->realname : "");
1216 silc_hash_table_list_reset(&htl);
1220 case SILC_COMMAND_BAN:
1222 SilcChannelEntry channel;
1228 channel = va_arg(vp, SilcChannelEntry);
1229 ban_list = va_arg(vp, char *);
1232 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1233 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1236 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1237 SILCTXT_CHANNEL_NO_BAN_LIST,
1238 channel->channel_name);
1242 case SILC_COMMAND_GETKEY:
1246 SilcPublicKey public_key;
1249 GetkeyContext getkey;
1255 id_type = va_arg(vp, SilcUInt32);
1256 entry = va_arg(vp, void *);
1257 public_key = va_arg(vp, SilcPublicKey);
1260 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1262 getkey = silc_calloc(1, sizeof(*getkey));
1263 getkey->entry = entry;
1264 getkey->id_type = id_type;
1265 getkey->client = client;
1266 getkey->conn = conn;
1267 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1269 name = (id_type == SILC_ID_CLIENT ?
1270 ((SilcClientEntry)entry)->nickname :
1271 ((SilcServerEntry)entry)->server_name);
1273 silc_verify_public_key_internal(client, conn, name,
1274 (id_type == SILC_ID_CLIENT ?
1275 SILC_SOCKET_TYPE_CLIENT :
1276 SILC_SOCKET_TYPE_SERVER),
1277 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1278 silc_getkey_cb, getkey);
1281 printformat_module("fe-common/silc", server, NULL,
1282 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1287 case SILC_COMMAND_INFO:
1289 SilcServerEntry server_entry;
1296 server_entry = va_arg(vp, SilcServerEntry);
1297 server_name = va_arg(vp, char *);
1298 server_info = va_arg(vp, char *);
1300 if (server_name && server_info )
1302 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1303 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1308 case SILC_COMMAND_TOPIC:
1310 SilcChannelEntry channel;
1316 channel = va_arg(vp, SilcChannelEntry);
1317 topic = va_arg(vp, char *);
1320 chanrec = silc_channel_find_entry(server, channel);
1322 g_free_not_null(chanrec->topic);
1323 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1324 signal_emit("channel topic changed", 1, chanrec);
1326 printformat_module("fe-common/silc", server, channel->channel_name,
1327 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1328 channel->channel_name, topic);
1330 printformat_module("fe-common/silc", server, channel->channel_name,
1331 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1332 channel->channel_name);
1344 SilcClientConnection conn;
1350 SilcSKEPKType pk_type;
1351 SilcVerifyPublicKey completion;
1355 static void verify_public_key_completion(const char *line, void *context)
1357 PublicKeyVerify verify = (PublicKeyVerify)context;
1359 if (line[0] == 'Y' || line[0] == 'y') {
1360 /* Call the completion */
1361 if (verify->completion)
1362 verify->completion(TRUE, verify->context);
1364 /* Save the key for future checking */
1365 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1366 verify->pk_len, SILC_PKCS_FILE_PEM);
1368 /* Call the completion */
1369 if (verify->completion)
1370 verify->completion(FALSE, verify->context);
1372 printformat_module("fe-common/silc", NULL, NULL,
1373 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1374 verify->entity_name ? verify->entity_name :
1378 silc_free(verify->filename);
1379 silc_free(verify->entity);
1380 silc_free(verify->entity_name);
1381 silc_free(verify->pk);
1385 /* Internal routine to verify public key. If the `completion' is provided
1386 it will be called to indicate whether public was verified or not. For
1387 server/router public key this will check for filename that includes the
1388 remote host's IP address and remote host's hostname. */
1391 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1392 const char *name, SilcSocketType conn_type,
1393 unsigned char *pk, SilcUInt32 pk_len,
1394 SilcSKEPKType pk_type,
1395 SilcVerifyPublicKey completion, void *context)
1398 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1399 char *fingerprint, *babbleprint, *format;
1402 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1403 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1404 "server" : "client");
1405 PublicKeyVerify verify;
1407 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1408 printformat_module("fe-common/silc", NULL, NULL,
1409 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1412 completion(FALSE, context);
1416 pw = getpwuid(getuid());
1419 completion(FALSE, context);
1423 memset(filename, 0, sizeof(filename));
1424 memset(filename2, 0, sizeof(filename2));
1425 memset(file, 0, sizeof(file));
1427 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1428 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1430 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1431 conn->sock->ip, conn->sock->port);
1432 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1433 get_irssi_dir(), entity, file);
1435 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1436 conn->sock->hostname, conn->sock->port);
1437 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1438 get_irssi_dir(), entity, file);
1443 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1444 name, conn->sock->port);
1445 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1446 get_irssi_dir(), entity, file);
1451 /* Replace all whitespaces with `_'. */
1452 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1453 for (i = 0; i < strlen(fingerprint); i++)
1454 if (fingerprint[i] == ' ')
1455 fingerprint[i] = '_';
1457 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1458 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1459 get_irssi_dir(), entity, file);
1460 silc_free(fingerprint);
1465 /* Take fingerprint of the public key */
1466 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1467 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1469 verify = silc_calloc(1, sizeof(*verify));
1470 verify->client = client;
1471 verify->conn = conn;
1472 verify->filename = strdup(ipf);
1473 verify->entity = strdup(entity);
1474 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1475 (name ? strdup(name) : strdup(conn->sock->hostname))
1477 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1478 memcpy(verify->pk, pk, pk_len);
1479 verify->pk_len = pk_len;
1480 verify->pk_type = pk_type;
1481 verify->completion = completion;
1482 verify->context = context;
1484 /* Check whether this key already exists */
1485 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1486 /* Key does not exist, ask user to verify the key and save it */
1488 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1489 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1490 verify->entity_name : entity);
1491 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1492 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1493 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1494 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1495 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1496 SILCTXT_PUBKEY_ACCEPT);
1497 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1500 silc_free(fingerprint);
1503 /* The key already exists, verify it. */
1504 SilcPublicKey public_key;
1505 unsigned char *encpk;
1506 SilcUInt32 encpk_len;
1508 /* Load the key file, try for both IP filename and hostname filename */
1509 if (!silc_pkcs_load_public_key(ipf, &public_key,
1510 SILC_PKCS_FILE_PEM) &&
1511 !silc_pkcs_load_public_key(ipf, &public_key,
1512 SILC_PKCS_FILE_BIN) &&
1513 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1514 SILC_PKCS_FILE_PEM) &&
1515 !silc_pkcs_load_public_key(hostf, &public_key,
1516 SILC_PKCS_FILE_BIN)))) {
1517 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1518 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1519 verify->entity_name : entity);
1520 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1521 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1522 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1523 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1524 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1525 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1526 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1527 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1528 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1531 silc_free(fingerprint);
1535 /* Encode the key data */
1536 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1538 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1539 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1540 verify->entity_name : entity);
1541 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1542 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1543 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1544 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1545 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1546 SILCTXT_PUBKEY_MALFORMED, entity);
1547 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1548 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1549 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1552 silc_free(fingerprint);
1556 /* Compare the keys */
1557 if (memcmp(encpk, pk, encpk_len)) {
1558 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1559 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1560 verify->entity_name : entity);
1561 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1562 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1563 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1564 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1565 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1566 SILCTXT_PUBKEY_NO_MATCH, entity);
1567 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1568 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1569 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1570 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1572 /* Ask user to verify the key and save it */
1573 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1574 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1575 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1578 silc_free(fingerprint);
1582 /* Local copy matched */
1584 completion(TRUE, context);
1585 silc_free(fingerprint);
1589 /* Verifies received public key. The `conn_type' indicates which entity
1590 (server, client etc.) has sent the public key. If user decides to trust
1591 the key may be saved as trusted public key for later use. The
1592 `completion' must be called after the public key has been verified. */
1595 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1596 SilcSocketType conn_type, unsigned char *pk,
1597 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1598 SilcVerifyPublicKey completion, void *context)
1600 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1602 completion, context);
1605 /* Asks passphrase from user on the input line. */
1608 SilcAskPassphrase completion;
1612 void ask_passphrase_completion(const char *passphrase, void *context)
1614 AskPassphrase p = (AskPassphrase)context;
1615 p->completion((unsigned char *)passphrase,
1616 passphrase ? strlen(passphrase) : 0, p->context);
1620 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1621 SilcAskPassphrase completion, void *context)
1623 AskPassphrase p = silc_calloc(1, sizeof(*p));
1624 p->completion = completion;
1625 p->context = context;
1627 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1628 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1632 SilcGetAuthMeth completion;
1634 } *InternalGetAuthMethod;
1636 /* Callback called when we've received the authentication method information
1637 from the server after we've requested it. This will get the authentication
1638 data from the user if needed. */
1640 static void silc_get_auth_method_callback(SilcClient client,
1641 SilcClientConnection conn,
1642 SilcAuthMethod auth_meth,
1645 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1647 SILC_LOG_DEBUG(("Start"));
1649 switch (auth_meth) {
1650 case SILC_AUTH_NONE:
1651 /* No authentication required. */
1652 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1654 case SILC_AUTH_PASSWORD:
1655 /* Do not ask the passphrase from user, the library will ask it if
1656 we do not provide it here. */
1657 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1659 case SILC_AUTH_PUBLIC_KEY:
1660 /* Do not get the authentication data now, the library will generate
1661 it using our default key, if we do not provide it here. */
1662 /* XXX In the future when we support multiple local keys and multiple
1663 local certificates we will need to ask from user which one to use. */
1664 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1668 silc_free(internal);
1671 /* Find authentication method and authentication data by hostname and
1672 port. The hostname may be IP address as well. The found authentication
1673 method and authentication data is returned to `auth_meth', `auth_data'
1674 and `auth_data_len'. The function returns TRUE if authentication method
1675 is found and FALSE if not. `conn' may be NULL. */
1677 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1678 char *hostname, SilcUInt16 port,
1679 SilcGetAuthMeth completion, void *context)
1681 InternalGetAuthMethod internal;
1683 SILC_LOG_DEBUG(("Start"));
1685 /* XXX must resolve from configuration whether this connection has
1686 any specific authentication data */
1688 /* If we do not have this connection configured by the user in a
1689 configuration file then resolve the authentication method from the
1690 server for this session. */
1691 internal = silc_calloc(1, sizeof(*internal));
1692 internal->completion = completion;
1693 internal->context = context;
1695 silc_client_request_authentication_method(client, conn,
1696 silc_get_auth_method_callback,
1700 /* Notifies application that failure packet was received. This is called
1701 if there is some protocol active in the client. The `protocol' is the
1702 protocol context. The `failure' is opaque pointer to the failure
1703 indication. Note, that the `failure' is protocol dependant and application
1704 must explicitly cast it to correct type. Usually `failure' is 32 bit
1705 failure type (see protocol specs for all protocol failure types). */
1707 void silc_failure(SilcClient client, SilcClientConnection conn,
1708 SilcProtocol protocol, void *failure)
1710 SILC_LOG_DEBUG(("Start"));
1712 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1713 SilcSKEStatus status = (SilcSKEStatus)failure;
1715 if (status == SILC_SKE_STATUS_BAD_VERSION)
1716 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1717 SILCTXT_KE_BAD_VERSION);
1718 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1719 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1720 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1721 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1722 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1723 SILCTXT_KE_UNKNOWN_GROUP);
1724 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1725 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1726 SILCTXT_KE_UNKNOWN_CIPHER);
1727 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1728 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1729 SILCTXT_KE_UNKNOWN_PKCS);
1730 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1731 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1732 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1733 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1734 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1735 SILCTXT_KE_UNKNOWN_HMAC);
1736 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1737 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1738 SILCTXT_KE_INCORRECT_SIGNATURE);
1739 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1740 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1741 SILCTXT_KE_INVALID_COOKIE);
1744 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1745 SilcUInt32 err = (SilcUInt32)failure;
1747 if (err == SILC_AUTH_FAILED)
1748 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1749 SILCTXT_AUTH_FAILED);
1753 /* Asks whether the user would like to perform the key agreement protocol.
1754 This is called after we have received an key agreement packet or an
1755 reply to our key agreement packet. This returns TRUE if the user wants
1756 the library to perform the key agreement protocol and FALSE if it is not
1757 desired (application may start it later by calling the function
1758 silc_client_perform_key_agreement). */
1760 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1761 SilcClientEntry client_entry, const char *hostname,
1762 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1767 SILC_LOG_DEBUG(("Start"));
1769 /* We will just display the info on the screen and return FALSE and user
1770 will have to start the key agreement with a command. */
1773 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1776 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1777 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1779 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1780 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1781 client_entry->nickname, hostname, portstr);
1789 void silc_ftp(SilcClient client, SilcClientConnection conn,
1790 SilcClientEntry client_entry, SilcUInt32 session_id,
1791 const char *hostname, SilcUInt16 port)
1793 SILC_SERVER_REC *server;
1795 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1797 SILC_LOG_DEBUG(("Start"));
1799 server = conn->context;
1801 ftp->client_entry = client_entry;
1802 ftp->session_id = session_id;
1805 silc_dlist_add(server->ftp_sessions, ftp);
1806 server->current_session = ftp;
1809 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1812 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1813 SILCTXT_FILE_REQUEST, client_entry->nickname);
1815 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1816 SILCTXT_FILE_REQUEST_HOST,
1817 client_entry->nickname, hostname, portstr);
1820 /* SILC client operations */
1821 SilcClientOperations ops = {
1823 silc_channel_message,
1824 silc_private_message,
1830 silc_get_auth_method,
1831 silc_verify_public_key,
1832 silc_ask_passphrase,