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 || server->connection_lost)
625 if (server->conn && server->conn->local_entry) {
626 nicklist_rename_unique(SERVER(server),
627 server->conn->local_entry, server->nick,
628 server->conn->local_entry,
629 silc_client->username);
630 silc_change_nick(server, silc_client->username);
633 server->conn->context = NULL;
635 server->connection_lost = TRUE;
636 server_disconnect(SERVER(server));
639 /* Command handler. This function is called always in the command function.
640 If error occurs it will be called as well. `conn' is the associated
641 client connection. `cmd_context' is the command context that was
642 originally sent to the command. `success' is FALSE if error occured
643 during command. `command' is the command being processed. It must be
644 noted that this is not reply from server. This is merely called just
645 after application has called the command. Just to tell application
646 that the command really was processed. */
648 void silc_command(SilcClient client, SilcClientConnection conn,
649 SilcClientCommandContext cmd_context, int success,
652 SILC_SERVER_REC *server = conn->context;
654 SILC_LOG_DEBUG(("Start"));
660 case SILC_COMMAND_INVITE:
661 printformat_module("fe-common/silc", server, NULL,
662 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
663 cmd_context->argv[2],
664 (cmd_context->argv[1][0] == '*' ?
665 (char *)conn->current_channel->channel_name :
666 (char *)cmd_context->argv[1]));
673 /* Client info resolving callback when JOIN command reply is received.
674 This will cache all users on the channel. */
676 static void silc_client_join_get_users(SilcClient client,
677 SilcClientConnection conn,
678 SilcClientEntry *clients,
679 SilcUInt32 clients_count,
682 SilcChannelEntry channel = (SilcChannelEntry)context;
683 SilcHashTableList htl;
685 SILC_SERVER_REC *server = conn->context;
686 SILC_CHANNEL_REC *chanrec;
687 SilcClientEntry founder = NULL;
693 chanrec = silc_channel_find(server, channel->channel_name);
697 silc_hash_table_list(channel->user_list, &htl);
698 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
699 if (!chu->client->nickname)
701 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
702 founder = chu->client;
703 silc_nicklist_insert(chanrec, chu, FALSE);
705 silc_hash_table_list_reset(&htl);
707 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
708 nicklist_set_own(CHANNEL(chanrec), ownnick);
709 signal_emit("channel joined", 1, chanrec);
712 printformat_module("fe-common/silc", server, channel->channel_name,
713 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
714 channel->channel_name, chanrec->topic);
716 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
719 if (founder == conn->local_entry)
720 printformat_module("fe-common/silc",
721 server, channel->channel_name, MSGLEVEL_CRAP,
722 SILCTXT_CHANNEL_FOUNDER_YOU,
723 channel->channel_name);
725 printformat_module("fe-common/silc",
726 server, channel->channel_name, MSGLEVEL_CRAP,
727 SILCTXT_CHANNEL_FOUNDER,
728 channel->channel_name, founder->nickname);
734 SilcClientConnection conn;
740 void silc_getkey_cb(bool success, void *context)
742 GetkeyContext getkey = (GetkeyContext)context;
743 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
744 char *name = (getkey->id_type == SILC_ID_CLIENT ?
745 ((SilcClientEntry)getkey->entry)->nickname :
746 ((SilcServerEntry)getkey->entry)->server_name);
749 printformat_module("fe-common/silc", NULL, NULL,
750 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
752 printformat_module("fe-common/silc", NULL, NULL,
753 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
756 silc_free(getkey->fingerprint);
760 /* Command reply handler. This function is called always in the command reply
761 function. If error occurs it will be called as well. Normal scenario
762 is that it will be called after the received command data has been parsed
763 and processed. The function is used to pass the received command data to
766 `conn' is the associated client connection. `cmd_payload' is the command
767 payload data received from server and it can be ignored. It is provided
768 if the application would like to re-parse the received command data,
769 however, it must be noted that the data is parsed already by the library
770 thus the payload can be ignored. `success' is FALSE if error occured.
771 In this case arguments are not sent to the application. `command' is the
772 command reply being processed. The function has variable argument list
773 and each command defines the number and type of arguments it passes to the
774 application (on error they are not sent). */
777 silc_command_reply(SilcClient client, SilcClientConnection conn,
778 SilcCommandPayload cmd_payload, int success,
779 SilcCommand command, SilcCommandStatus status, ...)
782 SILC_SERVER_REC *server = conn->context;
783 SILC_CHANNEL_REC *chanrec;
786 va_start(vp, status);
788 SILC_LOG_DEBUG(("Start"));
791 case SILC_COMMAND_WHOIS:
793 char buf[1024], *nickname, *username, *realname, *nick;
794 unsigned char *fingerprint;
795 SilcUInt32 idle, mode;
797 SilcClientEntry client_entry;
799 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
800 /* Print the unknown nick for user */
802 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
805 silc_say_error("%s: %s", tmp,
806 silc_client_command_status_message(status));
808 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
809 /* Try to find the entry for the unknown client ID, since we
810 might have, and print the nickname of it for user. */
813 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
816 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
819 client_entry = silc_client_get_client_by_id(client, conn,
821 if (client_entry && client_entry->nickname)
822 silc_say_error("%s: %s", client_entry->nickname,
823 silc_client_command_status_message(status));
824 silc_free(client_id);
833 client_entry = va_arg(vp, SilcClientEntry);
834 nickname = va_arg(vp, char *);
835 username = va_arg(vp, char *);
836 realname = va_arg(vp, char *);
837 channels = va_arg(vp, SilcBuffer);
838 mode = va_arg(vp, SilcUInt32);
839 idle = va_arg(vp, SilcUInt32);
840 fingerprint = va_arg(vp, unsigned char *);
842 silc_parse_userfqdn(nickname, &nick, NULL);
843 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
844 SILCTXT_WHOIS_USERINFO, nickname,
845 client_entry->username, client_entry->hostname,
846 nick, client_entry->nickname);
847 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
848 SILCTXT_WHOIS_REALNAME, realname);
852 SilcDList list = silc_channel_payload_parse_list(channels->data,
855 SilcChannelPayload entry;
856 memset(buf, 0, sizeof(buf));
857 silc_dlist_start(list);
858 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
859 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
861 char *name = silc_channel_get_name(entry, &name_len);
864 strncat(buf, m, strlen(m));
865 strncat(buf, name, name_len);
866 strncat(buf, " ", 1);
870 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
871 SILCTXT_WHOIS_CHANNELS, buf);
872 silc_channel_payload_list_free(list);
877 memset(buf, 0, sizeof(buf));
879 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
880 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
881 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
883 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
884 "SILC Operator " : "[Unknown mode] ");
886 if (mode & SILC_UMODE_GONE)
889 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
890 SILCTXT_WHOIS_MODES, buf);
893 if (idle && nickname) {
894 memset(buf, 0, sizeof(buf));
895 snprintf(buf, sizeof(buf) - 1, "%lu %s",
896 idle > 60 ? (idle / 60) : idle,
897 idle > 60 ? "minutes" : "seconds");
899 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
900 SILCTXT_WHOIS_IDLE, buf);
904 fingerprint = silc_fingerprint(fingerprint, 20);
905 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
906 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
907 silc_free(fingerprint);
912 case SILC_COMMAND_IDENTIFY:
914 SilcClientEntry client_entry;
916 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
917 /* Print the unknown nick for user */
919 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
922 silc_say_error("%s: %s", tmp,
923 silc_client_command_status_message(status));
925 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
926 /* Try to find the entry for the unknown client ID, since we
927 might have, and print the nickname of it for user. */
930 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
933 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
936 client_entry = silc_client_get_client_by_id(client, conn,
938 if (client_entry && client_entry->nickname)
939 silc_say_error("%s: %s", client_entry->nickname,
940 silc_client_command_status_message(status));
941 silc_free(client_id);
950 case SILC_COMMAND_WHOWAS:
952 char *nickname, *username, *realname;
954 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
955 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
957 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
960 silc_say_error("%s: %s", tmp,
961 silc_client_command_status_message(status));
968 (void)va_arg(vp, SilcClientEntry);
969 nickname = va_arg(vp, char *);
970 username = va_arg(vp, char *);
971 realname = va_arg(vp, char *);
973 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
974 SILCTXT_WHOWAS_USERINFO, nickname, username,
975 realname ? realname : "");
979 case SILC_COMMAND_INVITE:
981 SilcChannelEntry channel;
983 SilcArgumentPayload args;
989 channel = va_arg(vp, SilcChannelEntry);
990 invite_list = va_arg(vp, char *);
992 args = silc_command_get_args(cmd_payload);
994 argc = silc_argument_get_arg_num(args);
997 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
998 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1001 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1002 SILCTXT_CHANNEL_NO_INVITE_LIST,
1003 channel->channel_name);
1007 case SILC_COMMAND_JOIN:
1009 char *channel, *mode, *topic;
1011 SilcChannelEntry channel_entry;
1012 SilcBuffer client_id_list;
1013 SilcUInt32 list_count;
1018 channel = va_arg(vp, char *);
1019 channel_entry = va_arg(vp, SilcChannelEntry);
1020 modei = va_arg(vp, SilcUInt32);
1021 (void)va_arg(vp, SilcUInt32);
1022 (void)va_arg(vp, unsigned char *);
1023 (void)va_arg(vp, unsigned char *);
1024 (void)va_arg(vp, unsigned char *);
1025 topic = va_arg(vp, char *);
1026 (void)va_arg(vp, unsigned char *);
1027 list_count = va_arg(vp, SilcUInt32);
1028 client_id_list = va_arg(vp, SilcBuffer);
1030 chanrec = silc_channel_find(server, channel);
1032 chanrec = silc_channel_create(server, channel, TRUE);
1035 g_free_not_null(chanrec->topic);
1036 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1037 signal_emit("channel topic changed", 1, chanrec);
1040 mode = silc_client_chmode(modei,
1041 channel_entry->channel_key ?
1042 channel_entry->channel_key->cipher->name : "",
1043 channel_entry->hmac ?
1044 silc_hmac_get_name(channel_entry->hmac) : "");
1045 g_free_not_null(chanrec->mode);
1046 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1047 signal_emit("channel mode changed", 1, chanrec);
1049 /* Resolve the client information */
1050 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1051 silc_client_join_get_users,
1057 case SILC_COMMAND_NICK:
1059 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1065 old = g_strdup(server->nick);
1066 server_change_nick(SERVER(server), client->nickname);
1067 nicklist_rename_unique(SERVER(server),
1068 server->conn->local_entry, server->nick,
1069 client, client->nickname);
1070 signal_emit("message own_nick", 4, server, server->nick, old, "");
1075 case SILC_COMMAND_LIST:
1084 (void)va_arg(vp, SilcChannelEntry);
1085 name = va_arg(vp, char *);
1086 topic = va_arg(vp, char *);
1087 usercount = va_arg(vp, int);
1089 if (status == SILC_STATUS_LIST_START ||
1090 status == SILC_STATUS_OK)
1091 printformat_module("fe-common/silc", server, NULL,
1092 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1095 snprintf(users, sizeof(users) - 1, "N/A");
1097 snprintf(users, sizeof(users) - 1, "%d", usercount);
1098 printformat_module("fe-common/silc", server, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_LIST,
1100 name, users, topic ? topic : "");
1104 case SILC_COMMAND_UMODE:
1111 mode = va_arg(vp, SilcUInt32);
1113 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1114 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1115 printformat_module("fe-common/silc", server, NULL,
1116 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1118 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1119 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1120 printformat_module("fe-common/silc", server, NULL,
1121 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1123 server->umode = mode;
1124 signal_emit("user mode changed", 2, server, NULL);
1128 case SILC_COMMAND_OPER:
1132 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1133 signal_emit("user mode changed", 2, server, NULL);
1135 printformat_module("fe-common/silc", server, NULL,
1136 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1139 case SILC_COMMAND_SILCOPER:
1143 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1144 signal_emit("user mode changed", 2, server, NULL);
1146 printformat_module("fe-common/silc", server, NULL,
1147 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1150 case SILC_COMMAND_USERS:
1152 SilcHashTableList htl;
1153 SilcChannelEntry channel;
1154 SilcChannelUser chu;
1159 channel = va_arg(vp, SilcChannelEntry);
1161 printformat_module("fe-common/silc", server, channel->channel_name,
1162 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1163 channel->channel_name);
1165 silc_hash_table_list(channel->user_list, &htl);
1166 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1167 SilcClientEntry e = chu->client;
1168 char stat[5], *mode;
1173 memset(stat, 0, sizeof(stat));
1174 mode = silc_client_chumode_char(chu->mode);
1175 if (e->mode & SILC_UMODE_GONE)
1182 printformat_module("fe-common/silc", server, channel->channel_name,
1183 MSGLEVEL_CRAP, SILCTXT_USERS,
1185 e->username ? e->username : "",
1186 e->hostname ? e->hostname : "",
1187 e->realname ? e->realname : "");
1191 silc_hash_table_list_reset(&htl);
1195 case SILC_COMMAND_BAN:
1197 SilcChannelEntry channel;
1203 channel = va_arg(vp, SilcChannelEntry);
1204 ban_list = va_arg(vp, char *);
1207 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1208 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1211 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1212 SILCTXT_CHANNEL_NO_BAN_LIST,
1213 channel->channel_name);
1217 case SILC_COMMAND_GETKEY:
1221 SilcPublicKey public_key;
1224 GetkeyContext getkey;
1230 id_type = va_arg(vp, SilcUInt32);
1231 entry = va_arg(vp, void *);
1232 public_key = va_arg(vp, SilcPublicKey);
1235 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1237 getkey = silc_calloc(1, sizeof(*getkey));
1238 getkey->entry = entry;
1239 getkey->id_type = id_type;
1240 getkey->client = client;
1241 getkey->conn = conn;
1242 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1244 name = (id_type == SILC_ID_CLIENT ?
1245 ((SilcClientEntry)entry)->nickname :
1246 ((SilcServerEntry)entry)->server_name);
1248 silc_verify_public_key_internal(client, conn, name,
1249 (id_type == SILC_ID_CLIENT ?
1250 SILC_SOCKET_TYPE_CLIENT :
1251 SILC_SOCKET_TYPE_SERVER),
1252 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1253 silc_getkey_cb, getkey);
1256 printformat_module("fe-common/silc", server, NULL,
1257 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1262 case SILC_COMMAND_INFO:
1264 SilcServerEntry server_entry;
1271 server_entry = va_arg(vp, SilcServerEntry);
1272 server_name = va_arg(vp, char *);
1273 server_info = va_arg(vp, char *);
1275 if (server_name && server_info )
1277 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1278 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1283 case SILC_COMMAND_TOPIC:
1285 SilcChannelEntry channel;
1291 channel = va_arg(vp, SilcChannelEntry);
1292 topic = va_arg(vp, char *);
1295 chanrec = silc_channel_find_entry(server, channel);
1297 g_free_not_null(chanrec->topic);
1298 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1299 signal_emit("channel topic changed", 1, chanrec);
1301 printformat_module("fe-common/silc", server, channel->channel_name,
1302 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1303 channel->channel_name, topic);
1305 printformat_module("fe-common/silc", server, channel->channel_name,
1306 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1307 channel->channel_name);
1319 SilcClientConnection conn;
1325 SilcSKEPKType pk_type;
1326 SilcVerifyPublicKey completion;
1330 static void verify_public_key_completion(const char *line, void *context)
1332 PublicKeyVerify verify = (PublicKeyVerify)context;
1334 if (line[0] == 'Y' || line[0] == 'y') {
1335 /* Call the completion */
1336 if (verify->completion)
1337 verify->completion(TRUE, verify->context);
1339 /* Save the key for future checking */
1340 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1341 verify->pk_len, SILC_PKCS_FILE_PEM);
1343 /* Call the completion */
1344 if (verify->completion)
1345 verify->completion(FALSE, verify->context);
1347 printformat_module("fe-common/silc", NULL, NULL,
1348 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1349 verify->entity_name ? verify->entity_name :
1353 silc_free(verify->filename);
1354 silc_free(verify->entity);
1355 silc_free(verify->entity_name);
1356 silc_free(verify->pk);
1360 /* Internal routine to verify public key. If the `completion' is provided
1361 it will be called to indicate whether public was verified or not. For
1362 server/router public key this will check for filename that includes the
1363 remote host's IP address and remote host's hostname. */
1366 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1367 const char *name, SilcSocketType conn_type,
1368 unsigned char *pk, SilcUInt32 pk_len,
1369 SilcSKEPKType pk_type,
1370 SilcVerifyPublicKey completion, void *context)
1373 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1374 char *fingerprint, *babbleprint, *format;
1377 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1378 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1379 "server" : "client");
1380 PublicKeyVerify verify;
1382 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1383 printformat_module("fe-common/silc", NULL, NULL,
1384 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1387 completion(FALSE, context);
1391 pw = getpwuid(getuid());
1394 completion(FALSE, context);
1398 memset(filename, 0, sizeof(filename));
1399 memset(filename2, 0, sizeof(filename2));
1400 memset(file, 0, sizeof(file));
1402 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1403 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1405 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1406 conn->sock->ip, conn->sock->port);
1407 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1408 get_irssi_dir(), entity, file);
1410 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1411 conn->sock->hostname, conn->sock->port);
1412 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1413 get_irssi_dir(), entity, file);
1418 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1419 name, conn->sock->port);
1420 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1421 get_irssi_dir(), entity, file);
1426 /* Replace all whitespaces with `_'. */
1427 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1428 for (i = 0; i < strlen(fingerprint); i++)
1429 if (fingerprint[i] == ' ')
1430 fingerprint[i] = '_';
1432 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1433 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1434 get_irssi_dir(), entity, file);
1435 silc_free(fingerprint);
1440 /* Take fingerprint of the public key */
1441 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1442 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1444 verify = silc_calloc(1, sizeof(*verify));
1445 verify->client = client;
1446 verify->conn = conn;
1447 verify->filename = strdup(ipf);
1448 verify->entity = strdup(entity);
1449 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1450 (name ? strdup(name) : strdup(conn->sock->hostname))
1452 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1453 memcpy(verify->pk, pk, pk_len);
1454 verify->pk_len = pk_len;
1455 verify->pk_type = pk_type;
1456 verify->completion = completion;
1457 verify->context = context;
1459 /* Check whether this key already exists */
1460 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1461 /* Key does not exist, ask user to verify the key and save it */
1463 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1464 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1465 verify->entity_name : entity);
1466 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1467 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1468 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1469 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1470 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1471 SILCTXT_PUBKEY_ACCEPT);
1472 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1475 silc_free(fingerprint);
1478 /* The key already exists, verify it. */
1479 SilcPublicKey public_key;
1480 unsigned char *encpk;
1481 SilcUInt32 encpk_len;
1483 /* Load the key file, try for both IP filename and hostname filename */
1484 if (!silc_pkcs_load_public_key(ipf, &public_key,
1485 SILC_PKCS_FILE_PEM) &&
1486 !silc_pkcs_load_public_key(ipf, &public_key,
1487 SILC_PKCS_FILE_BIN) &&
1488 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1489 SILC_PKCS_FILE_PEM) &&
1490 !silc_pkcs_load_public_key(hostf, &public_key,
1491 SILC_PKCS_FILE_BIN)))) {
1492 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1493 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1494 verify->entity_name : entity);
1495 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1496 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1497 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1498 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1499 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1500 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1501 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1502 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1503 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1506 silc_free(fingerprint);
1510 /* Encode the key data */
1511 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1513 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1514 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1515 verify->entity_name : entity);
1516 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1517 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1518 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1519 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1520 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1521 SILCTXT_PUBKEY_MALFORMED, entity);
1522 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1523 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1524 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1527 silc_free(fingerprint);
1531 /* Compare the keys */
1532 if (memcmp(encpk, pk, encpk_len)) {
1533 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1534 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1535 verify->entity_name : entity);
1536 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1537 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1538 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1539 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1540 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1541 SILCTXT_PUBKEY_NO_MATCH, entity);
1542 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1543 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1544 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1545 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1547 /* Ask user to verify the key and save it */
1548 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1549 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1550 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1553 silc_free(fingerprint);
1557 /* Local copy matched */
1559 completion(TRUE, context);
1560 silc_free(fingerprint);
1564 /* Verifies received public key. The `conn_type' indicates which entity
1565 (server, client etc.) has sent the public key. If user decides to trust
1566 the key may be saved as trusted public key for later use. The
1567 `completion' must be called after the public key has been verified. */
1570 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1571 SilcSocketType conn_type, unsigned char *pk,
1572 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1573 SilcVerifyPublicKey completion, void *context)
1575 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1577 completion, context);
1580 /* Asks passphrase from user on the input line. */
1583 SilcAskPassphrase completion;
1587 void ask_passphrase_completion(const char *passphrase, void *context)
1589 AskPassphrase p = (AskPassphrase)context;
1590 p->completion((unsigned char *)passphrase,
1591 passphrase ? strlen(passphrase) : 0, p->context);
1595 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1596 SilcAskPassphrase completion, void *context)
1598 AskPassphrase p = silc_calloc(1, sizeof(*p));
1599 p->completion = completion;
1600 p->context = context;
1602 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1603 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1607 SilcGetAuthMeth completion;
1609 } *InternalGetAuthMethod;
1611 /* Callback called when we've received the authentication method information
1612 from the server after we've requested it. This will get the authentication
1613 data from the user if needed. */
1615 static void silc_get_auth_method_callback(SilcClient client,
1616 SilcClientConnection conn,
1617 SilcAuthMethod auth_meth,
1620 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1622 SILC_LOG_DEBUG(("Start"));
1624 switch (auth_meth) {
1625 case SILC_AUTH_NONE:
1626 /* No authentication required. */
1627 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1629 case SILC_AUTH_PASSWORD:
1630 /* Do not ask the passphrase from user, the library will ask it if
1631 we do not provide it here. */
1632 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1634 case SILC_AUTH_PUBLIC_KEY:
1635 /* Do not get the authentication data now, the library will generate
1636 it using our default key, if we do not provide it here. */
1637 /* XXX In the future when we support multiple local keys and multiple
1638 local certificates we will need to ask from user which one to use. */
1639 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1643 silc_free(internal);
1646 /* Find authentication method and authentication data by hostname and
1647 port. The hostname may be IP address as well. The found authentication
1648 method and authentication data is returned to `auth_meth', `auth_data'
1649 and `auth_data_len'. The function returns TRUE if authentication method
1650 is found and FALSE if not. `conn' may be NULL. */
1652 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1653 char *hostname, SilcUInt16 port,
1654 SilcGetAuthMeth completion, void *context)
1656 InternalGetAuthMethod internal;
1658 SILC_LOG_DEBUG(("Start"));
1660 /* XXX must resolve from configuration whether this connection has
1661 any specific authentication data */
1663 /* If we do not have this connection configured by the user in a
1664 configuration file then resolve the authentication method from the
1665 server for this session. */
1666 internal = silc_calloc(1, sizeof(*internal));
1667 internal->completion = completion;
1668 internal->context = context;
1670 silc_client_request_authentication_method(client, conn,
1671 silc_get_auth_method_callback,
1675 /* Notifies application that failure packet was received. This is called
1676 if there is some protocol active in the client. The `protocol' is the
1677 protocol context. The `failure' is opaque pointer to the failure
1678 indication. Note, that the `failure' is protocol dependant and application
1679 must explicitly cast it to correct type. Usually `failure' is 32 bit
1680 failure type (see protocol specs for all protocol failure types). */
1682 void silc_failure(SilcClient client, SilcClientConnection conn,
1683 SilcProtocol protocol, void *failure)
1685 SILC_LOG_DEBUG(("Start"));
1687 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1688 SilcSKEStatus status = (SilcSKEStatus)failure;
1690 if (status == SILC_SKE_STATUS_BAD_VERSION)
1691 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1692 SILCTXT_KE_BAD_VERSION);
1693 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1694 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1695 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1696 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1697 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1698 SILCTXT_KE_UNKNOWN_GROUP);
1699 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1700 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1701 SILCTXT_KE_UNKNOWN_CIPHER);
1702 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1703 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1704 SILCTXT_KE_UNKNOWN_PKCS);
1705 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1706 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1707 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1708 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1709 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1710 SILCTXT_KE_UNKNOWN_HMAC);
1711 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1712 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1713 SILCTXT_KE_INCORRECT_SIGNATURE);
1714 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1715 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1716 SILCTXT_KE_INVALID_COOKIE);
1719 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1720 SilcUInt32 err = (SilcUInt32)failure;
1722 if (err == SILC_AUTH_FAILED)
1723 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1724 SILCTXT_AUTH_FAILED);
1728 /* Asks whether the user would like to perform the key agreement protocol.
1729 This is called after we have received an key agreement packet or an
1730 reply to our key agreement packet. This returns TRUE if the user wants
1731 the library to perform the key agreement protocol and FALSE if it is not
1732 desired (application may start it later by calling the function
1733 silc_client_perform_key_agreement). */
1735 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1736 SilcClientEntry client_entry, const char *hostname,
1737 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1742 SILC_LOG_DEBUG(("Start"));
1744 /* We will just display the info on the screen and return FALSE and user
1745 will have to start the key agreement with a command. */
1748 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1751 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1752 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1754 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1755 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1756 client_entry->nickname, hostname, portstr);
1764 void silc_ftp(SilcClient client, SilcClientConnection conn,
1765 SilcClientEntry client_entry, SilcUInt32 session_id,
1766 const char *hostname, SilcUInt16 port)
1768 SILC_SERVER_REC *server;
1770 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1772 SILC_LOG_DEBUG(("Start"));
1774 server = conn->context;
1776 ftp->client_entry = client_entry;
1777 ftp->session_id = session_id;
1780 silc_dlist_add(server->ftp_sessions, ftp);
1781 server->current_session = ftp;
1784 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1787 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1788 SILCTXT_FILE_REQUEST, client_entry->nickname);
1790 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1791 SILCTXT_FILE_REQUEST_HOST,
1792 client_entry->nickname, hostname, portstr);
1795 /* SILC client operations */
1796 SilcClientOperations ops = {
1798 silc_channel_message,
1799 silc_private_message,
1805 silc_get_auth_method,
1806 silc_verify_public_key,
1807 silc_ask_passphrase,