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)
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,
572 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
574 message, message_len,
575 sender->nickname ? 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 ? sender->nickname : "[<unknown>]",
597 sender->username ? userhost : NULL,
600 signal_emit("message silc private_action", 5, server, cp,
601 sender->nickname ? sender->nickname : "[<unknown>]",
602 sender->username ? userhost : NULL, NULL);
605 if (flags & SILC_MESSAGE_FLAG_SIGNED)
606 signal_emit("message silc signed_private_action", 6, server, message,
607 sender->nickname ? sender->nickname : "[<unknown>]",
608 sender->username ? userhost : NULL,
611 signal_emit("message silc private_action", 5, server, message,
612 sender->nickname ? sender->nickname : "[<unknown>]",
613 sender->username ? 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 ? sender->nickname : "[<unknown>]",
629 sender->username ? userhost : NULL,
632 signal_emit("message silc private_notice", 5, server, cp,
633 sender->nickname ? sender->nickname : "[<unknown>]",
634 sender->username ? userhost : NULL, NULL);
637 if (flags & SILC_MESSAGE_FLAG_SIGNED)
638 signal_emit("message silc signed_private_notice", 6, server, message,
639 sender->nickname ? sender->nickname : "[<unknown>]",
640 sender->username ? userhost : NULL,
643 signal_emit("message silc private_notice", 5, server, message,
644 sender->nickname ? sender->nickname : "[<unknown>]",
645 sender->username ? 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 ? sender->nickname : "[<unknown>]",
663 sender->username ? userhost : NULL, verified);
665 signal_emit("message private", 4, server, cp,
666 sender->nickname ? sender->nickname : "[<unknown>]",
667 sender->username ? userhost : NULL);
672 if (flags & SILC_MESSAGE_FLAG_SIGNED)
673 signal_emit("message signed_private", 5, server, message,
674 sender->nickname ? sender->nickname : "[<unknown>]",
675 sender->username ? userhost : NULL, verified);
677 signal_emit("message private", 4, server, message,
678 sender->nickname ? sender->nickname : "[<unknown>]",
679 sender->username ? 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;
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);
752 if (chanrec != NULL && !chanrec->joined)
753 chanrec->entry = channel;
755 chanrec = silc_channel_find_entry(server, channel);
756 if (chanrec != NULL) {
757 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
759 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
763 memset(buf, 0, sizeof(buf));
764 if (client_entry->username)
765 snprintf(buf, sizeof(buf) - 1, "%s@%s",
766 client_entry->username, client_entry->hostname);
767 signal_emit("message join", 4, server, channel->channel_name,
768 client_entry->nickname,
769 client_entry->username == NULL ? "" : buf);
772 case SILC_NOTIFY_TYPE_LEAVE:
777 SILC_LOG_DEBUG(("Notify: LEAVE"));
779 client_entry = va_arg(va, SilcClientEntry);
780 channel = va_arg(va, SilcChannelEntry);
782 memset(buf, 0, sizeof(buf));
783 if (client_entry->username)
784 snprintf(buf, sizeof(buf) - 1, "%s@%s",
785 client_entry->username, client_entry->hostname);
786 signal_emit("message part", 5, server, channel->channel_name,
787 client_entry->nickname, client_entry->username ?
788 buf : "", client_entry->nickname);
790 chanrec = silc_channel_find_entry(server, channel);
791 if (chanrec != NULL) {
792 nickrec = silc_nicklist_find(chanrec, client_entry);
794 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
798 case SILC_NOTIFY_TYPE_SIGNOFF:
803 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
805 client_entry = va_arg(va, SilcClientEntry);
806 tmp = va_arg(va, char *);
809 silc_server_free_ftp(server, client_entry);
812 /* Print only if we have the nickname. If this cliente has just quit
813 when we were only resolving it, it is possible we don't have the
815 if (client_entry->nickname) {
816 memset(buf, 0, sizeof(buf));
817 if (client_entry->username)
818 snprintf(buf, sizeof(buf) - 1, "%s@%s",
819 client_entry->username, client_entry->hostname);
820 signal_emit("message quit", 4, server, client_entry->nickname,
821 client_entry->username ? buf : "",
825 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
826 for (list_tmp = list1; list_tmp != NULL; list_tmp =
827 list_tmp->next->next) {
828 CHANNEL_REC *channel = list_tmp->data;
829 NICK_REC *nickrec = list_tmp->next->data;
831 nicklist_remove(channel, nickrec);
835 case SILC_NOTIFY_TYPE_TOPIC_SET:
840 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
842 idtype = va_arg(va, int);
843 entry = va_arg(va, void *);
844 tmp = va_arg(va, char *);
845 channel = va_arg(va, SilcChannelEntry);
847 chanrec = silc_channel_find_entry(server, channel);
848 if (chanrec != NULL) {
849 char tmp2[256], *cp, *dm = NULL;
851 g_free_not_null(chanrec->topic);
852 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
853 memset(tmp2, 0, sizeof(tmp2));
855 if (strlen(tmp) > sizeof(tmp2) - 1) {
856 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
860 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
865 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
866 signal_emit("channel topic changed", 1, chanrec);
871 if (idtype == SILC_ID_CLIENT) {
872 client_entry = (SilcClientEntry)entry;
873 memset(buf, 0, sizeof(buf));
874 snprintf(buf, sizeof(buf) - 1, "%s@%s",
875 client_entry->username, client_entry->hostname);
876 signal_emit("message topic", 5, server, channel->channel_name,
877 tmp, client_entry->nickname, buf);
878 } else if (idtype == SILC_ID_SERVER) {
879 server_entry = (SilcServerEntry)entry;
880 signal_emit("message topic", 5, server, channel->channel_name,
881 tmp, server_entry->server_name,
882 server_entry->server_name);
883 } else if (idtype == SILC_ID_CHANNEL) {
884 channel = (SilcChannelEntry)entry;
885 signal_emit("message topic", 5, server, channel->channel_name,
886 tmp, channel->channel_name, channel->channel_name);
890 case SILC_NOTIFY_TYPE_NICK_CHANGE:
895 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
897 client_entry = va_arg(va, SilcClientEntry);
898 name = va_arg(va, char *); /* old nickname */
900 if (!strcmp(client_entry->nickname, name))
903 memset(buf, 0, sizeof(buf));
904 snprintf(buf, sizeof(buf) - 1, "%s@%s",
905 client_entry->username, client_entry->hostname);
906 nicklist_rename_unique(SERVER(server),
908 client_entry, client_entry->nickname);
909 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
912 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
914 * Changed channel mode.
917 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
919 idtype = va_arg(va, int);
920 entry = va_arg(va, void *);
921 mode = va_arg(va, SilcUInt32);
922 cipher = va_arg(va, char *); /* cipher */
923 hmac = va_arg(va, char *); /* hmac */
924 (void)va_arg(va, char *); /* passphrase */
925 (void)va_arg(va, SilcPublicKey); /* founder key */
926 chpks = va_arg(va, SilcDList); /* channel public keys */
927 channel = va_arg(va, SilcChannelEntry);
929 tmp = silc_client_chmode(mode, cipher ? cipher : "",
932 chanrec = silc_channel_find_entry(server, channel);
933 if (chanrec != NULL) {
934 g_free_not_null(chanrec->mode);
935 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
936 signal_emit("channel mode changed", 1, chanrec);
939 if (idtype == SILC_ID_CLIENT) {
940 client_entry = (SilcClientEntry)entry;
941 printformat_module("fe-common/silc", server, channel->channel_name,
942 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
943 channel->channel_name, tmp ? tmp : "removed all",
944 client_entry->nickname);
945 } else if (idtype == SILC_ID_SERVER) {
946 server_entry = (SilcServerEntry)entry;
947 printformat_module("fe-common/silc", server, channel->channel_name,
948 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
949 channel->channel_name, tmp ? tmp : "removed all",
950 server_entry->server_name);
951 } else if (idtype == SILC_ID_CHANNEL) {
952 channel2 = (SilcChannelEntry)entry;
953 printformat_module("fe-common/silc", server, channel->channel_name,
954 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
955 channel->channel_name, tmp ? tmp : "removed all",
956 channel2->channel_name);
959 /* Print the channel public key list */
961 silc_parse_channel_public_keys(server, channel, chpks);
966 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
968 * Changed user's mode on channel.
971 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
973 idtype = va_arg(va, int);
974 entry = va_arg(va, void *);
975 mode = va_arg(va, SilcUInt32);
976 client_entry2 = va_arg(va, SilcClientEntry);
977 channel = va_arg(va, SilcChannelEntry);
979 tmp = silc_client_chumode(mode);
980 chanrec = silc_channel_find_entry(server, channel);
981 if (chanrec != NULL) {
984 if (client_entry2 == server->conn->local_entry)
985 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
987 nick = silc_nicklist_find(chanrec, client_entry2);
989 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
990 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
991 signal_emit("nick mode changed", 2, chanrec, nick);
995 if (idtype == SILC_ID_CLIENT) {
996 client_entry = (SilcClientEntry)entry;
997 printformat_module("fe-common/silc", server, channel->channel_name,
998 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
999 channel->channel_name, client_entry2->nickname,
1000 tmp ? tmp : "removed all",
1001 client_entry->nickname);
1002 } else if (idtype == SILC_ID_SERVER) {
1003 server_entry = (SilcServerEntry)entry;
1004 printformat_module("fe-common/silc", server, channel->channel_name,
1005 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1006 channel->channel_name, client_entry2->nickname,
1007 tmp ? tmp : "removed all",
1008 server_entry->server_name);
1009 } else if (idtype == SILC_ID_CHANNEL) {
1010 channel2 = (SilcChannelEntry)entry;
1011 printformat_module("fe-common/silc", server, channel->channel_name,
1012 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1013 channel->channel_name, client_entry2->nickname,
1014 tmp ? tmp : "removed all",
1015 channel2->channel_name);
1018 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1019 printformat_module("fe-common/silc",
1020 server, channel->channel_name, MSGLEVEL_CRAP,
1021 SILCTXT_CHANNEL_FOUNDER,
1022 channel->channel_name, client_entry2->nickname);
1024 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1025 printformat_module("fe-common/silc",
1026 server, channel->channel_name, MSGLEVEL_CRAP,
1027 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1032 case SILC_NOTIFY_TYPE_MOTD:
1037 SILC_LOG_DEBUG(("Notify: MOTD"));
1039 tmp = va_arg(va, char *);
1041 if (!settings_get_bool("skip_motd"))
1042 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1045 case SILC_NOTIFY_TYPE_KICKED:
1047 * Someone was kicked from channel.
1050 SILC_LOG_DEBUG(("Notify: KICKED"));
1052 client_entry = va_arg(va, SilcClientEntry);
1053 tmp = va_arg(va, char *);
1054 client_entry2 = va_arg(va, SilcClientEntry);
1055 channel = va_arg(va, SilcChannelEntry);
1057 chanrec = silc_channel_find_entry(server, channel);
1059 if (client_entry == conn->local_entry) {
1060 printformat_module("fe-common/silc", server, channel->channel_name,
1061 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1062 channel->channel_name,
1063 client_entry ? client_entry2->nickname : "",
1066 chanrec->kicked = TRUE;
1067 channel_destroy((CHANNEL_REC *)chanrec);
1070 printformat_module("fe-common/silc", server, channel->channel_name,
1071 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1072 client_entry->nickname, channel->channel_name,
1073 client_entry2 ? client_entry2->nickname : "",
1077 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1078 if (nickrec != NULL)
1079 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1084 case SILC_NOTIFY_TYPE_KILLED:
1086 * Someone was killed from the network.
1089 SILC_LOG_DEBUG(("Notify: KILLED"));
1091 client_entry = va_arg(va, SilcClientEntry);
1092 tmp = va_arg(va, char *);
1093 idtype = va_arg(va, int);
1094 entry = va_arg(va, SilcClientEntry);
1096 if (client_entry == conn->local_entry) {
1097 if (idtype == SILC_ID_CLIENT) {
1098 client_entry2 = (SilcClientEntry)entry;
1099 printformat_module("fe-common/silc", server, NULL,
1100 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1101 client_entry2 ? client_entry2->nickname : "",
1103 } else if (idtype == SILC_ID_SERVER) {
1104 server_entry = (SilcServerEntry)entry;
1105 printformat_module("fe-common/silc", server, NULL,
1106 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1107 server_entry->server_name, tmp ? tmp : "");
1108 } else if (idtype == SILC_ID_CHANNEL) {
1109 channel = (SilcChannelEntry)entry;
1110 printformat_module("fe-common/silc", server, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1112 channel->channel_name, tmp ? tmp : "");
1115 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1116 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1117 list_tmp->next->next) {
1118 CHANNEL_REC *channel = list_tmp->data;
1119 NICK_REC *nickrec = list_tmp->next->data;
1120 nicklist_remove(channel, nickrec);
1123 if (idtype == SILC_ID_CLIENT) {
1124 client_entry2 = (SilcClientEntry)entry;
1125 printformat_module("fe-common/silc", server, NULL,
1126 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1127 client_entry->nickname,
1128 client_entry2 ? client_entry2->nickname : "",
1130 } else if (idtype == SILC_ID_SERVER) {
1131 server_entry = (SilcServerEntry)entry;
1132 printformat_module("fe-common/silc", server, NULL,
1133 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1134 client_entry->nickname,
1135 server_entry->server_name, tmp ? tmp : "");
1136 } else if (idtype == SILC_ID_CHANNEL) {
1137 channel = (SilcChannelEntry)entry;
1138 printformat_module("fe-common/silc", server, NULL,
1139 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1140 client_entry->nickname,
1141 channel->channel_name, tmp ? tmp : "");
1146 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1149 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1152 * Server has quit the network.
1156 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1158 (void)va_arg(va, void *);
1159 clients = va_arg(va, SilcDList);
1161 silc_dlist_start(clients);
1162 while ((client_entry = silc_dlist_get(clients))) {
1163 memset(buf, 0, sizeof(buf));
1165 /* Print only if we have the nickname. If this client has just quit
1166 when we were only resolving it, it is possible we don't have the
1168 if (client_entry->nickname[0]) {
1169 if (client_entry->username[0])
1170 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1171 client_entry->username, client_entry->hostname);
1172 signal_emit("message quit", 4, server, client_entry->nickname,
1173 client_entry->username[0] ? buf : "",
1178 silc_server_free_ftp(server, client_entry);
1181 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1182 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1183 list_tmp->next->next) {
1184 CHANNEL_REC *channel = list_tmp->data;
1185 NICK_REC *nickrec = list_tmp->next->data;
1186 nicklist_remove(channel, nickrec);
1192 case SILC_NOTIFY_TYPE_ERROR:
1194 SilcStatus error = va_arg(va, int);
1196 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1197 "%s", silc_get_status_message(error));
1201 case SILC_NOTIFY_TYPE_WATCH:
1203 SilcNotifyType notify;
1205 client_entry = va_arg(va, SilcClientEntry);
1206 name = va_arg(va, char *); /* Maybe NULL */
1207 mode = va_arg(va, SilcUInt32);
1208 notify = va_arg(va, int);
1210 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1212 printformat_module("fe-common/silc", server, NULL,
1213 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1214 client_entry->nickname, name);
1216 printformat_module("fe-common/silc", server, NULL,
1217 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1218 client_entry->nickname);
1219 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1220 /* See if client was away and is now present */
1221 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1222 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1223 SILC_UMODE_DETACHED)) &&
1224 (client_entry->mode & SILC_UMODE_GONE ||
1225 client_entry->mode & SILC_UMODE_INDISPOSED ||
1226 client_entry->mode & SILC_UMODE_BUSY ||
1227 client_entry->mode & SILC_UMODE_PAGE ||
1228 client_entry->mode & SILC_UMODE_DETACHED)) {
1229 printformat_module("fe-common/silc", server, NULL,
1230 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1231 client_entry->nickname);
1235 memset(buf, 0, sizeof(buf));
1236 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1237 printformat_module("fe-common/silc", server, NULL,
1238 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1239 client_entry->nickname, buf);
1241 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1242 printformat_module("fe-common/silc", server, NULL,
1243 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1244 client_entry->nickname);
1245 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1246 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1247 printformat_module("fe-common/silc", server, NULL,
1248 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1249 client_entry->nickname);
1250 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1251 /* Client logged in to the network */
1252 printformat_module("fe-common/silc", server, NULL,
1253 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1254 client_entry->nickname);
1260 /* Unknown notify */
1261 printformat_module("fe-common/silc", server, NULL,
1262 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1269 /* Command handler. This function is called always in the command function.
1270 If error occurs it will be called as well. `conn' is the associated
1271 client connection. `cmd_context' is the command context that was
1272 originally sent to the command. `success' is FALSE if error occured
1273 during command. `command' is the command being processed. It must be
1274 noted that this is not reply from server. This is merely called just
1275 after application has called the command. Just to tell application
1276 that the command really was processed. */
1278 static SilcBool cmode_list_chpks = FALSE;
1280 void silc_command(SilcClient client, SilcClientConnection conn,
1281 SilcBool success, SilcCommand command, SilcStatus status,
1282 SilcUInt32 argc, unsigned char **argv)
1284 SILC_SERVER_REC *server = conn->context;
1286 SILC_LOG_DEBUG(("Start"));
1289 silc_say_error("%s", silc_get_status_message(status));
1295 case SILC_COMMAND_INVITE:
1297 printformat_module("fe-common/silc", server, NULL,
1298 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1300 (argv[1][0] == '*' ?
1301 (char *)conn->current_channel->channel_name :
1305 case SILC_COMMAND_DETACH:
1306 server->no_reconnect = TRUE;
1309 case SILC_COMMAND_CMODE:
1310 if (argc == 3 && !strcmp(argv[2], "+C"))
1311 cmode_list_chpks = TRUE;
1313 cmode_list_chpks = FALSE;
1323 SilcClientConnection conn;
1328 void silc_getkey_cb(bool success, void *context)
1330 GetkeyContext getkey = (GetkeyContext)context;
1331 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1332 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1333 ((SilcClientEntry)getkey->entry)->nickname :
1334 ((SilcServerEntry)getkey->entry)->server_name);
1337 printformat_module("fe-common/silc", NULL, NULL,
1338 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1340 printformat_module("fe-common/silc", NULL, NULL,
1341 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1348 /* Parse an invite or ban list */
1349 void silc_parse_inviteban_list(SilcClient client,
1350 SilcClientConnection conn,
1351 SILC_SERVER_REC *server,
1352 SilcChannelEntry channel,
1353 const char *list_type,
1354 SilcArgumentPayload list)
1357 SilcUInt32 type, len;
1358 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1359 int counter=0, resolving = FALSE;
1361 if (!silc_argument_get_arg_num(list)) {
1362 printformat_module("fe-common/silc", server,
1363 (chanrec ? chanrec->visible_name : NULL),
1364 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1365 channel->channel_name, list_type);
1369 printformat_module("fe-common/silc", server,
1370 (chanrec ? chanrec->visible_name : NULL),
1371 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1372 channel->channel_name, list_type);
1374 /* Parse the list */
1375 tmp = silc_argument_get_first_arg(list, &type, &len);
1380 /* An invite string */
1384 if (tmp[len-1] == ',')
1387 list = g_strsplit(tmp, ",", -1);
1389 printformat_module("fe-common/silc", server,
1390 (chanrec ? chanrec->visible_name : NULL),
1391 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1392 ++counter, channel->channel_name, list_type,
1401 char *fingerprint, *babbleprint;
1403 /* tmp is Public Key Payload, take public key from it. */
1404 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1405 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1407 printformat_module("fe-common/silc", server,
1408 (chanrec ? chanrec->visible_name : NULL),
1409 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1410 ++counter, channel->channel_name, list_type,
1411 fingerprint, babbleprint);
1418 SilcClientEntry client_entry;
1421 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1422 silc_say_error("Invalid data in %s list encountered", list_type);
1426 client_entry = silc_client_get_client_by_id(client, conn,
1429 printformat_module("fe-common/silc", server,
1430 (chanrec ? chanrec->visible_name : NULL),
1431 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1432 ++counter, channel->channel_name, list_type,
1433 client_entry->nickname);
1434 silc_client_unref_client(client, conn, client_entry);
1437 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1445 silc_say_error("Unkown type in %s list: %u (len %u)",
1446 list_type, type, len);
1449 tmp = silc_argument_get_next_arg(list, &type, &len);
1453 printformat_module("fe-common/silc", server,
1454 (chanrec ? chanrec->visible_name : NULL),
1455 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1456 list_type, channel->channel_name);
1459 /* Command reply handler. This function is called always in the command reply
1460 function. If error occurs it will be called as well. Normal scenario
1461 is that it will be called after the received command data has been parsed
1462 and processed. The function is used to pass the received command data to
1465 `conn' is the associated client connection. `cmd_payload' is the command
1466 payload data received from server and it can be ignored. It is provided
1467 if the application would like to re-parse the received command data,
1468 however, it must be noted that the data is parsed already by the library
1469 thus the payload can be ignored. `success' is FALSE if error occured.
1470 In this case arguments are not sent to the application. `command' is the
1471 command reply being processed. The function has variable argument list
1472 and each command defines the number and type of arguments it passes to the
1473 application (on error they are not sent). */
1475 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1476 SilcCommand command, SilcStatus status,
1477 SilcStatus error, va_list vp)
1479 SILC_SERVER_REC *server = conn->context;
1480 SILC_CHANNEL_REC *chanrec;
1482 SILC_LOG_DEBUG(("Start"));
1485 case SILC_COMMAND_WHOIS:
1487 char buf[1024], *nickname, *username, *realname, nick[128 + 1];
1488 unsigned char *fingerprint;
1489 SilcUInt32 idle, mode, *user_modes;
1491 SilcClientEntry client_entry;
1494 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1495 /* Print the unknown nick for user */
1496 char *tmp = va_arg(vp, char *);
1498 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1500 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1501 /* Try to find the entry for the unknown client ID, since we
1502 might have, and print the nickname of it for user. */
1503 SilcClientID *id = va_arg(vp, SilcClientID *);
1505 client_entry = silc_client_get_client_by_id(client, conn, id);
1506 if (client_entry && client_entry->nickname[0])
1507 silc_say_error("%s: %s", client_entry->nickname,
1508 silc_get_status_message(status));
1509 silc_client_unref_client(client, conn, client_entry);
1512 } else if (SILC_STATUS_IS_ERROR(status)) {
1513 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1517 client_entry = va_arg(vp, SilcClientEntry);
1518 nickname = va_arg(vp, char *);
1519 username = va_arg(vp, char *);
1520 realname = va_arg(vp, char *);
1521 channels = va_arg(vp, SilcDList);
1522 mode = va_arg(vp, SilcUInt32);
1523 idle = va_arg(vp, SilcUInt32);
1524 fingerprint = va_arg(vp, unsigned char *);
1525 user_modes = va_arg(vp, SilcUInt32 *);
1526 attrs = va_arg(vp, SilcDList);
1528 silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
1529 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1530 SILCTXT_WHOIS_USERINFO, nickname,
1531 client_entry->username, client_entry->hostname,
1532 nick, client_entry->nickname);
1533 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1534 SILCTXT_WHOIS_REALNAME, realname);
1536 if (channels && user_modes) {
1537 SilcChannelPayload entry;
1540 memset(buf, 0, sizeof(buf));
1541 silc_dlist_start(channels);
1542 while ((entry = silc_dlist_get(channels))) {
1543 SilcUInt32 name_len;
1544 char *m = silc_client_chumode_char(user_modes[i++]);
1545 char *name = silc_channel_get_name(entry, &name_len);
1548 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1549 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1550 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1554 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1555 SILCTXT_WHOIS_CHANNELS, buf);
1559 memset(buf, 0, sizeof(buf));
1560 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1561 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1562 SILCTXT_WHOIS_MODES, buf);
1565 if (idle && nickname) {
1566 memset(buf, 0, sizeof(buf));
1567 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1568 idle > 60 ? (idle / 60) : idle,
1569 idle > 60 ? "minutes" : "seconds");
1571 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1572 SILCTXT_WHOIS_IDLE, buf);
1576 fingerprint = silc_fingerprint(fingerprint, 20);
1577 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1578 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1579 silc_free(fingerprint);
1583 silc_query_attributes_print(server, silc_client, conn, attrs,
1588 case SILC_COMMAND_WHOWAS:
1590 char *nickname, *username, *realname;
1592 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1593 char *tmp = va_arg(vp, char *);
1595 silc_say_error("%s: %s", tmp,
1596 silc_get_status_message(status));
1598 } else if (SILC_STATUS_IS_ERROR(status)) {
1599 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1603 (void)va_arg(vp, SilcClientEntry);
1604 nickname = va_arg(vp, char *);
1605 username = va_arg(vp, char *);
1606 realname = va_arg(vp, char *);
1608 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1609 SILCTXT_WHOWAS_USERINFO, nickname, username,
1610 realname ? realname : "");
1614 case SILC_COMMAND_INVITE:
1616 SilcChannelEntry channel;
1617 SilcArgumentPayload invite_list;
1619 if (SILC_STATUS_IS_ERROR(status))
1622 channel = va_arg(vp, SilcChannelEntry);
1623 invite_list = va_arg(vp, SilcArgumentPayload);
1626 silc_parse_inviteban_list(client, conn, server, channel,
1627 "invite", invite_list);
1631 case SILC_COMMAND_JOIN:
1633 char *channel, *mode, *topic, *cipher, *hmac;
1635 SilcHashTableList *user_list;
1636 SilcChannelEntry channel_entry;
1637 SilcChannelUser chu;
1638 SilcClientEntry founder = NULL;
1641 if (SILC_STATUS_IS_ERROR(status)) {
1642 silc_say_error("JOIN: %s", silc_get_status_message(status));
1646 channel = va_arg(vp, char *);
1647 channel_entry = va_arg(vp, SilcChannelEntry);
1648 modei = va_arg(vp, SilcUInt32);
1649 user_list = va_arg(vp, SilcHashTableList *);
1650 topic = va_arg(vp, char *);
1651 cipher = va_arg(vp, char *);
1652 hmac = va_arg(vp, char *);
1654 chanrec = silc_channel_find(server, channel);
1656 chanrec = silc_channel_create(server, channel, channel, TRUE);
1659 char tmp[256], *cp, *dm = NULL;
1660 g_free_not_null(chanrec->topic);
1662 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1663 memset(tmp, 0, sizeof(tmp));
1665 if (strlen(topic) > sizeof(tmp) - 1) {
1666 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1670 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1675 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1676 signal_emit("channel topic changed", 1, chanrec);
1681 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1682 g_free_not_null(chanrec->mode);
1683 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1684 signal_emit("channel mode changed", 1, chanrec);
1687 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1688 if (!chu->client->nickname)
1690 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1691 founder = chu->client;
1692 silc_nicklist_insert(chanrec, chu, FALSE);
1695 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1698 nicklist_set_own(CHANNEL(chanrec), ownnick);
1699 signal_emit("channel joined", 1, chanrec);
1700 chanrec->entry = channel_entry;
1703 printformat_module("fe-common/silc", server,
1704 channel_entry->channel_name,
1705 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1706 channel_entry->channel_name, chanrec->topic);
1709 if (founder == conn->local_entry) {
1710 printformat_module("fe-common/silc",
1711 server, channel_entry->channel_name,
1712 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1713 channel_entry->channel_name);
1714 signal_emit("nick mode changed", 2, chanrec, ownnick);
1716 printformat_module("fe-common/silc",
1717 server, channel_entry->channel_name,
1718 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1719 channel_entry->channel_name, founder->nickname);
1725 case SILC_COMMAND_NICK:
1728 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1731 if (SILC_STATUS_IS_ERROR(status)) {
1732 silc_say_error("NICK: %s", silc_get_status_message(status));
1736 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1737 if ((nicks != NULL) &&
1738 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1740 SilcClientEntry collider, old;
1742 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1743 collider = silc_client_get_client_by_id(client, conn, &old->id);
1744 if (collider != client_entry) {
1745 memset(buf, 0, sizeof(buf));
1746 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1747 collider->username, collider->hostname);
1748 nicklist_rename_unique(SERVER(server),
1750 collider, collider->nickname);
1751 silc_print_nick_change(server, collider->nickname,
1752 client_entry->nickname, buf);
1754 silc_client_unref_client(client, conn, collider);
1758 g_slist_free(nicks);
1760 old = g_strdup(server->nick);
1761 server_change_nick(SERVER(server), client_entry->nickname);
1762 nicklist_rename_unique(SERVER(server),
1763 server->conn->local_entry, server->nick,
1764 client_entry, client_entry->nickname);
1765 signal_emit("message own_nick", 4, server, server->nick, old, "");
1768 /* when connecting to a server, the last thing we receive
1769 is a SILC_COMMAND_LIST reply. Since we enable queueing
1770 during the connection, we can now safely disable it again */
1771 silc_queue_disable(conn);
1775 case SILC_COMMAND_LIST:
1780 char tmp[256], *cp, *dm = NULL;
1782 if (SILC_STATUS_IS_ERROR(status))
1785 (void)va_arg(vp, SilcChannelEntry);
1786 name = va_arg(vp, char *);
1787 topic = va_arg(vp, char *);
1788 usercount = va_arg(vp, int);
1790 if (topic && !silc_term_utf8() &&
1791 silc_utf8_valid(topic, strlen(topic))) {
1792 memset(tmp, 0, sizeof(tmp));
1794 if (strlen(topic) > sizeof(tmp) - 1) {
1795 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1799 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1804 if (status == SILC_STATUS_LIST_START ||
1805 status == SILC_STATUS_OK)
1806 printformat_module("fe-common/silc", server, NULL,
1807 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1810 snprintf(users, sizeof(users) - 1, "N/A");
1812 snprintf(users, sizeof(users) - 1, "%d", usercount);
1813 printformat_module("fe-common/silc", server, NULL,
1814 MSGLEVEL_CRAP, SILCTXT_LIST,
1815 name, users, topic ? topic : "");
1820 case SILC_COMMAND_UMODE:
1825 if (SILC_STATUS_IS_ERROR(status))
1828 mode = va_arg(vp, SilcUInt32);
1830 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1831 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1832 printformat_module("fe-common/silc", server, NULL,
1833 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1835 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1836 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1837 printformat_module("fe-common/silc", server, NULL,
1838 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1840 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1841 if (mode & SILC_UMODE_GONE) {
1842 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1843 reason = g_strdup(server->away_reason);
1845 reason = g_strdup("away");
1847 reason = g_strdup("");
1849 silc_set_away(reason, server);
1854 server->umode = mode;
1855 signal_emit("user mode changed", 2, server, NULL);
1859 case SILC_COMMAND_OPER:
1860 if (SILC_STATUS_IS_ERROR(status)) {
1861 silc_say_error("OPER: %s", silc_get_status_message(status));
1865 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1866 signal_emit("user mode changed", 2, server, NULL);
1868 printformat_module("fe-common/silc", server, NULL,
1869 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1872 case SILC_COMMAND_SILCOPER:
1873 if (SILC_STATUS_IS_ERROR(status)) {
1874 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
1878 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1879 signal_emit("user mode changed", 2, server, NULL);
1881 printformat_module("fe-common/silc", server, NULL,
1882 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1885 case SILC_COMMAND_USERS:
1887 SilcHashTableList htl;
1888 SilcChannelEntry channel;
1889 SilcChannelUser chu;
1891 if (SILC_STATUS_IS_ERROR(status)) {
1892 silc_say_error("USERS: %s", silc_get_status_message(status));
1896 channel = va_arg(vp, SilcChannelEntry);
1898 printformat_module("fe-common/silc", server, channel->channel_name,
1899 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1900 channel->channel_name);
1902 silc_hash_table_list(channel->user_list, &htl);
1903 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1904 SilcClientEntry e = chu->client;
1905 char stat[5], *mode;
1910 memset(stat, 0, sizeof(stat));
1911 mode = silc_client_chumode_char(chu->mode);
1912 if (e->mode & SILC_UMODE_GONE)
1914 else if (e->mode & SILC_UMODE_INDISPOSED)
1916 else if (e->mode & SILC_UMODE_BUSY)
1918 else if (e->mode & SILC_UMODE_PAGE)
1920 else if (e->mode & SILC_UMODE_HYPER)
1922 else if (e->mode & SILC_UMODE_ROBOT)
1924 else if (e->mode & SILC_UMODE_ANONYMOUS)
1931 printformat_module("fe-common/silc", server, channel->channel_name,
1932 MSGLEVEL_CRAP, SILCTXT_USERS,
1934 e->username ? e->username : "",
1935 e->hostname ? e->hostname : "",
1936 e->realname ? e->realname : "");
1940 silc_hash_table_list_reset(&htl);
1944 case SILC_COMMAND_BAN:
1946 SilcChannelEntry channel;
1947 SilcArgumentPayload invite_list;
1949 if (SILC_STATUS_IS_ERROR(status))
1952 channel = va_arg(vp, SilcChannelEntry);
1953 invite_list = va_arg(vp, SilcArgumentPayload);
1956 silc_parse_inviteban_list(client, conn, server, channel,
1957 "ban", invite_list);
1961 case SILC_COMMAND_GETKEY:
1965 SilcPublicKey public_key;
1966 GetkeyContext getkey;
1969 if (SILC_STATUS_IS_ERROR(status)) {
1970 silc_say_error("GETKEY: %s", silc_get_status_message(status));
1974 id_type = va_arg(vp, SilcUInt32);
1975 entry = va_arg(vp, void *);
1976 public_key = va_arg(vp, SilcPublicKey);
1979 getkey = silc_calloc(1, sizeof(*getkey));
1980 getkey->entry = entry;
1981 getkey->id_type = id_type;
1982 getkey->client = client;
1983 getkey->conn = conn;
1985 name = (id_type == SILC_ID_CLIENT ?
1986 ((SilcClientEntry)entry)->nickname :
1987 ((SilcServerEntry)entry)->server_name);
1989 silc_verify_public_key_internal(client, conn, name,
1990 (id_type == SILC_ID_CLIENT ?
1993 public_key, silc_getkey_cb, getkey);
1995 printformat_module("fe-common/silc", server, NULL,
1996 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2001 case SILC_COMMAND_INFO:
2003 SilcServerEntry server_entry;
2007 if (SILC_STATUS_IS_ERROR(status))
2010 server_entry = va_arg(vp, SilcServerEntry);
2011 server_name = va_arg(vp, char *);
2012 server_info = va_arg(vp, char *);
2014 if (server_name && server_info )
2016 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2017 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2022 case SILC_COMMAND_TOPIC:
2024 SilcChannelEntry channel;
2026 char tmp[256], *cp, *dm = NULL;
2028 if (SILC_STATUS_IS_ERROR(status))
2031 channel = va_arg(vp, SilcChannelEntry);
2032 topic = va_arg(vp, char *);
2034 if (topic && !silc_term_utf8() &&
2035 silc_utf8_valid(topic, strlen(topic))) {
2036 memset(tmp, 0, sizeof(tmp));
2038 if (strlen(topic) > sizeof(tmp) - 1) {
2039 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2043 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2049 chanrec = silc_channel_find_entry(server, channel);
2051 g_free_not_null(chanrec->topic);
2052 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2053 signal_emit("channel topic changed", 1, chanrec);
2055 printformat_module("fe-common/silc", server, channel->channel_name,
2056 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2057 channel->channel_name, topic);
2059 printformat_module("fe-common/silc", server, channel->channel_name,
2060 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2061 channel->channel_name);
2067 case SILC_COMMAND_WATCH:
2070 case SILC_COMMAND_STATS:
2072 SilcClientStats *cstats;
2074 const char *tmptime;
2075 int days, hours, mins, secs;
2077 if (SILC_STATUS_IS_ERROR(status))
2080 cstats = va_arg(vp, SilcClientStats *);
2082 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2086 tmptime = silc_time_string(cstats->starttime);
2087 printformat_module("fe-common/silc", server, NULL,
2088 MSGLEVEL_CRAP, SILCTXT_STATS,
2089 "Local server start time", tmptime);
2091 days = cstats->uptime / (24 * 60 * 60);
2092 cstats->uptime -= days * (24 * 60 * 60);
2093 hours = cstats->uptime / (60 * 60);
2094 cstats->uptime -= hours * (60 * 60);
2095 mins = cstats->uptime / 60;
2096 cstats->uptime -= mins * 60;
2097 secs = cstats->uptime;
2098 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2099 days, hours, mins, secs);
2100 printformat_module("fe-common/silc", server, NULL,
2101 MSGLEVEL_CRAP, SILCTXT_STATS,
2102 "Local server uptime", tmp);
2104 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2105 printformat_module("fe-common/silc", server, NULL,
2106 MSGLEVEL_CRAP, SILCTXT_STATS,
2107 "Local server clients", tmp);
2109 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2110 printformat_module("fe-common/silc", server, NULL,
2111 MSGLEVEL_CRAP, SILCTXT_STATS,
2112 "Local server channels", tmp);
2114 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2115 printformat_module("fe-common/silc", server, NULL,
2116 MSGLEVEL_CRAP, SILCTXT_STATS,
2117 "Local server operators", tmp);
2119 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2120 printformat_module("fe-common/silc", server, NULL,
2121 MSGLEVEL_CRAP, SILCTXT_STATS,
2122 "Local router operators", tmp);
2124 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2125 printformat_module("fe-common/silc", server, NULL,
2126 MSGLEVEL_CRAP, SILCTXT_STATS,
2127 "Local cell clients", tmp);
2129 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2130 printformat_module("fe-common/silc", server, NULL,
2131 MSGLEVEL_CRAP, SILCTXT_STATS,
2132 "Local cell channels", tmp);
2134 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2135 printformat_module("fe-common/silc", server, NULL,
2136 MSGLEVEL_CRAP, SILCTXT_STATS,
2137 "Local cell servers", tmp);
2139 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2140 printformat_module("fe-common/silc", server, NULL,
2141 MSGLEVEL_CRAP, SILCTXT_STATS,
2142 "Total clients", tmp);
2144 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2145 printformat_module("fe-common/silc", server, NULL,
2146 MSGLEVEL_CRAP, SILCTXT_STATS,
2147 "Total channels", tmp);
2149 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2150 printformat_module("fe-common/silc", server, NULL,
2151 MSGLEVEL_CRAP, SILCTXT_STATS,
2152 "Total servers", tmp);
2154 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2155 printformat_module("fe-common/silc", server, NULL,
2156 MSGLEVEL_CRAP, SILCTXT_STATS,
2157 "Total routers", tmp);
2159 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2160 printformat_module("fe-common/silc", server, NULL,
2161 MSGLEVEL_CRAP, SILCTXT_STATS,
2162 "Total server operators", tmp);
2164 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2165 printformat_module("fe-common/silc", server, NULL,
2166 MSGLEVEL_CRAP, SILCTXT_STATS,
2167 "Total router operators", tmp);
2171 case SILC_COMMAND_CMODE:
2173 SilcChannelEntry channel_entry;
2176 channel_entry = va_arg(vp, SilcChannelEntry);
2177 (void)va_arg(vp, SilcUInt32);
2178 (void)va_arg(vp, SilcPublicKey);
2179 chpks = va_arg(vp, SilcDList);
2181 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2182 !channel_entry || !channel_entry->channel_name)
2185 /* Print the channel public key list */
2187 silc_parse_channel_public_keys(server, channel_entry, chpks);
2189 printformat_module("fe-common/silc", server, NULL,
2190 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2191 channel_entry->channel_name);
2196 case SILC_COMMAND_LEAVE:
2198 if (SILC_STATUS_IS_ERROR(status))
2201 /* We might be cycling, so disable queueing again */
2202 silc_queue_disable(conn);
2206 case SILC_COMMAND_DETACH:
2208 /* Save the detachment data to file. */
2212 if (SILC_STATUS_IS_ERROR(status))
2215 detach = va_arg(vp, SilcBuffer);
2216 file = silc_get_session_filename(server);
2217 silc_file_writefile(file, silc_buffer_data(detach),
2218 silc_buffer_len(detach));
2223 case SILC_COMMAND_KILL:
2225 SilcClientEntry client_entry;
2227 if (SILC_STATUS_IS_ERROR(status)) {
2228 silc_say_error("KILL: %s", silc_get_status_message(status));
2232 client_entry = va_arg(vp, SilcClientEntry);
2233 if (!client_entry || !client_entry->nickname[0])
2236 /* Print this only if the killed client isn't joined on channels.
2237 If it is, we receive KILLED notify and we'll print this there. */
2238 if (!silc_hash_table_count(client_entry->channels))
2239 printformat_module("fe-common/silc", server, NULL,
2240 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2241 client_entry->nickname,
2242 conn->local_entry->nickname, "");
2249 SilcClientConnection conn;
2253 SilcPublicKey public_key;
2254 SilcVerifyPublicKey completion;
2258 static void verify_public_key_completion(const char *line, void *context)
2260 PublicKeyVerify verify = (PublicKeyVerify)context;
2262 if (line[0] == 'Y' || line[0] == 'y') {
2263 /* Call the completion */
2264 if (verify->completion)
2265 verify->completion(TRUE, verify->context);
2267 /* Save the key for future checking */
2268 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2269 SILC_PKCS_FILE_BASE64);
2271 /* Call the completion */
2272 if (verify->completion)
2273 verify->completion(FALSE, verify->context);
2275 printformat_module("fe-common/silc", NULL, NULL,
2276 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2277 verify->entity_name ? verify->entity_name :
2281 silc_free(verify->filename);
2282 silc_free(verify->entity);
2283 silc_free(verify->entity_name);
2287 /* Internal routine to verify public key. If the `completion' is provided
2288 it will be called to indicate whether public was verified or not. For
2289 server/router public key this will check for filename that includes the
2290 remote host's IP address and remote host's hostname. */
2293 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2295 SilcConnectionType conn_type,
2296 SilcPublicKey public_key,
2297 SilcVerifyPublicKey completion, void *context)
2299 PublicKeyVerify verify;
2300 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2301 char *fingerprint, *babbleprint, *format;
2302 SilcPublicKey local_pubkey;
2304 const char *hostname, *ip;
2309 char *entity = ((conn_type == SILC_CONN_SERVER ||
2310 conn_type == SILC_CONN_ROUTER) ?
2311 "server" : "client");
2314 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2315 printformat_module("fe-common/silc", NULL, NULL,
2316 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2317 entity, silc_pkcs_get_type(public_key));
2319 completion(FALSE, context);
2323 /* Encode public key */
2324 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2327 completion(FALSE, context);
2331 pw = getpwuid(getuid());
2334 completion(FALSE, context);
2338 memset(filename, 0, sizeof(filename));
2339 memset(filename2, 0, sizeof(filename2));
2340 memset(file, 0, sizeof(file));
2342 /* Get remote host information */
2343 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2344 NULL, &hostname, &ip, &port);
2346 if (conn_type == SILC_CONN_SERVER ||
2347 conn_type == SILC_CONN_ROUTER) {
2349 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2350 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2351 get_irssi_dir(), entity, file);
2353 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2355 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2356 get_irssi_dir(), entity, file);
2361 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2363 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2364 get_irssi_dir(), entity, file);
2369 /* Replace all whitespaces with `_'. */
2370 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2371 for (i = 0; i < strlen(fingerprint); i++)
2372 if (fingerprint[i] == ' ')
2373 fingerprint[i] = '_';
2375 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2376 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2377 get_irssi_dir(), entity, file);
2378 silc_free(fingerprint);
2383 /* Take fingerprint of the public key */
2384 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2385 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2387 verify = silc_calloc(1, sizeof(*verify));
2388 verify->client = client;
2389 verify->conn = conn;
2390 verify->filename = strdup(ipf);
2391 verify->entity = strdup(entity);
2392 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2393 (name ? strdup(name) : strdup(hostname))
2395 verify->public_key = public_key;
2396 verify->completion = completion;
2397 verify->context = context;
2399 /* Check whether this key already exists */
2400 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2401 /* Key does not exist, ask user to verify the key and save it */
2403 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2404 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2405 verify->entity_name : entity);
2406 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2407 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2408 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2409 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2410 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2411 SILCTXT_PUBKEY_ACCEPT);
2412 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2415 silc_free(fingerprint);
2418 /* The key already exists, verify it. */
2419 unsigned char *encpk;
2420 SilcUInt32 encpk_len;
2422 /* Load the key file, try for both IP filename and hostname filename */
2423 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2424 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2425 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2426 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2427 verify->entity_name : entity);
2428 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2429 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2430 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2431 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2432 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2433 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2434 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2435 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2436 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2439 silc_free(fingerprint);
2443 /* Encode the key data */
2444 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2446 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2447 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2448 verify->entity_name : entity);
2449 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2450 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2451 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2452 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2453 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2454 SILCTXT_PUBKEY_MALFORMED, entity);
2455 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2456 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2457 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2460 silc_free(fingerprint);
2464 /* Compare the keys */
2465 if (memcmp(encpk, pk, encpk_len)) {
2466 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2467 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2468 verify->entity_name : entity);
2469 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2470 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2471 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2472 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2473 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2474 SILCTXT_PUBKEY_NO_MATCH, entity);
2475 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2476 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2477 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2478 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2480 /* Ask user to verify the key and save it */
2481 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2482 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2483 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2486 silc_free(fingerprint);
2491 /* Local copy matched */
2493 completion(TRUE, context);
2495 silc_free(fingerprint);
2496 silc_free(verify->filename);
2497 silc_free(verify->entity);
2498 silc_free(verify->entity_name);
2503 /* Verifies received public key. The `conn_type' indicates which entity
2504 (server, client etc.) has sent the public key. If user decides to trust
2505 the key may be saved as trusted public key for later use. The
2506 `completion' must be called after the public key has been verified. */
2509 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2510 SilcConnectionType conn_type,
2511 SilcPublicKey public_key,
2512 SilcVerifyPublicKey completion, void *context)
2514 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2515 completion, context);
2518 /* Asks passphrase from user on the input line. */
2521 SilcAskPassphrase completion;
2525 void ask_passphrase_completion(const char *passphrase, void *context)
2527 AskPassphrase p = (AskPassphrase)context;
2528 if (passphrase && passphrase[0] == '\0')
2530 p->completion((unsigned char *)passphrase,
2531 passphrase ? strlen(passphrase) : 0, p->context);
2535 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2536 SilcAskPassphrase completion, void *context)
2538 AskPassphrase p = silc_calloc(1, sizeof(*p));
2539 p->completion = completion;
2540 p->context = context;
2542 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2543 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2547 SilcGetAuthMeth completion;
2551 static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
2552 SilcUInt32 passphrase_len,
2555 GetAuthMethod a = context;
2556 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2557 passphrase, passphrase_len, a->context);
2561 /* Find authentication data by hostname and port. The hostname may be IP
2564 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2565 char *hostname, SilcUInt16 port,
2566 SilcAuthMethod auth_meth,
2567 SilcGetAuthMeth completion, void *context)
2569 SERVER_SETUP_REC *setup;
2571 SILC_LOG_DEBUG(("Start"));
2573 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2574 /* Returning NULL will cause library to use our private key configured
2575 for this connection */
2576 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2580 /* Check whether we find the password for this server in our
2581 configuration. If it's set, always send it server. */
2582 setup = server_setup_find_port(hostname, port);
2583 if (setup && setup->password) {
2584 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2589 /* Didn't find password. If server wants it, ask it from user. */
2590 if (auth_meth == SILC_AUTH_PASSWORD) {
2592 a = silc_calloc(1, sizeof(*a));
2594 a->completion = completion;
2595 a->context = context;
2596 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2601 /* No authentication */
2602 completion(SILC_AUTH_NONE, NULL, 0, context);
2605 /* Asks whether the user would like to perform the key agreement protocol.
2606 This is called after we have received an key agreement packet or an
2607 reply to our key agreement packet. This returns TRUE if the user wants
2608 the library to perform the key agreement protocol and FALSE if it is not
2609 desired (application may start it later by calling the function
2610 silc_client_perform_key_agreement). */
2612 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2613 SilcClientEntry client_entry, const char *hostname,
2614 SilcUInt16 protocol, SilcUInt16 port)
2616 char portstr[12], protostr[5];
2618 SILC_LOG_DEBUG(("Start"));
2620 /* We will just display the info on the screen and return FALSE and user
2621 will have to start the key agreement with a command. */
2624 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2625 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2630 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2631 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2633 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2634 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2635 client_entry->nickname, hostname, portstr, protostr);
2638 /* Notifies application that file transfer protocol session is being
2639 requested by the remote client indicated by the `client_entry' from
2640 the `hostname' and `port'. The `session_id' is the file transfer
2641 session and it can be used to either accept or reject the file
2642 transfer request, by calling the silc_client_file_receive or
2643 silc_client_file_close, respectively. */
2645 void silc_ftp(SilcClient client, SilcClientConnection conn,
2646 SilcClientEntry client_entry, SilcUInt32 session_id,
2647 const char *hostname, SilcUInt16 port)
2649 SILC_SERVER_REC *server;
2651 FtpSession ftp = NULL;
2653 SILC_LOG_DEBUG(("Start"));
2655 server = conn->context;
2657 silc_dlist_start(server->ftp_sessions);
2658 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2659 if (ftp->client_entry == client_entry &&
2660 ftp->session_id == session_id) {
2661 server->current_session = ftp;
2665 if (ftp == SILC_LIST_END) {
2666 ftp = silc_calloc(1, sizeof(*ftp));
2667 ftp->client_entry = client_entry;
2668 ftp->session_id = session_id;
2671 silc_dlist_add(server->ftp_sessions, ftp);
2672 server->current_session = ftp;
2676 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2679 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2680 SILCTXT_FILE_REQUEST, client_entry->nickname);
2682 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2683 SILCTXT_FILE_REQUEST_HOST,
2684 client_entry->nickname, hostname, portstr);
2687 /* SILC client operations */
2688 SilcClientOperations ops = {
2690 silc_channel_message,
2691 silc_private_message,
2695 silc_get_auth_method,
2696 silc_verify_public_key,
2697 silc_ask_passphrase,