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"
42 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
43 const char *name, SilcSocketType conn_type,
44 unsigned char *pk, SilcUInt32 pk_len,
45 SilcSKEPKType pk_type,
46 SilcVerifyPublicKey completion, void *context);
48 void silc_say(SilcClient client, SilcClientConnection conn,
49 SilcClientMessageType type, char *msg, ...)
51 SILC_SERVER_REC *server;
55 server = conn == NULL ? NULL : conn->context;
58 str = g_strdup_vprintf(msg, va);
59 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
64 void silc_say_error(char *msg, ...)
70 str = g_strdup_vprintf(msg, va);
71 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
77 /* Message for a channel. The `sender' is the nickname of the sender
78 received in the packet. The `channel_name' is the name of the channel. */
80 void silc_channel_message(SilcClient client, SilcClientConnection conn,
81 SilcClientEntry sender, SilcChannelEntry channel,
82 SilcMessageFlags flags, char *msg)
84 SILC_SERVER_REC *server;
86 SILC_CHANNEL_REC *chanrec;
88 SILC_LOG_DEBUG(("Start"));
93 server = conn == NULL ? NULL : conn->context;
94 chanrec = silc_channel_find_entry(server, channel);
98 nick = silc_nicklist_find(chanrec, sender);
100 /* We didn't find client but it clearly exists, add it. */
101 SilcChannelUser chu = silc_client_on_channel(channel, sender);
103 nick = silc_nicklist_insert(chanrec, chu, FALSE);
106 if (flags & SILC_MESSAGE_FLAG_ACTION)
107 printformat_module("fe-common/silc", server, channel->channel_name,
108 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
109 nick == NULL ? "[<unknown>]" : nick->nick, msg);
110 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
111 printformat_module("fe-common/silc", server, channel->channel_name,
112 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
113 nick == NULL ? "[<unknown>]" : nick->nick, msg);
115 signal_emit("message public", 6, server, msg,
116 nick == NULL ? "[<unknown>]" : nick->nick,
117 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
118 chanrec->name, nick);
121 /* Private message to the client. The `sender' is the nickname of the
122 sender received in the packet. */
124 void silc_private_message(SilcClient client, SilcClientConnection conn,
125 SilcClientEntry sender, SilcMessageFlags flags,
128 SILC_SERVER_REC *server;
131 SILC_LOG_DEBUG(("Start"));
133 server = conn == NULL ? NULL : conn->context;
134 memset(userhost, 0, sizeof(userhost));
135 if (sender->username)
136 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
137 sender->username, sender->hostname);
138 signal_emit("message private", 4, server, msg,
139 sender->nickname ? sender->nickname : "[<unknown>]",
140 sender->username ? userhost : NULL);
143 /* Notify message to the client. The notify arguments are sent in the
144 same order as servers sends them. The arguments are same as received
145 from the server except for ID's. If ID is received application receives
146 the corresponding entry to the ID. For example, if Client ID is received
147 application receives SilcClientEntry. Also, if the notify type is
148 for channel the channel entry is sent to application (even if server
149 does not send it). */
151 void silc_notify(SilcClient client, SilcClientConnection conn,
152 SilcNotifyType type, ...)
155 SILC_SERVER_REC *server;
156 SILC_CHANNEL_REC *chanrec;
157 SILC_NICK_REC *nickrec;
158 SilcClientEntry client_entry, client_entry2;
159 SilcChannelEntry channel;
160 SilcServerEntry server_entry;
166 GSList *list1, *list_tmp;
168 SILC_LOG_DEBUG(("Start"));
172 server = conn == NULL ? NULL : conn->context;
175 case SILC_NOTIFY_TYPE_NONE:
176 /* Some generic notice from server */
177 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
180 case SILC_NOTIFY_TYPE_INVITE:
182 * Invited or modified invite list.
185 SILC_LOG_DEBUG(("Notify: INVITE"));
187 channel = va_arg(va, SilcChannelEntry);
188 name = va_arg(va, char *);
189 client_entry = va_arg(va, SilcClientEntry);
191 memset(userhost, 0, sizeof(userhost));
192 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
193 client_entry->username, client_entry->hostname);
194 signal_emit("message invite", 4, server, channel ? channel->channel_name :
195 name, client_entry->nickname, userhost);
198 case SILC_NOTIFY_TYPE_JOIN:
203 SILC_LOG_DEBUG(("Notify: JOIN"));
205 client_entry = va_arg(va, SilcClientEntry);
206 channel = va_arg(va, SilcChannelEntry);
208 if (client_entry == server->conn->local_entry) {
209 /* You joined to channel */
210 chanrec = silc_channel_find(server, channel->channel_name);
211 if (chanrec != NULL && !chanrec->joined)
212 chanrec->entry = channel;
214 chanrec = silc_channel_find_entry(server, channel);
215 if (chanrec != NULL) {
216 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
218 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
222 memset(userhost, 0, sizeof(userhost));
223 if (client_entry->username)
224 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
225 client_entry->username, client_entry->hostname);
226 signal_emit("message join", 4, server, channel->channel_name,
227 client_entry->nickname,
228 client_entry->username == NULL ? "" : userhost);
231 case SILC_NOTIFY_TYPE_LEAVE:
236 SILC_LOG_DEBUG(("Notify: LEAVE"));
238 client_entry = va_arg(va, SilcClientEntry);
239 channel = va_arg(va, SilcChannelEntry);
241 memset(userhost, 0, sizeof(userhost));
242 if (client_entry->username)
243 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
244 client_entry->username, client_entry->hostname);
245 signal_emit("message part", 5, server, channel->channel_name,
246 client_entry->nickname, client_entry->username ?
247 userhost : "", client_entry->nickname);
249 chanrec = silc_channel_find_entry(server, channel);
250 if (chanrec != NULL) {
251 nickrec = silc_nicklist_find(chanrec, client_entry);
253 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
257 case SILC_NOTIFY_TYPE_SIGNOFF:
262 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
264 client_entry = va_arg(va, SilcClientEntry);
265 tmp = va_arg(va, char *);
267 silc_server_free_ftp(server, client_entry);
269 memset(userhost, 0, sizeof(userhost));
270 if (client_entry->username)
271 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
272 client_entry->username, client_entry->hostname);
273 signal_emit("message quit", 4, server, client_entry->nickname,
274 client_entry->username ? userhost : "",
277 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
278 for (list_tmp = list1; list_tmp != NULL; list_tmp =
279 list_tmp->next->next) {
280 CHANNEL_REC *channel = list_tmp->data;
281 NICK_REC *nickrec = list_tmp->next->data;
283 nicklist_remove(channel, nickrec);
287 case SILC_NOTIFY_TYPE_TOPIC_SET:
292 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
294 idtype = va_arg(va, int);
295 entry = va_arg(va, void *);
296 tmp = va_arg(va, char *);
297 channel = va_arg(va, SilcChannelEntry);
299 chanrec = silc_channel_find_entry(server, channel);
300 if (chanrec != NULL) {
301 g_free_not_null(chanrec->topic);
302 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
303 signal_emit("channel topic changed", 1, chanrec);
306 if (idtype == SILC_ID_CLIENT) {
307 client_entry = (SilcClientEntry)entry;
308 memset(userhost, 0, sizeof(userhost));
309 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
310 client_entry->username, client_entry->hostname);
311 signal_emit("message topic", 5, server, channel->channel_name,
312 tmp, client_entry->nickname, userhost);
313 } else if (idtype == SILC_ID_SERVER) {
314 server_entry = (SilcServerEntry)entry;
315 signal_emit("message topic", 5, server, channel->channel_name,
316 tmp, server_entry->server_name,
317 server_entry->server_name);
319 channel = (SilcChannelEntry)entry;
320 signal_emit("message topic", 5, server, channel->channel_name,
321 tmp, channel->channel_name, channel->channel_name);
325 case SILC_NOTIFY_TYPE_NICK_CHANGE:
330 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
332 client_entry = va_arg(va, SilcClientEntry);
333 client_entry2 = va_arg(va, SilcClientEntry);
335 memset(userhost, 0, sizeof(userhost));
336 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
337 client_entry2->username, client_entry2->hostname);
338 nicklist_rename_unique(SERVER(server),
339 client_entry, client_entry->nickname,
340 client_entry2, client_entry2->nickname);
341 signal_emit("message nick", 4, server, client_entry2->nickname,
342 client_entry->nickname, userhost);
345 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
347 * Changed channel mode.
350 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
352 idtype = va_arg(va, int);
353 entry = va_arg(va, void *);
354 mode = va_arg(va, SilcUInt32);
355 (void)va_arg(va, char *);
356 (void)va_arg(va, char *);
357 channel = va_arg(va, SilcChannelEntry);
359 tmp = silc_client_chmode(mode,
360 channel->channel_key ?
361 channel->channel_key->cipher->name : "",
363 silc_hmac_get_name(channel->hmac) : "");
365 chanrec = silc_channel_find_entry(server, channel);
366 if (chanrec != NULL) {
367 g_free_not_null(chanrec->mode);
368 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
369 signal_emit("channel mode changed", 1, chanrec);
372 if (idtype == SILC_ID_CLIENT) {
373 client_entry = (SilcClientEntry)entry;
374 printformat_module("fe-common/silc", server, channel->channel_name,
375 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
376 channel->channel_name, tmp ? tmp : "removed all",
377 client_entry->nickname);
378 } else if (idtype == SILC_ID_SERVER) {
379 server_entry = (SilcServerEntry)entry;
380 printformat_module("fe-common/silc", server, channel->channel_name,
381 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
382 channel->channel_name, tmp ? tmp : "removed all",
383 server_entry->server_name);
389 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
391 * Changed user's mode on channel.
394 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
396 client_entry = va_arg(va, SilcClientEntry);
397 mode = va_arg(va, SilcUInt32);
398 client_entry2 = va_arg(va, SilcClientEntry);
399 channel = va_arg(va, SilcChannelEntry);
401 tmp = silc_client_chumode(mode);
402 chanrec = silc_channel_find_entry(server, channel);
403 if (chanrec != NULL) {
406 if (client_entry2 == server->conn->local_entry)
407 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
409 nick = silc_nicklist_find(chanrec, client_entry2);
411 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
412 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
413 signal_emit("nick mode changed", 2, chanrec, nick);
417 printformat_module("fe-common/silc", server, channel->channel_name,
418 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
419 channel->channel_name, client_entry2->nickname,
420 tmp ? tmp : "removed all",
421 client_entry->nickname);
423 if (mode & SILC_CHANNEL_UMODE_CHANFO)
424 printformat_module("fe-common/silc",
425 server, channel->channel_name, MSGLEVEL_CRAP,
426 SILCTXT_CHANNEL_FOUNDER,
427 channel->channel_name, client_entry2->nickname);
432 case SILC_NOTIFY_TYPE_MOTD:
437 SILC_LOG_DEBUG(("Notify: MOTD"));
439 tmp = va_arg(va, char *);
441 if (!settings_get_bool("skip_motd"))
442 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
445 case SILC_NOTIFY_TYPE_KICKED:
447 * Someone was kicked from channel.
450 SILC_LOG_DEBUG(("Notify: KICKED"));
452 client_entry = va_arg(va, SilcClientEntry);
453 tmp = va_arg(va, char *);
454 client_entry2 = va_arg(va, SilcClientEntry);
455 channel = va_arg(va, SilcChannelEntry);
457 chanrec = silc_channel_find_entry(server, channel);
459 if (client_entry == conn->local_entry) {
460 printformat_module("fe-common/silc", server, channel->channel_name,
461 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
462 channel->channel_name, client_entry2->nickname,
465 chanrec->kicked = TRUE;
466 channel_destroy((CHANNEL_REC *)chanrec);
469 printformat_module("fe-common/silc", server, channel->channel_name,
470 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
471 client_entry->nickname, channel->channel_name,
472 client_entry2->nickname, tmp ? tmp : "");
475 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
477 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
482 case SILC_NOTIFY_TYPE_KILLED:
484 * Someone was killed from the network.
487 SILC_LOG_DEBUG(("Notify: KILLED"));
489 client_entry = va_arg(va, SilcClientEntry);
490 tmp = va_arg(va, char *);
492 if (client_entry == conn->local_entry) {
493 printformat_module("fe-common/silc", server, NULL,
494 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
497 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
498 for (list_tmp = list1; list_tmp != NULL; list_tmp =
499 list_tmp->next->next) {
500 CHANNEL_REC *channel = list_tmp->data;
501 NICK_REC *nickrec = list_tmp->next->data;
502 nicklist_remove(channel, nickrec);
505 printformat_module("fe-common/silc", server, NULL,
506 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
507 client_entry->nickname,
512 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
515 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
518 * Server has quit the network.
521 SilcClientEntry *clients;
522 SilcUInt32 clients_count;
524 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
526 (void)va_arg(va, void *);
527 clients = va_arg(va, SilcClientEntry *);
528 clients_count = va_arg(va, SilcUInt32);
530 for (i = 0; i < clients_count; i++) {
531 memset(userhost, 0, sizeof(userhost));
532 if (clients[i]->username)
533 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
534 clients[i]->username, clients[i]->hostname);
535 signal_emit("message quit", 4, server, clients[i]->nickname,
536 clients[i]->username ? userhost : "",
539 silc_server_free_ftp(server, clients[i]);
541 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
542 for (list_tmp = list1; list_tmp != NULL; list_tmp =
543 list_tmp->next->next) {
544 CHANNEL_REC *channel = list_tmp->data;
545 NICK_REC *nickrec = list_tmp->next->data;
546 nicklist_remove(channel, nickrec);
554 printformat_module("fe-common/silc", server, NULL,
555 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
562 /* Called to indicate that connection was either successfully established
563 or connecting failed. This is also the first time application receives
564 the SilcClientConnection object which it should save somewhere. */
566 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
568 SILC_SERVER_REC *server = conn->context;
570 if (!server && !success) {
571 silc_client_close_connection(client, NULL, conn);
576 server->connected = TRUE;
577 signal_emit("event connected", 1, server);
579 server->connection_lost = TRUE;
581 server->conn->context = NULL;
582 server_disconnect(SERVER(server));
586 /* Called to indicate that connection was disconnected to the server. */
588 void silc_disconnect(SilcClient client, SilcClientConnection conn)
590 SILC_SERVER_REC *server = conn->context;
592 SILC_LOG_DEBUG(("Start"));
594 if (server->conn && server->conn->local_entry) {
595 nicklist_rename_unique(SERVER(server),
596 server->conn->local_entry, server->nick,
597 server->conn->local_entry,
598 silc_client->username);
599 silc_change_nick(server, silc_client->username);
602 server->conn->context = NULL;
604 server->connection_lost = TRUE;
605 server_disconnect(SERVER(server));
608 /* Command handler. This function is called always in the command function.
609 If error occurs it will be called as well. `conn' is the associated
610 client connection. `cmd_context' is the command context that was
611 originally sent to the command. `success' is FALSE if error occured
612 during command. `command' is the command being processed. It must be
613 noted that this is not reply from server. This is merely called just
614 after application has called the command. Just to tell application
615 that the command really was processed. */
617 void silc_command(SilcClient client, SilcClientConnection conn,
618 SilcClientCommandContext cmd_context, int success,
621 SILC_SERVER_REC *server = conn->context;
623 SILC_LOG_DEBUG(("Start"));
629 case SILC_COMMAND_INVITE:
630 printformat_module("fe-common/silc", server, NULL,
631 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
632 cmd_context->argv[2],
633 (cmd_context->argv[1][0] == '*' ?
634 (char *)conn->current_channel->channel_name :
635 (char *)cmd_context->argv[1]));
642 /* Client info resolving callback when JOIN command reply is received.
643 This will cache all users on the channel. */
645 static void silc_client_join_get_users(SilcClient client,
646 SilcClientConnection conn,
647 SilcClientEntry *clients,
648 SilcUInt32 clients_count,
651 SilcChannelEntry channel = (SilcChannelEntry)context;
652 SilcHashTableList htl;
654 SILC_SERVER_REC *server = conn->context;
655 SILC_CHANNEL_REC *chanrec;
656 SilcClientEntry founder = NULL;
662 chanrec = silc_channel_find(server, channel->channel_name);
666 silc_hash_table_list(channel->user_list, &htl);
667 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
668 if (!chu->client->nickname)
670 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
671 founder = chu->client;
672 silc_nicklist_insert(chanrec, chu, FALSE);
674 silc_hash_table_list_reset(&htl);
676 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
677 nicklist_set_own(CHANNEL(chanrec), ownnick);
678 signal_emit("channel joined", 1, chanrec);
681 printformat_module("fe-common/silc", server, channel->channel_name,
682 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
683 channel->channel_name, chanrec->topic);
685 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
688 if (founder == conn->local_entry)
689 printformat_module("fe-common/silc",
690 server, channel->channel_name, MSGLEVEL_CRAP,
691 SILCTXT_CHANNEL_FOUNDER_YOU,
692 channel->channel_name);
694 printformat_module("fe-common/silc",
695 server, channel->channel_name, MSGLEVEL_CRAP,
696 SILCTXT_CHANNEL_FOUNDER,
697 channel->channel_name, founder->nickname);
703 SilcClientConnection conn;
709 void silc_getkey_cb(bool success, void *context)
711 GetkeyContext getkey = (GetkeyContext)context;
712 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
713 char *name = (getkey->id_type == SILC_ID_CLIENT ?
714 ((SilcClientEntry)getkey->entry)->nickname :
715 ((SilcServerEntry)getkey->entry)->server_name);
718 printformat_module("fe-common/silc", NULL, NULL,
719 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
721 printformat_module("fe-common/silc", NULL, NULL,
722 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
725 silc_free(getkey->fingerprint);
729 /* Command reply handler. This function is called always in the command reply
730 function. If error occurs it will be called as well. Normal scenario
731 is that it will be called after the received command data has been parsed
732 and processed. The function is used to pass the received command data to
735 `conn' is the associated client connection. `cmd_payload' is the command
736 payload data received from server and it can be ignored. It is provided
737 if the application would like to re-parse the received command data,
738 however, it must be noted that the data is parsed already by the library
739 thus the payload can be ignored. `success' is FALSE if error occured.
740 In this case arguments are not sent to the application. `command' is the
741 command reply being processed. The function has variable argument list
742 and each command defines the number and type of arguments it passes to the
743 application (on error they are not sent). */
746 silc_command_reply(SilcClient client, SilcClientConnection conn,
747 SilcCommandPayload cmd_payload, int success,
748 SilcCommand command, SilcCommandStatus status, ...)
751 SILC_SERVER_REC *server = conn->context;
752 SILC_CHANNEL_REC *chanrec;
755 va_start(vp, status);
757 SILC_LOG_DEBUG(("Start"));
760 case SILC_COMMAND_WHOIS:
762 char buf[1024], *nickname, *username, *realname, *nick;
763 unsigned char *fingerprint;
764 SilcUInt32 idle, mode;
766 SilcClientEntry client_entry;
768 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
769 /* Print the unknown nick for user */
771 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
774 silc_say_error("%s: %s", tmp,
775 silc_client_command_status_message(status));
777 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
778 /* Try to find the entry for the unknown client ID, since we
779 might have, and print the nickname of it for user. */
782 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
785 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
787 client_entry = silc_client_get_client_by_id(client, conn,
789 if (client_entry && client_entry->nickname)
790 silc_say_error("%s: %s", client_entry->nickname,
791 silc_client_command_status_message(status));
792 silc_free(client_id);
801 client_entry = va_arg(vp, SilcClientEntry);
802 nickname = va_arg(vp, char *);
803 username = va_arg(vp, char *);
804 realname = va_arg(vp, char *);
805 channels = va_arg(vp, SilcBuffer);
806 mode = va_arg(vp, SilcUInt32);
807 idle = va_arg(vp, SilcUInt32);
808 fingerprint = va_arg(vp, unsigned char *);
810 silc_parse_userfqdn(nickname, &nick, NULL);
811 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
812 SILCTXT_WHOIS_USERINFO, nickname,
813 client_entry->username, client_entry->hostname,
814 nick, client_entry->nickname);
815 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
816 SILCTXT_WHOIS_REALNAME, realname);
820 SilcDList list = silc_channel_payload_parse_list(channels->data,
823 SilcChannelPayload entry;
824 memset(buf, 0, sizeof(buf));
825 silc_dlist_start(list);
826 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
827 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
829 char *name = silc_channel_get_name(entry, &name_len);
832 strncat(buf, m, strlen(m));
833 strncat(buf, name, name_len);
834 strncat(buf, " ", 1);
838 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
839 SILCTXT_WHOIS_CHANNELS, buf);
840 silc_channel_payload_list_free(list);
845 memset(buf, 0, sizeof(buf));
847 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
848 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
849 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
851 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
852 "SILC Operator " : "[Unknown mode] ");
854 if (mode & SILC_UMODE_GONE)
857 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
858 SILCTXT_WHOIS_MODES, buf);
861 if (idle && nickname) {
862 memset(buf, 0, sizeof(buf));
863 snprintf(buf, sizeof(buf) - 1, "%lu %s",
864 idle > 60 ? (idle / 60) : idle,
865 idle > 60 ? "minutes" : "seconds");
867 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
868 SILCTXT_WHOIS_IDLE, buf);
872 fingerprint = silc_fingerprint(fingerprint, 20);
873 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
874 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
875 silc_free(fingerprint);
880 case SILC_COMMAND_IDENTIFY:
882 SilcClientEntry client_entry;
884 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
885 /* Print the unknown nick for user */
887 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
890 silc_say_error("%s: %s", tmp,
891 silc_client_command_status_message(status));
893 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
894 /* Try to find the entry for the unknown client ID, since we
895 might have, and print the nickname of it for user. */
898 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
901 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
903 client_entry = silc_client_get_client_by_id(client, conn,
905 if (client_entry && client_entry->nickname)
906 silc_say_error("%s: %s", client_entry->nickname,
907 silc_client_command_status_message(status));
908 silc_free(client_id);
917 case SILC_COMMAND_WHOWAS:
919 char *nickname, *username, *realname;
921 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
922 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
924 tmp = 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));
935 (void)va_arg(vp, SilcClientEntry);
936 nickname = va_arg(vp, char *);
937 username = va_arg(vp, char *);
938 realname = va_arg(vp, char *);
940 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
941 SILCTXT_WHOWAS_USERINFO, nickname, username,
942 realname ? realname : "");
946 case SILC_COMMAND_INVITE:
948 SilcChannelEntry channel;
950 SilcArgumentPayload args;
956 channel = va_arg(vp, SilcChannelEntry);
957 invite_list = va_arg(vp, char *);
959 args = silc_command_get_args(cmd_payload);
961 argc = silc_argument_get_arg_num(args);
964 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
965 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
968 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
969 SILCTXT_CHANNEL_NO_INVITE_LIST,
970 channel->channel_name);
974 case SILC_COMMAND_JOIN:
976 char *channel, *mode, *topic;
978 SilcChannelEntry channel_entry;
979 SilcBuffer client_id_list;
980 SilcUInt32 list_count;
985 channel = va_arg(vp, char *);
986 channel_entry = va_arg(vp, SilcChannelEntry);
987 modei = va_arg(vp, SilcUInt32);
988 (void)va_arg(vp, SilcUInt32);
989 (void)va_arg(vp, unsigned char *);
990 (void)va_arg(vp, unsigned char *);
991 (void)va_arg(vp, unsigned char *);
992 topic = va_arg(vp, char *);
993 (void)va_arg(vp, unsigned char *);
994 list_count = va_arg(vp, SilcUInt32);
995 client_id_list = va_arg(vp, SilcBuffer);
997 chanrec = silc_channel_find(server, channel);
999 chanrec = silc_channel_create(server, channel, TRUE);
1002 g_free_not_null(chanrec->topic);
1003 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1004 signal_emit("channel topic changed", 1, chanrec);
1007 mode = silc_client_chmode(modei,
1008 channel_entry->channel_key ?
1009 channel_entry->channel_key->cipher->name : "",
1010 channel_entry->hmac ?
1011 silc_hmac_get_name(channel_entry->hmac) : "");
1012 g_free_not_null(chanrec->mode);
1013 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1014 signal_emit("channel mode changed", 1, chanrec);
1016 /* Resolve the client information */
1017 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1018 silc_client_join_get_users,
1024 case SILC_COMMAND_NICK:
1026 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1032 old = g_strdup(server->nick);
1033 server_change_nick(SERVER(server), client->nickname);
1034 nicklist_rename_unique(SERVER(server),
1035 server->conn->local_entry, server->nick,
1036 client, client->nickname);
1037 signal_emit("message own_nick", 4, server, server->nick, old, "");
1042 case SILC_COMMAND_LIST:
1051 (void)va_arg(vp, SilcChannelEntry);
1052 name = va_arg(vp, char *);
1053 topic = va_arg(vp, char *);
1054 usercount = va_arg(vp, int);
1056 if (status == SILC_STATUS_LIST_START ||
1057 status == SILC_STATUS_OK)
1058 printformat_module("fe-common/silc", server, NULL,
1059 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1062 snprintf(users, sizeof(users) - 1, "N/A");
1064 snprintf(users, sizeof(users) - 1, "%d", usercount);
1065 printformat_module("fe-common/silc", server, NULL,
1066 MSGLEVEL_CRAP, SILCTXT_LIST,
1067 name, users, topic ? topic : "");
1071 case SILC_COMMAND_UMODE:
1078 mode = va_arg(vp, SilcUInt32);
1080 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1081 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1082 printformat_module("fe-common/silc", server, NULL,
1083 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1085 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1086 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1087 printformat_module("fe-common/silc", server, NULL,
1088 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1090 server->umode = mode;
1091 signal_emit("user mode changed", 2, server, NULL);
1095 case SILC_COMMAND_OPER:
1099 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1100 signal_emit("user mode changed", 2, server, NULL);
1102 printformat_module("fe-common/silc", server, NULL,
1103 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1106 case SILC_COMMAND_SILCOPER:
1110 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1111 signal_emit("user mode changed", 2, server, NULL);
1113 printformat_module("fe-common/silc", server, NULL,
1114 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1117 case SILC_COMMAND_USERS:
1119 SilcHashTableList htl;
1120 SilcChannelEntry channel;
1121 SilcChannelUser chu;
1126 channel = va_arg(vp, SilcChannelEntry);
1128 printformat_module("fe-common/silc", server, channel->channel_name,
1129 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1130 channel->channel_name);
1132 silc_hash_table_list(channel->user_list, &htl);
1133 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1134 SilcClientEntry e = chu->client;
1135 char stat[5], *mode;
1140 memset(stat, 0, sizeof(stat));
1141 mode = silc_client_chumode_char(chu->mode);
1142 if (e->mode & SILC_UMODE_GONE)
1149 printformat_module("fe-common/silc", server, channel->channel_name,
1150 MSGLEVEL_CRAP, SILCTXT_USERS,
1152 e->username ? e->username : "",
1153 e->hostname ? e->hostname : "",
1154 e->realname ? e->realname : "");
1158 silc_hash_table_list_reset(&htl);
1162 case SILC_COMMAND_BAN:
1164 SilcChannelEntry channel;
1170 channel = va_arg(vp, SilcChannelEntry);
1171 ban_list = va_arg(vp, char *);
1174 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1175 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1178 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1179 SILCTXT_CHANNEL_NO_BAN_LIST,
1180 channel->channel_name);
1184 case SILC_COMMAND_GETKEY:
1188 SilcPublicKey public_key;
1191 GetkeyContext getkey;
1197 id_type = va_arg(vp, SilcUInt32);
1198 entry = va_arg(vp, void *);
1199 public_key = va_arg(vp, SilcPublicKey);
1202 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1204 getkey = silc_calloc(1, sizeof(*getkey));
1205 getkey->entry = entry;
1206 getkey->id_type = id_type;
1207 getkey->client = client;
1208 getkey->conn = conn;
1209 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1211 name = (id_type == SILC_ID_CLIENT ?
1212 ((SilcClientEntry)entry)->nickname :
1213 ((SilcServerEntry)entry)->server_name);
1215 silc_verify_public_key_internal(client, conn, name,
1216 (id_type == SILC_ID_CLIENT ?
1217 SILC_SOCKET_TYPE_CLIENT :
1218 SILC_SOCKET_TYPE_SERVER),
1219 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1220 silc_getkey_cb, getkey);
1223 printformat_module("fe-common/silc", server, NULL,
1224 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1229 case SILC_COMMAND_INFO:
1231 SilcServerEntry server_entry;
1238 server_entry = va_arg(vp, SilcServerEntry);
1239 server_name = va_arg(vp, char *);
1240 server_info = va_arg(vp, char *);
1242 if (server_name && server_info )
1244 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1245 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1250 case SILC_COMMAND_TOPIC:
1252 SilcChannelEntry channel;
1258 channel = va_arg(vp, SilcChannelEntry);
1259 topic = va_arg(vp, char *);
1262 chanrec = silc_channel_find_entry(server, channel);
1264 g_free_not_null(chanrec->topic);
1265 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1266 signal_emit("channel topic changed", 1, chanrec);
1268 printformat_module("fe-common/silc", server, channel->channel_name,
1269 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1270 channel->channel_name, topic);
1272 printformat_module("fe-common/silc", server, channel->channel_name,
1273 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1274 channel->channel_name);
1286 SilcClientConnection conn;
1292 SilcSKEPKType pk_type;
1293 SilcVerifyPublicKey completion;
1297 static void verify_public_key_completion(const char *line, void *context)
1299 PublicKeyVerify verify = (PublicKeyVerify)context;
1301 if (line[0] == 'Y' || line[0] == 'y') {
1302 /* Call the completion */
1303 if (verify->completion)
1304 verify->completion(TRUE, verify->context);
1306 /* Save the key for future checking */
1307 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1308 verify->pk_len, SILC_PKCS_FILE_PEM);
1310 /* Call the completion */
1311 if (verify->completion)
1312 verify->completion(FALSE, verify->context);
1314 printformat_module("fe-common/silc", NULL, NULL,
1315 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1316 verify->entity_name ? verify->entity_name :
1320 silc_free(verify->filename);
1321 silc_free(verify->entity);
1322 silc_free(verify->entity_name);
1323 silc_free(verify->pk);
1327 /* Internal routine to verify public key. If the `completion' is provided
1328 it will be called to indicate whether public was verified or not. For
1329 server/router public key this will check for filename that includes the
1330 remote host's IP address and remote host's hostname. */
1333 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1334 const char *name, SilcSocketType conn_type,
1335 unsigned char *pk, SilcUInt32 pk_len,
1336 SilcSKEPKType pk_type,
1337 SilcVerifyPublicKey completion, void *context)
1340 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1341 char *fingerprint, *babbleprint, *format;
1344 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1345 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1346 "server" : "client");
1347 PublicKeyVerify verify;
1349 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1350 printformat_module("fe-common/silc", NULL, NULL,
1351 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1354 completion(FALSE, context);
1358 pw = getpwuid(getuid());
1361 completion(FALSE, context);
1365 memset(filename, 0, sizeof(filename));
1366 memset(filename2, 0, sizeof(filename2));
1367 memset(file, 0, sizeof(file));
1369 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1370 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1372 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1373 conn->sock->ip, conn->sock->port);
1374 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1375 pw->pw_dir, entity, file);
1377 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1378 conn->sock->hostname, conn->sock->port);
1379 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1380 pw->pw_dir, entity, file);
1385 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1386 name, conn->sock->port);
1387 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1388 pw->pw_dir, entity, file);
1393 /* Replace all whitespaces with `_'. */
1394 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1395 for (i = 0; i < strlen(fingerprint); i++)
1396 if (fingerprint[i] == ' ')
1397 fingerprint[i] = '_';
1399 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1400 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1401 pw->pw_dir, entity, file);
1402 silc_free(fingerprint);
1407 /* Take fingerprint of the public key */
1408 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1409 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1411 verify = silc_calloc(1, sizeof(*verify));
1412 verify->client = client;
1413 verify->conn = conn;
1414 verify->filename = strdup(ipf);
1415 verify->entity = strdup(entity);
1416 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1417 (name ? strdup(name) : strdup(conn->sock->hostname))
1419 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1420 memcpy(verify->pk, pk, pk_len);
1421 verify->pk_len = pk_len;
1422 verify->pk_type = pk_type;
1423 verify->completion = completion;
1424 verify->context = context;
1426 /* Check whether this key already exists */
1427 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1428 /* Key does not exist, ask user to verify the key and save it */
1430 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1431 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1432 verify->entity_name : entity);
1433 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1434 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1435 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1436 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1437 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1438 SILCTXT_PUBKEY_ACCEPT);
1439 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1442 silc_free(fingerprint);
1445 /* The key already exists, verify it. */
1446 SilcPublicKey public_key;
1447 unsigned char *encpk;
1448 SilcUInt32 encpk_len;
1450 /* Load the key file, try for both IP filename and hostname filename */
1451 if (!silc_pkcs_load_public_key(ipf, &public_key,
1452 SILC_PKCS_FILE_PEM) &&
1453 !silc_pkcs_load_public_key(ipf, &public_key,
1454 SILC_PKCS_FILE_BIN) &&
1455 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1456 SILC_PKCS_FILE_PEM) &&
1457 !silc_pkcs_load_public_key(hostf, &public_key,
1458 SILC_PKCS_FILE_BIN)))) {
1459 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1460 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1461 verify->entity_name : entity);
1462 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1463 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1464 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1465 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1466 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1467 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1468 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1469 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1470 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1473 silc_free(fingerprint);
1477 /* Encode the key data */
1478 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1480 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1481 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1482 verify->entity_name : entity);
1483 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1484 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1485 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1486 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1487 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1488 SILCTXT_PUBKEY_MALFORMED, entity);
1489 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1490 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1491 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1494 silc_free(fingerprint);
1498 /* Compare the keys */
1499 if (memcmp(encpk, pk, encpk_len)) {
1500 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1501 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1502 verify->entity_name : entity);
1503 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1504 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1505 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1506 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1507 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1508 SILCTXT_PUBKEY_NO_MATCH, entity);
1509 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1510 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1511 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1512 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1514 /* Ask user to verify the key and save it */
1515 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1516 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1517 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1520 silc_free(fingerprint);
1524 /* Local copy matched */
1526 completion(TRUE, context);
1527 silc_free(fingerprint);
1531 /* Verifies received public key. The `conn_type' indicates which entity
1532 (server, client etc.) has sent the public key. If user decides to trust
1533 the key may be saved as trusted public key for later use. The
1534 `completion' must be called after the public key has been verified. */
1537 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1538 SilcSocketType conn_type, unsigned char *pk,
1539 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1540 SilcVerifyPublicKey completion, void *context)
1542 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1544 completion, context);
1547 /* Asks passphrase from user on the input line. */
1550 SilcAskPassphrase completion;
1554 void ask_passphrase_completion(const char *passphrase, void *context)
1556 AskPassphrase p = (AskPassphrase)context;
1557 p->completion((unsigned char *)passphrase,
1558 passphrase ? strlen(passphrase) : 0, p->context);
1562 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1563 SilcAskPassphrase completion, void *context)
1565 AskPassphrase p = silc_calloc(1, sizeof(*p));
1566 p->completion = completion;
1567 p->context = context;
1569 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1570 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1574 SilcGetAuthMeth completion;
1576 } *InternalGetAuthMethod;
1578 /* Callback called when we've received the authentication method information
1579 from the server after we've requested it. This will get the authentication
1580 data from the user if needed. */
1582 static void silc_get_auth_method_callback(SilcClient client,
1583 SilcClientConnection conn,
1584 SilcAuthMethod auth_meth,
1587 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1589 SILC_LOG_DEBUG(("Start"));
1591 switch (auth_meth) {
1592 case SILC_AUTH_NONE:
1593 /* No authentication required. */
1594 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1596 case SILC_AUTH_PASSWORD:
1597 /* Do not ask the passphrase from user, the library will ask it if
1598 we do not provide it here. */
1599 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1601 case SILC_AUTH_PUBLIC_KEY:
1602 /* Do not get the authentication data now, the library will generate
1603 it using our default key, if we do not provide it here. */
1604 /* XXX In the future when we support multiple local keys and multiple
1605 local certificates we will need to ask from user which one to use. */
1606 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1610 silc_free(internal);
1613 /* Find authentication method and authentication data by hostname and
1614 port. The hostname may be IP address as well. The found authentication
1615 method and authentication data is returned to `auth_meth', `auth_data'
1616 and `auth_data_len'. The function returns TRUE if authentication method
1617 is found and FALSE if not. `conn' may be NULL. */
1619 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1620 char *hostname, SilcUInt16 port,
1621 SilcGetAuthMeth completion, void *context)
1623 InternalGetAuthMethod internal;
1625 SILC_LOG_DEBUG(("Start"));
1627 /* XXX must resolve from configuration whether this connection has
1628 any specific authentication data */
1630 /* If we do not have this connection configured by the user in a
1631 configuration file then resolve the authentication method from the
1632 server for this session. */
1633 internal = silc_calloc(1, sizeof(*internal));
1634 internal->completion = completion;
1635 internal->context = context;
1637 silc_client_request_authentication_method(client, conn,
1638 silc_get_auth_method_callback,
1642 /* Notifies application that failure packet was received. This is called
1643 if there is some protocol active in the client. The `protocol' is the
1644 protocol context. The `failure' is opaque pointer to the failure
1645 indication. Note, that the `failure' is protocol dependant and application
1646 must explicitly cast it to correct type. Usually `failure' is 32 bit
1647 failure type (see protocol specs for all protocol failure types). */
1649 void silc_failure(SilcClient client, SilcClientConnection conn,
1650 SilcProtocol protocol, void *failure)
1652 SILC_LOG_DEBUG(("Start"));
1654 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1655 SilcSKEStatus status = (SilcSKEStatus)failure;
1657 if (status == SILC_SKE_STATUS_BAD_VERSION)
1658 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1659 SILCTXT_KE_BAD_VERSION);
1660 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1661 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1662 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1663 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1664 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1665 SILCTXT_KE_UNKNOWN_GROUP);
1666 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1667 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1668 SILCTXT_KE_UNKNOWN_CIPHER);
1669 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1670 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1671 SILCTXT_KE_UNKNOWN_PKCS);
1672 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1673 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1674 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1675 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1676 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1677 SILCTXT_KE_UNKNOWN_HMAC);
1678 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1679 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1680 SILCTXT_KE_INCORRECT_SIGNATURE);
1681 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1682 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1683 SILCTXT_KE_INVALID_COOKIE);
1686 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1687 SilcUInt32 err = (SilcUInt32)failure;
1689 if (err == SILC_AUTH_FAILED)
1690 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1691 SILCTXT_AUTH_FAILED);
1695 /* Asks whether the user would like to perform the key agreement protocol.
1696 This is called after we have received an key agreement packet or an
1697 reply to our key agreement packet. This returns TRUE if the user wants
1698 the library to perform the key agreement protocol and FALSE if it is not
1699 desired (application may start it later by calling the function
1700 silc_client_perform_key_agreement). */
1702 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1703 SilcClientEntry client_entry, const char *hostname,
1704 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1709 SILC_LOG_DEBUG(("Start"));
1711 /* We will just display the info on the screen and return FALSE and user
1712 will have to start the key agreement with a command. */
1715 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1718 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1719 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1721 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1722 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1723 client_entry->nickname, hostname, portstr);
1731 void silc_ftp(SilcClient client, SilcClientConnection conn,
1732 SilcClientEntry client_entry, SilcUInt32 session_id,
1733 const char *hostname, SilcUInt16 port)
1735 SILC_SERVER_REC *server;
1737 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1739 SILC_LOG_DEBUG(("Start"));
1741 server = conn->context;
1743 ftp->client_entry = client_entry;
1744 ftp->session_id = session_id;
1747 silc_dlist_add(server->ftp_sessions, ftp);
1748 server->current_session = ftp;
1751 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1754 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1755 SILCTXT_FILE_REQUEST, client_entry->nickname);
1757 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1758 SILCTXT_FILE_REQUEST_HOST,
1759 client_entry->nickname, hostname, portstr);
1762 /* SILC client operations */
1763 SilcClientOperations ops = {
1765 silc_channel_message,
1766 silc_private_message,
1772 silc_get_auth_method,
1773 silc_verify_public_key,
1774 silc_ask_passphrase,