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, const unsigned char *message,
85 SilcUInt32 message_len)
87 SILC_SERVER_REC *server;
89 SILC_CHANNEL_REC *chanrec;
91 SILC_LOG_DEBUG(("Start"));
96 server = conn == NULL ? NULL : conn->context;
97 chanrec = silc_channel_find_entry(server, channel);
101 nick = silc_nicklist_find(chanrec, sender);
103 /* We didn't find client but it clearly exists, add it. */
104 SilcChannelUser chu = silc_client_on_channel(channel, sender);
106 nick = silc_nicklist_insert(chanrec, chu, FALSE);
109 if (flags & SILC_MESSAGE_FLAG_ACTION)
110 printformat_module("fe-common/silc", server, channel->channel_name,
111 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
112 nick == NULL ? "[<unknown>]" : nick->nick, message);
113 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
114 printformat_module("fe-common/silc", server, channel->channel_name,
115 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
116 nick == NULL ? "[<unknown>]" : nick->nick, message);
118 signal_emit("message public", 6, server, message,
119 nick == NULL ? "[<unknown>]" : nick->nick,
120 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
121 chanrec->name, nick);
124 /* Private message to the client. The `sender' is the nickname of the
125 sender received in the packet. */
127 void silc_private_message(SilcClient client, SilcClientConnection conn,
128 SilcClientEntry sender, SilcMessageFlags flags,
129 const unsigned char *message,
130 SilcUInt32 message_len)
132 SILC_SERVER_REC *server;
135 SILC_LOG_DEBUG(("Start"));
137 server = conn == NULL ? NULL : conn->context;
138 memset(userhost, 0, sizeof(userhost));
139 if (sender->username)
140 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
141 sender->username, sender->hostname);
142 signal_emit("message private", 4, server, message,
143 sender->nickname ? sender->nickname : "[<unknown>]",
144 sender->username ? userhost : NULL);
147 /* Notify message to the client. The notify arguments are sent in the
148 same order as servers sends them. The arguments are same as received
149 from the server except for ID's. If ID is received application receives
150 the corresponding entry to the ID. For example, if Client ID is received
151 application receives SilcClientEntry. Also, if the notify type is
152 for channel the channel entry is sent to application (even if server
153 does not send it). */
155 void silc_notify(SilcClient client, SilcClientConnection conn,
156 SilcNotifyType type, ...)
159 SILC_SERVER_REC *server;
160 SILC_CHANNEL_REC *chanrec;
161 SILC_NICK_REC *nickrec;
162 SilcClientEntry client_entry, client_entry2;
163 SilcChannelEntry channel, channel2;
164 SilcServerEntry server_entry;
170 GSList *list1, *list_tmp;
172 SILC_LOG_DEBUG(("Start"));
176 server = conn == NULL ? NULL : conn->context;
179 case SILC_NOTIFY_TYPE_NONE:
180 /* Some generic notice from server */
181 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
184 case SILC_NOTIFY_TYPE_INVITE:
186 * Invited or modified invite list.
189 SILC_LOG_DEBUG(("Notify: INVITE"));
191 channel = va_arg(va, SilcChannelEntry);
192 name = va_arg(va, char *);
193 client_entry = va_arg(va, SilcClientEntry);
195 memset(userhost, 0, sizeof(userhost));
196 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
197 client_entry->username, client_entry->hostname);
198 signal_emit("message invite", 4, server, channel ? channel->channel_name :
199 name, client_entry->nickname, userhost);
202 case SILC_NOTIFY_TYPE_JOIN:
207 SILC_LOG_DEBUG(("Notify: JOIN"));
209 client_entry = va_arg(va, SilcClientEntry);
210 channel = va_arg(va, SilcChannelEntry);
212 if (client_entry == server->conn->local_entry) {
213 /* You joined to channel */
214 chanrec = silc_channel_find(server, channel->channel_name);
215 if (chanrec != NULL && !chanrec->joined)
216 chanrec->entry = channel;
218 chanrec = silc_channel_find_entry(server, channel);
219 if (chanrec != NULL) {
220 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
222 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
226 memset(userhost, 0, sizeof(userhost));
227 if (client_entry->username)
228 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
229 client_entry->username, client_entry->hostname);
230 signal_emit("message join", 4, server, channel->channel_name,
231 client_entry->nickname,
232 client_entry->username == NULL ? "" : userhost);
235 case SILC_NOTIFY_TYPE_LEAVE:
240 SILC_LOG_DEBUG(("Notify: LEAVE"));
242 client_entry = va_arg(va, SilcClientEntry);
243 channel = va_arg(va, SilcChannelEntry);
245 memset(userhost, 0, sizeof(userhost));
246 if (client_entry->username)
247 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
248 client_entry->username, client_entry->hostname);
249 signal_emit("message part", 5, server, channel->channel_name,
250 client_entry->nickname, client_entry->username ?
251 userhost : "", client_entry->nickname);
253 chanrec = silc_channel_find_entry(server, channel);
254 if (chanrec != NULL) {
255 nickrec = silc_nicklist_find(chanrec, client_entry);
257 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
261 case SILC_NOTIFY_TYPE_SIGNOFF:
266 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
268 client_entry = va_arg(va, SilcClientEntry);
269 tmp = va_arg(va, char *);
271 silc_server_free_ftp(server, client_entry);
273 memset(userhost, 0, sizeof(userhost));
274 if (client_entry->username)
275 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
276 client_entry->username, client_entry->hostname);
277 signal_emit("message quit", 4, server, client_entry->nickname,
278 client_entry->username ? userhost : "",
281 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
282 for (list_tmp = list1; list_tmp != NULL; list_tmp =
283 list_tmp->next->next) {
284 CHANNEL_REC *channel = list_tmp->data;
285 NICK_REC *nickrec = list_tmp->next->data;
287 nicklist_remove(channel, nickrec);
291 case SILC_NOTIFY_TYPE_TOPIC_SET:
296 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
298 idtype = va_arg(va, int);
299 entry = va_arg(va, void *);
300 tmp = va_arg(va, char *);
301 channel = va_arg(va, SilcChannelEntry);
303 chanrec = silc_channel_find_entry(server, channel);
304 if (chanrec != NULL) {
305 g_free_not_null(chanrec->topic);
306 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
307 signal_emit("channel topic changed", 1, chanrec);
310 if (idtype == SILC_ID_CLIENT) {
311 client_entry = (SilcClientEntry)entry;
312 memset(userhost, 0, sizeof(userhost));
313 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
314 client_entry->username, client_entry->hostname);
315 signal_emit("message topic", 5, server, channel->channel_name,
316 tmp, client_entry->nickname, userhost);
317 } else if (idtype == SILC_ID_SERVER) {
318 server_entry = (SilcServerEntry)entry;
319 signal_emit("message topic", 5, server, channel->channel_name,
320 tmp, server_entry->server_name,
321 server_entry->server_name);
323 channel = (SilcChannelEntry)entry;
324 signal_emit("message topic", 5, server, channel->channel_name,
325 tmp, channel->channel_name, channel->channel_name);
329 case SILC_NOTIFY_TYPE_NICK_CHANGE:
334 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
336 client_entry = va_arg(va, SilcClientEntry);
337 client_entry2 = va_arg(va, SilcClientEntry);
339 memset(userhost, 0, sizeof(userhost));
340 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
341 client_entry2->username, client_entry2->hostname);
342 nicklist_rename_unique(SERVER(server),
343 client_entry, client_entry->nickname,
344 client_entry2, client_entry2->nickname);
345 signal_emit("message nick", 4, server, client_entry2->nickname,
346 client_entry->nickname, userhost);
349 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
351 * Changed channel mode.
354 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
356 idtype = va_arg(va, int);
357 entry = va_arg(va, void *);
358 mode = va_arg(va, SilcUInt32);
359 (void)va_arg(va, char *);
360 (void)va_arg(va, char *);
361 channel = va_arg(va, SilcChannelEntry);
363 tmp = silc_client_chmode(mode,
364 channel->channel_key ?
365 channel->channel_key->cipher->name : "",
367 silc_hmac_get_name(channel->hmac) : "");
369 chanrec = silc_channel_find_entry(server, channel);
370 if (chanrec != NULL) {
371 g_free_not_null(chanrec->mode);
372 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
373 signal_emit("channel mode changed", 1, chanrec);
376 if (idtype == SILC_ID_CLIENT) {
377 client_entry = (SilcClientEntry)entry;
378 printformat_module("fe-common/silc", server, channel->channel_name,
379 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
380 channel->channel_name, tmp ? tmp : "removed all",
381 client_entry->nickname);
382 } else if (idtype == SILC_ID_SERVER) {
383 server_entry = (SilcServerEntry)entry;
384 printformat_module("fe-common/silc", server, channel->channel_name,
385 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
386 channel->channel_name, tmp ? tmp : "removed all",
387 server_entry->server_name);
389 channel2 = (SilcChannelEntry)entry;
390 printformat_module("fe-common/silc", server, channel->channel_name,
391 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
392 channel->channel_name, tmp ? tmp : "removed all",
393 channel2->channel_name);
399 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
401 * Changed user's mode on channel.
404 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
406 idtype = va_arg(va, int);
407 entry = va_arg(va, void *);
408 mode = va_arg(va, SilcUInt32);
409 client_entry2 = va_arg(va, SilcClientEntry);
410 channel = va_arg(va, SilcChannelEntry);
412 tmp = silc_client_chumode(mode);
413 chanrec = silc_channel_find_entry(server, channel);
414 if (chanrec != NULL) {
417 if (client_entry2 == server->conn->local_entry)
418 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
420 nick = silc_nicklist_find(chanrec, client_entry2);
422 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
423 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
424 signal_emit("nick mode changed", 2, chanrec, nick);
428 if (idtype == SILC_ID_CLIENT) {
429 client_entry = (SilcClientEntry)entry;
430 printformat_module("fe-common/silc", server, channel->channel_name,
431 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
432 channel->channel_name, client_entry2->nickname,
433 tmp ? tmp : "removed all",
434 client_entry->nickname);
435 } else if (idtype == SILC_ID_SERVER) {
436 server_entry = (SilcServerEntry)entry;
437 printformat_module("fe-common/silc", server, channel->channel_name,
438 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
439 channel->channel_name, client_entry2->nickname,
440 tmp ? tmp : "removed all",
441 server_entry->server_name);
443 channel2 = (SilcChannelEntry)entry;
444 printformat_module("fe-common/silc", server, channel->channel_name,
445 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
446 channel->channel_name, client_entry2->nickname,
447 tmp ? tmp : "removed all",
448 channel2->channel_name);
451 if (mode & SILC_CHANNEL_UMODE_CHANFO)
452 printformat_module("fe-common/silc",
453 server, channel->channel_name, MSGLEVEL_CRAP,
454 SILCTXT_CHANNEL_FOUNDER,
455 channel->channel_name, client_entry2->nickname);
460 case SILC_NOTIFY_TYPE_MOTD:
465 SILC_LOG_DEBUG(("Notify: MOTD"));
467 tmp = va_arg(va, char *);
469 if (!settings_get_bool("skip_motd"))
470 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
473 case SILC_NOTIFY_TYPE_KICKED:
475 * Someone was kicked from channel.
478 SILC_LOG_DEBUG(("Notify: KICKED"));
480 client_entry = va_arg(va, SilcClientEntry);
481 tmp = va_arg(va, char *);
482 client_entry2 = va_arg(va, SilcClientEntry);
483 channel = va_arg(va, SilcChannelEntry);
485 chanrec = silc_channel_find_entry(server, channel);
487 if (client_entry == conn->local_entry) {
488 printformat_module("fe-common/silc", server, channel->channel_name,
489 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
490 channel->channel_name,
491 client_entry ? client_entry2->nickname : "",
494 chanrec->kicked = TRUE;
495 channel_destroy((CHANNEL_REC *)chanrec);
498 printformat_module("fe-common/silc", server, channel->channel_name,
499 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
500 client_entry->nickname, channel->channel_name,
501 client_entry2 ? client_entry2->nickname : "",
505 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
507 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
512 case SILC_NOTIFY_TYPE_KILLED:
514 * Someone was killed from the network.
517 SILC_LOG_DEBUG(("Notify: KILLED"));
519 client_entry = va_arg(va, SilcClientEntry);
520 tmp = va_arg(va, char *);
521 client_entry2 = va_arg(va, SilcClientEntry);
523 if (client_entry == conn->local_entry) {
524 printformat_module("fe-common/silc", server, NULL,
525 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
526 client_entry2 ? client_entry2->nickname : "",
529 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
530 for (list_tmp = list1; list_tmp != NULL; list_tmp =
531 list_tmp->next->next) {
532 CHANNEL_REC *channel = list_tmp->data;
533 NICK_REC *nickrec = list_tmp->next->data;
534 nicklist_remove(channel, nickrec);
537 printformat_module("fe-common/silc", server, NULL,
538 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
539 client_entry->nickname,
540 client_entry2 ? client_entry2->nickname : "",
545 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
548 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
551 * Server has quit the network.
554 SilcClientEntry *clients;
555 SilcUInt32 clients_count;
557 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
559 (void)va_arg(va, void *);
560 clients = va_arg(va, SilcClientEntry *);
561 clients_count = va_arg(va, SilcUInt32);
563 for (i = 0; i < clients_count; i++) {
564 memset(userhost, 0, sizeof(userhost));
565 if (clients[i]->username)
566 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
567 clients[i]->username, clients[i]->hostname);
568 signal_emit("message quit", 4, server, clients[i]->nickname,
569 clients[i]->username ? userhost : "",
572 silc_server_free_ftp(server, clients[i]);
574 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
575 for (list_tmp = list1; list_tmp != NULL; list_tmp =
576 list_tmp->next->next) {
577 CHANNEL_REC *channel = list_tmp->data;
578 NICK_REC *nickrec = list_tmp->next->data;
579 nicklist_remove(channel, nickrec);
587 printformat_module("fe-common/silc", server, NULL,
588 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
595 /* Called to indicate that connection was either successfully established
596 or connecting failed. This is also the first time application receives
597 the SilcClientConnection object which it should save somewhere. */
599 void silc_connect(SilcClient client, SilcClientConnection conn, int success)
601 SILC_SERVER_REC *server = conn->context;
603 if (!server && !success) {
604 silc_client_close_connection(client, conn);
609 server->connected = TRUE;
610 signal_emit("event connected", 1, server);
612 server->connection_lost = TRUE;
614 server->conn->context = NULL;
615 server_disconnect(SERVER(server));
619 /* Called to indicate that connection was disconnected to the server. */
621 void silc_disconnect(SilcClient client, SilcClientConnection conn)
623 SILC_SERVER_REC *server = conn->context;
625 SILC_LOG_DEBUG(("Start"));
627 if (!server || server->connection_lost)
630 if (server->conn && server->conn->local_entry) {
631 nicklist_rename_unique(SERVER(server),
632 server->conn->local_entry, server->nick,
633 server->conn->local_entry,
634 silc_client->username);
635 silc_change_nick(server, silc_client->username);
638 server->conn->context = NULL;
640 server->connection_lost = TRUE;
641 server_disconnect(SERVER(server));
644 /* Command handler. This function is called always in the command function.
645 If error occurs it will be called as well. `conn' is the associated
646 client connection. `cmd_context' is the command context that was
647 originally sent to the command. `success' is FALSE if error occured
648 during command. `command' is the command being processed. It must be
649 noted that this is not reply from server. This is merely called just
650 after application has called the command. Just to tell application
651 that the command really was processed. */
653 void silc_command(SilcClient client, SilcClientConnection conn,
654 SilcClientCommandContext cmd_context, int success,
657 SILC_SERVER_REC *server = conn->context;
659 SILC_LOG_DEBUG(("Start"));
665 case SILC_COMMAND_INVITE:
666 printformat_module("fe-common/silc", server, NULL,
667 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
668 cmd_context->argv[2],
669 (cmd_context->argv[1][0] == '*' ?
670 (char *)conn->current_channel->channel_name :
671 (char *)cmd_context->argv[1]));
678 /* Client info resolving callback when JOIN command reply is received.
679 This will cache all users on the channel. */
681 static void silc_client_join_get_users(SilcClient client,
682 SilcClientConnection conn,
683 SilcClientEntry *clients,
684 SilcUInt32 clients_count,
687 SilcChannelEntry channel = (SilcChannelEntry)context;
688 SilcHashTableList htl;
690 SILC_SERVER_REC *server = conn->context;
691 SILC_CHANNEL_REC *chanrec;
692 SilcClientEntry founder = NULL;
698 chanrec = silc_channel_find(server, channel->channel_name);
702 silc_hash_table_list(channel->user_list, &htl);
703 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
704 if (!chu->client->nickname)
706 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
707 founder = chu->client;
708 silc_nicklist_insert(chanrec, chu, FALSE);
710 silc_hash_table_list_reset(&htl);
712 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
713 nicklist_set_own(CHANNEL(chanrec), ownnick);
714 signal_emit("channel joined", 1, chanrec);
717 printformat_module("fe-common/silc", server, channel->channel_name,
718 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
719 channel->channel_name, chanrec->topic);
721 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
724 if (founder == conn->local_entry)
725 printformat_module("fe-common/silc",
726 server, channel->channel_name, MSGLEVEL_CRAP,
727 SILCTXT_CHANNEL_FOUNDER_YOU,
728 channel->channel_name);
730 printformat_module("fe-common/silc",
731 server, channel->channel_name, MSGLEVEL_CRAP,
732 SILCTXT_CHANNEL_FOUNDER,
733 channel->channel_name, founder->nickname);
739 SilcClientConnection conn;
745 void silc_getkey_cb(bool success, void *context)
747 GetkeyContext getkey = (GetkeyContext)context;
748 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
749 char *name = (getkey->id_type == SILC_ID_CLIENT ?
750 ((SilcClientEntry)getkey->entry)->nickname :
751 ((SilcServerEntry)getkey->entry)->server_name);
754 printformat_module("fe-common/silc", NULL, NULL,
755 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
757 printformat_module("fe-common/silc", NULL, NULL,
758 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
761 silc_free(getkey->fingerprint);
765 /* Command reply handler. This function is called always in the command reply
766 function. If error occurs it will be called as well. Normal scenario
767 is that it will be called after the received command data has been parsed
768 and processed. The function is used to pass the received command data to
771 `conn' is the associated client connection. `cmd_payload' is the command
772 payload data received from server and it can be ignored. It is provided
773 if the application would like to re-parse the received command data,
774 however, it must be noted that the data is parsed already by the library
775 thus the payload can be ignored. `success' is FALSE if error occured.
776 In this case arguments are not sent to the application. `command' is the
777 command reply being processed. The function has variable argument list
778 and each command defines the number and type of arguments it passes to the
779 application (on error they are not sent). */
782 silc_command_reply(SilcClient client, SilcClientConnection conn,
783 SilcCommandPayload cmd_payload, int success,
784 SilcCommand command, SilcCommandStatus status, ...)
787 SILC_SERVER_REC *server = conn->context;
788 SILC_CHANNEL_REC *chanrec;
791 va_start(vp, status);
793 SILC_LOG_DEBUG(("Start"));
796 case SILC_COMMAND_WHOIS:
798 char buf[1024], *nickname, *username, *realname, *nick;
799 unsigned char *fingerprint;
800 SilcUInt32 idle, mode;
802 SilcClientEntry client_entry;
804 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
805 /* Print the unknown nick for user */
807 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
810 silc_say_error("%s: %s", tmp,
811 silc_client_command_status_message(status));
813 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
814 /* Try to find the entry for the unknown client ID, since we
815 might have, and print the nickname of it for user. */
818 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
821 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
824 client_entry = silc_client_get_client_by_id(client, conn,
826 if (client_entry && client_entry->nickname)
827 silc_say_error("%s: %s", client_entry->nickname,
828 silc_client_command_status_message(status));
829 silc_free(client_id);
838 client_entry = va_arg(vp, SilcClientEntry);
839 nickname = va_arg(vp, char *);
840 username = va_arg(vp, char *);
841 realname = va_arg(vp, char *);
842 channels = va_arg(vp, SilcBuffer);
843 mode = va_arg(vp, SilcUInt32);
844 idle = va_arg(vp, SilcUInt32);
845 fingerprint = va_arg(vp, unsigned char *);
847 silc_parse_userfqdn(nickname, &nick, NULL);
848 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
849 SILCTXT_WHOIS_USERINFO, nickname,
850 client_entry->username, client_entry->hostname,
851 nick, client_entry->nickname);
852 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
853 SILCTXT_WHOIS_REALNAME, realname);
857 SilcDList list = silc_channel_payload_parse_list(channels->data,
860 SilcChannelPayload entry;
861 memset(buf, 0, sizeof(buf));
862 silc_dlist_start(list);
863 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
864 char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
866 char *name = silc_channel_get_name(entry, &name_len);
869 strncat(buf, m, strlen(m));
870 strncat(buf, name, name_len);
871 strncat(buf, " ", 1);
875 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
876 SILCTXT_WHOIS_CHANNELS, buf);
877 silc_channel_payload_list_free(list);
882 memset(buf, 0, sizeof(buf));
884 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
885 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
886 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
888 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
889 "SILC Operator" : "[Unknown mode]");
891 if (mode & SILC_UMODE_GONE)
892 strcat(buf, " away");
893 if (mode & SILC_UMODE_INDISPOSED)
894 strcat(buf, " indisposed");
895 if (mode & SILC_UMODE_BUSY)
896 strcat(buf, " busy");
897 if (mode & SILC_UMODE_PAGE)
898 strcat(buf, " page to reach");
899 if (mode & SILC_UMODE_HYPER)
900 strcat(buf, " hyper active");
901 if (mode & SILC_UMODE_ROBOT)
902 strcat(buf, " robot");
903 if (mode & SILC_UMODE_ANONYMOUS)
904 strcat(buf, " anonymous");
905 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
906 strcat(buf, " blocks private messages");
908 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
909 SILCTXT_WHOIS_MODES, buf);
912 if (idle && nickname) {
913 memset(buf, 0, sizeof(buf));
914 snprintf(buf, sizeof(buf) - 1, "%lu %s",
915 idle > 60 ? (idle / 60) : idle,
916 idle > 60 ? "minutes" : "seconds");
918 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
919 SILCTXT_WHOIS_IDLE, buf);
923 fingerprint = silc_fingerprint(fingerprint, 20);
924 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
925 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
926 silc_free(fingerprint);
931 case SILC_COMMAND_IDENTIFY:
933 SilcClientEntry client_entry;
935 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
936 /* Print the unknown nick for user */
938 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
941 silc_say_error("%s: %s", tmp,
942 silc_client_command_status_message(status));
944 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
945 /* Try to find the entry for the unknown client ID, since we
946 might have, and print the nickname of it for user. */
949 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
952 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
955 client_entry = silc_client_get_client_by_id(client, conn,
957 if (client_entry && client_entry->nickname)
958 silc_say_error("%s: %s", client_entry->nickname,
959 silc_client_command_status_message(status));
960 silc_free(client_id);
969 case SILC_COMMAND_WHOWAS:
971 char *nickname, *username, *realname;
973 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
974 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
976 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
979 silc_say_error("%s: %s", tmp,
980 silc_client_command_status_message(status));
987 (void)va_arg(vp, SilcClientEntry);
988 nickname = va_arg(vp, char *);
989 username = va_arg(vp, char *);
990 realname = va_arg(vp, char *);
992 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
993 SILCTXT_WHOWAS_USERINFO, nickname, username,
994 realname ? realname : "");
998 case SILC_COMMAND_INVITE:
1000 SilcChannelEntry channel;
1002 SilcArgumentPayload args;
1008 channel = va_arg(vp, SilcChannelEntry);
1009 invite_list = va_arg(vp, char *);
1011 args = silc_command_get_args(cmd_payload);
1013 argc = silc_argument_get_arg_num(args);
1016 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1017 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1020 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1021 SILCTXT_CHANNEL_NO_INVITE_LIST,
1022 channel->channel_name);
1026 case SILC_COMMAND_JOIN:
1028 char *channel, *mode, *topic;
1030 SilcChannelEntry channel_entry;
1031 SilcBuffer client_id_list;
1032 SilcUInt32 list_count;
1037 channel = va_arg(vp, char *);
1038 channel_entry = va_arg(vp, SilcChannelEntry);
1039 modei = va_arg(vp, SilcUInt32);
1040 (void)va_arg(vp, SilcUInt32);
1041 (void)va_arg(vp, unsigned char *);
1042 (void)va_arg(vp, unsigned char *);
1043 (void)va_arg(vp, unsigned char *);
1044 topic = va_arg(vp, char *);
1045 (void)va_arg(vp, unsigned char *);
1046 list_count = va_arg(vp, SilcUInt32);
1047 client_id_list = va_arg(vp, SilcBuffer);
1049 chanrec = silc_channel_find(server, channel);
1051 chanrec = silc_channel_create(server, channel, TRUE);
1054 g_free_not_null(chanrec->topic);
1055 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1056 signal_emit("channel topic changed", 1, chanrec);
1059 mode = silc_client_chmode(modei,
1060 channel_entry->channel_key ?
1061 channel_entry->channel_key->cipher->name : "",
1062 channel_entry->hmac ?
1063 silc_hmac_get_name(channel_entry->hmac) : "");
1064 g_free_not_null(chanrec->mode);
1065 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1066 signal_emit("channel mode changed", 1, chanrec);
1068 /* Resolve the client information */
1069 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1070 silc_client_join_get_users,
1076 case SILC_COMMAND_NICK:
1078 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1084 old = g_strdup(server->nick);
1085 server_change_nick(SERVER(server), client->nickname);
1086 nicklist_rename_unique(SERVER(server),
1087 server->conn->local_entry, server->nick,
1088 client, client->nickname);
1089 signal_emit("message own_nick", 4, server, server->nick, old, "");
1094 case SILC_COMMAND_LIST:
1103 (void)va_arg(vp, SilcChannelEntry);
1104 name = va_arg(vp, char *);
1105 topic = va_arg(vp, char *);
1106 usercount = va_arg(vp, int);
1108 if (status == SILC_STATUS_LIST_START ||
1109 status == SILC_STATUS_OK)
1110 printformat_module("fe-common/silc", server, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1114 snprintf(users, sizeof(users) - 1, "N/A");
1116 snprintf(users, sizeof(users) - 1, "%d", usercount);
1117 printformat_module("fe-common/silc", server, NULL,
1118 MSGLEVEL_CRAP, SILCTXT_LIST,
1119 name, users, topic ? topic : "");
1123 case SILC_COMMAND_UMODE:
1130 mode = va_arg(vp, SilcUInt32);
1132 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1133 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1134 printformat_module("fe-common/silc", server, NULL,
1135 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1137 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1138 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1139 printformat_module("fe-common/silc", server, NULL,
1140 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1142 server->umode = mode;
1143 signal_emit("user mode changed", 2, server, NULL);
1147 case SILC_COMMAND_OPER:
1151 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1152 signal_emit("user mode changed", 2, server, NULL);
1154 printformat_module("fe-common/silc", server, NULL,
1155 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1158 case SILC_COMMAND_SILCOPER:
1162 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1163 signal_emit("user mode changed", 2, server, NULL);
1165 printformat_module("fe-common/silc", server, NULL,
1166 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1169 case SILC_COMMAND_USERS:
1171 SilcHashTableList htl;
1172 SilcChannelEntry channel;
1173 SilcChannelUser chu;
1178 channel = va_arg(vp, SilcChannelEntry);
1180 printformat_module("fe-common/silc", server, channel->channel_name,
1181 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1182 channel->channel_name);
1184 silc_hash_table_list(channel->user_list, &htl);
1185 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1186 SilcClientEntry e = chu->client;
1187 char stat[5], *mode;
1192 memset(stat, 0, sizeof(stat));
1193 mode = silc_client_chumode_char(chu->mode);
1194 if (e->mode & SILC_UMODE_GONE)
1196 else if (e->mode & SILC_UMODE_INDISPOSED)
1198 else if (e->mode & SILC_UMODE_BUSY)
1200 else if (e->mode & SILC_UMODE_PAGE)
1202 else if (e->mode & SILC_UMODE_HYPER)
1204 else if (e->mode & SILC_UMODE_ROBOT)
1206 else if (e->mode & SILC_UMODE_ANONYMOUS)
1213 printformat_module("fe-common/silc", server, channel->channel_name,
1214 MSGLEVEL_CRAP, SILCTXT_USERS,
1216 e->username ? e->username : "",
1217 e->hostname ? e->hostname : "",
1218 e->realname ? e->realname : "");
1222 silc_hash_table_list_reset(&htl);
1226 case SILC_COMMAND_BAN:
1228 SilcChannelEntry channel;
1234 channel = va_arg(vp, SilcChannelEntry);
1235 ban_list = va_arg(vp, char *);
1238 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1239 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1242 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1243 SILCTXT_CHANNEL_NO_BAN_LIST,
1244 channel->channel_name);
1248 case SILC_COMMAND_GETKEY:
1252 SilcPublicKey public_key;
1255 GetkeyContext getkey;
1261 id_type = va_arg(vp, SilcUInt32);
1262 entry = va_arg(vp, void *);
1263 public_key = va_arg(vp, SilcPublicKey);
1266 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1268 getkey = silc_calloc(1, sizeof(*getkey));
1269 getkey->entry = entry;
1270 getkey->id_type = id_type;
1271 getkey->client = client;
1272 getkey->conn = conn;
1273 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1275 name = (id_type == SILC_ID_CLIENT ?
1276 ((SilcClientEntry)entry)->nickname :
1277 ((SilcServerEntry)entry)->server_name);
1279 silc_verify_public_key_internal(client, conn, name,
1280 (id_type == SILC_ID_CLIENT ?
1281 SILC_SOCKET_TYPE_CLIENT :
1282 SILC_SOCKET_TYPE_SERVER),
1283 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1284 silc_getkey_cb, getkey);
1287 printformat_module("fe-common/silc", server, NULL,
1288 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1293 case SILC_COMMAND_INFO:
1295 SilcServerEntry server_entry;
1302 server_entry = va_arg(vp, SilcServerEntry);
1303 server_name = va_arg(vp, char *);
1304 server_info = va_arg(vp, char *);
1306 if (server_name && server_info )
1308 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1309 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1314 case SILC_COMMAND_TOPIC:
1316 SilcChannelEntry channel;
1322 channel = va_arg(vp, SilcChannelEntry);
1323 topic = va_arg(vp, char *);
1326 chanrec = silc_channel_find_entry(server, channel);
1328 g_free_not_null(chanrec->topic);
1329 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1330 signal_emit("channel topic changed", 1, chanrec);
1332 printformat_module("fe-common/silc", server, channel->channel_name,
1333 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1334 channel->channel_name, topic);
1336 printformat_module("fe-common/silc", server, channel->channel_name,
1337 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1338 channel->channel_name);
1350 SilcClientConnection conn;
1356 SilcSKEPKType pk_type;
1357 SilcVerifyPublicKey completion;
1361 static void verify_public_key_completion(const char *line, void *context)
1363 PublicKeyVerify verify = (PublicKeyVerify)context;
1365 if (line[0] == 'Y' || line[0] == 'y') {
1366 /* Call the completion */
1367 if (verify->completion)
1368 verify->completion(TRUE, verify->context);
1370 /* Save the key for future checking */
1371 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1372 verify->pk_len, SILC_PKCS_FILE_PEM);
1374 /* Call the completion */
1375 if (verify->completion)
1376 verify->completion(FALSE, verify->context);
1378 printformat_module("fe-common/silc", NULL, NULL,
1379 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1380 verify->entity_name ? verify->entity_name :
1384 silc_free(verify->filename);
1385 silc_free(verify->entity);
1386 silc_free(verify->entity_name);
1387 silc_free(verify->pk);
1391 /* Internal routine to verify public key. If the `completion' is provided
1392 it will be called to indicate whether public was verified or not. For
1393 server/router public key this will check for filename that includes the
1394 remote host's IP address and remote host's hostname. */
1397 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1398 const char *name, SilcSocketType conn_type,
1399 unsigned char *pk, SilcUInt32 pk_len,
1400 SilcSKEPKType pk_type,
1401 SilcVerifyPublicKey completion, void *context)
1404 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1405 char *fingerprint, *babbleprint, *format;
1408 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1409 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1410 "server" : "client");
1411 PublicKeyVerify verify;
1413 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1414 printformat_module("fe-common/silc", NULL, NULL,
1415 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1418 completion(FALSE, context);
1422 pw = getpwuid(getuid());
1425 completion(FALSE, context);
1429 memset(filename, 0, sizeof(filename));
1430 memset(filename2, 0, sizeof(filename2));
1431 memset(file, 0, sizeof(file));
1433 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1434 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1436 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1437 conn->sock->ip, conn->sock->port);
1438 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1439 get_irssi_dir(), entity, file);
1441 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1442 conn->sock->hostname, conn->sock->port);
1443 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1444 get_irssi_dir(), entity, file);
1449 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1450 name, conn->sock->port);
1451 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1452 get_irssi_dir(), entity, file);
1457 /* Replace all whitespaces with `_'. */
1458 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1459 for (i = 0; i < strlen(fingerprint); i++)
1460 if (fingerprint[i] == ' ')
1461 fingerprint[i] = '_';
1463 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1464 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1465 get_irssi_dir(), entity, file);
1466 silc_free(fingerprint);
1471 /* Take fingerprint of the public key */
1472 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1473 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1475 verify = silc_calloc(1, sizeof(*verify));
1476 verify->client = client;
1477 verify->conn = conn;
1478 verify->filename = strdup(ipf);
1479 verify->entity = strdup(entity);
1480 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1481 (name ? strdup(name) : strdup(conn->sock->hostname))
1483 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1484 memcpy(verify->pk, pk, pk_len);
1485 verify->pk_len = pk_len;
1486 verify->pk_type = pk_type;
1487 verify->completion = completion;
1488 verify->context = context;
1490 /* Check whether this key already exists */
1491 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1492 /* Key does not exist, ask user to verify the key and save it */
1494 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1495 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1496 verify->entity_name : entity);
1497 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1498 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1499 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1500 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1501 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1502 SILCTXT_PUBKEY_ACCEPT);
1503 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1506 silc_free(fingerprint);
1509 /* The key already exists, verify it. */
1510 SilcPublicKey public_key;
1511 unsigned char *encpk;
1512 SilcUInt32 encpk_len;
1514 /* Load the key file, try for both IP filename and hostname filename */
1515 if (!silc_pkcs_load_public_key(ipf, &public_key,
1516 SILC_PKCS_FILE_PEM) &&
1517 !silc_pkcs_load_public_key(ipf, &public_key,
1518 SILC_PKCS_FILE_BIN) &&
1519 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1520 SILC_PKCS_FILE_PEM) &&
1521 !silc_pkcs_load_public_key(hostf, &public_key,
1522 SILC_PKCS_FILE_BIN)))) {
1523 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1524 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1525 verify->entity_name : entity);
1526 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1527 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1528 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1529 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1530 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1531 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1532 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1533 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1534 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1537 silc_free(fingerprint);
1541 /* Encode the key data */
1542 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1544 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1545 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1546 verify->entity_name : entity);
1547 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1548 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1549 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1550 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1551 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1552 SILCTXT_PUBKEY_MALFORMED, entity);
1553 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1554 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1555 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1558 silc_free(fingerprint);
1562 /* Compare the keys */
1563 if (memcmp(encpk, pk, encpk_len)) {
1564 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1565 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1566 verify->entity_name : entity);
1567 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1568 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1569 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1570 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1571 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1572 SILCTXT_PUBKEY_NO_MATCH, entity);
1573 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1574 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1575 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1576 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1578 /* Ask user to verify the key and save it */
1579 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1580 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1581 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1584 silc_free(fingerprint);
1588 /* Local copy matched */
1590 completion(TRUE, context);
1591 silc_free(fingerprint);
1595 /* Verifies received public key. The `conn_type' indicates which entity
1596 (server, client etc.) has sent the public key. If user decides to trust
1597 the key may be saved as trusted public key for later use. The
1598 `completion' must be called after the public key has been verified. */
1601 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1602 SilcSocketType conn_type, unsigned char *pk,
1603 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1604 SilcVerifyPublicKey completion, void *context)
1606 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1608 completion, context);
1611 /* Asks passphrase from user on the input line. */
1614 SilcAskPassphrase completion;
1618 void ask_passphrase_completion(const char *passphrase, void *context)
1620 AskPassphrase p = (AskPassphrase)context;
1621 p->completion((unsigned char *)passphrase,
1622 passphrase ? strlen(passphrase) : 0, p->context);
1626 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1627 SilcAskPassphrase completion, void *context)
1629 AskPassphrase p = silc_calloc(1, sizeof(*p));
1630 p->completion = completion;
1631 p->context = context;
1633 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1634 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1638 SilcGetAuthMeth completion;
1640 } *InternalGetAuthMethod;
1642 /* Callback called when we've received the authentication method information
1643 from the server after we've requested it. This will get the authentication
1644 data from the user if needed. */
1646 static void silc_get_auth_method_callback(SilcClient client,
1647 SilcClientConnection conn,
1648 SilcAuthMethod auth_meth,
1651 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1653 SILC_LOG_DEBUG(("Start"));
1655 switch (auth_meth) {
1656 case SILC_AUTH_NONE:
1657 /* No authentication required. */
1658 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1660 case SILC_AUTH_PASSWORD:
1661 /* Do not ask the passphrase from user, the library will ask it if
1662 we do not provide it here. */
1663 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1665 case SILC_AUTH_PUBLIC_KEY:
1666 /* Do not get the authentication data now, the library will generate
1667 it using our default key, if we do not provide it here. */
1668 /* XXX In the future when we support multiple local keys and multiple
1669 local certificates we will need to ask from user which one to use. */
1670 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1674 silc_free(internal);
1677 /* Find authentication method and authentication data by hostname and
1678 port. The hostname may be IP address as well. The found authentication
1679 method and authentication data is returned to `auth_meth', `auth_data'
1680 and `auth_data_len'. The function returns TRUE if authentication method
1681 is found and FALSE if not. `conn' may be NULL. */
1683 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1684 char *hostname, SilcUInt16 port,
1685 SilcGetAuthMeth completion, void *context)
1687 InternalGetAuthMethod internal;
1689 SILC_LOG_DEBUG(("Start"));
1691 /* XXX must resolve from configuration whether this connection has
1692 any specific authentication data */
1694 /* If we do not have this connection configured by the user in a
1695 configuration file then resolve the authentication method from the
1696 server for this session. */
1697 internal = silc_calloc(1, sizeof(*internal));
1698 internal->completion = completion;
1699 internal->context = context;
1701 silc_client_request_authentication_method(client, conn,
1702 silc_get_auth_method_callback,
1706 /* Notifies application that failure packet was received. This is called
1707 if there is some protocol active in the client. The `protocol' is the
1708 protocol context. The `failure' is opaque pointer to the failure
1709 indication. Note, that the `failure' is protocol dependant and application
1710 must explicitly cast it to correct type. Usually `failure' is 32 bit
1711 failure type (see protocol specs for all protocol failure types). */
1713 void silc_failure(SilcClient client, SilcClientConnection conn,
1714 SilcProtocol protocol, void *failure)
1716 SILC_LOG_DEBUG(("Start"));
1718 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1719 SilcSKEStatus status = (SilcSKEStatus)failure;
1721 if (status == SILC_SKE_STATUS_BAD_VERSION)
1722 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1723 SILCTXT_KE_BAD_VERSION);
1724 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1725 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1726 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1727 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1728 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1729 SILCTXT_KE_UNKNOWN_GROUP);
1730 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1731 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1732 SILCTXT_KE_UNKNOWN_CIPHER);
1733 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1734 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1735 SILCTXT_KE_UNKNOWN_PKCS);
1736 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1737 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1738 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1739 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1740 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1741 SILCTXT_KE_UNKNOWN_HMAC);
1742 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1743 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1744 SILCTXT_KE_INCORRECT_SIGNATURE);
1745 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1746 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1747 SILCTXT_KE_INVALID_COOKIE);
1750 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1751 SilcUInt32 err = (SilcUInt32)failure;
1753 if (err == SILC_AUTH_FAILED)
1754 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1755 SILCTXT_AUTH_FAILED);
1759 /* Asks whether the user would like to perform the key agreement protocol.
1760 This is called after we have received an key agreement packet or an
1761 reply to our key agreement packet. This returns TRUE if the user wants
1762 the library to perform the key agreement protocol and FALSE if it is not
1763 desired (application may start it later by calling the function
1764 silc_client_perform_key_agreement). */
1766 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1767 SilcClientEntry client_entry, const char *hostname,
1768 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1773 SILC_LOG_DEBUG(("Start"));
1775 /* We will just display the info on the screen and return FALSE and user
1776 will have to start the key agreement with a command. */
1779 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1782 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1783 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1785 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1786 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1787 client_entry->nickname, hostname, portstr);
1795 /* Notifies application that file transfer protocol session is being
1796 requested by the remote client indicated by the `client_entry' from
1797 the `hostname' and `port'. The `session_id' is the file transfer
1798 session and it can be used to either accept or reject the file
1799 transfer request, by calling the silc_client_file_receive or
1800 silc_client_file_close, respectively. */
1802 void silc_ftp(SilcClient client, SilcClientConnection conn,
1803 SilcClientEntry client_entry, SilcUInt32 session_id,
1804 const char *hostname, SilcUInt16 port)
1806 SILC_SERVER_REC *server;
1808 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1810 SILC_LOG_DEBUG(("Start"));
1812 server = conn->context;
1814 ftp->client_entry = client_entry;
1815 ftp->session_id = session_id;
1818 silc_dlist_add(server->ftp_sessions, ftp);
1819 server->current_session = ftp;
1822 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1825 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1826 SILCTXT_FILE_REQUEST, client_entry->nickname);
1828 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1829 SILCTXT_FILE_REQUEST_HOST,
1830 client_entry->nickname, hostname, portstr);
1833 /* Delivers SILC session detachment data indicated by `detach_data' to the
1834 application. If application has issued SILC_COMMAND_DETACH command
1835 the client session in the SILC network is not quit. The client remains
1836 in the network but is detached. The detachment data may be used later
1837 to resume the session in the SILC Network. The appliation is
1838 responsible of saving the `detach_data', to for example in a file.
1840 The detachment data can be given as argument to the functions
1841 silc_client_connect_to_server, or silc_client_add_connection when
1842 creating connection to remote server, inside SilcClientConnectionParams
1843 structure. If it is provided the client library will attempt to resume
1844 the session in the network. After the connection is created
1845 successfully, the application is responsible of setting the user
1846 interface for user into the same state it was before detaching (showing
1847 same channels, channel modes, etc). It can do this by fetching the
1848 information (like joined channels) from the client library. */
1851 silc_detach(SilcClient client, SilcClientConnection conn,
1852 const unsigned char *detach_data, SilcUInt32 detach_data_len)
1858 /* SILC client operations */
1859 SilcClientOperations ops = {
1861 silc_channel_message,
1862 silc_private_message,
1868 silc_get_auth_method,
1869 silc_verify_public_key,
1870 silc_ask_passphrase,