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)
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,
572 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
574 message, message_len,
575 sender->nickname ? 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 ? sender->nickname : "[<unknown>]",
597 sender->username ? userhost : NULL,
600 signal_emit("message silc private_action", 5, server, cp,
601 sender->nickname ? sender->nickname : "[<unknown>]",
602 sender->username ? userhost : NULL, NULL);
605 if (flags & SILC_MESSAGE_FLAG_SIGNED)
606 signal_emit("message silc signed_private_action", 6, server, message,
607 sender->nickname ? sender->nickname : "[<unknown>]",
608 sender->username ? userhost : NULL,
611 signal_emit("message silc private_action", 5, server, message,
612 sender->nickname ? sender->nickname : "[<unknown>]",
613 sender->username ? 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 ? sender->nickname : "[<unknown>]",
629 sender->username ? userhost : NULL,
632 signal_emit("message silc private_notice", 5, server, cp,
633 sender->nickname ? sender->nickname : "[<unknown>]",
634 sender->username ? userhost : NULL, NULL);
637 if (flags & SILC_MESSAGE_FLAG_SIGNED)
638 signal_emit("message silc signed_private_notice", 6, server, message,
639 sender->nickname ? sender->nickname : "[<unknown>]",
640 sender->username ? userhost : NULL,
643 signal_emit("message silc private_notice", 5, server, message,
644 sender->nickname ? sender->nickname : "[<unknown>]",
645 sender->username ? 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 ? sender->nickname : "[<unknown>]",
663 sender->username ? userhost : NULL, verified);
665 signal_emit("message private", 4, server, cp,
666 sender->nickname ? sender->nickname : "[<unknown>]",
667 sender->username ? userhost : NULL);
672 if (flags & SILC_MESSAGE_FLAG_SIGNED)
673 signal_emit("message signed_private", 5, server, message,
674 sender->nickname ? sender->nickname : "[<unknown>]",
675 sender->username ? userhost : NULL, verified);
677 signal_emit("message private", 4, server, message,
678 sender->nickname ? sender->nickname : "[<unknown>]",
679 sender->username ? 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;
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)
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);
772 case SILC_NOTIFY_TYPE_LEAVE:
777 SILC_LOG_DEBUG(("Notify: LEAVE"));
779 client_entry = va_arg(va, SilcClientEntry);
780 channel = va_arg(va, SilcChannelEntry);
782 memset(buf, 0, sizeof(buf));
783 if (client_entry->username)
784 snprintf(buf, sizeof(buf) - 1, "%s@%s",
785 client_entry->username, client_entry->hostname);
786 signal_emit("message part", 5, server, channel->channel_name,
787 client_entry->nickname, client_entry->username ?
788 buf : "", client_entry->nickname);
790 chanrec = silc_channel_find_entry(server, channel);
791 if (chanrec != NULL) {
792 nickrec = silc_nicklist_find(chanrec, client_entry);
794 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
798 case SILC_NOTIFY_TYPE_SIGNOFF:
803 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
805 client_entry = va_arg(va, SilcClientEntry);
806 tmp = va_arg(va, char *);
809 silc_server_free_ftp(server, client_entry);
812 /* Print only if we have the nickname. If this cliente has just quit
813 when we were only resolving it, it is possible we don't have the
815 if (client_entry->nickname) {
816 memset(buf, 0, sizeof(buf));
817 if (client_entry->username)
818 snprintf(buf, sizeof(buf) - 1, "%s@%s",
819 client_entry->username, client_entry->hostname);
820 signal_emit("message quit", 4, server, client_entry->nickname,
821 client_entry->username ? buf : "",
825 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
826 for (list_tmp = list1; list_tmp != NULL; list_tmp =
827 list_tmp->next->next) {
828 CHANNEL_REC *channel = list_tmp->data;
829 NICK_REC *nickrec = list_tmp->next->data;
831 nicklist_remove(channel, nickrec);
835 case SILC_NOTIFY_TYPE_TOPIC_SET:
840 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
842 idtype = va_arg(va, int);
843 entry = va_arg(va, void *);
844 tmp = va_arg(va, char *);
845 channel = va_arg(va, SilcChannelEntry);
847 chanrec = silc_channel_find_entry(server, channel);
848 if (chanrec != NULL) {
849 char tmp2[256], *cp, *dm = NULL;
851 g_free_not_null(chanrec->topic);
852 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
853 memset(tmp2, 0, sizeof(tmp2));
855 if (strlen(tmp) > sizeof(tmp2) - 1) {
856 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
860 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
865 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
866 signal_emit("channel topic changed", 1, chanrec);
871 if (idtype == SILC_ID_CLIENT) {
872 client_entry = (SilcClientEntry)entry;
873 memset(buf, 0, sizeof(buf));
874 snprintf(buf, sizeof(buf) - 1, "%s@%s",
875 client_entry->username, client_entry->hostname);
876 signal_emit("message topic", 5, server, channel->channel_name,
877 tmp, client_entry->nickname, buf);
878 } else if (idtype == SILC_ID_SERVER) {
879 server_entry = (SilcServerEntry)entry;
880 signal_emit("message topic", 5, server, channel->channel_name,
881 tmp, server_entry->server_name,
882 server_entry->server_name);
883 } else if (idtype == SILC_ID_CHANNEL) {
884 channel = (SilcChannelEntry)entry;
885 signal_emit("message topic", 5, server, channel->channel_name,
886 tmp, channel->channel_name, channel->channel_name);
890 case SILC_NOTIFY_TYPE_NICK_CHANGE:
895 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
897 client_entry = va_arg(va, SilcClientEntry);
898 client_entry2 = va_arg(va, SilcClientEntry);
900 if (!strcmp(client_entry->nickname, client_entry2->nickname))
903 memset(buf, 0, sizeof(buf));
904 snprintf(buf, sizeof(buf) - 1, "%s@%s",
905 client_entry2->username, client_entry2->hostname);
906 nicklist_rename_unique(SERVER(server),
907 client_entry, client_entry->nickname,
908 client_entry2, client_entry2->nickname);
909 signal_emit("message nick", 4, server, client_entry2->nickname,
910 client_entry->nickname, buf);
913 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
915 * Changed channel mode.
918 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
920 idtype = va_arg(va, int);
921 entry = va_arg(va, void *);
922 mode = va_arg(va, SilcUInt32);
923 cipher = va_arg(va, char *); /* cipher */
924 hmac = va_arg(va, char *); /* hmac */
925 (void)va_arg(va, char *); /* passphrase */
926 (void)va_arg(va, SilcPublicKey); /* founder key */
927 chpks = va_arg(va, SilcDList); /* channel public keys */
928 channel = va_arg(va, SilcChannelEntry);
930 tmp = silc_client_chmode(mode, cipher ? cipher : "",
933 chanrec = silc_channel_find_entry(server, channel);
934 if (chanrec != NULL) {
935 g_free_not_null(chanrec->mode);
936 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
937 signal_emit("channel mode changed", 1, chanrec);
940 if (idtype == SILC_ID_CLIENT) {
941 client_entry = (SilcClientEntry)entry;
942 printformat_module("fe-common/silc", server, channel->channel_name,
943 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
944 channel->channel_name, tmp ? tmp : "removed all",
945 client_entry->nickname);
946 } else if (idtype == SILC_ID_SERVER) {
947 server_entry = (SilcServerEntry)entry;
948 printformat_module("fe-common/silc", server, channel->channel_name,
949 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
950 channel->channel_name, tmp ? tmp : "removed all",
951 server_entry->server_name);
952 } else if (idtype == SILC_ID_CHANNEL) {
953 channel2 = (SilcChannelEntry)entry;
954 printformat_module("fe-common/silc", server, channel->channel_name,
955 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
956 channel->channel_name, tmp ? tmp : "removed all",
957 channel2->channel_name);
960 /* Print the channel public key list */
962 silc_parse_channel_public_keys(server, channel, chpks);
967 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
969 * Changed user's mode on channel.
972 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
974 idtype = va_arg(va, int);
975 entry = va_arg(va, void *);
976 mode = va_arg(va, SilcUInt32);
977 client_entry2 = va_arg(va, SilcClientEntry);
978 channel = va_arg(va, SilcChannelEntry);
980 tmp = silc_client_chumode(mode);
981 chanrec = silc_channel_find_entry(server, channel);
982 if (chanrec != NULL) {
985 if (client_entry2 == server->conn->local_entry)
986 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
988 nick = silc_nicklist_find(chanrec, client_entry2);
990 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
991 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
992 signal_emit("nick mode changed", 2, chanrec, nick);
996 if (idtype == SILC_ID_CLIENT) {
997 client_entry = (SilcClientEntry)entry;
998 printformat_module("fe-common/silc", server, channel->channel_name,
999 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1000 channel->channel_name, client_entry2->nickname,
1001 tmp ? tmp : "removed all",
1002 client_entry->nickname);
1003 } else if (idtype == SILC_ID_SERVER) {
1004 server_entry = (SilcServerEntry)entry;
1005 printformat_module("fe-common/silc", server, channel->channel_name,
1006 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1007 channel->channel_name, client_entry2->nickname,
1008 tmp ? tmp : "removed all",
1009 server_entry->server_name);
1010 } else if (idtype == SILC_ID_CHANNEL) {
1011 channel2 = (SilcChannelEntry)entry;
1012 printformat_module("fe-common/silc", server, channel->channel_name,
1013 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1014 channel->channel_name, client_entry2->nickname,
1015 tmp ? tmp : "removed all",
1016 channel2->channel_name);
1019 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1020 printformat_module("fe-common/silc",
1021 server, channel->channel_name, MSGLEVEL_CRAP,
1022 SILCTXT_CHANNEL_FOUNDER,
1023 channel->channel_name, client_entry2->nickname);
1025 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1026 printformat_module("fe-common/silc",
1027 server, channel->channel_name, MSGLEVEL_CRAP,
1028 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1033 case SILC_NOTIFY_TYPE_MOTD:
1038 SILC_LOG_DEBUG(("Notify: MOTD"));
1040 tmp = va_arg(va, char *);
1042 if (!settings_get_bool("skip_motd"))
1043 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1046 case SILC_NOTIFY_TYPE_KICKED:
1048 * Someone was kicked from channel.
1051 SILC_LOG_DEBUG(("Notify: KICKED"));
1053 client_entry = va_arg(va, SilcClientEntry);
1054 tmp = va_arg(va, char *);
1055 client_entry2 = va_arg(va, SilcClientEntry);
1056 channel = va_arg(va, SilcChannelEntry);
1058 chanrec = silc_channel_find_entry(server, channel);
1060 if (client_entry == conn->local_entry) {
1061 printformat_module("fe-common/silc", server, channel->channel_name,
1062 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1063 channel->channel_name,
1064 client_entry ? client_entry2->nickname : "",
1067 chanrec->kicked = TRUE;
1068 channel_destroy((CHANNEL_REC *)chanrec);
1071 printformat_module("fe-common/silc", server, channel->channel_name,
1072 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1073 client_entry->nickname, channel->channel_name,
1074 client_entry2 ? client_entry2->nickname : "",
1078 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1079 if (nickrec != NULL)
1080 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1085 case SILC_NOTIFY_TYPE_KILLED:
1087 * Someone was killed from the network.
1090 SILC_LOG_DEBUG(("Notify: KILLED"));
1092 client_entry = va_arg(va, SilcClientEntry);
1093 tmp = va_arg(va, char *);
1094 idtype = va_arg(va, int);
1095 entry = va_arg(va, SilcClientEntry);
1097 if (client_entry == conn->local_entry) {
1098 if (idtype == SILC_ID_CLIENT) {
1099 client_entry2 = (SilcClientEntry)entry;
1100 printformat_module("fe-common/silc", server, NULL,
1101 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1102 client_entry2 ? client_entry2->nickname : "",
1104 } else if (idtype == SILC_ID_SERVER) {
1105 server_entry = (SilcServerEntry)entry;
1106 printformat_module("fe-common/silc", server, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1108 server_entry->server_name, tmp ? tmp : "");
1109 } else if (idtype == SILC_ID_CHANNEL) {
1110 channel = (SilcChannelEntry)entry;
1111 printformat_module("fe-common/silc", server, NULL,
1112 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1113 channel->channel_name, tmp ? tmp : "");
1116 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1117 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1118 list_tmp->next->next) {
1119 CHANNEL_REC *channel = list_tmp->data;
1120 NICK_REC *nickrec = list_tmp->next->data;
1121 nicklist_remove(channel, nickrec);
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,
1128 client_entry->nickname,
1129 client_entry2 ? client_entry2->nickname : "",
1131 } else if (idtype == SILC_ID_SERVER) {
1132 server_entry = (SilcServerEntry)entry;
1133 printformat_module("fe-common/silc", server, NULL,
1134 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1135 client_entry->nickname,
1136 server_entry->server_name, tmp ? tmp : "");
1137 } else if (idtype == SILC_ID_CHANNEL) {
1138 channel = (SilcChannelEntry)entry;
1139 printformat_module("fe-common/silc", server, NULL,
1140 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1141 client_entry->nickname,
1142 channel->channel_name, tmp ? tmp : "");
1147 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1150 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1153 * Server has quit the network.
1157 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1159 (void)va_arg(va, void *);
1160 clients = va_arg(va, SilcDList);
1162 silc_dlist_start(clients);
1163 while ((client_entry = silc_dlist_get(clients))) {
1164 memset(buf, 0, sizeof(buf));
1166 /* Print only if we have the nickname. If this client has just quit
1167 when we were only resolving it, it is possible we don't have the
1169 if (client_entry->nickname[0]) {
1170 if (client_entry->username[0])
1171 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1172 client_entry->username, client_entry->hostname);
1173 signal_emit("message quit", 4, server, client_entry->nickname,
1174 client_entry->username[0] ? buf : "",
1179 silc_server_free_ftp(server, client_entry);
1182 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1183 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1184 list_tmp->next->next) {
1185 CHANNEL_REC *channel = list_tmp->data;
1186 NICK_REC *nickrec = list_tmp->next->data;
1187 nicklist_remove(channel, nickrec);
1193 case SILC_NOTIFY_TYPE_ERROR:
1195 SilcStatus error = va_arg(va, int);
1197 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1198 "%s", silc_get_status_message(error));
1202 case SILC_NOTIFY_TYPE_WATCH:
1204 SilcNotifyType notify;
1206 client_entry = va_arg(va, SilcClientEntry);
1207 name = va_arg(va, char *); /* Maybe NULL */
1208 mode = va_arg(va, SilcUInt32);
1209 notify = va_arg(va, int);
1211 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1213 printformat_module("fe-common/silc", server, NULL,
1214 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1215 client_entry->nickname, name);
1217 printformat_module("fe-common/silc", server, NULL,
1218 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1219 client_entry->nickname);
1220 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1221 /* See if client was away and is now present */
1222 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1223 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1224 SILC_UMODE_DETACHED)) &&
1225 (client_entry->mode & SILC_UMODE_GONE ||
1226 client_entry->mode & SILC_UMODE_INDISPOSED ||
1227 client_entry->mode & SILC_UMODE_BUSY ||
1228 client_entry->mode & SILC_UMODE_PAGE ||
1229 client_entry->mode & SILC_UMODE_DETACHED)) {
1230 printformat_module("fe-common/silc", server, NULL,
1231 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1232 client_entry->nickname);
1236 memset(buf, 0, sizeof(buf));
1237 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1238 printformat_module("fe-common/silc", server, NULL,
1239 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1240 client_entry->nickname, buf);
1242 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1243 printformat_module("fe-common/silc", server, NULL,
1244 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1245 client_entry->nickname);
1246 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1247 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1248 printformat_module("fe-common/silc", server, NULL,
1249 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1250 client_entry->nickname);
1251 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1252 /* Client logged in to the network */
1253 printformat_module("fe-common/silc", server, NULL,
1254 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1255 client_entry->nickname);
1261 /* Unknown notify */
1262 printformat_module("fe-common/silc", server, NULL,
1263 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1270 /* Command handler. This function is called always in the command function.
1271 If error occurs it will be called as well. `conn' is the associated
1272 client connection. `cmd_context' is the command context that was
1273 originally sent to the command. `success' is FALSE if error occured
1274 during command. `command' is the command being processed. It must be
1275 noted that this is not reply from server. This is merely called just
1276 after application has called the command. Just to tell application
1277 that the command really was processed. */
1279 static SilcBool cmode_list_chpks = FALSE;
1281 void silc_command(SilcClient client, SilcClientConnection conn,
1282 SilcBool success, SilcCommand command, SilcStatus status,
1283 SilcUInt32 argc, unsigned char **argv)
1285 SILC_SERVER_REC *server = conn->context;
1287 SILC_LOG_DEBUG(("Start"));
1290 silc_say_error("%s", silc_get_status_message(status));
1296 case SILC_COMMAND_INVITE:
1298 printformat_module("fe-common/silc", server, NULL,
1299 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1301 (argv[1][0] == '*' ?
1302 (char *)conn->current_channel->channel_name :
1306 case SILC_COMMAND_DETACH:
1307 server->no_reconnect = TRUE;
1310 case SILC_COMMAND_CMODE:
1311 if (argc == 3 && !strcmp(argv[2], "+C"))
1312 cmode_list_chpks = TRUE;
1314 cmode_list_chpks = FALSE;
1324 SilcClientConnection conn;
1329 void silc_getkey_cb(bool success, void *context)
1331 GetkeyContext getkey = (GetkeyContext)context;
1332 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1333 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1334 ((SilcClientEntry)getkey->entry)->nickname :
1335 ((SilcServerEntry)getkey->entry)->server_name);
1338 printformat_module("fe-common/silc", NULL, NULL,
1339 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1341 printformat_module("fe-common/silc", NULL, NULL,
1342 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1349 /* Parse an invite or ban list */
1350 void silc_parse_inviteban_list(SilcClient client,
1351 SilcClientConnection conn,
1352 SILC_SERVER_REC *server,
1353 SilcChannelEntry channel,
1354 const char *list_type,
1355 SilcArgumentPayload list)
1358 SilcUInt32 type, len;
1359 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1360 int counter=0, resolving = FALSE;
1362 if (!silc_argument_get_arg_num(list)) {
1363 printformat_module("fe-common/silc", server,
1364 (chanrec ? chanrec->visible_name : NULL),
1365 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1366 channel->channel_name, list_type);
1370 printformat_module("fe-common/silc", server,
1371 (chanrec ? chanrec->visible_name : NULL),
1372 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1373 channel->channel_name, list_type);
1375 /* Parse the list */
1376 tmp = silc_argument_get_first_arg(list, &type, &len);
1381 /* An invite string */
1385 if (tmp[len-1] == ',')
1388 list = g_strsplit(tmp, ",", -1);
1390 printformat_module("fe-common/silc", server,
1391 (chanrec ? chanrec->visible_name : NULL),
1392 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1393 ++counter, channel->channel_name, list_type,
1402 char *fingerprint, *babbleprint;
1404 /* tmp is Public Key Payload, take public key from it. */
1405 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1406 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1408 printformat_module("fe-common/silc", server,
1409 (chanrec ? chanrec->visible_name : NULL),
1410 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1411 ++counter, channel->channel_name, list_type,
1412 fingerprint, babbleprint);
1419 SilcClientEntry client_entry;
1422 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1423 silc_say_error("Invalid data in %s list encountered", list_type);
1427 client_entry = silc_client_get_client_by_id(client, conn,
1430 printformat_module("fe-common/silc", server,
1431 (chanrec ? chanrec->visible_name : NULL),
1432 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1433 ++counter, channel->channel_name, list_type,
1434 client_entry->nickname);
1435 silc_client_unref_client(client, conn, client_entry);
1438 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1446 silc_say_error("Unkown type in %s list: %u (len %u)",
1447 list_type, type, len);
1450 tmp = silc_argument_get_next_arg(list, &type, &len);
1454 printformat_module("fe-common/silc", server,
1455 (chanrec ? chanrec->visible_name : NULL),
1456 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1457 list_type, channel->channel_name);
1460 /* Command reply handler. This function is called always in the command reply
1461 function. If error occurs it will be called as well. Normal scenario
1462 is that it will be called after the received command data has been parsed
1463 and processed. The function is used to pass the received command data to
1466 `conn' is the associated client connection. `cmd_payload' is the command
1467 payload data received from server and it can be ignored. It is provided
1468 if the application would like to re-parse the received command data,
1469 however, it must be noted that the data is parsed already by the library
1470 thus the payload can be ignored. `success' is FALSE if error occured.
1471 In this case arguments are not sent to the application. `command' is the
1472 command reply being processed. The function has variable argument list
1473 and each command defines the number and type of arguments it passes to the
1474 application (on error they are not sent). */
1476 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1477 SilcCommand command, SilcStatus status,
1478 SilcStatus error, va_list vp)
1480 SILC_SERVER_REC *server = conn->context;
1481 SILC_CHANNEL_REC *chanrec;
1483 SILC_LOG_DEBUG(("Start"));
1486 case SILC_COMMAND_WHOIS:
1488 char buf[1024], *nickname, *username, *realname, nick[128 + 1];
1489 unsigned char *fingerprint;
1490 SilcUInt32 idle, mode, *user_modes;
1492 SilcClientEntry client_entry;
1495 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1496 /* Print the unknown nick for user */
1497 char *tmp = va_arg(vp, char *);
1499 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1501 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1502 /* Try to find the entry for the unknown client ID, since we
1503 might have, and print the nickname of it for user. */
1504 SilcClientID *id = va_arg(vp, SilcClientID *);
1506 client_entry = silc_client_get_client_by_id(client, conn, id);
1507 if (client_entry && client_entry->nickname[0])
1508 silc_say_error("%s: %s", client_entry->nickname,
1509 silc_get_status_message(status));
1510 silc_client_unref_client(client, conn, client_entry);
1513 } else if (SILC_STATUS_IS_ERROR(status)) {
1514 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1518 client_entry = va_arg(vp, SilcClientEntry);
1519 nickname = va_arg(vp, char *);
1520 username = va_arg(vp, char *);
1521 realname = va_arg(vp, char *);
1522 channels = va_arg(vp, SilcDList);
1523 mode = va_arg(vp, SilcUInt32);
1524 idle = va_arg(vp, SilcUInt32);
1525 fingerprint = va_arg(vp, unsigned char *);
1526 user_modes = va_arg(vp, SilcUInt32 *);
1527 attrs = va_arg(vp, SilcDList);
1529 silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
1530 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1531 SILCTXT_WHOIS_USERINFO, nickname,
1532 client_entry->username, client_entry->hostname,
1533 nick, client_entry->nickname);
1534 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1535 SILCTXT_WHOIS_REALNAME, realname);
1537 if (channels && user_modes) {
1538 SilcChannelPayload entry;
1541 memset(buf, 0, sizeof(buf));
1542 silc_dlist_start(channels);
1543 while ((entry = silc_dlist_get(channels))) {
1544 SilcUInt32 name_len;
1545 char *m = silc_client_chumode_char(user_modes[i++]);
1546 char *name = silc_channel_get_name(entry, &name_len);
1549 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1550 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1551 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1555 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1556 SILCTXT_WHOIS_CHANNELS, buf);
1560 memset(buf, 0, sizeof(buf));
1561 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1562 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1563 SILCTXT_WHOIS_MODES, buf);
1566 if (idle && nickname) {
1567 memset(buf, 0, sizeof(buf));
1568 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1569 idle > 60 ? (idle / 60) : idle,
1570 idle > 60 ? "minutes" : "seconds");
1572 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1573 SILCTXT_WHOIS_IDLE, buf);
1577 fingerprint = silc_fingerprint(fingerprint, 20);
1578 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1579 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1580 silc_free(fingerprint);
1584 silc_query_attributes_print(server, silc_client, conn, attrs,
1589 case SILC_COMMAND_WHOWAS:
1591 char *nickname, *username, *realname;
1593 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1594 char *tmp = va_arg(vp, char *);
1596 silc_say_error("%s: %s", tmp,
1597 silc_get_status_message(status));
1599 } else if (SILC_STATUS_IS_ERROR(status)) {
1600 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1604 (void)va_arg(vp, SilcClientEntry);
1605 nickname = va_arg(vp, char *);
1606 username = va_arg(vp, char *);
1607 realname = va_arg(vp, char *);
1609 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1610 SILCTXT_WHOWAS_USERINFO, nickname, username,
1611 realname ? realname : "");
1615 case SILC_COMMAND_INVITE:
1617 SilcChannelEntry channel;
1618 SilcArgumentPayload invite_list;
1620 if (SILC_STATUS_IS_ERROR(status))
1623 channel = va_arg(vp, SilcChannelEntry);
1624 invite_list = va_arg(vp, SilcArgumentPayload);
1627 silc_parse_inviteban_list(client, conn, server, channel,
1628 "invite", invite_list);
1632 case SILC_COMMAND_JOIN:
1634 char *channel, *mode, *topic, *cipher, *hmac;
1636 SilcHashTableList *user_list;
1637 SilcChannelEntry channel_entry;
1638 SilcChannelUser chu;
1639 SilcClientEntry founder = NULL;
1642 if (SILC_STATUS_IS_ERROR(status)) {
1643 silc_say_error("JOIN: %s", silc_get_status_message(status));
1647 channel = va_arg(vp, char *);
1648 channel_entry = va_arg(vp, SilcChannelEntry);
1649 modei = va_arg(vp, SilcUInt32);
1650 user_list = va_arg(vp, SilcHashTableList *);
1651 topic = va_arg(vp, char *);
1652 cipher = va_arg(vp, char *);
1653 hmac = va_arg(vp, char *);
1655 chanrec = silc_channel_find(server, channel);
1657 chanrec = silc_channel_create(server, channel, channel, TRUE);
1660 char tmp[256], *cp, *dm = NULL;
1661 g_free_not_null(chanrec->topic);
1663 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1664 memset(tmp, 0, sizeof(tmp));
1666 if (strlen(topic) > sizeof(tmp) - 1) {
1667 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1671 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1676 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1677 signal_emit("channel topic changed", 1, chanrec);
1682 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1683 g_free_not_null(chanrec->mode);
1684 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1685 signal_emit("channel mode changed", 1, chanrec);
1688 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1689 if (!chu->client->nickname)
1691 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1692 founder = chu->client;
1693 silc_nicklist_insert(chanrec, chu, FALSE);
1696 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1699 nicklist_set_own(CHANNEL(chanrec), ownnick);
1700 signal_emit("channel joined", 1, chanrec);
1701 chanrec->entry = channel_entry;
1704 printformat_module("fe-common/silc", server,
1705 channel_entry->channel_name,
1706 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1707 channel_entry->channel_name, chanrec->topic);
1710 if (founder == conn->local_entry) {
1711 printformat_module("fe-common/silc",
1712 server, channel_entry->channel_name,
1713 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1714 channel_entry->channel_name);
1715 signal_emit("nick mode changed", 2, chanrec, ownnick);
1717 printformat_module("fe-common/silc",
1718 server, channel_entry->channel_name,
1719 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1720 channel_entry->channel_name, founder->nickname);
1726 case SILC_COMMAND_NICK:
1729 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1732 if (SILC_STATUS_IS_ERROR(status)) {
1733 silc_say_error("NICK: %s", silc_get_status_message(status));
1737 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1738 if ((nicks != NULL) &&
1739 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1741 SilcClientEntry collider, old;
1743 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1744 collider = silc_client_get_client_by_id(client, conn, &old->id);
1745 if (collider != client_entry) {
1746 memset(buf, 0, sizeof(buf));
1747 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1748 collider->username, collider->hostname);
1749 nicklist_rename_unique(SERVER(server),
1751 collider, collider->nickname);
1752 silc_print_nick_change(server, collider->nickname,
1753 client_entry->nickname, buf);
1755 silc_client_unref_client(client, conn, collider);
1759 g_slist_free(nicks);
1761 old = g_strdup(server->nick);
1762 server_change_nick(SERVER(server), client_entry->nickname);
1763 nicklist_rename_unique(SERVER(server),
1764 server->conn->local_entry, server->nick,
1765 client_entry, client_entry->nickname);
1766 signal_emit("message own_nick", 4, server, server->nick, old, "");
1769 /* when connecting to a server, the last thing we receive
1770 is a SILC_COMMAND_LIST reply. Since we enable queueing
1771 during the connection, we can now safely disable it again */
1772 silc_queue_disable(conn);
1776 case SILC_COMMAND_LIST:
1781 char tmp[256], *cp, *dm = NULL;
1783 if (SILC_STATUS_IS_ERROR(status))
1786 (void)va_arg(vp, SilcChannelEntry);
1787 name = va_arg(vp, char *);
1788 topic = va_arg(vp, char *);
1789 usercount = va_arg(vp, int);
1791 if (topic && !silc_term_utf8() &&
1792 silc_utf8_valid(topic, strlen(topic))) {
1793 memset(tmp, 0, sizeof(tmp));
1795 if (strlen(topic) > sizeof(tmp) - 1) {
1796 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1800 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1805 if (status == SILC_STATUS_LIST_START ||
1806 status == SILC_STATUS_OK)
1807 printformat_module("fe-common/silc", server, NULL,
1808 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1811 snprintf(users, sizeof(users) - 1, "N/A");
1813 snprintf(users, sizeof(users) - 1, "%d", usercount);
1814 printformat_module("fe-common/silc", server, NULL,
1815 MSGLEVEL_CRAP, SILCTXT_LIST,
1816 name, users, topic ? topic : "");
1821 case SILC_COMMAND_UMODE:
1826 if (SILC_STATUS_IS_ERROR(status))
1829 mode = va_arg(vp, SilcUInt32);
1831 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1832 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1833 printformat_module("fe-common/silc", server, NULL,
1834 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1836 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1837 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1838 printformat_module("fe-common/silc", server, NULL,
1839 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1841 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1842 if (mode & SILC_UMODE_GONE) {
1843 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1844 reason = g_strdup(server->away_reason);
1846 reason = g_strdup("away");
1848 reason = g_strdup("");
1850 silc_set_away(reason, server);
1855 server->umode = mode;
1856 signal_emit("user mode changed", 2, server, NULL);
1860 case SILC_COMMAND_OPER:
1861 if (SILC_STATUS_IS_ERROR(status)) {
1862 silc_say_error("OPER: %s", silc_get_status_message(status));
1866 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1867 signal_emit("user mode changed", 2, server, NULL);
1869 printformat_module("fe-common/silc", server, NULL,
1870 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1873 case SILC_COMMAND_SILCOPER:
1874 if (SILC_STATUS_IS_ERROR(status)) {
1875 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1879 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1880 signal_emit("user mode changed", 2, server, NULL);
1882 printformat_module("fe-common/silc", server, NULL,
1883 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1886 case SILC_COMMAND_USERS:
1888 SilcHashTableList htl;
1889 SilcChannelEntry channel;
1890 SilcChannelUser chu;
1892 if (SILC_STATUS_IS_ERROR(status)) {
1893 silc_say_error("USERS: %s", silc_get_status_message(status));
1897 channel = va_arg(vp, SilcChannelEntry);
1899 printformat_module("fe-common/silc", server, channel->channel_name,
1900 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1901 channel->channel_name);
1903 silc_hash_table_list(channel->user_list, &htl);
1904 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1905 SilcClientEntry e = chu->client;
1906 char stat[5], *mode;
1911 memset(stat, 0, sizeof(stat));
1912 mode = silc_client_chumode_char(chu->mode);
1913 if (e->mode & SILC_UMODE_GONE)
1915 else if (e->mode & SILC_UMODE_INDISPOSED)
1917 else if (e->mode & SILC_UMODE_BUSY)
1919 else if (e->mode & SILC_UMODE_PAGE)
1921 else if (e->mode & SILC_UMODE_HYPER)
1923 else if (e->mode & SILC_UMODE_ROBOT)
1925 else if (e->mode & SILC_UMODE_ANONYMOUS)
1932 printformat_module("fe-common/silc", server, channel->channel_name,
1933 MSGLEVEL_CRAP, SILCTXT_USERS,
1935 e->username ? e->username : "",
1936 e->hostname ? e->hostname : "",
1937 e->realname ? e->realname : "");
1941 silc_hash_table_list_reset(&htl);
1945 case SILC_COMMAND_BAN:
1947 SilcChannelEntry channel;
1948 SilcArgumentPayload invite_list;
1950 if (SILC_STATUS_IS_ERROR(status))
1953 channel = va_arg(vp, SilcChannelEntry);
1954 invite_list = va_arg(vp, SilcArgumentPayload);
1957 silc_parse_inviteban_list(client, conn, server, channel,
1958 "ban", invite_list);
1962 case SILC_COMMAND_GETKEY:
1966 SilcPublicKey public_key;
1967 GetkeyContext getkey;
1970 if (SILC_STATUS_IS_ERROR(status)) {
1971 silc_say_error("GETKEY: %s", silc_get_status_message(status));
1975 id_type = va_arg(vp, SilcUInt32);
1976 entry = va_arg(vp, void *);
1977 public_key = va_arg(vp, SilcPublicKey);
1980 getkey = silc_calloc(1, sizeof(*getkey));
1981 getkey->entry = entry;
1982 getkey->id_type = id_type;
1983 getkey->client = client;
1984 getkey->conn = conn;
1986 name = (id_type == SILC_ID_CLIENT ?
1987 ((SilcClientEntry)entry)->nickname :
1988 ((SilcServerEntry)entry)->server_name);
1990 silc_verify_public_key_internal(client, conn, name,
1991 (id_type == SILC_ID_CLIENT ?
1994 public_key, silc_getkey_cb, getkey);
1996 printformat_module("fe-common/silc", server, NULL,
1997 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2002 case SILC_COMMAND_INFO:
2004 SilcServerEntry server_entry;
2008 if (SILC_STATUS_IS_ERROR(status))
2011 server_entry = va_arg(vp, SilcServerEntry);
2012 server_name = va_arg(vp, char *);
2013 server_info = va_arg(vp, char *);
2015 if (server_name && server_info )
2017 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2018 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2023 case SILC_COMMAND_TOPIC:
2025 SilcChannelEntry channel;
2027 char tmp[256], *cp, *dm = NULL;
2029 if (SILC_STATUS_IS_ERROR(status))
2032 channel = va_arg(vp, SilcChannelEntry);
2033 topic = va_arg(vp, char *);
2035 if (topic && !silc_term_utf8() &&
2036 silc_utf8_valid(topic, strlen(topic))) {
2037 memset(tmp, 0, sizeof(tmp));
2039 if (strlen(topic) > sizeof(tmp) - 1) {
2040 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2044 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2050 chanrec = silc_channel_find_entry(server, channel);
2052 g_free_not_null(chanrec->topic);
2053 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2054 signal_emit("channel topic changed", 1, chanrec);
2056 printformat_module("fe-common/silc", server, channel->channel_name,
2057 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2058 channel->channel_name, topic);
2060 printformat_module("fe-common/silc", server, channel->channel_name,
2061 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2062 channel->channel_name);
2068 case SILC_COMMAND_WATCH:
2071 case SILC_COMMAND_STATS:
2073 SilcClientStats *cstats;
2075 const char *tmptime;
2076 int days, hours, mins, secs;
2078 if (SILC_STATUS_IS_ERROR(status))
2081 cstats = va_arg(vp, SilcClientStats *);
2083 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2087 tmptime = silc_time_string(cstats->starttime);
2088 printformat_module("fe-common/silc", server, NULL,
2089 MSGLEVEL_CRAP, SILCTXT_STATS,
2090 "Local server start time", tmptime);
2092 days = cstats->uptime / (24 * 60 * 60);
2093 cstats->uptime -= days * (24 * 60 * 60);
2094 hours = cstats->uptime / (60 * 60);
2095 cstats->uptime -= hours * (60 * 60);
2096 mins = cstats->uptime / 60;
2097 cstats->uptime -= mins * 60;
2098 secs = cstats->uptime;
2099 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2100 days, hours, mins, secs);
2101 printformat_module("fe-common/silc", server, NULL,
2102 MSGLEVEL_CRAP, SILCTXT_STATS,
2103 "Local server uptime", tmp);
2105 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2106 printformat_module("fe-common/silc", server, NULL,
2107 MSGLEVEL_CRAP, SILCTXT_STATS,
2108 "Local server clients", tmp);
2110 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2111 printformat_module("fe-common/silc", server, NULL,
2112 MSGLEVEL_CRAP, SILCTXT_STATS,
2113 "Local server channels", tmp);
2115 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2116 printformat_module("fe-common/silc", server, NULL,
2117 MSGLEVEL_CRAP, SILCTXT_STATS,
2118 "Local server operators", tmp);
2120 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2121 printformat_module("fe-common/silc", server, NULL,
2122 MSGLEVEL_CRAP, SILCTXT_STATS,
2123 "Local router operators", tmp);
2125 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2126 printformat_module("fe-common/silc", server, NULL,
2127 MSGLEVEL_CRAP, SILCTXT_STATS,
2128 "Local cell clients", tmp);
2130 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2131 printformat_module("fe-common/silc", server, NULL,
2132 MSGLEVEL_CRAP, SILCTXT_STATS,
2133 "Local cell channels", tmp);
2135 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2136 printformat_module("fe-common/silc", server, NULL,
2137 MSGLEVEL_CRAP, SILCTXT_STATS,
2138 "Local cell servers", tmp);
2140 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2141 printformat_module("fe-common/silc", server, NULL,
2142 MSGLEVEL_CRAP, SILCTXT_STATS,
2143 "Total clients", tmp);
2145 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2146 printformat_module("fe-common/silc", server, NULL,
2147 MSGLEVEL_CRAP, SILCTXT_STATS,
2148 "Total channels", tmp);
2150 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2151 printformat_module("fe-common/silc", server, NULL,
2152 MSGLEVEL_CRAP, SILCTXT_STATS,
2153 "Total servers", tmp);
2155 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2156 printformat_module("fe-common/silc", server, NULL,
2157 MSGLEVEL_CRAP, SILCTXT_STATS,
2158 "Total routers", tmp);
2160 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2161 printformat_module("fe-common/silc", server, NULL,
2162 MSGLEVEL_CRAP, SILCTXT_STATS,
2163 "Total server operators", tmp);
2165 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2166 printformat_module("fe-common/silc", server, NULL,
2167 MSGLEVEL_CRAP, SILCTXT_STATS,
2168 "Total router operators", tmp);
2172 case SILC_COMMAND_CMODE:
2174 SilcChannelEntry channel_entry;
2177 channel_entry = va_arg(vp, SilcChannelEntry);
2178 (void)va_arg(vp, SilcUInt32);
2179 (void)va_arg(vp, SilcPublicKey);
2180 chpks = va_arg(vp, SilcDList);
2182 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2183 !channel_entry || !channel_entry->channel_name)
2186 /* Print the channel public key list */
2188 silc_parse_channel_public_keys(server, channel_entry, chpks);
2190 printformat_module("fe-common/silc", server, NULL,
2191 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2192 channel_entry->channel_name);
2197 case SILC_COMMAND_LEAVE:
2199 if (SILC_STATUS_IS_ERROR(status))
2202 /* We might be cycling, so disable queueing again */
2203 silc_queue_disable(conn);
2207 case SILC_COMMAND_DETACH:
2209 /* Save the detachment data to file. */
2213 if (SILC_STATUS_IS_ERROR(status))
2216 detach = va_arg(vp, SilcBuffer);
2217 file = silc_get_session_filename(server);
2218 silc_file_writefile(file, silc_buffer_data(detach),
2219 silc_buffer_len(detach));
2224 case SILC_COMMAND_KILL:
2226 SilcClientEntry client_entry;
2228 if (SILC_STATUS_IS_ERROR(status)) {
2229 silc_say_error("KILL: %s", silc_get_status_message(status));
2233 client_entry = va_arg(vp, SilcClientEntry);
2234 if (!client_entry || !client_entry->nickname[0])
2237 /* Print this only if the killed client isn't joined on channels.
2238 If it is, we receive KILLED notify and we'll print this there. */
2239 if (!silc_hash_table_count(client_entry->channels))
2240 printformat_module("fe-common/silc", server, NULL,
2241 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2242 client_entry->nickname,
2243 conn->local_entry->nickname, "");
2250 SilcClientConnection conn;
2254 SilcPublicKey public_key;
2255 SilcVerifyPublicKey completion;
2259 static void verify_public_key_completion(const char *line, void *context)
2261 PublicKeyVerify verify = (PublicKeyVerify)context;
2263 if (line[0] == 'Y' || line[0] == 'y') {
2264 /* Call the completion */
2265 if (verify->completion)
2266 verify->completion(TRUE, verify->context);
2268 /* Save the key for future checking */
2269 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2270 SILC_PKCS_FILE_BASE64);
2272 /* Call the completion */
2273 if (verify->completion)
2274 verify->completion(FALSE, verify->context);
2276 printformat_module("fe-common/silc", NULL, NULL,
2277 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2278 verify->entity_name ? verify->entity_name :
2282 silc_free(verify->filename);
2283 silc_free(verify->entity);
2284 silc_free(verify->entity_name);
2288 /* Internal routine to verify public key. If the `completion' is provided
2289 it will be called to indicate whether public was verified or not. For
2290 server/router public key this will check for filename that includes the
2291 remote host's IP address and remote host's hostname. */
2294 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2296 SilcConnectionType conn_type,
2297 SilcPublicKey public_key,
2298 SilcVerifyPublicKey completion, void *context)
2300 PublicKeyVerify verify;
2301 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2302 char *fingerprint, *babbleprint, *format;
2303 SilcPublicKey local_pubkey;
2305 const char *hostname, *ip;
2310 char *entity = ((conn_type == SILC_CONN_SERVER ||
2311 conn_type == SILC_CONN_ROUTER) ?
2312 "server" : "client");
2315 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2316 printformat_module("fe-common/silc", NULL, NULL,
2317 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2318 entity, silc_pkcs_get_type(public_key));
2320 completion(FALSE, context);
2324 /* Encode public key */
2325 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2328 completion(FALSE, context);
2332 pw = getpwuid(getuid());
2335 completion(FALSE, context);
2339 memset(filename, 0, sizeof(filename));
2340 memset(filename2, 0, sizeof(filename2));
2341 memset(file, 0, sizeof(file));
2343 /* Get remote host information */
2344 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2345 NULL, &hostname, &ip, &port);
2347 if (conn_type == SILC_CONN_SERVER ||
2348 conn_type == SILC_CONN_ROUTER) {
2350 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2351 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2352 get_irssi_dir(), entity, file);
2354 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2356 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2357 get_irssi_dir(), entity, file);
2362 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2364 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2365 get_irssi_dir(), entity, file);
2370 /* Replace all whitespaces with `_'. */
2371 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2372 for (i = 0; i < strlen(fingerprint); i++)
2373 if (fingerprint[i] == ' ')
2374 fingerprint[i] = '_';
2376 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2377 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2378 get_irssi_dir(), entity, file);
2379 silc_free(fingerprint);
2384 /* Take fingerprint of the public key */
2385 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2386 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2388 verify = silc_calloc(1, sizeof(*verify));
2389 verify->client = client;
2390 verify->conn = conn;
2391 verify->filename = strdup(ipf);
2392 verify->entity = strdup(entity);
2393 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2394 (name ? strdup(name) : strdup(hostname))
2396 verify->public_key = public_key;
2397 verify->completion = completion;
2398 verify->context = context;
2400 /* Check whether this key already exists */
2401 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2402 /* Key does not exist, ask user to verify the key and save it */
2404 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2405 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2406 verify->entity_name : entity);
2407 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2408 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2409 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2410 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2411 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2412 SILCTXT_PUBKEY_ACCEPT);
2413 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2416 silc_free(fingerprint);
2419 /* The key already exists, verify it. */
2420 unsigned char *encpk;
2421 SilcUInt32 encpk_len;
2423 /* Load the key file, try for both IP filename and hostname filename */
2424 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2425 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2426 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2427 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2428 verify->entity_name : entity);
2429 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2430 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2431 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2432 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2433 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2434 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2435 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2436 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2437 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2440 silc_free(fingerprint);
2444 /* Encode the key data */
2445 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2447 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2448 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2449 verify->entity_name : entity);
2450 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2451 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2452 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2453 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2454 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2455 SILCTXT_PUBKEY_MALFORMED, entity);
2456 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2457 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2458 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2461 silc_free(fingerprint);
2465 /* Compare the keys */
2466 if (memcmp(encpk, pk, encpk_len)) {
2467 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2468 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2469 verify->entity_name : entity);
2470 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2471 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2472 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2473 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2474 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2475 SILCTXT_PUBKEY_NO_MATCH, entity);
2476 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2477 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2478 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2479 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2481 /* Ask user to verify the key and save it */
2482 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2483 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2484 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2487 silc_free(fingerprint);
2492 /* Local copy matched */
2494 completion(TRUE, context);
2496 silc_free(fingerprint);
2497 silc_free(verify->filename);
2498 silc_free(verify->entity);
2499 silc_free(verify->entity_name);
2504 /* Verifies received public key. The `conn_type' indicates which entity
2505 (server, client etc.) has sent the public key. If user decides to trust
2506 the key may be saved as trusted public key for later use. The
2507 `completion' must be called after the public key has been verified. */
2510 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2511 SilcConnectionType conn_type,
2512 SilcPublicKey public_key,
2513 SilcVerifyPublicKey completion, void *context)
2515 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2516 completion, context);
2519 /* Asks passphrase from user on the input line. */
2522 SilcAskPassphrase completion;
2526 void ask_passphrase_completion(const char *passphrase, void *context)
2528 AskPassphrase p = (AskPassphrase)context;
2529 if (passphrase && passphrase[0] == '\0')
2531 p->completion((unsigned char *)passphrase,
2532 passphrase ? strlen(passphrase) : 0, p->context);
2536 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2537 SilcAskPassphrase completion, void *context)
2539 AskPassphrase p = silc_calloc(1, sizeof(*p));
2540 p->completion = completion;
2541 p->context = context;
2543 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2544 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2548 SilcGetAuthMeth completion;
2552 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2553 SilcUInt32 passphrase_len,
2556 GetAuthMethod a = context;
2557 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2558 passphrase, passphrase_len, a->context);
2562 /* Find authentication data by hostname and port. The hostname may be IP
2565 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2566 char *hostname, SilcUInt16 port,
2567 SilcAuthMethod auth_meth,
2568 SilcGetAuthMeth completion, void *context)
2570 SERVER_SETUP_REC *setup;
2572 SILC_LOG_DEBUG(("Start"));
2574 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2575 /* Returning NULL will cause library to use our private key configured
2576 for this connection */
2577 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2581 /* Check whether we find the password for this server in our
2582 configuration. If it's set, always send it server. */
2583 setup = server_setup_find_port(hostname, port);
2584 if (setup && setup->password) {
2585 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2590 /* Didn't find password. If server wants it, ask it from user. */
2591 if (auth_meth == SILC_AUTH_PASSWORD) {
2593 a = silc_calloc(1, sizeof(*a));
2595 a->completion = completion;
2596 a->context = context;
2597 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2602 /* No authentication */
2603 completion(SILC_AUTH_NONE, NULL, 0, context);
2606 /* Asks whether the user would like to perform the key agreement protocol.
2607 This is called after we have received an key agreement packet or an
2608 reply to our key agreement packet. This returns TRUE if the user wants
2609 the library to perform the key agreement protocol and FALSE if it is not
2610 desired (application may start it later by calling the function
2611 silc_client_perform_key_agreement). */
2613 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2614 SilcClientEntry client_entry, const char *hostname,
2615 SilcUInt16 protocol, SilcUInt16 port)
2617 char portstr[12], protostr[5];
2619 SILC_LOG_DEBUG(("Start"));
2621 /* We will just display the info on the screen and return FALSE and user
2622 will have to start the key agreement with a command. */
2625 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2626 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2631 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2632 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2634 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2635 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2636 client_entry->nickname, hostname, portstr, protostr);
2639 /* Notifies application that file transfer protocol session is being
2640 requested by the remote client indicated by the `client_entry' from
2641 the `hostname' and `port'. The `session_id' is the file transfer
2642 session and it can be used to either accept or reject the file
2643 transfer request, by calling the silc_client_file_receive or
2644 silc_client_file_close, respectively. */
2646 void silc_ftp(SilcClient client, SilcClientConnection conn,
2647 SilcClientEntry client_entry, SilcUInt32 session_id,
2648 const char *hostname, SilcUInt16 port)
2650 SILC_SERVER_REC *server;
2652 FtpSession ftp = NULL;
2654 SILC_LOG_DEBUG(("Start"));
2656 server = conn->context;
2658 silc_dlist_start(server->ftp_sessions);
2659 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2660 if (ftp->client_entry == client_entry &&
2661 ftp->session_id == session_id) {
2662 server->current_session = ftp;
2666 if (ftp == SILC_LIST_END) {
2667 ftp = silc_calloc(1, sizeof(*ftp));
2668 ftp->client_entry = client_entry;
2669 ftp->session_id = session_id;
2672 silc_dlist_add(server->ftp_sessions, ftp);
2673 server->current_session = ftp;
2677 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2680 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2681 SILCTXT_FILE_REQUEST, client_entry->nickname);
2683 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2684 SILCTXT_FILE_REQUEST_HOST,
2685 client_entry->nickname, hostname, portstr);
2688 /* SILC client operations */
2689 SilcClientOperations ops = {
2691 silc_channel_message,
2692 silc_private_message,
2696 silc_get_auth_method,
2697 silc_verify_public_key,
2698 silc_ask_passphrase,