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(NULL, 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_public_key_get_pkcs(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 void static verify_message_signature_verified(SilcBool success,
242 *(SilcBool *)context = success;
245 /* Try to verify a message using locally stored public key data */
247 int verify_message_signature(SilcClientEntry sender,
248 SilcMessagePayload message)
251 char file[256], filename[256];
252 char *fingerprint, *fingerprint2;
253 const unsigned char *pk_data;
254 SilcUInt32 pk_datalen;
256 int ret = SILC_MSG_SIGNED_VERIFIED, i;
257 SilcBool verified = FALSE;
259 /* get public key from the signature payload and compare it with the
260 one stored in the client entry */
261 pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
264 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
266 if (sender->fingerprint[0]) {
267 fingerprint2 = silc_fingerprint(sender->fingerprint,
268 sizeof(sender->fingerprint));
269 if (strcmp(fingerprint, fingerprint2)) {
270 /* since the public key differs from the senders public key, the
271 verification _failed_ */
272 silc_pkcs_public_key_free(pk);
273 silc_free(fingerprint);
274 ret = SILC_MSG_SIGNED_UNKNOWN;
276 silc_free(fingerprint2);
278 } else if (sender->fingerprint[0])
279 fingerprint = silc_fingerprint(sender->fingerprint,
280 sizeof(sender->fingerprint));
282 /* no idea, who or what signed that message ... */
283 return SILC_MSG_SIGNED_UNKNOWN;
285 /* search our local client key cache */
286 for (i = 0; i < strlen(fingerprint); i++)
287 if (fingerprint[i] == ' ')
288 fingerprint[i] = '_';
290 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
291 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
292 get_irssi_dir(), file);
293 silc_free(fingerprint);
295 if (stat(filename, &st) < 0)
296 /* we don't have the public key cached ... use the one from the sig */
297 ret = SILC_MSG_SIGNED_UNKNOWN;
299 SilcPublicKey cached_pk=NULL;
301 /* try to load the file */
302 if (!silc_pkcs_load_public_key(filename, SILC_PKCS_ANY, &cached_pk)) {
303 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
304 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
306 return SILC_MSG_SIGNED_UNKNOWN;
308 ret = SILC_MSG_SIGNED_UNKNOWN;
313 silc_pkcs_public_key_free(pk);
318 /* the public key is now in pk, our "level of trust" in ret */
320 silc_message_signed_verify(message, pk, sha1hash,
321 verify_message_signature_verified, &verified);
323 ret = SILC_MSG_SIGNED_FAILED;
327 silc_pkcs_public_key_free(pk);
332 char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
335 int i = 0, j = 0, len = strlen(escaped_data);
337 data = silc_calloc(len, sizeof(char));
340 ptr = memchr(escaped_data + i, 1, len - i);
342 int inc = (ptr - escaped_data) - i;
343 memcpy(data + j, escaped_data + i, inc);
346 data[j++] = *(ptr + 1) - 1;
348 memcpy(data + j, escaped_data + i, len - i);
358 char *silc_escape_data(const char *data, SilcUInt32 len)
360 char *escaped_data, *ptr, *ptr0, *ptr1;
363 escaped_data = silc_calloc(2 * len, sizeof(char));
366 ptr0 = memchr(data + i, 0, len - i);
367 ptr1 = memchr(data + i, 1, len - i);
369 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
372 int inc = (ptr - data) - i;
374 memcpy(escaped_data + j, data + i, inc);
377 escaped_data[j++] = 1;
378 escaped_data[j++] = *(data + i++) + 1;
380 memcpy(escaped_data + j, data + i, len - i);
389 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
390 const char *data, SilcUInt32 data_len,
391 const char *nick, int verified)
395 escaped_data = silc_escape_data(data, data_len);
397 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
399 silc_free(escaped_data);
403 /* Message for a channel. The `sender' is the nickname of the sender
404 received in the packet. The `channel_name' is the name of the channel. */
406 void silc_channel_message(SilcClient client, SilcClientConnection conn,
407 SilcClientEntry sender, SilcChannelEntry channel,
408 SilcMessagePayload payload,
409 SilcChannelPrivateKey key,
410 SilcMessageFlags flags, const unsigned char *message,
411 SilcUInt32 message_len)
413 SILC_SERVER_REC *server;
415 SILC_CHANNEL_REC *chanrec;
418 SILC_LOG_DEBUG(("Start"));
423 server = conn == NULL ? NULL : conn->context;
424 chanrec = silc_channel_find_entry(server, channel);
428 nick = silc_nicklist_find(chanrec, sender);
430 /* We didn't find client but it clearly exists, add it. */
431 SilcChannelUser chu = silc_client_on_channel(channel, sender);
433 nick = silc_nicklist_insert(chanrec, chu, FALSE);
438 /* If the messages is digitally signed, verify it, if possible. */
439 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
440 if (!settings_get_bool("ignore_message_signatures")) {
441 verified = verify_message_signature(sender, payload);
443 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
447 if (flags & SILC_MESSAGE_FLAG_DATA) {
448 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
449 nick == NULL ? NULL : nick->nick,
450 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
457 if (flags & SILC_MESSAGE_FLAG_ACTION)
458 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
459 char tmp[256], *cp, *dm = NULL;
460 memset(tmp, 0, sizeof(tmp));
462 if(message_len > sizeof(tmp) - 1) {
463 dm = silc_calloc(message_len + 1, sizeof(*dm));
466 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
468 if (flags & SILC_MESSAGE_FLAG_SIGNED)
469 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
470 nick->host, channel->channel_name, verified);
472 signal_emit("message silc action", 5, server, cp, nick->nick,
473 nick->host, channel->channel_name);
476 if (flags & SILC_MESSAGE_FLAG_SIGNED)
477 signal_emit("message silc signed_action", 6, server, message,
478 nick->nick, nick->host, channel->channel_name, verified);
480 signal_emit("message silc action", 5, server, message,
481 nick->nick, nick->host, channel->channel_name);
483 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
484 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
485 char tmp[256], *cp, *dm = NULL;
486 memset(tmp, 0, sizeof(tmp));
488 if(message_len > sizeof(tmp) - 1) {
489 dm = silc_calloc(message_len + 1, sizeof(*dm));
492 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
494 if (flags & SILC_MESSAGE_FLAG_SIGNED)
495 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
496 nick->host, channel->channel_name, verified);
498 signal_emit("message silc notice", 5, server, cp, nick->nick,
499 nick->host, channel->channel_name);
502 if (flags & SILC_MESSAGE_FLAG_SIGNED)
503 signal_emit("message silc signed_notice", 6, server, message,
504 nick->nick, nick->host, channel->channel_name, verified);
506 signal_emit("message silc notice", 5, server, message,
507 nick->nick, nick->host, channel->channel_name);
510 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
511 char tmp[256], *cp, *dm = NULL;
513 memset(tmp, 0, sizeof(tmp));
515 if (message_len > sizeof(tmp) - 1) {
516 dm = silc_calloc(message_len + 1, sizeof(*dm));
520 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
522 if (flags & SILC_MESSAGE_FLAG_SIGNED)
523 signal_emit("message signed_public", 6, server, cp,
524 nick == NULL ? "[<unknown>]" : nick->nick,
525 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
526 chanrec->name, verified);
528 signal_emit("message public", 6, server, cp,
529 nick == NULL ? "[<unknown>]" : nick->nick,
530 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
531 chanrec->name, nick);
536 if (flags & SILC_MESSAGE_FLAG_SIGNED)
537 signal_emit("message signed_public", 6, server, message,
538 nick == NULL ? "[<unknown>]" : nick->nick,
539 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
540 chanrec->name, verified);
542 signal_emit("message public", 6, server, message,
543 nick == NULL ? "[<unknown>]" : nick->nick,
544 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
545 chanrec->name, nick);
549 /* Private message to the client. The `sender' is the nickname of the
550 sender received in the packet. */
552 void silc_private_message(SilcClient client, SilcClientConnection conn,
553 SilcClientEntry sender, SilcMessagePayload payload,
554 SilcMessageFlags flags,
555 const unsigned char *message,
556 SilcUInt32 message_len)
558 SILC_SERVER_REC *server;
562 SILC_LOG_DEBUG(("Start"));
564 server = conn == NULL ? NULL : conn->context;
565 memset(userhost, 0, sizeof(userhost));
566 if (sender->username[0])
567 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
568 sender->username, sender->hostname);
570 /* If the messages is digitally signed, verify it, if possible. */
571 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
572 if (!settings_get_bool("ignore_message_signatures")) {
573 verified = verify_message_signature(sender, payload);
575 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
579 if (flags & SILC_MESSAGE_FLAG_DATA) {
580 silc_emit_mime_sig(server,
581 sender->nickname[0] ?
582 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
584 message, message_len,
585 sender->nickname[0] ? sender->nickname : "[<unknown>]",
586 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
593 if (flags & SILC_MESSAGE_FLAG_ACTION)
594 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
595 char tmp[256], *cp, *dm = NULL;
596 memset(tmp, 0, sizeof(tmp));
598 if(message_len > sizeof(tmp) - 1) {
599 dm = silc_calloc(message_len + 1, sizeof(*dm));
602 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
604 if (flags & SILC_MESSAGE_FLAG_SIGNED)
605 signal_emit("message silc signed_private_action", 6, server, cp,
606 sender->nickname[0] ? sender->nickname : "[<unknown>]",
607 sender->username[0] ? userhost : NULL,
610 signal_emit("message silc private_action", 5, server, cp,
611 sender->nickname[0] ? sender->nickname : "[<unknown>]",
612 sender->username[0] ? userhost : NULL, NULL);
615 if (flags & SILC_MESSAGE_FLAG_SIGNED)
616 signal_emit("message silc signed_private_action", 6, server, message,
617 sender->nickname[0] ? sender->nickname : "[<unknown>]",
618 sender->username[0] ? userhost : NULL,
621 signal_emit("message silc private_action", 5, server, message,
622 sender->nickname[0] ? sender->nickname : "[<unknown>]",
623 sender->username[0] ? userhost : NULL, NULL);
625 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
626 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
627 char tmp[256], *cp, *dm = NULL;
628 memset(tmp, 0, sizeof(tmp));
630 if(message_len > sizeof(tmp) - 1) {
631 dm = silc_calloc(message_len + 1, sizeof(*dm));
634 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
636 if (flags & SILC_MESSAGE_FLAG_SIGNED)
637 signal_emit("message silc signed_private_notice", 6, server, cp,
638 sender->nickname[0] ? sender->nickname : "[<unknown>]",
639 sender->username[0] ? userhost : NULL,
642 signal_emit("message silc private_notice", 5, server, cp,
643 sender->nickname[0] ? sender->nickname : "[<unknown>]",
644 sender->username[0] ? userhost : NULL, NULL);
647 if (flags & SILC_MESSAGE_FLAG_SIGNED)
648 signal_emit("message silc signed_private_notice", 6, server, message,
649 sender->nickname[0] ? sender->nickname : "[<unknown>]",
650 sender->username[0] ? userhost : NULL,
653 signal_emit("message silc private_notice", 5, server, message,
654 sender->nickname[0] ? sender->nickname : "[<unknown>]",
655 sender->username[0] ? userhost : NULL, NULL);
658 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
659 char tmp[256], *cp, *dm = NULL;
661 memset(tmp, 0, sizeof(tmp));
663 if (message_len > sizeof(tmp) - 1) {
664 dm = silc_calloc(message_len + 1, sizeof(*dm));
668 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
670 if (flags & SILC_MESSAGE_FLAG_SIGNED)
671 signal_emit("message signed_private", 5, server, cp,
672 sender->nickname[0] ? sender->nickname : "[<unknown>]",
673 sender->username[0] ? userhost : NULL, verified);
675 signal_emit("message private", 4, server, cp,
676 sender->nickname[0] ? sender->nickname : "[<unknown>]",
677 sender->username[0] ? userhost : NULL);
682 if (flags & SILC_MESSAGE_FLAG_SIGNED)
683 signal_emit("message signed_private", 5, server, message,
684 sender->nickname[0] ? sender->nickname : "[<unknown>]",
685 sender->username[0] ? userhost : NULL, verified);
687 signal_emit("message private", 4, server, message,
688 sender->nickname[0] ? sender->nickname : "[<unknown>]",
689 sender->username[0] ? userhost : NULL);
693 /* Notify message to the client. The notify arguments are sent in the
694 same order as servers sends them. The arguments are same as received
695 from the server except for ID's. If ID is received application receives
696 the corresponding entry to the ID. For example, if Client ID is received
697 application receives SilcClientEntry. Also, if the notify type is
698 for channel the channel entry is sent to application (even if server
699 does not send it). */
701 void silc_notify(SilcClient client, SilcClientConnection conn,
702 SilcNotifyType type, ...)
705 SILC_SERVER_REC *server;
706 SILC_CHANNEL_REC *chanrec;
707 SILC_NICK_REC *nickrec;
708 SilcClientEntry client_entry, client_entry2;
709 SilcChannelEntry channel, channel2;
710 SilcServerEntry server_entry;
715 char *name, *tmp, *cipher, *hmac;
716 GSList *list1, *list_tmp;
717 SilcDList chpks, clients;
719 SILC_LOG_DEBUG(("Start"));
723 server = conn == NULL ? NULL : conn->context;
726 case SILC_NOTIFY_TYPE_NONE:
727 /* Some generic notice from server */
728 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
731 case SILC_NOTIFY_TYPE_INVITE:
733 * Invited or modified invite list.
736 SILC_LOG_DEBUG(("Notify: INVITE"));
738 channel = va_arg(va, SilcChannelEntry);
739 name = va_arg(va, char *);
740 client_entry = va_arg(va, SilcClientEntry);
742 silc_snprintf(buf, sizeof(buf) - 1, "%s@%s",
743 client_entry->username, client_entry->hostname);
744 signal_emit("message invite", 4, server, name,
745 client_entry->nickname, buf);
748 case SILC_NOTIFY_TYPE_JOIN:
753 SILC_LOG_DEBUG(("Notify: JOIN"));
755 client_entry = va_arg(va, SilcClientEntry);
756 channel = va_arg(va, SilcChannelEntry);
758 if (client_entry == server->conn->local_entry) {
759 /* You joined to channel */
760 chanrec = silc_channel_find(server, channel->channel_name);
762 chanrec = silc_channel_create(server, channel->channel_name,
763 channel->channel_name, TRUE);
764 if (!chanrec->joined)
765 chanrec->entry = channel;
767 chanrec = silc_channel_find_entry(server, channel);
768 if (chanrec != NULL) {
769 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
771 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
775 memset(buf, 0, sizeof(buf));
776 if (client_entry->username[0])
777 snprintf(buf, sizeof(buf) - 1, "%s@%s",
778 client_entry->username, client_entry->hostname);
779 signal_emit("message join", 4, server, channel->channel_name,
780 client_entry->nickname,
781 !client_entry->username[0] ? "" : buf);
783 /* If there are multiple same nicknames on channel now, tell it to user. */
784 if (client_entry != server->conn->local_entry) {
788 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
789 clients = silc_client_get_clients_local(client, conn, nick, TRUE);
790 if (!clients || silc_dlist_count(clients) < 2) {
792 silc_client_list_free(client, conn, clients);
795 silc_dlist_start(clients);
796 while ((client_entry2 = silc_dlist_get(clients)))
797 if (silc_client_on_channel(channel, client_entry2))
800 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
801 printformat_module("fe-common/silc", server, channel->channel_name,
802 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
804 printformat_module("fe-common/silc", server, channel->channel_name,
805 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
806 buf, client_entry->nickname);
808 silc_client_list_free(client, conn, clients);
813 case SILC_NOTIFY_TYPE_LEAVE:
818 SILC_LOG_DEBUG(("Notify: LEAVE"));
820 client_entry = va_arg(va, SilcClientEntry);
821 channel = va_arg(va, SilcChannelEntry);
823 memset(buf, 0, sizeof(buf));
824 if (client_entry->username)
825 snprintf(buf, sizeof(buf) - 1, "%s@%s",
826 client_entry->username, client_entry->hostname);
827 signal_emit("message part", 5, server, channel->channel_name,
828 client_entry->nickname, client_entry->username[0] ?
829 buf : "", client_entry->nickname);
831 chanrec = silc_channel_find_entry(server, channel);
832 if (chanrec != NULL) {
833 nickrec = silc_nicklist_find(chanrec, client_entry);
835 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
838 /* If there is only one client with this same nickname on channel now
839 change it to the base format if it is formatted nickname. */
841 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
842 clients = silc_client_get_clients_local(client, conn, name, TRUE);
843 if (!clients || silc_dlist_count(clients) != 2) {
845 silc_client_list_free(client, conn, clients);
848 silc_dlist_start(clients);
849 client_entry2 = silc_dlist_get(clients);
850 if (client_entry2 == client_entry)
851 client_entry2 = silc_dlist_get(clients);
852 if (silc_client_on_channel(channel, client_entry2)) {
853 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
854 silc_client_nickname_format(client, conn, client_entry2, TRUE);
855 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
856 nicklist_rename_unique(SERVER(server), client_entry2, buf,
857 client_entry2, client_entry2->nickname);
858 printformat_module("fe-common/silc", server, channel->channel_name,
859 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
860 buf, client_entry2->nickname);
863 silc_client_list_free(client, conn, clients);
868 case SILC_NOTIFY_TYPE_SIGNOFF:
873 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
875 client_entry = va_arg(va, SilcClientEntry);
876 tmp = va_arg(va, char *);
877 channel = va_arg(va, SilcChannelEntry);
879 silc_server_free_ftp(server, client_entry);
881 memset(buf, 0, sizeof(buf));
882 if (client_entry->username)
883 snprintf(buf, sizeof(buf) - 1, "%s@%s",
884 client_entry->username, client_entry->hostname);
885 signal_emit("message quit", 4, server, client_entry->nickname,
886 client_entry->username[0] ? buf : "", tmp ? tmp : "");
888 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
889 for (list_tmp = list1; list_tmp != NULL; list_tmp =
890 list_tmp->next->next) {
891 CHANNEL_REC *channel = list_tmp->data;
892 NICK_REC *nickrec = list_tmp->next->data;
894 nicklist_remove(channel, nickrec);
897 /* If there is only one client with this same nickname on channel now
898 change it to the base format if it is formatted nickname. */
900 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
901 clients = silc_client_get_clients_local(client, conn, name, TRUE);
902 if (!clients || silc_dlist_count(clients) != 2) {
904 silc_client_list_free(client, conn, clients);
907 silc_dlist_start(clients);
908 client_entry2 = silc_dlist_get(clients);
909 if (client_entry2 == client_entry)
910 client_entry2 = silc_dlist_get(clients);
911 if (silc_client_on_channel(channel, client_entry2)) {
912 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
913 silc_client_nickname_format(client, conn, client_entry2, TRUE);
914 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
915 nicklist_rename_unique(SERVER(server), client_entry2, buf,
916 client_entry2, client_entry2->nickname);
917 printformat_module("fe-common/silc", server, channel->channel_name,
918 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
919 buf, client_entry2->nickname);
922 silc_client_list_free(client, conn, clients);
927 case SILC_NOTIFY_TYPE_TOPIC_SET:
932 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
934 idtype = va_arg(va, int);
935 entry = va_arg(va, void *);
936 tmp = va_arg(va, char *);
937 channel = va_arg(va, SilcChannelEntry);
939 chanrec = silc_channel_find_entry(server, channel);
940 if (chanrec != NULL) {
941 char tmp2[256], *cp, *dm = NULL;
943 g_free_not_null(chanrec->topic);
944 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
945 memset(tmp2, 0, sizeof(tmp2));
947 if (strlen(tmp) > sizeof(tmp2) - 1) {
948 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
952 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
957 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
958 signal_emit("channel topic changed", 1, chanrec);
963 if (idtype == SILC_ID_CLIENT) {
964 client_entry = (SilcClientEntry)entry;
965 memset(buf, 0, sizeof(buf));
966 snprintf(buf, sizeof(buf) - 1, "%s@%s",
967 client_entry->username, client_entry->hostname);
968 signal_emit("message topic", 5, server, channel->channel_name,
969 tmp, client_entry->nickname, buf);
970 } else if (idtype == SILC_ID_SERVER) {
971 server_entry = (SilcServerEntry)entry;
972 signal_emit("message topic", 5, server, channel->channel_name,
973 tmp, server_entry->server_name,
974 server_entry->server_name);
975 } else if (idtype == SILC_ID_CHANNEL) {
976 channel = (SilcChannelEntry)entry;
977 signal_emit("message topic", 5, server, channel->channel_name,
978 tmp, channel->channel_name, channel->channel_name);
982 case SILC_NOTIFY_TYPE_NICK_CHANGE:
987 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
989 client_entry = va_arg(va, SilcClientEntry);
990 name = va_arg(va, char *); /* old nickname */
992 if (!strcmp(client_entry->nickname, name))
995 memset(buf, 0, sizeof(buf));
996 snprintf(buf, sizeof(buf) - 1, "%s@%s",
997 client_entry->username, client_entry->hostname);
998 nicklist_rename_unique(SERVER(server),
1000 client_entry, client_entry->nickname);
1001 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
1004 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
1006 * Changed channel mode.
1009 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
1011 idtype = va_arg(va, int);
1012 entry = va_arg(va, void *);
1013 mode = va_arg(va, SilcUInt32);
1014 cipher = va_arg(va, char *); /* cipher */
1015 hmac = va_arg(va, char *); /* hmac */
1016 (void)va_arg(va, char *); /* passphrase */
1017 (void)va_arg(va, SilcPublicKey); /* founder key */
1018 chpks = va_arg(va, SilcDList); /* channel public keys */
1019 channel = va_arg(va, SilcChannelEntry);
1021 tmp = silc_client_chmode(mode, cipher ? cipher : "",
1024 chanrec = silc_channel_find_entry(server, channel);
1025 if (chanrec != NULL) {
1026 g_free_not_null(chanrec->mode);
1027 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
1028 signal_emit("channel mode changed", 1, chanrec);
1031 if (idtype == SILC_ID_CLIENT) {
1032 client_entry = (SilcClientEntry)entry;
1033 printformat_module("fe-common/silc", server, channel->channel_name,
1034 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1035 channel->channel_name, tmp ? tmp : "removed all",
1036 client_entry->nickname);
1037 } else if (idtype == SILC_ID_SERVER) {
1038 server_entry = (SilcServerEntry)entry;
1039 printformat_module("fe-common/silc", server, channel->channel_name,
1040 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1041 channel->channel_name, tmp ? tmp : "removed all",
1042 server_entry->server_name);
1043 } else if (idtype == SILC_ID_CHANNEL) {
1044 channel2 = (SilcChannelEntry)entry;
1045 printformat_module("fe-common/silc", server, channel->channel_name,
1046 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1047 channel->channel_name, tmp ? tmp : "removed all",
1048 channel2->channel_name);
1051 /* Print the channel public key list */
1053 silc_parse_channel_public_keys(server, channel, chpks);
1058 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1060 * Changed user's mode on channel.
1063 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1065 idtype = va_arg(va, int);
1066 entry = va_arg(va, void *);
1067 mode = va_arg(va, SilcUInt32);
1068 client_entry2 = va_arg(va, SilcClientEntry);
1069 channel = va_arg(va, SilcChannelEntry);
1071 tmp = silc_client_chumode(mode);
1072 chanrec = silc_channel_find_entry(server, channel);
1073 if (chanrec != NULL) {
1074 SILC_NICK_REC *nick;
1076 if (client_entry2 == server->conn->local_entry)
1077 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1079 nick = silc_nicklist_find(chanrec, client_entry2);
1081 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1082 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1083 signal_emit("nick mode changed", 2, chanrec, nick);
1087 if (idtype == SILC_ID_CLIENT) {
1088 client_entry = (SilcClientEntry)entry;
1089 printformat_module("fe-common/silc", server, channel->channel_name,
1090 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1091 channel->channel_name, client_entry2->nickname,
1092 tmp ? tmp : "removed all",
1093 client_entry->nickname);
1094 } else if (idtype == SILC_ID_SERVER) {
1095 server_entry = (SilcServerEntry)entry;
1096 printformat_module("fe-common/silc", server, channel->channel_name,
1097 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1098 channel->channel_name, client_entry2->nickname,
1099 tmp ? tmp : "removed all",
1100 server_entry->server_name);
1101 } else if (idtype == SILC_ID_CHANNEL) {
1102 channel2 = (SilcChannelEntry)entry;
1103 printformat_module("fe-common/silc", server, channel->channel_name,
1104 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1105 channel->channel_name, client_entry2->nickname,
1106 tmp ? tmp : "removed all",
1107 channel2->channel_name);
1110 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1111 printformat_module("fe-common/silc",
1112 server, channel->channel_name, MSGLEVEL_CRAP,
1113 SILCTXT_CHANNEL_FOUNDER,
1114 channel->channel_name, client_entry2->nickname);
1116 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1117 printformat_module("fe-common/silc",
1118 server, channel->channel_name, MSGLEVEL_CRAP,
1119 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1124 case SILC_NOTIFY_TYPE_MOTD:
1129 SILC_LOG_DEBUG(("Notify: MOTD"));
1131 tmp = va_arg(va, char *);
1133 if (!settings_get_bool("skip_motd"))
1134 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1137 case SILC_NOTIFY_TYPE_KICKED:
1139 * Someone was kicked from channel.
1142 SILC_LOG_DEBUG(("Notify: KICKED"));
1144 client_entry = va_arg(va, SilcClientEntry);
1145 tmp = va_arg(va, char *);
1146 client_entry2 = va_arg(va, SilcClientEntry);
1147 channel = va_arg(va, SilcChannelEntry);
1149 chanrec = silc_channel_find_entry(server, channel);
1151 if (client_entry == conn->local_entry) {
1152 printformat_module("fe-common/silc", server, channel->channel_name,
1153 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1154 channel->channel_name,
1155 client_entry ? client_entry2->nickname : "",
1158 chanrec->kicked = TRUE;
1159 channel_destroy((CHANNEL_REC *)chanrec);
1162 printformat_module("fe-common/silc", server, channel->channel_name,
1163 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1164 client_entry->nickname, channel->channel_name,
1165 client_entry2 ? client_entry2->nickname : "",
1169 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1170 if (nickrec != NULL)
1171 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1176 case SILC_NOTIFY_TYPE_KILLED:
1178 * Someone was killed from the network.
1181 SILC_LOG_DEBUG(("Notify: KILLED"));
1183 client_entry = va_arg(va, SilcClientEntry);
1184 tmp = va_arg(va, char *);
1185 idtype = va_arg(va, int);
1186 entry = va_arg(va, SilcClientEntry);
1188 if (client_entry == conn->local_entry) {
1189 if (idtype == SILC_ID_CLIENT) {
1190 client_entry2 = (SilcClientEntry)entry;
1191 printformat_module("fe-common/silc", server, NULL,
1192 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1193 client_entry2 ? client_entry2->nickname : "",
1195 } else if (idtype == SILC_ID_SERVER) {
1196 server_entry = (SilcServerEntry)entry;
1197 printformat_module("fe-common/silc", server, NULL,
1198 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1199 server_entry->server_name, tmp ? tmp : "");
1200 } else if (idtype == SILC_ID_CHANNEL) {
1201 channel = (SilcChannelEntry)entry;
1202 printformat_module("fe-common/silc", server, NULL,
1203 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1204 channel->channel_name, tmp ? tmp : "");
1207 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1208 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1209 list_tmp->next->next) {
1210 CHANNEL_REC *channel = list_tmp->data;
1211 NICK_REC *nickrec = list_tmp->next->data;
1212 nicklist_remove(channel, nickrec);
1215 if (idtype == SILC_ID_CLIENT) {
1216 client_entry2 = (SilcClientEntry)entry;
1217 printformat_module("fe-common/silc", server, NULL,
1218 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1219 client_entry->nickname,
1220 client_entry2 ? client_entry2->nickname : "",
1222 } else if (idtype == SILC_ID_SERVER) {
1223 server_entry = (SilcServerEntry)entry;
1224 printformat_module("fe-common/silc", server, NULL,
1225 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1226 client_entry->nickname,
1227 server_entry->server_name, tmp ? tmp : "");
1228 } else if (idtype == SILC_ID_CHANNEL) {
1229 channel = (SilcChannelEntry)entry;
1230 printformat_module("fe-common/silc", server, NULL,
1231 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1232 client_entry->nickname,
1233 channel->channel_name, tmp ? tmp : "");
1238 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1241 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1244 * Server has quit the network.
1248 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1250 (void)va_arg(va, void *);
1251 clients = va_arg(va, SilcDList);
1253 silc_dlist_start(clients);
1254 while ((client_entry = silc_dlist_get(clients))) {
1255 memset(buf, 0, sizeof(buf));
1257 /* Print only if we have the nickname. If this client has just quit
1258 when we were only resolving it, it is possible we don't have the
1260 if (client_entry->nickname[0]) {
1261 if (client_entry->username[0])
1262 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1263 client_entry->username, client_entry->hostname);
1264 signal_emit("message quit", 4, server, client_entry->nickname,
1265 client_entry->username[0] ? buf : "",
1269 silc_server_free_ftp(server, client_entry);
1271 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1272 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1273 list_tmp->next->next) {
1274 CHANNEL_REC *channel = list_tmp->data;
1275 NICK_REC *nickrec = list_tmp->next->data;
1276 nicklist_remove(channel, nickrec);
1282 case SILC_NOTIFY_TYPE_ERROR:
1284 SilcStatus error = va_arg(va, int);
1286 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1287 "%s", silc_get_status_message(error));
1291 case SILC_NOTIFY_TYPE_WATCH:
1293 SilcNotifyType notify;
1295 client_entry = va_arg(va, SilcClientEntry);
1296 name = va_arg(va, char *); /* Maybe NULL */
1297 mode = va_arg(va, SilcUInt32);
1298 notify = va_arg(va, int);
1300 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1302 printformat_module("fe-common/silc", server, NULL,
1303 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1304 client_entry->nickname, name);
1306 printformat_module("fe-common/silc", server, NULL,
1307 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1308 client_entry->nickname);
1309 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1310 /* See if client was away and is now present */
1311 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1312 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1313 SILC_UMODE_DETACHED)) &&
1314 (client_entry->mode & SILC_UMODE_GONE ||
1315 client_entry->mode & SILC_UMODE_INDISPOSED ||
1316 client_entry->mode & SILC_UMODE_BUSY ||
1317 client_entry->mode & SILC_UMODE_PAGE ||
1318 client_entry->mode & SILC_UMODE_DETACHED)) {
1319 printformat_module("fe-common/silc", server, NULL,
1320 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1321 client_entry->nickname);
1325 memset(buf, 0, sizeof(buf));
1326 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1327 printformat_module("fe-common/silc", server, NULL,
1328 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1329 client_entry->nickname, buf);
1331 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1332 printformat_module("fe-common/silc", server, NULL,
1333 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1334 client_entry->nickname);
1335 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1336 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1337 printformat_module("fe-common/silc", server, NULL,
1338 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1339 client_entry->nickname);
1340 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1341 /* Client logged in to the network */
1342 printformat_module("fe-common/silc", server, NULL,
1343 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1344 client_entry->nickname);
1350 /* Unknown notify */
1351 printformat_module("fe-common/silc", server, NULL,
1352 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1359 /* Command handler. This function is called always in the command function.
1360 If error occurs it will be called as well. `conn' is the associated
1361 client connection. `cmd_context' is the command context that was
1362 originally sent to the command. `success' is FALSE if error occured
1363 during command. `command' is the command being processed. It must be
1364 noted that this is not reply from server. This is merely called just
1365 after application has called the command. Just to tell application
1366 that the command really was processed. */
1368 static SilcBool cmode_list_chpks = FALSE;
1370 void silc_command(SilcClient client, SilcClientConnection conn,
1371 SilcBool success, SilcCommand command, SilcStatus status,
1372 SilcUInt32 argc, unsigned char **argv)
1374 SILC_SERVER_REC *server = conn->context;
1376 SILC_LOG_DEBUG(("Start"));
1379 silc_say_error("%s", silc_get_status_message(status));
1385 case SILC_COMMAND_INVITE:
1387 printformat_module("fe-common/silc", server, NULL,
1388 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1390 (argv[1][0] == '*' ?
1391 (char *)conn->current_channel->channel_name :
1395 case SILC_COMMAND_DETACH:
1396 server->no_reconnect = TRUE;
1399 case SILC_COMMAND_CMODE:
1400 if (argc == 3 && !strcmp(argv[2], "+C"))
1401 cmode_list_chpks = TRUE;
1403 cmode_list_chpks = FALSE;
1413 SilcClientConnection conn;
1418 void silc_getkey_cb(bool success, void *context)
1420 GetkeyContext getkey = (GetkeyContext)context;
1421 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1422 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1423 ((SilcClientEntry)getkey->entry)->nickname :
1424 ((SilcServerEntry)getkey->entry)->server_name);
1425 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1426 ((SilcClientEntry)getkey->entry)->public_key :
1427 ((SilcServerEntry)getkey->entry)->public_key);
1428 SilcSILCPublicKey silc_pubkey;
1430 silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
1433 if (getkey->id_type == SILC_ID_CLIENT)
1434 printformat_module("fe-common/silc", NULL, NULL,
1435 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1437 silc_pubkey->identifier.realname ?
1438 silc_pubkey->identifier.realname : "",
1439 silc_pubkey->identifier.email ?
1440 silc_pubkey->identifier.email : "");
1442 printformat_module("fe-common/silc", NULL, NULL,
1443 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1446 printformat_module("fe-common/silc", NULL, NULL,
1447 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1454 /* Parse an invite or ban list */
1455 void silc_parse_inviteban_list(SilcClient client,
1456 SilcClientConnection conn,
1457 SILC_SERVER_REC *server,
1458 SilcChannelEntry channel,
1459 const char *list_type,
1460 SilcArgumentPayload list)
1463 SilcUInt32 type, len;
1464 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1465 int counter=0, resolving = FALSE;
1467 if (!silc_argument_get_arg_num(list)) {
1468 printformat_module("fe-common/silc", server,
1469 (chanrec ? chanrec->visible_name : NULL),
1470 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1471 channel->channel_name, list_type);
1475 printformat_module("fe-common/silc", server,
1476 (chanrec ? chanrec->visible_name : NULL),
1477 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1478 channel->channel_name, list_type);
1480 /* Parse the list */
1481 tmp = silc_argument_get_first_arg(list, &type, &len);
1486 /* An invite string */
1490 if (tmp[len-1] == ',')
1493 list = g_strsplit(tmp, ",", -1);
1495 printformat_module("fe-common/silc", server,
1496 (chanrec ? chanrec->visible_name : NULL),
1497 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1498 ++counter, channel->channel_name, list_type,
1507 char *fingerprint, *babbleprint;
1509 /* tmp is Public Key Payload, take public key from it. */
1510 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1511 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1513 printformat_module("fe-common/silc", server,
1514 (chanrec ? chanrec->visible_name : NULL),
1515 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1516 ++counter, channel->channel_name, list_type,
1517 fingerprint, babbleprint);
1524 SilcClientEntry client_entry;
1527 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1528 silc_say_error("Invalid data in %s list encountered", list_type);
1532 client_entry = silc_client_get_client_by_id(client, conn,
1535 printformat_module("fe-common/silc", server,
1536 (chanrec ? chanrec->visible_name : NULL),
1537 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1538 ++counter, channel->channel_name, list_type,
1539 client_entry->nickname);
1540 silc_client_unref_client(client, conn, client_entry);
1543 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1551 silc_say_error("Unkown type in %s list: %u (len %u)",
1552 list_type, type, len);
1555 tmp = silc_argument_get_next_arg(list, &type, &len);
1559 printformat_module("fe-common/silc", server,
1560 (chanrec ? chanrec->visible_name : NULL),
1561 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1562 list_type, channel->channel_name);
1565 /* Command reply handler. This function is called always in the command reply
1566 function. If error occurs it will be called as well. Normal scenario
1567 is that it will be called after the received command data has been parsed
1568 and processed. The function is used to pass the received command data to
1571 `conn' is the associated client connection. `cmd_payload' is the command
1572 payload data received from server and it can be ignored. It is provided
1573 if the application would like to re-parse the received command data,
1574 however, it must be noted that the data is parsed already by the library
1575 thus the payload can be ignored. `success' is FALSE if error occured.
1576 In this case arguments are not sent to the application. `command' is the
1577 command reply being processed. The function has variable argument list
1578 and each command defines the number and type of arguments it passes to the
1579 application (on error they are not sent). */
1581 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1582 SilcCommand command, SilcStatus status,
1583 SilcStatus error, va_list vp)
1585 SILC_SERVER_REC *server = conn->context;
1586 SILC_CHANNEL_REC *chanrec;
1588 SILC_LOG_DEBUG(("Start"));
1591 case SILC_COMMAND_WHOIS:
1593 char buf[1024], *nickname, *username, *realname, *nick;
1594 unsigned char *fingerprint;
1595 SilcUInt32 idle, mode, *user_modes;
1597 SilcClientEntry client_entry;
1600 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1601 /* Print the unknown nick for user */
1602 char *tmp = va_arg(vp, char *);
1604 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1606 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1607 /* Try to find the entry for the unknown client ID, since we
1608 might have, and print the nickname of it for user. */
1609 SilcClientID *id = va_arg(vp, SilcClientID *);
1611 client_entry = silc_client_get_client_by_id(client, conn, id);
1612 if (client_entry && client_entry->nickname[0])
1613 silc_say_error("%s: %s", client_entry->nickname,
1614 silc_get_status_message(status));
1615 silc_client_unref_client(client, conn, client_entry);
1618 } else if (SILC_STATUS_IS_ERROR(status)) {
1619 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1623 client_entry = va_arg(vp, SilcClientEntry);
1624 nickname = va_arg(vp, char *);
1625 username = va_arg(vp, char *);
1626 realname = va_arg(vp, char *);
1627 channels = va_arg(vp, SilcDList);
1628 mode = va_arg(vp, SilcUInt32);
1629 idle = va_arg(vp, SilcUInt32);
1630 fingerprint = va_arg(vp, unsigned char *);
1631 user_modes = va_arg(vp, SilcUInt32 *);
1632 attrs = va_arg(vp, SilcDList);
1634 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1635 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1636 SILCTXT_WHOIS_USERINFO, nickname,
1637 client_entry->username, client_entry->hostname,
1638 nick, client_entry->nickname);
1639 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1640 SILCTXT_WHOIS_REALNAME, realname);
1643 if (channels && user_modes) {
1644 SilcChannelPayload entry;
1647 memset(buf, 0, sizeof(buf));
1648 silc_dlist_start(channels);
1649 while ((entry = silc_dlist_get(channels))) {
1650 SilcUInt32 name_len;
1651 char *m = silc_client_chumode_char(user_modes[i++]);
1652 char *name = silc_channel_get_name(entry, &name_len);
1655 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1656 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1657 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1661 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1662 SILCTXT_WHOIS_CHANNELS, buf);
1666 memset(buf, 0, sizeof(buf));
1667 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1668 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1669 SILCTXT_WHOIS_MODES, buf);
1672 if (idle && nickname) {
1673 memset(buf, 0, sizeof(buf));
1674 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1675 idle > 60 ? (idle / 60) : idle,
1676 idle > 60 ? "minutes" : "seconds");
1678 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1679 SILCTXT_WHOIS_IDLE, buf);
1683 fingerprint = silc_fingerprint(fingerprint, 20);
1684 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1685 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1686 silc_free(fingerprint);
1690 silc_query_attributes_print(server, silc_client, conn, attrs,
1695 case SILC_COMMAND_WHOWAS:
1697 char *nickname, *username, *realname;
1699 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1700 char *tmp = va_arg(vp, char *);
1702 silc_say_error("%s: %s", tmp,
1703 silc_get_status_message(status));
1705 } else if (SILC_STATUS_IS_ERROR(status)) {
1706 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1710 (void)va_arg(vp, SilcClientEntry);
1711 nickname = va_arg(vp, char *);
1712 username = va_arg(vp, char *);
1713 realname = va_arg(vp, char *);
1715 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1716 SILCTXT_WHOWAS_USERINFO, nickname, username,
1717 realname ? realname : "");
1721 case SILC_COMMAND_INVITE:
1723 SilcChannelEntry channel;
1724 SilcArgumentPayload invite_list;
1726 if (SILC_STATUS_IS_ERROR(status))
1729 channel = va_arg(vp, SilcChannelEntry);
1730 invite_list = va_arg(vp, SilcArgumentPayload);
1733 silc_parse_inviteban_list(client, conn, server, channel,
1734 "invite", invite_list);
1738 case SILC_COMMAND_JOIN:
1740 char *channel, *mode, *topic, *cipher, *hmac;
1742 SilcHashTableList *user_list;
1743 SilcChannelEntry channel_entry;
1744 SilcChannelUser chu;
1745 SilcClientEntry founder = NULL;
1748 if (SILC_STATUS_IS_ERROR(status)) {
1749 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
1750 char *tmp = va_arg(vp, char *);
1752 silc_say_error("JOIN: %s: %s", tmp,
1753 silc_get_status_message(status));
1756 if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
1757 char *tmp = va_arg(vp, char *);
1759 silc_say_error("JOIN: %s: %s", tmp,
1760 silc_get_status_message(status));
1763 silc_say_error("JOIN: %s", silc_get_status_message(status));
1767 channel = va_arg(vp, char *);
1768 channel_entry = va_arg(vp, SilcChannelEntry);
1769 modei = va_arg(vp, SilcUInt32);
1770 user_list = va_arg(vp, SilcHashTableList *);
1771 topic = va_arg(vp, char *);
1772 cipher = va_arg(vp, char *);
1773 hmac = va_arg(vp, char *);
1775 chanrec = silc_channel_find(server, channel);
1777 chanrec = silc_channel_create(server, channel, channel, TRUE);
1780 char tmp[256], *cp, *dm = NULL;
1781 g_free_not_null(chanrec->topic);
1783 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1784 memset(tmp, 0, sizeof(tmp));
1786 if (strlen(topic) > sizeof(tmp) - 1) {
1787 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1791 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1796 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1797 signal_emit("channel topic changed", 1, chanrec);
1802 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1803 g_free_not_null(chanrec->mode);
1804 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1805 signal_emit("channel mode changed", 1, chanrec);
1808 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1809 if (!chu->client->nickname[0])
1811 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1812 founder = chu->client;
1813 silc_nicklist_insert(chanrec, chu, FALSE);
1816 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1819 nicklist_set_own(CHANNEL(chanrec), ownnick);
1820 signal_emit("channel joined", 1, chanrec);
1821 chanrec->entry = channel_entry;
1824 printformat_module("fe-common/silc", server,
1825 channel_entry->channel_name,
1826 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1827 channel_entry->channel_name, chanrec->topic);
1830 if (founder == conn->local_entry) {
1831 printformat_module("fe-common/silc",
1832 server, channel_entry->channel_name,
1833 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1834 channel_entry->channel_name);
1835 signal_emit("nick mode changed", 2, chanrec, ownnick);
1837 printformat_module("fe-common/silc",
1838 server, channel_entry->channel_name,
1839 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1840 channel_entry->channel_name, founder->nickname);
1846 case SILC_COMMAND_NICK:
1849 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1852 if (SILC_STATUS_IS_ERROR(status)) {
1853 silc_say_error("NICK: %s", silc_get_status_message(status));
1857 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1858 if ((nicks != NULL) &&
1859 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1861 SilcClientEntry collider, old;
1863 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1864 collider = silc_client_get_client_by_id(client, conn, &old->id);
1865 if (collider != client_entry) {
1866 memset(buf, 0, sizeof(buf));
1867 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1868 collider->username, collider->hostname);
1869 nicklist_rename_unique(SERVER(server),
1871 collider, collider->nickname);
1872 silc_print_nick_change(server, collider->nickname,
1873 client_entry->nickname, buf);
1875 silc_client_unref_client(client, conn, collider);
1879 g_slist_free(nicks);
1881 old = g_strdup(server->nick);
1882 server_change_nick(SERVER(server), client_entry->nickname);
1883 nicklist_rename_unique(SERVER(server),
1884 server->conn->local_entry, server->nick,
1885 client_entry, client_entry->nickname);
1886 signal_emit("message own_nick", 4, server, server->nick, old, "");
1889 /* when connecting to a server, the last thing we receive
1890 is a SILC_COMMAND_LIST reply. Since we enable queueing
1891 during the connection, we can now safely disable it again */
1892 silc_queue_disable(conn);
1896 case SILC_COMMAND_LIST:
1901 char tmp[256], *cp, *dm = NULL;
1903 if (SILC_STATUS_IS_ERROR(status))
1906 (void)va_arg(vp, SilcChannelEntry);
1907 name = va_arg(vp, char *);
1908 topic = va_arg(vp, char *);
1909 usercount = va_arg(vp, int);
1911 if (topic && !silc_term_utf8() &&
1912 silc_utf8_valid(topic, strlen(topic))) {
1913 memset(tmp, 0, sizeof(tmp));
1915 if (strlen(topic) > sizeof(tmp) - 1) {
1916 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1920 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1925 if (status == SILC_STATUS_LIST_START ||
1926 status == SILC_STATUS_OK)
1927 printformat_module("fe-common/silc", server, NULL,
1928 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1931 snprintf(users, sizeof(users) - 1, "N/A");
1933 snprintf(users, sizeof(users) - 1, "%d", usercount);
1934 printformat_module("fe-common/silc", server, NULL,
1935 MSGLEVEL_CRAP, SILCTXT_LIST,
1936 name, users, topic ? topic : "");
1941 case SILC_COMMAND_UMODE:
1946 if (SILC_STATUS_IS_ERROR(status))
1949 mode = va_arg(vp, SilcUInt32);
1951 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1952 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1953 printformat_module("fe-common/silc", server, NULL,
1954 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1956 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1957 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1958 printformat_module("fe-common/silc", server, NULL,
1959 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1961 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1962 if (mode & SILC_UMODE_GONE) {
1963 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1964 reason = g_strdup(server->away_reason);
1966 reason = g_strdup("away");
1968 reason = g_strdup("");
1970 silc_set_away(reason, server);
1975 server->umode = mode;
1976 signal_emit("user mode changed", 2, server, NULL);
1980 case SILC_COMMAND_OPER:
1981 if (SILC_STATUS_IS_ERROR(status)) {
1982 silc_say_error("OPER: %s", silc_get_status_message(status));
1986 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1987 signal_emit("user mode changed", 2, server, NULL);
1989 printformat_module("fe-common/silc", server, NULL,
1990 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1993 case SILC_COMMAND_SILCOPER:
1994 if (SILC_STATUS_IS_ERROR(status)) {
1995 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1999 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2000 signal_emit("user mode changed", 2, server, NULL);
2002 printformat_module("fe-common/silc", server, NULL,
2003 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2006 case SILC_COMMAND_USERS:
2008 SilcHashTableList htl;
2009 SilcChannelEntry channel;
2010 SilcChannelUser chu;
2012 if (SILC_STATUS_IS_ERROR(status)) {
2013 silc_say_error("USERS: %s", silc_get_status_message(status));
2017 channel = va_arg(vp, SilcChannelEntry);
2019 printformat_module("fe-common/silc", server, channel->channel_name,
2020 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2021 channel->channel_name);
2023 silc_hash_table_list(channel->user_list, &htl);
2024 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2025 SilcClientEntry e = chu->client;
2026 char stat[5], *mode;
2028 if (!e->nickname[0])
2031 memset(stat, 0, sizeof(stat));
2032 mode = silc_client_chumode_char(chu->mode);
2033 if (e->mode & SILC_UMODE_GONE)
2035 else if (e->mode & SILC_UMODE_INDISPOSED)
2037 else if (e->mode & SILC_UMODE_BUSY)
2039 else if (e->mode & SILC_UMODE_PAGE)
2041 else if (e->mode & SILC_UMODE_HYPER)
2043 else if (e->mode & SILC_UMODE_ROBOT)
2045 else if (e->mode & SILC_UMODE_ANONYMOUS)
2052 printformat_module("fe-common/silc", server, channel->channel_name,
2053 MSGLEVEL_CRAP, SILCTXT_USERS,
2055 e->username[0] ? e->username : "",
2056 e->hostname[0] ? e->hostname : "",
2057 e->realname ? e->realname : "");
2061 silc_hash_table_list_reset(&htl);
2065 case SILC_COMMAND_BAN:
2067 SilcChannelEntry channel;
2068 SilcArgumentPayload invite_list;
2070 if (SILC_STATUS_IS_ERROR(status))
2073 channel = va_arg(vp, SilcChannelEntry);
2074 invite_list = va_arg(vp, SilcArgumentPayload);
2077 silc_parse_inviteban_list(client, conn, server, channel,
2078 "ban", invite_list);
2082 case SILC_COMMAND_GETKEY:
2086 SilcPublicKey public_key;
2087 GetkeyContext getkey;
2090 if (SILC_STATUS_IS_ERROR(status)) {
2091 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2095 id_type = va_arg(vp, SilcUInt32);
2096 entry = va_arg(vp, void *);
2097 public_key = va_arg(vp, SilcPublicKey);
2100 getkey = silc_calloc(1, sizeof(*getkey));
2101 getkey->entry = entry;
2102 getkey->id_type = id_type;
2103 getkey->client = client;
2104 getkey->conn = conn;
2106 name = (id_type == SILC_ID_CLIENT ?
2107 ((SilcClientEntry)entry)->nickname :
2108 ((SilcServerEntry)entry)->server_name);
2110 silc_verify_public_key_internal(client, conn, name,
2111 (id_type == SILC_ID_CLIENT ?
2114 public_key, silc_getkey_cb, getkey);
2116 printformat_module("fe-common/silc", server, NULL,
2117 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2122 case SILC_COMMAND_INFO:
2124 SilcServerEntry server_entry;
2128 if (SILC_STATUS_IS_ERROR(status))
2131 server_entry = va_arg(vp, SilcServerEntry);
2132 server_name = va_arg(vp, char *);
2133 server_info = va_arg(vp, char *);
2135 if (server_name && server_info )
2137 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2138 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2143 case SILC_COMMAND_TOPIC:
2145 SilcChannelEntry channel;
2147 char tmp[256], *cp, *dm = NULL;
2149 if (SILC_STATUS_IS_ERROR(status))
2152 channel = va_arg(vp, SilcChannelEntry);
2153 topic = va_arg(vp, char *);
2155 if (topic && !silc_term_utf8() &&
2156 silc_utf8_valid(topic, strlen(topic))) {
2157 memset(tmp, 0, sizeof(tmp));
2159 if (strlen(topic) > sizeof(tmp) - 1) {
2160 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2164 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2170 chanrec = silc_channel_find_entry(server, channel);
2172 g_free_not_null(chanrec->topic);
2173 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2174 signal_emit("channel topic changed", 1, chanrec);
2176 printformat_module("fe-common/silc", server, channel->channel_name,
2177 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2178 channel->channel_name, topic);
2180 printformat_module("fe-common/silc", server, channel->channel_name,
2181 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2182 channel->channel_name);
2188 case SILC_COMMAND_WATCH:
2191 case SILC_COMMAND_STATS:
2193 SilcClientStats *cstats;
2195 const char *tmptime;
2196 int days, hours, mins, secs;
2198 if (SILC_STATUS_IS_ERROR(status))
2201 cstats = va_arg(vp, SilcClientStats *);
2203 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2207 tmptime = silc_time_string(cstats->starttime);
2208 printformat_module("fe-common/silc", server, NULL,
2209 MSGLEVEL_CRAP, SILCTXT_STATS,
2210 "Local server start time", tmptime);
2212 days = cstats->uptime / (24 * 60 * 60);
2213 cstats->uptime -= days * (24 * 60 * 60);
2214 hours = cstats->uptime / (60 * 60);
2215 cstats->uptime -= hours * (60 * 60);
2216 mins = cstats->uptime / 60;
2217 cstats->uptime -= mins * 60;
2218 secs = cstats->uptime;
2219 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2220 days, hours, mins, secs);
2221 printformat_module("fe-common/silc", server, NULL,
2222 MSGLEVEL_CRAP, SILCTXT_STATS,
2223 "Local server uptime", tmp);
2225 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2226 printformat_module("fe-common/silc", server, NULL,
2227 MSGLEVEL_CRAP, SILCTXT_STATS,
2228 "Local server clients", tmp);
2230 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2231 printformat_module("fe-common/silc", server, NULL,
2232 MSGLEVEL_CRAP, SILCTXT_STATS,
2233 "Local server channels", tmp);
2235 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2236 printformat_module("fe-common/silc", server, NULL,
2237 MSGLEVEL_CRAP, SILCTXT_STATS,
2238 "Local server operators", tmp);
2240 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2241 printformat_module("fe-common/silc", server, NULL,
2242 MSGLEVEL_CRAP, SILCTXT_STATS,
2243 "Local router operators", tmp);
2245 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2246 printformat_module("fe-common/silc", server, NULL,
2247 MSGLEVEL_CRAP, SILCTXT_STATS,
2248 "Local cell clients", tmp);
2250 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2251 printformat_module("fe-common/silc", server, NULL,
2252 MSGLEVEL_CRAP, SILCTXT_STATS,
2253 "Local cell channels", tmp);
2255 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2256 printformat_module("fe-common/silc", server, NULL,
2257 MSGLEVEL_CRAP, SILCTXT_STATS,
2258 "Local cell servers", tmp);
2260 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2261 printformat_module("fe-common/silc", server, NULL,
2262 MSGLEVEL_CRAP, SILCTXT_STATS,
2263 "Total clients", tmp);
2265 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2266 printformat_module("fe-common/silc", server, NULL,
2267 MSGLEVEL_CRAP, SILCTXT_STATS,
2268 "Total channels", tmp);
2270 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2271 printformat_module("fe-common/silc", server, NULL,
2272 MSGLEVEL_CRAP, SILCTXT_STATS,
2273 "Total servers", tmp);
2275 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2276 printformat_module("fe-common/silc", server, NULL,
2277 MSGLEVEL_CRAP, SILCTXT_STATS,
2278 "Total routers", tmp);
2280 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2281 printformat_module("fe-common/silc", server, NULL,
2282 MSGLEVEL_CRAP, SILCTXT_STATS,
2283 "Total server operators", tmp);
2285 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2286 printformat_module("fe-common/silc", server, NULL,
2287 MSGLEVEL_CRAP, SILCTXT_STATS,
2288 "Total router operators", tmp);
2292 case SILC_COMMAND_CMODE:
2294 SilcChannelEntry channel_entry;
2296 SilcPublicKey founder_key;
2298 channel_entry = va_arg(vp, SilcChannelEntry);
2299 (void)va_arg(vp, SilcUInt32);
2300 founder_key = va_arg(vp, SilcPublicKey);
2301 chpks = va_arg(vp, SilcDList);
2303 if (SILC_STATUS_IS_ERROR(status) || !channel_entry ||
2304 !channel_entry->channel_name)
2307 /* If founder was changed successfully, tell it to user */
2308 if (founder_key && channel_entry->founder_key &&
2309 !silc_pkcs_public_key_compare(founder_key,
2310 channel_entry->founder_key)) {
2311 printformat_module("fe-common/silc", server, NULL,
2312 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_CHANGED,
2313 channel_entry->channel_name);
2316 /* Print the channel public key list */
2317 if (cmode_list_chpks) {
2319 silc_parse_channel_public_keys(server, channel_entry, chpks);
2321 printformat_module("fe-common/silc", server, NULL,
2322 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2323 channel_entry->channel_name);
2328 case SILC_COMMAND_LEAVE:
2330 if (SILC_STATUS_IS_ERROR(status))
2333 /* We might be cycling, so disable queueing again */
2334 silc_queue_disable(conn);
2338 case SILC_COMMAND_DETACH:
2340 /* Save the detachment data to file. */
2344 if (SILC_STATUS_IS_ERROR(status))
2347 detach = va_arg(vp, SilcBuffer);
2348 file = silc_get_session_filename(server);
2349 silc_file_writefile(file, silc_buffer_data(detach),
2350 silc_buffer_len(detach));
2355 case SILC_COMMAND_KILL:
2357 SilcClientEntry client_entry;
2359 if (SILC_STATUS_IS_ERROR(status)) {
2360 silc_say_error("KILL: %s", silc_get_status_message(status));
2364 client_entry = va_arg(vp, SilcClientEntry);
2365 if (!client_entry || !client_entry->nickname[0])
2368 /* Print this only if the killed client isn't joined on channels.
2369 If it is, we receive KILLED notify and we'll print this there. */
2370 if (!silc_hash_table_count(client_entry->channels))
2371 printformat_module("fe-common/silc", server, NULL,
2372 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2373 client_entry->nickname,
2374 conn->local_entry->nickname, "");
2381 SilcClientConnection conn;
2385 SilcPublicKey public_key;
2386 SilcVerifyPublicKey completion;
2390 static void verify_public_key_completion(const char *line, void *context)
2392 PublicKeyVerify verify = (PublicKeyVerify)context;
2394 if (line[0] == 'Y' || line[0] == 'y') {
2395 /* Call the completion */
2396 if (verify->completion)
2397 verify->completion(TRUE, verify->context);
2399 /* Save the key for future checking */
2400 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2401 SILC_PKCS_FILE_BASE64);
2403 /* Call the completion */
2404 if (verify->completion)
2405 verify->completion(FALSE, verify->context);
2407 printformat_module("fe-common/silc", NULL, NULL,
2408 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2409 verify->entity_name ? verify->entity_name :
2413 silc_free(verify->filename);
2414 silc_free(verify->entity);
2415 silc_free(verify->entity_name);
2419 /* Internal routine to verify public key. If the `completion' is provided
2420 it will be called to indicate whether public was verified or not. For
2421 server/router public key this will check for filename that includes the
2422 remote host's IP address and remote host's hostname. */
2425 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2427 SilcConnectionType conn_type,
2428 SilcPublicKey public_key,
2429 SilcVerifyPublicKey completion, void *context)
2431 PublicKeyVerify verify;
2432 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2433 char *fingerprint, *babbleprint, *format;
2434 SilcPublicKey local_pubkey;
2435 SilcSILCPublicKey silc_pubkey;
2437 const char *hostname, *ip;
2442 char *entity = ((conn_type == SILC_CONN_SERVER ||
2443 conn_type == SILC_CONN_ROUTER) ?
2444 "server" : "client");
2447 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2448 printformat_module("fe-common/silc", NULL, NULL,
2449 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2450 entity, silc_pkcs_get_type(public_key));
2452 completion(FALSE, context);
2456 /* Encode public key */
2457 pk = silc_pkcs_public_key_encode(NULL, public_key, &pk_len);
2460 completion(FALSE, context);
2464 silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
2466 pw = getpwuid(getuid());
2469 completion(FALSE, context);
2474 memset(filename, 0, sizeof(filename));
2475 memset(filename2, 0, sizeof(filename2));
2476 memset(file, 0, sizeof(file));
2478 /* Get remote host information */
2479 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2480 NULL, &hostname, &ip, &port);
2482 if (conn_type == SILC_CONN_SERVER ||
2483 conn_type == SILC_CONN_ROUTER) {
2485 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2486 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2487 get_irssi_dir(), entity, file);
2489 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2491 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2492 get_irssi_dir(), entity, file);
2497 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2499 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2500 get_irssi_dir(), entity, file);
2505 /* Replace all whitespaces with `_'. */
2506 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2507 for (i = 0; i < strlen(fingerprint); i++)
2508 if (fingerprint[i] == ' ')
2509 fingerprint[i] = '_';
2511 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2512 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2513 get_irssi_dir(), entity, file);
2514 silc_free(fingerprint);
2519 /* Take fingerprint of the public key */
2520 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2521 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2523 verify = silc_calloc(1, sizeof(*verify));
2524 verify->client = client;
2525 verify->conn = conn;
2526 verify->filename = strdup(ipf);
2527 verify->entity = strdup(entity);
2528 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2529 (name ? strdup(name) : strdup(hostname))
2531 verify->public_key = public_key;
2532 verify->completion = completion;
2533 verify->context = context;
2535 /* Check whether this key already exists */
2536 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2537 /* Key does not exist, ask user to verify the key and save it */
2539 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2540 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2541 verify->entity_name : entity);
2542 if (conn_type == SILC_CONN_CLIENT && name &&
2543 silc_pubkey->identifier.realname)
2544 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2545 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2546 silc_pubkey->identifier.realname,
2547 silc_pubkey->identifier.email ?
2548 silc_pubkey->identifier.email : "");
2549 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2550 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2551 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2552 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2553 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2554 SILCTXT_PUBKEY_ACCEPT);
2555 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2558 silc_free(fingerprint);
2559 silc_free(babbleprint);
2563 /* The key already exists, verify it. */
2564 unsigned char *encpk;
2565 SilcUInt32 encpk_len;
2567 /* Load the key file, try for both IP filename and hostname filename */
2568 if (!silc_pkcs_load_public_key(ipf, SILC_PKCS_ANY, &local_pubkey) &&
2569 (!hostf || (!silc_pkcs_load_public_key(hostf, SILC_PKCS_ANY,
2571 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2572 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2573 verify->entity_name : entity);
2574 if (conn_type == SILC_CONN_CLIENT && name &&
2575 silc_pubkey->identifier.realname)
2576 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2577 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2578 silc_pubkey->identifier.realname,
2579 silc_pubkey->identifier.email ?
2580 silc_pubkey->identifier.email : "");
2581 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2582 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2583 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2584 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2585 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2586 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2587 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2588 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2589 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2592 silc_free(fingerprint);
2593 silc_free(babbleprint);
2598 /* Encode the key data */
2599 encpk = silc_pkcs_public_key_encode(NULL, local_pubkey, &encpk_len);
2601 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2602 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2603 verify->entity_name : entity);
2604 if (conn_type == SILC_CONN_CLIENT && name &&
2605 silc_pubkey->identifier.realname)
2606 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2607 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2608 silc_pubkey->identifier.realname,
2609 silc_pubkey->identifier.email ?
2610 silc_pubkey->identifier.email : "");
2611 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2612 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2613 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2614 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2615 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2616 SILCTXT_PUBKEY_MALFORMED, entity);
2617 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2618 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2619 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2622 silc_free(fingerprint);
2623 silc_free(babbleprint);
2627 silc_pkcs_public_key_free(local_pubkey);
2629 /* Compare the keys */
2630 if (memcmp(encpk, pk, encpk_len)) {
2631 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2632 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2633 verify->entity_name : entity);
2634 if (conn_type == SILC_CONN_CLIENT && name &&
2635 silc_pubkey->identifier.realname)
2636 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2637 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2638 silc_pubkey->identifier.realname,
2639 silc_pubkey->identifier.email ?
2640 silc_pubkey->identifier.email : "");
2641 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2642 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2643 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2644 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2645 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2646 SILCTXT_PUBKEY_NO_MATCH, entity);
2647 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2648 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2649 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2650 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2652 /* Ask user to verify the key and save it */
2653 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2654 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2655 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2658 silc_free(fingerprint);
2659 silc_free(babbleprint);
2665 /* Local copy matched */
2667 completion(TRUE, context);
2669 silc_free(fingerprint);
2670 silc_free(babbleprint);
2671 silc_free(verify->filename);
2672 silc_free(verify->entity);
2673 silc_free(verify->entity_name);
2679 /* Verifies received public key. The `conn_type' indicates which entity
2680 (server, client etc.) has sent the public key. If user decides to trust
2681 the key may be saved as trusted public key for later use. The
2682 `completion' must be called after the public key has been verified. */
2685 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2686 SilcConnectionType conn_type,
2687 SilcPublicKey public_key,
2688 SilcVerifyPublicKey completion, void *context)
2690 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2691 completion, context);
2694 /* Asks passphrase from user on the input line. */
2697 SilcAskPassphrase completion;
2701 void ask_passphrase_completion(const char *passphrase, void *context)
2703 AskPassphrase p = (AskPassphrase)context;
2704 if (passphrase && passphrase[0] == '\0')
2706 p->completion((unsigned char *)passphrase,
2707 passphrase ? strlen(passphrase) : 0, p->context);
2711 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2712 SilcAskPassphrase completion, void *context)
2714 AskPassphrase p = silc_calloc(1, sizeof(*p));
2715 p->completion = completion;
2716 p->context = context;
2718 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2719 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2723 SilcGetAuthMeth completion;
2727 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2728 SilcUInt32 passphrase_len,
2731 GetAuthMethod a = context;
2732 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2733 passphrase, passphrase_len, a->context);
2737 /* Find authentication data by hostname and port. The hostname may be IP
2740 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2741 char *hostname, SilcUInt16 port,
2742 SilcAuthMethod auth_meth,
2743 SilcGetAuthMeth completion, void *context)
2745 SERVER_SETUP_REC *setup;
2747 SILC_LOG_DEBUG(("Start"));
2749 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2750 /* Returning NULL will cause library to use our private key configured
2751 for this connection */
2752 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2756 /* Check whether we find the password for this server in our
2757 configuration. If it's set, always send it server. */
2758 setup = server_setup_find_port(hostname, port);
2759 if (setup && setup->password) {
2760 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2765 /* Didn't find password. If server wants it, ask it from user. */
2766 if (auth_meth == SILC_AUTH_PASSWORD) {
2768 a = silc_calloc(1, sizeof(*a));
2770 a->completion = completion;
2771 a->context = context;
2772 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2777 /* No authentication */
2778 completion(SILC_AUTH_NONE, NULL, 0, context);
2781 /* Asks whether the user would like to perform the key agreement protocol.
2782 This is called after we have received an key agreement packet or an
2783 reply to our key agreement packet. This returns TRUE if the user wants
2784 the library to perform the key agreement protocol and FALSE if it is not
2785 desired (application may start it later by calling the function
2786 silc_client_perform_key_agreement). */
2788 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2789 SilcClientEntry client_entry, const char *hostname,
2790 SilcUInt16 protocol, SilcUInt16 port)
2792 char portstr[12], protostr[5];
2794 SILC_LOG_DEBUG(("Start"));
2796 /* We will just display the info on the screen and return FALSE and user
2797 will have to start the key agreement with a command. */
2800 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2801 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2806 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2807 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2809 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2810 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2811 client_entry->nickname, hostname, portstr, protostr);
2814 /* Notifies application that file transfer protocol session is being
2815 requested by the remote client indicated by the `client_entry' from
2816 the `hostname' and `port'. The `session_id' is the file transfer
2817 session and it can be used to either accept or reject the file
2818 transfer request, by calling the silc_client_file_receive or
2819 silc_client_file_close, respectively. */
2821 void silc_ftp(SilcClient client, SilcClientConnection conn,
2822 SilcClientEntry client_entry, SilcUInt32 session_id,
2823 const char *hostname, SilcUInt16 port)
2825 SILC_SERVER_REC *server;
2827 FtpSession ftp = NULL;
2829 SILC_LOG_DEBUG(("Start"));
2831 server = conn->context;
2833 silc_dlist_start(server->ftp_sessions);
2834 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2835 if (ftp->client_entry == client_entry &&
2836 ftp->session_id == session_id) {
2837 server->current_session = ftp;
2841 if (ftp == SILC_LIST_END) {
2842 ftp = silc_calloc(1, sizeof(*ftp));
2843 ftp->client_entry = client_entry;
2844 ftp->session_id = session_id;
2847 silc_dlist_add(server->ftp_sessions, ftp);
2848 server->current_session = ftp;
2852 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2855 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2856 SILCTXT_FILE_REQUEST, client_entry->nickname);
2858 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2859 SILCTXT_FILE_REQUEST_HOST,
2860 client_entry->nickname, hostname, portstr);
2863 /* SILC client operations */
2864 SilcClientOperations ops = {
2866 silc_channel_message,
2867 silc_private_message,
2871 silc_get_auth_method,
2872 silc_verify_public_key,
2873 silc_ask_passphrase,