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"
33 #include "clientutil.h"
39 #include "special-vars.h"
40 #include "fe-common/core/printtext.h"
41 #include "fe-common/core/fe-channels.h"
42 #include "fe-common/core/keyboard.h"
43 #include "fe-common/core/window-items.h"
44 #include "fe-common/silc/module-formats.h"
49 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
50 const char *name, SilcConnectionType conn_type,
51 SilcPublicKey public_key,
52 SilcVerifyPublicKey completion, void *context);
54 char *silc_get_session_filename(SILC_SERVER_REC *server)
56 char *file, *expanded;
58 expanded = parse_special_string(settings_get_str("session_filename"),
59 SERVER(server), NULL, "", NULL, 0);
61 file = silc_calloc(1, strlen(expanded) + 255);
62 snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
68 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
71 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
72 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
73 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
75 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
76 "[SILC operator]" : "[unknown mode]");
78 if (mode & SILC_UMODE_GONE)
79 strcat(buf, " [away]");
80 if (mode & SILC_UMODE_INDISPOSED)
81 strcat(buf, " [indisposed]");
82 if (mode & SILC_UMODE_BUSY)
83 strcat(buf, " [busy]");
84 if (mode & SILC_UMODE_PAGE)
85 strcat(buf, " [page to reach]");
86 if (mode & SILC_UMODE_HYPER)
87 strcat(buf, " [hyper active]");
88 if (mode & SILC_UMODE_ROBOT)
89 strcat(buf, " [robot]");
90 if (mode & SILC_UMODE_ANONYMOUS)
91 strcat(buf, " [anonymous]");
92 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
93 strcat(buf, " [blocks private messages]");
94 if (mode & SILC_UMODE_DETACHED)
95 strcat(buf, " [detached]");
96 if (mode & SILC_UMODE_REJECT_WATCHING)
97 strcat(buf, " [rejects watching]");
98 if (mode & SILC_UMODE_BLOCK_INVITE)
99 strcat(buf, " [blocks invites]");
102 /* converts an utf-8 string to current locale */
103 char * silc_convert_utf8_string(const char *str)
105 int message_len = (str != NULL ? strlen(str) : 0);
106 char *message = silc_calloc(message_len + 1, sizeof(*message));
108 g_return_val_if_fail(message != NULL, NULL);
115 if (!silc_term_utf8() && silc_utf8_valid(str, message_len))
116 silc_utf8_decode(str, message_len, SILC_STRING_LOCALE,
117 message, message_len);
119 strcpy(message, str);
124 /* print "nick appears as" message to every channel of a server */
126 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
127 const char *newnick, const char *oldnick,
130 if (ignore_check(SERVER(server), oldnick, address,
131 channel, newnick, MSGLEVEL_NICKS))
134 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
135 SILCTXT_CHANNEL_APPEARS,
136 oldnick, newnick, channel, address);
140 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
141 const char *oldnick, const char *address)
143 GSList *tmp, *windows;
145 /* Print to each channel/query where the nick is.
146 Don't print more than once to the same window. */
149 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
150 CHANNEL_REC *channel = tmp->data;
151 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
153 if (nicklist_find(channel, newnick) == NULL ||
154 g_slist_find(windows, window) != NULL)
157 windows = g_slist_append(windows, window);
158 silc_print_nick_change_channel(server, channel->visible_name,
159 newnick, oldnick, address);
162 g_slist_free(windows);
165 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
166 SilcChannelEntry channel_entry,
167 SilcDList channel_pubkeys)
169 SilcArgumentDecodedList e;
170 SilcPublicKey pubkey;
171 SilcSILCPublicKey silc_pubkey;
172 SilcUInt32 pk_len, type;
174 char *fingerprint, *babbleprint;
177 printformat_module("fe-common/silc", server, NULL,
178 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
179 channel_entry->channel_name);
181 silc_dlist_start(channel_pubkeys);
182 while ((e = silc_dlist_get(channel_pubkeys))) {
183 pubkey = e->argument;
186 if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
189 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
193 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
194 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
195 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, pubkey);
197 printformat_module("fe-common/silc", server, NULL,
198 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
199 c++, channel_entry->channel_name,
200 type == 0x00 ? "Added" : "Removed",
201 silc_pubkey->identifier.realname ?
202 silc_pubkey->identifier.realname : "",
203 fingerprint, babbleprint);
205 silc_free(fingerprint);
206 silc_free(babbleprint);
211 void silc_say(SilcClient client, SilcClientConnection conn,
212 SilcClientMessageType type, char *msg, ...)
214 SILC_SERVER_REC *server;
218 server = conn == NULL ? NULL : conn->context;
221 str = g_strdup_vprintf(msg, va);
222 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
227 void silc_say_error(char *msg, ...)
233 str = g_strdup_vprintf(msg, va);
234 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
240 /* Try to verify a message using locally stored public key data */
242 int verify_message_signature(SilcClientEntry sender,
243 SilcMessagePayload message)
246 char file[256], filename[256];
247 char *fingerprint, *fingerprint2;
248 const unsigned char *pk_data;
249 SilcUInt32 pk_datalen;
251 int ret = SILC_MSG_SIGNED_VERIFIED, i;
253 /* get public key from the signature payload and compare it with the
254 one stored in the client entry */
255 pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
258 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
260 if (sender->fingerprint[0]) {
261 fingerprint2 = silc_fingerprint(sender->fingerprint,
262 sizeof(sender->fingerprint));
263 if (strcmp(fingerprint, fingerprint2)) {
264 /* since the public key differs from the senders public key, the
265 verification _failed_ */
266 silc_pkcs_public_key_free(pk);
267 silc_free(fingerprint);
268 ret = SILC_MSG_SIGNED_UNKNOWN;
270 silc_free(fingerprint2);
272 } else if (sender->fingerprint[0])
273 fingerprint = silc_fingerprint(sender->fingerprint,
274 sizeof(sender->fingerprint));
276 /* no idea, who or what signed that message ... */
277 return SILC_MSG_SIGNED_UNKNOWN;
279 /* search our local client key cache */
280 for (i = 0; i < strlen(fingerprint); i++)
281 if (fingerprint[i] == ' ')
282 fingerprint[i] = '_';
284 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
285 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
286 get_irssi_dir(), file);
287 silc_free(fingerprint);
289 if (stat(filename, &st) < 0)
290 /* we don't have the public key cached ... use the one from the sig */
291 ret = SILC_MSG_SIGNED_UNKNOWN;
293 SilcPublicKey cached_pk=NULL;
295 /* try to load the file */
296 if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
297 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
298 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
300 return SILC_MSG_SIGNED_UNKNOWN;
302 ret = SILC_MSG_SIGNED_UNKNOWN;
307 silc_pkcs_public_key_free(pk);
312 /* the public key is now in pk, our "level of trust" in ret */
313 if ((pk) && silc_message_signed_verify(message, pk,
314 sha1hash) != SILC_AUTH_OK)
315 ret = SILC_MSG_SIGNED_FAILED;
318 silc_pkcs_public_key_free(pk);
323 char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
326 int i = 0, j = 0, len = strlen(escaped_data);
328 data = silc_calloc(len, sizeof(char));
331 ptr = memchr(escaped_data + i, 1, len - i);
333 int inc = (ptr - escaped_data) - i;
334 memcpy(data + j, escaped_data + i, inc);
337 data[j++] = *(ptr + 1) - 1;
339 memcpy(data + j, escaped_data + i, len - i);
349 char *silc_escape_data(const char *data, SilcUInt32 len)
351 char *escaped_data, *ptr, *ptr0, *ptr1;
354 escaped_data = silc_calloc(2 * len, sizeof(char));
357 ptr0 = memchr(data + i, 0, len - i);
358 ptr1 = memchr(data + i, 1, len - i);
360 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
363 int inc = (ptr - data) - i;
365 memcpy(escaped_data + j, data + i, inc);
368 escaped_data[j++] = 1;
369 escaped_data[j++] = *(data + i++) + 1;
371 memcpy(escaped_data + j, data + i, len - i);
380 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
381 const char *data, SilcUInt32 data_len,
382 const char *nick, int verified)
386 escaped_data = silc_escape_data(data, data_len);
388 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
390 silc_free(escaped_data);
394 /* Message for a channel. The `sender' is the nickname of the sender
395 received in the packet. The `channel_name' is the name of the channel. */
397 void silc_channel_message(SilcClient client, SilcClientConnection conn,
398 SilcClientEntry sender, SilcChannelEntry channel,
399 SilcMessagePayload payload,
400 SilcChannelPrivateKey key,
401 SilcMessageFlags flags, const unsigned char *message,
402 SilcUInt32 message_len)
404 SILC_SERVER_REC *server;
406 SILC_CHANNEL_REC *chanrec;
409 SILC_LOG_DEBUG(("Start"));
414 server = conn == NULL ? NULL : conn->context;
415 chanrec = silc_channel_find_entry(server, channel);
419 nick = silc_nicklist_find(chanrec, sender);
421 /* We didn't find client but it clearly exists, add it. */
422 SilcChannelUser chu = silc_client_on_channel(channel, sender);
424 nick = silc_nicklist_insert(chanrec, chu, FALSE);
429 /* If the messages is digitally signed, verify it, if possible. */
430 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
431 if (!settings_get_bool("ignore_message_signatures")) {
432 verified = verify_message_signature(sender, payload);
434 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
438 if (flags & SILC_MESSAGE_FLAG_DATA) {
439 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
440 nick == NULL ? NULL : nick->nick,
441 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
448 if (flags & SILC_MESSAGE_FLAG_ACTION)
449 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
450 char tmp[256], *cp, *dm = NULL;
451 memset(tmp, 0, sizeof(tmp));
453 if(message_len > sizeof(tmp) - 1) {
454 dm = silc_calloc(message_len + 1, sizeof(*dm));
457 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
459 if (flags & SILC_MESSAGE_FLAG_SIGNED)
460 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
461 nick->host, channel->channel_name, verified);
463 signal_emit("message silc action", 5, server, cp, nick->nick,
464 nick->host, channel->channel_name);
467 if (flags & SILC_MESSAGE_FLAG_SIGNED)
468 signal_emit("message silc signed_action", 6, server, message,
469 nick->nick, nick->host, channel->channel_name, verified);
471 signal_emit("message silc action", 5, server, message,
472 nick->nick, nick->host, channel->channel_name);
474 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
475 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
476 char tmp[256], *cp, *dm = NULL;
477 memset(tmp, 0, sizeof(tmp));
479 if(message_len > sizeof(tmp) - 1) {
480 dm = silc_calloc(message_len + 1, sizeof(*dm));
483 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
485 if (flags & SILC_MESSAGE_FLAG_SIGNED)
486 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
487 nick->host, channel->channel_name, verified);
489 signal_emit("message silc notice", 5, server, cp, nick->nick,
490 nick->host, channel->channel_name);
493 if (flags & SILC_MESSAGE_FLAG_SIGNED)
494 signal_emit("message silc signed_notice", 6, server, message,
495 nick->nick, nick->host, channel->channel_name, verified);
497 signal_emit("message silc notice", 5, server, message,
498 nick->nick, nick->host, channel->channel_name);
501 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
502 char tmp[256], *cp, *dm = NULL;
504 memset(tmp, 0, sizeof(tmp));
506 if (message_len > sizeof(tmp) - 1) {
507 dm = silc_calloc(message_len + 1, sizeof(*dm));
511 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
513 if (flags & SILC_MESSAGE_FLAG_SIGNED)
514 signal_emit("message signed_public", 6, server, cp,
515 nick == NULL ? "[<unknown>]" : nick->nick,
516 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
517 chanrec->name, verified);
519 signal_emit("message public", 6, server, cp,
520 nick == NULL ? "[<unknown>]" : nick->nick,
521 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
522 chanrec->name, nick);
527 if (flags & SILC_MESSAGE_FLAG_SIGNED)
528 signal_emit("message signed_public", 6, server, message,
529 nick == NULL ? "[<unknown>]" : nick->nick,
530 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
531 chanrec->name, verified);
533 signal_emit("message public", 6, server, message,
534 nick == NULL ? "[<unknown>]" : nick->nick,
535 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
536 chanrec->name, nick);
540 /* Private message to the client. The `sender' is the nickname of the
541 sender received in the packet. */
543 void silc_private_message(SilcClient client, SilcClientConnection conn,
544 SilcClientEntry sender, SilcMessagePayload payload,
545 SilcMessageFlags flags,
546 const unsigned char *message,
547 SilcUInt32 message_len)
549 SILC_SERVER_REC *server;
553 SILC_LOG_DEBUG(("Start"));
555 server = conn == NULL ? NULL : conn->context;
556 memset(userhost, 0, sizeof(userhost));
557 if (sender->username[0])
558 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
559 sender->username, sender->hostname);
561 /* If the messages is digitally signed, verify it, if possible. */
562 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
563 if (!settings_get_bool("ignore_message_signatures")) {
564 verified = verify_message_signature(sender, payload);
566 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
570 if (flags & SILC_MESSAGE_FLAG_DATA) {
571 silc_emit_mime_sig(server,
572 sender->nickname[0] ?
573 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
575 message, message_len,
576 sender->nickname[0] ? sender->nickname : "[<unknown>]",
577 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
584 if (flags & SILC_MESSAGE_FLAG_ACTION)
585 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
586 char tmp[256], *cp, *dm = NULL;
587 memset(tmp, 0, sizeof(tmp));
589 if(message_len > sizeof(tmp) - 1) {
590 dm = silc_calloc(message_len + 1, sizeof(*dm));
593 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
595 if (flags & SILC_MESSAGE_FLAG_SIGNED)
596 signal_emit("message silc signed_private_action", 6, server, cp,
597 sender->nickname[0] ? sender->nickname : "[<unknown>]",
598 sender->username[0] ? userhost : NULL,
601 signal_emit("message silc private_action", 5, server, cp,
602 sender->nickname[0] ? sender->nickname : "[<unknown>]",
603 sender->username[0] ? userhost : NULL, NULL);
606 if (flags & SILC_MESSAGE_FLAG_SIGNED)
607 signal_emit("message silc signed_private_action", 6, server, message,
608 sender->nickname[0] ? sender->nickname : "[<unknown>]",
609 sender->username[0] ? userhost : NULL,
612 signal_emit("message silc private_action", 5, server, message,
613 sender->nickname[0] ? sender->nickname : "[<unknown>]",
614 sender->username[0] ? userhost : NULL, NULL);
616 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
617 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
618 char tmp[256], *cp, *dm = NULL;
619 memset(tmp, 0, sizeof(tmp));
621 if(message_len > sizeof(tmp) - 1) {
622 dm = silc_calloc(message_len + 1, sizeof(*dm));
625 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
627 if (flags & SILC_MESSAGE_FLAG_SIGNED)
628 signal_emit("message silc signed_private_notice", 6, server, cp,
629 sender->nickname[0] ? sender->nickname : "[<unknown>]",
630 sender->username[0] ? userhost : NULL,
633 signal_emit("message silc private_notice", 5, server, cp,
634 sender->nickname[0] ? sender->nickname : "[<unknown>]",
635 sender->username[0] ? userhost : NULL, NULL);
638 if (flags & SILC_MESSAGE_FLAG_SIGNED)
639 signal_emit("message silc signed_private_notice", 6, server, message,
640 sender->nickname[0] ? sender->nickname : "[<unknown>]",
641 sender->username[0] ? userhost : NULL,
644 signal_emit("message silc private_notice", 5, server, message,
645 sender->nickname[0] ? sender->nickname : "[<unknown>]",
646 sender->username[0] ? userhost : NULL, NULL);
649 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
650 char tmp[256], *cp, *dm = NULL;
652 memset(tmp, 0, sizeof(tmp));
654 if (message_len > sizeof(tmp) - 1) {
655 dm = silc_calloc(message_len + 1, sizeof(*dm));
659 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
661 if (flags & SILC_MESSAGE_FLAG_SIGNED)
662 signal_emit("message signed_private", 5, server, cp,
663 sender->nickname[0] ? sender->nickname : "[<unknown>]",
664 sender->username[0] ? userhost : NULL, verified);
666 signal_emit("message private", 4, server, cp,
667 sender->nickname[0] ? sender->nickname : "[<unknown>]",
668 sender->username[0] ? userhost : NULL);
673 if (flags & SILC_MESSAGE_FLAG_SIGNED)
674 signal_emit("message signed_private", 5, server, message,
675 sender->nickname[0] ? sender->nickname : "[<unknown>]",
676 sender->username[0] ? userhost : NULL, verified);
678 signal_emit("message private", 4, server, message,
679 sender->nickname[0] ? sender->nickname : "[<unknown>]",
680 sender->username[0] ? userhost : NULL);
684 /* Notify message to the client. The notify arguments are sent in the
685 same order as servers sends them. The arguments are same as received
686 from the server except for ID's. If ID is received application receives
687 the corresponding entry to the ID. For example, if Client ID is received
688 application receives SilcClientEntry. Also, if the notify type is
689 for channel the channel entry is sent to application (even if server
690 does not send it). */
692 void silc_notify(SilcClient client, SilcClientConnection conn,
693 SilcNotifyType type, ...)
696 SILC_SERVER_REC *server;
697 SILC_CHANNEL_REC *chanrec;
698 SILC_NICK_REC *nickrec;
699 SilcClientEntry client_entry, client_entry2;
700 SilcChannelEntry channel, channel2;
701 SilcServerEntry server_entry;
706 char *name, *tmp, *cipher, *hmac;
707 GSList *list1, *list_tmp;
708 SilcDList chpks, clients;
710 SILC_LOG_DEBUG(("Start"));
714 server = conn == NULL ? NULL : conn->context;
717 case SILC_NOTIFY_TYPE_NONE:
718 /* Some generic notice from server */
719 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
722 case SILC_NOTIFY_TYPE_INVITE:
724 * Invited or modified invite list.
727 SILC_LOG_DEBUG(("Notify: INVITE"));
729 channel = va_arg(va, SilcChannelEntry);
730 name = va_arg(va, char *);
731 client_entry = va_arg(va, SilcClientEntry);
733 silc_snprintf(buf, sizeof(buf) - 1, "%s@%s",
734 client_entry->username, client_entry->hostname);
735 signal_emit("message invite", 4, server, name,
736 client_entry->nickname, buf);
739 case SILC_NOTIFY_TYPE_JOIN:
744 SILC_LOG_DEBUG(("Notify: JOIN"));
746 client_entry = va_arg(va, SilcClientEntry);
747 channel = va_arg(va, SilcChannelEntry);
749 if (client_entry == server->conn->local_entry) {
750 /* You joined to channel */
751 chanrec = silc_channel_find(server, channel->channel_name);
753 chanrec = silc_channel_create(server, channel->channel_name,
754 channel->channel_name, TRUE);
755 if (!chanrec->joined)
756 chanrec->entry = channel;
758 chanrec = silc_channel_find_entry(server, channel);
759 if (chanrec != NULL) {
760 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
762 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
766 memset(buf, 0, sizeof(buf));
767 if (client_entry->username[0])
768 snprintf(buf, sizeof(buf) - 1, "%s@%s",
769 client_entry->username, client_entry->hostname);
770 signal_emit("message join", 4, server, channel->channel_name,
771 client_entry->nickname,
772 !client_entry->username[0] ? "" : buf);
774 /* If there are multiple same nicknames on channel now, tell it to user. */
775 if (client_entry != server->conn->local_entry) {
779 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
780 clients = silc_client_get_clients_local(client, conn, nick, TRUE);
781 if (!clients || silc_dlist_count(clients) < 2) {
783 silc_client_list_free(client, conn, clients);
786 silc_dlist_start(clients);
787 while ((client_entry2 = silc_dlist_get(clients)))
788 if (silc_client_on_channel(channel, client_entry2))
791 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
792 printformat_module("fe-common/silc", server, channel->channel_name,
793 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
795 printformat_module("fe-common/silc", server, channel->channel_name,
796 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
797 buf, client_entry->nickname);
799 silc_client_list_free(client, conn, clients);
804 case SILC_NOTIFY_TYPE_LEAVE:
809 SILC_LOG_DEBUG(("Notify: LEAVE"));
811 client_entry = va_arg(va, SilcClientEntry);
812 channel = va_arg(va, SilcChannelEntry);
814 memset(buf, 0, sizeof(buf));
815 if (client_entry->username)
816 snprintf(buf, sizeof(buf) - 1, "%s@%s",
817 client_entry->username, client_entry->hostname);
818 signal_emit("message part", 5, server, channel->channel_name,
819 client_entry->nickname, client_entry->username[0] ?
820 buf : "", client_entry->nickname);
822 chanrec = silc_channel_find_entry(server, channel);
823 if (chanrec != NULL) {
824 nickrec = silc_nicklist_find(chanrec, client_entry);
826 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
829 /* If there is only one client with this same nickname on channel now
830 change it to the base format if it is formatted nickname. */
832 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
833 clients = silc_client_get_clients_local(client, conn, name, TRUE);
834 if (!clients || silc_dlist_count(clients) != 2) {
836 silc_client_list_free(client, conn, clients);
839 silc_dlist_start(clients);
840 client_entry2 = silc_dlist_get(clients);
841 if (client_entry2 == client_entry)
842 client_entry2 = silc_dlist_get(clients);
843 if (silc_client_on_channel(channel, client_entry2)) {
844 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
845 silc_client_nickname_format(client, conn, client_entry2, TRUE);
846 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
847 nicklist_rename_unique(SERVER(server), client_entry2, buf,
848 client_entry2, client_entry2->nickname);
849 printformat_module("fe-common/silc", server, channel->channel_name,
850 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
851 buf, client_entry2->nickname);
854 silc_client_list_free(client, conn, clients);
859 case SILC_NOTIFY_TYPE_SIGNOFF:
864 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
866 client_entry = va_arg(va, SilcClientEntry);
867 tmp = va_arg(va, char *);
868 channel = va_arg(va, SilcChannelEntry);
870 silc_server_free_ftp(server, client_entry);
872 memset(buf, 0, sizeof(buf));
873 if (client_entry->username)
874 snprintf(buf, sizeof(buf) - 1, "%s@%s",
875 client_entry->username, client_entry->hostname);
876 signal_emit("message quit", 4, server, client_entry->nickname,
877 client_entry->username[0] ? buf : "", tmp ? tmp : "");
879 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
880 for (list_tmp = list1; list_tmp != NULL; list_tmp =
881 list_tmp->next->next) {
882 CHANNEL_REC *channel = list_tmp->data;
883 NICK_REC *nickrec = list_tmp->next->data;
885 nicklist_remove(channel, nickrec);
888 /* If there is only one client with this same nickname on channel now
889 change it to the base format if it is formatted nickname. */
891 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
892 clients = silc_client_get_clients_local(client, conn, name, TRUE);
893 if (!clients || silc_dlist_count(clients) != 2) {
895 silc_client_list_free(client, conn, clients);
898 silc_dlist_start(clients);
899 client_entry2 = silc_dlist_get(clients);
900 if (client_entry2 == client_entry)
901 client_entry2 = silc_dlist_get(clients);
902 if (silc_client_on_channel(channel, client_entry2)) {
903 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
904 silc_client_nickname_format(client, conn, client_entry2, TRUE);
905 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
906 nicklist_rename_unique(SERVER(server), client_entry2, buf,
907 client_entry2, client_entry2->nickname);
908 printformat_module("fe-common/silc", server, channel->channel_name,
909 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
910 buf, client_entry2->nickname);
913 silc_client_list_free(client, conn, clients);
918 case SILC_NOTIFY_TYPE_TOPIC_SET:
923 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
925 idtype = va_arg(va, int);
926 entry = va_arg(va, void *);
927 tmp = va_arg(va, char *);
928 channel = va_arg(va, SilcChannelEntry);
930 chanrec = silc_channel_find_entry(server, channel);
931 if (chanrec != NULL) {
932 char tmp2[256], *cp, *dm = NULL;
934 g_free_not_null(chanrec->topic);
935 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
936 memset(tmp2, 0, sizeof(tmp2));
938 if (strlen(tmp) > sizeof(tmp2) - 1) {
939 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
943 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
948 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
949 signal_emit("channel topic changed", 1, chanrec);
954 if (idtype == SILC_ID_CLIENT) {
955 client_entry = (SilcClientEntry)entry;
956 memset(buf, 0, sizeof(buf));
957 snprintf(buf, sizeof(buf) - 1, "%s@%s",
958 client_entry->username, client_entry->hostname);
959 signal_emit("message topic", 5, server, channel->channel_name,
960 tmp, client_entry->nickname, buf);
961 } else if (idtype == SILC_ID_SERVER) {
962 server_entry = (SilcServerEntry)entry;
963 signal_emit("message topic", 5, server, channel->channel_name,
964 tmp, server_entry->server_name,
965 server_entry->server_name);
966 } else if (idtype == SILC_ID_CHANNEL) {
967 channel = (SilcChannelEntry)entry;
968 signal_emit("message topic", 5, server, channel->channel_name,
969 tmp, channel->channel_name, channel->channel_name);
973 case SILC_NOTIFY_TYPE_NICK_CHANGE:
978 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
980 client_entry = va_arg(va, SilcClientEntry);
981 name = va_arg(va, char *); /* old nickname */
983 if (!strcmp(client_entry->nickname, name))
986 memset(buf, 0, sizeof(buf));
987 snprintf(buf, sizeof(buf) - 1, "%s@%s",
988 client_entry->username, client_entry->hostname);
989 nicklist_rename_unique(SERVER(server),
991 client_entry, client_entry->nickname);
992 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
995 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
997 * Changed channel mode.
1000 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
1002 idtype = va_arg(va, int);
1003 entry = va_arg(va, void *);
1004 mode = va_arg(va, SilcUInt32);
1005 cipher = va_arg(va, char *); /* cipher */
1006 hmac = va_arg(va, char *); /* hmac */
1007 (void)va_arg(va, char *); /* passphrase */
1008 (void)va_arg(va, SilcPublicKey); /* founder key */
1009 chpks = va_arg(va, SilcDList); /* channel public keys */
1010 channel = va_arg(va, SilcChannelEntry);
1012 tmp = silc_client_chmode(mode, cipher ? cipher : "",
1015 chanrec = silc_channel_find_entry(server, channel);
1016 if (chanrec != NULL) {
1017 g_free_not_null(chanrec->mode);
1018 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
1019 signal_emit("channel mode changed", 1, chanrec);
1022 if (idtype == SILC_ID_CLIENT) {
1023 client_entry = (SilcClientEntry)entry;
1024 printformat_module("fe-common/silc", server, channel->channel_name,
1025 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1026 channel->channel_name, tmp ? tmp : "removed all",
1027 client_entry->nickname);
1028 } else if (idtype == SILC_ID_SERVER) {
1029 server_entry = (SilcServerEntry)entry;
1030 printformat_module("fe-common/silc", server, channel->channel_name,
1031 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1032 channel->channel_name, tmp ? tmp : "removed all",
1033 server_entry->server_name);
1034 } else if (idtype == SILC_ID_CHANNEL) {
1035 channel2 = (SilcChannelEntry)entry;
1036 printformat_module("fe-common/silc", server, channel->channel_name,
1037 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1038 channel->channel_name, tmp ? tmp : "removed all",
1039 channel2->channel_name);
1042 /* Print the channel public key list */
1044 silc_parse_channel_public_keys(server, channel, chpks);
1049 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1051 * Changed user's mode on channel.
1054 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1056 idtype = va_arg(va, int);
1057 entry = va_arg(va, void *);
1058 mode = va_arg(va, SilcUInt32);
1059 client_entry2 = va_arg(va, SilcClientEntry);
1060 channel = va_arg(va, SilcChannelEntry);
1062 tmp = silc_client_chumode(mode);
1063 chanrec = silc_channel_find_entry(server, channel);
1064 if (chanrec != NULL) {
1065 SILC_NICK_REC *nick;
1067 if (client_entry2 == server->conn->local_entry)
1068 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1070 nick = silc_nicklist_find(chanrec, client_entry2);
1072 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1073 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1074 signal_emit("nick mode changed", 2, chanrec, nick);
1078 if (idtype == SILC_ID_CLIENT) {
1079 client_entry = (SilcClientEntry)entry;
1080 printformat_module("fe-common/silc", server, channel->channel_name,
1081 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1082 channel->channel_name, client_entry2->nickname,
1083 tmp ? tmp : "removed all",
1084 client_entry->nickname);
1085 } else if (idtype == SILC_ID_SERVER) {
1086 server_entry = (SilcServerEntry)entry;
1087 printformat_module("fe-common/silc", server, channel->channel_name,
1088 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1089 channel->channel_name, client_entry2->nickname,
1090 tmp ? tmp : "removed all",
1091 server_entry->server_name);
1092 } else if (idtype == SILC_ID_CHANNEL) {
1093 channel2 = (SilcChannelEntry)entry;
1094 printformat_module("fe-common/silc", server, channel->channel_name,
1095 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1096 channel->channel_name, client_entry2->nickname,
1097 tmp ? tmp : "removed all",
1098 channel2->channel_name);
1101 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1102 printformat_module("fe-common/silc",
1103 server, channel->channel_name, MSGLEVEL_CRAP,
1104 SILCTXT_CHANNEL_FOUNDER,
1105 channel->channel_name, client_entry2->nickname);
1107 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1108 printformat_module("fe-common/silc",
1109 server, channel->channel_name, MSGLEVEL_CRAP,
1110 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1115 case SILC_NOTIFY_TYPE_MOTD:
1120 SILC_LOG_DEBUG(("Notify: MOTD"));
1122 tmp = va_arg(va, char *);
1124 if (!settings_get_bool("skip_motd"))
1125 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1128 case SILC_NOTIFY_TYPE_KICKED:
1130 * Someone was kicked from channel.
1133 SILC_LOG_DEBUG(("Notify: KICKED"));
1135 client_entry = va_arg(va, SilcClientEntry);
1136 tmp = va_arg(va, char *);
1137 client_entry2 = va_arg(va, SilcClientEntry);
1138 channel = va_arg(va, SilcChannelEntry);
1140 chanrec = silc_channel_find_entry(server, channel);
1142 if (client_entry == conn->local_entry) {
1143 printformat_module("fe-common/silc", server, channel->channel_name,
1144 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1145 channel->channel_name,
1146 client_entry ? client_entry2->nickname : "",
1149 chanrec->kicked = TRUE;
1150 channel_destroy((CHANNEL_REC *)chanrec);
1153 printformat_module("fe-common/silc", server, channel->channel_name,
1154 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1155 client_entry->nickname, channel->channel_name,
1156 client_entry2 ? client_entry2->nickname : "",
1160 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1161 if (nickrec != NULL)
1162 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1167 case SILC_NOTIFY_TYPE_KILLED:
1169 * Someone was killed from the network.
1172 SILC_LOG_DEBUG(("Notify: KILLED"));
1174 client_entry = va_arg(va, SilcClientEntry);
1175 tmp = va_arg(va, char *);
1176 idtype = va_arg(va, int);
1177 entry = va_arg(va, SilcClientEntry);
1179 if (client_entry == conn->local_entry) {
1180 if (idtype == SILC_ID_CLIENT) {
1181 client_entry2 = (SilcClientEntry)entry;
1182 printformat_module("fe-common/silc", server, NULL,
1183 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1184 client_entry2 ? client_entry2->nickname : "",
1186 } else if (idtype == SILC_ID_SERVER) {
1187 server_entry = (SilcServerEntry)entry;
1188 printformat_module("fe-common/silc", server, NULL,
1189 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1190 server_entry->server_name, tmp ? tmp : "");
1191 } else if (idtype == SILC_ID_CHANNEL) {
1192 channel = (SilcChannelEntry)entry;
1193 printformat_module("fe-common/silc", server, NULL,
1194 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1195 channel->channel_name, tmp ? tmp : "");
1198 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1199 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1200 list_tmp->next->next) {
1201 CHANNEL_REC *channel = list_tmp->data;
1202 NICK_REC *nickrec = list_tmp->next->data;
1203 nicklist_remove(channel, nickrec);
1206 if (idtype == SILC_ID_CLIENT) {
1207 client_entry2 = (SilcClientEntry)entry;
1208 printformat_module("fe-common/silc", server, NULL,
1209 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1210 client_entry->nickname,
1211 client_entry2 ? client_entry2->nickname : "",
1213 } else if (idtype == SILC_ID_SERVER) {
1214 server_entry = (SilcServerEntry)entry;
1215 printformat_module("fe-common/silc", server, NULL,
1216 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1217 client_entry->nickname,
1218 server_entry->server_name, tmp ? tmp : "");
1219 } else if (idtype == SILC_ID_CHANNEL) {
1220 channel = (SilcChannelEntry)entry;
1221 printformat_module("fe-common/silc", server, NULL,
1222 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1223 client_entry->nickname,
1224 channel->channel_name, tmp ? tmp : "");
1229 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1232 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1235 * Server has quit the network.
1239 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1241 (void)va_arg(va, void *);
1242 clients = va_arg(va, SilcDList);
1244 silc_dlist_start(clients);
1245 while ((client_entry = silc_dlist_get(clients))) {
1246 memset(buf, 0, sizeof(buf));
1248 /* Print only if we have the nickname. If this client has just quit
1249 when we were only resolving it, it is possible we don't have the
1251 if (client_entry->nickname[0]) {
1252 if (client_entry->username[0])
1253 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1254 client_entry->username, client_entry->hostname);
1255 signal_emit("message quit", 4, server, client_entry->nickname,
1256 client_entry->username[0] ? buf : "",
1260 silc_server_free_ftp(server, client_entry);
1262 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1263 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1264 list_tmp->next->next) {
1265 CHANNEL_REC *channel = list_tmp->data;
1266 NICK_REC *nickrec = list_tmp->next->data;
1267 nicklist_remove(channel, nickrec);
1273 case SILC_NOTIFY_TYPE_ERROR:
1275 SilcStatus error = va_arg(va, int);
1277 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1278 "%s", silc_get_status_message(error));
1282 case SILC_NOTIFY_TYPE_WATCH:
1284 SilcNotifyType notify;
1286 client_entry = va_arg(va, SilcClientEntry);
1287 name = va_arg(va, char *); /* Maybe NULL */
1288 mode = va_arg(va, SilcUInt32);
1289 notify = va_arg(va, int);
1291 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1293 printformat_module("fe-common/silc", server, NULL,
1294 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1295 client_entry->nickname, name);
1297 printformat_module("fe-common/silc", server, NULL,
1298 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1299 client_entry->nickname);
1300 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1301 /* See if client was away and is now present */
1302 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1303 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1304 SILC_UMODE_DETACHED)) &&
1305 (client_entry->mode & SILC_UMODE_GONE ||
1306 client_entry->mode & SILC_UMODE_INDISPOSED ||
1307 client_entry->mode & SILC_UMODE_BUSY ||
1308 client_entry->mode & SILC_UMODE_PAGE ||
1309 client_entry->mode & SILC_UMODE_DETACHED)) {
1310 printformat_module("fe-common/silc", server, NULL,
1311 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1312 client_entry->nickname);
1316 memset(buf, 0, sizeof(buf));
1317 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1318 printformat_module("fe-common/silc", server, NULL,
1319 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1320 client_entry->nickname, buf);
1322 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1323 printformat_module("fe-common/silc", server, NULL,
1324 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1325 client_entry->nickname);
1326 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1327 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1328 printformat_module("fe-common/silc", server, NULL,
1329 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1330 client_entry->nickname);
1331 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1332 /* Client logged in to the network */
1333 printformat_module("fe-common/silc", server, NULL,
1334 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1335 client_entry->nickname);
1341 /* Unknown notify */
1342 printformat_module("fe-common/silc", server, NULL,
1343 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1350 /* Command handler. This function is called always in the command function.
1351 If error occurs it will be called as well. `conn' is the associated
1352 client connection. `cmd_context' is the command context that was
1353 originally sent to the command. `success' is FALSE if error occured
1354 during command. `command' is the command being processed. It must be
1355 noted that this is not reply from server. This is merely called just
1356 after application has called the command. Just to tell application
1357 that the command really was processed. */
1359 static SilcBool cmode_list_chpks = FALSE;
1361 void silc_command(SilcClient client, SilcClientConnection conn,
1362 SilcBool success, SilcCommand command, SilcStatus status,
1363 SilcUInt32 argc, unsigned char **argv)
1365 SILC_SERVER_REC *server = conn->context;
1367 SILC_LOG_DEBUG(("Start"));
1370 silc_say_error("%s", silc_get_status_message(status));
1376 case SILC_COMMAND_INVITE:
1378 printformat_module("fe-common/silc", server, NULL,
1379 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1381 (argv[1][0] == '*' ?
1382 (char *)conn->current_channel->channel_name :
1386 case SILC_COMMAND_DETACH:
1387 server->no_reconnect = TRUE;
1390 case SILC_COMMAND_CMODE:
1391 if (argc == 3 && !strcmp(argv[2], "+C"))
1392 cmode_list_chpks = TRUE;
1394 cmode_list_chpks = FALSE;
1404 SilcClientConnection conn;
1409 void silc_getkey_cb(bool success, void *context)
1411 GetkeyContext getkey = (GetkeyContext)context;
1412 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1413 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1414 ((SilcClientEntry)getkey->entry)->nickname :
1415 ((SilcServerEntry)getkey->entry)->server_name);
1416 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1417 ((SilcClientEntry)getkey->entry)->public_key :
1418 ((SilcServerEntry)getkey->entry)->public_key);
1419 SilcSILCPublicKey silc_pubkey;
1421 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1424 if (getkey->id_type == SILC_ID_CLIENT)
1425 printformat_module("fe-common/silc", NULL, NULL,
1426 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1428 silc_pubkey->identifier.realname ?
1429 silc_pubkey->identifier.realname : "",
1430 silc_pubkey->identifier.email ?
1431 silc_pubkey->identifier.email : "");
1433 printformat_module("fe-common/silc", NULL, NULL,
1434 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1437 printformat_module("fe-common/silc", NULL, NULL,
1438 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1443 * Drop our references as need be.
1445 switch (getkey->id_type)
1447 case SILC_ID_CLIENT:
1448 silc_client_unref_client(getkey->client, getkey->conn, (SilcClientEntry)getkey->entry);
1451 case SILC_ID_SERVER:
1452 silc_client_unref_server(getkey->client, getkey->conn, (SilcServerEntry)getkey->entry);
1459 /* Parse an invite or ban list */
1460 void silc_parse_inviteban_list(SilcClient client,
1461 SilcClientConnection conn,
1462 SILC_SERVER_REC *server,
1463 SilcChannelEntry channel,
1464 const char *list_type,
1465 SilcArgumentPayload list)
1468 SilcUInt32 type, len;
1469 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1470 int counter=0, resolving = FALSE;
1472 if (!silc_argument_get_arg_num(list)) {
1473 printformat_module("fe-common/silc", server,
1474 (chanrec ? chanrec->visible_name : NULL),
1475 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1476 channel->channel_name, list_type);
1480 printformat_module("fe-common/silc", server,
1481 (chanrec ? chanrec->visible_name : NULL),
1482 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1483 channel->channel_name, list_type);
1485 /* Parse the list */
1486 tmp = silc_argument_get_first_arg(list, &type, &len);
1491 /* An invite string */
1495 if (tmp[len-1] == ',')
1498 list = g_strsplit(tmp, ",", -1);
1500 printformat_module("fe-common/silc", server,
1501 (chanrec ? chanrec->visible_name : NULL),
1502 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1503 ++counter, channel->channel_name, list_type,
1512 char *fingerprint, *babbleprint;
1514 /* tmp is Public Key Payload, take public key from it. */
1515 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1516 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1518 printformat_module("fe-common/silc", server,
1519 (chanrec ? chanrec->visible_name : NULL),
1520 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1521 ++counter, channel->channel_name, list_type,
1522 fingerprint, babbleprint);
1529 SilcClientEntry client_entry;
1532 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1533 silc_say_error("Invalid data in %s list encountered", list_type);
1537 client_entry = silc_client_get_client_by_id(client, conn,
1540 printformat_module("fe-common/silc", server,
1541 (chanrec ? chanrec->visible_name : NULL),
1542 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1543 ++counter, channel->channel_name, list_type,
1544 client_entry->nickname);
1545 silc_client_unref_client(client, conn, client_entry);
1548 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1556 silc_say_error("Unkown type in %s list: %u (len %u)",
1557 list_type, type, len);
1560 tmp = silc_argument_get_next_arg(list, &type, &len);
1564 printformat_module("fe-common/silc", server,
1565 (chanrec ? chanrec->visible_name : NULL),
1566 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1567 list_type, channel->channel_name);
1570 /* Command reply handler. This function is called always in the command reply
1571 function. If error occurs it will be called as well. Normal scenario
1572 is that it will be called after the received command data has been parsed
1573 and processed. The function is used to pass the received command data to
1576 `conn' is the associated client connection. `cmd_payload' is the command
1577 payload data received from server and it can be ignored. It is provided
1578 if the application would like to re-parse the received command data,
1579 however, it must be noted that the data is parsed already by the library
1580 thus the payload can be ignored. `success' is FALSE if error occured.
1581 In this case arguments are not sent to the application. `command' is the
1582 command reply being processed. The function has variable argument list
1583 and each command defines the number and type of arguments it passes to the
1584 application (on error they are not sent). */
1586 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1587 SilcCommand command, SilcStatus status,
1588 SilcStatus error, va_list vp)
1590 SILC_SERVER_REC *server = conn->context;
1591 SILC_CHANNEL_REC *chanrec;
1593 SILC_LOG_DEBUG(("Start"));
1596 case SILC_COMMAND_WHOIS:
1598 char buf[1024], *nickname, *username, *realname, *nick;
1599 unsigned char *fingerprint;
1600 SilcUInt32 idle, mode, *user_modes;
1602 SilcClientEntry client_entry;
1605 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1606 /* Print the unknown nick for user */
1607 char *tmp = va_arg(vp, char *);
1609 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1611 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1612 /* Try to find the entry for the unknown client ID, since we
1613 might have, and print the nickname of it for user. */
1614 SilcClientID *id = va_arg(vp, SilcClientID *);
1616 client_entry = silc_client_get_client_by_id(client, conn, id);
1617 if (client_entry && client_entry->nickname[0])
1618 silc_say_error("%s: %s", client_entry->nickname,
1619 silc_get_status_message(status));
1620 silc_client_unref_client(client, conn, client_entry);
1623 } else if (SILC_STATUS_IS_ERROR(status)) {
1624 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1628 client_entry = va_arg(vp, SilcClientEntry);
1629 nickname = va_arg(vp, char *);
1630 username = va_arg(vp, char *);
1631 realname = va_arg(vp, char *);
1632 channels = va_arg(vp, SilcDList);
1633 mode = va_arg(vp, SilcUInt32);
1634 idle = va_arg(vp, SilcUInt32);
1635 fingerprint = va_arg(vp, unsigned char *);
1636 user_modes = va_arg(vp, SilcUInt32 *);
1637 attrs = va_arg(vp, SilcDList);
1639 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1640 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1641 SILCTXT_WHOIS_USERINFO, nickname,
1642 client_entry->username, client_entry->hostname,
1643 nick, client_entry->nickname);
1644 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1645 SILCTXT_WHOIS_REALNAME, realname);
1648 if (channels && user_modes) {
1649 SilcChannelPayload entry;
1652 memset(buf, 0, sizeof(buf));
1653 silc_dlist_start(channels);
1654 while ((entry = silc_dlist_get(channels))) {
1655 SilcUInt32 name_len;
1656 char *m = silc_client_chumode_char(user_modes[i++]);
1657 char *name = silc_channel_get_name(entry, &name_len);
1660 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1661 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1662 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1666 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1667 SILCTXT_WHOIS_CHANNELS, buf);
1671 memset(buf, 0, sizeof(buf));
1672 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1673 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1674 SILCTXT_WHOIS_MODES, buf);
1677 if (idle && nickname) {
1678 memset(buf, 0, sizeof(buf));
1679 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1680 idle > 60 ? (idle / 60) : idle,
1681 idle > 60 ? "minutes" : "seconds");
1683 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1684 SILCTXT_WHOIS_IDLE, buf);
1688 fingerprint = silc_fingerprint(fingerprint, 20);
1689 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1690 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1691 silc_free(fingerprint);
1695 silc_query_attributes_print(server, silc_client, conn, attrs,
1700 case SILC_COMMAND_WHOWAS:
1702 char *nickname, *username, *realname;
1704 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1705 char *tmp = va_arg(vp, char *);
1707 silc_say_error("%s: %s", tmp,
1708 silc_get_status_message(status));
1710 } else if (SILC_STATUS_IS_ERROR(status)) {
1711 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1715 (void)va_arg(vp, SilcClientEntry);
1716 nickname = va_arg(vp, char *);
1717 username = va_arg(vp, char *);
1718 realname = va_arg(vp, char *);
1720 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1721 SILCTXT_WHOWAS_USERINFO, nickname, username,
1722 realname ? realname : "");
1726 case SILC_COMMAND_INVITE:
1728 SilcChannelEntry channel;
1729 SilcArgumentPayload invite_list;
1731 if (SILC_STATUS_IS_ERROR(status))
1734 channel = va_arg(vp, SilcChannelEntry);
1735 invite_list = va_arg(vp, SilcArgumentPayload);
1738 silc_parse_inviteban_list(client, conn, server, channel,
1739 "invite", invite_list);
1743 case SILC_COMMAND_JOIN:
1745 char *channel, *mode, *topic, *cipher, *hmac;
1747 SilcHashTableList *user_list;
1748 SilcChannelEntry channel_entry;
1749 SilcChannelUser chu;
1750 SilcClientEntry founder = NULL;
1753 if (SILC_STATUS_IS_ERROR(status)) {
1754 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
1755 char *tmp = va_arg(vp, char *);
1757 silc_say_error("JOIN: %s: %s", tmp,
1758 silc_get_status_message(status));
1761 if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
1762 char *tmp = va_arg(vp, char *);
1764 silc_say_error("JOIN: %s: %s", tmp,
1765 silc_get_status_message(status));
1768 silc_say_error("JOIN: %s", silc_get_status_message(status));
1772 channel = va_arg(vp, char *);
1773 channel_entry = va_arg(vp, SilcChannelEntry);
1774 modei = va_arg(vp, SilcUInt32);
1775 user_list = va_arg(vp, SilcHashTableList *);
1776 topic = va_arg(vp, char *);
1777 cipher = va_arg(vp, char *);
1778 hmac = va_arg(vp, char *);
1780 chanrec = silc_channel_find(server, channel);
1782 chanrec = silc_channel_create(server, channel, channel, TRUE);
1785 char tmp[256], *cp, *dm = NULL;
1786 g_free_not_null(chanrec->topic);
1788 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1789 memset(tmp, 0, sizeof(tmp));
1791 if (strlen(topic) > sizeof(tmp) - 1) {
1792 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1796 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1801 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1802 signal_emit("channel topic changed", 1, chanrec);
1807 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1808 g_free_not_null(chanrec->mode);
1809 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1810 signal_emit("channel mode changed", 1, chanrec);
1813 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1814 if (!chu->client->nickname[0])
1816 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1817 founder = chu->client;
1818 silc_nicklist_insert(chanrec, chu, FALSE);
1821 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1824 nicklist_set_own(CHANNEL(chanrec), ownnick);
1825 chanrec->entry = channel_entry;
1826 signal_emit("channel joined", 1, chanrec);
1829 printformat_module("fe-common/silc", server,
1830 channel_entry->channel_name,
1831 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1832 channel_entry->channel_name, chanrec->topic);
1835 if (founder == conn->local_entry) {
1836 printformat_module("fe-common/silc",
1837 server, channel_entry->channel_name,
1838 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1839 channel_entry->channel_name);
1840 signal_emit("nick mode changed", 2, chanrec, ownnick);
1842 printformat_module("fe-common/silc",
1843 server, channel_entry->channel_name,
1844 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1845 channel_entry->channel_name, founder->nickname);
1851 case SILC_COMMAND_NICK:
1854 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1857 if (SILC_STATUS_IS_ERROR(status)) {
1858 silc_say_error("NICK: %s", silc_get_status_message(status));
1862 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1863 if ((nicks != NULL) &&
1864 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1866 SilcClientEntry collider, old;
1868 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1869 collider = silc_client_get_client_by_id(client, conn, &old->id);
1870 if (collider != client_entry) {
1871 memset(buf, 0, sizeof(buf));
1872 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1873 collider->username, collider->hostname);
1874 nicklist_rename_unique(SERVER(server),
1876 collider, collider->nickname);
1877 silc_print_nick_change(server, collider->nickname,
1878 client_entry->nickname, buf);
1880 silc_client_unref_client(client, conn, collider);
1884 g_slist_free(nicks);
1886 old = g_strdup(server->nick);
1887 server_change_nick(SERVER(server), client_entry->nickname);
1888 nicklist_rename_unique(SERVER(server),
1889 server->conn->local_entry, server->nick,
1890 client_entry, client_entry->nickname);
1891 signal_emit("message own_nick", 4, server, server->nick, old, "");
1894 /* when connecting to a server, the last thing we receive
1895 is a SILC_COMMAND_LIST reply. Since we enable queueing
1896 during the connection, we can now safely disable it again */
1897 silc_queue_disable(conn);
1901 case SILC_COMMAND_LIST:
1906 char tmp[256], *cp, *dm = NULL;
1908 if (SILC_STATUS_IS_ERROR(status))
1911 (void)va_arg(vp, SilcChannelEntry);
1912 name = va_arg(vp, char *);
1913 topic = va_arg(vp, char *);
1914 usercount = va_arg(vp, int);
1916 if (topic && !silc_term_utf8() &&
1917 silc_utf8_valid(topic, strlen(topic))) {
1918 memset(tmp, 0, sizeof(tmp));
1920 if (strlen(topic) > sizeof(tmp) - 1) {
1921 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1925 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1930 if (status == SILC_STATUS_LIST_START ||
1931 status == SILC_STATUS_OK)
1932 printformat_module("fe-common/silc", server, NULL,
1933 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1936 snprintf(users, sizeof(users) - 1, "N/A");
1938 snprintf(users, sizeof(users) - 1, "%d", usercount);
1939 printformat_module("fe-common/silc", server, NULL,
1940 MSGLEVEL_CRAP, SILCTXT_LIST,
1941 name, users, topic ? topic : "");
1946 case SILC_COMMAND_UMODE:
1951 if (SILC_STATUS_IS_ERROR(status))
1954 mode = va_arg(vp, SilcUInt32);
1956 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1957 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1958 printformat_module("fe-common/silc", server, NULL,
1959 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1961 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1962 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1963 printformat_module("fe-common/silc", server, NULL,
1964 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1966 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1967 if (mode & SILC_UMODE_GONE) {
1968 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1969 reason = g_strdup(server->away_reason);
1971 reason = g_strdup("away");
1973 reason = g_strdup("");
1975 silc_set_away(reason, server);
1980 server->umode = mode;
1981 signal_emit("user mode changed", 2, server, NULL);
1985 case SILC_COMMAND_OPER:
1986 if (SILC_STATUS_IS_ERROR(status)) {
1987 silc_say_error("OPER: %s", silc_get_status_message(status));
1991 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1992 signal_emit("user mode changed", 2, server, NULL);
1994 printformat_module("fe-common/silc", server, NULL,
1995 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1998 case SILC_COMMAND_SILCOPER:
1999 if (SILC_STATUS_IS_ERROR(status)) {
2000 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
2004 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2005 signal_emit("user mode changed", 2, server, NULL);
2007 printformat_module("fe-common/silc", server, NULL,
2008 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2011 case SILC_COMMAND_USERS:
2013 SilcHashTableList htl;
2014 SilcChannelEntry channel;
2015 SilcChannelUser chu;
2017 if (SILC_STATUS_IS_ERROR(status)) {
2018 silc_say_error("USERS: %s", silc_get_status_message(status));
2022 channel = va_arg(vp, SilcChannelEntry);
2024 printformat_module("fe-common/silc", server, channel->channel_name,
2025 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2026 channel->channel_name);
2028 silc_hash_table_list(channel->user_list, &htl);
2029 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2030 SilcClientEntry e = chu->client;
2031 char stat[5], *mode;
2033 if (!e->nickname[0])
2036 memset(stat, 0, sizeof(stat));
2037 mode = silc_client_chumode_char(chu->mode);
2038 if (e->mode & SILC_UMODE_GONE)
2040 else if (e->mode & SILC_UMODE_INDISPOSED)
2042 else if (e->mode & SILC_UMODE_BUSY)
2044 else if (e->mode & SILC_UMODE_PAGE)
2046 else if (e->mode & SILC_UMODE_HYPER)
2048 else if (e->mode & SILC_UMODE_ROBOT)
2050 else if (e->mode & SILC_UMODE_ANONYMOUS)
2057 printformat_module("fe-common/silc", server, channel->channel_name,
2058 MSGLEVEL_CRAP, SILCTXT_USERS,
2060 e->username[0] ? e->username : "",
2061 e->hostname[0] ? e->hostname : "",
2062 e->realname ? e->realname : "");
2066 silc_hash_table_list_reset(&htl);
2070 case SILC_COMMAND_BAN:
2072 SilcChannelEntry channel;
2073 SilcArgumentPayload invite_list;
2075 if (SILC_STATUS_IS_ERROR(status))
2078 channel = va_arg(vp, SilcChannelEntry);
2079 invite_list = va_arg(vp, SilcArgumentPayload);
2082 silc_parse_inviteban_list(client, conn, server, channel,
2083 "ban", invite_list);
2087 case SILC_COMMAND_GETKEY:
2091 SilcPublicKey public_key;
2092 GetkeyContext getkey;
2095 if (SILC_STATUS_IS_ERROR(status)) {
2096 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2100 id_type = va_arg(vp, SilcUInt32);
2101 entry = va_arg(vp, void *);
2102 public_key = va_arg(vp, SilcPublicKey);
2105 getkey = silc_calloc(1, sizeof(*getkey));
2106 getkey->entry = entry;
2107 getkey->id_type = id_type;
2108 getkey->client = client;
2109 getkey->conn = conn;
2111 name = (id_type == SILC_ID_CLIENT ?
2112 ((SilcClientEntry)entry)->nickname :
2113 ((SilcServerEntry)entry)->server_name);
2117 case SILC_ID_CLIENT:
2118 name = ((SilcClientEntry)entry)->nickname;
2119 silc_client_ref_client(client, conn, (SilcClientEntry)entry);
2122 case SILC_ID_SERVER:
2123 name = ((SilcServerEntry)entry)->server_name;
2124 silc_client_ref_server(client, conn, (SilcServerEntry)entry);
2128 silc_verify_public_key_internal(client, conn, name,
2129 (id_type == SILC_ID_CLIENT ?
2132 public_key, silc_getkey_cb, getkey);
2134 printformat_module("fe-common/silc", server, NULL,
2135 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2140 case SILC_COMMAND_INFO:
2142 SilcServerEntry server_entry;
2146 if (SILC_STATUS_IS_ERROR(status))
2149 server_entry = va_arg(vp, SilcServerEntry);
2150 server_name = va_arg(vp, char *);
2151 server_info = va_arg(vp, char *);
2153 if (server_name && server_info )
2155 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2156 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2161 case SILC_COMMAND_TOPIC:
2163 SilcChannelEntry channel;
2165 char tmp[256], *cp, *dm = NULL;
2167 if (SILC_STATUS_IS_ERROR(status))
2170 channel = va_arg(vp, SilcChannelEntry);
2171 topic = va_arg(vp, char *);
2173 if (topic && !silc_term_utf8() &&
2174 silc_utf8_valid(topic, strlen(topic))) {
2175 memset(tmp, 0, sizeof(tmp));
2177 if (strlen(topic) > sizeof(tmp) - 1) {
2178 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2182 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2188 chanrec = silc_channel_find_entry(server, channel);
2190 g_free_not_null(chanrec->topic);
2191 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2192 signal_emit("channel topic changed", 1, chanrec);
2194 printformat_module("fe-common/silc", server, channel->channel_name,
2195 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2196 channel->channel_name, topic);
2198 printformat_module("fe-common/silc", server, channel->channel_name,
2199 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2200 channel->channel_name);
2206 case SILC_COMMAND_WATCH:
2209 case SILC_COMMAND_STATS:
2211 SilcClientStats *cstats;
2213 const char *tmptime;
2214 int days, hours, mins, secs;
2216 if (SILC_STATUS_IS_ERROR(status))
2219 cstats = va_arg(vp, SilcClientStats *);
2221 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2225 tmptime = silc_time_string(cstats->starttime);
2226 printformat_module("fe-common/silc", server, NULL,
2227 MSGLEVEL_CRAP, SILCTXT_STATS,
2228 "Local server start time", tmptime);
2230 days = cstats->uptime / (24 * 60 * 60);
2231 cstats->uptime -= days * (24 * 60 * 60);
2232 hours = cstats->uptime / (60 * 60);
2233 cstats->uptime -= hours * (60 * 60);
2234 mins = cstats->uptime / 60;
2235 cstats->uptime -= mins * 60;
2236 secs = cstats->uptime;
2237 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2238 days, hours, mins, secs);
2239 printformat_module("fe-common/silc", server, NULL,
2240 MSGLEVEL_CRAP, SILCTXT_STATS,
2241 "Local server uptime", tmp);
2243 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2244 printformat_module("fe-common/silc", server, NULL,
2245 MSGLEVEL_CRAP, SILCTXT_STATS,
2246 "Local server clients", tmp);
2248 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2249 printformat_module("fe-common/silc", server, NULL,
2250 MSGLEVEL_CRAP, SILCTXT_STATS,
2251 "Local server channels", tmp);
2253 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2254 printformat_module("fe-common/silc", server, NULL,
2255 MSGLEVEL_CRAP, SILCTXT_STATS,
2256 "Local server operators", tmp);
2258 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2259 printformat_module("fe-common/silc", server, NULL,
2260 MSGLEVEL_CRAP, SILCTXT_STATS,
2261 "Local router operators", tmp);
2263 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2264 printformat_module("fe-common/silc", server, NULL,
2265 MSGLEVEL_CRAP, SILCTXT_STATS,
2266 "Local cell clients", tmp);
2268 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2269 printformat_module("fe-common/silc", server, NULL,
2270 MSGLEVEL_CRAP, SILCTXT_STATS,
2271 "Local cell channels", tmp);
2273 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2274 printformat_module("fe-common/silc", server, NULL,
2275 MSGLEVEL_CRAP, SILCTXT_STATS,
2276 "Local cell servers", tmp);
2278 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2279 printformat_module("fe-common/silc", server, NULL,
2280 MSGLEVEL_CRAP, SILCTXT_STATS,
2281 "Total clients", tmp);
2283 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2284 printformat_module("fe-common/silc", server, NULL,
2285 MSGLEVEL_CRAP, SILCTXT_STATS,
2286 "Total channels", tmp);
2288 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2289 printformat_module("fe-common/silc", server, NULL,
2290 MSGLEVEL_CRAP, SILCTXT_STATS,
2291 "Total servers", tmp);
2293 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2294 printformat_module("fe-common/silc", server, NULL,
2295 MSGLEVEL_CRAP, SILCTXT_STATS,
2296 "Total routers", tmp);
2298 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2299 printformat_module("fe-common/silc", server, NULL,
2300 MSGLEVEL_CRAP, SILCTXT_STATS,
2301 "Total server operators", tmp);
2303 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2304 printformat_module("fe-common/silc", server, NULL,
2305 MSGLEVEL_CRAP, SILCTXT_STATS,
2306 "Total router operators", tmp);
2310 case SILC_COMMAND_CMODE:
2312 SilcChannelEntry channel_entry;
2315 channel_entry = va_arg(vp, SilcChannelEntry);
2316 (void)va_arg(vp, SilcUInt32);
2317 (void)va_arg(vp, SilcPublicKey);
2318 chpks = va_arg(vp, SilcDList);
2320 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2321 !channel_entry || !channel_entry->channel_name)
2324 /* Print the channel public key list */
2326 silc_parse_channel_public_keys(server, channel_entry, chpks);
2328 printformat_module("fe-common/silc", server, NULL,
2329 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2330 channel_entry->channel_name);
2335 case SILC_COMMAND_LEAVE:
2337 if (SILC_STATUS_IS_ERROR(status))
2340 /* We might be cycling, so disable queueing again */
2341 silc_queue_disable(conn);
2345 case SILC_COMMAND_DETACH:
2347 /* Save the detachment data to file. */
2351 if (SILC_STATUS_IS_ERROR(status))
2354 detach = va_arg(vp, SilcBuffer);
2355 file = silc_get_session_filename(server);
2356 silc_file_writefile(file, silc_buffer_data(detach),
2357 silc_buffer_len(detach));
2362 case SILC_COMMAND_KILL:
2364 SilcClientEntry client_entry;
2366 if (SILC_STATUS_IS_ERROR(status)) {
2367 silc_say_error("KILL: %s", silc_get_status_message(status));
2371 client_entry = va_arg(vp, SilcClientEntry);
2372 if (!client_entry || !client_entry->nickname[0])
2375 /* Print this only if the killed client isn't joined on channels.
2376 If it is, we receive KILLED notify and we'll print this there. */
2377 if (!silc_hash_table_count(client_entry->channels))
2378 printformat_module("fe-common/silc", server, NULL,
2379 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2380 client_entry->nickname,
2381 conn->local_entry->nickname, "");
2388 SilcClientConnection conn;
2392 SilcPublicKey public_key;
2393 SilcVerifyPublicKey completion;
2397 static void verify_public_key_completion(const char *line, void *context,
2398 SilcKeyboardPromptStatus reason)
2400 PublicKeyVerify verify = (PublicKeyVerify)context;
2401 bool success = (reason == KeyboardCompletionSuccess);
2403 if (success && (line[0] == 'Y' || line[0] == 'y')) {
2404 /* Call the completion */
2405 if (verify->completion)
2406 verify->completion(TRUE, verify->context);
2408 /* Save the key for future checking */
2409 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2410 SILC_PKCS_FILE_BASE64);
2412 /* Call the completion */
2413 if (verify->completion)
2414 verify->completion(FALSE, verify->context);
2416 printformat_module("fe-common/silc", NULL, NULL,
2417 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2418 verify->entity_name ? verify->entity_name :
2423 * If we were not called due to a failure to begin the callback, then we
2424 * shall zero the async context block in the server record. If we were
2425 * called due to a failure to begin the callback, then it is possible that
2426 * we failed due to an overlapping callback, in which case we shouldn't
2427 * overwrite the async context block pointer.
2430 if (reason != KeyboardCompletionFailed)
2433 * Null out the completion context in the server record as this operation
2434 * is done as far as we are concerned. The underlying keyboard library
2435 * routine will take care of freeing the async context memory when the
2436 * actual callback is called by irssi in the abort case. In the success
2437 * case, it will free the async context memory after we return from this
2441 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
2443 server->prompt_op = NULL;
2446 silc_free(verify->filename);
2447 silc_free(verify->entity);
2448 silc_free(verify->entity_name);
2452 /* Internal routine to verify public key. If the `completion' is provided
2453 it will be called to indicate whether public was verified or not. For
2454 server/router public key this will check for filename that includes the
2455 remote host's IP address and remote host's hostname. */
2458 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2460 SilcConnectionType conn_type,
2461 SilcPublicKey public_key,
2462 SilcVerifyPublicKey completion, void *context)
2464 PublicKeyVerify verify;
2465 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2466 char *fingerprint, *babbleprint, *format;
2467 SilcPublicKey local_pubkey;
2468 SilcSILCPublicKey silc_pubkey;
2470 SILC_SERVER_REC *server;
2471 const char *hostname, *ip;
2476 char *entity = ((conn_type == SILC_CONN_SERVER ||
2477 conn_type == SILC_CONN_ROUTER) ?
2478 "server" : "client");
2481 server = (SILC_SERVER_REC*)conn->context;
2484 * If we don't have a context yet, then we'll set it up based on the
2485 * stream context associated with the SilcPacketStream that is attached
2486 * to the SilcClientConnection. This is a bit ugly, but we need to have a
2487 * per-connection context value to perform the public key verify operation,
2488 * and the public API was not designed to let us have this in a particularly
2489 * straightforward fashion.
2493 SilcPacketStream packet_stream;
2496 packet_stream = conn->stream;
2501 completion(FALSE, context);
2505 stream = silc_packet_stream_get_stream(packet_stream);
2510 completion(FALSE, context);
2514 server = (SILC_SERVER_REC*)(silc_socket_stream_get_context(stream));
2519 completion(FALSE, context);
2523 conn->context = (void *)server;
2526 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2527 printformat_module("fe-common/silc", NULL, NULL,
2528 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2529 entity, silc_pkcs_get_type(public_key));
2531 completion(FALSE, context);
2535 /* Encode public key */
2536 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2539 completion(FALSE, context);
2543 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2545 pw = getpwuid(getuid());
2548 completion(FALSE, context);
2553 memset(filename, 0, sizeof(filename));
2554 memset(filename2, 0, sizeof(filename2));
2555 memset(file, 0, sizeof(file));
2557 /* Get remote host information */
2558 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2559 NULL, &hostname, &ip, &port);
2561 if (conn_type == SILC_CONN_SERVER ||
2562 conn_type == SILC_CONN_ROUTER) {
2564 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2565 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2566 get_irssi_dir(), entity, file);
2568 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2570 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2571 get_irssi_dir(), entity, file);
2576 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2578 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2579 get_irssi_dir(), entity, file);
2584 /* Replace all whitespaces with `_'. */
2585 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2586 for (i = 0; i < strlen(fingerprint); i++)
2587 if (fingerprint[i] == ' ')
2588 fingerprint[i] = '_';
2590 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2591 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2592 get_irssi_dir(), entity, file);
2593 silc_free(fingerprint);
2598 /* Take fingerprint of the public key */
2599 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2600 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2602 verify = silc_calloc(1, sizeof(*verify));
2603 verify->client = client;
2604 verify->conn = conn;
2605 verify->filename = strdup(ipf);
2606 verify->entity = strdup(entity);
2607 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2608 (name ? strdup(name) : strdup(hostname))
2610 verify->public_key = public_key;
2611 verify->completion = completion;
2612 verify->context = context;
2614 /* Check whether this key already exists */
2615 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2616 /* Key does not exist, ask user to verify the key and save it */
2618 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2619 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2620 verify->entity_name : entity);
2621 if (conn_type == SILC_CONN_CLIENT && name &&
2622 silc_pubkey->identifier.realname)
2623 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2624 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2625 silc_pubkey->identifier.realname,
2626 silc_pubkey->identifier.email ?
2627 silc_pubkey->identifier.email : "");
2628 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2629 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2630 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2631 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2632 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2633 SILCTXT_PUBKEY_ACCEPT);
2634 silc_keyboard_entry_redirect(verify_public_key_completion,
2635 format, 0, verify, &server->prompt_op);
2637 silc_free(fingerprint);
2638 silc_free(babbleprint);
2642 /* The key already exists, verify it. */
2643 unsigned char *encpk;
2644 SilcUInt32 encpk_len;
2646 /* Load the key file, try for both IP filename and hostname filename */
2647 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2648 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2649 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2650 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2651 verify->entity_name : entity);
2652 if (conn_type == SILC_CONN_CLIENT && name &&
2653 silc_pubkey->identifier.realname)
2654 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2655 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2656 silc_pubkey->identifier.realname,
2657 silc_pubkey->identifier.email ?
2658 silc_pubkey->identifier.email : "");
2659 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2660 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2661 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2662 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2663 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2664 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2665 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2666 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2667 silc_keyboard_entry_redirect(verify_public_key_completion,
2668 format, 0, verify, &server->prompt_op);
2670 silc_free(fingerprint);
2671 silc_free(babbleprint);
2676 /* Encode the key data */
2677 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2679 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2680 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2681 verify->entity_name : entity);
2682 if (conn_type == SILC_CONN_CLIENT && name &&
2683 silc_pubkey->identifier.realname)
2684 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2685 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2686 silc_pubkey->identifier.realname,
2687 silc_pubkey->identifier.email ?
2688 silc_pubkey->identifier.email : "");
2689 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2690 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2691 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2692 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2693 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2694 SILCTXT_PUBKEY_MALFORMED, entity);
2695 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2696 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2697 silc_keyboard_entry_redirect(verify_public_key_completion,
2698 format, 0, verify, &server->prompt_op);
2700 silc_free(fingerprint);
2701 silc_free(babbleprint);
2705 silc_pkcs_public_key_free(local_pubkey);
2707 /* Compare the keys */
2708 if (memcmp(encpk, pk, encpk_len)) {
2709 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2710 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2711 verify->entity_name : entity);
2712 if (conn_type == SILC_CONN_CLIENT && name &&
2713 silc_pubkey->identifier.realname)
2714 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2715 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2716 silc_pubkey->identifier.realname,
2717 silc_pubkey->identifier.email ?
2718 silc_pubkey->identifier.email : "");
2719 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2720 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2721 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2722 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2723 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2724 SILCTXT_PUBKEY_NO_MATCH, entity);
2725 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2726 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2727 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2728 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2730 /* Ask user to verify the key and save it */
2731 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2732 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2733 silc_keyboard_entry_redirect(verify_public_key_completion,
2734 format, 0, verify, &server->prompt_op);
2736 silc_free(fingerprint);
2737 silc_free(babbleprint);
2743 /* Local copy matched */
2745 completion(TRUE, context);
2747 silc_free(fingerprint);
2748 silc_free(babbleprint);
2749 silc_free(verify->filename);
2750 silc_free(verify->entity);
2751 silc_free(verify->entity_name);
2757 /* Verifies received public key. The `conn_type' indicates which entity
2758 (server, client etc.) has sent the public key. If user decides to trust
2759 the key may be saved as trusted public key for later use. The
2760 `completion' must be called after the public key has been verified. */
2763 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2764 SilcConnectionType conn_type,
2765 SilcPublicKey public_key,
2766 SilcVerifyPublicKey completion, void *context)
2768 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2769 completion, context);
2772 /* Asks passphrase from user on the input line. */
2775 SilcAskPassphrase completion;
2776 SilcClientConnection conn;
2780 void ask_passphrase_completion(const char *passphrase, void *context,
2781 SilcKeyboardPromptStatus reason)
2783 AskPassphrase p = (AskPassphrase)context;
2784 if (passphrase && passphrase[0] == '\0')
2786 p->completion((unsigned char *)passphrase,
2787 passphrase ? strlen(passphrase) : 0, p->context);
2789 if (reason != KeyboardCompletionFailed)
2791 SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
2793 server->prompt_op = NULL;
2799 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2800 SilcAskPassphrase completion, void *context)
2802 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
2803 AskPassphrase p = silc_calloc(1, sizeof(*p));
2805 p->completion = completion;
2807 p->context = context;
2809 silc_keyboard_entry_redirect(ask_passphrase_completion,
2810 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p, &server->prompt_op);
2814 SilcGetAuthMeth completion;
2818 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2819 SilcUInt32 passphrase_len,
2822 GetAuthMethod a = context;
2823 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2824 passphrase, passphrase_len, a->context);
2828 /* Find authentication data by hostname and port. The hostname may be IP
2831 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2832 char *hostname, SilcUInt16 port,
2833 SilcAuthMethod auth_meth,
2834 SilcGetAuthMeth completion, void *context)
2836 SERVER_SETUP_REC *setup;
2838 SILC_LOG_DEBUG(("Start"));
2840 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2841 /* Returning NULL will cause library to use our private key configured
2842 for this connection */
2843 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2847 /* Check whether we find the password for this server in our
2848 configuration. If it's set, always send it server. */
2849 setup = server_setup_find_port(hostname, port);
2850 if (setup && setup->password) {
2851 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2856 /* Didn't find password. If server wants it, ask it from user. */
2857 if (auth_meth == SILC_AUTH_PASSWORD) {
2859 a = silc_calloc(1, sizeof(*a));
2861 a->completion = completion;
2862 a->context = context;
2863 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2868 /* No authentication */
2869 completion(SILC_AUTH_NONE, NULL, 0, context);
2872 /* Asks whether the user would like to perform the key agreement protocol.
2873 This is called after we have received an key agreement packet or an
2874 reply to our key agreement packet. This returns TRUE if the user wants
2875 the library to perform the key agreement protocol and FALSE if it is not
2876 desired (application may start it later by calling the function
2877 silc_client_perform_key_agreement). */
2879 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2880 SilcClientEntry client_entry, const char *hostname,
2881 SilcUInt16 protocol, SilcUInt16 port)
2883 char portstr[12], protostr[5];
2885 SILC_LOG_DEBUG(("Start"));
2887 /* We will just display the info on the screen and return FALSE and user
2888 will have to start the key agreement with a command. */
2891 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2892 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2897 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2898 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2900 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2901 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2902 client_entry->nickname, hostname, portstr, protostr);
2905 /* Notifies application that file transfer protocol session is being
2906 requested by the remote client indicated by the `client_entry' from
2907 the `hostname' and `port'. The `session_id' is the file transfer
2908 session and it can be used to either accept or reject the file
2909 transfer request, by calling the silc_client_file_receive or
2910 silc_client_file_close, respectively. */
2912 void silc_ftp(SilcClient client, SilcClientConnection conn,
2913 SilcClientEntry client_entry, SilcUInt32 session_id,
2914 const char *hostname, SilcUInt16 port)
2916 SILC_SERVER_REC *server;
2918 FtpSession ftp = NULL;
2920 SILC_LOG_DEBUG(("Start"));
2922 server = conn->context;
2924 silc_dlist_start(server->ftp_sessions);
2925 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2926 if (ftp->client_entry == client_entry &&
2927 ftp->session_id == session_id) {
2928 server->current_session = ftp;
2932 if (ftp == SILC_LIST_END) {
2933 ftp = silc_calloc(1, sizeof(*ftp));
2934 ftp->client_entry = client_entry;
2935 ftp->session_id = session_id;
2938 silc_dlist_add(server->ftp_sessions, ftp);
2939 server->current_session = ftp;
2943 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2946 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2947 SILCTXT_FILE_REQUEST, client_entry->nickname);
2949 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2950 SILCTXT_FILE_REQUEST_HOST,
2951 client_entry->nickname, hostname, portstr);
2954 /* SILC client operations */
2955 SilcClientOperations ops = {
2957 silc_channel_message,
2958 silc_private_message,
2962 silc_get_auth_method,
2963 silc_verify_public_key,
2964 silc_ask_passphrase,