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));
829 /* If there is only one client with this same nickname on channel now
830 change it to the base format if it is formatted nickname. */
832 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
833 clients = silc_client_get_clients_local(client, conn, name, TRUE);
834 if (!clients || silc_dlist_count(clients) != 2) {
836 silc_client_list_free(client, conn, clients);
839 silc_dlist_start(clients);
840 client_entry2 = silc_dlist_get(clients);
841 if (client_entry2 == client_entry)
842 client_entry2 = silc_dlist_get(clients);
843 if (silc_client_on_channel(channel, client_entry2)) {
844 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
845 silc_client_nickname_format(client, conn, client_entry2, TRUE);
846 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
847 nicklist_rename_unique(SERVER(server), client_entry2, buf,
848 client_entry2, client_entry2->nickname);
849 printformat_module("fe-common/silc", server, channel->channel_name,
850 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
851 buf, client_entry2->nickname);
854 silc_client_list_free(client, conn, clients);
859 case SILC_NOTIFY_TYPE_SIGNOFF:
864 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
866 client_entry = va_arg(va, SilcClientEntry);
867 tmp = va_arg(va, char *);
868 channel = va_arg(va, SilcChannelEntry);
870 silc_server_free_ftp(server, client_entry);
872 memset(buf, 0, sizeof(buf));
873 if (client_entry->username)
874 snprintf(buf, sizeof(buf) - 1, "%s@%s",
875 client_entry->username, client_entry->hostname);
876 signal_emit("message quit", 4, server, client_entry->nickname,
877 client_entry->username[0] ? buf : "", tmp ? tmp : "");
879 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
880 for (list_tmp = list1; list_tmp != NULL; list_tmp =
881 list_tmp->next->next) {
882 CHANNEL_REC *channel = list_tmp->data;
883 NICK_REC *nickrec = list_tmp->next->data;
885 nicklist_remove(channel, nickrec);
888 /* If there is only one client with this same nickname on channel now
889 change it to the base format if it is formatted nickname. */
891 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
892 clients = silc_client_get_clients_local(client, conn, name, TRUE);
893 if (!clients || silc_dlist_count(clients) != 2) {
895 silc_client_list_free(client, conn, clients);
898 silc_dlist_start(clients);
899 client_entry2 = silc_dlist_get(clients);
900 if (client_entry2 == client_entry)
901 client_entry2 = silc_dlist_get(clients);
902 if (silc_client_on_channel(channel, client_entry2)) {
903 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
904 silc_client_nickname_format(client, conn, client_entry2, TRUE);
905 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
906 nicklist_rename_unique(SERVER(server), client_entry2, buf,
907 client_entry2, client_entry2->nickname);
908 printformat_module("fe-common/silc", server, channel->channel_name,
909 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
910 buf, client_entry2->nickname);
913 silc_client_list_free(client, conn, clients);
918 case SILC_NOTIFY_TYPE_TOPIC_SET:
923 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
925 idtype = va_arg(va, int);
926 entry = va_arg(va, void *);
927 tmp = va_arg(va, char *);
928 channel = va_arg(va, SilcChannelEntry);
930 chanrec = silc_channel_find_entry(server, channel);
931 if (chanrec != NULL) {
932 char tmp2[256], *cp, *dm = NULL;
934 g_free_not_null(chanrec->topic);
935 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
936 memset(tmp2, 0, sizeof(tmp2));
938 if (strlen(tmp) > sizeof(tmp2) - 1) {
939 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
943 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
948 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
949 signal_emit("channel topic changed", 1, chanrec);
954 if (idtype == SILC_ID_CLIENT) {
955 client_entry = (SilcClientEntry)entry;
956 memset(buf, 0, sizeof(buf));
957 snprintf(buf, sizeof(buf) - 1, "%s@%s",
958 client_entry->username, client_entry->hostname);
959 signal_emit("message topic", 5, server, channel->channel_name,
960 tmp, client_entry->nickname, buf);
961 } else if (idtype == SILC_ID_SERVER) {
962 server_entry = (SilcServerEntry)entry;
963 signal_emit("message topic", 5, server, channel->channel_name,
964 tmp, server_entry->server_name,
965 server_entry->server_name);
966 } else if (idtype == SILC_ID_CHANNEL) {
967 channel = (SilcChannelEntry)entry;
968 signal_emit("message topic", 5, server, channel->channel_name,
969 tmp, channel->channel_name, channel->channel_name);
973 case SILC_NOTIFY_TYPE_NICK_CHANGE:
978 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
980 client_entry = va_arg(va, SilcClientEntry);
981 name = va_arg(va, char *); /* old nickname */
983 if (!strcmp(client_entry->nickname, name))
986 memset(buf, 0, sizeof(buf));
987 snprintf(buf, sizeof(buf) - 1, "%s@%s",
988 client_entry->username, client_entry->hostname);
989 nicklist_rename_unique(SERVER(server),
991 client_entry, client_entry->nickname);
992 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
995 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
997 * Changed channel mode.
1000 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
1002 idtype = va_arg(va, int);
1003 entry = va_arg(va, void *);
1004 mode = va_arg(va, SilcUInt32);
1005 cipher = va_arg(va, char *); /* cipher */
1006 hmac = va_arg(va, char *); /* hmac */
1007 (void)va_arg(va, char *); /* passphrase */
1008 (void)va_arg(va, SilcPublicKey); /* founder key */
1009 chpks = va_arg(va, SilcDList); /* channel public keys */
1010 channel = va_arg(va, SilcChannelEntry);
1012 tmp = silc_client_chmode(mode, cipher ? cipher : "",
1015 chanrec = silc_channel_find_entry(server, channel);
1016 if (chanrec != NULL) {
1017 g_free_not_null(chanrec->mode);
1018 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
1019 signal_emit("channel mode changed", 1, chanrec);
1022 if (idtype == SILC_ID_CLIENT) {
1023 client_entry = (SilcClientEntry)entry;
1024 printformat_module("fe-common/silc", server, channel->channel_name,
1025 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1026 channel->channel_name, tmp ? tmp : "removed all",
1027 client_entry->nickname);
1028 } else if (idtype == SILC_ID_SERVER) {
1029 server_entry = (SilcServerEntry)entry;
1030 printformat_module("fe-common/silc", server, channel->channel_name,
1031 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1032 channel->channel_name, tmp ? tmp : "removed all",
1033 server_entry->server_name);
1034 } else if (idtype == SILC_ID_CHANNEL) {
1035 channel2 = (SilcChannelEntry)entry;
1036 printformat_module("fe-common/silc", server, channel->channel_name,
1037 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1038 channel->channel_name, tmp ? tmp : "removed all",
1039 channel2->channel_name);
1042 /* Print the channel public key list */
1044 silc_parse_channel_public_keys(server, channel, chpks);
1049 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1051 * Changed user's mode on channel.
1054 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1056 idtype = va_arg(va, int);
1057 entry = va_arg(va, void *);
1058 mode = va_arg(va, SilcUInt32);
1059 client_entry2 = va_arg(va, SilcClientEntry);
1060 channel = va_arg(va, SilcChannelEntry);
1062 tmp = silc_client_chumode(mode);
1063 chanrec = silc_channel_find_entry(server, channel);
1064 if (chanrec != NULL) {
1065 SILC_NICK_REC *nick;
1067 if (client_entry2 == server->conn->local_entry)
1068 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1070 nick = silc_nicklist_find(chanrec, client_entry2);
1072 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1073 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1074 signal_emit("nick mode changed", 2, chanrec, nick);
1078 if (idtype == SILC_ID_CLIENT) {
1079 client_entry = (SilcClientEntry)entry;
1080 printformat_module("fe-common/silc", server, channel->channel_name,
1081 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1082 channel->channel_name, client_entry2->nickname,
1083 tmp ? tmp : "removed all",
1084 client_entry->nickname);
1085 } else if (idtype == SILC_ID_SERVER) {
1086 server_entry = (SilcServerEntry)entry;
1087 printformat_module("fe-common/silc", server, channel->channel_name,
1088 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1089 channel->channel_name, client_entry2->nickname,
1090 tmp ? tmp : "removed all",
1091 server_entry->server_name);
1092 } else if (idtype == SILC_ID_CHANNEL) {
1093 channel2 = (SilcChannelEntry)entry;
1094 printformat_module("fe-common/silc", server, channel->channel_name,
1095 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1096 channel->channel_name, client_entry2->nickname,
1097 tmp ? tmp : "removed all",
1098 channel2->channel_name);
1101 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1102 printformat_module("fe-common/silc",
1103 server, channel->channel_name, MSGLEVEL_CRAP,
1104 SILCTXT_CHANNEL_FOUNDER,
1105 channel->channel_name, client_entry2->nickname);
1107 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1108 printformat_module("fe-common/silc",
1109 server, channel->channel_name, MSGLEVEL_CRAP,
1110 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1115 case SILC_NOTIFY_TYPE_MOTD:
1120 SILC_LOG_DEBUG(("Notify: MOTD"));
1122 tmp = va_arg(va, char *);
1124 if (!settings_get_bool("skip_motd"))
1125 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1128 case SILC_NOTIFY_TYPE_KICKED:
1130 * Someone was kicked from channel.
1133 SILC_LOG_DEBUG(("Notify: KICKED"));
1135 client_entry = va_arg(va, SilcClientEntry);
1136 tmp = va_arg(va, char *);
1137 client_entry2 = va_arg(va, SilcClientEntry);
1138 channel = va_arg(va, SilcChannelEntry);
1140 chanrec = silc_channel_find_entry(server, channel);
1142 if (client_entry == conn->local_entry) {
1143 printformat_module("fe-common/silc", server, channel->channel_name,
1144 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1145 channel->channel_name,
1146 client_entry ? client_entry2->nickname : "",
1149 chanrec->kicked = TRUE;
1150 channel_destroy((CHANNEL_REC *)chanrec);
1153 printformat_module("fe-common/silc", server, channel->channel_name,
1154 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1155 client_entry->nickname, channel->channel_name,
1156 client_entry2 ? client_entry2->nickname : "",
1160 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1161 if (nickrec != NULL)
1162 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1167 case SILC_NOTIFY_TYPE_KILLED:
1169 * Someone was killed from the network.
1172 SILC_LOG_DEBUG(("Notify: KILLED"));
1174 client_entry = va_arg(va, SilcClientEntry);
1175 tmp = va_arg(va, char *);
1176 idtype = va_arg(va, int);
1177 entry = va_arg(va, SilcClientEntry);
1179 if (client_entry == conn->local_entry) {
1180 if (idtype == SILC_ID_CLIENT) {
1181 client_entry2 = (SilcClientEntry)entry;
1182 printformat_module("fe-common/silc", server, NULL,
1183 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1184 client_entry2 ? client_entry2->nickname : "",
1186 } else if (idtype == SILC_ID_SERVER) {
1187 server_entry = (SilcServerEntry)entry;
1188 printformat_module("fe-common/silc", server, NULL,
1189 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1190 server_entry->server_name, tmp ? tmp : "");
1191 } else if (idtype == SILC_ID_CHANNEL) {
1192 channel = (SilcChannelEntry)entry;
1193 printformat_module("fe-common/silc", server, NULL,
1194 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1195 channel->channel_name, tmp ? tmp : "");
1198 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1199 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1200 list_tmp->next->next) {
1201 CHANNEL_REC *channel = list_tmp->data;
1202 NICK_REC *nickrec = list_tmp->next->data;
1203 nicklist_remove(channel, nickrec);
1206 if (idtype == SILC_ID_CLIENT) {
1207 client_entry2 = (SilcClientEntry)entry;
1208 printformat_module("fe-common/silc", server, NULL,
1209 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1210 client_entry->nickname,
1211 client_entry2 ? client_entry2->nickname : "",
1213 } else if (idtype == SILC_ID_SERVER) {
1214 server_entry = (SilcServerEntry)entry;
1215 printformat_module("fe-common/silc", server, NULL,
1216 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1217 client_entry->nickname,
1218 server_entry->server_name, tmp ? tmp : "");
1219 } else if (idtype == SILC_ID_CHANNEL) {
1220 channel = (SilcChannelEntry)entry;
1221 printformat_module("fe-common/silc", server, NULL,
1222 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1223 client_entry->nickname,
1224 channel->channel_name, tmp ? tmp : "");
1229 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1232 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1235 * Server has quit the network.
1239 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1241 (void)va_arg(va, void *);
1242 clients = va_arg(va, SilcDList);
1244 silc_dlist_start(clients);
1245 while ((client_entry = silc_dlist_get(clients))) {
1246 memset(buf, 0, sizeof(buf));
1248 /* Print only if we have the nickname. If this client has just quit
1249 when we were only resolving it, it is possible we don't have the
1251 if (client_entry->nickname[0]) {
1252 if (client_entry->username[0])
1253 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1254 client_entry->username, client_entry->hostname);
1255 signal_emit("message quit", 4, server, client_entry->nickname,
1256 client_entry->username[0] ? buf : "",
1260 silc_server_free_ftp(server, client_entry);
1262 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1263 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1264 list_tmp->next->next) {
1265 CHANNEL_REC *channel = list_tmp->data;
1266 NICK_REC *nickrec = list_tmp->next->data;
1267 nicklist_remove(channel, nickrec);
1273 case SILC_NOTIFY_TYPE_ERROR:
1275 SilcStatus error = va_arg(va, int);
1277 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1278 "%s", silc_get_status_message(error));
1282 case SILC_NOTIFY_TYPE_WATCH:
1284 SilcNotifyType notify;
1286 client_entry = va_arg(va, SilcClientEntry);
1287 name = va_arg(va, char *); /* Maybe NULL */
1288 mode = va_arg(va, SilcUInt32);
1289 notify = va_arg(va, int);
1291 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1293 printformat_module("fe-common/silc", server, NULL,
1294 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1295 client_entry->nickname, name);
1297 printformat_module("fe-common/silc", server, NULL,
1298 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1299 client_entry->nickname);
1300 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1301 /* See if client was away and is now present */
1302 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1303 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1304 SILC_UMODE_DETACHED)) &&
1305 (client_entry->mode & SILC_UMODE_GONE ||
1306 client_entry->mode & SILC_UMODE_INDISPOSED ||
1307 client_entry->mode & SILC_UMODE_BUSY ||
1308 client_entry->mode & SILC_UMODE_PAGE ||
1309 client_entry->mode & SILC_UMODE_DETACHED)) {
1310 printformat_module("fe-common/silc", server, NULL,
1311 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1312 client_entry->nickname);
1316 memset(buf, 0, sizeof(buf));
1317 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1318 printformat_module("fe-common/silc", server, NULL,
1319 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1320 client_entry->nickname, buf);
1322 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1323 printformat_module("fe-common/silc", server, NULL,
1324 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1325 client_entry->nickname);
1326 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1327 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1328 printformat_module("fe-common/silc", server, NULL,
1329 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1330 client_entry->nickname);
1331 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1332 /* Client logged in to the network */
1333 printformat_module("fe-common/silc", server, NULL,
1334 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1335 client_entry->nickname);
1341 /* Unknown notify */
1342 printformat_module("fe-common/silc", server, NULL,
1343 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1350 /* Command handler. This function is called always in the command function.
1351 If error occurs it will be called as well. `conn' is the associated
1352 client connection. `cmd_context' is the command context that was
1353 originally sent to the command. `success' is FALSE if error occured
1354 during command. `command' is the command being processed. It must be
1355 noted that this is not reply from server. This is merely called just
1356 after application has called the command. Just to tell application
1357 that the command really was processed. */
1359 static SilcBool cmode_list_chpks = FALSE;
1361 void silc_command(SilcClient client, SilcClientConnection conn,
1362 SilcBool success, SilcCommand command, SilcStatus status,
1363 SilcUInt32 argc, unsigned char **argv)
1365 SILC_SERVER_REC *server = conn->context;
1367 SILC_LOG_DEBUG(("Start"));
1370 silc_say_error("%s", silc_get_status_message(status));
1376 case SILC_COMMAND_INVITE:
1378 printformat_module("fe-common/silc", server, NULL,
1379 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1381 (argv[1][0] == '*' ?
1382 (char *)conn->current_channel->channel_name :
1386 case SILC_COMMAND_DETACH:
1387 server->no_reconnect = TRUE;
1390 case SILC_COMMAND_CMODE:
1391 if (argc == 3 && !strcmp(argv[2], "+C"))
1392 cmode_list_chpks = TRUE;
1394 cmode_list_chpks = FALSE;
1404 SilcClientConnection conn;
1409 void silc_getkey_cb(bool success, void *context)
1411 GetkeyContext getkey = (GetkeyContext)context;
1412 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1413 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1414 ((SilcClientEntry)getkey->entry)->nickname :
1415 ((SilcServerEntry)getkey->entry)->server_name);
1416 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1417 ((SilcClientEntry)getkey->entry)->public_key :
1418 ((SilcServerEntry)getkey->entry)->public_key);
1419 SilcSILCPublicKey silc_pubkey;
1421 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1424 if (getkey->id_type == SILC_ID_CLIENT)
1425 printformat_module("fe-common/silc", NULL, NULL,
1426 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1428 silc_pubkey->identifier.realname ?
1429 silc_pubkey->identifier.realname : "",
1430 silc_pubkey->identifier.email ?
1431 silc_pubkey->identifier.email : "");
1433 printformat_module("fe-common/silc", NULL, NULL,
1434 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1437 printformat_module("fe-common/silc", NULL, NULL,
1438 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1445 /* Parse an invite or ban list */
1446 void silc_parse_inviteban_list(SilcClient client,
1447 SilcClientConnection conn,
1448 SILC_SERVER_REC *server,
1449 SilcChannelEntry channel,
1450 const char *list_type,
1451 SilcArgumentPayload list)
1454 SilcUInt32 type, len;
1455 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1456 int counter=0, resolving = FALSE;
1458 if (!silc_argument_get_arg_num(list)) {
1459 printformat_module("fe-common/silc", server,
1460 (chanrec ? chanrec->visible_name : NULL),
1461 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1462 channel->channel_name, list_type);
1466 printformat_module("fe-common/silc", server,
1467 (chanrec ? chanrec->visible_name : NULL),
1468 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1469 channel->channel_name, list_type);
1471 /* Parse the list */
1472 tmp = silc_argument_get_first_arg(list, &type, &len);
1477 /* An invite string */
1481 if (tmp[len-1] == ',')
1484 list = g_strsplit(tmp, ",", -1);
1486 printformat_module("fe-common/silc", server,
1487 (chanrec ? chanrec->visible_name : NULL),
1488 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1489 ++counter, channel->channel_name, list_type,
1498 char *fingerprint, *babbleprint;
1500 /* tmp is Public Key Payload, take public key from it. */
1501 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1502 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1504 printformat_module("fe-common/silc", server,
1505 (chanrec ? chanrec->visible_name : NULL),
1506 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1507 ++counter, channel->channel_name, list_type,
1508 fingerprint, babbleprint);
1515 SilcClientEntry client_entry;
1518 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1519 silc_say_error("Invalid data in %s list encountered", list_type);
1523 client_entry = silc_client_get_client_by_id(client, conn,
1526 printformat_module("fe-common/silc", server,
1527 (chanrec ? chanrec->visible_name : NULL),
1528 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1529 ++counter, channel->channel_name, list_type,
1530 client_entry->nickname);
1531 silc_client_unref_client(client, conn, client_entry);
1534 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1542 silc_say_error("Unkown type in %s list: %u (len %u)",
1543 list_type, type, len);
1546 tmp = silc_argument_get_next_arg(list, &type, &len);
1550 printformat_module("fe-common/silc", server,
1551 (chanrec ? chanrec->visible_name : NULL),
1552 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1553 list_type, channel->channel_name);
1556 /* Command reply handler. This function is called always in the command reply
1557 function. If error occurs it will be called as well. Normal scenario
1558 is that it will be called after the received command data has been parsed
1559 and processed. The function is used to pass the received command data to
1562 `conn' is the associated client connection. `cmd_payload' is the command
1563 payload data received from server and it can be ignored. It is provided
1564 if the application would like to re-parse the received command data,
1565 however, it must be noted that the data is parsed already by the library
1566 thus the payload can be ignored. `success' is FALSE if error occured.
1567 In this case arguments are not sent to the application. `command' is the
1568 command reply being processed. The function has variable argument list
1569 and each command defines the number and type of arguments it passes to the
1570 application (on error they are not sent). */
1572 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1573 SilcCommand command, SilcStatus status,
1574 SilcStatus error, va_list vp)
1576 SILC_SERVER_REC *server = conn->context;
1577 SILC_CHANNEL_REC *chanrec;
1579 SILC_LOG_DEBUG(("Start"));
1582 case SILC_COMMAND_WHOIS:
1584 char buf[1024], *nickname, *username, *realname, *nick;
1585 unsigned char *fingerprint;
1586 SilcUInt32 idle, mode, *user_modes;
1588 SilcClientEntry client_entry;
1591 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1592 /* Print the unknown nick for user */
1593 char *tmp = va_arg(vp, char *);
1595 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1597 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1598 /* Try to find the entry for the unknown client ID, since we
1599 might have, and print the nickname of it for user. */
1600 SilcClientID *id = va_arg(vp, SilcClientID *);
1602 client_entry = silc_client_get_client_by_id(client, conn, id);
1603 if (client_entry && client_entry->nickname[0])
1604 silc_say_error("%s: %s", client_entry->nickname,
1605 silc_get_status_message(status));
1606 silc_client_unref_client(client, conn, client_entry);
1609 } else if (SILC_STATUS_IS_ERROR(status)) {
1610 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1614 client_entry = va_arg(vp, SilcClientEntry);
1615 nickname = va_arg(vp, char *);
1616 username = va_arg(vp, char *);
1617 realname = va_arg(vp, char *);
1618 channels = va_arg(vp, SilcDList);
1619 mode = va_arg(vp, SilcUInt32);
1620 idle = va_arg(vp, SilcUInt32);
1621 fingerprint = va_arg(vp, unsigned char *);
1622 user_modes = va_arg(vp, SilcUInt32 *);
1623 attrs = va_arg(vp, SilcDList);
1625 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1626 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1627 SILCTXT_WHOIS_USERINFO, nickname,
1628 client_entry->username, client_entry->hostname,
1629 nick, client_entry->nickname);
1630 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1631 SILCTXT_WHOIS_REALNAME, realname);
1634 if (channels && user_modes) {
1635 SilcChannelPayload entry;
1638 memset(buf, 0, sizeof(buf));
1639 silc_dlist_start(channels);
1640 while ((entry = silc_dlist_get(channels))) {
1641 SilcUInt32 name_len;
1642 char *m = silc_client_chumode_char(user_modes[i++]);
1643 char *name = silc_channel_get_name(entry, &name_len);
1646 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1647 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1648 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1652 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1653 SILCTXT_WHOIS_CHANNELS, buf);
1657 memset(buf, 0, sizeof(buf));
1658 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1659 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1660 SILCTXT_WHOIS_MODES, buf);
1663 if (idle && nickname) {
1664 memset(buf, 0, sizeof(buf));
1665 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1666 idle > 60 ? (idle / 60) : idle,
1667 idle > 60 ? "minutes" : "seconds");
1669 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1670 SILCTXT_WHOIS_IDLE, buf);
1674 fingerprint = silc_fingerprint(fingerprint, 20);
1675 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1676 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1677 silc_free(fingerprint);
1681 silc_query_attributes_print(server, silc_client, conn, attrs,
1686 case SILC_COMMAND_WHOWAS:
1688 char *nickname, *username, *realname;
1690 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1691 char *tmp = va_arg(vp, char *);
1693 silc_say_error("%s: %s", tmp,
1694 silc_get_status_message(status));
1696 } else if (SILC_STATUS_IS_ERROR(status)) {
1697 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1701 (void)va_arg(vp, SilcClientEntry);
1702 nickname = va_arg(vp, char *);
1703 username = va_arg(vp, char *);
1704 realname = va_arg(vp, char *);
1706 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1707 SILCTXT_WHOWAS_USERINFO, nickname, username,
1708 realname ? realname : "");
1712 case SILC_COMMAND_INVITE:
1714 SilcChannelEntry channel;
1715 SilcArgumentPayload invite_list;
1717 if (SILC_STATUS_IS_ERROR(status))
1720 channel = va_arg(vp, SilcChannelEntry);
1721 invite_list = va_arg(vp, SilcArgumentPayload);
1724 silc_parse_inviteban_list(client, conn, server, channel,
1725 "invite", invite_list);
1729 case SILC_COMMAND_JOIN:
1731 char *channel, *mode, *topic, *cipher, *hmac;
1733 SilcHashTableList *user_list;
1734 SilcChannelEntry channel_entry;
1735 SilcChannelUser chu;
1736 SilcClientEntry founder = NULL;
1739 if (SILC_STATUS_IS_ERROR(status)) {
1740 silc_say_error("JOIN: %s", silc_get_status_message(status));
1744 channel = va_arg(vp, char *);
1745 channel_entry = va_arg(vp, SilcChannelEntry);
1746 modei = va_arg(vp, SilcUInt32);
1747 user_list = va_arg(vp, SilcHashTableList *);
1748 topic = va_arg(vp, char *);
1749 cipher = va_arg(vp, char *);
1750 hmac = va_arg(vp, char *);
1752 chanrec = silc_channel_find(server, channel);
1754 chanrec = silc_channel_create(server, channel, channel, TRUE);
1757 char tmp[256], *cp, *dm = NULL;
1758 g_free_not_null(chanrec->topic);
1760 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1761 memset(tmp, 0, sizeof(tmp));
1763 if (strlen(topic) > sizeof(tmp) - 1) {
1764 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1768 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1773 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1774 signal_emit("channel topic changed", 1, chanrec);
1779 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1780 g_free_not_null(chanrec->mode);
1781 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1782 signal_emit("channel mode changed", 1, chanrec);
1785 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1786 if (!chu->client->nickname[0])
1788 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1789 founder = chu->client;
1790 silc_nicklist_insert(chanrec, chu, FALSE);
1793 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1796 nicklist_set_own(CHANNEL(chanrec), ownnick);
1797 signal_emit("channel joined", 1, chanrec);
1798 chanrec->entry = channel_entry;
1801 printformat_module("fe-common/silc", server,
1802 channel_entry->channel_name,
1803 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1804 channel_entry->channel_name, chanrec->topic);
1807 if (founder == conn->local_entry) {
1808 printformat_module("fe-common/silc",
1809 server, channel_entry->channel_name,
1810 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1811 channel_entry->channel_name);
1812 signal_emit("nick mode changed", 2, chanrec, ownnick);
1814 printformat_module("fe-common/silc",
1815 server, channel_entry->channel_name,
1816 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1817 channel_entry->channel_name, founder->nickname);
1823 case SILC_COMMAND_NICK:
1826 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1829 if (SILC_STATUS_IS_ERROR(status)) {
1830 silc_say_error("NICK: %s", silc_get_status_message(status));
1834 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1835 if ((nicks != NULL) &&
1836 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1838 SilcClientEntry collider, old;
1840 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1841 collider = silc_client_get_client_by_id(client, conn, &old->id);
1842 if (collider != client_entry) {
1843 memset(buf, 0, sizeof(buf));
1844 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1845 collider->username, collider->hostname);
1846 nicklist_rename_unique(SERVER(server),
1848 collider, collider->nickname);
1849 silc_print_nick_change(server, collider->nickname,
1850 client_entry->nickname, buf);
1852 silc_client_unref_client(client, conn, collider);
1856 g_slist_free(nicks);
1858 old = g_strdup(server->nick);
1859 server_change_nick(SERVER(server), client_entry->nickname);
1860 nicklist_rename_unique(SERVER(server),
1861 server->conn->local_entry, server->nick,
1862 client_entry, client_entry->nickname);
1863 signal_emit("message own_nick", 4, server, server->nick, old, "");
1866 /* when connecting to a server, the last thing we receive
1867 is a SILC_COMMAND_LIST reply. Since we enable queueing
1868 during the connection, we can now safely disable it again */
1869 silc_queue_disable(conn);
1873 case SILC_COMMAND_LIST:
1878 char tmp[256], *cp, *dm = NULL;
1880 if (SILC_STATUS_IS_ERROR(status))
1883 (void)va_arg(vp, SilcChannelEntry);
1884 name = va_arg(vp, char *);
1885 topic = va_arg(vp, char *);
1886 usercount = va_arg(vp, int);
1888 if (topic && !silc_term_utf8() &&
1889 silc_utf8_valid(topic, strlen(topic))) {
1890 memset(tmp, 0, sizeof(tmp));
1892 if (strlen(topic) > sizeof(tmp) - 1) {
1893 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1897 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1902 if (status == SILC_STATUS_LIST_START ||
1903 status == SILC_STATUS_OK)
1904 printformat_module("fe-common/silc", server, NULL,
1905 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1908 snprintf(users, sizeof(users) - 1, "N/A");
1910 snprintf(users, sizeof(users) - 1, "%d", usercount);
1911 printformat_module("fe-common/silc", server, NULL,
1912 MSGLEVEL_CRAP, SILCTXT_LIST,
1913 name, users, topic ? topic : "");
1918 case SILC_COMMAND_UMODE:
1923 if (SILC_STATUS_IS_ERROR(status))
1926 mode = va_arg(vp, SilcUInt32);
1928 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1929 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1930 printformat_module("fe-common/silc", server, NULL,
1931 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1933 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1934 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1935 printformat_module("fe-common/silc", server, NULL,
1936 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1938 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1939 if (mode & SILC_UMODE_GONE) {
1940 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1941 reason = g_strdup(server->away_reason);
1943 reason = g_strdup("away");
1945 reason = g_strdup("");
1947 silc_set_away(reason, server);
1952 server->umode = mode;
1953 signal_emit("user mode changed", 2, server, NULL);
1957 case SILC_COMMAND_OPER:
1958 if (SILC_STATUS_IS_ERROR(status)) {
1959 silc_say_error("OPER: %s", silc_get_status_message(status));
1963 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1964 signal_emit("user mode changed", 2, server, NULL);
1966 printformat_module("fe-common/silc", server, NULL,
1967 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1970 case SILC_COMMAND_SILCOPER:
1971 if (SILC_STATUS_IS_ERROR(status)) {
1972 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1976 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1977 signal_emit("user mode changed", 2, server, NULL);
1979 printformat_module("fe-common/silc", server, NULL,
1980 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1983 case SILC_COMMAND_USERS:
1985 SilcHashTableList htl;
1986 SilcChannelEntry channel;
1987 SilcChannelUser chu;
1989 if (SILC_STATUS_IS_ERROR(status)) {
1990 silc_say_error("USERS: %s", silc_get_status_message(status));
1994 channel = va_arg(vp, SilcChannelEntry);
1996 printformat_module("fe-common/silc", server, channel->channel_name,
1997 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1998 channel->channel_name);
2000 silc_hash_table_list(channel->user_list, &htl);
2001 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2002 SilcClientEntry e = chu->client;
2003 char stat[5], *mode;
2005 if (!e->nickname[0])
2008 memset(stat, 0, sizeof(stat));
2009 mode = silc_client_chumode_char(chu->mode);
2010 if (e->mode & SILC_UMODE_GONE)
2012 else if (e->mode & SILC_UMODE_INDISPOSED)
2014 else if (e->mode & SILC_UMODE_BUSY)
2016 else if (e->mode & SILC_UMODE_PAGE)
2018 else if (e->mode & SILC_UMODE_HYPER)
2020 else if (e->mode & SILC_UMODE_ROBOT)
2022 else if (e->mode & SILC_UMODE_ANONYMOUS)
2029 printformat_module("fe-common/silc", server, channel->channel_name,
2030 MSGLEVEL_CRAP, SILCTXT_USERS,
2032 e->username[0] ? e->username : "",
2033 e->hostname[0] ? e->hostname : "",
2034 e->realname ? e->realname : "");
2038 silc_hash_table_list_reset(&htl);
2042 case SILC_COMMAND_BAN:
2044 SilcChannelEntry channel;
2045 SilcArgumentPayload invite_list;
2047 if (SILC_STATUS_IS_ERROR(status))
2050 channel = va_arg(vp, SilcChannelEntry);
2051 invite_list = va_arg(vp, SilcArgumentPayload);
2054 silc_parse_inviteban_list(client, conn, server, channel,
2055 "ban", invite_list);
2059 case SILC_COMMAND_GETKEY:
2063 SilcPublicKey public_key;
2064 GetkeyContext getkey;
2067 if (SILC_STATUS_IS_ERROR(status)) {
2068 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2072 id_type = va_arg(vp, SilcUInt32);
2073 entry = va_arg(vp, void *);
2074 public_key = va_arg(vp, SilcPublicKey);
2077 getkey = silc_calloc(1, sizeof(*getkey));
2078 getkey->entry = entry;
2079 getkey->id_type = id_type;
2080 getkey->client = client;
2081 getkey->conn = conn;
2083 name = (id_type == SILC_ID_CLIENT ?
2084 ((SilcClientEntry)entry)->nickname :
2085 ((SilcServerEntry)entry)->server_name);
2087 silc_verify_public_key_internal(client, conn, name,
2088 (id_type == SILC_ID_CLIENT ?
2091 public_key, silc_getkey_cb, getkey);
2093 printformat_module("fe-common/silc", server, NULL,
2094 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2099 case SILC_COMMAND_INFO:
2101 SilcServerEntry server_entry;
2105 if (SILC_STATUS_IS_ERROR(status))
2108 server_entry = va_arg(vp, SilcServerEntry);
2109 server_name = va_arg(vp, char *);
2110 server_info = va_arg(vp, char *);
2112 if (server_name && server_info )
2114 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2115 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2120 case SILC_COMMAND_TOPIC:
2122 SilcChannelEntry channel;
2124 char tmp[256], *cp, *dm = NULL;
2126 if (SILC_STATUS_IS_ERROR(status))
2129 channel = va_arg(vp, SilcChannelEntry);
2130 topic = va_arg(vp, char *);
2132 if (topic && !silc_term_utf8() &&
2133 silc_utf8_valid(topic, strlen(topic))) {
2134 memset(tmp, 0, sizeof(tmp));
2136 if (strlen(topic) > sizeof(tmp) - 1) {
2137 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2141 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2147 chanrec = silc_channel_find_entry(server, channel);
2149 g_free_not_null(chanrec->topic);
2150 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2151 signal_emit("channel topic changed", 1, chanrec);
2153 printformat_module("fe-common/silc", server, channel->channel_name,
2154 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2155 channel->channel_name, topic);
2157 printformat_module("fe-common/silc", server, channel->channel_name,
2158 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2159 channel->channel_name);
2165 case SILC_COMMAND_WATCH:
2168 case SILC_COMMAND_STATS:
2170 SilcClientStats *cstats;
2172 const char *tmptime;
2173 int days, hours, mins, secs;
2175 if (SILC_STATUS_IS_ERROR(status))
2178 cstats = va_arg(vp, SilcClientStats *);
2180 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2184 tmptime = silc_time_string(cstats->starttime);
2185 printformat_module("fe-common/silc", server, NULL,
2186 MSGLEVEL_CRAP, SILCTXT_STATS,
2187 "Local server start time", tmptime);
2189 days = cstats->uptime / (24 * 60 * 60);
2190 cstats->uptime -= days * (24 * 60 * 60);
2191 hours = cstats->uptime / (60 * 60);
2192 cstats->uptime -= hours * (60 * 60);
2193 mins = cstats->uptime / 60;
2194 cstats->uptime -= mins * 60;
2195 secs = cstats->uptime;
2196 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2197 days, hours, mins, secs);
2198 printformat_module("fe-common/silc", server, NULL,
2199 MSGLEVEL_CRAP, SILCTXT_STATS,
2200 "Local server uptime", tmp);
2202 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2203 printformat_module("fe-common/silc", server, NULL,
2204 MSGLEVEL_CRAP, SILCTXT_STATS,
2205 "Local server clients", tmp);
2207 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2208 printformat_module("fe-common/silc", server, NULL,
2209 MSGLEVEL_CRAP, SILCTXT_STATS,
2210 "Local server channels", tmp);
2212 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2213 printformat_module("fe-common/silc", server, NULL,
2214 MSGLEVEL_CRAP, SILCTXT_STATS,
2215 "Local server operators", tmp);
2217 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2218 printformat_module("fe-common/silc", server, NULL,
2219 MSGLEVEL_CRAP, SILCTXT_STATS,
2220 "Local router operators", tmp);
2222 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2223 printformat_module("fe-common/silc", server, NULL,
2224 MSGLEVEL_CRAP, SILCTXT_STATS,
2225 "Local cell clients", tmp);
2227 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2228 printformat_module("fe-common/silc", server, NULL,
2229 MSGLEVEL_CRAP, SILCTXT_STATS,
2230 "Local cell channels", tmp);
2232 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2233 printformat_module("fe-common/silc", server, NULL,
2234 MSGLEVEL_CRAP, SILCTXT_STATS,
2235 "Local cell servers", tmp);
2237 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2238 printformat_module("fe-common/silc", server, NULL,
2239 MSGLEVEL_CRAP, SILCTXT_STATS,
2240 "Total clients", tmp);
2242 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2243 printformat_module("fe-common/silc", server, NULL,
2244 MSGLEVEL_CRAP, SILCTXT_STATS,
2245 "Total channels", tmp);
2247 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2248 printformat_module("fe-common/silc", server, NULL,
2249 MSGLEVEL_CRAP, SILCTXT_STATS,
2250 "Total servers", tmp);
2252 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2253 printformat_module("fe-common/silc", server, NULL,
2254 MSGLEVEL_CRAP, SILCTXT_STATS,
2255 "Total routers", tmp);
2257 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2258 printformat_module("fe-common/silc", server, NULL,
2259 MSGLEVEL_CRAP, SILCTXT_STATS,
2260 "Total server operators", tmp);
2262 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2263 printformat_module("fe-common/silc", server, NULL,
2264 MSGLEVEL_CRAP, SILCTXT_STATS,
2265 "Total router operators", tmp);
2269 case SILC_COMMAND_CMODE:
2271 SilcChannelEntry channel_entry;
2274 channel_entry = va_arg(vp, SilcChannelEntry);
2275 (void)va_arg(vp, SilcUInt32);
2276 (void)va_arg(vp, SilcPublicKey);
2277 chpks = va_arg(vp, SilcDList);
2279 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2280 !channel_entry || !channel_entry->channel_name)
2283 /* Print the channel public key list */
2285 silc_parse_channel_public_keys(server, channel_entry, chpks);
2287 printformat_module("fe-common/silc", server, NULL,
2288 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2289 channel_entry->channel_name);
2294 case SILC_COMMAND_LEAVE:
2296 if (SILC_STATUS_IS_ERROR(status))
2299 /* We might be cycling, so disable queueing again */
2300 silc_queue_disable(conn);
2304 case SILC_COMMAND_DETACH:
2306 /* Save the detachment data to file. */
2310 if (SILC_STATUS_IS_ERROR(status))
2313 detach = va_arg(vp, SilcBuffer);
2314 file = silc_get_session_filename(server);
2315 silc_file_writefile(file, silc_buffer_data(detach),
2316 silc_buffer_len(detach));
2321 case SILC_COMMAND_KILL:
2323 SilcClientEntry client_entry;
2325 if (SILC_STATUS_IS_ERROR(status)) {
2326 silc_say_error("KILL: %s", silc_get_status_message(status));
2330 client_entry = va_arg(vp, SilcClientEntry);
2331 if (!client_entry || !client_entry->nickname[0])
2334 /* Print this only if the killed client isn't joined on channels.
2335 If it is, we receive KILLED notify and we'll print this there. */
2336 if (!silc_hash_table_count(client_entry->channels))
2337 printformat_module("fe-common/silc", server, NULL,
2338 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2339 client_entry->nickname,
2340 conn->local_entry->nickname, "");
2347 SilcClientConnection conn;
2351 SilcPublicKey public_key;
2352 SilcVerifyPublicKey completion;
2356 static void verify_public_key_completion(const char *line, void *context)
2358 PublicKeyVerify verify = (PublicKeyVerify)context;
2360 if (line[0] == 'Y' || line[0] == 'y') {
2361 /* Call the completion */
2362 if (verify->completion)
2363 verify->completion(TRUE, verify->context);
2365 /* Save the key for future checking */
2366 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2367 SILC_PKCS_FILE_BASE64);
2369 /* Call the completion */
2370 if (verify->completion)
2371 verify->completion(FALSE, verify->context);
2373 printformat_module("fe-common/silc", NULL, NULL,
2374 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2375 verify->entity_name ? verify->entity_name :
2379 silc_free(verify->filename);
2380 silc_free(verify->entity);
2381 silc_free(verify->entity_name);
2385 /* Internal routine to verify public key. If the `completion' is provided
2386 it will be called to indicate whether public was verified or not. For
2387 server/router public key this will check for filename that includes the
2388 remote host's IP address and remote host's hostname. */
2391 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2393 SilcConnectionType conn_type,
2394 SilcPublicKey public_key,
2395 SilcVerifyPublicKey completion, void *context)
2397 PublicKeyVerify verify;
2398 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2399 char *fingerprint, *babbleprint, *format;
2400 SilcPublicKey local_pubkey;
2401 SilcSILCPublicKey silc_pubkey;
2403 const char *hostname, *ip;
2408 char *entity = ((conn_type == SILC_CONN_SERVER ||
2409 conn_type == SILC_CONN_ROUTER) ?
2410 "server" : "client");
2413 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2414 printformat_module("fe-common/silc", NULL, NULL,
2415 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2416 entity, silc_pkcs_get_type(public_key));
2418 completion(FALSE, context);
2422 /* Encode public key */
2423 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2426 completion(FALSE, context);
2430 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2432 pw = getpwuid(getuid());
2435 completion(FALSE, context);
2440 memset(filename, 0, sizeof(filename));
2441 memset(filename2, 0, sizeof(filename2));
2442 memset(file, 0, sizeof(file));
2444 /* Get remote host information */
2445 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2446 NULL, &hostname, &ip, &port);
2448 if (conn_type == SILC_CONN_SERVER ||
2449 conn_type == SILC_CONN_ROUTER) {
2451 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2452 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2453 get_irssi_dir(), entity, file);
2455 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2457 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2458 get_irssi_dir(), entity, file);
2463 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2465 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2466 get_irssi_dir(), entity, file);
2471 /* Replace all whitespaces with `_'. */
2472 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2473 for (i = 0; i < strlen(fingerprint); i++)
2474 if (fingerprint[i] == ' ')
2475 fingerprint[i] = '_';
2477 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2478 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2479 get_irssi_dir(), entity, file);
2480 silc_free(fingerprint);
2485 /* Take fingerprint of the public key */
2486 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2487 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2489 verify = silc_calloc(1, sizeof(*verify));
2490 verify->client = client;
2491 verify->conn = conn;
2492 verify->filename = strdup(ipf);
2493 verify->entity = strdup(entity);
2494 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2495 (name ? strdup(name) : strdup(hostname))
2497 verify->public_key = public_key;
2498 verify->completion = completion;
2499 verify->context = context;
2501 /* Check whether this key already exists */
2502 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2503 /* Key does not exist, ask user to verify the key and save it */
2505 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2506 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2507 verify->entity_name : entity);
2508 if (conn_type == SILC_CONN_CLIENT && name &&
2509 silc_pubkey->identifier.realname)
2510 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2511 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2512 silc_pubkey->identifier.realname,
2513 silc_pubkey->identifier.email ?
2514 silc_pubkey->identifier.email : "");
2515 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2516 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2517 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2518 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2519 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2520 SILCTXT_PUBKEY_ACCEPT);
2521 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2524 silc_free(fingerprint);
2525 silc_free(babbleprint);
2529 /* The key already exists, verify it. */
2530 unsigned char *encpk;
2531 SilcUInt32 encpk_len;
2533 /* Load the key file, try for both IP filename and hostname filename */
2534 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2535 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2536 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2537 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2538 verify->entity_name : entity);
2539 if (conn_type == SILC_CONN_CLIENT && name &&
2540 silc_pubkey->identifier.realname)
2541 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2542 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2543 silc_pubkey->identifier.realname,
2544 silc_pubkey->identifier.email ?
2545 silc_pubkey->identifier.email : "");
2546 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2547 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2548 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2549 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2550 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2551 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2552 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2553 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2554 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2557 silc_free(fingerprint);
2558 silc_free(babbleprint);
2563 /* Encode the key data */
2564 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2566 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2567 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2568 verify->entity_name : entity);
2569 if (conn_type == SILC_CONN_CLIENT && name &&
2570 silc_pubkey->identifier.realname)
2571 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2572 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2573 silc_pubkey->identifier.realname,
2574 silc_pubkey->identifier.email ?
2575 silc_pubkey->identifier.email : "");
2576 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2577 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2578 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2579 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2580 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2581 SILCTXT_PUBKEY_MALFORMED, entity);
2582 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2583 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2584 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2587 silc_free(fingerprint);
2588 silc_free(babbleprint);
2592 silc_pkcs_public_key_free(local_pubkey);
2594 /* Compare the keys */
2595 if (memcmp(encpk, pk, encpk_len)) {
2596 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2597 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2598 verify->entity_name : entity);
2599 if (conn_type == SILC_CONN_CLIENT && name &&
2600 silc_pubkey->identifier.realname)
2601 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2602 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2603 silc_pubkey->identifier.realname,
2604 silc_pubkey->identifier.email ?
2605 silc_pubkey->identifier.email : "");
2606 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2607 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2608 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2609 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2610 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2611 SILCTXT_PUBKEY_NO_MATCH, entity);
2612 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2613 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2614 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2615 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2617 /* Ask user to verify the key and save it */
2618 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2619 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2620 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2623 silc_free(fingerprint);
2624 silc_free(babbleprint);
2630 /* Local copy matched */
2632 completion(TRUE, context);
2634 silc_free(fingerprint);
2635 silc_free(babbleprint);
2636 silc_free(verify->filename);
2637 silc_free(verify->entity);
2638 silc_free(verify->entity_name);
2644 /* Verifies received public key. The `conn_type' indicates which entity
2645 (server, client etc.) has sent the public key. If user decides to trust
2646 the key may be saved as trusted public key for later use. The
2647 `completion' must be called after the public key has been verified. */
2650 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2651 SilcConnectionType conn_type,
2652 SilcPublicKey public_key,
2653 SilcVerifyPublicKey completion, void *context)
2655 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2656 completion, context);
2659 /* Asks passphrase from user on the input line. */
2662 SilcAskPassphrase completion;
2666 void ask_passphrase_completion(const char *passphrase, void *context)
2668 AskPassphrase p = (AskPassphrase)context;
2669 if (passphrase && passphrase[0] == '\0')
2671 p->completion((unsigned char *)passphrase,
2672 passphrase ? strlen(passphrase) : 0, p->context);
2676 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2677 SilcAskPassphrase completion, void *context)
2679 AskPassphrase p = silc_calloc(1, sizeof(*p));
2680 p->completion = completion;
2681 p->context = context;
2683 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2684 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2688 SilcGetAuthMeth completion;
2692 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2693 SilcUInt32 passphrase_len,
2696 GetAuthMethod a = context;
2697 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2698 passphrase, passphrase_len, a->context);
2702 /* Find authentication data by hostname and port. The hostname may be IP
2705 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2706 char *hostname, SilcUInt16 port,
2707 SilcAuthMethod auth_meth,
2708 SilcGetAuthMeth completion, void *context)
2710 SERVER_SETUP_REC *setup;
2712 SILC_LOG_DEBUG(("Start"));
2714 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2715 /* Returning NULL will cause library to use our private key configured
2716 for this connection */
2717 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2721 /* Check whether we find the password for this server in our
2722 configuration. If it's set, always send it server. */
2723 setup = server_setup_find_port(hostname, port);
2724 if (setup && setup->password) {
2725 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2730 /* Didn't find password. If server wants it, ask it from user. */
2731 if (auth_meth == SILC_AUTH_PASSWORD) {
2733 a = silc_calloc(1, sizeof(*a));
2735 a->completion = completion;
2736 a->context = context;
2737 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2742 /* No authentication */
2743 completion(SILC_AUTH_NONE, NULL, 0, context);
2746 /* Asks whether the user would like to perform the key agreement protocol.
2747 This is called after we have received an key agreement packet or an
2748 reply to our key agreement packet. This returns TRUE if the user wants
2749 the library to perform the key agreement protocol and FALSE if it is not
2750 desired (application may start it later by calling the function
2751 silc_client_perform_key_agreement). */
2753 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2754 SilcClientEntry client_entry, const char *hostname,
2755 SilcUInt16 protocol, SilcUInt16 port)
2757 char portstr[12], protostr[5];
2759 SILC_LOG_DEBUG(("Start"));
2761 /* We will just display the info on the screen and return FALSE and user
2762 will have to start the key agreement with a command. */
2765 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2766 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2771 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2772 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2774 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2775 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2776 client_entry->nickname, hostname, portstr, protostr);
2779 /* Notifies application that file transfer protocol session is being
2780 requested by the remote client indicated by the `client_entry' from
2781 the `hostname' and `port'. The `session_id' is the file transfer
2782 session and it can be used to either accept or reject the file
2783 transfer request, by calling the silc_client_file_receive or
2784 silc_client_file_close, respectively. */
2786 void silc_ftp(SilcClient client, SilcClientConnection conn,
2787 SilcClientEntry client_entry, SilcUInt32 session_id,
2788 const char *hostname, SilcUInt16 port)
2790 SILC_SERVER_REC *server;
2792 FtpSession ftp = NULL;
2794 SILC_LOG_DEBUG(("Start"));
2796 server = conn->context;
2798 silc_dlist_start(server->ftp_sessions);
2799 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2800 if (ftp->client_entry == client_entry &&
2801 ftp->session_id == session_id) {
2802 server->current_session = ftp;
2806 if (ftp == SILC_LIST_END) {
2807 ftp = silc_calloc(1, sizeof(*ftp));
2808 ftp->client_entry = client_entry;
2809 ftp->session_id = session_id;
2812 silc_dlist_add(server->ftp_sessions, ftp);
2813 server->current_session = ftp;
2817 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2820 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2821 SILCTXT_FILE_REQUEST, client_entry->nickname);
2823 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2824 SILCTXT_FILE_REQUEST_HOST,
2825 client_entry->nickname, hostname, portstr);
2828 /* SILC client operations */
2829 SilcClientOperations ops = {
2831 silc_channel_message,
2832 silc_private_message,
2836 silc_get_auth_method,
2837 silc_verify_public_key,
2838 silc_ask_passphrase,