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;
161 printformat_module("fe-common/silc", server, channel->channel_name,
162 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
163 nick == NULL ? "[<unknown>]" : nick->nick, type);
171 if (flags & SILC_MESSAGE_FLAG_ACTION)
172 printformat_module("fe-common/silc", server, channel->channel_name,
173 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
174 nick == NULL ? "[<unknown>]" : nick->nick, message);
175 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
176 printformat_module("fe-common/silc", server, channel->channel_name,
177 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
178 nick == NULL ? "[<unknown>]" : nick->nick, message);
180 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
181 char tmp[256], *cp, *dm = NULL;
183 memset(tmp, 0, sizeof(tmp));
185 if (message_len > sizeof(tmp) - 1) {
186 dm = silc_calloc(message_len + 1, sizeof(*dm));
190 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
192 signal_emit("message public", 6, server, cp,
193 nick == NULL ? "[<unknown>]" : nick->nick,
194 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
195 chanrec->name, nick);
200 signal_emit("message public", 6, server, message,
201 nick == NULL ? "[<unknown>]" : nick->nick,
202 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
203 chanrec->name, nick);
207 /* Private message to the client. The `sender' is the nickname of the
208 sender received in the packet. */
210 void silc_private_message(SilcClient client, SilcClientConnection conn,
211 SilcClientEntry sender, SilcMessageFlags flags,
212 const unsigned char *message,
213 SilcUInt32 message_len)
215 SILC_SERVER_REC *server;
218 SILC_LOG_DEBUG(("Start"));
220 server = conn == NULL ? NULL : conn->context;
221 memset(userhost, 0, sizeof(userhost));
222 if (sender->username)
223 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
224 sender->username, sender->hostname);
226 if (flags & SILC_MESSAGE_FLAG_DATA) {
227 /* MIME object received, try to display it as well as we can */
228 char type[128], enc[128];
232 memset(type, 0, sizeof(type));
233 memset(enc, 0, sizeof(enc));
234 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
235 enc, sizeof(enc) - 1, &data, &data_len))
238 /* Then figure out what we can display */
239 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
240 !strstr(type, "text/vnd")) {
241 /* It is something textual, display it */
242 message = (const unsigned char *)data;
244 printformat_module("fe-common/silc", server, NULL,
245 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
246 sender->nickname ? sender->nickname : "[<unknown>]",
255 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
256 char tmp[256], *cp, *dm = NULL;
258 memset(tmp, 0, sizeof(tmp));
260 if (message_len > sizeof(tmp) - 1) {
261 dm = silc_calloc(message_len + 1, sizeof(*dm));
265 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
267 signal_emit("message private", 4, server, cp,
268 sender->nickname ? sender->nickname : "[<unknown>]",
269 sender->username ? userhost : NULL);
274 signal_emit("message private", 4, server, message,
275 sender->nickname ? sender->nickname : "[<unknown>]",
276 sender->username ? userhost : NULL);
279 /* Notify message to the client. The notify arguments are sent in the
280 same order as servers sends them. The arguments are same as received
281 from the server except for ID's. If ID is received application receives
282 the corresponding entry to the ID. For example, if Client ID is received
283 application receives SilcClientEntry. Also, if the notify type is
284 for channel the channel entry is sent to application (even if server
285 does not send it). */
287 void silc_notify(SilcClient client, SilcClientConnection conn,
288 SilcNotifyType type, ...)
291 SILC_SERVER_REC *server;
292 SILC_CHANNEL_REC *chanrec;
293 SILC_NICK_REC *nickrec;
294 SilcClientEntry client_entry, client_entry2;
295 SilcChannelEntry channel, channel2;
296 SilcServerEntry server_entry;
302 GSList *list1, *list_tmp;
304 SILC_LOG_DEBUG(("Start"));
308 server = conn == NULL ? NULL : conn->context;
311 case SILC_NOTIFY_TYPE_NONE:
312 /* Some generic notice from server */
313 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
316 case SILC_NOTIFY_TYPE_INVITE:
318 * Invited or modified invite list.
321 SILC_LOG_DEBUG(("Notify: INVITE"));
323 channel = va_arg(va, SilcChannelEntry);
324 name = va_arg(va, char *);
325 client_entry = va_arg(va, SilcClientEntry);
327 memset(buf, 0, sizeof(buf));
328 snprintf(buf, sizeof(buf) - 1, "%s@%s",
329 client_entry->username, client_entry->hostname);
330 signal_emit("message invite", 4, server, channel ? channel->channel_name :
331 name, client_entry->nickname, buf);
334 case SILC_NOTIFY_TYPE_JOIN:
339 SILC_LOG_DEBUG(("Notify: JOIN"));
341 client_entry = va_arg(va, SilcClientEntry);
342 channel = va_arg(va, SilcChannelEntry);
344 if (client_entry == server->conn->local_entry) {
345 /* You joined to channel */
346 chanrec = silc_channel_find(server, channel->channel_name);
347 if (chanrec != NULL && !chanrec->joined)
348 chanrec->entry = channel;
350 chanrec = silc_channel_find_entry(server, channel);
351 if (chanrec != NULL) {
352 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
354 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
358 memset(buf, 0, sizeof(buf));
359 if (client_entry->username)
360 snprintf(buf, sizeof(buf) - 1, "%s@%s",
361 client_entry->username, client_entry->hostname);
362 signal_emit("message join", 4, server, channel->channel_name,
363 client_entry->nickname,
364 client_entry->username == NULL ? "" : buf);
367 case SILC_NOTIFY_TYPE_LEAVE:
372 SILC_LOG_DEBUG(("Notify: LEAVE"));
374 client_entry = va_arg(va, SilcClientEntry);
375 channel = va_arg(va, SilcChannelEntry);
377 memset(buf, 0, sizeof(buf));
378 if (client_entry->username)
379 snprintf(buf, sizeof(buf) - 1, "%s@%s",
380 client_entry->username, client_entry->hostname);
381 signal_emit("message part", 5, server, channel->channel_name,
382 client_entry->nickname, client_entry->username ?
383 buf : "", client_entry->nickname);
385 chanrec = silc_channel_find_entry(server, channel);
386 if (chanrec != NULL) {
387 nickrec = silc_nicklist_find(chanrec, client_entry);
389 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
393 case SILC_NOTIFY_TYPE_SIGNOFF:
398 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
400 client_entry = va_arg(va, SilcClientEntry);
401 tmp = va_arg(va, char *);
403 silc_server_free_ftp(server, client_entry);
405 memset(buf, 0, sizeof(buf));
406 if (client_entry->username)
407 snprintf(buf, sizeof(buf) - 1, "%s@%s",
408 client_entry->username, client_entry->hostname);
409 signal_emit("message quit", 4, server, client_entry->nickname,
410 client_entry->username ? buf : "",
413 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
414 for (list_tmp = list1; list_tmp != NULL; list_tmp =
415 list_tmp->next->next) {
416 CHANNEL_REC *channel = list_tmp->data;
417 NICK_REC *nickrec = list_tmp->next->data;
419 nicklist_remove(channel, nickrec);
423 case SILC_NOTIFY_TYPE_TOPIC_SET:
428 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
430 idtype = va_arg(va, int);
431 entry = va_arg(va, void *);
432 tmp = va_arg(va, char *);
433 channel = va_arg(va, SilcChannelEntry);
435 chanrec = silc_channel_find_entry(server, channel);
436 if (chanrec != NULL) {
437 g_free_not_null(chanrec->topic);
438 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
439 signal_emit("channel topic changed", 1, chanrec);
442 if (idtype == SILC_ID_CLIENT) {
443 client_entry = (SilcClientEntry)entry;
444 memset(buf, 0, sizeof(buf));
445 snprintf(buf, sizeof(buf) - 1, "%s@%s",
446 client_entry->username, client_entry->hostname);
447 signal_emit("message topic", 5, server, channel->channel_name,
448 tmp, client_entry->nickname, buf);
449 } else if (idtype == SILC_ID_SERVER) {
450 server_entry = (SilcServerEntry)entry;
451 signal_emit("message topic", 5, server, channel->channel_name,
452 tmp, server_entry->server_name,
453 server_entry->server_name);
454 } else if (idtype == SILC_ID_CHANNEL) {
455 channel = (SilcChannelEntry)entry;
456 signal_emit("message topic", 5, server, channel->channel_name,
457 tmp, channel->channel_name, channel->channel_name);
461 case SILC_NOTIFY_TYPE_NICK_CHANGE:
466 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
468 client_entry = va_arg(va, SilcClientEntry);
469 client_entry2 = va_arg(va, SilcClientEntry);
471 if (!strcmp(client_entry->nickname, client_entry2->nickname))
474 memset(buf, 0, sizeof(buf));
475 snprintf(buf, sizeof(buf) - 1, "%s@%s",
476 client_entry2->username, client_entry2->hostname);
477 nicklist_rename_unique(SERVER(server),
478 client_entry, client_entry->nickname,
479 client_entry2, client_entry2->nickname);
480 signal_emit("message nick", 4, server, client_entry2->nickname,
481 client_entry->nickname, buf);
484 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
486 * Changed channel mode.
489 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
491 idtype = va_arg(va, int);
492 entry = va_arg(va, void *);
493 mode = va_arg(va, SilcUInt32);
494 (void)va_arg(va, char *);
495 (void)va_arg(va, char *);
496 channel = va_arg(va, SilcChannelEntry);
498 tmp = silc_client_chmode(mode,
499 channel->channel_key ?
500 silc_cipher_get_name(channel->channel_key) : "",
502 silc_hmac_get_name(channel->hmac) : "");
504 chanrec = silc_channel_find_entry(server, channel);
505 if (chanrec != NULL) {
506 g_free_not_null(chanrec->mode);
507 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
508 signal_emit("channel mode changed", 1, chanrec);
511 if (idtype == SILC_ID_CLIENT) {
512 client_entry = (SilcClientEntry)entry;
513 printformat_module("fe-common/silc", server, channel->channel_name,
514 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
515 channel->channel_name, tmp ? tmp : "removed all",
516 client_entry->nickname);
517 } else if (idtype == SILC_ID_SERVER) {
518 server_entry = (SilcServerEntry)entry;
519 printformat_module("fe-common/silc", server, channel->channel_name,
520 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
521 channel->channel_name, tmp ? tmp : "removed all",
522 server_entry->server_name);
523 } else if (idtype == SILC_ID_CHANNEL) {
524 channel2 = (SilcChannelEntry)entry;
525 printformat_module("fe-common/silc", server, channel->channel_name,
526 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
527 channel->channel_name, tmp ? tmp : "removed all",
528 channel2->channel_name);
534 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
536 * Changed user's mode on channel.
539 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
541 idtype = va_arg(va, int);
542 entry = va_arg(va, void *);
543 mode = va_arg(va, SilcUInt32);
544 client_entry2 = va_arg(va, SilcClientEntry);
545 channel = va_arg(va, SilcChannelEntry);
547 tmp = silc_client_chumode(mode);
548 chanrec = silc_channel_find_entry(server, channel);
549 if (chanrec != NULL) {
552 if (client_entry2 == server->conn->local_entry)
553 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
555 nick = silc_nicklist_find(chanrec, client_entry2);
557 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
558 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
559 signal_emit("nick mode changed", 2, chanrec, nick);
563 if (idtype == SILC_ID_CLIENT) {
564 client_entry = (SilcClientEntry)entry;
565 printformat_module("fe-common/silc", server, channel->channel_name,
566 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
567 channel->channel_name, client_entry2->nickname,
568 tmp ? tmp : "removed all",
569 client_entry->nickname);
570 } else if (idtype == SILC_ID_SERVER) {
571 server_entry = (SilcServerEntry)entry;
572 printformat_module("fe-common/silc", server, channel->channel_name,
573 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
574 channel->channel_name, client_entry2->nickname,
575 tmp ? tmp : "removed all",
576 server_entry->server_name);
577 } else if (idtype == SILC_ID_CHANNEL) {
578 channel2 = (SilcChannelEntry)entry;
579 printformat_module("fe-common/silc", server, channel->channel_name,
580 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
581 channel->channel_name, client_entry2->nickname,
582 tmp ? tmp : "removed all",
583 channel2->channel_name);
586 if (mode & SILC_CHANNEL_UMODE_CHANFO)
587 printformat_module("fe-common/silc",
588 server, channel->channel_name, MSGLEVEL_CRAP,
589 SILCTXT_CHANNEL_FOUNDER,
590 channel->channel_name, client_entry2->nickname);
592 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
593 printformat_module("fe-common/silc",
594 server, channel->channel_name, MSGLEVEL_CRAP,
595 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
600 case SILC_NOTIFY_TYPE_MOTD:
605 SILC_LOG_DEBUG(("Notify: MOTD"));
607 tmp = va_arg(va, char *);
609 if (!settings_get_bool("skip_motd"))
610 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
613 case SILC_NOTIFY_TYPE_KICKED:
615 * Someone was kicked from channel.
618 SILC_LOG_DEBUG(("Notify: KICKED"));
620 client_entry = va_arg(va, SilcClientEntry);
621 tmp = va_arg(va, char *);
622 client_entry2 = va_arg(va, SilcClientEntry);
623 channel = va_arg(va, SilcChannelEntry);
625 chanrec = silc_channel_find_entry(server, channel);
627 if (client_entry == conn->local_entry) {
628 printformat_module("fe-common/silc", server, channel->channel_name,
629 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
630 channel->channel_name,
631 client_entry ? client_entry2->nickname : "",
634 chanrec->kicked = TRUE;
635 channel_destroy((CHANNEL_REC *)chanrec);
638 printformat_module("fe-common/silc", server, channel->channel_name,
639 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
640 client_entry->nickname, channel->channel_name,
641 client_entry2 ? client_entry2->nickname : "",
645 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
647 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
652 case SILC_NOTIFY_TYPE_KILLED:
654 * Someone was killed from the network.
657 SILC_LOG_DEBUG(("Notify: KILLED"));
659 client_entry = va_arg(va, SilcClientEntry);
660 tmp = va_arg(va, char *);
661 idtype = va_arg(va, int);
662 entry = va_arg(va, SilcClientEntry);
664 if (client_entry == conn->local_entry) {
665 if (idtype == SILC_ID_CLIENT) {
666 client_entry2 = (SilcClientEntry)entry;
667 printformat_module("fe-common/silc", server, NULL,
668 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
669 client_entry2 ? client_entry2->nickname : "",
671 } else if (idtype == SILC_ID_SERVER) {
672 server_entry = (SilcServerEntry)entry;
673 printformat_module("fe-common/silc", server, NULL,
674 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
675 server_entry->server_name, tmp ? tmp : "");
676 } else if (idtype == SILC_ID_CHANNEL) {
677 channel = (SilcChannelEntry)entry;
678 printformat_module("fe-common/silc", server, NULL,
679 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
680 channel->channel_name, tmp ? tmp : "");
683 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
684 for (list_tmp = list1; list_tmp != NULL; list_tmp =
685 list_tmp->next->next) {
686 CHANNEL_REC *channel = list_tmp->data;
687 NICK_REC *nickrec = list_tmp->next->data;
688 nicklist_remove(channel, nickrec);
691 if (idtype == SILC_ID_CLIENT) {
692 client_entry2 = (SilcClientEntry)entry;
693 printformat_module("fe-common/silc", server, NULL,
694 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
695 client_entry->nickname,
696 client_entry2 ? client_entry2->nickname : "",
698 } else if (idtype == SILC_ID_SERVER) {
699 server_entry = (SilcServerEntry)entry;
700 printformat_module("fe-common/silc", server, NULL,
701 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
702 client_entry->nickname,
703 server_entry->server_name, tmp ? tmp : "");
704 } else if (idtype == SILC_ID_CHANNEL) {
705 channel = (SilcChannelEntry)entry;
706 printformat_module("fe-common/silc", server, NULL,
707 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
708 client_entry->nickname,
709 channel->channel_name, tmp ? tmp : "");
714 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
717 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
720 * Server has quit the network.
723 SilcClientEntry *clients;
724 SilcUInt32 clients_count;
726 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
728 (void)va_arg(va, void *);
729 clients = va_arg(va, SilcClientEntry *);
730 clients_count = va_arg(va, SilcUInt32);
732 for (i = 0; i < clients_count; i++) {
733 memset(buf, 0, sizeof(buf));
734 if (clients[i]->username)
735 snprintf(buf, sizeof(buf) - 1, "%s@%s",
736 clients[i]->username, clients[i]->hostname);
737 signal_emit("message quit", 4, server, clients[i]->nickname,
738 clients[i]->username ? buf : "",
741 silc_server_free_ftp(server, clients[i]);
743 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
744 for (list_tmp = list1; list_tmp != NULL; list_tmp =
745 list_tmp->next->next) {
746 CHANNEL_REC *channel = list_tmp->data;
747 NICK_REC *nickrec = list_tmp->next->data;
748 nicklist_remove(channel, nickrec);
754 case SILC_NOTIFY_TYPE_ERROR:
756 SilcStatus error = va_arg(va, int);
758 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
759 "%s", silc_get_status_message(error));
763 case SILC_NOTIFY_TYPE_WATCH:
765 SilcNotifyType notify;
767 client_entry = va_arg(va, SilcClientEntry);
768 name = va_arg(va, char *); /* Maybe NULL */
769 mode = va_arg(va, SilcUInt32);
770 notify = va_arg(va, int);
772 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
774 printformat_module("fe-common/silc", server, NULL,
775 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
776 client_entry->nickname, name);
778 printformat_module("fe-common/silc", server, NULL,
779 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
780 client_entry->nickname);
781 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
782 /* See if client was away and is now present */
783 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
784 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
785 SILC_UMODE_DETACHED)) &&
786 (client_entry->mode & SILC_UMODE_GONE ||
787 client_entry->mode & SILC_UMODE_INDISPOSED ||
788 client_entry->mode & SILC_UMODE_BUSY ||
789 client_entry->mode & SILC_UMODE_PAGE ||
790 client_entry->mode & SILC_UMODE_DETACHED)) {
791 printformat_module("fe-common/silc", server, NULL,
792 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
793 client_entry->nickname);
797 memset(buf, 0, sizeof(buf));
798 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
799 printformat_module("fe-common/silc", server, NULL,
800 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
801 client_entry->nickname, buf);
803 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
804 printformat_module("fe-common/silc", server, NULL,
805 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
806 client_entry->nickname);
807 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
808 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
809 printformat_module("fe-common/silc", server, NULL,
810 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
811 client_entry->nickname);
812 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
813 /* Client logged in to the network */
814 printformat_module("fe-common/silc", server, NULL,
815 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
816 client_entry->nickname);
823 printformat_module("fe-common/silc", server, NULL,
824 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
831 /* Called to indicate that connection was either successfully established
832 or connecting failed. This is also the first time application receives
833 the SilcClientConnection object which it should save somewhere. */
835 void silc_connect(SilcClient client, SilcClientConnection conn,
836 SilcClientConnectionStatus status)
838 SILC_SERVER_REC *server = conn->context;
840 if (!server || server->disconnected) {
841 silc_client_close_connection(client, conn);
846 case SILC_CLIENT_CONN_SUCCESS:
847 /* We have successfully connected to server */
848 server->connected = TRUE;
849 signal_emit("event connected", 1, server);
852 case SILC_CLIENT_CONN_SUCCESS_RESUME:
853 /* We have successfully resumed old detached session */
854 server->connected = TRUE;
855 signal_emit("event connected", 1, server);
857 /* If we resumed old session check whether we need to update
859 if (strcmp(server->nick, conn->local_entry->nickname)) {
861 old = g_strdup(server->nick);
862 server_change_nick(SERVER(server), conn->local_entry->nickname);
863 nicklist_rename_unique(SERVER(server),
864 conn->local_entry, server->nick,
865 conn->local_entry, conn->local_entry->nickname);
866 signal_emit("message own_nick", 4, server, server->nick, old, "");
872 server->connection_lost = TRUE;
874 server->conn->context = NULL;
875 server_disconnect(SERVER(server));
880 /* Called to indicate that connection was disconnected to the server. */
882 void silc_disconnect(SilcClient client, SilcClientConnection conn,
883 SilcStatus status, const char *message)
885 SILC_SERVER_REC *server = conn->context;
887 SILC_LOG_DEBUG(("Start"));
889 if (!server || server->connection_lost)
892 if (server->conn && server->conn->local_entry) {
893 nicklist_rename_unique(SERVER(server),
894 server->conn->local_entry, server->nick,
895 server->conn->local_entry,
896 silc_client->username);
897 silc_change_nick(server, silc_client->username);
901 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
902 "Server closed connection: %s (%d) %s",
903 silc_get_status_message(status), status,
904 message ? message : "");
906 server->conn->context = NULL;
908 server->connection_lost = TRUE;
909 server_disconnect(SERVER(server));
912 /* Command handler. This function is called always in the command function.
913 If error occurs it will be called as well. `conn' is the associated
914 client connection. `cmd_context' is the command context that was
915 originally sent to the command. `success' is FALSE if error occured
916 during command. `command' is the command being processed. It must be
917 noted that this is not reply from server. This is merely called just
918 after application has called the command. Just to tell application
919 that the command really was processed. */
921 void silc_command(SilcClient client, SilcClientConnection conn,
922 SilcClientCommandContext cmd_context, bool success,
923 SilcCommand command, SilcStatus status)
925 SILC_SERVER_REC *server = conn->context;
927 SILC_LOG_DEBUG(("Start"));
930 silc_say_error("%s", silc_get_status_message(status));
936 case SILC_COMMAND_INVITE:
937 printformat_module("fe-common/silc", server, NULL,
938 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
939 cmd_context->argv[2],
940 (cmd_context->argv[1][0] == '*' ?
941 (char *)conn->current_channel->channel_name :
942 (char *)cmd_context->argv[1]));
945 case SILC_COMMAND_DETACH:
946 server->no_reconnect = TRUE;
954 /* Client info resolving callback when JOIN command reply is received.
955 This will cache all users on the channel. */
957 static void silc_client_join_get_users(SilcClient client,
958 SilcClientConnection conn,
959 SilcClientEntry *clients,
960 SilcUInt32 clients_count,
963 SilcChannelEntry channel = (SilcChannelEntry)context;
964 SilcHashTableList htl;
966 SILC_SERVER_REC *server = conn->context;
967 SILC_CHANNEL_REC *chanrec;
968 SilcClientEntry founder = NULL;
971 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
972 silc_hash_table_count(channel->user_list)));
977 chanrec = silc_channel_find(server, channel->channel_name);
981 silc_hash_table_list(channel->user_list, &htl);
982 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
983 if (!chu->client->nickname)
985 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
986 founder = chu->client;
987 silc_nicklist_insert(chanrec, chu, FALSE);
989 silc_hash_table_list_reset(&htl);
991 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
992 nicklist_set_own(CHANNEL(chanrec), ownnick);
993 signal_emit("channel joined", 1, chanrec);
994 chanrec->entry = channel;
997 printformat_module("fe-common/silc", server, channel->channel_name,
998 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
999 channel->channel_name, chanrec->topic);
1002 if (founder == conn->local_entry)
1003 printformat_module("fe-common/silc",
1004 server, channel->channel_name, MSGLEVEL_CRAP,
1005 SILCTXT_CHANNEL_FOUNDER_YOU,
1006 channel->channel_name);
1008 printformat_module("fe-common/silc",
1009 server, channel->channel_name, MSGLEVEL_CRAP,
1010 SILCTXT_CHANNEL_FOUNDER,
1011 channel->channel_name, founder->nickname);
1017 SilcClientConnection conn;
1023 void silc_getkey_cb(bool success, void *context)
1025 GetkeyContext getkey = (GetkeyContext)context;
1026 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1027 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1028 ((SilcClientEntry)getkey->entry)->nickname :
1029 ((SilcServerEntry)getkey->entry)->server_name);
1032 printformat_module("fe-common/silc", NULL, NULL,
1033 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1035 printformat_module("fe-common/silc", NULL, NULL,
1036 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1040 silc_free(getkey->fingerprint);
1044 /* Command reply handler. This function is called always in the command reply
1045 function. If error occurs it will be called as well. Normal scenario
1046 is that it will be called after the received command data has been parsed
1047 and processed. The function is used to pass the received command data to
1050 `conn' is the associated client connection. `cmd_payload' is the command
1051 payload data received from server and it can be ignored. It is provided
1052 if the application would like to re-parse the received command data,
1053 however, it must be noted that the data is parsed already by the library
1054 thus the payload can be ignored. `success' is FALSE if error occured.
1055 In this case arguments are not sent to the application. `command' is the
1056 command reply being processed. The function has variable argument list
1057 and each command defines the number and type of arguments it passes to the
1058 application (on error they are not sent). */
1061 silc_command_reply(SilcClient client, SilcClientConnection conn,
1062 SilcCommandPayload cmd_payload, bool success,
1063 SilcCommand command, SilcStatus status, ...)
1066 SILC_SERVER_REC *server = conn->context;
1067 SILC_CHANNEL_REC *chanrec;
1070 va_start(vp, status);
1072 SILC_LOG_DEBUG(("Start"));
1075 case SILC_COMMAND_WHOIS:
1077 char buf[1024], *nickname, *username, *realname, *nick;
1078 unsigned char *fingerprint;
1079 SilcUInt32 idle, mode;
1080 SilcBuffer channels, user_modes;
1081 SilcClientEntry client_entry;
1084 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1085 /* Print the unknown nick for user */
1086 unsigned char *tmp =
1087 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1090 silc_say_error("%s: %s", tmp,
1091 silc_get_status_message(status));
1093 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1094 /* Try to find the entry for the unknown client ID, since we
1095 might have, and print the nickname of it for user. */
1097 unsigned char *tmp =
1098 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1101 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1104 client_entry = silc_client_get_client_by_id(client, conn,
1106 if (client_entry && client_entry->nickname)
1107 silc_say_error("%s: %s", client_entry->nickname,
1108 silc_get_status_message(status));
1109 silc_free(client_id);
1113 } else if (!success) {
1114 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1118 client_entry = va_arg(vp, SilcClientEntry);
1119 nickname = va_arg(vp, char *);
1120 username = va_arg(vp, char *);
1121 realname = va_arg(vp, char *);
1122 channels = va_arg(vp, SilcBuffer);
1123 mode = va_arg(vp, SilcUInt32);
1124 idle = va_arg(vp, SilcUInt32);
1125 fingerprint = va_arg(vp, unsigned char *);
1126 user_modes = va_arg(vp, SilcBuffer);
1127 attrs = va_arg(vp, SilcDList);
1129 silc_parse_userfqdn(nickname, &nick, NULL);
1130 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1131 SILCTXT_WHOIS_USERINFO, nickname,
1132 client_entry->username, client_entry->hostname,
1133 nick, client_entry->nickname);
1134 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1135 SILCTXT_WHOIS_REALNAME, realname);
1138 if (channels && user_modes) {
1140 SilcDList list = silc_channel_payload_parse_list(channels->data,
1142 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1144 SilcChannelPayload entry;
1147 memset(buf, 0, sizeof(buf));
1148 silc_dlist_start(list);
1149 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1150 SilcUInt32 name_len;
1151 char *m = silc_client_chumode_char(umodes[i++]);
1152 char *name = silc_channel_get_name(entry, &name_len);
1155 strncat(buf, m, strlen(m));
1156 strncat(buf, name, name_len);
1157 strncat(buf, " ", 1);
1161 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1162 SILCTXT_WHOIS_CHANNELS, buf);
1163 silc_channel_payload_list_free(list);
1169 memset(buf, 0, sizeof(buf));
1170 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1171 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1172 SILCTXT_WHOIS_MODES, buf);
1175 if (idle && nickname) {
1176 memset(buf, 0, sizeof(buf));
1177 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1178 idle > 60 ? (idle / 60) : idle,
1179 idle > 60 ? "minutes" : "seconds");
1181 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1182 SILCTXT_WHOIS_IDLE, buf);
1186 fingerprint = silc_fingerprint(fingerprint, 20);
1187 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1188 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1189 silc_free(fingerprint);
1193 silc_query_attributes_print(server, silc_client, conn, attrs,
1198 case SILC_COMMAND_IDENTIFY:
1200 SilcClientEntry client_entry;
1202 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1203 /* Print the unknown nick for user */
1204 unsigned char *tmp =
1205 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1208 silc_say_error("%s: %s", tmp,
1209 silc_get_status_message(status));
1211 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1212 /* Try to find the entry for the unknown client ID, since we
1213 might have, and print the nickname of it for user. */
1215 unsigned char *tmp =
1216 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1219 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1222 client_entry = silc_client_get_client_by_id(client, conn,
1224 if (client_entry && client_entry->nickname)
1225 silc_say_error("%s: %s", client_entry->nickname,
1226 silc_get_status_message(status));
1227 silc_free(client_id);
1236 case SILC_COMMAND_WHOWAS:
1238 char *nickname, *username, *realname;
1240 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1241 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1243 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1246 silc_say_error("%s: %s", tmp,
1247 silc_get_status_message(status));
1249 } else if (!success) {
1250 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1254 (void)va_arg(vp, SilcClientEntry);
1255 nickname = va_arg(vp, char *);
1256 username = va_arg(vp, char *);
1257 realname = va_arg(vp, char *);
1259 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1260 SILCTXT_WHOWAS_USERINFO, nickname, username,
1261 realname ? realname : "");
1265 case SILC_COMMAND_INVITE:
1267 SilcChannelEntry channel;
1269 SilcArgumentPayload args;
1275 channel = va_arg(vp, SilcChannelEntry);
1276 invite_list = va_arg(vp, char *);
1278 args = silc_command_get_args(cmd_payload);
1280 argc = silc_argument_get_arg_num(args);
1283 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1284 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1287 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1288 SILCTXT_CHANNEL_NO_INVITE_LIST,
1289 channel->channel_name);
1293 case SILC_COMMAND_JOIN:
1295 char *channel, *mode, *topic;
1297 SilcChannelEntry channel_entry;
1298 SilcBuffer client_id_list;
1299 SilcUInt32 list_count;
1304 channel = va_arg(vp, char *);
1305 channel_entry = va_arg(vp, SilcChannelEntry);
1306 modei = va_arg(vp, SilcUInt32);
1307 (void)va_arg(vp, SilcUInt32);
1308 (void)va_arg(vp, unsigned char *);
1309 (void)va_arg(vp, unsigned char *);
1310 (void)va_arg(vp, unsigned char *);
1311 topic = va_arg(vp, char *);
1312 (void)va_arg(vp, unsigned char *);
1313 list_count = va_arg(vp, SilcUInt32);
1314 client_id_list = va_arg(vp, SilcBuffer);
1316 chanrec = silc_channel_find(server, channel);
1318 chanrec = silc_channel_create(server, channel, channel, TRUE);
1321 g_free_not_null(chanrec->topic);
1322 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1323 signal_emit("channel topic changed", 1, chanrec);
1326 mode = silc_client_chmode(modei,
1327 channel_entry->channel_key ?
1328 silc_cipher_get_name(channel_entry->
1330 channel_entry->hmac ?
1331 silc_hmac_get_name(channel_entry->hmac) : "");
1332 g_free_not_null(chanrec->mode);
1333 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1334 signal_emit("channel mode changed", 1, chanrec);
1336 /* Resolve the client information */
1337 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1338 silc_client_join_get_users,
1344 case SILC_COMMAND_NICK:
1347 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1352 old = g_strdup(server->nick);
1353 server_change_nick(SERVER(server), client->nickname);
1354 nicklist_rename_unique(SERVER(server),
1355 server->conn->local_entry, server->nick,
1356 client, client->nickname);
1357 signal_emit("message own_nick", 4, server, server->nick, old, "");
1362 case SILC_COMMAND_LIST:
1371 (void)va_arg(vp, SilcChannelEntry);
1372 name = va_arg(vp, char *);
1373 topic = va_arg(vp, char *);
1374 usercount = va_arg(vp, int);
1376 if (status == SILC_STATUS_LIST_START ||
1377 status == SILC_STATUS_OK)
1378 printformat_module("fe-common/silc", server, NULL,
1379 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1382 snprintf(users, sizeof(users) - 1, "N/A");
1384 snprintf(users, sizeof(users) - 1, "%d", usercount);
1385 printformat_module("fe-common/silc", server, NULL,
1386 MSGLEVEL_CRAP, SILCTXT_LIST,
1387 name, users, topic ? topic : "");
1391 case SILC_COMMAND_UMODE:
1398 mode = va_arg(vp, SilcUInt32);
1400 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1401 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1402 printformat_module("fe-common/silc", server, NULL,
1403 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1405 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1406 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1407 printformat_module("fe-common/silc", server, NULL,
1408 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1410 server->umode = mode;
1411 signal_emit("user mode changed", 2, server, NULL);
1415 case SILC_COMMAND_OPER:
1419 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1420 signal_emit("user mode changed", 2, server, NULL);
1422 printformat_module("fe-common/silc", server, NULL,
1423 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1426 case SILC_COMMAND_SILCOPER:
1430 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1431 signal_emit("user mode changed", 2, server, NULL);
1433 printformat_module("fe-common/silc", server, NULL,
1434 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1437 case SILC_COMMAND_USERS:
1439 SilcHashTableList htl;
1440 SilcChannelEntry channel;
1441 SilcChannelUser chu;
1446 channel = va_arg(vp, SilcChannelEntry);
1448 printformat_module("fe-common/silc", server, channel->channel_name,
1449 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1450 channel->channel_name);
1452 silc_hash_table_list(channel->user_list, &htl);
1453 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1454 SilcClientEntry e = chu->client;
1455 char stat[5], *mode;
1460 memset(stat, 0, sizeof(stat));
1461 mode = silc_client_chumode_char(chu->mode);
1462 if (e->mode & SILC_UMODE_GONE)
1464 else if (e->mode & SILC_UMODE_INDISPOSED)
1466 else if (e->mode & SILC_UMODE_BUSY)
1468 else if (e->mode & SILC_UMODE_PAGE)
1470 else if (e->mode & SILC_UMODE_HYPER)
1472 else if (e->mode & SILC_UMODE_ROBOT)
1474 else if (e->mode & SILC_UMODE_ANONYMOUS)
1481 printformat_module("fe-common/silc", server, channel->channel_name,
1482 MSGLEVEL_CRAP, SILCTXT_USERS,
1484 e->username ? e->username : "",
1485 e->hostname ? e->hostname : "",
1486 e->realname ? e->realname : "");
1490 silc_hash_table_list_reset(&htl);
1494 case SILC_COMMAND_BAN:
1496 SilcChannelEntry channel;
1502 channel = va_arg(vp, SilcChannelEntry);
1503 ban_list = va_arg(vp, char *);
1506 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1507 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1510 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1511 SILCTXT_CHANNEL_NO_BAN_LIST,
1512 channel->channel_name);
1516 case SILC_COMMAND_GETKEY:
1520 SilcPublicKey public_key;
1523 GetkeyContext getkey;
1529 id_type = va_arg(vp, SilcUInt32);
1530 entry = va_arg(vp, void *);
1531 public_key = va_arg(vp, SilcPublicKey);
1534 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1536 getkey = silc_calloc(1, sizeof(*getkey));
1537 getkey->entry = entry;
1538 getkey->id_type = id_type;
1539 getkey->client = client;
1540 getkey->conn = conn;
1541 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1543 name = (id_type == SILC_ID_CLIENT ?
1544 ((SilcClientEntry)entry)->nickname :
1545 ((SilcServerEntry)entry)->server_name);
1547 silc_verify_public_key_internal(client, conn, name,
1548 (id_type == SILC_ID_CLIENT ?
1549 SILC_SOCKET_TYPE_CLIENT :
1550 SILC_SOCKET_TYPE_SERVER),
1551 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1552 silc_getkey_cb, getkey);
1555 printformat_module("fe-common/silc", server, NULL,
1556 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1561 case SILC_COMMAND_INFO:
1563 SilcServerEntry server_entry;
1570 server_entry = va_arg(vp, SilcServerEntry);
1571 server_name = va_arg(vp, char *);
1572 server_info = va_arg(vp, char *);
1574 if (server_name && server_info )
1576 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1577 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1582 case SILC_COMMAND_TOPIC:
1584 SilcChannelEntry channel;
1590 channel = va_arg(vp, SilcChannelEntry);
1591 topic = va_arg(vp, char *);
1594 chanrec = silc_channel_find_entry(server, channel);
1596 g_free_not_null(chanrec->topic);
1597 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1598 signal_emit("channel topic changed", 1, chanrec);
1600 printformat_module("fe-common/silc", server, channel->channel_name,
1601 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1602 channel->channel_name, topic);
1604 printformat_module("fe-common/silc", server, channel->channel_name,
1605 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1606 channel->channel_name);
1611 case SILC_COMMAND_WATCH:
1614 case SILC_COMMAND_STATS:
1616 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1617 my_router_ops, cell_clients, cell_channels, cell_servers,
1618 clients, channels, servers, routers, server_ops, router_ops;
1620 SilcBufferStruct buf;
1621 unsigned char *tmp_buf;
1623 const char *tmptime;
1624 int days, hours, mins, secs;
1629 tmp_buf = va_arg(vp, unsigned char *);
1630 buf_len = va_arg(vp, SilcUInt32);
1632 if (!tmp_buf || !buf_len) {
1633 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
1637 /* Get statistics structure */
1638 silc_buffer_set(&buf, tmp_buf, buf_len);
1639 silc_buffer_unformat(&buf,
1640 SILC_STR_UI_INT(&starttime),
1641 SILC_STR_UI_INT(&uptime),
1642 SILC_STR_UI_INT(&my_clients),
1643 SILC_STR_UI_INT(&my_channels),
1644 SILC_STR_UI_INT(&my_server_ops),
1645 SILC_STR_UI_INT(&my_router_ops),
1646 SILC_STR_UI_INT(&cell_clients),
1647 SILC_STR_UI_INT(&cell_channels),
1648 SILC_STR_UI_INT(&cell_servers),
1649 SILC_STR_UI_INT(&clients),
1650 SILC_STR_UI_INT(&channels),
1651 SILC_STR_UI_INT(&servers),
1652 SILC_STR_UI_INT(&routers),
1653 SILC_STR_UI_INT(&server_ops),
1654 SILC_STR_UI_INT(&router_ops),
1657 tmptime = silc_get_time(starttime);
1658 printformat_module("fe-common/silc", server, NULL,
1659 MSGLEVEL_CRAP, SILCTXT_STATS,
1660 "Local server start time", tmptime);
1662 days = uptime / (24 * 60 * 60);
1663 uptime -= days * (24 * 60 * 60);
1664 hours = uptime / (60 * 60);
1665 uptime -= hours * (60 * 60);
1667 uptime -= mins * 60;
1669 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
1670 days, hours, mins, secs);
1671 printformat_module("fe-common/silc", server, NULL,
1672 MSGLEVEL_CRAP, SILCTXT_STATS,
1673 "Local server uptime", tmp);
1675 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
1676 printformat_module("fe-common/silc", server, NULL,
1677 MSGLEVEL_CRAP, SILCTXT_STATS,
1678 "Local server clients", tmp);
1680 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
1681 printformat_module("fe-common/silc", server, NULL,
1682 MSGLEVEL_CRAP, SILCTXT_STATS,
1683 "Local server channels", tmp);
1685 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
1686 printformat_module("fe-common/silc", server, NULL,
1687 MSGLEVEL_CRAP, SILCTXT_STATS,
1688 "Local server operators", tmp);
1690 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
1691 printformat_module("fe-common/silc", server, NULL,
1692 MSGLEVEL_CRAP, SILCTXT_STATS,
1693 "Local router operators", tmp);
1695 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
1696 printformat_module("fe-common/silc", server, NULL,
1697 MSGLEVEL_CRAP, SILCTXT_STATS,
1698 "Local cell clients", tmp);
1700 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
1701 printformat_module("fe-common/silc", server, NULL,
1702 MSGLEVEL_CRAP, SILCTXT_STATS,
1703 "Local cell channels", tmp);
1705 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
1706 printformat_module("fe-common/silc", server, NULL,
1707 MSGLEVEL_CRAP, SILCTXT_STATS,
1708 "Local cell servers", tmp);
1710 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
1711 printformat_module("fe-common/silc", server, NULL,
1712 MSGLEVEL_CRAP, SILCTXT_STATS,
1713 "Total clients", tmp);
1715 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
1716 printformat_module("fe-common/silc", server, NULL,
1717 MSGLEVEL_CRAP, SILCTXT_STATS,
1718 "Total channels", tmp);
1720 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
1721 printformat_module("fe-common/silc", server, NULL,
1722 MSGLEVEL_CRAP, SILCTXT_STATS,
1723 "Total servers", tmp);
1725 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
1726 printformat_module("fe-common/silc", server, NULL,
1727 MSGLEVEL_CRAP, SILCTXT_STATS,
1728 "Total routers", tmp);
1730 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
1731 printformat_module("fe-common/silc", server, NULL,
1732 MSGLEVEL_CRAP, SILCTXT_STATS,
1733 "Total server operators", tmp);
1735 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
1736 printformat_module("fe-common/silc", server, NULL,
1737 MSGLEVEL_CRAP, SILCTXT_STATS,
1738 "Total router operators", tmp);
1749 SilcClientConnection conn;
1755 SilcSKEPKType pk_type;
1756 SilcVerifyPublicKey completion;
1760 static void verify_public_key_completion(const char *line, void *context)
1762 PublicKeyVerify verify = (PublicKeyVerify)context;
1764 if (line[0] == 'Y' || line[0] == 'y') {
1765 /* Call the completion */
1766 if (verify->completion)
1767 verify->completion(TRUE, verify->context);
1769 /* Save the key for future checking */
1770 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1771 verify->pk_len, SILC_PKCS_FILE_PEM);
1773 /* Call the completion */
1774 if (verify->completion)
1775 verify->completion(FALSE, verify->context);
1777 printformat_module("fe-common/silc", NULL, NULL,
1778 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1779 verify->entity_name ? verify->entity_name :
1783 silc_free(verify->filename);
1784 silc_free(verify->entity);
1785 silc_free(verify->entity_name);
1786 silc_free(verify->pk);
1790 /* Internal routine to verify public key. If the `completion' is provided
1791 it will be called to indicate whether public was verified or not. For
1792 server/router public key this will check for filename that includes the
1793 remote host's IP address and remote host's hostname. */
1796 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1797 const char *name, SilcSocketType conn_type,
1798 unsigned char *pk, SilcUInt32 pk_len,
1799 SilcSKEPKType pk_type,
1800 SilcVerifyPublicKey completion, void *context)
1803 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1804 char *fingerprint, *babbleprint, *format;
1807 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1808 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1809 "server" : "client");
1810 PublicKeyVerify verify;
1812 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1813 printformat_module("fe-common/silc", NULL, NULL,
1814 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1817 completion(FALSE, context);
1821 pw = getpwuid(getuid());
1824 completion(FALSE, context);
1828 memset(filename, 0, sizeof(filename));
1829 memset(filename2, 0, sizeof(filename2));
1830 memset(file, 0, sizeof(file));
1832 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1833 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1835 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1836 conn->sock->ip, conn->sock->port);
1837 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1838 get_irssi_dir(), entity, file);
1840 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1841 conn->sock->hostname, conn->sock->port);
1842 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1843 get_irssi_dir(), entity, file);
1848 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1849 name, conn->sock->port);
1850 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1851 get_irssi_dir(), entity, file);
1856 /* Replace all whitespaces with `_'. */
1857 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1858 for (i = 0; i < strlen(fingerprint); i++)
1859 if (fingerprint[i] == ' ')
1860 fingerprint[i] = '_';
1862 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1863 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1864 get_irssi_dir(), entity, file);
1865 silc_free(fingerprint);
1870 /* Take fingerprint of the public key */
1871 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1872 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1874 verify = silc_calloc(1, sizeof(*verify));
1875 verify->client = client;
1876 verify->conn = conn;
1877 verify->filename = strdup(ipf);
1878 verify->entity = strdup(entity);
1879 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1880 (name ? strdup(name) : strdup(conn->sock->hostname))
1882 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1883 memcpy(verify->pk, pk, pk_len);
1884 verify->pk_len = pk_len;
1885 verify->pk_type = pk_type;
1886 verify->completion = completion;
1887 verify->context = context;
1889 /* Check whether this key already exists */
1890 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1891 /* Key does not exist, ask user to verify the key and save it */
1893 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1894 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1895 verify->entity_name : entity);
1896 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1897 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1898 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1899 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1900 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1901 SILCTXT_PUBKEY_ACCEPT);
1902 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1905 silc_free(fingerprint);
1908 /* The key already exists, verify it. */
1909 SilcPublicKey public_key;
1910 unsigned char *encpk;
1911 SilcUInt32 encpk_len;
1913 /* Load the key file, try for both IP filename and hostname filename */
1914 if (!silc_pkcs_load_public_key(ipf, &public_key,
1915 SILC_PKCS_FILE_PEM) &&
1916 !silc_pkcs_load_public_key(ipf, &public_key,
1917 SILC_PKCS_FILE_BIN) &&
1918 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1919 SILC_PKCS_FILE_PEM) &&
1920 !silc_pkcs_load_public_key(hostf, &public_key,
1921 SILC_PKCS_FILE_BIN)))) {
1922 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1923 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1924 verify->entity_name : entity);
1925 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1926 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1927 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1928 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1929 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1930 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1931 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1932 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1933 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1936 silc_free(fingerprint);
1940 /* Encode the key data */
1941 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1943 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1944 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1945 verify->entity_name : entity);
1946 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1947 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1948 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1949 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1950 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1951 SILCTXT_PUBKEY_MALFORMED, entity);
1952 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1953 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1954 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1957 silc_free(fingerprint);
1961 /* Compare the keys */
1962 if (memcmp(encpk, pk, encpk_len)) {
1963 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1964 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1965 verify->entity_name : entity);
1966 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1967 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1968 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1969 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1970 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1971 SILCTXT_PUBKEY_NO_MATCH, entity);
1972 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1973 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1974 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1975 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1977 /* Ask user to verify the key and save it */
1978 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1979 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1980 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1983 silc_free(fingerprint);
1987 /* Local copy matched */
1989 completion(TRUE, context);
1990 silc_free(fingerprint);
1994 /* Verifies received public key. The `conn_type' indicates which entity
1995 (server, client etc.) has sent the public key. If user decides to trust
1996 the key may be saved as trusted public key for later use. The
1997 `completion' must be called after the public key has been verified. */
2000 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2001 SilcSocketType conn_type, unsigned char *pk,
2002 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2003 SilcVerifyPublicKey completion, void *context)
2005 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2007 completion, context);
2010 /* Asks passphrase from user on the input line. */
2013 SilcAskPassphrase completion;
2017 void ask_passphrase_completion(const char *passphrase, void *context)
2019 AskPassphrase p = (AskPassphrase)context;
2020 if (passphrase && passphrase[0] == '\0')
2022 p->completion((unsigned char *)passphrase,
2023 passphrase ? strlen(passphrase) : 0, p->context);
2027 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2028 SilcAskPassphrase completion, void *context)
2030 AskPassphrase p = silc_calloc(1, sizeof(*p));
2031 p->completion = completion;
2032 p->context = context;
2034 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2035 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2039 SilcGetAuthMeth completion;
2041 } *InternalGetAuthMethod;
2043 /* Callback called when we've received the authentication method information
2044 from the server after we've requested it. This will get the authentication
2045 data from the user if needed. */
2047 static void silc_get_auth_method_callback(SilcClient client,
2048 SilcClientConnection conn,
2049 SilcAuthMethod auth_meth,
2052 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2054 SILC_LOG_DEBUG(("Start"));
2056 switch (auth_meth) {
2057 case SILC_AUTH_NONE:
2058 /* No authentication required. */
2059 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2061 case SILC_AUTH_PASSWORD:
2063 /* Check whether we find the password for this server in our
2064 configuration. If not, then don't provide so library will ask
2065 it from the user. */
2066 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2068 if (!setup || !setup->password) {
2069 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2073 (*internal->completion)(TRUE, auth_meth, setup->password,
2074 strlen(setup->password), internal->context);
2077 case SILC_AUTH_PUBLIC_KEY:
2078 /* Do not get the authentication data now, the library will generate
2079 it using our default key, if we do not provide it here. */
2080 /* XXX In the future when we support multiple local keys and multiple
2081 local certificates we will need to ask from user which one to use. */
2082 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2086 silc_free(internal);
2089 /* Find authentication method and authentication data by hostname and
2090 port. The hostname may be IP address as well. The found authentication
2091 method and authentication data is returned to `auth_meth', `auth_data'
2092 and `auth_data_len'. The function returns TRUE if authentication method
2093 is found and FALSE if not. `conn' may be NULL. */
2095 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2096 char *hostname, SilcUInt16 port,
2097 SilcGetAuthMeth completion, void *context)
2099 InternalGetAuthMethod internal;
2101 SILC_LOG_DEBUG(("Start"));
2103 /* If we do not have this connection configured by the user in a
2104 configuration file then resolve the authentication method from the
2105 server for this session. */
2106 internal = silc_calloc(1, sizeof(*internal));
2107 internal->completion = completion;
2108 internal->context = context;
2110 silc_client_request_authentication_method(client, conn,
2111 silc_get_auth_method_callback,
2115 /* Notifies application that failure packet was received. This is called
2116 if there is some protocol active in the client. The `protocol' is the
2117 protocol context. The `failure' is opaque pointer to the failure
2118 indication. Note, that the `failure' is protocol dependant and application
2119 must explicitly cast it to correct type. Usually `failure' is 32 bit
2120 failure type (see protocol specs for all protocol failure types). */
2122 void silc_failure(SilcClient client, SilcClientConnection conn,
2123 SilcProtocol protocol, void *failure)
2125 SILC_LOG_DEBUG(("Start"));
2127 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2128 SilcSKEStatus status = (SilcSKEStatus)failure;
2130 if (status == SILC_SKE_STATUS_BAD_VERSION)
2131 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2132 SILCTXT_KE_BAD_VERSION);
2133 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2134 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2135 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2136 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2137 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2138 SILCTXT_KE_UNKNOWN_GROUP);
2139 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2140 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2141 SILCTXT_KE_UNKNOWN_CIPHER);
2142 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2143 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2144 SILCTXT_KE_UNKNOWN_PKCS);
2145 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2146 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2147 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2148 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2149 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2150 SILCTXT_KE_UNKNOWN_HMAC);
2151 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2152 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2153 SILCTXT_KE_INCORRECT_SIGNATURE);
2154 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2155 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2156 SILCTXT_KE_INVALID_COOKIE);
2159 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2160 SilcUInt32 err = (SilcUInt32)failure;
2162 if (err == SILC_AUTH_FAILED)
2163 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2164 SILCTXT_AUTH_FAILED);
2168 /* Asks whether the user would like to perform the key agreement protocol.
2169 This is called after we have received an key agreement packet or an
2170 reply to our key agreement packet. This returns TRUE if the user wants
2171 the library to perform the key agreement protocol and FALSE if it is not
2172 desired (application may start it later by calling the function
2173 silc_client_perform_key_agreement). */
2175 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2176 SilcClientEntry client_entry, const char *hostname,
2177 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2182 SILC_LOG_DEBUG(("Start"));
2184 /* We will just display the info on the screen and return FALSE and user
2185 will have to start the key agreement with a command. */
2188 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2191 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2192 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2194 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2195 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2196 client_entry->nickname, hostname, portstr);
2204 /* Notifies application that file transfer protocol session is being
2205 requested by the remote client indicated by the `client_entry' from
2206 the `hostname' and `port'. The `session_id' is the file transfer
2207 session and it can be used to either accept or reject the file
2208 transfer request, by calling the silc_client_file_receive or
2209 silc_client_file_close, respectively. */
2211 void silc_ftp(SilcClient client, SilcClientConnection conn,
2212 SilcClientEntry client_entry, SilcUInt32 session_id,
2213 const char *hostname, SilcUInt16 port)
2215 SILC_SERVER_REC *server;
2217 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2219 SILC_LOG_DEBUG(("Start"));
2221 server = conn->context;
2223 ftp->client_entry = client_entry;
2224 ftp->session_id = session_id;
2227 silc_dlist_add(server->ftp_sessions, ftp);
2228 server->current_session = ftp;
2231 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2234 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2235 SILCTXT_FILE_REQUEST, client_entry->nickname);
2237 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2238 SILCTXT_FILE_REQUEST_HOST,
2239 client_entry->nickname, hostname, portstr);
2242 /* Delivers SILC session detachment data indicated by `detach_data' to the
2243 application. If application has issued SILC_COMMAND_DETACH command
2244 the client session in the SILC network is not quit. The client remains
2245 in the network but is detached. The detachment data may be used later
2246 to resume the session in the SILC Network. The appliation is
2247 responsible of saving the `detach_data', to for example in a file.
2249 The detachment data can be given as argument to the functions
2250 silc_client_connect_to_server, or silc_client_add_connection when
2251 creating connection to remote server, inside SilcClientConnectionParams
2252 structure. If it is provided the client library will attempt to resume
2253 the session in the network. After the connection is created
2254 successfully, the application is responsible of setting the user
2255 interface for user into the same state it was before detaching (showing
2256 same channels, channel modes, etc). It can do this by fetching the
2257 information (like joined channels) from the client library. */
2260 silc_detach(SilcClient client, SilcClientConnection conn,
2261 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2265 /* Save the detachment data to file. */
2267 memset(file, 0, sizeof(file));
2268 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2269 silc_file_writefile(file, detach_data, detach_data_len);
2273 /* SILC client operations */
2274 SilcClientOperations ops = {
2276 silc_channel_message,
2277 silc_private_message,
2283 silc_get_auth_method,
2284 silc_verify_public_key,
2285 silc_ask_passphrase,