5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 - 2005 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, SilcSocketType conn_type,
50 unsigned char *pk, SilcUInt32 pk_len,
51 SilcSKEPKType pk_type,
52 SilcVerifyPublicKey completion, void *context);
54 char *silc_get_session_filename(SILC_SERVER_REC *server)
56 char *file, *expanded;
58 expanded = parse_special_string(settings_get_str("session_filename"),
59 SERVER(server), NULL, "", NULL, 0);
61 file = silc_calloc(1, strlen(expanded) + 255);
62 snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
68 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
71 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
72 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
73 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
75 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
76 "[SILC operator]" : "[unknown mode]");
78 if (mode & SILC_UMODE_GONE)
79 strcat(buf, " [away]");
80 if (mode & SILC_UMODE_INDISPOSED)
81 strcat(buf, " [indisposed]");
82 if (mode & SILC_UMODE_BUSY)
83 strcat(buf, " [busy]");
84 if (mode & SILC_UMODE_PAGE)
85 strcat(buf, " [page to reach]");
86 if (mode & SILC_UMODE_HYPER)
87 strcat(buf, " [hyper active]");
88 if (mode & SILC_UMODE_ROBOT)
89 strcat(buf, " [robot]");
90 if (mode & SILC_UMODE_ANONYMOUS)
91 strcat(buf, " [anonymous]");
92 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
93 strcat(buf, " [blocks private messages]");
94 if (mode & SILC_UMODE_DETACHED)
95 strcat(buf, " [detached]");
96 if (mode & SILC_UMODE_REJECT_WATCHING)
97 strcat(buf, " [rejects watching]");
98 if (mode & SILC_UMODE_BLOCK_INVITE)
99 strcat(buf, " [blocks invites]");
102 /* converts an utf-8 string to current locale */
103 char * silc_convert_utf8_string(const char *str)
105 int message_len = (str != NULL ? strlen(str) : 0);
106 char *message = silc_calloc(message_len + 1, sizeof(*message));
108 g_return_val_if_fail(message != NULL, NULL);
115 if (!silc_term_utf8() && silc_utf8_valid(str, message_len))
116 silc_utf8_decode(str, message_len, SILC_STRING_LOCALE,
117 message, message_len);
119 strcpy(message, str);
124 /* print "nick appears as" message to every channel of a server */
126 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
127 const char *newnick, const char *oldnick,
130 if (ignore_check(SERVER(server), oldnick, address,
131 channel, newnick, MSGLEVEL_NICKS))
134 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
135 SILCTXT_CHANNEL_APPEARS,
136 oldnick, newnick, channel, address);
140 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
141 const char *oldnick, const char *address)
143 GSList *tmp, *windows;
145 /* Print to each channel/query where the nick is.
146 Don't print more than once to the same window. */
149 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
150 CHANNEL_REC *channel = tmp->data;
151 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
153 if (nicklist_find(channel, newnick) == NULL ||
154 g_slist_find(windows, window) != NULL)
157 windows = g_slist_append(windows, window);
158 silc_print_nick_change_channel(server, channel->visible_name,
159 newnick, oldnick, address);
162 g_slist_free(windows);
165 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
166 SilcChannelEntry channel_entry,
167 SilcBuffer channel_pubkeys)
170 SilcArgumentPayload chpks;
172 SilcUInt32 pk_len, type;
174 char *fingerprint, *babbleprint;
175 SilcPublicKey pubkey;
176 SilcPublicKeyIdentifier ident;
178 printformat_module("fe-common/silc", server, NULL,
179 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
180 channel_entry->channel_name);
182 SILC_GET16_MSB(argc, channel_pubkeys->data);
183 chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
184 channel_pubkeys->len - 2, argc);
188 pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
190 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
191 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
192 silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
193 ident = silc_pkcs_decode_identifier(pubkey->identifier);
195 printformat_module("fe-common/silc", server, NULL,
196 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
197 c++, channel_entry->channel_name,
198 type == 0x00 ? "Added" : "Removed",
199 ident->realname ? ident->realname : "",
200 fingerprint, babbleprint);
202 silc_free(fingerprint);
203 silc_free(babbleprint);
204 silc_pkcs_public_key_free(pubkey);
205 silc_pkcs_free_identifier(ident);
206 pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
209 silc_argument_payload_free(chpks);
212 void silc_say(SilcClient client, SilcClientConnection conn,
213 SilcClientMessageType type, char *msg, ...)
215 SILC_SERVER_REC *server;
219 server = conn == NULL ? NULL : conn->context;
222 str = g_strdup_vprintf(msg, va);
223 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
228 void silc_say_error(char *msg, ...)
234 str = g_strdup_vprintf(msg, va);
235 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
241 /* try to verify a message using locally stored public key data */
242 int verify_message_signature(SilcClientEntry sender,
243 SilcMessageSignedPayload sig,
244 SilcMessagePayload message)
247 char file[256], filename[256];
248 char *fingerprint, *fingerprint2;
249 unsigned char *pk_data;
250 SilcUInt32 pk_datalen;
252 int ret = SILC_MSG_SIGNED_VERIFIED, i;
255 return SILC_MSG_SIGNED_UNKNOWN;
257 /* get public key from the signature payload and compare it with the
258 one stored in the client entry */
259 pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
262 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
264 if (sender->fingerprint) {
265 fingerprint2 = silc_fingerprint(sender->fingerprint,
266 sender->fingerprint_len);
267 if (strcmp(fingerprint, fingerprint2)) {
268 /* since the public key differs from the senders public key, the
269 verification _failed_ */
270 silc_pkcs_public_key_free(pk);
271 silc_free(fingerprint);
272 ret = SILC_MSG_SIGNED_UNKNOWN;
274 silc_free(fingerprint2);
276 } else if (sender->fingerprint)
277 fingerprint = silc_fingerprint(sender->fingerprint,
278 sender->fingerprint_len);
280 /* no idea, who or what signed that message ... */
281 return SILC_MSG_SIGNED_UNKNOWN;
283 /* search our local client key cache */
284 for (i = 0; i < strlen(fingerprint); i++)
285 if (fingerprint[i] == ' ')
286 fingerprint[i] = '_';
288 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
289 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
290 get_irssi_dir(), file);
291 silc_free(fingerprint);
293 if (stat(filename, &st) < 0)
294 /* we don't have the public key cached ... use the one from the sig */
295 ret = SILC_MSG_SIGNED_UNKNOWN;
297 SilcPublicKey cached_pk=NULL;
299 /* try to load the file */
300 if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
301 !silc_pkcs_load_public_key(filename, &cached_pk,
302 SILC_PKCS_FILE_BIN)) {
303 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
304 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
306 return SILC_MSG_SIGNED_UNKNOWN;
308 ret = SILC_MSG_SIGNED_UNKNOWN;
313 silc_pkcs_public_key_free(pk);
318 /* the public key is now in pk, our "level of trust" in ret */
319 if ((pk) && silc_message_signed_verify(sig, message, pk,
320 silc_client->sha1hash)!= SILC_AUTH_OK)
321 ret = SILC_MSG_SIGNED_FAILED;
324 silc_pkcs_public_key_free(pk);
329 char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
332 int i = 0, j = 0, len = strlen(escaped_data);
334 data = silc_calloc(len, sizeof(char));
337 ptr = memchr(escaped_data + i, 1, len - i);
339 int inc = (ptr - escaped_data) - i;
340 memcpy(data + j, escaped_data + i, inc);
343 data[j++] = *(ptr + 1) - 1;
345 memcpy(data + j, escaped_data + i, len - i);
355 char * silc_escape_data(const char *data, SilcUInt32 len)
357 char *escaped_data, *ptr, *ptr0, *ptr1;
360 escaped_data = silc_calloc(2 * len, sizeof(char));
363 ptr0 = memchr(data + i, 0, len - i);
364 ptr1 = memchr(data + i, 1, len - i);
366 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
369 int inc = (ptr - data) - i;
371 memcpy(escaped_data + j, data + i, inc);
374 escaped_data[j++] = 1;
375 escaped_data[j++] = *(data + i++) + 1;
377 memcpy(escaped_data + j, data + i, len - i);
386 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
387 const char *data, SilcUInt32 data_len, const char *nick,
392 escaped_data = silc_escape_data(data, data_len);
394 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
396 silc_free(escaped_data);
400 /* Message for a channel. The `sender' is the nickname of the sender
401 received in the packet. The `channel_name' is the name of the channel. */
403 void silc_channel_message(SilcClient client, SilcClientConnection conn,
404 SilcClientEntry sender, SilcChannelEntry channel,
405 SilcMessagePayload payload,
406 SilcChannelPrivateKey key,
407 SilcMessageFlags flags, const unsigned char *message,
408 SilcUInt32 message_len)
410 SILC_SERVER_REC *server;
412 SILC_CHANNEL_REC *chanrec;
415 SILC_LOG_DEBUG(("Start"));
420 server = conn == NULL ? NULL : conn->context;
421 chanrec = silc_channel_find_entry(server, channel);
425 nick = silc_nicklist_find(chanrec, sender);
427 /* We didn't find client but it clearly exists, add it. */
428 SilcChannelUser chu = silc_client_on_channel(channel, sender);
430 nick = silc_nicklist_insert(chanrec, chu, FALSE);
433 /* If the messages is digitally signed, verify it, if possible. */
434 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
435 if (!settings_get_bool("ignore_message_signatures")) {
436 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
437 verified = verify_message_signature(sender, sig, payload);
439 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
443 if (flags & SILC_MESSAGE_FLAG_DATA) {
444 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
445 nick == NULL ? NULL : nick->nick,
446 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
453 if (flags & SILC_MESSAGE_FLAG_ACTION)
454 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
455 char tmp[256], *cp, *dm = NULL;
456 memset(tmp, 0, sizeof(tmp));
458 if(message_len > sizeof(tmp) - 1) {
459 dm = silc_calloc(message_len + 1, sizeof(*dm));
462 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
464 if (flags & SILC_MESSAGE_FLAG_SIGNED)
465 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
466 nick->host, channel->channel_name, verified);
468 signal_emit("message silc action", 5, server, cp, nick->nick,
469 nick->host, channel->channel_name);
472 if (flags & SILC_MESSAGE_FLAG_SIGNED)
473 signal_emit("message silc signed_action", 6, server, message,
474 nick->nick, nick->host, channel->channel_name, verified);
476 signal_emit("message silc action", 5, server, message,
477 nick->nick, nick->host, channel->channel_name);
479 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
480 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
481 char tmp[256], *cp, *dm = NULL;
482 memset(tmp, 0, sizeof(tmp));
484 if(message_len > sizeof(tmp) - 1) {
485 dm = silc_calloc(message_len + 1, sizeof(*dm));
488 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
490 if (flags & SILC_MESSAGE_FLAG_SIGNED)
491 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
492 nick->host, channel->channel_name, verified);
494 signal_emit("message silc notice", 5, server, cp, nick->nick,
495 nick->host, channel->channel_name);
498 if (flags & SILC_MESSAGE_FLAG_SIGNED)
499 signal_emit("message silc signed_notice", 6, server, message,
500 nick->nick, nick->host, channel->channel_name, verified);
502 signal_emit("message silc notice", 5, server, message,
503 nick->nick, nick->host, channel->channel_name);
506 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
507 char tmp[256], *cp, *dm = NULL;
509 memset(tmp, 0, sizeof(tmp));
511 if (message_len > sizeof(tmp) - 1) {
512 dm = silc_calloc(message_len + 1, sizeof(*dm));
516 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
518 if (flags & SILC_MESSAGE_FLAG_SIGNED)
519 signal_emit("message signed_public", 6, server, cp,
520 nick == NULL ? "[<unknown>]" : nick->nick,
521 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
522 chanrec->name, verified);
524 signal_emit("message public", 6, server, cp,
525 nick == NULL ? "[<unknown>]" : nick->nick,
526 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
527 chanrec->name, nick);
532 if (flags & SILC_MESSAGE_FLAG_SIGNED)
533 signal_emit("message signed_public", 6, server, message,
534 nick == NULL ? "[<unknown>]" : nick->nick,
535 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
536 chanrec->name, verified);
538 signal_emit("message public", 6, server, message,
539 nick == NULL ? "[<unknown>]" : nick->nick,
540 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
541 chanrec->name, nick);
545 /* Private message to the client. The `sender' is the nickname of the
546 sender received in the packet. */
548 void silc_private_message(SilcClient client, SilcClientConnection conn,
549 SilcClientEntry sender, SilcMessagePayload payload,
550 SilcMessageFlags flags,
551 const unsigned char *message,
552 SilcUInt32 message_len)
554 SILC_SERVER_REC *server;
558 SILC_LOG_DEBUG(("Start"));
560 server = conn == NULL ? NULL : conn->context;
561 memset(userhost, 0, sizeof(userhost));
562 if (sender->username)
563 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
564 sender->username, sender->hostname);
566 /* If the messages is digitally signed, verify it, if possible. */
567 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
568 if (!settings_get_bool("ignore_message_signatures")) {
569 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
570 verified = verify_message_signature(sender, sig, payload);
572 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
576 if (flags & SILC_MESSAGE_FLAG_DATA) {
577 silc_emit_mime_sig(server,
579 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
581 message, message_len,
582 sender->nickname ? sender->nickname : "[<unknown>]",
583 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
590 if (flags & SILC_MESSAGE_FLAG_ACTION)
591 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
592 char tmp[256], *cp, *dm = NULL;
593 memset(tmp, 0, sizeof(tmp));
595 if(message_len > sizeof(tmp) - 1) {
596 dm = silc_calloc(message_len + 1, sizeof(*dm));
599 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
601 if (flags & SILC_MESSAGE_FLAG_SIGNED)
602 signal_emit("message silc signed_private_action", 6, server, cp,
603 sender->nickname ? sender->nickname : "[<unknown>]",
604 sender->username ? userhost : NULL,
607 signal_emit("message silc private_action", 5, server, cp,
608 sender->nickname ? sender->nickname : "[<unknown>]",
609 sender->username ? userhost : NULL, NULL);
612 if (flags & SILC_MESSAGE_FLAG_SIGNED)
613 signal_emit("message silc signed_private_action", 6, server, message,
614 sender->nickname ? sender->nickname : "[<unknown>]",
615 sender->username ? userhost : NULL,
618 signal_emit("message silc private_action", 5, server, message,
619 sender->nickname ? sender->nickname : "[<unknown>]",
620 sender->username ? userhost : NULL, NULL);
622 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
623 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
624 char tmp[256], *cp, *dm = NULL;
625 memset(tmp, 0, sizeof(tmp));
627 if(message_len > sizeof(tmp) - 1) {
628 dm = silc_calloc(message_len + 1, sizeof(*dm));
631 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
633 if (flags & SILC_MESSAGE_FLAG_SIGNED)
634 signal_emit("message silc signed_private_notice", 6, server, cp,
635 sender->nickname ? sender->nickname : "[<unknown>]",
636 sender->username ? userhost : NULL,
639 signal_emit("message silc private_notice", 5, server, cp,
640 sender->nickname ? sender->nickname : "[<unknown>]",
641 sender->username ? userhost : NULL, NULL);
644 if (flags & SILC_MESSAGE_FLAG_SIGNED)
645 signal_emit("message silc signed_private_notice", 6, server, message,
646 sender->nickname ? sender->nickname : "[<unknown>]",
647 sender->username ? userhost : NULL,
650 signal_emit("message silc private_notice", 5, server, message,
651 sender->nickname ? sender->nickname : "[<unknown>]",
652 sender->username ? userhost : NULL, NULL);
655 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
656 char tmp[256], *cp, *dm = NULL;
658 memset(tmp, 0, sizeof(tmp));
660 if (message_len > sizeof(tmp) - 1) {
661 dm = silc_calloc(message_len + 1, sizeof(*dm));
665 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
667 if (flags & SILC_MESSAGE_FLAG_SIGNED)
668 signal_emit("message signed_private", 5, server, cp,
669 sender->nickname ? sender->nickname : "[<unknown>]",
670 sender->username ? userhost : NULL, verified);
672 signal_emit("message private", 4, server, cp,
673 sender->nickname ? sender->nickname : "[<unknown>]",
674 sender->username ? userhost : NULL);
679 if (flags & SILC_MESSAGE_FLAG_SIGNED)
680 signal_emit("message signed_private", 5, server, message,
681 sender->nickname ? sender->nickname : "[<unknown>]",
682 sender->username ? userhost : NULL, verified);
684 signal_emit("message private", 4, server, message,
685 sender->nickname ? sender->nickname : "[<unknown>]",
686 sender->username ? userhost : NULL);
690 /* Notify message to the client. The notify arguments are sent in the
691 same order as servers sends them. The arguments are same as received
692 from the server except for ID's. If ID is received application receives
693 the corresponding entry to the ID. For example, if Client ID is received
694 application receives SilcClientEntry. Also, if the notify type is
695 for channel the channel entry is sent to application (even if server
696 does not send it). */
698 void silc_notify(SilcClient client, SilcClientConnection conn,
699 SilcNotifyType type, ...)
702 SILC_SERVER_REC *server;
703 SILC_CHANNEL_REC *chanrec;
704 SILC_NICK_REC *nickrec;
705 SilcClientEntry client_entry, client_entry2;
706 SilcChannelEntry channel, channel2;
707 SilcServerEntry server_entry;
713 GSList *list1, *list_tmp;
716 SILC_LOG_DEBUG(("Start"));
720 server = conn == NULL ? NULL : conn->context;
723 case SILC_NOTIFY_TYPE_NONE:
724 /* Some generic notice from server */
725 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
728 case SILC_NOTIFY_TYPE_INVITE:
730 * Invited or modified invite list.
733 SILC_LOG_DEBUG(("Notify: INVITE"));
735 channel = va_arg(va, SilcChannelEntry);
736 name = va_arg(va, char *);
737 client_entry = va_arg(va, SilcClientEntry);
739 memset(buf, 0, sizeof(buf));
740 snprintf(buf, sizeof(buf) - 1, "%s@%s",
741 client_entry->username, client_entry->hostname);
742 signal_emit("message invite", 4, server, channel ? channel->channel_name :
743 name, client_entry->nickname, buf);
746 case SILC_NOTIFY_TYPE_JOIN:
751 SILC_LOG_DEBUG(("Notify: JOIN"));
753 client_entry = va_arg(va, SilcClientEntry);
754 channel = va_arg(va, SilcChannelEntry);
756 if (client_entry == server->conn->local_entry) {
757 /* You joined to channel */
758 chanrec = silc_channel_find(server, channel->channel_name);
759 if (chanrec != NULL && !chanrec->joined)
760 chanrec->entry = channel;
762 chanrec = silc_channel_find_entry(server, channel);
763 if (chanrec != NULL) {
764 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
766 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
770 memset(buf, 0, sizeof(buf));
771 if (client_entry->username)
772 snprintf(buf, sizeof(buf) - 1, "%s@%s",
773 client_entry->username, client_entry->hostname);
774 signal_emit("message join", 4, server, channel->channel_name,
775 client_entry->nickname,
776 client_entry->username == NULL ? "" : buf);
779 case SILC_NOTIFY_TYPE_LEAVE:
784 SILC_LOG_DEBUG(("Notify: LEAVE"));
786 client_entry = va_arg(va, SilcClientEntry);
787 channel = va_arg(va, SilcChannelEntry);
789 memset(buf, 0, sizeof(buf));
790 if (client_entry->username)
791 snprintf(buf, sizeof(buf) - 1, "%s@%s",
792 client_entry->username, client_entry->hostname);
793 signal_emit("message part", 5, server, channel->channel_name,
794 client_entry->nickname, client_entry->username ?
795 buf : "", client_entry->nickname);
797 chanrec = silc_channel_find_entry(server, channel);
798 if (chanrec != NULL) {
799 nickrec = silc_nicklist_find(chanrec, client_entry);
801 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
805 case SILC_NOTIFY_TYPE_SIGNOFF:
810 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
812 client_entry = va_arg(va, SilcClientEntry);
813 tmp = va_arg(va, char *);
815 silc_server_free_ftp(server, client_entry);
817 /* Print only if we have the nickname. If this cliente has just quit
818 when we were only resolving it, it is possible we don't have the
820 if (client_entry->nickname) {
821 memset(buf, 0, sizeof(buf));
822 if (client_entry->username)
823 snprintf(buf, sizeof(buf) - 1, "%s@%s",
824 client_entry->username, client_entry->hostname);
825 signal_emit("message quit", 4, server, client_entry->nickname,
826 client_entry->username ? buf : "",
830 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
831 for (list_tmp = list1; list_tmp != NULL; list_tmp =
832 list_tmp->next->next) {
833 CHANNEL_REC *channel = list_tmp->data;
834 NICK_REC *nickrec = list_tmp->next->data;
836 nicklist_remove(channel, nickrec);
840 case SILC_NOTIFY_TYPE_TOPIC_SET:
845 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
847 idtype = va_arg(va, int);
848 entry = va_arg(va, void *);
849 tmp = va_arg(va, char *);
850 channel = va_arg(va, SilcChannelEntry);
852 chanrec = silc_channel_find_entry(server, channel);
853 if (chanrec != NULL) {
854 char tmp2[256], *cp, *dm = NULL;
856 g_free_not_null(chanrec->topic);
857 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
858 memset(tmp2, 0, sizeof(tmp2));
860 if (strlen(tmp) > sizeof(tmp2) - 1) {
861 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
865 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
870 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
871 signal_emit("channel topic changed", 1, chanrec);
876 if (idtype == SILC_ID_CLIENT) {
877 client_entry = (SilcClientEntry)entry;
878 memset(buf, 0, sizeof(buf));
879 snprintf(buf, sizeof(buf) - 1, "%s@%s",
880 client_entry->username, client_entry->hostname);
881 signal_emit("message topic", 5, server, channel->channel_name,
882 tmp, client_entry->nickname, buf);
883 } else if (idtype == SILC_ID_SERVER) {
884 server_entry = (SilcServerEntry)entry;
885 signal_emit("message topic", 5, server, channel->channel_name,
886 tmp, server_entry->server_name,
887 server_entry->server_name);
888 } else if (idtype == SILC_ID_CHANNEL) {
889 channel = (SilcChannelEntry)entry;
890 signal_emit("message topic", 5, server, channel->channel_name,
891 tmp, channel->channel_name, channel->channel_name);
895 case SILC_NOTIFY_TYPE_NICK_CHANGE:
900 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
902 client_entry = va_arg(va, SilcClientEntry);
903 client_entry2 = va_arg(va, SilcClientEntry);
905 if (!strcmp(client_entry->nickname, client_entry2->nickname))
908 memset(buf, 0, sizeof(buf));
909 snprintf(buf, sizeof(buf) - 1, "%s@%s",
910 client_entry2->username, client_entry2->hostname);
911 nicklist_rename_unique(SERVER(server),
912 client_entry, client_entry->nickname,
913 client_entry2, client_entry2->nickname);
914 signal_emit("message nick", 4, server, client_entry2->nickname,
915 client_entry->nickname, buf);
918 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
920 * Changed channel mode.
923 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
925 idtype = va_arg(va, int);
926 entry = va_arg(va, void *);
927 mode = va_arg(va, SilcUInt32);
928 (void)va_arg(va, char *); /* cipher */
929 (void)va_arg(va, char *); /* hmac */
930 (void)va_arg(va, char *); /* passphrase */
931 (void)va_arg(va, SilcPublicKey); /* founder key */
932 buffer = va_arg(va, SilcBuffer); /* channel public keys */
933 channel = va_arg(va, SilcChannelEntry);
935 tmp = silc_client_chmode(mode,
936 channel->channel_key ?
937 silc_cipher_get_name(channel->channel_key) : "",
939 silc_hmac_get_name(channel->hmac) : "");
941 chanrec = silc_channel_find_entry(server, channel);
942 if (chanrec != NULL) {
943 g_free_not_null(chanrec->mode);
944 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
945 signal_emit("channel mode changed", 1, chanrec);
948 if (idtype == SILC_ID_CLIENT) {
949 client_entry = (SilcClientEntry)entry;
950 printformat_module("fe-common/silc", server, channel->channel_name,
951 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
952 channel->channel_name, tmp ? tmp : "removed all",
953 client_entry->nickname);
954 } else if (idtype == SILC_ID_SERVER) {
955 server_entry = (SilcServerEntry)entry;
956 printformat_module("fe-common/silc", server, channel->channel_name,
957 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
958 channel->channel_name, tmp ? tmp : "removed all",
959 server_entry->server_name);
960 } else if (idtype == SILC_ID_CHANNEL) {
961 channel2 = (SilcChannelEntry)entry;
962 printformat_module("fe-common/silc", server, channel->channel_name,
963 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
964 channel->channel_name, tmp ? tmp : "removed all",
965 channel2->channel_name);
968 /* Print the channel public key list */
970 silc_parse_channel_public_keys(server, channel, buffer);
975 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
977 * Changed user's mode on channel.
980 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
982 idtype = va_arg(va, int);
983 entry = va_arg(va, void *);
984 mode = va_arg(va, SilcUInt32);
985 client_entry2 = va_arg(va, SilcClientEntry);
986 channel = va_arg(va, SilcChannelEntry);
988 tmp = silc_client_chumode(mode);
989 chanrec = silc_channel_find_entry(server, channel);
990 if (chanrec != NULL) {
993 if (client_entry2 == server->conn->local_entry)
994 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
996 nick = silc_nicklist_find(chanrec, client_entry2);
998 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
999 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1000 signal_emit("nick mode changed", 2, chanrec, nick);
1004 if (idtype == SILC_ID_CLIENT) {
1005 client_entry = (SilcClientEntry)entry;
1006 printformat_module("fe-common/silc", server, channel->channel_name,
1007 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1008 channel->channel_name, client_entry2->nickname,
1009 tmp ? tmp : "removed all",
1010 client_entry->nickname);
1011 } else if (idtype == SILC_ID_SERVER) {
1012 server_entry = (SilcServerEntry)entry;
1013 printformat_module("fe-common/silc", server, channel->channel_name,
1014 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1015 channel->channel_name, client_entry2->nickname,
1016 tmp ? tmp : "removed all",
1017 server_entry->server_name);
1018 } else if (idtype == SILC_ID_CHANNEL) {
1019 channel2 = (SilcChannelEntry)entry;
1020 printformat_module("fe-common/silc", server, channel->channel_name,
1021 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1022 channel->channel_name, client_entry2->nickname,
1023 tmp ? tmp : "removed all",
1024 channel2->channel_name);
1027 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1028 printformat_module("fe-common/silc",
1029 server, channel->channel_name, MSGLEVEL_CRAP,
1030 SILCTXT_CHANNEL_FOUNDER,
1031 channel->channel_name, client_entry2->nickname);
1033 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1034 printformat_module("fe-common/silc",
1035 server, channel->channel_name, MSGLEVEL_CRAP,
1036 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1041 case SILC_NOTIFY_TYPE_MOTD:
1046 SILC_LOG_DEBUG(("Notify: MOTD"));
1048 tmp = va_arg(va, char *);
1050 if (!settings_get_bool("skip_motd"))
1051 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1054 case SILC_NOTIFY_TYPE_KICKED:
1056 * Someone was kicked from channel.
1059 SILC_LOG_DEBUG(("Notify: KICKED"));
1061 client_entry = va_arg(va, SilcClientEntry);
1062 tmp = va_arg(va, char *);
1063 client_entry2 = va_arg(va, SilcClientEntry);
1064 channel = va_arg(va, SilcChannelEntry);
1066 chanrec = silc_channel_find_entry(server, channel);
1068 if (client_entry == conn->local_entry) {
1069 printformat_module("fe-common/silc", server, channel->channel_name,
1070 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1071 channel->channel_name,
1072 client_entry ? client_entry2->nickname : "",
1075 chanrec->kicked = TRUE;
1076 channel_destroy((CHANNEL_REC *)chanrec);
1079 printformat_module("fe-common/silc", server, channel->channel_name,
1080 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1081 client_entry->nickname, channel->channel_name,
1082 client_entry2 ? client_entry2->nickname : "",
1086 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1087 if (nickrec != NULL)
1088 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1093 case SILC_NOTIFY_TYPE_KILLED:
1095 * Someone was killed from the network.
1098 SILC_LOG_DEBUG(("Notify: KILLED"));
1100 client_entry = va_arg(va, SilcClientEntry);
1101 tmp = va_arg(va, char *);
1102 idtype = va_arg(va, int);
1103 entry = va_arg(va, SilcClientEntry);
1105 if (client_entry == conn->local_entry) {
1106 if (idtype == SILC_ID_CLIENT) {
1107 client_entry2 = (SilcClientEntry)entry;
1108 printformat_module("fe-common/silc", server, NULL,
1109 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1110 client_entry2 ? client_entry2->nickname : "",
1112 } else if (idtype == SILC_ID_SERVER) {
1113 server_entry = (SilcServerEntry)entry;
1114 printformat_module("fe-common/silc", server, NULL,
1115 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1116 server_entry->server_name, tmp ? tmp : "");
1117 } else if (idtype == SILC_ID_CHANNEL) {
1118 channel = (SilcChannelEntry)entry;
1119 printformat_module("fe-common/silc", server, NULL,
1120 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1121 channel->channel_name, tmp ? tmp : "");
1124 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1125 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1126 list_tmp->next->next) {
1127 CHANNEL_REC *channel = list_tmp->data;
1128 NICK_REC *nickrec = list_tmp->next->data;
1129 nicklist_remove(channel, nickrec);
1132 if (idtype == SILC_ID_CLIENT) {
1133 client_entry2 = (SilcClientEntry)entry;
1134 printformat_module("fe-common/silc", server, NULL,
1135 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1136 client_entry->nickname,
1137 client_entry2 ? client_entry2->nickname : "",
1139 } else if (idtype == SILC_ID_SERVER) {
1140 server_entry = (SilcServerEntry)entry;
1141 printformat_module("fe-common/silc", server, NULL,
1142 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1143 client_entry->nickname,
1144 server_entry->server_name, tmp ? tmp : "");
1145 } else if (idtype == SILC_ID_CHANNEL) {
1146 channel = (SilcChannelEntry)entry;
1147 printformat_module("fe-common/silc", server, NULL,
1148 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1149 client_entry->nickname,
1150 channel->channel_name, tmp ? tmp : "");
1155 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1158 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1161 * Server has quit the network.
1164 SilcClientEntry *clients;
1165 SilcUInt32 clients_count;
1167 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1169 (void)va_arg(va, void *);
1170 clients = va_arg(va, SilcClientEntry *);
1171 clients_count = va_arg(va, SilcUInt32);
1173 for (i = 0; i < clients_count; i++) {
1174 memset(buf, 0, sizeof(buf));
1176 /* Print only if we have the nickname. If this client has just quit
1177 when we were only resolving it, it is possible we don't have the
1179 if (clients[i]->nickname) {
1180 if (clients[i]->username)
1181 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1182 clients[i]->username, clients[i]->hostname);
1183 signal_emit("message quit", 4, server, clients[i]->nickname,
1184 clients[i]->username ? buf : "",
1188 silc_server_free_ftp(server, clients[i]);
1190 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1191 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1192 list_tmp->next->next) {
1193 CHANNEL_REC *channel = list_tmp->data;
1194 NICK_REC *nickrec = list_tmp->next->data;
1195 nicklist_remove(channel, nickrec);
1201 case SILC_NOTIFY_TYPE_ERROR:
1203 SilcStatus error = va_arg(va, int);
1205 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1206 "%s", silc_get_status_message(error));
1210 case SILC_NOTIFY_TYPE_WATCH:
1212 SilcNotifyType notify;
1214 client_entry = va_arg(va, SilcClientEntry);
1215 name = va_arg(va, char *); /* Maybe NULL */
1216 mode = va_arg(va, SilcUInt32);
1217 notify = va_arg(va, int);
1219 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1221 printformat_module("fe-common/silc", server, NULL,
1222 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1223 client_entry->nickname, name);
1225 printformat_module("fe-common/silc", server, NULL,
1226 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1227 client_entry->nickname);
1228 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1229 /* See if client was away and is now present */
1230 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1231 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1232 SILC_UMODE_DETACHED)) &&
1233 (client_entry->mode & SILC_UMODE_GONE ||
1234 client_entry->mode & SILC_UMODE_INDISPOSED ||
1235 client_entry->mode & SILC_UMODE_BUSY ||
1236 client_entry->mode & SILC_UMODE_PAGE ||
1237 client_entry->mode & SILC_UMODE_DETACHED)) {
1238 printformat_module("fe-common/silc", server, NULL,
1239 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1240 client_entry->nickname);
1244 memset(buf, 0, sizeof(buf));
1245 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1246 printformat_module("fe-common/silc", server, NULL,
1247 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1248 client_entry->nickname, buf);
1250 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1251 printformat_module("fe-common/silc", server, NULL,
1252 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1253 client_entry->nickname);
1254 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1255 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1256 printformat_module("fe-common/silc", server, NULL,
1257 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1258 client_entry->nickname);
1259 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1260 /* Client logged in to the network */
1261 printformat_module("fe-common/silc", server, NULL,
1262 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1263 client_entry->nickname);
1269 /* Unknown notify */
1270 printformat_module("fe-common/silc", server, NULL,
1271 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1278 /* Called to indicate that connection was either successfully established
1279 or connecting failed. This is also the first time application receives
1280 the SilcClientConnection object which it should save somewhere. */
1282 void silc_connect(SilcClient client, SilcClientConnection conn,
1283 SilcClientConnectionStatus status)
1285 SILC_SERVER_REC *server = conn->context;
1287 if (!server || server->disconnected) {
1288 silc_client_close_connection(client, conn);
1293 case SILC_CLIENT_CONN_SUCCESS:
1294 /* We have successfully connected to server */
1295 if ((client->nickname != NULL) &&
1296 (strcmp(client->nickname, client->username)))
1297 silc_queue_enable(conn); /* enable queueing until we have our nick */
1298 server->connected = TRUE;
1299 signal_emit("event connected", 1, server);
1302 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1303 /* We have successfully resumed old detached session */
1304 server->connected = TRUE;
1305 signal_emit("event connected", 1, server);
1307 /* If we resumed old session check whether we need to update
1309 if (strcmp(server->nick, conn->local_entry->nickname)) {
1311 old = g_strdup(server->nick);
1312 server_change_nick(SERVER(server), conn->local_entry->nickname);
1313 nicklist_rename_unique(SERVER(server),
1314 conn->local_entry, server->nick,
1315 conn->local_entry, conn->local_entry->nickname);
1316 signal_emit("message own_nick", 4, server, server->nick, old, "");
1320 /* remove the detach data now */
1324 file = silc_get_session_filename(server);
1335 file = silc_get_session_filename(server);
1337 if (silc_file_size(file) > 0)
1338 printformat_module("fe-common/silc", server, NULL,
1339 MSGLEVEL_CRAP, SILCTXT_REATTACH_FAILED, file);
1343 server->connection_lost = TRUE;
1345 server->conn->context = NULL;
1346 server_disconnect(SERVER(server));
1353 /* Called to indicate that connection was disconnected to the server. */
1355 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1356 SilcStatus status, const char *message)
1358 SILC_SERVER_REC *server = conn->context;
1360 SILC_LOG_DEBUG(("Start"));
1362 if (!server || server->connection_lost)
1365 if (server->conn && server->conn->local_entry) {
1366 nicklist_rename_unique(SERVER(server),
1367 server->conn->local_entry, server->nick,
1368 server->conn->local_entry,
1369 silc_client->username);
1370 silc_change_nick(server, silc_client->username);
1374 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1375 "Server closed connection: %s (%d) %s",
1376 silc_get_status_message(status), status,
1377 message ? message : "");
1380 server->conn->context = NULL;
1381 server->conn = NULL;
1382 server->connection_lost = TRUE;
1383 server_disconnect(SERVER(server));
1386 /* Command handler. This function is called always in the command function.
1387 If error occurs it will be called as well. `conn' is the associated
1388 client connection. `cmd_context' is the command context that was
1389 originally sent to the command. `success' is FALSE if error occured
1390 during command. `command' is the command being processed. It must be
1391 noted that this is not reply from server. This is merely called just
1392 after application has called the command. Just to tell application
1393 that the command really was processed. */
1395 static bool cmode_list_chpks = FALSE;
1397 void silc_command(SilcClient client, SilcClientConnection conn,
1398 SilcClientCommandContext cmd_context, bool success,
1399 SilcCommand command, SilcStatus status)
1401 SILC_SERVER_REC *server = conn->context;
1403 SILC_LOG_DEBUG(("Start"));
1406 silc_say_error("%s", silc_get_status_message(status));
1412 case SILC_COMMAND_INVITE:
1413 if (cmd_context->argc > 2)
1414 printformat_module("fe-common/silc", server, NULL,
1415 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1416 cmd_context->argv[2],
1417 (cmd_context->argv[1][0] == '*' ?
1418 (char *)conn->current_channel->channel_name :
1419 (char *)cmd_context->argv[1]));
1422 case SILC_COMMAND_DETACH:
1423 server->no_reconnect = TRUE;
1426 case SILC_COMMAND_CMODE:
1427 if (cmd_context->argc == 3 &&
1428 !strcmp(cmd_context->argv[2], "+C"))
1429 cmode_list_chpks = TRUE;
1431 cmode_list_chpks = FALSE;
1440 SilcChannelEntry channel;
1444 /* Client info resolving callback when JOIN command reply is received.
1445 This will cache all users on the channel. */
1447 static void silc_client_join_get_users(SilcClient client,
1448 SilcClientConnection conn,
1449 SilcClientEntry *clients,
1450 SilcUInt32 clients_count,
1453 SilcJoinResolve r = context;
1454 SilcChannelEntry channel = r->channel;
1455 SilcHashTableList htl;
1456 SilcChannelUser chu;
1457 SILC_SERVER_REC *server = conn->context;
1458 SILC_CHANNEL_REC *chanrec;
1459 SilcClientEntry founder = NULL;
1462 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1463 silc_hash_table_count(channel->user_list)));
1465 if (!clients && r->retry < 1) {
1466 /* Retry to resolve */
1468 silc_client_get_clients_by_channel(client, conn, channel,
1469 silc_client_join_get_users, context);
1473 chanrec = silc_channel_find(server, channel->channel_name);
1474 if (chanrec == NULL)
1477 silc_hash_table_list(channel->user_list, &htl);
1478 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1479 if (!chu->client->nickname)
1481 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1482 founder = chu->client;
1483 silc_nicklist_insert(chanrec, chu, FALSE);
1485 silc_hash_table_list_reset(&htl);
1487 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1488 nicklist_set_own(CHANNEL(chanrec), ownnick);
1489 signal_emit("channel joined", 1, chanrec);
1490 chanrec->entry = channel;
1493 printformat_module("fe-common/silc", server, channel->channel_name,
1494 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1495 channel->channel_name, chanrec->topic);
1498 if (founder == conn->local_entry) {
1499 printformat_module("fe-common/silc",
1500 server, channel->channel_name, MSGLEVEL_CRAP,
1501 SILCTXT_CHANNEL_FOUNDER_YOU,
1502 channel->channel_name);
1503 signal_emit("nick mode changed", 2, chanrec, ownnick);
1505 printformat_module("fe-common/silc",
1506 server, channel->channel_name, MSGLEVEL_CRAP,
1507 SILCTXT_CHANNEL_FOUNDER,
1508 channel->channel_name, founder->nickname);
1514 SilcClientConnection conn;
1520 void silc_getkey_cb(bool success, void *context)
1522 GetkeyContext getkey = (GetkeyContext)context;
1523 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1524 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1525 ((SilcClientEntry)getkey->entry)->nickname :
1526 ((SilcServerEntry)getkey->entry)->server_name);
1529 printformat_module("fe-common/silc", NULL, NULL,
1530 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1532 printformat_module("fe-common/silc", NULL, NULL,
1533 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1537 silc_free(getkey->fingerprint);
1541 /* Parse an invite or ban list */
1542 void silc_parse_inviteban_list(SilcClient client,
1543 SilcClientConnection conn,
1544 SILC_SERVER_REC *server,
1545 SilcChannelEntry channel,
1546 const char *list_type,
1547 SilcArgumentPayload list)
1550 SilcUInt32 type, len;
1551 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1552 int counter=0, resolving = FALSE;
1554 if (!silc_argument_get_arg_num(list)) {
1555 printformat_module("fe-common/silc", server,
1556 (chanrec ? chanrec->visible_name : NULL),
1557 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1558 channel->channel_name, list_type);
1562 printformat_module("fe-common/silc", server,
1563 (chanrec ? chanrec->visible_name : NULL),
1564 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1565 channel->channel_name, list_type);
1567 /* parse the list */
1568 tmp = silc_argument_get_first_arg(list, &type, &len);
1573 /* an invite string */
1577 if (tmp[len-1] == ',')
1580 list = g_strsplit(tmp, ",", -1);
1582 printformat_module("fe-common/silc", server,
1583 (chanrec ? chanrec->visible_name : NULL),
1584 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1585 ++counter, channel->channel_name, list_type,
1594 char *fingerprint, *babbleprint;
1596 /* tmp is Public Key Payload, take public key from it. */
1597 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1598 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1600 printformat_module("fe-common/silc", server,
1601 (chanrec ? chanrec->visible_name : NULL),
1602 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1603 ++counter, channel->channel_name, list_type,
1604 fingerprint, babbleprint);
1611 SilcClientID *client_id;
1612 SilcClientEntry client_entry;
1614 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1616 if (client_id == NULL) {
1617 silc_say_error("Invalid data in %s list encountered", list_type);
1621 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1624 printformat_module("fe-common/silc", server,
1625 (chanrec ? chanrec->visible_name : NULL),
1626 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1627 ++counter, channel->channel_name, list_type,
1628 client_entry->nickname);
1631 silc_client_get_client_by_id_resolve(client, conn, client_id,
1635 silc_free(client_id);
1641 silc_say_error("Unkown type in %s list: %u (len %u)",
1642 list_type, type, len);
1644 tmp = silc_argument_get_next_arg(list, &type, &len);
1648 printformat_module("fe-common/silc", server,
1649 (chanrec ? chanrec->visible_name : NULL),
1650 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1651 list_type, channel->channel_name);
1654 /* Command reply handler. This function is called always in the command reply
1655 function. If error occurs it will be called as well. Normal scenario
1656 is that it will be called after the received command data has been parsed
1657 and processed. The function is used to pass the received command data to
1660 `conn' is the associated client connection. `cmd_payload' is the command
1661 payload data received from server and it can be ignored. It is provided
1662 if the application would like to re-parse the received command data,
1663 however, it must be noted that the data is parsed already by the library
1664 thus the payload can be ignored. `success' is FALSE if error occured.
1665 In this case arguments are not sent to the application. `command' is the
1666 command reply being processed. The function has variable argument list
1667 and each command defines the number and type of arguments it passes to the
1668 application (on error they are not sent). */
1671 silc_command_reply(SilcClient client, SilcClientConnection conn,
1672 SilcCommandPayload cmd_payload, bool success,
1673 SilcCommand command, SilcStatus status, ...)
1676 SILC_SERVER_REC *server = conn->context;
1677 SILC_CHANNEL_REC *chanrec;
1680 va_start(vp, status);
1682 SILC_LOG_DEBUG(("Start"));
1685 case SILC_COMMAND_WHOIS:
1687 char buf[1024], *nickname, *username, *realname, *nick;
1688 unsigned char *fingerprint;
1689 SilcUInt32 idle, mode;
1690 SilcBuffer channels, user_modes;
1691 SilcClientEntry client_entry;
1694 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1695 /* Print the unknown nick for user */
1696 unsigned char *tmp =
1697 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1700 silc_say_error("%s: %s", tmp,
1701 silc_get_status_message(status));
1703 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1704 /* Try to find the entry for the unknown client ID, since we
1705 might have, and print the nickname of it for user. */
1707 unsigned char *tmp =
1708 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1711 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1714 client_entry = silc_client_get_client_by_id(client, conn,
1716 if (client_entry && client_entry->nickname)
1717 silc_say_error("%s: %s", client_entry->nickname,
1718 silc_get_status_message(status));
1719 silc_free(client_id);
1723 } else if (!success) {
1724 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1728 client_entry = va_arg(vp, SilcClientEntry);
1729 nickname = va_arg(vp, char *);
1730 username = va_arg(vp, char *);
1731 realname = va_arg(vp, char *);
1732 channels = va_arg(vp, SilcBuffer);
1733 mode = va_arg(vp, SilcUInt32);
1734 idle = va_arg(vp, SilcUInt32);
1735 fingerprint = va_arg(vp, unsigned char *);
1736 user_modes = va_arg(vp, SilcBuffer);
1737 attrs = va_arg(vp, SilcDList);
1739 silc_parse_userfqdn(nickname, &nick, NULL);
1740 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1741 SILCTXT_WHOIS_USERINFO, nickname,
1742 client_entry->username, client_entry->hostname,
1743 nick, client_entry->nickname);
1744 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1745 SILCTXT_WHOIS_REALNAME, realname);
1748 if (channels && user_modes) {
1750 SilcDList list = silc_channel_payload_parse_list(channels->data,
1752 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1754 SilcChannelPayload entry;
1757 memset(buf, 0, sizeof(buf));
1758 silc_dlist_start(list);
1759 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1760 SilcUInt32 name_len;
1761 char *m = silc_client_chumode_char(umodes[i++]);
1762 char *name = silc_channel_get_name(entry, &name_len);
1765 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1766 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1767 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1771 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1772 SILCTXT_WHOIS_CHANNELS, buf);
1773 silc_channel_payload_list_free(list);
1779 memset(buf, 0, sizeof(buf));
1780 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1781 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1782 SILCTXT_WHOIS_MODES, buf);
1785 if (idle && nickname) {
1786 memset(buf, 0, sizeof(buf));
1787 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1788 idle > 60 ? (idle / 60) : idle,
1789 idle > 60 ? "minutes" : "seconds");
1791 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1792 SILCTXT_WHOIS_IDLE, buf);
1796 fingerprint = silc_fingerprint(fingerprint, 20);
1797 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1798 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1799 silc_free(fingerprint);
1803 silc_query_attributes_print(server, silc_client, conn, attrs,
1808 case SILC_COMMAND_IDENTIFY:
1810 SilcClientEntry client_entry;
1812 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1813 /* Print the unknown nick for user */
1814 unsigned char *tmp =
1815 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1818 silc_say_error("%s: %s", tmp,
1819 silc_get_status_message(status));
1821 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1822 /* Try to find the entry for the unknown client ID, since we
1823 might have, and print the nickname of it for user. */
1825 unsigned char *tmp =
1826 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1829 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1832 client_entry = silc_client_get_client_by_id(client, conn,
1834 if (client_entry && client_entry->nickname)
1835 silc_say_error("%s: %s", client_entry->nickname,
1836 silc_get_status_message(status));
1837 silc_free(client_id);
1846 case SILC_COMMAND_WHOWAS:
1848 char *nickname, *username, *realname;
1850 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1852 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1855 silc_say_error("%s: %s", tmp,
1856 silc_get_status_message(status));
1858 } else if (!success) {
1859 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1863 (void)va_arg(vp, SilcClientEntry);
1864 nickname = va_arg(vp, char *);
1865 username = va_arg(vp, char *);
1866 realname = va_arg(vp, char *);
1868 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1869 SILCTXT_WHOWAS_USERINFO, nickname, username,
1870 realname ? realname : "");
1874 case SILC_COMMAND_INVITE:
1876 SilcChannelEntry channel;
1878 SilcArgumentPayload invite_list;
1884 channel = va_arg(vp, SilcChannelEntry);
1885 payload = va_arg(vp, SilcBuffer);
1888 SILC_GET16_MSB(argc, payload->data);
1889 invite_list = silc_argument_payload_parse(payload->data + 2,
1890 payload->len - 2, argc);
1892 silc_parse_inviteban_list(client, conn, server, channel,
1893 "invite", invite_list);
1894 silc_argument_payload_free(invite_list);
1900 case SILC_COMMAND_JOIN:
1902 char *channel, *mode, *topic;
1904 SilcChannelEntry channel_entry;
1905 SilcBuffer client_id_list;
1906 SilcUInt32 list_count;
1911 channel = va_arg(vp, char *);
1912 channel_entry = va_arg(vp, SilcChannelEntry);
1913 modei = va_arg(vp, SilcUInt32);
1914 (void)va_arg(vp, SilcUInt32);
1915 (void)va_arg(vp, unsigned char *);
1916 (void)va_arg(vp, unsigned char *);
1917 (void)va_arg(vp, unsigned char *);
1918 topic = va_arg(vp, char *);
1919 (void)va_arg(vp, unsigned char *);
1920 list_count = va_arg(vp, SilcUInt32);
1921 client_id_list = va_arg(vp, SilcBuffer);
1923 chanrec = silc_channel_find(server, channel);
1925 chanrec = silc_channel_create(server, channel, channel, TRUE);
1928 char tmp[256], *cp, *dm = NULL;
1929 g_free_not_null(chanrec->topic);
1931 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1932 memset(tmp, 0, sizeof(tmp));
1934 if (strlen(topic) > sizeof(tmp) - 1) {
1935 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1939 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1944 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1945 signal_emit("channel topic changed", 1, chanrec);
1950 mode = silc_client_chmode(modei,
1951 channel_entry->channel_key ?
1952 silc_cipher_get_name(channel_entry->
1954 channel_entry->hmac ?
1955 silc_hmac_get_name(channel_entry->hmac) : "");
1956 g_free_not_null(chanrec->mode);
1957 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1958 signal_emit("channel mode changed", 1, chanrec);
1960 /* Resolve the client information */
1962 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1963 r->channel = channel_entry;
1964 silc_client_get_clients_by_list(client, conn, list_count,
1966 silc_client_join_get_users, r);
1972 case SILC_COMMAND_NICK:
1975 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1981 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1982 if ((nicks != NULL) &&
1983 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1985 SilcClientEntry collider, old;
1987 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1988 collider = silc_client_get_client_by_id(client, conn,
1991 if (collider != client_entry) {
1993 memset(buf, 0, sizeof(buf));
1994 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1995 collider->username, collider->hostname);
1996 nicklist_rename_unique(SERVER(server),
1998 collider, collider->nickname);
1999 silc_print_nick_change(server, collider->nickname,
2000 client_entry->nickname, buf);
2005 g_slist_free(nicks);
2007 old = g_strdup(server->nick);
2008 server_change_nick(SERVER(server), client_entry->nickname);
2009 nicklist_rename_unique(SERVER(server),
2010 server->conn->local_entry, server->nick,
2011 client_entry, client_entry->nickname);
2012 signal_emit("message own_nick", 4, server, server->nick, old, "");
2015 /* when connecting to a server, the last thing we receive
2016 is a SILC_COMMAND_LIST reply. Since we enable queueing
2017 during the connection, we can now safely disable it again */
2018 silc_queue_disable(conn);
2022 case SILC_COMMAND_LIST:
2027 char tmp[256], *cp, *dm = NULL;
2032 (void)va_arg(vp, SilcChannelEntry);
2033 name = va_arg(vp, char *);
2036 topic = va_arg(vp, char *);
2037 usercount = va_arg(vp, int);
2039 if (topic && !silc_term_utf8() &&
2040 silc_utf8_valid(topic, strlen(topic))) {
2041 memset(tmp, 0, sizeof(tmp));
2043 if (strlen(topic) > sizeof(tmp) - 1) {
2044 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2048 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2053 if (status == SILC_STATUS_LIST_START ||
2054 status == SILC_STATUS_OK)
2055 printformat_module("fe-common/silc", server, NULL,
2056 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
2059 snprintf(users, sizeof(users) - 1, "N/A");
2061 snprintf(users, sizeof(users) - 1, "%d", usercount);
2062 printformat_module("fe-common/silc", server, NULL,
2063 MSGLEVEL_CRAP, SILCTXT_LIST,
2064 name, users, topic ? topic : "");
2069 case SILC_COMMAND_UMODE:
2077 mode = va_arg(vp, SilcUInt32);
2079 if (mode & SILC_UMODE_SERVER_OPERATOR &&
2080 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
2081 printformat_module("fe-common/silc", server, NULL,
2082 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2084 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
2085 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
2086 printformat_module("fe-common/silc", server, NULL,
2087 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2089 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
2090 if (mode & SILC_UMODE_GONE) {
2091 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
2092 reason = g_strdup(server->away_reason);
2094 reason = g_strdup("away");
2096 reason = g_strdup("");
2098 silc_set_away(reason, server);
2103 server->umode = mode;
2104 signal_emit("user mode changed", 2, server, NULL);
2108 case SILC_COMMAND_OPER:
2112 server->umode |= SILC_UMODE_SERVER_OPERATOR;
2113 signal_emit("user mode changed", 2, server, NULL);
2115 printformat_module("fe-common/silc", server, NULL,
2116 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2119 case SILC_COMMAND_SILCOPER:
2123 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2124 signal_emit("user mode changed", 2, server, NULL);
2126 printformat_module("fe-common/silc", server, NULL,
2127 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2130 case SILC_COMMAND_USERS:
2132 SilcHashTableList htl;
2133 SilcChannelEntry channel;
2134 SilcChannelUser chu;
2139 channel = va_arg(vp, SilcChannelEntry);
2141 printformat_module("fe-common/silc", server, channel->channel_name,
2142 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2143 channel->channel_name);
2145 silc_hash_table_list(channel->user_list, &htl);
2146 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2147 SilcClientEntry e = chu->client;
2148 char stat[5], *mode;
2153 memset(stat, 0, sizeof(stat));
2154 mode = silc_client_chumode_char(chu->mode);
2155 if (e->mode & SILC_UMODE_GONE)
2157 else if (e->mode & SILC_UMODE_INDISPOSED)
2159 else if (e->mode & SILC_UMODE_BUSY)
2161 else if (e->mode & SILC_UMODE_PAGE)
2163 else if (e->mode & SILC_UMODE_HYPER)
2165 else if (e->mode & SILC_UMODE_ROBOT)
2167 else if (e->mode & SILC_UMODE_ANONYMOUS)
2174 printformat_module("fe-common/silc", server, channel->channel_name,
2175 MSGLEVEL_CRAP, SILCTXT_USERS,
2177 e->username ? e->username : "",
2178 e->hostname ? e->hostname : "",
2179 e->realname ? e->realname : "");
2183 silc_hash_table_list_reset(&htl);
2187 case SILC_COMMAND_BAN:
2189 SilcChannelEntry channel;
2191 SilcArgumentPayload ban_list;
2197 channel = va_arg(vp, SilcChannelEntry);
2198 payload = va_arg(vp, SilcBuffer);
2201 SILC_GET16_MSB(argc, payload->data);
2202 ban_list = silc_argument_payload_parse(payload->data + 2,
2203 payload->len - 2, argc);
2205 silc_parse_inviteban_list(client, conn, server, channel,
2207 silc_argument_payload_free(ban_list);
2213 case SILC_COMMAND_GETKEY:
2217 SilcPublicKey public_key;
2220 GetkeyContext getkey;
2226 id_type = va_arg(vp, SilcUInt32);
2227 entry = va_arg(vp, void *);
2228 public_key = va_arg(vp, SilcPublicKey);
2231 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2233 getkey = silc_calloc(1, sizeof(*getkey));
2234 getkey->entry = entry;
2235 getkey->id_type = id_type;
2236 getkey->client = client;
2237 getkey->conn = conn;
2238 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2240 name = (id_type == SILC_ID_CLIENT ?
2241 ((SilcClientEntry)entry)->nickname :
2242 ((SilcServerEntry)entry)->server_name);
2244 silc_verify_public_key_internal(client, conn, name,
2245 (id_type == SILC_ID_CLIENT ?
2246 SILC_SOCKET_TYPE_CLIENT :
2247 SILC_SOCKET_TYPE_SERVER),
2248 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2249 silc_getkey_cb, getkey);
2252 printformat_module("fe-common/silc", server, NULL,
2253 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2258 case SILC_COMMAND_INFO:
2260 SilcServerEntry server_entry;
2267 server_entry = va_arg(vp, SilcServerEntry);
2268 server_name = va_arg(vp, char *);
2269 server_info = va_arg(vp, char *);
2271 if (server_name && server_info )
2273 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2274 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2279 case SILC_COMMAND_TOPIC:
2281 SilcChannelEntry channel;
2283 char tmp[256], *cp, *dm = NULL;
2288 channel = va_arg(vp, SilcChannelEntry);
2289 topic = va_arg(vp, char *);
2291 if (topic && !silc_term_utf8() &&
2292 silc_utf8_valid(topic, strlen(topic))) {
2293 memset(tmp, 0, sizeof(tmp));
2295 if (strlen(topic) > sizeof(tmp) - 1) {
2296 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2300 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2306 chanrec = silc_channel_find_entry(server, channel);
2308 g_free_not_null(chanrec->topic);
2309 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2310 signal_emit("channel topic changed", 1, chanrec);
2312 printformat_module("fe-common/silc", server, channel->channel_name,
2313 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2314 channel->channel_name, topic);
2316 printformat_module("fe-common/silc", server, channel->channel_name,
2317 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2318 channel->channel_name);
2324 case SILC_COMMAND_WATCH:
2327 case SILC_COMMAND_STATS:
2329 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2330 my_router_ops, cell_clients, cell_channels, cell_servers,
2331 clients, channels, servers, routers, server_ops, router_ops;
2333 SilcBufferStruct buf;
2334 unsigned char *tmp_buf;
2336 const char *tmptime;
2337 int days, hours, mins, secs;
2342 tmp_buf = va_arg(vp, unsigned char *);
2343 buf_len = va_arg(vp, SilcUInt32);
2345 if (!tmp_buf || !buf_len) {
2346 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2350 /* Get statistics structure */
2351 silc_buffer_set(&buf, tmp_buf, buf_len);
2352 silc_buffer_unformat(&buf,
2353 SILC_STR_UI_INT(&starttime),
2354 SILC_STR_UI_INT(&uptime),
2355 SILC_STR_UI_INT(&my_clients),
2356 SILC_STR_UI_INT(&my_channels),
2357 SILC_STR_UI_INT(&my_server_ops),
2358 SILC_STR_UI_INT(&my_router_ops),
2359 SILC_STR_UI_INT(&cell_clients),
2360 SILC_STR_UI_INT(&cell_channels),
2361 SILC_STR_UI_INT(&cell_servers),
2362 SILC_STR_UI_INT(&clients),
2363 SILC_STR_UI_INT(&channels),
2364 SILC_STR_UI_INT(&servers),
2365 SILC_STR_UI_INT(&routers),
2366 SILC_STR_UI_INT(&server_ops),
2367 SILC_STR_UI_INT(&router_ops),
2370 tmptime = silc_get_time(starttime);
2371 printformat_module("fe-common/silc", server, NULL,
2372 MSGLEVEL_CRAP, SILCTXT_STATS,
2373 "Local server start time", tmptime);
2375 days = uptime / (24 * 60 * 60);
2376 uptime -= days * (24 * 60 * 60);
2377 hours = uptime / (60 * 60);
2378 uptime -= hours * (60 * 60);
2380 uptime -= mins * 60;
2382 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2383 days, hours, mins, secs);
2384 printformat_module("fe-common/silc", server, NULL,
2385 MSGLEVEL_CRAP, SILCTXT_STATS,
2386 "Local server uptime", tmp);
2388 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2389 printformat_module("fe-common/silc", server, NULL,
2390 MSGLEVEL_CRAP, SILCTXT_STATS,
2391 "Local server clients", tmp);
2393 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2394 printformat_module("fe-common/silc", server, NULL,
2395 MSGLEVEL_CRAP, SILCTXT_STATS,
2396 "Local server channels", tmp);
2398 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2399 printformat_module("fe-common/silc", server, NULL,
2400 MSGLEVEL_CRAP, SILCTXT_STATS,
2401 "Local server operators", tmp);
2403 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2404 printformat_module("fe-common/silc", server, NULL,
2405 MSGLEVEL_CRAP, SILCTXT_STATS,
2406 "Local router operators", tmp);
2408 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2409 printformat_module("fe-common/silc", server, NULL,
2410 MSGLEVEL_CRAP, SILCTXT_STATS,
2411 "Local cell clients", tmp);
2413 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2414 printformat_module("fe-common/silc", server, NULL,
2415 MSGLEVEL_CRAP, SILCTXT_STATS,
2416 "Local cell channels", tmp);
2418 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2419 printformat_module("fe-common/silc", server, NULL,
2420 MSGLEVEL_CRAP, SILCTXT_STATS,
2421 "Local cell servers", tmp);
2423 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2424 printformat_module("fe-common/silc", server, NULL,
2425 MSGLEVEL_CRAP, SILCTXT_STATS,
2426 "Total clients", tmp);
2428 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2429 printformat_module("fe-common/silc", server, NULL,
2430 MSGLEVEL_CRAP, SILCTXT_STATS,
2431 "Total channels", tmp);
2433 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2434 printformat_module("fe-common/silc", server, NULL,
2435 MSGLEVEL_CRAP, SILCTXT_STATS,
2436 "Total servers", tmp);
2438 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2439 printformat_module("fe-common/silc", server, NULL,
2440 MSGLEVEL_CRAP, SILCTXT_STATS,
2441 "Total routers", tmp);
2443 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2444 printformat_module("fe-common/silc", server, NULL,
2445 MSGLEVEL_CRAP, SILCTXT_STATS,
2446 "Total server operators", tmp);
2448 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2449 printformat_module("fe-common/silc", server, NULL,
2450 MSGLEVEL_CRAP, SILCTXT_STATS,
2451 "Total router operators", tmp);
2455 case SILC_COMMAND_CMODE:
2457 SilcChannelEntry channel_entry;
2458 SilcBuffer channel_pubkeys;
2460 channel_entry = va_arg(vp, SilcChannelEntry);
2461 (void)va_arg(vp, SilcUInt32);
2462 (void)va_arg(vp, SilcPublicKey);
2463 channel_pubkeys = va_arg(vp, SilcBuffer);
2465 if (!success || !cmode_list_chpks ||
2466 !channel_entry || !channel_entry->channel_name)
2469 /* Print the channel public key list */
2470 if (channel_pubkeys)
2471 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2473 printformat_module("fe-common/silc", server, NULL,
2474 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2475 channel_entry->channel_name);
2480 case SILC_COMMAND_LEAVE:
2482 /* we might be cycling, so disable queueing again */
2483 silc_queue_disable(conn);
2494 SilcClientConnection conn;
2500 SilcSKEPKType pk_type;
2501 SilcVerifyPublicKey completion;
2505 static void verify_public_key_completion(const char *line, void *context)
2507 PublicKeyVerify verify = (PublicKeyVerify)context;
2509 if (line[0] == 'Y' || line[0] == 'y') {
2510 /* Call the completion */
2511 if (verify->completion)
2512 verify->completion(TRUE, verify->context);
2514 /* Save the key for future checking */
2515 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2516 verify->pk_len, SILC_PKCS_FILE_PEM);
2518 /* Call the completion */
2519 if (verify->completion)
2520 verify->completion(FALSE, verify->context);
2522 printformat_module("fe-common/silc", NULL, NULL,
2523 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2524 verify->entity_name ? verify->entity_name :
2528 silc_free(verify->filename);
2529 silc_free(verify->entity);
2530 silc_free(verify->entity_name);
2531 silc_free(verify->pk);
2535 /* Internal routine to verify public key. If the `completion' is provided
2536 it will be called to indicate whether public was verified or not. For
2537 server/router public key this will check for filename that includes the
2538 remote host's IP address and remote host's hostname. */
2541 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2542 const char *name, SilcSocketType conn_type,
2543 unsigned char *pk, SilcUInt32 pk_len,
2544 SilcSKEPKType pk_type,
2545 SilcVerifyPublicKey completion, void *context)
2548 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2549 char *fingerprint, *babbleprint, *format;
2552 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2553 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2554 "server" : "client");
2555 PublicKeyVerify verify;
2557 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2558 printformat_module("fe-common/silc", NULL, NULL,
2559 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2562 completion(FALSE, context);
2566 pw = getpwuid(getuid());
2569 completion(FALSE, context);
2573 memset(filename, 0, sizeof(filename));
2574 memset(filename2, 0, sizeof(filename2));
2575 memset(file, 0, sizeof(file));
2577 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2578 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2580 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2581 conn->sock->ip, conn->sock->port);
2582 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2583 get_irssi_dir(), entity, file);
2585 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2586 conn->sock->hostname, conn->sock->port);
2587 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2588 get_irssi_dir(), entity, file);
2593 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2594 name, conn->sock->port);
2595 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2596 get_irssi_dir(), entity, file);
2601 /* Replace all whitespaces with `_'. */
2602 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2603 for (i = 0; i < strlen(fingerprint); i++)
2604 if (fingerprint[i] == ' ')
2605 fingerprint[i] = '_';
2607 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2608 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2609 get_irssi_dir(), entity, file);
2610 silc_free(fingerprint);
2615 /* Take fingerprint of the public key */
2616 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2617 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2619 verify = silc_calloc(1, sizeof(*verify));
2620 verify->client = client;
2621 verify->conn = conn;
2622 verify->filename = strdup(ipf);
2623 verify->entity = strdup(entity);
2624 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2625 (name ? strdup(name) : strdup(conn->sock->hostname))
2627 verify->pk = silc_memdup(pk, pk_len);
2628 verify->pk_len = pk_len;
2629 verify->pk_type = pk_type;
2630 verify->completion = completion;
2631 verify->context = context;
2633 /* Check whether this key already exists */
2634 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2635 /* Key does not exist, ask user to verify the key and save it */
2637 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2638 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2639 verify->entity_name : entity);
2640 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2641 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2642 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2643 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2644 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2645 SILCTXT_PUBKEY_ACCEPT);
2646 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2649 silc_free(fingerprint);
2652 /* The key already exists, verify it. */
2653 SilcPublicKey public_key;
2654 unsigned char *encpk;
2655 SilcUInt32 encpk_len;
2657 /* Load the key file, try for both IP filename and hostname filename */
2658 if (!silc_pkcs_load_public_key(ipf, &public_key,
2659 SILC_PKCS_FILE_PEM) &&
2660 !silc_pkcs_load_public_key(ipf, &public_key,
2661 SILC_PKCS_FILE_BIN) &&
2662 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2663 SILC_PKCS_FILE_PEM) &&
2664 !silc_pkcs_load_public_key(hostf, &public_key,
2665 SILC_PKCS_FILE_BIN)))) {
2666 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2667 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2668 verify->entity_name : entity);
2669 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2670 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2671 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2672 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2673 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2674 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2675 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2676 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2677 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2680 silc_free(fingerprint);
2684 /* Encode the key data */
2685 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2687 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2688 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2689 verify->entity_name : entity);
2690 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2691 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2692 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2693 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2694 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2695 SILCTXT_PUBKEY_MALFORMED, entity);
2696 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2697 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2698 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2701 silc_free(fingerprint);
2705 /* Compare the keys */
2706 if (memcmp(encpk, pk, encpk_len)) {
2707 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2708 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2709 verify->entity_name : entity);
2710 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2711 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2712 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2713 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2714 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2715 SILCTXT_PUBKEY_NO_MATCH, entity);
2716 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2717 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2718 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2719 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2721 /* Ask user to verify the key and save it */
2722 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2723 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2724 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2727 silc_free(fingerprint);
2731 /* Local copy matched */
2733 completion(TRUE, context);
2734 silc_free(fingerprint);
2735 silc_free(verify->filename);
2736 silc_free(verify->entity);
2737 silc_free(verify->entity_name);
2738 silc_free(verify->pk);
2743 /* Verifies received public key. The `conn_type' indicates which entity
2744 (server, client etc.) has sent the public key. If user decides to trust
2745 the key may be saved as trusted public key for later use. The
2746 `completion' must be called after the public key has been verified. */
2749 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2750 SilcSocketType conn_type, unsigned char *pk,
2751 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2752 SilcVerifyPublicKey completion, void *context)
2754 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2756 completion, context);
2759 /* Asks passphrase from user on the input line. */
2762 SilcAskPassphrase completion;
2766 void ask_passphrase_completion(const char *passphrase, void *context)
2768 AskPassphrase p = (AskPassphrase)context;
2769 if (passphrase && passphrase[0] == '\0')
2771 p->completion((unsigned char *)passphrase,
2772 passphrase ? strlen(passphrase) : 0, p->context);
2776 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2777 SilcAskPassphrase completion, void *context)
2779 AskPassphrase p = silc_calloc(1, sizeof(*p));
2780 p->completion = completion;
2781 p->context = context;
2783 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2784 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2788 SilcGetAuthMeth completion;
2790 } *InternalGetAuthMethod;
2792 /* Callback called when we've received the authentication method information
2793 from the server after we've requested it. This will get the authentication
2794 data from the user if needed. */
2796 static void silc_get_auth_method_callback(SilcClient client,
2797 SilcClientConnection conn,
2798 SilcAuthMethod auth_meth,
2801 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2803 SILC_LOG_DEBUG(("Start"));
2805 switch (auth_meth) {
2806 case SILC_AUTH_NONE:
2807 /* No authentication required. */
2808 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2810 case SILC_AUTH_PASSWORD:
2812 /* Check whether we find the password for this server in our
2813 configuration. If not, then don't provide so library will ask
2814 it from the user. */
2815 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2817 if (!setup || !setup->password) {
2818 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2822 (*internal->completion)(TRUE, auth_meth, setup->password,
2823 strlen(setup->password), internal->context);
2826 case SILC_AUTH_PUBLIC_KEY:
2827 /* Do not get the authentication data now, the library will generate
2828 it using our default key, if we do not provide it here. */
2829 /* XXX In the future when we support multiple local keys and multiple
2830 local certificates we will need to ask from user which one to use. */
2831 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2835 silc_free(internal);
2838 /* Find authentication method and authentication data by hostname and
2839 port. The hostname may be IP address as well. The found authentication
2840 method and authentication data is returned to `auth_meth', `auth_data'
2841 and `auth_data_len'. The function returns TRUE if authentication method
2842 is found and FALSE if not. `conn' may be NULL. */
2844 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2845 char *hostname, SilcUInt16 port,
2846 SilcGetAuthMeth completion, void *context)
2848 InternalGetAuthMethod internal;
2850 SILC_LOG_DEBUG(("Start"));
2852 /* If we do not have this connection configured by the user in a
2853 configuration file then resolve the authentication method from the
2854 server for this session. */
2855 internal = silc_calloc(1, sizeof(*internal));
2856 internal->completion = completion;
2857 internal->context = context;
2859 silc_client_request_authentication_method(client, conn,
2860 silc_get_auth_method_callback,
2864 /* Notifies application that failure packet was received. This is called
2865 if there is some protocol active in the client. The `protocol' is the
2866 protocol context. The `failure' is opaque pointer to the failure
2867 indication. Note, that the `failure' is protocol dependant and application
2868 must explicitly cast it to correct type. Usually `failure' is 32 bit
2869 failure type (see protocol specs for all protocol failure types). */
2871 void silc_failure(SilcClient client, SilcClientConnection conn,
2872 SilcProtocol protocol, void *failure)
2874 SILC_LOG_DEBUG(("Start"));
2876 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2877 SilcSKEStatus status = (SilcSKEStatus)failure;
2879 if (status == SILC_SKE_STATUS_BAD_VERSION)
2880 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2881 SILCTXT_KE_BAD_VERSION);
2882 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2883 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2884 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2885 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2886 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2887 SILCTXT_KE_UNKNOWN_GROUP);
2888 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2889 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2890 SILCTXT_KE_UNKNOWN_CIPHER);
2891 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2892 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2893 SILCTXT_KE_UNKNOWN_PKCS);
2894 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2895 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2896 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2897 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2898 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2899 SILCTXT_KE_UNKNOWN_HMAC);
2900 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2901 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2902 SILCTXT_KE_INCORRECT_SIGNATURE);
2903 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2904 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2905 SILCTXT_KE_INVALID_COOKIE);
2908 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2909 SilcUInt32 err = (SilcUInt32)failure;
2911 if (err == SILC_AUTH_FAILED)
2912 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2913 SILCTXT_AUTH_FAILED);
2917 /* Asks whether the user would like to perform the key agreement protocol.
2918 This is called after we have received an key agreement packet or an
2919 reply to our key agreement packet. This returns TRUE if the user wants
2920 the library to perform the key agreement protocol and FALSE if it is not
2921 desired (application may start it later by calling the function
2922 silc_client_perform_key_agreement). */
2924 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2925 SilcClientEntry client_entry, const char *hostname,
2926 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2931 SILC_LOG_DEBUG(("Start"));
2933 /* We will just display the info on the screen and return FALSE and user
2934 will have to start the key agreement with a command. */
2937 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2940 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2941 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2943 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2944 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2945 client_entry->nickname, hostname, portstr);
2953 /* Notifies application that file transfer protocol session is being
2954 requested by the remote client indicated by the `client_entry' from
2955 the `hostname' and `port'. The `session_id' is the file transfer
2956 session and it can be used to either accept or reject the file
2957 transfer request, by calling the silc_client_file_receive or
2958 silc_client_file_close, respectively. */
2960 void silc_ftp(SilcClient client, SilcClientConnection conn,
2961 SilcClientEntry client_entry, SilcUInt32 session_id,
2962 const char *hostname, SilcUInt16 port)
2964 SILC_SERVER_REC *server;
2966 FtpSession ftp = NULL;
2968 SILC_LOG_DEBUG(("Start"));
2970 server = conn->context;
2972 silc_dlist_start(server->ftp_sessions);
2973 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2974 if (ftp->client_entry == client_entry &&
2975 ftp->session_id == session_id) {
2976 server->current_session = ftp;
2980 if (ftp == SILC_LIST_END) {
2981 ftp = silc_calloc(1, sizeof(*ftp));
2982 ftp->client_entry = client_entry;
2983 ftp->session_id = session_id;
2986 silc_dlist_add(server->ftp_sessions, ftp);
2987 server->current_session = ftp;
2991 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2994 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2995 SILCTXT_FILE_REQUEST, client_entry->nickname);
2997 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2998 SILCTXT_FILE_REQUEST_HOST,
2999 client_entry->nickname, hostname, portstr);
3002 /* Delivers SILC session detachment data indicated by `detach_data' to the
3003 application. If application has issued SILC_COMMAND_DETACH command
3004 the client session in the SILC network is not quit. The client remains
3005 in the network but is detached. The detachment data may be used later
3006 to resume the session in the SILC Network. The appliation is
3007 responsible of saving the `detach_data', to for example in a file.
3009 The detachment data can be given as argument to the functions
3010 silc_client_connect_to_server, or silc_client_add_connection when
3011 creating connection to remote server, inside SilcClientConnectionParams
3012 structure. If it is provided the client library will attempt to resume
3013 the session in the network. After the connection is created
3014 successfully, the application is responsible of setting the user
3015 interface for user into the same state it was before detaching (showing
3016 same channels, channel modes, etc). It can do this by fetching the
3017 information (like joined channels) from the client library. */
3020 silc_detach(SilcClient client, SilcClientConnection conn,
3021 const unsigned char *detach_data, SilcUInt32 detach_data_len)
3023 SILC_SERVER_REC *server = conn->context;
3026 /* Save the detachment data to file. */
3028 file = silc_get_session_filename(server);
3029 silc_file_writefile(file, detach_data, detach_data_len);
3034 /* SILC client operations */
3035 SilcClientOperations ops = {
3037 silc_channel_message,
3038 silc_private_message,
3044 silc_get_auth_method,
3045 silc_verify_public_key,
3046 silc_ask_passphrase,