5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
44 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
45 const char *name, SilcSocketType conn_type,
46 unsigned char *pk, SilcUInt32 pk_len,
47 SilcSKEPKType pk_type,
48 SilcVerifyPublicKey completion, void *context);
50 void silc_say(SilcClient client, SilcClientConnection conn,
51 SilcClientMessageType type, char *msg, ...)
53 SILC_SERVER_REC *server;
57 server = conn == NULL ? NULL : conn->context;
60 str = g_strdup_vprintf(msg, va);
61 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
66 void silc_say_error(char *msg, ...)
72 str = g_strdup_vprintf(msg, va);
73 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
79 /* Message for a channel. The `sender' is the nickname of the sender
80 received in the packet. The `channel_name' is the name of the channel. */
82 void silc_channel_message(SilcClient client, SilcClientConnection conn,
83 SilcClientEntry sender, SilcChannelEntry channel,
84 SilcMessageFlags flags, char *msg)
86 SILC_SERVER_REC *server;
88 SILC_CHANNEL_REC *chanrec;
90 SILC_LOG_DEBUG(("Start"));
95 server = conn == NULL ? NULL : conn->context;
96 chanrec = silc_channel_find_entry(server, channel);
100 nick = silc_nicklist_find(chanrec, sender);
102 /* We didn't find client but it clearly exists, add it. */
103 SilcChannelUser chu = silc_client_on_channel(channel, sender);
105 nick = silc_nicklist_insert(chanrec, chu, FALSE);
108 if (flags & SILC_MESSAGE_FLAG_ACTION)
109 printformat_module("fe-common/silc", server, channel->channel_name,
110 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
111 nick == NULL ? "[<unknown>]" : nick->nick, msg);
112 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
113 printformat_module("fe-common/silc", server, channel->channel_name,
114 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
115 nick == NULL ? "[<unknown>]" : nick->nick, msg);
117 signal_emit("message public", 6, server, msg,
118 nick == NULL ? "[<unknown>]" : nick->nick,
119 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
120 chanrec->name, nick);
123 /* Private message to the client. The `sender' is the nickname of the
124 sender received in the packet. */
126 void silc_private_message(SilcClient client, SilcClientConnection conn,
127 SilcClientEntry sender, SilcMessageFlags flags,
130 SILC_SERVER_REC *server;
133 SILC_LOG_DEBUG(("Start"));
135 server = conn == NULL ? NULL : conn->context;
136 memset(userhost, 0, sizeof(userhost));
137 if (sender->username)
138 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
139 sender->username, sender->hostname);
140 signal_emit("message private", 4, server, msg,
141 sender->nickname ? sender->nickname : "[<unknown>]",
142 sender->username ? userhost : NULL);
145 /* Notify message to the client. The notify arguments are sent in the
146 same order as servers sends them. The arguments are same as received
147 from the server except for ID's. If ID is received application receives
148 the corresponding entry to the ID. For example, if Client ID is received
149 application receives SilcClientEntry. Also, if the notify type is
150 for channel the channel entry is sent to application (even if server
151 does not send it). */
153 void silc_notify(SilcClient client, SilcClientConnection conn,
154 SilcNotifyType type, ...)
157 SILC_SERVER_REC *server;
158 SILC_CHANNEL_REC *chanrec;
159 SILC_NICK_REC *nickrec;
160 SilcClientEntry client_entry, client_entry2;
161 SilcChannelEntry channel, channel2;
162 SilcServerEntry server_entry;
168 GSList *list1, *list_tmp;
170 SILC_LOG_DEBUG(("Start"));
174 server = conn == NULL ? NULL : conn->context;
177 case SILC_NOTIFY_TYPE_NONE:
178 /* Some generic notice from server */
179 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
182 case SILC_NOTIFY_TYPE_INVITE:
184 * Invited or modified invite list.
187 SILC_LOG_DEBUG(("Notify: INVITE"));
189 channel = va_arg(va, SilcChannelEntry);
190 name = va_arg(va, char *);
191 client_entry = va_arg(va, SilcClientEntry);
193 memset(userhost, 0, sizeof(userhost));
194 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
195 client_entry->username, client_entry->hostname);
196 signal_emit("message invite", 4, server, channel ? channel->channel_name :
197 name, client_entry->nickname, userhost);
200 case SILC_NOTIFY_TYPE_JOIN:
205 SILC_LOG_DEBUG(("Notify: JOIN"));
207 client_entry = va_arg(va, SilcClientEntry);
208 channel = va_arg(va, SilcChannelEntry);
210 if (client_entry == server->conn->local_entry) {
211 /* You joined to channel */
212 chanrec = silc_channel_find(server, channel->channel_name);
213 if (chanrec != NULL && !chanrec->joined)
214 chanrec->entry = channel;
216 chanrec = silc_channel_find_entry(server, channel);
217 if (chanrec != NULL) {
218 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
220 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
224 memset(userhost, 0, sizeof(userhost));
225 if (client_entry->username)
226 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
227 client_entry->username, client_entry->hostname);
228 signal_emit("message join", 4, server, channel->channel_name,
229 client_entry->nickname,
230 client_entry->username == NULL ? "" : userhost);
233 case SILC_NOTIFY_TYPE_LEAVE:
238 SILC_LOG_DEBUG(("Notify: LEAVE"));
240 client_entry = va_arg(va, SilcClientEntry);
241 channel = va_arg(va, SilcChannelEntry);
243 memset(userhost, 0, sizeof(userhost));
244 if (client_entry->username)
245 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
246 client_entry->username, client_entry->hostname);
247 signal_emit("message part", 5, server, channel->channel_name,
248 client_entry->nickname, client_entry->username ?
249 userhost : "", client_entry->nickname);
251 chanrec = silc_channel_find_entry(server, channel);
252 if (chanrec != NULL) {
253 nickrec = silc_nicklist_find(chanrec, client_entry);
255 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
259 case SILC_NOTIFY_TYPE_SIGNOFF:
264 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
266 client_entry = va_arg(va, SilcClientEntry);
267 tmp = va_arg(va, char *);
269 silc_server_free_ftp(server, client_entry);
271 memset(userhost, 0, sizeof(userhost));
272 if (client_entry->username)
273 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
274 client_entry->username, client_entry->hostname);
275 signal_emit("message quit", 4, server, client_entry->nickname,
276 client_entry->username ? userhost : "",
279 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
280 for (list_tmp = list1; list_tmp != NULL; list_tmp =
281 list_tmp->next->next) {
282 CHANNEL_REC *channel = list_tmp->data;
283 NICK_REC *nickrec = list_tmp->next->data;
285 nicklist_remove(channel, nickrec);
289 case SILC_NOTIFY_TYPE_TOPIC_SET:
294 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
296 idtype = va_arg(va, int);
297 entry = va_arg(va, void *);
298 tmp = va_arg(va, char *);
299 channel = va_arg(va, SilcChannelEntry);
301 chanrec = silc_channel_find_entry(server, channel);
302 if (chanrec != NULL) {
303 g_free_not_null(chanrec->topic);
304 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
305 signal_emit("channel topic changed", 1, chanrec);
308 if (idtype == SILC_ID_CLIENT) {
309 client_entry = (SilcClientEntry)entry;
310 memset(userhost, 0, sizeof(userhost));
311 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
312 client_entry->username, client_entry->hostname);
313 signal_emit("message topic", 5, server, channel->channel_name,
314 tmp, client_entry->nickname, userhost);
315 } else if (idtype == SILC_ID_SERVER) {
316 server_entry = (SilcServerEntry)entry;
317 signal_emit("message topic", 5, server, channel->channel_name,
318 tmp, server_entry->server_name,
319 server_entry->server_name);
321 channel = (SilcChannelEntry)entry;
322 signal_emit("message topic", 5, server, channel->channel_name,
323 tmp, channel->channel_name, channel->channel_name);
327 case SILC_NOTIFY_TYPE_NICK_CHANGE:
332 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
334 client_entry = va_arg(va, SilcClientEntry);
335 client_entry2 = va_arg(va, SilcClientEntry);
337 memset(userhost, 0, sizeof(userhost));
338 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
339 client_entry2->username, client_entry2->hostname);
340 nicklist_rename_unique(SERVER(server),
341 client_entry, client_entry->nickname,
342 client_entry2, client_entry2->nickname);
343 signal_emit("message nick", 4, server, client_entry2->nickname,
344 client_entry->nickname, userhost);
347 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
349 * Changed channel mode.
352 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
354 idtype = va_arg(va, int);
355 entry = va_arg(va, void *);
356 mode = va_arg(va, SilcUInt32);
357 (void)va_arg(va, char *);
358 (void)va_arg(va, char *);
359 channel = va_arg(va, SilcChannelEntry);
361 tmp = silc_client_chmode(mode,
362 channel->channel_key ?
363 channel->channel_key->cipher->name : "",
365 silc_hmac_get_name(channel->hmac) : "");
367 chanrec = silc_channel_find_entry(server, channel);
368 if (chanrec != NULL) {
369 g_free_not_null(chanrec->mode);
370 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
371 signal_emit("channel mode changed", 1, chanrec);
374 if (idtype == SILC_ID_CLIENT) {
375 client_entry = (SilcClientEntry)entry;
376 printformat_module("fe-common/silc", server, channel->channel_name,
377 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
378 channel->channel_name, tmp ? tmp : "removed all",
379 client_entry->nickname);
380 } else if (idtype == SILC_ID_SERVER) {
381 server_entry = (SilcServerEntry)entry;
382 printformat_module("fe-common/silc", server, channel->channel_name,
383 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
384 channel->channel_name, tmp ? tmp : "removed all",
385 server_entry->server_name);
387 channel2 = (SilcChannelEntry)entry;
388 printformat_module("fe-common/silc", server, channel->channel_name,
389 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
390 channel->channel_name, tmp ? tmp : "removed all",
391 channel2->channel_name);
397 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
399 * Changed user's mode on channel.
402 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
404 idtype = va_arg(va, int);
405 entry = va_arg(va, void *);
406 mode = va_arg(va, SilcUInt32);
407 client_entry2 = va_arg(va, SilcClientEntry);
408 channel = va_arg(va, SilcChannelEntry);
410 tmp = silc_client_chumode(mode);
411 chanrec = silc_channel_find_entry(server, channel);
412 if (chanrec != NULL) {
415 if (client_entry2 == server->conn->local_entry)
416 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
418 nick = silc_nicklist_find(chanrec, client_entry2);
420 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
421 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
422 signal_emit("nick mode changed", 2, chanrec, nick);
426 if (idtype == SILC_ID_CLIENT) {
427 client_entry = (SilcClientEntry)entry;
428 printformat_module("fe-common/silc", server, channel->channel_name,
429 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
430 channel->channel_name, client_entry2->nickname,
431 tmp ? tmp : "removed all",
432 client_entry->nickname);
433 } else if (idtype == SILC_ID_SERVER) {
434 server_entry = (SilcServerEntry)entry;
435 printformat_module("fe-common/silc", server, channel->channel_name,
436 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
437 channel->channel_name, client_entry2->nickname,
438 tmp ? tmp : "removed all",
439 server_entry->server_name);
441 channel2 = (SilcChannelEntry)entry;
442 printformat_module("fe-common/silc", server, channel->channel_name,
443 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
444 channel->channel_name, client_entry2->nickname,
445 tmp ? tmp : "removed all",
446 channel2->channel_name);
449 if (mode & SILC_CHANNEL_UMODE_CHANFO)
450 printformat_module("fe-common/silc",
451 server, channel->channel_name, MSGLEVEL_CRAP,
452 SILCTXT_CHANNEL_FOUNDER,
453 channel->channel_name, client_entry2->nickname);
458 case SILC_NOTIFY_TYPE_MOTD:
463 SILC_LOG_DEBUG(("Notify: MOTD"));
465 tmp = va_arg(va, char *);
467 if (!settings_get_bool("skip_motd"))
468 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
471 case SILC_NOTIFY_TYPE_KICKED:
473 * Someone was kicked from channel.
476 SILC_LOG_DEBUG(("Notify: KICKED"));
478 client_entry = va_arg(va, SilcClientEntry);
479 tmp = va_arg(va, char *);
480 client_entry2 = va_arg(va, SilcClientEntry);
481 channel = va_arg(va, SilcChannelEntry);
483 chanrec = silc_channel_find_entry(server, channel);
485 if (client_entry == conn->local_entry) {
486 printformat_module("fe-common/silc", server, channel->channel_name,
487 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
488 channel->channel_name,
489 client_entry ? client_entry2->nickname : "",
492 chanrec->kicked = TRUE;
493 channel_destroy((CHANNEL_REC *)chanrec);
496 printformat_module("fe-common/silc", server, channel->channel_name,
497 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
498 client_entry->nickname, channel->channel_name,
499 client_entry2 ? client_entry2->nickname : "",
503 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
505 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
510 case SILC_NOTIFY_TYPE_KILLED:
512 * Someone was killed from the network.
515 SILC_LOG_DEBUG(("Notify: KILLED"));
517 client_entry = va_arg(va, SilcClientEntry);
518 tmp = va_arg(va, char *);
520 if (client_entry == conn->local_entry) {
521 printformat_module("fe-common/silc", server, NULL,
522 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
525 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
526 for (list_tmp = list1; list_tmp != NULL; list_tmp =
527 list_tmp->next->next) {
528 CHANNEL_REC *channel = list_tmp->data;
529 NICK_REC *nickrec = list_tmp->next->data;
530 nicklist_remove(channel, nickrec);
533 printformat_module("fe-common/silc", server, NULL,
534 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
535 client_entry->nickname,
540 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
543 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
546 * Server has quit the network.
549 SilcClientEntry *clients;
550 SilcUInt32 clients_count;
552 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
554 (void)va_arg(va, void *);
555 clients = va_arg(va, SilcClientEntry *);
556 clients_count = va_arg(va, SilcUInt32);
558 for (i = 0; i < clients_count; i++) {
559 memset(userhost, 0, sizeof(userhost));
560 if (clients[i]->username)
561 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
562 clients[i]->username, clients[i]->hostname);
563 signal_emit("message quit", 4, server, clients[i]->nickname,
564 clients[i]->username ? userhost : "",
567 silc_server_free_ftp(server, clients[i]);
569 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
570 for (list_tmp = list1; list_tmp != NULL; list_tmp =
571 list_tmp->next->next) {
572 CHANNEL_REC *channel = list_tmp->data;
573 NICK_REC *nickrec = list_tmp->next->data;
574 nicklist_remove(channel, nickrec);
582 printformat_module("fe-common/silc", server, NULL,
583 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
590 /* Called to indicate that connection was either successfully established
591 or connecting failed. This is also the first time application receives
592 the SilcClientConnection object which it should save somewhere. */
594 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
596 SILC_SERVER_REC *server = conn->context;
598 if (!server && !success) {
599 silc_client_close_connection(client, NULL, conn);
604 server->connected = TRUE;
605 signal_emit("event connected", 1, server);
607 server->connection_lost = TRUE;
609 server->conn->context = NULL;
610 server_disconnect(SERVER(server));
614 /* Called to indicate that connection was disconnected to the server. */
616 void silc_disconnect(SilcClient client, SilcClientConnection conn)
618 SILC_SERVER_REC *server = conn->context;
620 SILC_LOG_DEBUG(("Start"));
622 if (server->conn && server->conn->local_entry) {
623 nicklist_rename_unique(SERVER(server),
624 server->conn->local_entry, server->nick,
625 server->conn->local_entry,
626 silc_client->username);
627 silc_change_nick(server, silc_client->username);
630 server->conn->context = NULL;
632 server->connection_lost = TRUE;
633 server_disconnect(SERVER(server));
636 /* Command handler. This function is called always in the command function.
637 If error occurs it will be called as well. `conn' is the associated
638 client connection. `cmd_context' is the command context that was
639 originally sent to the command. `success' is FALSE if error occured
640 during command. `command' is the command being processed. It must be
641 noted that this is not reply from server. This is merely called just
642 after application has called the command. Just to tell application
643 that the command really was processed. */
645 void silc_command(SilcClient client, SilcClientConnection conn,
646 SilcClientCommandContext cmd_context, int success,
649 SILC_SERVER_REC *server = conn->context;
651 SILC_LOG_DEBUG(("Start"));
657 case SILC_COMMAND_INVITE:
658 printformat_module("fe-common/silc", server, NULL,
659 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
660 cmd_context->argv[2],
661 (cmd_context->argv[1][0] == '*' ?
662 (char *)conn->current_channel->channel_name :
663 (char *)cmd_context->argv[1]));
670 /* Client info resolving callback when JOIN command reply is received.
671 This will cache all users on the channel. */
673 static void silc_client_join_get_users(SilcClient client,
674 SilcClientConnection conn,
675 SilcClientEntry *clients,
676 SilcUInt32 clients_count,
679 SilcChannelEntry channel = (SilcChannelEntry)context;
680 SilcHashTableList htl;
682 SILC_SERVER_REC *server = conn->context;
683 SILC_CHANNEL_REC *chanrec;
684 SilcClientEntry founder = NULL;
690 chanrec = silc_channel_find(server, channel->channel_name);
694 silc_hash_table_list(channel->user_list, &htl);
695 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
696 if (!chu->client->nickname)
698 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
699 founder = chu->client;
700 silc_nicklist_insert(chanrec, chu, FALSE);
702 silc_hash_table_list_reset(&htl);
704 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
705 nicklist_set_own(CHANNEL(chanrec), ownnick);
706 signal_emit("channel joined", 1, chanrec);
709 printformat_module("fe-common/silc", server, channel->channel_name,
710 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
711 channel->channel_name, chanrec->topic);
713 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
716 if (founder == conn->local_entry)
717 printformat_module("fe-common/silc",
718 server, channel->channel_name, MSGLEVEL_CRAP,
719 SILCTXT_CHANNEL_FOUNDER_YOU,
720 channel->channel_name);
722 printformat_module("fe-common/silc",
723 server, channel->channel_name, MSGLEVEL_CRAP,
724 SILCTXT_CHANNEL_FOUNDER,
725 channel->channel_name, founder->nickname);
731 SilcClientConnection conn;
737 void silc_getkey_cb(bool success, void *context)
739 GetkeyContext getkey = (GetkeyContext)context;
740 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
741 char *name = (getkey->id_type == SILC_ID_CLIENT ?
742 ((SilcClientEntry)getkey->entry)->nickname :
743 ((SilcServerEntry)getkey->entry)->server_name);
746 printformat_module("fe-common/silc", NULL, NULL,
747 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
749 printformat_module("fe-common/silc", NULL, NULL,
750 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
753 silc_free(getkey->fingerprint);
757 /* Command reply handler. This function is called always in the command reply
758 function. If error occurs it will be called as well. Normal scenario
759 is that it will be called after the received command data has been parsed
760 and processed. The function is used to pass the received command data to
763 `conn' is the associated client connection. `cmd_payload' is the command
764 payload data received from server and it can be ignored. It is provided
765 if the application would like to re-parse the received command data,
766 however, it must be noted that the data is parsed already by the library
767 thus the payload can be ignored. `success' is FALSE if error occured.
768 In this case arguments are not sent to the application. `command' is the
769 command reply being processed. The function has variable argument list
770 and each command defines the number and type of arguments it passes to the
771 application (on error they are not sent). */
774 silc_command_reply(SilcClient client, SilcClientConnection conn,
775 SilcCommandPayload cmd_payload, int success,
776 SilcCommand command, SilcCommandStatus status, ...)
779 SILC_SERVER_REC *server = conn->context;
780 SILC_CHANNEL_REC *chanrec;
783 va_start(vp, status);
785 SILC_LOG_DEBUG(("Start"));
788 case SILC_COMMAND_WHOIS:
790 char buf[1024], *nickname, *username, *realname, *nick;
791 unsigned char *fingerprint;
792 SilcUInt32 idle, mode;
794 SilcClientEntry client_entry;
796 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
797 /* Print the unknown nick for user */
799 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
802 silc_say_error("%s: %s", tmp,
803 silc_client_command_status_message(status));
805 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
806 /* Try to find the entry for the unknown client ID, since we
807 might have, and print the nickname of it for user. */
810 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
813 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
816 client_entry = silc_client_get_client_by_id(client, conn,
818 if (client_entry && client_entry->nickname)
819 silc_say_error("%s: %s", client_entry->nickname,
820 silc_client_command_status_message(status));
821 silc_free(client_id);
830 client_entry = va_arg(vp, SilcClientEntry);
831 nickname = va_arg(vp, char *);
832 username = va_arg(vp, char *);
833 realname = va_arg(vp, char *);
834 channels = va_arg(vp, SilcBuffer);
835 mode = va_arg(vp, SilcUInt32);
836 idle = va_arg(vp, SilcUInt32);
837 fingerprint = va_arg(vp, unsigned char *);
839 silc_parse_userfqdn(nickname, &nick, NULL);
840 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
841 SILCTXT_WHOIS_USERINFO, nickname,
842 client_entry->username, client_entry->hostname,
843 nick, client_entry->nickname);
844 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
845 SILCTXT_WHOIS_REALNAME, realname);
849 SilcDList list = silc_channel_payload_parse_list(channels->data,
852 SilcChannelPayload entry;
853 memset(buf, 0, sizeof(buf));
854 silc_dlist_start(list);
855 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
856 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
858 char *name = silc_channel_get_name(entry, &name_len);
861 strncat(buf, m, strlen(m));
862 strncat(buf, name, name_len);
863 strncat(buf, " ", 1);
867 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
868 SILCTXT_WHOIS_CHANNELS, buf);
869 silc_channel_payload_list_free(list);
874 memset(buf, 0, sizeof(buf));
876 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
877 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
878 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
880 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
881 "SILC Operator " : "[Unknown mode] ");
883 if (mode & SILC_UMODE_GONE)
886 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
887 SILCTXT_WHOIS_MODES, buf);
890 if (idle && nickname) {
891 memset(buf, 0, sizeof(buf));
892 snprintf(buf, sizeof(buf) - 1, "%lu %s",
893 idle > 60 ? (idle / 60) : idle,
894 idle > 60 ? "minutes" : "seconds");
896 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
897 SILCTXT_WHOIS_IDLE, buf);
901 fingerprint = silc_fingerprint(fingerprint, 20);
902 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
903 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
904 silc_free(fingerprint);
909 case SILC_COMMAND_IDENTIFY:
911 SilcClientEntry client_entry;
913 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
914 /* Print the unknown nick for user */
916 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
919 silc_say_error("%s: %s", tmp,
920 silc_client_command_status_message(status));
922 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
923 /* Try to find the entry for the unknown client ID, since we
924 might have, and print the nickname of it for user. */
927 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
930 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
933 client_entry = silc_client_get_client_by_id(client, conn,
935 if (client_entry && client_entry->nickname)
936 silc_say_error("%s: %s", client_entry->nickname,
937 silc_client_command_status_message(status));
938 silc_free(client_id);
947 case SILC_COMMAND_WHOWAS:
949 char *nickname, *username, *realname;
951 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
952 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
954 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
957 silc_say_error("%s: %s", tmp,
958 silc_client_command_status_message(status));
965 (void)va_arg(vp, SilcClientEntry);
966 nickname = va_arg(vp, char *);
967 username = va_arg(vp, char *);
968 realname = va_arg(vp, char *);
970 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
971 SILCTXT_WHOWAS_USERINFO, nickname, username,
972 realname ? realname : "");
976 case SILC_COMMAND_INVITE:
978 SilcChannelEntry channel;
980 SilcArgumentPayload args;
986 channel = va_arg(vp, SilcChannelEntry);
987 invite_list = va_arg(vp, char *);
989 args = silc_command_get_args(cmd_payload);
991 argc = silc_argument_get_arg_num(args);
994 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
995 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
998 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
999 SILCTXT_CHANNEL_NO_INVITE_LIST,
1000 channel->channel_name);
1004 case SILC_COMMAND_JOIN:
1006 char *channel, *mode, *topic;
1008 SilcChannelEntry channel_entry;
1009 SilcBuffer client_id_list;
1010 SilcUInt32 list_count;
1015 channel = va_arg(vp, char *);
1016 channel_entry = va_arg(vp, SilcChannelEntry);
1017 modei = va_arg(vp, SilcUInt32);
1018 (void)va_arg(vp, SilcUInt32);
1019 (void)va_arg(vp, unsigned char *);
1020 (void)va_arg(vp, unsigned char *);
1021 (void)va_arg(vp, unsigned char *);
1022 topic = va_arg(vp, char *);
1023 (void)va_arg(vp, unsigned char *);
1024 list_count = va_arg(vp, SilcUInt32);
1025 client_id_list = va_arg(vp, SilcBuffer);
1027 chanrec = silc_channel_find(server, channel);
1029 chanrec = silc_channel_create(server, channel, TRUE);
1032 g_free_not_null(chanrec->topic);
1033 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1034 signal_emit("channel topic changed", 1, chanrec);
1037 mode = silc_client_chmode(modei,
1038 channel_entry->channel_key ?
1039 channel_entry->channel_key->cipher->name : "",
1040 channel_entry->hmac ?
1041 silc_hmac_get_name(channel_entry->hmac) : "");
1042 g_free_not_null(chanrec->mode);
1043 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1044 signal_emit("channel mode changed", 1, chanrec);
1046 /* Resolve the client information */
1047 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1048 silc_client_join_get_users,
1054 case SILC_COMMAND_NICK:
1056 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1062 old = g_strdup(server->nick);
1063 server_change_nick(SERVER(server), client->nickname);
1064 nicklist_rename_unique(SERVER(server),
1065 server->conn->local_entry, server->nick,
1066 client, client->nickname);
1067 signal_emit("message own_nick", 4, server, server->nick, old, "");
1072 case SILC_COMMAND_LIST:
1081 (void)va_arg(vp, SilcChannelEntry);
1082 name = va_arg(vp, char *);
1083 topic = va_arg(vp, char *);
1084 usercount = va_arg(vp, int);
1086 if (status == SILC_STATUS_LIST_START ||
1087 status == SILC_STATUS_OK)
1088 printformat_module("fe-common/silc", server, NULL,
1089 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1092 snprintf(users, sizeof(users) - 1, "N/A");
1094 snprintf(users, sizeof(users) - 1, "%d", usercount);
1095 printformat_module("fe-common/silc", server, NULL,
1096 MSGLEVEL_CRAP, SILCTXT_LIST,
1097 name, users, topic ? topic : "");
1101 case SILC_COMMAND_UMODE:
1108 mode = va_arg(vp, SilcUInt32);
1110 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1111 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1112 printformat_module("fe-common/silc", server, NULL,
1113 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1115 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1116 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1117 printformat_module("fe-common/silc", server, NULL,
1118 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1120 server->umode = mode;
1121 signal_emit("user mode changed", 2, server, NULL);
1125 case SILC_COMMAND_OPER:
1129 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1130 signal_emit("user mode changed", 2, server, NULL);
1132 printformat_module("fe-common/silc", server, NULL,
1133 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1136 case SILC_COMMAND_SILCOPER:
1140 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1141 signal_emit("user mode changed", 2, server, NULL);
1143 printformat_module("fe-common/silc", server, NULL,
1144 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1147 case SILC_COMMAND_USERS:
1149 SilcHashTableList htl;
1150 SilcChannelEntry channel;
1151 SilcChannelUser chu;
1156 channel = va_arg(vp, SilcChannelEntry);
1158 printformat_module("fe-common/silc", server, channel->channel_name,
1159 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1160 channel->channel_name);
1162 silc_hash_table_list(channel->user_list, &htl);
1163 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1164 SilcClientEntry e = chu->client;
1165 char stat[5], *mode;
1170 memset(stat, 0, sizeof(stat));
1171 mode = silc_client_chumode_char(chu->mode);
1172 if (e->mode & SILC_UMODE_GONE)
1179 printformat_module("fe-common/silc", server, channel->channel_name,
1180 MSGLEVEL_CRAP, SILCTXT_USERS,
1182 e->username ? e->username : "",
1183 e->hostname ? e->hostname : "",
1184 e->realname ? e->realname : "");
1188 silc_hash_table_list_reset(&htl);
1192 case SILC_COMMAND_BAN:
1194 SilcChannelEntry channel;
1200 channel = va_arg(vp, SilcChannelEntry);
1201 ban_list = va_arg(vp, char *);
1204 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1205 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1208 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1209 SILCTXT_CHANNEL_NO_BAN_LIST,
1210 channel->channel_name);
1214 case SILC_COMMAND_GETKEY:
1218 SilcPublicKey public_key;
1221 GetkeyContext getkey;
1227 id_type = va_arg(vp, SilcUInt32);
1228 entry = va_arg(vp, void *);
1229 public_key = va_arg(vp, SilcPublicKey);
1232 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1234 getkey = silc_calloc(1, sizeof(*getkey));
1235 getkey->entry = entry;
1236 getkey->id_type = id_type;
1237 getkey->client = client;
1238 getkey->conn = conn;
1239 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1241 name = (id_type == SILC_ID_CLIENT ?
1242 ((SilcClientEntry)entry)->nickname :
1243 ((SilcServerEntry)entry)->server_name);
1245 silc_verify_public_key_internal(client, conn, name,
1246 (id_type == SILC_ID_CLIENT ?
1247 SILC_SOCKET_TYPE_CLIENT :
1248 SILC_SOCKET_TYPE_SERVER),
1249 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1250 silc_getkey_cb, getkey);
1253 printformat_module("fe-common/silc", server, NULL,
1254 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1259 case SILC_COMMAND_INFO:
1261 SilcServerEntry server_entry;
1268 server_entry = va_arg(vp, SilcServerEntry);
1269 server_name = va_arg(vp, char *);
1270 server_info = va_arg(vp, char *);
1272 if (server_name && server_info )
1274 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1275 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1280 case SILC_COMMAND_TOPIC:
1282 SilcChannelEntry channel;
1288 channel = va_arg(vp, SilcChannelEntry);
1289 topic = va_arg(vp, char *);
1292 chanrec = silc_channel_find_entry(server, channel);
1294 g_free_not_null(chanrec->topic);
1295 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1296 signal_emit("channel topic changed", 1, chanrec);
1298 printformat_module("fe-common/silc", server, channel->channel_name,
1299 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1300 channel->channel_name, topic);
1302 printformat_module("fe-common/silc", server, channel->channel_name,
1303 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1304 channel->channel_name);
1316 SilcClientConnection conn;
1322 SilcSKEPKType pk_type;
1323 SilcVerifyPublicKey completion;
1327 static void verify_public_key_completion(const char *line, void *context)
1329 PublicKeyVerify verify = (PublicKeyVerify)context;
1331 if (line[0] == 'Y' || line[0] == 'y') {
1332 /* Call the completion */
1333 if (verify->completion)
1334 verify->completion(TRUE, verify->context);
1336 /* Save the key for future checking */
1337 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1338 verify->pk_len, SILC_PKCS_FILE_PEM);
1340 /* Call the completion */
1341 if (verify->completion)
1342 verify->completion(FALSE, verify->context);
1344 printformat_module("fe-common/silc", NULL, NULL,
1345 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1346 verify->entity_name ? verify->entity_name :
1350 silc_free(verify->filename);
1351 silc_free(verify->entity);
1352 silc_free(verify->entity_name);
1353 silc_free(verify->pk);
1357 /* Internal routine to verify public key. If the `completion' is provided
1358 it will be called to indicate whether public was verified or not. For
1359 server/router public key this will check for filename that includes the
1360 remote host's IP address and remote host's hostname. */
1363 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1364 const char *name, SilcSocketType conn_type,
1365 unsigned char *pk, SilcUInt32 pk_len,
1366 SilcSKEPKType pk_type,
1367 SilcVerifyPublicKey completion, void *context)
1370 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1371 char *fingerprint, *babbleprint, *format;
1374 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1375 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1376 "server" : "client");
1377 PublicKeyVerify verify;
1379 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1380 printformat_module("fe-common/silc", NULL, NULL,
1381 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1384 completion(FALSE, context);
1388 pw = getpwuid(getuid());
1391 completion(FALSE, context);
1395 memset(filename, 0, sizeof(filename));
1396 memset(filename2, 0, sizeof(filename2));
1397 memset(file, 0, sizeof(file));
1399 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1400 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1402 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1403 conn->sock->ip, conn->sock->port);
1404 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1405 get_irssi_dir(), entity, file);
1407 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1408 conn->sock->hostname, conn->sock->port);
1409 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1410 get_irssi_dir(), entity, file);
1415 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1416 name, conn->sock->port);
1417 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1418 get_irssi_dir(), entity, file);
1423 /* Replace all whitespaces with `_'. */
1424 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1425 for (i = 0; i < strlen(fingerprint); i++)
1426 if (fingerprint[i] == ' ')
1427 fingerprint[i] = '_';
1429 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1430 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1431 get_irssi_dir(), entity, file);
1432 silc_free(fingerprint);
1437 /* Take fingerprint of the public key */
1438 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1439 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1441 verify = silc_calloc(1, sizeof(*verify));
1442 verify->client = client;
1443 verify->conn = conn;
1444 verify->filename = strdup(ipf);
1445 verify->entity = strdup(entity);
1446 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1447 (name ? strdup(name) : strdup(conn->sock->hostname))
1449 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1450 memcpy(verify->pk, pk, pk_len);
1451 verify->pk_len = pk_len;
1452 verify->pk_type = pk_type;
1453 verify->completion = completion;
1454 verify->context = context;
1456 /* Check whether this key already exists */
1457 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1458 /* Key does not exist, ask user to verify the key and save it */
1460 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1461 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1462 verify->entity_name : entity);
1463 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1464 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1465 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1466 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1467 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1468 SILCTXT_PUBKEY_ACCEPT);
1469 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1472 silc_free(fingerprint);
1475 /* The key already exists, verify it. */
1476 SilcPublicKey public_key;
1477 unsigned char *encpk;
1478 SilcUInt32 encpk_len;
1480 /* Load the key file, try for both IP filename and hostname filename */
1481 if (!silc_pkcs_load_public_key(ipf, &public_key,
1482 SILC_PKCS_FILE_PEM) &&
1483 !silc_pkcs_load_public_key(ipf, &public_key,
1484 SILC_PKCS_FILE_BIN) &&
1485 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1486 SILC_PKCS_FILE_PEM) &&
1487 !silc_pkcs_load_public_key(hostf, &public_key,
1488 SILC_PKCS_FILE_BIN)))) {
1489 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1490 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1491 verify->entity_name : entity);
1492 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1493 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1494 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1495 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1496 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1497 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1498 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1499 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1500 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1503 silc_free(fingerprint);
1507 /* Encode the key data */
1508 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1510 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1511 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1512 verify->entity_name : entity);
1513 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1514 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1515 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1516 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1517 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1518 SILCTXT_PUBKEY_MALFORMED, entity);
1519 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1520 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1521 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1524 silc_free(fingerprint);
1528 /* Compare the keys */
1529 if (memcmp(encpk, pk, encpk_len)) {
1530 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1531 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1532 verify->entity_name : entity);
1533 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1534 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1535 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1536 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1537 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1538 SILCTXT_PUBKEY_NO_MATCH, entity);
1539 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1540 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1541 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1542 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1544 /* Ask user to verify the key and save it */
1545 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1546 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1547 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1550 silc_free(fingerprint);
1554 /* Local copy matched */
1556 completion(TRUE, context);
1557 silc_free(fingerprint);
1561 /* Verifies received public key. The `conn_type' indicates which entity
1562 (server, client etc.) has sent the public key. If user decides to trust
1563 the key may be saved as trusted public key for later use. The
1564 `completion' must be called after the public key has been verified. */
1567 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1568 SilcSocketType conn_type, unsigned char *pk,
1569 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1570 SilcVerifyPublicKey completion, void *context)
1572 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1574 completion, context);
1577 /* Asks passphrase from user on the input line. */
1580 SilcAskPassphrase completion;
1584 void ask_passphrase_completion(const char *passphrase, void *context)
1586 AskPassphrase p = (AskPassphrase)context;
1587 p->completion((unsigned char *)passphrase,
1588 passphrase ? strlen(passphrase) : 0, p->context);
1592 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1593 SilcAskPassphrase completion, void *context)
1595 AskPassphrase p = silc_calloc(1, sizeof(*p));
1596 p->completion = completion;
1597 p->context = context;
1599 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1600 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1604 SilcGetAuthMeth completion;
1606 } *InternalGetAuthMethod;
1608 /* Callback called when we've received the authentication method information
1609 from the server after we've requested it. This will get the authentication
1610 data from the user if needed. */
1612 static void silc_get_auth_method_callback(SilcClient client,
1613 SilcClientConnection conn,
1614 SilcAuthMethod auth_meth,
1617 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1619 SILC_LOG_DEBUG(("Start"));
1621 switch (auth_meth) {
1622 case SILC_AUTH_NONE:
1623 /* No authentication required. */
1624 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1626 case SILC_AUTH_PASSWORD:
1627 /* Do not ask the passphrase from user, the library will ask it if
1628 we do not provide it here. */
1629 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1631 case SILC_AUTH_PUBLIC_KEY:
1632 /* Do not get the authentication data now, the library will generate
1633 it using our default key, if we do not provide it here. */
1634 /* XXX In the future when we support multiple local keys and multiple
1635 local certificates we will need to ask from user which one to use. */
1636 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1640 silc_free(internal);
1643 /* Find authentication method and authentication data by hostname and
1644 port. The hostname may be IP address as well. The found authentication
1645 method and authentication data is returned to `auth_meth', `auth_data'
1646 and `auth_data_len'. The function returns TRUE if authentication method
1647 is found and FALSE if not. `conn' may be NULL. */
1649 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1650 char *hostname, SilcUInt16 port,
1651 SilcGetAuthMeth completion, void *context)
1653 InternalGetAuthMethod internal;
1655 SILC_LOG_DEBUG(("Start"));
1657 /* XXX must resolve from configuration whether this connection has
1658 any specific authentication data */
1660 /* If we do not have this connection configured by the user in a
1661 configuration file then resolve the authentication method from the
1662 server for this session. */
1663 internal = silc_calloc(1, sizeof(*internal));
1664 internal->completion = completion;
1665 internal->context = context;
1667 silc_client_request_authentication_method(client, conn,
1668 silc_get_auth_method_callback,
1672 /* Notifies application that failure packet was received. This is called
1673 if there is some protocol active in the client. The `protocol' is the
1674 protocol context. The `failure' is opaque pointer to the failure
1675 indication. Note, that the `failure' is protocol dependant and application
1676 must explicitly cast it to correct type. Usually `failure' is 32 bit
1677 failure type (see protocol specs for all protocol failure types). */
1679 void silc_failure(SilcClient client, SilcClientConnection conn,
1680 SilcProtocol protocol, void *failure)
1682 SILC_LOG_DEBUG(("Start"));
1684 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1685 SilcSKEStatus status = (SilcSKEStatus)failure;
1687 if (status == SILC_SKE_STATUS_BAD_VERSION)
1688 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1689 SILCTXT_KE_BAD_VERSION);
1690 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1691 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1692 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1693 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1694 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1695 SILCTXT_KE_UNKNOWN_GROUP);
1696 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1697 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1698 SILCTXT_KE_UNKNOWN_CIPHER);
1699 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1700 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1701 SILCTXT_KE_UNKNOWN_PKCS);
1702 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1703 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1704 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1705 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1706 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1707 SILCTXT_KE_UNKNOWN_HMAC);
1708 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1709 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1710 SILCTXT_KE_INCORRECT_SIGNATURE);
1711 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1712 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1713 SILCTXT_KE_INVALID_COOKIE);
1716 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1717 SilcUInt32 err = (SilcUInt32)failure;
1719 if (err == SILC_AUTH_FAILED)
1720 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1721 SILCTXT_AUTH_FAILED);
1725 /* Asks whether the user would like to perform the key agreement protocol.
1726 This is called after we have received an key agreement packet or an
1727 reply to our key agreement packet. This returns TRUE if the user wants
1728 the library to perform the key agreement protocol and FALSE if it is not
1729 desired (application may start it later by calling the function
1730 silc_client_perform_key_agreement). */
1732 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1733 SilcClientEntry client_entry, const char *hostname,
1734 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1739 SILC_LOG_DEBUG(("Start"));
1741 /* We will just display the info on the screen and return FALSE and user
1742 will have to start the key agreement with a command. */
1745 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1748 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1749 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1751 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1752 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1753 client_entry->nickname, hostname, portstr);
1761 void silc_ftp(SilcClient client, SilcClientConnection conn,
1762 SilcClientEntry client_entry, SilcUInt32 session_id,
1763 const char *hostname, SilcUInt16 port)
1765 SILC_SERVER_REC *server;
1767 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1769 SILC_LOG_DEBUG(("Start"));
1771 server = conn->context;
1773 ftp->client_entry = client_entry;
1774 ftp->session_id = session_id;
1777 silc_dlist_add(server->ftp_sessions, ftp);
1778 server->current_session = ftp;
1781 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1784 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1785 SILCTXT_FILE_REQUEST, client_entry->nickname);
1787 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1788 SILCTXT_FILE_REQUEST_HOST,
1789 client_entry->nickname, hostname, portstr);
1792 /* SILC client operations */
1793 SilcClientOperations ops = {
1795 silc_channel_message,
1796 silc_private_message,
1802 silc_get_auth_method,
1803 silc_verify_public_key,
1804 silc_ask_passphrase,