5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 - 2003 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"
37 #include "fe-common/core/printtext.h"
38 #include "fe-common/core/fe-channels.h"
39 #include "fe-common/core/keyboard.h"
40 #include "fe-common/core/window-items.h"
41 #include "fe-common/silc/module-formats.h"
46 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
47 const char *name, SilcSocketType conn_type,
48 unsigned char *pk, SilcUInt32 pk_len,
49 SilcSKEPKType pk_type,
50 SilcVerifyPublicKey completion, void *context);
52 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
55 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
56 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
57 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
59 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
60 "[SILC operator]" : "[unknown mode]");
62 if (mode & SILC_UMODE_GONE)
63 strcat(buf, " [away]");
64 if (mode & SILC_UMODE_INDISPOSED)
65 strcat(buf, " [indisposed]");
66 if (mode & SILC_UMODE_BUSY)
67 strcat(buf, " [busy]");
68 if (mode & SILC_UMODE_PAGE)
69 strcat(buf, " [page to reach]");
70 if (mode & SILC_UMODE_HYPER)
71 strcat(buf, " [hyper active]");
72 if (mode & SILC_UMODE_ROBOT)
73 strcat(buf, " [robot]");
74 if (mode & SILC_UMODE_ANONYMOUS)
75 strcat(buf, " [anonymous]");
76 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
77 strcat(buf, " [blocks private messages]");
78 if (mode & SILC_UMODE_DETACHED)
79 strcat(buf, " [detached]");
80 if (mode & SILC_UMODE_REJECT_WATCHING)
81 strcat(buf, " [rejects watching]");
82 if (mode & SILC_UMODE_BLOCK_INVITE)
83 strcat(buf, " [blocks invites]");
86 /* print "nick appears as" message to every channel of a server */
88 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
89 const char *newnick, const char *oldnick,
92 if (ignore_check(SERVER(server), oldnick, address,
93 channel, newnick, MSGLEVEL_NICKS))
96 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
97 SILCTXT_CHANNEL_APPEARS,
98 oldnick, newnick, channel, address);
102 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
103 const char *oldnick, const char *address)
105 GSList *tmp, *windows;
107 /* Print to each channel/query where the nick is.
108 Don't print more than once to the same window. */
111 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
112 CHANNEL_REC *channel = tmp->data;
113 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
115 if (nicklist_find(channel, newnick) == NULL ||
116 g_slist_find(windows, window) != NULL)
119 windows = g_slist_append(windows, window);
120 silc_print_nick_change_channel(server, channel->visible_name,
121 newnick, oldnick, address);
124 g_slist_free(windows);
127 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
128 SilcChannelEntry channel_entry,
129 SilcBuffer channel_pubkeys)
132 SilcArgumentPayload chpks;
134 SilcUInt32 pk_len, type;
136 char *fingerprint, *babbleprint;
137 SilcPublicKey pubkey;
138 SilcPublicKeyIdentifier ident;
140 printformat_module("fe-common/silc", server, NULL,
141 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
142 channel_entry->channel_name);
144 SILC_GET16_MSB(argc, channel_pubkeys->data);
145 chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
146 channel_pubkeys->len - 2, argc);
150 pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
152 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
153 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
154 silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
155 ident = silc_pkcs_decode_identifier(pubkey->identifier);
157 printformat_module("fe-common/silc", server, NULL,
158 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
159 c++, channel_entry->channel_name,
160 type == 0x00 ? "Added" : "Removed",
161 ident->realname ? ident->realname : "",
162 fingerprint, babbleprint);
164 silc_free(fingerprint);
165 silc_free(babbleprint);
166 silc_pkcs_public_key_free(pubkey);
167 silc_pkcs_free_identifier(ident);
168 pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
171 silc_argument_payload_free(chpks);
174 void silc_say(SilcClient client, SilcClientConnection conn,
175 SilcClientMessageType type, char *msg, ...)
177 SILC_SERVER_REC *server;
181 server = conn == NULL ? NULL : conn->context;
184 str = g_strdup_vprintf(msg, va);
185 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
190 void silc_say_error(char *msg, ...)
196 str = g_strdup_vprintf(msg, va);
197 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
203 /* try to verify a message using locally stored public key data */
204 int verify_message_signature(SilcClientEntry sender,
205 SilcMessageSignedPayload sig,
206 SilcMessagePayload message)
209 char file[256], filename[256];
210 char *fingerprint, *fingerprint2;
211 unsigned char *pk_data;
212 SilcUInt32 pk_datalen;
214 int ret = SILC_MSG_SIGNED_VERIFIED, i;
217 return SILC_MSG_SIGNED_UNKNOWN;
219 /* get public key from the signature payload and compare it with the
220 one stored in the client entry */
221 pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
224 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
226 if (sender->fingerprint) {
227 fingerprint2 = silc_fingerprint(sender->fingerprint,
228 sender->fingerprint_len);
229 if (strcmp(fingerprint, fingerprint2)) {
230 /* since the public key differs from the senders public key, the
231 verification _failed_ */
232 silc_pkcs_public_key_free(pk);
233 silc_free(fingerprint);
234 ret = SILC_MSG_SIGNED_UNKNOWN;
236 silc_free(fingerprint2);
238 } else if (sender->fingerprint)
239 fingerprint = silc_fingerprint(sender->fingerprint,
240 sender->fingerprint_len);
242 /* no idea, who or what signed that message ... */
243 return SILC_MSG_SIGNED_UNKNOWN;
245 /* search our local client key cache */
246 for (i = 0; i < strlen(fingerprint); i++)
247 if (fingerprint[i] == ' ')
248 fingerprint[i] = '_';
250 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
251 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
252 get_irssi_dir(), file);
253 silc_free(fingerprint);
255 if (stat(filename, &st) < 0)
256 /* we don't have the public key cached ... use the one from the sig */
257 ret = SILC_MSG_SIGNED_UNKNOWN;
259 SilcPublicKey cached_pk=NULL;
261 /* try to load the file */
262 if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
263 !silc_pkcs_load_public_key(filename, &cached_pk,
264 SILC_PKCS_FILE_BIN)) {
265 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
266 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
268 return SILC_MSG_SIGNED_UNKNOWN;
270 ret = SILC_MSG_SIGNED_UNKNOWN;
275 silc_pkcs_public_key_free(pk);
280 /* the public key is now in pk, our "level of trust" in ret */
281 if ((pk) && silc_message_signed_verify(sig, message, pk,
282 silc_client->sha1hash)!= SILC_AUTH_OK)
283 ret = SILC_MSG_SIGNED_FAILED;
286 silc_pkcs_public_key_free(pk);
291 char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
294 int i = 0, j = 0, len = strlen(escaped_data);
296 data = silc_calloc(len, sizeof(char));
299 ptr = memchr(escaped_data + i, 1, len - i);
301 int inc = (ptr - escaped_data) - i;
302 memcpy(data + j, escaped_data + i, inc);
305 data[j++] = *(ptr + 1) - 1;
307 memcpy(data + j, escaped_data + i, len - i);
317 char * silc_escape_data(const char *data, SilcUInt32 len)
319 char *escaped_data, *ptr, *ptr0, *ptr1;
322 escaped_data = silc_calloc(2 * len, sizeof(char));
325 ptr0 = memchr(data + i, 0, len - i);
326 ptr1 = memchr(data + i, 1, len - i);
328 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
331 int inc = (ptr - data) - i;
333 memcpy(escaped_data + j, data + i, inc);
336 escaped_data[j++] = 1;
337 escaped_data[j++] = *(data + i++) + 1;
339 memcpy(escaped_data + j, data + i, len - i);
348 void silc_emit_mime_sig(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
349 const char *data, SilcUInt32 data_len, const char *nick,
354 escaped_data = silc_escape_data(data, data_len);
356 signal_emit("mime", 4, server, channel, escaped_data, nick, verified);
358 silc_free(escaped_data);
362 /* Message for a channel. The `sender' is the nickname of the sender
363 received in the packet. The `channel_name' is the name of the channel. */
365 void silc_channel_message(SilcClient client, SilcClientConnection conn,
366 SilcClientEntry sender, SilcChannelEntry channel,
367 SilcMessagePayload payload,
368 SilcMessageFlags flags, const unsigned char *message,
369 SilcUInt32 message_len)
371 SILC_SERVER_REC *server;
373 SILC_CHANNEL_REC *chanrec;
376 SILC_LOG_DEBUG(("Start"));
381 server = conn == NULL ? NULL : conn->context;
382 chanrec = silc_channel_find_entry(server, channel);
386 nick = silc_nicklist_find(chanrec, sender);
388 /* We didn't find client but it clearly exists, add it. */
389 SilcChannelUser chu = silc_client_on_channel(channel, sender);
391 nick = silc_nicklist_insert(chanrec, chu, FALSE);
394 /* If the messages is digitally signed, verify it, if possible. */
395 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
396 if (!settings_get_bool("ignore_message_signatures")) {
397 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
398 verified = verify_message_signature(sender, sig, payload);
400 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
404 if (flags & SILC_MESSAGE_FLAG_DATA) {
405 silc_emit_mime_sig(server, chanrec, message, message_len,
406 nick == NULL ? NULL : nick->nick,
407 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
414 /* FIXME: replace those printformat calls with signals and add signature
415 information to them (if present) */
416 if (flags & SILC_MESSAGE_FLAG_ACTION)
417 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
418 char tmp[256], *cp, *dm = NULL;
419 memset(tmp, 0, sizeof(tmp));
421 if(message_len > sizeof(tmp) - 1) {
422 dm = silc_calloc(message_len + 1, sizeof(*dm));
425 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
427 printformat_module("fe-common/silc", server, channel->channel_name,
428 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
429 nick == NULL ? "[<unknown>]" : nick->nick, cp);
432 printformat_module("fe-common/silc", server, channel->channel_name,
433 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
434 nick == NULL ? "[<unknown>]" : nick->nick,
437 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
438 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
439 char tmp[256], *cp, *dm = NULL;
440 memset(tmp, 0, sizeof(tmp));
442 if(message_len > sizeof(tmp) - 1) {
443 dm = silc_calloc(message_len + 1, sizeof(*dm));
446 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
448 printformat_module("fe-common/silc", server, channel->channel_name,
449 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
450 nick == NULL ? "[<unknown>]" : nick->nick, cp);
453 printformat_module("fe-common/silc", server, channel->channel_name,
454 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
455 nick == NULL ? "[<unknown>]" : nick->nick,
459 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
460 char tmp[256], *cp, *dm = NULL;
462 memset(tmp, 0, sizeof(tmp));
464 if (message_len > sizeof(tmp) - 1) {
465 dm = silc_calloc(message_len + 1, sizeof(*dm));
469 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
471 if (flags & SILC_MESSAGE_FLAG_SIGNED)
472 signal_emit("message signed_public", 6, server, cp,
473 nick == NULL ? "[<unknown>]" : nick->nick,
474 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
475 chanrec->name, verified);
477 signal_emit("message public", 6, server, cp,
478 nick == NULL ? "[<unknown>]" : nick->nick,
479 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
480 chanrec->name, nick);
485 if (flags & SILC_MESSAGE_FLAG_SIGNED)
486 signal_emit("message signed_public", 6, server, message,
487 nick == NULL ? "[<unknown>]" : nick->nick,
488 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
489 chanrec->name, verified);
491 signal_emit("message public", 6, server, message,
492 nick == NULL ? "[<unknown>]" : nick->nick,
493 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
494 chanrec->name, nick);
498 /* Private message to the client. The `sender' is the nickname of the
499 sender received in the packet. */
501 void silc_private_message(SilcClient client, SilcClientConnection conn,
502 SilcClientEntry sender, SilcMessagePayload payload,
503 SilcMessageFlags flags,
504 const unsigned char *message,
505 SilcUInt32 message_len)
507 SILC_SERVER_REC *server;
511 SILC_LOG_DEBUG(("Start"));
513 server = conn == NULL ? NULL : conn->context;
514 memset(userhost, 0, sizeof(userhost));
515 if (sender->username)
516 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
517 sender->username, sender->hostname);
519 /* If the messages is digitally signed, verify it, if possible. */
520 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
521 if (!settings_get_bool("ignore_message_signatures")) {
522 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
523 verified = verify_message_signature(sender, sig, payload);
525 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
529 if (flags & SILC_MESSAGE_FLAG_DATA) {
530 silc_emit_mime_sig(server, NULL, message, message_len,
531 sender->nickname ? sender->nickname : "[<unknown>]",
532 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
539 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
540 char tmp[256], *cp, *dm = NULL;
542 memset(tmp, 0, sizeof(tmp));
544 if (message_len > sizeof(tmp) - 1) {
545 dm = silc_calloc(message_len + 1, sizeof(*dm));
549 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
551 if (flags & SILC_MESSAGE_FLAG_SIGNED)
552 signal_emit("message signed_private", 5, server, cp,
553 sender->nickname ? sender->nickname : "[<unknown>]",
554 sender->username ? userhost : NULL, verified);
556 signal_emit("message private", 4, server, cp,
557 sender->nickname ? sender->nickname : "[<unknown>]",
558 sender->username ? userhost : NULL);
563 if (flags & SILC_MESSAGE_FLAG_SIGNED)
564 signal_emit("message signed_private", 5, server, message,
565 sender->nickname ? sender->nickname : "[<unknown>]",
566 sender->username ? userhost : NULL, verified);
568 signal_emit("message private", 4, server, message,
569 sender->nickname ? sender->nickname : "[<unknown>]",
570 sender->username ? userhost : NULL);
573 /* Notify message to the client. The notify arguments are sent in the
574 same order as servers sends them. The arguments are same as received
575 from the server except for ID's. If ID is received application receives
576 the corresponding entry to the ID. For example, if Client ID is received
577 application receives SilcClientEntry. Also, if the notify type is
578 for channel the channel entry is sent to application (even if server
579 does not send it). */
581 void silc_notify(SilcClient client, SilcClientConnection conn,
582 SilcNotifyType type, ...)
585 SILC_SERVER_REC *server;
586 SILC_CHANNEL_REC *chanrec;
587 SILC_NICK_REC *nickrec;
588 SilcClientEntry client_entry, client_entry2;
589 SilcChannelEntry channel, channel2;
590 SilcServerEntry server_entry;
596 GSList *list1, *list_tmp;
599 SILC_LOG_DEBUG(("Start"));
603 server = conn == NULL ? NULL : conn->context;
606 case SILC_NOTIFY_TYPE_NONE:
607 /* Some generic notice from server */
608 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
611 case SILC_NOTIFY_TYPE_INVITE:
613 * Invited or modified invite list.
616 SILC_LOG_DEBUG(("Notify: INVITE"));
618 channel = va_arg(va, SilcChannelEntry);
619 name = va_arg(va, char *);
620 client_entry = va_arg(va, SilcClientEntry);
622 memset(buf, 0, sizeof(buf));
623 snprintf(buf, sizeof(buf) - 1, "%s@%s",
624 client_entry->username, client_entry->hostname);
625 signal_emit("message invite", 4, server, channel ? channel->channel_name :
626 name, client_entry->nickname, buf);
629 case SILC_NOTIFY_TYPE_JOIN:
634 SILC_LOG_DEBUG(("Notify: JOIN"));
636 client_entry = va_arg(va, SilcClientEntry);
637 channel = va_arg(va, SilcChannelEntry);
639 if (client_entry == server->conn->local_entry) {
640 /* You joined to channel */
641 chanrec = silc_channel_find(server, channel->channel_name);
642 if (chanrec != NULL && !chanrec->joined)
643 chanrec->entry = channel;
645 chanrec = silc_channel_find_entry(server, channel);
646 if (chanrec != NULL) {
647 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
649 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
653 memset(buf, 0, sizeof(buf));
654 if (client_entry->username)
655 snprintf(buf, sizeof(buf) - 1, "%s@%s",
656 client_entry->username, client_entry->hostname);
657 signal_emit("message join", 4, server, channel->channel_name,
658 client_entry->nickname,
659 client_entry->username == NULL ? "" : buf);
662 case SILC_NOTIFY_TYPE_LEAVE:
667 SILC_LOG_DEBUG(("Notify: LEAVE"));
669 client_entry = va_arg(va, SilcClientEntry);
670 channel = va_arg(va, SilcChannelEntry);
672 memset(buf, 0, sizeof(buf));
673 if (client_entry->username)
674 snprintf(buf, sizeof(buf) - 1, "%s@%s",
675 client_entry->username, client_entry->hostname);
676 signal_emit("message part", 5, server, channel->channel_name,
677 client_entry->nickname, client_entry->username ?
678 buf : "", client_entry->nickname);
680 chanrec = silc_channel_find_entry(server, channel);
681 if (chanrec != NULL) {
682 nickrec = silc_nicklist_find(chanrec, client_entry);
684 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
688 case SILC_NOTIFY_TYPE_SIGNOFF:
693 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
695 client_entry = va_arg(va, SilcClientEntry);
696 tmp = va_arg(va, char *);
698 silc_server_free_ftp(server, client_entry);
700 /* Print only if we have the nickname. If this cliente has just quit
701 when we were only resolving it, it is possible we don't have the
703 if (client_entry->nickname) {
704 memset(buf, 0, sizeof(buf));
705 if (client_entry->username)
706 snprintf(buf, sizeof(buf) - 1, "%s@%s",
707 client_entry->username, client_entry->hostname);
708 signal_emit("message quit", 4, server, client_entry->nickname,
709 client_entry->username ? buf : "",
713 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
714 for (list_tmp = list1; list_tmp != NULL; list_tmp =
715 list_tmp->next->next) {
716 CHANNEL_REC *channel = list_tmp->data;
717 NICK_REC *nickrec = list_tmp->next->data;
719 nicklist_remove(channel, nickrec);
723 case SILC_NOTIFY_TYPE_TOPIC_SET:
728 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
730 idtype = va_arg(va, int);
731 entry = va_arg(va, void *);
732 tmp = va_arg(va, char *);
733 channel = va_arg(va, SilcChannelEntry);
735 chanrec = silc_channel_find_entry(server, channel);
736 if (chanrec != NULL) {
737 char tmp2[256], *cp, *dm = NULL;
739 g_free_not_null(chanrec->topic);
740 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
741 memset(tmp2, 0, sizeof(tmp2));
743 if (strlen(tmp) > sizeof(tmp2) - 1) {
744 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
748 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
753 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
754 signal_emit("channel topic changed", 1, chanrec);
759 if (idtype == SILC_ID_CLIENT) {
760 client_entry = (SilcClientEntry)entry;
761 memset(buf, 0, sizeof(buf));
762 snprintf(buf, sizeof(buf) - 1, "%s@%s",
763 client_entry->username, client_entry->hostname);
764 signal_emit("message topic", 5, server, channel->channel_name,
765 tmp, client_entry->nickname, buf);
766 } else if (idtype == SILC_ID_SERVER) {
767 server_entry = (SilcServerEntry)entry;
768 signal_emit("message topic", 5, server, channel->channel_name,
769 tmp, server_entry->server_name,
770 server_entry->server_name);
771 } else if (idtype == SILC_ID_CHANNEL) {
772 channel = (SilcChannelEntry)entry;
773 signal_emit("message topic", 5, server, channel->channel_name,
774 tmp, channel->channel_name, channel->channel_name);
778 case SILC_NOTIFY_TYPE_NICK_CHANGE:
783 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
785 client_entry = va_arg(va, SilcClientEntry);
786 client_entry2 = va_arg(va, SilcClientEntry);
788 if (!strcmp(client_entry->nickname, client_entry2->nickname))
791 memset(buf, 0, sizeof(buf));
792 snprintf(buf, sizeof(buf) - 1, "%s@%s",
793 client_entry2->username, client_entry2->hostname);
794 nicklist_rename_unique(SERVER(server),
795 client_entry, client_entry->nickname,
796 client_entry2, client_entry2->nickname);
797 signal_emit("message nick", 4, server, client_entry2->nickname,
798 client_entry->nickname, buf);
801 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
803 * Changed channel mode.
806 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
808 idtype = va_arg(va, int);
809 entry = va_arg(va, void *);
810 mode = va_arg(va, SilcUInt32);
811 (void)va_arg(va, char *); /* cipher */
812 (void)va_arg(va, char *); /* hmac */
813 (void)va_arg(va, char *); /* passphrase */
814 (void)va_arg(va, SilcPublicKey); /* founder key */
815 buffer = va_arg(va, SilcBuffer); /* channel public keys */
816 channel = va_arg(va, SilcChannelEntry);
818 tmp = silc_client_chmode(mode,
819 channel->channel_key ?
820 silc_cipher_get_name(channel->channel_key) : "",
822 silc_hmac_get_name(channel->hmac) : "");
824 chanrec = silc_channel_find_entry(server, channel);
825 if (chanrec != NULL) {
826 g_free_not_null(chanrec->mode);
827 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
828 signal_emit("channel mode changed", 1, chanrec);
831 if (idtype == SILC_ID_CLIENT) {
832 client_entry = (SilcClientEntry)entry;
833 printformat_module("fe-common/silc", server, channel->channel_name,
834 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
835 channel->channel_name, tmp ? tmp : "removed all",
836 client_entry->nickname);
837 } else if (idtype == SILC_ID_SERVER) {
838 server_entry = (SilcServerEntry)entry;
839 printformat_module("fe-common/silc", server, channel->channel_name,
840 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
841 channel->channel_name, tmp ? tmp : "removed all",
842 server_entry->server_name);
843 } else if (idtype == SILC_ID_CHANNEL) {
844 channel2 = (SilcChannelEntry)entry;
845 printformat_module("fe-common/silc", server, channel->channel_name,
846 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
847 channel->channel_name, tmp ? tmp : "removed all",
848 channel2->channel_name);
851 /* Print the channel public key list */
853 silc_parse_channel_public_keys(server, channel, buffer);
858 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
860 * Changed user's mode on channel.
863 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
865 idtype = va_arg(va, int);
866 entry = va_arg(va, void *);
867 mode = va_arg(va, SilcUInt32);
868 client_entry2 = va_arg(va, SilcClientEntry);
869 channel = va_arg(va, SilcChannelEntry);
871 tmp = silc_client_chumode(mode);
872 chanrec = silc_channel_find_entry(server, channel);
873 if (chanrec != NULL) {
876 if (client_entry2 == server->conn->local_entry)
877 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
879 nick = silc_nicklist_find(chanrec, client_entry2);
881 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
882 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
883 signal_emit("nick mode changed", 2, chanrec, nick);
887 if (idtype == SILC_ID_CLIENT) {
888 client_entry = (SilcClientEntry)entry;
889 printformat_module("fe-common/silc", server, channel->channel_name,
890 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
891 channel->channel_name, client_entry2->nickname,
892 tmp ? tmp : "removed all",
893 client_entry->nickname);
894 } else if (idtype == SILC_ID_SERVER) {
895 server_entry = (SilcServerEntry)entry;
896 printformat_module("fe-common/silc", server, channel->channel_name,
897 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
898 channel->channel_name, client_entry2->nickname,
899 tmp ? tmp : "removed all",
900 server_entry->server_name);
901 } else if (idtype == SILC_ID_CHANNEL) {
902 channel2 = (SilcChannelEntry)entry;
903 printformat_module("fe-common/silc", server, channel->channel_name,
904 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
905 channel->channel_name, client_entry2->nickname,
906 tmp ? tmp : "removed all",
907 channel2->channel_name);
910 if (mode & SILC_CHANNEL_UMODE_CHANFO)
911 printformat_module("fe-common/silc",
912 server, channel->channel_name, MSGLEVEL_CRAP,
913 SILCTXT_CHANNEL_FOUNDER,
914 channel->channel_name, client_entry2->nickname);
916 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
917 printformat_module("fe-common/silc",
918 server, channel->channel_name, MSGLEVEL_CRAP,
919 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
924 case SILC_NOTIFY_TYPE_MOTD:
929 SILC_LOG_DEBUG(("Notify: MOTD"));
931 tmp = va_arg(va, char *);
933 if (!settings_get_bool("skip_motd"))
934 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
937 case SILC_NOTIFY_TYPE_KICKED:
939 * Someone was kicked from channel.
942 SILC_LOG_DEBUG(("Notify: KICKED"));
944 client_entry = va_arg(va, SilcClientEntry);
945 tmp = va_arg(va, char *);
946 client_entry2 = va_arg(va, SilcClientEntry);
947 channel = va_arg(va, SilcChannelEntry);
949 chanrec = silc_channel_find_entry(server, channel);
951 if (client_entry == conn->local_entry) {
952 printformat_module("fe-common/silc", server, channel->channel_name,
953 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
954 channel->channel_name,
955 client_entry ? client_entry2->nickname : "",
958 chanrec->kicked = TRUE;
959 channel_destroy((CHANNEL_REC *)chanrec);
962 printformat_module("fe-common/silc", server, channel->channel_name,
963 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
964 client_entry->nickname, channel->channel_name,
965 client_entry2 ? client_entry2->nickname : "",
969 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
971 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
976 case SILC_NOTIFY_TYPE_KILLED:
978 * Someone was killed from the network.
981 SILC_LOG_DEBUG(("Notify: KILLED"));
983 client_entry = va_arg(va, SilcClientEntry);
984 tmp = va_arg(va, char *);
985 idtype = va_arg(va, int);
986 entry = va_arg(va, SilcClientEntry);
988 if (client_entry == conn->local_entry) {
989 if (idtype == SILC_ID_CLIENT) {
990 client_entry2 = (SilcClientEntry)entry;
991 printformat_module("fe-common/silc", server, NULL,
992 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
993 client_entry2 ? client_entry2->nickname : "",
995 } else if (idtype == SILC_ID_SERVER) {
996 server_entry = (SilcServerEntry)entry;
997 printformat_module("fe-common/silc", server, NULL,
998 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
999 server_entry->server_name, tmp ? tmp : "");
1000 } else if (idtype == SILC_ID_CHANNEL) {
1001 channel = (SilcChannelEntry)entry;
1002 printformat_module("fe-common/silc", server, NULL,
1003 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1004 channel->channel_name, tmp ? tmp : "");
1007 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1008 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1009 list_tmp->next->next) {
1010 CHANNEL_REC *channel = list_tmp->data;
1011 NICK_REC *nickrec = list_tmp->next->data;
1012 nicklist_remove(channel, nickrec);
1015 if (idtype == SILC_ID_CLIENT) {
1016 client_entry2 = (SilcClientEntry)entry;
1017 printformat_module("fe-common/silc", server, NULL,
1018 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1019 client_entry->nickname,
1020 client_entry2 ? client_entry2->nickname : "",
1022 } else if (idtype == SILC_ID_SERVER) {
1023 server_entry = (SilcServerEntry)entry;
1024 printformat_module("fe-common/silc", server, NULL,
1025 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1026 client_entry->nickname,
1027 server_entry->server_name, tmp ? tmp : "");
1028 } else if (idtype == SILC_ID_CHANNEL) {
1029 channel = (SilcChannelEntry)entry;
1030 printformat_module("fe-common/silc", server, NULL,
1031 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1032 client_entry->nickname,
1033 channel->channel_name, tmp ? tmp : "");
1038 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1041 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1044 * Server has quit the network.
1047 SilcClientEntry *clients;
1048 SilcUInt32 clients_count;
1050 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1052 (void)va_arg(va, void *);
1053 clients = va_arg(va, SilcClientEntry *);
1054 clients_count = va_arg(va, SilcUInt32);
1056 for (i = 0; i < clients_count; i++) {
1057 memset(buf, 0, sizeof(buf));
1059 /* Print only if we have the nickname. If this client has just quit
1060 when we were only resolving it, it is possible we don't have the
1062 if (clients[i]->nickname) {
1063 if (clients[i]->username)
1064 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1065 clients[i]->username, clients[i]->hostname);
1066 signal_emit("message quit", 4, server, clients[i]->nickname,
1067 clients[i]->username ? buf : "",
1071 silc_server_free_ftp(server, clients[i]);
1073 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1074 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1075 list_tmp->next->next) {
1076 CHANNEL_REC *channel = list_tmp->data;
1077 NICK_REC *nickrec = list_tmp->next->data;
1078 nicklist_remove(channel, nickrec);
1084 case SILC_NOTIFY_TYPE_ERROR:
1086 SilcStatus error = va_arg(va, int);
1088 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1089 "%s", silc_get_status_message(error));
1093 case SILC_NOTIFY_TYPE_WATCH:
1095 SilcNotifyType notify;
1097 client_entry = va_arg(va, SilcClientEntry);
1098 name = va_arg(va, char *); /* Maybe NULL */
1099 mode = va_arg(va, SilcUInt32);
1100 notify = va_arg(va, int);
1102 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1104 printformat_module("fe-common/silc", server, NULL,
1105 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1106 client_entry->nickname, name);
1108 printformat_module("fe-common/silc", server, NULL,
1109 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1110 client_entry->nickname);
1111 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1112 /* See if client was away and is now present */
1113 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1114 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1115 SILC_UMODE_DETACHED)) &&
1116 (client_entry->mode & SILC_UMODE_GONE ||
1117 client_entry->mode & SILC_UMODE_INDISPOSED ||
1118 client_entry->mode & SILC_UMODE_BUSY ||
1119 client_entry->mode & SILC_UMODE_PAGE ||
1120 client_entry->mode & SILC_UMODE_DETACHED)) {
1121 printformat_module("fe-common/silc", server, NULL,
1122 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1123 client_entry->nickname);
1127 memset(buf, 0, sizeof(buf));
1128 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1129 printformat_module("fe-common/silc", server, NULL,
1130 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1131 client_entry->nickname, buf);
1133 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1134 printformat_module("fe-common/silc", server, NULL,
1135 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1136 client_entry->nickname);
1137 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1138 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1139 printformat_module("fe-common/silc", server, NULL,
1140 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1141 client_entry->nickname);
1142 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1143 /* Client logged in to the network */
1144 printformat_module("fe-common/silc", server, NULL,
1145 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1146 client_entry->nickname);
1152 /* Unknown notify */
1153 printformat_module("fe-common/silc", server, NULL,
1154 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1161 /* Called to indicate that connection was either successfully established
1162 or connecting failed. This is also the first time application receives
1163 the SilcClientConnection object which it should save somewhere. */
1165 void silc_connect(SilcClient client, SilcClientConnection conn,
1166 SilcClientConnectionStatus status)
1168 SILC_SERVER_REC *server = conn->context;
1170 if (!server || server->disconnected) {
1171 silc_client_close_connection(client, conn);
1176 case SILC_CLIENT_CONN_SUCCESS:
1177 /* We have successfully connected to server */
1178 server->connected = TRUE;
1179 signal_emit("event connected", 1, server);
1182 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1183 /* We have successfully resumed old detached session */
1184 server->connected = TRUE;
1185 signal_emit("event connected", 1, server);
1187 /* If we resumed old session check whether we need to update
1189 if (strcmp(server->nick, conn->local_entry->nickname)) {
1191 old = g_strdup(server->nick);
1192 server_change_nick(SERVER(server), conn->local_entry->nickname);
1193 nicklist_rename_unique(SERVER(server),
1194 conn->local_entry, server->nick,
1195 conn->local_entry, conn->local_entry->nickname);
1196 signal_emit("message own_nick", 4, server, server->nick, old, "");
1202 server->connection_lost = TRUE;
1204 server->conn->context = NULL;
1205 server_disconnect(SERVER(server));
1210 /* Called to indicate that connection was disconnected to the server. */
1212 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1213 SilcStatus status, const char *message)
1215 SILC_SERVER_REC *server = conn->context;
1217 SILC_LOG_DEBUG(("Start"));
1219 if (!server || server->connection_lost)
1222 if (server->conn && server->conn->local_entry) {
1223 nicklist_rename_unique(SERVER(server),
1224 server->conn->local_entry, server->nick,
1225 server->conn->local_entry,
1226 silc_client->username);
1227 silc_change_nick(server, silc_client->username);
1231 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1232 "Server closed connection: %s (%d) %s",
1233 silc_get_status_message(status), status,
1234 message ? message : "");
1237 server->conn->context = NULL;
1238 server->conn = NULL;
1239 server->connection_lost = TRUE;
1240 server_disconnect(SERVER(server));
1243 /* Command handler. This function is called always in the command function.
1244 If error occurs it will be called as well. `conn' is the associated
1245 client connection. `cmd_context' is the command context that was
1246 originally sent to the command. `success' is FALSE if error occured
1247 during command. `command' is the command being processed. It must be
1248 noted that this is not reply from server. This is merely called just
1249 after application has called the command. Just to tell application
1250 that the command really was processed. */
1252 static bool cmode_list_chpks = FALSE;
1254 void silc_command(SilcClient client, SilcClientConnection conn,
1255 SilcClientCommandContext cmd_context, bool success,
1256 SilcCommand command, SilcStatus status)
1258 SILC_SERVER_REC *server = conn->context;
1260 SILC_LOG_DEBUG(("Start"));
1263 silc_say_error("%s", silc_get_status_message(status));
1269 case SILC_COMMAND_INVITE:
1270 if (cmd_context->argc > 2)
1271 printformat_module("fe-common/silc", server, NULL,
1272 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1273 cmd_context->argv[2],
1274 (cmd_context->argv[1][0] == '*' ?
1275 (char *)conn->current_channel->channel_name :
1276 (char *)cmd_context->argv[1]));
1279 case SILC_COMMAND_DETACH:
1280 server->no_reconnect = TRUE;
1283 case SILC_COMMAND_CMODE:
1284 if (cmd_context->argc == 3 &&
1285 !strcmp(cmd_context->argv[2], "+C"))
1286 cmode_list_chpks = TRUE;
1288 cmode_list_chpks = FALSE;
1297 SilcChannelEntry channel;
1301 /* Client info resolving callback when JOIN command reply is received.
1302 This will cache all users on the channel. */
1304 static void silc_client_join_get_users(SilcClient client,
1305 SilcClientConnection conn,
1306 SilcClientEntry *clients,
1307 SilcUInt32 clients_count,
1310 SilcJoinResolve r = context;
1311 SilcChannelEntry channel = r->channel;
1312 SilcHashTableList htl;
1313 SilcChannelUser chu;
1314 SILC_SERVER_REC *server = conn->context;
1315 SILC_CHANNEL_REC *chanrec;
1316 SilcClientEntry founder = NULL;
1319 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1320 silc_hash_table_count(channel->user_list)));
1322 if (!clients && r->retry < 1) {
1323 /* Retry to resolve */
1325 silc_client_get_clients_by_channel(client, conn, channel,
1326 silc_client_join_get_users, context);
1330 chanrec = silc_channel_find(server, channel->channel_name);
1331 if (chanrec == NULL)
1334 silc_hash_table_list(channel->user_list, &htl);
1335 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1336 if (!chu->client->nickname)
1338 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1339 founder = chu->client;
1340 silc_nicklist_insert(chanrec, chu, FALSE);
1342 silc_hash_table_list_reset(&htl);
1344 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1345 nicklist_set_own(CHANNEL(chanrec), ownnick);
1346 signal_emit("channel joined", 1, chanrec);
1347 chanrec->entry = channel;
1350 printformat_module("fe-common/silc", server, channel->channel_name,
1351 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1352 channel->channel_name, chanrec->topic);
1355 if (founder == conn->local_entry) {
1356 printformat_module("fe-common/silc",
1357 server, channel->channel_name, MSGLEVEL_CRAP,
1358 SILCTXT_CHANNEL_FOUNDER_YOU,
1359 channel->channel_name);
1360 signal_emit("nick mode changed", 2, chanrec, ownnick);
1362 printformat_module("fe-common/silc",
1363 server, channel->channel_name, MSGLEVEL_CRAP,
1364 SILCTXT_CHANNEL_FOUNDER,
1365 channel->channel_name, founder->nickname);
1371 SilcClientConnection conn;
1377 void silc_getkey_cb(bool success, void *context)
1379 GetkeyContext getkey = (GetkeyContext)context;
1380 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1381 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1382 ((SilcClientEntry)getkey->entry)->nickname :
1383 ((SilcServerEntry)getkey->entry)->server_name);
1386 printformat_module("fe-common/silc", NULL, NULL,
1387 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1389 printformat_module("fe-common/silc", NULL, NULL,
1390 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1394 silc_free(getkey->fingerprint);
1398 /* Parse an invite or ban list */
1399 void silc_parse_inviteban_list(SilcClient client,
1400 SilcClientConnection conn,
1401 SILC_SERVER_REC *server,
1402 SilcChannelEntry channel,
1403 const char *list_type,
1404 SilcArgumentPayload list)
1407 SilcUInt32 type, len;
1408 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1409 int counter=0, resolving = FALSE;
1411 if (!silc_argument_get_arg_num(list)) {
1412 printformat_module("fe-common/silc", server,
1413 (chanrec ? chanrec->visible_name : NULL),
1414 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1415 channel->channel_name, list_type);
1419 printformat_module("fe-common/silc", server,
1420 (chanrec ? chanrec->visible_name : NULL),
1421 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1422 channel->channel_name, list_type);
1424 /* parse the list */
1425 tmp = silc_argument_get_first_arg(list, &type, &len);
1430 /* an invite string */
1434 if (tmp[len-1] == ',')
1437 list = g_strsplit(tmp, ",", -1);
1439 printformat_module("fe-common/silc", server,
1440 (chanrec ? chanrec->visible_name : NULL),
1441 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1442 ++counter, channel->channel_name, list_type,
1451 char *fingerprint, *babbleprint;
1453 /* tmp is Public Key Payload, take public key from it. */
1454 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1455 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1457 printformat_module("fe-common/silc", server,
1458 (chanrec ? chanrec->visible_name : NULL),
1459 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1460 ++counter, channel->channel_name, list_type,
1461 fingerprint, babbleprint);
1468 SilcClientID *client_id;
1469 SilcClientEntry client_entry;
1471 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1473 if (client_id == NULL) {
1474 silc_say_error("Invalid data in %s list encountered", list_type);
1478 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1481 printformat_module("fe-common/silc", server,
1482 (chanrec ? chanrec->visible_name : NULL),
1483 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1484 ++counter, channel->channel_name, list_type,
1485 client_entry->nickname);
1488 silc_client_get_client_by_id_resolve(client, conn, client_id,
1492 silc_free(client_id);
1498 silc_say_error("Unkown type in %s list: %u (len %u)",
1499 list_type, type, len);
1501 tmp = silc_argument_get_next_arg(list, &type, &len);
1505 printformat_module("fe-common/silc", server,
1506 (chanrec ? chanrec->visible_name : NULL),
1507 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1508 list_type, channel->channel_name);
1511 /* Command reply handler. This function is called always in the command reply
1512 function. If error occurs it will be called as well. Normal scenario
1513 is that it will be called after the received command data has been parsed
1514 and processed. The function is used to pass the received command data to
1517 `conn' is the associated client connection. `cmd_payload' is the command
1518 payload data received from server and it can be ignored. It is provided
1519 if the application would like to re-parse the received command data,
1520 however, it must be noted that the data is parsed already by the library
1521 thus the payload can be ignored. `success' is FALSE if error occured.
1522 In this case arguments are not sent to the application. `command' is the
1523 command reply being processed. The function has variable argument list
1524 and each command defines the number and type of arguments it passes to the
1525 application (on error they are not sent). */
1528 silc_command_reply(SilcClient client, SilcClientConnection conn,
1529 SilcCommandPayload cmd_payload, bool success,
1530 SilcCommand command, SilcStatus status, ...)
1533 SILC_SERVER_REC *server = conn->context;
1534 SILC_CHANNEL_REC *chanrec;
1537 va_start(vp, status);
1539 SILC_LOG_DEBUG(("Start"));
1542 case SILC_COMMAND_WHOIS:
1544 char buf[1024], *nickname, *username, *realname, *nick;
1545 unsigned char *fingerprint;
1546 SilcUInt32 idle, mode;
1547 SilcBuffer channels, user_modes;
1548 SilcClientEntry client_entry;
1551 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1552 /* Print the unknown nick for user */
1553 unsigned char *tmp =
1554 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1557 silc_say_error("%s: %s", tmp,
1558 silc_get_status_message(status));
1560 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1561 /* Try to find the entry for the unknown client ID, since we
1562 might have, and print the nickname of it for user. */
1564 unsigned char *tmp =
1565 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1568 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1571 client_entry = silc_client_get_client_by_id(client, conn,
1573 if (client_entry && client_entry->nickname)
1574 silc_say_error("%s: %s", client_entry->nickname,
1575 silc_get_status_message(status));
1576 silc_free(client_id);
1580 } else if (!success) {
1581 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1585 client_entry = va_arg(vp, SilcClientEntry);
1586 nickname = va_arg(vp, char *);
1587 username = va_arg(vp, char *);
1588 realname = va_arg(vp, char *);
1589 channels = va_arg(vp, SilcBuffer);
1590 mode = va_arg(vp, SilcUInt32);
1591 idle = va_arg(vp, SilcUInt32);
1592 fingerprint = va_arg(vp, unsigned char *);
1593 user_modes = va_arg(vp, SilcBuffer);
1594 attrs = va_arg(vp, SilcDList);
1596 silc_parse_userfqdn(nickname, &nick, NULL);
1597 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1598 SILCTXT_WHOIS_USERINFO, nickname,
1599 client_entry->username, client_entry->hostname,
1600 nick, client_entry->nickname);
1601 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1602 SILCTXT_WHOIS_REALNAME, realname);
1605 if (channels && user_modes) {
1607 SilcDList list = silc_channel_payload_parse_list(channels->data,
1609 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1611 SilcChannelPayload entry;
1614 memset(buf, 0, sizeof(buf));
1615 silc_dlist_start(list);
1616 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1617 SilcUInt32 name_len;
1618 char *m = silc_client_chumode_char(umodes[i++]);
1619 char *name = silc_channel_get_name(entry, &name_len);
1622 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1623 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1624 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1628 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1629 SILCTXT_WHOIS_CHANNELS, buf);
1630 silc_channel_payload_list_free(list);
1636 memset(buf, 0, sizeof(buf));
1637 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1638 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1639 SILCTXT_WHOIS_MODES, buf);
1642 if (idle && nickname) {
1643 memset(buf, 0, sizeof(buf));
1644 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1645 idle > 60 ? (idle / 60) : idle,
1646 idle > 60 ? "minutes" : "seconds");
1648 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1649 SILCTXT_WHOIS_IDLE, buf);
1653 fingerprint = silc_fingerprint(fingerprint, 20);
1654 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1655 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1656 silc_free(fingerprint);
1660 silc_query_attributes_print(server, silc_client, conn, attrs,
1665 case SILC_COMMAND_IDENTIFY:
1667 SilcClientEntry client_entry;
1669 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1670 /* Print the unknown nick for user */
1671 unsigned char *tmp =
1672 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1675 silc_say_error("%s: %s", tmp,
1676 silc_get_status_message(status));
1678 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1679 /* Try to find the entry for the unknown client ID, since we
1680 might have, and print the nickname of it for user. */
1682 unsigned char *tmp =
1683 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1686 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1689 client_entry = silc_client_get_client_by_id(client, conn,
1691 if (client_entry && client_entry->nickname)
1692 silc_say_error("%s: %s", client_entry->nickname,
1693 silc_get_status_message(status));
1694 silc_free(client_id);
1703 case SILC_COMMAND_WHOWAS:
1705 char *nickname, *username, *realname;
1707 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1708 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1710 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1713 silc_say_error("%s: %s", tmp,
1714 silc_get_status_message(status));
1716 } else if (!success) {
1717 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1721 (void)va_arg(vp, SilcClientEntry);
1722 nickname = va_arg(vp, char *);
1723 username = va_arg(vp, char *);
1724 realname = va_arg(vp, char *);
1726 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1727 SILCTXT_WHOWAS_USERINFO, nickname, username,
1728 realname ? realname : "");
1732 case SILC_COMMAND_INVITE:
1734 SilcChannelEntry channel;
1736 SilcArgumentPayload invite_list;
1742 channel = va_arg(vp, SilcChannelEntry);
1743 payload = va_arg(vp, SilcBuffer);
1746 SILC_GET16_MSB(argc, payload->data);
1747 invite_list = silc_argument_payload_parse(payload->data + 2,
1748 payload->len - 2, argc);
1750 silc_parse_inviteban_list(client, conn, server, channel,
1751 "invite", invite_list);
1752 silc_argument_payload_free(invite_list);
1758 case SILC_COMMAND_JOIN:
1760 char *channel, *mode, *topic;
1762 SilcChannelEntry channel_entry;
1763 SilcBuffer client_id_list;
1764 SilcUInt32 list_count;
1769 channel = va_arg(vp, char *);
1770 channel_entry = va_arg(vp, SilcChannelEntry);
1771 modei = va_arg(vp, SilcUInt32);
1772 (void)va_arg(vp, SilcUInt32);
1773 (void)va_arg(vp, unsigned char *);
1774 (void)va_arg(vp, unsigned char *);
1775 (void)va_arg(vp, unsigned char *);
1776 topic = va_arg(vp, char *);
1777 (void)va_arg(vp, unsigned char *);
1778 list_count = va_arg(vp, SilcUInt32);
1779 client_id_list = va_arg(vp, SilcBuffer);
1781 chanrec = silc_channel_find(server, channel);
1783 chanrec = silc_channel_create(server, channel, channel, TRUE);
1786 char tmp[256], *cp, *dm = NULL;
1787 g_free_not_null(chanrec->topic);
1789 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1790 memset(tmp, 0, sizeof(tmp));
1792 if (strlen(topic) > sizeof(tmp) - 1) {
1793 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1797 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1802 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1803 signal_emit("channel topic changed", 1, chanrec);
1808 mode = silc_client_chmode(modei,
1809 channel_entry->channel_key ?
1810 silc_cipher_get_name(channel_entry->
1812 channel_entry->hmac ?
1813 silc_hmac_get_name(channel_entry->hmac) : "");
1814 g_free_not_null(chanrec->mode);
1815 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1816 signal_emit("channel mode changed", 1, chanrec);
1818 /* Resolve the client information */
1820 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1821 r->channel = channel_entry;
1822 silc_client_get_clients_by_list(client, conn, list_count,
1824 silc_client_join_get_users, r);
1830 case SILC_COMMAND_NICK:
1833 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1839 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1840 if ((nicks != NULL) &&
1841 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1843 SilcClientEntry collider, old;
1845 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1846 collider = silc_client_get_client_by_id(client, conn,
1849 memset(buf, 0, sizeof(buf));
1850 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1851 collider->username, collider->hostname);
1852 nicklist_rename_unique(SERVER(server),
1854 collider, collider->nickname);
1855 silc_print_nick_change(server, collider->nickname,
1856 client_entry->nickname, buf);
1857 g_slist_free(nicks);
1860 old = g_strdup(server->nick);
1861 server_change_nick(SERVER(server), client_entry->nickname);
1862 nicklist_rename_unique(SERVER(server),
1863 server->conn->local_entry, server->nick,
1864 client_entry, client_entry->nickname);
1865 signal_emit("message own_nick", 4, server, server->nick, old, "");
1870 case SILC_COMMAND_LIST:
1875 char tmp[256], *cp, *dm = NULL;
1880 (void)va_arg(vp, SilcChannelEntry);
1881 name = va_arg(vp, char *);
1882 topic = va_arg(vp, char *);
1883 usercount = va_arg(vp, int);
1885 if (topic && !silc_term_utf8() &&
1886 silc_utf8_valid(topic, strlen(topic))) {
1887 memset(tmp, 0, sizeof(tmp));
1889 if (strlen(topic) > sizeof(tmp) - 1) {
1890 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1894 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1899 if (status == SILC_STATUS_LIST_START ||
1900 status == SILC_STATUS_OK)
1901 printformat_module("fe-common/silc", server, NULL,
1902 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1905 snprintf(users, sizeof(users) - 1, "N/A");
1907 snprintf(users, sizeof(users) - 1, "%d", usercount);
1908 printformat_module("fe-common/silc", server, NULL,
1909 MSGLEVEL_CRAP, SILCTXT_LIST,
1910 name, users, topic ? topic : "");
1915 case SILC_COMMAND_UMODE:
1923 mode = va_arg(vp, SilcUInt32);
1925 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1926 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1927 printformat_module("fe-common/silc", server, NULL,
1928 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1930 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1931 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1932 printformat_module("fe-common/silc", server, NULL,
1933 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1935 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1936 if (mode & SILC_UMODE_GONE) {
1937 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1938 reason = g_strdup(server->away_reason);
1940 reason = g_strdup("away");
1942 reason = g_strdup("");
1944 silc_set_away(reason, server);
1949 server->umode = mode;
1950 signal_emit("user mode changed", 2, server, NULL);
1954 case SILC_COMMAND_OPER:
1958 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1959 signal_emit("user mode changed", 2, server, NULL);
1961 printformat_module("fe-common/silc", server, NULL,
1962 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1965 case SILC_COMMAND_SILCOPER:
1969 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1970 signal_emit("user mode changed", 2, server, NULL);
1972 printformat_module("fe-common/silc", server, NULL,
1973 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1976 case SILC_COMMAND_USERS:
1978 SilcHashTableList htl;
1979 SilcChannelEntry channel;
1980 SilcChannelUser chu;
1985 channel = va_arg(vp, SilcChannelEntry);
1987 printformat_module("fe-common/silc", server, channel->channel_name,
1988 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1989 channel->channel_name);
1991 silc_hash_table_list(channel->user_list, &htl);
1992 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1993 SilcClientEntry e = chu->client;
1994 char stat[5], *mode;
1999 memset(stat, 0, sizeof(stat));
2000 mode = silc_client_chumode_char(chu->mode);
2001 if (e->mode & SILC_UMODE_GONE)
2003 else if (e->mode & SILC_UMODE_INDISPOSED)
2005 else if (e->mode & SILC_UMODE_BUSY)
2007 else if (e->mode & SILC_UMODE_PAGE)
2009 else if (e->mode & SILC_UMODE_HYPER)
2011 else if (e->mode & SILC_UMODE_ROBOT)
2013 else if (e->mode & SILC_UMODE_ANONYMOUS)
2020 printformat_module("fe-common/silc", server, channel->channel_name,
2021 MSGLEVEL_CRAP, SILCTXT_USERS,
2023 e->username ? e->username : "",
2024 e->hostname ? e->hostname : "",
2025 e->realname ? e->realname : "");
2029 silc_hash_table_list_reset(&htl);
2033 case SILC_COMMAND_BAN:
2035 SilcChannelEntry channel;
2037 SilcArgumentPayload ban_list;
2043 channel = va_arg(vp, SilcChannelEntry);
2044 payload = va_arg(vp, SilcBuffer);
2047 SILC_GET16_MSB(argc, payload->data);
2048 ban_list = silc_argument_payload_parse(payload->data + 2,
2049 payload->len - 2, argc);
2051 silc_parse_inviteban_list(client, conn, server, channel,
2053 silc_argument_payload_free(ban_list);
2059 case SILC_COMMAND_GETKEY:
2063 SilcPublicKey public_key;
2066 GetkeyContext getkey;
2072 id_type = va_arg(vp, SilcUInt32);
2073 entry = va_arg(vp, void *);
2074 public_key = va_arg(vp, SilcPublicKey);
2077 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2079 getkey = silc_calloc(1, sizeof(*getkey));
2080 getkey->entry = entry;
2081 getkey->id_type = id_type;
2082 getkey->client = client;
2083 getkey->conn = conn;
2084 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2086 name = (id_type == SILC_ID_CLIENT ?
2087 ((SilcClientEntry)entry)->nickname :
2088 ((SilcServerEntry)entry)->server_name);
2090 silc_verify_public_key_internal(client, conn, name,
2091 (id_type == SILC_ID_CLIENT ?
2092 SILC_SOCKET_TYPE_CLIENT :
2093 SILC_SOCKET_TYPE_SERVER),
2094 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2095 silc_getkey_cb, getkey);
2098 printformat_module("fe-common/silc", server, NULL,
2099 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2104 case SILC_COMMAND_INFO:
2106 SilcServerEntry server_entry;
2113 server_entry = va_arg(vp, SilcServerEntry);
2114 server_name = va_arg(vp, char *);
2115 server_info = va_arg(vp, char *);
2117 if (server_name && server_info )
2119 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2120 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2125 case SILC_COMMAND_TOPIC:
2127 SilcChannelEntry channel;
2129 char tmp[256], *cp, *dm = NULL;
2134 channel = va_arg(vp, SilcChannelEntry);
2135 topic = va_arg(vp, char *);
2137 if (topic && !silc_term_utf8() &&
2138 silc_utf8_valid(topic, strlen(topic))) {
2139 memset(tmp, 0, sizeof(tmp));
2141 if (strlen(topic) > sizeof(tmp) - 1) {
2142 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2146 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2152 chanrec = silc_channel_find_entry(server, channel);
2154 g_free_not_null(chanrec->topic);
2155 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2156 signal_emit("channel topic changed", 1, chanrec);
2158 printformat_module("fe-common/silc", server, channel->channel_name,
2159 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2160 channel->channel_name, topic);
2162 printformat_module("fe-common/silc", server, channel->channel_name,
2163 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2164 channel->channel_name);
2170 case SILC_COMMAND_WATCH:
2173 case SILC_COMMAND_STATS:
2175 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2176 my_router_ops, cell_clients, cell_channels, cell_servers,
2177 clients, channels, servers, routers, server_ops, router_ops;
2179 SilcBufferStruct buf;
2180 unsigned char *tmp_buf;
2182 const char *tmptime;
2183 int days, hours, mins, secs;
2188 tmp_buf = va_arg(vp, unsigned char *);
2189 buf_len = va_arg(vp, SilcUInt32);
2191 if (!tmp_buf || !buf_len) {
2192 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2196 /* Get statistics structure */
2197 silc_buffer_set(&buf, tmp_buf, buf_len);
2198 silc_buffer_unformat(&buf,
2199 SILC_STR_UI_INT(&starttime),
2200 SILC_STR_UI_INT(&uptime),
2201 SILC_STR_UI_INT(&my_clients),
2202 SILC_STR_UI_INT(&my_channels),
2203 SILC_STR_UI_INT(&my_server_ops),
2204 SILC_STR_UI_INT(&my_router_ops),
2205 SILC_STR_UI_INT(&cell_clients),
2206 SILC_STR_UI_INT(&cell_channels),
2207 SILC_STR_UI_INT(&cell_servers),
2208 SILC_STR_UI_INT(&clients),
2209 SILC_STR_UI_INT(&channels),
2210 SILC_STR_UI_INT(&servers),
2211 SILC_STR_UI_INT(&routers),
2212 SILC_STR_UI_INT(&server_ops),
2213 SILC_STR_UI_INT(&router_ops),
2216 tmptime = silc_get_time(starttime);
2217 printformat_module("fe-common/silc", server, NULL,
2218 MSGLEVEL_CRAP, SILCTXT_STATS,
2219 "Local server start time", tmptime);
2221 days = uptime / (24 * 60 * 60);
2222 uptime -= days * (24 * 60 * 60);
2223 hours = uptime / (60 * 60);
2224 uptime -= hours * (60 * 60);
2226 uptime -= mins * 60;
2228 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2229 days, hours, mins, secs);
2230 printformat_module("fe-common/silc", server, NULL,
2231 MSGLEVEL_CRAP, SILCTXT_STATS,
2232 "Local server uptime", tmp);
2234 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2235 printformat_module("fe-common/silc", server, NULL,
2236 MSGLEVEL_CRAP, SILCTXT_STATS,
2237 "Local server clients", tmp);
2239 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2240 printformat_module("fe-common/silc", server, NULL,
2241 MSGLEVEL_CRAP, SILCTXT_STATS,
2242 "Local server channels", tmp);
2244 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2245 printformat_module("fe-common/silc", server, NULL,
2246 MSGLEVEL_CRAP, SILCTXT_STATS,
2247 "Local server operators", tmp);
2249 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2250 printformat_module("fe-common/silc", server, NULL,
2251 MSGLEVEL_CRAP, SILCTXT_STATS,
2252 "Local router operators", tmp);
2254 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2255 printformat_module("fe-common/silc", server, NULL,
2256 MSGLEVEL_CRAP, SILCTXT_STATS,
2257 "Local cell clients", tmp);
2259 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2260 printformat_module("fe-common/silc", server, NULL,
2261 MSGLEVEL_CRAP, SILCTXT_STATS,
2262 "Local cell channels", tmp);
2264 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2265 printformat_module("fe-common/silc", server, NULL,
2266 MSGLEVEL_CRAP, SILCTXT_STATS,
2267 "Local cell servers", tmp);
2269 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2270 printformat_module("fe-common/silc", server, NULL,
2271 MSGLEVEL_CRAP, SILCTXT_STATS,
2272 "Total clients", tmp);
2274 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2275 printformat_module("fe-common/silc", server, NULL,
2276 MSGLEVEL_CRAP, SILCTXT_STATS,
2277 "Total channels", tmp);
2279 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2280 printformat_module("fe-common/silc", server, NULL,
2281 MSGLEVEL_CRAP, SILCTXT_STATS,
2282 "Total servers", tmp);
2284 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2285 printformat_module("fe-common/silc", server, NULL,
2286 MSGLEVEL_CRAP, SILCTXT_STATS,
2287 "Total routers", tmp);
2289 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2290 printformat_module("fe-common/silc", server, NULL,
2291 MSGLEVEL_CRAP, SILCTXT_STATS,
2292 "Total server operators", tmp);
2294 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2295 printformat_module("fe-common/silc", server, NULL,
2296 MSGLEVEL_CRAP, SILCTXT_STATS,
2297 "Total router operators", tmp);
2301 case SILC_COMMAND_CMODE:
2303 SilcChannelEntry channel_entry;
2304 SilcBuffer channel_pubkeys;
2306 channel_entry = va_arg(vp, SilcChannelEntry);
2307 (void)va_arg(vp, SilcUInt32);
2308 (void)va_arg(vp, SilcPublicKey);
2309 channel_pubkeys = va_arg(vp, SilcBuffer);
2311 if (!success || !cmode_list_chpks ||
2312 !channel_entry || !channel_entry->channel_name)
2315 /* Print the channel public key list */
2316 if (channel_pubkeys)
2317 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2319 printformat_module("fe-common/silc", server, NULL,
2320 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2321 channel_entry->channel_name);
2332 SilcClientConnection conn;
2338 SilcSKEPKType pk_type;
2339 SilcVerifyPublicKey completion;
2343 static void verify_public_key_completion(const char *line, void *context)
2345 PublicKeyVerify verify = (PublicKeyVerify)context;
2347 if (line[0] == 'Y' || line[0] == 'y') {
2348 /* Call the completion */
2349 if (verify->completion)
2350 verify->completion(TRUE, verify->context);
2352 /* Save the key for future checking */
2353 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2354 verify->pk_len, SILC_PKCS_FILE_PEM);
2356 /* Call the completion */
2357 if (verify->completion)
2358 verify->completion(FALSE, verify->context);
2360 printformat_module("fe-common/silc", NULL, NULL,
2361 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2362 verify->entity_name ? verify->entity_name :
2366 silc_free(verify->filename);
2367 silc_free(verify->entity);
2368 silc_free(verify->entity_name);
2369 silc_free(verify->pk);
2373 /* Internal routine to verify public key. If the `completion' is provided
2374 it will be called to indicate whether public was verified or not. For
2375 server/router public key this will check for filename that includes the
2376 remote host's IP address and remote host's hostname. */
2379 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2380 const char *name, SilcSocketType conn_type,
2381 unsigned char *pk, SilcUInt32 pk_len,
2382 SilcSKEPKType pk_type,
2383 SilcVerifyPublicKey completion, void *context)
2386 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2387 char *fingerprint, *babbleprint, *format;
2390 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2391 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2392 "server" : "client");
2393 PublicKeyVerify verify;
2395 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2396 printformat_module("fe-common/silc", NULL, NULL,
2397 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2400 completion(FALSE, context);
2404 pw = getpwuid(getuid());
2407 completion(FALSE, context);
2411 memset(filename, 0, sizeof(filename));
2412 memset(filename2, 0, sizeof(filename2));
2413 memset(file, 0, sizeof(file));
2415 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2416 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2418 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2419 conn->sock->ip, conn->sock->port);
2420 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2421 get_irssi_dir(), entity, file);
2423 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2424 conn->sock->hostname, conn->sock->port);
2425 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2426 get_irssi_dir(), entity, file);
2431 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2432 name, conn->sock->port);
2433 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2434 get_irssi_dir(), entity, file);
2439 /* Replace all whitespaces with `_'. */
2440 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2441 for (i = 0; i < strlen(fingerprint); i++)
2442 if (fingerprint[i] == ' ')
2443 fingerprint[i] = '_';
2445 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2446 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2447 get_irssi_dir(), entity, file);
2448 silc_free(fingerprint);
2453 /* Take fingerprint of the public key */
2454 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2455 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2457 verify = silc_calloc(1, sizeof(*verify));
2458 verify->client = client;
2459 verify->conn = conn;
2460 verify->filename = strdup(ipf);
2461 verify->entity = strdup(entity);
2462 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2463 (name ? strdup(name) : strdup(conn->sock->hostname))
2465 verify->pk = silc_memdup(pk, pk_len);
2466 verify->pk_len = pk_len;
2467 verify->pk_type = pk_type;
2468 verify->completion = completion;
2469 verify->context = context;
2471 /* Check whether this key already exists */
2472 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2473 /* Key does not exist, ask user to verify the key and save it */
2475 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2476 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2477 verify->entity_name : entity);
2478 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2479 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2480 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2481 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2482 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2483 SILCTXT_PUBKEY_ACCEPT);
2484 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2487 silc_free(fingerprint);
2490 /* The key already exists, verify it. */
2491 SilcPublicKey public_key;
2492 unsigned char *encpk;
2493 SilcUInt32 encpk_len;
2495 /* Load the key file, try for both IP filename and hostname filename */
2496 if (!silc_pkcs_load_public_key(ipf, &public_key,
2497 SILC_PKCS_FILE_PEM) &&
2498 !silc_pkcs_load_public_key(ipf, &public_key,
2499 SILC_PKCS_FILE_BIN) &&
2500 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2501 SILC_PKCS_FILE_PEM) &&
2502 !silc_pkcs_load_public_key(hostf, &public_key,
2503 SILC_PKCS_FILE_BIN)))) {
2504 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2505 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2506 verify->entity_name : entity);
2507 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2508 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2509 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2510 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2511 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2512 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2513 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2514 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2515 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2518 silc_free(fingerprint);
2522 /* Encode the key data */
2523 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2525 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2526 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2527 verify->entity_name : entity);
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 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2533 SILCTXT_PUBKEY_MALFORMED, entity);
2534 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2535 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2536 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2539 silc_free(fingerprint);
2543 /* Compare the keys */
2544 if (memcmp(encpk, pk, encpk_len)) {
2545 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2546 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2547 verify->entity_name : entity);
2548 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2549 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2550 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2551 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2552 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2553 SILCTXT_PUBKEY_NO_MATCH, entity);
2554 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2555 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2556 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2557 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2559 /* Ask user to verify the key and save it */
2560 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2561 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2562 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2565 silc_free(fingerprint);
2569 /* Local copy matched */
2571 completion(TRUE, context);
2572 silc_free(fingerprint);
2573 silc_free(verify->filename);
2574 silc_free(verify->entity);
2575 silc_free(verify->entity_name);
2576 silc_free(verify->pk);
2581 /* Verifies received public key. The `conn_type' indicates which entity
2582 (server, client etc.) has sent the public key. If user decides to trust
2583 the key may be saved as trusted public key for later use. The
2584 `completion' must be called after the public key has been verified. */
2587 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2588 SilcSocketType conn_type, unsigned char *pk,
2589 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2590 SilcVerifyPublicKey completion, void *context)
2592 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2594 completion, context);
2597 /* Asks passphrase from user on the input line. */
2600 SilcAskPassphrase completion;
2604 void ask_passphrase_completion(const char *passphrase, void *context)
2606 AskPassphrase p = (AskPassphrase)context;
2607 if (passphrase && passphrase[0] == '\0')
2609 p->completion((unsigned char *)passphrase,
2610 passphrase ? strlen(passphrase) : 0, p->context);
2614 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2615 SilcAskPassphrase completion, void *context)
2617 AskPassphrase p = silc_calloc(1, sizeof(*p));
2618 p->completion = completion;
2619 p->context = context;
2621 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2622 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2626 SilcGetAuthMeth completion;
2628 } *InternalGetAuthMethod;
2630 /* Callback called when we've received the authentication method information
2631 from the server after we've requested it. This will get the authentication
2632 data from the user if needed. */
2634 static void silc_get_auth_method_callback(SilcClient client,
2635 SilcClientConnection conn,
2636 SilcAuthMethod auth_meth,
2639 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2641 SILC_LOG_DEBUG(("Start"));
2643 switch (auth_meth) {
2644 case SILC_AUTH_NONE:
2645 /* No authentication required. */
2646 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2648 case SILC_AUTH_PASSWORD:
2650 /* Check whether we find the password for this server in our
2651 configuration. If not, then don't provide so library will ask
2652 it from the user. */
2653 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2655 if (!setup || !setup->password) {
2656 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2660 (*internal->completion)(TRUE, auth_meth, setup->password,
2661 strlen(setup->password), internal->context);
2664 case SILC_AUTH_PUBLIC_KEY:
2665 /* Do not get the authentication data now, the library will generate
2666 it using our default key, if we do not provide it here. */
2667 /* XXX In the future when we support multiple local keys and multiple
2668 local certificates we will need to ask from user which one to use. */
2669 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2673 silc_free(internal);
2676 /* Find authentication method and authentication data by hostname and
2677 port. The hostname may be IP address as well. The found authentication
2678 method and authentication data is returned to `auth_meth', `auth_data'
2679 and `auth_data_len'. The function returns TRUE if authentication method
2680 is found and FALSE if not. `conn' may be NULL. */
2682 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2683 char *hostname, SilcUInt16 port,
2684 SilcGetAuthMeth completion, void *context)
2686 InternalGetAuthMethod internal;
2688 SILC_LOG_DEBUG(("Start"));
2690 /* If we do not have this connection configured by the user in a
2691 configuration file then resolve the authentication method from the
2692 server for this session. */
2693 internal = silc_calloc(1, sizeof(*internal));
2694 internal->completion = completion;
2695 internal->context = context;
2697 silc_client_request_authentication_method(client, conn,
2698 silc_get_auth_method_callback,
2702 /* Notifies application that failure packet was received. This is called
2703 if there is some protocol active in the client. The `protocol' is the
2704 protocol context. The `failure' is opaque pointer to the failure
2705 indication. Note, that the `failure' is protocol dependant and application
2706 must explicitly cast it to correct type. Usually `failure' is 32 bit
2707 failure type (see protocol specs for all protocol failure types). */
2709 void silc_failure(SilcClient client, SilcClientConnection conn,
2710 SilcProtocol protocol, void *failure)
2712 SILC_LOG_DEBUG(("Start"));
2714 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2715 SilcSKEStatus status = (SilcSKEStatus)failure;
2717 if (status == SILC_SKE_STATUS_BAD_VERSION)
2718 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2719 SILCTXT_KE_BAD_VERSION);
2720 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2721 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2722 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2723 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2724 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2725 SILCTXT_KE_UNKNOWN_GROUP);
2726 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2727 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2728 SILCTXT_KE_UNKNOWN_CIPHER);
2729 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2730 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2731 SILCTXT_KE_UNKNOWN_PKCS);
2732 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2733 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2734 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2735 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2736 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2737 SILCTXT_KE_UNKNOWN_HMAC);
2738 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2739 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2740 SILCTXT_KE_INCORRECT_SIGNATURE);
2741 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2742 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2743 SILCTXT_KE_INVALID_COOKIE);
2746 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2747 SilcUInt32 err = (SilcUInt32)failure;
2749 if (err == SILC_AUTH_FAILED)
2750 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2751 SILCTXT_AUTH_FAILED);
2755 /* Asks whether the user would like to perform the key agreement protocol.
2756 This is called after we have received an key agreement packet or an
2757 reply to our key agreement packet. This returns TRUE if the user wants
2758 the library to perform the key agreement protocol and FALSE if it is not
2759 desired (application may start it later by calling the function
2760 silc_client_perform_key_agreement). */
2762 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2763 SilcClientEntry client_entry, const char *hostname,
2764 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2769 SILC_LOG_DEBUG(("Start"));
2771 /* We will just display the info on the screen and return FALSE and user
2772 will have to start the key agreement with a command. */
2775 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2778 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2779 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2781 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2782 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2783 client_entry->nickname, hostname, portstr);
2791 /* Notifies application that file transfer protocol session is being
2792 requested by the remote client indicated by the `client_entry' from
2793 the `hostname' and `port'. The `session_id' is the file transfer
2794 session and it can be used to either accept or reject the file
2795 transfer request, by calling the silc_client_file_receive or
2796 silc_client_file_close, respectively. */
2798 void silc_ftp(SilcClient client, SilcClientConnection conn,
2799 SilcClientEntry client_entry, SilcUInt32 session_id,
2800 const char *hostname, SilcUInt16 port)
2802 SILC_SERVER_REC *server;
2804 FtpSession ftp = NULL;
2806 SILC_LOG_DEBUG(("Start"));
2808 server = conn->context;
2810 silc_dlist_start(server->ftp_sessions);
2811 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2812 if (ftp->client_entry == client_entry &&
2813 ftp->session_id == session_id) {
2814 server->current_session = ftp;
2818 if (ftp == SILC_LIST_END) {
2819 ftp = silc_calloc(1, sizeof(*ftp));
2820 ftp->client_entry = client_entry;
2821 ftp->session_id = session_id;
2824 silc_dlist_add(server->ftp_sessions, ftp);
2825 server->current_session = ftp;
2829 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2832 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2833 SILCTXT_FILE_REQUEST, client_entry->nickname);
2835 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2836 SILCTXT_FILE_REQUEST_HOST,
2837 client_entry->nickname, hostname, portstr);
2840 /* Delivers SILC session detachment data indicated by `detach_data' to the
2841 application. If application has issued SILC_COMMAND_DETACH command
2842 the client session in the SILC network is not quit. The client remains
2843 in the network but is detached. The detachment data may be used later
2844 to resume the session in the SILC Network. The appliation is
2845 responsible of saving the `detach_data', to for example in a file.
2847 The detachment data can be given as argument to the functions
2848 silc_client_connect_to_server, or silc_client_add_connection when
2849 creating connection to remote server, inside SilcClientConnectionParams
2850 structure. If it is provided the client library will attempt to resume
2851 the session in the network. After the connection is created
2852 successfully, the application is responsible of setting the user
2853 interface for user into the same state it was before detaching (showing
2854 same channels, channel modes, etc). It can do this by fetching the
2855 information (like joined channels) from the client library. */
2858 silc_detach(SilcClient client, SilcClientConnection conn,
2859 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2863 /* Save the detachment data to file. */
2865 memset(file, 0, sizeof(file));
2866 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2867 silc_file_writefile(file, detach_data, detach_data_len);
2871 /* SILC client operations */
2872 SilcClientOperations ops = {
2874 silc_channel_message,
2875 silc_private_message,
2881 silc_get_auth_method,
2882 silc_verify_public_key,
2883 silc_ask_passphrase,