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 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
53 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
54 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
55 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
57 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
58 "[SILC operator]" : "[unknown mode]");
60 if (mode & SILC_UMODE_GONE)
61 strcat(buf, " [away]");
62 if (mode & SILC_UMODE_INDISPOSED)
63 strcat(buf, " [indisposed]");
64 if (mode & SILC_UMODE_BUSY)
65 strcat(buf, " [busy]");
66 if (mode & SILC_UMODE_PAGE)
67 strcat(buf, " [page to reach]");
68 if (mode & SILC_UMODE_HYPER)
69 strcat(buf, " [hyper active]");
70 if (mode & SILC_UMODE_ROBOT)
71 strcat(buf, " [robot]");
72 if (mode & SILC_UMODE_ANONYMOUS)
73 strcat(buf, " [anonymous]");
74 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
75 strcat(buf, " [blocks private messages]");
76 if (mode & SILC_UMODE_DETACHED)
77 strcat(buf, " [detached]");
78 if (mode & SILC_UMODE_REJECT_WATCHING)
79 strcat(buf, " [rejects watching]");
80 if (mode & SILC_UMODE_BLOCK_INVITE)
81 strcat(buf, " [blocks invites]");
84 void silc_say(SilcClient client, SilcClientConnection conn,
85 SilcClientMessageType type, char *msg, ...)
87 SILC_SERVER_REC *server;
91 server = conn == NULL ? NULL : conn->context;
94 str = g_strdup_vprintf(msg, va);
95 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
100 void silc_say_error(char *msg, ...)
106 str = g_strdup_vprintf(msg, va);
107 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
113 /* Message for a channel. The `sender' is the nickname of the sender
114 received in the packet. The `channel_name' is the name of the channel. */
116 void silc_channel_message(SilcClient client, SilcClientConnection conn,
117 SilcClientEntry sender, SilcChannelEntry channel,
118 SilcMessageFlags flags, const unsigned char *message,
119 SilcUInt32 message_len)
121 SILC_SERVER_REC *server;
123 SILC_CHANNEL_REC *chanrec;
125 SILC_LOG_DEBUG(("Start"));
130 server = conn == NULL ? NULL : conn->context;
131 chanrec = silc_channel_find_entry(server, channel);
135 nick = silc_nicklist_find(chanrec, sender);
137 /* We didn't find client but it clearly exists, add it. */
138 SilcChannelUser chu = silc_client_on_channel(channel, sender);
140 nick = silc_nicklist_insert(chanrec, chu, FALSE);
143 if (flags & SILC_MESSAGE_FLAG_DATA) {
144 /* MIME object received, try to display it as well as we can */
145 char type[128], enc[128];
149 memset(type, 0, sizeof(type));
150 memset(enc, 0, sizeof(enc));
151 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
152 enc, sizeof(enc) - 1, &data, &data_len))
155 /* Then figure out what we can display */
156 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
157 !strstr(type, "text/vnd")) {
158 /* It is something textual, display it */
159 message = (const unsigned char *)data;
166 if (flags & SILC_MESSAGE_FLAG_ACTION)
167 printformat_module("fe-common/silc", server, channel->channel_name,
168 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
169 nick == NULL ? "[<unknown>]" : nick->nick, message);
170 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
171 printformat_module("fe-common/silc", server, channel->channel_name,
172 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
173 nick == NULL ? "[<unknown>]" : nick->nick, message);
175 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
176 char tmp[256], *cp, *dm = NULL;
178 memset(tmp, 0, sizeof(tmp));
180 if (message_len > sizeof(tmp) - 1) {
181 dm = silc_calloc(message_len + 1, sizeof(*dm));
185 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
187 signal_emit("message public", 6, server, cp,
188 nick == NULL ? "[<unknown>]" : nick->nick,
189 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
190 chanrec->name, nick);
195 signal_emit("message public", 6, server, message,
196 nick == NULL ? "[<unknown>]" : nick->nick,
197 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
198 chanrec->name, nick);
202 /* Private message to the client. The `sender' is the nickname of the
203 sender received in the packet. */
205 void silc_private_message(SilcClient client, SilcClientConnection conn,
206 SilcClientEntry sender, SilcMessageFlags flags,
207 const unsigned char *message,
208 SilcUInt32 message_len)
210 SILC_SERVER_REC *server;
213 SILC_LOG_DEBUG(("Start"));
215 server = conn == NULL ? NULL : conn->context;
216 memset(userhost, 0, sizeof(userhost));
217 if (sender->username)
218 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
219 sender->username, sender->hostname);
221 if (flags & SILC_MESSAGE_FLAG_DATA) {
222 /* MIME object received, try to display it as well as we can */
223 char type[128], enc[128];
227 memset(type, 0, sizeof(type));
228 memset(enc, 0, sizeof(enc));
229 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
230 enc, sizeof(enc) - 1, &data, &data_len))
233 /* Then figure out what we can display */
234 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
235 !strstr(type, "text/vnd")) {
236 /* It is something textual, display it */
237 message = (const unsigned char *)data;
244 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
245 char tmp[256], *cp, *dm = NULL;
247 memset(tmp, 0, sizeof(tmp));
249 if (message_len > sizeof(tmp) - 1) {
250 dm = silc_calloc(message_len + 1, sizeof(*dm));
254 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
256 signal_emit("message private", 4, server, cp,
257 sender->nickname ? sender->nickname : "[<unknown>]",
258 sender->username ? userhost : NULL);
263 signal_emit("message private", 4, server, message,
264 sender->nickname ? sender->nickname : "[<unknown>]",
265 sender->username ? userhost : NULL);
268 /* Notify message to the client. The notify arguments are sent in the
269 same order as servers sends them. The arguments are same as received
270 from the server except for ID's. If ID is received application receives
271 the corresponding entry to the ID. For example, if Client ID is received
272 application receives SilcClientEntry. Also, if the notify type is
273 for channel the channel entry is sent to application (even if server
274 does not send it). */
276 void silc_notify(SilcClient client, SilcClientConnection conn,
277 SilcNotifyType type, ...)
280 SILC_SERVER_REC *server;
281 SILC_CHANNEL_REC *chanrec;
282 SILC_NICK_REC *nickrec;
283 SilcClientEntry client_entry, client_entry2;
284 SilcChannelEntry channel, channel2;
285 SilcServerEntry server_entry;
291 GSList *list1, *list_tmp;
293 SILC_LOG_DEBUG(("Start"));
297 server = conn == NULL ? NULL : conn->context;
300 case SILC_NOTIFY_TYPE_NONE:
301 /* Some generic notice from server */
302 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
305 case SILC_NOTIFY_TYPE_INVITE:
307 * Invited or modified invite list.
310 SILC_LOG_DEBUG(("Notify: INVITE"));
312 channel = va_arg(va, SilcChannelEntry);
313 name = va_arg(va, char *);
314 client_entry = va_arg(va, SilcClientEntry);
316 memset(buf, 0, sizeof(buf));
317 snprintf(buf, sizeof(buf) - 1, "%s@%s",
318 client_entry->username, client_entry->hostname);
319 signal_emit("message invite", 4, server, channel ? channel->channel_name :
320 name, client_entry->nickname, buf);
323 case SILC_NOTIFY_TYPE_JOIN:
328 SILC_LOG_DEBUG(("Notify: JOIN"));
330 client_entry = va_arg(va, SilcClientEntry);
331 channel = va_arg(va, SilcChannelEntry);
333 if (client_entry == server->conn->local_entry) {
334 /* You joined to channel */
335 chanrec = silc_channel_find(server, channel->channel_name);
336 if (chanrec != NULL && !chanrec->joined)
337 chanrec->entry = channel;
339 chanrec = silc_channel_find_entry(server, channel);
340 if (chanrec != NULL) {
341 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
343 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
347 memset(buf, 0, sizeof(buf));
348 if (client_entry->username)
349 snprintf(buf, sizeof(buf) - 1, "%s@%s",
350 client_entry->username, client_entry->hostname);
351 signal_emit("message join", 4, server, channel->channel_name,
352 client_entry->nickname,
353 client_entry->username == NULL ? "" : buf);
356 case SILC_NOTIFY_TYPE_LEAVE:
361 SILC_LOG_DEBUG(("Notify: LEAVE"));
363 client_entry = va_arg(va, SilcClientEntry);
364 channel = va_arg(va, SilcChannelEntry);
366 memset(buf, 0, sizeof(buf));
367 if (client_entry->username)
368 snprintf(buf, sizeof(buf) - 1, "%s@%s",
369 client_entry->username, client_entry->hostname);
370 signal_emit("message part", 5, server, channel->channel_name,
371 client_entry->nickname, client_entry->username ?
372 buf : "", client_entry->nickname);
374 chanrec = silc_channel_find_entry(server, channel);
375 if (chanrec != NULL) {
376 nickrec = silc_nicklist_find(chanrec, client_entry);
378 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
382 case SILC_NOTIFY_TYPE_SIGNOFF:
387 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
389 client_entry = va_arg(va, SilcClientEntry);
390 tmp = va_arg(va, char *);
392 silc_server_free_ftp(server, client_entry);
394 memset(buf, 0, sizeof(buf));
395 if (client_entry->username)
396 snprintf(buf, sizeof(buf) - 1, "%s@%s",
397 client_entry->username, client_entry->hostname);
398 signal_emit("message quit", 4, server, client_entry->nickname,
399 client_entry->username ? buf : "",
402 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
403 for (list_tmp = list1; list_tmp != NULL; list_tmp =
404 list_tmp->next->next) {
405 CHANNEL_REC *channel = list_tmp->data;
406 NICK_REC *nickrec = list_tmp->next->data;
408 nicklist_remove(channel, nickrec);
412 case SILC_NOTIFY_TYPE_TOPIC_SET:
417 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
419 idtype = va_arg(va, int);
420 entry = va_arg(va, void *);
421 tmp = va_arg(va, char *);
422 channel = va_arg(va, SilcChannelEntry);
424 chanrec = silc_channel_find_entry(server, channel);
425 if (chanrec != NULL) {
426 g_free_not_null(chanrec->topic);
427 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
428 signal_emit("channel topic changed", 1, chanrec);
431 if (idtype == SILC_ID_CLIENT) {
432 client_entry = (SilcClientEntry)entry;
433 memset(buf, 0, sizeof(buf));
434 snprintf(buf, sizeof(buf) - 1, "%s@%s",
435 client_entry->username, client_entry->hostname);
436 signal_emit("message topic", 5, server, channel->channel_name,
437 tmp, client_entry->nickname, buf);
438 } else if (idtype == SILC_ID_SERVER) {
439 server_entry = (SilcServerEntry)entry;
440 signal_emit("message topic", 5, server, channel->channel_name,
441 tmp, server_entry->server_name,
442 server_entry->server_name);
443 } else if (idtype == SILC_ID_CHANNEL) {
444 channel = (SilcChannelEntry)entry;
445 signal_emit("message topic", 5, server, channel->channel_name,
446 tmp, channel->channel_name, channel->channel_name);
450 case SILC_NOTIFY_TYPE_NICK_CHANGE:
455 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
457 client_entry = va_arg(va, SilcClientEntry);
458 client_entry2 = va_arg(va, SilcClientEntry);
460 if (!strcmp(client_entry->nickname, client_entry2->nickname))
463 memset(buf, 0, sizeof(buf));
464 snprintf(buf, sizeof(buf) - 1, "%s@%s",
465 client_entry2->username, client_entry2->hostname);
466 nicklist_rename_unique(SERVER(server),
467 client_entry, client_entry->nickname,
468 client_entry2, client_entry2->nickname);
469 signal_emit("message nick", 4, server, client_entry2->nickname,
470 client_entry->nickname, buf);
473 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
475 * Changed channel mode.
478 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
480 idtype = va_arg(va, int);
481 entry = va_arg(va, void *);
482 mode = va_arg(va, SilcUInt32);
483 (void)va_arg(va, char *);
484 (void)va_arg(va, char *);
485 channel = va_arg(va, SilcChannelEntry);
487 tmp = silc_client_chmode(mode,
488 channel->channel_key ?
489 channel->channel_key->cipher->name : "",
491 silc_hmac_get_name(channel->hmac) : "");
493 chanrec = silc_channel_find_entry(server, channel);
494 if (chanrec != NULL) {
495 g_free_not_null(chanrec->mode);
496 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
497 signal_emit("channel mode changed", 1, chanrec);
500 if (idtype == SILC_ID_CLIENT) {
501 client_entry = (SilcClientEntry)entry;
502 printformat_module("fe-common/silc", server, channel->channel_name,
503 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
504 channel->channel_name, tmp ? tmp : "removed all",
505 client_entry->nickname);
506 } else if (idtype == SILC_ID_SERVER) {
507 server_entry = (SilcServerEntry)entry;
508 printformat_module("fe-common/silc", server, channel->channel_name,
509 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
510 channel->channel_name, tmp ? tmp : "removed all",
511 server_entry->server_name);
512 } else if (idtype == SILC_ID_CHANNEL) {
513 channel2 = (SilcChannelEntry)entry;
514 printformat_module("fe-common/silc", server, channel->channel_name,
515 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
516 channel->channel_name, tmp ? tmp : "removed all",
517 channel2->channel_name);
523 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
525 * Changed user's mode on channel.
528 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
530 idtype = va_arg(va, int);
531 entry = va_arg(va, void *);
532 mode = va_arg(va, SilcUInt32);
533 client_entry2 = va_arg(va, SilcClientEntry);
534 channel = va_arg(va, SilcChannelEntry);
536 tmp = silc_client_chumode(mode);
537 chanrec = silc_channel_find_entry(server, channel);
538 if (chanrec != NULL) {
541 if (client_entry2 == server->conn->local_entry)
542 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
544 nick = silc_nicklist_find(chanrec, client_entry2);
546 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
547 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
548 signal_emit("nick mode changed", 2, chanrec, nick);
552 if (idtype == SILC_ID_CLIENT) {
553 client_entry = (SilcClientEntry)entry;
554 printformat_module("fe-common/silc", server, channel->channel_name,
555 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
556 channel->channel_name, client_entry2->nickname,
557 tmp ? tmp : "removed all",
558 client_entry->nickname);
559 } else if (idtype == SILC_ID_SERVER) {
560 server_entry = (SilcServerEntry)entry;
561 printformat_module("fe-common/silc", server, channel->channel_name,
562 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
563 channel->channel_name, client_entry2->nickname,
564 tmp ? tmp : "removed all",
565 server_entry->server_name);
566 } else if (idtype == SILC_ID_CHANNEL) {
567 channel2 = (SilcChannelEntry)entry;
568 printformat_module("fe-common/silc", server, channel->channel_name,
569 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
570 channel->channel_name, client_entry2->nickname,
571 tmp ? tmp : "removed all",
572 channel2->channel_name);
575 if (mode & SILC_CHANNEL_UMODE_CHANFO)
576 printformat_module("fe-common/silc",
577 server, channel->channel_name, MSGLEVEL_CRAP,
578 SILCTXT_CHANNEL_FOUNDER,
579 channel->channel_name, client_entry2->nickname);
581 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
582 printformat_module("fe-common/silc",
583 server, channel->channel_name, MSGLEVEL_CRAP,
584 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
589 case SILC_NOTIFY_TYPE_MOTD:
594 SILC_LOG_DEBUG(("Notify: MOTD"));
596 tmp = va_arg(va, char *);
598 if (!settings_get_bool("skip_motd"))
599 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
602 case SILC_NOTIFY_TYPE_KICKED:
604 * Someone was kicked from channel.
607 SILC_LOG_DEBUG(("Notify: KICKED"));
609 client_entry = va_arg(va, SilcClientEntry);
610 tmp = va_arg(va, char *);
611 client_entry2 = va_arg(va, SilcClientEntry);
612 channel = va_arg(va, SilcChannelEntry);
614 chanrec = silc_channel_find_entry(server, channel);
616 if (client_entry == conn->local_entry) {
617 printformat_module("fe-common/silc", server, channel->channel_name,
618 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
619 channel->channel_name,
620 client_entry ? client_entry2->nickname : "",
623 chanrec->kicked = TRUE;
624 channel_destroy((CHANNEL_REC *)chanrec);
627 printformat_module("fe-common/silc", server, channel->channel_name,
628 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
629 client_entry->nickname, channel->channel_name,
630 client_entry2 ? client_entry2->nickname : "",
634 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
636 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
641 case SILC_NOTIFY_TYPE_KILLED:
643 * Someone was killed from the network.
646 SILC_LOG_DEBUG(("Notify: KILLED"));
648 client_entry = va_arg(va, SilcClientEntry);
649 tmp = va_arg(va, char *);
650 idtype = va_arg(va, int);
651 entry = va_arg(va, SilcClientEntry);
653 if (client_entry == conn->local_entry) {
654 if (idtype == SILC_ID_CLIENT) {
655 client_entry2 = (SilcClientEntry)entry;
656 printformat_module("fe-common/silc", server, NULL,
657 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
658 client_entry2 ? client_entry2->nickname : "",
660 } else if (idtype == SILC_ID_SERVER) {
661 server_entry = (SilcServerEntry)entry;
662 printformat_module("fe-common/silc", server, NULL,
663 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
664 server_entry->server_name, tmp ? tmp : "");
665 } else if (idtype == SILC_ID_CHANNEL) {
666 channel = (SilcChannelEntry)entry;
667 printformat_module("fe-common/silc", server, NULL,
668 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
669 channel->channel_name, tmp ? tmp : "");
672 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
673 for (list_tmp = list1; list_tmp != NULL; list_tmp =
674 list_tmp->next->next) {
675 CHANNEL_REC *channel = list_tmp->data;
676 NICK_REC *nickrec = list_tmp->next->data;
677 nicklist_remove(channel, nickrec);
680 if (idtype == SILC_ID_CLIENT) {
681 client_entry2 = (SilcClientEntry)entry;
682 printformat_module("fe-common/silc", server, NULL,
683 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
684 client_entry->nickname,
685 client_entry2 ? client_entry2->nickname : "",
687 } else if (idtype == SILC_ID_SERVER) {
688 server_entry = (SilcServerEntry)entry;
689 printformat_module("fe-common/silc", server, NULL,
690 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
691 client_entry->nickname,
692 server_entry->server_name, tmp ? tmp : "");
693 } else if (idtype == SILC_ID_CHANNEL) {
694 channel = (SilcChannelEntry)entry;
695 printformat_module("fe-common/silc", server, NULL,
696 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
697 client_entry->nickname,
698 channel->channel_name, tmp ? tmp : "");
703 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
706 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
709 * Server has quit the network.
712 SilcClientEntry *clients;
713 SilcUInt32 clients_count;
715 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
717 (void)va_arg(va, void *);
718 clients = va_arg(va, SilcClientEntry *);
719 clients_count = va_arg(va, SilcUInt32);
721 for (i = 0; i < clients_count; i++) {
722 memset(buf, 0, sizeof(buf));
723 if (clients[i]->username)
724 snprintf(buf, sizeof(buf) - 1, "%s@%s",
725 clients[i]->username, clients[i]->hostname);
726 signal_emit("message quit", 4, server, clients[i]->nickname,
727 clients[i]->username ? buf : "",
730 silc_server_free_ftp(server, clients[i]);
732 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
733 for (list_tmp = list1; list_tmp != NULL; list_tmp =
734 list_tmp->next->next) {
735 CHANNEL_REC *channel = list_tmp->data;
736 NICK_REC *nickrec = list_tmp->next->data;
737 nicklist_remove(channel, nickrec);
743 case SILC_NOTIFY_TYPE_ERROR:
745 SilcStatus error = va_arg(va, int);
747 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
748 "%s", silc_get_status_message(error));
752 case SILC_NOTIFY_TYPE_WATCH:
754 SilcNotifyType notify;
756 client_entry = va_arg(va, SilcClientEntry);
757 name = va_arg(va, char *); /* Maybe NULL */
758 mode = va_arg(va, SilcUInt32);
759 notify = va_arg(va, int);
761 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
763 printformat_module("fe-common/silc", server, NULL,
764 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
765 client_entry->nickname, name);
767 printformat_module("fe-common/silc", server, NULL,
768 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
769 client_entry->nickname);
770 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
771 /* See if client was away and is now present */
772 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
773 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
774 SILC_UMODE_DETACHED)) &&
775 (client_entry->mode & SILC_UMODE_GONE ||
776 client_entry->mode & SILC_UMODE_INDISPOSED ||
777 client_entry->mode & SILC_UMODE_BUSY ||
778 client_entry->mode & SILC_UMODE_PAGE ||
779 client_entry->mode & SILC_UMODE_DETACHED)) {
780 printformat_module("fe-common/silc", server, NULL,
781 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
782 client_entry->nickname);
786 memset(buf, 0, sizeof(buf));
787 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
788 printformat_module("fe-common/silc", server, NULL,
789 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
790 client_entry->nickname, buf);
792 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
793 printformat_module("fe-common/silc", server, NULL,
794 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
795 client_entry->nickname);
796 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
797 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
798 printformat_module("fe-common/silc", server, NULL,
799 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
800 client_entry->nickname);
801 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
802 /* Client logged in to the network */
803 printformat_module("fe-common/silc", server, NULL,
804 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
805 client_entry->nickname);
812 printformat_module("fe-common/silc", server, NULL,
813 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
820 /* Called to indicate that connection was either successfully established
821 or connecting failed. This is also the first time application receives
822 the SilcClientConnection object which it should save somewhere. */
824 void silc_connect(SilcClient client, SilcClientConnection conn,
825 SilcClientConnectionStatus status)
827 SILC_SERVER_REC *server = conn->context;
829 if (!server || server->disconnected) {
830 silc_client_close_connection(client, conn);
835 case SILC_CLIENT_CONN_SUCCESS:
836 /* We have successfully connected to server */
837 server->connected = TRUE;
838 signal_emit("event connected", 1, server);
841 case SILC_CLIENT_CONN_SUCCESS_RESUME:
842 /* We have successfully resumed old detached session */
843 server->connected = TRUE;
844 signal_emit("event connected", 1, server);
846 /* If we resumed old session check whether we need to update
848 if (strcmp(server->nick, conn->local_entry->nickname)) {
850 old = g_strdup(server->nick);
851 server_change_nick(SERVER(server), conn->local_entry->nickname);
852 nicklist_rename_unique(SERVER(server),
853 conn->local_entry, server->nick,
854 conn->local_entry, conn->local_entry->nickname);
855 signal_emit("message own_nick", 4, server, server->nick, old, "");
861 server->connection_lost = TRUE;
863 server->conn->context = NULL;
864 server_disconnect(SERVER(server));
869 /* Called to indicate that connection was disconnected to the server. */
871 void silc_disconnect(SilcClient client, SilcClientConnection conn,
872 SilcStatus status, const char *message)
874 SILC_SERVER_REC *server = conn->context;
876 SILC_LOG_DEBUG(("Start"));
878 if (!server || server->connection_lost)
881 if (server->conn && server->conn->local_entry) {
882 nicklist_rename_unique(SERVER(server),
883 server->conn->local_entry, server->nick,
884 server->conn->local_entry,
885 silc_client->username);
886 silc_change_nick(server, silc_client->username);
890 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
891 "Server closed connection: %s (%d) %s",
892 silc_get_status_message(status), status,
893 message ? message : "");
895 server->conn->context = NULL;
897 server->connection_lost = TRUE;
898 server_disconnect(SERVER(server));
901 /* Command handler. This function is called always in the command function.
902 If error occurs it will be called as well. `conn' is the associated
903 client connection. `cmd_context' is the command context that was
904 originally sent to the command. `success' is FALSE if error occured
905 during command. `command' is the command being processed. It must be
906 noted that this is not reply from server. This is merely called just
907 after application has called the command. Just to tell application
908 that the command really was processed. */
910 void silc_command(SilcClient client, SilcClientConnection conn,
911 SilcClientCommandContext cmd_context, bool success,
912 SilcCommand command, SilcStatus status)
914 SILC_SERVER_REC *server = conn->context;
916 SILC_LOG_DEBUG(("Start"));
919 silc_say_error("%s", silc_get_status_message(status));
925 case SILC_COMMAND_INVITE:
926 printformat_module("fe-common/silc", server, NULL,
927 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
928 cmd_context->argv[2],
929 (cmd_context->argv[1][0] == '*' ?
930 (char *)conn->current_channel->channel_name :
931 (char *)cmd_context->argv[1]));
934 case SILC_COMMAND_DETACH:
935 server->no_reconnect = TRUE;
943 /* Client info resolving callback when JOIN command reply is received.
944 This will cache all users on the channel. */
946 static void silc_client_join_get_users(SilcClient client,
947 SilcClientConnection conn,
948 SilcClientEntry *clients,
949 SilcUInt32 clients_count,
952 SilcChannelEntry channel = (SilcChannelEntry)context;
953 SilcHashTableList htl;
955 SILC_SERVER_REC *server = conn->context;
956 SILC_CHANNEL_REC *chanrec;
957 SilcClientEntry founder = NULL;
960 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
961 silc_hash_table_count(channel->user_list)));
966 chanrec = silc_channel_find(server, channel->channel_name);
970 silc_hash_table_list(channel->user_list, &htl);
971 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
972 if (!chu->client->nickname)
974 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
975 founder = chu->client;
976 silc_nicklist_insert(chanrec, chu, FALSE);
978 silc_hash_table_list_reset(&htl);
980 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
981 nicklist_set_own(CHANNEL(chanrec), ownnick);
982 signal_emit("channel joined", 1, chanrec);
983 chanrec->entry = channel;
986 printformat_module("fe-common/silc", server, channel->channel_name,
987 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
988 channel->channel_name, chanrec->topic);
991 if (founder == conn->local_entry)
992 printformat_module("fe-common/silc",
993 server, channel->channel_name, MSGLEVEL_CRAP,
994 SILCTXT_CHANNEL_FOUNDER_YOU,
995 channel->channel_name);
997 printformat_module("fe-common/silc",
998 server, channel->channel_name, MSGLEVEL_CRAP,
999 SILCTXT_CHANNEL_FOUNDER,
1000 channel->channel_name, founder->nickname);
1006 SilcClientConnection conn;
1012 void silc_getkey_cb(bool success, void *context)
1014 GetkeyContext getkey = (GetkeyContext)context;
1015 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1016 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1017 ((SilcClientEntry)getkey->entry)->nickname :
1018 ((SilcServerEntry)getkey->entry)->server_name);
1021 printformat_module("fe-common/silc", NULL, NULL,
1022 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1024 printformat_module("fe-common/silc", NULL, NULL,
1025 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1029 silc_free(getkey->fingerprint);
1033 /* Command reply handler. This function is called always in the command reply
1034 function. If error occurs it will be called as well. Normal scenario
1035 is that it will be called after the received command data has been parsed
1036 and processed. The function is used to pass the received command data to
1039 `conn' is the associated client connection. `cmd_payload' is the command
1040 payload data received from server and it can be ignored. It is provided
1041 if the application would like to re-parse the received command data,
1042 however, it must be noted that the data is parsed already by the library
1043 thus the payload can be ignored. `success' is FALSE if error occured.
1044 In this case arguments are not sent to the application. `command' is the
1045 command reply being processed. The function has variable argument list
1046 and each command defines the number and type of arguments it passes to the
1047 application (on error they are not sent). */
1050 silc_command_reply(SilcClient client, SilcClientConnection conn,
1051 SilcCommandPayload cmd_payload, bool success,
1052 SilcCommand command, SilcStatus status, ...)
1055 SILC_SERVER_REC *server = conn->context;
1056 SILC_CHANNEL_REC *chanrec;
1059 va_start(vp, status);
1061 SILC_LOG_DEBUG(("Start"));
1064 case SILC_COMMAND_WHOIS:
1066 char buf[1024], *nickname, *username, *realname, *nick;
1067 unsigned char *fingerprint;
1068 SilcUInt32 idle, mode;
1069 SilcBuffer channels, user_modes;
1070 SilcClientEntry client_entry;
1073 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1074 /* Print the unknown nick for user */
1075 unsigned char *tmp =
1076 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1079 silc_say_error("%s: %s", tmp,
1080 silc_get_status_message(status));
1082 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1083 /* Try to find the entry for the unknown client ID, since we
1084 might have, and print the nickname of it for user. */
1086 unsigned char *tmp =
1087 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1090 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1093 client_entry = silc_client_get_client_by_id(client, conn,
1095 if (client_entry && client_entry->nickname)
1096 silc_say_error("%s: %s", client_entry->nickname,
1097 silc_get_status_message(status));
1098 silc_free(client_id);
1102 } else if (!success) {
1103 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1107 client_entry = va_arg(vp, SilcClientEntry);
1108 nickname = va_arg(vp, char *);
1109 username = va_arg(vp, char *);
1110 realname = va_arg(vp, char *);
1111 channels = va_arg(vp, SilcBuffer);
1112 mode = va_arg(vp, SilcUInt32);
1113 idle = va_arg(vp, SilcUInt32);
1114 fingerprint = va_arg(vp, unsigned char *);
1115 user_modes = va_arg(vp, SilcBuffer);
1116 attrs = va_arg(vp, SilcDList);
1118 silc_parse_userfqdn(nickname, &nick, NULL);
1119 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1120 SILCTXT_WHOIS_USERINFO, nickname,
1121 client_entry->username, client_entry->hostname,
1122 nick, client_entry->nickname);
1123 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1124 SILCTXT_WHOIS_REALNAME, realname);
1127 if (channels && user_modes) {
1129 SilcDList list = silc_channel_payload_parse_list(channels->data,
1131 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1133 SilcChannelPayload entry;
1136 memset(buf, 0, sizeof(buf));
1137 silc_dlist_start(list);
1138 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1139 SilcUInt32 name_len;
1140 char *m = silc_client_chumode_char(umodes[i++]);
1141 char *name = silc_channel_get_name(entry, &name_len);
1144 strncat(buf, m, strlen(m));
1145 strncat(buf, name, name_len);
1146 strncat(buf, " ", 1);
1150 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1151 SILCTXT_WHOIS_CHANNELS, buf);
1152 silc_channel_payload_list_free(list);
1158 memset(buf, 0, sizeof(buf));
1159 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1160 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1161 SILCTXT_WHOIS_MODES, buf);
1164 if (idle && nickname) {
1165 memset(buf, 0, sizeof(buf));
1166 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1167 idle > 60 ? (idle / 60) : idle,
1168 idle > 60 ? "minutes" : "seconds");
1170 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1171 SILCTXT_WHOIS_IDLE, buf);
1175 fingerprint = silc_fingerprint(fingerprint, 20);
1176 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1177 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1178 silc_free(fingerprint);
1182 silc_query_attributes_print(server, silc_client, conn, attrs,
1187 case SILC_COMMAND_IDENTIFY:
1189 SilcClientEntry client_entry;
1191 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1192 /* Print the unknown nick for user */
1193 unsigned char *tmp =
1194 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1197 silc_say_error("%s: %s", tmp,
1198 silc_get_status_message(status));
1200 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1201 /* Try to find the entry for the unknown client ID, since we
1202 might have, and print the nickname of it for user. */
1204 unsigned char *tmp =
1205 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1208 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1211 client_entry = silc_client_get_client_by_id(client, conn,
1213 if (client_entry && client_entry->nickname)
1214 silc_say_error("%s: %s", client_entry->nickname,
1215 silc_get_status_message(status));
1216 silc_free(client_id);
1225 case SILC_COMMAND_WHOWAS:
1227 char *nickname, *username, *realname;
1229 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1230 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1232 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1235 silc_say_error("%s: %s", tmp,
1236 silc_get_status_message(status));
1238 } else if (!success) {
1239 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1243 (void)va_arg(vp, SilcClientEntry);
1244 nickname = va_arg(vp, char *);
1245 username = va_arg(vp, char *);
1246 realname = va_arg(vp, char *);
1248 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1249 SILCTXT_WHOWAS_USERINFO, nickname, username,
1250 realname ? realname : "");
1254 case SILC_COMMAND_INVITE:
1256 SilcChannelEntry channel;
1258 SilcArgumentPayload args;
1264 channel = va_arg(vp, SilcChannelEntry);
1265 invite_list = va_arg(vp, char *);
1267 args = silc_command_get_args(cmd_payload);
1269 argc = silc_argument_get_arg_num(args);
1272 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1273 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1276 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1277 SILCTXT_CHANNEL_NO_INVITE_LIST,
1278 channel->channel_name);
1282 case SILC_COMMAND_JOIN:
1284 char *channel, *mode, *topic;
1286 SilcChannelEntry channel_entry;
1287 SilcBuffer client_id_list;
1288 SilcUInt32 list_count;
1293 channel = va_arg(vp, char *);
1294 channel_entry = va_arg(vp, SilcChannelEntry);
1295 modei = va_arg(vp, SilcUInt32);
1296 (void)va_arg(vp, SilcUInt32);
1297 (void)va_arg(vp, unsigned char *);
1298 (void)va_arg(vp, unsigned char *);
1299 (void)va_arg(vp, unsigned char *);
1300 topic = va_arg(vp, char *);
1301 (void)va_arg(vp, unsigned char *);
1302 list_count = va_arg(vp, SilcUInt32);
1303 client_id_list = va_arg(vp, SilcBuffer);
1305 chanrec = silc_channel_find(server, channel);
1307 chanrec = silc_channel_create(server, channel, channel, TRUE);
1310 g_free_not_null(chanrec->topic);
1311 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1312 signal_emit("channel topic changed", 1, chanrec);
1315 mode = silc_client_chmode(modei,
1316 channel_entry->channel_key ?
1317 channel_entry->channel_key->cipher->name : "",
1318 channel_entry->hmac ?
1319 silc_hmac_get_name(channel_entry->hmac) : "");
1320 g_free_not_null(chanrec->mode);
1321 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1322 signal_emit("channel mode changed", 1, chanrec);
1324 /* Resolve the client information */
1325 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1326 silc_client_join_get_users,
1332 case SILC_COMMAND_NICK:
1335 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1340 old = g_strdup(server->nick);
1341 server_change_nick(SERVER(server), client->nickname);
1342 nicklist_rename_unique(SERVER(server),
1343 server->conn->local_entry, server->nick,
1344 client, client->nickname);
1345 signal_emit("message own_nick", 4, server, server->nick, old, "");
1350 case SILC_COMMAND_LIST:
1359 (void)va_arg(vp, SilcChannelEntry);
1360 name = va_arg(vp, char *);
1361 topic = va_arg(vp, char *);
1362 usercount = va_arg(vp, int);
1364 if (status == SILC_STATUS_LIST_START ||
1365 status == SILC_STATUS_OK)
1366 printformat_module("fe-common/silc", server, NULL,
1367 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1370 snprintf(users, sizeof(users) - 1, "N/A");
1372 snprintf(users, sizeof(users) - 1, "%d", usercount);
1373 printformat_module("fe-common/silc", server, NULL,
1374 MSGLEVEL_CRAP, SILCTXT_LIST,
1375 name, users, topic ? topic : "");
1379 case SILC_COMMAND_UMODE:
1386 mode = va_arg(vp, SilcUInt32);
1388 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1389 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1390 printformat_module("fe-common/silc", server, NULL,
1391 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1393 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1394 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1395 printformat_module("fe-common/silc", server, NULL,
1396 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1398 server->umode = mode;
1399 signal_emit("user mode changed", 2, server, NULL);
1403 case SILC_COMMAND_OPER:
1407 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1408 signal_emit("user mode changed", 2, server, NULL);
1410 printformat_module("fe-common/silc", server, NULL,
1411 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1414 case SILC_COMMAND_SILCOPER:
1418 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1419 signal_emit("user mode changed", 2, server, NULL);
1421 printformat_module("fe-common/silc", server, NULL,
1422 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1425 case SILC_COMMAND_USERS:
1427 SilcHashTableList htl;
1428 SilcChannelEntry channel;
1429 SilcChannelUser chu;
1434 channel = va_arg(vp, SilcChannelEntry);
1436 printformat_module("fe-common/silc", server, channel->channel_name,
1437 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1438 channel->channel_name);
1440 silc_hash_table_list(channel->user_list, &htl);
1441 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1442 SilcClientEntry e = chu->client;
1443 char stat[5], *mode;
1448 memset(stat, 0, sizeof(stat));
1449 mode = silc_client_chumode_char(chu->mode);
1450 if (e->mode & SILC_UMODE_GONE)
1452 else if (e->mode & SILC_UMODE_INDISPOSED)
1454 else if (e->mode & SILC_UMODE_BUSY)
1456 else if (e->mode & SILC_UMODE_PAGE)
1458 else if (e->mode & SILC_UMODE_HYPER)
1460 else if (e->mode & SILC_UMODE_ROBOT)
1462 else if (e->mode & SILC_UMODE_ANONYMOUS)
1469 printformat_module("fe-common/silc", server, channel->channel_name,
1470 MSGLEVEL_CRAP, SILCTXT_USERS,
1472 e->username ? e->username : "",
1473 e->hostname ? e->hostname : "",
1474 e->realname ? e->realname : "");
1478 silc_hash_table_list_reset(&htl);
1482 case SILC_COMMAND_BAN:
1484 SilcChannelEntry channel;
1490 channel = va_arg(vp, SilcChannelEntry);
1491 ban_list = va_arg(vp, char *);
1494 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1495 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1498 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1499 SILCTXT_CHANNEL_NO_BAN_LIST,
1500 channel->channel_name);
1504 case SILC_COMMAND_GETKEY:
1508 SilcPublicKey public_key;
1511 GetkeyContext getkey;
1517 id_type = va_arg(vp, SilcUInt32);
1518 entry = va_arg(vp, void *);
1519 public_key = va_arg(vp, SilcPublicKey);
1522 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1524 getkey = silc_calloc(1, sizeof(*getkey));
1525 getkey->entry = entry;
1526 getkey->id_type = id_type;
1527 getkey->client = client;
1528 getkey->conn = conn;
1529 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1531 name = (id_type == SILC_ID_CLIENT ?
1532 ((SilcClientEntry)entry)->nickname :
1533 ((SilcServerEntry)entry)->server_name);
1535 silc_verify_public_key_internal(client, conn, name,
1536 (id_type == SILC_ID_CLIENT ?
1537 SILC_SOCKET_TYPE_CLIENT :
1538 SILC_SOCKET_TYPE_SERVER),
1539 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1540 silc_getkey_cb, getkey);
1543 printformat_module("fe-common/silc", server, NULL,
1544 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1549 case SILC_COMMAND_INFO:
1551 SilcServerEntry server_entry;
1558 server_entry = va_arg(vp, SilcServerEntry);
1559 server_name = va_arg(vp, char *);
1560 server_info = va_arg(vp, char *);
1562 if (server_name && server_info )
1564 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1565 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1570 case SILC_COMMAND_TOPIC:
1572 SilcChannelEntry channel;
1578 channel = va_arg(vp, SilcChannelEntry);
1579 topic = va_arg(vp, char *);
1582 chanrec = silc_channel_find_entry(server, channel);
1584 g_free_not_null(chanrec->topic);
1585 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1586 signal_emit("channel topic changed", 1, chanrec);
1588 printformat_module("fe-common/silc", server, channel->channel_name,
1589 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1590 channel->channel_name, topic);
1592 printformat_module("fe-common/silc", server, channel->channel_name,
1593 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1594 channel->channel_name);
1599 case SILC_COMMAND_WATCH:
1602 case SILC_COMMAND_STATS:
1604 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1605 my_router_ops, cell_clients, cell_channels, cell_servers,
1606 clients, channels, servers, routers, server_ops, router_ops;
1608 SilcBufferStruct buf;
1609 unsigned char *tmp_buf;
1611 const char *tmptime;
1612 int days, hours, mins, secs;
1617 tmp_buf = va_arg(vp, unsigned char *);
1618 buf_len = va_arg(vp, SilcUInt32);
1620 if (!tmp_buf || !buf_len) {
1621 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
1625 /* Get statistics structure */
1626 silc_buffer_set(&buf, tmp_buf, buf_len);
1627 silc_buffer_unformat(&buf,
1628 SILC_STR_UI_INT(&starttime),
1629 SILC_STR_UI_INT(&uptime),
1630 SILC_STR_UI_INT(&my_clients),
1631 SILC_STR_UI_INT(&my_channels),
1632 SILC_STR_UI_INT(&my_server_ops),
1633 SILC_STR_UI_INT(&my_router_ops),
1634 SILC_STR_UI_INT(&cell_clients),
1635 SILC_STR_UI_INT(&cell_channels),
1636 SILC_STR_UI_INT(&cell_servers),
1637 SILC_STR_UI_INT(&clients),
1638 SILC_STR_UI_INT(&channels),
1639 SILC_STR_UI_INT(&servers),
1640 SILC_STR_UI_INT(&routers),
1641 SILC_STR_UI_INT(&server_ops),
1642 SILC_STR_UI_INT(&router_ops),
1645 tmptime = silc_get_time(starttime);
1646 printformat_module("fe-common/silc", server, NULL,
1647 MSGLEVEL_CRAP, SILCTXT_STATS,
1648 "Local server start time", tmptime);
1650 days = uptime / (24 * 60 * 60);
1651 uptime -= days * (24 * 60 * 60);
1652 hours = uptime / (60 * 60);
1653 uptime -= hours * (60 * 60);
1655 uptime -= mins * 60;
1657 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
1658 days, hours, mins, secs);
1659 printformat_module("fe-common/silc", server, NULL,
1660 MSGLEVEL_CRAP, SILCTXT_STATS,
1661 "Local server uptime", tmp);
1663 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
1664 printformat_module("fe-common/silc", server, NULL,
1665 MSGLEVEL_CRAP, SILCTXT_STATS,
1666 "Local server clients", tmp);
1668 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
1669 printformat_module("fe-common/silc", server, NULL,
1670 MSGLEVEL_CRAP, SILCTXT_STATS,
1671 "Local server channels", tmp);
1673 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
1674 printformat_module("fe-common/silc", server, NULL,
1675 MSGLEVEL_CRAP, SILCTXT_STATS,
1676 "Local server operators", tmp);
1678 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
1679 printformat_module("fe-common/silc", server, NULL,
1680 MSGLEVEL_CRAP, SILCTXT_STATS,
1681 "Local router operators", tmp);
1683 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
1684 printformat_module("fe-common/silc", server, NULL,
1685 MSGLEVEL_CRAP, SILCTXT_STATS,
1686 "Local cell clients", tmp);
1688 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
1689 printformat_module("fe-common/silc", server, NULL,
1690 MSGLEVEL_CRAP, SILCTXT_STATS,
1691 "Local cell channels", tmp);
1693 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
1694 printformat_module("fe-common/silc", server, NULL,
1695 MSGLEVEL_CRAP, SILCTXT_STATS,
1696 "Local cell servers", tmp);
1698 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
1699 printformat_module("fe-common/silc", server, NULL,
1700 MSGLEVEL_CRAP, SILCTXT_STATS,
1701 "Total clients", tmp);
1703 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
1704 printformat_module("fe-common/silc", server, NULL,
1705 MSGLEVEL_CRAP, SILCTXT_STATS,
1706 "Total channels", tmp);
1708 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
1709 printformat_module("fe-common/silc", server, NULL,
1710 MSGLEVEL_CRAP, SILCTXT_STATS,
1711 "Total servers", tmp);
1713 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
1714 printformat_module("fe-common/silc", server, NULL,
1715 MSGLEVEL_CRAP, SILCTXT_STATS,
1716 "Total routers", tmp);
1718 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
1719 printformat_module("fe-common/silc", server, NULL,
1720 MSGLEVEL_CRAP, SILCTXT_STATS,
1721 "Total server operators", tmp);
1723 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
1724 printformat_module("fe-common/silc", server, NULL,
1725 MSGLEVEL_CRAP, SILCTXT_STATS,
1726 "Total router operators", tmp);
1737 SilcClientConnection conn;
1743 SilcSKEPKType pk_type;
1744 SilcVerifyPublicKey completion;
1748 static void verify_public_key_completion(const char *line, void *context)
1750 PublicKeyVerify verify = (PublicKeyVerify)context;
1752 if (line[0] == 'Y' || line[0] == 'y') {
1753 /* Call the completion */
1754 if (verify->completion)
1755 verify->completion(TRUE, verify->context);
1757 /* Save the key for future checking */
1758 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1759 verify->pk_len, SILC_PKCS_FILE_PEM);
1761 /* Call the completion */
1762 if (verify->completion)
1763 verify->completion(FALSE, verify->context);
1765 printformat_module("fe-common/silc", NULL, NULL,
1766 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1767 verify->entity_name ? verify->entity_name :
1771 silc_free(verify->filename);
1772 silc_free(verify->entity);
1773 silc_free(verify->entity_name);
1774 silc_free(verify->pk);
1778 /* Internal routine to verify public key. If the `completion' is provided
1779 it will be called to indicate whether public was verified or not. For
1780 server/router public key this will check for filename that includes the
1781 remote host's IP address and remote host's hostname. */
1784 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1785 const char *name, SilcSocketType conn_type,
1786 unsigned char *pk, SilcUInt32 pk_len,
1787 SilcSKEPKType pk_type,
1788 SilcVerifyPublicKey completion, void *context)
1791 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1792 char *fingerprint, *babbleprint, *format;
1795 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1796 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1797 "server" : "client");
1798 PublicKeyVerify verify;
1800 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1801 printformat_module("fe-common/silc", NULL, NULL,
1802 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1805 completion(FALSE, context);
1809 pw = getpwuid(getuid());
1812 completion(FALSE, context);
1816 memset(filename, 0, sizeof(filename));
1817 memset(filename2, 0, sizeof(filename2));
1818 memset(file, 0, sizeof(file));
1820 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1821 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1823 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1824 conn->sock->ip, conn->sock->port);
1825 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1826 get_irssi_dir(), entity, file);
1828 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1829 conn->sock->hostname, conn->sock->port);
1830 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1831 get_irssi_dir(), entity, file);
1836 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1837 name, conn->sock->port);
1838 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1839 get_irssi_dir(), entity, file);
1844 /* Replace all whitespaces with `_'. */
1845 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1846 for (i = 0; i < strlen(fingerprint); i++)
1847 if (fingerprint[i] == ' ')
1848 fingerprint[i] = '_';
1850 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1851 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1852 get_irssi_dir(), entity, file);
1853 silc_free(fingerprint);
1858 /* Take fingerprint of the public key */
1859 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1860 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1862 verify = silc_calloc(1, sizeof(*verify));
1863 verify->client = client;
1864 verify->conn = conn;
1865 verify->filename = strdup(ipf);
1866 verify->entity = strdup(entity);
1867 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1868 (name ? strdup(name) : strdup(conn->sock->hostname))
1870 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1871 memcpy(verify->pk, pk, pk_len);
1872 verify->pk_len = pk_len;
1873 verify->pk_type = pk_type;
1874 verify->completion = completion;
1875 verify->context = context;
1877 /* Check whether this key already exists */
1878 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1879 /* Key does not exist, ask user to verify the key and save it */
1881 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1882 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1883 verify->entity_name : entity);
1884 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1885 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1886 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1887 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1888 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1889 SILCTXT_PUBKEY_ACCEPT);
1890 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1893 silc_free(fingerprint);
1896 /* The key already exists, verify it. */
1897 SilcPublicKey public_key;
1898 unsigned char *encpk;
1899 SilcUInt32 encpk_len;
1901 /* Load the key file, try for both IP filename and hostname filename */
1902 if (!silc_pkcs_load_public_key(ipf, &public_key,
1903 SILC_PKCS_FILE_PEM) &&
1904 !silc_pkcs_load_public_key(ipf, &public_key,
1905 SILC_PKCS_FILE_BIN) &&
1906 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1907 SILC_PKCS_FILE_PEM) &&
1908 !silc_pkcs_load_public_key(hostf, &public_key,
1909 SILC_PKCS_FILE_BIN)))) {
1910 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1911 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1912 verify->entity_name : entity);
1913 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1914 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1915 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1916 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1917 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1918 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1919 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1920 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1921 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1924 silc_free(fingerprint);
1928 /* Encode the key data */
1929 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1931 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1932 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1933 verify->entity_name : entity);
1934 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1935 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1936 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1937 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1938 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1939 SILCTXT_PUBKEY_MALFORMED, entity);
1940 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1941 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1942 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1945 silc_free(fingerprint);
1949 /* Compare the keys */
1950 if (memcmp(encpk, pk, encpk_len)) {
1951 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1952 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1953 verify->entity_name : entity);
1954 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1955 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1956 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1957 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1958 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1959 SILCTXT_PUBKEY_NO_MATCH, entity);
1960 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1961 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1962 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1963 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1965 /* Ask user to verify the key and save it */
1966 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1967 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1968 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1971 silc_free(fingerprint);
1975 /* Local copy matched */
1977 completion(TRUE, context);
1978 silc_free(fingerprint);
1982 /* Verifies received public key. The `conn_type' indicates which entity
1983 (server, client etc.) has sent the public key. If user decides to trust
1984 the key may be saved as trusted public key for later use. The
1985 `completion' must be called after the public key has been verified. */
1988 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1989 SilcSocketType conn_type, unsigned char *pk,
1990 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1991 SilcVerifyPublicKey completion, void *context)
1993 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1995 completion, context);
1998 /* Asks passphrase from user on the input line. */
2001 SilcAskPassphrase completion;
2005 void ask_passphrase_completion(const char *passphrase, void *context)
2007 AskPassphrase p = (AskPassphrase)context;
2008 if (passphrase && passphrase[0] == '\0')
2010 p->completion((unsigned char *)passphrase,
2011 passphrase ? strlen(passphrase) : 0, p->context);
2015 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2016 SilcAskPassphrase completion, void *context)
2018 AskPassphrase p = silc_calloc(1, sizeof(*p));
2019 p->completion = completion;
2020 p->context = context;
2022 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2023 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2027 SilcGetAuthMeth completion;
2029 } *InternalGetAuthMethod;
2031 /* Callback called when we've received the authentication method information
2032 from the server after we've requested it. This will get the authentication
2033 data from the user if needed. */
2035 static void silc_get_auth_method_callback(SilcClient client,
2036 SilcClientConnection conn,
2037 SilcAuthMethod auth_meth,
2040 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2042 SILC_LOG_DEBUG(("Start"));
2044 switch (auth_meth) {
2045 case SILC_AUTH_NONE:
2046 /* No authentication required. */
2047 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2049 case SILC_AUTH_PASSWORD:
2051 /* Check whether we find the password for this server in our
2052 configuration. If not, then don't provide so library will ask
2053 it from the user. */
2054 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2056 if (!setup || !setup->password) {
2057 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2061 (*internal->completion)(TRUE, auth_meth, setup->password,
2062 strlen(setup->password), internal->context);
2065 case SILC_AUTH_PUBLIC_KEY:
2066 /* Do not get the authentication data now, the library will generate
2067 it using our default key, if we do not provide it here. */
2068 /* XXX In the future when we support multiple local keys and multiple
2069 local certificates we will need to ask from user which one to use. */
2070 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2074 silc_free(internal);
2077 /* Find authentication method and authentication data by hostname and
2078 port. The hostname may be IP address as well. The found authentication
2079 method and authentication data is returned to `auth_meth', `auth_data'
2080 and `auth_data_len'. The function returns TRUE if authentication method
2081 is found and FALSE if not. `conn' may be NULL. */
2083 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2084 char *hostname, SilcUInt16 port,
2085 SilcGetAuthMeth completion, void *context)
2087 InternalGetAuthMethod internal;
2089 SILC_LOG_DEBUG(("Start"));
2091 /* If we do not have this connection configured by the user in a
2092 configuration file then resolve the authentication method from the
2093 server for this session. */
2094 internal = silc_calloc(1, sizeof(*internal));
2095 internal->completion = completion;
2096 internal->context = context;
2098 silc_client_request_authentication_method(client, conn,
2099 silc_get_auth_method_callback,
2103 /* Notifies application that failure packet was received. This is called
2104 if there is some protocol active in the client. The `protocol' is the
2105 protocol context. The `failure' is opaque pointer to the failure
2106 indication. Note, that the `failure' is protocol dependant and application
2107 must explicitly cast it to correct type. Usually `failure' is 32 bit
2108 failure type (see protocol specs for all protocol failure types). */
2110 void silc_failure(SilcClient client, SilcClientConnection conn,
2111 SilcProtocol protocol, void *failure)
2113 SILC_LOG_DEBUG(("Start"));
2115 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2116 SilcSKEStatus status = (SilcSKEStatus)failure;
2118 if (status == SILC_SKE_STATUS_BAD_VERSION)
2119 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2120 SILCTXT_KE_BAD_VERSION);
2121 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2122 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2123 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2124 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2125 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2126 SILCTXT_KE_UNKNOWN_GROUP);
2127 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2128 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2129 SILCTXT_KE_UNKNOWN_CIPHER);
2130 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2131 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2132 SILCTXT_KE_UNKNOWN_PKCS);
2133 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2134 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2135 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2136 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2137 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2138 SILCTXT_KE_UNKNOWN_HMAC);
2139 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2140 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2141 SILCTXT_KE_INCORRECT_SIGNATURE);
2142 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2143 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2144 SILCTXT_KE_INVALID_COOKIE);
2147 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2148 SilcUInt32 err = (SilcUInt32)failure;
2150 if (err == SILC_AUTH_FAILED)
2151 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2152 SILCTXT_AUTH_FAILED);
2156 /* Asks whether the user would like to perform the key agreement protocol.
2157 This is called after we have received an key agreement packet or an
2158 reply to our key agreement packet. This returns TRUE if the user wants
2159 the library to perform the key agreement protocol and FALSE if it is not
2160 desired (application may start it later by calling the function
2161 silc_client_perform_key_agreement). */
2163 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2164 SilcClientEntry client_entry, const char *hostname,
2165 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2170 SILC_LOG_DEBUG(("Start"));
2172 /* We will just display the info on the screen and return FALSE and user
2173 will have to start the key agreement with a command. */
2176 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2179 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2180 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2182 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2183 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2184 client_entry->nickname, hostname, portstr);
2192 /* Notifies application that file transfer protocol session is being
2193 requested by the remote client indicated by the `client_entry' from
2194 the `hostname' and `port'. The `session_id' is the file transfer
2195 session and it can be used to either accept or reject the file
2196 transfer request, by calling the silc_client_file_receive or
2197 silc_client_file_close, respectively. */
2199 void silc_ftp(SilcClient client, SilcClientConnection conn,
2200 SilcClientEntry client_entry, SilcUInt32 session_id,
2201 const char *hostname, SilcUInt16 port)
2203 SILC_SERVER_REC *server;
2205 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2207 SILC_LOG_DEBUG(("Start"));
2209 server = conn->context;
2211 ftp->client_entry = client_entry;
2212 ftp->session_id = session_id;
2215 silc_dlist_add(server->ftp_sessions, ftp);
2216 server->current_session = ftp;
2219 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2222 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2223 SILCTXT_FILE_REQUEST, client_entry->nickname);
2225 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2226 SILCTXT_FILE_REQUEST_HOST,
2227 client_entry->nickname, hostname, portstr);
2230 /* Delivers SILC session detachment data indicated by `detach_data' to the
2231 application. If application has issued SILC_COMMAND_DETACH command
2232 the client session in the SILC network is not quit. The client remains
2233 in the network but is detached. The detachment data may be used later
2234 to resume the session in the SILC Network. The appliation is
2235 responsible of saving the `detach_data', to for example in a file.
2237 The detachment data can be given as argument to the functions
2238 silc_client_connect_to_server, or silc_client_add_connection when
2239 creating connection to remote server, inside SilcClientConnectionParams
2240 structure. If it is provided the client library will attempt to resume
2241 the session in the network. After the connection is created
2242 successfully, the application is responsible of setting the user
2243 interface for user into the same state it was before detaching (showing
2244 same channels, channel modes, etc). It can do this by fetching the
2245 information (like joined channels) from the client library. */
2248 silc_detach(SilcClient client, SilcClientConnection conn,
2249 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2253 /* Save the detachment data to file. */
2255 memset(file, 0, sizeof(file));
2256 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2257 silc_file_writefile(file, detach_data, detach_data_len);
2261 /* SILC client operations */
2262 SilcClientOperations ops = {
2264 silc_channel_message,
2265 silc_private_message,
2271 silc_get_auth_method,
2272 silc_verify_public_key,
2273 silc_ask_passphrase,