5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2007 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"
32 #include "silc-cmdqueue.h"
38 #include "special-vars.h"
39 #include "fe-common/core/printtext.h"
40 #include "fe-common/core/fe-channels.h"
41 #include "fe-common/core/keyboard.h"
42 #include "fe-common/core/window-items.h"
43 #include "fe-common/silc/module-formats.h"
48 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
49 const char *name, SilcConnectionType conn_type,
50 SilcPublicKey public_key,
51 SilcVerifyPublicKey completion, void *context);
53 char *silc_get_session_filename(SILC_SERVER_REC *server)
55 char *file, *expanded;
57 expanded = parse_special_string(settings_get_str("session_filename"),
58 SERVER(server), NULL, "", NULL, 0);
60 file = silc_calloc(1, strlen(expanded) + 255);
61 snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
67 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
70 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
71 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
72 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
74 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
75 "[SILC operator]" : "[unknown mode]");
77 if (mode & SILC_UMODE_GONE)
78 strcat(buf, " [away]");
79 if (mode & SILC_UMODE_INDISPOSED)
80 strcat(buf, " [indisposed]");
81 if (mode & SILC_UMODE_BUSY)
82 strcat(buf, " [busy]");
83 if (mode & SILC_UMODE_PAGE)
84 strcat(buf, " [page to reach]");
85 if (mode & SILC_UMODE_HYPER)
86 strcat(buf, " [hyper active]");
87 if (mode & SILC_UMODE_ROBOT)
88 strcat(buf, " [robot]");
89 if (mode & SILC_UMODE_ANONYMOUS)
90 strcat(buf, " [anonymous]");
91 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
92 strcat(buf, " [blocks private messages]");
93 if (mode & SILC_UMODE_DETACHED)
94 strcat(buf, " [detached]");
95 if (mode & SILC_UMODE_REJECT_WATCHING)
96 strcat(buf, " [rejects watching]");
97 if (mode & SILC_UMODE_BLOCK_INVITE)
98 strcat(buf, " [blocks invites]");
101 /* converts an utf-8 string to current locale */
102 char * silc_convert_utf8_string(const char *str)
104 int message_len = (str != NULL ? strlen(str) : 0);
105 char *message = silc_calloc(message_len + 1, sizeof(*message));
107 g_return_val_if_fail(message != NULL, NULL);
114 if (!silc_term_utf8() && silc_utf8_valid(str, message_len))
115 silc_utf8_decode(str, message_len, SILC_STRING_LOCALE,
116 message, message_len);
118 strcpy(message, str);
123 /* print "nick appears as" message to every channel of a server */
125 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
126 const char *newnick, const char *oldnick,
129 if (ignore_check(SERVER(server), oldnick, address,
130 channel, newnick, MSGLEVEL_NICKS))
133 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
134 SILCTXT_CHANNEL_APPEARS,
135 oldnick, newnick, channel, address);
139 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
140 const char *oldnick, const char *address)
142 GSList *tmp, *windows;
144 /* Print to each channel/query where the nick is.
145 Don't print more than once to the same window. */
148 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
149 CHANNEL_REC *channel = tmp->data;
150 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
152 if (nicklist_find(channel, newnick) == NULL ||
153 g_slist_find(windows, window) != NULL)
156 windows = g_slist_append(windows, window);
157 silc_print_nick_change_channel(server, channel->visible_name,
158 newnick, oldnick, address);
161 g_slist_free(windows);
164 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
165 SilcChannelEntry channel_entry,
166 SilcDList channel_pubkeys)
168 SilcArgumentDecodedList e;
169 SilcPublicKey pubkey;
170 SilcSILCPublicKey silc_pubkey;
171 SilcUInt32 pk_len, type;
173 char *fingerprint, *babbleprint;
176 printformat_module("fe-common/silc", server, NULL,
177 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
178 channel_entry->channel_name);
180 silc_dlist_start(channel_pubkeys);
181 while ((e = silc_dlist_get(channel_pubkeys))) {
182 pubkey = e->argument;
185 if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
188 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
192 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
193 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
194 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, pubkey);
196 printformat_module("fe-common/silc", server, NULL,
197 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
198 c++, channel_entry->channel_name,
199 type == 0x00 ? "Added" : "Removed",
200 silc_pubkey->identifier.realname ?
201 silc_pubkey->identifier.realname : "",
202 fingerprint, babbleprint);
204 silc_free(fingerprint);
205 silc_free(babbleprint);
210 void silc_say(SilcClient client, SilcClientConnection conn,
211 SilcClientMessageType type, char *msg, ...)
213 SILC_SERVER_REC *server;
217 server = conn == NULL ? NULL : conn->context;
220 str = g_strdup_vprintf(msg, va);
221 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
226 void silc_say_error(char *msg, ...)
232 str = g_strdup_vprintf(msg, va);
233 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
239 /* Try to verify a message using locally stored public key data */
241 int verify_message_signature(SilcClientEntry sender,
242 SilcMessagePayload message)
245 char file[256], filename[256];
246 char *fingerprint, *fingerprint2;
247 const unsigned char *pk_data;
248 SilcUInt32 pk_datalen;
250 int ret = SILC_MSG_SIGNED_VERIFIED, i;
252 /* get public key from the signature payload and compare it with the
253 one stored in the client entry */
254 pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
257 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
259 if (sender->fingerprint[0]) {
260 fingerprint2 = silc_fingerprint(sender->fingerprint,
261 sizeof(sender->fingerprint));
262 if (strcmp(fingerprint, fingerprint2)) {
263 /* since the public key differs from the senders public key, the
264 verification _failed_ */
265 silc_pkcs_public_key_free(pk);
266 silc_free(fingerprint);
267 ret = SILC_MSG_SIGNED_UNKNOWN;
269 silc_free(fingerprint2);
271 } else if (sender->fingerprint[0])
272 fingerprint = silc_fingerprint(sender->fingerprint,
273 sizeof(sender->fingerprint));
275 /* no idea, who or what signed that message ... */
276 return SILC_MSG_SIGNED_UNKNOWN;
278 /* search our local client key cache */
279 for (i = 0; i < strlen(fingerprint); i++)
280 if (fingerprint[i] == ' ')
281 fingerprint[i] = '_';
283 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
284 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
285 get_irssi_dir(), file);
286 silc_free(fingerprint);
288 if (stat(filename, &st) < 0)
289 /* we don't have the public key cached ... use the one from the sig */
290 ret = SILC_MSG_SIGNED_UNKNOWN;
292 SilcPublicKey cached_pk=NULL;
294 /* try to load the file */
295 if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
296 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
297 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
299 return SILC_MSG_SIGNED_UNKNOWN;
301 ret = SILC_MSG_SIGNED_UNKNOWN;
306 silc_pkcs_public_key_free(pk);
311 /* the public key is now in pk, our "level of trust" in ret */
312 if ((pk) && silc_message_signed_verify(message, pk,
313 sha1hash) != SILC_AUTH_OK)
314 ret = SILC_MSG_SIGNED_FAILED;
317 silc_pkcs_public_key_free(pk);
322 char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
325 int i = 0, j = 0, len = strlen(escaped_data);
327 data = silc_calloc(len, sizeof(char));
330 ptr = memchr(escaped_data + i, 1, len - i);
332 int inc = (ptr - escaped_data) - i;
333 memcpy(data + j, escaped_data + i, inc);
336 data[j++] = *(ptr + 1) - 1;
338 memcpy(data + j, escaped_data + i, len - i);
348 char *silc_escape_data(const char *data, SilcUInt32 len)
350 char *escaped_data, *ptr, *ptr0, *ptr1;
353 escaped_data = silc_calloc(2 * len, sizeof(char));
356 ptr0 = memchr(data + i, 0, len - i);
357 ptr1 = memchr(data + i, 1, len - i);
359 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
362 int inc = (ptr - data) - i;
364 memcpy(escaped_data + j, data + i, inc);
367 escaped_data[j++] = 1;
368 escaped_data[j++] = *(data + i++) + 1;
370 memcpy(escaped_data + j, data + i, len - i);
379 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
380 const char *data, SilcUInt32 data_len,
381 const char *nick, int verified)
385 escaped_data = silc_escape_data(data, data_len);
387 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
389 silc_free(escaped_data);
393 /* Message for a channel. The `sender' is the nickname of the sender
394 received in the packet. The `channel_name' is the name of the channel. */
396 void silc_channel_message(SilcClient client, SilcClientConnection conn,
397 SilcClientEntry sender, SilcChannelEntry channel,
398 SilcMessagePayload payload,
399 SilcChannelPrivateKey key,
400 SilcMessageFlags flags, const unsigned char *message,
401 SilcUInt32 message_len)
403 SILC_SERVER_REC *server;
405 SILC_CHANNEL_REC *chanrec;
408 SILC_LOG_DEBUG(("Start"));
413 server = conn == NULL ? NULL : conn->context;
414 chanrec = silc_channel_find_entry(server, channel);
418 nick = silc_nicklist_find(chanrec, sender);
420 /* We didn't find client but it clearly exists, add it. */
421 SilcChannelUser chu = silc_client_on_channel(channel, sender);
423 nick = silc_nicklist_insert(chanrec, chu, FALSE);
428 /* If the messages is digitally signed, verify it, if possible. */
429 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
430 if (!settings_get_bool("ignore_message_signatures")) {
431 verified = verify_message_signature(sender, payload);
433 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
437 if (flags & SILC_MESSAGE_FLAG_DATA) {
438 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
439 nick == NULL ? NULL : nick->nick,
440 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
447 if (flags & SILC_MESSAGE_FLAG_ACTION)
448 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
449 char tmp[256], *cp, *dm = NULL;
450 memset(tmp, 0, sizeof(tmp));
452 if(message_len > sizeof(tmp) - 1) {
453 dm = silc_calloc(message_len + 1, sizeof(*dm));
456 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
458 if (flags & SILC_MESSAGE_FLAG_SIGNED)
459 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
460 nick->host, channel->channel_name, verified);
462 signal_emit("message silc action", 5, server, cp, nick->nick,
463 nick->host, channel->channel_name);
466 if (flags & SILC_MESSAGE_FLAG_SIGNED)
467 signal_emit("message silc signed_action", 6, server, message,
468 nick->nick, nick->host, channel->channel_name, verified);
470 signal_emit("message silc action", 5, server, message,
471 nick->nick, nick->host, channel->channel_name);
473 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
474 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
475 char tmp[256], *cp, *dm = NULL;
476 memset(tmp, 0, sizeof(tmp));
478 if(message_len > sizeof(tmp) - 1) {
479 dm = silc_calloc(message_len + 1, sizeof(*dm));
482 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
484 if (flags & SILC_MESSAGE_FLAG_SIGNED)
485 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
486 nick->host, channel->channel_name, verified);
488 signal_emit("message silc notice", 5, server, cp, nick->nick,
489 nick->host, channel->channel_name);
492 if (flags & SILC_MESSAGE_FLAG_SIGNED)
493 signal_emit("message silc signed_notice", 6, server, message,
494 nick->nick, nick->host, channel->channel_name, verified);
496 signal_emit("message silc notice", 5, server, message,
497 nick->nick, nick->host, channel->channel_name);
500 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
501 char tmp[256], *cp, *dm = NULL;
503 memset(tmp, 0, sizeof(tmp));
505 if (message_len > sizeof(tmp) - 1) {
506 dm = silc_calloc(message_len + 1, sizeof(*dm));
510 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
512 if (flags & SILC_MESSAGE_FLAG_SIGNED)
513 signal_emit("message signed_public", 6, server, cp,
514 nick == NULL ? "[<unknown>]" : nick->nick,
515 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
516 chanrec->name, verified);
518 signal_emit("message public", 6, server, cp,
519 nick == NULL ? "[<unknown>]" : nick->nick,
520 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
521 chanrec->name, nick);
526 if (flags & SILC_MESSAGE_FLAG_SIGNED)
527 signal_emit("message signed_public", 6, server, message,
528 nick == NULL ? "[<unknown>]" : nick->nick,
529 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
530 chanrec->name, verified);
532 signal_emit("message public", 6, server, message,
533 nick == NULL ? "[<unknown>]" : nick->nick,
534 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
535 chanrec->name, nick);
539 /* Private message to the client. The `sender' is the nickname of the
540 sender received in the packet. */
542 void silc_private_message(SilcClient client, SilcClientConnection conn,
543 SilcClientEntry sender, SilcMessagePayload payload,
544 SilcMessageFlags flags,
545 const unsigned char *message,
546 SilcUInt32 message_len)
548 SILC_SERVER_REC *server;
552 SILC_LOG_DEBUG(("Start"));
554 server = conn == NULL ? NULL : conn->context;
555 memset(userhost, 0, sizeof(userhost));
556 if (sender->username[0])
557 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
558 sender->username, sender->hostname);
560 /* If the messages is digitally signed, verify it, if possible. */
561 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
562 if (!settings_get_bool("ignore_message_signatures")) {
563 verified = verify_message_signature(sender, payload);
565 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
569 if (flags & SILC_MESSAGE_FLAG_DATA) {
570 silc_emit_mime_sig(server,
571 sender->nickname[0] ?
572 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
574 message, message_len,
575 sender->nickname[0] ? sender->nickname : "[<unknown>]",
576 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
583 if (flags & SILC_MESSAGE_FLAG_ACTION)
584 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
585 char tmp[256], *cp, *dm = NULL;
586 memset(tmp, 0, sizeof(tmp));
588 if(message_len > sizeof(tmp) - 1) {
589 dm = silc_calloc(message_len + 1, sizeof(*dm));
592 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
594 if (flags & SILC_MESSAGE_FLAG_SIGNED)
595 signal_emit("message silc signed_private_action", 6, server, cp,
596 sender->nickname[0] ? sender->nickname : "[<unknown>]",
597 sender->username[0] ? userhost : NULL,
600 signal_emit("message silc private_action", 5, server, cp,
601 sender->nickname[0] ? sender->nickname : "[<unknown>]",
602 sender->username[0] ? userhost : NULL, NULL);
605 if (flags & SILC_MESSAGE_FLAG_SIGNED)
606 signal_emit("message silc signed_private_action", 6, server, message,
607 sender->nickname[0] ? sender->nickname : "[<unknown>]",
608 sender->username[0] ? userhost : NULL,
611 signal_emit("message silc private_action", 5, server, message,
612 sender->nickname[0] ? sender->nickname : "[<unknown>]",
613 sender->username[0] ? userhost : NULL, NULL);
615 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
616 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
617 char tmp[256], *cp, *dm = NULL;
618 memset(tmp, 0, sizeof(tmp));
620 if(message_len > sizeof(tmp) - 1) {
621 dm = silc_calloc(message_len + 1, sizeof(*dm));
624 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
626 if (flags & SILC_MESSAGE_FLAG_SIGNED)
627 signal_emit("message silc signed_private_notice", 6, server, cp,
628 sender->nickname[0] ? sender->nickname : "[<unknown>]",
629 sender->username[0] ? userhost : NULL,
632 signal_emit("message silc private_notice", 5, server, cp,
633 sender->nickname[0] ? sender->nickname : "[<unknown>]",
634 sender->username[0] ? userhost : NULL, NULL);
637 if (flags & SILC_MESSAGE_FLAG_SIGNED)
638 signal_emit("message silc signed_private_notice", 6, server, message,
639 sender->nickname[0] ? sender->nickname : "[<unknown>]",
640 sender->username[0] ? userhost : NULL,
643 signal_emit("message silc private_notice", 5, server, message,
644 sender->nickname[0] ? sender->nickname : "[<unknown>]",
645 sender->username[0] ? userhost : NULL, NULL);
648 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
649 char tmp[256], *cp, *dm = NULL;
651 memset(tmp, 0, sizeof(tmp));
653 if (message_len > sizeof(tmp) - 1) {
654 dm = silc_calloc(message_len + 1, sizeof(*dm));
658 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
660 if (flags & SILC_MESSAGE_FLAG_SIGNED)
661 signal_emit("message signed_private", 5, server, cp,
662 sender->nickname[0] ? sender->nickname : "[<unknown>]",
663 sender->username[0] ? userhost : NULL, verified);
665 signal_emit("message private", 4, server, cp,
666 sender->nickname[0] ? sender->nickname : "[<unknown>]",
667 sender->username[0] ? userhost : NULL);
672 if (flags & SILC_MESSAGE_FLAG_SIGNED)
673 signal_emit("message signed_private", 5, server, message,
674 sender->nickname[0] ? sender->nickname : "[<unknown>]",
675 sender->username[0] ? userhost : NULL, verified);
677 signal_emit("message private", 4, server, message,
678 sender->nickname[0] ? sender->nickname : "[<unknown>]",
679 sender->username[0] ? userhost : NULL);
683 /* Notify message to the client. The notify arguments are sent in the
684 same order as servers sends them. The arguments are same as received
685 from the server except for ID's. If ID is received application receives
686 the corresponding entry to the ID. For example, if Client ID is received
687 application receives SilcClientEntry. Also, if the notify type is
688 for channel the channel entry is sent to application (even if server
689 does not send it). */
691 void silc_notify(SilcClient client, SilcClientConnection conn,
692 SilcNotifyType type, ...)
695 SILC_SERVER_REC *server;
696 SILC_CHANNEL_REC *chanrec;
697 SILC_NICK_REC *nickrec;
698 SilcClientEntry client_entry, client_entry2;
699 SilcChannelEntry channel, channel2;
700 SilcServerEntry server_entry;
705 char *name, *tmp, *cipher, *hmac;
706 GSList *list1, *list_tmp;
707 SilcDList chpks, clients;
709 SILC_LOG_DEBUG(("Start"));
713 server = conn == NULL ? NULL : conn->context;
716 case SILC_NOTIFY_TYPE_NONE:
717 /* Some generic notice from server */
718 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
721 case SILC_NOTIFY_TYPE_INVITE:
723 * Invited or modified invite list.
726 SILC_LOG_DEBUG(("Notify: INVITE"));
728 channel = va_arg(va, SilcChannelEntry);
729 name = va_arg(va, char *);
730 client_entry = va_arg(va, SilcClientEntry);
732 silc_snprintf(buf, sizeof(buf) - 1, "%s@%s",
733 client_entry->username, client_entry->hostname);
734 signal_emit("message invite", 4, server, name,
735 client_entry->nickname, buf);
738 case SILC_NOTIFY_TYPE_JOIN:
743 SILC_LOG_DEBUG(("Notify: JOIN"));
745 client_entry = va_arg(va, SilcClientEntry);
746 channel = va_arg(va, SilcChannelEntry);
748 if (client_entry == server->conn->local_entry) {
749 /* You joined to channel */
750 chanrec = silc_channel_find(server, channel->channel_name);
752 chanrec = silc_channel_create(server, channel->channel_name,
753 channel->channel_name, TRUE);
754 if (!chanrec->joined)
755 chanrec->entry = channel;
757 chanrec = silc_channel_find_entry(server, channel);
758 if (chanrec != NULL) {
759 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
761 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
765 memset(buf, 0, sizeof(buf));
766 if (client_entry->username[0])
767 snprintf(buf, sizeof(buf) - 1, "%s@%s",
768 client_entry->username, client_entry->hostname);
769 signal_emit("message join", 4, server, channel->channel_name,
770 client_entry->nickname,
771 !client_entry->username[0] ? "" : buf);
773 /* If there are multiple same nicknames on channel now, tell it to user. */
774 if (client_entry != server->conn->local_entry) {
778 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
779 clients = silc_client_get_clients_local(client, conn, nick, TRUE);
780 if (!clients || silc_dlist_count(clients) < 2) {
782 silc_client_list_free(client, conn, clients);
785 silc_dlist_start(clients);
786 while ((client_entry2 = silc_dlist_get(clients)))
787 if (silc_client_on_channel(channel, client_entry2))
790 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
791 printformat_module("fe-common/silc", server, channel->channel_name,
792 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
794 printformat_module("fe-common/silc", server, channel->channel_name,
795 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
796 buf, client_entry->nickname);
798 silc_client_list_free(client, conn, clients);
803 case SILC_NOTIFY_TYPE_LEAVE:
808 SILC_LOG_DEBUG(("Notify: LEAVE"));
810 client_entry = va_arg(va, SilcClientEntry);
811 channel = va_arg(va, SilcChannelEntry);
813 memset(buf, 0, sizeof(buf));
814 if (client_entry->username)
815 snprintf(buf, sizeof(buf) - 1, "%s@%s",
816 client_entry->username, client_entry->hostname);
817 signal_emit("message part", 5, server, channel->channel_name,
818 client_entry->nickname, client_entry->username[0] ?
819 buf : "", client_entry->nickname);
821 chanrec = silc_channel_find_entry(server, channel);
822 if (chanrec != NULL) {
823 nickrec = silc_nicklist_find(chanrec, client_entry);
825 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
828 /* If there is only one client with this same nickname on channel now
829 change it to the base format if it is formatted nickname. */
831 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
832 clients = silc_client_get_clients_local(client, conn, name, TRUE);
833 if (!clients || silc_dlist_count(clients) != 2) {
835 silc_client_list_free(client, conn, clients);
838 silc_dlist_start(clients);
839 client_entry2 = silc_dlist_get(clients);
840 if (client_entry2 == client_entry)
841 client_entry2 = silc_dlist_get(clients);
842 if (silc_client_on_channel(channel, client_entry2)) {
843 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
844 silc_client_nickname_format(client, conn, client_entry2, TRUE);
845 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
846 nicklist_rename_unique(SERVER(server), client_entry2, buf,
847 client_entry2, client_entry2->nickname);
848 printformat_module("fe-common/silc", server, channel->channel_name,
849 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
850 buf, client_entry2->nickname);
853 silc_client_list_free(client, conn, clients);
858 case SILC_NOTIFY_TYPE_SIGNOFF:
863 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
865 client_entry = va_arg(va, SilcClientEntry);
866 tmp = va_arg(va, char *);
867 channel = va_arg(va, SilcChannelEntry);
869 silc_server_free_ftp(server, client_entry);
871 memset(buf, 0, sizeof(buf));
872 if (client_entry->username)
873 snprintf(buf, sizeof(buf) - 1, "%s@%s",
874 client_entry->username, client_entry->hostname);
875 signal_emit("message quit", 4, server, client_entry->nickname,
876 client_entry->username[0] ? buf : "", tmp ? tmp : "");
878 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
879 for (list_tmp = list1; list_tmp != NULL; list_tmp =
880 list_tmp->next->next) {
881 CHANNEL_REC *channel = list_tmp->data;
882 NICK_REC *nickrec = list_tmp->next->data;
884 nicklist_remove(channel, nickrec);
887 /* If there is only one client with this same nickname on channel now
888 change it to the base format if it is formatted nickname. */
890 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
891 clients = silc_client_get_clients_local(client, conn, name, TRUE);
892 if (!clients || silc_dlist_count(clients) != 2) {
894 silc_client_list_free(client, conn, clients);
897 silc_dlist_start(clients);
898 client_entry2 = silc_dlist_get(clients);
899 if (client_entry2 == client_entry)
900 client_entry2 = silc_dlist_get(clients);
901 if (silc_client_on_channel(channel, client_entry2)) {
902 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
903 silc_client_nickname_format(client, conn, client_entry2, TRUE);
904 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
905 nicklist_rename_unique(SERVER(server), client_entry2, buf,
906 client_entry2, client_entry2->nickname);
907 printformat_module("fe-common/silc", server, channel->channel_name,
908 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
909 buf, client_entry2->nickname);
912 silc_client_list_free(client, conn, clients);
917 case SILC_NOTIFY_TYPE_TOPIC_SET:
922 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
924 idtype = va_arg(va, int);
925 entry = va_arg(va, void *);
926 tmp = va_arg(va, char *);
927 channel = va_arg(va, SilcChannelEntry);
929 chanrec = silc_channel_find_entry(server, channel);
930 if (chanrec != NULL) {
931 char tmp2[256], *cp, *dm = NULL;
933 g_free_not_null(chanrec->topic);
934 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
935 memset(tmp2, 0, sizeof(tmp2));
937 if (strlen(tmp) > sizeof(tmp2) - 1) {
938 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
942 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
947 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
948 signal_emit("channel topic changed", 1, chanrec);
953 if (idtype == SILC_ID_CLIENT) {
954 client_entry = (SilcClientEntry)entry;
955 memset(buf, 0, sizeof(buf));
956 snprintf(buf, sizeof(buf) - 1, "%s@%s",
957 client_entry->username, client_entry->hostname);
958 signal_emit("message topic", 5, server, channel->channel_name,
959 tmp, client_entry->nickname, buf);
960 } else if (idtype == SILC_ID_SERVER) {
961 server_entry = (SilcServerEntry)entry;
962 signal_emit("message topic", 5, server, channel->channel_name,
963 tmp, server_entry->server_name,
964 server_entry->server_name);
965 } else if (idtype == SILC_ID_CHANNEL) {
966 channel = (SilcChannelEntry)entry;
967 signal_emit("message topic", 5, server, channel->channel_name,
968 tmp, channel->channel_name, channel->channel_name);
972 case SILC_NOTIFY_TYPE_NICK_CHANGE:
977 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
979 client_entry = va_arg(va, SilcClientEntry);
980 name = va_arg(va, char *); /* old nickname */
982 if (!strcmp(client_entry->nickname, name))
985 memset(buf, 0, sizeof(buf));
986 snprintf(buf, sizeof(buf) - 1, "%s@%s",
987 client_entry->username, client_entry->hostname);
988 nicklist_rename_unique(SERVER(server),
990 client_entry, client_entry->nickname);
991 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
994 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
996 * Changed channel mode.
999 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
1001 idtype = va_arg(va, int);
1002 entry = va_arg(va, void *);
1003 mode = va_arg(va, SilcUInt32);
1004 cipher = va_arg(va, char *); /* cipher */
1005 hmac = va_arg(va, char *); /* hmac */
1006 (void)va_arg(va, char *); /* passphrase */
1007 (void)va_arg(va, SilcPublicKey); /* founder key */
1008 chpks = va_arg(va, SilcDList); /* channel public keys */
1009 channel = va_arg(va, SilcChannelEntry);
1011 tmp = silc_client_chmode(mode, cipher ? cipher : "",
1014 chanrec = silc_channel_find_entry(server, channel);
1015 if (chanrec != NULL) {
1016 g_free_not_null(chanrec->mode);
1017 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
1018 signal_emit("channel mode changed", 1, chanrec);
1021 if (idtype == SILC_ID_CLIENT) {
1022 client_entry = (SilcClientEntry)entry;
1023 printformat_module("fe-common/silc", server, channel->channel_name,
1024 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1025 channel->channel_name, tmp ? tmp : "removed all",
1026 client_entry->nickname);
1027 } else if (idtype == SILC_ID_SERVER) {
1028 server_entry = (SilcServerEntry)entry;
1029 printformat_module("fe-common/silc", server, channel->channel_name,
1030 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1031 channel->channel_name, tmp ? tmp : "removed all",
1032 server_entry->server_name);
1033 } else if (idtype == SILC_ID_CHANNEL) {
1034 channel2 = (SilcChannelEntry)entry;
1035 printformat_module("fe-common/silc", server, channel->channel_name,
1036 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1037 channel->channel_name, tmp ? tmp : "removed all",
1038 channel2->channel_name);
1041 /* Print the channel public key list */
1043 silc_parse_channel_public_keys(server, channel, chpks);
1048 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1050 * Changed user's mode on channel.
1053 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1055 idtype = va_arg(va, int);
1056 entry = va_arg(va, void *);
1057 mode = va_arg(va, SilcUInt32);
1058 client_entry2 = va_arg(va, SilcClientEntry);
1059 channel = va_arg(va, SilcChannelEntry);
1061 tmp = silc_client_chumode(mode);
1062 chanrec = silc_channel_find_entry(server, channel);
1063 if (chanrec != NULL) {
1064 SILC_NICK_REC *nick;
1066 if (client_entry2 == server->conn->local_entry)
1067 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1069 nick = silc_nicklist_find(chanrec, client_entry2);
1071 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1072 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1073 signal_emit("nick mode changed", 2, chanrec, nick);
1077 if (idtype == SILC_ID_CLIENT) {
1078 client_entry = (SilcClientEntry)entry;
1079 printformat_module("fe-common/silc", server, channel->channel_name,
1080 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1081 channel->channel_name, client_entry2->nickname,
1082 tmp ? tmp : "removed all",
1083 client_entry->nickname);
1084 } else if (idtype == SILC_ID_SERVER) {
1085 server_entry = (SilcServerEntry)entry;
1086 printformat_module("fe-common/silc", server, channel->channel_name,
1087 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1088 channel->channel_name, client_entry2->nickname,
1089 tmp ? tmp : "removed all",
1090 server_entry->server_name);
1091 } else if (idtype == SILC_ID_CHANNEL) {
1092 channel2 = (SilcChannelEntry)entry;
1093 printformat_module("fe-common/silc", server, channel->channel_name,
1094 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1095 channel->channel_name, client_entry2->nickname,
1096 tmp ? tmp : "removed all",
1097 channel2->channel_name);
1100 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1101 printformat_module("fe-common/silc",
1102 server, channel->channel_name, MSGLEVEL_CRAP,
1103 SILCTXT_CHANNEL_FOUNDER,
1104 channel->channel_name, client_entry2->nickname);
1106 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1107 printformat_module("fe-common/silc",
1108 server, channel->channel_name, MSGLEVEL_CRAP,
1109 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1114 case SILC_NOTIFY_TYPE_MOTD:
1119 SILC_LOG_DEBUG(("Notify: MOTD"));
1121 tmp = va_arg(va, char *);
1123 if (!settings_get_bool("skip_motd"))
1124 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1127 case SILC_NOTIFY_TYPE_KICKED:
1129 * Someone was kicked from channel.
1132 SILC_LOG_DEBUG(("Notify: KICKED"));
1134 client_entry = va_arg(va, SilcClientEntry);
1135 tmp = va_arg(va, char *);
1136 client_entry2 = va_arg(va, SilcClientEntry);
1137 channel = va_arg(va, SilcChannelEntry);
1139 chanrec = silc_channel_find_entry(server, channel);
1141 if (client_entry == conn->local_entry) {
1142 printformat_module("fe-common/silc", server, channel->channel_name,
1143 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1144 channel->channel_name,
1145 client_entry ? client_entry2->nickname : "",
1148 chanrec->kicked = TRUE;
1149 channel_destroy((CHANNEL_REC *)chanrec);
1152 printformat_module("fe-common/silc", server, channel->channel_name,
1153 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1154 client_entry->nickname, channel->channel_name,
1155 client_entry2 ? client_entry2->nickname : "",
1159 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1160 if (nickrec != NULL)
1161 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1166 case SILC_NOTIFY_TYPE_KILLED:
1168 * Someone was killed from the network.
1171 SILC_LOG_DEBUG(("Notify: KILLED"));
1173 client_entry = va_arg(va, SilcClientEntry);
1174 tmp = va_arg(va, char *);
1175 idtype = va_arg(va, int);
1176 entry = va_arg(va, SilcClientEntry);
1178 if (client_entry == conn->local_entry) {
1179 if (idtype == SILC_ID_CLIENT) {
1180 client_entry2 = (SilcClientEntry)entry;
1181 printformat_module("fe-common/silc", server, NULL,
1182 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1183 client_entry2 ? client_entry2->nickname : "",
1185 } else if (idtype == SILC_ID_SERVER) {
1186 server_entry = (SilcServerEntry)entry;
1187 printformat_module("fe-common/silc", server, NULL,
1188 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1189 server_entry->server_name, tmp ? tmp : "");
1190 } else if (idtype == SILC_ID_CHANNEL) {
1191 channel = (SilcChannelEntry)entry;
1192 printformat_module("fe-common/silc", server, NULL,
1193 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1194 channel->channel_name, tmp ? tmp : "");
1197 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1198 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1199 list_tmp->next->next) {
1200 CHANNEL_REC *channel = list_tmp->data;
1201 NICK_REC *nickrec = list_tmp->next->data;
1202 nicklist_remove(channel, nickrec);
1205 if (idtype == SILC_ID_CLIENT) {
1206 client_entry2 = (SilcClientEntry)entry;
1207 printformat_module("fe-common/silc", server, NULL,
1208 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1209 client_entry->nickname,
1210 client_entry2 ? client_entry2->nickname : "",
1212 } else if (idtype == SILC_ID_SERVER) {
1213 server_entry = (SilcServerEntry)entry;
1214 printformat_module("fe-common/silc", server, NULL,
1215 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1216 client_entry->nickname,
1217 server_entry->server_name, tmp ? tmp : "");
1218 } else if (idtype == SILC_ID_CHANNEL) {
1219 channel = (SilcChannelEntry)entry;
1220 printformat_module("fe-common/silc", server, NULL,
1221 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1222 client_entry->nickname,
1223 channel->channel_name, tmp ? tmp : "");
1228 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1231 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1234 * Server has quit the network.
1238 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1240 (void)va_arg(va, void *);
1241 clients = va_arg(va, SilcDList);
1243 silc_dlist_start(clients);
1244 while ((client_entry = silc_dlist_get(clients))) {
1245 memset(buf, 0, sizeof(buf));
1247 /* Print only if we have the nickname. If this client has just quit
1248 when we were only resolving it, it is possible we don't have the
1250 if (client_entry->nickname[0]) {
1251 if (client_entry->username[0])
1252 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1253 client_entry->username, client_entry->hostname);
1254 signal_emit("message quit", 4, server, client_entry->nickname,
1255 client_entry->username[0] ? buf : "",
1259 silc_server_free_ftp(server, client_entry);
1261 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1262 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1263 list_tmp->next->next) {
1264 CHANNEL_REC *channel = list_tmp->data;
1265 NICK_REC *nickrec = list_tmp->next->data;
1266 nicklist_remove(channel, nickrec);
1272 case SILC_NOTIFY_TYPE_ERROR:
1274 SilcStatus error = va_arg(va, int);
1276 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1277 "%s", silc_get_status_message(error));
1281 case SILC_NOTIFY_TYPE_WATCH:
1283 SilcNotifyType notify;
1285 client_entry = va_arg(va, SilcClientEntry);
1286 name = va_arg(va, char *); /* Maybe NULL */
1287 mode = va_arg(va, SilcUInt32);
1288 notify = va_arg(va, int);
1290 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1292 printformat_module("fe-common/silc", server, NULL,
1293 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1294 client_entry->nickname, name);
1296 printformat_module("fe-common/silc", server, NULL,
1297 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1298 client_entry->nickname);
1299 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1300 /* See if client was away and is now present */
1301 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1302 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1303 SILC_UMODE_DETACHED)) &&
1304 (client_entry->mode & SILC_UMODE_GONE ||
1305 client_entry->mode & SILC_UMODE_INDISPOSED ||
1306 client_entry->mode & SILC_UMODE_BUSY ||
1307 client_entry->mode & SILC_UMODE_PAGE ||
1308 client_entry->mode & SILC_UMODE_DETACHED)) {
1309 printformat_module("fe-common/silc", server, NULL,
1310 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1311 client_entry->nickname);
1315 memset(buf, 0, sizeof(buf));
1316 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1317 printformat_module("fe-common/silc", server, NULL,
1318 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1319 client_entry->nickname, buf);
1321 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1322 printformat_module("fe-common/silc", server, NULL,
1323 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1324 client_entry->nickname);
1325 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1326 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1327 printformat_module("fe-common/silc", server, NULL,
1328 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1329 client_entry->nickname);
1330 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1331 /* Client logged in to the network */
1332 printformat_module("fe-common/silc", server, NULL,
1333 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1334 client_entry->nickname);
1340 /* Unknown notify */
1341 printformat_module("fe-common/silc", server, NULL,
1342 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1349 /* Command handler. This function is called always in the command function.
1350 If error occurs it will be called as well. `conn' is the associated
1351 client connection. `cmd_context' is the command context that was
1352 originally sent to the command. `success' is FALSE if error occured
1353 during command. `command' is the command being processed. It must be
1354 noted that this is not reply from server. This is merely called just
1355 after application has called the command. Just to tell application
1356 that the command really was processed. */
1358 static SilcBool cmode_list_chpks = FALSE;
1360 void silc_command(SilcClient client, SilcClientConnection conn,
1361 SilcBool success, SilcCommand command, SilcStatus status,
1362 SilcUInt32 argc, unsigned char **argv)
1364 SILC_SERVER_REC *server = conn->context;
1366 SILC_LOG_DEBUG(("Start"));
1369 silc_say_error("%s", silc_get_status_message(status));
1375 case SILC_COMMAND_INVITE:
1377 printformat_module("fe-common/silc", server, NULL,
1378 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1380 (argv[1][0] == '*' ?
1381 (char *)conn->current_channel->channel_name :
1385 case SILC_COMMAND_DETACH:
1386 server->no_reconnect = TRUE;
1389 case SILC_COMMAND_CMODE:
1390 if (argc == 3 && !strcmp(argv[2], "+C"))
1391 cmode_list_chpks = TRUE;
1393 cmode_list_chpks = FALSE;
1403 SilcClientConnection conn;
1408 void silc_getkey_cb(bool success, void *context)
1410 GetkeyContext getkey = (GetkeyContext)context;
1411 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1412 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1413 ((SilcClientEntry)getkey->entry)->nickname :
1414 ((SilcServerEntry)getkey->entry)->server_name);
1415 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1416 ((SilcClientEntry)getkey->entry)->public_key :
1417 ((SilcServerEntry)getkey->entry)->public_key);
1418 SilcSILCPublicKey silc_pubkey;
1420 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1423 if (getkey->id_type == SILC_ID_CLIENT)
1424 printformat_module("fe-common/silc", NULL, NULL,
1425 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1427 silc_pubkey->identifier.realname ?
1428 silc_pubkey->identifier.realname : "",
1429 silc_pubkey->identifier.email ?
1430 silc_pubkey->identifier.email : "");
1432 printformat_module("fe-common/silc", NULL, NULL,
1433 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1436 printformat_module("fe-common/silc", NULL, NULL,
1437 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1444 /* Parse an invite or ban list */
1445 void silc_parse_inviteban_list(SilcClient client,
1446 SilcClientConnection conn,
1447 SILC_SERVER_REC *server,
1448 SilcChannelEntry channel,
1449 const char *list_type,
1450 SilcArgumentPayload list)
1453 SilcUInt32 type, len;
1454 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1455 int counter=0, resolving = FALSE;
1457 if (!silc_argument_get_arg_num(list)) {
1458 printformat_module("fe-common/silc", server,
1459 (chanrec ? chanrec->visible_name : NULL),
1460 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1461 channel->channel_name, list_type);
1465 printformat_module("fe-common/silc", server,
1466 (chanrec ? chanrec->visible_name : NULL),
1467 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1468 channel->channel_name, list_type);
1470 /* Parse the list */
1471 tmp = silc_argument_get_first_arg(list, &type, &len);
1476 /* An invite string */
1480 if (tmp[len-1] == ',')
1483 list = g_strsplit(tmp, ",", -1);
1485 printformat_module("fe-common/silc", server,
1486 (chanrec ? chanrec->visible_name : NULL),
1487 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1488 ++counter, channel->channel_name, list_type,
1497 char *fingerprint, *babbleprint;
1499 /* tmp is Public Key Payload, take public key from it. */
1500 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1501 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1503 printformat_module("fe-common/silc", server,
1504 (chanrec ? chanrec->visible_name : NULL),
1505 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1506 ++counter, channel->channel_name, list_type,
1507 fingerprint, babbleprint);
1514 SilcClientEntry client_entry;
1517 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1518 silc_say_error("Invalid data in %s list encountered", list_type);
1522 client_entry = silc_client_get_client_by_id(client, conn,
1525 printformat_module("fe-common/silc", server,
1526 (chanrec ? chanrec->visible_name : NULL),
1527 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1528 ++counter, channel->channel_name, list_type,
1529 client_entry->nickname);
1530 silc_client_unref_client(client, conn, client_entry);
1533 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1541 silc_say_error("Unkown type in %s list: %u (len %u)",
1542 list_type, type, len);
1545 tmp = silc_argument_get_next_arg(list, &type, &len);
1549 printformat_module("fe-common/silc", server,
1550 (chanrec ? chanrec->visible_name : NULL),
1551 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1552 list_type, channel->channel_name);
1555 /* Command reply handler. This function is called always in the command reply
1556 function. If error occurs it will be called as well. Normal scenario
1557 is that it will be called after the received command data has been parsed
1558 and processed. The function is used to pass the received command data to
1561 `conn' is the associated client connection. `cmd_payload' is the command
1562 payload data received from server and it can be ignored. It is provided
1563 if the application would like to re-parse the received command data,
1564 however, it must be noted that the data is parsed already by the library
1565 thus the payload can be ignored. `success' is FALSE if error occured.
1566 In this case arguments are not sent to the application. `command' is the
1567 command reply being processed. The function has variable argument list
1568 and each command defines the number and type of arguments it passes to the
1569 application (on error they are not sent). */
1571 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1572 SilcCommand command, SilcStatus status,
1573 SilcStatus error, va_list vp)
1575 SILC_SERVER_REC *server = conn->context;
1576 SILC_CHANNEL_REC *chanrec;
1578 SILC_LOG_DEBUG(("Start"));
1581 case SILC_COMMAND_WHOIS:
1583 char buf[1024], *nickname, *username, *realname, *nick;
1584 unsigned char *fingerprint;
1585 SilcUInt32 idle, mode, *user_modes;
1587 SilcClientEntry client_entry;
1590 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1591 /* Print the unknown nick for user */
1592 char *tmp = va_arg(vp, char *);
1594 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1596 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1597 /* Try to find the entry for the unknown client ID, since we
1598 might have, and print the nickname of it for user. */
1599 SilcClientID *id = va_arg(vp, SilcClientID *);
1601 client_entry = silc_client_get_client_by_id(client, conn, id);
1602 if (client_entry && client_entry->nickname[0])
1603 silc_say_error("%s: %s", client_entry->nickname,
1604 silc_get_status_message(status));
1605 silc_client_unref_client(client, conn, client_entry);
1608 } else if (SILC_STATUS_IS_ERROR(status)) {
1609 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1613 client_entry = va_arg(vp, SilcClientEntry);
1614 nickname = va_arg(vp, char *);
1615 username = va_arg(vp, char *);
1616 realname = va_arg(vp, char *);
1617 channels = va_arg(vp, SilcDList);
1618 mode = va_arg(vp, SilcUInt32);
1619 idle = va_arg(vp, SilcUInt32);
1620 fingerprint = va_arg(vp, unsigned char *);
1621 user_modes = va_arg(vp, SilcUInt32 *);
1622 attrs = va_arg(vp, SilcDList);
1624 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1625 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1626 SILCTXT_WHOIS_USERINFO, nickname,
1627 client_entry->username, client_entry->hostname,
1628 nick, client_entry->nickname);
1629 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1630 SILCTXT_WHOIS_REALNAME, realname);
1633 if (channels && user_modes) {
1634 SilcChannelPayload entry;
1637 memset(buf, 0, sizeof(buf));
1638 silc_dlist_start(channels);
1639 while ((entry = silc_dlist_get(channels))) {
1640 SilcUInt32 name_len;
1641 char *m = silc_client_chumode_char(user_modes[i++]);
1642 char *name = silc_channel_get_name(entry, &name_len);
1645 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1646 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1647 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1651 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1652 SILCTXT_WHOIS_CHANNELS, buf);
1656 memset(buf, 0, sizeof(buf));
1657 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1658 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1659 SILCTXT_WHOIS_MODES, buf);
1662 if (idle && nickname) {
1663 memset(buf, 0, sizeof(buf));
1664 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1665 idle > 60 ? (idle / 60) : idle,
1666 idle > 60 ? "minutes" : "seconds");
1668 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1669 SILCTXT_WHOIS_IDLE, buf);
1673 fingerprint = silc_fingerprint(fingerprint, 20);
1674 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1675 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1676 silc_free(fingerprint);
1680 silc_query_attributes_print(server, silc_client, conn, attrs,
1685 case SILC_COMMAND_WHOWAS:
1687 char *nickname, *username, *realname;
1689 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1690 char *tmp = va_arg(vp, char *);
1692 silc_say_error("%s: %s", tmp,
1693 silc_get_status_message(status));
1695 } else if (SILC_STATUS_IS_ERROR(status)) {
1696 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1700 (void)va_arg(vp, SilcClientEntry);
1701 nickname = va_arg(vp, char *);
1702 username = va_arg(vp, char *);
1703 realname = va_arg(vp, char *);
1705 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1706 SILCTXT_WHOWAS_USERINFO, nickname, username,
1707 realname ? realname : "");
1711 case SILC_COMMAND_INVITE:
1713 SilcChannelEntry channel;
1714 SilcArgumentPayload invite_list;
1716 if (SILC_STATUS_IS_ERROR(status))
1719 channel = va_arg(vp, SilcChannelEntry);
1720 invite_list = va_arg(vp, SilcArgumentPayload);
1723 silc_parse_inviteban_list(client, conn, server, channel,
1724 "invite", invite_list);
1728 case SILC_COMMAND_JOIN:
1730 char *channel, *mode, *topic, *cipher, *hmac;
1732 SilcHashTableList *user_list;
1733 SilcChannelEntry channel_entry;
1734 SilcChannelUser chu;
1735 SilcClientEntry founder = NULL;
1738 if (SILC_STATUS_IS_ERROR(status)) {
1739 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
1740 char *tmp = va_arg(vp, char *);
1742 silc_say_error("JOIN: %s: %s", tmp,
1743 silc_get_status_message(status));
1746 if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
1747 char *tmp = va_arg(vp, char *);
1749 silc_say_error("JOIN: %s: %s", tmp,
1750 silc_get_status_message(status));
1753 silc_say_error("JOIN: %s", silc_get_status_message(status));
1757 channel = va_arg(vp, char *);
1758 channel_entry = va_arg(vp, SilcChannelEntry);
1759 modei = va_arg(vp, SilcUInt32);
1760 user_list = va_arg(vp, SilcHashTableList *);
1761 topic = va_arg(vp, char *);
1762 cipher = va_arg(vp, char *);
1763 hmac = va_arg(vp, char *);
1765 chanrec = silc_channel_find(server, channel);
1767 chanrec = silc_channel_create(server, channel, channel, TRUE);
1770 char tmp[256], *cp, *dm = NULL;
1771 g_free_not_null(chanrec->topic);
1773 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1774 memset(tmp, 0, sizeof(tmp));
1776 if (strlen(topic) > sizeof(tmp) - 1) {
1777 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1781 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1786 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1787 signal_emit("channel topic changed", 1, chanrec);
1792 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1793 g_free_not_null(chanrec->mode);
1794 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1795 signal_emit("channel mode changed", 1, chanrec);
1798 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1799 if (!chu->client->nickname[0])
1801 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1802 founder = chu->client;
1803 silc_nicklist_insert(chanrec, chu, FALSE);
1806 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1809 nicklist_set_own(CHANNEL(chanrec), ownnick);
1810 signal_emit("channel joined", 1, chanrec);
1811 chanrec->entry = channel_entry;
1814 printformat_module("fe-common/silc", server,
1815 channel_entry->channel_name,
1816 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1817 channel_entry->channel_name, chanrec->topic);
1820 if (founder == conn->local_entry) {
1821 printformat_module("fe-common/silc",
1822 server, channel_entry->channel_name,
1823 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1824 channel_entry->channel_name);
1825 signal_emit("nick mode changed", 2, chanrec, ownnick);
1827 printformat_module("fe-common/silc",
1828 server, channel_entry->channel_name,
1829 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1830 channel_entry->channel_name, founder->nickname);
1836 case SILC_COMMAND_NICK:
1839 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1842 if (SILC_STATUS_IS_ERROR(status)) {
1843 silc_say_error("NICK: %s", silc_get_status_message(status));
1847 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1848 if ((nicks != NULL) &&
1849 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1851 SilcClientEntry collider, old;
1853 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1854 collider = silc_client_get_client_by_id(client, conn, &old->id);
1855 if (collider != client_entry) {
1856 memset(buf, 0, sizeof(buf));
1857 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1858 collider->username, collider->hostname);
1859 nicklist_rename_unique(SERVER(server),
1861 collider, collider->nickname);
1862 silc_print_nick_change(server, collider->nickname,
1863 client_entry->nickname, buf);
1865 silc_client_unref_client(client, conn, collider);
1869 g_slist_free(nicks);
1871 old = g_strdup(server->nick);
1872 server_change_nick(SERVER(server), client_entry->nickname);
1873 nicklist_rename_unique(SERVER(server),
1874 server->conn->local_entry, server->nick,
1875 client_entry, client_entry->nickname);
1876 signal_emit("message own_nick", 4, server, server->nick, old, "");
1879 /* when connecting to a server, the last thing we receive
1880 is a SILC_COMMAND_LIST reply. Since we enable queueing
1881 during the connection, we can now safely disable it again */
1882 silc_queue_disable(conn);
1886 case SILC_COMMAND_LIST:
1891 char tmp[256], *cp, *dm = NULL;
1893 if (SILC_STATUS_IS_ERROR(status))
1896 (void)va_arg(vp, SilcChannelEntry);
1897 name = va_arg(vp, char *);
1898 topic = va_arg(vp, char *);
1899 usercount = va_arg(vp, int);
1901 if (topic && !silc_term_utf8() &&
1902 silc_utf8_valid(topic, strlen(topic))) {
1903 memset(tmp, 0, sizeof(tmp));
1905 if (strlen(topic) > sizeof(tmp) - 1) {
1906 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1910 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1915 if (status == SILC_STATUS_LIST_START ||
1916 status == SILC_STATUS_OK)
1917 printformat_module("fe-common/silc", server, NULL,
1918 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1921 snprintf(users, sizeof(users) - 1, "N/A");
1923 snprintf(users, sizeof(users) - 1, "%d", usercount);
1924 printformat_module("fe-common/silc", server, NULL,
1925 MSGLEVEL_CRAP, SILCTXT_LIST,
1926 name, users, topic ? topic : "");
1931 case SILC_COMMAND_UMODE:
1936 if (SILC_STATUS_IS_ERROR(status))
1939 mode = va_arg(vp, SilcUInt32);
1941 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1942 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1943 printformat_module("fe-common/silc", server, NULL,
1944 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1946 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1947 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1948 printformat_module("fe-common/silc", server, NULL,
1949 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1951 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1952 if (mode & SILC_UMODE_GONE) {
1953 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1954 reason = g_strdup(server->away_reason);
1956 reason = g_strdup("away");
1958 reason = g_strdup("");
1960 silc_set_away(reason, server);
1965 server->umode = mode;
1966 signal_emit("user mode changed", 2, server, NULL);
1970 case SILC_COMMAND_OPER:
1971 if (SILC_STATUS_IS_ERROR(status)) {
1972 silc_say_error("OPER: %s", silc_get_status_message(status));
1976 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1977 signal_emit("user mode changed", 2, server, NULL);
1979 printformat_module("fe-common/silc", server, NULL,
1980 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1983 case SILC_COMMAND_SILCOPER:
1984 if (SILC_STATUS_IS_ERROR(status)) {
1985 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1989 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1990 signal_emit("user mode changed", 2, server, NULL);
1992 printformat_module("fe-common/silc", server, NULL,
1993 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1996 case SILC_COMMAND_USERS:
1998 SilcHashTableList htl;
1999 SilcChannelEntry channel;
2000 SilcChannelUser chu;
2002 if (SILC_STATUS_IS_ERROR(status)) {
2003 silc_say_error("USERS: %s", silc_get_status_message(status));
2007 channel = va_arg(vp, SilcChannelEntry);
2009 printformat_module("fe-common/silc", server, channel->channel_name,
2010 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2011 channel->channel_name);
2013 silc_hash_table_list(channel->user_list, &htl);
2014 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2015 SilcClientEntry e = chu->client;
2016 char stat[5], *mode;
2018 if (!e->nickname[0])
2021 memset(stat, 0, sizeof(stat));
2022 mode = silc_client_chumode_char(chu->mode);
2023 if (e->mode & SILC_UMODE_GONE)
2025 else if (e->mode & SILC_UMODE_INDISPOSED)
2027 else if (e->mode & SILC_UMODE_BUSY)
2029 else if (e->mode & SILC_UMODE_PAGE)
2031 else if (e->mode & SILC_UMODE_HYPER)
2033 else if (e->mode & SILC_UMODE_ROBOT)
2035 else if (e->mode & SILC_UMODE_ANONYMOUS)
2042 printformat_module("fe-common/silc", server, channel->channel_name,
2043 MSGLEVEL_CRAP, SILCTXT_USERS,
2045 e->username[0] ? e->username : "",
2046 e->hostname[0] ? e->hostname : "",
2047 e->realname ? e->realname : "");
2051 silc_hash_table_list_reset(&htl);
2055 case SILC_COMMAND_BAN:
2057 SilcChannelEntry channel;
2058 SilcArgumentPayload invite_list;
2060 if (SILC_STATUS_IS_ERROR(status))
2063 channel = va_arg(vp, SilcChannelEntry);
2064 invite_list = va_arg(vp, SilcArgumentPayload);
2067 silc_parse_inviteban_list(client, conn, server, channel,
2068 "ban", invite_list);
2072 case SILC_COMMAND_GETKEY:
2076 SilcPublicKey public_key;
2077 GetkeyContext getkey;
2080 if (SILC_STATUS_IS_ERROR(status)) {
2081 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2085 id_type = va_arg(vp, SilcUInt32);
2086 entry = va_arg(vp, void *);
2087 public_key = va_arg(vp, SilcPublicKey);
2090 getkey = silc_calloc(1, sizeof(*getkey));
2091 getkey->entry = entry;
2092 getkey->id_type = id_type;
2093 getkey->client = client;
2094 getkey->conn = conn;
2096 name = (id_type == SILC_ID_CLIENT ?
2097 ((SilcClientEntry)entry)->nickname :
2098 ((SilcServerEntry)entry)->server_name);
2100 silc_verify_public_key_internal(client, conn, name,
2101 (id_type == SILC_ID_CLIENT ?
2104 public_key, silc_getkey_cb, getkey);
2106 printformat_module("fe-common/silc", server, NULL,
2107 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2112 case SILC_COMMAND_INFO:
2114 SilcServerEntry server_entry;
2118 if (SILC_STATUS_IS_ERROR(status))
2121 server_entry = va_arg(vp, SilcServerEntry);
2122 server_name = va_arg(vp, char *);
2123 server_info = va_arg(vp, char *);
2125 if (server_name && server_info )
2127 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2128 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2133 case SILC_COMMAND_TOPIC:
2135 SilcChannelEntry channel;
2137 char tmp[256], *cp, *dm = NULL;
2139 if (SILC_STATUS_IS_ERROR(status))
2142 channel = va_arg(vp, SilcChannelEntry);
2143 topic = va_arg(vp, char *);
2145 if (topic && !silc_term_utf8() &&
2146 silc_utf8_valid(topic, strlen(topic))) {
2147 memset(tmp, 0, sizeof(tmp));
2149 if (strlen(topic) > sizeof(tmp) - 1) {
2150 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2154 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2160 chanrec = silc_channel_find_entry(server, channel);
2162 g_free_not_null(chanrec->topic);
2163 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2164 signal_emit("channel topic changed", 1, chanrec);
2166 printformat_module("fe-common/silc", server, channel->channel_name,
2167 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2168 channel->channel_name, topic);
2170 printformat_module("fe-common/silc", server, channel->channel_name,
2171 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2172 channel->channel_name);
2178 case SILC_COMMAND_WATCH:
2181 case SILC_COMMAND_STATS:
2183 SilcClientStats *cstats;
2185 const char *tmptime;
2186 int days, hours, mins, secs;
2188 if (SILC_STATUS_IS_ERROR(status))
2191 cstats = va_arg(vp, SilcClientStats *);
2193 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2197 tmptime = silc_time_string(cstats->starttime);
2198 printformat_module("fe-common/silc", server, NULL,
2199 MSGLEVEL_CRAP, SILCTXT_STATS,
2200 "Local server start time", tmptime);
2202 days = cstats->uptime / (24 * 60 * 60);
2203 cstats->uptime -= days * (24 * 60 * 60);
2204 hours = cstats->uptime / (60 * 60);
2205 cstats->uptime -= hours * (60 * 60);
2206 mins = cstats->uptime / 60;
2207 cstats->uptime -= mins * 60;
2208 secs = cstats->uptime;
2209 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2210 days, hours, mins, secs);
2211 printformat_module("fe-common/silc", server, NULL,
2212 MSGLEVEL_CRAP, SILCTXT_STATS,
2213 "Local server uptime", tmp);
2215 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2216 printformat_module("fe-common/silc", server, NULL,
2217 MSGLEVEL_CRAP, SILCTXT_STATS,
2218 "Local server clients", tmp);
2220 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2221 printformat_module("fe-common/silc", server, NULL,
2222 MSGLEVEL_CRAP, SILCTXT_STATS,
2223 "Local server channels", tmp);
2225 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2226 printformat_module("fe-common/silc", server, NULL,
2227 MSGLEVEL_CRAP, SILCTXT_STATS,
2228 "Local server operators", tmp);
2230 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2231 printformat_module("fe-common/silc", server, NULL,
2232 MSGLEVEL_CRAP, SILCTXT_STATS,
2233 "Local router operators", tmp);
2235 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2236 printformat_module("fe-common/silc", server, NULL,
2237 MSGLEVEL_CRAP, SILCTXT_STATS,
2238 "Local cell clients", tmp);
2240 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2241 printformat_module("fe-common/silc", server, NULL,
2242 MSGLEVEL_CRAP, SILCTXT_STATS,
2243 "Local cell channels", tmp);
2245 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2246 printformat_module("fe-common/silc", server, NULL,
2247 MSGLEVEL_CRAP, SILCTXT_STATS,
2248 "Local cell servers", tmp);
2250 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2251 printformat_module("fe-common/silc", server, NULL,
2252 MSGLEVEL_CRAP, SILCTXT_STATS,
2253 "Total clients", tmp);
2255 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2256 printformat_module("fe-common/silc", server, NULL,
2257 MSGLEVEL_CRAP, SILCTXT_STATS,
2258 "Total channels", tmp);
2260 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2261 printformat_module("fe-common/silc", server, NULL,
2262 MSGLEVEL_CRAP, SILCTXT_STATS,
2263 "Total servers", tmp);
2265 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2266 printformat_module("fe-common/silc", server, NULL,
2267 MSGLEVEL_CRAP, SILCTXT_STATS,
2268 "Total routers", tmp);
2270 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2271 printformat_module("fe-common/silc", server, NULL,
2272 MSGLEVEL_CRAP, SILCTXT_STATS,
2273 "Total server operators", tmp);
2275 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2276 printformat_module("fe-common/silc", server, NULL,
2277 MSGLEVEL_CRAP, SILCTXT_STATS,
2278 "Total router operators", tmp);
2282 case SILC_COMMAND_CMODE:
2284 SilcChannelEntry channel_entry;
2287 channel_entry = va_arg(vp, SilcChannelEntry);
2288 (void)va_arg(vp, SilcUInt32);
2289 (void)va_arg(vp, SilcPublicKey);
2290 chpks = va_arg(vp, SilcDList);
2292 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2293 !channel_entry || !channel_entry->channel_name)
2296 /* Print the channel public key list */
2298 silc_parse_channel_public_keys(server, channel_entry, chpks);
2300 printformat_module("fe-common/silc", server, NULL,
2301 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2302 channel_entry->channel_name);
2307 case SILC_COMMAND_LEAVE:
2309 if (SILC_STATUS_IS_ERROR(status))
2312 /* We might be cycling, so disable queueing again */
2313 silc_queue_disable(conn);
2317 case SILC_COMMAND_DETACH:
2319 /* Save the detachment data to file. */
2323 if (SILC_STATUS_IS_ERROR(status))
2326 detach = va_arg(vp, SilcBuffer);
2327 file = silc_get_session_filename(server);
2328 silc_file_writefile(file, silc_buffer_data(detach),
2329 silc_buffer_len(detach));
2334 case SILC_COMMAND_KILL:
2336 SilcClientEntry client_entry;
2338 if (SILC_STATUS_IS_ERROR(status)) {
2339 silc_say_error("KILL: %s", silc_get_status_message(status));
2343 client_entry = va_arg(vp, SilcClientEntry);
2344 if (!client_entry || !client_entry->nickname[0])
2347 /* Print this only if the killed client isn't joined on channels.
2348 If it is, we receive KILLED notify and we'll print this there. */
2349 if (!silc_hash_table_count(client_entry->channels))
2350 printformat_module("fe-common/silc", server, NULL,
2351 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2352 client_entry->nickname,
2353 conn->local_entry->nickname, "");
2360 SilcClientConnection conn;
2364 SilcPublicKey public_key;
2365 SilcVerifyPublicKey completion;
2369 static void verify_public_key_completion(const char *line, void *context)
2371 PublicKeyVerify verify = (PublicKeyVerify)context;
2373 if (line[0] == 'Y' || line[0] == 'y') {
2374 /* Call the completion */
2375 if (verify->completion)
2376 verify->completion(TRUE, verify->context);
2378 /* Save the key for future checking */
2379 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2380 SILC_PKCS_FILE_BASE64);
2382 /* Call the completion */
2383 if (verify->completion)
2384 verify->completion(FALSE, verify->context);
2386 printformat_module("fe-common/silc", NULL, NULL,
2387 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2388 verify->entity_name ? verify->entity_name :
2392 silc_free(verify->filename);
2393 silc_free(verify->entity);
2394 silc_free(verify->entity_name);
2398 /* Internal routine to verify public key. If the `completion' is provided
2399 it will be called to indicate whether public was verified or not. For
2400 server/router public key this will check for filename that includes the
2401 remote host's IP address and remote host's hostname. */
2404 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2406 SilcConnectionType conn_type,
2407 SilcPublicKey public_key,
2408 SilcVerifyPublicKey completion, void *context)
2410 PublicKeyVerify verify;
2411 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2412 char *fingerprint, *babbleprint, *format;
2413 SilcPublicKey local_pubkey;
2414 SilcSILCPublicKey silc_pubkey;
2416 const char *hostname, *ip;
2421 char *entity = ((conn_type == SILC_CONN_SERVER ||
2422 conn_type == SILC_CONN_ROUTER) ?
2423 "server" : "client");
2426 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2427 printformat_module("fe-common/silc", NULL, NULL,
2428 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2429 entity, silc_pkcs_get_type(public_key));
2431 completion(FALSE, context);
2435 /* Encode public key */
2436 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2439 completion(FALSE, context);
2443 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2445 pw = getpwuid(getuid());
2448 completion(FALSE, context);
2453 memset(filename, 0, sizeof(filename));
2454 memset(filename2, 0, sizeof(filename2));
2455 memset(file, 0, sizeof(file));
2457 /* Get remote host information */
2458 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2459 NULL, &hostname, &ip, &port);
2461 if (conn_type == SILC_CONN_SERVER ||
2462 conn_type == SILC_CONN_ROUTER) {
2464 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2465 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2466 get_irssi_dir(), entity, file);
2468 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2470 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2471 get_irssi_dir(), entity, file);
2476 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2478 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2479 get_irssi_dir(), entity, file);
2484 /* Replace all whitespaces with `_'. */
2485 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2486 for (i = 0; i < strlen(fingerprint); i++)
2487 if (fingerprint[i] == ' ')
2488 fingerprint[i] = '_';
2490 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2491 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2492 get_irssi_dir(), entity, file);
2493 silc_free(fingerprint);
2498 /* Take fingerprint of the public key */
2499 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2500 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2502 verify = silc_calloc(1, sizeof(*verify));
2503 verify->client = client;
2504 verify->conn = conn;
2505 verify->filename = strdup(ipf);
2506 verify->entity = strdup(entity);
2507 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2508 (name ? strdup(name) : strdup(hostname))
2510 verify->public_key = public_key;
2511 verify->completion = completion;
2512 verify->context = context;
2514 /* Check whether this key already exists */
2515 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2516 /* Key does not exist, ask user to verify the key and save it */
2518 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2519 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2520 verify->entity_name : entity);
2521 if (conn_type == SILC_CONN_CLIENT && name &&
2522 silc_pubkey->identifier.realname)
2523 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2524 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2525 silc_pubkey->identifier.realname,
2526 silc_pubkey->identifier.email ?
2527 silc_pubkey->identifier.email : "");
2528 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2529 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2530 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2531 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2532 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2533 SILCTXT_PUBKEY_ACCEPT);
2534 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2537 silc_free(fingerprint);
2538 silc_free(babbleprint);
2542 /* The key already exists, verify it. */
2543 unsigned char *encpk;
2544 SilcUInt32 encpk_len;
2546 /* Load the key file, try for both IP filename and hostname filename */
2547 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2548 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2549 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2550 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2551 verify->entity_name : entity);
2552 if (conn_type == SILC_CONN_CLIENT && name &&
2553 silc_pubkey->identifier.realname)
2554 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2555 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2556 silc_pubkey->identifier.realname,
2557 silc_pubkey->identifier.email ?
2558 silc_pubkey->identifier.email : "");
2559 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2560 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2561 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2562 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2563 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2564 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2565 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2566 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2567 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2570 silc_free(fingerprint);
2571 silc_free(babbleprint);
2576 /* Encode the key data */
2577 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2579 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2580 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2581 verify->entity_name : entity);
2582 if (conn_type == SILC_CONN_CLIENT && name &&
2583 silc_pubkey->identifier.realname)
2584 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2585 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2586 silc_pubkey->identifier.realname,
2587 silc_pubkey->identifier.email ?
2588 silc_pubkey->identifier.email : "");
2589 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2590 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2591 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2592 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2593 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2594 SILCTXT_PUBKEY_MALFORMED, entity);
2595 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2596 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2597 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2600 silc_free(fingerprint);
2601 silc_free(babbleprint);
2605 silc_pkcs_public_key_free(local_pubkey);
2607 /* Compare the keys */
2608 if (memcmp(encpk, pk, encpk_len)) {
2609 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2610 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2611 verify->entity_name : entity);
2612 if (conn_type == SILC_CONN_CLIENT && name &&
2613 silc_pubkey->identifier.realname)
2614 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2615 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2616 silc_pubkey->identifier.realname,
2617 silc_pubkey->identifier.email ?
2618 silc_pubkey->identifier.email : "");
2619 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2620 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2621 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2622 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2623 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2624 SILCTXT_PUBKEY_NO_MATCH, entity);
2625 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2626 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2627 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2628 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2630 /* Ask user to verify the key and save it */
2631 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2632 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2633 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2636 silc_free(fingerprint);
2637 silc_free(babbleprint);
2643 /* Local copy matched */
2645 completion(TRUE, context);
2647 silc_free(fingerprint);
2648 silc_free(babbleprint);
2649 silc_free(verify->filename);
2650 silc_free(verify->entity);
2651 silc_free(verify->entity_name);
2657 /* Verifies received public key. The `conn_type' indicates which entity
2658 (server, client etc.) has sent the public key. If user decides to trust
2659 the key may be saved as trusted public key for later use. The
2660 `completion' must be called after the public key has been verified. */
2663 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2664 SilcConnectionType conn_type,
2665 SilcPublicKey public_key,
2666 SilcVerifyPublicKey completion, void *context)
2668 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2669 completion, context);
2672 /* Asks passphrase from user on the input line. */
2675 SilcAskPassphrase completion;
2679 void ask_passphrase_completion(const char *passphrase, void *context)
2681 AskPassphrase p = (AskPassphrase)context;
2682 if (passphrase && passphrase[0] == '\0')
2684 p->completion((unsigned char *)passphrase,
2685 passphrase ? strlen(passphrase) : 0, p->context);
2689 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2690 SilcAskPassphrase completion, void *context)
2692 AskPassphrase p = silc_calloc(1, sizeof(*p));
2693 p->completion = completion;
2694 p->context = context;
2696 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2697 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2701 SilcGetAuthMeth completion;
2705 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2706 SilcUInt32 passphrase_len,
2709 GetAuthMethod a = context;
2710 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2711 passphrase, passphrase_len, a->context);
2715 /* Find authentication data by hostname and port. The hostname may be IP
2718 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2719 char *hostname, SilcUInt16 port,
2720 SilcAuthMethod auth_meth,
2721 SilcGetAuthMeth completion, void *context)
2723 SERVER_SETUP_REC *setup;
2725 SILC_LOG_DEBUG(("Start"));
2727 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2728 /* Returning NULL will cause library to use our private key configured
2729 for this connection */
2730 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2734 /* Check whether we find the password for this server in our
2735 configuration. If it's set, always send it server. */
2736 setup = server_setup_find_port(hostname, port);
2737 if (setup && setup->password) {
2738 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2743 /* Didn't find password. If server wants it, ask it from user. */
2744 if (auth_meth == SILC_AUTH_PASSWORD) {
2746 a = silc_calloc(1, sizeof(*a));
2748 a->completion = completion;
2749 a->context = context;
2750 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2755 /* No authentication */
2756 completion(SILC_AUTH_NONE, NULL, 0, context);
2759 /* Asks whether the user would like to perform the key agreement protocol.
2760 This is called after we have received an key agreement packet or an
2761 reply to our key agreement packet. This returns TRUE if the user wants
2762 the library to perform the key agreement protocol and FALSE if it is not
2763 desired (application may start it later by calling the function
2764 silc_client_perform_key_agreement). */
2766 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2767 SilcClientEntry client_entry, const char *hostname,
2768 SilcUInt16 protocol, SilcUInt16 port)
2770 char portstr[12], protostr[5];
2772 SILC_LOG_DEBUG(("Start"));
2774 /* We will just display the info on the screen and return FALSE and user
2775 will have to start the key agreement with a command. */
2778 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2779 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2784 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2785 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2787 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2788 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2789 client_entry->nickname, hostname, portstr, protostr);
2792 /* Notifies application that file transfer protocol session is being
2793 requested by the remote client indicated by the `client_entry' from
2794 the `hostname' and `port'. The `session_id' is the file transfer
2795 session and it can be used to either accept or reject the file
2796 transfer request, by calling the silc_client_file_receive or
2797 silc_client_file_close, respectively. */
2799 void silc_ftp(SilcClient client, SilcClientConnection conn,
2800 SilcClientEntry client_entry, SilcUInt32 session_id,
2801 const char *hostname, SilcUInt16 port)
2803 SILC_SERVER_REC *server;
2805 FtpSession ftp = NULL;
2807 SILC_LOG_DEBUG(("Start"));
2809 server = conn->context;
2811 silc_dlist_start(server->ftp_sessions);
2812 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2813 if (ftp->client_entry == client_entry &&
2814 ftp->session_id == session_id) {
2815 server->current_session = ftp;
2819 if (ftp == SILC_LIST_END) {
2820 ftp = silc_calloc(1, sizeof(*ftp));
2821 ftp->client_entry = client_entry;
2822 ftp->session_id = session_id;
2825 silc_dlist_add(server->ftp_sessions, ftp);
2826 server->current_session = ftp;
2830 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2833 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2834 SILCTXT_FILE_REQUEST, client_entry->nickname);
2836 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2837 SILCTXT_FILE_REQUEST_HOST,
2838 client_entry->nickname, hostname, portstr);
2841 /* SILC client operations */
2842 SilcClientOperations ops = {
2844 silc_channel_message,
2845 silc_private_message,
2849 silc_get_auth_method,
2850 silc_verify_public_key,
2851 silc_ask_passphrase,