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);
752 if (chanrec != NULL && !chanrec->joined)
753 chanrec->entry = channel;
755 chanrec = silc_channel_find_entry(server, channel);
756 if (chanrec != NULL) {
757 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
759 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
763 memset(buf, 0, sizeof(buf));
764 if (client_entry->username[0])
765 snprintf(buf, sizeof(buf) - 1, "%s@%s",
766 client_entry->username, client_entry->hostname);
767 signal_emit("message join", 4, server, channel->channel_name,
768 client_entry->nickname,
769 client_entry->username == NULL ? "" : buf);
771 /* If there are multiple same nicknames on channel now, tell it to user. */
772 if (client_entry != server->conn->local_entry) {
773 char nick[128 + 1], tmp[32];
775 silc_parse_userfqdn(client_entry->nickname, nick, sizeof(nick), NULL, 0);
776 clients = silc_client_get_clients_local(client, conn, nick, NULL);
777 if (!clients || silc_dlist_count(clients) < 2) {
778 silc_client_list_free(client, conn, clients);
781 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
782 printformat_module("fe-common/silc", server, NULL,
783 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
785 printformat_module("fe-common/silc", server, NULL,
786 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
787 buf, client_entry->nickname);
788 silc_client_list_free(client, conn, clients);
792 case SILC_NOTIFY_TYPE_LEAVE:
797 SILC_LOG_DEBUG(("Notify: LEAVE"));
799 client_entry = va_arg(va, SilcClientEntry);
800 channel = va_arg(va, SilcChannelEntry);
802 memset(buf, 0, sizeof(buf));
803 if (client_entry->username)
804 snprintf(buf, sizeof(buf) - 1, "%s@%s",
805 client_entry->username, client_entry->hostname);
806 signal_emit("message part", 5, server, channel->channel_name,
807 client_entry->nickname, client_entry->username[0] ?
808 buf : "", client_entry->nickname);
810 chanrec = silc_channel_find_entry(server, channel);
811 if (chanrec != NULL) {
812 nickrec = silc_nicklist_find(chanrec, client_entry);
814 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
818 case SILC_NOTIFY_TYPE_SIGNOFF:
823 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
825 client_entry = va_arg(va, SilcClientEntry);
826 tmp = va_arg(va, char *);
828 silc_server_free_ftp(server, client_entry);
830 /* Print only if we have the nickname. If this cliente has just quit
831 when we were only resolving it, it is possible we don't have the
833 if (client_entry->nickname[0]) {
834 memset(buf, 0, sizeof(buf));
835 if (client_entry->username)
836 snprintf(buf, sizeof(buf) - 1, "%s@%s",
837 client_entry->username, client_entry->hostname);
838 signal_emit("message quit", 4, server, client_entry->nickname,
839 client_entry->username[0] ? buf : "",
843 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
844 for (list_tmp = list1; list_tmp != NULL; list_tmp =
845 list_tmp->next->next) {
846 CHANNEL_REC *channel = list_tmp->data;
847 NICK_REC *nickrec = list_tmp->next->data;
849 nicklist_remove(channel, nickrec);
853 case SILC_NOTIFY_TYPE_TOPIC_SET:
858 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
860 idtype = va_arg(va, int);
861 entry = va_arg(va, void *);
862 tmp = va_arg(va, char *);
863 channel = va_arg(va, SilcChannelEntry);
865 chanrec = silc_channel_find_entry(server, channel);
866 if (chanrec != NULL) {
867 char tmp2[256], *cp, *dm = NULL;
869 g_free_not_null(chanrec->topic);
870 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
871 memset(tmp2, 0, sizeof(tmp2));
873 if (strlen(tmp) > sizeof(tmp2) - 1) {
874 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
878 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
883 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
884 signal_emit("channel topic changed", 1, chanrec);
889 if (idtype == SILC_ID_CLIENT) {
890 client_entry = (SilcClientEntry)entry;
891 memset(buf, 0, sizeof(buf));
892 snprintf(buf, sizeof(buf) - 1, "%s@%s",
893 client_entry->username, client_entry->hostname);
894 signal_emit("message topic", 5, server, channel->channel_name,
895 tmp, client_entry->nickname, buf);
896 } else if (idtype == SILC_ID_SERVER) {
897 server_entry = (SilcServerEntry)entry;
898 signal_emit("message topic", 5, server, channel->channel_name,
899 tmp, server_entry->server_name,
900 server_entry->server_name);
901 } else if (idtype == SILC_ID_CHANNEL) {
902 channel = (SilcChannelEntry)entry;
903 signal_emit("message topic", 5, server, channel->channel_name,
904 tmp, channel->channel_name, channel->channel_name);
908 case SILC_NOTIFY_TYPE_NICK_CHANGE:
913 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
915 client_entry = va_arg(va, SilcClientEntry);
916 name = va_arg(va, char *); /* old nickname */
918 if (!strcmp(client_entry->nickname, name))
921 memset(buf, 0, sizeof(buf));
922 snprintf(buf, sizeof(buf) - 1, "%s@%s",
923 client_entry->username, client_entry->hostname);
924 nicklist_rename_unique(SERVER(server),
926 client_entry, client_entry->nickname);
927 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
930 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
932 * Changed channel mode.
935 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
937 idtype = va_arg(va, int);
938 entry = va_arg(va, void *);
939 mode = va_arg(va, SilcUInt32);
940 cipher = va_arg(va, char *); /* cipher */
941 hmac = va_arg(va, char *); /* hmac */
942 (void)va_arg(va, char *); /* passphrase */
943 (void)va_arg(va, SilcPublicKey); /* founder key */
944 chpks = va_arg(va, SilcDList); /* channel public keys */
945 channel = va_arg(va, SilcChannelEntry);
947 tmp = silc_client_chmode(mode, cipher ? cipher : "",
950 chanrec = silc_channel_find_entry(server, channel);
951 if (chanrec != NULL) {
952 g_free_not_null(chanrec->mode);
953 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
954 signal_emit("channel mode changed", 1, chanrec);
957 if (idtype == SILC_ID_CLIENT) {
958 client_entry = (SilcClientEntry)entry;
959 printformat_module("fe-common/silc", server, channel->channel_name,
960 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
961 channel->channel_name, tmp ? tmp : "removed all",
962 client_entry->nickname);
963 } else if (idtype == SILC_ID_SERVER) {
964 server_entry = (SilcServerEntry)entry;
965 printformat_module("fe-common/silc", server, channel->channel_name,
966 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
967 channel->channel_name, tmp ? tmp : "removed all",
968 server_entry->server_name);
969 } else if (idtype == SILC_ID_CHANNEL) {
970 channel2 = (SilcChannelEntry)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 channel2->channel_name);
977 /* Print the channel public key list */
979 silc_parse_channel_public_keys(server, channel, chpks);
984 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
986 * Changed user's mode on channel.
989 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
991 idtype = va_arg(va, int);
992 entry = va_arg(va, void *);
993 mode = va_arg(va, SilcUInt32);
994 client_entry2 = va_arg(va, SilcClientEntry);
995 channel = va_arg(va, SilcChannelEntry);
997 tmp = silc_client_chumode(mode);
998 chanrec = silc_channel_find_entry(server, channel);
999 if (chanrec != NULL) {
1000 SILC_NICK_REC *nick;
1002 if (client_entry2 == server->conn->local_entry)
1003 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1005 nick = silc_nicklist_find(chanrec, client_entry2);
1007 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1008 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1009 signal_emit("nick mode changed", 2, chanrec, nick);
1013 if (idtype == SILC_ID_CLIENT) {
1014 client_entry = (SilcClientEntry)entry;
1015 printformat_module("fe-common/silc", server, channel->channel_name,
1016 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1017 channel->channel_name, client_entry2->nickname,
1018 tmp ? tmp : "removed all",
1019 client_entry->nickname);
1020 } else if (idtype == SILC_ID_SERVER) {
1021 server_entry = (SilcServerEntry)entry;
1022 printformat_module("fe-common/silc", server, channel->channel_name,
1023 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1024 channel->channel_name, client_entry2->nickname,
1025 tmp ? tmp : "removed all",
1026 server_entry->server_name);
1027 } else if (idtype == SILC_ID_CHANNEL) {
1028 channel2 = (SilcChannelEntry)entry;
1029 printformat_module("fe-common/silc", server, channel->channel_name,
1030 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1031 channel->channel_name, client_entry2->nickname,
1032 tmp ? tmp : "removed all",
1033 channel2->channel_name);
1036 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1037 printformat_module("fe-common/silc",
1038 server, channel->channel_name, MSGLEVEL_CRAP,
1039 SILCTXT_CHANNEL_FOUNDER,
1040 channel->channel_name, client_entry2->nickname);
1042 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1043 printformat_module("fe-common/silc",
1044 server, channel->channel_name, MSGLEVEL_CRAP,
1045 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1050 case SILC_NOTIFY_TYPE_MOTD:
1055 SILC_LOG_DEBUG(("Notify: MOTD"));
1057 tmp = va_arg(va, char *);
1059 if (!settings_get_bool("skip_motd"))
1060 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1063 case SILC_NOTIFY_TYPE_KICKED:
1065 * Someone was kicked from channel.
1068 SILC_LOG_DEBUG(("Notify: KICKED"));
1070 client_entry = va_arg(va, SilcClientEntry);
1071 tmp = va_arg(va, char *);
1072 client_entry2 = va_arg(va, SilcClientEntry);
1073 channel = va_arg(va, SilcChannelEntry);
1075 chanrec = silc_channel_find_entry(server, channel);
1077 if (client_entry == conn->local_entry) {
1078 printformat_module("fe-common/silc", server, channel->channel_name,
1079 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1080 channel->channel_name,
1081 client_entry ? client_entry2->nickname : "",
1084 chanrec->kicked = TRUE;
1085 channel_destroy((CHANNEL_REC *)chanrec);
1088 printformat_module("fe-common/silc", server, channel->channel_name,
1089 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1090 client_entry->nickname, channel->channel_name,
1091 client_entry2 ? client_entry2->nickname : "",
1095 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1096 if (nickrec != NULL)
1097 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1102 case SILC_NOTIFY_TYPE_KILLED:
1104 * Someone was killed from the network.
1107 SILC_LOG_DEBUG(("Notify: KILLED"));
1109 client_entry = va_arg(va, SilcClientEntry);
1110 tmp = va_arg(va, char *);
1111 idtype = va_arg(va, int);
1112 entry = va_arg(va, SilcClientEntry);
1114 if (client_entry == conn->local_entry) {
1115 if (idtype == SILC_ID_CLIENT) {
1116 client_entry2 = (SilcClientEntry)entry;
1117 printformat_module("fe-common/silc", server, NULL,
1118 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1119 client_entry2 ? client_entry2->nickname : "",
1121 } else if (idtype == SILC_ID_SERVER) {
1122 server_entry = (SilcServerEntry)entry;
1123 printformat_module("fe-common/silc", server, NULL,
1124 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1125 server_entry->server_name, tmp ? tmp : "");
1126 } else if (idtype == SILC_ID_CHANNEL) {
1127 channel = (SilcChannelEntry)entry;
1128 printformat_module("fe-common/silc", server, NULL,
1129 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1130 channel->channel_name, tmp ? tmp : "");
1133 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1134 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1135 list_tmp->next->next) {
1136 CHANNEL_REC *channel = list_tmp->data;
1137 NICK_REC *nickrec = list_tmp->next->data;
1138 nicklist_remove(channel, nickrec);
1141 if (idtype == SILC_ID_CLIENT) {
1142 client_entry2 = (SilcClientEntry)entry;
1143 printformat_module("fe-common/silc", server, NULL,
1144 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1145 client_entry->nickname,
1146 client_entry2 ? client_entry2->nickname : "",
1148 } else if (idtype == SILC_ID_SERVER) {
1149 server_entry = (SilcServerEntry)entry;
1150 printformat_module("fe-common/silc", server, NULL,
1151 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1152 client_entry->nickname,
1153 server_entry->server_name, tmp ? tmp : "");
1154 } else if (idtype == SILC_ID_CHANNEL) {
1155 channel = (SilcChannelEntry)entry;
1156 printformat_module("fe-common/silc", server, NULL,
1157 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1158 client_entry->nickname,
1159 channel->channel_name, tmp ? tmp : "");
1164 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1167 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1170 * Server has quit the network.
1174 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1176 (void)va_arg(va, void *);
1177 clients = va_arg(va, SilcDList);
1179 silc_dlist_start(clients);
1180 while ((client_entry = silc_dlist_get(clients))) {
1181 memset(buf, 0, sizeof(buf));
1183 /* Print only if we have the nickname. If this client has just quit
1184 when we were only resolving it, it is possible we don't have the
1186 if (client_entry->nickname[0]) {
1187 if (client_entry->username[0])
1188 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1189 client_entry->username, client_entry->hostname);
1190 signal_emit("message quit", 4, server, client_entry->nickname,
1191 client_entry->username[0] ? buf : "",
1195 silc_server_free_ftp(server, client_entry);
1197 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1198 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1199 list_tmp->next->next) {
1200 CHANNEL_REC *channel = list_tmp->data;
1201 NICK_REC *nickrec = list_tmp->next->data;
1202 nicklist_remove(channel, nickrec);
1208 case SILC_NOTIFY_TYPE_ERROR:
1210 SilcStatus error = va_arg(va, int);
1212 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1213 "%s", silc_get_status_message(error));
1217 case SILC_NOTIFY_TYPE_WATCH:
1219 SilcNotifyType notify;
1221 client_entry = va_arg(va, SilcClientEntry);
1222 name = va_arg(va, char *); /* Maybe NULL */
1223 mode = va_arg(va, SilcUInt32);
1224 notify = va_arg(va, int);
1226 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1228 printformat_module("fe-common/silc", server, NULL,
1229 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1230 client_entry->nickname, name);
1232 printformat_module("fe-common/silc", server, NULL,
1233 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1234 client_entry->nickname);
1235 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1236 /* See if client was away and is now present */
1237 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1238 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1239 SILC_UMODE_DETACHED)) &&
1240 (client_entry->mode & SILC_UMODE_GONE ||
1241 client_entry->mode & SILC_UMODE_INDISPOSED ||
1242 client_entry->mode & SILC_UMODE_BUSY ||
1243 client_entry->mode & SILC_UMODE_PAGE ||
1244 client_entry->mode & SILC_UMODE_DETACHED)) {
1245 printformat_module("fe-common/silc", server, NULL,
1246 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1247 client_entry->nickname);
1251 memset(buf, 0, sizeof(buf));
1252 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1253 printformat_module("fe-common/silc", server, NULL,
1254 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1255 client_entry->nickname, buf);
1257 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1258 printformat_module("fe-common/silc", server, NULL,
1259 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1260 client_entry->nickname);
1261 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1262 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1263 printformat_module("fe-common/silc", server, NULL,
1264 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1265 client_entry->nickname);
1266 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1267 /* Client logged in to the network */
1268 printformat_module("fe-common/silc", server, NULL,
1269 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1270 client_entry->nickname);
1276 /* Unknown notify */
1277 printformat_module("fe-common/silc", server, NULL,
1278 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1285 /* Command handler. This function is called always in the command function.
1286 If error occurs it will be called as well. `conn' is the associated
1287 client connection. `cmd_context' is the command context that was
1288 originally sent to the command. `success' is FALSE if error occured
1289 during command. `command' is the command being processed. It must be
1290 noted that this is not reply from server. This is merely called just
1291 after application has called the command. Just to tell application
1292 that the command really was processed. */
1294 static SilcBool cmode_list_chpks = FALSE;
1296 void silc_command(SilcClient client, SilcClientConnection conn,
1297 SilcBool success, SilcCommand command, SilcStatus status,
1298 SilcUInt32 argc, unsigned char **argv)
1300 SILC_SERVER_REC *server = conn->context;
1302 SILC_LOG_DEBUG(("Start"));
1305 silc_say_error("%s", silc_get_status_message(status));
1311 case SILC_COMMAND_INVITE:
1313 printformat_module("fe-common/silc", server, NULL,
1314 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1316 (argv[1][0] == '*' ?
1317 (char *)conn->current_channel->channel_name :
1321 case SILC_COMMAND_DETACH:
1322 server->no_reconnect = TRUE;
1325 case SILC_COMMAND_CMODE:
1326 if (argc == 3 && !strcmp(argv[2], "+C"))
1327 cmode_list_chpks = TRUE;
1329 cmode_list_chpks = FALSE;
1339 SilcClientConnection conn;
1344 void silc_getkey_cb(bool success, void *context)
1346 GetkeyContext getkey = (GetkeyContext)context;
1347 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1348 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1349 ((SilcClientEntry)getkey->entry)->nickname :
1350 ((SilcServerEntry)getkey->entry)->server_name);
1353 printformat_module("fe-common/silc", NULL, NULL,
1354 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1356 printformat_module("fe-common/silc", NULL, NULL,
1357 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1364 /* Parse an invite or ban list */
1365 void silc_parse_inviteban_list(SilcClient client,
1366 SilcClientConnection conn,
1367 SILC_SERVER_REC *server,
1368 SilcChannelEntry channel,
1369 const char *list_type,
1370 SilcArgumentPayload list)
1373 SilcUInt32 type, len;
1374 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1375 int counter=0, resolving = FALSE;
1377 if (!silc_argument_get_arg_num(list)) {
1378 printformat_module("fe-common/silc", server,
1379 (chanrec ? chanrec->visible_name : NULL),
1380 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1381 channel->channel_name, list_type);
1385 printformat_module("fe-common/silc", server,
1386 (chanrec ? chanrec->visible_name : NULL),
1387 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1388 channel->channel_name, list_type);
1390 /* Parse the list */
1391 tmp = silc_argument_get_first_arg(list, &type, &len);
1396 /* An invite string */
1400 if (tmp[len-1] == ',')
1403 list = g_strsplit(tmp, ",", -1);
1405 printformat_module("fe-common/silc", server,
1406 (chanrec ? chanrec->visible_name : NULL),
1407 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1408 ++counter, channel->channel_name, list_type,
1417 char *fingerprint, *babbleprint;
1419 /* tmp is Public Key Payload, take public key from it. */
1420 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1421 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1423 printformat_module("fe-common/silc", server,
1424 (chanrec ? chanrec->visible_name : NULL),
1425 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1426 ++counter, channel->channel_name, list_type,
1427 fingerprint, babbleprint);
1434 SilcClientEntry client_entry;
1437 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1438 silc_say_error("Invalid data in %s list encountered", list_type);
1442 client_entry = silc_client_get_client_by_id(client, conn,
1445 printformat_module("fe-common/silc", server,
1446 (chanrec ? chanrec->visible_name : NULL),
1447 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1448 ++counter, channel->channel_name, list_type,
1449 client_entry->nickname);
1450 silc_client_unref_client(client, conn, client_entry);
1453 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1461 silc_say_error("Unkown type in %s list: %u (len %u)",
1462 list_type, type, len);
1465 tmp = silc_argument_get_next_arg(list, &type, &len);
1469 printformat_module("fe-common/silc", server,
1470 (chanrec ? chanrec->visible_name : NULL),
1471 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1472 list_type, channel->channel_name);
1475 /* Command reply handler. This function is called always in the command reply
1476 function. If error occurs it will be called as well. Normal scenario
1477 is that it will be called after the received command data has been parsed
1478 and processed. The function is used to pass the received command data to
1481 `conn' is the associated client connection. `cmd_payload' is the command
1482 payload data received from server and it can be ignored. It is provided
1483 if the application would like to re-parse the received command data,
1484 however, it must be noted that the data is parsed already by the library
1485 thus the payload can be ignored. `success' is FALSE if error occured.
1486 In this case arguments are not sent to the application. `command' is the
1487 command reply being processed. The function has variable argument list
1488 and each command defines the number and type of arguments it passes to the
1489 application (on error they are not sent). */
1491 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1492 SilcCommand command, SilcStatus status,
1493 SilcStatus error, va_list vp)
1495 SILC_SERVER_REC *server = conn->context;
1496 SILC_CHANNEL_REC *chanrec;
1498 SILC_LOG_DEBUG(("Start"));
1501 case SILC_COMMAND_WHOIS:
1503 char buf[1024], *nickname, *username, *realname, nick[128 + 1];
1504 unsigned char *fingerprint;
1505 SilcUInt32 idle, mode, *user_modes;
1507 SilcClientEntry client_entry;
1510 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1511 /* Print the unknown nick for user */
1512 char *tmp = va_arg(vp, char *);
1514 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1516 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1517 /* Try to find the entry for the unknown client ID, since we
1518 might have, and print the nickname of it for user. */
1519 SilcClientID *id = va_arg(vp, SilcClientID *);
1521 client_entry = silc_client_get_client_by_id(client, conn, id);
1522 if (client_entry && client_entry->nickname[0])
1523 silc_say_error("%s: %s", client_entry->nickname,
1524 silc_get_status_message(status));
1525 silc_client_unref_client(client, conn, client_entry);
1528 } else if (SILC_STATUS_IS_ERROR(status)) {
1529 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1533 client_entry = va_arg(vp, SilcClientEntry);
1534 nickname = va_arg(vp, char *);
1535 username = va_arg(vp, char *);
1536 realname = va_arg(vp, char *);
1537 channels = va_arg(vp, SilcDList);
1538 mode = va_arg(vp, SilcUInt32);
1539 idle = va_arg(vp, SilcUInt32);
1540 fingerprint = va_arg(vp, unsigned char *);
1541 user_modes = va_arg(vp, SilcUInt32 *);
1542 attrs = va_arg(vp, SilcDList);
1544 silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
1545 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1546 SILCTXT_WHOIS_USERINFO, nickname,
1547 client_entry->username, client_entry->hostname,
1548 nick, client_entry->nickname);
1549 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1550 SILCTXT_WHOIS_REALNAME, realname);
1552 if (channels && user_modes) {
1553 SilcChannelPayload entry;
1556 memset(buf, 0, sizeof(buf));
1557 silc_dlist_start(channels);
1558 while ((entry = silc_dlist_get(channels))) {
1559 SilcUInt32 name_len;
1560 char *m = silc_client_chumode_char(user_modes[i++]);
1561 char *name = silc_channel_get_name(entry, &name_len);
1564 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1565 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1566 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1570 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1571 SILCTXT_WHOIS_CHANNELS, buf);
1575 memset(buf, 0, sizeof(buf));
1576 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1577 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1578 SILCTXT_WHOIS_MODES, buf);
1581 if (idle && nickname) {
1582 memset(buf, 0, sizeof(buf));
1583 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1584 idle > 60 ? (idle / 60) : idle,
1585 idle > 60 ? "minutes" : "seconds");
1587 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1588 SILCTXT_WHOIS_IDLE, buf);
1592 fingerprint = silc_fingerprint(fingerprint, 20);
1593 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1594 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1595 silc_free(fingerprint);
1599 silc_query_attributes_print(server, silc_client, conn, attrs,
1604 case SILC_COMMAND_WHOWAS:
1606 char *nickname, *username, *realname;
1608 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1609 char *tmp = va_arg(vp, char *);
1611 silc_say_error("%s: %s", tmp,
1612 silc_get_status_message(status));
1614 } else if (SILC_STATUS_IS_ERROR(status)) {
1615 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1619 (void)va_arg(vp, SilcClientEntry);
1620 nickname = va_arg(vp, char *);
1621 username = va_arg(vp, char *);
1622 realname = va_arg(vp, char *);
1624 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1625 SILCTXT_WHOWAS_USERINFO, nickname, username,
1626 realname ? realname : "");
1630 case SILC_COMMAND_INVITE:
1632 SilcChannelEntry channel;
1633 SilcArgumentPayload invite_list;
1635 if (SILC_STATUS_IS_ERROR(status))
1638 channel = va_arg(vp, SilcChannelEntry);
1639 invite_list = va_arg(vp, SilcArgumentPayload);
1642 silc_parse_inviteban_list(client, conn, server, channel,
1643 "invite", invite_list);
1647 case SILC_COMMAND_JOIN:
1649 char *channel, *mode, *topic, *cipher, *hmac;
1651 SilcHashTableList *user_list;
1652 SilcChannelEntry channel_entry;
1653 SilcChannelUser chu;
1654 SilcClientEntry founder = NULL;
1657 if (SILC_STATUS_IS_ERROR(status)) {
1658 silc_say_error("JOIN: %s", silc_get_status_message(status));
1662 channel = va_arg(vp, char *);
1663 channel_entry = va_arg(vp, SilcChannelEntry);
1664 modei = va_arg(vp, SilcUInt32);
1665 user_list = va_arg(vp, SilcHashTableList *);
1666 topic = va_arg(vp, char *);
1667 cipher = va_arg(vp, char *);
1668 hmac = va_arg(vp, char *);
1670 chanrec = silc_channel_find(server, channel);
1672 chanrec = silc_channel_create(server, channel, channel, TRUE);
1675 char tmp[256], *cp, *dm = NULL;
1676 g_free_not_null(chanrec->topic);
1678 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1679 memset(tmp, 0, sizeof(tmp));
1681 if (strlen(topic) > sizeof(tmp) - 1) {
1682 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1686 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1691 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1692 signal_emit("channel topic changed", 1, chanrec);
1697 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1698 g_free_not_null(chanrec->mode);
1699 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1700 signal_emit("channel mode changed", 1, chanrec);
1703 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1704 if (!chu->client->nickname[0])
1706 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1707 founder = chu->client;
1708 silc_nicklist_insert(chanrec, chu, FALSE);
1711 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1714 nicklist_set_own(CHANNEL(chanrec), ownnick);
1715 signal_emit("channel joined", 1, chanrec);
1716 chanrec->entry = channel_entry;
1719 printformat_module("fe-common/silc", server,
1720 channel_entry->channel_name,
1721 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1722 channel_entry->channel_name, chanrec->topic);
1725 if (founder == conn->local_entry) {
1726 printformat_module("fe-common/silc",
1727 server, channel_entry->channel_name,
1728 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1729 channel_entry->channel_name);
1730 signal_emit("nick mode changed", 2, chanrec, ownnick);
1732 printformat_module("fe-common/silc",
1733 server, channel_entry->channel_name,
1734 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1735 channel_entry->channel_name, founder->nickname);
1741 case SILC_COMMAND_NICK:
1744 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1747 if (SILC_STATUS_IS_ERROR(status)) {
1748 silc_say_error("NICK: %s", silc_get_status_message(status));
1752 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1753 if ((nicks != NULL) &&
1754 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1756 SilcClientEntry collider, old;
1758 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1759 collider = silc_client_get_client_by_id(client, conn, &old->id);
1760 if (collider != client_entry) {
1761 memset(buf, 0, sizeof(buf));
1762 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1763 collider->username, collider->hostname);
1764 nicklist_rename_unique(SERVER(server),
1766 collider, collider->nickname);
1767 silc_print_nick_change(server, collider->nickname,
1768 client_entry->nickname, buf);
1770 silc_client_unref_client(client, conn, collider);
1774 g_slist_free(nicks);
1776 old = g_strdup(server->nick);
1777 server_change_nick(SERVER(server), client_entry->nickname);
1778 nicklist_rename_unique(SERVER(server),
1779 server->conn->local_entry, server->nick,
1780 client_entry, client_entry->nickname);
1781 signal_emit("message own_nick", 4, server, server->nick, old, "");
1784 /* when connecting to a server, the last thing we receive
1785 is a SILC_COMMAND_LIST reply. Since we enable queueing
1786 during the connection, we can now safely disable it again */
1787 silc_queue_disable(conn);
1791 case SILC_COMMAND_LIST:
1796 char tmp[256], *cp, *dm = NULL;
1798 if (SILC_STATUS_IS_ERROR(status))
1801 (void)va_arg(vp, SilcChannelEntry);
1802 name = va_arg(vp, char *);
1803 topic = va_arg(vp, char *);
1804 usercount = va_arg(vp, int);
1806 if (topic && !silc_term_utf8() &&
1807 silc_utf8_valid(topic, strlen(topic))) {
1808 memset(tmp, 0, sizeof(tmp));
1810 if (strlen(topic) > sizeof(tmp) - 1) {
1811 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1815 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1820 if (status == SILC_STATUS_LIST_START ||
1821 status == SILC_STATUS_OK)
1822 printformat_module("fe-common/silc", server, NULL,
1823 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1826 snprintf(users, sizeof(users) - 1, "N/A");
1828 snprintf(users, sizeof(users) - 1, "%d", usercount);
1829 printformat_module("fe-common/silc", server, NULL,
1830 MSGLEVEL_CRAP, SILCTXT_LIST,
1831 name, users, topic ? topic : "");
1836 case SILC_COMMAND_UMODE:
1841 if (SILC_STATUS_IS_ERROR(status))
1844 mode = va_arg(vp, SilcUInt32);
1846 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1847 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1848 printformat_module("fe-common/silc", server, NULL,
1849 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1851 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1852 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1853 printformat_module("fe-common/silc", server, NULL,
1854 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1856 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1857 if (mode & SILC_UMODE_GONE) {
1858 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1859 reason = g_strdup(server->away_reason);
1861 reason = g_strdup("away");
1863 reason = g_strdup("");
1865 silc_set_away(reason, server);
1870 server->umode = mode;
1871 signal_emit("user mode changed", 2, server, NULL);
1875 case SILC_COMMAND_OPER:
1876 if (SILC_STATUS_IS_ERROR(status)) {
1877 silc_say_error("OPER: %s", silc_get_status_message(status));
1881 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1882 signal_emit("user mode changed", 2, server, NULL);
1884 printformat_module("fe-common/silc", server, NULL,
1885 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1888 case SILC_COMMAND_SILCOPER:
1889 if (SILC_STATUS_IS_ERROR(status)) {
1890 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1894 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1895 signal_emit("user mode changed", 2, server, NULL);
1897 printformat_module("fe-common/silc", server, NULL,
1898 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1901 case SILC_COMMAND_USERS:
1903 SilcHashTableList htl;
1904 SilcChannelEntry channel;
1905 SilcChannelUser chu;
1907 if (SILC_STATUS_IS_ERROR(status)) {
1908 silc_say_error("USERS: %s", silc_get_status_message(status));
1912 channel = va_arg(vp, SilcChannelEntry);
1914 printformat_module("fe-common/silc", server, channel->channel_name,
1915 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1916 channel->channel_name);
1918 silc_hash_table_list(channel->user_list, &htl);
1919 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1920 SilcClientEntry e = chu->client;
1921 char stat[5], *mode;
1923 if (!e->nickname[0])
1926 memset(stat, 0, sizeof(stat));
1927 mode = silc_client_chumode_char(chu->mode);
1928 if (e->mode & SILC_UMODE_GONE)
1930 else if (e->mode & SILC_UMODE_INDISPOSED)
1932 else if (e->mode & SILC_UMODE_BUSY)
1934 else if (e->mode & SILC_UMODE_PAGE)
1936 else if (e->mode & SILC_UMODE_HYPER)
1938 else if (e->mode & SILC_UMODE_ROBOT)
1940 else if (e->mode & SILC_UMODE_ANONYMOUS)
1947 printformat_module("fe-common/silc", server, channel->channel_name,
1948 MSGLEVEL_CRAP, SILCTXT_USERS,
1950 e->username[0] ? e->username : "",
1951 e->hostname[0] ? e->hostname : "",
1952 e->realname ? e->realname : "");
1956 silc_hash_table_list_reset(&htl);
1960 case SILC_COMMAND_BAN:
1962 SilcChannelEntry channel;
1963 SilcArgumentPayload invite_list;
1965 if (SILC_STATUS_IS_ERROR(status))
1968 channel = va_arg(vp, SilcChannelEntry);
1969 invite_list = va_arg(vp, SilcArgumentPayload);
1972 silc_parse_inviteban_list(client, conn, server, channel,
1973 "ban", invite_list);
1977 case SILC_COMMAND_GETKEY:
1981 SilcPublicKey public_key;
1982 GetkeyContext getkey;
1985 if (SILC_STATUS_IS_ERROR(status)) {
1986 silc_say_error("GETKEY: %s", silc_get_status_message(status));
1990 id_type = va_arg(vp, SilcUInt32);
1991 entry = va_arg(vp, void *);
1992 public_key = va_arg(vp, SilcPublicKey);
1995 getkey = silc_calloc(1, sizeof(*getkey));
1996 getkey->entry = entry;
1997 getkey->id_type = id_type;
1998 getkey->client = client;
1999 getkey->conn = conn;
2001 name = (id_type == SILC_ID_CLIENT ?
2002 ((SilcClientEntry)entry)->nickname :
2003 ((SilcServerEntry)entry)->server_name);
2005 silc_verify_public_key_internal(client, conn, name,
2006 (id_type == SILC_ID_CLIENT ?
2009 public_key, silc_getkey_cb, getkey);
2011 printformat_module("fe-common/silc", server, NULL,
2012 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2017 case SILC_COMMAND_INFO:
2019 SilcServerEntry server_entry;
2023 if (SILC_STATUS_IS_ERROR(status))
2026 server_entry = va_arg(vp, SilcServerEntry);
2027 server_name = va_arg(vp, char *);
2028 server_info = va_arg(vp, char *);
2030 if (server_name && server_info )
2032 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2033 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2038 case SILC_COMMAND_TOPIC:
2040 SilcChannelEntry channel;
2042 char tmp[256], *cp, *dm = NULL;
2044 if (SILC_STATUS_IS_ERROR(status))
2047 channel = va_arg(vp, SilcChannelEntry);
2048 topic = va_arg(vp, char *);
2050 if (topic && !silc_term_utf8() &&
2051 silc_utf8_valid(topic, strlen(topic))) {
2052 memset(tmp, 0, sizeof(tmp));
2054 if (strlen(topic) > sizeof(tmp) - 1) {
2055 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2059 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2065 chanrec = silc_channel_find_entry(server, channel);
2067 g_free_not_null(chanrec->topic);
2068 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2069 signal_emit("channel topic changed", 1, chanrec);
2071 printformat_module("fe-common/silc", server, channel->channel_name,
2072 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2073 channel->channel_name, topic);
2075 printformat_module("fe-common/silc", server, channel->channel_name,
2076 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2077 channel->channel_name);
2083 case SILC_COMMAND_WATCH:
2086 case SILC_COMMAND_STATS:
2088 SilcClientStats *cstats;
2090 const char *tmptime;
2091 int days, hours, mins, secs;
2093 if (SILC_STATUS_IS_ERROR(status))
2096 cstats = va_arg(vp, SilcClientStats *);
2098 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2102 tmptime = silc_time_string(cstats->starttime);
2103 printformat_module("fe-common/silc", server, NULL,
2104 MSGLEVEL_CRAP, SILCTXT_STATS,
2105 "Local server start time", tmptime);
2107 days = cstats->uptime / (24 * 60 * 60);
2108 cstats->uptime -= days * (24 * 60 * 60);
2109 hours = cstats->uptime / (60 * 60);
2110 cstats->uptime -= hours * (60 * 60);
2111 mins = cstats->uptime / 60;
2112 cstats->uptime -= mins * 60;
2113 secs = cstats->uptime;
2114 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2115 days, hours, mins, secs);
2116 printformat_module("fe-common/silc", server, NULL,
2117 MSGLEVEL_CRAP, SILCTXT_STATS,
2118 "Local server uptime", tmp);
2120 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2121 printformat_module("fe-common/silc", server, NULL,
2122 MSGLEVEL_CRAP, SILCTXT_STATS,
2123 "Local server clients", tmp);
2125 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2126 printformat_module("fe-common/silc", server, NULL,
2127 MSGLEVEL_CRAP, SILCTXT_STATS,
2128 "Local server channels", tmp);
2130 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2131 printformat_module("fe-common/silc", server, NULL,
2132 MSGLEVEL_CRAP, SILCTXT_STATS,
2133 "Local server operators", tmp);
2135 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2136 printformat_module("fe-common/silc", server, NULL,
2137 MSGLEVEL_CRAP, SILCTXT_STATS,
2138 "Local router operators", tmp);
2140 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2141 printformat_module("fe-common/silc", server, NULL,
2142 MSGLEVEL_CRAP, SILCTXT_STATS,
2143 "Local cell clients", tmp);
2145 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2146 printformat_module("fe-common/silc", server, NULL,
2147 MSGLEVEL_CRAP, SILCTXT_STATS,
2148 "Local cell channels", tmp);
2150 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2151 printformat_module("fe-common/silc", server, NULL,
2152 MSGLEVEL_CRAP, SILCTXT_STATS,
2153 "Local cell servers", tmp);
2155 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2156 printformat_module("fe-common/silc", server, NULL,
2157 MSGLEVEL_CRAP, SILCTXT_STATS,
2158 "Total clients", tmp);
2160 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2161 printformat_module("fe-common/silc", server, NULL,
2162 MSGLEVEL_CRAP, SILCTXT_STATS,
2163 "Total channels", tmp);
2165 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2166 printformat_module("fe-common/silc", server, NULL,
2167 MSGLEVEL_CRAP, SILCTXT_STATS,
2168 "Total servers", tmp);
2170 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2171 printformat_module("fe-common/silc", server, NULL,
2172 MSGLEVEL_CRAP, SILCTXT_STATS,
2173 "Total routers", tmp);
2175 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2176 printformat_module("fe-common/silc", server, NULL,
2177 MSGLEVEL_CRAP, SILCTXT_STATS,
2178 "Total server operators", tmp);
2180 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2181 printformat_module("fe-common/silc", server, NULL,
2182 MSGLEVEL_CRAP, SILCTXT_STATS,
2183 "Total router operators", tmp);
2187 case SILC_COMMAND_CMODE:
2189 SilcChannelEntry channel_entry;
2192 channel_entry = va_arg(vp, SilcChannelEntry);
2193 (void)va_arg(vp, SilcUInt32);
2194 (void)va_arg(vp, SilcPublicKey);
2195 chpks = va_arg(vp, SilcDList);
2197 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2198 !channel_entry || !channel_entry->channel_name)
2201 /* Print the channel public key list */
2203 silc_parse_channel_public_keys(server, channel_entry, chpks);
2205 printformat_module("fe-common/silc", server, NULL,
2206 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2207 channel_entry->channel_name);
2212 case SILC_COMMAND_LEAVE:
2214 if (SILC_STATUS_IS_ERROR(status))
2217 /* We might be cycling, so disable queueing again */
2218 silc_queue_disable(conn);
2222 case SILC_COMMAND_DETACH:
2224 /* Save the detachment data to file. */
2228 if (SILC_STATUS_IS_ERROR(status))
2231 detach = va_arg(vp, SilcBuffer);
2232 file = silc_get_session_filename(server);
2233 silc_file_writefile(file, silc_buffer_data(detach),
2234 silc_buffer_len(detach));
2239 case SILC_COMMAND_KILL:
2241 SilcClientEntry client_entry;
2243 if (SILC_STATUS_IS_ERROR(status)) {
2244 silc_say_error("KILL: %s", silc_get_status_message(status));
2248 client_entry = va_arg(vp, SilcClientEntry);
2249 if (!client_entry || !client_entry->nickname[0])
2252 /* Print this only if the killed client isn't joined on channels.
2253 If it is, we receive KILLED notify and we'll print this there. */
2254 if (!silc_hash_table_count(client_entry->channels))
2255 printformat_module("fe-common/silc", server, NULL,
2256 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2257 client_entry->nickname,
2258 conn->local_entry->nickname, "");
2265 SilcClientConnection conn;
2269 SilcPublicKey public_key;
2270 SilcVerifyPublicKey completion;
2274 static void verify_public_key_completion(const char *line, void *context)
2276 PublicKeyVerify verify = (PublicKeyVerify)context;
2278 if (line[0] == 'Y' || line[0] == 'y') {
2279 /* Call the completion */
2280 if (verify->completion)
2281 verify->completion(TRUE, verify->context);
2283 /* Save the key for future checking */
2284 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2285 SILC_PKCS_FILE_BASE64);
2287 /* Call the completion */
2288 if (verify->completion)
2289 verify->completion(FALSE, verify->context);
2291 printformat_module("fe-common/silc", NULL, NULL,
2292 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2293 verify->entity_name ? verify->entity_name :
2297 silc_free(verify->filename);
2298 silc_free(verify->entity);
2299 silc_free(verify->entity_name);
2303 /* Internal routine to verify public key. If the `completion' is provided
2304 it will be called to indicate whether public was verified or not. For
2305 server/router public key this will check for filename that includes the
2306 remote host's IP address and remote host's hostname. */
2309 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2311 SilcConnectionType conn_type,
2312 SilcPublicKey public_key,
2313 SilcVerifyPublicKey completion, void *context)
2315 PublicKeyVerify verify;
2316 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2317 char *fingerprint, *babbleprint, *format;
2318 SilcPublicKey local_pubkey;
2320 const char *hostname, *ip;
2325 char *entity = ((conn_type == SILC_CONN_SERVER ||
2326 conn_type == SILC_CONN_ROUTER) ?
2327 "server" : "client");
2330 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2331 printformat_module("fe-common/silc", NULL, NULL,
2332 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2333 entity, silc_pkcs_get_type(public_key));
2335 completion(FALSE, context);
2339 /* Encode public key */
2340 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2343 completion(FALSE, context);
2347 pw = getpwuid(getuid());
2350 completion(FALSE, context);
2354 memset(filename, 0, sizeof(filename));
2355 memset(filename2, 0, sizeof(filename2));
2356 memset(file, 0, sizeof(file));
2358 /* Get remote host information */
2359 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2360 NULL, &hostname, &ip, &port);
2362 if (conn_type == SILC_CONN_SERVER ||
2363 conn_type == SILC_CONN_ROUTER) {
2365 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2366 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2367 get_irssi_dir(), entity, file);
2369 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2371 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2372 get_irssi_dir(), entity, file);
2377 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2379 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2380 get_irssi_dir(), entity, file);
2385 /* Replace all whitespaces with `_'. */
2386 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2387 for (i = 0; i < strlen(fingerprint); i++)
2388 if (fingerprint[i] == ' ')
2389 fingerprint[i] = '_';
2391 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2392 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2393 get_irssi_dir(), entity, file);
2394 silc_free(fingerprint);
2399 /* Take fingerprint of the public key */
2400 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2401 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2403 verify = silc_calloc(1, sizeof(*verify));
2404 verify->client = client;
2405 verify->conn = conn;
2406 verify->filename = strdup(ipf);
2407 verify->entity = strdup(entity);
2408 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2409 (name ? strdup(name) : strdup(hostname))
2411 verify->public_key = public_key;
2412 verify->completion = completion;
2413 verify->context = context;
2415 /* Check whether this key already exists */
2416 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2417 /* Key does not exist, ask user to verify the key and save it */
2419 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2420 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2421 verify->entity_name : entity);
2422 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2423 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2424 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2425 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2426 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2427 SILCTXT_PUBKEY_ACCEPT);
2428 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2431 silc_free(fingerprint);
2434 /* The key already exists, verify it. */
2435 unsigned char *encpk;
2436 SilcUInt32 encpk_len;
2438 /* Load the key file, try for both IP filename and hostname filename */
2439 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2440 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2441 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2442 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2443 verify->entity_name : entity);
2444 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2445 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2446 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2447 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2448 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2449 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2450 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2451 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2452 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2455 silc_free(fingerprint);
2459 /* Encode the key data */
2460 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2462 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2463 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2464 verify->entity_name : entity);
2465 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2466 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2467 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2468 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2469 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2470 SILCTXT_PUBKEY_MALFORMED, entity);
2471 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2472 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2473 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2476 silc_free(fingerprint);
2480 /* Compare the keys */
2481 if (memcmp(encpk, pk, encpk_len)) {
2482 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2483 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2484 verify->entity_name : entity);
2485 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2486 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2487 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2488 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2489 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2490 SILCTXT_PUBKEY_NO_MATCH, entity);
2491 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2492 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2493 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2494 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2496 /* Ask user to verify the key and save it */
2497 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2498 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2499 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2502 silc_free(fingerprint);
2507 /* Local copy matched */
2509 completion(TRUE, context);
2511 silc_free(fingerprint);
2512 silc_free(verify->filename);
2513 silc_free(verify->entity);
2514 silc_free(verify->entity_name);
2519 /* Verifies received public key. The `conn_type' indicates which entity
2520 (server, client etc.) has sent the public key. If user decides to trust
2521 the key may be saved as trusted public key for later use. The
2522 `completion' must be called after the public key has been verified. */
2525 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2526 SilcConnectionType conn_type,
2527 SilcPublicKey public_key,
2528 SilcVerifyPublicKey completion, void *context)
2530 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2531 completion, context);
2534 /* Asks passphrase from user on the input line. */
2537 SilcAskPassphrase completion;
2541 void ask_passphrase_completion(const char *passphrase, void *context)
2543 AskPassphrase p = (AskPassphrase)context;
2544 if (passphrase && passphrase[0] == '\0')
2546 p->completion((unsigned char *)passphrase,
2547 passphrase ? strlen(passphrase) : 0, p->context);
2551 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2552 SilcAskPassphrase completion, void *context)
2554 AskPassphrase p = silc_calloc(1, sizeof(*p));
2555 p->completion = completion;
2556 p->context = context;
2558 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2559 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2563 SilcGetAuthMeth completion;
2567 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2568 SilcUInt32 passphrase_len,
2571 GetAuthMethod a = context;
2572 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2573 passphrase, passphrase_len, a->context);
2577 /* Find authentication data by hostname and port. The hostname may be IP
2580 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2581 char *hostname, SilcUInt16 port,
2582 SilcAuthMethod auth_meth,
2583 SilcGetAuthMeth completion, void *context)
2585 SERVER_SETUP_REC *setup;
2587 SILC_LOG_DEBUG(("Start"));
2589 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2590 /* Returning NULL will cause library to use our private key configured
2591 for this connection */
2592 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2596 /* Check whether we find the password for this server in our
2597 configuration. If it's set, always send it server. */
2598 setup = server_setup_find_port(hostname, port);
2599 if (setup && setup->password) {
2600 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2605 /* Didn't find password. If server wants it, ask it from user. */
2606 if (auth_meth == SILC_AUTH_PASSWORD) {
2608 a = silc_calloc(1, sizeof(*a));
2610 a->completion = completion;
2611 a->context = context;
2612 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2617 /* No authentication */
2618 completion(SILC_AUTH_NONE, NULL, 0, context);
2621 /* Asks whether the user would like to perform the key agreement protocol.
2622 This is called after we have received an key agreement packet or an
2623 reply to our key agreement packet. This returns TRUE if the user wants
2624 the library to perform the key agreement protocol and FALSE if it is not
2625 desired (application may start it later by calling the function
2626 silc_client_perform_key_agreement). */
2628 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2629 SilcClientEntry client_entry, const char *hostname,
2630 SilcUInt16 protocol, SilcUInt16 port)
2632 char portstr[12], protostr[5];
2634 SILC_LOG_DEBUG(("Start"));
2636 /* We will just display the info on the screen and return FALSE and user
2637 will have to start the key agreement with a command. */
2640 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2641 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2646 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2647 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2649 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2650 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2651 client_entry->nickname, hostname, portstr, protostr);
2654 /* Notifies application that file transfer protocol session is being
2655 requested by the remote client indicated by the `client_entry' from
2656 the `hostname' and `port'. The `session_id' is the file transfer
2657 session and it can be used to either accept or reject the file
2658 transfer request, by calling the silc_client_file_receive or
2659 silc_client_file_close, respectively. */
2661 void silc_ftp(SilcClient client, SilcClientConnection conn,
2662 SilcClientEntry client_entry, SilcUInt32 session_id,
2663 const char *hostname, SilcUInt16 port)
2665 SILC_SERVER_REC *server;
2667 FtpSession ftp = NULL;
2669 SILC_LOG_DEBUG(("Start"));
2671 server = conn->context;
2673 silc_dlist_start(server->ftp_sessions);
2674 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2675 if (ftp->client_entry == client_entry &&
2676 ftp->session_id == session_id) {
2677 server->current_session = ftp;
2681 if (ftp == SILC_LIST_END) {
2682 ftp = silc_calloc(1, sizeof(*ftp));
2683 ftp->client_entry = client_entry;
2684 ftp->session_id = session_id;
2687 silc_dlist_add(server->ftp_sessions, ftp);
2688 server->current_session = ftp;
2692 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2695 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2696 SILCTXT_FILE_REQUEST, client_entry->nickname);
2698 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2699 SILCTXT_FILE_REQUEST_HOST,
2700 client_entry->nickname, hostname, portstr);
2703 /* SILC client operations */
2704 SilcClientOperations ops = {
2706 silc_channel_message,
2707 silc_private_message,
2711 silc_get_auth_method,
2712 silc_verify_public_key,
2713 silc_ask_passphrase,