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_SERVER_SIGNOFF:
515 * Server has quit the network.
518 SilcClientEntry *clients;
519 SilcUInt32 clients_count;
521 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
523 (void)va_arg(va, void *);
524 clients = va_arg(va, SilcClientEntry *);
525 clients_count = va_arg(va, SilcUInt32);
527 for (i = 0; i < clients_count; i++) {
528 memset(userhost, 0, sizeof(userhost));
529 if (clients[i]->username)
530 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
531 clients[i]->username, clients[i]->hostname);
532 signal_emit("message quit", 4, server, clients[i]->nickname,
533 clients[i]->username ? userhost : "",
536 silc_server_free_ftp(server, clients[i]);
538 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
539 for (list_tmp = list1; list_tmp != NULL; list_tmp =
540 list_tmp->next->next) {
541 CHANNEL_REC *channel = list_tmp->data;
542 NICK_REC *nickrec = list_tmp->next->data;
543 nicklist_remove(channel, nickrec);
551 printformat_module("fe-common/silc", server, NULL,
552 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
559 /* Called to indicate that connection was either successfully established
560 or connecting failed. This is also the first time application receives
561 the SilcClientConnection object which it should save somewhere. */
563 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
565 SILC_SERVER_REC *server = conn->context;
567 if (!server && !success) {
568 silc_client_close_connection(client, NULL, conn);
573 server->connected = TRUE;
574 signal_emit("event connected", 1, server);
576 server->connection_lost = TRUE;
578 server->conn->context = NULL;
579 server_disconnect(SERVER(server));
583 /* Called to indicate that connection was disconnected to the server. */
585 void silc_disconnect(SilcClient client, SilcClientConnection conn)
587 SILC_SERVER_REC *server = conn->context;
589 SILC_LOG_DEBUG(("Start"));
591 if (server->conn && server->conn->local_entry) {
592 nicklist_rename_unique(SERVER(server),
593 server->conn->local_entry, server->nick,
594 server->conn->local_entry,
595 silc_client->username);
596 silc_change_nick(server, silc_client->username);
599 server->conn->context = NULL;
601 server->connection_lost = TRUE;
602 server_disconnect(SERVER(server));
605 /* Command handler. This function is called always in the command function.
606 If error occurs it will be called as well. `conn' is the associated
607 client connection. `cmd_context' is the command context that was
608 originally sent to the command. `success' is FALSE if error occured
609 during command. `command' is the command being processed. It must be
610 noted that this is not reply from server. This is merely called just
611 after application has called the command. Just to tell application
612 that the command really was processed. */
614 void silc_command(SilcClient client, SilcClientConnection conn,
615 SilcClientCommandContext cmd_context, int success,
618 SILC_SERVER_REC *server = conn->context;
620 SILC_LOG_DEBUG(("Start"));
626 case SILC_COMMAND_INVITE:
627 printformat_module("fe-common/silc", server, NULL,
628 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
629 cmd_context->argv[2],
630 (cmd_context->argv[1][0] == '*' ?
631 (char *)conn->current_channel->channel_name :
632 (char *)cmd_context->argv[1]));
639 /* Client info resolving callback when JOIN command reply is received.
640 This will cache all users on the channel. */
642 static void silc_client_join_get_users(SilcClient client,
643 SilcClientConnection conn,
644 SilcClientEntry *clients,
645 SilcUInt32 clients_count,
648 SilcChannelEntry channel = (SilcChannelEntry)context;
649 SilcHashTableList htl;
651 SILC_SERVER_REC *server = conn->context;
652 SILC_CHANNEL_REC *chanrec;
653 SilcClientEntry founder = NULL;
659 chanrec = silc_channel_find(server, channel->channel_name);
663 silc_hash_table_list(channel->user_list, &htl);
664 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
665 if (!chu->client->nickname)
667 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
668 founder = chu->client;
669 silc_nicklist_insert(chanrec, chu, FALSE);
671 silc_hash_table_list_reset(&htl);
673 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
674 nicklist_set_own(CHANNEL(chanrec), ownnick);
675 signal_emit("channel joined", 1, chanrec);
678 printformat_module("fe-common/silc", server, channel->channel_name,
679 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
680 channel->channel_name, chanrec->topic);
682 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
685 if (founder == conn->local_entry)
686 printformat_module("fe-common/silc",
687 server, channel->channel_name, MSGLEVEL_CRAP,
688 SILCTXT_CHANNEL_FOUNDER_YOU,
689 channel->channel_name);
691 printformat_module("fe-common/silc",
692 server, channel->channel_name, MSGLEVEL_CRAP,
693 SILCTXT_CHANNEL_FOUNDER,
694 channel->channel_name, founder->nickname);
700 SilcClientConnection conn;
706 void silc_getkey_cb(bool success, void *context)
708 GetkeyContext getkey = (GetkeyContext)context;
709 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
710 char *name = (getkey->id_type == SILC_ID_CLIENT ?
711 ((SilcClientEntry)getkey->entry)->nickname :
712 ((SilcServerEntry)getkey->entry)->server_name);
715 printformat_module("fe-common/silc", NULL, NULL,
716 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
718 printformat_module("fe-common/silc", NULL, NULL,
719 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
722 silc_free(getkey->fingerprint);
726 /* Command reply handler. This function is called always in the command reply
727 function. If error occurs it will be called as well. Normal scenario
728 is that it will be called after the received command data has been parsed
729 and processed. The function is used to pass the received command data to
732 `conn' is the associated client connection. `cmd_payload' is the command
733 payload data received from server and it can be ignored. It is provided
734 if the application would like to re-parse the received command data,
735 however, it must be noted that the data is parsed already by the library
736 thus the payload can be ignored. `success' is FALSE if error occured.
737 In this case arguments are not sent to the application. `command' is the
738 command reply being processed. The function has variable argument list
739 and each command defines the number and type of arguments it passes to the
740 application (on error they are not sent). */
743 silc_command_reply(SilcClient client, SilcClientConnection conn,
744 SilcCommandPayload cmd_payload, int success,
745 SilcCommand command, SilcCommandStatus status, ...)
748 SILC_SERVER_REC *server = conn->context;
749 SILC_CHANNEL_REC *chanrec;
752 va_start(vp, status);
754 SILC_LOG_DEBUG(("Start"));
757 case SILC_COMMAND_WHOIS:
759 char buf[1024], *nickname, *username, *realname, *nick;
760 unsigned char *fingerprint;
761 SilcUInt32 idle, mode;
763 SilcClientEntry client_entry;
765 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
766 /* Print the unknown nick for user */
768 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
771 silc_say_error("%s: %s", tmp,
772 silc_client_command_status_message(status));
774 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
775 /* Try to find the entry for the unknown client ID, since we
776 might have, and print the nickname of it for user. */
779 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
782 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
784 client_entry = silc_client_get_client_by_id(client, conn,
786 if (client_entry && client_entry->nickname)
787 silc_say_error("%s: %s", client_entry->nickname,
788 silc_client_command_status_message(status));
789 silc_free(client_id);
798 client_entry = va_arg(vp, SilcClientEntry);
799 nickname = va_arg(vp, char *);
800 username = va_arg(vp, char *);
801 realname = va_arg(vp, char *);
802 channels = va_arg(vp, SilcBuffer);
803 mode = va_arg(vp, SilcUInt32);
804 idle = va_arg(vp, SilcUInt32);
805 fingerprint = va_arg(vp, unsigned char *);
807 silc_parse_userfqdn(nickname, &nick, NULL);
808 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
809 SILCTXT_WHOIS_USERINFO, nickname,
810 client_entry->username, client_entry->hostname,
811 nick, client_entry->nickname);
812 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
813 SILCTXT_WHOIS_REALNAME, realname);
817 SilcDList list = silc_channel_payload_parse_list(channels->data,
820 SilcChannelPayload entry;
821 memset(buf, 0, sizeof(buf));
822 silc_dlist_start(list);
823 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
824 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
826 char *name = silc_channel_get_name(entry, &name_len);
829 strncat(buf, m, strlen(m));
830 strncat(buf, name, name_len);
831 strncat(buf, " ", 1);
835 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
836 SILCTXT_WHOIS_CHANNELS, buf);
837 silc_channel_payload_list_free(list);
842 memset(buf, 0, sizeof(buf));
844 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
845 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
846 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
848 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
849 "SILC Operator " : "[Unknown mode] ");
851 if (mode & SILC_UMODE_GONE)
854 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
855 SILCTXT_WHOIS_MODES, buf);
858 if (idle && nickname) {
859 memset(buf, 0, sizeof(buf));
860 snprintf(buf, sizeof(buf) - 1, "%lu %s",
861 idle > 60 ? (idle / 60) : idle,
862 idle > 60 ? "minutes" : "seconds");
864 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
865 SILCTXT_WHOIS_IDLE, buf);
869 fingerprint = silc_fingerprint(fingerprint, 20);
870 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
871 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
872 silc_free(fingerprint);
877 case SILC_COMMAND_IDENTIFY:
879 SilcClientEntry client_entry;
881 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
882 /* Print the unknown nick for user */
884 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
887 silc_say_error("%s: %s", tmp,
888 silc_client_command_status_message(status));
890 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
891 /* Try to find the entry for the unknown client ID, since we
892 might have, and print the nickname of it for user. */
895 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
898 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
900 client_entry = silc_client_get_client_by_id(client, conn,
902 if (client_entry && client_entry->nickname)
903 silc_say_error("%s: %s", client_entry->nickname,
904 silc_client_command_status_message(status));
905 silc_free(client_id);
914 case SILC_COMMAND_WHOWAS:
916 char *nickname, *username, *realname;
918 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
919 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
921 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
924 silc_say_error("%s: %s", tmp,
925 silc_client_command_status_message(status));
932 (void)va_arg(vp, SilcClientEntry);
933 nickname = va_arg(vp, char *);
934 username = va_arg(vp, char *);
935 realname = va_arg(vp, char *);
937 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
938 SILCTXT_WHOWAS_USERINFO, nickname, username,
939 realname ? realname : "");
943 case SILC_COMMAND_INVITE:
945 SilcChannelEntry channel;
947 SilcArgumentPayload args;
953 channel = va_arg(vp, SilcChannelEntry);
954 invite_list = va_arg(vp, char *);
956 args = silc_command_get_args(cmd_payload);
958 argc = silc_argument_get_arg_num(args);
961 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
962 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
965 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
966 SILCTXT_CHANNEL_NO_INVITE_LIST,
967 channel->channel_name);
971 case SILC_COMMAND_JOIN:
973 char *channel, *mode, *topic;
975 SilcChannelEntry channel_entry;
976 SilcBuffer client_id_list;
977 SilcUInt32 list_count;
982 channel = va_arg(vp, char *);
983 channel_entry = va_arg(vp, SilcChannelEntry);
984 modei = va_arg(vp, SilcUInt32);
985 (void)va_arg(vp, SilcUInt32);
986 (void)va_arg(vp, unsigned char *);
987 (void)va_arg(vp, unsigned char *);
988 (void)va_arg(vp, unsigned char *);
989 topic = va_arg(vp, char *);
990 (void)va_arg(vp, unsigned char *);
991 list_count = va_arg(vp, SilcUInt32);
992 client_id_list = va_arg(vp, SilcBuffer);
994 chanrec = silc_channel_find(server, channel);
996 chanrec = silc_channel_create(server, channel, TRUE);
999 g_free_not_null(chanrec->topic);
1000 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1001 signal_emit("channel topic changed", 1, chanrec);
1004 mode = silc_client_chmode(modei,
1005 channel_entry->channel_key ?
1006 channel_entry->channel_key->cipher->name : "",
1007 channel_entry->hmac ?
1008 silc_hmac_get_name(channel_entry->hmac) : "");
1009 g_free_not_null(chanrec->mode);
1010 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1011 signal_emit("channel mode changed", 1, chanrec);
1013 /* Resolve the client information */
1014 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1015 silc_client_join_get_users,
1021 case SILC_COMMAND_NICK:
1023 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1029 old = g_strdup(server->nick);
1030 server_change_nick(SERVER(server), client->nickname);
1031 nicklist_rename_unique(SERVER(server),
1032 server->conn->local_entry, server->nick,
1033 client, client->nickname);
1034 signal_emit("message own_nick", 4, server, server->nick, old, "");
1039 case SILC_COMMAND_LIST:
1048 (void)va_arg(vp, SilcChannelEntry);
1049 name = va_arg(vp, char *);
1050 topic = va_arg(vp, char *);
1051 usercount = va_arg(vp, int);
1053 if (status == SILC_STATUS_LIST_START ||
1054 status == SILC_STATUS_OK)
1055 printformat_module("fe-common/silc", server, NULL,
1056 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1059 snprintf(users, sizeof(users) - 1, "N/A");
1061 snprintf(users, sizeof(users) - 1, "%d", usercount);
1062 printformat_module("fe-common/silc", server, NULL,
1063 MSGLEVEL_CRAP, SILCTXT_LIST,
1064 name, users, topic ? topic : "");
1068 case SILC_COMMAND_UMODE:
1075 mode = va_arg(vp, SilcUInt32);
1077 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1078 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1079 printformat_module("fe-common/silc", server, NULL,
1080 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1082 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1083 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1084 printformat_module("fe-common/silc", server, NULL,
1085 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1087 server->umode = mode;
1091 case SILC_COMMAND_OPER:
1095 printformat_module("fe-common/silc", server, NULL,
1096 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1099 case SILC_COMMAND_SILCOPER:
1103 printformat_module("fe-common/silc", server, NULL,
1104 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1107 case SILC_COMMAND_USERS:
1109 SilcHashTableList htl;
1110 SilcChannelEntry channel;
1111 SilcChannelUser chu;
1116 channel = va_arg(vp, SilcChannelEntry);
1118 printformat_module("fe-common/silc", server, channel->channel_name,
1119 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1120 channel->channel_name);
1122 silc_hash_table_list(channel->user_list, &htl);
1123 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1124 SilcClientEntry e = chu->client;
1125 char stat[5], *mode;
1130 memset(stat, 0, sizeof(stat));
1131 mode = silc_client_chumode_char(chu->mode);
1132 if (e->mode & SILC_UMODE_GONE)
1139 printformat_module("fe-common/silc", server, channel->channel_name,
1140 MSGLEVEL_CRAP, SILCTXT_USERS,
1142 e->username ? e->username : "",
1143 e->hostname ? e->hostname : "",
1144 e->realname ? e->realname : "");
1148 silc_hash_table_list_reset(&htl);
1152 case SILC_COMMAND_BAN:
1154 SilcChannelEntry channel;
1160 channel = va_arg(vp, SilcChannelEntry);
1161 ban_list = va_arg(vp, char *);
1164 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1165 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1168 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1169 SILCTXT_CHANNEL_NO_BAN_LIST,
1170 channel->channel_name);
1174 case SILC_COMMAND_GETKEY:
1178 SilcPublicKey public_key;
1181 GetkeyContext getkey;
1187 id_type = va_arg(vp, SilcUInt32);
1188 entry = va_arg(vp, void *);
1189 public_key = va_arg(vp, SilcPublicKey);
1192 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1194 getkey = silc_calloc(1, sizeof(*getkey));
1195 getkey->entry = entry;
1196 getkey->id_type = id_type;
1197 getkey->client = client;
1198 getkey->conn = conn;
1199 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1201 name = (id_type == SILC_ID_CLIENT ?
1202 ((SilcClientEntry)entry)->nickname :
1203 ((SilcServerEntry)entry)->server_name);
1205 silc_verify_public_key_internal(client, conn, name,
1206 (id_type == SILC_ID_CLIENT ?
1207 SILC_SOCKET_TYPE_CLIENT :
1208 SILC_SOCKET_TYPE_SERVER),
1209 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1210 silc_getkey_cb, getkey);
1213 printformat_module("fe-common/silc", server, NULL,
1214 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1219 case SILC_COMMAND_INFO:
1221 SilcServerEntry server_entry;
1228 server_entry = va_arg(vp, SilcServerEntry);
1229 server_name = va_arg(vp, char *);
1230 server_info = va_arg(vp, char *);
1232 if (server_name && server_info )
1234 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1235 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1240 case SILC_COMMAND_TOPIC:
1242 SilcChannelEntry channel;
1248 channel = va_arg(vp, SilcChannelEntry);
1249 topic = va_arg(vp, char *);
1252 chanrec = silc_channel_find_entry(server, channel);
1254 g_free_not_null(chanrec->topic);
1255 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1256 signal_emit("channel topic changed", 1, chanrec);
1258 printformat_module("fe-common/silc", server, channel->channel_name,
1259 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1260 channel->channel_name, topic);
1262 printformat_module("fe-common/silc", server, channel->channel_name,
1263 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1264 channel->channel_name);
1276 SilcClientConnection conn;
1282 SilcSKEPKType pk_type;
1283 SilcVerifyPublicKey completion;
1287 static void verify_public_key_completion(const char *line, void *context)
1289 PublicKeyVerify verify = (PublicKeyVerify)context;
1291 if (line[0] == 'Y' || line[0] == 'y') {
1292 /* Call the completion */
1293 if (verify->completion)
1294 verify->completion(TRUE, verify->context);
1296 /* Save the key for future checking */
1297 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1298 verify->pk_len, SILC_PKCS_FILE_PEM);
1300 /* Call the completion */
1301 if (verify->completion)
1302 verify->completion(FALSE, verify->context);
1304 printformat_module("fe-common/silc", NULL, NULL,
1305 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1306 verify->entity_name ? verify->entity_name :
1310 silc_free(verify->filename);
1311 silc_free(verify->entity);
1312 silc_free(verify->entity_name);
1313 silc_free(verify->pk);
1317 /* Internal routine to verify public key. If the `completion' is provided
1318 it will be called to indicate whether public was verified or not. For
1319 server/router public key this will check for filename that includes the
1320 remote host's IP address and remote host's hostname. */
1323 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1324 const char *name, SilcSocketType conn_type,
1325 unsigned char *pk, SilcUInt32 pk_len,
1326 SilcSKEPKType pk_type,
1327 SilcVerifyPublicKey completion, void *context)
1330 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1331 char *fingerprint, *babbleprint, *format;
1334 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1335 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1336 "server" : "client");
1337 PublicKeyVerify verify;
1339 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1340 printformat_module("fe-common/silc", NULL, NULL,
1341 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1344 completion(FALSE, context);
1348 pw = getpwuid(getuid());
1351 completion(FALSE, context);
1355 memset(filename, 0, sizeof(filename));
1356 memset(filename2, 0, sizeof(filename2));
1357 memset(file, 0, sizeof(file));
1359 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1360 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1362 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1363 conn->sock->ip, conn->sock->port);
1364 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1365 pw->pw_dir, entity, file);
1367 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1368 conn->sock->hostname, conn->sock->port);
1369 snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s",
1370 pw->pw_dir, entity, file);
1375 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1376 name, conn->sock->port);
1377 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1378 pw->pw_dir, entity, file);
1383 /* Replace all whitespaces with `_'. */
1384 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1385 for (i = 0; i < strlen(fingerprint); i++)
1386 if (fingerprint[i] == ' ')
1387 fingerprint[i] = '_';
1389 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1390 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
1391 pw->pw_dir, entity, file);
1392 silc_free(fingerprint);
1397 /* Take fingerprint of the public key */
1398 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1399 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1401 verify = silc_calloc(1, sizeof(*verify));
1402 verify->client = client;
1403 verify->conn = conn;
1404 verify->filename = strdup(ipf);
1405 verify->entity = strdup(entity);
1406 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1407 (name ? strdup(name) : strdup(conn->sock->hostname))
1409 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1410 memcpy(verify->pk, pk, pk_len);
1411 verify->pk_len = pk_len;
1412 verify->pk_type = pk_type;
1413 verify->completion = completion;
1414 verify->context = context;
1416 /* Check whether this key already exists */
1417 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1418 /* Key does not exist, ask user to verify the key and save it */
1420 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1421 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1422 verify->entity_name : entity);
1423 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1424 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1425 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1426 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1427 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1428 SILCTXT_PUBKEY_ACCEPT);
1429 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1432 silc_free(fingerprint);
1435 /* The key already exists, verify it. */
1436 SilcPublicKey public_key;
1437 unsigned char *encpk;
1438 SilcUInt32 encpk_len;
1440 /* Load the key file, try for both IP filename and hostname filename */
1441 if (!silc_pkcs_load_public_key(ipf, &public_key,
1442 SILC_PKCS_FILE_PEM) &&
1443 !silc_pkcs_load_public_key(ipf, &public_key,
1444 SILC_PKCS_FILE_BIN) &&
1445 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1446 SILC_PKCS_FILE_PEM) &&
1447 !silc_pkcs_load_public_key(hostf, &public_key,
1448 SILC_PKCS_FILE_BIN)))) {
1449 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1450 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1451 verify->entity_name : entity);
1452 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1453 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1454 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1455 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1456 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1457 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1458 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1459 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1460 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1463 silc_free(fingerprint);
1467 /* Encode the key data */
1468 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1470 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1471 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1472 verify->entity_name : entity);
1473 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1474 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1475 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1476 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1477 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1478 SILCTXT_PUBKEY_MALFORMED, entity);
1479 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1480 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1481 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1484 silc_free(fingerprint);
1488 /* Compare the keys */
1489 if (memcmp(encpk, pk, encpk_len)) {
1490 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1491 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1492 verify->entity_name : entity);
1493 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1494 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1495 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1496 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1497 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1498 SILCTXT_PUBKEY_NO_MATCH, entity);
1499 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1500 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1501 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1502 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1504 /* Ask user to verify the key and save it */
1505 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1506 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1507 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1510 silc_free(fingerprint);
1514 /* Local copy matched */
1516 completion(TRUE, context);
1517 silc_free(fingerprint);
1521 /* Verifies received public key. The `conn_type' indicates which entity
1522 (server, client etc.) has sent the public key. If user decides to trust
1523 the key may be saved as trusted public key for later use. The
1524 `completion' must be called after the public key has been verified. */
1527 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1528 SilcSocketType conn_type, unsigned char *pk,
1529 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1530 SilcVerifyPublicKey completion, void *context)
1532 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1534 completion, context);
1537 /* Asks passphrase from user on the input line. */
1540 SilcAskPassphrase completion;
1544 void ask_passphrase_completion(const char *passphrase, void *context)
1546 AskPassphrase p = (AskPassphrase)context;
1547 p->completion((unsigned char *)passphrase,
1548 passphrase ? strlen(passphrase) : 0, p->context);
1552 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1553 SilcAskPassphrase completion, void *context)
1555 AskPassphrase p = silc_calloc(1, sizeof(*p));
1556 p->completion = completion;
1557 p->context = context;
1559 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1560 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1564 SilcGetAuthMeth completion;
1566 } *InternalGetAuthMethod;
1568 /* Callback called when we've received the authentication method information
1569 from the server after we've requested it. This will get the authentication
1570 data from the user if needed. */
1572 static void silc_get_auth_method_callback(SilcClient client,
1573 SilcClientConnection conn,
1574 SilcAuthMethod auth_meth,
1577 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1579 SILC_LOG_DEBUG(("Start"));
1581 switch (auth_meth) {
1582 case SILC_AUTH_NONE:
1583 /* No authentication required. */
1584 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1586 case SILC_AUTH_PASSWORD:
1587 /* Do not ask the passphrase from user, the library will ask it if
1588 we do not provide it here. */
1589 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1591 case SILC_AUTH_PUBLIC_KEY:
1592 /* Do not get the authentication data now, the library will generate
1593 it using our default key, if we do not provide it here. */
1594 /* XXX In the future when we support multiple local keys and multiple
1595 local certificates we will need to ask from user which one to use. */
1596 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1600 silc_free(internal);
1603 /* Find authentication method and authentication data by hostname and
1604 port. The hostname may be IP address as well. The found authentication
1605 method and authentication data is returned to `auth_meth', `auth_data'
1606 and `auth_data_len'. The function returns TRUE if authentication method
1607 is found and FALSE if not. `conn' may be NULL. */
1609 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1610 char *hostname, SilcUInt16 port,
1611 SilcGetAuthMeth completion, void *context)
1613 InternalGetAuthMethod internal;
1615 SILC_LOG_DEBUG(("Start"));
1617 /* XXX must resolve from configuration whether this connection has
1618 any specific authentication data */
1620 /* If we do not have this connection configured by the user in a
1621 configuration file then resolve the authentication method from the
1622 server for this session. */
1623 internal = silc_calloc(1, sizeof(*internal));
1624 internal->completion = completion;
1625 internal->context = context;
1627 silc_client_request_authentication_method(client, conn,
1628 silc_get_auth_method_callback,
1632 /* Notifies application that failure packet was received. This is called
1633 if there is some protocol active in the client. The `protocol' is the
1634 protocol context. The `failure' is opaque pointer to the failure
1635 indication. Note, that the `failure' is protocol dependant and application
1636 must explicitly cast it to correct type. Usually `failure' is 32 bit
1637 failure type (see protocol specs for all protocol failure types). */
1639 void silc_failure(SilcClient client, SilcClientConnection conn,
1640 SilcProtocol protocol, void *failure)
1642 SILC_LOG_DEBUG(("Start"));
1644 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1645 SilcSKEStatus status = (SilcSKEStatus)failure;
1647 if (status == SILC_SKE_STATUS_BAD_VERSION)
1648 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1649 SILCTXT_KE_BAD_VERSION);
1650 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1651 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1652 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1653 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1654 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1655 SILCTXT_KE_UNKNOWN_GROUP);
1656 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1657 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1658 SILCTXT_KE_UNKNOWN_CIPHER);
1659 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1660 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1661 SILCTXT_KE_UNKNOWN_PKCS);
1662 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1663 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1664 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1665 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1666 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1667 SILCTXT_KE_UNKNOWN_HMAC);
1668 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1669 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1670 SILCTXT_KE_INCORRECT_SIGNATURE);
1671 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1672 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1673 SILCTXT_KE_INVALID_COOKIE);
1676 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1677 SilcUInt32 err = (SilcUInt32)failure;
1679 if (err == SILC_AUTH_FAILED)
1680 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1681 SILCTXT_AUTH_FAILED);
1685 /* Asks whether the user would like to perform the key agreement protocol.
1686 This is called after we have received an key agreement packet or an
1687 reply to our key agreement packet. This returns TRUE if the user wants
1688 the library to perform the key agreement protocol and FALSE if it is not
1689 desired (application may start it later by calling the function
1690 silc_client_perform_key_agreement). */
1692 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1693 SilcClientEntry client_entry, const char *hostname,
1694 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1699 SILC_LOG_DEBUG(("Start"));
1701 /* We will just display the info on the screen and return FALSE and user
1702 will have to start the key agreement with a command. */
1705 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1708 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1709 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1711 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1712 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1713 client_entry->nickname, hostname, portstr);
1721 void silc_ftp(SilcClient client, SilcClientConnection conn,
1722 SilcClientEntry client_entry, SilcUInt32 session_id,
1723 const char *hostname, SilcUInt16 port)
1725 SILC_SERVER_REC *server;
1727 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1729 SILC_LOG_DEBUG(("Start"));
1731 server = conn->context;
1733 ftp->client_entry = client_entry;
1734 ftp->session_id = session_id;
1737 silc_dlist_add(server->ftp_sessions, ftp);
1738 server->current_session = ftp;
1741 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1744 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1745 SILCTXT_FILE_REQUEST, client_entry->nickname);
1747 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1748 SILCTXT_FILE_REQUEST_HOST,
1749 client_entry->nickname, hostname, portstr);
1752 /* SILC client operations */
1753 SilcClientOperations ops = {
1755 silc_channel_message,
1756 silc_private_message,
1762 silc_get_auth_method,
1763 silc_verify_public_key,
1764 silc_ask_passphrase,