5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
32 #include "silc-cmdqueue.h"
38 #include "special-vars.h"
39 #include "fe-common/core/printtext.h"
40 #include "fe-common/core/fe-channels.h"
41 #include "fe-common/core/keyboard.h"
42 #include "fe-common/core/window-items.h"
43 #include "fe-common/silc/module-formats.h"
48 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
49 const char *name, SilcConnectionType conn_type,
50 SilcPublicKey public_key,
51 SilcVerifyPublicKey completion, void *context);
53 char *silc_get_session_filename(SILC_SERVER_REC *server)
55 char *file, *expanded;
57 expanded = parse_special_string(settings_get_str("session_filename"),
58 SERVER(server), NULL, "", NULL, 0);
60 file = silc_calloc(1, strlen(expanded) + 255);
61 snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
67 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
70 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
71 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
72 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
74 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
75 "[SILC operator]" : "[unknown mode]");
77 if (mode & SILC_UMODE_GONE)
78 strcat(buf, " [away]");
79 if (mode & SILC_UMODE_INDISPOSED)
80 strcat(buf, " [indisposed]");
81 if (mode & SILC_UMODE_BUSY)
82 strcat(buf, " [busy]");
83 if (mode & SILC_UMODE_PAGE)
84 strcat(buf, " [page to reach]");
85 if (mode & SILC_UMODE_HYPER)
86 strcat(buf, " [hyper active]");
87 if (mode & SILC_UMODE_ROBOT)
88 strcat(buf, " [robot]");
89 if (mode & SILC_UMODE_ANONYMOUS)
90 strcat(buf, " [anonymous]");
91 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
92 strcat(buf, " [blocks private messages]");
93 if (mode & SILC_UMODE_DETACHED)
94 strcat(buf, " [detached]");
95 if (mode & SILC_UMODE_REJECT_WATCHING)
96 strcat(buf, " [rejects watching]");
97 if (mode & SILC_UMODE_BLOCK_INVITE)
98 strcat(buf, " [blocks invites]");
101 /* converts an utf-8 string to current locale */
102 char * silc_convert_utf8_string(const char *str)
104 int message_len = (str != NULL ? strlen(str) : 0);
105 char *message = silc_calloc(message_len + 1, sizeof(*message));
107 g_return_val_if_fail(message != NULL, NULL);
114 if (!silc_term_utf8() && silc_utf8_valid(str, message_len))
115 silc_utf8_decode(str, message_len, SILC_STRING_LOCALE,
116 message, message_len);
118 strcpy(message, str);
123 /* print "nick appears as" message to every channel of a server */
125 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
126 const char *newnick, const char *oldnick,
129 if (ignore_check(SERVER(server), oldnick, address,
130 channel, newnick, MSGLEVEL_NICKS))
133 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
134 SILCTXT_CHANNEL_APPEARS,
135 oldnick, newnick, channel, address);
139 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
140 const char *oldnick, const char *address)
142 GSList *tmp, *windows;
144 /* Print to each channel/query where the nick is.
145 Don't print more than once to the same window. */
148 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
149 CHANNEL_REC *channel = tmp->data;
150 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
152 if (nicklist_find(channel, newnick) == NULL ||
153 g_slist_find(windows, window) != NULL)
156 windows = g_slist_append(windows, window);
157 silc_print_nick_change_channel(server, channel->visible_name,
158 newnick, oldnick, address);
161 g_slist_free(windows);
164 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
165 SilcChannelEntry channel_entry,
166 SilcDList channel_pubkeys)
168 SilcArgumentDecodedList e;
169 SilcPublicKey pubkey;
170 SilcSILCPublicKey silc_pubkey;
171 SilcUInt32 pk_len, type;
173 char *fingerprint, *babbleprint;
176 printformat_module("fe-common/silc", server, NULL,
177 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
178 channel_entry->channel_name);
180 silc_dlist_start(channel_pubkeys);
181 while ((e = silc_dlist_get(channel_pubkeys))) {
182 pubkey = e->argument;
185 if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
188 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
192 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
193 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
194 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, pubkey);
196 printformat_module("fe-common/silc", server, NULL,
197 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
198 c++, channel_entry->channel_name,
199 type == 0x00 ? "Added" : "Removed",
200 silc_pubkey->identifier.realname ?
201 silc_pubkey->identifier.realname : "",
202 fingerprint, babbleprint);
204 silc_free(fingerprint);
205 silc_free(babbleprint);
210 void silc_say(SilcClient client, SilcClientConnection conn,
211 SilcClientMessageType type, char *msg, ...)
213 SILC_SERVER_REC *server;
217 server = conn == NULL ? NULL : conn->context;
220 str = g_strdup_vprintf(msg, va);
221 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
226 void silc_say_error(char *msg, ...)
232 str = g_strdup_vprintf(msg, va);
233 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
239 /* Try to verify a message using locally stored public key data */
241 int verify_message_signature(SilcClientEntry sender,
242 SilcMessagePayload message)
245 char file[256], filename[256];
246 char *fingerprint, *fingerprint2;
247 const unsigned char *pk_data;
248 SilcUInt32 pk_datalen;
250 int ret = SILC_MSG_SIGNED_VERIFIED, i;
252 /* get public key from the signature payload and compare it with the
253 one stored in the client entry */
254 pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
257 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
259 if (sender->fingerprint[0]) {
260 fingerprint2 = silc_fingerprint(sender->fingerprint,
261 sizeof(sender->fingerprint));
262 if (strcmp(fingerprint, fingerprint2)) {
263 /* since the public key differs from the senders public key, the
264 verification _failed_ */
265 silc_pkcs_public_key_free(pk);
266 silc_free(fingerprint);
267 ret = SILC_MSG_SIGNED_UNKNOWN;
269 silc_free(fingerprint2);
271 } else if (sender->fingerprint[0])
272 fingerprint = silc_fingerprint(sender->fingerprint,
273 sizeof(sender->fingerprint));
275 /* no idea, who or what signed that message ... */
276 return SILC_MSG_SIGNED_UNKNOWN;
278 /* search our local client key cache */
279 for (i = 0; i < strlen(fingerprint); i++)
280 if (fingerprint[i] == ' ')
281 fingerprint[i] = '_';
283 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
284 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
285 get_irssi_dir(), file);
286 silc_free(fingerprint);
288 if (stat(filename, &st) < 0)
289 /* we don't have the public key cached ... use the one from the sig */
290 ret = SILC_MSG_SIGNED_UNKNOWN;
292 SilcPublicKey cached_pk=NULL;
294 /* try to load the file */
295 if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
296 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
297 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
299 return SILC_MSG_SIGNED_UNKNOWN;
301 ret = SILC_MSG_SIGNED_UNKNOWN;
306 silc_pkcs_public_key_free(pk);
311 /* the public key is now in pk, our "level of trust" in ret */
312 if ((pk) && silc_message_signed_verify(message, pk,
313 sha1hash) != SILC_AUTH_OK)
314 ret = SILC_MSG_SIGNED_FAILED;
317 silc_pkcs_public_key_free(pk);
322 char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
325 int i = 0, j = 0, len = strlen(escaped_data);
327 data = silc_calloc(len, sizeof(char));
330 ptr = memchr(escaped_data + i, 1, len - i);
332 int inc = (ptr - escaped_data) - i;
333 memcpy(data + j, escaped_data + i, inc);
336 data[j++] = *(ptr + 1) - 1;
338 memcpy(data + j, escaped_data + i, len - i);
348 char *silc_escape_data(const char *data, SilcUInt32 len)
350 char *escaped_data, *ptr, *ptr0, *ptr1;
353 escaped_data = silc_calloc(2 * len, sizeof(char));
356 ptr0 = memchr(data + i, 0, len - i);
357 ptr1 = memchr(data + i, 1, len - i);
359 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
362 int inc = (ptr - data) - i;
364 memcpy(escaped_data + j, data + i, inc);
367 escaped_data[j++] = 1;
368 escaped_data[j++] = *(data + i++) + 1;
370 memcpy(escaped_data + j, data + i, len - i);
379 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
380 const char *data, SilcUInt32 data_len,
381 const char *nick, int verified)
385 escaped_data = silc_escape_data(data, data_len);
387 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
389 silc_free(escaped_data);
393 /* Message for a channel. The `sender' is the nickname of the sender
394 received in the packet. The `channel_name' is the name of the channel. */
396 void silc_channel_message(SilcClient client, SilcClientConnection conn,
397 SilcClientEntry sender, SilcChannelEntry channel,
398 SilcMessagePayload payload,
399 SilcChannelPrivateKey key,
400 SilcMessageFlags flags, const unsigned char *message,
401 SilcUInt32 message_len)
403 SILC_SERVER_REC *server;
405 SILC_CHANNEL_REC *chanrec;
408 SILC_LOG_DEBUG(("Start"));
413 server = conn == NULL ? NULL : conn->context;
414 chanrec = silc_channel_find_entry(server, channel);
418 nick = silc_nicklist_find(chanrec, sender);
420 /* We didn't find client but it clearly exists, add it. */
421 SilcChannelUser chu = silc_client_on_channel(channel, sender);
423 nick = silc_nicklist_insert(chanrec, chu, FALSE);
428 /* If the messages is digitally signed, verify it, if possible. */
429 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
430 if (!settings_get_bool("ignore_message_signatures")) {
431 verified = verify_message_signature(sender, payload);
433 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
437 if (flags & SILC_MESSAGE_FLAG_DATA) {
438 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
439 nick == NULL ? NULL : nick->nick,
440 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
447 if (flags & SILC_MESSAGE_FLAG_ACTION)
448 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
449 char tmp[256], *cp, *dm = NULL;
450 memset(tmp, 0, sizeof(tmp));
452 if(message_len > sizeof(tmp) - 1) {
453 dm = silc_calloc(message_len + 1, sizeof(*dm));
456 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
458 if (flags & SILC_MESSAGE_FLAG_SIGNED)
459 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
460 nick->host, channel->channel_name, verified);
462 signal_emit("message silc action", 5, server, cp, nick->nick,
463 nick->host, channel->channel_name);
466 if (flags & SILC_MESSAGE_FLAG_SIGNED)
467 signal_emit("message silc signed_action", 6, server, message,
468 nick->nick, nick->host, channel->channel_name, verified);
470 signal_emit("message silc action", 5, server, message,
471 nick->nick, nick->host, channel->channel_name);
473 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
474 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
475 char tmp[256], *cp, *dm = NULL;
476 memset(tmp, 0, sizeof(tmp));
478 if(message_len > sizeof(tmp) - 1) {
479 dm = silc_calloc(message_len + 1, sizeof(*dm));
482 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
484 if (flags & SILC_MESSAGE_FLAG_SIGNED)
485 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
486 nick->host, channel->channel_name, verified);
488 signal_emit("message silc notice", 5, server, cp, nick->nick,
489 nick->host, channel->channel_name);
492 if (flags & SILC_MESSAGE_FLAG_SIGNED)
493 signal_emit("message silc signed_notice", 6, server, message,
494 nick->nick, nick->host, channel->channel_name, verified);
496 signal_emit("message silc notice", 5, server, message,
497 nick->nick, nick->host, channel->channel_name);
500 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
501 char tmp[256], *cp, *dm = NULL;
503 memset(tmp, 0, sizeof(tmp));
505 if (message_len > sizeof(tmp) - 1) {
506 dm = silc_calloc(message_len + 1, sizeof(*dm));
510 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
512 if (flags & SILC_MESSAGE_FLAG_SIGNED)
513 signal_emit("message signed_public", 6, server, cp,
514 nick == NULL ? "[<unknown>]" : nick->nick,
515 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
516 chanrec->name, verified);
518 signal_emit("message public", 6, server, cp,
519 nick == NULL ? "[<unknown>]" : nick->nick,
520 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
521 chanrec->name, nick);
526 if (flags & SILC_MESSAGE_FLAG_SIGNED)
527 signal_emit("message signed_public", 6, server, message,
528 nick == NULL ? "[<unknown>]" : nick->nick,
529 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
530 chanrec->name, verified);
532 signal_emit("message public", 6, server, message,
533 nick == NULL ? "[<unknown>]" : nick->nick,
534 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
535 chanrec->name, nick);
539 /* Private message to the client. The `sender' is the nickname of the
540 sender received in the packet. */
542 void silc_private_message(SilcClient client, SilcClientConnection conn,
543 SilcClientEntry sender, SilcMessagePayload payload,
544 SilcMessageFlags flags,
545 const unsigned char *message,
546 SilcUInt32 message_len)
548 SILC_SERVER_REC *server;
552 SILC_LOG_DEBUG(("Start"));
554 server = conn == NULL ? NULL : conn->context;
555 memset(userhost, 0, sizeof(userhost));
556 if (sender->username[0])
557 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
558 sender->username, sender->hostname);
560 /* If the messages is digitally signed, verify it, if possible. */
561 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
562 if (!settings_get_bool("ignore_message_signatures")) {
563 verified = verify_message_signature(sender, payload);
565 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
569 if (flags & SILC_MESSAGE_FLAG_DATA) {
570 silc_emit_mime_sig(server,
571 sender->nickname[0] ?
572 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
574 message, message_len,
575 sender->nickname[0] ? sender->nickname : "[<unknown>]",
576 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
583 if (flags & SILC_MESSAGE_FLAG_ACTION)
584 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
585 char tmp[256], *cp, *dm = NULL;
586 memset(tmp, 0, sizeof(tmp));
588 if(message_len > sizeof(tmp) - 1) {
589 dm = silc_calloc(message_len + 1, sizeof(*dm));
592 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
594 if (flags & SILC_MESSAGE_FLAG_SIGNED)
595 signal_emit("message silc signed_private_action", 6, server, cp,
596 sender->nickname[0] ? sender->nickname : "[<unknown>]",
597 sender->username[0] ? userhost : NULL,
600 signal_emit("message silc private_action", 5, server, cp,
601 sender->nickname[0] ? sender->nickname : "[<unknown>]",
602 sender->username[0] ? userhost : NULL, NULL);
605 if (flags & SILC_MESSAGE_FLAG_SIGNED)
606 signal_emit("message silc signed_private_action", 6, server, message,
607 sender->nickname[0] ? sender->nickname : "[<unknown>]",
608 sender->username[0] ? userhost : NULL,
611 signal_emit("message silc private_action", 5, server, message,
612 sender->nickname[0] ? sender->nickname : "[<unknown>]",
613 sender->username[0] ? userhost : NULL, NULL);
615 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
616 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
617 char tmp[256], *cp, *dm = NULL;
618 memset(tmp, 0, sizeof(tmp));
620 if(message_len > sizeof(tmp) - 1) {
621 dm = silc_calloc(message_len + 1, sizeof(*dm));
624 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
626 if (flags & SILC_MESSAGE_FLAG_SIGNED)
627 signal_emit("message silc signed_private_notice", 6, server, cp,
628 sender->nickname[0] ? sender->nickname : "[<unknown>]",
629 sender->username[0] ? userhost : NULL,
632 signal_emit("message silc private_notice", 5, server, cp,
633 sender->nickname[0] ? sender->nickname : "[<unknown>]",
634 sender->username[0] ? userhost : NULL, NULL);
637 if (flags & SILC_MESSAGE_FLAG_SIGNED)
638 signal_emit("message silc signed_private_notice", 6, server, message,
639 sender->nickname[0] ? sender->nickname : "[<unknown>]",
640 sender->username[0] ? userhost : NULL,
643 signal_emit("message silc private_notice", 5, server, message,
644 sender->nickname[0] ? sender->nickname : "[<unknown>]",
645 sender->username[0] ? userhost : NULL, NULL);
648 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
649 char tmp[256], *cp, *dm = NULL;
651 memset(tmp, 0, sizeof(tmp));
653 if (message_len > sizeof(tmp) - 1) {
654 dm = silc_calloc(message_len + 1, sizeof(*dm));
658 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
660 if (flags & SILC_MESSAGE_FLAG_SIGNED)
661 signal_emit("message signed_private", 5, server, cp,
662 sender->nickname[0] ? sender->nickname : "[<unknown>]",
663 sender->username[0] ? userhost : NULL, verified);
665 signal_emit("message private", 4, server, cp,
666 sender->nickname[0] ? sender->nickname : "[<unknown>]",
667 sender->username[0] ? userhost : NULL);
672 if (flags & SILC_MESSAGE_FLAG_SIGNED)
673 signal_emit("message signed_private", 5, server, message,
674 sender->nickname[0] ? sender->nickname : "[<unknown>]",
675 sender->username[0] ? userhost : NULL, verified);
677 signal_emit("message private", 4, server, message,
678 sender->nickname[0] ? sender->nickname : "[<unknown>]",
679 sender->username[0] ? userhost : NULL);
683 /* Notify message to the client. The notify arguments are sent in the
684 same order as servers sends them. The arguments are same as received
685 from the server except for ID's. If ID is received application receives
686 the corresponding entry to the ID. For example, if Client ID is received
687 application receives SilcClientEntry. Also, if the notify type is
688 for channel the channel entry is sent to application (even if server
689 does not send it). */
691 void silc_notify(SilcClient client, SilcClientConnection conn,
692 SilcNotifyType type, ...)
695 SILC_SERVER_REC *server;
696 SILC_CHANNEL_REC *chanrec;
697 SILC_NICK_REC *nickrec;
698 SilcClientEntry client_entry, client_entry2;
699 SilcChannelEntry channel, channel2;
700 SilcServerEntry server_entry;
705 char *name, *tmp, *cipher, *hmac;
706 GSList *list1, *list_tmp;
707 SilcDList chpks, clients;
709 SILC_LOG_DEBUG(("Start"));
713 server = conn == NULL ? NULL : conn->context;
716 case SILC_NOTIFY_TYPE_NONE:
717 /* Some generic notice from server */
718 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
721 case SILC_NOTIFY_TYPE_INVITE:
723 * Invited or modified invite list.
726 SILC_LOG_DEBUG(("Notify: INVITE"));
728 channel = va_arg(va, SilcChannelEntry);
729 name = va_arg(va, char *);
730 client_entry = va_arg(va, SilcClientEntry);
732 memset(buf, 0, sizeof(buf));
733 snprintf(buf, sizeof(buf) - 1, "%s@%s",
734 client_entry->username, client_entry->hostname);
735 signal_emit("message invite", 4, server, channel ? channel->channel_name :
736 name, client_entry->nickname, buf);
739 case SILC_NOTIFY_TYPE_JOIN:
744 SILC_LOG_DEBUG(("Notify: JOIN"));
746 client_entry = va_arg(va, SilcClientEntry);
747 channel = va_arg(va, SilcChannelEntry);
749 if (client_entry == server->conn->local_entry) {
750 /* You joined to channel */
751 chanrec = silc_channel_find(server, channel->channel_name);
753 chanrec = silc_channel_create(server, channel->channel_name,
754 channel->channel_name, TRUE);
755 if (!chanrec->joined)
756 chanrec->entry = channel;
758 chanrec = silc_channel_find_entry(server, channel);
759 if (chanrec != NULL) {
760 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
762 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
766 memset(buf, 0, sizeof(buf));
767 if (client_entry->username[0])
768 snprintf(buf, sizeof(buf) - 1, "%s@%s",
769 client_entry->username, client_entry->hostname);
770 signal_emit("message join", 4, server, channel->channel_name,
771 client_entry->nickname,
772 !client_entry->username[0] ? "" : buf);
774 /* If there are multiple same nicknames on channel now, tell it to user. */
775 if (client_entry != server->conn->local_entry) {
779 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
780 clients = silc_client_get_clients_local(client, conn, nick, TRUE);
781 if (!clients || silc_dlist_count(clients) < 2) {
783 silc_client_list_free(client, conn, clients);
786 silc_dlist_start(clients);
787 while ((client_entry2 = silc_dlist_get(clients)))
788 if (silc_client_on_channel(channel, client_entry2))
791 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
792 printformat_module("fe-common/silc", server, channel->channel_name,
793 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
795 printformat_module("fe-common/silc", server, channel->channel_name,
796 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
797 buf, client_entry->nickname);
799 silc_client_list_free(client, conn, clients);
804 case SILC_NOTIFY_TYPE_LEAVE:
809 SILC_LOG_DEBUG(("Notify: LEAVE"));
811 client_entry = va_arg(va, SilcClientEntry);
812 channel = va_arg(va, SilcChannelEntry);
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 part", 5, server, channel->channel_name,
819 client_entry->nickname, client_entry->username[0] ?
820 buf : "", client_entry->nickname);
822 chanrec = silc_channel_find_entry(server, channel);
823 if (chanrec != NULL) {
824 nickrec = silc_nicklist_find(chanrec, client_entry);
826 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
829 /* If there is only one client with this same nickname on channel now
830 change it to the base format if it is formatted nickname. */
832 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
833 clients = silc_client_get_clients_local(client, conn, name, TRUE);
834 if (!clients || silc_dlist_count(clients) != 2) {
836 silc_client_list_free(client, conn, clients);
839 silc_dlist_start(clients);
840 client_entry2 = silc_dlist_get(clients);
841 if (client_entry2 == client_entry)
842 client_entry2 = silc_dlist_get(clients);
843 if (silc_client_on_channel(channel, client_entry2)) {
844 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
845 silc_client_nickname_format(client, conn, client_entry2, TRUE);
846 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname))
847 printformat_module("fe-common/silc", server, channel->channel_name,
848 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
849 buf, client_entry2->nickname);
851 silc_client_list_free(client, conn, clients);
856 case SILC_NOTIFY_TYPE_SIGNOFF:
861 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
863 client_entry = va_arg(va, SilcClientEntry);
864 tmp = va_arg(va, char *);
865 channel = va_arg(va, SilcChannelEntry);
867 silc_server_free_ftp(server, client_entry);
869 memset(buf, 0, sizeof(buf));
870 if (client_entry->username)
871 snprintf(buf, sizeof(buf) - 1, "%s@%s",
872 client_entry->username, client_entry->hostname);
873 signal_emit("message quit", 4, server, client_entry->nickname,
874 client_entry->username[0] ? buf : "", tmp ? tmp : "");
876 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
877 for (list_tmp = list1; list_tmp != NULL; list_tmp =
878 list_tmp->next->next) {
879 CHANNEL_REC *channel = list_tmp->data;
880 NICK_REC *nickrec = list_tmp->next->data;
882 nicklist_remove(channel, nickrec);
885 /* If there is only one client with this same nickname on channel now
886 change it to the base format if it is formatted nickname. */
888 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
889 clients = silc_client_get_clients_local(client, conn, name, TRUE);
890 if (!clients || silc_dlist_count(clients) != 2) {
892 silc_client_list_free(client, conn, clients);
895 silc_dlist_start(clients);
896 client_entry2 = silc_dlist_get(clients);
897 if (client_entry2 == client_entry)
898 client_entry2 = silc_dlist_get(clients);
899 if (silc_client_on_channel(channel, client_entry2)) {
900 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
901 silc_client_nickname_format(client, conn, client_entry2, TRUE);
902 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname))
903 printformat_module("fe-common/silc", server, channel->channel_name,
904 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
905 buf, client_entry2->nickname);
907 silc_client_list_free(client, conn, clients);
912 case SILC_NOTIFY_TYPE_TOPIC_SET:
917 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
919 idtype = va_arg(va, int);
920 entry = va_arg(va, void *);
921 tmp = va_arg(va, char *);
922 channel = va_arg(va, SilcChannelEntry);
924 chanrec = silc_channel_find_entry(server, channel);
925 if (chanrec != NULL) {
926 char tmp2[256], *cp, *dm = NULL;
928 g_free_not_null(chanrec->topic);
929 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
930 memset(tmp2, 0, sizeof(tmp2));
932 if (strlen(tmp) > sizeof(tmp2) - 1) {
933 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
937 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
942 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
943 signal_emit("channel topic changed", 1, chanrec);
948 if (idtype == SILC_ID_CLIENT) {
949 client_entry = (SilcClientEntry)entry;
950 memset(buf, 0, sizeof(buf));
951 snprintf(buf, sizeof(buf) - 1, "%s@%s",
952 client_entry->username, client_entry->hostname);
953 signal_emit("message topic", 5, server, channel->channel_name,
954 tmp, client_entry->nickname, buf);
955 } else if (idtype == SILC_ID_SERVER) {
956 server_entry = (SilcServerEntry)entry;
957 signal_emit("message topic", 5, server, channel->channel_name,
958 tmp, server_entry->server_name,
959 server_entry->server_name);
960 } else if (idtype == SILC_ID_CHANNEL) {
961 channel = (SilcChannelEntry)entry;
962 signal_emit("message topic", 5, server, channel->channel_name,
963 tmp, channel->channel_name, channel->channel_name);
967 case SILC_NOTIFY_TYPE_NICK_CHANGE:
972 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
974 client_entry = va_arg(va, SilcClientEntry);
975 name = va_arg(va, char *); /* old nickname */
977 if (!strcmp(client_entry->nickname, name))
980 memset(buf, 0, sizeof(buf));
981 snprintf(buf, sizeof(buf) - 1, "%s@%s",
982 client_entry->username, client_entry->hostname);
983 nicklist_rename_unique(SERVER(server),
985 client_entry, client_entry->nickname);
986 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
989 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
991 * Changed channel mode.
994 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
996 idtype = va_arg(va, int);
997 entry = va_arg(va, void *);
998 mode = va_arg(va, SilcUInt32);
999 cipher = va_arg(va, char *); /* cipher */
1000 hmac = va_arg(va, char *); /* hmac */
1001 (void)va_arg(va, char *); /* passphrase */
1002 (void)va_arg(va, SilcPublicKey); /* founder key */
1003 chpks = va_arg(va, SilcDList); /* channel public keys */
1004 channel = va_arg(va, SilcChannelEntry);
1006 tmp = silc_client_chmode(mode, cipher ? cipher : "",
1009 chanrec = silc_channel_find_entry(server, channel);
1010 if (chanrec != NULL) {
1011 g_free_not_null(chanrec->mode);
1012 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
1013 signal_emit("channel mode changed", 1, chanrec);
1016 if (idtype == SILC_ID_CLIENT) {
1017 client_entry = (SilcClientEntry)entry;
1018 printformat_module("fe-common/silc", server, channel->channel_name,
1019 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1020 channel->channel_name, tmp ? tmp : "removed all",
1021 client_entry->nickname);
1022 } else if (idtype == SILC_ID_SERVER) {
1023 server_entry = (SilcServerEntry)entry;
1024 printformat_module("fe-common/silc", server, channel->channel_name,
1025 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1026 channel->channel_name, tmp ? tmp : "removed all",
1027 server_entry->server_name);
1028 } else if (idtype == SILC_ID_CHANNEL) {
1029 channel2 = (SilcChannelEntry)entry;
1030 printformat_module("fe-common/silc", server, channel->channel_name,
1031 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1032 channel->channel_name, tmp ? tmp : "removed all",
1033 channel2->channel_name);
1036 /* Print the channel public key list */
1038 silc_parse_channel_public_keys(server, channel, chpks);
1043 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1045 * Changed user's mode on channel.
1048 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1050 idtype = va_arg(va, int);
1051 entry = va_arg(va, void *);
1052 mode = va_arg(va, SilcUInt32);
1053 client_entry2 = va_arg(va, SilcClientEntry);
1054 channel = va_arg(va, SilcChannelEntry);
1056 tmp = silc_client_chumode(mode);
1057 chanrec = silc_channel_find_entry(server, channel);
1058 if (chanrec != NULL) {
1059 SILC_NICK_REC *nick;
1061 if (client_entry2 == server->conn->local_entry)
1062 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1064 nick = silc_nicklist_find(chanrec, client_entry2);
1066 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1067 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1068 signal_emit("nick mode changed", 2, chanrec, nick);
1072 if (idtype == SILC_ID_CLIENT) {
1073 client_entry = (SilcClientEntry)entry;
1074 printformat_module("fe-common/silc", server, channel->channel_name,
1075 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1076 channel->channel_name, client_entry2->nickname,
1077 tmp ? tmp : "removed all",
1078 client_entry->nickname);
1079 } else if (idtype == SILC_ID_SERVER) {
1080 server_entry = (SilcServerEntry)entry;
1081 printformat_module("fe-common/silc", server, channel->channel_name,
1082 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1083 channel->channel_name, client_entry2->nickname,
1084 tmp ? tmp : "removed all",
1085 server_entry->server_name);
1086 } else if (idtype == SILC_ID_CHANNEL) {
1087 channel2 = (SilcChannelEntry)entry;
1088 printformat_module("fe-common/silc", server, channel->channel_name,
1089 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1090 channel->channel_name, client_entry2->nickname,
1091 tmp ? tmp : "removed all",
1092 channel2->channel_name);
1095 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1096 printformat_module("fe-common/silc",
1097 server, channel->channel_name, MSGLEVEL_CRAP,
1098 SILCTXT_CHANNEL_FOUNDER,
1099 channel->channel_name, client_entry2->nickname);
1101 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1102 printformat_module("fe-common/silc",
1103 server, channel->channel_name, MSGLEVEL_CRAP,
1104 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1109 case SILC_NOTIFY_TYPE_MOTD:
1114 SILC_LOG_DEBUG(("Notify: MOTD"));
1116 tmp = va_arg(va, char *);
1118 if (!settings_get_bool("skip_motd"))
1119 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1122 case SILC_NOTIFY_TYPE_KICKED:
1124 * Someone was kicked from channel.
1127 SILC_LOG_DEBUG(("Notify: KICKED"));
1129 client_entry = va_arg(va, SilcClientEntry);
1130 tmp = va_arg(va, char *);
1131 client_entry2 = va_arg(va, SilcClientEntry);
1132 channel = va_arg(va, SilcChannelEntry);
1134 chanrec = silc_channel_find_entry(server, channel);
1136 if (client_entry == conn->local_entry) {
1137 printformat_module("fe-common/silc", server, channel->channel_name,
1138 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1139 channel->channel_name,
1140 client_entry ? client_entry2->nickname : "",
1143 chanrec->kicked = TRUE;
1144 channel_destroy((CHANNEL_REC *)chanrec);
1147 printformat_module("fe-common/silc", server, channel->channel_name,
1148 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1149 client_entry->nickname, channel->channel_name,
1150 client_entry2 ? client_entry2->nickname : "",
1154 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1155 if (nickrec != NULL)
1156 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1161 case SILC_NOTIFY_TYPE_KILLED:
1163 * Someone was killed from the network.
1166 SILC_LOG_DEBUG(("Notify: KILLED"));
1168 client_entry = va_arg(va, SilcClientEntry);
1169 tmp = va_arg(va, char *);
1170 idtype = va_arg(va, int);
1171 entry = va_arg(va, SilcClientEntry);
1173 if (client_entry == conn->local_entry) {
1174 if (idtype == SILC_ID_CLIENT) {
1175 client_entry2 = (SilcClientEntry)entry;
1176 printformat_module("fe-common/silc", server, NULL,
1177 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1178 client_entry2 ? client_entry2->nickname : "",
1180 } else if (idtype == SILC_ID_SERVER) {
1181 server_entry = (SilcServerEntry)entry;
1182 printformat_module("fe-common/silc", server, NULL,
1183 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1184 server_entry->server_name, tmp ? tmp : "");
1185 } else if (idtype == SILC_ID_CHANNEL) {
1186 channel = (SilcChannelEntry)entry;
1187 printformat_module("fe-common/silc", server, NULL,
1188 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1189 channel->channel_name, tmp ? tmp : "");
1192 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1193 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1194 list_tmp->next->next) {
1195 CHANNEL_REC *channel = list_tmp->data;
1196 NICK_REC *nickrec = list_tmp->next->data;
1197 nicklist_remove(channel, nickrec);
1200 if (idtype == SILC_ID_CLIENT) {
1201 client_entry2 = (SilcClientEntry)entry;
1202 printformat_module("fe-common/silc", server, NULL,
1203 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1204 client_entry->nickname,
1205 client_entry2 ? client_entry2->nickname : "",
1207 } else if (idtype == SILC_ID_SERVER) {
1208 server_entry = (SilcServerEntry)entry;
1209 printformat_module("fe-common/silc", server, NULL,
1210 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1211 client_entry->nickname,
1212 server_entry->server_name, tmp ? tmp : "");
1213 } else if (idtype == SILC_ID_CHANNEL) {
1214 channel = (SilcChannelEntry)entry;
1215 printformat_module("fe-common/silc", server, NULL,
1216 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1217 client_entry->nickname,
1218 channel->channel_name, tmp ? tmp : "");
1223 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1226 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1229 * Server has quit the network.
1233 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1235 (void)va_arg(va, void *);
1236 clients = va_arg(va, SilcDList);
1238 silc_dlist_start(clients);
1239 while ((client_entry = silc_dlist_get(clients))) {
1240 memset(buf, 0, sizeof(buf));
1242 /* Print only if we have the nickname. If this client has just quit
1243 when we were only resolving it, it is possible we don't have the
1245 if (client_entry->nickname[0]) {
1246 if (client_entry->username[0])
1247 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1248 client_entry->username, client_entry->hostname);
1249 signal_emit("message quit", 4, server, client_entry->nickname,
1250 client_entry->username[0] ? buf : "",
1254 silc_server_free_ftp(server, client_entry);
1256 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1257 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1258 list_tmp->next->next) {
1259 CHANNEL_REC *channel = list_tmp->data;
1260 NICK_REC *nickrec = list_tmp->next->data;
1261 nicklist_remove(channel, nickrec);
1267 case SILC_NOTIFY_TYPE_ERROR:
1269 SilcStatus error = va_arg(va, int);
1271 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1272 "%s", silc_get_status_message(error));
1276 case SILC_NOTIFY_TYPE_WATCH:
1278 SilcNotifyType notify;
1280 client_entry = va_arg(va, SilcClientEntry);
1281 name = va_arg(va, char *); /* Maybe NULL */
1282 mode = va_arg(va, SilcUInt32);
1283 notify = va_arg(va, int);
1285 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1287 printformat_module("fe-common/silc", server, NULL,
1288 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1289 client_entry->nickname, name);
1291 printformat_module("fe-common/silc", server, NULL,
1292 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1293 client_entry->nickname);
1294 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1295 /* See if client was away and is now present */
1296 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1297 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1298 SILC_UMODE_DETACHED)) &&
1299 (client_entry->mode & SILC_UMODE_GONE ||
1300 client_entry->mode & SILC_UMODE_INDISPOSED ||
1301 client_entry->mode & SILC_UMODE_BUSY ||
1302 client_entry->mode & SILC_UMODE_PAGE ||
1303 client_entry->mode & SILC_UMODE_DETACHED)) {
1304 printformat_module("fe-common/silc", server, NULL,
1305 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1306 client_entry->nickname);
1310 memset(buf, 0, sizeof(buf));
1311 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1312 printformat_module("fe-common/silc", server, NULL,
1313 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1314 client_entry->nickname, buf);
1316 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1317 printformat_module("fe-common/silc", server, NULL,
1318 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1319 client_entry->nickname);
1320 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1321 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1322 printformat_module("fe-common/silc", server, NULL,
1323 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1324 client_entry->nickname);
1325 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1326 /* Client logged in to the network */
1327 printformat_module("fe-common/silc", server, NULL,
1328 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1329 client_entry->nickname);
1335 /* Unknown notify */
1336 printformat_module("fe-common/silc", server, NULL,
1337 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1344 /* Command handler. This function is called always in the command function.
1345 If error occurs it will be called as well. `conn' is the associated
1346 client connection. `cmd_context' is the command context that was
1347 originally sent to the command. `success' is FALSE if error occured
1348 during command. `command' is the command being processed. It must be
1349 noted that this is not reply from server. This is merely called just
1350 after application has called the command. Just to tell application
1351 that the command really was processed. */
1353 static SilcBool cmode_list_chpks = FALSE;
1355 void silc_command(SilcClient client, SilcClientConnection conn,
1356 SilcBool success, SilcCommand command, SilcStatus status,
1357 SilcUInt32 argc, unsigned char **argv)
1359 SILC_SERVER_REC *server = conn->context;
1361 SILC_LOG_DEBUG(("Start"));
1364 silc_say_error("%s", silc_get_status_message(status));
1370 case SILC_COMMAND_INVITE:
1372 printformat_module("fe-common/silc", server, NULL,
1373 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1375 (argv[1][0] == '*' ?
1376 (char *)conn->current_channel->channel_name :
1380 case SILC_COMMAND_DETACH:
1381 server->no_reconnect = TRUE;
1384 case SILC_COMMAND_CMODE:
1385 if (argc == 3 && !strcmp(argv[2], "+C"))
1386 cmode_list_chpks = TRUE;
1388 cmode_list_chpks = FALSE;
1398 SilcClientConnection conn;
1403 void silc_getkey_cb(bool success, void *context)
1405 GetkeyContext getkey = (GetkeyContext)context;
1406 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1407 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1408 ((SilcClientEntry)getkey->entry)->nickname :
1409 ((SilcServerEntry)getkey->entry)->server_name);
1410 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1411 ((SilcClientEntry)getkey->entry)->public_key :
1412 ((SilcServerEntry)getkey->entry)->public_key);
1413 SilcSILCPublicKey silc_pubkey;
1415 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1418 if (getkey->id_type == SILC_ID_CLIENT)
1419 printformat_module("fe-common/silc", NULL, NULL,
1420 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1422 silc_pubkey->identifier.realname ?
1423 silc_pubkey->identifier.realname : "",
1424 silc_pubkey->identifier.email ?
1425 silc_pubkey->identifier.email : "");
1427 printformat_module("fe-common/silc", NULL, NULL,
1428 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1431 printformat_module("fe-common/silc", NULL, NULL,
1432 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1439 /* Parse an invite or ban list */
1440 void silc_parse_inviteban_list(SilcClient client,
1441 SilcClientConnection conn,
1442 SILC_SERVER_REC *server,
1443 SilcChannelEntry channel,
1444 const char *list_type,
1445 SilcArgumentPayload list)
1448 SilcUInt32 type, len;
1449 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1450 int counter=0, resolving = FALSE;
1452 if (!silc_argument_get_arg_num(list)) {
1453 printformat_module("fe-common/silc", server,
1454 (chanrec ? chanrec->visible_name : NULL),
1455 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1456 channel->channel_name, list_type);
1460 printformat_module("fe-common/silc", server,
1461 (chanrec ? chanrec->visible_name : NULL),
1462 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1463 channel->channel_name, list_type);
1465 /* Parse the list */
1466 tmp = silc_argument_get_first_arg(list, &type, &len);
1471 /* An invite string */
1475 if (tmp[len-1] == ',')
1478 list = g_strsplit(tmp, ",", -1);
1480 printformat_module("fe-common/silc", server,
1481 (chanrec ? chanrec->visible_name : NULL),
1482 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1483 ++counter, channel->channel_name, list_type,
1492 char *fingerprint, *babbleprint;
1494 /* tmp is Public Key Payload, take public key from it. */
1495 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1496 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1498 printformat_module("fe-common/silc", server,
1499 (chanrec ? chanrec->visible_name : NULL),
1500 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1501 ++counter, channel->channel_name, list_type,
1502 fingerprint, babbleprint);
1509 SilcClientEntry client_entry;
1512 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1513 silc_say_error("Invalid data in %s list encountered", list_type);
1517 client_entry = silc_client_get_client_by_id(client, conn,
1520 printformat_module("fe-common/silc", server,
1521 (chanrec ? chanrec->visible_name : NULL),
1522 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1523 ++counter, channel->channel_name, list_type,
1524 client_entry->nickname);
1525 silc_client_unref_client(client, conn, client_entry);
1528 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1536 silc_say_error("Unkown type in %s list: %u (len %u)",
1537 list_type, type, len);
1540 tmp = silc_argument_get_next_arg(list, &type, &len);
1544 printformat_module("fe-common/silc", server,
1545 (chanrec ? chanrec->visible_name : NULL),
1546 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1547 list_type, channel->channel_name);
1550 /* Command reply handler. This function is called always in the command reply
1551 function. If error occurs it will be called as well. Normal scenario
1552 is that it will be called after the received command data has been parsed
1553 and processed. The function is used to pass the received command data to
1556 `conn' is the associated client connection. `cmd_payload' is the command
1557 payload data received from server and it can be ignored. It is provided
1558 if the application would like to re-parse the received command data,
1559 however, it must be noted that the data is parsed already by the library
1560 thus the payload can be ignored. `success' is FALSE if error occured.
1561 In this case arguments are not sent to the application. `command' is the
1562 command reply being processed. The function has variable argument list
1563 and each command defines the number and type of arguments it passes to the
1564 application (on error they are not sent). */
1566 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1567 SilcCommand command, SilcStatus status,
1568 SilcStatus error, va_list vp)
1570 SILC_SERVER_REC *server = conn->context;
1571 SILC_CHANNEL_REC *chanrec;
1573 SILC_LOG_DEBUG(("Start"));
1576 case SILC_COMMAND_WHOIS:
1578 char buf[1024], *nickname, *username, *realname, *nick;
1579 unsigned char *fingerprint;
1580 SilcUInt32 idle, mode, *user_modes;
1582 SilcClientEntry client_entry;
1585 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1586 /* Print the unknown nick for user */
1587 char *tmp = va_arg(vp, char *);
1589 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1591 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1592 /* Try to find the entry for the unknown client ID, since we
1593 might have, and print the nickname of it for user. */
1594 SilcClientID *id = va_arg(vp, SilcClientID *);
1596 client_entry = silc_client_get_client_by_id(client, conn, id);
1597 if (client_entry && client_entry->nickname[0])
1598 silc_say_error("%s: %s", client_entry->nickname,
1599 silc_get_status_message(status));
1600 silc_client_unref_client(client, conn, client_entry);
1603 } else if (SILC_STATUS_IS_ERROR(status)) {
1604 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1608 client_entry = va_arg(vp, SilcClientEntry);
1609 nickname = va_arg(vp, char *);
1610 username = va_arg(vp, char *);
1611 realname = va_arg(vp, char *);
1612 channels = va_arg(vp, SilcDList);
1613 mode = va_arg(vp, SilcUInt32);
1614 idle = va_arg(vp, SilcUInt32);
1615 fingerprint = va_arg(vp, unsigned char *);
1616 user_modes = va_arg(vp, SilcUInt32 *);
1617 attrs = va_arg(vp, SilcDList);
1619 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1620 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1621 SILCTXT_WHOIS_USERINFO, nickname,
1622 client_entry->username, client_entry->hostname,
1623 nick, client_entry->nickname);
1624 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1625 SILCTXT_WHOIS_REALNAME, realname);
1628 if (channels && user_modes) {
1629 SilcChannelPayload entry;
1632 memset(buf, 0, sizeof(buf));
1633 silc_dlist_start(channels);
1634 while ((entry = silc_dlist_get(channels))) {
1635 SilcUInt32 name_len;
1636 char *m = silc_client_chumode_char(user_modes[i++]);
1637 char *name = silc_channel_get_name(entry, &name_len);
1640 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1641 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1642 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1646 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1647 SILCTXT_WHOIS_CHANNELS, buf);
1651 memset(buf, 0, sizeof(buf));
1652 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1653 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1654 SILCTXT_WHOIS_MODES, buf);
1657 if (idle && nickname) {
1658 memset(buf, 0, sizeof(buf));
1659 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1660 idle > 60 ? (idle / 60) : idle,
1661 idle > 60 ? "minutes" : "seconds");
1663 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1664 SILCTXT_WHOIS_IDLE, buf);
1668 fingerprint = silc_fingerprint(fingerprint, 20);
1669 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1670 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1671 silc_free(fingerprint);
1675 silc_query_attributes_print(server, silc_client, conn, attrs,
1680 case SILC_COMMAND_WHOWAS:
1682 char *nickname, *username, *realname;
1684 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1685 char *tmp = va_arg(vp, char *);
1687 silc_say_error("%s: %s", tmp,
1688 silc_get_status_message(status));
1690 } else if (SILC_STATUS_IS_ERROR(status)) {
1691 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1695 (void)va_arg(vp, SilcClientEntry);
1696 nickname = va_arg(vp, char *);
1697 username = va_arg(vp, char *);
1698 realname = va_arg(vp, char *);
1700 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1701 SILCTXT_WHOWAS_USERINFO, nickname, username,
1702 realname ? realname : "");
1706 case SILC_COMMAND_INVITE:
1708 SilcChannelEntry channel;
1709 SilcArgumentPayload invite_list;
1711 if (SILC_STATUS_IS_ERROR(status))
1714 channel = va_arg(vp, SilcChannelEntry);
1715 invite_list = va_arg(vp, SilcArgumentPayload);
1718 silc_parse_inviteban_list(client, conn, server, channel,
1719 "invite", invite_list);
1723 case SILC_COMMAND_JOIN:
1725 char *channel, *mode, *topic, *cipher, *hmac;
1727 SilcHashTableList *user_list;
1728 SilcChannelEntry channel_entry;
1729 SilcChannelUser chu;
1730 SilcClientEntry founder = NULL;
1733 if (SILC_STATUS_IS_ERROR(status)) {
1734 silc_say_error("JOIN: %s", silc_get_status_message(status));
1738 channel = va_arg(vp, char *);
1739 channel_entry = va_arg(vp, SilcChannelEntry);
1740 modei = va_arg(vp, SilcUInt32);
1741 user_list = va_arg(vp, SilcHashTableList *);
1742 topic = va_arg(vp, char *);
1743 cipher = va_arg(vp, char *);
1744 hmac = va_arg(vp, char *);
1746 chanrec = silc_channel_find(server, channel);
1748 chanrec = silc_channel_create(server, channel, channel, TRUE);
1751 char tmp[256], *cp, *dm = NULL;
1752 g_free_not_null(chanrec->topic);
1754 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1755 memset(tmp, 0, sizeof(tmp));
1757 if (strlen(topic) > sizeof(tmp) - 1) {
1758 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1762 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1767 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1768 signal_emit("channel topic changed", 1, chanrec);
1773 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1774 g_free_not_null(chanrec->mode);
1775 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1776 signal_emit("channel mode changed", 1, chanrec);
1779 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1780 if (!chu->client->nickname[0])
1782 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1783 founder = chu->client;
1784 silc_nicklist_insert(chanrec, chu, FALSE);
1787 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1790 nicklist_set_own(CHANNEL(chanrec), ownnick);
1791 signal_emit("channel joined", 1, chanrec);
1792 chanrec->entry = channel_entry;
1795 printformat_module("fe-common/silc", server,
1796 channel_entry->channel_name,
1797 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1798 channel_entry->channel_name, chanrec->topic);
1801 if (founder == conn->local_entry) {
1802 printformat_module("fe-common/silc",
1803 server, channel_entry->channel_name,
1804 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1805 channel_entry->channel_name);
1806 signal_emit("nick mode changed", 2, chanrec, ownnick);
1808 printformat_module("fe-common/silc",
1809 server, channel_entry->channel_name,
1810 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1811 channel_entry->channel_name, founder->nickname);
1817 case SILC_COMMAND_NICK:
1820 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1823 if (SILC_STATUS_IS_ERROR(status)) {
1824 silc_say_error("NICK: %s", silc_get_status_message(status));
1828 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1829 if ((nicks != NULL) &&
1830 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1832 SilcClientEntry collider, old;
1834 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1835 collider = silc_client_get_client_by_id(client, conn, &old->id);
1836 if (collider != client_entry) {
1837 memset(buf, 0, sizeof(buf));
1838 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1839 collider->username, collider->hostname);
1840 nicklist_rename_unique(SERVER(server),
1842 collider, collider->nickname);
1843 silc_print_nick_change(server, collider->nickname,
1844 client_entry->nickname, buf);
1846 silc_client_unref_client(client, conn, collider);
1850 g_slist_free(nicks);
1852 old = g_strdup(server->nick);
1853 server_change_nick(SERVER(server), client_entry->nickname);
1854 nicklist_rename_unique(SERVER(server),
1855 server->conn->local_entry, server->nick,
1856 client_entry, client_entry->nickname);
1857 signal_emit("message own_nick", 4, server, server->nick, old, "");
1860 /* when connecting to a server, the last thing we receive
1861 is a SILC_COMMAND_LIST reply. Since we enable queueing
1862 during the connection, we can now safely disable it again */
1863 silc_queue_disable(conn);
1867 case SILC_COMMAND_LIST:
1872 char tmp[256], *cp, *dm = NULL;
1874 if (SILC_STATUS_IS_ERROR(status))
1877 (void)va_arg(vp, SilcChannelEntry);
1878 name = va_arg(vp, char *);
1879 topic = va_arg(vp, char *);
1880 usercount = va_arg(vp, int);
1882 if (topic && !silc_term_utf8() &&
1883 silc_utf8_valid(topic, strlen(topic))) {
1884 memset(tmp, 0, sizeof(tmp));
1886 if (strlen(topic) > sizeof(tmp) - 1) {
1887 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1891 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1896 if (status == SILC_STATUS_LIST_START ||
1897 status == SILC_STATUS_OK)
1898 printformat_module("fe-common/silc", server, NULL,
1899 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1902 snprintf(users, sizeof(users) - 1, "N/A");
1904 snprintf(users, sizeof(users) - 1, "%d", usercount);
1905 printformat_module("fe-common/silc", server, NULL,
1906 MSGLEVEL_CRAP, SILCTXT_LIST,
1907 name, users, topic ? topic : "");
1912 case SILC_COMMAND_UMODE:
1917 if (SILC_STATUS_IS_ERROR(status))
1920 mode = va_arg(vp, SilcUInt32);
1922 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1923 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1924 printformat_module("fe-common/silc", server, NULL,
1925 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1927 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1928 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1929 printformat_module("fe-common/silc", server, NULL,
1930 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1932 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1933 if (mode & SILC_UMODE_GONE) {
1934 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1935 reason = g_strdup(server->away_reason);
1937 reason = g_strdup("away");
1939 reason = g_strdup("");
1941 silc_set_away(reason, server);
1946 server->umode = mode;
1947 signal_emit("user mode changed", 2, server, NULL);
1951 case SILC_COMMAND_OPER:
1952 if (SILC_STATUS_IS_ERROR(status)) {
1953 silc_say_error("OPER: %s", silc_get_status_message(status));
1957 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1958 signal_emit("user mode changed", 2, server, NULL);
1960 printformat_module("fe-common/silc", server, NULL,
1961 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1964 case SILC_COMMAND_SILCOPER:
1965 if (SILC_STATUS_IS_ERROR(status)) {
1966 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1970 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1971 signal_emit("user mode changed", 2, server, NULL);
1973 printformat_module("fe-common/silc", server, NULL,
1974 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1977 case SILC_COMMAND_USERS:
1979 SilcHashTableList htl;
1980 SilcChannelEntry channel;
1981 SilcChannelUser chu;
1983 if (SILC_STATUS_IS_ERROR(status)) {
1984 silc_say_error("USERS: %s", silc_get_status_message(status));
1988 channel = va_arg(vp, SilcChannelEntry);
1990 printformat_module("fe-common/silc", server, channel->channel_name,
1991 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1992 channel->channel_name);
1994 silc_hash_table_list(channel->user_list, &htl);
1995 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1996 SilcClientEntry e = chu->client;
1997 char stat[5], *mode;
1999 if (!e->nickname[0])
2002 memset(stat, 0, sizeof(stat));
2003 mode = silc_client_chumode_char(chu->mode);
2004 if (e->mode & SILC_UMODE_GONE)
2006 else if (e->mode & SILC_UMODE_INDISPOSED)
2008 else if (e->mode & SILC_UMODE_BUSY)
2010 else if (e->mode & SILC_UMODE_PAGE)
2012 else if (e->mode & SILC_UMODE_HYPER)
2014 else if (e->mode & SILC_UMODE_ROBOT)
2016 else if (e->mode & SILC_UMODE_ANONYMOUS)
2023 printformat_module("fe-common/silc", server, channel->channel_name,
2024 MSGLEVEL_CRAP, SILCTXT_USERS,
2026 e->username[0] ? e->username : "",
2027 e->hostname[0] ? e->hostname : "",
2028 e->realname ? e->realname : "");
2032 silc_hash_table_list_reset(&htl);
2036 case SILC_COMMAND_BAN:
2038 SilcChannelEntry channel;
2039 SilcArgumentPayload invite_list;
2041 if (SILC_STATUS_IS_ERROR(status))
2044 channel = va_arg(vp, SilcChannelEntry);
2045 invite_list = va_arg(vp, SilcArgumentPayload);
2048 silc_parse_inviteban_list(client, conn, server, channel,
2049 "ban", invite_list);
2053 case SILC_COMMAND_GETKEY:
2057 SilcPublicKey public_key;
2058 GetkeyContext getkey;
2061 if (SILC_STATUS_IS_ERROR(status)) {
2062 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2066 id_type = va_arg(vp, SilcUInt32);
2067 entry = va_arg(vp, void *);
2068 public_key = va_arg(vp, SilcPublicKey);
2071 getkey = silc_calloc(1, sizeof(*getkey));
2072 getkey->entry = entry;
2073 getkey->id_type = id_type;
2074 getkey->client = client;
2075 getkey->conn = conn;
2077 name = (id_type == SILC_ID_CLIENT ?
2078 ((SilcClientEntry)entry)->nickname :
2079 ((SilcServerEntry)entry)->server_name);
2081 silc_verify_public_key_internal(client, conn, name,
2082 (id_type == SILC_ID_CLIENT ?
2085 public_key, silc_getkey_cb, getkey);
2087 printformat_module("fe-common/silc", server, NULL,
2088 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2093 case SILC_COMMAND_INFO:
2095 SilcServerEntry server_entry;
2099 if (SILC_STATUS_IS_ERROR(status))
2102 server_entry = va_arg(vp, SilcServerEntry);
2103 server_name = va_arg(vp, char *);
2104 server_info = va_arg(vp, char *);
2106 if (server_name && server_info )
2108 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2109 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2114 case SILC_COMMAND_TOPIC:
2116 SilcChannelEntry channel;
2118 char tmp[256], *cp, *dm = NULL;
2120 if (SILC_STATUS_IS_ERROR(status))
2123 channel = va_arg(vp, SilcChannelEntry);
2124 topic = va_arg(vp, char *);
2126 if (topic && !silc_term_utf8() &&
2127 silc_utf8_valid(topic, strlen(topic))) {
2128 memset(tmp, 0, sizeof(tmp));
2130 if (strlen(topic) > sizeof(tmp) - 1) {
2131 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2135 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2141 chanrec = silc_channel_find_entry(server, channel);
2143 g_free_not_null(chanrec->topic);
2144 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2145 signal_emit("channel topic changed", 1, chanrec);
2147 printformat_module("fe-common/silc", server, channel->channel_name,
2148 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2149 channel->channel_name, topic);
2151 printformat_module("fe-common/silc", server, channel->channel_name,
2152 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2153 channel->channel_name);
2159 case SILC_COMMAND_WATCH:
2162 case SILC_COMMAND_STATS:
2164 SilcClientStats *cstats;
2166 const char *tmptime;
2167 int days, hours, mins, secs;
2169 if (SILC_STATUS_IS_ERROR(status))
2172 cstats = va_arg(vp, SilcClientStats *);
2174 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2178 tmptime = silc_time_string(cstats->starttime);
2179 printformat_module("fe-common/silc", server, NULL,
2180 MSGLEVEL_CRAP, SILCTXT_STATS,
2181 "Local server start time", tmptime);
2183 days = cstats->uptime / (24 * 60 * 60);
2184 cstats->uptime -= days * (24 * 60 * 60);
2185 hours = cstats->uptime / (60 * 60);
2186 cstats->uptime -= hours * (60 * 60);
2187 mins = cstats->uptime / 60;
2188 cstats->uptime -= mins * 60;
2189 secs = cstats->uptime;
2190 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2191 days, hours, mins, secs);
2192 printformat_module("fe-common/silc", server, NULL,
2193 MSGLEVEL_CRAP, SILCTXT_STATS,
2194 "Local server uptime", tmp);
2196 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2197 printformat_module("fe-common/silc", server, NULL,
2198 MSGLEVEL_CRAP, SILCTXT_STATS,
2199 "Local server clients", tmp);
2201 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2202 printformat_module("fe-common/silc", server, NULL,
2203 MSGLEVEL_CRAP, SILCTXT_STATS,
2204 "Local server channels", tmp);
2206 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2207 printformat_module("fe-common/silc", server, NULL,
2208 MSGLEVEL_CRAP, SILCTXT_STATS,
2209 "Local server operators", tmp);
2211 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2212 printformat_module("fe-common/silc", server, NULL,
2213 MSGLEVEL_CRAP, SILCTXT_STATS,
2214 "Local router operators", tmp);
2216 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2217 printformat_module("fe-common/silc", server, NULL,
2218 MSGLEVEL_CRAP, SILCTXT_STATS,
2219 "Local cell clients", tmp);
2221 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2222 printformat_module("fe-common/silc", server, NULL,
2223 MSGLEVEL_CRAP, SILCTXT_STATS,
2224 "Local cell channels", tmp);
2226 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2227 printformat_module("fe-common/silc", server, NULL,
2228 MSGLEVEL_CRAP, SILCTXT_STATS,
2229 "Local cell servers", tmp);
2231 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2232 printformat_module("fe-common/silc", server, NULL,
2233 MSGLEVEL_CRAP, SILCTXT_STATS,
2234 "Total clients", tmp);
2236 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2237 printformat_module("fe-common/silc", server, NULL,
2238 MSGLEVEL_CRAP, SILCTXT_STATS,
2239 "Total channels", tmp);
2241 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2242 printformat_module("fe-common/silc", server, NULL,
2243 MSGLEVEL_CRAP, SILCTXT_STATS,
2244 "Total servers", tmp);
2246 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2247 printformat_module("fe-common/silc", server, NULL,
2248 MSGLEVEL_CRAP, SILCTXT_STATS,
2249 "Total routers", tmp);
2251 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2252 printformat_module("fe-common/silc", server, NULL,
2253 MSGLEVEL_CRAP, SILCTXT_STATS,
2254 "Total server operators", tmp);
2256 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2257 printformat_module("fe-common/silc", server, NULL,
2258 MSGLEVEL_CRAP, SILCTXT_STATS,
2259 "Total router operators", tmp);
2263 case SILC_COMMAND_CMODE:
2265 SilcChannelEntry channel_entry;
2268 channel_entry = va_arg(vp, SilcChannelEntry);
2269 (void)va_arg(vp, SilcUInt32);
2270 (void)va_arg(vp, SilcPublicKey);
2271 chpks = va_arg(vp, SilcDList);
2273 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2274 !channel_entry || !channel_entry->channel_name)
2277 /* Print the channel public key list */
2279 silc_parse_channel_public_keys(server, channel_entry, chpks);
2281 printformat_module("fe-common/silc", server, NULL,
2282 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2283 channel_entry->channel_name);
2288 case SILC_COMMAND_LEAVE:
2290 if (SILC_STATUS_IS_ERROR(status))
2293 /* We might be cycling, so disable queueing again */
2294 silc_queue_disable(conn);
2298 case SILC_COMMAND_DETACH:
2300 /* Save the detachment data to file. */
2304 if (SILC_STATUS_IS_ERROR(status))
2307 detach = va_arg(vp, SilcBuffer);
2308 file = silc_get_session_filename(server);
2309 silc_file_writefile(file, silc_buffer_data(detach),
2310 silc_buffer_len(detach));
2315 case SILC_COMMAND_KILL:
2317 SilcClientEntry client_entry;
2319 if (SILC_STATUS_IS_ERROR(status)) {
2320 silc_say_error("KILL: %s", silc_get_status_message(status));
2324 client_entry = va_arg(vp, SilcClientEntry);
2325 if (!client_entry || !client_entry->nickname[0])
2328 /* Print this only if the killed client isn't joined on channels.
2329 If it is, we receive KILLED notify and we'll print this there. */
2330 if (!silc_hash_table_count(client_entry->channels))
2331 printformat_module("fe-common/silc", server, NULL,
2332 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2333 client_entry->nickname,
2334 conn->local_entry->nickname, "");
2341 SilcClientConnection conn;
2345 SilcPublicKey public_key;
2346 SilcVerifyPublicKey completion;
2350 static void verify_public_key_completion(const char *line, void *context)
2352 PublicKeyVerify verify = (PublicKeyVerify)context;
2354 if (line[0] == 'Y' || line[0] == 'y') {
2355 /* Call the completion */
2356 if (verify->completion)
2357 verify->completion(TRUE, verify->context);
2359 /* Save the key for future checking */
2360 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2361 SILC_PKCS_FILE_BASE64);
2363 /* Call the completion */
2364 if (verify->completion)
2365 verify->completion(FALSE, verify->context);
2367 printformat_module("fe-common/silc", NULL, NULL,
2368 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2369 verify->entity_name ? verify->entity_name :
2373 silc_free(verify->filename);
2374 silc_free(verify->entity);
2375 silc_free(verify->entity_name);
2379 /* Internal routine to verify public key. If the `completion' is provided
2380 it will be called to indicate whether public was verified or not. For
2381 server/router public key this will check for filename that includes the
2382 remote host's IP address and remote host's hostname. */
2385 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2387 SilcConnectionType conn_type,
2388 SilcPublicKey public_key,
2389 SilcVerifyPublicKey completion, void *context)
2391 PublicKeyVerify verify;
2392 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2393 char *fingerprint, *babbleprint, *format;
2394 SilcPublicKey local_pubkey;
2395 SilcSILCPublicKey silc_pubkey;
2397 const char *hostname, *ip;
2402 char *entity = ((conn_type == SILC_CONN_SERVER ||
2403 conn_type == SILC_CONN_ROUTER) ?
2404 "server" : "client");
2407 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2408 printformat_module("fe-common/silc", NULL, NULL,
2409 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2410 entity, silc_pkcs_get_type(public_key));
2412 completion(FALSE, context);
2416 /* Encode public key */
2417 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2420 completion(FALSE, context);
2424 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2426 pw = getpwuid(getuid());
2429 completion(FALSE, context);
2434 memset(filename, 0, sizeof(filename));
2435 memset(filename2, 0, sizeof(filename2));
2436 memset(file, 0, sizeof(file));
2438 /* Get remote host information */
2439 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2440 NULL, &hostname, &ip, &port);
2442 if (conn_type == SILC_CONN_SERVER ||
2443 conn_type == SILC_CONN_ROUTER) {
2445 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2446 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2447 get_irssi_dir(), entity, file);
2449 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2451 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2452 get_irssi_dir(), entity, file);
2457 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2459 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2460 get_irssi_dir(), entity, file);
2465 /* Replace all whitespaces with `_'. */
2466 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2467 for (i = 0; i < strlen(fingerprint); i++)
2468 if (fingerprint[i] == ' ')
2469 fingerprint[i] = '_';
2471 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2472 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2473 get_irssi_dir(), entity, file);
2474 silc_free(fingerprint);
2479 /* Take fingerprint of the public key */
2480 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2481 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2483 verify = silc_calloc(1, sizeof(*verify));
2484 verify->client = client;
2485 verify->conn = conn;
2486 verify->filename = strdup(ipf);
2487 verify->entity = strdup(entity);
2488 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2489 (name ? strdup(name) : strdup(hostname))
2491 verify->public_key = public_key;
2492 verify->completion = completion;
2493 verify->context = context;
2495 /* Check whether this key already exists */
2496 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2497 /* Key does not exist, ask user to verify the key and save it */
2499 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2500 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2501 verify->entity_name : entity);
2502 if (conn_type == SILC_CONN_CLIENT && name &&
2503 silc_pubkey->identifier.realname)
2504 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2505 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2506 silc_pubkey->identifier.realname,
2507 silc_pubkey->identifier.email ?
2508 silc_pubkey->identifier.email : "");
2509 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2510 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2511 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2512 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2513 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2514 SILCTXT_PUBKEY_ACCEPT);
2515 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2518 silc_free(fingerprint);
2519 silc_free(babbleprint);
2523 /* The key already exists, verify it. */
2524 unsigned char *encpk;
2525 SilcUInt32 encpk_len;
2527 /* Load the key file, try for both IP filename and hostname filename */
2528 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2529 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2530 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2531 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2532 verify->entity_name : entity);
2533 if (conn_type == SILC_CONN_CLIENT && name &&
2534 silc_pubkey->identifier.realname)
2535 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2536 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2537 silc_pubkey->identifier.realname,
2538 silc_pubkey->identifier.email ?
2539 silc_pubkey->identifier.email : "");
2540 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2541 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2542 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2543 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2544 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2545 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2546 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2547 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2548 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2551 silc_free(fingerprint);
2552 silc_free(babbleprint);
2557 /* Encode the key data */
2558 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2560 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2561 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2562 verify->entity_name : entity);
2563 if (conn_type == SILC_CONN_CLIENT && name &&
2564 silc_pubkey->identifier.realname)
2565 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2566 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2567 silc_pubkey->identifier.realname,
2568 silc_pubkey->identifier.email ?
2569 silc_pubkey->identifier.email : "");
2570 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2571 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2572 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2573 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2574 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2575 SILCTXT_PUBKEY_MALFORMED, entity);
2576 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2577 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2578 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2581 silc_free(fingerprint);
2582 silc_free(babbleprint);
2586 silc_pkcs_public_key_free(local_pubkey);
2588 /* Compare the keys */
2589 if (memcmp(encpk, pk, encpk_len)) {
2590 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2591 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2592 verify->entity_name : entity);
2593 if (conn_type == SILC_CONN_CLIENT && name &&
2594 silc_pubkey->identifier.realname)
2595 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2596 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2597 silc_pubkey->identifier.realname,
2598 silc_pubkey->identifier.email ?
2599 silc_pubkey->identifier.email : "");
2600 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2601 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2602 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2603 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2604 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2605 SILCTXT_PUBKEY_NO_MATCH, entity);
2606 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2607 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2608 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2609 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2611 /* Ask user to verify the key and save it */
2612 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2613 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2614 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2617 silc_free(fingerprint);
2618 silc_free(babbleprint);
2624 /* Local copy matched */
2626 completion(TRUE, context);
2628 silc_free(fingerprint);
2629 silc_free(babbleprint);
2630 silc_free(verify->filename);
2631 silc_free(verify->entity);
2632 silc_free(verify->entity_name);
2638 /* Verifies received public key. The `conn_type' indicates which entity
2639 (server, client etc.) has sent the public key. If user decides to trust
2640 the key may be saved as trusted public key for later use. The
2641 `completion' must be called after the public key has been verified. */
2644 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2645 SilcConnectionType conn_type,
2646 SilcPublicKey public_key,
2647 SilcVerifyPublicKey completion, void *context)
2649 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2650 completion, context);
2653 /* Asks passphrase from user on the input line. */
2656 SilcAskPassphrase completion;
2660 void ask_passphrase_completion(const char *passphrase, void *context)
2662 AskPassphrase p = (AskPassphrase)context;
2663 if (passphrase && passphrase[0] == '\0')
2665 p->completion((unsigned char *)passphrase,
2666 passphrase ? strlen(passphrase) : 0, p->context);
2670 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2671 SilcAskPassphrase completion, void *context)
2673 AskPassphrase p = silc_calloc(1, sizeof(*p));
2674 p->completion = completion;
2675 p->context = context;
2677 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2678 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2682 SilcGetAuthMeth completion;
2686 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2687 SilcUInt32 passphrase_len,
2690 GetAuthMethod a = context;
2691 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2692 passphrase, passphrase_len, a->context);
2696 /* Find authentication data by hostname and port. The hostname may be IP
2699 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2700 char *hostname, SilcUInt16 port,
2701 SilcAuthMethod auth_meth,
2702 SilcGetAuthMeth completion, void *context)
2704 SERVER_SETUP_REC *setup;
2706 SILC_LOG_DEBUG(("Start"));
2708 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2709 /* Returning NULL will cause library to use our private key configured
2710 for this connection */
2711 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2715 /* Check whether we find the password for this server in our
2716 configuration. If it's set, always send it server. */
2717 setup = server_setup_find_port(hostname, port);
2718 if (setup && setup->password) {
2719 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2724 /* Didn't find password. If server wants it, ask it from user. */
2725 if (auth_meth == SILC_AUTH_PASSWORD) {
2727 a = silc_calloc(1, sizeof(*a));
2729 a->completion = completion;
2730 a->context = context;
2731 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2736 /* No authentication */
2737 completion(SILC_AUTH_NONE, NULL, 0, context);
2740 /* Asks whether the user would like to perform the key agreement protocol.
2741 This is called after we have received an key agreement packet or an
2742 reply to our key agreement packet. This returns TRUE if the user wants
2743 the library to perform the key agreement protocol and FALSE if it is not
2744 desired (application may start it later by calling the function
2745 silc_client_perform_key_agreement). */
2747 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2748 SilcClientEntry client_entry, const char *hostname,
2749 SilcUInt16 protocol, SilcUInt16 port)
2751 char portstr[12], protostr[5];
2753 SILC_LOG_DEBUG(("Start"));
2755 /* We will just display the info on the screen and return FALSE and user
2756 will have to start the key agreement with a command. */
2759 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2760 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2765 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2766 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2768 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2769 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2770 client_entry->nickname, hostname, portstr, protostr);
2773 /* Notifies application that file transfer protocol session is being
2774 requested by the remote client indicated by the `client_entry' from
2775 the `hostname' and `port'. The `session_id' is the file transfer
2776 session and it can be used to either accept or reject the file
2777 transfer request, by calling the silc_client_file_receive or
2778 silc_client_file_close, respectively. */
2780 void silc_ftp(SilcClient client, SilcClientConnection conn,
2781 SilcClientEntry client_entry, SilcUInt32 session_id,
2782 const char *hostname, SilcUInt16 port)
2784 SILC_SERVER_REC *server;
2786 FtpSession ftp = NULL;
2788 SILC_LOG_DEBUG(("Start"));
2790 server = conn->context;
2792 silc_dlist_start(server->ftp_sessions);
2793 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2794 if (ftp->client_entry == client_entry &&
2795 ftp->session_id == session_id) {
2796 server->current_session = ftp;
2800 if (ftp == SILC_LIST_END) {
2801 ftp = silc_calloc(1, sizeof(*ftp));
2802 ftp->client_entry = client_entry;
2803 ftp->session_id = session_id;
2806 silc_dlist_add(server->ftp_sessions, ftp);
2807 server->current_session = ftp;
2811 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2814 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2815 SILCTXT_FILE_REQUEST, client_entry->nickname);
2817 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2818 SILCTXT_FILE_REQUEST_HOST,
2819 client_entry->nickname, hostname, portstr);
2822 /* SILC client operations */
2823 SilcClientOperations ops = {
2825 silc_channel_message,
2826 silc_private_message,
2830 silc_get_auth_method,
2831 silc_verify_public_key,
2832 silc_ask_passphrase,