5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2008 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) {
1446 case SILC_ID_CLIENT:
1447 silc_client_unref_client(getkey->client, getkey->conn,
1448 (SilcClientEntry)getkey->entry);
1451 case SILC_ID_SERVER:
1452 silc_client_unref_server(getkey->client, getkey->conn,
1453 (SilcServerEntry)getkey->entry);
1460 /* Parse an invite or ban list */
1461 void silc_parse_inviteban_list(SilcClient client,
1462 SilcClientConnection conn,
1463 SILC_SERVER_REC *server,
1464 SilcChannelEntry channel,
1465 const char *list_type,
1466 SilcArgumentPayload list)
1469 SilcUInt32 type, len;
1470 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1471 int counter=0, resolving = FALSE;
1473 if (!silc_argument_get_arg_num(list)) {
1474 printformat_module("fe-common/silc", server,
1475 (chanrec ? chanrec->visible_name : NULL),
1476 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1477 channel->channel_name, list_type);
1481 printformat_module("fe-common/silc", server,
1482 (chanrec ? chanrec->visible_name : NULL),
1483 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1484 channel->channel_name, list_type);
1486 /* Parse the list */
1487 tmp = silc_argument_get_first_arg(list, &type, &len);
1492 /* An invite string */
1496 if (tmp[len-1] == ',')
1499 list = g_strsplit(tmp, ",", -1);
1501 printformat_module("fe-common/silc", server,
1502 (chanrec ? chanrec->visible_name : NULL),
1503 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1504 ++counter, channel->channel_name, list_type,
1513 char *fingerprint, *babbleprint;
1515 /* tmp is Public Key Payload, take public key from it. */
1516 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1517 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1519 printformat_module("fe-common/silc", server,
1520 (chanrec ? chanrec->visible_name : NULL),
1521 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1522 ++counter, channel->channel_name, list_type,
1523 fingerprint, babbleprint);
1530 SilcClientEntry client_entry;
1533 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1534 silc_say_error("Invalid data in %s list encountered", list_type);
1538 client_entry = silc_client_get_client_by_id(client, conn,
1541 printformat_module("fe-common/silc", server,
1542 (chanrec ? chanrec->visible_name : NULL),
1543 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1544 ++counter, channel->channel_name, list_type,
1545 client_entry->nickname);
1546 silc_client_unref_client(client, conn, client_entry);
1549 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1557 silc_say_error("Unkown type in %s list: %u (len %u)",
1558 list_type, type, len);
1561 tmp = silc_argument_get_next_arg(list, &type, &len);
1565 printformat_module("fe-common/silc", server,
1566 (chanrec ? chanrec->visible_name : NULL),
1567 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1568 list_type, channel->channel_name);
1571 /* Command reply handler. This function is called always in the command reply
1572 function. If error occurs it will be called as well. Normal scenario
1573 is that it will be called after the received command data has been parsed
1574 and processed. The function is used to pass the received command data to
1577 `conn' is the associated client connection. `cmd_payload' is the command
1578 payload data received from server and it can be ignored. It is provided
1579 if the application would like to re-parse the received command data,
1580 however, it must be noted that the data is parsed already by the library
1581 thus the payload can be ignored. `success' is FALSE if error occured.
1582 In this case arguments are not sent to the application. `command' is the
1583 command reply being processed. The function has variable argument list
1584 and each command defines the number and type of arguments it passes to the
1585 application (on error they are not sent). */
1587 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1588 SilcCommand command, SilcStatus status,
1589 SilcStatus error, va_list vp)
1591 SILC_SERVER_REC *server = conn->context;
1592 SILC_CHANNEL_REC *chanrec;
1594 SILC_LOG_DEBUG(("Start"));
1597 case SILC_COMMAND_WHOIS:
1599 char buf[1024], *nickname, *username, *realname, *nick;
1600 unsigned char *fingerprint;
1601 SilcUInt32 idle, mode, *user_modes;
1603 SilcClientEntry client_entry;
1606 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1607 /* Print the unknown nick for user */
1608 char *tmp = va_arg(vp, char *);
1610 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1612 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1613 /* Try to find the entry for the unknown client ID, since we
1614 might have, and print the nickname of it for user. */
1615 SilcClientID *id = va_arg(vp, SilcClientID *);
1617 client_entry = silc_client_get_client_by_id(client, conn, id);
1618 if (client_entry && client_entry->nickname[0])
1619 silc_say_error("%s: %s", client_entry->nickname,
1620 silc_get_status_message(status));
1621 silc_client_unref_client(client, conn, client_entry);
1624 } else if (SILC_STATUS_IS_ERROR(status)) {
1625 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1629 client_entry = va_arg(vp, SilcClientEntry);
1630 nickname = va_arg(vp, char *);
1631 username = va_arg(vp, char *);
1632 realname = va_arg(vp, char *);
1633 channels = va_arg(vp, SilcDList);
1634 mode = va_arg(vp, SilcUInt32);
1635 idle = va_arg(vp, SilcUInt32);
1636 fingerprint = va_arg(vp, unsigned char *);
1637 user_modes = va_arg(vp, SilcUInt32 *);
1638 attrs = va_arg(vp, SilcDList);
1640 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1641 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1642 SILCTXT_WHOIS_USERINFO, nickname,
1643 client_entry->username, client_entry->hostname,
1644 nick, client_entry->nickname);
1645 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1646 SILCTXT_WHOIS_REALNAME, realname);
1649 if (channels && user_modes) {
1650 SilcChannelPayload entry;
1653 memset(buf, 0, sizeof(buf));
1654 silc_dlist_start(channels);
1655 while ((entry = silc_dlist_get(channels))) {
1656 SilcUInt32 name_len;
1657 char *m = silc_client_chumode_char(user_modes[i++]);
1658 char *name = silc_channel_get_name(entry, &name_len);
1661 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1662 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1663 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1667 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1668 SILCTXT_WHOIS_CHANNELS, buf);
1672 memset(buf, 0, sizeof(buf));
1673 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1674 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1675 SILCTXT_WHOIS_MODES, buf);
1678 if (idle && nickname) {
1679 memset(buf, 0, sizeof(buf));
1680 snprintf(buf, sizeof(buf) - 1, "%u %s",
1681 idle > 60 ? (idle / 60) : idle,
1682 idle > 60 ? "minutes" : "seconds");
1684 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1685 SILCTXT_WHOIS_IDLE, buf);
1689 fingerprint = silc_fingerprint(fingerprint, 20);
1690 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1691 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1692 silc_free(fingerprint);
1696 silc_query_attributes_print(server, silc_client, conn, attrs,
1701 case SILC_COMMAND_WHOWAS:
1703 char *nickname, *username, *realname;
1705 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1706 char *tmp = va_arg(vp, char *);
1708 silc_say_error("%s: %s", tmp,
1709 silc_get_status_message(status));
1711 } else if (SILC_STATUS_IS_ERROR(status)) {
1712 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1716 (void)va_arg(vp, SilcClientEntry);
1717 nickname = va_arg(vp, char *);
1718 username = va_arg(vp, char *);
1719 realname = va_arg(vp, char *);
1721 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1722 SILCTXT_WHOWAS_USERINFO, nickname, username,
1723 realname ? realname : "");
1727 case SILC_COMMAND_INVITE:
1729 SilcChannelEntry channel;
1730 SilcArgumentPayload invite_list;
1732 if (SILC_STATUS_IS_ERROR(status))
1735 channel = va_arg(vp, SilcChannelEntry);
1736 invite_list = va_arg(vp, SilcArgumentPayload);
1739 silc_parse_inviteban_list(client, conn, server, channel,
1740 "invite", invite_list);
1744 case SILC_COMMAND_JOIN:
1746 char *channel, *mode, *topic, *cipher, *hmac;
1748 SilcHashTableList *user_list;
1749 SilcChannelEntry channel_entry;
1750 SilcChannelUser chu;
1751 SilcClientEntry founder = NULL;
1754 if (SILC_STATUS_IS_ERROR(status)) {
1755 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
1756 char *tmp = va_arg(vp, char *);
1758 silc_say_error("JOIN: %s: %s", tmp,
1759 silc_get_status_message(status));
1762 if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
1763 char *tmp = va_arg(vp, char *);
1765 silc_say_error("JOIN: %s: %s", tmp,
1766 silc_get_status_message(status));
1769 silc_say_error("JOIN: %s", silc_get_status_message(status));
1773 channel = va_arg(vp, char *);
1774 channel_entry = va_arg(vp, SilcChannelEntry);
1775 modei = va_arg(vp, SilcUInt32);
1776 user_list = va_arg(vp, SilcHashTableList *);
1777 topic = va_arg(vp, char *);
1778 cipher = va_arg(vp, char *);
1779 hmac = va_arg(vp, char *);
1781 chanrec = silc_channel_find(server, channel);
1783 chanrec = silc_channel_create(server, channel, channel, TRUE);
1786 char tmp[256], *cp, *dm = NULL;
1787 g_free_not_null(chanrec->topic);
1789 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1790 memset(tmp, 0, sizeof(tmp));
1792 if (strlen(topic) > sizeof(tmp) - 1) {
1793 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1797 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1802 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1803 signal_emit("channel topic changed", 1, chanrec);
1808 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1809 g_free_not_null(chanrec->mode);
1810 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1811 signal_emit("channel mode changed", 1, chanrec);
1814 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1815 if (!chu->client->nickname[0])
1817 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1818 founder = chu->client;
1819 silc_nicklist_insert(chanrec, chu, FALSE);
1822 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1825 nicklist_set_own(CHANNEL(chanrec), ownnick);
1826 chanrec->entry = channel_entry;
1827 signal_emit("channel joined", 1, chanrec);
1830 printformat_module("fe-common/silc", server,
1831 channel_entry->channel_name,
1832 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1833 channel_entry->channel_name, chanrec->topic);
1836 if (founder == conn->local_entry) {
1837 printformat_module("fe-common/silc",
1838 server, channel_entry->channel_name,
1839 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1840 channel_entry->channel_name);
1841 signal_emit("nick mode changed", 2, chanrec, ownnick);
1843 printformat_module("fe-common/silc",
1844 server, channel_entry->channel_name,
1845 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1846 channel_entry->channel_name, founder->nickname);
1852 case SILC_COMMAND_NICK:
1855 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1858 if (SILC_STATUS_IS_ERROR(status)) {
1859 silc_say_error("NICK: %s", silc_get_status_message(status));
1863 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1864 if ((nicks != NULL) &&
1865 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1867 SilcClientEntry collider, old;
1869 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1870 collider = silc_client_get_client_by_id(client, conn, &old->id);
1871 if (collider != client_entry) {
1872 memset(buf, 0, sizeof(buf));
1873 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1874 collider->username, collider->hostname);
1875 nicklist_rename_unique(SERVER(server),
1877 collider, collider->nickname);
1878 silc_print_nick_change(server, collider->nickname,
1879 client_entry->nickname, buf);
1881 silc_client_unref_client(client, conn, collider);
1885 g_slist_free(nicks);
1887 old = g_strdup(server->nick);
1888 server_change_nick(SERVER(server), client_entry->nickname);
1889 nicklist_rename_unique(SERVER(server),
1890 server->conn->local_entry, server->nick,
1891 client_entry, client_entry->nickname);
1892 signal_emit("message own_nick", 4, server, server->nick, old, "");
1895 /* when connecting to a server, the last thing we receive
1896 is a SILC_COMMAND_LIST reply. Since we enable queueing
1897 during the connection, we can now safely disable it again */
1898 silc_queue_disable(conn);
1902 case SILC_COMMAND_LIST:
1907 char tmp[256], *cp, *dm = NULL;
1909 if (SILC_STATUS_IS_ERROR(status))
1912 (void)va_arg(vp, SilcChannelEntry);
1913 name = va_arg(vp, char *);
1914 topic = va_arg(vp, char *);
1915 usercount = va_arg(vp, int);
1917 if (topic && !silc_term_utf8() &&
1918 silc_utf8_valid(topic, strlen(topic))) {
1919 memset(tmp, 0, sizeof(tmp));
1921 if (strlen(topic) > sizeof(tmp) - 1) {
1922 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1926 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1931 if (status == SILC_STATUS_LIST_START ||
1932 status == SILC_STATUS_OK)
1933 printformat_module("fe-common/silc", server, NULL,
1934 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1937 snprintf(users, sizeof(users) - 1, "N/A");
1939 snprintf(users, sizeof(users) - 1, "%d", usercount);
1940 printformat_module("fe-common/silc", server, NULL,
1941 MSGLEVEL_CRAP, SILCTXT_LIST,
1942 name, users, topic ? topic : "");
1947 case SILC_COMMAND_UMODE:
1952 if (SILC_STATUS_IS_ERROR(status))
1955 mode = va_arg(vp, SilcUInt32);
1957 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1958 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1959 printformat_module("fe-common/silc", server, NULL,
1960 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1962 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1963 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1964 printformat_module("fe-common/silc", server, NULL,
1965 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1967 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1968 if (mode & SILC_UMODE_GONE) {
1969 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1970 reason = g_strdup(server->away_reason);
1972 reason = g_strdup("away");
1974 reason = g_strdup("");
1976 silc_set_away(reason, server);
1981 server->umode = mode;
1982 signal_emit("user mode changed", 2, server, NULL);
1986 case SILC_COMMAND_OPER:
1987 if (SILC_STATUS_IS_ERROR(status)) {
1988 silc_say_error("OPER: %s", silc_get_status_message(status));
1992 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1993 signal_emit("user mode changed", 2, server, NULL);
1995 printformat_module("fe-common/silc", server, NULL,
1996 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1999 case SILC_COMMAND_SILCOPER:
2000 if (SILC_STATUS_IS_ERROR(status)) {
2001 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
2005 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2006 signal_emit("user mode changed", 2, server, NULL);
2008 printformat_module("fe-common/silc", server, NULL,
2009 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2012 case SILC_COMMAND_USERS:
2014 SilcHashTableList htl;
2015 SilcChannelEntry channel;
2016 SilcChannelUser chu;
2018 if (SILC_STATUS_IS_ERROR(status)) {
2019 silc_say_error("USERS: %s", silc_get_status_message(status));
2023 channel = va_arg(vp, SilcChannelEntry);
2025 printformat_module("fe-common/silc", server, channel->channel_name,
2026 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2027 channel->channel_name);
2029 silc_hash_table_list(channel->user_list, &htl);
2030 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2031 SilcClientEntry e = chu->client;
2032 char stat[5], *mode;
2034 if (!e->nickname[0])
2037 memset(stat, 0, sizeof(stat));
2038 mode = silc_client_chumode_char(chu->mode);
2039 if (e->mode & SILC_UMODE_GONE)
2041 else if (e->mode & SILC_UMODE_INDISPOSED)
2043 else if (e->mode & SILC_UMODE_BUSY)
2045 else if (e->mode & SILC_UMODE_PAGE)
2047 else if (e->mode & SILC_UMODE_HYPER)
2049 else if (e->mode & SILC_UMODE_ROBOT)
2051 else if (e->mode & SILC_UMODE_ANONYMOUS)
2058 printformat_module("fe-common/silc", server, channel->channel_name,
2059 MSGLEVEL_CRAP, SILCTXT_USERS,
2061 e->username[0] ? e->username : "",
2062 e->hostname[0] ? e->hostname : "",
2063 e->realname ? e->realname : "");
2067 silc_hash_table_list_reset(&htl);
2071 case SILC_COMMAND_BAN:
2073 SilcChannelEntry channel;
2074 SilcArgumentPayload invite_list;
2076 if (SILC_STATUS_IS_ERROR(status))
2079 channel = va_arg(vp, SilcChannelEntry);
2080 invite_list = va_arg(vp, SilcArgumentPayload);
2083 silc_parse_inviteban_list(client, conn, server, channel,
2084 "ban", invite_list);
2088 case SILC_COMMAND_GETKEY:
2092 SilcPublicKey public_key;
2093 GetkeyContext getkey;
2096 if (SILC_STATUS_IS_ERROR(status)) {
2097 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2101 id_type = va_arg(vp, SilcUInt32);
2102 entry = va_arg(vp, void *);
2103 public_key = va_arg(vp, SilcPublicKey);
2106 getkey = silc_calloc(1, sizeof(*getkey));
2107 getkey->entry = entry;
2108 getkey->id_type = id_type;
2109 getkey->client = client;
2110 getkey->conn = conn;
2112 name = (id_type == SILC_ID_CLIENT ?
2113 ((SilcClientEntry)entry)->nickname :
2114 ((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 SilcBool 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.
2429 if (reason != KeyboardCompletionFailed) {
2431 * Null out the completion context in the server record as this operation
2432 * is done as far as we are concerned. The underlying keyboard library
2433 * routine will take care of freeing the async context memory when the
2434 * actual callback is called by irssi in the abort case. In the success
2435 * case, it will free the async context memory after we return from this
2438 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
2439 server->prompt_op = NULL;
2442 silc_free(verify->filename);
2443 silc_free(verify->entity);
2444 silc_free(verify->entity_name);
2448 /* Internal routine to verify public key. If the `completion' is provided
2449 it will be called to indicate whether public was verified or not. For
2450 server/router public key this will check for filename that includes the
2451 remote host's IP address and remote host's hostname. */
2454 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2456 SilcConnectionType conn_type,
2457 SilcPublicKey public_key,
2458 SilcVerifyPublicKey completion, void *context)
2460 PublicKeyVerify verify;
2461 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2462 char *fingerprint, *babbleprint, *format;
2463 SilcPublicKey local_pubkey;
2464 SilcSILCPublicKey silc_pubkey;
2466 SILC_SERVER_REC *server;
2467 const char *hostname, *ip;
2472 char *entity = ((conn_type == SILC_CONN_SERVER ||
2473 conn_type == SILC_CONN_ROUTER) ?
2474 "server" : "client");
2477 server = (SILC_SERVER_REC*)conn->context;
2478 SILC_VERIFY(server);
2481 completion(FALSE, context);
2485 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2486 printformat_module("fe-common/silc", NULL, NULL,
2487 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2488 entity, silc_pkcs_get_type(public_key));
2490 completion(FALSE, context);
2494 /* Encode public key */
2495 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2498 completion(FALSE, context);
2502 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2504 pw = getpwuid(getuid());
2507 completion(FALSE, context);
2512 memset(filename, 0, sizeof(filename));
2513 memset(filename2, 0, sizeof(filename2));
2514 memset(file, 0, sizeof(file));
2516 /* Get remote host information */
2517 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2518 NULL, &hostname, &ip, &port);
2520 if (conn_type == SILC_CONN_SERVER ||
2521 conn_type == SILC_CONN_ROUTER) {
2523 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2524 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2525 get_irssi_dir(), entity, file);
2527 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2529 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2530 get_irssi_dir(), entity, file);
2535 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2537 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2538 get_irssi_dir(), entity, file);
2543 /* Replace all whitespaces with `_'. */
2544 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2545 for (i = 0; i < strlen(fingerprint); i++)
2546 if (fingerprint[i] == ' ')
2547 fingerprint[i] = '_';
2549 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2550 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2551 get_irssi_dir(), entity, file);
2552 silc_free(fingerprint);
2557 /* Take fingerprint of the public key */
2558 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2559 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2561 verify = silc_calloc(1, sizeof(*verify));
2562 verify->client = client;
2563 verify->conn = conn;
2564 verify->filename = strdup(ipf);
2565 verify->entity = strdup(entity);
2566 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2567 (name ? strdup(name) : strdup(hostname))
2569 verify->public_key = public_key;
2570 verify->completion = completion;
2571 verify->context = context;
2573 /* Check whether this key already exists */
2574 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2575 /* Key does not exist, ask user to verify the key and save it */
2577 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2578 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2579 verify->entity_name : entity);
2580 if (conn_type == SILC_CONN_CLIENT && name &&
2581 silc_pubkey->identifier.realname)
2582 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2583 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2584 silc_pubkey->identifier.realname,
2585 silc_pubkey->identifier.email ?
2586 silc_pubkey->identifier.email : "");
2587 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2588 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2589 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2590 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2591 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2592 SILCTXT_PUBKEY_ACCEPT);
2593 silc_keyboard_entry_redirect(verify_public_key_completion,
2594 format, 0, verify, &server->prompt_op);
2596 silc_free(fingerprint);
2597 silc_free(babbleprint);
2601 /* The key already exists, verify it. */
2602 unsigned char *encpk;
2603 SilcUInt32 encpk_len;
2605 /* Load the key file, try for both IP filename and hostname filename */
2606 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2607 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2608 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2609 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2610 verify->entity_name : entity);
2611 if (conn_type == SILC_CONN_CLIENT && name &&
2612 silc_pubkey->identifier.realname)
2613 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2614 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2615 silc_pubkey->identifier.realname,
2616 silc_pubkey->identifier.email ?
2617 silc_pubkey->identifier.email : "");
2618 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2619 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2620 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2621 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2622 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2623 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2624 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2625 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2626 silc_keyboard_entry_redirect(verify_public_key_completion,
2627 format, 0, verify, &server->prompt_op);
2629 silc_free(fingerprint);
2630 silc_free(babbleprint);
2635 /* Encode the key data */
2636 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2638 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2639 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2640 verify->entity_name : entity);
2641 if (conn_type == SILC_CONN_CLIENT && name &&
2642 silc_pubkey->identifier.realname)
2643 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2644 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2645 silc_pubkey->identifier.realname,
2646 silc_pubkey->identifier.email ?
2647 silc_pubkey->identifier.email : "");
2648 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2649 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2650 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2651 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2652 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2653 SILCTXT_PUBKEY_MALFORMED, entity);
2654 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2655 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2656 silc_keyboard_entry_redirect(verify_public_key_completion,
2657 format, 0, verify, &server->prompt_op);
2659 silc_free(fingerprint);
2660 silc_free(babbleprint);
2664 silc_pkcs_public_key_free(local_pubkey);
2666 /* Compare the keys */
2667 if (memcmp(encpk, pk, encpk_len)) {
2668 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2669 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2670 verify->entity_name : entity);
2671 if (conn_type == SILC_CONN_CLIENT && name &&
2672 silc_pubkey->identifier.realname)
2673 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2674 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2675 silc_pubkey->identifier.realname,
2676 silc_pubkey->identifier.email ?
2677 silc_pubkey->identifier.email : "");
2678 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2679 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2680 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2681 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2682 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2683 SILCTXT_PUBKEY_NO_MATCH, entity);
2684 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2685 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2686 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2687 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2689 /* Ask user to verify the key and save it */
2690 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2691 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2692 silc_keyboard_entry_redirect(verify_public_key_completion,
2693 format, 0, verify, &server->prompt_op);
2695 silc_free(fingerprint);
2696 silc_free(babbleprint);
2702 /* Local copy matched */
2704 completion(TRUE, context);
2706 silc_free(fingerprint);
2707 silc_free(babbleprint);
2708 silc_free(verify->filename);
2709 silc_free(verify->entity);
2710 silc_free(verify->entity_name);
2716 /* Verifies received public key. The `conn_type' indicates which entity
2717 (server, client etc.) has sent the public key. If user decides to trust
2718 the key may be saved as trusted public key for later use. The
2719 `completion' must be called after the public key has been verified. */
2722 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2723 SilcConnectionType conn_type,
2724 SilcPublicKey public_key,
2725 SilcVerifyPublicKey completion, void *context)
2727 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2728 completion, context);
2731 /* Asks passphrase from user on the input line. */
2734 SilcAskPassphrase completion;
2735 SilcClientConnection conn;
2739 void ask_passphrase_completion(const char *passphrase, void *context,
2740 SilcKeyboardPromptStatus reason)
2742 AskPassphrase p = (AskPassphrase)context;
2743 if (passphrase && passphrase[0] == '\0')
2745 p->completion((unsigned char *)passphrase,
2746 passphrase ? strlen(passphrase) : 0, p->context);
2748 if (reason != KeyboardCompletionFailed) {
2749 SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
2750 server->prompt_op = NULL;
2756 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2757 SilcAskPassphrase completion, void *context)
2759 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
2762 p = silc_calloc(1, sizeof(*p));
2765 completion(NULL, 0, context);
2769 p->completion = completion;
2771 p->context = context;
2773 silc_keyboard_entry_redirect(ask_passphrase_completion,
2774 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN,
2775 p, &server->prompt_op);
2779 SilcGetAuthMeth completion;
2783 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2784 SilcUInt32 passphrase_len,
2787 GetAuthMethod a = context;
2788 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2789 passphrase, passphrase_len, a->context);
2793 /* Find authentication data by hostname and port. The hostname may be IP
2796 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2797 char *hostname, SilcUInt16 port,
2798 SilcAuthMethod auth_meth,
2799 SilcGetAuthMeth completion, void *context)
2801 SERVER_SETUP_REC *setup;
2803 SILC_LOG_DEBUG(("Start"));
2805 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2806 /* Returning NULL will cause library to use our private key configured
2807 for this connection */
2808 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2812 /* Check whether we find the password for this server in our
2813 configuration. If it's set, always send it server. */
2814 setup = server_setup_find_port(hostname, port);
2815 if (setup && setup->password) {
2816 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2821 /* Didn't find password. If server wants it, ask it from user. */
2822 if (auth_meth == SILC_AUTH_PASSWORD) {
2824 a = silc_calloc(1, sizeof(*a));
2826 a->completion = completion;
2827 a->context = context;
2828 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2833 /* No authentication */
2834 completion(SILC_AUTH_NONE, NULL, 0, context);
2837 /* Asks whether the user would like to perform the key agreement protocol.
2838 This is called after we have received an key agreement packet or an
2839 reply to our key agreement packet. This returns TRUE if the user wants
2840 the library to perform the key agreement protocol and FALSE if it is not
2841 desired (application may start it later by calling the function
2842 silc_client_perform_key_agreement). */
2844 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2845 SilcClientEntry client_entry, const char *hostname,
2846 SilcUInt16 protocol, SilcUInt16 port)
2848 char portstr[12], protostr[5];
2850 SILC_LOG_DEBUG(("Start"));
2852 /* We will just display the info on the screen and return FALSE and user
2853 will have to start the key agreement with a command. */
2856 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2857 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2862 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2863 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2865 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2866 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2867 client_entry->nickname, hostname, portstr, protostr);
2870 /* Notifies application that file transfer protocol session is being
2871 requested by the remote client indicated by the `client_entry' from
2872 the `hostname' and `port'. The `session_id' is the file transfer
2873 session and it can be used to either accept or reject the file
2874 transfer request, by calling the silc_client_file_receive or
2875 silc_client_file_close, respectively. */
2877 void silc_ftp(SilcClient client, SilcClientConnection conn,
2878 SilcClientEntry client_entry, SilcUInt32 session_id,
2879 const char *hostname, SilcUInt16 port)
2881 SILC_SERVER_REC *server;
2883 FtpSession ftp = NULL;
2885 SILC_LOG_DEBUG(("Start"));
2887 server = conn->context;
2889 silc_dlist_start(server->ftp_sessions);
2890 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2891 if (ftp->client_entry == client_entry &&
2892 ftp->session_id == session_id) {
2893 server->current_session = ftp;
2897 if (ftp == SILC_LIST_END) {
2898 ftp = silc_calloc(1, sizeof(*ftp));
2899 ftp->client_entry = client_entry;
2900 ftp->session_id = session_id;
2903 silc_dlist_add(server->ftp_sessions, ftp);
2904 server->current_session = ftp;
2908 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2911 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2912 SILCTXT_FILE_REQUEST, client_entry->nickname);
2914 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2915 SILCTXT_FILE_REQUEST_HOST,
2916 client_entry->nickname, hostname, portstr);
2919 /* SILC client operations */
2920 SilcClientOperations ops = {
2922 silc_channel_message,
2923 silc_private_message,
2927 silc_get_auth_method,
2928 silc_verify_public_key,
2929 silc_ask_passphrase,