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[0] ? "" : buf);
771 /* If there are multiple same nicknames on channel now, tell it to user. */
772 if (client_entry != server->conn->local_entry) {
776 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
777 clients = silc_client_get_clients_local(client, conn, nick, TRUE);
778 if (!clients || silc_dlist_count(clients) < 2) {
780 silc_client_list_free(client, conn, clients);
783 silc_dlist_start(clients);
784 while ((client_entry2 = silc_dlist_get(clients)))
785 if (silc_client_on_channel(channel, client_entry2))
788 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
789 printformat_module("fe-common/silc", server, channel->channel_name,
790 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
792 printformat_module("fe-common/silc", server, channel->channel_name,
793 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
794 buf, client_entry->nickname);
796 silc_client_list_free(client, conn, clients);
801 case SILC_NOTIFY_TYPE_LEAVE:
806 SILC_LOG_DEBUG(("Notify: LEAVE"));
808 client_entry = va_arg(va, SilcClientEntry);
809 channel = va_arg(va, SilcChannelEntry);
811 memset(buf, 0, sizeof(buf));
812 if (client_entry->username)
813 snprintf(buf, sizeof(buf) - 1, "%s@%s",
814 client_entry->username, client_entry->hostname);
815 signal_emit("message part", 5, server, channel->channel_name,
816 client_entry->nickname, client_entry->username[0] ?
817 buf : "", client_entry->nickname);
819 chanrec = silc_channel_find_entry(server, channel);
820 if (chanrec != NULL) {
821 nickrec = silc_nicklist_find(chanrec, client_entry);
823 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
827 case SILC_NOTIFY_TYPE_SIGNOFF:
832 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
834 client_entry = va_arg(va, SilcClientEntry);
835 tmp = va_arg(va, char *);
837 silc_server_free_ftp(server, client_entry);
839 /* Print only if we have the nickname. If this cliente has just quit
840 when we were only resolving it, it is possible we don't have the
842 if (client_entry->nickname[0]) {
843 memset(buf, 0, sizeof(buf));
844 if (client_entry->username)
845 snprintf(buf, sizeof(buf) - 1, "%s@%s",
846 client_entry->username, client_entry->hostname);
847 signal_emit("message quit", 4, server, client_entry->nickname,
848 client_entry->username[0] ? buf : "",
852 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
853 for (list_tmp = list1; list_tmp != NULL; list_tmp =
854 list_tmp->next->next) {
855 CHANNEL_REC *channel = list_tmp->data;
856 NICK_REC *nickrec = list_tmp->next->data;
858 nicklist_remove(channel, nickrec);
862 case SILC_NOTIFY_TYPE_TOPIC_SET:
867 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
869 idtype = va_arg(va, int);
870 entry = va_arg(va, void *);
871 tmp = va_arg(va, char *);
872 channel = va_arg(va, SilcChannelEntry);
874 chanrec = silc_channel_find_entry(server, channel);
875 if (chanrec != NULL) {
876 char tmp2[256], *cp, *dm = NULL;
878 g_free_not_null(chanrec->topic);
879 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
880 memset(tmp2, 0, sizeof(tmp2));
882 if (strlen(tmp) > sizeof(tmp2) - 1) {
883 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
887 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
892 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
893 signal_emit("channel topic changed", 1, chanrec);
898 if (idtype == SILC_ID_CLIENT) {
899 client_entry = (SilcClientEntry)entry;
900 memset(buf, 0, sizeof(buf));
901 snprintf(buf, sizeof(buf) - 1, "%s@%s",
902 client_entry->username, client_entry->hostname);
903 signal_emit("message topic", 5, server, channel->channel_name,
904 tmp, client_entry->nickname, buf);
905 } else if (idtype == SILC_ID_SERVER) {
906 server_entry = (SilcServerEntry)entry;
907 signal_emit("message topic", 5, server, channel->channel_name,
908 tmp, server_entry->server_name,
909 server_entry->server_name);
910 } else if (idtype == SILC_ID_CHANNEL) {
911 channel = (SilcChannelEntry)entry;
912 signal_emit("message topic", 5, server, channel->channel_name,
913 tmp, channel->channel_name, channel->channel_name);
917 case SILC_NOTIFY_TYPE_NICK_CHANGE:
922 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
924 client_entry = va_arg(va, SilcClientEntry);
925 name = va_arg(va, char *); /* old nickname */
927 if (!strcmp(client_entry->nickname, name))
930 memset(buf, 0, sizeof(buf));
931 snprintf(buf, sizeof(buf) - 1, "%s@%s",
932 client_entry->username, client_entry->hostname);
933 nicklist_rename_unique(SERVER(server),
935 client_entry, client_entry->nickname);
936 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
939 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
941 * Changed channel mode.
944 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
946 idtype = va_arg(va, int);
947 entry = va_arg(va, void *);
948 mode = va_arg(va, SilcUInt32);
949 cipher = va_arg(va, char *); /* cipher */
950 hmac = va_arg(va, char *); /* hmac */
951 (void)va_arg(va, char *); /* passphrase */
952 (void)va_arg(va, SilcPublicKey); /* founder key */
953 chpks = va_arg(va, SilcDList); /* channel public keys */
954 channel = va_arg(va, SilcChannelEntry);
956 tmp = silc_client_chmode(mode, cipher ? cipher : "",
959 chanrec = silc_channel_find_entry(server, channel);
960 if (chanrec != NULL) {
961 g_free_not_null(chanrec->mode);
962 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
963 signal_emit("channel mode changed", 1, chanrec);
966 if (idtype == SILC_ID_CLIENT) {
967 client_entry = (SilcClientEntry)entry;
968 printformat_module("fe-common/silc", server, channel->channel_name,
969 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
970 channel->channel_name, tmp ? tmp : "removed all",
971 client_entry->nickname);
972 } else if (idtype == SILC_ID_SERVER) {
973 server_entry = (SilcServerEntry)entry;
974 printformat_module("fe-common/silc", server, channel->channel_name,
975 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
976 channel->channel_name, tmp ? tmp : "removed all",
977 server_entry->server_name);
978 } else if (idtype == SILC_ID_CHANNEL) {
979 channel2 = (SilcChannelEntry)entry;
980 printformat_module("fe-common/silc", server, channel->channel_name,
981 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
982 channel->channel_name, tmp ? tmp : "removed all",
983 channel2->channel_name);
986 /* Print the channel public key list */
988 silc_parse_channel_public_keys(server, channel, chpks);
993 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
995 * Changed user's mode on channel.
998 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1000 idtype = va_arg(va, int);
1001 entry = va_arg(va, void *);
1002 mode = va_arg(va, SilcUInt32);
1003 client_entry2 = va_arg(va, SilcClientEntry);
1004 channel = va_arg(va, SilcChannelEntry);
1006 tmp = silc_client_chumode(mode);
1007 chanrec = silc_channel_find_entry(server, channel);
1008 if (chanrec != NULL) {
1009 SILC_NICK_REC *nick;
1011 if (client_entry2 == server->conn->local_entry)
1012 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1014 nick = silc_nicklist_find(chanrec, client_entry2);
1016 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1017 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1018 signal_emit("nick mode changed", 2, chanrec, nick);
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_CUMODE,
1026 channel->channel_name, client_entry2->nickname,
1027 tmp ? tmp : "removed all",
1028 client_entry->nickname);
1029 } else if (idtype == SILC_ID_SERVER) {
1030 server_entry = (SilcServerEntry)entry;
1031 printformat_module("fe-common/silc", server, channel->channel_name,
1032 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1033 channel->channel_name, client_entry2->nickname,
1034 tmp ? tmp : "removed all",
1035 server_entry->server_name);
1036 } else if (idtype == SILC_ID_CHANNEL) {
1037 channel2 = (SilcChannelEntry)entry;
1038 printformat_module("fe-common/silc", server, channel->channel_name,
1039 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1040 channel->channel_name, client_entry2->nickname,
1041 tmp ? tmp : "removed all",
1042 channel2->channel_name);
1045 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1046 printformat_module("fe-common/silc",
1047 server, channel->channel_name, MSGLEVEL_CRAP,
1048 SILCTXT_CHANNEL_FOUNDER,
1049 channel->channel_name, client_entry2->nickname);
1051 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1052 printformat_module("fe-common/silc",
1053 server, channel->channel_name, MSGLEVEL_CRAP,
1054 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1059 case SILC_NOTIFY_TYPE_MOTD:
1064 SILC_LOG_DEBUG(("Notify: MOTD"));
1066 tmp = va_arg(va, char *);
1068 if (!settings_get_bool("skip_motd"))
1069 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1072 case SILC_NOTIFY_TYPE_KICKED:
1074 * Someone was kicked from channel.
1077 SILC_LOG_DEBUG(("Notify: KICKED"));
1079 client_entry = va_arg(va, SilcClientEntry);
1080 tmp = va_arg(va, char *);
1081 client_entry2 = va_arg(va, SilcClientEntry);
1082 channel = va_arg(va, SilcChannelEntry);
1084 chanrec = silc_channel_find_entry(server, channel);
1086 if (client_entry == conn->local_entry) {
1087 printformat_module("fe-common/silc", server, channel->channel_name,
1088 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1089 channel->channel_name,
1090 client_entry ? client_entry2->nickname : "",
1093 chanrec->kicked = TRUE;
1094 channel_destroy((CHANNEL_REC *)chanrec);
1097 printformat_module("fe-common/silc", server, channel->channel_name,
1098 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1099 client_entry->nickname, channel->channel_name,
1100 client_entry2 ? client_entry2->nickname : "",
1104 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1105 if (nickrec != NULL)
1106 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1111 case SILC_NOTIFY_TYPE_KILLED:
1113 * Someone was killed from the network.
1116 SILC_LOG_DEBUG(("Notify: KILLED"));
1118 client_entry = va_arg(va, SilcClientEntry);
1119 tmp = va_arg(va, char *);
1120 idtype = va_arg(va, int);
1121 entry = va_arg(va, SilcClientEntry);
1123 if (client_entry == conn->local_entry) {
1124 if (idtype == SILC_ID_CLIENT) {
1125 client_entry2 = (SilcClientEntry)entry;
1126 printformat_module("fe-common/silc", server, NULL,
1127 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1128 client_entry2 ? client_entry2->nickname : "",
1130 } else if (idtype == SILC_ID_SERVER) {
1131 server_entry = (SilcServerEntry)entry;
1132 printformat_module("fe-common/silc", server, NULL,
1133 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1134 server_entry->server_name, tmp ? tmp : "");
1135 } else if (idtype == SILC_ID_CHANNEL) {
1136 channel = (SilcChannelEntry)entry;
1137 printformat_module("fe-common/silc", server, NULL,
1138 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1139 channel->channel_name, tmp ? tmp : "");
1142 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1143 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1144 list_tmp->next->next) {
1145 CHANNEL_REC *channel = list_tmp->data;
1146 NICK_REC *nickrec = list_tmp->next->data;
1147 nicklist_remove(channel, nickrec);
1150 if (idtype == SILC_ID_CLIENT) {
1151 client_entry2 = (SilcClientEntry)entry;
1152 printformat_module("fe-common/silc", server, NULL,
1153 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1154 client_entry->nickname,
1155 client_entry2 ? client_entry2->nickname : "",
1157 } else if (idtype == SILC_ID_SERVER) {
1158 server_entry = (SilcServerEntry)entry;
1159 printformat_module("fe-common/silc", server, NULL,
1160 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1161 client_entry->nickname,
1162 server_entry->server_name, tmp ? tmp : "");
1163 } else if (idtype == SILC_ID_CHANNEL) {
1164 channel = (SilcChannelEntry)entry;
1165 printformat_module("fe-common/silc", server, NULL,
1166 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1167 client_entry->nickname,
1168 channel->channel_name, tmp ? tmp : "");
1173 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1176 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1179 * Server has quit the network.
1183 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1185 (void)va_arg(va, void *);
1186 clients = va_arg(va, SilcDList);
1188 silc_dlist_start(clients);
1189 while ((client_entry = silc_dlist_get(clients))) {
1190 memset(buf, 0, sizeof(buf));
1192 /* Print only if we have the nickname. If this client has just quit
1193 when we were only resolving it, it is possible we don't have the
1195 if (client_entry->nickname[0]) {
1196 if (client_entry->username[0])
1197 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1198 client_entry->username, client_entry->hostname);
1199 signal_emit("message quit", 4, server, client_entry->nickname,
1200 client_entry->username[0] ? buf : "",
1204 silc_server_free_ftp(server, client_entry);
1206 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1207 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1208 list_tmp->next->next) {
1209 CHANNEL_REC *channel = list_tmp->data;
1210 NICK_REC *nickrec = list_tmp->next->data;
1211 nicklist_remove(channel, nickrec);
1217 case SILC_NOTIFY_TYPE_ERROR:
1219 SilcStatus error = va_arg(va, int);
1221 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1222 "%s", silc_get_status_message(error));
1226 case SILC_NOTIFY_TYPE_WATCH:
1228 SilcNotifyType notify;
1230 client_entry = va_arg(va, SilcClientEntry);
1231 name = va_arg(va, char *); /* Maybe NULL */
1232 mode = va_arg(va, SilcUInt32);
1233 notify = va_arg(va, int);
1235 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1237 printformat_module("fe-common/silc", server, NULL,
1238 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1239 client_entry->nickname, name);
1241 printformat_module("fe-common/silc", server, NULL,
1242 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1243 client_entry->nickname);
1244 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1245 /* See if client was away and is now present */
1246 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1247 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1248 SILC_UMODE_DETACHED)) &&
1249 (client_entry->mode & SILC_UMODE_GONE ||
1250 client_entry->mode & SILC_UMODE_INDISPOSED ||
1251 client_entry->mode & SILC_UMODE_BUSY ||
1252 client_entry->mode & SILC_UMODE_PAGE ||
1253 client_entry->mode & SILC_UMODE_DETACHED)) {
1254 printformat_module("fe-common/silc", server, NULL,
1255 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1256 client_entry->nickname);
1260 memset(buf, 0, sizeof(buf));
1261 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1262 printformat_module("fe-common/silc", server, NULL,
1263 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1264 client_entry->nickname, buf);
1266 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1267 printformat_module("fe-common/silc", server, NULL,
1268 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1269 client_entry->nickname);
1270 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1271 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1272 printformat_module("fe-common/silc", server, NULL,
1273 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1274 client_entry->nickname);
1275 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1276 /* Client logged in to the network */
1277 printformat_module("fe-common/silc", server, NULL,
1278 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1279 client_entry->nickname);
1285 /* Unknown notify */
1286 printformat_module("fe-common/silc", server, NULL,
1287 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1294 /* Command handler. This function is called always in the command function.
1295 If error occurs it will be called as well. `conn' is the associated
1296 client connection. `cmd_context' is the command context that was
1297 originally sent to the command. `success' is FALSE if error occured
1298 during command. `command' is the command being processed. It must be
1299 noted that this is not reply from server. This is merely called just
1300 after application has called the command. Just to tell application
1301 that the command really was processed. */
1303 static SilcBool cmode_list_chpks = FALSE;
1305 void silc_command(SilcClient client, SilcClientConnection conn,
1306 SilcBool success, SilcCommand command, SilcStatus status,
1307 SilcUInt32 argc, unsigned char **argv)
1309 SILC_SERVER_REC *server = conn->context;
1311 SILC_LOG_DEBUG(("Start"));
1314 silc_say_error("%s", silc_get_status_message(status));
1320 case SILC_COMMAND_INVITE:
1322 printformat_module("fe-common/silc", server, NULL,
1323 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1325 (argv[1][0] == '*' ?
1326 (char *)conn->current_channel->channel_name :
1330 case SILC_COMMAND_DETACH:
1331 server->no_reconnect = TRUE;
1334 case SILC_COMMAND_CMODE:
1335 if (argc == 3 && !strcmp(argv[2], "+C"))
1336 cmode_list_chpks = TRUE;
1338 cmode_list_chpks = FALSE;
1348 SilcClientConnection conn;
1353 void silc_getkey_cb(bool success, void *context)
1355 GetkeyContext getkey = (GetkeyContext)context;
1356 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1357 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1358 ((SilcClientEntry)getkey->entry)->nickname :
1359 ((SilcServerEntry)getkey->entry)->server_name);
1362 printformat_module("fe-common/silc", NULL, NULL,
1363 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1365 printformat_module("fe-common/silc", NULL, NULL,
1366 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1373 /* Parse an invite or ban list */
1374 void silc_parse_inviteban_list(SilcClient client,
1375 SilcClientConnection conn,
1376 SILC_SERVER_REC *server,
1377 SilcChannelEntry channel,
1378 const char *list_type,
1379 SilcArgumentPayload list)
1382 SilcUInt32 type, len;
1383 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1384 int counter=0, resolving = FALSE;
1386 if (!silc_argument_get_arg_num(list)) {
1387 printformat_module("fe-common/silc", server,
1388 (chanrec ? chanrec->visible_name : NULL),
1389 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1390 channel->channel_name, list_type);
1394 printformat_module("fe-common/silc", server,
1395 (chanrec ? chanrec->visible_name : NULL),
1396 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1397 channel->channel_name, list_type);
1399 /* Parse the list */
1400 tmp = silc_argument_get_first_arg(list, &type, &len);
1405 /* An invite string */
1409 if (tmp[len-1] == ',')
1412 list = g_strsplit(tmp, ",", -1);
1414 printformat_module("fe-common/silc", server,
1415 (chanrec ? chanrec->visible_name : NULL),
1416 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1417 ++counter, channel->channel_name, list_type,
1426 char *fingerprint, *babbleprint;
1428 /* tmp is Public Key Payload, take public key from it. */
1429 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1430 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1432 printformat_module("fe-common/silc", server,
1433 (chanrec ? chanrec->visible_name : NULL),
1434 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1435 ++counter, channel->channel_name, list_type,
1436 fingerprint, babbleprint);
1443 SilcClientEntry client_entry;
1446 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1447 silc_say_error("Invalid data in %s list encountered", list_type);
1451 client_entry = silc_client_get_client_by_id(client, conn,
1454 printformat_module("fe-common/silc", server,
1455 (chanrec ? chanrec->visible_name : NULL),
1456 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1457 ++counter, channel->channel_name, list_type,
1458 client_entry->nickname);
1459 silc_client_unref_client(client, conn, client_entry);
1462 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1470 silc_say_error("Unkown type in %s list: %u (len %u)",
1471 list_type, type, len);
1474 tmp = silc_argument_get_next_arg(list, &type, &len);
1478 printformat_module("fe-common/silc", server,
1479 (chanrec ? chanrec->visible_name : NULL),
1480 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1481 list_type, channel->channel_name);
1484 /* Command reply handler. This function is called always in the command reply
1485 function. If error occurs it will be called as well. Normal scenario
1486 is that it will be called after the received command data has been parsed
1487 and processed. The function is used to pass the received command data to
1490 `conn' is the associated client connection. `cmd_payload' is the command
1491 payload data received from server and it can be ignored. It is provided
1492 if the application would like to re-parse the received command data,
1493 however, it must be noted that the data is parsed already by the library
1494 thus the payload can be ignored. `success' is FALSE if error occured.
1495 In this case arguments are not sent to the application. `command' is the
1496 command reply being processed. The function has variable argument list
1497 and each command defines the number and type of arguments it passes to the
1498 application (on error they are not sent). */
1500 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1501 SilcCommand command, SilcStatus status,
1502 SilcStatus error, va_list vp)
1504 SILC_SERVER_REC *server = conn->context;
1505 SILC_CHANNEL_REC *chanrec;
1507 SILC_LOG_DEBUG(("Start"));
1510 case SILC_COMMAND_WHOIS:
1512 char buf[1024], *nickname, *username, *realname, *nick;
1513 unsigned char *fingerprint;
1514 SilcUInt32 idle, mode, *user_modes;
1516 SilcClientEntry client_entry;
1519 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1520 /* Print the unknown nick for user */
1521 char *tmp = va_arg(vp, char *);
1523 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1525 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1526 /* Try to find the entry for the unknown client ID, since we
1527 might have, and print the nickname of it for user. */
1528 SilcClientID *id = va_arg(vp, SilcClientID *);
1530 client_entry = silc_client_get_client_by_id(client, conn, id);
1531 if (client_entry && client_entry->nickname[0])
1532 silc_say_error("%s: %s", client_entry->nickname,
1533 silc_get_status_message(status));
1534 silc_client_unref_client(client, conn, client_entry);
1537 } else if (SILC_STATUS_IS_ERROR(status)) {
1538 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1542 client_entry = va_arg(vp, SilcClientEntry);
1543 nickname = va_arg(vp, char *);
1544 username = va_arg(vp, char *);
1545 realname = va_arg(vp, char *);
1546 channels = va_arg(vp, SilcDList);
1547 mode = va_arg(vp, SilcUInt32);
1548 idle = va_arg(vp, SilcUInt32);
1549 fingerprint = va_arg(vp, unsigned char *);
1550 user_modes = va_arg(vp, SilcUInt32 *);
1551 attrs = va_arg(vp, SilcDList);
1553 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1554 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1555 SILCTXT_WHOIS_USERINFO, nickname,
1556 client_entry->username, client_entry->hostname,
1557 nick, client_entry->nickname);
1558 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1559 SILCTXT_WHOIS_REALNAME, realname);
1562 if (channels && user_modes) {
1563 SilcChannelPayload entry;
1566 memset(buf, 0, sizeof(buf));
1567 silc_dlist_start(channels);
1568 while ((entry = silc_dlist_get(channels))) {
1569 SilcUInt32 name_len;
1570 char *m = silc_client_chumode_char(user_modes[i++]);
1571 char *name = silc_channel_get_name(entry, &name_len);
1574 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1575 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1576 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1580 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1581 SILCTXT_WHOIS_CHANNELS, buf);
1585 memset(buf, 0, sizeof(buf));
1586 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1587 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1588 SILCTXT_WHOIS_MODES, buf);
1591 if (idle && nickname) {
1592 memset(buf, 0, sizeof(buf));
1593 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1594 idle > 60 ? (idle / 60) : idle,
1595 idle > 60 ? "minutes" : "seconds");
1597 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1598 SILCTXT_WHOIS_IDLE, buf);
1602 fingerprint = silc_fingerprint(fingerprint, 20);
1603 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1604 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1605 silc_free(fingerprint);
1609 silc_query_attributes_print(server, silc_client, conn, attrs,
1614 case SILC_COMMAND_WHOWAS:
1616 char *nickname, *username, *realname;
1618 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1619 char *tmp = va_arg(vp, char *);
1621 silc_say_error("%s: %s", tmp,
1622 silc_get_status_message(status));
1624 } else if (SILC_STATUS_IS_ERROR(status)) {
1625 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1629 (void)va_arg(vp, SilcClientEntry);
1630 nickname = va_arg(vp, char *);
1631 username = va_arg(vp, char *);
1632 realname = va_arg(vp, char *);
1634 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1635 SILCTXT_WHOWAS_USERINFO, nickname, username,
1636 realname ? realname : "");
1640 case SILC_COMMAND_INVITE:
1642 SilcChannelEntry channel;
1643 SilcArgumentPayload invite_list;
1645 if (SILC_STATUS_IS_ERROR(status))
1648 channel = va_arg(vp, SilcChannelEntry);
1649 invite_list = va_arg(vp, SilcArgumentPayload);
1652 silc_parse_inviteban_list(client, conn, server, channel,
1653 "invite", invite_list);
1657 case SILC_COMMAND_JOIN:
1659 char *channel, *mode, *topic, *cipher, *hmac;
1661 SilcHashTableList *user_list;
1662 SilcChannelEntry channel_entry;
1663 SilcChannelUser chu;
1664 SilcClientEntry founder = NULL;
1667 if (SILC_STATUS_IS_ERROR(status)) {
1668 silc_say_error("JOIN: %s", silc_get_status_message(status));
1672 channel = va_arg(vp, char *);
1673 channel_entry = va_arg(vp, SilcChannelEntry);
1674 modei = va_arg(vp, SilcUInt32);
1675 user_list = va_arg(vp, SilcHashTableList *);
1676 topic = va_arg(vp, char *);
1677 cipher = va_arg(vp, char *);
1678 hmac = va_arg(vp, char *);
1680 chanrec = silc_channel_find(server, channel);
1682 chanrec = silc_channel_create(server, channel, channel, TRUE);
1685 char tmp[256], *cp, *dm = NULL;
1686 g_free_not_null(chanrec->topic);
1688 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1689 memset(tmp, 0, sizeof(tmp));
1691 if (strlen(topic) > sizeof(tmp) - 1) {
1692 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1696 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1701 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1702 signal_emit("channel topic changed", 1, chanrec);
1707 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1708 g_free_not_null(chanrec->mode);
1709 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1710 signal_emit("channel mode changed", 1, chanrec);
1713 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1714 if (!chu->client->nickname[0])
1716 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1717 founder = chu->client;
1718 silc_nicklist_insert(chanrec, chu, FALSE);
1721 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1724 nicklist_set_own(CHANNEL(chanrec), ownnick);
1725 signal_emit("channel joined", 1, chanrec);
1726 chanrec->entry = channel_entry;
1729 printformat_module("fe-common/silc", server,
1730 channel_entry->channel_name,
1731 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1732 channel_entry->channel_name, chanrec->topic);
1735 if (founder == conn->local_entry) {
1736 printformat_module("fe-common/silc",
1737 server, channel_entry->channel_name,
1738 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1739 channel_entry->channel_name);
1740 signal_emit("nick mode changed", 2, chanrec, ownnick);
1742 printformat_module("fe-common/silc",
1743 server, channel_entry->channel_name,
1744 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1745 channel_entry->channel_name, founder->nickname);
1751 case SILC_COMMAND_NICK:
1754 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1757 if (SILC_STATUS_IS_ERROR(status)) {
1758 silc_say_error("NICK: %s", silc_get_status_message(status));
1762 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1763 if ((nicks != NULL) &&
1764 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1766 SilcClientEntry collider, old;
1768 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1769 collider = silc_client_get_client_by_id(client, conn, &old->id);
1770 if (collider != client_entry) {
1771 memset(buf, 0, sizeof(buf));
1772 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1773 collider->username, collider->hostname);
1774 nicklist_rename_unique(SERVER(server),
1776 collider, collider->nickname);
1777 silc_print_nick_change(server, collider->nickname,
1778 client_entry->nickname, buf);
1780 silc_client_unref_client(client, conn, collider);
1784 g_slist_free(nicks);
1786 old = g_strdup(server->nick);
1787 server_change_nick(SERVER(server), client_entry->nickname);
1788 nicklist_rename_unique(SERVER(server),
1789 server->conn->local_entry, server->nick,
1790 client_entry, client_entry->nickname);
1791 signal_emit("message own_nick", 4, server, server->nick, old, "");
1794 /* when connecting to a server, the last thing we receive
1795 is a SILC_COMMAND_LIST reply. Since we enable queueing
1796 during the connection, we can now safely disable it again */
1797 silc_queue_disable(conn);
1801 case SILC_COMMAND_LIST:
1806 char tmp[256], *cp, *dm = NULL;
1808 if (SILC_STATUS_IS_ERROR(status))
1811 (void)va_arg(vp, SilcChannelEntry);
1812 name = va_arg(vp, char *);
1813 topic = va_arg(vp, char *);
1814 usercount = va_arg(vp, int);
1816 if (topic && !silc_term_utf8() &&
1817 silc_utf8_valid(topic, strlen(topic))) {
1818 memset(tmp, 0, sizeof(tmp));
1820 if (strlen(topic) > sizeof(tmp) - 1) {
1821 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1825 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1830 if (status == SILC_STATUS_LIST_START ||
1831 status == SILC_STATUS_OK)
1832 printformat_module("fe-common/silc", server, NULL,
1833 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1836 snprintf(users, sizeof(users) - 1, "N/A");
1838 snprintf(users, sizeof(users) - 1, "%d", usercount);
1839 printformat_module("fe-common/silc", server, NULL,
1840 MSGLEVEL_CRAP, SILCTXT_LIST,
1841 name, users, topic ? topic : "");
1846 case SILC_COMMAND_UMODE:
1851 if (SILC_STATUS_IS_ERROR(status))
1854 mode = va_arg(vp, SilcUInt32);
1856 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1857 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1858 printformat_module("fe-common/silc", server, NULL,
1859 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1861 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1862 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1863 printformat_module("fe-common/silc", server, NULL,
1864 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1866 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1867 if (mode & SILC_UMODE_GONE) {
1868 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1869 reason = g_strdup(server->away_reason);
1871 reason = g_strdup("away");
1873 reason = g_strdup("");
1875 silc_set_away(reason, server);
1880 server->umode = mode;
1881 signal_emit("user mode changed", 2, server, NULL);
1885 case SILC_COMMAND_OPER:
1886 if (SILC_STATUS_IS_ERROR(status)) {
1887 silc_say_error("OPER: %s", silc_get_status_message(status));
1891 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1892 signal_emit("user mode changed", 2, server, NULL);
1894 printformat_module("fe-common/silc", server, NULL,
1895 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1898 case SILC_COMMAND_SILCOPER:
1899 if (SILC_STATUS_IS_ERROR(status)) {
1900 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1904 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1905 signal_emit("user mode changed", 2, server, NULL);
1907 printformat_module("fe-common/silc", server, NULL,
1908 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1911 case SILC_COMMAND_USERS:
1913 SilcHashTableList htl;
1914 SilcChannelEntry channel;
1915 SilcChannelUser chu;
1917 if (SILC_STATUS_IS_ERROR(status)) {
1918 silc_say_error("USERS: %s", silc_get_status_message(status));
1922 channel = va_arg(vp, SilcChannelEntry);
1924 printformat_module("fe-common/silc", server, channel->channel_name,
1925 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1926 channel->channel_name);
1928 silc_hash_table_list(channel->user_list, &htl);
1929 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1930 SilcClientEntry e = chu->client;
1931 char stat[5], *mode;
1933 if (!e->nickname[0])
1936 memset(stat, 0, sizeof(stat));
1937 mode = silc_client_chumode_char(chu->mode);
1938 if (e->mode & SILC_UMODE_GONE)
1940 else if (e->mode & SILC_UMODE_INDISPOSED)
1942 else if (e->mode & SILC_UMODE_BUSY)
1944 else if (e->mode & SILC_UMODE_PAGE)
1946 else if (e->mode & SILC_UMODE_HYPER)
1948 else if (e->mode & SILC_UMODE_ROBOT)
1950 else if (e->mode & SILC_UMODE_ANONYMOUS)
1957 printformat_module("fe-common/silc", server, channel->channel_name,
1958 MSGLEVEL_CRAP, SILCTXT_USERS,
1960 e->username[0] ? e->username : "",
1961 e->hostname[0] ? e->hostname : "",
1962 e->realname ? e->realname : "");
1966 silc_hash_table_list_reset(&htl);
1970 case SILC_COMMAND_BAN:
1972 SilcChannelEntry channel;
1973 SilcArgumentPayload invite_list;
1975 if (SILC_STATUS_IS_ERROR(status))
1978 channel = va_arg(vp, SilcChannelEntry);
1979 invite_list = va_arg(vp, SilcArgumentPayload);
1982 silc_parse_inviteban_list(client, conn, server, channel,
1983 "ban", invite_list);
1987 case SILC_COMMAND_GETKEY:
1991 SilcPublicKey public_key;
1992 GetkeyContext getkey;
1995 if (SILC_STATUS_IS_ERROR(status)) {
1996 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2000 id_type = va_arg(vp, SilcUInt32);
2001 entry = va_arg(vp, void *);
2002 public_key = va_arg(vp, SilcPublicKey);
2005 getkey = silc_calloc(1, sizeof(*getkey));
2006 getkey->entry = entry;
2007 getkey->id_type = id_type;
2008 getkey->client = client;
2009 getkey->conn = conn;
2011 name = (id_type == SILC_ID_CLIENT ?
2012 ((SilcClientEntry)entry)->nickname :
2013 ((SilcServerEntry)entry)->server_name);
2015 silc_verify_public_key_internal(client, conn, name,
2016 (id_type == SILC_ID_CLIENT ?
2019 public_key, silc_getkey_cb, getkey);
2021 printformat_module("fe-common/silc", server, NULL,
2022 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2027 case SILC_COMMAND_INFO:
2029 SilcServerEntry server_entry;
2033 if (SILC_STATUS_IS_ERROR(status))
2036 server_entry = va_arg(vp, SilcServerEntry);
2037 server_name = va_arg(vp, char *);
2038 server_info = va_arg(vp, char *);
2040 if (server_name && server_info )
2042 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2043 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2048 case SILC_COMMAND_TOPIC:
2050 SilcChannelEntry channel;
2052 char tmp[256], *cp, *dm = NULL;
2054 if (SILC_STATUS_IS_ERROR(status))
2057 channel = va_arg(vp, SilcChannelEntry);
2058 topic = va_arg(vp, char *);
2060 if (topic && !silc_term_utf8() &&
2061 silc_utf8_valid(topic, strlen(topic))) {
2062 memset(tmp, 0, sizeof(tmp));
2064 if (strlen(topic) > sizeof(tmp) - 1) {
2065 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2069 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2075 chanrec = silc_channel_find_entry(server, channel);
2077 g_free_not_null(chanrec->topic);
2078 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2079 signal_emit("channel topic changed", 1, chanrec);
2081 printformat_module("fe-common/silc", server, channel->channel_name,
2082 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2083 channel->channel_name, topic);
2085 printformat_module("fe-common/silc", server, channel->channel_name,
2086 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2087 channel->channel_name);
2093 case SILC_COMMAND_WATCH:
2096 case SILC_COMMAND_STATS:
2098 SilcClientStats *cstats;
2100 const char *tmptime;
2101 int days, hours, mins, secs;
2103 if (SILC_STATUS_IS_ERROR(status))
2106 cstats = va_arg(vp, SilcClientStats *);
2108 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2112 tmptime = silc_time_string(cstats->starttime);
2113 printformat_module("fe-common/silc", server, NULL,
2114 MSGLEVEL_CRAP, SILCTXT_STATS,
2115 "Local server start time", tmptime);
2117 days = cstats->uptime / (24 * 60 * 60);
2118 cstats->uptime -= days * (24 * 60 * 60);
2119 hours = cstats->uptime / (60 * 60);
2120 cstats->uptime -= hours * (60 * 60);
2121 mins = cstats->uptime / 60;
2122 cstats->uptime -= mins * 60;
2123 secs = cstats->uptime;
2124 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2125 days, hours, mins, secs);
2126 printformat_module("fe-common/silc", server, NULL,
2127 MSGLEVEL_CRAP, SILCTXT_STATS,
2128 "Local server uptime", tmp);
2130 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2131 printformat_module("fe-common/silc", server, NULL,
2132 MSGLEVEL_CRAP, SILCTXT_STATS,
2133 "Local server clients", tmp);
2135 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2136 printformat_module("fe-common/silc", server, NULL,
2137 MSGLEVEL_CRAP, SILCTXT_STATS,
2138 "Local server channels", tmp);
2140 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2141 printformat_module("fe-common/silc", server, NULL,
2142 MSGLEVEL_CRAP, SILCTXT_STATS,
2143 "Local server operators", tmp);
2145 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2146 printformat_module("fe-common/silc", server, NULL,
2147 MSGLEVEL_CRAP, SILCTXT_STATS,
2148 "Local router operators", tmp);
2150 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2151 printformat_module("fe-common/silc", server, NULL,
2152 MSGLEVEL_CRAP, SILCTXT_STATS,
2153 "Local cell clients", tmp);
2155 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2156 printformat_module("fe-common/silc", server, NULL,
2157 MSGLEVEL_CRAP, SILCTXT_STATS,
2158 "Local cell channels", tmp);
2160 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2161 printformat_module("fe-common/silc", server, NULL,
2162 MSGLEVEL_CRAP, SILCTXT_STATS,
2163 "Local cell servers", tmp);
2165 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2166 printformat_module("fe-common/silc", server, NULL,
2167 MSGLEVEL_CRAP, SILCTXT_STATS,
2168 "Total clients", tmp);
2170 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2171 printformat_module("fe-common/silc", server, NULL,
2172 MSGLEVEL_CRAP, SILCTXT_STATS,
2173 "Total channels", tmp);
2175 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2176 printformat_module("fe-common/silc", server, NULL,
2177 MSGLEVEL_CRAP, SILCTXT_STATS,
2178 "Total servers", tmp);
2180 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2181 printformat_module("fe-common/silc", server, NULL,
2182 MSGLEVEL_CRAP, SILCTXT_STATS,
2183 "Total routers", tmp);
2185 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2186 printformat_module("fe-common/silc", server, NULL,
2187 MSGLEVEL_CRAP, SILCTXT_STATS,
2188 "Total server operators", tmp);
2190 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2191 printformat_module("fe-common/silc", server, NULL,
2192 MSGLEVEL_CRAP, SILCTXT_STATS,
2193 "Total router operators", tmp);
2197 case SILC_COMMAND_CMODE:
2199 SilcChannelEntry channel_entry;
2202 channel_entry = va_arg(vp, SilcChannelEntry);
2203 (void)va_arg(vp, SilcUInt32);
2204 (void)va_arg(vp, SilcPublicKey);
2205 chpks = va_arg(vp, SilcDList);
2207 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2208 !channel_entry || !channel_entry->channel_name)
2211 /* Print the channel public key list */
2213 silc_parse_channel_public_keys(server, channel_entry, chpks);
2215 printformat_module("fe-common/silc", server, NULL,
2216 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2217 channel_entry->channel_name);
2222 case SILC_COMMAND_LEAVE:
2224 if (SILC_STATUS_IS_ERROR(status))
2227 /* We might be cycling, so disable queueing again */
2228 silc_queue_disable(conn);
2232 case SILC_COMMAND_DETACH:
2234 /* Save the detachment data to file. */
2238 if (SILC_STATUS_IS_ERROR(status))
2241 detach = va_arg(vp, SilcBuffer);
2242 file = silc_get_session_filename(server);
2243 silc_file_writefile(file, silc_buffer_data(detach),
2244 silc_buffer_len(detach));
2249 case SILC_COMMAND_KILL:
2251 SilcClientEntry client_entry;
2253 if (SILC_STATUS_IS_ERROR(status)) {
2254 silc_say_error("KILL: %s", silc_get_status_message(status));
2258 client_entry = va_arg(vp, SilcClientEntry);
2259 if (!client_entry || !client_entry->nickname[0])
2262 /* Print this only if the killed client isn't joined on channels.
2263 If it is, we receive KILLED notify and we'll print this there. */
2264 if (!silc_hash_table_count(client_entry->channels))
2265 printformat_module("fe-common/silc", server, NULL,
2266 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2267 client_entry->nickname,
2268 conn->local_entry->nickname, "");
2275 SilcClientConnection conn;
2279 SilcPublicKey public_key;
2280 SilcVerifyPublicKey completion;
2284 static void verify_public_key_completion(const char *line, void *context)
2286 PublicKeyVerify verify = (PublicKeyVerify)context;
2288 if (line[0] == 'Y' || line[0] == 'y') {
2289 /* Call the completion */
2290 if (verify->completion)
2291 verify->completion(TRUE, verify->context);
2293 /* Save the key for future checking */
2294 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2295 SILC_PKCS_FILE_BASE64);
2297 /* Call the completion */
2298 if (verify->completion)
2299 verify->completion(FALSE, verify->context);
2301 printformat_module("fe-common/silc", NULL, NULL,
2302 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2303 verify->entity_name ? verify->entity_name :
2307 silc_free(verify->filename);
2308 silc_free(verify->entity);
2309 silc_free(verify->entity_name);
2313 /* Internal routine to verify public key. If the `completion' is provided
2314 it will be called to indicate whether public was verified or not. For
2315 server/router public key this will check for filename that includes the
2316 remote host's IP address and remote host's hostname. */
2319 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2321 SilcConnectionType conn_type,
2322 SilcPublicKey public_key,
2323 SilcVerifyPublicKey completion, void *context)
2325 PublicKeyVerify verify;
2326 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2327 char *fingerprint, *babbleprint, *format;
2328 SilcPublicKey local_pubkey;
2330 const char *hostname, *ip;
2335 char *entity = ((conn_type == SILC_CONN_SERVER ||
2336 conn_type == SILC_CONN_ROUTER) ?
2337 "server" : "client");
2340 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2341 printformat_module("fe-common/silc", NULL, NULL,
2342 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2343 entity, silc_pkcs_get_type(public_key));
2345 completion(FALSE, context);
2349 /* Encode public key */
2350 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2353 completion(FALSE, context);
2357 pw = getpwuid(getuid());
2360 completion(FALSE, context);
2365 memset(filename, 0, sizeof(filename));
2366 memset(filename2, 0, sizeof(filename2));
2367 memset(file, 0, sizeof(file));
2369 /* Get remote host information */
2370 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2371 NULL, &hostname, &ip, &port);
2373 if (conn_type == SILC_CONN_SERVER ||
2374 conn_type == SILC_CONN_ROUTER) {
2376 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2377 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2378 get_irssi_dir(), entity, file);
2380 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2382 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2383 get_irssi_dir(), entity, file);
2388 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2390 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2391 get_irssi_dir(), entity, file);
2396 /* Replace all whitespaces with `_'. */
2397 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2398 for (i = 0; i < strlen(fingerprint); i++)
2399 if (fingerprint[i] == ' ')
2400 fingerprint[i] = '_';
2402 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2403 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2404 get_irssi_dir(), entity, file);
2405 silc_free(fingerprint);
2410 /* Take fingerprint of the public key */
2411 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2412 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2414 verify = silc_calloc(1, sizeof(*verify));
2415 verify->client = client;
2416 verify->conn = conn;
2417 verify->filename = strdup(ipf);
2418 verify->entity = strdup(entity);
2419 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2420 (name ? strdup(name) : strdup(hostname))
2422 verify->public_key = public_key;
2423 verify->completion = completion;
2424 verify->context = context;
2426 /* Check whether this key already exists */
2427 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2428 /* Key does not exist, ask user to verify the key and save it */
2430 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2431 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2432 verify->entity_name : entity);
2433 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2434 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2435 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2436 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2437 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2438 SILCTXT_PUBKEY_ACCEPT);
2439 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2442 silc_free(fingerprint);
2443 silc_free(babbleprint);
2447 /* The key already exists, verify it. */
2448 unsigned char *encpk;
2449 SilcUInt32 encpk_len;
2451 /* Load the key file, try for both IP filename and hostname filename */
2452 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2453 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2454 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2455 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2456 verify->entity_name : entity);
2457 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2458 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2459 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2460 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2461 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2462 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2463 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2464 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2465 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2468 silc_free(fingerprint);
2469 silc_free(babbleprint);
2474 /* Encode the key data */
2475 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2477 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2478 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2479 verify->entity_name : entity);
2480 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2481 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2482 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2483 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2484 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2485 SILCTXT_PUBKEY_MALFORMED, entity);
2486 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2487 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2488 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2491 silc_free(fingerprint);
2492 silc_free(babbleprint);
2496 silc_pkcs_public_key_free(local_pubkey);
2498 /* Compare the keys */
2499 if (memcmp(encpk, pk, encpk_len)) {
2500 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2501 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2502 verify->entity_name : entity);
2503 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2504 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2505 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2506 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2507 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2508 SILCTXT_PUBKEY_NO_MATCH, entity);
2509 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2510 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2511 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2512 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2514 /* Ask user to verify the key and save it */
2515 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2516 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2517 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2520 silc_free(fingerprint);
2521 silc_free(babbleprint);
2527 /* Local copy matched */
2529 completion(TRUE, context);
2531 silc_free(fingerprint);
2532 silc_free(babbleprint);
2533 silc_free(verify->filename);
2534 silc_free(verify->entity);
2535 silc_free(verify->entity_name);
2541 /* Verifies received public key. The `conn_type' indicates which entity
2542 (server, client etc.) has sent the public key. If user decides to trust
2543 the key may be saved as trusted public key for later use. The
2544 `completion' must be called after the public key has been verified. */
2547 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2548 SilcConnectionType conn_type,
2549 SilcPublicKey public_key,
2550 SilcVerifyPublicKey completion, void *context)
2552 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2553 completion, context);
2556 /* Asks passphrase from user on the input line. */
2559 SilcAskPassphrase completion;
2563 void ask_passphrase_completion(const char *passphrase, void *context)
2565 AskPassphrase p = (AskPassphrase)context;
2566 if (passphrase && passphrase[0] == '\0')
2568 p->completion((unsigned char *)passphrase,
2569 passphrase ? strlen(passphrase) : 0, p->context);
2573 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2574 SilcAskPassphrase completion, void *context)
2576 AskPassphrase p = silc_calloc(1, sizeof(*p));
2577 p->completion = completion;
2578 p->context = context;
2580 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2581 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2585 SilcGetAuthMeth completion;
2589 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2590 SilcUInt32 passphrase_len,
2593 GetAuthMethod a = context;
2594 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2595 passphrase, passphrase_len, a->context);
2599 /* Find authentication data by hostname and port. The hostname may be IP
2602 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2603 char *hostname, SilcUInt16 port,
2604 SilcAuthMethod auth_meth,
2605 SilcGetAuthMeth completion, void *context)
2607 SERVER_SETUP_REC *setup;
2609 SILC_LOG_DEBUG(("Start"));
2611 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2612 /* Returning NULL will cause library to use our private key configured
2613 for this connection */
2614 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2618 /* Check whether we find the password for this server in our
2619 configuration. If it's set, always send it server. */
2620 setup = server_setup_find_port(hostname, port);
2621 if (setup && setup->password) {
2622 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2627 /* Didn't find password. If server wants it, ask it from user. */
2628 if (auth_meth == SILC_AUTH_PASSWORD) {
2630 a = silc_calloc(1, sizeof(*a));
2632 a->completion = completion;
2633 a->context = context;
2634 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2639 /* No authentication */
2640 completion(SILC_AUTH_NONE, NULL, 0, context);
2643 /* Asks whether the user would like to perform the key agreement protocol.
2644 This is called after we have received an key agreement packet or an
2645 reply to our key agreement packet. This returns TRUE if the user wants
2646 the library to perform the key agreement protocol and FALSE if it is not
2647 desired (application may start it later by calling the function
2648 silc_client_perform_key_agreement). */
2650 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2651 SilcClientEntry client_entry, const char *hostname,
2652 SilcUInt16 protocol, SilcUInt16 port)
2654 char portstr[12], protostr[5];
2656 SILC_LOG_DEBUG(("Start"));
2658 /* We will just display the info on the screen and return FALSE and user
2659 will have to start the key agreement with a command. */
2662 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2663 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2668 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2669 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2671 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2672 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2673 client_entry->nickname, hostname, portstr, protostr);
2676 /* Notifies application that file transfer protocol session is being
2677 requested by the remote client indicated by the `client_entry' from
2678 the `hostname' and `port'. The `session_id' is the file transfer
2679 session and it can be used to either accept or reject the file
2680 transfer request, by calling the silc_client_file_receive or
2681 silc_client_file_close, respectively. */
2683 void silc_ftp(SilcClient client, SilcClientConnection conn,
2684 SilcClientEntry client_entry, SilcUInt32 session_id,
2685 const char *hostname, SilcUInt16 port)
2687 SILC_SERVER_REC *server;
2689 FtpSession ftp = NULL;
2691 SILC_LOG_DEBUG(("Start"));
2693 server = conn->context;
2695 silc_dlist_start(server->ftp_sessions);
2696 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2697 if (ftp->client_entry == client_entry &&
2698 ftp->session_id == session_id) {
2699 server->current_session = ftp;
2703 if (ftp == SILC_LIST_END) {
2704 ftp = silc_calloc(1, sizeof(*ftp));
2705 ftp->client_entry = client_entry;
2706 ftp->session_id = session_id;
2709 silc_dlist_add(server->ftp_sessions, ftp);
2710 server->current_session = ftp;
2714 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2717 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2718 SILCTXT_FILE_REQUEST, client_entry->nickname);
2720 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2721 SILCTXT_FILE_REQUEST_HOST,
2722 client_entry->nickname, hostname, portstr);
2725 /* SILC client operations */
2726 SilcClientOperations ops = {
2728 silc_channel_message,
2729 silc_private_message,
2733 silc_get_auth_method,
2734 silc_verify_public_key,
2735 silc_ask_passphrase,