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);
1365 printformat_module("fe-common/silc", NULL, NULL,
1366 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1368 printformat_module("fe-common/silc", NULL, NULL,
1369 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1376 /* Parse an invite or ban list */
1377 void silc_parse_inviteban_list(SilcClient client,
1378 SilcClientConnection conn,
1379 SILC_SERVER_REC *server,
1380 SilcChannelEntry channel,
1381 const char *list_type,
1382 SilcArgumentPayload list)
1385 SilcUInt32 type, len;
1386 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1387 int counter=0, resolving = FALSE;
1389 if (!silc_argument_get_arg_num(list)) {
1390 printformat_module("fe-common/silc", server,
1391 (chanrec ? chanrec->visible_name : NULL),
1392 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1393 channel->channel_name, list_type);
1397 printformat_module("fe-common/silc", server,
1398 (chanrec ? chanrec->visible_name : NULL),
1399 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1400 channel->channel_name, list_type);
1402 /* Parse the list */
1403 tmp = silc_argument_get_first_arg(list, &type, &len);
1408 /* An invite string */
1412 if (tmp[len-1] == ',')
1415 list = g_strsplit(tmp, ",", -1);
1417 printformat_module("fe-common/silc", server,
1418 (chanrec ? chanrec->visible_name : NULL),
1419 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1420 ++counter, channel->channel_name, list_type,
1429 char *fingerprint, *babbleprint;
1431 /* tmp is Public Key Payload, take public key from it. */
1432 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1433 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1435 printformat_module("fe-common/silc", server,
1436 (chanrec ? chanrec->visible_name : NULL),
1437 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1438 ++counter, channel->channel_name, list_type,
1439 fingerprint, babbleprint);
1446 SilcClientEntry client_entry;
1449 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1450 silc_say_error("Invalid data in %s list encountered", list_type);
1454 client_entry = silc_client_get_client_by_id(client, conn,
1457 printformat_module("fe-common/silc", server,
1458 (chanrec ? chanrec->visible_name : NULL),
1459 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1460 ++counter, channel->channel_name, list_type,
1461 client_entry->nickname);
1462 silc_client_unref_client(client, conn, client_entry);
1465 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1473 silc_say_error("Unkown type in %s list: %u (len %u)",
1474 list_type, type, len);
1477 tmp = silc_argument_get_next_arg(list, &type, &len);
1481 printformat_module("fe-common/silc", server,
1482 (chanrec ? chanrec->visible_name : NULL),
1483 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1484 list_type, channel->channel_name);
1487 /* Command reply handler. This function is called always in the command reply
1488 function. If error occurs it will be called as well. Normal scenario
1489 is that it will be called after the received command data has been parsed
1490 and processed. The function is used to pass the received command data to
1493 `conn' is the associated client connection. `cmd_payload' is the command
1494 payload data received from server and it can be ignored. It is provided
1495 if the application would like to re-parse the received command data,
1496 however, it must be noted that the data is parsed already by the library
1497 thus the payload can be ignored. `success' is FALSE if error occured.
1498 In this case arguments are not sent to the application. `command' is the
1499 command reply being processed. The function has variable argument list
1500 and each command defines the number and type of arguments it passes to the
1501 application (on error they are not sent). */
1503 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1504 SilcCommand command, SilcStatus status,
1505 SilcStatus error, va_list vp)
1507 SILC_SERVER_REC *server = conn->context;
1508 SILC_CHANNEL_REC *chanrec;
1510 SILC_LOG_DEBUG(("Start"));
1513 case SILC_COMMAND_WHOIS:
1515 char buf[1024], *nickname, *username, *realname, *nick;
1516 unsigned char *fingerprint;
1517 SilcUInt32 idle, mode, *user_modes;
1519 SilcClientEntry client_entry;
1522 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1523 /* Print the unknown nick for user */
1524 char *tmp = va_arg(vp, char *);
1526 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1528 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1529 /* Try to find the entry for the unknown client ID, since we
1530 might have, and print the nickname of it for user. */
1531 SilcClientID *id = va_arg(vp, SilcClientID *);
1533 client_entry = silc_client_get_client_by_id(client, conn, id);
1534 if (client_entry && client_entry->nickname[0])
1535 silc_say_error("%s: %s", client_entry->nickname,
1536 silc_get_status_message(status));
1537 silc_client_unref_client(client, conn, client_entry);
1540 } else if (SILC_STATUS_IS_ERROR(status)) {
1541 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1545 client_entry = va_arg(vp, SilcClientEntry);
1546 nickname = va_arg(vp, char *);
1547 username = va_arg(vp, char *);
1548 realname = va_arg(vp, char *);
1549 channels = va_arg(vp, SilcDList);
1550 mode = va_arg(vp, SilcUInt32);
1551 idle = va_arg(vp, SilcUInt32);
1552 fingerprint = va_arg(vp, unsigned char *);
1553 user_modes = va_arg(vp, SilcUInt32 *);
1554 attrs = va_arg(vp, SilcDList);
1556 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1557 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1558 SILCTXT_WHOIS_USERINFO, nickname,
1559 client_entry->username, client_entry->hostname,
1560 nick, client_entry->nickname);
1561 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1562 SILCTXT_WHOIS_REALNAME, realname);
1565 if (channels && user_modes) {
1566 SilcChannelPayload entry;
1569 memset(buf, 0, sizeof(buf));
1570 silc_dlist_start(channels);
1571 while ((entry = silc_dlist_get(channels))) {
1572 SilcUInt32 name_len;
1573 char *m = silc_client_chumode_char(user_modes[i++]);
1574 char *name = silc_channel_get_name(entry, &name_len);
1577 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1578 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1579 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1583 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1584 SILCTXT_WHOIS_CHANNELS, buf);
1588 memset(buf, 0, sizeof(buf));
1589 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1590 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1591 SILCTXT_WHOIS_MODES, buf);
1594 if (idle && nickname) {
1595 memset(buf, 0, sizeof(buf));
1596 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1597 idle > 60 ? (idle / 60) : idle,
1598 idle > 60 ? "minutes" : "seconds");
1600 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1601 SILCTXT_WHOIS_IDLE, buf);
1605 fingerprint = silc_fingerprint(fingerprint, 20);
1606 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1607 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1608 silc_free(fingerprint);
1612 silc_query_attributes_print(server, silc_client, conn, attrs,
1617 case SILC_COMMAND_WHOWAS:
1619 char *nickname, *username, *realname;
1621 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1622 char *tmp = va_arg(vp, char *);
1624 silc_say_error("%s: %s", tmp,
1625 silc_get_status_message(status));
1627 } else if (SILC_STATUS_IS_ERROR(status)) {
1628 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1632 (void)va_arg(vp, SilcClientEntry);
1633 nickname = va_arg(vp, char *);
1634 username = va_arg(vp, char *);
1635 realname = va_arg(vp, char *);
1637 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1638 SILCTXT_WHOWAS_USERINFO, nickname, username,
1639 realname ? realname : "");
1643 case SILC_COMMAND_INVITE:
1645 SilcChannelEntry channel;
1646 SilcArgumentPayload invite_list;
1648 if (SILC_STATUS_IS_ERROR(status))
1651 channel = va_arg(vp, SilcChannelEntry);
1652 invite_list = va_arg(vp, SilcArgumentPayload);
1655 silc_parse_inviteban_list(client, conn, server, channel,
1656 "invite", invite_list);
1660 case SILC_COMMAND_JOIN:
1662 char *channel, *mode, *topic, *cipher, *hmac;
1664 SilcHashTableList *user_list;
1665 SilcChannelEntry channel_entry;
1666 SilcChannelUser chu;
1667 SilcClientEntry founder = NULL;
1670 if (SILC_STATUS_IS_ERROR(status)) {
1671 silc_say_error("JOIN: %s", silc_get_status_message(status));
1675 channel = va_arg(vp, char *);
1676 channel_entry = va_arg(vp, SilcChannelEntry);
1677 modei = va_arg(vp, SilcUInt32);
1678 user_list = va_arg(vp, SilcHashTableList *);
1679 topic = va_arg(vp, char *);
1680 cipher = va_arg(vp, char *);
1681 hmac = va_arg(vp, char *);
1683 chanrec = silc_channel_find(server, channel);
1685 chanrec = silc_channel_create(server, channel, channel, TRUE);
1688 char tmp[256], *cp, *dm = NULL;
1689 g_free_not_null(chanrec->topic);
1691 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1692 memset(tmp, 0, sizeof(tmp));
1694 if (strlen(topic) > sizeof(tmp) - 1) {
1695 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1699 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1704 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1705 signal_emit("channel topic changed", 1, chanrec);
1710 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1711 g_free_not_null(chanrec->mode);
1712 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1713 signal_emit("channel mode changed", 1, chanrec);
1716 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1717 if (!chu->client->nickname[0])
1719 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1720 founder = chu->client;
1721 silc_nicklist_insert(chanrec, chu, FALSE);
1724 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1727 nicklist_set_own(CHANNEL(chanrec), ownnick);
1728 signal_emit("channel joined", 1, chanrec);
1729 chanrec->entry = channel_entry;
1732 printformat_module("fe-common/silc", server,
1733 channel_entry->channel_name,
1734 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1735 channel_entry->channel_name, chanrec->topic);
1738 if (founder == conn->local_entry) {
1739 printformat_module("fe-common/silc",
1740 server, channel_entry->channel_name,
1741 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1742 channel_entry->channel_name);
1743 signal_emit("nick mode changed", 2, chanrec, ownnick);
1745 printformat_module("fe-common/silc",
1746 server, channel_entry->channel_name,
1747 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1748 channel_entry->channel_name, founder->nickname);
1754 case SILC_COMMAND_NICK:
1757 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1760 if (SILC_STATUS_IS_ERROR(status)) {
1761 silc_say_error("NICK: %s", silc_get_status_message(status));
1765 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1766 if ((nicks != NULL) &&
1767 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1769 SilcClientEntry collider, old;
1771 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1772 collider = silc_client_get_client_by_id(client, conn, &old->id);
1773 if (collider != client_entry) {
1774 memset(buf, 0, sizeof(buf));
1775 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1776 collider->username, collider->hostname);
1777 nicklist_rename_unique(SERVER(server),
1779 collider, collider->nickname);
1780 silc_print_nick_change(server, collider->nickname,
1781 client_entry->nickname, buf);
1783 silc_client_unref_client(client, conn, collider);
1787 g_slist_free(nicks);
1789 old = g_strdup(server->nick);
1790 server_change_nick(SERVER(server), client_entry->nickname);
1791 nicklist_rename_unique(SERVER(server),
1792 server->conn->local_entry, server->nick,
1793 client_entry, client_entry->nickname);
1794 signal_emit("message own_nick", 4, server, server->nick, old, "");
1797 /* when connecting to a server, the last thing we receive
1798 is a SILC_COMMAND_LIST reply. Since we enable queueing
1799 during the connection, we can now safely disable it again */
1800 silc_queue_disable(conn);
1804 case SILC_COMMAND_LIST:
1809 char tmp[256], *cp, *dm = NULL;
1811 if (SILC_STATUS_IS_ERROR(status))
1814 (void)va_arg(vp, SilcChannelEntry);
1815 name = va_arg(vp, char *);
1816 topic = va_arg(vp, char *);
1817 usercount = va_arg(vp, int);
1819 if (topic && !silc_term_utf8() &&
1820 silc_utf8_valid(topic, strlen(topic))) {
1821 memset(tmp, 0, sizeof(tmp));
1823 if (strlen(topic) > sizeof(tmp) - 1) {
1824 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1828 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1833 if (status == SILC_STATUS_LIST_START ||
1834 status == SILC_STATUS_OK)
1835 printformat_module("fe-common/silc", server, NULL,
1836 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1839 snprintf(users, sizeof(users) - 1, "N/A");
1841 snprintf(users, sizeof(users) - 1, "%d", usercount);
1842 printformat_module("fe-common/silc", server, NULL,
1843 MSGLEVEL_CRAP, SILCTXT_LIST,
1844 name, users, topic ? topic : "");
1849 case SILC_COMMAND_UMODE:
1854 if (SILC_STATUS_IS_ERROR(status))
1857 mode = va_arg(vp, SilcUInt32);
1859 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1860 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1861 printformat_module("fe-common/silc", server, NULL,
1862 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1864 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1865 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1866 printformat_module("fe-common/silc", server, NULL,
1867 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1869 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1870 if (mode & SILC_UMODE_GONE) {
1871 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1872 reason = g_strdup(server->away_reason);
1874 reason = g_strdup("away");
1876 reason = g_strdup("");
1878 silc_set_away(reason, server);
1883 server->umode = mode;
1884 signal_emit("user mode changed", 2, server, NULL);
1888 case SILC_COMMAND_OPER:
1889 if (SILC_STATUS_IS_ERROR(status)) {
1890 silc_say_error("OPER: %s", silc_get_status_message(status));
1894 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1895 signal_emit("user mode changed", 2, server, NULL);
1897 printformat_module("fe-common/silc", server, NULL,
1898 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1901 case SILC_COMMAND_SILCOPER:
1902 if (SILC_STATUS_IS_ERROR(status)) {
1903 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1907 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1908 signal_emit("user mode changed", 2, server, NULL);
1910 printformat_module("fe-common/silc", server, NULL,
1911 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1914 case SILC_COMMAND_USERS:
1916 SilcHashTableList htl;
1917 SilcChannelEntry channel;
1918 SilcChannelUser chu;
1920 if (SILC_STATUS_IS_ERROR(status)) {
1921 silc_say_error("USERS: %s", silc_get_status_message(status));
1925 channel = va_arg(vp, SilcChannelEntry);
1927 printformat_module("fe-common/silc", server, channel->channel_name,
1928 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1929 channel->channel_name);
1931 silc_hash_table_list(channel->user_list, &htl);
1932 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1933 SilcClientEntry e = chu->client;
1934 char stat[5], *mode;
1936 if (!e->nickname[0])
1939 memset(stat, 0, sizeof(stat));
1940 mode = silc_client_chumode_char(chu->mode);
1941 if (e->mode & SILC_UMODE_GONE)
1943 else if (e->mode & SILC_UMODE_INDISPOSED)
1945 else if (e->mode & SILC_UMODE_BUSY)
1947 else if (e->mode & SILC_UMODE_PAGE)
1949 else if (e->mode & SILC_UMODE_HYPER)
1951 else if (e->mode & SILC_UMODE_ROBOT)
1953 else if (e->mode & SILC_UMODE_ANONYMOUS)
1960 printformat_module("fe-common/silc", server, channel->channel_name,
1961 MSGLEVEL_CRAP, SILCTXT_USERS,
1963 e->username[0] ? e->username : "",
1964 e->hostname[0] ? e->hostname : "",
1965 e->realname ? e->realname : "");
1969 silc_hash_table_list_reset(&htl);
1973 case SILC_COMMAND_BAN:
1975 SilcChannelEntry channel;
1976 SilcArgumentPayload invite_list;
1978 if (SILC_STATUS_IS_ERROR(status))
1981 channel = va_arg(vp, SilcChannelEntry);
1982 invite_list = va_arg(vp, SilcArgumentPayload);
1985 silc_parse_inviteban_list(client, conn, server, channel,
1986 "ban", invite_list);
1990 case SILC_COMMAND_GETKEY:
1994 SilcPublicKey public_key;
1995 GetkeyContext getkey;
1998 if (SILC_STATUS_IS_ERROR(status)) {
1999 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2003 id_type = va_arg(vp, SilcUInt32);
2004 entry = va_arg(vp, void *);
2005 public_key = va_arg(vp, SilcPublicKey);
2008 getkey = silc_calloc(1, sizeof(*getkey));
2009 getkey->entry = entry;
2010 getkey->id_type = id_type;
2011 getkey->client = client;
2012 getkey->conn = conn;
2014 name = (id_type == SILC_ID_CLIENT ?
2015 ((SilcClientEntry)entry)->nickname :
2016 ((SilcServerEntry)entry)->server_name);
2018 silc_verify_public_key_internal(client, conn, name,
2019 (id_type == SILC_ID_CLIENT ?
2022 public_key, silc_getkey_cb, getkey);
2024 printformat_module("fe-common/silc", server, NULL,
2025 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2030 case SILC_COMMAND_INFO:
2032 SilcServerEntry server_entry;
2036 if (SILC_STATUS_IS_ERROR(status))
2039 server_entry = va_arg(vp, SilcServerEntry);
2040 server_name = va_arg(vp, char *);
2041 server_info = va_arg(vp, char *);
2043 if (server_name && server_info )
2045 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2046 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2051 case SILC_COMMAND_TOPIC:
2053 SilcChannelEntry channel;
2055 char tmp[256], *cp, *dm = NULL;
2057 if (SILC_STATUS_IS_ERROR(status))
2060 channel = va_arg(vp, SilcChannelEntry);
2061 topic = va_arg(vp, char *);
2063 if (topic && !silc_term_utf8() &&
2064 silc_utf8_valid(topic, strlen(topic))) {
2065 memset(tmp, 0, sizeof(tmp));
2067 if (strlen(topic) > sizeof(tmp) - 1) {
2068 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2072 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2078 chanrec = silc_channel_find_entry(server, channel);
2080 g_free_not_null(chanrec->topic);
2081 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2082 signal_emit("channel topic changed", 1, chanrec);
2084 printformat_module("fe-common/silc", server, channel->channel_name,
2085 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2086 channel->channel_name, topic);
2088 printformat_module("fe-common/silc", server, channel->channel_name,
2089 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2090 channel->channel_name);
2096 case SILC_COMMAND_WATCH:
2099 case SILC_COMMAND_STATS:
2101 SilcClientStats *cstats;
2103 const char *tmptime;
2104 int days, hours, mins, secs;
2106 if (SILC_STATUS_IS_ERROR(status))
2109 cstats = va_arg(vp, SilcClientStats *);
2111 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2115 tmptime = silc_time_string(cstats->starttime);
2116 printformat_module("fe-common/silc", server, NULL,
2117 MSGLEVEL_CRAP, SILCTXT_STATS,
2118 "Local server start time", tmptime);
2120 days = cstats->uptime / (24 * 60 * 60);
2121 cstats->uptime -= days * (24 * 60 * 60);
2122 hours = cstats->uptime / (60 * 60);
2123 cstats->uptime -= hours * (60 * 60);
2124 mins = cstats->uptime / 60;
2125 cstats->uptime -= mins * 60;
2126 secs = cstats->uptime;
2127 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2128 days, hours, mins, secs);
2129 printformat_module("fe-common/silc", server, NULL,
2130 MSGLEVEL_CRAP, SILCTXT_STATS,
2131 "Local server uptime", tmp);
2133 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2134 printformat_module("fe-common/silc", server, NULL,
2135 MSGLEVEL_CRAP, SILCTXT_STATS,
2136 "Local server clients", tmp);
2138 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2139 printformat_module("fe-common/silc", server, NULL,
2140 MSGLEVEL_CRAP, SILCTXT_STATS,
2141 "Local server channels", tmp);
2143 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2144 printformat_module("fe-common/silc", server, NULL,
2145 MSGLEVEL_CRAP, SILCTXT_STATS,
2146 "Local server operators", tmp);
2148 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2149 printformat_module("fe-common/silc", server, NULL,
2150 MSGLEVEL_CRAP, SILCTXT_STATS,
2151 "Local router operators", tmp);
2153 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2154 printformat_module("fe-common/silc", server, NULL,
2155 MSGLEVEL_CRAP, SILCTXT_STATS,
2156 "Local cell clients", tmp);
2158 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2159 printformat_module("fe-common/silc", server, NULL,
2160 MSGLEVEL_CRAP, SILCTXT_STATS,
2161 "Local cell channels", tmp);
2163 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2164 printformat_module("fe-common/silc", server, NULL,
2165 MSGLEVEL_CRAP, SILCTXT_STATS,
2166 "Local cell servers", tmp);
2168 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2169 printformat_module("fe-common/silc", server, NULL,
2170 MSGLEVEL_CRAP, SILCTXT_STATS,
2171 "Total clients", tmp);
2173 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2174 printformat_module("fe-common/silc", server, NULL,
2175 MSGLEVEL_CRAP, SILCTXT_STATS,
2176 "Total channels", tmp);
2178 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2179 printformat_module("fe-common/silc", server, NULL,
2180 MSGLEVEL_CRAP, SILCTXT_STATS,
2181 "Total servers", tmp);
2183 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2184 printformat_module("fe-common/silc", server, NULL,
2185 MSGLEVEL_CRAP, SILCTXT_STATS,
2186 "Total routers", tmp);
2188 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2189 printformat_module("fe-common/silc", server, NULL,
2190 MSGLEVEL_CRAP, SILCTXT_STATS,
2191 "Total server operators", tmp);
2193 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2194 printformat_module("fe-common/silc", server, NULL,
2195 MSGLEVEL_CRAP, SILCTXT_STATS,
2196 "Total router operators", tmp);
2200 case SILC_COMMAND_CMODE:
2202 SilcChannelEntry channel_entry;
2205 channel_entry = va_arg(vp, SilcChannelEntry);
2206 (void)va_arg(vp, SilcUInt32);
2207 (void)va_arg(vp, SilcPublicKey);
2208 chpks = va_arg(vp, SilcDList);
2210 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2211 !channel_entry || !channel_entry->channel_name)
2214 /* Print the channel public key list */
2216 silc_parse_channel_public_keys(server, channel_entry, chpks);
2218 printformat_module("fe-common/silc", server, NULL,
2219 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2220 channel_entry->channel_name);
2225 case SILC_COMMAND_LEAVE:
2227 if (SILC_STATUS_IS_ERROR(status))
2230 /* We might be cycling, so disable queueing again */
2231 silc_queue_disable(conn);
2235 case SILC_COMMAND_DETACH:
2237 /* Save the detachment data to file. */
2241 if (SILC_STATUS_IS_ERROR(status))
2244 detach = va_arg(vp, SilcBuffer);
2245 file = silc_get_session_filename(server);
2246 silc_file_writefile(file, silc_buffer_data(detach),
2247 silc_buffer_len(detach));
2252 case SILC_COMMAND_KILL:
2254 SilcClientEntry client_entry;
2256 if (SILC_STATUS_IS_ERROR(status)) {
2257 silc_say_error("KILL: %s", silc_get_status_message(status));
2261 client_entry = va_arg(vp, SilcClientEntry);
2262 if (!client_entry || !client_entry->nickname[0])
2265 /* Print this only if the killed client isn't joined on channels.
2266 If it is, we receive KILLED notify and we'll print this there. */
2267 if (!silc_hash_table_count(client_entry->channels))
2268 printformat_module("fe-common/silc", server, NULL,
2269 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2270 client_entry->nickname,
2271 conn->local_entry->nickname, "");
2278 SilcClientConnection conn;
2282 SilcPublicKey public_key;
2283 SilcVerifyPublicKey completion;
2287 static void verify_public_key_completion(const char *line, void *context)
2289 PublicKeyVerify verify = (PublicKeyVerify)context;
2291 if (line[0] == 'Y' || line[0] == 'y') {
2292 /* Call the completion */
2293 if (verify->completion)
2294 verify->completion(TRUE, verify->context);
2296 /* Save the key for future checking */
2297 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2298 SILC_PKCS_FILE_BASE64);
2300 /* Call the completion */
2301 if (verify->completion)
2302 verify->completion(FALSE, verify->context);
2304 printformat_module("fe-common/silc", NULL, NULL,
2305 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2306 verify->entity_name ? verify->entity_name :
2310 silc_free(verify->filename);
2311 silc_free(verify->entity);
2312 silc_free(verify->entity_name);
2316 /* Internal routine to verify public key. If the `completion' is provided
2317 it will be called to indicate whether public was verified or not. For
2318 server/router public key this will check for filename that includes the
2319 remote host's IP address and remote host's hostname. */
2322 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2324 SilcConnectionType conn_type,
2325 SilcPublicKey public_key,
2326 SilcVerifyPublicKey completion, void *context)
2328 PublicKeyVerify verify;
2329 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2330 char *fingerprint, *babbleprint, *format;
2331 SilcPublicKey local_pubkey;
2333 const char *hostname, *ip;
2338 char *entity = ((conn_type == SILC_CONN_SERVER ||
2339 conn_type == SILC_CONN_ROUTER) ?
2340 "server" : "client");
2343 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2344 printformat_module("fe-common/silc", NULL, NULL,
2345 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2346 entity, silc_pkcs_get_type(public_key));
2348 completion(FALSE, context);
2352 /* Encode public key */
2353 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2356 completion(FALSE, context);
2360 pw = getpwuid(getuid());
2363 completion(FALSE, context);
2368 memset(filename, 0, sizeof(filename));
2369 memset(filename2, 0, sizeof(filename2));
2370 memset(file, 0, sizeof(file));
2372 /* Get remote host information */
2373 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2374 NULL, &hostname, &ip, &port);
2376 if (conn_type == SILC_CONN_SERVER ||
2377 conn_type == SILC_CONN_ROUTER) {
2379 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2380 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2381 get_irssi_dir(), entity, file);
2383 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2385 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2386 get_irssi_dir(), entity, file);
2391 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2393 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2394 get_irssi_dir(), entity, file);
2399 /* Replace all whitespaces with `_'. */
2400 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2401 for (i = 0; i < strlen(fingerprint); i++)
2402 if (fingerprint[i] == ' ')
2403 fingerprint[i] = '_';
2405 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2406 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2407 get_irssi_dir(), entity, file);
2408 silc_free(fingerprint);
2413 /* Take fingerprint of the public key */
2414 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2415 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2417 verify = silc_calloc(1, sizeof(*verify));
2418 verify->client = client;
2419 verify->conn = conn;
2420 verify->filename = strdup(ipf);
2421 verify->entity = strdup(entity);
2422 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2423 (name ? strdup(name) : strdup(hostname))
2425 verify->public_key = public_key;
2426 verify->completion = completion;
2427 verify->context = context;
2429 /* Check whether this key already exists */
2430 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2431 /* Key does not exist, ask user to verify the key and save it */
2433 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2434 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2435 verify->entity_name : entity);
2436 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2437 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2438 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2439 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2440 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2441 SILCTXT_PUBKEY_ACCEPT);
2442 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2445 silc_free(fingerprint);
2446 silc_free(babbleprint);
2450 /* The key already exists, verify it. */
2451 unsigned char *encpk;
2452 SilcUInt32 encpk_len;
2454 /* Load the key file, try for both IP filename and hostname filename */
2455 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2456 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2457 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2458 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2459 verify->entity_name : entity);
2460 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2461 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2462 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2463 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2464 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2465 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2466 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2467 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2468 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2471 silc_free(fingerprint);
2472 silc_free(babbleprint);
2477 /* Encode the key data */
2478 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2480 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2481 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2482 verify->entity_name : entity);
2483 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2484 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2485 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2486 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2487 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2488 SILCTXT_PUBKEY_MALFORMED, entity);
2489 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2490 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2491 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2494 silc_free(fingerprint);
2495 silc_free(babbleprint);
2499 silc_pkcs_public_key_free(local_pubkey);
2501 /* Compare the keys */
2502 if (memcmp(encpk, pk, encpk_len)) {
2503 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2504 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2505 verify->entity_name : entity);
2506 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2507 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2508 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2509 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2510 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2511 SILCTXT_PUBKEY_NO_MATCH, entity);
2512 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2513 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2514 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2515 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2517 /* Ask user to verify the key and save it */
2518 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2519 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2520 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2523 silc_free(fingerprint);
2524 silc_free(babbleprint);
2530 /* Local copy matched */
2532 completion(TRUE, context);
2534 silc_free(fingerprint);
2535 silc_free(babbleprint);
2536 silc_free(verify->filename);
2537 silc_free(verify->entity);
2538 silc_free(verify->entity_name);
2544 /* Verifies received public key. The `conn_type' indicates which entity
2545 (server, client etc.) has sent the public key. If user decides to trust
2546 the key may be saved as trusted public key for later use. The
2547 `completion' must be called after the public key has been verified. */
2550 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2551 SilcConnectionType conn_type,
2552 SilcPublicKey public_key,
2553 SilcVerifyPublicKey completion, void *context)
2555 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2556 completion, context);
2559 /* Asks passphrase from user on the input line. */
2562 SilcAskPassphrase completion;
2566 void ask_passphrase_completion(const char *passphrase, void *context)
2568 AskPassphrase p = (AskPassphrase)context;
2569 if (passphrase && passphrase[0] == '\0')
2571 p->completion((unsigned char *)passphrase,
2572 passphrase ? strlen(passphrase) : 0, p->context);
2576 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2577 SilcAskPassphrase completion, void *context)
2579 AskPassphrase p = silc_calloc(1, sizeof(*p));
2580 p->completion = completion;
2581 p->context = context;
2583 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2584 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2588 SilcGetAuthMeth completion;
2592 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2593 SilcUInt32 passphrase_len,
2596 GetAuthMethod a = context;
2597 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2598 passphrase, passphrase_len, a->context);
2602 /* Find authentication data by hostname and port. The hostname may be IP
2605 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2606 char *hostname, SilcUInt16 port,
2607 SilcAuthMethod auth_meth,
2608 SilcGetAuthMeth completion, void *context)
2610 SERVER_SETUP_REC *setup;
2612 SILC_LOG_DEBUG(("Start"));
2614 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2615 /* Returning NULL will cause library to use our private key configured
2616 for this connection */
2617 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2621 /* Check whether we find the password for this server in our
2622 configuration. If it's set, always send it server. */
2623 setup = server_setup_find_port(hostname, port);
2624 if (setup && setup->password) {
2625 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2630 /* Didn't find password. If server wants it, ask it from user. */
2631 if (auth_meth == SILC_AUTH_PASSWORD) {
2633 a = silc_calloc(1, sizeof(*a));
2635 a->completion = completion;
2636 a->context = context;
2637 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2642 /* No authentication */
2643 completion(SILC_AUTH_NONE, NULL, 0, context);
2646 /* Asks whether the user would like to perform the key agreement protocol.
2647 This is called after we have received an key agreement packet or an
2648 reply to our key agreement packet. This returns TRUE if the user wants
2649 the library to perform the key agreement protocol and FALSE if it is not
2650 desired (application may start it later by calling the function
2651 silc_client_perform_key_agreement). */
2653 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2654 SilcClientEntry client_entry, const char *hostname,
2655 SilcUInt16 protocol, SilcUInt16 port)
2657 char portstr[12], protostr[5];
2659 SILC_LOG_DEBUG(("Start"));
2661 /* We will just display the info on the screen and return FALSE and user
2662 will have to start the key agreement with a command. */
2665 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2666 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2671 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2672 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2674 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2675 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2676 client_entry->nickname, hostname, portstr, protostr);
2679 /* Notifies application that file transfer protocol session is being
2680 requested by the remote client indicated by the `client_entry' from
2681 the `hostname' and `port'. The `session_id' is the file transfer
2682 session and it can be used to either accept or reject the file
2683 transfer request, by calling the silc_client_file_receive or
2684 silc_client_file_close, respectively. */
2686 void silc_ftp(SilcClient client, SilcClientConnection conn,
2687 SilcClientEntry client_entry, SilcUInt32 session_id,
2688 const char *hostname, SilcUInt16 port)
2690 SILC_SERVER_REC *server;
2692 FtpSession ftp = NULL;
2694 SILC_LOG_DEBUG(("Start"));
2696 server = conn->context;
2698 silc_dlist_start(server->ftp_sessions);
2699 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2700 if (ftp->client_entry == client_entry &&
2701 ftp->session_id == session_id) {
2702 server->current_session = ftp;
2706 if (ftp == SILC_LIST_END) {
2707 ftp = silc_calloc(1, sizeof(*ftp));
2708 ftp->client_entry = client_entry;
2709 ftp->session_id = session_id;
2712 silc_dlist_add(server->ftp_sessions, ftp);
2713 server->current_session = ftp;
2717 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2720 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2721 SILCTXT_FILE_REQUEST, client_entry->nickname);
2723 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2724 SILCTXT_FILE_REQUEST_HOST,
2725 client_entry->nickname, hostname, portstr);
2728 /* SILC client operations */
2729 SilcClientOperations ops = {
2731 silc_channel_message,
2732 silc_private_message,
2736 silc_get_auth_method,
2737 silc_verify_public_key,
2738 silc_ask_passphrase,