5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2006 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 bool 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 /* we might be cycling, so disable queueing again */
2200 silc_queue_disable(conn);
2209 SilcClientConnection conn;
2213 SilcPublicKey public_key;
2214 SilcVerifyPublicKey completion;
2218 static void verify_public_key_completion(const char *line, void *context)
2220 PublicKeyVerify verify = (PublicKeyVerify)context;
2222 if (line[0] == 'Y' || line[0] == 'y') {
2223 /* Call the completion */
2224 if (verify->completion)
2225 verify->completion(TRUE, verify->context);
2227 /* Save the key for future checking */
2228 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2229 SILC_PKCS_FILE_BASE64);
2231 /* Call the completion */
2232 if (verify->completion)
2233 verify->completion(FALSE, verify->context);
2235 printformat_module("fe-common/silc", NULL, NULL,
2236 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2237 verify->entity_name ? verify->entity_name :
2241 silc_free(verify->filename);
2242 silc_free(verify->entity);
2243 silc_free(verify->entity_name);
2247 /* Internal routine to verify public key. If the `completion' is provided
2248 it will be called to indicate whether public was verified or not. For
2249 server/router public key this will check for filename that includes the
2250 remote host's IP address and remote host's hostname. */
2253 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2255 SilcConnectionType conn_type,
2256 SilcPublicKey public_key,
2257 SilcVerifyPublicKey completion, void *context)
2259 PublicKeyVerify verify;
2260 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2261 char *fingerprint, *babbleprint, *format;
2262 SilcPublicKey local_pubkey;
2264 const char *hostname, *ip;
2269 char *entity = ((conn_type == SILC_CONN_SERVER ||
2270 conn_type == SILC_CONN_ROUTER) ?
2271 "server" : "client");
2274 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2275 printformat_module("fe-common/silc", NULL, NULL,
2276 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2277 entity, silc_pkcs_get_type(public_key));
2279 completion(FALSE, context);
2283 /* Encode public key */
2284 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2287 completion(FALSE, context);
2291 pw = getpwuid(getuid());
2294 completion(FALSE, context);
2298 memset(filename, 0, sizeof(filename));
2299 memset(filename2, 0, sizeof(filename2));
2300 memset(file, 0, sizeof(file));
2302 /* Get remote host information */
2303 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2304 NULL, &hostname, &ip, &port);
2306 if (conn_type == SILC_CONN_SERVER ||
2307 conn_type == SILC_CONN_ROUTER) {
2309 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2310 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2311 get_irssi_dir(), entity, file);
2313 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2315 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2316 get_irssi_dir(), entity, file);
2321 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2323 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2324 get_irssi_dir(), entity, file);
2329 /* Replace all whitespaces with `_'. */
2330 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2331 for (i = 0; i < strlen(fingerprint); i++)
2332 if (fingerprint[i] == ' ')
2333 fingerprint[i] = '_';
2335 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2336 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2337 get_irssi_dir(), entity, file);
2338 silc_free(fingerprint);
2343 /* Take fingerprint of the public key */
2344 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2345 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2347 verify = silc_calloc(1, sizeof(*verify));
2348 verify->client = client;
2349 verify->conn = conn;
2350 verify->filename = strdup(ipf);
2351 verify->entity = strdup(entity);
2352 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2353 (name ? strdup(name) : strdup(hostname))
2355 verify->public_key = public_key;
2356 verify->completion = completion;
2357 verify->context = context;
2359 /* Check whether this key already exists */
2360 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2361 /* Key does not exist, ask user to verify the key and save it */
2363 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2364 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2365 verify->entity_name : entity);
2366 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2367 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2368 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2369 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2370 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2371 SILCTXT_PUBKEY_ACCEPT);
2372 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2375 silc_free(fingerprint);
2378 /* The key already exists, verify it. */
2379 unsigned char *encpk;
2380 SilcUInt32 encpk_len;
2382 /* Load the key file, try for both IP filename and hostname filename */
2383 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2384 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2385 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2386 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2387 verify->entity_name : entity);
2388 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2389 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2390 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2391 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2392 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2393 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2394 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2395 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2396 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2399 silc_free(fingerprint);
2403 /* Encode the key data */
2404 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2406 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2407 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2408 verify->entity_name : entity);
2409 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2410 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2411 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2412 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2413 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2414 SILCTXT_PUBKEY_MALFORMED, entity);
2415 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2416 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2417 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2420 silc_free(fingerprint);
2424 /* Compare the keys */
2425 if (memcmp(encpk, pk, encpk_len)) {
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_NO_MATCH, entity);
2435 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2436 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2437 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2438 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2440 /* Ask user to verify the key and save it */
2441 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2442 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2443 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2446 silc_free(fingerprint);
2451 /* Local copy matched */
2453 completion(TRUE, context);
2455 silc_free(fingerprint);
2456 silc_free(verify->filename);
2457 silc_free(verify->entity);
2458 silc_free(verify->entity_name);
2463 /* Verifies received public key. The `conn_type' indicates which entity
2464 (server, client etc.) has sent the public key. If user decides to trust
2465 the key may be saved as trusted public key for later use. The
2466 `completion' must be called after the public key has been verified. */
2469 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2470 SilcConnectionType conn_type,
2471 SilcPublicKey public_key,
2472 SilcVerifyPublicKey completion, void *context)
2474 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2475 completion, context);
2478 /* Asks passphrase from user on the input line. */
2481 SilcAskPassphrase completion;
2485 void ask_passphrase_completion(const char *passphrase, void *context)
2487 AskPassphrase p = (AskPassphrase)context;
2488 if (passphrase && passphrase[0] == '\0')
2490 p->completion((unsigned char *)passphrase,
2491 passphrase ? strlen(passphrase) : 0, p->context);
2495 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2496 SilcAskPassphrase completion, void *context)
2498 AskPassphrase p = silc_calloc(1, sizeof(*p));
2499 p->completion = completion;
2500 p->context = context;
2502 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2503 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2507 SilcGetAuthMeth completion;
2509 } *InternalGetAuthMethod;
2511 /* Callback called when we've received the authentication method information
2512 from the server after we've requested it. This will get the authentication
2513 data from the user if needed. */
2515 static void silc_get_auth_method_callback(SilcClient client,
2516 SilcClientConnection conn,
2517 SilcAuthMethod auth_meth,
2520 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2522 SILC_LOG_DEBUG(("Start"));
2524 switch (auth_meth) {
2525 case SILC_AUTH_NONE:
2526 /* No authentication required. */
2527 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2529 case SILC_AUTH_PASSWORD:
2531 /* Check whether we find the password for this server in our
2532 configuration. If not, then don't provide so library will ask
2533 it from the user. */
2534 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2536 if (!setup || !setup->password) {
2537 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2541 (*internal->completion)(TRUE, auth_meth, setup->password,
2542 strlen(setup->password), internal->context);
2545 case SILC_AUTH_PUBLIC_KEY:
2546 /* Do not get the authentication data now, the library will generate
2547 it using our default key, if we do not provide it here. */
2548 /* XXX In the future when we support multiple local keys and multiple
2549 local certificates we will need to ask from user which one to use. */
2550 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2554 silc_free(internal);
2557 /* Find authentication method and authentication data by hostname and
2558 port. The hostname may be IP address as well. The found authentication
2559 method and authentication data is returned to `auth_meth', `auth_data'
2560 and `auth_data_len'. The function returns TRUE if authentication method
2561 is found and FALSE if not. `conn' may be NULL. */
2563 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2564 char *hostname, SilcUInt16 port,
2565 SilcGetAuthMeth completion, void *context)
2567 InternalGetAuthMethod internal;
2569 SILC_LOG_DEBUG(("Start"));
2571 /* If we do not have this connection configured by the user in a
2572 configuration file then resolve the authentication method from the
2573 server for this session. */
2574 internal = silc_calloc(1, sizeof(*internal));
2575 internal->completion = completion;
2576 internal->context = context;
2579 silc_client_request_authentication_method(client, conn,
2580 silc_get_auth_method_callback,
2583 completion(TRUE, SILC_AUTH_NONE, NULL, 0, context);
2587 /* Asks whether the user would like to perform the key agreement protocol.
2588 This is called after we have received an key agreement packet or an
2589 reply to our key agreement packet. This returns TRUE if the user wants
2590 the library to perform the key agreement protocol and FALSE if it is not
2591 desired (application may start it later by calling the function
2592 silc_client_perform_key_agreement). */
2594 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2595 SilcClientEntry client_entry, const char *hostname,
2596 SilcUInt16 protocol, SilcUInt16 port)
2598 char portstr[12], protostr[5];
2600 SILC_LOG_DEBUG(("Start"));
2602 /* We will just display the info on the screen and return FALSE and user
2603 will have to start the key agreement with a command. */
2606 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2607 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2612 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2613 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2615 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2616 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2617 client_entry->nickname, hostname, portstr, protostr);
2620 /* Notifies application that file transfer protocol session is being
2621 requested by the remote client indicated by the `client_entry' from
2622 the `hostname' and `port'. The `session_id' is the file transfer
2623 session and it can be used to either accept or reject the file
2624 transfer request, by calling the silc_client_file_receive or
2625 silc_client_file_close, respectively. */
2627 void silc_ftp(SilcClient client, SilcClientConnection conn,
2628 SilcClientEntry client_entry, SilcUInt32 session_id,
2629 const char *hostname, SilcUInt16 port)
2631 SILC_SERVER_REC *server;
2633 FtpSession ftp = NULL;
2635 SILC_LOG_DEBUG(("Start"));
2637 server = conn->context;
2639 silc_dlist_start(server->ftp_sessions);
2640 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2641 if (ftp->client_entry == client_entry &&
2642 ftp->session_id == session_id) {
2643 server->current_session = ftp;
2647 if (ftp == SILC_LIST_END) {
2648 ftp = silc_calloc(1, sizeof(*ftp));
2649 ftp->client_entry = client_entry;
2650 ftp->session_id = session_id;
2653 silc_dlist_add(server->ftp_sessions, ftp);
2654 server->current_session = ftp;
2658 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2661 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2662 SILCTXT_FILE_REQUEST, client_entry->nickname);
2664 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2665 SILCTXT_FILE_REQUEST_HOST,
2666 client_entry->nickname, hostname, portstr);
2669 /* Delivers SILC session detachment data indicated by `detach_data' to the
2670 application. If application has issued SILC_COMMAND_DETACH command
2671 the client session in the SILC network is not quit. The client remains
2672 in the network but is detached. The detachment data may be used later
2673 to resume the session in the SILC Network. The appliation is
2674 responsible of saving the `detach_data', to for example in a file.
2676 The detachment data can be given as argument to the functions
2677 silc_client_connect_to_server, or silc_client_add_connection when
2678 creating connection to remote server, inside SilcClientConnectionParams
2679 structure. If it is provided the client library will attempt to resume
2680 the session in the network. After the connection is created
2681 successfully, the application is responsible of setting the user
2682 interface for user into the same state it was before detaching (showing
2683 same channels, channel modes, etc). It can do this by fetching the
2684 information (like joined channels) from the client library. */
2687 silc_detach(SilcClient client, SilcClientConnection conn,
2688 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2690 SILC_SERVER_REC *server = conn->context;
2693 /* Save the detachment data to file. */
2695 file = silc_get_session_filename(server);
2696 silc_file_writefile(file, detach_data, detach_data_len);
2700 /* SILC client operations */
2701 SilcClientOperations ops = {
2703 silc_channel_message,
2704 silc_private_message,
2708 silc_get_auth_method,
2709 silc_verify_public_key,
2710 silc_ask_passphrase,