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);
322 } else if (idtype == SILC_ID_CHANNEL) {
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 if (!strcmp(client_entry->nickname, client_entry2->nickname))
342 memset(userhost, 0, sizeof(userhost));
343 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
344 client_entry2->username, client_entry2->hostname);
345 nicklist_rename_unique(SERVER(server),
346 client_entry, client_entry->nickname,
347 client_entry2, client_entry2->nickname);
348 signal_emit("message nick", 4, server, client_entry2->nickname,
349 client_entry->nickname, userhost);
352 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
354 * Changed channel mode.
357 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
359 idtype = va_arg(va, int);
360 entry = va_arg(va, void *);
361 mode = va_arg(va, SilcUInt32);
362 (void)va_arg(va, char *);
363 (void)va_arg(va, char *);
364 channel = va_arg(va, SilcChannelEntry);
366 tmp = silc_client_chmode(mode,
367 channel->channel_key ?
368 channel->channel_key->cipher->name : "",
370 silc_hmac_get_name(channel->hmac) : "");
372 chanrec = silc_channel_find_entry(server, channel);
373 if (chanrec != NULL) {
374 g_free_not_null(chanrec->mode);
375 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
376 signal_emit("channel mode changed", 1, chanrec);
379 if (idtype == SILC_ID_CLIENT) {
380 client_entry = (SilcClientEntry)entry;
381 printformat_module("fe-common/silc", server, channel->channel_name,
382 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
383 channel->channel_name, tmp ? tmp : "removed all",
384 client_entry->nickname);
385 } else if (idtype == SILC_ID_SERVER) {
386 server_entry = (SilcServerEntry)entry;
387 printformat_module("fe-common/silc", server, channel->channel_name,
388 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
389 channel->channel_name, tmp ? tmp : "removed all",
390 server_entry->server_name);
391 } else if (idtype == SILC_ID_CHANNEL) {
392 channel2 = (SilcChannelEntry)entry;
393 printformat_module("fe-common/silc", server, channel->channel_name,
394 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
395 channel->channel_name, tmp ? tmp : "removed all",
396 channel2->channel_name);
402 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
404 * Changed user's mode on channel.
407 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
409 idtype = va_arg(va, int);
410 entry = va_arg(va, void *);
411 mode = va_arg(va, SilcUInt32);
412 client_entry2 = va_arg(va, SilcClientEntry);
413 channel = va_arg(va, SilcChannelEntry);
415 tmp = silc_client_chumode(mode);
416 chanrec = silc_channel_find_entry(server, channel);
417 if (chanrec != NULL) {
420 if (client_entry2 == server->conn->local_entry)
421 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
423 nick = silc_nicklist_find(chanrec, client_entry2);
425 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
426 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
427 signal_emit("nick mode changed", 2, chanrec, nick);
431 if (idtype == SILC_ID_CLIENT) {
432 client_entry = (SilcClientEntry)entry;
433 printformat_module("fe-common/silc", server, channel->channel_name,
434 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
435 channel->channel_name, client_entry2->nickname,
436 tmp ? tmp : "removed all",
437 client_entry->nickname);
438 } else if (idtype == SILC_ID_SERVER) {
439 server_entry = (SilcServerEntry)entry;
440 printformat_module("fe-common/silc", server, channel->channel_name,
441 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
442 channel->channel_name, client_entry2->nickname,
443 tmp ? tmp : "removed all",
444 server_entry->server_name);
445 } else if (idtype == SILC_ID_CHANNEL) {
446 channel2 = (SilcChannelEntry)entry;
447 printformat_module("fe-common/silc", server, channel->channel_name,
448 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
449 channel->channel_name, client_entry2->nickname,
450 tmp ? tmp : "removed all",
451 channel2->channel_name);
454 if (mode & SILC_CHANNEL_UMODE_CHANFO)
455 printformat_module("fe-common/silc",
456 server, channel->channel_name, MSGLEVEL_CRAP,
457 SILCTXT_CHANNEL_FOUNDER,
458 channel->channel_name, client_entry2->nickname);
463 case SILC_NOTIFY_TYPE_MOTD:
468 SILC_LOG_DEBUG(("Notify: MOTD"));
470 tmp = va_arg(va, char *);
472 if (!settings_get_bool("skip_motd"))
473 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
476 case SILC_NOTIFY_TYPE_KICKED:
478 * Someone was kicked from channel.
481 SILC_LOG_DEBUG(("Notify: KICKED"));
483 client_entry = va_arg(va, SilcClientEntry);
484 tmp = va_arg(va, char *);
485 client_entry2 = va_arg(va, SilcClientEntry);
486 channel = va_arg(va, SilcChannelEntry);
488 chanrec = silc_channel_find_entry(server, channel);
490 if (client_entry == conn->local_entry) {
491 printformat_module("fe-common/silc", server, channel->channel_name,
492 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
493 channel->channel_name,
494 client_entry ? client_entry2->nickname : "",
497 chanrec->kicked = TRUE;
498 channel_destroy((CHANNEL_REC *)chanrec);
501 printformat_module("fe-common/silc", server, channel->channel_name,
502 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
503 client_entry->nickname, channel->channel_name,
504 client_entry2 ? client_entry2->nickname : "",
508 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
510 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
515 case SILC_NOTIFY_TYPE_KILLED:
517 * Someone was killed from the network.
520 SILC_LOG_DEBUG(("Notify: KILLED"));
522 client_entry = va_arg(va, SilcClientEntry);
523 tmp = va_arg(va, char *);
524 idtype = va_arg(va, int);
525 entry = va_arg(va, SilcClientEntry);
527 if (client_entry == conn->local_entry) {
528 if (idtype == SILC_ID_CLIENT) {
529 client_entry2 = (SilcClientEntry)entry;
530 printformat_module("fe-common/silc", server, NULL,
531 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
532 client_entry2 ? client_entry2->nickname : "",
534 } else if (idtype == SILC_ID_SERVER) {
535 server_entry = (SilcServerEntry)entry;
536 printformat_module("fe-common/silc", server, NULL,
537 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
538 server_entry->server_name, tmp ? tmp : "");
539 } else if (idtype == SILC_ID_CHANNEL) {
540 channel = (SilcChannelEntry)entry;
541 printformat_module("fe-common/silc", server, NULL,
542 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
543 channel->channel_name, tmp ? tmp : "");
546 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
547 for (list_tmp = list1; list_tmp != NULL; list_tmp =
548 list_tmp->next->next) {
549 CHANNEL_REC *channel = list_tmp->data;
550 NICK_REC *nickrec = list_tmp->next->data;
551 nicklist_remove(channel, nickrec);
554 if (idtype == SILC_ID_CLIENT) {
555 client_entry2 = (SilcClientEntry)entry;
556 printformat_module("fe-common/silc", server, NULL,
557 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
558 client_entry->nickname,
559 client_entry2 ? client_entry2->nickname : "",
561 } else if (idtype == SILC_ID_SERVER) {
562 server_entry = (SilcServerEntry)entry;
563 printformat_module("fe-common/silc", server, NULL,
564 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
565 client_entry->nickname,
566 server_entry->server_name, tmp ? tmp : "");
567 } else if (idtype == SILC_ID_CHANNEL) {
568 channel = (SilcChannelEntry)entry;
569 printformat_module("fe-common/silc", server, NULL,
570 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
571 client_entry->nickname,
572 channel->channel_name, tmp ? tmp : "");
577 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
580 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
583 * Server has quit the network.
586 SilcClientEntry *clients;
587 SilcUInt32 clients_count;
589 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
591 (void)va_arg(va, void *);
592 clients = va_arg(va, SilcClientEntry *);
593 clients_count = va_arg(va, SilcUInt32);
595 for (i = 0; i < clients_count; i++) {
596 memset(userhost, 0, sizeof(userhost));
597 if (clients[i]->username)
598 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
599 clients[i]->username, clients[i]->hostname);
600 signal_emit("message quit", 4, server, clients[i]->nickname,
601 clients[i]->username ? userhost : "",
604 silc_server_free_ftp(server, clients[i]);
606 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
607 for (list_tmp = list1; list_tmp != NULL; list_tmp =
608 list_tmp->next->next) {
609 CHANNEL_REC *channel = list_tmp->data;
610 NICK_REC *nickrec = list_tmp->next->data;
611 nicklist_remove(channel, nickrec);
617 case SILC_NOTIFY_TYPE_ERROR:
619 SilcStatus error = va_arg(va, int);
621 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
622 "%s", silc_client_status_message(error));
628 printformat_module("fe-common/silc", server, NULL,
629 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
636 /* Called to indicate that connection was either successfully established
637 or connecting failed. This is also the first time application receives
638 the SilcClientConnection object which it should save somewhere. */
640 void silc_connect(SilcClient client, SilcClientConnection conn,
641 SilcClientConnectionStatus status)
643 SILC_SERVER_REC *server = conn->context;
646 silc_client_close_connection(client, conn);
651 case SILC_CLIENT_CONN_SUCCESS:
652 /* We have successfully connected to server */
653 server->connected = TRUE;
654 signal_emit("event connected", 1, server);
657 case SILC_CLIENT_CONN_SUCCESS_RESUME:
658 /* We have successfully resumed old detached session */
659 server->connected = TRUE;
660 signal_emit("event connected", 1, server);
662 /* If we resumed old session check whether we need to update
664 if (strcmp(server->nick, conn->local_entry->nickname)) {
666 old = g_strdup(server->nick);
667 server_change_nick(SERVER(server), conn->local_entry->nickname);
668 nicklist_rename_unique(SERVER(server),
669 conn->local_entry, server->nick,
670 conn->local_entry, conn->local_entry->nickname);
671 signal_emit("message own_nick", 4, server, server->nick, old, "");
677 server->connection_lost = TRUE;
679 server->conn->context = NULL;
680 server_disconnect(SERVER(server));
685 /* Called to indicate that connection was disconnected to the server. */
687 void silc_disconnect(SilcClient client, SilcClientConnection conn)
689 SILC_SERVER_REC *server = conn->context;
691 SILC_LOG_DEBUG(("Start"));
693 if (!server || server->connection_lost)
696 if (server->conn && server->conn->local_entry) {
697 nicklist_rename_unique(SERVER(server),
698 server->conn->local_entry, server->nick,
699 server->conn->local_entry,
700 silc_client->username);
701 silc_change_nick(server, silc_client->username);
704 server->conn->context = NULL;
706 server->connection_lost = TRUE;
707 server_disconnect(SERVER(server));
710 /* Command handler. This function is called always in the command function.
711 If error occurs it will be called as well. `conn' is the associated
712 client connection. `cmd_context' is the command context that was
713 originally sent to the command. `success' is FALSE if error occured
714 during command. `command' is the command being processed. It must be
715 noted that this is not reply from server. This is merely called just
716 after application has called the command. Just to tell application
717 that the command really was processed. */
719 void silc_command(SilcClient client, SilcClientConnection conn,
720 SilcClientCommandContext cmd_context, int success,
723 SILC_SERVER_REC *server = conn->context;
725 SILC_LOG_DEBUG(("Start"));
731 case SILC_COMMAND_INVITE:
732 printformat_module("fe-common/silc", server, NULL,
733 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
734 cmd_context->argv[2],
735 (cmd_context->argv[1][0] == '*' ?
736 (char *)conn->current_channel->channel_name :
737 (char *)cmd_context->argv[1]));
744 /* Client info resolving callback when JOIN command reply is received.
745 This will cache all users on the channel. */
747 static void silc_client_join_get_users(SilcClient client,
748 SilcClientConnection conn,
749 SilcClientEntry *clients,
750 SilcUInt32 clients_count,
753 SilcChannelEntry channel = (SilcChannelEntry)context;
754 SilcHashTableList htl;
756 SILC_SERVER_REC *server = conn->context;
757 SILC_CHANNEL_REC *chanrec;
758 SilcClientEntry founder = NULL;
761 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
762 silc_hash_table_count(channel->user_list)));
767 chanrec = silc_channel_find(server, channel->channel_name);
771 silc_hash_table_list(channel->user_list, &htl);
772 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
773 if (!chu->client->nickname)
775 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
776 founder = chu->client;
777 silc_nicklist_insert(chanrec, chu, FALSE);
779 silc_hash_table_list_reset(&htl);
781 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
782 nicklist_set_own(CHANNEL(chanrec), ownnick);
783 signal_emit("channel joined", 1, chanrec);
784 chanrec->entry = channel;
787 printformat_module("fe-common/silc", server, channel->channel_name,
788 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
789 channel->channel_name, chanrec->topic);
791 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
794 if (founder == conn->local_entry)
795 printformat_module("fe-common/silc",
796 server, channel->channel_name, MSGLEVEL_CRAP,
797 SILCTXT_CHANNEL_FOUNDER_YOU,
798 channel->channel_name);
800 printformat_module("fe-common/silc",
801 server, channel->channel_name, MSGLEVEL_CRAP,
802 SILCTXT_CHANNEL_FOUNDER,
803 channel->channel_name, founder->nickname);
809 SilcClientConnection conn;
815 void silc_getkey_cb(bool success, void *context)
817 GetkeyContext getkey = (GetkeyContext)context;
818 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
819 char *name = (getkey->id_type == SILC_ID_CLIENT ?
820 ((SilcClientEntry)getkey->entry)->nickname :
821 ((SilcServerEntry)getkey->entry)->server_name);
824 printformat_module("fe-common/silc", NULL, NULL,
825 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
827 printformat_module("fe-common/silc", NULL, NULL,
828 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
831 silc_free(getkey->fingerprint);
835 /* Command reply handler. This function is called always in the command reply
836 function. If error occurs it will be called as well. Normal scenario
837 is that it will be called after the received command data has been parsed
838 and processed. The function is used to pass the received command data to
841 `conn' is the associated client connection. `cmd_payload' is the command
842 payload data received from server and it can be ignored. It is provided
843 if the application would like to re-parse the received command data,
844 however, it must be noted that the data is parsed already by the library
845 thus the payload can be ignored. `success' is FALSE if error occured.
846 In this case arguments are not sent to the application. `command' is the
847 command reply being processed. The function has variable argument list
848 and each command defines the number and type of arguments it passes to the
849 application (on error they are not sent). */
852 silc_command_reply(SilcClient client, SilcClientConnection conn,
853 SilcCommandPayload cmd_payload, int success,
854 SilcCommand command, SilcStatus status, ...)
857 SILC_SERVER_REC *server = conn->context;
858 SILC_CHANNEL_REC *chanrec;
861 va_start(vp, status);
863 SILC_LOG_DEBUG(("Start"));
866 case SILC_COMMAND_WHOIS:
868 char buf[1024], *nickname, *username, *realname, *nick;
869 unsigned char *fingerprint;
870 SilcUInt32 idle, mode;
871 SilcBuffer channels, user_modes;
872 SilcClientEntry client_entry;
874 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
875 /* Print the unknown nick for user */
877 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
880 silc_say_error("%s: %s", tmp,
881 silc_client_status_message(status));
883 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
884 /* Try to find the entry for the unknown client ID, since we
885 might have, and print the nickname of it for user. */
888 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
891 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
894 client_entry = silc_client_get_client_by_id(client, conn,
896 if (client_entry && client_entry->nickname)
897 silc_say_error("%s: %s", client_entry->nickname,
898 silc_client_status_message(status));
899 silc_free(client_id);
908 client_entry = va_arg(vp, SilcClientEntry);
909 nickname = va_arg(vp, char *);
910 username = va_arg(vp, char *);
911 realname = va_arg(vp, char *);
912 channels = va_arg(vp, SilcBuffer);
913 mode = va_arg(vp, SilcUInt32);
914 idle = va_arg(vp, SilcUInt32);
915 fingerprint = va_arg(vp, unsigned char *);
916 user_modes = va_arg(vp, SilcBuffer);
918 silc_parse_userfqdn(nickname, &nick, NULL);
919 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
920 SILCTXT_WHOIS_USERINFO, nickname,
921 client_entry->username, client_entry->hostname,
922 nick, client_entry->nickname);
923 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
924 SILCTXT_WHOIS_REALNAME, realname);
927 if (channels && user_modes) {
929 SilcDList list = silc_channel_payload_parse_list(channels->data,
931 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
933 SilcChannelPayload entry;
936 memset(buf, 0, sizeof(buf));
937 silc_dlist_start(list);
938 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
940 char *m = silc_client_chumode_char(umodes[i++]);
941 char *name = silc_channel_get_name(entry, &name_len);
944 strncat(buf, m, strlen(m));
945 strncat(buf, name, name_len);
946 strncat(buf, " ", 1);
950 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
951 SILCTXT_WHOIS_CHANNELS, buf);
952 silc_channel_payload_list_free(list);
958 memset(buf, 0, sizeof(buf));
960 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
961 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
962 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
964 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
965 "SILC Operator" : "[Unknown mode]");
967 if (mode & SILC_UMODE_GONE)
968 strcat(buf, " [away]");
969 if (mode & SILC_UMODE_INDISPOSED)
970 strcat(buf, " [indisposed]");
971 if (mode & SILC_UMODE_BUSY)
972 strcat(buf, " [busy]");
973 if (mode & SILC_UMODE_PAGE)
974 strcat(buf, " [page to reach]");
975 if (mode & SILC_UMODE_HYPER)
976 strcat(buf, " [hyper active]");
977 if (mode & SILC_UMODE_ROBOT)
978 strcat(buf, " [robot]");
979 if (mode & SILC_UMODE_ANONYMOUS)
980 strcat(buf, " [anonymous]");
981 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
982 strcat(buf, " [blocks private messages]");
983 if (mode & SILC_UMODE_DETACHED)
984 strcat(buf, " [detached]");
986 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
987 SILCTXT_WHOIS_MODES, buf);
990 if (idle && nickname) {
991 memset(buf, 0, sizeof(buf));
992 snprintf(buf, sizeof(buf) - 1, "%lu %s",
993 idle > 60 ? (idle / 60) : idle,
994 idle > 60 ? "minutes" : "seconds");
996 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
997 SILCTXT_WHOIS_IDLE, buf);
1001 fingerprint = silc_fingerprint(fingerprint, 20);
1002 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1003 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1004 silc_free(fingerprint);
1009 case SILC_COMMAND_IDENTIFY:
1011 SilcClientEntry client_entry;
1013 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1014 /* Print the unknown nick for user */
1015 unsigned char *tmp =
1016 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1019 silc_say_error("%s: %s", tmp,
1020 silc_client_status_message(status));
1022 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1023 /* Try to find the entry for the unknown client ID, since we
1024 might have, and print the nickname of it for user. */
1026 unsigned char *tmp =
1027 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1030 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1033 client_entry = silc_client_get_client_by_id(client, conn,
1035 if (client_entry && client_entry->nickname)
1036 silc_say_error("%s: %s", client_entry->nickname,
1037 silc_client_status_message(status));
1038 silc_free(client_id);
1047 case SILC_COMMAND_WHOWAS:
1049 char *nickname, *username, *realname;
1051 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1052 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1054 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1057 silc_say_error("%s: %s", tmp,
1058 silc_client_status_message(status));
1065 (void)va_arg(vp, SilcClientEntry);
1066 nickname = va_arg(vp, char *);
1067 username = va_arg(vp, char *);
1068 realname = va_arg(vp, char *);
1070 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1071 SILCTXT_WHOWAS_USERINFO, nickname, username,
1072 realname ? realname : "");
1076 case SILC_COMMAND_INVITE:
1078 SilcChannelEntry channel;
1080 SilcArgumentPayload args;
1086 channel = va_arg(vp, SilcChannelEntry);
1087 invite_list = va_arg(vp, char *);
1089 args = silc_command_get_args(cmd_payload);
1091 argc = silc_argument_get_arg_num(args);
1094 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1095 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1098 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1099 SILCTXT_CHANNEL_NO_INVITE_LIST,
1100 channel->channel_name);
1104 case SILC_COMMAND_JOIN:
1106 char *channel, *mode, *topic;
1108 SilcChannelEntry channel_entry;
1109 SilcBuffer client_id_list;
1110 SilcUInt32 list_count;
1115 channel = va_arg(vp, char *);
1116 channel_entry = va_arg(vp, SilcChannelEntry);
1117 modei = va_arg(vp, SilcUInt32);
1118 (void)va_arg(vp, SilcUInt32);
1119 (void)va_arg(vp, unsigned char *);
1120 (void)va_arg(vp, unsigned char *);
1121 (void)va_arg(vp, unsigned char *);
1122 topic = va_arg(vp, char *);
1123 (void)va_arg(vp, unsigned char *);
1124 list_count = va_arg(vp, SilcUInt32);
1125 client_id_list = va_arg(vp, SilcBuffer);
1127 chanrec = silc_channel_find(server, channel);
1129 chanrec = silc_channel_create(server, channel, TRUE);
1132 g_free_not_null(chanrec->topic);
1133 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1134 signal_emit("channel topic changed", 1, chanrec);
1137 mode = silc_client_chmode(modei,
1138 channel_entry->channel_key ?
1139 channel_entry->channel_key->cipher->name : "",
1140 channel_entry->hmac ?
1141 silc_hmac_get_name(channel_entry->hmac) : "");
1142 g_free_not_null(chanrec->mode);
1143 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1144 signal_emit("channel mode changed", 1, chanrec);
1146 /* Resolve the client information */
1147 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1148 silc_client_join_get_users,
1154 case SILC_COMMAND_NICK:
1156 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1162 old = g_strdup(server->nick);
1163 server_change_nick(SERVER(server), client->nickname);
1164 nicklist_rename_unique(SERVER(server),
1165 server->conn->local_entry, server->nick,
1166 client, client->nickname);
1167 signal_emit("message own_nick", 4, server, server->nick, old, "");
1172 case SILC_COMMAND_LIST:
1181 (void)va_arg(vp, SilcChannelEntry);
1182 name = va_arg(vp, char *);
1183 topic = va_arg(vp, char *);
1184 usercount = va_arg(vp, int);
1186 if (status == SILC_STATUS_LIST_START ||
1187 status == SILC_STATUS_OK)
1188 printformat_module("fe-common/silc", server, NULL,
1189 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1192 snprintf(users, sizeof(users) - 1, "N/A");
1194 snprintf(users, sizeof(users) - 1, "%d", usercount);
1195 printformat_module("fe-common/silc", server, NULL,
1196 MSGLEVEL_CRAP, SILCTXT_LIST,
1197 name, users, topic ? topic : "");
1201 case SILC_COMMAND_UMODE:
1208 mode = va_arg(vp, SilcUInt32);
1210 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1211 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1212 printformat_module("fe-common/silc", server, NULL,
1213 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1215 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1216 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1217 printformat_module("fe-common/silc", server, NULL,
1218 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1220 server->umode = mode;
1221 signal_emit("user mode changed", 2, server, NULL);
1225 case SILC_COMMAND_OPER:
1229 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1230 signal_emit("user mode changed", 2, server, NULL);
1232 printformat_module("fe-common/silc", server, NULL,
1233 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1236 case SILC_COMMAND_SILCOPER:
1240 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1241 signal_emit("user mode changed", 2, server, NULL);
1243 printformat_module("fe-common/silc", server, NULL,
1244 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1247 case SILC_COMMAND_USERS:
1249 SilcHashTableList htl;
1250 SilcChannelEntry channel;
1251 SilcChannelUser chu;
1256 channel = va_arg(vp, SilcChannelEntry);
1258 printformat_module("fe-common/silc", server, channel->channel_name,
1259 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1260 channel->channel_name);
1262 silc_hash_table_list(channel->user_list, &htl);
1263 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1264 SilcClientEntry e = chu->client;
1265 char stat[5], *mode;
1270 memset(stat, 0, sizeof(stat));
1271 mode = silc_client_chumode_char(chu->mode);
1272 if (e->mode & SILC_UMODE_GONE)
1274 else if (e->mode & SILC_UMODE_INDISPOSED)
1276 else if (e->mode & SILC_UMODE_BUSY)
1278 else if (e->mode & SILC_UMODE_PAGE)
1280 else if (e->mode & SILC_UMODE_HYPER)
1282 else if (e->mode & SILC_UMODE_ROBOT)
1284 else if (e->mode & SILC_UMODE_ANONYMOUS)
1291 printformat_module("fe-common/silc", server, channel->channel_name,
1292 MSGLEVEL_CRAP, SILCTXT_USERS,
1294 e->username ? e->username : "",
1295 e->hostname ? e->hostname : "",
1296 e->realname ? e->realname : "");
1300 silc_hash_table_list_reset(&htl);
1304 case SILC_COMMAND_BAN:
1306 SilcChannelEntry channel;
1312 channel = va_arg(vp, SilcChannelEntry);
1313 ban_list = va_arg(vp, char *);
1316 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1317 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1320 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1321 SILCTXT_CHANNEL_NO_BAN_LIST,
1322 channel->channel_name);
1326 case SILC_COMMAND_GETKEY:
1330 SilcPublicKey public_key;
1333 GetkeyContext getkey;
1339 id_type = va_arg(vp, SilcUInt32);
1340 entry = va_arg(vp, void *);
1341 public_key = va_arg(vp, SilcPublicKey);
1344 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1346 getkey = silc_calloc(1, sizeof(*getkey));
1347 getkey->entry = entry;
1348 getkey->id_type = id_type;
1349 getkey->client = client;
1350 getkey->conn = conn;
1351 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1353 name = (id_type == SILC_ID_CLIENT ?
1354 ((SilcClientEntry)entry)->nickname :
1355 ((SilcServerEntry)entry)->server_name);
1357 silc_verify_public_key_internal(client, conn, name,
1358 (id_type == SILC_ID_CLIENT ?
1359 SILC_SOCKET_TYPE_CLIENT :
1360 SILC_SOCKET_TYPE_SERVER),
1361 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1362 silc_getkey_cb, getkey);
1365 printformat_module("fe-common/silc", server, NULL,
1366 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1371 case SILC_COMMAND_INFO:
1373 SilcServerEntry server_entry;
1380 server_entry = va_arg(vp, SilcServerEntry);
1381 server_name = va_arg(vp, char *);
1382 server_info = va_arg(vp, char *);
1384 if (server_name && server_info )
1386 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1387 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1392 case SILC_COMMAND_TOPIC:
1394 SilcChannelEntry channel;
1400 channel = va_arg(vp, SilcChannelEntry);
1401 topic = va_arg(vp, char *);
1404 chanrec = silc_channel_find_entry(server, channel);
1406 g_free_not_null(chanrec->topic);
1407 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1408 signal_emit("channel topic changed", 1, chanrec);
1410 printformat_module("fe-common/silc", server, channel->channel_name,
1411 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1412 channel->channel_name, topic);
1414 printformat_module("fe-common/silc", server, channel->channel_name,
1415 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1416 channel->channel_name);
1428 SilcClientConnection conn;
1434 SilcSKEPKType pk_type;
1435 SilcVerifyPublicKey completion;
1439 static void verify_public_key_completion(const char *line, void *context)
1441 PublicKeyVerify verify = (PublicKeyVerify)context;
1443 if (line[0] == 'Y' || line[0] == 'y') {
1444 /* Call the completion */
1445 if (verify->completion)
1446 verify->completion(TRUE, verify->context);
1448 /* Save the key for future checking */
1449 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1450 verify->pk_len, SILC_PKCS_FILE_PEM);
1452 /* Call the completion */
1453 if (verify->completion)
1454 verify->completion(FALSE, verify->context);
1456 printformat_module("fe-common/silc", NULL, NULL,
1457 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1458 verify->entity_name ? verify->entity_name :
1462 silc_free(verify->filename);
1463 silc_free(verify->entity);
1464 silc_free(verify->entity_name);
1465 silc_free(verify->pk);
1469 /* Internal routine to verify public key. If the `completion' is provided
1470 it will be called to indicate whether public was verified or not. For
1471 server/router public key this will check for filename that includes the
1472 remote host's IP address and remote host's hostname. */
1475 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1476 const char *name, SilcSocketType conn_type,
1477 unsigned char *pk, SilcUInt32 pk_len,
1478 SilcSKEPKType pk_type,
1479 SilcVerifyPublicKey completion, void *context)
1482 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1483 char *fingerprint, *babbleprint, *format;
1486 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1487 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1488 "server" : "client");
1489 PublicKeyVerify verify;
1491 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1492 printformat_module("fe-common/silc", NULL, NULL,
1493 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1496 completion(FALSE, context);
1500 pw = getpwuid(getuid());
1503 completion(FALSE, context);
1507 memset(filename, 0, sizeof(filename));
1508 memset(filename2, 0, sizeof(filename2));
1509 memset(file, 0, sizeof(file));
1511 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1512 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1514 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1515 conn->sock->ip, conn->sock->port);
1516 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1517 get_irssi_dir(), entity, file);
1519 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1520 conn->sock->hostname, conn->sock->port);
1521 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1522 get_irssi_dir(), entity, file);
1527 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1528 name, conn->sock->port);
1529 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1530 get_irssi_dir(), entity, file);
1535 /* Replace all whitespaces with `_'. */
1536 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1537 for (i = 0; i < strlen(fingerprint); i++)
1538 if (fingerprint[i] == ' ')
1539 fingerprint[i] = '_';
1541 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1542 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1543 get_irssi_dir(), entity, file);
1544 silc_free(fingerprint);
1549 /* Take fingerprint of the public key */
1550 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1551 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1553 verify = silc_calloc(1, sizeof(*verify));
1554 verify->client = client;
1555 verify->conn = conn;
1556 verify->filename = strdup(ipf);
1557 verify->entity = strdup(entity);
1558 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1559 (name ? strdup(name) : strdup(conn->sock->hostname))
1561 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1562 memcpy(verify->pk, pk, pk_len);
1563 verify->pk_len = pk_len;
1564 verify->pk_type = pk_type;
1565 verify->completion = completion;
1566 verify->context = context;
1568 /* Check whether this key already exists */
1569 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1570 /* Key does not exist, ask user to verify the key and save it */
1572 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1573 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1574 verify->entity_name : entity);
1575 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1576 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1577 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1578 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1579 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1580 SILCTXT_PUBKEY_ACCEPT);
1581 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1584 silc_free(fingerprint);
1587 /* The key already exists, verify it. */
1588 SilcPublicKey public_key;
1589 unsigned char *encpk;
1590 SilcUInt32 encpk_len;
1592 /* Load the key file, try for both IP filename and hostname filename */
1593 if (!silc_pkcs_load_public_key(ipf, &public_key,
1594 SILC_PKCS_FILE_PEM) &&
1595 !silc_pkcs_load_public_key(ipf, &public_key,
1596 SILC_PKCS_FILE_BIN) &&
1597 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1598 SILC_PKCS_FILE_PEM) &&
1599 !silc_pkcs_load_public_key(hostf, &public_key,
1600 SILC_PKCS_FILE_BIN)))) {
1601 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1602 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1603 verify->entity_name : entity);
1604 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1605 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1606 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1607 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1608 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1609 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1610 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1611 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1612 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1615 silc_free(fingerprint);
1619 /* Encode the key data */
1620 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1622 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1623 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1624 verify->entity_name : entity);
1625 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1626 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1627 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1628 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1629 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1630 SILCTXT_PUBKEY_MALFORMED, entity);
1631 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1632 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1633 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1636 silc_free(fingerprint);
1640 /* Compare the keys */
1641 if (memcmp(encpk, pk, encpk_len)) {
1642 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1643 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1644 verify->entity_name : entity);
1645 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1646 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1647 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1648 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1649 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1650 SILCTXT_PUBKEY_NO_MATCH, entity);
1651 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1652 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1653 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1654 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1656 /* Ask user to verify the key and save it */
1657 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1658 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1659 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1662 silc_free(fingerprint);
1666 /* Local copy matched */
1668 completion(TRUE, context);
1669 silc_free(fingerprint);
1673 /* Verifies received public key. The `conn_type' indicates which entity
1674 (server, client etc.) has sent the public key. If user decides to trust
1675 the key may be saved as trusted public key for later use. The
1676 `completion' must be called after the public key has been verified. */
1679 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1680 SilcSocketType conn_type, unsigned char *pk,
1681 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1682 SilcVerifyPublicKey completion, void *context)
1684 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1686 completion, context);
1689 /* Asks passphrase from user on the input line. */
1692 SilcAskPassphrase completion;
1696 void ask_passphrase_completion(const char *passphrase, void *context)
1698 AskPassphrase p = (AskPassphrase)context;
1699 p->completion((unsigned char *)passphrase,
1700 passphrase ? strlen(passphrase) : 0, p->context);
1704 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1705 SilcAskPassphrase completion, void *context)
1707 AskPassphrase p = silc_calloc(1, sizeof(*p));
1708 p->completion = completion;
1709 p->context = context;
1711 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1712 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1716 SilcGetAuthMeth completion;
1718 } *InternalGetAuthMethod;
1720 /* Callback called when we've received the authentication method information
1721 from the server after we've requested it. This will get the authentication
1722 data from the user if needed. */
1724 static void silc_get_auth_method_callback(SilcClient client,
1725 SilcClientConnection conn,
1726 SilcAuthMethod auth_meth,
1729 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1731 SILC_LOG_DEBUG(("Start"));
1733 switch (auth_meth) {
1734 case SILC_AUTH_NONE:
1735 /* No authentication required. */
1736 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1738 case SILC_AUTH_PASSWORD:
1739 /* Do not ask the passphrase from user, the library will ask it if
1740 we do not provide it here. */
1741 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1743 case SILC_AUTH_PUBLIC_KEY:
1744 /* Do not get the authentication data now, the library will generate
1745 it using our default key, if we do not provide it here. */
1746 /* XXX In the future when we support multiple local keys and multiple
1747 local certificates we will need to ask from user which one to use. */
1748 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1752 silc_free(internal);
1755 /* Find authentication method and authentication data by hostname and
1756 port. The hostname may be IP address as well. The found authentication
1757 method and authentication data is returned to `auth_meth', `auth_data'
1758 and `auth_data_len'. The function returns TRUE if authentication method
1759 is found and FALSE if not. `conn' may be NULL. */
1761 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1762 char *hostname, SilcUInt16 port,
1763 SilcGetAuthMeth completion, void *context)
1765 InternalGetAuthMethod internal;
1767 SILC_LOG_DEBUG(("Start"));
1769 /* XXX must resolve from configuration whether this connection has
1770 any specific authentication data */
1772 /* If we do not have this connection configured by the user in a
1773 configuration file then resolve the authentication method from the
1774 server for this session. */
1775 internal = silc_calloc(1, sizeof(*internal));
1776 internal->completion = completion;
1777 internal->context = context;
1779 silc_client_request_authentication_method(client, conn,
1780 silc_get_auth_method_callback,
1784 /* Notifies application that failure packet was received. This is called
1785 if there is some protocol active in the client. The `protocol' is the
1786 protocol context. The `failure' is opaque pointer to the failure
1787 indication. Note, that the `failure' is protocol dependant and application
1788 must explicitly cast it to correct type. Usually `failure' is 32 bit
1789 failure type (see protocol specs for all protocol failure types). */
1791 void silc_failure(SilcClient client, SilcClientConnection conn,
1792 SilcProtocol protocol, void *failure)
1794 SILC_LOG_DEBUG(("Start"));
1796 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1797 SilcSKEStatus status = (SilcSKEStatus)failure;
1799 if (status == SILC_SKE_STATUS_BAD_VERSION)
1800 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1801 SILCTXT_KE_BAD_VERSION);
1802 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1803 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1804 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1805 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1806 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1807 SILCTXT_KE_UNKNOWN_GROUP);
1808 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1809 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1810 SILCTXT_KE_UNKNOWN_CIPHER);
1811 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1812 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1813 SILCTXT_KE_UNKNOWN_PKCS);
1814 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1815 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1816 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1817 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1818 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1819 SILCTXT_KE_UNKNOWN_HMAC);
1820 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1821 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1822 SILCTXT_KE_INCORRECT_SIGNATURE);
1823 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1824 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1825 SILCTXT_KE_INVALID_COOKIE);
1828 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1829 SilcUInt32 err = (SilcUInt32)failure;
1831 if (err == SILC_AUTH_FAILED)
1832 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1833 SILCTXT_AUTH_FAILED);
1837 /* Asks whether the user would like to perform the key agreement protocol.
1838 This is called after we have received an key agreement packet or an
1839 reply to our key agreement packet. This returns TRUE if the user wants
1840 the library to perform the key agreement protocol and FALSE if it is not
1841 desired (application may start it later by calling the function
1842 silc_client_perform_key_agreement). */
1844 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1845 SilcClientEntry client_entry, const char *hostname,
1846 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1851 SILC_LOG_DEBUG(("Start"));
1853 /* We will just display the info on the screen and return FALSE and user
1854 will have to start the key agreement with a command. */
1857 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1860 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1861 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1863 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1864 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1865 client_entry->nickname, hostname, portstr);
1873 /* Notifies application that file transfer protocol session is being
1874 requested by the remote client indicated by the `client_entry' from
1875 the `hostname' and `port'. The `session_id' is the file transfer
1876 session and it can be used to either accept or reject the file
1877 transfer request, by calling the silc_client_file_receive or
1878 silc_client_file_close, respectively. */
1880 void silc_ftp(SilcClient client, SilcClientConnection conn,
1881 SilcClientEntry client_entry, SilcUInt32 session_id,
1882 const char *hostname, SilcUInt16 port)
1884 SILC_SERVER_REC *server;
1886 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
1888 SILC_LOG_DEBUG(("Start"));
1890 server = conn->context;
1892 ftp->client_entry = client_entry;
1893 ftp->session_id = session_id;
1896 silc_dlist_add(server->ftp_sessions, ftp);
1897 server->current_session = ftp;
1900 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1903 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1904 SILCTXT_FILE_REQUEST, client_entry->nickname);
1906 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1907 SILCTXT_FILE_REQUEST_HOST,
1908 client_entry->nickname, hostname, portstr);
1911 /* Delivers SILC session detachment data indicated by `detach_data' to the
1912 application. If application has issued SILC_COMMAND_DETACH command
1913 the client session in the SILC network is not quit. The client remains
1914 in the network but is detached. The detachment data may be used later
1915 to resume the session in the SILC Network. The appliation is
1916 responsible of saving the `detach_data', to for example in a file.
1918 The detachment data can be given as argument to the functions
1919 silc_client_connect_to_server, or silc_client_add_connection when
1920 creating connection to remote server, inside SilcClientConnectionParams
1921 structure. If it is provided the client library will attempt to resume
1922 the session in the network. After the connection is created
1923 successfully, the application is responsible of setting the user
1924 interface for user into the same state it was before detaching (showing
1925 same channels, channel modes, etc). It can do this by fetching the
1926 information (like joined channels) from the client library. */
1929 silc_detach(SilcClient client, SilcClientConnection conn,
1930 const unsigned char *detach_data, SilcUInt32 detach_data_len)
1934 /* Save the detachment data to file. */
1936 memset(file, 0, sizeof(file));
1937 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
1938 silc_file_writefile(file, detach_data, detach_data_len);
1942 /* SILC client operations */
1943 SilcClientOperations ops = {
1945 silc_channel_message,
1946 silc_private_message,
1952 silc_get_auth_method,
1953 silc_verify_public_key,
1954 silc_ask_passphrase,