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,
463 client_entry ? client_entry2->nickname : "",
466 chanrec->kicked = TRUE;
467 channel_destroy((CHANNEL_REC *)chanrec);
470 printformat_module("fe-common/silc", server, channel->channel_name,
471 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
472 client_entry->nickname, channel->channel_name,
473 client_entry2 ? client_entry2->nickname : "",
477 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
479 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
484 case SILC_NOTIFY_TYPE_KILLED:
486 * Someone was killed from the network.
489 SILC_LOG_DEBUG(("Notify: KILLED"));
491 client_entry = va_arg(va, SilcClientEntry);
492 tmp = va_arg(va, char *);
494 if (client_entry == conn->local_entry) {
495 printformat_module("fe-common/silc", server, NULL,
496 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
499 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
500 for (list_tmp = list1; list_tmp != NULL; list_tmp =
501 list_tmp->next->next) {
502 CHANNEL_REC *channel = list_tmp->data;
503 NICK_REC *nickrec = list_tmp->next->data;
504 nicklist_remove(channel, nickrec);
507 printformat_module("fe-common/silc", server, NULL,
508 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
509 client_entry->nickname,
514 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
517 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
520 * Server has quit the network.
523 SilcClientEntry *clients;
524 SilcUInt32 clients_count;
526 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
528 (void)va_arg(va, void *);
529 clients = va_arg(va, SilcClientEntry *);
530 clients_count = va_arg(va, SilcUInt32);
532 for (i = 0; i < clients_count; i++) {
533 memset(userhost, 0, sizeof(userhost));
534 if (clients[i]->username)
535 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
536 clients[i]->username, clients[i]->hostname);
537 signal_emit("message quit", 4, server, clients[i]->nickname,
538 clients[i]->username ? userhost : "",
541 silc_server_free_ftp(server, clients[i]);
543 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
544 for (list_tmp = list1; list_tmp != NULL; list_tmp =
545 list_tmp->next->next) {
546 CHANNEL_REC *channel = list_tmp->data;
547 NICK_REC *nickrec = list_tmp->next->data;
548 nicklist_remove(channel, nickrec);
556 printformat_module("fe-common/silc", server, NULL,
557 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
564 /* Called to indicate that connection was either successfully established
565 or connecting failed. This is also the first time application receives
566 the SilcClientConnection object which it should save somewhere. */
568 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
570 SILC_SERVER_REC *server = conn->context;
572 if (!server && !success) {
573 silc_client_close_connection(client, NULL, conn);
578 server->connected = TRUE;
579 signal_emit("event connected", 1, server);
581 server->connection_lost = TRUE;
583 server->conn->context = NULL;
584 server_disconnect(SERVER(server));
588 /* Called to indicate that connection was disconnected to the server. */
590 void silc_disconnect(SilcClient client, SilcClientConnection conn)
592 SILC_SERVER_REC *server = conn->context;
594 SILC_LOG_DEBUG(("Start"));
596 if (server->conn && server->conn->local_entry) {
597 nicklist_rename_unique(SERVER(server),
598 server->conn->local_entry, server->nick,
599 server->conn->local_entry,
600 silc_client->username);
601 silc_change_nick(server, silc_client->username);
604 server->conn->context = NULL;
606 server->connection_lost = TRUE;
607 server_disconnect(SERVER(server));
610 /* Command handler. This function is called always in the command function.
611 If error occurs it will be called as well. `conn' is the associated
612 client connection. `cmd_context' is the command context that was
613 originally sent to the command. `success' is FALSE if error occured
614 during command. `command' is the command being processed. It must be
615 noted that this is not reply from server. This is merely called just
616 after application has called the command. Just to tell application
617 that the command really was processed. */
619 void silc_command(SilcClient client, SilcClientConnection conn,
620 SilcClientCommandContext cmd_context, int success,
623 SILC_SERVER_REC *server = conn->context;
625 SILC_LOG_DEBUG(("Start"));
631 case SILC_COMMAND_INVITE:
632 printformat_module("fe-common/silc", server, NULL,
633 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
634 cmd_context->argv[2],
635 (cmd_context->argv[1][0] == '*' ?
636 (char *)conn->current_channel->channel_name :
637 (char *)cmd_context->argv[1]));
644 /* Client info resolving callback when JOIN command reply is received.
645 This will cache all users on the channel. */
647 static void silc_client_join_get_users(SilcClient client,
648 SilcClientConnection conn,
649 SilcClientEntry *clients,
650 SilcUInt32 clients_count,
653 SilcChannelEntry channel = (SilcChannelEntry)context;
654 SilcHashTableList htl;
656 SILC_SERVER_REC *server = conn->context;
657 SILC_CHANNEL_REC *chanrec;
658 SilcClientEntry founder = NULL;
664 chanrec = silc_channel_find(server, channel->channel_name);
668 silc_hash_table_list(channel->user_list, &htl);
669 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
670 if (!chu->client->nickname)
672 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
673 founder = chu->client;
674 silc_nicklist_insert(chanrec, chu, FALSE);
676 silc_hash_table_list_reset(&htl);
678 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
679 nicklist_set_own(CHANNEL(chanrec), ownnick);
680 signal_emit("channel joined", 1, chanrec);
683 printformat_module("fe-common/silc", server, channel->channel_name,
684 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
685 channel->channel_name, chanrec->topic);
687 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
690 if (founder == conn->local_entry)
691 printformat_module("fe-common/silc",
692 server, channel->channel_name, MSGLEVEL_CRAP,
693 SILCTXT_CHANNEL_FOUNDER_YOU,
694 channel->channel_name);
696 printformat_module("fe-common/silc",
697 server, channel->channel_name, MSGLEVEL_CRAP,
698 SILCTXT_CHANNEL_FOUNDER,
699 channel->channel_name, founder->nickname);
705 SilcClientConnection conn;
711 void silc_getkey_cb(bool success, void *context)
713 GetkeyContext getkey = (GetkeyContext)context;
714 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
715 char *name = (getkey->id_type == SILC_ID_CLIENT ?
716 ((SilcClientEntry)getkey->entry)->nickname :
717 ((SilcServerEntry)getkey->entry)->server_name);
720 printformat_module("fe-common/silc", NULL, NULL,
721 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
723 printformat_module("fe-common/silc", NULL, NULL,
724 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
727 silc_free(getkey->fingerprint);
731 /* Command reply handler. This function is called always in the command reply
732 function. If error occurs it will be called as well. Normal scenario
733 is that it will be called after the received command data has been parsed
734 and processed. The function is used to pass the received command data to
737 `conn' is the associated client connection. `cmd_payload' is the command
738 payload data received from server and it can be ignored. It is provided
739 if the application would like to re-parse the received command data,
740 however, it must be noted that the data is parsed already by the library
741 thus the payload can be ignored. `success' is FALSE if error occured.
742 In this case arguments are not sent to the application. `command' is the
743 command reply being processed. The function has variable argument list
744 and each command defines the number and type of arguments it passes to the
745 application (on error they are not sent). */
748 silc_command_reply(SilcClient client, SilcClientConnection conn,
749 SilcCommandPayload cmd_payload, int success,
750 SilcCommand command, SilcCommandStatus status, ...)
753 SILC_SERVER_REC *server = conn->context;
754 SILC_CHANNEL_REC *chanrec;
757 va_start(vp, status);
759 SILC_LOG_DEBUG(("Start"));
762 case SILC_COMMAND_WHOIS:
764 char buf[1024], *nickname, *username, *realname, *nick;
765 unsigned char *fingerprint;
766 SilcUInt32 idle, mode;
768 SilcClientEntry client_entry;
770 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
771 /* Print the unknown nick for user */
773 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
776 silc_say_error("%s: %s", tmp,
777 silc_client_command_status_message(status));
779 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
780 /* Try to find the entry for the unknown client ID, since we
781 might have, and print the nickname of it for user. */
784 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
787 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
789 client_entry = silc_client_get_client_by_id(client, conn,
791 if (client_entry && client_entry->nickname)
792 silc_say_error("%s: %s", client_entry->nickname,
793 silc_client_command_status_message(status));
794 silc_free(client_id);
803 client_entry = va_arg(vp, SilcClientEntry);
804 nickname = va_arg(vp, char *);
805 username = va_arg(vp, char *);
806 realname = va_arg(vp, char *);
807 channels = va_arg(vp, SilcBuffer);
808 mode = va_arg(vp, SilcUInt32);
809 idle = va_arg(vp, SilcUInt32);
810 fingerprint = va_arg(vp, unsigned char *);
812 silc_parse_userfqdn(nickname, &nick, NULL);
813 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
814 SILCTXT_WHOIS_USERINFO, nickname,
815 client_entry->username, client_entry->hostname,
816 nick, client_entry->nickname);
817 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
818 SILCTXT_WHOIS_REALNAME, realname);
822 SilcDList list = silc_channel_payload_parse_list(channels->data,
825 SilcChannelPayload entry;
826 memset(buf, 0, sizeof(buf));
827 silc_dlist_start(list);
828 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
829 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
831 char *name = silc_channel_get_name(entry, &name_len);
834 strncat(buf, m, strlen(m));
835 strncat(buf, name, name_len);
836 strncat(buf, " ", 1);
840 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
841 SILCTXT_WHOIS_CHANNELS, buf);
842 silc_channel_payload_list_free(list);
847 memset(buf, 0, sizeof(buf));
849 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
850 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
851 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
853 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
854 "SILC Operator " : "[Unknown mode] ");
856 if (mode & SILC_UMODE_GONE)
859 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
860 SILCTXT_WHOIS_MODES, buf);
863 if (idle && nickname) {
864 memset(buf, 0, sizeof(buf));
865 snprintf(buf, sizeof(buf) - 1, "%lu %s",
866 idle > 60 ? (idle / 60) : idle,
867 idle > 60 ? "minutes" : "seconds");
869 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
870 SILCTXT_WHOIS_IDLE, buf);
874 fingerprint = silc_fingerprint(fingerprint, 20);
875 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
876 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
877 silc_free(fingerprint);
882 case SILC_COMMAND_IDENTIFY:
884 SilcClientEntry client_entry;
886 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
887 /* Print the unknown nick for user */
889 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
892 silc_say_error("%s: %s", tmp,
893 silc_client_command_status_message(status));
895 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
896 /* Try to find the entry for the unknown client ID, since we
897 might have, and print the nickname of it for user. */
900 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
903 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
905 client_entry = silc_client_get_client_by_id(client, conn,
907 if (client_entry && client_entry->nickname)
908 silc_say_error("%s: %s", client_entry->nickname,
909 silc_client_command_status_message(status));
910 silc_free(client_id);
919 case SILC_COMMAND_WHOWAS:
921 char *nickname, *username, *realname;
923 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
924 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
926 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
929 silc_say_error("%s: %s", tmp,
930 silc_client_command_status_message(status));
937 (void)va_arg(vp, SilcClientEntry);
938 nickname = va_arg(vp, char *);
939 username = va_arg(vp, char *);
940 realname = va_arg(vp, char *);
942 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
943 SILCTXT_WHOWAS_USERINFO, nickname, username,
944 realname ? realname : "");
948 case SILC_COMMAND_INVITE:
950 SilcChannelEntry channel;
952 SilcArgumentPayload args;
958 channel = va_arg(vp, SilcChannelEntry);
959 invite_list = va_arg(vp, char *);
961 args = silc_command_get_args(cmd_payload);
963 argc = silc_argument_get_arg_num(args);
966 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
967 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
970 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
971 SILCTXT_CHANNEL_NO_INVITE_LIST,
972 channel->channel_name);
976 case SILC_COMMAND_JOIN:
978 char *channel, *mode, *topic;
980 SilcChannelEntry channel_entry;
981 SilcBuffer client_id_list;
982 SilcUInt32 list_count;
987 channel = va_arg(vp, char *);
988 channel_entry = va_arg(vp, SilcChannelEntry);
989 modei = va_arg(vp, SilcUInt32);
990 (void)va_arg(vp, SilcUInt32);
991 (void)va_arg(vp, unsigned char *);
992 (void)va_arg(vp, unsigned char *);
993 (void)va_arg(vp, unsigned char *);
994 topic = va_arg(vp, char *);
995 (void)va_arg(vp, unsigned char *);
996 list_count = va_arg(vp, SilcUInt32);
997 client_id_list = va_arg(vp, SilcBuffer);
999 chanrec = silc_channel_find(server, channel);
1001 chanrec = silc_channel_create(server, channel, TRUE);
1004 g_free_not_null(chanrec->topic);
1005 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1006 signal_emit("channel topic changed", 1, chanrec);
1009 mode = silc_client_chmode(modei,
1010 channel_entry->channel_key ?
1011 channel_entry->channel_key->cipher->name : "",
1012 channel_entry->hmac ?
1013 silc_hmac_get_name(channel_entry->hmac) : "");
1014 g_free_not_null(chanrec->mode);
1015 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1016 signal_emit("channel mode changed", 1, chanrec);
1018 /* Resolve the client information */
1019 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1020 silc_client_join_get_users,
1026 case SILC_COMMAND_NICK:
1028 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1034 old = g_strdup(server->nick);
1035 server_change_nick(SERVER(server), client->nickname);
1036 nicklist_rename_unique(SERVER(server),
1037 server->conn->local_entry, server->nick,
1038 client, client->nickname);
1039 signal_emit("message own_nick", 4, server, server->nick, old, "");
1044 case SILC_COMMAND_LIST:
1053 (void)va_arg(vp, SilcChannelEntry);
1054 name = va_arg(vp, char *);
1055 topic = va_arg(vp, char *);
1056 usercount = va_arg(vp, int);
1058 if (status == SILC_STATUS_LIST_START ||
1059 status == SILC_STATUS_OK)
1060 printformat_module("fe-common/silc", server, NULL,
1061 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1064 snprintf(users, sizeof(users) - 1, "N/A");
1066 snprintf(users, sizeof(users) - 1, "%d", usercount);
1067 printformat_module("fe-common/silc", server, NULL,
1068 MSGLEVEL_CRAP, SILCTXT_LIST,
1069 name, users, topic ? topic : "");
1073 case SILC_COMMAND_UMODE:
1080 mode = va_arg(vp, SilcUInt32);
1082 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1083 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1084 printformat_module("fe-common/silc", server, NULL,
1085 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1087 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1088 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1089 printformat_module("fe-common/silc", server, NULL,
1090 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1092 server->umode = mode;
1093 signal_emit("user mode changed", 2, server, NULL);
1097 case SILC_COMMAND_OPER:
1101 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1102 signal_emit("user mode changed", 2, server, NULL);
1104 printformat_module("fe-common/silc", server, NULL,
1105 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1108 case SILC_COMMAND_SILCOPER:
1112 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1113 signal_emit("user mode changed", 2, server, NULL);
1115 printformat_module("fe-common/silc", server, NULL,
1116 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1119 case SILC_COMMAND_USERS:
1121 SilcHashTableList htl;
1122 SilcChannelEntry channel;
1123 SilcChannelUser chu;
1128 channel = va_arg(vp, SilcChannelEntry);
1130 printformat_module("fe-common/silc", server, channel->channel_name,
1131 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1132 channel->channel_name);
1134 silc_hash_table_list(channel->user_list, &htl);
1135 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1136 SilcClientEntry e = chu->client;
1137 char stat[5], *mode;
1142 memset(stat, 0, sizeof(stat));
1143 mode = silc_client_chumode_char(chu->mode);
1144 if (e->mode & SILC_UMODE_GONE)
1151 printformat_module("fe-common/silc", server, channel->channel_name,
1152 MSGLEVEL_CRAP, SILCTXT_USERS,
1154 e->username ? e->username : "",
1155 e->hostname ? e->hostname : "",
1156 e->realname ? e->realname : "");
1160 silc_hash_table_list_reset(&htl);
1164 case SILC_COMMAND_BAN:
1166 SilcChannelEntry channel;
1172 channel = va_arg(vp, SilcChannelEntry);
1173 ban_list = va_arg(vp, char *);
1176 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1177 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1180 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1181 SILCTXT_CHANNEL_NO_BAN_LIST,
1182 channel->channel_name);
1186 case SILC_COMMAND_GETKEY:
1190 SilcPublicKey public_key;
1193 GetkeyContext getkey;
1199 id_type = va_arg(vp, SilcUInt32);
1200 entry = va_arg(vp, void *);
1201 public_key = va_arg(vp, SilcPublicKey);
1204 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1206 getkey = silc_calloc(1, sizeof(*getkey));
1207 getkey->entry = entry;
1208 getkey->id_type = id_type;
1209 getkey->client = client;
1210 getkey->conn = conn;
1211 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1213 name = (id_type == SILC_ID_CLIENT ?
1214 ((SilcClientEntry)entry)->nickname :
1215 ((SilcServerEntry)entry)->server_name);
1217 silc_verify_public_key_internal(client, conn, name,
1218 (id_type == SILC_ID_CLIENT ?
1219 SILC_SOCKET_TYPE_CLIENT :
1220 SILC_SOCKET_TYPE_SERVER),
1221 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1222 silc_getkey_cb, getkey);
1225 printformat_module("fe-common/silc", server, NULL,
1226 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1231 case SILC_COMMAND_INFO:
1233 SilcServerEntry server_entry;
1240 server_entry = va_arg(vp, SilcServerEntry);
1241 server_name = va_arg(vp, char *);
1242 server_info = va_arg(vp, char *);
1244 if (server_name && server_info )
1246 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1247 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1252 case SILC_COMMAND_TOPIC:
1254 SilcChannelEntry channel;
1260 channel = va_arg(vp, SilcChannelEntry);
1261 topic = va_arg(vp, char *);
1264 chanrec = silc_channel_find_entry(server, channel);
1266 g_free_not_null(chanrec->topic);
1267 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1268 signal_emit("channel topic changed", 1, chanrec);
1270 printformat_module("fe-common/silc", server, channel->channel_name,
1271 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1272 channel->channel_name, topic);
1274 printformat_module("fe-common/silc", server, channel->channel_name,
1275 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1276 channel->channel_name);
1288 SilcClientConnection conn;
1294 SilcSKEPKType pk_type;
1295 SilcVerifyPublicKey completion;
1299 static void verify_public_key_completion(const char *line, void *context)
1301 PublicKeyVerify verify = (PublicKeyVerify)context;
1303 if (line[0] == 'Y' || line[0] == 'y') {
1304 /* Call the completion */
1305 if (verify->completion)
1306 verify->completion(TRUE, verify->context);
1308 /* Save the key for future checking */
1309 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1310 verify->pk_len, SILC_PKCS_FILE_PEM);
1312 /* Call the completion */
1313 if (verify->completion)
1314 verify->completion(FALSE, verify->context);
1316 printformat_module("fe-common/silc", NULL, NULL,
1317 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1318 verify->entity_name ? verify->entity_name :
1322 silc_free(verify->filename);
1323 silc_free(verify->entity);
1324 silc_free(verify->entity_name);
1325 silc_free(verify->pk);
1329 /* Internal routine to verify public key. If the `completion' is provided
1330 it will be called to indicate whether public was verified or not. For
1331 server/router public key this will check for filename that includes the
1332 remote host's IP address and remote host's hostname. */
1335 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1336 const char *name, SilcSocketType conn_type,
1337 unsigned char *pk, SilcUInt32 pk_len,
1338 SilcSKEPKType pk_type,
1339 SilcVerifyPublicKey completion, void *context)
1342 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1343 char *fingerprint, *babbleprint, *format;
1346 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1347 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1348 "server" : "client");
1349 PublicKeyVerify verify;
1351 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1352 printformat_module("fe-common/silc", NULL, NULL,
1353 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1356 completion(FALSE, context);
1360 pw = getpwuid(getuid());
1363 completion(FALSE, context);
1367 memset(filename, 0, sizeof(filename));
1368 memset(filename2, 0, sizeof(filename2));
1369 memset(file, 0, sizeof(file));
1371 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1372 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1374 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1375 conn->sock->ip, conn->sock->port);
1376 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1377 pw->pw_dir, entity, file);
1379 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1380 conn->sock->hostname, conn->sock->port);
1381 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1382 pw->pw_dir, entity, file);
1387 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1388 name, conn->sock->port);
1389 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1390 pw->pw_dir, entity, file);
1395 /* Replace all whitespaces with `_'. */
1396 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1397 for (i = 0; i < strlen(fingerprint); i++)
1398 if (fingerprint[i] == ' ')
1399 fingerprint[i] = '_';
1401 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1402 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1403 pw->pw_dir, entity, file);
1404 silc_free(fingerprint);
1409 /* Take fingerprint of the public key */
1410 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1411 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1413 verify = silc_calloc(1, sizeof(*verify));
1414 verify->client = client;
1415 verify->conn = conn;
1416 verify->filename = strdup(ipf);
1417 verify->entity = strdup(entity);
1418 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1419 (name ? strdup(name) : strdup(conn->sock->hostname))
1421 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1422 memcpy(verify->pk, pk, pk_len);
1423 verify->pk_len = pk_len;
1424 verify->pk_type = pk_type;
1425 verify->completion = completion;
1426 verify->context = context;
1428 /* Check whether this key already exists */
1429 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1430 /* Key does not exist, ask user to verify the key and save it */
1432 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1433 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1434 verify->entity_name : entity);
1435 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1436 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1437 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1438 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1439 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1440 SILCTXT_PUBKEY_ACCEPT);
1441 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1444 silc_free(fingerprint);
1447 /* The key already exists, verify it. */
1448 SilcPublicKey public_key;
1449 unsigned char *encpk;
1450 SilcUInt32 encpk_len;
1452 /* Load the key file, try for both IP filename and hostname filename */
1453 if (!silc_pkcs_load_public_key(ipf, &public_key,
1454 SILC_PKCS_FILE_PEM) &&
1455 !silc_pkcs_load_public_key(ipf, &public_key,
1456 SILC_PKCS_FILE_BIN) &&
1457 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1458 SILC_PKCS_FILE_PEM) &&
1459 !silc_pkcs_load_public_key(hostf, &public_key,
1460 SILC_PKCS_FILE_BIN)))) {
1461 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1462 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1463 verify->entity_name : entity);
1464 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1465 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1466 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1467 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1468 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1469 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1470 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1471 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1472 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1475 silc_free(fingerprint);
1479 /* Encode the key data */
1480 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1482 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1483 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1484 verify->entity_name : entity);
1485 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1486 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1487 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1488 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1489 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1490 SILCTXT_PUBKEY_MALFORMED, entity);
1491 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1492 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1493 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1496 silc_free(fingerprint);
1500 /* Compare the keys */
1501 if (memcmp(encpk, pk, encpk_len)) {
1502 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1503 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1504 verify->entity_name : entity);
1505 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1506 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1507 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1508 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1509 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1510 SILCTXT_PUBKEY_NO_MATCH, entity);
1511 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1512 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1513 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1514 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1516 /* Ask user to verify the key and save it */
1517 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1518 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1519 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1522 silc_free(fingerprint);
1526 /* Local copy matched */
1528 completion(TRUE, context);
1529 silc_free(fingerprint);
1533 /* Verifies received public key. The `conn_type' indicates which entity
1534 (server, client etc.) has sent the public key. If user decides to trust
1535 the key may be saved as trusted public key for later use. The
1536 `completion' must be called after the public key has been verified. */
1539 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1540 SilcSocketType conn_type, unsigned char *pk,
1541 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1542 SilcVerifyPublicKey completion, void *context)
1544 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1546 completion, context);
1549 /* Asks passphrase from user on the input line. */
1552 SilcAskPassphrase completion;
1556 void ask_passphrase_completion(const char *passphrase, void *context)
1558 AskPassphrase p = (AskPassphrase)context;
1559 p->completion((unsigned char *)passphrase,
1560 passphrase ? strlen(passphrase) : 0, p->context);
1564 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1565 SilcAskPassphrase completion, void *context)
1567 AskPassphrase p = silc_calloc(1, sizeof(*p));
1568 p->completion = completion;
1569 p->context = context;
1571 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1572 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1576 SilcGetAuthMeth completion;
1578 } *InternalGetAuthMethod;
1580 /* Callback called when we've received the authentication method information
1581 from the server after we've requested it. This will get the authentication
1582 data from the user if needed. */
1584 static void silc_get_auth_method_callback(SilcClient client,
1585 SilcClientConnection conn,
1586 SilcAuthMethod auth_meth,
1589 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1591 SILC_LOG_DEBUG(("Start"));
1593 switch (auth_meth) {
1594 case SILC_AUTH_NONE:
1595 /* No authentication required. */
1596 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1598 case SILC_AUTH_PASSWORD:
1599 /* Do not ask the passphrase from user, the library will ask it if
1600 we do not provide it here. */
1601 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1603 case SILC_AUTH_PUBLIC_KEY:
1604 /* Do not get the authentication data now, the library will generate
1605 it using our default key, if we do not provide it here. */
1606 /* XXX In the future when we support multiple local keys and multiple
1607 local certificates we will need to ask from user which one to use. */
1608 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1612 silc_free(internal);
1615 /* Find authentication method and authentication data by hostname and
1616 port. The hostname may be IP address as well. The found authentication
1617 method and authentication data is returned to `auth_meth', `auth_data'
1618 and `auth_data_len'. The function returns TRUE if authentication method
1619 is found and FALSE if not. `conn' may be NULL. */
1621 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1622 char *hostname, SilcUInt16 port,
1623 SilcGetAuthMeth completion, void *context)
1625 InternalGetAuthMethod internal;
1627 SILC_LOG_DEBUG(("Start"));
1629 /* XXX must resolve from configuration whether this connection has
1630 any specific authentication data */
1632 /* If we do not have this connection configured by the user in a
1633 configuration file then resolve the authentication method from the
1634 server for this session. */
1635 internal = silc_calloc(1, sizeof(*internal));
1636 internal->completion = completion;
1637 internal->context = context;
1639 silc_client_request_authentication_method(client, conn,
1640 silc_get_auth_method_callback,
1644 /* Notifies application that failure packet was received. This is called
1645 if there is some protocol active in the client. The `protocol' is the
1646 protocol context. The `failure' is opaque pointer to the failure
1647 indication. Note, that the `failure' is protocol dependant and application
1648 must explicitly cast it to correct type. Usually `failure' is 32 bit
1649 failure type (see protocol specs for all protocol failure types). */
1651 void silc_failure(SilcClient client, SilcClientConnection conn,
1652 SilcProtocol protocol, void *failure)
1654 SILC_LOG_DEBUG(("Start"));
1656 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1657 SilcSKEStatus status = (SilcSKEStatus)failure;
1659 if (status == SILC_SKE_STATUS_BAD_VERSION)
1660 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1661 SILCTXT_KE_BAD_VERSION);
1662 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1663 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1664 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1665 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1666 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1667 SILCTXT_KE_UNKNOWN_GROUP);
1668 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1669 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1670 SILCTXT_KE_UNKNOWN_CIPHER);
1671 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1672 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1673 SILCTXT_KE_UNKNOWN_PKCS);
1674 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1675 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1676 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1677 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1678 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1679 SILCTXT_KE_UNKNOWN_HMAC);
1680 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1681 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1682 SILCTXT_KE_INCORRECT_SIGNATURE);
1683 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1684 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1685 SILCTXT_KE_INVALID_COOKIE);
1688 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1689 SilcUInt32 err = (SilcUInt32)failure;
1691 if (err == SILC_AUTH_FAILED)
1692 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1693 SILCTXT_AUTH_FAILED);
1697 /* Asks whether the user would like to perform the key agreement protocol.
1698 This is called after we have received an key agreement packet or an
1699 reply to our key agreement packet. This returns TRUE if the user wants
1700 the library to perform the key agreement protocol and FALSE if it is not
1701 desired (application may start it later by calling the function
1702 silc_client_perform_key_agreement). */
1704 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1705 SilcClientEntry client_entry, const char *hostname,
1706 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1711 SILC_LOG_DEBUG(("Start"));
1713 /* We will just display the info on the screen and return FALSE and user
1714 will have to start the key agreement with a command. */
1717 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1720 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1721 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1723 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1724 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1725 client_entry->nickname, hostname, portstr);
1733 void silc_ftp(SilcClient client, SilcClientConnection conn,
1734 SilcClientEntry client_entry, SilcUInt32 session_id,
1735 const char *hostname, SilcUInt16 port)
1737 SILC_SERVER_REC *server;
1739 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1741 SILC_LOG_DEBUG(("Start"));
1743 server = conn->context;
1745 ftp->client_entry = client_entry;
1746 ftp->session_id = session_id;
1749 silc_dlist_add(server->ftp_sessions, ftp);
1750 server->current_session = ftp;
1753 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1756 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1757 SILCTXT_FILE_REQUEST, client_entry->nickname);
1759 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1760 SILCTXT_FILE_REQUEST_HOST,
1761 client_entry->nickname, hostname, portstr);
1764 /* SILC client operations */
1765 SilcClientOperations ops = {
1767 silc_channel_message,
1768 silc_private_message,
1774 silc_get_auth_method,
1775 silc_verify_public_key,
1776 silc_ask_passphrase,