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 silc_cipher_get_name(channel->channel_key) : "",
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 silc_cipher_get_name(channel_entry->
1319 channel_entry->hmac ?
1320 silc_hmac_get_name(channel_entry->hmac) : "");
1321 g_free_not_null(chanrec->mode);
1322 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1323 signal_emit("channel mode changed", 1, chanrec);
1325 /* Resolve the client information */
1326 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1327 silc_client_join_get_users,
1333 case SILC_COMMAND_NICK:
1336 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1341 old = g_strdup(server->nick);
1342 server_change_nick(SERVER(server), client->nickname);
1343 nicklist_rename_unique(SERVER(server),
1344 server->conn->local_entry, server->nick,
1345 client, client->nickname);
1346 signal_emit("message own_nick", 4, server, server->nick, old, "");
1351 case SILC_COMMAND_LIST:
1360 (void)va_arg(vp, SilcChannelEntry);
1361 name = va_arg(vp, char *);
1362 topic = va_arg(vp, char *);
1363 usercount = va_arg(vp, int);
1365 if (status == SILC_STATUS_LIST_START ||
1366 status == SILC_STATUS_OK)
1367 printformat_module("fe-common/silc", server, NULL,
1368 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1371 snprintf(users, sizeof(users) - 1, "N/A");
1373 snprintf(users, sizeof(users) - 1, "%d", usercount);
1374 printformat_module("fe-common/silc", server, NULL,
1375 MSGLEVEL_CRAP, SILCTXT_LIST,
1376 name, users, topic ? topic : "");
1380 case SILC_COMMAND_UMODE:
1387 mode = va_arg(vp, SilcUInt32);
1389 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1390 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1391 printformat_module("fe-common/silc", server, NULL,
1392 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1394 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1395 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1396 printformat_module("fe-common/silc", server, NULL,
1397 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1399 server->umode = mode;
1400 signal_emit("user mode changed", 2, server, NULL);
1404 case SILC_COMMAND_OPER:
1408 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1409 signal_emit("user mode changed", 2, server, NULL);
1411 printformat_module("fe-common/silc", server, NULL,
1412 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1415 case SILC_COMMAND_SILCOPER:
1419 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1420 signal_emit("user mode changed", 2, server, NULL);
1422 printformat_module("fe-common/silc", server, NULL,
1423 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1426 case SILC_COMMAND_USERS:
1428 SilcHashTableList htl;
1429 SilcChannelEntry channel;
1430 SilcChannelUser chu;
1435 channel = va_arg(vp, SilcChannelEntry);
1437 printformat_module("fe-common/silc", server, channel->channel_name,
1438 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1439 channel->channel_name);
1441 silc_hash_table_list(channel->user_list, &htl);
1442 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1443 SilcClientEntry e = chu->client;
1444 char stat[5], *mode;
1449 memset(stat, 0, sizeof(stat));
1450 mode = silc_client_chumode_char(chu->mode);
1451 if (e->mode & SILC_UMODE_GONE)
1453 else if (e->mode & SILC_UMODE_INDISPOSED)
1455 else if (e->mode & SILC_UMODE_BUSY)
1457 else if (e->mode & SILC_UMODE_PAGE)
1459 else if (e->mode & SILC_UMODE_HYPER)
1461 else if (e->mode & SILC_UMODE_ROBOT)
1463 else if (e->mode & SILC_UMODE_ANONYMOUS)
1470 printformat_module("fe-common/silc", server, channel->channel_name,
1471 MSGLEVEL_CRAP, SILCTXT_USERS,
1473 e->username ? e->username : "",
1474 e->hostname ? e->hostname : "",
1475 e->realname ? e->realname : "");
1479 silc_hash_table_list_reset(&htl);
1483 case SILC_COMMAND_BAN:
1485 SilcChannelEntry channel;
1491 channel = va_arg(vp, SilcChannelEntry);
1492 ban_list = va_arg(vp, char *);
1495 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1496 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1499 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1500 SILCTXT_CHANNEL_NO_BAN_LIST,
1501 channel->channel_name);
1505 case SILC_COMMAND_GETKEY:
1509 SilcPublicKey public_key;
1512 GetkeyContext getkey;
1518 id_type = va_arg(vp, SilcUInt32);
1519 entry = va_arg(vp, void *);
1520 public_key = va_arg(vp, SilcPublicKey);
1523 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1525 getkey = silc_calloc(1, sizeof(*getkey));
1526 getkey->entry = entry;
1527 getkey->id_type = id_type;
1528 getkey->client = client;
1529 getkey->conn = conn;
1530 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1532 name = (id_type == SILC_ID_CLIENT ?
1533 ((SilcClientEntry)entry)->nickname :
1534 ((SilcServerEntry)entry)->server_name);
1536 silc_verify_public_key_internal(client, conn, name,
1537 (id_type == SILC_ID_CLIENT ?
1538 SILC_SOCKET_TYPE_CLIENT :
1539 SILC_SOCKET_TYPE_SERVER),
1540 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1541 silc_getkey_cb, getkey);
1544 printformat_module("fe-common/silc", server, NULL,
1545 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1550 case SILC_COMMAND_INFO:
1552 SilcServerEntry server_entry;
1559 server_entry = va_arg(vp, SilcServerEntry);
1560 server_name = va_arg(vp, char *);
1561 server_info = va_arg(vp, char *);
1563 if (server_name && server_info )
1565 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1566 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1571 case SILC_COMMAND_TOPIC:
1573 SilcChannelEntry channel;
1579 channel = va_arg(vp, SilcChannelEntry);
1580 topic = va_arg(vp, char *);
1583 chanrec = silc_channel_find_entry(server, channel);
1585 g_free_not_null(chanrec->topic);
1586 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1587 signal_emit("channel topic changed", 1, chanrec);
1589 printformat_module("fe-common/silc", server, channel->channel_name,
1590 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1591 channel->channel_name, topic);
1593 printformat_module("fe-common/silc", server, channel->channel_name,
1594 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1595 channel->channel_name);
1600 case SILC_COMMAND_WATCH:
1603 case SILC_COMMAND_STATS:
1605 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1606 my_router_ops, cell_clients, cell_channels, cell_servers,
1607 clients, channels, servers, routers, server_ops, router_ops;
1609 SilcBufferStruct buf;
1610 unsigned char *tmp_buf;
1612 const char *tmptime;
1613 int days, hours, mins, secs;
1618 tmp_buf = va_arg(vp, unsigned char *);
1619 buf_len = va_arg(vp, SilcUInt32);
1621 if (!tmp_buf || !buf_len) {
1622 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
1626 /* Get statistics structure */
1627 silc_buffer_set(&buf, tmp_buf, buf_len);
1628 silc_buffer_unformat(&buf,
1629 SILC_STR_UI_INT(&starttime),
1630 SILC_STR_UI_INT(&uptime),
1631 SILC_STR_UI_INT(&my_clients),
1632 SILC_STR_UI_INT(&my_channels),
1633 SILC_STR_UI_INT(&my_server_ops),
1634 SILC_STR_UI_INT(&my_router_ops),
1635 SILC_STR_UI_INT(&cell_clients),
1636 SILC_STR_UI_INT(&cell_channels),
1637 SILC_STR_UI_INT(&cell_servers),
1638 SILC_STR_UI_INT(&clients),
1639 SILC_STR_UI_INT(&channels),
1640 SILC_STR_UI_INT(&servers),
1641 SILC_STR_UI_INT(&routers),
1642 SILC_STR_UI_INT(&server_ops),
1643 SILC_STR_UI_INT(&router_ops),
1646 tmptime = silc_get_time(starttime);
1647 printformat_module("fe-common/silc", server, NULL,
1648 MSGLEVEL_CRAP, SILCTXT_STATS,
1649 "Local server start time", tmptime);
1651 days = uptime / (24 * 60 * 60);
1652 uptime -= days * (24 * 60 * 60);
1653 hours = uptime / (60 * 60);
1654 uptime -= hours * (60 * 60);
1656 uptime -= mins * 60;
1658 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
1659 days, hours, mins, secs);
1660 printformat_module("fe-common/silc", server, NULL,
1661 MSGLEVEL_CRAP, SILCTXT_STATS,
1662 "Local server uptime", tmp);
1664 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
1665 printformat_module("fe-common/silc", server, NULL,
1666 MSGLEVEL_CRAP, SILCTXT_STATS,
1667 "Local server clients", tmp);
1669 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
1670 printformat_module("fe-common/silc", server, NULL,
1671 MSGLEVEL_CRAP, SILCTXT_STATS,
1672 "Local server channels", tmp);
1674 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
1675 printformat_module("fe-common/silc", server, NULL,
1676 MSGLEVEL_CRAP, SILCTXT_STATS,
1677 "Local server operators", tmp);
1679 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
1680 printformat_module("fe-common/silc", server, NULL,
1681 MSGLEVEL_CRAP, SILCTXT_STATS,
1682 "Local router operators", tmp);
1684 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
1685 printformat_module("fe-common/silc", server, NULL,
1686 MSGLEVEL_CRAP, SILCTXT_STATS,
1687 "Local cell clients", tmp);
1689 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
1690 printformat_module("fe-common/silc", server, NULL,
1691 MSGLEVEL_CRAP, SILCTXT_STATS,
1692 "Local cell channels", tmp);
1694 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
1695 printformat_module("fe-common/silc", server, NULL,
1696 MSGLEVEL_CRAP, SILCTXT_STATS,
1697 "Local cell servers", tmp);
1699 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
1700 printformat_module("fe-common/silc", server, NULL,
1701 MSGLEVEL_CRAP, SILCTXT_STATS,
1702 "Total clients", tmp);
1704 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
1705 printformat_module("fe-common/silc", server, NULL,
1706 MSGLEVEL_CRAP, SILCTXT_STATS,
1707 "Total channels", tmp);
1709 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
1710 printformat_module("fe-common/silc", server, NULL,
1711 MSGLEVEL_CRAP, SILCTXT_STATS,
1712 "Total servers", tmp);
1714 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
1715 printformat_module("fe-common/silc", server, NULL,
1716 MSGLEVEL_CRAP, SILCTXT_STATS,
1717 "Total routers", tmp);
1719 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
1720 printformat_module("fe-common/silc", server, NULL,
1721 MSGLEVEL_CRAP, SILCTXT_STATS,
1722 "Total server operators", tmp);
1724 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
1725 printformat_module("fe-common/silc", server, NULL,
1726 MSGLEVEL_CRAP, SILCTXT_STATS,
1727 "Total router operators", tmp);
1738 SilcClientConnection conn;
1744 SilcSKEPKType pk_type;
1745 SilcVerifyPublicKey completion;
1749 static void verify_public_key_completion(const char *line, void *context)
1751 PublicKeyVerify verify = (PublicKeyVerify)context;
1753 if (line[0] == 'Y' || line[0] == 'y') {
1754 /* Call the completion */
1755 if (verify->completion)
1756 verify->completion(TRUE, verify->context);
1758 /* Save the key for future checking */
1759 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1760 verify->pk_len, SILC_PKCS_FILE_PEM);
1762 /* Call the completion */
1763 if (verify->completion)
1764 verify->completion(FALSE, verify->context);
1766 printformat_module("fe-common/silc", NULL, NULL,
1767 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1768 verify->entity_name ? verify->entity_name :
1772 silc_free(verify->filename);
1773 silc_free(verify->entity);
1774 silc_free(verify->entity_name);
1775 silc_free(verify->pk);
1779 /* Internal routine to verify public key. If the `completion' is provided
1780 it will be called to indicate whether public was verified or not. For
1781 server/router public key this will check for filename that includes the
1782 remote host's IP address and remote host's hostname. */
1785 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1786 const char *name, SilcSocketType conn_type,
1787 unsigned char *pk, SilcUInt32 pk_len,
1788 SilcSKEPKType pk_type,
1789 SilcVerifyPublicKey completion, void *context)
1792 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1793 char *fingerprint, *babbleprint, *format;
1796 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1797 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1798 "server" : "client");
1799 PublicKeyVerify verify;
1801 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1802 printformat_module("fe-common/silc", NULL, NULL,
1803 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1806 completion(FALSE, context);
1810 pw = getpwuid(getuid());
1813 completion(FALSE, context);
1817 memset(filename, 0, sizeof(filename));
1818 memset(filename2, 0, sizeof(filename2));
1819 memset(file, 0, sizeof(file));
1821 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1822 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1824 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1825 conn->sock->ip, conn->sock->port);
1826 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1827 get_irssi_dir(), entity, file);
1829 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1830 conn->sock->hostname, conn->sock->port);
1831 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1832 get_irssi_dir(), entity, file);
1837 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1838 name, conn->sock->port);
1839 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1840 get_irssi_dir(), entity, file);
1845 /* Replace all whitespaces with `_'. */
1846 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1847 for (i = 0; i < strlen(fingerprint); i++)
1848 if (fingerprint[i] == ' ')
1849 fingerprint[i] = '_';
1851 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1852 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1853 get_irssi_dir(), entity, file);
1854 silc_free(fingerprint);
1859 /* Take fingerprint of the public key */
1860 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1861 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1863 verify = silc_calloc(1, sizeof(*verify));
1864 verify->client = client;
1865 verify->conn = conn;
1866 verify->filename = strdup(ipf);
1867 verify->entity = strdup(entity);
1868 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1869 (name ? strdup(name) : strdup(conn->sock->hostname))
1871 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1872 memcpy(verify->pk, pk, pk_len);
1873 verify->pk_len = pk_len;
1874 verify->pk_type = pk_type;
1875 verify->completion = completion;
1876 verify->context = context;
1878 /* Check whether this key already exists */
1879 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1880 /* Key does not exist, ask user to verify the key and save it */
1882 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1883 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1884 verify->entity_name : entity);
1885 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1886 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1887 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1888 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1889 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1890 SILCTXT_PUBKEY_ACCEPT);
1891 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1894 silc_free(fingerprint);
1897 /* The key already exists, verify it. */
1898 SilcPublicKey public_key;
1899 unsigned char *encpk;
1900 SilcUInt32 encpk_len;
1902 /* Load the key file, try for both IP filename and hostname filename */
1903 if (!silc_pkcs_load_public_key(ipf, &public_key,
1904 SILC_PKCS_FILE_PEM) &&
1905 !silc_pkcs_load_public_key(ipf, &public_key,
1906 SILC_PKCS_FILE_BIN) &&
1907 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1908 SILC_PKCS_FILE_PEM) &&
1909 !silc_pkcs_load_public_key(hostf, &public_key,
1910 SILC_PKCS_FILE_BIN)))) {
1911 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1912 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1913 verify->entity_name : entity);
1914 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1915 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1916 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1917 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1918 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1919 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1920 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1921 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1922 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1925 silc_free(fingerprint);
1929 /* Encode the key data */
1930 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1932 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1933 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1934 verify->entity_name : entity);
1935 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1936 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1937 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1938 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1939 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1940 SILCTXT_PUBKEY_MALFORMED, entity);
1941 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1942 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1943 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1946 silc_free(fingerprint);
1950 /* Compare the keys */
1951 if (memcmp(encpk, pk, encpk_len)) {
1952 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1953 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1954 verify->entity_name : entity);
1955 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1956 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1957 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1958 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1959 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1960 SILCTXT_PUBKEY_NO_MATCH, entity);
1961 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1962 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1963 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1964 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1966 /* Ask user to verify the key and save it */
1967 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1968 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1969 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1972 silc_free(fingerprint);
1976 /* Local copy matched */
1978 completion(TRUE, context);
1979 silc_free(fingerprint);
1983 /* Verifies received public key. The `conn_type' indicates which entity
1984 (server, client etc.) has sent the public key. If user decides to trust
1985 the key may be saved as trusted public key for later use. The
1986 `completion' must be called after the public key has been verified. */
1989 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1990 SilcSocketType conn_type, unsigned char *pk,
1991 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1992 SilcVerifyPublicKey completion, void *context)
1994 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1996 completion, context);
1999 /* Asks passphrase from user on the input line. */
2002 SilcAskPassphrase completion;
2006 void ask_passphrase_completion(const char *passphrase, void *context)
2008 AskPassphrase p = (AskPassphrase)context;
2009 if (passphrase && passphrase[0] == '\0')
2011 p->completion((unsigned char *)passphrase,
2012 passphrase ? strlen(passphrase) : 0, p->context);
2016 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2017 SilcAskPassphrase completion, void *context)
2019 AskPassphrase p = silc_calloc(1, sizeof(*p));
2020 p->completion = completion;
2021 p->context = context;
2023 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2024 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2028 SilcGetAuthMeth completion;
2030 } *InternalGetAuthMethod;
2032 /* Callback called when we've received the authentication method information
2033 from the server after we've requested it. This will get the authentication
2034 data from the user if needed. */
2036 static void silc_get_auth_method_callback(SilcClient client,
2037 SilcClientConnection conn,
2038 SilcAuthMethod auth_meth,
2041 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2043 SILC_LOG_DEBUG(("Start"));
2045 switch (auth_meth) {
2046 case SILC_AUTH_NONE:
2047 /* No authentication required. */
2048 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2050 case SILC_AUTH_PASSWORD:
2052 /* Check whether we find the password for this server in our
2053 configuration. If not, then don't provide so library will ask
2054 it from the user. */
2055 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2057 if (!setup || !setup->password) {
2058 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2062 (*internal->completion)(TRUE, auth_meth, setup->password,
2063 strlen(setup->password), internal->context);
2066 case SILC_AUTH_PUBLIC_KEY:
2067 /* Do not get the authentication data now, the library will generate
2068 it using our default key, if we do not provide it here. */
2069 /* XXX In the future when we support multiple local keys and multiple
2070 local certificates we will need to ask from user which one to use. */
2071 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2075 silc_free(internal);
2078 /* Find authentication method and authentication data by hostname and
2079 port. The hostname may be IP address as well. The found authentication
2080 method and authentication data is returned to `auth_meth', `auth_data'
2081 and `auth_data_len'. The function returns TRUE if authentication method
2082 is found and FALSE if not. `conn' may be NULL. */
2084 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2085 char *hostname, SilcUInt16 port,
2086 SilcGetAuthMeth completion, void *context)
2088 InternalGetAuthMethod internal;
2090 SILC_LOG_DEBUG(("Start"));
2092 /* If we do not have this connection configured by the user in a
2093 configuration file then resolve the authentication method from the
2094 server for this session. */
2095 internal = silc_calloc(1, sizeof(*internal));
2096 internal->completion = completion;
2097 internal->context = context;
2099 silc_client_request_authentication_method(client, conn,
2100 silc_get_auth_method_callback,
2104 /* Notifies application that failure packet was received. This is called
2105 if there is some protocol active in the client. The `protocol' is the
2106 protocol context. The `failure' is opaque pointer to the failure
2107 indication. Note, that the `failure' is protocol dependant and application
2108 must explicitly cast it to correct type. Usually `failure' is 32 bit
2109 failure type (see protocol specs for all protocol failure types). */
2111 void silc_failure(SilcClient client, SilcClientConnection conn,
2112 SilcProtocol protocol, void *failure)
2114 SILC_LOG_DEBUG(("Start"));
2116 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2117 SilcSKEStatus status = (SilcSKEStatus)failure;
2119 if (status == SILC_SKE_STATUS_BAD_VERSION)
2120 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2121 SILCTXT_KE_BAD_VERSION);
2122 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2123 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2124 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2125 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2126 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2127 SILCTXT_KE_UNKNOWN_GROUP);
2128 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2129 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2130 SILCTXT_KE_UNKNOWN_CIPHER);
2131 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2132 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2133 SILCTXT_KE_UNKNOWN_PKCS);
2134 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2135 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2136 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2137 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2138 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2139 SILCTXT_KE_UNKNOWN_HMAC);
2140 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2141 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2142 SILCTXT_KE_INCORRECT_SIGNATURE);
2143 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2144 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2145 SILCTXT_KE_INVALID_COOKIE);
2148 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2149 SilcUInt32 err = (SilcUInt32)failure;
2151 if (err == SILC_AUTH_FAILED)
2152 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2153 SILCTXT_AUTH_FAILED);
2157 /* Asks whether the user would like to perform the key agreement protocol.
2158 This is called after we have received an key agreement packet or an
2159 reply to our key agreement packet. This returns TRUE if the user wants
2160 the library to perform the key agreement protocol and FALSE if it is not
2161 desired (application may start it later by calling the function
2162 silc_client_perform_key_agreement). */
2164 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2165 SilcClientEntry client_entry, const char *hostname,
2166 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2171 SILC_LOG_DEBUG(("Start"));
2173 /* We will just display the info on the screen and return FALSE and user
2174 will have to start the key agreement with a command. */
2177 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2180 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2181 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2183 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2184 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2185 client_entry->nickname, hostname, portstr);
2193 /* Notifies application that file transfer protocol session is being
2194 requested by the remote client indicated by the `client_entry' from
2195 the `hostname' and `port'. The `session_id' is the file transfer
2196 session and it can be used to either accept or reject the file
2197 transfer request, by calling the silc_client_file_receive or
2198 silc_client_file_close, respectively. */
2200 void silc_ftp(SilcClient client, SilcClientConnection conn,
2201 SilcClientEntry client_entry, SilcUInt32 session_id,
2202 const char *hostname, SilcUInt16 port)
2204 SILC_SERVER_REC *server;
2206 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2208 SILC_LOG_DEBUG(("Start"));
2210 server = conn->context;
2212 ftp->client_entry = client_entry;
2213 ftp->session_id = session_id;
2216 silc_dlist_add(server->ftp_sessions, ftp);
2217 server->current_session = ftp;
2220 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2223 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2224 SILCTXT_FILE_REQUEST, client_entry->nickname);
2226 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2227 SILCTXT_FILE_REQUEST_HOST,
2228 client_entry->nickname, hostname, portstr);
2231 /* Delivers SILC session detachment data indicated by `detach_data' to the
2232 application. If application has issued SILC_COMMAND_DETACH command
2233 the client session in the SILC network is not quit. The client remains
2234 in the network but is detached. The detachment data may be used later
2235 to resume the session in the SILC Network. The appliation is
2236 responsible of saving the `detach_data', to for example in a file.
2238 The detachment data can be given as argument to the functions
2239 silc_client_connect_to_server, or silc_client_add_connection when
2240 creating connection to remote server, inside SilcClientConnectionParams
2241 structure. If it is provided the client library will attempt to resume
2242 the session in the network. After the connection is created
2243 successfully, the application is responsible of setting the user
2244 interface for user into the same state it was before detaching (showing
2245 same channels, channel modes, etc). It can do this by fetching the
2246 information (like joined channels) from the client library. */
2249 silc_detach(SilcClient client, SilcClientConnection conn,
2250 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2254 /* Save the detachment data to file. */
2256 memset(file, 0, sizeof(file));
2257 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2258 silc_file_writefile(file, detach_data, detach_data_len);
2262 /* SILC client operations */
2263 SilcClientOperations ops = {
2265 silc_channel_message,
2266 silc_private_message,
2272 silc_get_auth_method,
2273 silc_verify_public_key,
2274 silc_ask_passphrase,