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) {
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)
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.
1154 SilcClientEntry *clients;
1155 SilcUInt32 clients_count;
1157 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1159 (void)va_arg(va, void *);
1160 clients = va_arg(va, SilcClientEntry *);
1161 clients_count = va_arg(va, SilcUInt32);
1163 for (i = 0; i < clients_count; i++) {
1164 memset(buf, 0, sizeof(buf));
1166 /* Print only if we have the nickname. If this client has just quit
1167 when we were only resolving it, it is possible we don't have the
1169 if (clients[i]->nickname) {
1170 if (clients[i]->username)
1171 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1172 clients[i]->username, clients[i]->hostname);
1173 signal_emit("message quit", 4, server, clients[i]->nickname,
1174 clients[i]->username ? buf : "",
1179 silc_server_free_ftp(server, clients[i]);
1182 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1183 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1184 list_tmp->next->next) {
1185 CHANNEL_REC *channel = list_tmp->data;
1186 NICK_REC *nickrec = list_tmp->next->data;
1187 nicklist_remove(channel, nickrec);
1193 case SILC_NOTIFY_TYPE_ERROR:
1195 SilcStatus error = va_arg(va, int);
1197 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1198 "%s", silc_get_status_message(error));
1202 case SILC_NOTIFY_TYPE_WATCH:
1204 SilcNotifyType notify;
1206 client_entry = va_arg(va, SilcClientEntry);
1207 name = va_arg(va, char *); /* Maybe NULL */
1208 mode = va_arg(va, SilcUInt32);
1209 notify = va_arg(va, int);
1211 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1213 printformat_module("fe-common/silc", server, NULL,
1214 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1215 client_entry->nickname, name);
1217 printformat_module("fe-common/silc", server, NULL,
1218 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1219 client_entry->nickname);
1220 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1221 /* See if client was away and is now present */
1222 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1223 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1224 SILC_UMODE_DETACHED)) &&
1225 (client_entry->mode & SILC_UMODE_GONE ||
1226 client_entry->mode & SILC_UMODE_INDISPOSED ||
1227 client_entry->mode & SILC_UMODE_BUSY ||
1228 client_entry->mode & SILC_UMODE_PAGE ||
1229 client_entry->mode & SILC_UMODE_DETACHED)) {
1230 printformat_module("fe-common/silc", server, NULL,
1231 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1232 client_entry->nickname);
1236 memset(buf, 0, sizeof(buf));
1237 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1238 printformat_module("fe-common/silc", server, NULL,
1239 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1240 client_entry->nickname, buf);
1242 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1243 printformat_module("fe-common/silc", server, NULL,
1244 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1245 client_entry->nickname);
1246 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1247 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1248 printformat_module("fe-common/silc", server, NULL,
1249 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1250 client_entry->nickname);
1251 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1252 /* Client logged in to the network */
1253 printformat_module("fe-common/silc", server, NULL,
1254 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1255 client_entry->nickname);
1261 /* Unknown notify */
1262 printformat_module("fe-common/silc", server, NULL,
1263 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1270 /* Command handler. This function is called always in the command function.
1271 If error occurs it will be called as well. `conn' is the associated
1272 client connection. `cmd_context' is the command context that was
1273 originally sent to the command. `success' is FALSE if error occured
1274 during command. `command' is the command being processed. It must be
1275 noted that this is not reply from server. This is merely called just
1276 after application has called the command. Just to tell application
1277 that the command really was processed. */
1279 static bool cmode_list_chpks = FALSE;
1281 void silc_command(SilcClient client, SilcClientConnection conn,
1282 SilcBool success, SilcCommand command, SilcStatus status,
1283 SilcUInt32 argc, unsigned char **argv)
1285 SILC_SERVER_REC *server = conn->context;
1287 SILC_LOG_DEBUG(("Start"));
1290 silc_say_error("%s", silc_get_status_message(status));
1296 case SILC_COMMAND_INVITE:
1298 printformat_module("fe-common/silc", server, NULL,
1299 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1301 (argv[1][0] == '*' ?
1302 (char *)conn->current_channel->channel_name :
1306 case SILC_COMMAND_DETACH:
1307 server->no_reconnect = TRUE;
1310 case SILC_COMMAND_CMODE:
1311 if (argc == 3 && !strcmp(argv[2], "+C"))
1312 cmode_list_chpks = TRUE;
1314 cmode_list_chpks = FALSE;
1324 SilcClientConnection conn;
1329 void silc_getkey_cb(bool success, void *context)
1331 GetkeyContext getkey = (GetkeyContext)context;
1332 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1333 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1334 ((SilcClientEntry)getkey->entry)->nickname :
1335 ((SilcServerEntry)getkey->entry)->server_name);
1338 printformat_module("fe-common/silc", NULL, NULL,
1339 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1341 printformat_module("fe-common/silc", NULL, NULL,
1342 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1349 /* Parse an invite or ban list */
1350 void silc_parse_inviteban_list(SilcClient client,
1351 SilcClientConnection conn,
1352 SILC_SERVER_REC *server,
1353 SilcChannelEntry channel,
1354 const char *list_type,
1355 SilcArgumentPayload list)
1358 SilcUInt32 type, len;
1359 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1360 int counter=0, resolving = FALSE;
1362 if (!silc_argument_get_arg_num(list)) {
1363 printformat_module("fe-common/silc", server,
1364 (chanrec ? chanrec->visible_name : NULL),
1365 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1366 channel->channel_name, list_type);
1370 printformat_module("fe-common/silc", server,
1371 (chanrec ? chanrec->visible_name : NULL),
1372 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1373 channel->channel_name, list_type);
1375 /* Parse the list */
1376 tmp = silc_argument_get_first_arg(list, &type, &len);
1381 /* An invite string */
1385 if (tmp[len-1] == ',')
1388 list = g_strsplit(tmp, ",", -1);
1390 printformat_module("fe-common/silc", server,
1391 (chanrec ? chanrec->visible_name : NULL),
1392 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1393 ++counter, channel->channel_name, list_type,
1402 char *fingerprint, *babbleprint;
1404 /* tmp is Public Key Payload, take public key from it. */
1405 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1406 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1408 printformat_module("fe-common/silc", server,
1409 (chanrec ? chanrec->visible_name : NULL),
1410 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1411 ++counter, channel->channel_name, list_type,
1412 fingerprint, babbleprint);
1419 SilcClientEntry client_entry;
1422 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1423 silc_say_error("Invalid data in %s list encountered", list_type);
1427 client_entry = silc_client_get_client_by_id(client, conn,
1430 printformat_module("fe-common/silc", server,
1431 (chanrec ? chanrec->visible_name : NULL),
1432 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1433 ++counter, channel->channel_name, list_type,
1434 client_entry->nickname);
1435 silc_client_unref_client(client, conn, client_entry);
1438 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1446 silc_say_error("Unkown type in %s list: %u (len %u)",
1447 list_type, type, len);
1450 tmp = silc_argument_get_next_arg(list, &type, &len);
1454 printformat_module("fe-common/silc", server,
1455 (chanrec ? chanrec->visible_name : NULL),
1456 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1457 list_type, channel->channel_name);
1460 /* Command reply handler. This function is called always in the command reply
1461 function. If error occurs it will be called as well. Normal scenario
1462 is that it will be called after the received command data has been parsed
1463 and processed. The function is used to pass the received command data to
1466 `conn' is the associated client connection. `cmd_payload' is the command
1467 payload data received from server and it can be ignored. It is provided
1468 if the application would like to re-parse the received command data,
1469 however, it must be noted that the data is parsed already by the library
1470 thus the payload can be ignored. `success' is FALSE if error occured.
1471 In this case arguments are not sent to the application. `command' is the
1472 command reply being processed. The function has variable argument list
1473 and each command defines the number and type of arguments it passes to the
1474 application (on error they are not sent). */
1476 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1477 SilcCommand command, SilcStatus status,
1478 SilcStatus error, va_list vp)
1480 SILC_SERVER_REC *server = conn->context;
1481 SILC_CHANNEL_REC *chanrec;
1483 SILC_LOG_DEBUG(("Start"));
1486 case SILC_COMMAND_WHOIS:
1488 char buf[1024], *nickname, *username, *realname, nick[128 + 1];
1489 unsigned char *fingerprint;
1490 SilcUInt32 idle, mode, *user_modes;
1492 SilcClientEntry client_entry;
1495 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1496 /* Print the unknown nick for user */
1497 char *tmp = va_arg(vp, char *);
1499 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1501 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1502 /* Try to find the entry for the unknown client ID, since we
1503 might have, and print the nickname of it for user. */
1504 SilcClientID *id = va_arg(vp, SilcClientID *);
1506 client_entry = silc_client_get_client_by_id(client, conn, id);
1507 if (client_entry && client_entry->nickname[0])
1508 silc_say_error("%s: %s", client_entry->nickname,
1509 silc_get_status_message(status));
1510 silc_client_unref_client(client, conn, client_entry);
1513 } else if (status != SILC_STATUS_OK) {
1514 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1518 client_entry = va_arg(vp, SilcClientEntry);
1519 nickname = va_arg(vp, char *);
1520 username = va_arg(vp, char *);
1521 realname = va_arg(vp, char *);
1522 channels = va_arg(vp, SilcDList);
1523 mode = va_arg(vp, SilcUInt32);
1524 idle = va_arg(vp, SilcUInt32);
1525 fingerprint = va_arg(vp, unsigned char *);
1526 user_modes = va_arg(vp, SilcUInt32 *);
1527 attrs = va_arg(vp, SilcDList);
1529 silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
1530 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1531 SILCTXT_WHOIS_USERINFO, nickname,
1532 client_entry->username, client_entry->hostname,
1533 nick, client_entry->nickname);
1534 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1535 SILCTXT_WHOIS_REALNAME, realname);
1537 if (channels && user_modes) {
1538 SilcChannelPayload entry;
1541 silc_dlist_start(channels);
1542 while ((entry = silc_dlist_get(channels))) {
1543 SilcUInt32 name_len;
1544 char *m = silc_client_chumode_char(user_modes[i++]);
1545 char *name = silc_channel_get_name(entry, &name_len);
1548 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1549 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1550 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1554 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1555 SILCTXT_WHOIS_CHANNELS, buf);
1559 memset(buf, 0, sizeof(buf));
1560 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1561 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1562 SILCTXT_WHOIS_MODES, buf);
1565 if (idle && nickname) {
1566 memset(buf, 0, sizeof(buf));
1567 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1568 idle > 60 ? (idle / 60) : idle,
1569 idle > 60 ? "minutes" : "seconds");
1571 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1572 SILCTXT_WHOIS_IDLE, buf);
1576 fingerprint = silc_fingerprint(fingerprint, 20);
1577 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1578 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1579 silc_free(fingerprint);
1583 silc_query_attributes_print(server, silc_client, conn, attrs,
1588 case SILC_COMMAND_WHOWAS:
1590 char *nickname, *username, *realname;
1592 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1593 char *tmp = va_arg(vp, char *);
1595 silc_say_error("%s: %s", tmp,
1596 silc_get_status_message(status));
1598 } else if (status != SILC_STATUS_OK) {
1599 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1603 (void)va_arg(vp, SilcClientEntry);
1604 nickname = va_arg(vp, char *);
1605 username = va_arg(vp, char *);
1606 realname = va_arg(vp, char *);
1608 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1609 SILCTXT_WHOWAS_USERINFO, nickname, username,
1610 realname ? realname : "");
1614 case SILC_COMMAND_INVITE:
1616 SilcChannelEntry channel;
1617 SilcArgumentPayload invite_list;
1619 if (status != SILC_STATUS_OK)
1622 channel = va_arg(vp, SilcChannelEntry);
1623 invite_list = va_arg(vp, SilcArgumentPayload);
1626 silc_parse_inviteban_list(client, conn, server, channel,
1627 "invite", invite_list);
1631 case SILC_COMMAND_JOIN:
1633 char *channel, *mode, *topic, *cipher, *hmac;
1635 SilcHashTableList *user_list;
1636 SilcChannelEntry channel_entry;
1637 SilcChannelUser chu;
1638 SilcClientEntry founder = NULL;
1641 if (status != SILC_STATUS_OK)
1644 channel = va_arg(vp, char *);
1645 channel_entry = va_arg(vp, SilcChannelEntry);
1646 modei = va_arg(vp, SilcUInt32);
1647 user_list = va_arg(vp, SilcHashTableList *);
1648 topic = va_arg(vp, char *);
1649 cipher = va_arg(vp, char *);
1650 hmac = va_arg(vp, char *);
1652 chanrec = silc_channel_find(server, channel);
1654 chanrec = silc_channel_create(server, channel, channel, TRUE);
1657 char tmp[256], *cp, *dm = NULL;
1658 g_free_not_null(chanrec->topic);
1660 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1661 memset(tmp, 0, sizeof(tmp));
1663 if (strlen(topic) > sizeof(tmp) - 1) {
1664 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1668 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1673 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1674 signal_emit("channel topic changed", 1, chanrec);
1679 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1680 g_free_not_null(chanrec->mode);
1681 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1682 signal_emit("channel mode changed", 1, chanrec);
1685 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1686 if (!chu->client->nickname)
1688 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1689 founder = chu->client;
1690 silc_nicklist_insert(chanrec, chu, FALSE);
1693 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1694 nicklist_set_own(CHANNEL(chanrec), ownnick);
1695 signal_emit("channel joined", 1, chanrec);
1696 chanrec->entry = channel_entry;
1699 printformat_module("fe-common/silc", server,
1700 channel_entry->channel_name,
1701 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1702 channel_entry->channel_name, chanrec->topic);
1705 if (founder == conn->local_entry) {
1706 printformat_module("fe-common/silc",
1707 server, channel_entry->channel_name,
1708 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1709 channel_entry->channel_name);
1710 signal_emit("nick mode changed", 2, chanrec, ownnick);
1712 printformat_module("fe-common/silc",
1713 server, channel_entry->channel_name,
1714 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1715 channel_entry->channel_name, founder->nickname);
1721 case SILC_COMMAND_NICK:
1724 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1727 if (status != SILC_STATUS_OK)
1730 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1731 if ((nicks != NULL) &&
1732 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1734 SilcClientEntry collider, old;
1736 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1737 collider = silc_client_get_client_by_id(client, conn, &old->id);
1738 if (collider != client_entry) {
1739 memset(buf, 0, sizeof(buf));
1740 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1741 collider->username, collider->hostname);
1742 nicklist_rename_unique(SERVER(server),
1744 collider, collider->nickname);
1745 silc_print_nick_change(server, collider->nickname,
1746 client_entry->nickname, buf);
1748 silc_client_unref_client(client, conn, collider);
1752 g_slist_free(nicks);
1754 old = g_strdup(server->nick);
1755 server_change_nick(SERVER(server), client_entry->nickname);
1756 nicklist_rename_unique(SERVER(server),
1757 server->conn->local_entry, server->nick,
1758 client_entry, client_entry->nickname);
1759 signal_emit("message own_nick", 4, server, server->nick, old, "");
1762 /* when connecting to a server, the last thing we receive
1763 is a SILC_COMMAND_LIST reply. Since we enable queueing
1764 during the connection, we can now safely disable it again */
1765 silc_queue_disable(conn);
1769 case SILC_COMMAND_LIST:
1774 char tmp[256], *cp, *dm = NULL;
1776 if (status != SILC_STATUS_OK)
1779 (void)va_arg(vp, SilcChannelEntry);
1780 name = va_arg(vp, char *);
1783 topic = va_arg(vp, char *);
1784 usercount = va_arg(vp, int);
1786 if (topic && !silc_term_utf8() &&
1787 silc_utf8_valid(topic, strlen(topic))) {
1788 memset(tmp, 0, sizeof(tmp));
1790 if (strlen(topic) > sizeof(tmp) - 1) {
1791 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1795 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1800 if (status == SILC_STATUS_LIST_START ||
1801 status == SILC_STATUS_OK)
1802 printformat_module("fe-common/silc", server, NULL,
1803 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1806 snprintf(users, sizeof(users) - 1, "N/A");
1808 snprintf(users, sizeof(users) - 1, "%d", usercount);
1809 printformat_module("fe-common/silc", server, NULL,
1810 MSGLEVEL_CRAP, SILCTXT_LIST,
1811 name, users, topic ? topic : "");
1816 case SILC_COMMAND_UMODE:
1821 if (status != SILC_STATUS_OK)
1824 mode = va_arg(vp, SilcUInt32);
1826 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1827 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1828 printformat_module("fe-common/silc", server, NULL,
1829 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1831 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1832 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1833 printformat_module("fe-common/silc", server, NULL,
1834 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1836 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1837 if (mode & SILC_UMODE_GONE) {
1838 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1839 reason = g_strdup(server->away_reason);
1841 reason = g_strdup("away");
1843 reason = g_strdup("");
1845 silc_set_away(reason, server);
1850 server->umode = mode;
1851 signal_emit("user mode changed", 2, server, NULL);
1855 case SILC_COMMAND_OPER:
1856 if (status != SILC_STATUS_OK)
1859 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1860 signal_emit("user mode changed", 2, server, NULL);
1862 printformat_module("fe-common/silc", server, NULL,
1863 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1866 case SILC_COMMAND_SILCOPER:
1867 if (status != SILC_STATUS_OK)
1870 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1871 signal_emit("user mode changed", 2, server, NULL);
1873 printformat_module("fe-common/silc", server, NULL,
1874 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1877 case SILC_COMMAND_USERS:
1879 SilcHashTableList htl;
1880 SilcChannelEntry channel;
1881 SilcChannelUser chu;
1883 if (status != SILC_STATUS_OK)
1886 channel = va_arg(vp, SilcChannelEntry);
1888 printformat_module("fe-common/silc", server, channel->channel_name,
1889 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1890 channel->channel_name);
1892 silc_hash_table_list(channel->user_list, &htl);
1893 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1894 SilcClientEntry e = chu->client;
1895 char stat[5], *mode;
1900 memset(stat, 0, sizeof(stat));
1901 mode = silc_client_chumode_char(chu->mode);
1902 if (e->mode & SILC_UMODE_GONE)
1904 else if (e->mode & SILC_UMODE_INDISPOSED)
1906 else if (e->mode & SILC_UMODE_BUSY)
1908 else if (e->mode & SILC_UMODE_PAGE)
1910 else if (e->mode & SILC_UMODE_HYPER)
1912 else if (e->mode & SILC_UMODE_ROBOT)
1914 else if (e->mode & SILC_UMODE_ANONYMOUS)
1921 printformat_module("fe-common/silc", server, channel->channel_name,
1922 MSGLEVEL_CRAP, SILCTXT_USERS,
1924 e->username ? e->username : "",
1925 e->hostname ? e->hostname : "",
1926 e->realname ? e->realname : "");
1930 silc_hash_table_list_reset(&htl);
1934 case SILC_COMMAND_BAN:
1936 SilcChannelEntry channel;
1937 SilcArgumentPayload invite_list;
1939 if (status != SILC_STATUS_OK)
1942 channel = va_arg(vp, SilcChannelEntry);
1943 invite_list = va_arg(vp, SilcArgumentPayload);
1946 silc_parse_inviteban_list(client, conn, server, channel,
1947 "ban", invite_list);
1951 case SILC_COMMAND_GETKEY:
1955 SilcPublicKey public_key;
1956 GetkeyContext getkey;
1959 if (status != SILC_STATUS_OK)
1962 id_type = va_arg(vp, SilcUInt32);
1963 entry = va_arg(vp, void *);
1964 public_key = va_arg(vp, SilcPublicKey);
1967 getkey = silc_calloc(1, sizeof(*getkey));
1968 getkey->entry = entry;
1969 getkey->id_type = id_type;
1970 getkey->client = client;
1971 getkey->conn = conn;
1973 name = (id_type == SILC_ID_CLIENT ?
1974 ((SilcClientEntry)entry)->nickname :
1975 ((SilcServerEntry)entry)->server_name);
1977 silc_verify_public_key_internal(client, conn, name,
1978 (id_type == SILC_ID_CLIENT ?
1981 public_key, silc_getkey_cb, getkey);
1983 printformat_module("fe-common/silc", server, NULL,
1984 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1989 case SILC_COMMAND_INFO:
1991 SilcServerEntry server_entry;
1995 if (status != SILC_STATUS_OK)
1998 server_entry = va_arg(vp, SilcServerEntry);
1999 server_name = va_arg(vp, char *);
2000 server_info = va_arg(vp, char *);
2002 if (server_name && server_info )
2004 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2005 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2010 case SILC_COMMAND_TOPIC:
2012 SilcChannelEntry channel;
2014 char tmp[256], *cp, *dm = NULL;
2016 if (status != SILC_STATUS_OK)
2019 channel = va_arg(vp, SilcChannelEntry);
2020 topic = va_arg(vp, char *);
2022 if (topic && !silc_term_utf8() &&
2023 silc_utf8_valid(topic, strlen(topic))) {
2024 memset(tmp, 0, sizeof(tmp));
2026 if (strlen(topic) > sizeof(tmp) - 1) {
2027 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2031 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2037 chanrec = silc_channel_find_entry(server, channel);
2039 g_free_not_null(chanrec->topic);
2040 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2041 signal_emit("channel topic changed", 1, chanrec);
2043 printformat_module("fe-common/silc", server, channel->channel_name,
2044 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2045 channel->channel_name, topic);
2047 printformat_module("fe-common/silc", server, channel->channel_name,
2048 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2049 channel->channel_name);
2055 case SILC_COMMAND_WATCH:
2058 case SILC_COMMAND_STATS:
2060 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2061 my_router_ops, cell_clients, cell_channels, cell_servers,
2062 clients, channels, servers, routers, server_ops, router_ops;
2064 SilcBufferStruct buf;
2065 unsigned char *tmp_buf;
2067 const char *tmptime;
2068 int days, hours, mins, secs;
2070 if (status != SILC_STATUS_OK)
2073 tmp_buf = va_arg(vp, unsigned char *);
2074 buf_len = va_arg(vp, SilcUInt32);
2076 if (!tmp_buf || !buf_len) {
2077 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2081 /* Get statistics structure */
2082 silc_buffer_set(&buf, tmp_buf, buf_len);
2083 silc_buffer_unformat(&buf,
2084 SILC_STR_UI_INT(&starttime),
2085 SILC_STR_UI_INT(&uptime),
2086 SILC_STR_UI_INT(&my_clients),
2087 SILC_STR_UI_INT(&my_channels),
2088 SILC_STR_UI_INT(&my_server_ops),
2089 SILC_STR_UI_INT(&my_router_ops),
2090 SILC_STR_UI_INT(&cell_clients),
2091 SILC_STR_UI_INT(&cell_channels),
2092 SILC_STR_UI_INT(&cell_servers),
2093 SILC_STR_UI_INT(&clients),
2094 SILC_STR_UI_INT(&channels),
2095 SILC_STR_UI_INT(&servers),
2096 SILC_STR_UI_INT(&routers),
2097 SILC_STR_UI_INT(&server_ops),
2098 SILC_STR_UI_INT(&router_ops),
2101 tmptime = silc_time_string(starttime);
2102 printformat_module("fe-common/silc", server, NULL,
2103 MSGLEVEL_CRAP, SILCTXT_STATS,
2104 "Local server start time", tmptime);
2106 days = uptime / (24 * 60 * 60);
2107 uptime -= days * (24 * 60 * 60);
2108 hours = uptime / (60 * 60);
2109 uptime -= hours * (60 * 60);
2111 uptime -= mins * 60;
2113 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2114 days, hours, mins, secs);
2115 printformat_module("fe-common/silc", server, NULL,
2116 MSGLEVEL_CRAP, SILCTXT_STATS,
2117 "Local server uptime", tmp);
2119 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2120 printformat_module("fe-common/silc", server, NULL,
2121 MSGLEVEL_CRAP, SILCTXT_STATS,
2122 "Local server clients", tmp);
2124 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2125 printformat_module("fe-common/silc", server, NULL,
2126 MSGLEVEL_CRAP, SILCTXT_STATS,
2127 "Local server channels", tmp);
2129 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2130 printformat_module("fe-common/silc", server, NULL,
2131 MSGLEVEL_CRAP, SILCTXT_STATS,
2132 "Local server operators", tmp);
2134 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2135 printformat_module("fe-common/silc", server, NULL,
2136 MSGLEVEL_CRAP, SILCTXT_STATS,
2137 "Local router operators", tmp);
2139 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2140 printformat_module("fe-common/silc", server, NULL,
2141 MSGLEVEL_CRAP, SILCTXT_STATS,
2142 "Local cell clients", tmp);
2144 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2145 printformat_module("fe-common/silc", server, NULL,
2146 MSGLEVEL_CRAP, SILCTXT_STATS,
2147 "Local cell channels", tmp);
2149 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2150 printformat_module("fe-common/silc", server, NULL,
2151 MSGLEVEL_CRAP, SILCTXT_STATS,
2152 "Local cell servers", tmp);
2154 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2155 printformat_module("fe-common/silc", server, NULL,
2156 MSGLEVEL_CRAP, SILCTXT_STATS,
2157 "Total clients", tmp);
2159 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2160 printformat_module("fe-common/silc", server, NULL,
2161 MSGLEVEL_CRAP, SILCTXT_STATS,
2162 "Total channels", tmp);
2164 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2165 printformat_module("fe-common/silc", server, NULL,
2166 MSGLEVEL_CRAP, SILCTXT_STATS,
2167 "Total servers", tmp);
2169 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2170 printformat_module("fe-common/silc", server, NULL,
2171 MSGLEVEL_CRAP, SILCTXT_STATS,
2172 "Total routers", tmp);
2174 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2175 printformat_module("fe-common/silc", server, NULL,
2176 MSGLEVEL_CRAP, SILCTXT_STATS,
2177 "Total server operators", tmp);
2179 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2180 printformat_module("fe-common/silc", server, NULL,
2181 MSGLEVEL_CRAP, SILCTXT_STATS,
2182 "Total router operators", tmp);
2186 case SILC_COMMAND_CMODE:
2188 SilcChannelEntry channel_entry;
2191 channel_entry = va_arg(vp, SilcChannelEntry);
2192 (void)va_arg(vp, SilcUInt32);
2193 (void)va_arg(vp, SilcPublicKey);
2194 chpks = va_arg(vp, SilcDList);
2196 if (status != SILC_STATUS_OK || !cmode_list_chpks ||
2197 !channel_entry || !channel_entry->channel_name)
2200 /* Print the channel public key list */
2202 silc_parse_channel_public_keys(server, channel_entry, chpks);
2204 printformat_module("fe-common/silc", server, NULL,
2205 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2206 channel_entry->channel_name);
2211 case SILC_COMMAND_LEAVE:
2213 /* we might be cycling, so disable queueing again */
2214 silc_queue_disable(conn);
2223 SilcClientConnection conn;
2227 SilcPublicKey public_key;
2228 SilcVerifyPublicKey completion;
2232 static void verify_public_key_completion(const char *line, void *context)
2234 PublicKeyVerify verify = (PublicKeyVerify)context;
2236 if (line[0] == 'Y' || line[0] == 'y') {
2237 /* Call the completion */
2238 if (verify->completion)
2239 verify->completion(TRUE, verify->context);
2241 /* Save the key for future checking */
2242 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2243 SILC_PKCS_FILE_BASE64);
2245 /* Call the completion */
2246 if (verify->completion)
2247 verify->completion(FALSE, verify->context);
2249 printformat_module("fe-common/silc", NULL, NULL,
2250 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2251 verify->entity_name ? verify->entity_name :
2255 silc_free(verify->filename);
2256 silc_free(verify->entity);
2257 silc_free(verify->entity_name);
2261 /* Internal routine to verify public key. If the `completion' is provided
2262 it will be called to indicate whether public was verified or not. For
2263 server/router public key this will check for filename that includes the
2264 remote host's IP address and remote host's hostname. */
2267 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2269 SilcConnectionType conn_type,
2270 SilcPublicKey public_key,
2271 SilcVerifyPublicKey completion, void *context)
2273 PublicKeyVerify verify;
2274 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2275 char *fingerprint, *babbleprint, *format;
2276 SilcPublicKey local_pubkey;
2278 const char *hostname, *ip;
2283 char *entity = ((conn_type == SILC_CONN_SERVER ||
2284 conn_type == SILC_CONN_ROUTER) ?
2285 "server" : "client");
2288 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2289 printformat_module("fe-common/silc", NULL, NULL,
2290 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2291 entity, silc_pkcs_get_type(public_key));
2293 completion(FALSE, context);
2297 /* Encode public key */
2298 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2301 completion(FALSE, context);
2305 pw = getpwuid(getuid());
2308 completion(FALSE, context);
2312 memset(filename, 0, sizeof(filename));
2313 memset(filename2, 0, sizeof(filename2));
2314 memset(file, 0, sizeof(file));
2316 /* Get remote host information */
2317 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2318 NULL, &hostname, &ip, &port);
2320 if (conn_type == SILC_CONN_SERVER ||
2321 conn_type == SILC_CONN_ROUTER) {
2323 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2324 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2325 get_irssi_dir(), entity, file);
2327 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2329 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2330 get_irssi_dir(), entity, file);
2335 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2337 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2338 get_irssi_dir(), entity, file);
2343 /* Replace all whitespaces with `_'. */
2344 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2345 for (i = 0; i < strlen(fingerprint); i++)
2346 if (fingerprint[i] == ' ')
2347 fingerprint[i] = '_';
2349 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2350 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2351 get_irssi_dir(), entity, file);
2352 silc_free(fingerprint);
2357 /* Take fingerprint of the public key */
2358 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2359 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2361 verify = silc_calloc(1, sizeof(*verify));
2362 verify->client = client;
2363 verify->conn = conn;
2364 verify->filename = strdup(ipf);
2365 verify->entity = strdup(entity);
2366 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2367 (name ? strdup(name) : strdup(hostname))
2369 verify->public_key = public_key;
2370 verify->completion = completion;
2371 verify->context = context;
2373 /* Check whether this key already exists */
2374 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2375 /* Key does not exist, ask user to verify the key and save it */
2377 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2378 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2379 verify->entity_name : entity);
2380 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2381 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2382 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2383 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2384 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2385 SILCTXT_PUBKEY_ACCEPT);
2386 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2389 silc_free(fingerprint);
2392 /* The key already exists, verify it. */
2393 unsigned char *encpk;
2394 SilcUInt32 encpk_len;
2396 /* Load the key file, try for both IP filename and hostname filename */
2397 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2398 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2399 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2400 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2401 verify->entity_name : entity);
2402 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2403 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2404 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2405 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2406 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2407 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2408 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2409 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2410 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2413 silc_free(fingerprint);
2417 /* Encode the key data */
2418 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2420 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2421 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2422 verify->entity_name : entity);
2423 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2424 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2425 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2426 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2427 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2428 SILCTXT_PUBKEY_MALFORMED, entity);
2429 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2430 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2431 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2434 silc_free(fingerprint);
2438 /* Compare the keys */
2439 if (memcmp(encpk, pk, encpk_len)) {
2440 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2441 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2442 verify->entity_name : entity);
2443 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2444 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2445 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2446 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2447 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2448 SILCTXT_PUBKEY_NO_MATCH, entity);
2449 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2450 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2451 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2452 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2454 /* Ask user to verify the key and save it */
2455 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2456 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2457 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2460 silc_free(fingerprint);
2465 /* Local copy matched */
2467 completion(TRUE, context);
2469 silc_free(fingerprint);
2470 silc_free(verify->filename);
2471 silc_free(verify->entity);
2472 silc_free(verify->entity_name);
2477 /* Verifies received public key. The `conn_type' indicates which entity
2478 (server, client etc.) has sent the public key. If user decides to trust
2479 the key may be saved as trusted public key for later use. The
2480 `completion' must be called after the public key has been verified. */
2483 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2484 SilcConnectionType conn_type,
2485 SilcPublicKey public_key,
2486 SilcVerifyPublicKey completion, void *context)
2488 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2489 completion, context);
2492 /* Asks passphrase from user on the input line. */
2495 SilcAskPassphrase completion;
2499 void ask_passphrase_completion(const char *passphrase, void *context)
2501 AskPassphrase p = (AskPassphrase)context;
2502 if (passphrase && passphrase[0] == '\0')
2504 p->completion((unsigned char *)passphrase,
2505 passphrase ? strlen(passphrase) : 0, p->context);
2509 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2510 SilcAskPassphrase completion, void *context)
2512 AskPassphrase p = silc_calloc(1, sizeof(*p));
2513 p->completion = completion;
2514 p->context = context;
2516 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2517 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2521 SilcGetAuthMeth completion;
2523 } *InternalGetAuthMethod;
2525 /* Callback called when we've received the authentication method information
2526 from the server after we've requested it. This will get the authentication
2527 data from the user if needed. */
2529 static void silc_get_auth_method_callback(SilcClient client,
2530 SilcClientConnection conn,
2531 SilcAuthMethod auth_meth,
2534 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2536 SILC_LOG_DEBUG(("Start"));
2538 switch (auth_meth) {
2539 case SILC_AUTH_NONE:
2540 /* No authentication required. */
2541 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2543 case SILC_AUTH_PASSWORD:
2545 /* Check whether we find the password for this server in our
2546 configuration. If not, then don't provide so library will ask
2547 it from the user. */
2548 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2550 if (!setup || !setup->password) {
2551 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2555 (*internal->completion)(TRUE, auth_meth, setup->password,
2556 strlen(setup->password), internal->context);
2559 case SILC_AUTH_PUBLIC_KEY:
2560 /* Do not get the authentication data now, the library will generate
2561 it using our default key, if we do not provide it here. */
2562 /* XXX In the future when we support multiple local keys and multiple
2563 local certificates we will need to ask from user which one to use. */
2564 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2568 silc_free(internal);
2571 /* Find authentication method and authentication data by hostname and
2572 port. The hostname may be IP address as well. The found authentication
2573 method and authentication data is returned to `auth_meth', `auth_data'
2574 and `auth_data_len'. The function returns TRUE if authentication method
2575 is found and FALSE if not. `conn' may be NULL. */
2577 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2578 char *hostname, SilcUInt16 port,
2579 SilcGetAuthMeth completion, void *context)
2581 InternalGetAuthMethod internal;
2583 SILC_LOG_DEBUG(("Start"));
2585 /* If we do not have this connection configured by the user in a
2586 configuration file then resolve the authentication method from the
2587 server for this session. */
2588 internal = silc_calloc(1, sizeof(*internal));
2589 internal->completion = completion;
2590 internal->context = context;
2593 silc_client_request_authentication_method(client, conn,
2594 silc_get_auth_method_callback,
2597 completion(TRUE, SILC_AUTH_NONE, NULL, 0, context);
2601 /* Asks whether the user would like to perform the key agreement protocol.
2602 This is called after we have received an key agreement packet or an
2603 reply to our key agreement packet. This returns TRUE if the user wants
2604 the library to perform the key agreement protocol and FALSE if it is not
2605 desired (application may start it later by calling the function
2606 silc_client_perform_key_agreement). */
2608 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2609 SilcClientEntry client_entry, const char *hostname,
2610 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2615 SILC_LOG_DEBUG(("Start"));
2617 /* We will just display the info on the screen and return FALSE and user
2618 will have to start the key agreement with a command. */
2621 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2624 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2625 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2627 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2628 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2629 client_entry->nickname, hostname, portstr);
2637 /* Notifies application that file transfer protocol session is being
2638 requested by the remote client indicated by the `client_entry' from
2639 the `hostname' and `port'. The `session_id' is the file transfer
2640 session and it can be used to either accept or reject the file
2641 transfer request, by calling the silc_client_file_receive or
2642 silc_client_file_close, respectively. */
2644 void silc_ftp(SilcClient client, SilcClientConnection conn,
2645 SilcClientEntry client_entry, SilcUInt32 session_id,
2646 const char *hostname, SilcUInt16 port)
2648 SILC_SERVER_REC *server;
2650 FtpSession ftp = NULL;
2652 SILC_LOG_DEBUG(("Start"));
2654 server = conn->context;
2656 silc_dlist_start(server->ftp_sessions);
2657 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2658 if (ftp->client_entry == client_entry &&
2659 ftp->session_id == session_id) {
2660 server->current_session = ftp;
2664 if (ftp == SILC_LIST_END) {
2665 ftp = silc_calloc(1, sizeof(*ftp));
2666 ftp->client_entry = client_entry;
2667 ftp->session_id = session_id;
2670 silc_dlist_add(server->ftp_sessions, ftp);
2671 server->current_session = ftp;
2675 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2678 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2679 SILCTXT_FILE_REQUEST, client_entry->nickname);
2681 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2682 SILCTXT_FILE_REQUEST_HOST,
2683 client_entry->nickname, hostname, portstr);
2686 /* Delivers SILC session detachment data indicated by `detach_data' to the
2687 application. If application has issued SILC_COMMAND_DETACH command
2688 the client session in the SILC network is not quit. The client remains
2689 in the network but is detached. The detachment data may be used later
2690 to resume the session in the SILC Network. The appliation is
2691 responsible of saving the `detach_data', to for example in a file.
2693 The detachment data can be given as argument to the functions
2694 silc_client_connect_to_server, or silc_client_add_connection when
2695 creating connection to remote server, inside SilcClientConnectionParams
2696 structure. If it is provided the client library will attempt to resume
2697 the session in the network. After the connection is created
2698 successfully, the application is responsible of setting the user
2699 interface for user into the same state it was before detaching (showing
2700 same channels, channel modes, etc). It can do this by fetching the
2701 information (like joined channels) from the client library. */
2704 silc_detach(SilcClient client, SilcClientConnection conn,
2705 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2707 SILC_SERVER_REC *server = conn->context;
2710 /* Save the detachment data to file. */
2712 file = silc_get_session_filename(server);
2713 silc_file_writefile(file, detach_data, detach_data_len);
2717 /* Called to indicate the client library is running. */
2720 silc_running(SilcClient client, void *application)
2722 SILC_LOG_DEBUG(("Client library is running"));
2725 /* SILC client operations */
2726 SilcClientOperations ops = {
2728 silc_channel_message,
2729 silc_private_message,
2733 silc_get_auth_method,
2734 silc_verify_public_key,
2735 silc_ask_passphrase,