5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
32 #include "silc-cmdqueue.h"
38 #include "special-vars.h"
39 #include "fe-common/core/printtext.h"
40 #include "fe-common/core/fe-channels.h"
41 #include "fe-common/core/keyboard.h"
42 #include "fe-common/core/window-items.h"
43 #include "fe-common/silc/module-formats.h"
48 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
49 const char *name, SilcConnectionType conn_type,
50 SilcPublicKey public_key,
51 SilcVerifyPublicKey completion, void *context);
53 char *silc_get_session_filename(SILC_SERVER_REC *server)
55 char *file, *expanded;
57 expanded = parse_special_string(settings_get_str("session_filename"),
58 SERVER(server), NULL, "", NULL, 0);
60 file = silc_calloc(1, strlen(expanded) + 255);
61 snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
67 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
70 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
71 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
72 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
74 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
75 "[SILC operator]" : "[unknown mode]");
77 if (mode & SILC_UMODE_GONE)
78 strcat(buf, " [away]");
79 if (mode & SILC_UMODE_INDISPOSED)
80 strcat(buf, " [indisposed]");
81 if (mode & SILC_UMODE_BUSY)
82 strcat(buf, " [busy]");
83 if (mode & SILC_UMODE_PAGE)
84 strcat(buf, " [page to reach]");
85 if (mode & SILC_UMODE_HYPER)
86 strcat(buf, " [hyper active]");
87 if (mode & SILC_UMODE_ROBOT)
88 strcat(buf, " [robot]");
89 if (mode & SILC_UMODE_ANONYMOUS)
90 strcat(buf, " [anonymous]");
91 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
92 strcat(buf, " [blocks private messages]");
93 if (mode & SILC_UMODE_DETACHED)
94 strcat(buf, " [detached]");
95 if (mode & SILC_UMODE_REJECT_WATCHING)
96 strcat(buf, " [rejects watching]");
97 if (mode & SILC_UMODE_BLOCK_INVITE)
98 strcat(buf, " [blocks invites]");
101 /* converts an utf-8 string to current locale */
102 char * silc_convert_utf8_string(const char *str)
104 int message_len = (str != NULL ? strlen(str) : 0);
105 char *message = silc_calloc(message_len + 1, sizeof(*message));
107 g_return_val_if_fail(message != NULL, NULL);
114 if (!silc_term_utf8() && silc_utf8_valid(str, message_len))
115 silc_utf8_decode(str, message_len, SILC_STRING_LOCALE,
116 message, message_len);
118 strcpy(message, str);
123 /* print "nick appears as" message to every channel of a server */
125 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
126 const char *newnick, const char *oldnick,
129 if (ignore_check(SERVER(server), oldnick, address,
130 channel, newnick, MSGLEVEL_NICKS))
133 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
134 SILCTXT_CHANNEL_APPEARS,
135 oldnick, newnick, channel, address);
139 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
140 const char *oldnick, const char *address)
142 GSList *tmp, *windows;
144 /* Print to each channel/query where the nick is.
145 Don't print more than once to the same window. */
148 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
149 CHANNEL_REC *channel = tmp->data;
150 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
152 if (nicklist_find(channel, newnick) == NULL ||
153 g_slist_find(windows, window) != NULL)
156 windows = g_slist_append(windows, window);
157 silc_print_nick_change_channel(server, channel->visible_name,
158 newnick, oldnick, address);
161 g_slist_free(windows);
164 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
165 SilcChannelEntry channel_entry,
166 SilcDList channel_pubkeys)
168 SilcArgumentDecodedList e;
169 SilcPublicKey pubkey;
170 SilcSILCPublicKey silc_pubkey;
171 SilcUInt32 pk_len, type;
173 char *fingerprint, *babbleprint;
176 printformat_module("fe-common/silc", server, NULL,
177 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
178 channel_entry->channel_name);
180 silc_dlist_start(channel_pubkeys);
181 while ((e = silc_dlist_get(channel_pubkeys))) {
182 pubkey = e->argument;
185 if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
188 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
192 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
193 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
194 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, pubkey);
196 printformat_module("fe-common/silc", server, NULL,
197 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
198 c++, channel_entry->channel_name,
199 type == 0x00 ? "Added" : "Removed",
200 silc_pubkey->identifier.realname ?
201 silc_pubkey->identifier.realname : "",
202 fingerprint, babbleprint);
204 silc_free(fingerprint);
205 silc_free(babbleprint);
210 void silc_say(SilcClient client, SilcClientConnection conn,
211 SilcClientMessageType type, char *msg, ...)
213 SILC_SERVER_REC *server;
217 server = conn == NULL ? NULL : conn->context;
220 str = g_strdup_vprintf(msg, va);
221 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
226 void silc_say_error(char *msg, ...)
232 str = g_strdup_vprintf(msg, va);
233 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
239 /* Try to verify a message using locally stored public key data */
241 int verify_message_signature(SilcClientEntry sender,
242 SilcMessagePayload message)
245 char file[256], filename[256];
246 char *fingerprint, *fingerprint2;
247 const unsigned char *pk_data;
248 SilcUInt32 pk_datalen;
250 int ret = SILC_MSG_SIGNED_VERIFIED, i;
252 /* get public key from the signature payload and compare it with the
253 one stored in the client entry */
254 pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
257 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
259 if (sender->fingerprint[0]) {
260 fingerprint2 = silc_fingerprint(sender->fingerprint,
261 sizeof(sender->fingerprint));
262 if (strcmp(fingerprint, fingerprint2)) {
263 /* since the public key differs from the senders public key, the
264 verification _failed_ */
265 silc_pkcs_public_key_free(pk);
266 silc_free(fingerprint);
267 ret = SILC_MSG_SIGNED_UNKNOWN;
269 silc_free(fingerprint2);
271 } else if (sender->fingerprint[0])
272 fingerprint = silc_fingerprint(sender->fingerprint,
273 sizeof(sender->fingerprint));
275 /* no idea, who or what signed that message ... */
276 return SILC_MSG_SIGNED_UNKNOWN;
278 /* search our local client key cache */
279 for (i = 0; i < strlen(fingerprint); i++)
280 if (fingerprint[i] == ' ')
281 fingerprint[i] = '_';
283 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
284 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
285 get_irssi_dir(), file);
286 silc_free(fingerprint);
288 if (stat(filename, &st) < 0)
289 /* we don't have the public key cached ... use the one from the sig */
290 ret = SILC_MSG_SIGNED_UNKNOWN;
292 SilcPublicKey cached_pk=NULL;
294 /* try to load the file */
295 if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
296 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
297 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
299 return SILC_MSG_SIGNED_UNKNOWN;
301 ret = SILC_MSG_SIGNED_UNKNOWN;
306 silc_pkcs_public_key_free(pk);
311 /* the public key is now in pk, our "level of trust" in ret */
312 if ((pk) && silc_message_signed_verify(message, pk,
313 sha1hash) != SILC_AUTH_OK)
314 ret = SILC_MSG_SIGNED_FAILED;
317 silc_pkcs_public_key_free(pk);
322 char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
325 int i = 0, j = 0, len = strlen(escaped_data);
327 data = silc_calloc(len, sizeof(char));
330 ptr = memchr(escaped_data + i, 1, len - i);
332 int inc = (ptr - escaped_data) - i;
333 memcpy(data + j, escaped_data + i, inc);
336 data[j++] = *(ptr + 1) - 1;
338 memcpy(data + j, escaped_data + i, len - i);
348 char *silc_escape_data(const char *data, SilcUInt32 len)
350 char *escaped_data, *ptr, *ptr0, *ptr1;
353 escaped_data = silc_calloc(2 * len, sizeof(char));
356 ptr0 = memchr(data + i, 0, len - i);
357 ptr1 = memchr(data + i, 1, len - i);
359 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
362 int inc = (ptr - data) - i;
364 memcpy(escaped_data + j, data + i, inc);
367 escaped_data[j++] = 1;
368 escaped_data[j++] = *(data + i++) + 1;
370 memcpy(escaped_data + j, data + i, len - i);
379 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
380 const char *data, SilcUInt32 data_len,
381 const char *nick, int verified)
385 escaped_data = silc_escape_data(data, data_len);
387 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
389 silc_free(escaped_data);
393 /* Message for a channel. The `sender' is the nickname of the sender
394 received in the packet. The `channel_name' is the name of the channel. */
396 void silc_channel_message(SilcClient client, SilcClientConnection conn,
397 SilcClientEntry sender, SilcChannelEntry channel,
398 SilcMessagePayload payload,
399 SilcChannelPrivateKey key,
400 SilcMessageFlags flags, const unsigned char *message,
401 SilcUInt32 message_len)
403 SILC_SERVER_REC *server;
405 SILC_CHANNEL_REC *chanrec;
408 SILC_LOG_DEBUG(("Start"));
413 server = conn == NULL ? NULL : conn->context;
414 chanrec = silc_channel_find_entry(server, channel);
418 nick = silc_nicklist_find(chanrec, sender);
420 /* We didn't find client but it clearly exists, add it. */
421 SilcChannelUser chu = silc_client_on_channel(channel, sender);
423 nick = silc_nicklist_insert(chanrec, chu, FALSE);
428 /* If the messages is digitally signed, verify it, if possible. */
429 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
430 if (!settings_get_bool("ignore_message_signatures")) {
431 verified = verify_message_signature(sender, payload);
433 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
437 if (flags & SILC_MESSAGE_FLAG_DATA) {
438 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
439 nick == NULL ? NULL : nick->nick,
440 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
447 if (flags & SILC_MESSAGE_FLAG_ACTION)
448 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
449 char tmp[256], *cp, *dm = NULL;
450 memset(tmp, 0, sizeof(tmp));
452 if(message_len > sizeof(tmp) - 1) {
453 dm = silc_calloc(message_len + 1, sizeof(*dm));
456 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
458 if (flags & SILC_MESSAGE_FLAG_SIGNED)
459 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
460 nick->host, channel->channel_name, verified);
462 signal_emit("message silc action", 5, server, cp, nick->nick,
463 nick->host, channel->channel_name);
466 if (flags & SILC_MESSAGE_FLAG_SIGNED)
467 signal_emit("message silc signed_action", 6, server, message,
468 nick->nick, nick->host, channel->channel_name, verified);
470 signal_emit("message silc action", 5, server, message,
471 nick->nick, nick->host, channel->channel_name);
473 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
474 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
475 char tmp[256], *cp, *dm = NULL;
476 memset(tmp, 0, sizeof(tmp));
478 if(message_len > sizeof(tmp) - 1) {
479 dm = silc_calloc(message_len + 1, sizeof(*dm));
482 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
484 if (flags & SILC_MESSAGE_FLAG_SIGNED)
485 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
486 nick->host, channel->channel_name, verified);
488 signal_emit("message silc notice", 5, server, cp, nick->nick,
489 nick->host, channel->channel_name);
492 if (flags & SILC_MESSAGE_FLAG_SIGNED)
493 signal_emit("message silc signed_notice", 6, server, message,
494 nick->nick, nick->host, channel->channel_name, verified);
496 signal_emit("message silc notice", 5, server, message,
497 nick->nick, nick->host, channel->channel_name);
500 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
501 char tmp[256], *cp, *dm = NULL;
503 memset(tmp, 0, sizeof(tmp));
505 if (message_len > sizeof(tmp) - 1) {
506 dm = silc_calloc(message_len + 1, sizeof(*dm));
510 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
512 if (flags & SILC_MESSAGE_FLAG_SIGNED)
513 signal_emit("message signed_public", 6, server, cp,
514 nick == NULL ? "[<unknown>]" : nick->nick,
515 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
516 chanrec->name, verified);
518 signal_emit("message public", 6, server, cp,
519 nick == NULL ? "[<unknown>]" : nick->nick,
520 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
521 chanrec->name, nick);
526 if (flags & SILC_MESSAGE_FLAG_SIGNED)
527 signal_emit("message signed_public", 6, server, message,
528 nick == NULL ? "[<unknown>]" : nick->nick,
529 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
530 chanrec->name, verified);
532 signal_emit("message public", 6, server, message,
533 nick == NULL ? "[<unknown>]" : nick->nick,
534 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
535 chanrec->name, nick);
539 /* Private message to the client. The `sender' is the nickname of the
540 sender received in the packet. */
542 void silc_private_message(SilcClient client, SilcClientConnection conn,
543 SilcClientEntry sender, SilcMessagePayload payload,
544 SilcMessageFlags flags,
545 const unsigned char *message,
546 SilcUInt32 message_len)
548 SILC_SERVER_REC *server;
552 SILC_LOG_DEBUG(("Start"));
554 server = conn == NULL ? NULL : conn->context;
555 memset(userhost, 0, sizeof(userhost));
556 if (sender->username[0])
557 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
558 sender->username, sender->hostname);
560 /* If the messages is digitally signed, verify it, if possible. */
561 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
562 if (!settings_get_bool("ignore_message_signatures")) {
563 verified = verify_message_signature(sender, payload);
565 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
569 if (flags & SILC_MESSAGE_FLAG_DATA) {
570 silc_emit_mime_sig(server,
571 sender->nickname[0] ?
572 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
574 message, message_len,
575 sender->nickname[0] ? sender->nickname : "[<unknown>]",
576 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
583 if (flags & SILC_MESSAGE_FLAG_ACTION)
584 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
585 char tmp[256], *cp, *dm = NULL;
586 memset(tmp, 0, sizeof(tmp));
588 if(message_len > sizeof(tmp) - 1) {
589 dm = silc_calloc(message_len + 1, sizeof(*dm));
592 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
594 if (flags & SILC_MESSAGE_FLAG_SIGNED)
595 signal_emit("message silc signed_private_action", 6, server, cp,
596 sender->nickname[0] ? sender->nickname : "[<unknown>]",
597 sender->username[0] ? userhost : NULL,
600 signal_emit("message silc private_action", 5, server, cp,
601 sender->nickname[0] ? sender->nickname : "[<unknown>]",
602 sender->username[0] ? userhost : NULL, NULL);
605 if (flags & SILC_MESSAGE_FLAG_SIGNED)
606 signal_emit("message silc signed_private_action", 6, server, message,
607 sender->nickname[0] ? sender->nickname : "[<unknown>]",
608 sender->username[0] ? userhost : NULL,
611 signal_emit("message silc private_action", 5, server, message,
612 sender->nickname[0] ? sender->nickname : "[<unknown>]",
613 sender->username[0] ? userhost : NULL, NULL);
615 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
616 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
617 char tmp[256], *cp, *dm = NULL;
618 memset(tmp, 0, sizeof(tmp));
620 if(message_len > sizeof(tmp) - 1) {
621 dm = silc_calloc(message_len + 1, sizeof(*dm));
624 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
626 if (flags & SILC_MESSAGE_FLAG_SIGNED)
627 signal_emit("message silc signed_private_notice", 6, server, cp,
628 sender->nickname[0] ? sender->nickname : "[<unknown>]",
629 sender->username[0] ? userhost : NULL,
632 signal_emit("message silc private_notice", 5, server, cp,
633 sender->nickname[0] ? sender->nickname : "[<unknown>]",
634 sender->username[0] ? userhost : NULL, NULL);
637 if (flags & SILC_MESSAGE_FLAG_SIGNED)
638 signal_emit("message silc signed_private_notice", 6, server, message,
639 sender->nickname[0] ? sender->nickname : "[<unknown>]",
640 sender->username[0] ? userhost : NULL,
643 signal_emit("message silc private_notice", 5, server, message,
644 sender->nickname[0] ? sender->nickname : "[<unknown>]",
645 sender->username[0] ? userhost : NULL, NULL);
648 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
649 char tmp[256], *cp, *dm = NULL;
651 memset(tmp, 0, sizeof(tmp));
653 if (message_len > sizeof(tmp) - 1) {
654 dm = silc_calloc(message_len + 1, sizeof(*dm));
658 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
660 if (flags & SILC_MESSAGE_FLAG_SIGNED)
661 signal_emit("message signed_private", 5, server, cp,
662 sender->nickname[0] ? sender->nickname : "[<unknown>]",
663 sender->username[0] ? userhost : NULL, verified);
665 signal_emit("message private", 4, server, cp,
666 sender->nickname[0] ? sender->nickname : "[<unknown>]",
667 sender->username[0] ? userhost : NULL);
672 if (flags & SILC_MESSAGE_FLAG_SIGNED)
673 signal_emit("message signed_private", 5, server, message,
674 sender->nickname[0] ? sender->nickname : "[<unknown>]",
675 sender->username[0] ? userhost : NULL, verified);
677 signal_emit("message private", 4, server, message,
678 sender->nickname[0] ? sender->nickname : "[<unknown>]",
679 sender->username[0] ? userhost : NULL);
683 /* Notify message to the client. The notify arguments are sent in the
684 same order as servers sends them. The arguments are same as received
685 from the server except for ID's. If ID is received application receives
686 the corresponding entry to the ID. For example, if Client ID is received
687 application receives SilcClientEntry. Also, if the notify type is
688 for channel the channel entry is sent to application (even if server
689 does not send it). */
691 void silc_notify(SilcClient client, SilcClientConnection conn,
692 SilcNotifyType type, ...)
695 SILC_SERVER_REC *server;
696 SILC_CHANNEL_REC *chanrec;
697 SILC_NICK_REC *nickrec;
698 SilcClientEntry client_entry, client_entry2;
699 SilcChannelEntry channel, channel2;
700 SilcServerEntry server_entry;
705 char *name, *tmp, *cipher, *hmac;
706 GSList *list1, *list_tmp;
707 SilcDList chpks, clients;
709 SILC_LOG_DEBUG(("Start"));
713 server = conn == NULL ? NULL : conn->context;
716 case SILC_NOTIFY_TYPE_NONE:
717 /* Some generic notice from server */
718 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
721 case SILC_NOTIFY_TYPE_INVITE:
723 * Invited or modified invite list.
726 SILC_LOG_DEBUG(("Notify: INVITE"));
728 channel = va_arg(va, SilcChannelEntry);
729 name = va_arg(va, char *);
730 client_entry = va_arg(va, SilcClientEntry);
732 memset(buf, 0, sizeof(buf));
733 snprintf(buf, sizeof(buf) - 1, "%s@%s",
734 client_entry->username, client_entry->hostname);
735 signal_emit("message invite", 4, server, channel ? channel->channel_name :
736 name, 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));
830 case SILC_NOTIFY_TYPE_SIGNOFF:
835 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
837 client_entry = va_arg(va, SilcClientEntry);
838 tmp = va_arg(va, char *);
840 silc_server_free_ftp(server, client_entry);
842 /* Print only if we have the nickname. If this cliente has just quit
843 when we were only resolving it, it is possible we don't have the
845 if (client_entry->nickname[0]) {
846 memset(buf, 0, sizeof(buf));
847 if (client_entry->username)
848 snprintf(buf, sizeof(buf) - 1, "%s@%s",
849 client_entry->username, client_entry->hostname);
850 signal_emit("message quit", 4, server, client_entry->nickname,
851 client_entry->username[0] ? buf : "",
855 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
856 for (list_tmp = list1; list_tmp != NULL; list_tmp =
857 list_tmp->next->next) {
858 CHANNEL_REC *channel = list_tmp->data;
859 NICK_REC *nickrec = list_tmp->next->data;
861 nicklist_remove(channel, nickrec);
865 case SILC_NOTIFY_TYPE_TOPIC_SET:
870 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
872 idtype = va_arg(va, int);
873 entry = va_arg(va, void *);
874 tmp = va_arg(va, char *);
875 channel = va_arg(va, SilcChannelEntry);
877 chanrec = silc_channel_find_entry(server, channel);
878 if (chanrec != NULL) {
879 char tmp2[256], *cp, *dm = NULL;
881 g_free_not_null(chanrec->topic);
882 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
883 memset(tmp2, 0, sizeof(tmp2));
885 if (strlen(tmp) > sizeof(tmp2) - 1) {
886 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
890 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
895 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
896 signal_emit("channel topic changed", 1, chanrec);
901 if (idtype == SILC_ID_CLIENT) {
902 client_entry = (SilcClientEntry)entry;
903 memset(buf, 0, sizeof(buf));
904 snprintf(buf, sizeof(buf) - 1, "%s@%s",
905 client_entry->username, client_entry->hostname);
906 signal_emit("message topic", 5, server, channel->channel_name,
907 tmp, client_entry->nickname, buf);
908 } else if (idtype == SILC_ID_SERVER) {
909 server_entry = (SilcServerEntry)entry;
910 signal_emit("message topic", 5, server, channel->channel_name,
911 tmp, server_entry->server_name,
912 server_entry->server_name);
913 } else if (idtype == SILC_ID_CHANNEL) {
914 channel = (SilcChannelEntry)entry;
915 signal_emit("message topic", 5, server, channel->channel_name,
916 tmp, channel->channel_name, channel->channel_name);
920 case SILC_NOTIFY_TYPE_NICK_CHANGE:
925 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
927 client_entry = va_arg(va, SilcClientEntry);
928 name = va_arg(va, char *); /* old nickname */
930 if (!strcmp(client_entry->nickname, name))
933 memset(buf, 0, sizeof(buf));
934 snprintf(buf, sizeof(buf) - 1, "%s@%s",
935 client_entry->username, client_entry->hostname);
936 nicklist_rename_unique(SERVER(server),
938 client_entry, client_entry->nickname);
939 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
942 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
944 * Changed channel mode.
947 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
949 idtype = va_arg(va, int);
950 entry = va_arg(va, void *);
951 mode = va_arg(va, SilcUInt32);
952 cipher = va_arg(va, char *); /* cipher */
953 hmac = va_arg(va, char *); /* hmac */
954 (void)va_arg(va, char *); /* passphrase */
955 (void)va_arg(va, SilcPublicKey); /* founder key */
956 chpks = va_arg(va, SilcDList); /* channel public keys */
957 channel = va_arg(va, SilcChannelEntry);
959 tmp = silc_client_chmode(mode, cipher ? cipher : "",
962 chanrec = silc_channel_find_entry(server, channel);
963 if (chanrec != NULL) {
964 g_free_not_null(chanrec->mode);
965 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
966 signal_emit("channel mode changed", 1, chanrec);
969 if (idtype == SILC_ID_CLIENT) {
970 client_entry = (SilcClientEntry)entry;
971 printformat_module("fe-common/silc", server, channel->channel_name,
972 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
973 channel->channel_name, tmp ? tmp : "removed all",
974 client_entry->nickname);
975 } else if (idtype == SILC_ID_SERVER) {
976 server_entry = (SilcServerEntry)entry;
977 printformat_module("fe-common/silc", server, channel->channel_name,
978 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
979 channel->channel_name, tmp ? tmp : "removed all",
980 server_entry->server_name);
981 } else if (idtype == SILC_ID_CHANNEL) {
982 channel2 = (SilcChannelEntry)entry;
983 printformat_module("fe-common/silc", server, channel->channel_name,
984 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
985 channel->channel_name, tmp ? tmp : "removed all",
986 channel2->channel_name);
989 /* Print the channel public key list */
991 silc_parse_channel_public_keys(server, channel, chpks);
996 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
998 * Changed user's mode on channel.
1001 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1003 idtype = va_arg(va, int);
1004 entry = va_arg(va, void *);
1005 mode = va_arg(va, SilcUInt32);
1006 client_entry2 = va_arg(va, SilcClientEntry);
1007 channel = va_arg(va, SilcChannelEntry);
1009 tmp = silc_client_chumode(mode);
1010 chanrec = silc_channel_find_entry(server, channel);
1011 if (chanrec != NULL) {
1012 SILC_NICK_REC *nick;
1014 if (client_entry2 == server->conn->local_entry)
1015 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1017 nick = silc_nicklist_find(chanrec, client_entry2);
1019 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1020 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1021 signal_emit("nick mode changed", 2, chanrec, nick);
1025 if (idtype == SILC_ID_CLIENT) {
1026 client_entry = (SilcClientEntry)entry;
1027 printformat_module("fe-common/silc", server, channel->channel_name,
1028 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1029 channel->channel_name, client_entry2->nickname,
1030 tmp ? tmp : "removed all",
1031 client_entry->nickname);
1032 } else if (idtype == SILC_ID_SERVER) {
1033 server_entry = (SilcServerEntry)entry;
1034 printformat_module("fe-common/silc", server, channel->channel_name,
1035 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1036 channel->channel_name, client_entry2->nickname,
1037 tmp ? tmp : "removed all",
1038 server_entry->server_name);
1039 } else if (idtype == SILC_ID_CHANNEL) {
1040 channel2 = (SilcChannelEntry)entry;
1041 printformat_module("fe-common/silc", server, channel->channel_name,
1042 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1043 channel->channel_name, client_entry2->nickname,
1044 tmp ? tmp : "removed all",
1045 channel2->channel_name);
1048 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1049 printformat_module("fe-common/silc",
1050 server, channel->channel_name, MSGLEVEL_CRAP,
1051 SILCTXT_CHANNEL_FOUNDER,
1052 channel->channel_name, client_entry2->nickname);
1054 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1055 printformat_module("fe-common/silc",
1056 server, channel->channel_name, MSGLEVEL_CRAP,
1057 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1062 case SILC_NOTIFY_TYPE_MOTD:
1067 SILC_LOG_DEBUG(("Notify: MOTD"));
1069 tmp = va_arg(va, char *);
1071 if (!settings_get_bool("skip_motd"))
1072 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1075 case SILC_NOTIFY_TYPE_KICKED:
1077 * Someone was kicked from channel.
1080 SILC_LOG_DEBUG(("Notify: KICKED"));
1082 client_entry = va_arg(va, SilcClientEntry);
1083 tmp = va_arg(va, char *);
1084 client_entry2 = va_arg(va, SilcClientEntry);
1085 channel = va_arg(va, SilcChannelEntry);
1087 chanrec = silc_channel_find_entry(server, channel);
1089 if (client_entry == conn->local_entry) {
1090 printformat_module("fe-common/silc", server, channel->channel_name,
1091 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1092 channel->channel_name,
1093 client_entry ? client_entry2->nickname : "",
1096 chanrec->kicked = TRUE;
1097 channel_destroy((CHANNEL_REC *)chanrec);
1100 printformat_module("fe-common/silc", server, channel->channel_name,
1101 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1102 client_entry->nickname, channel->channel_name,
1103 client_entry2 ? client_entry2->nickname : "",
1107 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1108 if (nickrec != NULL)
1109 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1114 case SILC_NOTIFY_TYPE_KILLED:
1116 * Someone was killed from the network.
1119 SILC_LOG_DEBUG(("Notify: KILLED"));
1121 client_entry = va_arg(va, SilcClientEntry);
1122 tmp = va_arg(va, char *);
1123 idtype = va_arg(va, int);
1124 entry = va_arg(va, SilcClientEntry);
1126 if (client_entry == conn->local_entry) {
1127 if (idtype == SILC_ID_CLIENT) {
1128 client_entry2 = (SilcClientEntry)entry;
1129 printformat_module("fe-common/silc", server, NULL,
1130 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1131 client_entry2 ? client_entry2->nickname : "",
1133 } else if (idtype == SILC_ID_SERVER) {
1134 server_entry = (SilcServerEntry)entry;
1135 printformat_module("fe-common/silc", server, NULL,
1136 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1137 server_entry->server_name, tmp ? tmp : "");
1138 } else if (idtype == SILC_ID_CHANNEL) {
1139 channel = (SilcChannelEntry)entry;
1140 printformat_module("fe-common/silc", server, NULL,
1141 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1142 channel->channel_name, tmp ? tmp : "");
1145 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1146 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1147 list_tmp->next->next) {
1148 CHANNEL_REC *channel = list_tmp->data;
1149 NICK_REC *nickrec = list_tmp->next->data;
1150 nicklist_remove(channel, nickrec);
1153 if (idtype == SILC_ID_CLIENT) {
1154 client_entry2 = (SilcClientEntry)entry;
1155 printformat_module("fe-common/silc", server, NULL,
1156 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1157 client_entry->nickname,
1158 client_entry2 ? client_entry2->nickname : "",
1160 } else if (idtype == SILC_ID_SERVER) {
1161 server_entry = (SilcServerEntry)entry;
1162 printformat_module("fe-common/silc", server, NULL,
1163 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1164 client_entry->nickname,
1165 server_entry->server_name, tmp ? tmp : "");
1166 } else if (idtype == SILC_ID_CHANNEL) {
1167 channel = (SilcChannelEntry)entry;
1168 printformat_module("fe-common/silc", server, NULL,
1169 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1170 client_entry->nickname,
1171 channel->channel_name, tmp ? tmp : "");
1176 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1179 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1182 * Server has quit the network.
1186 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1188 (void)va_arg(va, void *);
1189 clients = va_arg(va, SilcDList);
1191 silc_dlist_start(clients);
1192 while ((client_entry = silc_dlist_get(clients))) {
1193 memset(buf, 0, sizeof(buf));
1195 /* Print only if we have the nickname. If this client has just quit
1196 when we were only resolving it, it is possible we don't have the
1198 if (client_entry->nickname[0]) {
1199 if (client_entry->username[0])
1200 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1201 client_entry->username, client_entry->hostname);
1202 signal_emit("message quit", 4, server, client_entry->nickname,
1203 client_entry->username[0] ? buf : "",
1207 silc_server_free_ftp(server, client_entry);
1209 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1210 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1211 list_tmp->next->next) {
1212 CHANNEL_REC *channel = list_tmp->data;
1213 NICK_REC *nickrec = list_tmp->next->data;
1214 nicklist_remove(channel, nickrec);
1220 case SILC_NOTIFY_TYPE_ERROR:
1222 SilcStatus error = va_arg(va, int);
1224 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1225 "%s", silc_get_status_message(error));
1229 case SILC_NOTIFY_TYPE_WATCH:
1231 SilcNotifyType notify;
1233 client_entry = va_arg(va, SilcClientEntry);
1234 name = va_arg(va, char *); /* Maybe NULL */
1235 mode = va_arg(va, SilcUInt32);
1236 notify = va_arg(va, int);
1238 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1240 printformat_module("fe-common/silc", server, NULL,
1241 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1242 client_entry->nickname, name);
1244 printformat_module("fe-common/silc", server, NULL,
1245 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1246 client_entry->nickname);
1247 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1248 /* See if client was away and is now present */
1249 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1250 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1251 SILC_UMODE_DETACHED)) &&
1252 (client_entry->mode & SILC_UMODE_GONE ||
1253 client_entry->mode & SILC_UMODE_INDISPOSED ||
1254 client_entry->mode & SILC_UMODE_BUSY ||
1255 client_entry->mode & SILC_UMODE_PAGE ||
1256 client_entry->mode & SILC_UMODE_DETACHED)) {
1257 printformat_module("fe-common/silc", server, NULL,
1258 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1259 client_entry->nickname);
1263 memset(buf, 0, sizeof(buf));
1264 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1265 printformat_module("fe-common/silc", server, NULL,
1266 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1267 client_entry->nickname, buf);
1269 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1270 printformat_module("fe-common/silc", server, NULL,
1271 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1272 client_entry->nickname);
1273 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1274 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1275 printformat_module("fe-common/silc", server, NULL,
1276 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1277 client_entry->nickname);
1278 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1279 /* Client logged in to the network */
1280 printformat_module("fe-common/silc", server, NULL,
1281 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1282 client_entry->nickname);
1288 /* Unknown notify */
1289 printformat_module("fe-common/silc", server, NULL,
1290 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1297 /* Command handler. This function is called always in the command function.
1298 If error occurs it will be called as well. `conn' is the associated
1299 client connection. `cmd_context' is the command context that was
1300 originally sent to the command. `success' is FALSE if error occured
1301 during command. `command' is the command being processed. It must be
1302 noted that this is not reply from server. This is merely called just
1303 after application has called the command. Just to tell application
1304 that the command really was processed. */
1306 static SilcBool cmode_list_chpks = FALSE;
1308 void silc_command(SilcClient client, SilcClientConnection conn,
1309 SilcBool success, SilcCommand command, SilcStatus status,
1310 SilcUInt32 argc, unsigned char **argv)
1312 SILC_SERVER_REC *server = conn->context;
1314 SILC_LOG_DEBUG(("Start"));
1317 silc_say_error("%s", silc_get_status_message(status));
1323 case SILC_COMMAND_INVITE:
1325 printformat_module("fe-common/silc", server, NULL,
1326 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1328 (argv[1][0] == '*' ?
1329 (char *)conn->current_channel->channel_name :
1333 case SILC_COMMAND_DETACH:
1334 server->no_reconnect = TRUE;
1337 case SILC_COMMAND_CMODE:
1338 if (argc == 3 && !strcmp(argv[2], "+C"))
1339 cmode_list_chpks = TRUE;
1341 cmode_list_chpks = FALSE;
1351 SilcClientConnection conn;
1356 void silc_getkey_cb(bool success, void *context)
1358 GetkeyContext getkey = (GetkeyContext)context;
1359 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1360 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1361 ((SilcClientEntry)getkey->entry)->nickname :
1362 ((SilcServerEntry)getkey->entry)->server_name);
1363 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1364 ((SilcClientEntry)getkey->entry)->public_key :
1365 ((SilcServerEntry)getkey->entry)->public_key);
1366 SilcSILCPublicKey silc_pubkey;
1368 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1371 if (getkey->id_type == SILC_ID_CLIENT)
1372 printformat_module("fe-common/silc", NULL, NULL,
1373 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1375 silc_pubkey->identifier.realname ?
1376 silc_pubkey->identifier.realname : "",
1377 silc_pubkey->identifier.email ?
1378 silc_pubkey->identifier.email : "");
1380 printformat_module("fe-common/silc", NULL, NULL,
1381 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1384 printformat_module("fe-common/silc", NULL, NULL,
1385 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1392 /* Parse an invite or ban list */
1393 void silc_parse_inviteban_list(SilcClient client,
1394 SilcClientConnection conn,
1395 SILC_SERVER_REC *server,
1396 SilcChannelEntry channel,
1397 const char *list_type,
1398 SilcArgumentPayload list)
1401 SilcUInt32 type, len;
1402 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1403 int counter=0, resolving = FALSE;
1405 if (!silc_argument_get_arg_num(list)) {
1406 printformat_module("fe-common/silc", server,
1407 (chanrec ? chanrec->visible_name : NULL),
1408 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1409 channel->channel_name, list_type);
1413 printformat_module("fe-common/silc", server,
1414 (chanrec ? chanrec->visible_name : NULL),
1415 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1416 channel->channel_name, list_type);
1418 /* Parse the list */
1419 tmp = silc_argument_get_first_arg(list, &type, &len);
1424 /* An invite string */
1428 if (tmp[len-1] == ',')
1431 list = g_strsplit(tmp, ",", -1);
1433 printformat_module("fe-common/silc", server,
1434 (chanrec ? chanrec->visible_name : NULL),
1435 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1436 ++counter, channel->channel_name, list_type,
1445 char *fingerprint, *babbleprint;
1447 /* tmp is Public Key Payload, take public key from it. */
1448 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1449 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1451 printformat_module("fe-common/silc", server,
1452 (chanrec ? chanrec->visible_name : NULL),
1453 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1454 ++counter, channel->channel_name, list_type,
1455 fingerprint, babbleprint);
1462 SilcClientEntry client_entry;
1465 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1466 silc_say_error("Invalid data in %s list encountered", list_type);
1470 client_entry = silc_client_get_client_by_id(client, conn,
1473 printformat_module("fe-common/silc", server,
1474 (chanrec ? chanrec->visible_name : NULL),
1475 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1476 ++counter, channel->channel_name, list_type,
1477 client_entry->nickname);
1478 silc_client_unref_client(client, conn, client_entry);
1481 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1489 silc_say_error("Unkown type in %s list: %u (len %u)",
1490 list_type, type, len);
1493 tmp = silc_argument_get_next_arg(list, &type, &len);
1497 printformat_module("fe-common/silc", server,
1498 (chanrec ? chanrec->visible_name : NULL),
1499 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1500 list_type, channel->channel_name);
1503 /* Command reply handler. This function is called always in the command reply
1504 function. If error occurs it will be called as well. Normal scenario
1505 is that it will be called after the received command data has been parsed
1506 and processed. The function is used to pass the received command data to
1509 `conn' is the associated client connection. `cmd_payload' is the command
1510 payload data received from server and it can be ignored. It is provided
1511 if the application would like to re-parse the received command data,
1512 however, it must be noted that the data is parsed already by the library
1513 thus the payload can be ignored. `success' is FALSE if error occured.
1514 In this case arguments are not sent to the application. `command' is the
1515 command reply being processed. The function has variable argument list
1516 and each command defines the number and type of arguments it passes to the
1517 application (on error they are not sent). */
1519 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1520 SilcCommand command, SilcStatus status,
1521 SilcStatus error, va_list vp)
1523 SILC_SERVER_REC *server = conn->context;
1524 SILC_CHANNEL_REC *chanrec;
1526 SILC_LOG_DEBUG(("Start"));
1529 case SILC_COMMAND_WHOIS:
1531 char buf[1024], *nickname, *username, *realname, *nick;
1532 unsigned char *fingerprint;
1533 SilcUInt32 idle, mode, *user_modes;
1535 SilcClientEntry client_entry;
1538 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1539 /* Print the unknown nick for user */
1540 char *tmp = va_arg(vp, char *);
1542 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1544 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1545 /* Try to find the entry for the unknown client ID, since we
1546 might have, and print the nickname of it for user. */
1547 SilcClientID *id = va_arg(vp, SilcClientID *);
1549 client_entry = silc_client_get_client_by_id(client, conn, id);
1550 if (client_entry && client_entry->nickname[0])
1551 silc_say_error("%s: %s", client_entry->nickname,
1552 silc_get_status_message(status));
1553 silc_client_unref_client(client, conn, client_entry);
1556 } else if (SILC_STATUS_IS_ERROR(status)) {
1557 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1561 client_entry = va_arg(vp, SilcClientEntry);
1562 nickname = va_arg(vp, char *);
1563 username = va_arg(vp, char *);
1564 realname = va_arg(vp, char *);
1565 channels = va_arg(vp, SilcDList);
1566 mode = va_arg(vp, SilcUInt32);
1567 idle = va_arg(vp, SilcUInt32);
1568 fingerprint = va_arg(vp, unsigned char *);
1569 user_modes = va_arg(vp, SilcUInt32 *);
1570 attrs = va_arg(vp, SilcDList);
1572 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1573 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1574 SILCTXT_WHOIS_USERINFO, nickname,
1575 client_entry->username, client_entry->hostname,
1576 nick, client_entry->nickname);
1577 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1578 SILCTXT_WHOIS_REALNAME, realname);
1581 if (channels && user_modes) {
1582 SilcChannelPayload entry;
1585 memset(buf, 0, sizeof(buf));
1586 silc_dlist_start(channels);
1587 while ((entry = silc_dlist_get(channels))) {
1588 SilcUInt32 name_len;
1589 char *m = silc_client_chumode_char(user_modes[i++]);
1590 char *name = silc_channel_get_name(entry, &name_len);
1593 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1594 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1595 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1599 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1600 SILCTXT_WHOIS_CHANNELS, buf);
1604 memset(buf, 0, sizeof(buf));
1605 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1606 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1607 SILCTXT_WHOIS_MODES, buf);
1610 if (idle && nickname) {
1611 memset(buf, 0, sizeof(buf));
1612 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1613 idle > 60 ? (idle / 60) : idle,
1614 idle > 60 ? "minutes" : "seconds");
1616 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1617 SILCTXT_WHOIS_IDLE, buf);
1621 fingerprint = silc_fingerprint(fingerprint, 20);
1622 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1623 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1624 silc_free(fingerprint);
1628 silc_query_attributes_print(server, silc_client, conn, attrs,
1633 case SILC_COMMAND_WHOWAS:
1635 char *nickname, *username, *realname;
1637 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1638 char *tmp = va_arg(vp, char *);
1640 silc_say_error("%s: %s", tmp,
1641 silc_get_status_message(status));
1643 } else if (SILC_STATUS_IS_ERROR(status)) {
1644 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1648 (void)va_arg(vp, SilcClientEntry);
1649 nickname = va_arg(vp, char *);
1650 username = va_arg(vp, char *);
1651 realname = va_arg(vp, char *);
1653 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1654 SILCTXT_WHOWAS_USERINFO, nickname, username,
1655 realname ? realname : "");
1659 case SILC_COMMAND_INVITE:
1661 SilcChannelEntry channel;
1662 SilcArgumentPayload invite_list;
1664 if (SILC_STATUS_IS_ERROR(status))
1667 channel = va_arg(vp, SilcChannelEntry);
1668 invite_list = va_arg(vp, SilcArgumentPayload);
1671 silc_parse_inviteban_list(client, conn, server, channel,
1672 "invite", invite_list);
1676 case SILC_COMMAND_JOIN:
1678 char *channel, *mode, *topic, *cipher, *hmac;
1680 SilcHashTableList *user_list;
1681 SilcChannelEntry channel_entry;
1682 SilcChannelUser chu;
1683 SilcClientEntry founder = NULL;
1686 if (SILC_STATUS_IS_ERROR(status)) {
1687 silc_say_error("JOIN: %s", silc_get_status_message(status));
1691 channel = va_arg(vp, char *);
1692 channel_entry = va_arg(vp, SilcChannelEntry);
1693 modei = va_arg(vp, SilcUInt32);
1694 user_list = va_arg(vp, SilcHashTableList *);
1695 topic = va_arg(vp, char *);
1696 cipher = va_arg(vp, char *);
1697 hmac = va_arg(vp, char *);
1699 chanrec = silc_channel_find(server, channel);
1701 chanrec = silc_channel_create(server, channel, channel, TRUE);
1704 char tmp[256], *cp, *dm = NULL;
1705 g_free_not_null(chanrec->topic);
1707 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1708 memset(tmp, 0, sizeof(tmp));
1710 if (strlen(topic) > sizeof(tmp) - 1) {
1711 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1715 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1720 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1721 signal_emit("channel topic changed", 1, chanrec);
1726 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1727 g_free_not_null(chanrec->mode);
1728 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1729 signal_emit("channel mode changed", 1, chanrec);
1732 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1733 if (!chu->client->nickname[0])
1735 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1736 founder = chu->client;
1737 silc_nicklist_insert(chanrec, chu, FALSE);
1740 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1743 nicklist_set_own(CHANNEL(chanrec), ownnick);
1744 signal_emit("channel joined", 1, chanrec);
1745 chanrec->entry = channel_entry;
1748 printformat_module("fe-common/silc", server,
1749 channel_entry->channel_name,
1750 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1751 channel_entry->channel_name, chanrec->topic);
1754 if (founder == conn->local_entry) {
1755 printformat_module("fe-common/silc",
1756 server, channel_entry->channel_name,
1757 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1758 channel_entry->channel_name);
1759 signal_emit("nick mode changed", 2, chanrec, ownnick);
1761 printformat_module("fe-common/silc",
1762 server, channel_entry->channel_name,
1763 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1764 channel_entry->channel_name, founder->nickname);
1770 case SILC_COMMAND_NICK:
1773 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1776 if (SILC_STATUS_IS_ERROR(status)) {
1777 silc_say_error("NICK: %s", silc_get_status_message(status));
1781 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1782 if ((nicks != NULL) &&
1783 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1785 SilcClientEntry collider, old;
1787 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1788 collider = silc_client_get_client_by_id(client, conn, &old->id);
1789 if (collider != client_entry) {
1790 memset(buf, 0, sizeof(buf));
1791 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1792 collider->username, collider->hostname);
1793 nicklist_rename_unique(SERVER(server),
1795 collider, collider->nickname);
1796 silc_print_nick_change(server, collider->nickname,
1797 client_entry->nickname, buf);
1799 silc_client_unref_client(client, conn, collider);
1803 g_slist_free(nicks);
1805 old = g_strdup(server->nick);
1806 server_change_nick(SERVER(server), client_entry->nickname);
1807 nicklist_rename_unique(SERVER(server),
1808 server->conn->local_entry, server->nick,
1809 client_entry, client_entry->nickname);
1810 signal_emit("message own_nick", 4, server, server->nick, old, "");
1813 /* when connecting to a server, the last thing we receive
1814 is a SILC_COMMAND_LIST reply. Since we enable queueing
1815 during the connection, we can now safely disable it again */
1816 silc_queue_disable(conn);
1820 case SILC_COMMAND_LIST:
1825 char tmp[256], *cp, *dm = NULL;
1827 if (SILC_STATUS_IS_ERROR(status))
1830 (void)va_arg(vp, SilcChannelEntry);
1831 name = va_arg(vp, char *);
1832 topic = va_arg(vp, char *);
1833 usercount = va_arg(vp, int);
1835 if (topic && !silc_term_utf8() &&
1836 silc_utf8_valid(topic, strlen(topic))) {
1837 memset(tmp, 0, sizeof(tmp));
1839 if (strlen(topic) > sizeof(tmp) - 1) {
1840 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1844 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1849 if (status == SILC_STATUS_LIST_START ||
1850 status == SILC_STATUS_OK)
1851 printformat_module("fe-common/silc", server, NULL,
1852 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1855 snprintf(users, sizeof(users) - 1, "N/A");
1857 snprintf(users, sizeof(users) - 1, "%d", usercount);
1858 printformat_module("fe-common/silc", server, NULL,
1859 MSGLEVEL_CRAP, SILCTXT_LIST,
1860 name, users, topic ? topic : "");
1865 case SILC_COMMAND_UMODE:
1870 if (SILC_STATUS_IS_ERROR(status))
1873 mode = va_arg(vp, SilcUInt32);
1875 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1876 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1877 printformat_module("fe-common/silc", server, NULL,
1878 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1880 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1881 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1882 printformat_module("fe-common/silc", server, NULL,
1883 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1885 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1886 if (mode & SILC_UMODE_GONE) {
1887 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1888 reason = g_strdup(server->away_reason);
1890 reason = g_strdup("away");
1892 reason = g_strdup("");
1894 silc_set_away(reason, server);
1899 server->umode = mode;
1900 signal_emit("user mode changed", 2, server, NULL);
1904 case SILC_COMMAND_OPER:
1905 if (SILC_STATUS_IS_ERROR(status)) {
1906 silc_say_error("OPER: %s", silc_get_status_message(status));
1910 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1911 signal_emit("user mode changed", 2, server, NULL);
1913 printformat_module("fe-common/silc", server, NULL,
1914 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1917 case SILC_COMMAND_SILCOPER:
1918 if (SILC_STATUS_IS_ERROR(status)) {
1919 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1923 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1924 signal_emit("user mode changed", 2, server, NULL);
1926 printformat_module("fe-common/silc", server, NULL,
1927 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1930 case SILC_COMMAND_USERS:
1932 SilcHashTableList htl;
1933 SilcChannelEntry channel;
1934 SilcChannelUser chu;
1936 if (SILC_STATUS_IS_ERROR(status)) {
1937 silc_say_error("USERS: %s", silc_get_status_message(status));
1941 channel = va_arg(vp, SilcChannelEntry);
1943 printformat_module("fe-common/silc", server, channel->channel_name,
1944 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1945 channel->channel_name);
1947 silc_hash_table_list(channel->user_list, &htl);
1948 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1949 SilcClientEntry e = chu->client;
1950 char stat[5], *mode;
1952 if (!e->nickname[0])
1955 memset(stat, 0, sizeof(stat));
1956 mode = silc_client_chumode_char(chu->mode);
1957 if (e->mode & SILC_UMODE_GONE)
1959 else if (e->mode & SILC_UMODE_INDISPOSED)
1961 else if (e->mode & SILC_UMODE_BUSY)
1963 else if (e->mode & SILC_UMODE_PAGE)
1965 else if (e->mode & SILC_UMODE_HYPER)
1967 else if (e->mode & SILC_UMODE_ROBOT)
1969 else if (e->mode & SILC_UMODE_ANONYMOUS)
1976 printformat_module("fe-common/silc", server, channel->channel_name,
1977 MSGLEVEL_CRAP, SILCTXT_USERS,
1979 e->username[0] ? e->username : "",
1980 e->hostname[0] ? e->hostname : "",
1981 e->realname ? e->realname : "");
1985 silc_hash_table_list_reset(&htl);
1989 case SILC_COMMAND_BAN:
1991 SilcChannelEntry channel;
1992 SilcArgumentPayload invite_list;
1994 if (SILC_STATUS_IS_ERROR(status))
1997 channel = va_arg(vp, SilcChannelEntry);
1998 invite_list = va_arg(vp, SilcArgumentPayload);
2001 silc_parse_inviteban_list(client, conn, server, channel,
2002 "ban", invite_list);
2006 case SILC_COMMAND_GETKEY:
2010 SilcPublicKey public_key;
2011 GetkeyContext getkey;
2014 if (SILC_STATUS_IS_ERROR(status)) {
2015 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2019 id_type = va_arg(vp, SilcUInt32);
2020 entry = va_arg(vp, void *);
2021 public_key = va_arg(vp, SilcPublicKey);
2024 getkey = silc_calloc(1, sizeof(*getkey));
2025 getkey->entry = entry;
2026 getkey->id_type = id_type;
2027 getkey->client = client;
2028 getkey->conn = conn;
2030 name = (id_type == SILC_ID_CLIENT ?
2031 ((SilcClientEntry)entry)->nickname :
2032 ((SilcServerEntry)entry)->server_name);
2034 silc_verify_public_key_internal(client, conn, name,
2035 (id_type == SILC_ID_CLIENT ?
2038 public_key, silc_getkey_cb, getkey);
2040 printformat_module("fe-common/silc", server, NULL,
2041 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2046 case SILC_COMMAND_INFO:
2048 SilcServerEntry server_entry;
2052 if (SILC_STATUS_IS_ERROR(status))
2055 server_entry = va_arg(vp, SilcServerEntry);
2056 server_name = va_arg(vp, char *);
2057 server_info = va_arg(vp, char *);
2059 if (server_name && server_info )
2061 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2062 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2067 case SILC_COMMAND_TOPIC:
2069 SilcChannelEntry channel;
2071 char tmp[256], *cp, *dm = NULL;
2073 if (SILC_STATUS_IS_ERROR(status))
2076 channel = va_arg(vp, SilcChannelEntry);
2077 topic = va_arg(vp, char *);
2079 if (topic && !silc_term_utf8() &&
2080 silc_utf8_valid(topic, strlen(topic))) {
2081 memset(tmp, 0, sizeof(tmp));
2083 if (strlen(topic) > sizeof(tmp) - 1) {
2084 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2088 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2094 chanrec = silc_channel_find_entry(server, channel);
2096 g_free_not_null(chanrec->topic);
2097 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2098 signal_emit("channel topic changed", 1, chanrec);
2100 printformat_module("fe-common/silc", server, channel->channel_name,
2101 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2102 channel->channel_name, topic);
2104 printformat_module("fe-common/silc", server, channel->channel_name,
2105 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2106 channel->channel_name);
2112 case SILC_COMMAND_WATCH:
2115 case SILC_COMMAND_STATS:
2117 SilcClientStats *cstats;
2119 const char *tmptime;
2120 int days, hours, mins, secs;
2122 if (SILC_STATUS_IS_ERROR(status))
2125 cstats = va_arg(vp, SilcClientStats *);
2127 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2131 tmptime = silc_time_string(cstats->starttime);
2132 printformat_module("fe-common/silc", server, NULL,
2133 MSGLEVEL_CRAP, SILCTXT_STATS,
2134 "Local server start time", tmptime);
2136 days = cstats->uptime / (24 * 60 * 60);
2137 cstats->uptime -= days * (24 * 60 * 60);
2138 hours = cstats->uptime / (60 * 60);
2139 cstats->uptime -= hours * (60 * 60);
2140 mins = cstats->uptime / 60;
2141 cstats->uptime -= mins * 60;
2142 secs = cstats->uptime;
2143 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2144 days, hours, mins, secs);
2145 printformat_module("fe-common/silc", server, NULL,
2146 MSGLEVEL_CRAP, SILCTXT_STATS,
2147 "Local server uptime", tmp);
2149 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2150 printformat_module("fe-common/silc", server, NULL,
2151 MSGLEVEL_CRAP, SILCTXT_STATS,
2152 "Local server clients", tmp);
2154 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2155 printformat_module("fe-common/silc", server, NULL,
2156 MSGLEVEL_CRAP, SILCTXT_STATS,
2157 "Local server channels", tmp);
2159 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2160 printformat_module("fe-common/silc", server, NULL,
2161 MSGLEVEL_CRAP, SILCTXT_STATS,
2162 "Local server operators", tmp);
2164 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2165 printformat_module("fe-common/silc", server, NULL,
2166 MSGLEVEL_CRAP, SILCTXT_STATS,
2167 "Local router operators", tmp);
2169 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2170 printformat_module("fe-common/silc", server, NULL,
2171 MSGLEVEL_CRAP, SILCTXT_STATS,
2172 "Local cell clients", tmp);
2174 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2175 printformat_module("fe-common/silc", server, NULL,
2176 MSGLEVEL_CRAP, SILCTXT_STATS,
2177 "Local cell channels", tmp);
2179 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2180 printformat_module("fe-common/silc", server, NULL,
2181 MSGLEVEL_CRAP, SILCTXT_STATS,
2182 "Local cell servers", tmp);
2184 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2185 printformat_module("fe-common/silc", server, NULL,
2186 MSGLEVEL_CRAP, SILCTXT_STATS,
2187 "Total clients", tmp);
2189 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2190 printformat_module("fe-common/silc", server, NULL,
2191 MSGLEVEL_CRAP, SILCTXT_STATS,
2192 "Total channels", tmp);
2194 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2195 printformat_module("fe-common/silc", server, NULL,
2196 MSGLEVEL_CRAP, SILCTXT_STATS,
2197 "Total servers", tmp);
2199 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2200 printformat_module("fe-common/silc", server, NULL,
2201 MSGLEVEL_CRAP, SILCTXT_STATS,
2202 "Total routers", tmp);
2204 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2205 printformat_module("fe-common/silc", server, NULL,
2206 MSGLEVEL_CRAP, SILCTXT_STATS,
2207 "Total server operators", tmp);
2209 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2210 printformat_module("fe-common/silc", server, NULL,
2211 MSGLEVEL_CRAP, SILCTXT_STATS,
2212 "Total router operators", tmp);
2216 case SILC_COMMAND_CMODE:
2218 SilcChannelEntry channel_entry;
2221 channel_entry = va_arg(vp, SilcChannelEntry);
2222 (void)va_arg(vp, SilcUInt32);
2223 (void)va_arg(vp, SilcPublicKey);
2224 chpks = va_arg(vp, SilcDList);
2226 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2227 !channel_entry || !channel_entry->channel_name)
2230 /* Print the channel public key list */
2232 silc_parse_channel_public_keys(server, channel_entry, chpks);
2234 printformat_module("fe-common/silc", server, NULL,
2235 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2236 channel_entry->channel_name);
2241 case SILC_COMMAND_LEAVE:
2243 if (SILC_STATUS_IS_ERROR(status))
2246 /* We might be cycling, so disable queueing again */
2247 silc_queue_disable(conn);
2251 case SILC_COMMAND_DETACH:
2253 /* Save the detachment data to file. */
2257 if (SILC_STATUS_IS_ERROR(status))
2260 detach = va_arg(vp, SilcBuffer);
2261 file = silc_get_session_filename(server);
2262 silc_file_writefile(file, silc_buffer_data(detach),
2263 silc_buffer_len(detach));
2268 case SILC_COMMAND_KILL:
2270 SilcClientEntry client_entry;
2272 if (SILC_STATUS_IS_ERROR(status)) {
2273 silc_say_error("KILL: %s", silc_get_status_message(status));
2277 client_entry = va_arg(vp, SilcClientEntry);
2278 if (!client_entry || !client_entry->nickname[0])
2281 /* Print this only if the killed client isn't joined on channels.
2282 If it is, we receive KILLED notify and we'll print this there. */
2283 if (!silc_hash_table_count(client_entry->channels))
2284 printformat_module("fe-common/silc", server, NULL,
2285 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2286 client_entry->nickname,
2287 conn->local_entry->nickname, "");
2294 SilcClientConnection conn;
2298 SilcPublicKey public_key;
2299 SilcVerifyPublicKey completion;
2303 static void verify_public_key_completion(const char *line, void *context)
2305 PublicKeyVerify verify = (PublicKeyVerify)context;
2307 if (line[0] == 'Y' || line[0] == 'y') {
2308 /* Call the completion */
2309 if (verify->completion)
2310 verify->completion(TRUE, verify->context);
2312 /* Save the key for future checking */
2313 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2314 SILC_PKCS_FILE_BASE64);
2316 /* Call the completion */
2317 if (verify->completion)
2318 verify->completion(FALSE, verify->context);
2320 printformat_module("fe-common/silc", NULL, NULL,
2321 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2322 verify->entity_name ? verify->entity_name :
2326 silc_free(verify->filename);
2327 silc_free(verify->entity);
2328 silc_free(verify->entity_name);
2332 /* Internal routine to verify public key. If the `completion' is provided
2333 it will be called to indicate whether public was verified or not. For
2334 server/router public key this will check for filename that includes the
2335 remote host's IP address and remote host's hostname. */
2338 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2340 SilcConnectionType conn_type,
2341 SilcPublicKey public_key,
2342 SilcVerifyPublicKey completion, void *context)
2344 PublicKeyVerify verify;
2345 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2346 char *fingerprint, *babbleprint, *format;
2347 SilcPublicKey local_pubkey;
2348 SilcSILCPublicKey silc_pubkey;
2350 const char *hostname, *ip;
2355 char *entity = ((conn_type == SILC_CONN_SERVER ||
2356 conn_type == SILC_CONN_ROUTER) ?
2357 "server" : "client");
2360 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2361 printformat_module("fe-common/silc", NULL, NULL,
2362 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2363 entity, silc_pkcs_get_type(public_key));
2365 completion(FALSE, context);
2369 /* Encode public key */
2370 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2373 completion(FALSE, context);
2377 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2379 pw = getpwuid(getuid());
2382 completion(FALSE, context);
2387 memset(filename, 0, sizeof(filename));
2388 memset(filename2, 0, sizeof(filename2));
2389 memset(file, 0, sizeof(file));
2391 /* Get remote host information */
2392 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2393 NULL, &hostname, &ip, &port);
2395 if (conn_type == SILC_CONN_SERVER ||
2396 conn_type == SILC_CONN_ROUTER) {
2398 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2399 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2400 get_irssi_dir(), entity, file);
2402 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2404 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2405 get_irssi_dir(), entity, file);
2410 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2412 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2413 get_irssi_dir(), entity, file);
2418 /* Replace all whitespaces with `_'. */
2419 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2420 for (i = 0; i < strlen(fingerprint); i++)
2421 if (fingerprint[i] == ' ')
2422 fingerprint[i] = '_';
2424 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2425 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2426 get_irssi_dir(), entity, file);
2427 silc_free(fingerprint);
2432 /* Take fingerprint of the public key */
2433 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2434 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2436 verify = silc_calloc(1, sizeof(*verify));
2437 verify->client = client;
2438 verify->conn = conn;
2439 verify->filename = strdup(ipf);
2440 verify->entity = strdup(entity);
2441 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2442 (name ? strdup(name) : strdup(hostname))
2444 verify->public_key = public_key;
2445 verify->completion = completion;
2446 verify->context = context;
2448 /* Check whether this key already exists */
2449 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2450 /* Key does not exist, ask user to verify the key and save it */
2452 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2453 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2454 verify->entity_name : entity);
2455 if (conn_type == SILC_CONN_CLIENT && name &&
2456 silc_pubkey->identifier.realname)
2457 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2458 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2459 silc_pubkey->identifier.realname,
2460 silc_pubkey->identifier.email ?
2461 silc_pubkey->identifier.email : "");
2462 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2463 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2464 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2465 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2466 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2467 SILCTXT_PUBKEY_ACCEPT);
2468 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2471 silc_free(fingerprint);
2472 silc_free(babbleprint);
2476 /* The key already exists, verify it. */
2477 unsigned char *encpk;
2478 SilcUInt32 encpk_len;
2480 /* Load the key file, try for both IP filename and hostname filename */
2481 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2482 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2483 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2484 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2485 verify->entity_name : entity);
2486 if (conn_type == SILC_CONN_CLIENT && name &&
2487 silc_pubkey->identifier.realname)
2488 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2489 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2490 silc_pubkey->identifier.realname,
2491 silc_pubkey->identifier.email ?
2492 silc_pubkey->identifier.email : "");
2493 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2494 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2495 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2496 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2497 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2498 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2499 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2500 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2501 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2504 silc_free(fingerprint);
2505 silc_free(babbleprint);
2510 /* Encode the key data */
2511 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2513 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2514 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2515 verify->entity_name : entity);
2516 if (conn_type == SILC_CONN_CLIENT && name &&
2517 silc_pubkey->identifier.realname)
2518 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2519 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2520 silc_pubkey->identifier.realname,
2521 silc_pubkey->identifier.email ?
2522 silc_pubkey->identifier.email : "");
2523 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2524 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2525 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2526 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2527 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2528 SILCTXT_PUBKEY_MALFORMED, entity);
2529 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2530 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2531 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2534 silc_free(fingerprint);
2535 silc_free(babbleprint);
2539 silc_pkcs_public_key_free(local_pubkey);
2541 /* Compare the keys */
2542 if (memcmp(encpk, pk, encpk_len)) {
2543 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2544 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2545 verify->entity_name : entity);
2546 if (conn_type == SILC_CONN_CLIENT && name &&
2547 silc_pubkey->identifier.realname)
2548 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2549 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2550 silc_pubkey->identifier.realname,
2551 silc_pubkey->identifier.email ?
2552 silc_pubkey->identifier.email : "");
2553 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2554 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2555 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2556 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2557 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2558 SILCTXT_PUBKEY_NO_MATCH, entity);
2559 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2560 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2561 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2562 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2564 /* Ask user to verify the key and save it */
2565 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2566 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2567 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2570 silc_free(fingerprint);
2571 silc_free(babbleprint);
2577 /* Local copy matched */
2579 completion(TRUE, context);
2581 silc_free(fingerprint);
2582 silc_free(babbleprint);
2583 silc_free(verify->filename);
2584 silc_free(verify->entity);
2585 silc_free(verify->entity_name);
2591 /* Verifies received public key. The `conn_type' indicates which entity
2592 (server, client etc.) has sent the public key. If user decides to trust
2593 the key may be saved as trusted public key for later use. The
2594 `completion' must be called after the public key has been verified. */
2597 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2598 SilcConnectionType conn_type,
2599 SilcPublicKey public_key,
2600 SilcVerifyPublicKey completion, void *context)
2602 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2603 completion, context);
2606 /* Asks passphrase from user on the input line. */
2609 SilcAskPassphrase completion;
2613 void ask_passphrase_completion(const char *passphrase, void *context)
2615 AskPassphrase p = (AskPassphrase)context;
2616 if (passphrase && passphrase[0] == '\0')
2618 p->completion((unsigned char *)passphrase,
2619 passphrase ? strlen(passphrase) : 0, p->context);
2623 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2624 SilcAskPassphrase completion, void *context)
2626 AskPassphrase p = silc_calloc(1, sizeof(*p));
2627 p->completion = completion;
2628 p->context = context;
2630 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2631 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2635 SilcGetAuthMeth completion;
2639 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2640 SilcUInt32 passphrase_len,
2643 GetAuthMethod a = context;
2644 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2645 passphrase, passphrase_len, a->context);
2649 /* Find authentication data by hostname and port. The hostname may be IP
2652 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2653 char *hostname, SilcUInt16 port,
2654 SilcAuthMethod auth_meth,
2655 SilcGetAuthMeth completion, void *context)
2657 SERVER_SETUP_REC *setup;
2659 SILC_LOG_DEBUG(("Start"));
2661 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2662 /* Returning NULL will cause library to use our private key configured
2663 for this connection */
2664 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2668 /* Check whether we find the password for this server in our
2669 configuration. If it's set, always send it server. */
2670 setup = server_setup_find_port(hostname, port);
2671 if (setup && setup->password) {
2672 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2677 /* Didn't find password. If server wants it, ask it from user. */
2678 if (auth_meth == SILC_AUTH_PASSWORD) {
2680 a = silc_calloc(1, sizeof(*a));
2682 a->completion = completion;
2683 a->context = context;
2684 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2689 /* No authentication */
2690 completion(SILC_AUTH_NONE, NULL, 0, context);
2693 /* Asks whether the user would like to perform the key agreement protocol.
2694 This is called after we have received an key agreement packet or an
2695 reply to our key agreement packet. This returns TRUE if the user wants
2696 the library to perform the key agreement protocol and FALSE if it is not
2697 desired (application may start it later by calling the function
2698 silc_client_perform_key_agreement). */
2700 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2701 SilcClientEntry client_entry, const char *hostname,
2702 SilcUInt16 protocol, SilcUInt16 port)
2704 char portstr[12], protostr[5];
2706 SILC_LOG_DEBUG(("Start"));
2708 /* We will just display the info on the screen and return FALSE and user
2709 will have to start the key agreement with a command. */
2712 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2713 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2718 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2719 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2721 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2722 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2723 client_entry->nickname, hostname, portstr, protostr);
2726 /* Notifies application that file transfer protocol session is being
2727 requested by the remote client indicated by the `client_entry' from
2728 the `hostname' and `port'. The `session_id' is the file transfer
2729 session and it can be used to either accept or reject the file
2730 transfer request, by calling the silc_client_file_receive or
2731 silc_client_file_close, respectively. */
2733 void silc_ftp(SilcClient client, SilcClientConnection conn,
2734 SilcClientEntry client_entry, SilcUInt32 session_id,
2735 const char *hostname, SilcUInt16 port)
2737 SILC_SERVER_REC *server;
2739 FtpSession ftp = NULL;
2741 SILC_LOG_DEBUG(("Start"));
2743 server = conn->context;
2745 silc_dlist_start(server->ftp_sessions);
2746 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2747 if (ftp->client_entry == client_entry &&
2748 ftp->session_id == session_id) {
2749 server->current_session = ftp;
2753 if (ftp == SILC_LIST_END) {
2754 ftp = silc_calloc(1, sizeof(*ftp));
2755 ftp->client_entry = client_entry;
2756 ftp->session_id = session_id;
2759 silc_dlist_add(server->ftp_sessions, ftp);
2760 server->current_session = ftp;
2764 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2767 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2768 SILCTXT_FILE_REQUEST, client_entry->nickname);
2770 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2771 SILCTXT_FILE_REQUEST_HOST,
2772 client_entry->nickname, hostname, portstr);
2775 /* SILC client operations */
2776 SilcClientOperations ops = {
2778 silc_channel_message,
2779 silc_private_message,
2783 silc_get_auth_method,
2784 silc_verify_public_key,
2785 silc_ask_passphrase,