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)
894 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
895 SILCTXT_WHOIS_MODES, buf);
898 if (idle && nickname) {
899 memset(buf, 0, sizeof(buf));
900 snprintf(buf, sizeof(buf) - 1, "%lu %s",
901 idle > 60 ? (idle / 60) : idle,
902 idle > 60 ? "minutes" : "seconds");
904 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
905 SILCTXT_WHOIS_IDLE, buf);
909 fingerprint = silc_fingerprint(fingerprint, 20);
910 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
911 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
912 silc_free(fingerprint);
917 case SILC_COMMAND_IDENTIFY:
919 SilcClientEntry client_entry;
921 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
922 /* Print the unknown nick for user */
924 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
927 silc_say_error("%s: %s", tmp,
928 silc_client_command_status_message(status));
930 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
931 /* Try to find the entry for the unknown client ID, since we
932 might have, and print the nickname of it for user. */
935 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
938 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
941 client_entry = silc_client_get_client_by_id(client, conn,
943 if (client_entry && client_entry->nickname)
944 silc_say_error("%s: %s", client_entry->nickname,
945 silc_client_command_status_message(status));
946 silc_free(client_id);
955 case SILC_COMMAND_WHOWAS:
957 char *nickname, *username, *realname;
959 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
960 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
962 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
965 silc_say_error("%s: %s", tmp,
966 silc_client_command_status_message(status));
973 (void)va_arg(vp, SilcClientEntry);
974 nickname = va_arg(vp, char *);
975 username = va_arg(vp, char *);
976 realname = va_arg(vp, char *);
978 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
979 SILCTXT_WHOWAS_USERINFO, nickname, username,
980 realname ? realname : "");
984 case SILC_COMMAND_INVITE:
986 SilcChannelEntry channel;
988 SilcArgumentPayload args;
994 channel = va_arg(vp, SilcChannelEntry);
995 invite_list = va_arg(vp, char *);
997 args = silc_command_get_args(cmd_payload);
999 argc = silc_argument_get_arg_num(args);
1002 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1003 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1006 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1007 SILCTXT_CHANNEL_NO_INVITE_LIST,
1008 channel->channel_name);
1012 case SILC_COMMAND_JOIN:
1014 char *channel, *mode, *topic;
1016 SilcChannelEntry channel_entry;
1017 SilcBuffer client_id_list;
1018 SilcUInt32 list_count;
1023 channel = va_arg(vp, char *);
1024 channel_entry = va_arg(vp, SilcChannelEntry);
1025 modei = va_arg(vp, SilcUInt32);
1026 (void)va_arg(vp, SilcUInt32);
1027 (void)va_arg(vp, unsigned char *);
1028 (void)va_arg(vp, unsigned char *);
1029 (void)va_arg(vp, unsigned char *);
1030 topic = va_arg(vp, char *);
1031 (void)va_arg(vp, unsigned char *);
1032 list_count = va_arg(vp, SilcUInt32);
1033 client_id_list = va_arg(vp, SilcBuffer);
1035 chanrec = silc_channel_find(server, channel);
1037 chanrec = silc_channel_create(server, channel, TRUE);
1040 g_free_not_null(chanrec->topic);
1041 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1042 signal_emit("channel topic changed", 1, chanrec);
1045 mode = silc_client_chmode(modei,
1046 channel_entry->channel_key ?
1047 channel_entry->channel_key->cipher->name : "",
1048 channel_entry->hmac ?
1049 silc_hmac_get_name(channel_entry->hmac) : "");
1050 g_free_not_null(chanrec->mode);
1051 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1052 signal_emit("channel mode changed", 1, chanrec);
1054 /* Resolve the client information */
1055 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1056 silc_client_join_get_users,
1062 case SILC_COMMAND_NICK:
1064 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1070 old = g_strdup(server->nick);
1071 server_change_nick(SERVER(server), client->nickname);
1072 nicklist_rename_unique(SERVER(server),
1073 server->conn->local_entry, server->nick,
1074 client, client->nickname);
1075 signal_emit("message own_nick", 4, server, server->nick, old, "");
1080 case SILC_COMMAND_LIST:
1089 (void)va_arg(vp, SilcChannelEntry);
1090 name = va_arg(vp, char *);
1091 topic = va_arg(vp, char *);
1092 usercount = va_arg(vp, int);
1094 if (status == SILC_STATUS_LIST_START ||
1095 status == SILC_STATUS_OK)
1096 printformat_module("fe-common/silc", server, NULL,
1097 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1100 snprintf(users, sizeof(users) - 1, "N/A");
1102 snprintf(users, sizeof(users) - 1, "%d", usercount);
1103 printformat_module("fe-common/silc", server, NULL,
1104 MSGLEVEL_CRAP, SILCTXT_LIST,
1105 name, users, topic ? topic : "");
1109 case SILC_COMMAND_UMODE:
1116 mode = va_arg(vp, SilcUInt32);
1118 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1119 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1120 printformat_module("fe-common/silc", server, NULL,
1121 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1123 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1124 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1125 printformat_module("fe-common/silc", server, NULL,
1126 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1128 server->umode = mode;
1129 signal_emit("user mode changed", 2, server, NULL);
1133 case SILC_COMMAND_OPER:
1137 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1138 signal_emit("user mode changed", 2, server, NULL);
1140 printformat_module("fe-common/silc", server, NULL,
1141 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1144 case SILC_COMMAND_SILCOPER:
1148 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1149 signal_emit("user mode changed", 2, server, NULL);
1151 printformat_module("fe-common/silc", server, NULL,
1152 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1155 case SILC_COMMAND_USERS:
1157 SilcHashTableList htl;
1158 SilcChannelEntry channel;
1159 SilcChannelUser chu;
1164 channel = va_arg(vp, SilcChannelEntry);
1166 printformat_module("fe-common/silc", server, channel->channel_name,
1167 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1168 channel->channel_name);
1170 silc_hash_table_list(channel->user_list, &htl);
1171 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1172 SilcClientEntry e = chu->client;
1173 char stat[5], *mode;
1178 memset(stat, 0, sizeof(stat));
1179 mode = silc_client_chumode_char(chu->mode);
1180 if (e->mode & SILC_UMODE_GONE)
1187 printformat_module("fe-common/silc", server, channel->channel_name,
1188 MSGLEVEL_CRAP, SILCTXT_USERS,
1190 e->username ? e->username : "",
1191 e->hostname ? e->hostname : "",
1192 e->realname ? e->realname : "");
1196 silc_hash_table_list_reset(&htl);
1200 case SILC_COMMAND_BAN:
1202 SilcChannelEntry channel;
1208 channel = va_arg(vp, SilcChannelEntry);
1209 ban_list = va_arg(vp, char *);
1212 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1213 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1216 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1217 SILCTXT_CHANNEL_NO_BAN_LIST,
1218 channel->channel_name);
1222 case SILC_COMMAND_GETKEY:
1226 SilcPublicKey public_key;
1229 GetkeyContext getkey;
1235 id_type = va_arg(vp, SilcUInt32);
1236 entry = va_arg(vp, void *);
1237 public_key = va_arg(vp, SilcPublicKey);
1240 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1242 getkey = silc_calloc(1, sizeof(*getkey));
1243 getkey->entry = entry;
1244 getkey->id_type = id_type;
1245 getkey->client = client;
1246 getkey->conn = conn;
1247 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1249 name = (id_type == SILC_ID_CLIENT ?
1250 ((SilcClientEntry)entry)->nickname :
1251 ((SilcServerEntry)entry)->server_name);
1253 silc_verify_public_key_internal(client, conn, name,
1254 (id_type == SILC_ID_CLIENT ?
1255 SILC_SOCKET_TYPE_CLIENT :
1256 SILC_SOCKET_TYPE_SERVER),
1257 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1258 silc_getkey_cb, getkey);
1261 printformat_module("fe-common/silc", server, NULL,
1262 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1267 case SILC_COMMAND_INFO:
1269 SilcServerEntry server_entry;
1276 server_entry = va_arg(vp, SilcServerEntry);
1277 server_name = va_arg(vp, char *);
1278 server_info = va_arg(vp, char *);
1280 if (server_name && server_info )
1282 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1283 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1288 case SILC_COMMAND_TOPIC:
1290 SilcChannelEntry channel;
1296 channel = va_arg(vp, SilcChannelEntry);
1297 topic = va_arg(vp, char *);
1300 chanrec = silc_channel_find_entry(server, channel);
1302 g_free_not_null(chanrec->topic);
1303 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1304 signal_emit("channel topic changed", 1, chanrec);
1306 printformat_module("fe-common/silc", server, channel->channel_name,
1307 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1308 channel->channel_name, topic);
1310 printformat_module("fe-common/silc", server, channel->channel_name,
1311 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1312 channel->channel_name);
1324 SilcClientConnection conn;
1330 SilcSKEPKType pk_type;
1331 SilcVerifyPublicKey completion;
1335 static void verify_public_key_completion(const char *line, void *context)
1337 PublicKeyVerify verify = (PublicKeyVerify)context;
1339 if (line[0] == 'Y' || line[0] == 'y') {
1340 /* Call the completion */
1341 if (verify->completion)
1342 verify->completion(TRUE, verify->context);
1344 /* Save the key for future checking */
1345 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1346 verify->pk_len, SILC_PKCS_FILE_PEM);
1348 /* Call the completion */
1349 if (verify->completion)
1350 verify->completion(FALSE, verify->context);
1352 printformat_module("fe-common/silc", NULL, NULL,
1353 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1354 verify->entity_name ? verify->entity_name :
1358 silc_free(verify->filename);
1359 silc_free(verify->entity);
1360 silc_free(verify->entity_name);
1361 silc_free(verify->pk);
1365 /* Internal routine to verify public key. If the `completion' is provided
1366 it will be called to indicate whether public was verified or not. For
1367 server/router public key this will check for filename that includes the
1368 remote host's IP address and remote host's hostname. */
1371 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1372 const char *name, SilcSocketType conn_type,
1373 unsigned char *pk, SilcUInt32 pk_len,
1374 SilcSKEPKType pk_type,
1375 SilcVerifyPublicKey completion, void *context)
1378 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1379 char *fingerprint, *babbleprint, *format;
1382 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1383 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1384 "server" : "client");
1385 PublicKeyVerify verify;
1387 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1388 printformat_module("fe-common/silc", NULL, NULL,
1389 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1392 completion(FALSE, context);
1396 pw = getpwuid(getuid());
1399 completion(FALSE, context);
1403 memset(filename, 0, sizeof(filename));
1404 memset(filename2, 0, sizeof(filename2));
1405 memset(file, 0, sizeof(file));
1407 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1408 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1410 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1411 conn->sock->ip, conn->sock->port);
1412 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1413 get_irssi_dir(), entity, file);
1415 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1416 conn->sock->hostname, conn->sock->port);
1417 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1418 get_irssi_dir(), entity, file);
1423 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1424 name, conn->sock->port);
1425 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1426 get_irssi_dir(), entity, file);
1431 /* Replace all whitespaces with `_'. */
1432 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1433 for (i = 0; i < strlen(fingerprint); i++)
1434 if (fingerprint[i] == ' ')
1435 fingerprint[i] = '_';
1437 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1438 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1439 get_irssi_dir(), entity, file);
1440 silc_free(fingerprint);
1445 /* Take fingerprint of the public key */
1446 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1447 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1449 verify = silc_calloc(1, sizeof(*verify));
1450 verify->client = client;
1451 verify->conn = conn;
1452 verify->filename = strdup(ipf);
1453 verify->entity = strdup(entity);
1454 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1455 (name ? strdup(name) : strdup(conn->sock->hostname))
1457 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1458 memcpy(verify->pk, pk, pk_len);
1459 verify->pk_len = pk_len;
1460 verify->pk_type = pk_type;
1461 verify->completion = completion;
1462 verify->context = context;
1464 /* Check whether this key already exists */
1465 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1466 /* Key does not exist, ask user to verify the key and save it */
1468 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1469 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1470 verify->entity_name : entity);
1471 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1472 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1473 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1474 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1475 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1476 SILCTXT_PUBKEY_ACCEPT);
1477 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1480 silc_free(fingerprint);
1483 /* The key already exists, verify it. */
1484 SilcPublicKey public_key;
1485 unsigned char *encpk;
1486 SilcUInt32 encpk_len;
1488 /* Load the key file, try for both IP filename and hostname filename */
1489 if (!silc_pkcs_load_public_key(ipf, &public_key,
1490 SILC_PKCS_FILE_PEM) &&
1491 !silc_pkcs_load_public_key(ipf, &public_key,
1492 SILC_PKCS_FILE_BIN) &&
1493 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1494 SILC_PKCS_FILE_PEM) &&
1495 !silc_pkcs_load_public_key(hostf, &public_key,
1496 SILC_PKCS_FILE_BIN)))) {
1497 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1498 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1499 verify->entity_name : entity);
1500 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1501 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1502 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1503 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1504 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1505 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1506 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1507 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1508 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1511 silc_free(fingerprint);
1515 /* Encode the key data */
1516 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1518 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1519 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1520 verify->entity_name : entity);
1521 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1522 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1523 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1524 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1525 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1526 SILCTXT_PUBKEY_MALFORMED, entity);
1527 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1528 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1529 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1532 silc_free(fingerprint);
1536 /* Compare the keys */
1537 if (memcmp(encpk, pk, 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_NO_MATCH, entity);
1547 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1548 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1549 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1550 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1552 /* Ask user to verify the key and save it */
1553 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1554 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1555 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1558 silc_free(fingerprint);
1562 /* Local copy matched */
1564 completion(TRUE, context);
1565 silc_free(fingerprint);
1569 /* Verifies received public key. The `conn_type' indicates which entity
1570 (server, client etc.) has sent the public key. If user decides to trust
1571 the key may be saved as trusted public key for later use. The
1572 `completion' must be called after the public key has been verified. */
1575 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1576 SilcSocketType conn_type, unsigned char *pk,
1577 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1578 SilcVerifyPublicKey completion, void *context)
1580 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1582 completion, context);
1585 /* Asks passphrase from user on the input line. */
1588 SilcAskPassphrase completion;
1592 void ask_passphrase_completion(const char *passphrase, void *context)
1594 AskPassphrase p = (AskPassphrase)context;
1595 p->completion((unsigned char *)passphrase,
1596 passphrase ? strlen(passphrase) : 0, p->context);
1600 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1601 SilcAskPassphrase completion, void *context)
1603 AskPassphrase p = silc_calloc(1, sizeof(*p));
1604 p->completion = completion;
1605 p->context = context;
1607 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1608 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1612 SilcGetAuthMeth completion;
1614 } *InternalGetAuthMethod;
1616 /* Callback called when we've received the authentication method information
1617 from the server after we've requested it. This will get the authentication
1618 data from the user if needed. */
1620 static void silc_get_auth_method_callback(SilcClient client,
1621 SilcClientConnection conn,
1622 SilcAuthMethod auth_meth,
1625 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1627 SILC_LOG_DEBUG(("Start"));
1629 switch (auth_meth) {
1630 case SILC_AUTH_NONE:
1631 /* No authentication required. */
1632 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1634 case SILC_AUTH_PASSWORD:
1635 /* Do not ask the passphrase from user, the library will ask it if
1636 we do not provide it here. */
1637 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1639 case SILC_AUTH_PUBLIC_KEY:
1640 /* Do not get the authentication data now, the library will generate
1641 it using our default key, if we do not provide it here. */
1642 /* XXX In the future when we support multiple local keys and multiple
1643 local certificates we will need to ask from user which one to use. */
1644 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1648 silc_free(internal);
1651 /* Find authentication method and authentication data by hostname and
1652 port. The hostname may be IP address as well. The found authentication
1653 method and authentication data is returned to `auth_meth', `auth_data'
1654 and `auth_data_len'. The function returns TRUE if authentication method
1655 is found and FALSE if not. `conn' may be NULL. */
1657 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1658 char *hostname, SilcUInt16 port,
1659 SilcGetAuthMeth completion, void *context)
1661 InternalGetAuthMethod internal;
1663 SILC_LOG_DEBUG(("Start"));
1665 /* XXX must resolve from configuration whether this connection has
1666 any specific authentication data */
1668 /* If we do not have this connection configured by the user in a
1669 configuration file then resolve the authentication method from the
1670 server for this session. */
1671 internal = silc_calloc(1, sizeof(*internal));
1672 internal->completion = completion;
1673 internal->context = context;
1675 silc_client_request_authentication_method(client, conn,
1676 silc_get_auth_method_callback,
1680 /* Notifies application that failure packet was received. This is called
1681 if there is some protocol active in the client. The `protocol' is the
1682 protocol context. The `failure' is opaque pointer to the failure
1683 indication. Note, that the `failure' is protocol dependant and application
1684 must explicitly cast it to correct type. Usually `failure' is 32 bit
1685 failure type (see protocol specs for all protocol failure types). */
1687 void silc_failure(SilcClient client, SilcClientConnection conn,
1688 SilcProtocol protocol, void *failure)
1690 SILC_LOG_DEBUG(("Start"));
1692 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1693 SilcSKEStatus status = (SilcSKEStatus)failure;
1695 if (status == SILC_SKE_STATUS_BAD_VERSION)
1696 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1697 SILCTXT_KE_BAD_VERSION);
1698 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1699 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1700 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1701 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1702 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1703 SILCTXT_KE_UNKNOWN_GROUP);
1704 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1705 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1706 SILCTXT_KE_UNKNOWN_CIPHER);
1707 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1708 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1709 SILCTXT_KE_UNKNOWN_PKCS);
1710 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1711 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1712 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1713 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1714 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1715 SILCTXT_KE_UNKNOWN_HMAC);
1716 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1717 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1718 SILCTXT_KE_INCORRECT_SIGNATURE);
1719 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1720 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1721 SILCTXT_KE_INVALID_COOKIE);
1724 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1725 SilcUInt32 err = (SilcUInt32)failure;
1727 if (err == SILC_AUTH_FAILED)
1728 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1729 SILCTXT_AUTH_FAILED);
1733 /* Asks whether the user would like to perform the key agreement protocol.
1734 This is called after we have received an key agreement packet or an
1735 reply to our key agreement packet. This returns TRUE if the user wants
1736 the library to perform the key agreement protocol and FALSE if it is not
1737 desired (application may start it later by calling the function
1738 silc_client_perform_key_agreement). */
1740 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1741 SilcClientEntry client_entry, const char *hostname,
1742 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1747 SILC_LOG_DEBUG(("Start"));
1749 /* We will just display the info on the screen and return FALSE and user
1750 will have to start the key agreement with a command. */
1753 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1756 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1757 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1759 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1760 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1761 client_entry->nickname, hostname, portstr);
1769 void silc_ftp(SilcClient client, SilcClientConnection conn,
1770 SilcClientEntry client_entry, SilcUInt32 session_id,
1771 const char *hostname, SilcUInt16 port)
1773 SILC_SERVER_REC *server;
1775 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1777 SILC_LOG_DEBUG(("Start"));
1779 server = conn->context;
1781 ftp->client_entry = client_entry;
1782 ftp->session_id = session_id;
1785 silc_dlist_add(server->ftp_sessions, ftp);
1786 server->current_session = ftp;
1789 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1792 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1793 SILCTXT_FILE_REQUEST, client_entry->nickname);
1795 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1796 SILCTXT_FILE_REQUEST_HOST,
1797 client_entry->nickname, hostname, portstr);
1800 /* SILC client operations */
1801 SilcClientOperations ops = {
1803 silc_channel_message,
1804 silc_private_message,
1810 silc_get_auth_method,
1811 silc_verify_public_key,
1812 silc_ask_passphrase,