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.
1155 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1157 (void)va_arg(va, void *);
1158 clients = va_arg(va, SilcDList);
1160 silc_dlist_start(clients);
1161 while ((client_entry = silc_dlist_get(clients))) {
1162 memset(buf, 0, sizeof(buf));
1164 /* Print only if we have the nickname. If this client has just quit
1165 when we were only resolving it, it is possible we don't have the
1167 if (client_entry->nickname[0]) {
1168 if (client_entry->username[0])
1169 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1170 client_entry->username, client_entry->hostname);
1171 signal_emit("message quit", 4, server, client_entry->nickname,
1172 client_entry->username[0] ? buf : "",
1177 silc_server_free_ftp(server, client_entry);
1180 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1181 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1182 list_tmp->next->next) {
1183 CHANNEL_REC *channel = list_tmp->data;
1184 NICK_REC *nickrec = list_tmp->next->data;
1185 nicklist_remove(channel, nickrec);
1191 case SILC_NOTIFY_TYPE_ERROR:
1193 SilcStatus error = va_arg(va, int);
1195 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1196 "%s", silc_get_status_message(error));
1200 case SILC_NOTIFY_TYPE_WATCH:
1202 SilcNotifyType notify;
1204 client_entry = va_arg(va, SilcClientEntry);
1205 name = va_arg(va, char *); /* Maybe NULL */
1206 mode = va_arg(va, SilcUInt32);
1207 notify = va_arg(va, int);
1209 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1211 printformat_module("fe-common/silc", server, NULL,
1212 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1213 client_entry->nickname, name);
1215 printformat_module("fe-common/silc", server, NULL,
1216 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1217 client_entry->nickname);
1218 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1219 /* See if client was away and is now present */
1220 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1221 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1222 SILC_UMODE_DETACHED)) &&
1223 (client_entry->mode & SILC_UMODE_GONE ||
1224 client_entry->mode & SILC_UMODE_INDISPOSED ||
1225 client_entry->mode & SILC_UMODE_BUSY ||
1226 client_entry->mode & SILC_UMODE_PAGE ||
1227 client_entry->mode & SILC_UMODE_DETACHED)) {
1228 printformat_module("fe-common/silc", server, NULL,
1229 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1230 client_entry->nickname);
1234 memset(buf, 0, sizeof(buf));
1235 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1236 printformat_module("fe-common/silc", server, NULL,
1237 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1238 client_entry->nickname, buf);
1240 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1241 printformat_module("fe-common/silc", server, NULL,
1242 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1243 client_entry->nickname);
1244 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1245 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1246 printformat_module("fe-common/silc", server, NULL,
1247 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1248 client_entry->nickname);
1249 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1250 /* Client logged in to the network */
1251 printformat_module("fe-common/silc", server, NULL,
1252 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1253 client_entry->nickname);
1259 /* Unknown notify */
1260 printformat_module("fe-common/silc", server, NULL,
1261 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1268 /* Command handler. This function is called always in the command function.
1269 If error occurs it will be called as well. `conn' is the associated
1270 client connection. `cmd_context' is the command context that was
1271 originally sent to the command. `success' is FALSE if error occured
1272 during command. `command' is the command being processed. It must be
1273 noted that this is not reply from server. This is merely called just
1274 after application has called the command. Just to tell application
1275 that the command really was processed. */
1277 static bool cmode_list_chpks = FALSE;
1279 void silc_command(SilcClient client, SilcClientConnection conn,
1280 SilcBool success, SilcCommand command, SilcStatus status,
1281 SilcUInt32 argc, unsigned char **argv)
1283 SILC_SERVER_REC *server = conn->context;
1285 SILC_LOG_DEBUG(("Start"));
1288 silc_say_error("%s", silc_get_status_message(status));
1294 case SILC_COMMAND_INVITE:
1296 printformat_module("fe-common/silc", server, NULL,
1297 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1299 (argv[1][0] == '*' ?
1300 (char *)conn->current_channel->channel_name :
1304 case SILC_COMMAND_DETACH:
1305 server->no_reconnect = TRUE;
1308 case SILC_COMMAND_CMODE:
1309 if (argc == 3 && !strcmp(argv[2], "+C"))
1310 cmode_list_chpks = TRUE;
1312 cmode_list_chpks = FALSE;
1322 SilcClientConnection conn;
1327 void silc_getkey_cb(bool success, void *context)
1329 GetkeyContext getkey = (GetkeyContext)context;
1330 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1331 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1332 ((SilcClientEntry)getkey->entry)->nickname :
1333 ((SilcServerEntry)getkey->entry)->server_name);
1336 printformat_module("fe-common/silc", NULL, NULL,
1337 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1339 printformat_module("fe-common/silc", NULL, NULL,
1340 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1347 /* Parse an invite or ban list */
1348 void silc_parse_inviteban_list(SilcClient client,
1349 SilcClientConnection conn,
1350 SILC_SERVER_REC *server,
1351 SilcChannelEntry channel,
1352 const char *list_type,
1353 SilcArgumentPayload list)
1356 SilcUInt32 type, len;
1357 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1358 int counter=0, resolving = FALSE;
1360 if (!silc_argument_get_arg_num(list)) {
1361 printformat_module("fe-common/silc", server,
1362 (chanrec ? chanrec->visible_name : NULL),
1363 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1364 channel->channel_name, list_type);
1368 printformat_module("fe-common/silc", server,
1369 (chanrec ? chanrec->visible_name : NULL),
1370 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1371 channel->channel_name, list_type);
1373 /* Parse the list */
1374 tmp = silc_argument_get_first_arg(list, &type, &len);
1379 /* An invite string */
1383 if (tmp[len-1] == ',')
1386 list = g_strsplit(tmp, ",", -1);
1388 printformat_module("fe-common/silc", server,
1389 (chanrec ? chanrec->visible_name : NULL),
1390 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1391 ++counter, channel->channel_name, list_type,
1400 char *fingerprint, *babbleprint;
1402 /* tmp is Public Key Payload, take public key from it. */
1403 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1404 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1406 printformat_module("fe-common/silc", server,
1407 (chanrec ? chanrec->visible_name : NULL),
1408 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1409 ++counter, channel->channel_name, list_type,
1410 fingerprint, babbleprint);
1417 SilcClientEntry client_entry;
1420 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1421 silc_say_error("Invalid data in %s list encountered", list_type);
1425 client_entry = silc_client_get_client_by_id(client, conn,
1428 printformat_module("fe-common/silc", server,
1429 (chanrec ? chanrec->visible_name : NULL),
1430 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1431 ++counter, channel->channel_name, list_type,
1432 client_entry->nickname);
1433 silc_client_unref_client(client, conn, client_entry);
1436 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1444 silc_say_error("Unkown type in %s list: %u (len %u)",
1445 list_type, type, len);
1448 tmp = silc_argument_get_next_arg(list, &type, &len);
1452 printformat_module("fe-common/silc", server,
1453 (chanrec ? chanrec->visible_name : NULL),
1454 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1455 list_type, channel->channel_name);
1458 /* Command reply handler. This function is called always in the command reply
1459 function. If error occurs it will be called as well. Normal scenario
1460 is that it will be called after the received command data has been parsed
1461 and processed. The function is used to pass the received command data to
1464 `conn' is the associated client connection. `cmd_payload' is the command
1465 payload data received from server and it can be ignored. It is provided
1466 if the application would like to re-parse the received command data,
1467 however, it must be noted that the data is parsed already by the library
1468 thus the payload can be ignored. `success' is FALSE if error occured.
1469 In this case arguments are not sent to the application. `command' is the
1470 command reply being processed. The function has variable argument list
1471 and each command defines the number and type of arguments it passes to the
1472 application (on error they are not sent). */
1474 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1475 SilcCommand command, SilcStatus status,
1476 SilcStatus error, va_list vp)
1478 SILC_SERVER_REC *server = conn->context;
1479 SILC_CHANNEL_REC *chanrec;
1481 SILC_LOG_DEBUG(("Start"));
1484 case SILC_COMMAND_WHOIS:
1486 char buf[1024], *nickname, *username, *realname, nick[128 + 1];
1487 unsigned char *fingerprint;
1488 SilcUInt32 idle, mode, *user_modes;
1490 SilcClientEntry client_entry;
1493 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1494 /* Print the unknown nick for user */
1495 char *tmp = va_arg(vp, char *);
1497 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1499 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1500 /* Try to find the entry for the unknown client ID, since we
1501 might have, and print the nickname of it for user. */
1502 SilcClientID *id = va_arg(vp, SilcClientID *);
1504 client_entry = silc_client_get_client_by_id(client, conn, id);
1505 if (client_entry && client_entry->nickname[0])
1506 silc_say_error("%s: %s", client_entry->nickname,
1507 silc_get_status_message(status));
1508 silc_client_unref_client(client, conn, client_entry);
1511 } else if (SILC_STATUS_IS_ERROR(status)) {
1512 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1516 client_entry = va_arg(vp, SilcClientEntry);
1517 nickname = va_arg(vp, char *);
1518 username = va_arg(vp, char *);
1519 realname = va_arg(vp, char *);
1520 channels = va_arg(vp, SilcDList);
1521 mode = va_arg(vp, SilcUInt32);
1522 idle = va_arg(vp, SilcUInt32);
1523 fingerprint = va_arg(vp, unsigned char *);
1524 user_modes = va_arg(vp, SilcUInt32 *);
1525 attrs = va_arg(vp, SilcDList);
1527 silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
1528 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1529 SILCTXT_WHOIS_USERINFO, nickname,
1530 client_entry->username, client_entry->hostname,
1531 nick, client_entry->nickname);
1532 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1533 SILCTXT_WHOIS_REALNAME, realname);
1535 if (channels && user_modes) {
1536 SilcChannelPayload entry;
1539 memset(buf, 0, sizeof(buf));
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)) {
1860 silc_say_error("OPER: %s", silc_get_status_message(status));
1864 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1865 signal_emit("user mode changed", 2, server, NULL);
1867 printformat_module("fe-common/silc", server, NULL,
1868 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1871 case SILC_COMMAND_SILCOPER:
1872 if (SILC_STATUS_IS_ERROR(status)) {
1873 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1877 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1878 signal_emit("user mode changed", 2, server, NULL);
1880 printformat_module("fe-common/silc", server, NULL,
1881 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1884 case SILC_COMMAND_USERS:
1886 SilcHashTableList htl;
1887 SilcChannelEntry channel;
1888 SilcChannelUser chu;
1890 if (SILC_STATUS_IS_ERROR(status)) {
1891 silc_say_error("USERS: %s", silc_get_status_message(status));
1895 channel = va_arg(vp, SilcChannelEntry);
1897 printformat_module("fe-common/silc", server, channel->channel_name,
1898 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1899 channel->channel_name);
1901 silc_hash_table_list(channel->user_list, &htl);
1902 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1903 SilcClientEntry e = chu->client;
1904 char stat[5], *mode;
1909 memset(stat, 0, sizeof(stat));
1910 mode = silc_client_chumode_char(chu->mode);
1911 if (e->mode & SILC_UMODE_GONE)
1913 else if (e->mode & SILC_UMODE_INDISPOSED)
1915 else if (e->mode & SILC_UMODE_BUSY)
1917 else if (e->mode & SILC_UMODE_PAGE)
1919 else if (e->mode & SILC_UMODE_HYPER)
1921 else if (e->mode & SILC_UMODE_ROBOT)
1923 else if (e->mode & SILC_UMODE_ANONYMOUS)
1930 printformat_module("fe-common/silc", server, channel->channel_name,
1931 MSGLEVEL_CRAP, SILCTXT_USERS,
1933 e->username ? e->username : "",
1934 e->hostname ? e->hostname : "",
1935 e->realname ? e->realname : "");
1939 silc_hash_table_list_reset(&htl);
1943 case SILC_COMMAND_BAN:
1945 SilcChannelEntry channel;
1946 SilcArgumentPayload invite_list;
1948 if (SILC_STATUS_IS_ERROR(status))
1951 channel = va_arg(vp, SilcChannelEntry);
1952 invite_list = va_arg(vp, SilcArgumentPayload);
1955 silc_parse_inviteban_list(client, conn, server, channel,
1956 "ban", invite_list);
1960 case SILC_COMMAND_GETKEY:
1964 SilcPublicKey public_key;
1965 GetkeyContext getkey;
1968 if (SILC_STATUS_IS_ERROR(status)) {
1969 silc_say_error("GETKEY: %s", silc_get_status_message(status));
1973 id_type = va_arg(vp, SilcUInt32);
1974 entry = va_arg(vp, void *);
1975 public_key = va_arg(vp, SilcPublicKey);
1978 getkey = silc_calloc(1, sizeof(*getkey));
1979 getkey->entry = entry;
1980 getkey->id_type = id_type;
1981 getkey->client = client;
1982 getkey->conn = conn;
1984 name = (id_type == SILC_ID_CLIENT ?
1985 ((SilcClientEntry)entry)->nickname :
1986 ((SilcServerEntry)entry)->server_name);
1988 silc_verify_public_key_internal(client, conn, name,
1989 (id_type == SILC_ID_CLIENT ?
1992 public_key, silc_getkey_cb, getkey);
1994 printformat_module("fe-common/silc", server, NULL,
1995 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2000 case SILC_COMMAND_INFO:
2002 SilcServerEntry server_entry;
2006 if (SILC_STATUS_IS_ERROR(status))
2009 server_entry = va_arg(vp, SilcServerEntry);
2010 server_name = va_arg(vp, char *);
2011 server_info = va_arg(vp, char *);
2013 if (server_name && server_info )
2015 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2016 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2021 case SILC_COMMAND_TOPIC:
2023 SilcChannelEntry channel;
2025 char tmp[256], *cp, *dm = NULL;
2027 if (SILC_STATUS_IS_ERROR(status))
2030 channel = va_arg(vp, SilcChannelEntry);
2031 topic = va_arg(vp, char *);
2033 if (topic && !silc_term_utf8() &&
2034 silc_utf8_valid(topic, strlen(topic))) {
2035 memset(tmp, 0, sizeof(tmp));
2037 if (strlen(topic) > sizeof(tmp) - 1) {
2038 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2042 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2048 chanrec = silc_channel_find_entry(server, channel);
2050 g_free_not_null(chanrec->topic);
2051 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2052 signal_emit("channel topic changed", 1, chanrec);
2054 printformat_module("fe-common/silc", server, channel->channel_name,
2055 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2056 channel->channel_name, topic);
2058 printformat_module("fe-common/silc", server, channel->channel_name,
2059 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2060 channel->channel_name);
2066 case SILC_COMMAND_WATCH:
2069 case SILC_COMMAND_STATS:
2071 SilcClientStats *cstats;
2073 const char *tmptime;
2074 int days, hours, mins, secs;
2076 if (SILC_STATUS_IS_ERROR(status))
2079 cstats = va_arg(vp, SilcClientStats *);
2081 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2085 tmptime = silc_time_string(cstats->starttime);
2086 printformat_module("fe-common/silc", server, NULL,
2087 MSGLEVEL_CRAP, SILCTXT_STATS,
2088 "Local server start time", tmptime);
2090 days = cstats->uptime / (24 * 60 * 60);
2091 cstats->uptime -= days * (24 * 60 * 60);
2092 hours = cstats->uptime / (60 * 60);
2093 cstats->uptime -= hours * (60 * 60);
2094 mins = cstats->uptime / 60;
2095 cstats->uptime -= mins * 60;
2096 secs = cstats->uptime;
2097 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2098 days, hours, mins, secs);
2099 printformat_module("fe-common/silc", server, NULL,
2100 MSGLEVEL_CRAP, SILCTXT_STATS,
2101 "Local server uptime", tmp);
2103 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2104 printformat_module("fe-common/silc", server, NULL,
2105 MSGLEVEL_CRAP, SILCTXT_STATS,
2106 "Local server clients", tmp);
2108 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2109 printformat_module("fe-common/silc", server, NULL,
2110 MSGLEVEL_CRAP, SILCTXT_STATS,
2111 "Local server channels", tmp);
2113 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2114 printformat_module("fe-common/silc", server, NULL,
2115 MSGLEVEL_CRAP, SILCTXT_STATS,
2116 "Local server operators", tmp);
2118 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2119 printformat_module("fe-common/silc", server, NULL,
2120 MSGLEVEL_CRAP, SILCTXT_STATS,
2121 "Local router operators", tmp);
2123 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2124 printformat_module("fe-common/silc", server, NULL,
2125 MSGLEVEL_CRAP, SILCTXT_STATS,
2126 "Local cell clients", tmp);
2128 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2129 printformat_module("fe-common/silc", server, NULL,
2130 MSGLEVEL_CRAP, SILCTXT_STATS,
2131 "Local cell channels", tmp);
2133 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2134 printformat_module("fe-common/silc", server, NULL,
2135 MSGLEVEL_CRAP, SILCTXT_STATS,
2136 "Local cell servers", tmp);
2138 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2139 printformat_module("fe-common/silc", server, NULL,
2140 MSGLEVEL_CRAP, SILCTXT_STATS,
2141 "Total clients", tmp);
2143 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2144 printformat_module("fe-common/silc", server, NULL,
2145 MSGLEVEL_CRAP, SILCTXT_STATS,
2146 "Total channels", tmp);
2148 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2149 printformat_module("fe-common/silc", server, NULL,
2150 MSGLEVEL_CRAP, SILCTXT_STATS,
2151 "Total servers", tmp);
2153 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2154 printformat_module("fe-common/silc", server, NULL,
2155 MSGLEVEL_CRAP, SILCTXT_STATS,
2156 "Total routers", tmp);
2158 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2159 printformat_module("fe-common/silc", server, NULL,
2160 MSGLEVEL_CRAP, SILCTXT_STATS,
2161 "Total server operators", tmp);
2163 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2164 printformat_module("fe-common/silc", server, NULL,
2165 MSGLEVEL_CRAP, SILCTXT_STATS,
2166 "Total router operators", tmp);
2170 case SILC_COMMAND_CMODE:
2172 SilcChannelEntry channel_entry;
2175 channel_entry = va_arg(vp, SilcChannelEntry);
2176 (void)va_arg(vp, SilcUInt32);
2177 (void)va_arg(vp, SilcPublicKey);
2178 chpks = va_arg(vp, SilcDList);
2180 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2181 !channel_entry || !channel_entry->channel_name)
2184 /* Print the channel public key list */
2186 silc_parse_channel_public_keys(server, channel_entry, chpks);
2188 printformat_module("fe-common/silc", server, NULL,
2189 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2190 channel_entry->channel_name);
2195 case SILC_COMMAND_LEAVE:
2197 /* we might be cycling, so disable queueing again */
2198 silc_queue_disable(conn);
2207 SilcClientConnection conn;
2211 SilcPublicKey public_key;
2212 SilcVerifyPublicKey completion;
2216 static void verify_public_key_completion(const char *line, void *context)
2218 PublicKeyVerify verify = (PublicKeyVerify)context;
2220 if (line[0] == 'Y' || line[0] == 'y') {
2221 /* Call the completion */
2222 if (verify->completion)
2223 verify->completion(TRUE, verify->context);
2225 /* Save the key for future checking */
2226 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2227 SILC_PKCS_FILE_BASE64);
2229 /* Call the completion */
2230 if (verify->completion)
2231 verify->completion(FALSE, verify->context);
2233 printformat_module("fe-common/silc", NULL, NULL,
2234 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2235 verify->entity_name ? verify->entity_name :
2239 silc_free(verify->filename);
2240 silc_free(verify->entity);
2241 silc_free(verify->entity_name);
2245 /* Internal routine to verify public key. If the `completion' is provided
2246 it will be called to indicate whether public was verified or not. For
2247 server/router public key this will check for filename that includes the
2248 remote host's IP address and remote host's hostname. */
2251 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2253 SilcConnectionType conn_type,
2254 SilcPublicKey public_key,
2255 SilcVerifyPublicKey completion, void *context)
2257 PublicKeyVerify verify;
2258 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2259 char *fingerprint, *babbleprint, *format;
2260 SilcPublicKey local_pubkey;
2262 const char *hostname, *ip;
2267 char *entity = ((conn_type == SILC_CONN_SERVER ||
2268 conn_type == SILC_CONN_ROUTER) ?
2269 "server" : "client");
2272 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2273 printformat_module("fe-common/silc", NULL, NULL,
2274 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2275 entity, silc_pkcs_get_type(public_key));
2277 completion(FALSE, context);
2281 /* Encode public key */
2282 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2285 completion(FALSE, context);
2289 pw = getpwuid(getuid());
2292 completion(FALSE, context);
2296 memset(filename, 0, sizeof(filename));
2297 memset(filename2, 0, sizeof(filename2));
2298 memset(file, 0, sizeof(file));
2300 /* Get remote host information */
2301 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2302 NULL, &hostname, &ip, &port);
2304 if (conn_type == SILC_CONN_SERVER ||
2305 conn_type == SILC_CONN_ROUTER) {
2307 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2308 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2309 get_irssi_dir(), entity, file);
2311 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2313 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2314 get_irssi_dir(), entity, file);
2319 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2321 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2322 get_irssi_dir(), entity, file);
2327 /* Replace all whitespaces with `_'. */
2328 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2329 for (i = 0; i < strlen(fingerprint); i++)
2330 if (fingerprint[i] == ' ')
2331 fingerprint[i] = '_';
2333 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2334 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2335 get_irssi_dir(), entity, file);
2336 silc_free(fingerprint);
2341 /* Take fingerprint of the public key */
2342 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2343 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2345 verify = silc_calloc(1, sizeof(*verify));
2346 verify->client = client;
2347 verify->conn = conn;
2348 verify->filename = strdup(ipf);
2349 verify->entity = strdup(entity);
2350 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2351 (name ? strdup(name) : strdup(hostname))
2353 verify->public_key = public_key;
2354 verify->completion = completion;
2355 verify->context = context;
2357 /* Check whether this key already exists */
2358 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2359 /* Key does not exist, ask user to verify the key and save it */
2361 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2362 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2363 verify->entity_name : entity);
2364 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2365 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2366 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2367 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2368 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2369 SILCTXT_PUBKEY_ACCEPT);
2370 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2373 silc_free(fingerprint);
2376 /* The key already exists, verify it. */
2377 unsigned char *encpk;
2378 SilcUInt32 encpk_len;
2380 /* Load the key file, try for both IP filename and hostname filename */
2381 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2382 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2383 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2384 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2385 verify->entity_name : entity);
2386 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2387 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2388 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2389 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2390 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2391 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2392 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2393 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2394 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2397 silc_free(fingerprint);
2401 /* Encode the key data */
2402 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2404 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2405 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2406 verify->entity_name : entity);
2407 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2408 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2409 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2410 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2411 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2412 SILCTXT_PUBKEY_MALFORMED, entity);
2413 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2414 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2415 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2418 silc_free(fingerprint);
2422 /* Compare the keys */
2423 if (memcmp(encpk, pk, encpk_len)) {
2424 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2425 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2426 verify->entity_name : entity);
2427 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2428 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2429 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2430 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2431 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2432 SILCTXT_PUBKEY_NO_MATCH, entity);
2433 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2434 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2435 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2436 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2438 /* Ask user to verify the key and save it */
2439 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2440 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2441 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2444 silc_free(fingerprint);
2449 /* Local copy matched */
2451 completion(TRUE, context);
2453 silc_free(fingerprint);
2454 silc_free(verify->filename);
2455 silc_free(verify->entity);
2456 silc_free(verify->entity_name);
2461 /* Verifies received public key. The `conn_type' indicates which entity
2462 (server, client etc.) has sent the public key. If user decides to trust
2463 the key may be saved as trusted public key for later use. The
2464 `completion' must be called after the public key has been verified. */
2467 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2468 SilcConnectionType conn_type,
2469 SilcPublicKey public_key,
2470 SilcVerifyPublicKey completion, void *context)
2472 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2473 completion, context);
2476 /* Asks passphrase from user on the input line. */
2479 SilcAskPassphrase completion;
2483 void ask_passphrase_completion(const char *passphrase, void *context)
2485 AskPassphrase p = (AskPassphrase)context;
2486 if (passphrase && passphrase[0] == '\0')
2488 p->completion((unsigned char *)passphrase,
2489 passphrase ? strlen(passphrase) : 0, p->context);
2493 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2494 SilcAskPassphrase completion, void *context)
2496 AskPassphrase p = silc_calloc(1, sizeof(*p));
2497 p->completion = completion;
2498 p->context = context;
2500 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2501 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2505 SilcGetAuthMeth completion;
2507 } *InternalGetAuthMethod;
2509 /* Callback called when we've received the authentication method information
2510 from the server after we've requested it. This will get the authentication
2511 data from the user if needed. */
2513 static void silc_get_auth_method_callback(SilcClient client,
2514 SilcClientConnection conn,
2515 SilcAuthMethod auth_meth,
2518 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2520 SILC_LOG_DEBUG(("Start"));
2522 switch (auth_meth) {
2523 case SILC_AUTH_NONE:
2524 /* No authentication required. */
2525 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2527 case SILC_AUTH_PASSWORD:
2529 /* Check whether we find the password for this server in our
2530 configuration. If not, then don't provide so library will ask
2531 it from the user. */
2532 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2534 if (!setup || !setup->password) {
2535 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2539 (*internal->completion)(TRUE, auth_meth, setup->password,
2540 strlen(setup->password), internal->context);
2543 case SILC_AUTH_PUBLIC_KEY:
2544 /* Do not get the authentication data now, the library will generate
2545 it using our default key, if we do not provide it here. */
2546 /* XXX In the future when we support multiple local keys and multiple
2547 local certificates we will need to ask from user which one to use. */
2548 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2552 silc_free(internal);
2555 /* Find authentication method and authentication data by hostname and
2556 port. The hostname may be IP address as well. The found authentication
2557 method and authentication data is returned to `auth_meth', `auth_data'
2558 and `auth_data_len'. The function returns TRUE if authentication method
2559 is found and FALSE if not. `conn' may be NULL. */
2561 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2562 char *hostname, SilcUInt16 port,
2563 SilcGetAuthMeth completion, void *context)
2565 InternalGetAuthMethod internal;
2567 SILC_LOG_DEBUG(("Start"));
2569 /* If we do not have this connection configured by the user in a
2570 configuration file then resolve the authentication method from the
2571 server for this session. */
2572 internal = silc_calloc(1, sizeof(*internal));
2573 internal->completion = completion;
2574 internal->context = context;
2577 silc_client_request_authentication_method(client, conn,
2578 silc_get_auth_method_callback,
2581 completion(TRUE, SILC_AUTH_NONE, NULL, 0, context);
2585 /* Asks whether the user would like to perform the key agreement protocol.
2586 This is called after we have received an key agreement packet or an
2587 reply to our key agreement packet. This returns TRUE if the user wants
2588 the library to perform the key agreement protocol and FALSE if it is not
2589 desired (application may start it later by calling the function
2590 silc_client_perform_key_agreement). */
2592 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2593 SilcClientEntry client_entry, const char *hostname,
2594 SilcUInt16 protocol, SilcUInt16 port)
2596 char portstr[12], protostr[5];
2598 SILC_LOG_DEBUG(("Start"));
2600 /* We will just display the info on the screen and return FALSE and user
2601 will have to start the key agreement with a command. */
2604 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2605 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2610 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2611 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2613 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2614 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2615 client_entry->nickname, hostname, portstr, protostr);
2618 /* Notifies application that file transfer protocol session is being
2619 requested by the remote client indicated by the `client_entry' from
2620 the `hostname' and `port'. The `session_id' is the file transfer
2621 session and it can be used to either accept or reject the file
2622 transfer request, by calling the silc_client_file_receive or
2623 silc_client_file_close, respectively. */
2625 void silc_ftp(SilcClient client, SilcClientConnection conn,
2626 SilcClientEntry client_entry, SilcUInt32 session_id,
2627 const char *hostname, SilcUInt16 port)
2629 SILC_SERVER_REC *server;
2631 FtpSession ftp = NULL;
2633 SILC_LOG_DEBUG(("Start"));
2635 server = conn->context;
2637 silc_dlist_start(server->ftp_sessions);
2638 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2639 if (ftp->client_entry == client_entry &&
2640 ftp->session_id == session_id) {
2641 server->current_session = ftp;
2645 if (ftp == SILC_LIST_END) {
2646 ftp = silc_calloc(1, sizeof(*ftp));
2647 ftp->client_entry = client_entry;
2648 ftp->session_id = session_id;
2651 silc_dlist_add(server->ftp_sessions, ftp);
2652 server->current_session = ftp;
2656 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2659 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2660 SILCTXT_FILE_REQUEST, client_entry->nickname);
2662 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2663 SILCTXT_FILE_REQUEST_HOST,
2664 client_entry->nickname, hostname, portstr);
2667 /* Delivers SILC session detachment data indicated by `detach_data' to the
2668 application. If application has issued SILC_COMMAND_DETACH command
2669 the client session in the SILC network is not quit. The client remains
2670 in the network but is detached. The detachment data may be used later
2671 to resume the session in the SILC Network. The appliation is
2672 responsible of saving the `detach_data', to for example in a file.
2674 The detachment data can be given as argument to the functions
2675 silc_client_connect_to_server, or silc_client_add_connection when
2676 creating connection to remote server, inside SilcClientConnectionParams
2677 structure. If it is provided the client library will attempt to resume
2678 the session in the network. After the connection is created
2679 successfully, the application is responsible of setting the user
2680 interface for user into the same state it was before detaching (showing
2681 same channels, channel modes, etc). It can do this by fetching the
2682 information (like joined channels) from the client library. */
2685 silc_detach(SilcClient client, SilcClientConnection conn,
2686 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2688 SILC_SERVER_REC *server = conn->context;
2691 /* Save the detachment data to file. */
2693 file = silc_get_session_filename(server);
2694 silc_file_writefile(file, detach_data, detach_data_len);
2698 /* SILC client operations */
2699 SilcClientOperations ops = {
2701 silc_channel_message,
2702 silc_private_message,
2706 silc_get_auth_method,
2707 silc_verify_public_key,
2708 silc_ask_passphrase,