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];
776 silc_parse_userfqdn(client_entry->nickname, nick, sizeof(nick), NULL, 0);
777 clients = silc_client_get_clients_local(client, conn, nick, NULL);
778 if (!clients || silc_dlist_count(clients) < 2) {
779 silc_client_list_free(client, conn, clients);
782 silc_dlist_start(clients);
783 while ((client_entry2 = silc_dlist_get(clients)))
784 if (silc_client_on_channel(channel, client_entry2))
787 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
788 printformat_module("fe-common/silc", server, channel->channel_name,
789 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
791 printformat_module("fe-common/silc", server, channel->channel_name,
792 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
793 buf, client_entry->nickname);
795 silc_client_list_free(client, conn, clients);
799 case SILC_NOTIFY_TYPE_LEAVE:
804 SILC_LOG_DEBUG(("Notify: LEAVE"));
806 client_entry = va_arg(va, SilcClientEntry);
807 channel = va_arg(va, SilcChannelEntry);
809 memset(buf, 0, sizeof(buf));
810 if (client_entry->username)
811 snprintf(buf, sizeof(buf) - 1, "%s@%s",
812 client_entry->username, client_entry->hostname);
813 signal_emit("message part", 5, server, channel->channel_name,
814 client_entry->nickname, client_entry->username[0] ?
815 buf : "", client_entry->nickname);
817 chanrec = silc_channel_find_entry(server, channel);
818 if (chanrec != NULL) {
819 nickrec = silc_nicklist_find(chanrec, client_entry);
821 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
825 case SILC_NOTIFY_TYPE_SIGNOFF:
830 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
832 client_entry = va_arg(va, SilcClientEntry);
833 tmp = va_arg(va, char *);
835 silc_server_free_ftp(server, client_entry);
837 /* Print only if we have the nickname. If this cliente has just quit
838 when we were only resolving it, it is possible we don't have the
840 if (client_entry->nickname[0]) {
841 memset(buf, 0, sizeof(buf));
842 if (client_entry->username)
843 snprintf(buf, sizeof(buf) - 1, "%s@%s",
844 client_entry->username, client_entry->hostname);
845 signal_emit("message quit", 4, server, client_entry->nickname,
846 client_entry->username[0] ? buf : "",
850 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
851 for (list_tmp = list1; list_tmp != NULL; list_tmp =
852 list_tmp->next->next) {
853 CHANNEL_REC *channel = list_tmp->data;
854 NICK_REC *nickrec = list_tmp->next->data;
856 nicklist_remove(channel, nickrec);
860 case SILC_NOTIFY_TYPE_TOPIC_SET:
865 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
867 idtype = va_arg(va, int);
868 entry = va_arg(va, void *);
869 tmp = va_arg(va, char *);
870 channel = va_arg(va, SilcChannelEntry);
872 chanrec = silc_channel_find_entry(server, channel);
873 if (chanrec != NULL) {
874 char tmp2[256], *cp, *dm = NULL;
876 g_free_not_null(chanrec->topic);
877 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
878 memset(tmp2, 0, sizeof(tmp2));
880 if (strlen(tmp) > sizeof(tmp2) - 1) {
881 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
885 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
890 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
891 signal_emit("channel topic changed", 1, chanrec);
896 if (idtype == SILC_ID_CLIENT) {
897 client_entry = (SilcClientEntry)entry;
898 memset(buf, 0, sizeof(buf));
899 snprintf(buf, sizeof(buf) - 1, "%s@%s",
900 client_entry->username, client_entry->hostname);
901 signal_emit("message topic", 5, server, channel->channel_name,
902 tmp, client_entry->nickname, buf);
903 } else if (idtype == SILC_ID_SERVER) {
904 server_entry = (SilcServerEntry)entry;
905 signal_emit("message topic", 5, server, channel->channel_name,
906 tmp, server_entry->server_name,
907 server_entry->server_name);
908 } else if (idtype == SILC_ID_CHANNEL) {
909 channel = (SilcChannelEntry)entry;
910 signal_emit("message topic", 5, server, channel->channel_name,
911 tmp, channel->channel_name, channel->channel_name);
915 case SILC_NOTIFY_TYPE_NICK_CHANGE:
920 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
922 client_entry = va_arg(va, SilcClientEntry);
923 name = va_arg(va, char *); /* old nickname */
925 if (!strcmp(client_entry->nickname, name))
928 memset(buf, 0, sizeof(buf));
929 snprintf(buf, sizeof(buf) - 1, "%s@%s",
930 client_entry->username, client_entry->hostname);
931 nicklist_rename_unique(SERVER(server),
933 client_entry, client_entry->nickname);
934 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
937 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
939 * Changed channel mode.
942 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
944 idtype = va_arg(va, int);
945 entry = va_arg(va, void *);
946 mode = va_arg(va, SilcUInt32);
947 cipher = va_arg(va, char *); /* cipher */
948 hmac = va_arg(va, char *); /* hmac */
949 (void)va_arg(va, char *); /* passphrase */
950 (void)va_arg(va, SilcPublicKey); /* founder key */
951 chpks = va_arg(va, SilcDList); /* channel public keys */
952 channel = va_arg(va, SilcChannelEntry);
954 tmp = silc_client_chmode(mode, cipher ? cipher : "",
957 chanrec = silc_channel_find_entry(server, channel);
958 if (chanrec != NULL) {
959 g_free_not_null(chanrec->mode);
960 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
961 signal_emit("channel mode changed", 1, chanrec);
964 if (idtype == SILC_ID_CLIENT) {
965 client_entry = (SilcClientEntry)entry;
966 printformat_module("fe-common/silc", server, channel->channel_name,
967 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
968 channel->channel_name, tmp ? tmp : "removed all",
969 client_entry->nickname);
970 } else if (idtype == SILC_ID_SERVER) {
971 server_entry = (SilcServerEntry)entry;
972 printformat_module("fe-common/silc", server, channel->channel_name,
973 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
974 channel->channel_name, tmp ? tmp : "removed all",
975 server_entry->server_name);
976 } else if (idtype == SILC_ID_CHANNEL) {
977 channel2 = (SilcChannelEntry)entry;
978 printformat_module("fe-common/silc", server, channel->channel_name,
979 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
980 channel->channel_name, tmp ? tmp : "removed all",
981 channel2->channel_name);
984 /* Print the channel public key list */
986 silc_parse_channel_public_keys(server, channel, chpks);
991 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
993 * Changed user's mode on channel.
996 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
998 idtype = va_arg(va, int);
999 entry = va_arg(va, void *);
1000 mode = va_arg(va, SilcUInt32);
1001 client_entry2 = va_arg(va, SilcClientEntry);
1002 channel = va_arg(va, SilcChannelEntry);
1004 tmp = silc_client_chumode(mode);
1005 chanrec = silc_channel_find_entry(server, channel);
1006 if (chanrec != NULL) {
1007 SILC_NICK_REC *nick;
1009 if (client_entry2 == server->conn->local_entry)
1010 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1012 nick = silc_nicklist_find(chanrec, client_entry2);
1014 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1015 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1016 signal_emit("nick mode changed", 2, chanrec, nick);
1020 if (idtype == SILC_ID_CLIENT) {
1021 client_entry = (SilcClientEntry)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 client_entry->nickname);
1027 } else if (idtype == SILC_ID_SERVER) {
1028 server_entry = (SilcServerEntry)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 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_CUMODE,
1038 channel->channel_name, client_entry2->nickname,
1039 tmp ? tmp : "removed all",
1040 channel2->channel_name);
1043 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1044 printformat_module("fe-common/silc",
1045 server, channel->channel_name, MSGLEVEL_CRAP,
1046 SILCTXT_CHANNEL_FOUNDER,
1047 channel->channel_name, client_entry2->nickname);
1049 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1050 printformat_module("fe-common/silc",
1051 server, channel->channel_name, MSGLEVEL_CRAP,
1052 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1057 case SILC_NOTIFY_TYPE_MOTD:
1062 SILC_LOG_DEBUG(("Notify: MOTD"));
1064 tmp = va_arg(va, char *);
1066 if (!settings_get_bool("skip_motd"))
1067 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1070 case SILC_NOTIFY_TYPE_KICKED:
1072 * Someone was kicked from channel.
1075 SILC_LOG_DEBUG(("Notify: KICKED"));
1077 client_entry = va_arg(va, SilcClientEntry);
1078 tmp = va_arg(va, char *);
1079 client_entry2 = va_arg(va, SilcClientEntry);
1080 channel = va_arg(va, SilcChannelEntry);
1082 chanrec = silc_channel_find_entry(server, channel);
1084 if (client_entry == conn->local_entry) {
1085 printformat_module("fe-common/silc", server, channel->channel_name,
1086 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1087 channel->channel_name,
1088 client_entry ? client_entry2->nickname : "",
1091 chanrec->kicked = TRUE;
1092 channel_destroy((CHANNEL_REC *)chanrec);
1095 printformat_module("fe-common/silc", server, channel->channel_name,
1096 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1097 client_entry->nickname, channel->channel_name,
1098 client_entry2 ? client_entry2->nickname : "",
1102 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1103 if (nickrec != NULL)
1104 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1109 case SILC_NOTIFY_TYPE_KILLED:
1111 * Someone was killed from the network.
1114 SILC_LOG_DEBUG(("Notify: KILLED"));
1116 client_entry = va_arg(va, SilcClientEntry);
1117 tmp = va_arg(va, char *);
1118 idtype = va_arg(va, int);
1119 entry = va_arg(va, SilcClientEntry);
1121 if (client_entry == conn->local_entry) {
1122 if (idtype == SILC_ID_CLIENT) {
1123 client_entry2 = (SilcClientEntry)entry;
1124 printformat_module("fe-common/silc", server, NULL,
1125 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1126 client_entry2 ? client_entry2->nickname : "",
1128 } else if (idtype == SILC_ID_SERVER) {
1129 server_entry = (SilcServerEntry)entry;
1130 printformat_module("fe-common/silc", server, NULL,
1131 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1132 server_entry->server_name, tmp ? tmp : "");
1133 } else if (idtype == SILC_ID_CHANNEL) {
1134 channel = (SilcChannelEntry)entry;
1135 printformat_module("fe-common/silc", server, NULL,
1136 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1137 channel->channel_name, tmp ? tmp : "");
1140 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1141 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1142 list_tmp->next->next) {
1143 CHANNEL_REC *channel = list_tmp->data;
1144 NICK_REC *nickrec = list_tmp->next->data;
1145 nicklist_remove(channel, nickrec);
1148 if (idtype == SILC_ID_CLIENT) {
1149 client_entry2 = (SilcClientEntry)entry;
1150 printformat_module("fe-common/silc", server, NULL,
1151 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1152 client_entry->nickname,
1153 client_entry2 ? client_entry2->nickname : "",
1155 } else if (idtype == SILC_ID_SERVER) {
1156 server_entry = (SilcServerEntry)entry;
1157 printformat_module("fe-common/silc", server, NULL,
1158 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1159 client_entry->nickname,
1160 server_entry->server_name, tmp ? tmp : "");
1161 } else if (idtype == SILC_ID_CHANNEL) {
1162 channel = (SilcChannelEntry)entry;
1163 printformat_module("fe-common/silc", server, NULL,
1164 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1165 client_entry->nickname,
1166 channel->channel_name, tmp ? tmp : "");
1171 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1174 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1177 * Server has quit the network.
1181 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1183 (void)va_arg(va, void *);
1184 clients = va_arg(va, SilcDList);
1186 silc_dlist_start(clients);
1187 while ((client_entry = silc_dlist_get(clients))) {
1188 memset(buf, 0, sizeof(buf));
1190 /* Print only if we have the nickname. If this client has just quit
1191 when we were only resolving it, it is possible we don't have the
1193 if (client_entry->nickname[0]) {
1194 if (client_entry->username[0])
1195 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1196 client_entry->username, client_entry->hostname);
1197 signal_emit("message quit", 4, server, client_entry->nickname,
1198 client_entry->username[0] ? buf : "",
1202 silc_server_free_ftp(server, client_entry);
1204 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1205 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1206 list_tmp->next->next) {
1207 CHANNEL_REC *channel = list_tmp->data;
1208 NICK_REC *nickrec = list_tmp->next->data;
1209 nicklist_remove(channel, nickrec);
1215 case SILC_NOTIFY_TYPE_ERROR:
1217 SilcStatus error = va_arg(va, int);
1219 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1220 "%s", silc_get_status_message(error));
1224 case SILC_NOTIFY_TYPE_WATCH:
1226 SilcNotifyType notify;
1228 client_entry = va_arg(va, SilcClientEntry);
1229 name = va_arg(va, char *); /* Maybe NULL */
1230 mode = va_arg(va, SilcUInt32);
1231 notify = va_arg(va, int);
1233 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1235 printformat_module("fe-common/silc", server, NULL,
1236 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1237 client_entry->nickname, name);
1239 printformat_module("fe-common/silc", server, NULL,
1240 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1241 client_entry->nickname);
1242 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1243 /* See if client was away and is now present */
1244 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1245 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1246 SILC_UMODE_DETACHED)) &&
1247 (client_entry->mode & SILC_UMODE_GONE ||
1248 client_entry->mode & SILC_UMODE_INDISPOSED ||
1249 client_entry->mode & SILC_UMODE_BUSY ||
1250 client_entry->mode & SILC_UMODE_PAGE ||
1251 client_entry->mode & SILC_UMODE_DETACHED)) {
1252 printformat_module("fe-common/silc", server, NULL,
1253 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1254 client_entry->nickname);
1258 memset(buf, 0, sizeof(buf));
1259 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1260 printformat_module("fe-common/silc", server, NULL,
1261 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1262 client_entry->nickname, buf);
1264 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1265 printformat_module("fe-common/silc", server, NULL,
1266 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1267 client_entry->nickname);
1268 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1269 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1270 printformat_module("fe-common/silc", server, NULL,
1271 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1272 client_entry->nickname);
1273 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1274 /* Client logged in to the network */
1275 printformat_module("fe-common/silc", server, NULL,
1276 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1277 client_entry->nickname);
1283 /* Unknown notify */
1284 printformat_module("fe-common/silc", server, NULL,
1285 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1292 /* Command handler. This function is called always in the command function.
1293 If error occurs it will be called as well. `conn' is the associated
1294 client connection. `cmd_context' is the command context that was
1295 originally sent to the command. `success' is FALSE if error occured
1296 during command. `command' is the command being processed. It must be
1297 noted that this is not reply from server. This is merely called just
1298 after application has called the command. Just to tell application
1299 that the command really was processed. */
1301 static SilcBool cmode_list_chpks = FALSE;
1303 void silc_command(SilcClient client, SilcClientConnection conn,
1304 SilcBool success, SilcCommand command, SilcStatus status,
1305 SilcUInt32 argc, unsigned char **argv)
1307 SILC_SERVER_REC *server = conn->context;
1309 SILC_LOG_DEBUG(("Start"));
1312 silc_say_error("%s", silc_get_status_message(status));
1318 case SILC_COMMAND_INVITE:
1320 printformat_module("fe-common/silc", server, NULL,
1321 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1323 (argv[1][0] == '*' ?
1324 (char *)conn->current_channel->channel_name :
1328 case SILC_COMMAND_DETACH:
1329 server->no_reconnect = TRUE;
1332 case SILC_COMMAND_CMODE:
1333 if (argc == 3 && !strcmp(argv[2], "+C"))
1334 cmode_list_chpks = TRUE;
1336 cmode_list_chpks = FALSE;
1346 SilcClientConnection conn;
1351 void silc_getkey_cb(bool success, void *context)
1353 GetkeyContext getkey = (GetkeyContext)context;
1354 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1355 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1356 ((SilcClientEntry)getkey->entry)->nickname :
1357 ((SilcServerEntry)getkey->entry)->server_name);
1360 printformat_module("fe-common/silc", NULL, NULL,
1361 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1363 printformat_module("fe-common/silc", NULL, NULL,
1364 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1371 /* Parse an invite or ban list */
1372 void silc_parse_inviteban_list(SilcClient client,
1373 SilcClientConnection conn,
1374 SILC_SERVER_REC *server,
1375 SilcChannelEntry channel,
1376 const char *list_type,
1377 SilcArgumentPayload list)
1380 SilcUInt32 type, len;
1381 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1382 int counter=0, resolving = FALSE;
1384 if (!silc_argument_get_arg_num(list)) {
1385 printformat_module("fe-common/silc", server,
1386 (chanrec ? chanrec->visible_name : NULL),
1387 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1388 channel->channel_name, list_type);
1392 printformat_module("fe-common/silc", server,
1393 (chanrec ? chanrec->visible_name : NULL),
1394 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1395 channel->channel_name, list_type);
1397 /* Parse the list */
1398 tmp = silc_argument_get_first_arg(list, &type, &len);
1403 /* An invite string */
1407 if (tmp[len-1] == ',')
1410 list = g_strsplit(tmp, ",", -1);
1412 printformat_module("fe-common/silc", server,
1413 (chanrec ? chanrec->visible_name : NULL),
1414 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1415 ++counter, channel->channel_name, list_type,
1424 char *fingerprint, *babbleprint;
1426 /* tmp is Public Key Payload, take public key from it. */
1427 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1428 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1430 printformat_module("fe-common/silc", server,
1431 (chanrec ? chanrec->visible_name : NULL),
1432 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1433 ++counter, channel->channel_name, list_type,
1434 fingerprint, babbleprint);
1441 SilcClientEntry client_entry;
1444 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1445 silc_say_error("Invalid data in %s list encountered", list_type);
1449 client_entry = silc_client_get_client_by_id(client, conn,
1452 printformat_module("fe-common/silc", server,
1453 (chanrec ? chanrec->visible_name : NULL),
1454 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1455 ++counter, channel->channel_name, list_type,
1456 client_entry->nickname);
1457 silc_client_unref_client(client, conn, client_entry);
1460 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1468 silc_say_error("Unkown type in %s list: %u (len %u)",
1469 list_type, type, len);
1472 tmp = silc_argument_get_next_arg(list, &type, &len);
1476 printformat_module("fe-common/silc", server,
1477 (chanrec ? chanrec->visible_name : NULL),
1478 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1479 list_type, channel->channel_name);
1482 /* Command reply handler. This function is called always in the command reply
1483 function. If error occurs it will be called as well. Normal scenario
1484 is that it will be called after the received command data has been parsed
1485 and processed. The function is used to pass the received command data to
1488 `conn' is the associated client connection. `cmd_payload' is the command
1489 payload data received from server and it can be ignored. It is provided
1490 if the application would like to re-parse the received command data,
1491 however, it must be noted that the data is parsed already by the library
1492 thus the payload can be ignored. `success' is FALSE if error occured.
1493 In this case arguments are not sent to the application. `command' is the
1494 command reply being processed. The function has variable argument list
1495 and each command defines the number and type of arguments it passes to the
1496 application (on error they are not sent). */
1498 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1499 SilcCommand command, SilcStatus status,
1500 SilcStatus error, va_list vp)
1502 SILC_SERVER_REC *server = conn->context;
1503 SILC_CHANNEL_REC *chanrec;
1505 SILC_LOG_DEBUG(("Start"));
1508 case SILC_COMMAND_WHOIS:
1510 char buf[1024], *nickname, *username, *realname, nick[128 + 1];
1511 unsigned char *fingerprint;
1512 SilcUInt32 idle, mode, *user_modes;
1514 SilcClientEntry client_entry;
1517 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1518 /* Print the unknown nick for user */
1519 char *tmp = va_arg(vp, char *);
1521 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1523 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1524 /* Try to find the entry for the unknown client ID, since we
1525 might have, and print the nickname of it for user. */
1526 SilcClientID *id = va_arg(vp, SilcClientID *);
1528 client_entry = silc_client_get_client_by_id(client, conn, id);
1529 if (client_entry && client_entry->nickname[0])
1530 silc_say_error("%s: %s", client_entry->nickname,
1531 silc_get_status_message(status));
1532 silc_client_unref_client(client, conn, client_entry);
1535 } else if (SILC_STATUS_IS_ERROR(status)) {
1536 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1540 client_entry = va_arg(vp, SilcClientEntry);
1541 nickname = va_arg(vp, char *);
1542 username = va_arg(vp, char *);
1543 realname = va_arg(vp, char *);
1544 channels = va_arg(vp, SilcDList);
1545 mode = va_arg(vp, SilcUInt32);
1546 idle = va_arg(vp, SilcUInt32);
1547 fingerprint = va_arg(vp, unsigned char *);
1548 user_modes = va_arg(vp, SilcUInt32 *);
1549 attrs = va_arg(vp, SilcDList);
1551 silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
1552 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1553 SILCTXT_WHOIS_USERINFO, nickname,
1554 client_entry->username, client_entry->hostname,
1555 nick, client_entry->nickname);
1556 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1557 SILCTXT_WHOIS_REALNAME, realname);
1559 if (channels && user_modes) {
1560 SilcChannelPayload entry;
1563 memset(buf, 0, sizeof(buf));
1564 silc_dlist_start(channels);
1565 while ((entry = silc_dlist_get(channels))) {
1566 SilcUInt32 name_len;
1567 char *m = silc_client_chumode_char(user_modes[i++]);
1568 char *name = silc_channel_get_name(entry, &name_len);
1571 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1572 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1573 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1577 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1578 SILCTXT_WHOIS_CHANNELS, buf);
1582 memset(buf, 0, sizeof(buf));
1583 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1584 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1585 SILCTXT_WHOIS_MODES, buf);
1588 if (idle && nickname) {
1589 memset(buf, 0, sizeof(buf));
1590 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1591 idle > 60 ? (idle / 60) : idle,
1592 idle > 60 ? "minutes" : "seconds");
1594 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1595 SILCTXT_WHOIS_IDLE, buf);
1599 fingerprint = silc_fingerprint(fingerprint, 20);
1600 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1601 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1602 silc_free(fingerprint);
1606 silc_query_attributes_print(server, silc_client, conn, attrs,
1611 case SILC_COMMAND_WHOWAS:
1613 char *nickname, *username, *realname;
1615 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1616 char *tmp = va_arg(vp, char *);
1618 silc_say_error("%s: %s", tmp,
1619 silc_get_status_message(status));
1621 } else if (SILC_STATUS_IS_ERROR(status)) {
1622 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1626 (void)va_arg(vp, SilcClientEntry);
1627 nickname = va_arg(vp, char *);
1628 username = va_arg(vp, char *);
1629 realname = va_arg(vp, char *);
1631 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1632 SILCTXT_WHOWAS_USERINFO, nickname, username,
1633 realname ? realname : "");
1637 case SILC_COMMAND_INVITE:
1639 SilcChannelEntry channel;
1640 SilcArgumentPayload invite_list;
1642 if (SILC_STATUS_IS_ERROR(status))
1645 channel = va_arg(vp, SilcChannelEntry);
1646 invite_list = va_arg(vp, SilcArgumentPayload);
1649 silc_parse_inviteban_list(client, conn, server, channel,
1650 "invite", invite_list);
1654 case SILC_COMMAND_JOIN:
1656 char *channel, *mode, *topic, *cipher, *hmac;
1658 SilcHashTableList *user_list;
1659 SilcChannelEntry channel_entry;
1660 SilcChannelUser chu;
1661 SilcClientEntry founder = NULL;
1664 if (SILC_STATUS_IS_ERROR(status)) {
1665 silc_say_error("JOIN: %s", silc_get_status_message(status));
1669 channel = va_arg(vp, char *);
1670 channel_entry = va_arg(vp, SilcChannelEntry);
1671 modei = va_arg(vp, SilcUInt32);
1672 user_list = va_arg(vp, SilcHashTableList *);
1673 topic = va_arg(vp, char *);
1674 cipher = va_arg(vp, char *);
1675 hmac = va_arg(vp, char *);
1677 chanrec = silc_channel_find(server, channel);
1679 chanrec = silc_channel_create(server, channel, channel, TRUE);
1682 char tmp[256], *cp, *dm = NULL;
1683 g_free_not_null(chanrec->topic);
1685 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1686 memset(tmp, 0, sizeof(tmp));
1688 if (strlen(topic) > sizeof(tmp) - 1) {
1689 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1693 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1698 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1699 signal_emit("channel topic changed", 1, chanrec);
1704 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1705 g_free_not_null(chanrec->mode);
1706 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1707 signal_emit("channel mode changed", 1, chanrec);
1710 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1711 if (!chu->client->nickname[0])
1713 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1714 founder = chu->client;
1715 silc_nicklist_insert(chanrec, chu, FALSE);
1718 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1721 nicklist_set_own(CHANNEL(chanrec), ownnick);
1722 signal_emit("channel joined", 1, chanrec);
1723 chanrec->entry = channel_entry;
1726 printformat_module("fe-common/silc", server,
1727 channel_entry->channel_name,
1728 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1729 channel_entry->channel_name, chanrec->topic);
1732 if (founder == conn->local_entry) {
1733 printformat_module("fe-common/silc",
1734 server, channel_entry->channel_name,
1735 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1736 channel_entry->channel_name);
1737 signal_emit("nick mode changed", 2, chanrec, ownnick);
1739 printformat_module("fe-common/silc",
1740 server, channel_entry->channel_name,
1741 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1742 channel_entry->channel_name, founder->nickname);
1748 case SILC_COMMAND_NICK:
1751 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1754 if (SILC_STATUS_IS_ERROR(status)) {
1755 silc_say_error("NICK: %s", silc_get_status_message(status));
1759 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1760 if ((nicks != NULL) &&
1761 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1763 SilcClientEntry collider, old;
1765 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1766 collider = silc_client_get_client_by_id(client, conn, &old->id);
1767 if (collider != client_entry) {
1768 memset(buf, 0, sizeof(buf));
1769 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1770 collider->username, collider->hostname);
1771 nicklist_rename_unique(SERVER(server),
1773 collider, collider->nickname);
1774 silc_print_nick_change(server, collider->nickname,
1775 client_entry->nickname, buf);
1777 silc_client_unref_client(client, conn, collider);
1781 g_slist_free(nicks);
1783 old = g_strdup(server->nick);
1784 server_change_nick(SERVER(server), client_entry->nickname);
1785 nicklist_rename_unique(SERVER(server),
1786 server->conn->local_entry, server->nick,
1787 client_entry, client_entry->nickname);
1788 signal_emit("message own_nick", 4, server, server->nick, old, "");
1791 /* when connecting to a server, the last thing we receive
1792 is a SILC_COMMAND_LIST reply. Since we enable queueing
1793 during the connection, we can now safely disable it again */
1794 silc_queue_disable(conn);
1798 case SILC_COMMAND_LIST:
1803 char tmp[256], *cp, *dm = NULL;
1805 if (SILC_STATUS_IS_ERROR(status))
1808 (void)va_arg(vp, SilcChannelEntry);
1809 name = va_arg(vp, char *);
1810 topic = va_arg(vp, char *);
1811 usercount = va_arg(vp, int);
1813 if (topic && !silc_term_utf8() &&
1814 silc_utf8_valid(topic, strlen(topic))) {
1815 memset(tmp, 0, sizeof(tmp));
1817 if (strlen(topic) > sizeof(tmp) - 1) {
1818 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1822 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1827 if (status == SILC_STATUS_LIST_START ||
1828 status == SILC_STATUS_OK)
1829 printformat_module("fe-common/silc", server, NULL,
1830 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1833 snprintf(users, sizeof(users) - 1, "N/A");
1835 snprintf(users, sizeof(users) - 1, "%d", usercount);
1836 printformat_module("fe-common/silc", server, NULL,
1837 MSGLEVEL_CRAP, SILCTXT_LIST,
1838 name, users, topic ? topic : "");
1843 case SILC_COMMAND_UMODE:
1848 if (SILC_STATUS_IS_ERROR(status))
1851 mode = va_arg(vp, SilcUInt32);
1853 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1854 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1855 printformat_module("fe-common/silc", server, NULL,
1856 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1858 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1859 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1860 printformat_module("fe-common/silc", server, NULL,
1861 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1863 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1864 if (mode & SILC_UMODE_GONE) {
1865 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1866 reason = g_strdup(server->away_reason);
1868 reason = g_strdup("away");
1870 reason = g_strdup("");
1872 silc_set_away(reason, server);
1877 server->umode = mode;
1878 signal_emit("user mode changed", 2, server, NULL);
1882 case SILC_COMMAND_OPER:
1883 if (SILC_STATUS_IS_ERROR(status)) {
1884 silc_say_error("OPER: %s", silc_get_status_message(status));
1888 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1889 signal_emit("user mode changed", 2, server, NULL);
1891 printformat_module("fe-common/silc", server, NULL,
1892 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1895 case SILC_COMMAND_SILCOPER:
1896 if (SILC_STATUS_IS_ERROR(status)) {
1897 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1901 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1902 signal_emit("user mode changed", 2, server, NULL);
1904 printformat_module("fe-common/silc", server, NULL,
1905 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1908 case SILC_COMMAND_USERS:
1910 SilcHashTableList htl;
1911 SilcChannelEntry channel;
1912 SilcChannelUser chu;
1914 if (SILC_STATUS_IS_ERROR(status)) {
1915 silc_say_error("USERS: %s", silc_get_status_message(status));
1919 channel = va_arg(vp, SilcChannelEntry);
1921 printformat_module("fe-common/silc", server, channel->channel_name,
1922 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1923 channel->channel_name);
1925 silc_hash_table_list(channel->user_list, &htl);
1926 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1927 SilcClientEntry e = chu->client;
1928 char stat[5], *mode;
1930 if (!e->nickname[0])
1933 memset(stat, 0, sizeof(stat));
1934 mode = silc_client_chumode_char(chu->mode);
1935 if (e->mode & SILC_UMODE_GONE)
1937 else if (e->mode & SILC_UMODE_INDISPOSED)
1939 else if (e->mode & SILC_UMODE_BUSY)
1941 else if (e->mode & SILC_UMODE_PAGE)
1943 else if (e->mode & SILC_UMODE_HYPER)
1945 else if (e->mode & SILC_UMODE_ROBOT)
1947 else if (e->mode & SILC_UMODE_ANONYMOUS)
1954 printformat_module("fe-common/silc", server, channel->channel_name,
1955 MSGLEVEL_CRAP, SILCTXT_USERS,
1957 e->username[0] ? e->username : "",
1958 e->hostname[0] ? e->hostname : "",
1959 e->realname ? e->realname : "");
1963 silc_hash_table_list_reset(&htl);
1967 case SILC_COMMAND_BAN:
1969 SilcChannelEntry channel;
1970 SilcArgumentPayload invite_list;
1972 if (SILC_STATUS_IS_ERROR(status))
1975 channel = va_arg(vp, SilcChannelEntry);
1976 invite_list = va_arg(vp, SilcArgumentPayload);
1979 silc_parse_inviteban_list(client, conn, server, channel,
1980 "ban", invite_list);
1984 case SILC_COMMAND_GETKEY:
1988 SilcPublicKey public_key;
1989 GetkeyContext getkey;
1992 if (SILC_STATUS_IS_ERROR(status)) {
1993 silc_say_error("GETKEY: %s", silc_get_status_message(status));
1997 id_type = va_arg(vp, SilcUInt32);
1998 entry = va_arg(vp, void *);
1999 public_key = va_arg(vp, SilcPublicKey);
2002 getkey = silc_calloc(1, sizeof(*getkey));
2003 getkey->entry = entry;
2004 getkey->id_type = id_type;
2005 getkey->client = client;
2006 getkey->conn = conn;
2008 name = (id_type == SILC_ID_CLIENT ?
2009 ((SilcClientEntry)entry)->nickname :
2010 ((SilcServerEntry)entry)->server_name);
2012 silc_verify_public_key_internal(client, conn, name,
2013 (id_type == SILC_ID_CLIENT ?
2016 public_key, silc_getkey_cb, getkey);
2018 printformat_module("fe-common/silc", server, NULL,
2019 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2024 case SILC_COMMAND_INFO:
2026 SilcServerEntry server_entry;
2030 if (SILC_STATUS_IS_ERROR(status))
2033 server_entry = va_arg(vp, SilcServerEntry);
2034 server_name = va_arg(vp, char *);
2035 server_info = va_arg(vp, char *);
2037 if (server_name && server_info )
2039 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2040 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2045 case SILC_COMMAND_TOPIC:
2047 SilcChannelEntry channel;
2049 char tmp[256], *cp, *dm = NULL;
2051 if (SILC_STATUS_IS_ERROR(status))
2054 channel = va_arg(vp, SilcChannelEntry);
2055 topic = va_arg(vp, char *);
2057 if (topic && !silc_term_utf8() &&
2058 silc_utf8_valid(topic, strlen(topic))) {
2059 memset(tmp, 0, sizeof(tmp));
2061 if (strlen(topic) > sizeof(tmp) - 1) {
2062 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2066 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2072 chanrec = silc_channel_find_entry(server, channel);
2074 g_free_not_null(chanrec->topic);
2075 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2076 signal_emit("channel topic changed", 1, chanrec);
2078 printformat_module("fe-common/silc", server, channel->channel_name,
2079 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2080 channel->channel_name, topic);
2082 printformat_module("fe-common/silc", server, channel->channel_name,
2083 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2084 channel->channel_name);
2090 case SILC_COMMAND_WATCH:
2093 case SILC_COMMAND_STATS:
2095 SilcClientStats *cstats;
2097 const char *tmptime;
2098 int days, hours, mins, secs;
2100 if (SILC_STATUS_IS_ERROR(status))
2103 cstats = va_arg(vp, SilcClientStats *);
2105 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2109 tmptime = silc_time_string(cstats->starttime);
2110 printformat_module("fe-common/silc", server, NULL,
2111 MSGLEVEL_CRAP, SILCTXT_STATS,
2112 "Local server start time", tmptime);
2114 days = cstats->uptime / (24 * 60 * 60);
2115 cstats->uptime -= days * (24 * 60 * 60);
2116 hours = cstats->uptime / (60 * 60);
2117 cstats->uptime -= hours * (60 * 60);
2118 mins = cstats->uptime / 60;
2119 cstats->uptime -= mins * 60;
2120 secs = cstats->uptime;
2121 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2122 days, hours, mins, secs);
2123 printformat_module("fe-common/silc", server, NULL,
2124 MSGLEVEL_CRAP, SILCTXT_STATS,
2125 "Local server uptime", tmp);
2127 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2128 printformat_module("fe-common/silc", server, NULL,
2129 MSGLEVEL_CRAP, SILCTXT_STATS,
2130 "Local server clients", tmp);
2132 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2133 printformat_module("fe-common/silc", server, NULL,
2134 MSGLEVEL_CRAP, SILCTXT_STATS,
2135 "Local server channels", tmp);
2137 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2138 printformat_module("fe-common/silc", server, NULL,
2139 MSGLEVEL_CRAP, SILCTXT_STATS,
2140 "Local server operators", tmp);
2142 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2143 printformat_module("fe-common/silc", server, NULL,
2144 MSGLEVEL_CRAP, SILCTXT_STATS,
2145 "Local router operators", tmp);
2147 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2148 printformat_module("fe-common/silc", server, NULL,
2149 MSGLEVEL_CRAP, SILCTXT_STATS,
2150 "Local cell clients", tmp);
2152 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2153 printformat_module("fe-common/silc", server, NULL,
2154 MSGLEVEL_CRAP, SILCTXT_STATS,
2155 "Local cell channels", tmp);
2157 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2158 printformat_module("fe-common/silc", server, NULL,
2159 MSGLEVEL_CRAP, SILCTXT_STATS,
2160 "Local cell servers", tmp);
2162 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2163 printformat_module("fe-common/silc", server, NULL,
2164 MSGLEVEL_CRAP, SILCTXT_STATS,
2165 "Total clients", tmp);
2167 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2168 printformat_module("fe-common/silc", server, NULL,
2169 MSGLEVEL_CRAP, SILCTXT_STATS,
2170 "Total channels", tmp);
2172 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2173 printformat_module("fe-common/silc", server, NULL,
2174 MSGLEVEL_CRAP, SILCTXT_STATS,
2175 "Total servers", tmp);
2177 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2178 printformat_module("fe-common/silc", server, NULL,
2179 MSGLEVEL_CRAP, SILCTXT_STATS,
2180 "Total routers", tmp);
2182 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2183 printformat_module("fe-common/silc", server, NULL,
2184 MSGLEVEL_CRAP, SILCTXT_STATS,
2185 "Total server operators", tmp);
2187 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2188 printformat_module("fe-common/silc", server, NULL,
2189 MSGLEVEL_CRAP, SILCTXT_STATS,
2190 "Total router operators", tmp);
2194 case SILC_COMMAND_CMODE:
2196 SilcChannelEntry channel_entry;
2199 channel_entry = va_arg(vp, SilcChannelEntry);
2200 (void)va_arg(vp, SilcUInt32);
2201 (void)va_arg(vp, SilcPublicKey);
2202 chpks = va_arg(vp, SilcDList);
2204 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2205 !channel_entry || !channel_entry->channel_name)
2208 /* Print the channel public key list */
2210 silc_parse_channel_public_keys(server, channel_entry, chpks);
2212 printformat_module("fe-common/silc", server, NULL,
2213 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2214 channel_entry->channel_name);
2219 case SILC_COMMAND_LEAVE:
2221 if (SILC_STATUS_IS_ERROR(status))
2224 /* We might be cycling, so disable queueing again */
2225 silc_queue_disable(conn);
2229 case SILC_COMMAND_DETACH:
2231 /* Save the detachment data to file. */
2235 if (SILC_STATUS_IS_ERROR(status))
2238 detach = va_arg(vp, SilcBuffer);
2239 file = silc_get_session_filename(server);
2240 silc_file_writefile(file, silc_buffer_data(detach),
2241 silc_buffer_len(detach));
2246 case SILC_COMMAND_KILL:
2248 SilcClientEntry client_entry;
2250 if (SILC_STATUS_IS_ERROR(status)) {
2251 silc_say_error("KILL: %s", silc_get_status_message(status));
2255 client_entry = va_arg(vp, SilcClientEntry);
2256 if (!client_entry || !client_entry->nickname[0])
2259 /* Print this only if the killed client isn't joined on channels.
2260 If it is, we receive KILLED notify and we'll print this there. */
2261 if (!silc_hash_table_count(client_entry->channels))
2262 printformat_module("fe-common/silc", server, NULL,
2263 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2264 client_entry->nickname,
2265 conn->local_entry->nickname, "");
2272 SilcClientConnection conn;
2276 SilcPublicKey public_key;
2277 SilcVerifyPublicKey completion;
2281 static void verify_public_key_completion(const char *line, void *context)
2283 PublicKeyVerify verify = (PublicKeyVerify)context;
2285 if (line[0] == 'Y' || line[0] == 'y') {
2286 /* Call the completion */
2287 if (verify->completion)
2288 verify->completion(TRUE, verify->context);
2290 /* Save the key for future checking */
2291 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2292 SILC_PKCS_FILE_BASE64);
2294 /* Call the completion */
2295 if (verify->completion)
2296 verify->completion(FALSE, verify->context);
2298 printformat_module("fe-common/silc", NULL, NULL,
2299 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2300 verify->entity_name ? verify->entity_name :
2304 silc_free(verify->filename);
2305 silc_free(verify->entity);
2306 silc_free(verify->entity_name);
2310 /* Internal routine to verify public key. If the `completion' is provided
2311 it will be called to indicate whether public was verified or not. For
2312 server/router public key this will check for filename that includes the
2313 remote host's IP address and remote host's hostname. */
2316 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2318 SilcConnectionType conn_type,
2319 SilcPublicKey public_key,
2320 SilcVerifyPublicKey completion, void *context)
2322 PublicKeyVerify verify;
2323 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2324 char *fingerprint, *babbleprint, *format;
2325 SilcPublicKey local_pubkey;
2327 const char *hostname, *ip;
2332 char *entity = ((conn_type == SILC_CONN_SERVER ||
2333 conn_type == SILC_CONN_ROUTER) ?
2334 "server" : "client");
2337 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2338 printformat_module("fe-common/silc", NULL, NULL,
2339 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2340 entity, silc_pkcs_get_type(public_key));
2342 completion(FALSE, context);
2346 /* Encode public key */
2347 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2350 completion(FALSE, context);
2354 pw = getpwuid(getuid());
2357 completion(FALSE, context);
2362 memset(filename, 0, sizeof(filename));
2363 memset(filename2, 0, sizeof(filename2));
2364 memset(file, 0, sizeof(file));
2366 /* Get remote host information */
2367 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2368 NULL, &hostname, &ip, &port);
2370 if (conn_type == SILC_CONN_SERVER ||
2371 conn_type == SILC_CONN_ROUTER) {
2373 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2374 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2375 get_irssi_dir(), entity, file);
2377 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2379 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2380 get_irssi_dir(), entity, file);
2385 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2387 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2388 get_irssi_dir(), entity, file);
2393 /* Replace all whitespaces with `_'. */
2394 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2395 for (i = 0; i < strlen(fingerprint); i++)
2396 if (fingerprint[i] == ' ')
2397 fingerprint[i] = '_';
2399 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2400 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2401 get_irssi_dir(), entity, file);
2402 silc_free(fingerprint);
2407 /* Take fingerprint of the public key */
2408 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2409 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2411 verify = silc_calloc(1, sizeof(*verify));
2412 verify->client = client;
2413 verify->conn = conn;
2414 verify->filename = strdup(ipf);
2415 verify->entity = strdup(entity);
2416 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2417 (name ? strdup(name) : strdup(hostname))
2419 verify->public_key = public_key;
2420 verify->completion = completion;
2421 verify->context = context;
2423 /* Check whether this key already exists */
2424 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2425 /* Key does not exist, ask user to verify the key and save it */
2427 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2428 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2429 verify->entity_name : entity);
2430 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2431 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2432 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2433 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2434 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2435 SILCTXT_PUBKEY_ACCEPT);
2436 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2439 silc_free(fingerprint);
2440 silc_free(babbleprint);
2444 /* The key already exists, verify it. */
2445 unsigned char *encpk;
2446 SilcUInt32 encpk_len;
2448 /* Load the key file, try for both IP filename and hostname filename */
2449 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2450 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2451 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2452 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2453 verify->entity_name : entity);
2454 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2455 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2456 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2457 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2458 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2459 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2460 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2461 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2462 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2465 silc_free(fingerprint);
2466 silc_free(babbleprint);
2471 /* Encode the key data */
2472 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2474 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2475 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2476 verify->entity_name : entity);
2477 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2478 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2479 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2480 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2481 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2482 SILCTXT_PUBKEY_MALFORMED, entity);
2483 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2484 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2485 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2488 silc_free(fingerprint);
2489 silc_free(babbleprint);
2493 silc_pkcs_public_key_free(local_pubkey);
2495 /* Compare the keys */
2496 if (memcmp(encpk, pk, encpk_len)) {
2497 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2498 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2499 verify->entity_name : entity);
2500 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2501 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2502 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2503 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2504 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2505 SILCTXT_PUBKEY_NO_MATCH, entity);
2506 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2507 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2508 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2509 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2511 /* Ask user to verify the key and save it */
2512 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2513 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2514 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2517 silc_free(fingerprint);
2518 silc_free(babbleprint);
2524 /* Local copy matched */
2526 completion(TRUE, context);
2528 silc_free(fingerprint);
2529 silc_free(babbleprint);
2530 silc_free(verify->filename);
2531 silc_free(verify->entity);
2532 silc_free(verify->entity_name);
2538 /* Verifies received public key. The `conn_type' indicates which entity
2539 (server, client etc.) has sent the public key. If user decides to trust
2540 the key may be saved as trusted public key for later use. The
2541 `completion' must be called after the public key has been verified. */
2544 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2545 SilcConnectionType conn_type,
2546 SilcPublicKey public_key,
2547 SilcVerifyPublicKey completion, void *context)
2549 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2550 completion, context);
2553 /* Asks passphrase from user on the input line. */
2556 SilcAskPassphrase completion;
2560 void ask_passphrase_completion(const char *passphrase, void *context)
2562 AskPassphrase p = (AskPassphrase)context;
2563 if (passphrase && passphrase[0] == '\0')
2565 p->completion((unsigned char *)passphrase,
2566 passphrase ? strlen(passphrase) : 0, p->context);
2570 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2571 SilcAskPassphrase completion, void *context)
2573 AskPassphrase p = silc_calloc(1, sizeof(*p));
2574 p->completion = completion;
2575 p->context = context;
2577 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2578 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2582 SilcGetAuthMeth completion;
2586 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2587 SilcUInt32 passphrase_len,
2590 GetAuthMethod a = context;
2591 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2592 passphrase, passphrase_len, a->context);
2596 /* Find authentication data by hostname and port. The hostname may be IP
2599 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2600 char *hostname, SilcUInt16 port,
2601 SilcAuthMethod auth_meth,
2602 SilcGetAuthMeth completion, void *context)
2604 SERVER_SETUP_REC *setup;
2606 SILC_LOG_DEBUG(("Start"));
2608 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2609 /* Returning NULL will cause library to use our private key configured
2610 for this connection */
2611 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2615 /* Check whether we find the password for this server in our
2616 configuration. If it's set, always send it server. */
2617 setup = server_setup_find_port(hostname, port);
2618 if (setup && setup->password) {
2619 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2624 /* Didn't find password. If server wants it, ask it from user. */
2625 if (auth_meth == SILC_AUTH_PASSWORD) {
2627 a = silc_calloc(1, sizeof(*a));
2629 a->completion = completion;
2630 a->context = context;
2631 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2636 /* No authentication */
2637 completion(SILC_AUTH_NONE, NULL, 0, context);
2640 /* Asks whether the user would like to perform the key agreement protocol.
2641 This is called after we have received an key agreement packet or an
2642 reply to our key agreement packet. This returns TRUE if the user wants
2643 the library to perform the key agreement protocol and FALSE if it is not
2644 desired (application may start it later by calling the function
2645 silc_client_perform_key_agreement). */
2647 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2648 SilcClientEntry client_entry, const char *hostname,
2649 SilcUInt16 protocol, SilcUInt16 port)
2651 char portstr[12], protostr[5];
2653 SILC_LOG_DEBUG(("Start"));
2655 /* We will just display the info on the screen and return FALSE and user
2656 will have to start the key agreement with a command. */
2659 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2660 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2665 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2666 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2668 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2669 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2670 client_entry->nickname, hostname, portstr, protostr);
2673 /* Notifies application that file transfer protocol session is being
2674 requested by the remote client indicated by the `client_entry' from
2675 the `hostname' and `port'. The `session_id' is the file transfer
2676 session and it can be used to either accept or reject the file
2677 transfer request, by calling the silc_client_file_receive or
2678 silc_client_file_close, respectively. */
2680 void silc_ftp(SilcClient client, SilcClientConnection conn,
2681 SilcClientEntry client_entry, SilcUInt32 session_id,
2682 const char *hostname, SilcUInt16 port)
2684 SILC_SERVER_REC *server;
2686 FtpSession ftp = NULL;
2688 SILC_LOG_DEBUG(("Start"));
2690 server = conn->context;
2692 silc_dlist_start(server->ftp_sessions);
2693 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2694 if (ftp->client_entry == client_entry &&
2695 ftp->session_id == session_id) {
2696 server->current_session = ftp;
2700 if (ftp == SILC_LIST_END) {
2701 ftp = silc_calloc(1, sizeof(*ftp));
2702 ftp->client_entry = client_entry;
2703 ftp->session_id = session_id;
2706 silc_dlist_add(server->ftp_sessions, ftp);
2707 server->current_session = ftp;
2711 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2714 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2715 SILCTXT_FILE_REQUEST, client_entry->nickname);
2717 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2718 SILCTXT_FILE_REQUEST_HOST,
2719 client_entry->nickname, hostname, portstr);
2722 /* SILC client operations */
2723 SilcClientOperations ops = {
2725 silc_channel_message,
2726 silc_private_message,
2730 silc_get_auth_method,
2731 silc_verify_public_key,
2732 silc_ask_passphrase,