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);
426 /* If the messages is digitally signed, verify it, if possible. */
427 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
428 if (!settings_get_bool("ignore_message_signatures")) {
429 verified = verify_message_signature(sender, payload);
431 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
435 if (flags & SILC_MESSAGE_FLAG_DATA) {
436 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
437 nick == NULL ? NULL : nick->nick,
438 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
445 if (flags & SILC_MESSAGE_FLAG_ACTION)
446 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
447 char tmp[256], *cp, *dm = NULL;
448 memset(tmp, 0, sizeof(tmp));
450 if(message_len > sizeof(tmp) - 1) {
451 dm = silc_calloc(message_len + 1, sizeof(*dm));
454 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
456 if (flags & SILC_MESSAGE_FLAG_SIGNED)
457 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
458 nick->host, channel->channel_name, verified);
460 signal_emit("message silc action", 5, server, cp, nick->nick,
461 nick->host, channel->channel_name);
464 if (flags & SILC_MESSAGE_FLAG_SIGNED)
465 signal_emit("message silc signed_action", 6, server, message,
466 nick->nick, nick->host, channel->channel_name, verified);
468 signal_emit("message silc action", 5, server, message,
469 nick->nick, nick->host, channel->channel_name);
471 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
472 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
473 char tmp[256], *cp, *dm = NULL;
474 memset(tmp, 0, sizeof(tmp));
476 if(message_len > sizeof(tmp) - 1) {
477 dm = silc_calloc(message_len + 1, sizeof(*dm));
480 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
482 if (flags & SILC_MESSAGE_FLAG_SIGNED)
483 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
484 nick->host, channel->channel_name, verified);
486 signal_emit("message silc notice", 5, server, cp, nick->nick,
487 nick->host, channel->channel_name);
490 if (flags & SILC_MESSAGE_FLAG_SIGNED)
491 signal_emit("message silc signed_notice", 6, server, message,
492 nick->nick, nick->host, channel->channel_name, verified);
494 signal_emit("message silc notice", 5, server, message,
495 nick->nick, nick->host, channel->channel_name);
498 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
499 char tmp[256], *cp, *dm = NULL;
501 memset(tmp, 0, sizeof(tmp));
503 if (message_len > sizeof(tmp) - 1) {
504 dm = silc_calloc(message_len + 1, sizeof(*dm));
508 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
510 if (flags & SILC_MESSAGE_FLAG_SIGNED)
511 signal_emit("message signed_public", 6, server, cp,
512 nick == NULL ? "[<unknown>]" : nick->nick,
513 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
514 chanrec->name, verified);
516 signal_emit("message public", 6, server, cp,
517 nick == NULL ? "[<unknown>]" : nick->nick,
518 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
519 chanrec->name, nick);
524 if (flags & SILC_MESSAGE_FLAG_SIGNED)
525 signal_emit("message signed_public", 6, server, message,
526 nick == NULL ? "[<unknown>]" : nick->nick,
527 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
528 chanrec->name, verified);
530 signal_emit("message public", 6, server, message,
531 nick == NULL ? "[<unknown>]" : nick->nick,
532 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
533 chanrec->name, nick);
537 /* Private message to the client. The `sender' is the nickname of the
538 sender received in the packet. */
540 void silc_private_message(SilcClient client, SilcClientConnection conn,
541 SilcClientEntry sender, SilcMessagePayload payload,
542 SilcMessageFlags flags,
543 const unsigned char *message,
544 SilcUInt32 message_len)
546 SILC_SERVER_REC *server;
550 SILC_LOG_DEBUG(("Start"));
552 server = conn == NULL ? NULL : conn->context;
553 memset(userhost, 0, sizeof(userhost));
554 if (sender->username)
555 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
556 sender->username, sender->hostname);
558 /* If the messages is digitally signed, verify it, if possible. */
559 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
560 if (!settings_get_bool("ignore_message_signatures")) {
561 verified = verify_message_signature(sender, payload);
563 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
567 if (flags & SILC_MESSAGE_FLAG_DATA) {
568 silc_emit_mime_sig(server,
570 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
572 message, message_len,
573 sender->nickname ? sender->nickname : "[<unknown>]",
574 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
581 if (flags & SILC_MESSAGE_FLAG_ACTION)
582 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
583 char tmp[256], *cp, *dm = NULL;
584 memset(tmp, 0, sizeof(tmp));
586 if(message_len > sizeof(tmp) - 1) {
587 dm = silc_calloc(message_len + 1, sizeof(*dm));
590 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
592 if (flags & SILC_MESSAGE_FLAG_SIGNED)
593 signal_emit("message silc signed_private_action", 6, server, cp,
594 sender->nickname ? sender->nickname : "[<unknown>]",
595 sender->username ? userhost : NULL,
598 signal_emit("message silc private_action", 5, server, cp,
599 sender->nickname ? sender->nickname : "[<unknown>]",
600 sender->username ? userhost : NULL, NULL);
603 if (flags & SILC_MESSAGE_FLAG_SIGNED)
604 signal_emit("message silc signed_private_action", 6, server, message,
605 sender->nickname ? sender->nickname : "[<unknown>]",
606 sender->username ? userhost : NULL,
609 signal_emit("message silc private_action", 5, server, message,
610 sender->nickname ? sender->nickname : "[<unknown>]",
611 sender->username ? userhost : NULL, NULL);
613 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
614 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
615 char tmp[256], *cp, *dm = NULL;
616 memset(tmp, 0, sizeof(tmp));
618 if(message_len > sizeof(tmp) - 1) {
619 dm = silc_calloc(message_len + 1, sizeof(*dm));
622 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
624 if (flags & SILC_MESSAGE_FLAG_SIGNED)
625 signal_emit("message silc signed_private_notice", 6, server, cp,
626 sender->nickname ? sender->nickname : "[<unknown>]",
627 sender->username ? userhost : NULL,
630 signal_emit("message silc private_notice", 5, server, cp,
631 sender->nickname ? sender->nickname : "[<unknown>]",
632 sender->username ? userhost : NULL, NULL);
635 if (flags & SILC_MESSAGE_FLAG_SIGNED)
636 signal_emit("message silc signed_private_notice", 6, server, message,
637 sender->nickname ? sender->nickname : "[<unknown>]",
638 sender->username ? userhost : NULL,
641 signal_emit("message silc private_notice", 5, server, message,
642 sender->nickname ? sender->nickname : "[<unknown>]",
643 sender->username ? userhost : NULL, NULL);
646 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
647 char tmp[256], *cp, *dm = NULL;
649 memset(tmp, 0, sizeof(tmp));
651 if (message_len > sizeof(tmp) - 1) {
652 dm = silc_calloc(message_len + 1, sizeof(*dm));
656 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
658 if (flags & SILC_MESSAGE_FLAG_SIGNED)
659 signal_emit("message signed_private", 5, server, cp,
660 sender->nickname ? sender->nickname : "[<unknown>]",
661 sender->username ? userhost : NULL, verified);
663 signal_emit("message private", 4, server, cp,
664 sender->nickname ? sender->nickname : "[<unknown>]",
665 sender->username ? userhost : NULL);
670 if (flags & SILC_MESSAGE_FLAG_SIGNED)
671 signal_emit("message signed_private", 5, server, message,
672 sender->nickname ? sender->nickname : "[<unknown>]",
673 sender->username ? userhost : NULL, verified);
675 signal_emit("message private", 4, server, message,
676 sender->nickname ? sender->nickname : "[<unknown>]",
677 sender->username ? userhost : NULL);
681 /* Notify message to the client. The notify arguments are sent in the
682 same order as servers sends them. The arguments are same as received
683 from the server except for ID's. If ID is received application receives
684 the corresponding entry to the ID. For example, if Client ID is received
685 application receives SilcClientEntry. Also, if the notify type is
686 for channel the channel entry is sent to application (even if server
687 does not send it). */
689 void silc_notify(SilcClient client, SilcClientConnection conn,
690 SilcNotifyType type, ...)
693 SILC_SERVER_REC *server;
694 SILC_CHANNEL_REC *chanrec;
695 SILC_NICK_REC *nickrec;
696 SilcClientEntry client_entry, client_entry2;
697 SilcChannelEntry channel, channel2;
698 SilcServerEntry server_entry;
703 char *name, *tmp, *cipher, *hmac;
704 GSList *list1, *list_tmp;
707 SILC_LOG_DEBUG(("Start"));
711 server = conn == NULL ? NULL : conn->context;
714 case SILC_NOTIFY_TYPE_NONE:
715 /* Some generic notice from server */
716 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
719 case SILC_NOTIFY_TYPE_INVITE:
721 * Invited or modified invite list.
724 SILC_LOG_DEBUG(("Notify: INVITE"));
726 channel = va_arg(va, SilcChannelEntry);
727 name = va_arg(va, char *);
728 client_entry = va_arg(va, SilcClientEntry);
730 memset(buf, 0, sizeof(buf));
731 snprintf(buf, sizeof(buf) - 1, "%s@%s",
732 client_entry->username, client_entry->hostname);
733 signal_emit("message invite", 4, server, channel ? channel->channel_name :
734 name, client_entry->nickname, buf);
737 case SILC_NOTIFY_TYPE_JOIN:
742 SILC_LOG_DEBUG(("Notify: JOIN"));
744 client_entry = va_arg(va, SilcClientEntry);
745 channel = va_arg(va, SilcChannelEntry);
747 if (client_entry == server->conn->local_entry) {
748 /* You joined to channel */
749 chanrec = silc_channel_find(server, channel->channel_name);
750 if (chanrec != NULL && !chanrec->joined)
751 chanrec->entry = channel;
753 chanrec = silc_channel_find_entry(server, channel);
754 if (chanrec != NULL) {
755 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
757 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
761 memset(buf, 0, sizeof(buf));
762 if (client_entry->username)
763 snprintf(buf, sizeof(buf) - 1, "%s@%s",
764 client_entry->username, client_entry->hostname);
765 signal_emit("message join", 4, server, channel->channel_name,
766 client_entry->nickname,
767 client_entry->username == NULL ? "" : buf);
770 case SILC_NOTIFY_TYPE_LEAVE:
775 SILC_LOG_DEBUG(("Notify: LEAVE"));
777 client_entry = va_arg(va, SilcClientEntry);
778 channel = va_arg(va, SilcChannelEntry);
780 memset(buf, 0, sizeof(buf));
781 if (client_entry->username)
782 snprintf(buf, sizeof(buf) - 1, "%s@%s",
783 client_entry->username, client_entry->hostname);
784 signal_emit("message part", 5, server, channel->channel_name,
785 client_entry->nickname, client_entry->username ?
786 buf : "", client_entry->nickname);
788 chanrec = silc_channel_find_entry(server, channel);
789 if (chanrec != NULL) {
790 nickrec = silc_nicklist_find(chanrec, client_entry);
792 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
796 case SILC_NOTIFY_TYPE_SIGNOFF:
801 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
803 client_entry = va_arg(va, SilcClientEntry);
804 tmp = va_arg(va, char *);
807 silc_server_free_ftp(server, client_entry);
810 /* Print only if we have the nickname. If this cliente has just quit
811 when we were only resolving it, it is possible we don't have the
813 if (client_entry->nickname) {
814 memset(buf, 0, sizeof(buf));
815 if (client_entry->username)
816 snprintf(buf, sizeof(buf) - 1, "%s@%s",
817 client_entry->username, client_entry->hostname);
818 signal_emit("message quit", 4, server, client_entry->nickname,
819 client_entry->username ? buf : "",
823 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
824 for (list_tmp = list1; list_tmp != NULL; list_tmp =
825 list_tmp->next->next) {
826 CHANNEL_REC *channel = list_tmp->data;
827 NICK_REC *nickrec = list_tmp->next->data;
829 nicklist_remove(channel, nickrec);
833 case SILC_NOTIFY_TYPE_TOPIC_SET:
838 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
840 idtype = va_arg(va, int);
841 entry = va_arg(va, void *);
842 tmp = va_arg(va, char *);
843 channel = va_arg(va, SilcChannelEntry);
845 chanrec = silc_channel_find_entry(server, channel);
846 if (chanrec != NULL) {
847 char tmp2[256], *cp, *dm = NULL;
849 g_free_not_null(chanrec->topic);
850 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
851 memset(tmp2, 0, sizeof(tmp2));
853 if (strlen(tmp) > sizeof(tmp2) - 1) {
854 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
858 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
863 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
864 signal_emit("channel topic changed", 1, chanrec);
869 if (idtype == SILC_ID_CLIENT) {
870 client_entry = (SilcClientEntry)entry;
871 memset(buf, 0, sizeof(buf));
872 snprintf(buf, sizeof(buf) - 1, "%s@%s",
873 client_entry->username, client_entry->hostname);
874 signal_emit("message topic", 5, server, channel->channel_name,
875 tmp, client_entry->nickname, buf);
876 } else if (idtype == SILC_ID_SERVER) {
877 server_entry = (SilcServerEntry)entry;
878 signal_emit("message topic", 5, server, channel->channel_name,
879 tmp, server_entry->server_name,
880 server_entry->server_name);
881 } else if (idtype == SILC_ID_CHANNEL) {
882 channel = (SilcChannelEntry)entry;
883 signal_emit("message topic", 5, server, channel->channel_name,
884 tmp, channel->channel_name, channel->channel_name);
888 case SILC_NOTIFY_TYPE_NICK_CHANGE:
893 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
895 client_entry = va_arg(va, SilcClientEntry);
896 client_entry2 = va_arg(va, SilcClientEntry);
898 if (!strcmp(client_entry->nickname, client_entry2->nickname))
901 memset(buf, 0, sizeof(buf));
902 snprintf(buf, sizeof(buf) - 1, "%s@%s",
903 client_entry2->username, client_entry2->hostname);
904 nicklist_rename_unique(SERVER(server),
905 client_entry, client_entry->nickname,
906 client_entry2, client_entry2->nickname);
907 signal_emit("message nick", 4, server, client_entry2->nickname,
908 client_entry->nickname, buf);
911 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
913 * Changed channel mode.
916 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
918 idtype = va_arg(va, int);
919 entry = va_arg(va, void *);
920 mode = va_arg(va, SilcUInt32);
921 cipher = va_arg(va, char *); /* cipher */
922 hmac = va_arg(va, char *); /* hmac */
923 (void)va_arg(va, char *); /* passphrase */
924 (void)va_arg(va, SilcPublicKey); /* founder key */
925 chpks = va_arg(va, SilcDList); /* channel public keys */
926 channel = va_arg(va, SilcChannelEntry);
928 tmp = silc_client_chmode(mode, cipher ? cipher : "",
931 chanrec = silc_channel_find_entry(server, channel);
932 if (chanrec != NULL) {
933 g_free_not_null(chanrec->mode);
934 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
935 signal_emit("channel mode changed", 1, chanrec);
938 if (idtype == SILC_ID_CLIENT) {
939 client_entry = (SilcClientEntry)entry;
940 printformat_module("fe-common/silc", server, channel->channel_name,
941 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
942 channel->channel_name, tmp ? tmp : "removed all",
943 client_entry->nickname);
944 } else if (idtype == SILC_ID_SERVER) {
945 server_entry = (SilcServerEntry)entry;
946 printformat_module("fe-common/silc", server, channel->channel_name,
947 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
948 channel->channel_name, tmp ? tmp : "removed all",
949 server_entry->server_name);
950 } else if (idtype == SILC_ID_CHANNEL) {
951 channel2 = (SilcChannelEntry)entry;
952 printformat_module("fe-common/silc", server, channel->channel_name,
953 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
954 channel->channel_name, tmp ? tmp : "removed all",
955 channel2->channel_name);
958 /* Print the channel public key list */
960 silc_parse_channel_public_keys(server, channel, chpks);
965 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
967 * Changed user's mode on channel.
970 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
972 idtype = va_arg(va, int);
973 entry = va_arg(va, void *);
974 mode = va_arg(va, SilcUInt32);
975 client_entry2 = va_arg(va, SilcClientEntry);
976 channel = va_arg(va, SilcChannelEntry);
978 tmp = silc_client_chumode(mode);
979 chanrec = silc_channel_find_entry(server, channel);
980 if (chanrec != NULL) {
983 if (client_entry2 == server->conn->local_entry)
984 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
986 nick = silc_nicklist_find(chanrec, client_entry2);
988 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
989 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
990 signal_emit("nick mode changed", 2, chanrec, nick);
994 if (idtype == SILC_ID_CLIENT) {
995 client_entry = (SilcClientEntry)entry;
996 printformat_module("fe-common/silc", server, channel->channel_name,
997 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
998 channel->channel_name, client_entry2->nickname,
999 tmp ? tmp : "removed all",
1000 client_entry->nickname);
1001 } else if (idtype == SILC_ID_SERVER) {
1002 server_entry = (SilcServerEntry)entry;
1003 printformat_module("fe-common/silc", server, channel->channel_name,
1004 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1005 channel->channel_name, client_entry2->nickname,
1006 tmp ? tmp : "removed all",
1007 server_entry->server_name);
1008 } else if (idtype == SILC_ID_CHANNEL) {
1009 channel2 = (SilcChannelEntry)entry;
1010 printformat_module("fe-common/silc", server, channel->channel_name,
1011 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1012 channel->channel_name, client_entry2->nickname,
1013 tmp ? tmp : "removed all",
1014 channel2->channel_name);
1017 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1018 printformat_module("fe-common/silc",
1019 server, channel->channel_name, MSGLEVEL_CRAP,
1020 SILCTXT_CHANNEL_FOUNDER,
1021 channel->channel_name, client_entry2->nickname);
1023 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1024 printformat_module("fe-common/silc",
1025 server, channel->channel_name, MSGLEVEL_CRAP,
1026 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1031 case SILC_NOTIFY_TYPE_MOTD:
1036 SILC_LOG_DEBUG(("Notify: MOTD"));
1038 tmp = va_arg(va, char *);
1040 if (!settings_get_bool("skip_motd"))
1041 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1044 case SILC_NOTIFY_TYPE_KICKED:
1046 * Someone was kicked from channel.
1049 SILC_LOG_DEBUG(("Notify: KICKED"));
1051 client_entry = va_arg(va, SilcClientEntry);
1052 tmp = va_arg(va, char *);
1053 client_entry2 = va_arg(va, SilcClientEntry);
1054 channel = va_arg(va, SilcChannelEntry);
1056 chanrec = silc_channel_find_entry(server, channel);
1058 if (client_entry == conn->local_entry) {
1059 printformat_module("fe-common/silc", server, channel->channel_name,
1060 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1061 channel->channel_name,
1062 client_entry ? client_entry2->nickname : "",
1065 chanrec->kicked = TRUE;
1066 channel_destroy((CHANNEL_REC *)chanrec);
1069 printformat_module("fe-common/silc", server, channel->channel_name,
1070 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1071 client_entry->nickname, channel->channel_name,
1072 client_entry2 ? client_entry2->nickname : "",
1076 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1077 if (nickrec != NULL)
1078 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1083 case SILC_NOTIFY_TYPE_KILLED:
1085 * Someone was killed from the network.
1088 SILC_LOG_DEBUG(("Notify: KILLED"));
1090 client_entry = va_arg(va, SilcClientEntry);
1091 tmp = va_arg(va, char *);
1092 idtype = va_arg(va, int);
1093 entry = va_arg(va, SilcClientEntry);
1095 if (client_entry == conn->local_entry) {
1096 if (idtype == SILC_ID_CLIENT) {
1097 client_entry2 = (SilcClientEntry)entry;
1098 printformat_module("fe-common/silc", server, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1100 client_entry2 ? client_entry2->nickname : "",
1102 } else if (idtype == SILC_ID_SERVER) {
1103 server_entry = (SilcServerEntry)entry;
1104 printformat_module("fe-common/silc", server, NULL,
1105 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1106 server_entry->server_name, tmp ? tmp : "");
1107 } else if (idtype == SILC_ID_CHANNEL) {
1108 channel = (SilcChannelEntry)entry;
1109 printformat_module("fe-common/silc", server, NULL,
1110 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1111 channel->channel_name, tmp ? tmp : "");
1114 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1115 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1116 list_tmp->next->next) {
1117 CHANNEL_REC *channel = list_tmp->data;
1118 NICK_REC *nickrec = list_tmp->next->data;
1119 nicklist_remove(channel, nickrec);
1122 if (idtype == SILC_ID_CLIENT) {
1123 client_entry2 = (SilcClientEntry)entry;
1124 printformat_module("fe-common/silc", server, NULL,
1125 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1126 client_entry->nickname,
1127 client_entry2 ? client_entry2->nickname : "",
1129 } else if (idtype == SILC_ID_SERVER) {
1130 server_entry = (SilcServerEntry)entry;
1131 printformat_module("fe-common/silc", server, NULL,
1132 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1133 client_entry->nickname,
1134 server_entry->server_name, tmp ? tmp : "");
1135 } else if (idtype == SILC_ID_CHANNEL) {
1136 channel = (SilcChannelEntry)entry;
1137 printformat_module("fe-common/silc", server, NULL,
1138 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1139 client_entry->nickname,
1140 channel->channel_name, tmp ? tmp : "");
1145 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1148 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1151 * Server has quit the network.
1156 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1158 (void)va_arg(va, void *);
1159 clients = va_arg(va, SilcDList);
1161 silc_dlist_start(clients);
1162 while ((client_entry = silc_dlist_get(clients))) {
1163 memset(buf, 0, sizeof(buf));
1165 /* Print only if we have the nickname. If this client has just quit
1166 when we were only resolving it, it is possible we don't have the
1168 if (client_entry->nickname[0]) {
1169 if (client_entry->username[0])
1170 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1171 client_entry->username, client_entry->hostname);
1172 signal_emit("message quit", 4, server, client_entry->nickname,
1173 client_entry->username[0] ? buf : "",
1178 silc_server_free_ftp(server, client_entry);
1181 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1182 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1183 list_tmp->next->next) {
1184 CHANNEL_REC *channel = list_tmp->data;
1185 NICK_REC *nickrec = list_tmp->next->data;
1186 nicklist_remove(channel, nickrec);
1192 case SILC_NOTIFY_TYPE_ERROR:
1194 SilcStatus error = va_arg(va, int);
1196 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1197 "%s", silc_get_status_message(error));
1201 case SILC_NOTIFY_TYPE_WATCH:
1203 SilcNotifyType notify;
1205 client_entry = va_arg(va, SilcClientEntry);
1206 name = va_arg(va, char *); /* Maybe NULL */
1207 mode = va_arg(va, SilcUInt32);
1208 notify = va_arg(va, int);
1210 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1212 printformat_module("fe-common/silc", server, NULL,
1213 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1214 client_entry->nickname, name);
1216 printformat_module("fe-common/silc", server, NULL,
1217 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1218 client_entry->nickname);
1219 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1220 /* See if client was away and is now present */
1221 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1222 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1223 SILC_UMODE_DETACHED)) &&
1224 (client_entry->mode & SILC_UMODE_GONE ||
1225 client_entry->mode & SILC_UMODE_INDISPOSED ||
1226 client_entry->mode & SILC_UMODE_BUSY ||
1227 client_entry->mode & SILC_UMODE_PAGE ||
1228 client_entry->mode & SILC_UMODE_DETACHED)) {
1229 printformat_module("fe-common/silc", server, NULL,
1230 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1231 client_entry->nickname);
1235 memset(buf, 0, sizeof(buf));
1236 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1237 printformat_module("fe-common/silc", server, NULL,
1238 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1239 client_entry->nickname, buf);
1241 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1242 printformat_module("fe-common/silc", server, NULL,
1243 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1244 client_entry->nickname);
1245 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1246 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1247 printformat_module("fe-common/silc", server, NULL,
1248 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1249 client_entry->nickname);
1250 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1251 /* Client logged in to the network */
1252 printformat_module("fe-common/silc", server, NULL,
1253 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1254 client_entry->nickname);
1260 /* Unknown notify */
1261 printformat_module("fe-common/silc", server, NULL,
1262 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1269 /* Command handler. This function is called always in the command function.
1270 If error occurs it will be called as well. `conn' is the associated
1271 client connection. `cmd_context' is the command context that was
1272 originally sent to the command. `success' is FALSE if error occured
1273 during command. `command' is the command being processed. It must be
1274 noted that this is not reply from server. This is merely called just
1275 after application has called the command. Just to tell application
1276 that the command really was processed. */
1278 static bool cmode_list_chpks = FALSE;
1280 void silc_command(SilcClient client, SilcClientConnection conn,
1281 SilcBool success, SilcCommand command, SilcStatus status,
1282 SilcUInt32 argc, unsigned char **argv)
1284 SILC_SERVER_REC *server = conn->context;
1286 SILC_LOG_DEBUG(("Start"));
1289 silc_say_error("%s", silc_get_status_message(status));
1295 case SILC_COMMAND_INVITE:
1297 printformat_module("fe-common/silc", server, NULL,
1298 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1300 (argv[1][0] == '*' ?
1301 (char *)conn->current_channel->channel_name :
1305 case SILC_COMMAND_DETACH:
1306 server->no_reconnect = TRUE;
1309 case SILC_COMMAND_CMODE:
1310 if (argc == 3 && !strcmp(argv[2], "+C"))
1311 cmode_list_chpks = TRUE;
1313 cmode_list_chpks = FALSE;
1323 SilcClientConnection conn;
1328 void silc_getkey_cb(bool success, void *context)
1330 GetkeyContext getkey = (GetkeyContext)context;
1331 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1332 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1333 ((SilcClientEntry)getkey->entry)->nickname :
1334 ((SilcServerEntry)getkey->entry)->server_name);
1337 printformat_module("fe-common/silc", NULL, NULL,
1338 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1340 printformat_module("fe-common/silc", NULL, NULL,
1341 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1348 /* Parse an invite or ban list */
1349 void silc_parse_inviteban_list(SilcClient client,
1350 SilcClientConnection conn,
1351 SILC_SERVER_REC *server,
1352 SilcChannelEntry channel,
1353 const char *list_type,
1354 SilcArgumentPayload list)
1357 SilcUInt32 type, len;
1358 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1359 int counter=0, resolving = FALSE;
1361 if (!silc_argument_get_arg_num(list)) {
1362 printformat_module("fe-common/silc", server,
1363 (chanrec ? chanrec->visible_name : NULL),
1364 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1365 channel->channel_name, list_type);
1369 printformat_module("fe-common/silc", server,
1370 (chanrec ? chanrec->visible_name : NULL),
1371 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1372 channel->channel_name, list_type);
1374 /* Parse the list */
1375 tmp = silc_argument_get_first_arg(list, &type, &len);
1380 /* An invite string */
1384 if (tmp[len-1] == ',')
1387 list = g_strsplit(tmp, ",", -1);
1389 printformat_module("fe-common/silc", server,
1390 (chanrec ? chanrec->visible_name : NULL),
1391 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1392 ++counter, channel->channel_name, list_type,
1401 char *fingerprint, *babbleprint;
1403 /* tmp is Public Key Payload, take public key from it. */
1404 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1405 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1407 printformat_module("fe-common/silc", server,
1408 (chanrec ? chanrec->visible_name : NULL),
1409 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1410 ++counter, channel->channel_name, list_type,
1411 fingerprint, babbleprint);
1418 SilcClientEntry client_entry;
1421 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1422 silc_say_error("Invalid data in %s list encountered", list_type);
1426 client_entry = silc_client_get_client_by_id(client, conn,
1429 printformat_module("fe-common/silc", server,
1430 (chanrec ? chanrec->visible_name : NULL),
1431 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1432 ++counter, channel->channel_name, list_type,
1433 client_entry->nickname);
1434 silc_client_unref_client(client, conn, client_entry);
1437 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1445 silc_say_error("Unkown type in %s list: %u (len %u)",
1446 list_type, type, len);
1449 tmp = silc_argument_get_next_arg(list, &type, &len);
1453 printformat_module("fe-common/silc", server,
1454 (chanrec ? chanrec->visible_name : NULL),
1455 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1456 list_type, channel->channel_name);
1459 /* Command reply handler. This function is called always in the command reply
1460 function. If error occurs it will be called as well. Normal scenario
1461 is that it will be called after the received command data has been parsed
1462 and processed. The function is used to pass the received command data to
1465 `conn' is the associated client connection. `cmd_payload' is the command
1466 payload data received from server and it can be ignored. It is provided
1467 if the application would like to re-parse the received command data,
1468 however, it must be noted that the data is parsed already by the library
1469 thus the payload can be ignored. `success' is FALSE if error occured.
1470 In this case arguments are not sent to the application. `command' is the
1471 command reply being processed. The function has variable argument list
1472 and each command defines the number and type of arguments it passes to the
1473 application (on error they are not sent). */
1475 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1476 SilcCommand command, SilcStatus status,
1477 SilcStatus error, va_list vp)
1479 SILC_SERVER_REC *server = conn->context;
1480 SILC_CHANNEL_REC *chanrec;
1482 SILC_LOG_DEBUG(("Start"));
1485 case SILC_COMMAND_WHOIS:
1487 char buf[1024], *nickname, *username, *realname, nick[128 + 1];
1488 unsigned char *fingerprint;
1489 SilcUInt32 idle, mode, *user_modes;
1491 SilcClientEntry client_entry;
1494 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1495 /* Print the unknown nick for user */
1496 char *tmp = va_arg(vp, char *);
1498 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1500 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1501 /* Try to find the entry for the unknown client ID, since we
1502 might have, and print the nickname of it for user. */
1503 SilcClientID *id = va_arg(vp, SilcClientID *);
1505 client_entry = silc_client_get_client_by_id(client, conn, id);
1506 if (client_entry && client_entry->nickname[0])
1507 silc_say_error("%s: %s", client_entry->nickname,
1508 silc_get_status_message(status));
1509 silc_client_unref_client(client, conn, client_entry);
1512 } else if (SILC_STATUS_IS_ERROR(status)) {
1513 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1517 client_entry = va_arg(vp, SilcClientEntry);
1518 nickname = va_arg(vp, char *);
1519 username = va_arg(vp, char *);
1520 realname = va_arg(vp, char *);
1521 channels = va_arg(vp, SilcDList);
1522 mode = va_arg(vp, SilcUInt32);
1523 idle = va_arg(vp, SilcUInt32);
1524 fingerprint = va_arg(vp, unsigned char *);
1525 user_modes = va_arg(vp, SilcUInt32 *);
1526 attrs = va_arg(vp, SilcDList);
1528 silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
1529 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1530 SILCTXT_WHOIS_USERINFO, nickname,
1531 client_entry->username, client_entry->hostname,
1532 nick, client_entry->nickname);
1533 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1534 SILCTXT_WHOIS_REALNAME, realname);
1536 if (channels && user_modes) {
1537 SilcChannelPayload entry;
1540 silc_dlist_start(channels);
1541 while ((entry = silc_dlist_get(channels))) {
1542 SilcUInt32 name_len;
1543 char *m = silc_client_chumode_char(user_modes[i++]);
1544 char *name = silc_channel_get_name(entry, &name_len);
1547 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1548 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1549 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1553 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1554 SILCTXT_WHOIS_CHANNELS, buf);
1558 memset(buf, 0, sizeof(buf));
1559 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1560 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1561 SILCTXT_WHOIS_MODES, buf);
1564 if (idle && nickname) {
1565 memset(buf, 0, sizeof(buf));
1566 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1567 idle > 60 ? (idle / 60) : idle,
1568 idle > 60 ? "minutes" : "seconds");
1570 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1571 SILCTXT_WHOIS_IDLE, buf);
1575 fingerprint = silc_fingerprint(fingerprint, 20);
1576 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1577 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1578 silc_free(fingerprint);
1582 silc_query_attributes_print(server, silc_client, conn, attrs,
1587 case SILC_COMMAND_WHOWAS:
1589 char *nickname, *username, *realname;
1591 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1592 char *tmp = va_arg(vp, char *);
1594 silc_say_error("%s: %s", tmp,
1595 silc_get_status_message(status));
1597 } else if (SILC_STATUS_IS_ERROR(status)) {
1598 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1602 (void)va_arg(vp, SilcClientEntry);
1603 nickname = va_arg(vp, char *);
1604 username = va_arg(vp, char *);
1605 realname = va_arg(vp, char *);
1607 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1608 SILCTXT_WHOWAS_USERINFO, nickname, username,
1609 realname ? realname : "");
1613 case SILC_COMMAND_INVITE:
1615 SilcChannelEntry channel;
1616 SilcArgumentPayload invite_list;
1618 if (SILC_STATUS_IS_ERROR(status))
1621 channel = va_arg(vp, SilcChannelEntry);
1622 invite_list = va_arg(vp, SilcArgumentPayload);
1625 silc_parse_inviteban_list(client, conn, server, channel,
1626 "invite", invite_list);
1630 case SILC_COMMAND_JOIN:
1632 char *channel, *mode, *topic, *cipher, *hmac;
1634 SilcHashTableList *user_list;
1635 SilcChannelEntry channel_entry;
1636 SilcChannelUser chu;
1637 SilcClientEntry founder = NULL;
1640 if (SILC_STATUS_IS_ERROR(status)) {
1641 silc_say_error("JOIN: %s", silc_get_status_message(status));
1645 channel = va_arg(vp, char *);
1646 channel_entry = va_arg(vp, SilcChannelEntry);
1647 modei = va_arg(vp, SilcUInt32);
1648 user_list = va_arg(vp, SilcHashTableList *);
1649 topic = va_arg(vp, char *);
1650 cipher = va_arg(vp, char *);
1651 hmac = va_arg(vp, char *);
1653 chanrec = silc_channel_find(server, channel);
1655 chanrec = silc_channel_create(server, channel, channel, TRUE);
1658 char tmp[256], *cp, *dm = NULL;
1659 g_free_not_null(chanrec->topic);
1661 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1662 memset(tmp, 0, sizeof(tmp));
1664 if (strlen(topic) > sizeof(tmp) - 1) {
1665 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1669 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1674 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1675 signal_emit("channel topic changed", 1, chanrec);
1680 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1681 g_free_not_null(chanrec->mode);
1682 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1683 signal_emit("channel mode changed", 1, chanrec);
1686 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1687 if (!chu->client->nickname)
1689 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1690 founder = chu->client;
1691 silc_nicklist_insert(chanrec, chu, FALSE);
1694 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1697 nicklist_set_own(CHANNEL(chanrec), ownnick);
1698 signal_emit("channel joined", 1, chanrec);
1699 chanrec->entry = channel_entry;
1702 printformat_module("fe-common/silc", server,
1703 channel_entry->channel_name,
1704 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1705 channel_entry->channel_name, chanrec->topic);
1708 if (founder == conn->local_entry) {
1709 printformat_module("fe-common/silc",
1710 server, channel_entry->channel_name,
1711 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1712 channel_entry->channel_name);
1713 signal_emit("nick mode changed", 2, chanrec, ownnick);
1715 printformat_module("fe-common/silc",
1716 server, channel_entry->channel_name,
1717 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1718 channel_entry->channel_name, founder->nickname);
1724 case SILC_COMMAND_NICK:
1727 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1730 if (SILC_STATUS_IS_ERROR(status)) {
1731 silc_say_error("NICK: %s", silc_get_status_message(status));
1735 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1736 if ((nicks != NULL) &&
1737 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1739 SilcClientEntry collider, old;
1741 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1742 collider = silc_client_get_client_by_id(client, conn, &old->id);
1743 if (collider != client_entry) {
1744 memset(buf, 0, sizeof(buf));
1745 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1746 collider->username, collider->hostname);
1747 nicklist_rename_unique(SERVER(server),
1749 collider, collider->nickname);
1750 silc_print_nick_change(server, collider->nickname,
1751 client_entry->nickname, buf);
1753 silc_client_unref_client(client, conn, collider);
1757 g_slist_free(nicks);
1759 old = g_strdup(server->nick);
1760 server_change_nick(SERVER(server), client_entry->nickname);
1761 nicklist_rename_unique(SERVER(server),
1762 server->conn->local_entry, server->nick,
1763 client_entry, client_entry->nickname);
1764 signal_emit("message own_nick", 4, server, server->nick, old, "");
1767 /* when connecting to a server, the last thing we receive
1768 is a SILC_COMMAND_LIST reply. Since we enable queueing
1769 during the connection, we can now safely disable it again */
1770 silc_queue_disable(conn);
1774 case SILC_COMMAND_LIST:
1779 char tmp[256], *cp, *dm = NULL;
1781 if (SILC_STATUS_IS_ERROR(status))
1784 (void)va_arg(vp, SilcChannelEntry);
1785 name = va_arg(vp, char *);
1786 topic = va_arg(vp, char *);
1787 usercount = va_arg(vp, int);
1789 if (topic && !silc_term_utf8() &&
1790 silc_utf8_valid(topic, strlen(topic))) {
1791 memset(tmp, 0, sizeof(tmp));
1793 if (strlen(topic) > sizeof(tmp) - 1) {
1794 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1798 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1803 if (status == SILC_STATUS_LIST_START ||
1804 status == SILC_STATUS_OK)
1805 printformat_module("fe-common/silc", server, NULL,
1806 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1809 snprintf(users, sizeof(users) - 1, "N/A");
1811 snprintf(users, sizeof(users) - 1, "%d", usercount);
1812 printformat_module("fe-common/silc", server, NULL,
1813 MSGLEVEL_CRAP, SILCTXT_LIST,
1814 name, users, topic ? topic : "");
1819 case SILC_COMMAND_UMODE:
1824 if (SILC_STATUS_IS_ERROR(status))
1827 mode = va_arg(vp, SilcUInt32);
1829 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1830 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1831 printformat_module("fe-common/silc", server, NULL,
1832 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1834 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1835 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1836 printformat_module("fe-common/silc", server, NULL,
1837 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1839 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1840 if (mode & SILC_UMODE_GONE) {
1841 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1842 reason = g_strdup(server->away_reason);
1844 reason = g_strdup("away");
1846 reason = g_strdup("");
1848 silc_set_away(reason, server);
1853 server->umode = mode;
1854 signal_emit("user mode changed", 2, server, NULL);
1858 case SILC_COMMAND_OPER:
1859 if (SILC_STATUS_IS_ERROR(status))
1862 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1863 signal_emit("user mode changed", 2, server, NULL);
1865 printformat_module("fe-common/silc", server, NULL,
1866 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1869 case SILC_COMMAND_SILCOPER:
1870 if (SILC_STATUS_IS_ERROR(status))
1873 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1874 signal_emit("user mode changed", 2, server, NULL);
1876 printformat_module("fe-common/silc", server, NULL,
1877 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1880 case SILC_COMMAND_USERS:
1882 SilcHashTableList htl;
1883 SilcChannelEntry channel;
1884 SilcChannelUser chu;
1886 if (SILC_STATUS_IS_ERROR(status)) {
1887 silc_say_error("USERS: %s", silc_get_status_message(status));
1891 channel = va_arg(vp, SilcChannelEntry);
1893 printformat_module("fe-common/silc", server, channel->channel_name,
1894 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1895 channel->channel_name);
1897 silc_hash_table_list(channel->user_list, &htl);
1898 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1899 SilcClientEntry e = chu->client;
1900 char stat[5], *mode;
1905 memset(stat, 0, sizeof(stat));
1906 mode = silc_client_chumode_char(chu->mode);
1907 if (e->mode & SILC_UMODE_GONE)
1909 else if (e->mode & SILC_UMODE_INDISPOSED)
1911 else if (e->mode & SILC_UMODE_BUSY)
1913 else if (e->mode & SILC_UMODE_PAGE)
1915 else if (e->mode & SILC_UMODE_HYPER)
1917 else if (e->mode & SILC_UMODE_ROBOT)
1919 else if (e->mode & SILC_UMODE_ANONYMOUS)
1926 printformat_module("fe-common/silc", server, channel->channel_name,
1927 MSGLEVEL_CRAP, SILCTXT_USERS,
1929 e->username ? e->username : "",
1930 e->hostname ? e->hostname : "",
1931 e->realname ? e->realname : "");
1935 silc_hash_table_list_reset(&htl);
1939 case SILC_COMMAND_BAN:
1941 SilcChannelEntry channel;
1942 SilcArgumentPayload invite_list;
1944 if (SILC_STATUS_IS_ERROR(status))
1947 channel = va_arg(vp, SilcChannelEntry);
1948 invite_list = va_arg(vp, SilcArgumentPayload);
1951 silc_parse_inviteban_list(client, conn, server, channel,
1952 "ban", invite_list);
1956 case SILC_COMMAND_GETKEY:
1960 SilcPublicKey public_key;
1961 GetkeyContext getkey;
1964 if (SILC_STATUS_IS_ERROR(status)) {
1965 silc_say_error("GETKEY: %s", silc_get_status_message(status));
1969 id_type = va_arg(vp, SilcUInt32);
1970 entry = va_arg(vp, void *);
1971 public_key = va_arg(vp, SilcPublicKey);
1974 getkey = silc_calloc(1, sizeof(*getkey));
1975 getkey->entry = entry;
1976 getkey->id_type = id_type;
1977 getkey->client = client;
1978 getkey->conn = conn;
1980 name = (id_type == SILC_ID_CLIENT ?
1981 ((SilcClientEntry)entry)->nickname :
1982 ((SilcServerEntry)entry)->server_name);
1984 silc_verify_public_key_internal(client, conn, name,
1985 (id_type == SILC_ID_CLIENT ?
1988 public_key, silc_getkey_cb, getkey);
1990 printformat_module("fe-common/silc", server, NULL,
1991 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1996 case SILC_COMMAND_INFO:
1998 SilcServerEntry server_entry;
2002 if (SILC_STATUS_IS_ERROR(status))
2005 server_entry = va_arg(vp, SilcServerEntry);
2006 server_name = va_arg(vp, char *);
2007 server_info = va_arg(vp, char *);
2009 if (server_name && server_info )
2011 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2012 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2017 case SILC_COMMAND_TOPIC:
2019 SilcChannelEntry channel;
2021 char tmp[256], *cp, *dm = NULL;
2023 if (SILC_STATUS_IS_ERROR(status))
2026 channel = va_arg(vp, SilcChannelEntry);
2027 topic = va_arg(vp, char *);
2029 if (topic && !silc_term_utf8() &&
2030 silc_utf8_valid(topic, strlen(topic))) {
2031 memset(tmp, 0, sizeof(tmp));
2033 if (strlen(topic) > sizeof(tmp) - 1) {
2034 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2038 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2044 chanrec = silc_channel_find_entry(server, channel);
2046 g_free_not_null(chanrec->topic);
2047 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2048 signal_emit("channel topic changed", 1, chanrec);
2050 printformat_module("fe-common/silc", server, channel->channel_name,
2051 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2052 channel->channel_name, topic);
2054 printformat_module("fe-common/silc", server, channel->channel_name,
2055 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2056 channel->channel_name);
2062 case SILC_COMMAND_WATCH:
2065 case SILC_COMMAND_STATS:
2067 SilcClientStats *cstats;
2069 SilcBufferStruct buf;
2070 unsigned char *tmp_buf;
2072 const char *tmptime;
2073 int days, hours, mins, secs;
2075 if (SILC_STATUS_IS_ERROR(status))
2078 cstats = va_arg(vp, SilcClientStats *);
2080 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2084 tmptime = silc_time_string(cstats->starttime);
2085 printformat_module("fe-common/silc", server, NULL,
2086 MSGLEVEL_CRAP, SILCTXT_STATS,
2087 "Local server start time", tmptime);
2089 days = cstats->uptime / (24 * 60 * 60);
2090 cstats->uptime -= days * (24 * 60 * 60);
2091 hours = cstats->uptime / (60 * 60);
2092 cstats->uptime -= hours * (60 * 60);
2093 mins = cstats->uptime / 60;
2094 cstats->uptime -= mins * 60;
2095 secs = cstats->uptime;
2096 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2097 days, hours, mins, secs);
2098 printformat_module("fe-common/silc", server, NULL,
2099 MSGLEVEL_CRAP, SILCTXT_STATS,
2100 "Local server uptime", tmp);
2102 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2103 printformat_module("fe-common/silc", server, NULL,
2104 MSGLEVEL_CRAP, SILCTXT_STATS,
2105 "Local server clients", tmp);
2107 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2108 printformat_module("fe-common/silc", server, NULL,
2109 MSGLEVEL_CRAP, SILCTXT_STATS,
2110 "Local server channels", tmp);
2112 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2113 printformat_module("fe-common/silc", server, NULL,
2114 MSGLEVEL_CRAP, SILCTXT_STATS,
2115 "Local server operators", tmp);
2117 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2118 printformat_module("fe-common/silc", server, NULL,
2119 MSGLEVEL_CRAP, SILCTXT_STATS,
2120 "Local router operators", tmp);
2122 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2123 printformat_module("fe-common/silc", server, NULL,
2124 MSGLEVEL_CRAP, SILCTXT_STATS,
2125 "Local cell clients", tmp);
2127 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2128 printformat_module("fe-common/silc", server, NULL,
2129 MSGLEVEL_CRAP, SILCTXT_STATS,
2130 "Local cell channels", tmp);
2132 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2133 printformat_module("fe-common/silc", server, NULL,
2134 MSGLEVEL_CRAP, SILCTXT_STATS,
2135 "Local cell servers", tmp);
2137 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2138 printformat_module("fe-common/silc", server, NULL,
2139 MSGLEVEL_CRAP, SILCTXT_STATS,
2140 "Total clients", tmp);
2142 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2143 printformat_module("fe-common/silc", server, NULL,
2144 MSGLEVEL_CRAP, SILCTXT_STATS,
2145 "Total channels", tmp);
2147 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2148 printformat_module("fe-common/silc", server, NULL,
2149 MSGLEVEL_CRAP, SILCTXT_STATS,
2150 "Total servers", tmp);
2152 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2153 printformat_module("fe-common/silc", server, NULL,
2154 MSGLEVEL_CRAP, SILCTXT_STATS,
2155 "Total routers", tmp);
2157 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2158 printformat_module("fe-common/silc", server, NULL,
2159 MSGLEVEL_CRAP, SILCTXT_STATS,
2160 "Total server operators", tmp);
2162 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2163 printformat_module("fe-common/silc", server, NULL,
2164 MSGLEVEL_CRAP, SILCTXT_STATS,
2165 "Total router operators", tmp);
2169 case SILC_COMMAND_CMODE:
2171 SilcChannelEntry channel_entry;
2174 channel_entry = va_arg(vp, SilcChannelEntry);
2175 (void)va_arg(vp, SilcUInt32);
2176 (void)va_arg(vp, SilcPublicKey);
2177 chpks = va_arg(vp, SilcDList);
2179 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2180 !channel_entry || !channel_entry->channel_name)
2183 /* Print the channel public key list */
2185 silc_parse_channel_public_keys(server, channel_entry, chpks);
2187 printformat_module("fe-common/silc", server, NULL,
2188 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2189 channel_entry->channel_name);
2194 case SILC_COMMAND_LEAVE:
2196 /* we might be cycling, so disable queueing again */
2197 silc_queue_disable(conn);
2206 SilcClientConnection conn;
2210 SilcPublicKey public_key;
2211 SilcVerifyPublicKey completion;
2215 static void verify_public_key_completion(const char *line, void *context)
2217 PublicKeyVerify verify = (PublicKeyVerify)context;
2219 if (line[0] == 'Y' || line[0] == 'y') {
2220 /* Call the completion */
2221 if (verify->completion)
2222 verify->completion(TRUE, verify->context);
2224 /* Save the key for future checking */
2225 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2226 SILC_PKCS_FILE_BASE64);
2228 /* Call the completion */
2229 if (verify->completion)
2230 verify->completion(FALSE, verify->context);
2232 printformat_module("fe-common/silc", NULL, NULL,
2233 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2234 verify->entity_name ? verify->entity_name :
2238 silc_free(verify->filename);
2239 silc_free(verify->entity);
2240 silc_free(verify->entity_name);
2244 /* Internal routine to verify public key. If the `completion' is provided
2245 it will be called to indicate whether public was verified or not. For
2246 server/router public key this will check for filename that includes the
2247 remote host's IP address and remote host's hostname. */
2250 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2252 SilcConnectionType conn_type,
2253 SilcPublicKey public_key,
2254 SilcVerifyPublicKey completion, void *context)
2256 PublicKeyVerify verify;
2257 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2258 char *fingerprint, *babbleprint, *format;
2259 SilcPublicKey local_pubkey;
2261 const char *hostname, *ip;
2266 char *entity = ((conn_type == SILC_CONN_SERVER ||
2267 conn_type == SILC_CONN_ROUTER) ?
2268 "server" : "client");
2271 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2272 printformat_module("fe-common/silc", NULL, NULL,
2273 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2274 entity, silc_pkcs_get_type(public_key));
2276 completion(FALSE, context);
2280 /* Encode public key */
2281 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2284 completion(FALSE, context);
2288 pw = getpwuid(getuid());
2291 completion(FALSE, context);
2295 memset(filename, 0, sizeof(filename));
2296 memset(filename2, 0, sizeof(filename2));
2297 memset(file, 0, sizeof(file));
2299 /* Get remote host information */
2300 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2301 NULL, &hostname, &ip, &port);
2303 if (conn_type == SILC_CONN_SERVER ||
2304 conn_type == SILC_CONN_ROUTER) {
2306 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2307 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2308 get_irssi_dir(), entity, file);
2310 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2312 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2313 get_irssi_dir(), entity, file);
2318 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2320 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2321 get_irssi_dir(), entity, file);
2326 /* Replace all whitespaces with `_'. */
2327 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2328 for (i = 0; i < strlen(fingerprint); i++)
2329 if (fingerprint[i] == ' ')
2330 fingerprint[i] = '_';
2332 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2333 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2334 get_irssi_dir(), entity, file);
2335 silc_free(fingerprint);
2340 /* Take fingerprint of the public key */
2341 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2342 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2344 verify = silc_calloc(1, sizeof(*verify));
2345 verify->client = client;
2346 verify->conn = conn;
2347 verify->filename = strdup(ipf);
2348 verify->entity = strdup(entity);
2349 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2350 (name ? strdup(name) : strdup(hostname))
2352 verify->public_key = public_key;
2353 verify->completion = completion;
2354 verify->context = context;
2356 /* Check whether this key already exists */
2357 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2358 /* Key does not exist, ask user to verify the key and save it */
2360 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2361 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2362 verify->entity_name : entity);
2363 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2364 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2365 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2366 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2367 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2368 SILCTXT_PUBKEY_ACCEPT);
2369 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2372 silc_free(fingerprint);
2375 /* The key already exists, verify it. */
2376 unsigned char *encpk;
2377 SilcUInt32 encpk_len;
2379 /* Load the key file, try for both IP filename and hostname filename */
2380 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2381 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2382 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2383 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2384 verify->entity_name : entity);
2385 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2386 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2387 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2388 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2389 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2390 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2391 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2392 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2393 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2396 silc_free(fingerprint);
2400 /* Encode the key data */
2401 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2403 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2404 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2405 verify->entity_name : entity);
2406 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2407 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2408 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2409 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2410 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2411 SILCTXT_PUBKEY_MALFORMED, entity);
2412 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2413 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2414 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2417 silc_free(fingerprint);
2421 /* Compare the keys */
2422 if (memcmp(encpk, pk, encpk_len)) {
2423 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2424 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2425 verify->entity_name : entity);
2426 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2427 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2428 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2429 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2430 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2431 SILCTXT_PUBKEY_NO_MATCH, entity);
2432 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2433 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2434 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2435 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2437 /* Ask user to verify the key and save it */
2438 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2439 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2440 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2443 silc_free(fingerprint);
2448 /* Local copy matched */
2450 completion(TRUE, context);
2452 silc_free(fingerprint);
2453 silc_free(verify->filename);
2454 silc_free(verify->entity);
2455 silc_free(verify->entity_name);
2460 /* Verifies received public key. The `conn_type' indicates which entity
2461 (server, client etc.) has sent the public key. If user decides to trust
2462 the key may be saved as trusted public key for later use. The
2463 `completion' must be called after the public key has been verified. */
2466 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2467 SilcConnectionType conn_type,
2468 SilcPublicKey public_key,
2469 SilcVerifyPublicKey completion, void *context)
2471 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2472 completion, context);
2475 /* Asks passphrase from user on the input line. */
2478 SilcAskPassphrase completion;
2482 void ask_passphrase_completion(const char *passphrase, void *context)
2484 AskPassphrase p = (AskPassphrase)context;
2485 if (passphrase && passphrase[0] == '\0')
2487 p->completion((unsigned char *)passphrase,
2488 passphrase ? strlen(passphrase) : 0, p->context);
2492 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2493 SilcAskPassphrase completion, void *context)
2495 AskPassphrase p = silc_calloc(1, sizeof(*p));
2496 p->completion = completion;
2497 p->context = context;
2499 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2500 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2504 SilcGetAuthMeth completion;
2506 } *InternalGetAuthMethod;
2508 /* Callback called when we've received the authentication method information
2509 from the server after we've requested it. This will get the authentication
2510 data from the user if needed. */
2512 static void silc_get_auth_method_callback(SilcClient client,
2513 SilcClientConnection conn,
2514 SilcAuthMethod auth_meth,
2517 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2519 SILC_LOG_DEBUG(("Start"));
2521 switch (auth_meth) {
2522 case SILC_AUTH_NONE:
2523 /* No authentication required. */
2524 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2526 case SILC_AUTH_PASSWORD:
2528 /* Check whether we find the password for this server in our
2529 configuration. If not, then don't provide so library will ask
2530 it from the user. */
2531 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2533 if (!setup || !setup->password) {
2534 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2538 (*internal->completion)(TRUE, auth_meth, setup->password,
2539 strlen(setup->password), internal->context);
2542 case SILC_AUTH_PUBLIC_KEY:
2543 /* Do not get the authentication data now, the library will generate
2544 it using our default key, if we do not provide it here. */
2545 /* XXX In the future when we support multiple local keys and multiple
2546 local certificates we will need to ask from user which one to use. */
2547 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2551 silc_free(internal);
2554 /* Find authentication method and authentication data by hostname and
2555 port. The hostname may be IP address as well. The found authentication
2556 method and authentication data is returned to `auth_meth', `auth_data'
2557 and `auth_data_len'. The function returns TRUE if authentication method
2558 is found and FALSE if not. `conn' may be NULL. */
2560 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2561 char *hostname, SilcUInt16 port,
2562 SilcGetAuthMeth completion, void *context)
2564 InternalGetAuthMethod internal;
2566 SILC_LOG_DEBUG(("Start"));
2568 /* If we do not have this connection configured by the user in a
2569 configuration file then resolve the authentication method from the
2570 server for this session. */
2571 internal = silc_calloc(1, sizeof(*internal));
2572 internal->completion = completion;
2573 internal->context = context;
2576 silc_client_request_authentication_method(client, conn,
2577 silc_get_auth_method_callback,
2580 completion(TRUE, SILC_AUTH_NONE, NULL, 0, context);
2584 /* Asks whether the user would like to perform the key agreement protocol.
2585 This is called after we have received an key agreement packet or an
2586 reply to our key agreement packet. This returns TRUE if the user wants
2587 the library to perform the key agreement protocol and FALSE if it is not
2588 desired (application may start it later by calling the function
2589 silc_client_perform_key_agreement). */
2591 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2592 SilcClientEntry client_entry, const char *hostname,
2593 SilcUInt16 protocol, SilcUInt16 port)
2595 char portstr[12], protostr[5];
2597 SILC_LOG_DEBUG(("Start"));
2599 /* We will just display the info on the screen and return FALSE and user
2600 will have to start the key agreement with a command. */
2603 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2604 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2609 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2610 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2612 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2613 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2614 client_entry->nickname, hostname, portstr, protostr);
2617 /* Notifies application that file transfer protocol session is being
2618 requested by the remote client indicated by the `client_entry' from
2619 the `hostname' and `port'. The `session_id' is the file transfer
2620 session and it can be used to either accept or reject the file
2621 transfer request, by calling the silc_client_file_receive or
2622 silc_client_file_close, respectively. */
2624 void silc_ftp(SilcClient client, SilcClientConnection conn,
2625 SilcClientEntry client_entry, SilcUInt32 session_id,
2626 const char *hostname, SilcUInt16 port)
2628 SILC_SERVER_REC *server;
2630 FtpSession ftp = NULL;
2632 SILC_LOG_DEBUG(("Start"));
2634 server = conn->context;
2636 silc_dlist_start(server->ftp_sessions);
2637 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2638 if (ftp->client_entry == client_entry &&
2639 ftp->session_id == session_id) {
2640 server->current_session = ftp;
2644 if (ftp == SILC_LIST_END) {
2645 ftp = silc_calloc(1, sizeof(*ftp));
2646 ftp->client_entry = client_entry;
2647 ftp->session_id = session_id;
2650 silc_dlist_add(server->ftp_sessions, ftp);
2651 server->current_session = ftp;
2655 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2658 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2659 SILCTXT_FILE_REQUEST, client_entry->nickname);
2661 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2662 SILCTXT_FILE_REQUEST_HOST,
2663 client_entry->nickname, hostname, portstr);
2666 /* Delivers SILC session detachment data indicated by `detach_data' to the
2667 application. If application has issued SILC_COMMAND_DETACH command
2668 the client session in the SILC network is not quit. The client remains
2669 in the network but is detached. The detachment data may be used later
2670 to resume the session in the SILC Network. The appliation is
2671 responsible of saving the `detach_data', to for example in a file.
2673 The detachment data can be given as argument to the functions
2674 silc_client_connect_to_server, or silc_client_add_connection when
2675 creating connection to remote server, inside SilcClientConnectionParams
2676 structure. If it is provided the client library will attempt to resume
2677 the session in the network. After the connection is created
2678 successfully, the application is responsible of setting the user
2679 interface for user into the same state it was before detaching (showing
2680 same channels, channel modes, etc). It can do this by fetching the
2681 information (like joined channels) from the client library. */
2684 silc_detach(SilcClient client, SilcClientConnection conn,
2685 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2687 SILC_SERVER_REC *server = conn->context;
2690 /* Save the detachment data to file. */
2692 file = silc_get_session_filename(server);
2693 silc_file_writefile(file, detach_data, detach_data_len);
2697 /* Called to indicate the client library is running. */
2700 silc_running(SilcClient client, void *application)
2702 SILC_LOG_DEBUG(("Client library is running"));
2705 /* SILC client operations */
2706 SilcClientOperations ops = {
2708 silc_channel_message,
2709 silc_private_message,
2713 silc_get_auth_method,
2714 silc_verify_public_key,
2715 silc_ask_passphrase,