5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2014 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"
33 #include "clientutil.h"
39 #include "special-vars.h"
40 #include "fe-common/core/printtext.h"
41 #include "fe-common/core/fe-channels.h"
42 #include "fe-common/core/keyboard.h"
43 #include "fe-common/core/window-items.h"
44 #include "fe-common/silc/module-formats.h"
49 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
50 const char *name, SilcConnectionType conn_type,
51 SilcPublicKey public_key,
52 SilcVerifyPublicKey completion, void *context);
54 char *silc_get_session_filename(SILC_SERVER_REC *server)
56 char *file, *expanded;
58 expanded = parse_special_string(settings_get_str("session_filename"),
59 SERVER(server), NULL, "", NULL, 0);
61 file = silc_calloc(1, strlen(expanded) + 255);
62 snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
68 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
71 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
72 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
73 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
75 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
76 "[SILC operator]" : "[unknown mode]");
78 if (mode & SILC_UMODE_GONE)
79 strcat(buf, " [away]");
80 if (mode & SILC_UMODE_INDISPOSED)
81 strcat(buf, " [indisposed]");
82 if (mode & SILC_UMODE_BUSY)
83 strcat(buf, " [busy]");
84 if (mode & SILC_UMODE_PAGE)
85 strcat(buf, " [page to reach]");
86 if (mode & SILC_UMODE_HYPER)
87 strcat(buf, " [hyper active]");
88 if (mode & SILC_UMODE_ROBOT)
89 strcat(buf, " [robot]");
90 if (mode & SILC_UMODE_ANONYMOUS)
91 strcat(buf, " [anonymous]");
92 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
93 strcat(buf, " [blocks private messages]");
94 if (mode & SILC_UMODE_DETACHED)
95 strcat(buf, " [detached]");
96 if (mode & SILC_UMODE_REJECT_WATCHING)
97 strcat(buf, " [rejects watching]");
98 if (mode & SILC_UMODE_BLOCK_INVITE)
99 strcat(buf, " [blocks invites]");
102 /* converts an utf-8 string to current locale */
103 char * silc_convert_utf8_string(const char *str)
105 int message_len = (str != NULL ? strlen(str) : 0);
106 char *message = silc_calloc(message_len + 1, sizeof(*message));
108 g_return_val_if_fail(message != NULL, NULL);
115 if (!silc_term_utf8() && silc_utf8_valid(str, message_len))
116 silc_utf8_decode(str, message_len, SILC_STRING_LOCALE,
117 message, message_len);
119 strcpy(message, str);
124 /* print "nick appears as" message to every channel of a server */
126 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
127 const char *newnick, const char *oldnick,
130 if (ignore_check(SERVER(server), oldnick, address,
131 channel, newnick, MSGLEVEL_NICKS))
134 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
135 SILCTXT_CHANNEL_APPEARS,
136 oldnick, newnick, channel, address);
140 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
141 const char *oldnick, const char *address)
143 GSList *tmp, *windows;
145 /* Print to each channel/query where the nick is.
146 Don't print more than once to the same window. */
149 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
150 CHANNEL_REC *channel = tmp->data;
151 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
153 if (nicklist_find(channel, newnick) == NULL ||
154 g_slist_find(windows, window) != NULL)
157 windows = g_slist_append(windows, window);
158 silc_print_nick_change_channel(server, channel->visible_name,
159 newnick, oldnick, address);
162 g_slist_free(windows);
165 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
166 SilcChannelEntry channel_entry,
167 SilcDList channel_pubkeys)
169 SilcArgumentDecodedList e;
170 SilcPublicKey pubkey;
171 SilcSILCPublicKey silc_pubkey;
172 SilcUInt32 pk_len, type;
174 char *fingerprint, *babbleprint;
177 printformat_module("fe-common/silc", server, NULL,
178 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
179 channel_entry->channel_name);
181 silc_dlist_start(channel_pubkeys);
182 while ((e = silc_dlist_get(channel_pubkeys))) {
183 pubkey = e->argument;
186 if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
189 pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
193 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
194 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
195 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, pubkey);
197 printformat_module("fe-common/silc", server, NULL,
198 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
199 c++, channel_entry->channel_name,
200 type == 0x00 ? "Added" : "Removed",
201 silc_pubkey->identifier.realname ?
202 silc_pubkey->identifier.realname : "",
203 fingerprint, babbleprint);
205 silc_free(fingerprint);
206 silc_free(babbleprint);
211 void silc_say(SilcClient client, SilcClientConnection conn,
212 SilcClientMessageType type, char *msg, ...)
214 SILC_SERVER_REC *server;
219 server = conn == NULL ? NULL : conn->context;
221 switch (conn->context_type) {
223 target = (conn->client_entry->nickname[0] ?
224 conn->client_entry->nickname : NULL);
227 case SILC_ID_CHANNEL:
228 target = conn->channel_entry->channel_name;
233 str = g_strdup_vprintf(msg, va);
234 printtext(server, target, MSGLEVEL_CRAP, "%s", str);
239 void silc_say_error(char *msg, ...)
245 str = g_strdup_vprintf(msg, va);
246 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
252 /* Try to verify a message using locally stored public key data */
254 int verify_message_signature(SilcClientEntry sender,
255 SilcMessagePayload message)
258 char file[256], filename[256];
259 char *fingerprint, *fingerprint2;
260 const unsigned char *pk_data;
261 SilcUInt32 pk_datalen;
263 int ret = SILC_MSG_SIGNED_VERIFIED, i;
265 /* get public key from the signature payload and compare it with the
266 one stored in the client entry */
267 pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
270 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
272 if (sender->fingerprint[0]) {
273 fingerprint2 = silc_fingerprint(sender->fingerprint,
274 sizeof(sender->fingerprint));
275 if (strcmp(fingerprint, fingerprint2)) {
276 /* since the public key differs from the senders public key, the
277 verification won't be done */
278 silc_pkcs_public_key_free(pk);
279 silc_free(fingerprint);
280 silc_free(fingerprint2);
281 return SILC_MSG_SIGNED_UNKNOWN;
283 silc_free(fingerprint2);
285 } else if (sender->fingerprint[0])
286 fingerprint = silc_fingerprint(sender->fingerprint,
287 sizeof(sender->fingerprint));
289 /* no idea, who or what signed that message ... */
290 return SILC_MSG_SIGNED_UNKNOWN;
292 /* search our local client key cache */
293 for (i = 0; i < strlen(fingerprint); i++)
294 if (fingerprint[i] == ' ')
295 fingerprint[i] = '_';
297 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
298 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
299 get_irssi_dir(), file);
300 silc_free(fingerprint);
302 if (stat(filename, &st) < 0)
303 /* we don't have the public key cached ... use the one from the sig */
304 ret = SILC_MSG_SIGNED_UNKNOWN;
306 SilcPublicKey cached_pk=NULL;
308 /* try to load the file */
309 if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
310 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
311 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
313 return SILC_MSG_SIGNED_UNKNOWN;
315 ret = SILC_MSG_SIGNED_UNKNOWN;
320 silc_pkcs_public_key_free(pk);
325 /* the public key is now in pk, our "level of trust" in ret */
326 if ((pk) && silc_message_signed_verify(message, pk,
327 sha1hash) != SILC_AUTH_OK)
328 ret = SILC_MSG_SIGNED_FAILED;
331 silc_pkcs_public_key_free(pk);
336 char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
339 int i = 0, j = 0, len = strlen(escaped_data);
341 data = silc_calloc(len, sizeof(char));
344 ptr = memchr(escaped_data + i, 1, len - i);
346 int inc = (ptr - escaped_data) - i;
347 memcpy(data + j, escaped_data + i, inc);
350 data[j++] = *(ptr + 1) - 1;
352 memcpy(data + j, escaped_data + i, len - i);
362 char *silc_escape_data(const char *data, SilcUInt32 len)
364 char *escaped_data, *ptr, *ptr0, *ptr1;
367 escaped_data = silc_calloc(2 * len, sizeof(char));
370 ptr0 = memchr(data + i, 0, len - i);
371 ptr1 = memchr(data + i, 1, len - i);
373 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
376 int inc = (ptr - data) - i;
378 memcpy(escaped_data + j, data + i, inc);
381 escaped_data[j++] = 1;
382 escaped_data[j++] = *(data + i++) + 1;
384 memcpy(escaped_data + j, data + i, len - i);
393 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
394 const char *data, SilcUInt32 data_len,
395 const char *nick, int verified)
399 escaped_data = silc_escape_data(data, data_len);
401 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
403 silc_free(escaped_data);
407 /* Message for a channel. The `sender' is the nickname of the sender
408 received in the packet. The `channel_name' is the name of the channel. */
410 void silc_channel_message(SilcClient client, SilcClientConnection conn,
411 SilcClientEntry sender, SilcChannelEntry channel,
412 SilcMessagePayload payload,
413 SilcChannelPrivateKey key,
414 SilcMessageFlags flags, const unsigned char *message,
415 SilcUInt32 message_len)
417 SILC_SERVER_REC *server;
419 SILC_CHANNEL_REC *chanrec;
422 SILC_LOG_DEBUG(("Start"));
427 server = conn == NULL ? NULL : conn->context;
428 chanrec = silc_channel_find_entry(server, channel);
432 nick = silc_nicklist_find(chanrec, sender);
434 /* We didn't find client but it clearly exists, add it. */
435 SilcChannelUser chu = silc_client_on_channel(channel, sender);
437 nick = silc_nicklist_insert(chanrec, chu, FALSE);
442 /* If the messages is digitally signed, verify it, if possible. */
443 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
444 if (!settings_get_bool("ignore_message_signatures")) {
445 verified = verify_message_signature(sender, payload);
447 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
451 if (flags & SILC_MESSAGE_FLAG_DATA) {
452 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
453 nick == NULL ? NULL : nick->nick,
454 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
461 if (flags & SILC_MESSAGE_FLAG_ACTION)
462 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
463 char tmp[256], *cp, *dm = NULL;
464 memset(tmp, 0, sizeof(tmp));
466 if(message_len > sizeof(tmp) - 1) {
467 dm = silc_calloc(message_len + 1, sizeof(*dm));
470 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
472 if (flags & SILC_MESSAGE_FLAG_SIGNED)
473 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
474 nick->host, channel->channel_name, verified);
476 signal_emit("message silc action", 5, server, cp, nick->nick,
477 nick->host, channel->channel_name);
480 if (flags & SILC_MESSAGE_FLAG_SIGNED)
481 signal_emit("message silc signed_action", 6, server, message,
482 nick->nick, nick->host, channel->channel_name, verified);
484 signal_emit("message silc action", 5, server, message,
485 nick->nick, nick->host, channel->channel_name);
487 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
488 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
489 char tmp[256], *cp, *dm = NULL;
490 memset(tmp, 0, sizeof(tmp));
492 if(message_len > sizeof(tmp) - 1) {
493 dm = silc_calloc(message_len + 1, sizeof(*dm));
496 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
498 if (flags & SILC_MESSAGE_FLAG_SIGNED)
499 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
500 nick->host, channel->channel_name, verified);
502 signal_emit("message silc notice", 5, server, cp, nick->nick,
503 nick->host, channel->channel_name);
506 if (flags & SILC_MESSAGE_FLAG_SIGNED)
507 signal_emit("message silc signed_notice", 6, server, message,
508 nick->nick, nick->host, channel->channel_name, verified);
510 signal_emit("message silc notice", 5, server, message,
511 nick->nick, nick->host, channel->channel_name);
514 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
515 char tmp[256], *cp, *dm = NULL;
517 memset(tmp, 0, sizeof(tmp));
519 if (message_len > sizeof(tmp) - 1) {
520 dm = silc_calloc(message_len + 1, sizeof(*dm));
524 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
526 if (flags & SILC_MESSAGE_FLAG_SIGNED)
527 signal_emit("message signed_public", 6, server, cp,
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, cp,
533 nick == NULL ? "[<unknown>]" : nick->nick,
534 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
535 chanrec->name, nick);
540 if (flags & SILC_MESSAGE_FLAG_SIGNED)
541 signal_emit("message signed_public", 6, server, message,
542 nick == NULL ? "[<unknown>]" : nick->nick,
543 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
544 chanrec->name, verified);
546 signal_emit("message public", 6, server, message,
547 nick == NULL ? "[<unknown>]" : nick->nick,
548 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
549 chanrec->name, nick);
553 /* Private message to the client. The `sender' is the nickname of the
554 sender received in the packet. */
556 void silc_private_message(SilcClient client, SilcClientConnection conn,
557 SilcClientEntry sender, SilcMessagePayload payload,
558 SilcMessageFlags flags,
559 const unsigned char *message,
560 SilcUInt32 message_len)
562 SILC_SERVER_REC *server;
566 SILC_LOG_DEBUG(("Start"));
568 server = conn == NULL ? NULL : conn->context;
569 memset(userhost, 0, sizeof(userhost));
570 if (sender->username[0])
571 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
572 sender->username, sender->hostname);
574 /* If the messages is digitally signed, verify it, if possible. */
575 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
576 if (!settings_get_bool("ignore_message_signatures")) {
577 verified = verify_message_signature(sender, payload);
579 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
583 if (flags & SILC_MESSAGE_FLAG_DATA) {
584 silc_emit_mime_sig(server,
585 sender->nickname[0] ?
586 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
588 message, message_len,
589 sender->nickname[0] ? sender->nickname : "[<unknown>]",
590 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
597 if (flags & SILC_MESSAGE_FLAG_ACTION)
598 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
599 char tmp[256], *cp, *dm = NULL;
600 memset(tmp, 0, sizeof(tmp));
602 if(message_len > sizeof(tmp) - 1) {
603 dm = silc_calloc(message_len + 1, sizeof(*dm));
606 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
608 if (flags & SILC_MESSAGE_FLAG_SIGNED)
609 signal_emit("message silc signed_private_action", 6, server, cp,
610 sender->nickname[0] ? sender->nickname : "[<unknown>]",
611 sender->username[0] ? userhost : NULL,
614 signal_emit("message silc private_action", 5, server, cp,
615 sender->nickname[0] ? sender->nickname : "[<unknown>]",
616 sender->username[0] ? userhost : NULL, NULL);
619 if (flags & SILC_MESSAGE_FLAG_SIGNED)
620 signal_emit("message silc signed_private_action", 6, server, message,
621 sender->nickname[0] ? sender->nickname : "[<unknown>]",
622 sender->username[0] ? userhost : NULL,
625 signal_emit("message silc private_action", 5, server, message,
626 sender->nickname[0] ? sender->nickname : "[<unknown>]",
627 sender->username[0] ? userhost : NULL, NULL);
629 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
630 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
631 char tmp[256], *cp, *dm = NULL;
632 memset(tmp, 0, sizeof(tmp));
634 if(message_len > sizeof(tmp) - 1) {
635 dm = silc_calloc(message_len + 1, sizeof(*dm));
638 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
640 if (flags & SILC_MESSAGE_FLAG_SIGNED)
641 signal_emit("message silc signed_private_notice", 6, server, cp,
642 sender->nickname[0] ? sender->nickname : "[<unknown>]",
643 sender->username[0] ? userhost : NULL,
646 signal_emit("message silc private_notice", 5, server, cp,
647 sender->nickname[0] ? sender->nickname : "[<unknown>]",
648 sender->username[0] ? userhost : NULL, NULL);
651 if (flags & SILC_MESSAGE_FLAG_SIGNED)
652 signal_emit("message silc signed_private_notice", 6, server, message,
653 sender->nickname[0] ? sender->nickname : "[<unknown>]",
654 sender->username[0] ? userhost : NULL,
657 signal_emit("message silc private_notice", 5, server, message,
658 sender->nickname[0] ? sender->nickname : "[<unknown>]",
659 sender->username[0] ? userhost : NULL, NULL);
662 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
663 char tmp[256], *cp, *dm = NULL;
665 memset(tmp, 0, sizeof(tmp));
667 if (message_len > sizeof(tmp) - 1) {
668 dm = silc_calloc(message_len + 1, sizeof(*dm));
672 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
674 if (flags & SILC_MESSAGE_FLAG_SIGNED)
675 signal_emit("message signed_private", 5, server, cp,
676 sender->nickname[0] ? sender->nickname : "[<unknown>]",
677 sender->username[0] ? userhost : NULL, verified);
679 signal_emit("message private", 4, server, cp,
680 sender->nickname[0] ? sender->nickname : "[<unknown>]",
681 sender->username[0] ? userhost : NULL);
686 if (flags & SILC_MESSAGE_FLAG_SIGNED)
687 signal_emit("message signed_private", 5, server, message,
688 sender->nickname[0] ? sender->nickname : "[<unknown>]",
689 sender->username[0] ? userhost : NULL, verified);
691 signal_emit("message private", 4, server, message,
692 sender->nickname[0] ? sender->nickname : "[<unknown>]",
693 sender->username[0] ? userhost : NULL);
697 /* Notify message to the client. The notify arguments are sent in the
698 same order as servers sends them. The arguments are same as received
699 from the server except for ID's. If ID is received application receives
700 the corresponding entry to the ID. For example, if Client ID is received
701 application receives SilcClientEntry. Also, if the notify type is
702 for channel the channel entry is sent to application (even if server
703 does not send it). */
705 void silc_notify(SilcClient client, SilcClientConnection conn,
706 SilcNotifyType type, ...)
709 SILC_SERVER_REC *server;
710 SILC_CHANNEL_REC *chanrec;
711 SILC_NICK_REC *nickrec;
712 SilcClientEntry client_entry, client_entry2;
713 SilcChannelEntry channel, channel2;
714 SilcServerEntry server_entry;
719 char *name, *tmp, *cipher, *hmac;
720 GSList *list1, *list_tmp;
721 SilcDList chpks, clients;
723 SILC_LOG_DEBUG(("Start"));
727 server = conn == NULL ? NULL : conn->context;
730 case SILC_NOTIFY_TYPE_NONE:
731 /* Some generic notice from server */
732 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
735 case SILC_NOTIFY_TYPE_INVITE:
737 * Invited or modified invite list.
740 SILC_LOG_DEBUG(("Notify: INVITE"));
742 channel = va_arg(va, SilcChannelEntry);
743 name = va_arg(va, char *);
744 client_entry = va_arg(va, SilcClientEntry);
746 silc_snprintf(buf, sizeof(buf) - 1, "%s@%s",
747 client_entry->username, client_entry->hostname);
748 signal_emit("message invite", 4, server, name,
749 client_entry->nickname, buf);
752 case SILC_NOTIFY_TYPE_JOIN:
757 SILC_LOG_DEBUG(("Notify: JOIN"));
759 client_entry = va_arg(va, SilcClientEntry);
760 channel = va_arg(va, SilcChannelEntry);
762 if (client_entry == server->conn->local_entry) {
763 /* You joined to channel */
764 chanrec = silc_channel_find(server, channel->channel_name);
766 chanrec = silc_channel_create(server, channel->channel_name,
767 channel->channel_name, TRUE);
768 if (!chanrec->joined)
769 chanrec->entry = channel;
771 chanrec = silc_channel_find_entry(server, channel);
772 if (chanrec != NULL) {
773 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
775 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
779 memset(buf, 0, sizeof(buf));
780 if (client_entry->username[0])
781 snprintf(buf, sizeof(buf) - 1, "%s@%s",
782 client_entry->username, client_entry->hostname);
783 signal_emit("message join", 4, server, channel->channel_name,
784 client_entry->nickname,
785 !client_entry->username[0] ? "" : buf);
787 /* If there are multiple same nicknames on channel now, tell it to user. */
788 if (client_entry != server->conn->local_entry) {
792 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
793 clients = silc_client_get_clients_local(client, conn, nick, TRUE);
794 if (!clients || silc_dlist_count(clients) < 2) {
796 silc_client_list_free(client, conn, clients);
799 silc_dlist_start(clients);
800 while ((client_entry2 = silc_dlist_get(clients)))
801 if (silc_client_on_channel(channel, client_entry2))
804 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
805 printformat_module("fe-common/silc", server, channel->channel_name,
806 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
808 printformat_module("fe-common/silc", server, channel->channel_name,
809 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
810 buf, client_entry->nickname);
812 silc_client_list_free(client, conn, clients);
817 case SILC_NOTIFY_TYPE_LEAVE:
822 SILC_LOG_DEBUG(("Notify: LEAVE"));
824 client_entry = va_arg(va, SilcClientEntry);
825 channel = va_arg(va, SilcChannelEntry);
827 memset(buf, 0, sizeof(buf));
828 if (client_entry->username)
829 snprintf(buf, sizeof(buf) - 1, "%s@%s",
830 client_entry->username, client_entry->hostname);
831 signal_emit("message part", 5, server, channel->channel_name,
832 client_entry->nickname, client_entry->username[0] ?
833 buf : "", client_entry->nickname);
835 chanrec = silc_channel_find_entry(server, channel);
836 if (chanrec != NULL) {
837 nickrec = silc_nicklist_find(chanrec, client_entry);
839 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
842 /* If there is only one client with this same nickname on channel now
843 change it to the base format if it is formatted nickname. */
845 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
846 clients = silc_client_get_clients_local(client, conn, name, TRUE);
847 if (!clients || silc_dlist_count(clients) != 2) {
849 silc_client_list_free(client, conn, clients);
852 silc_dlist_start(clients);
853 client_entry2 = silc_dlist_get(clients);
854 if (client_entry2 == client_entry)
855 client_entry2 = silc_dlist_get(clients);
856 if (silc_client_on_channel(channel, client_entry2)) {
857 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
858 silc_client_nickname_format(client, conn, client_entry2, TRUE);
859 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
860 nicklist_rename_unique(SERVER(server), client_entry2, buf,
861 client_entry2, client_entry2->nickname);
862 printformat_module("fe-common/silc", server, channel->channel_name,
863 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
864 buf, client_entry2->nickname);
867 silc_client_list_free(client, conn, clients);
872 case SILC_NOTIFY_TYPE_SIGNOFF:
877 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
879 client_entry = va_arg(va, SilcClientEntry);
880 tmp = va_arg(va, char *);
881 channel = va_arg(va, SilcChannelEntry);
883 silc_server_free_ftp(server, client_entry);
885 memset(buf, 0, sizeof(buf));
886 if (client_entry->username)
887 snprintf(buf, sizeof(buf) - 1, "%s@%s",
888 client_entry->username, client_entry->hostname);
889 signal_emit("message quit", 4, server, client_entry->nickname,
890 client_entry->username[0] ? buf : "", tmp ? tmp : "");
892 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
893 for (list_tmp = list1; list_tmp != NULL; list_tmp =
894 list_tmp->next->next) {
895 CHANNEL_REC *channel = list_tmp->data;
896 NICK_REC *nickrec = list_tmp->next->data;
898 nicklist_remove(channel, nickrec);
901 /* If there is only one client with this same nickname on channel now
902 change it to the base format if it is formatted nickname. */
904 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
905 clients = silc_client_get_clients_local(client, conn, name, TRUE);
906 if (!clients || silc_dlist_count(clients) != 2) {
908 silc_client_list_free(client, conn, clients);
911 silc_dlist_start(clients);
912 client_entry2 = silc_dlist_get(clients);
913 if (client_entry2 == client_entry)
914 client_entry2 = silc_dlist_get(clients);
915 if (silc_client_on_channel(channel, client_entry2)) {
916 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
917 silc_client_nickname_format(client, conn, client_entry2, TRUE);
918 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
919 nicklist_rename_unique(SERVER(server), client_entry2, buf,
920 client_entry2, client_entry2->nickname);
921 printformat_module("fe-common/silc", server, channel->channel_name,
922 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
923 buf, client_entry2->nickname);
926 silc_client_list_free(client, conn, clients);
931 case SILC_NOTIFY_TYPE_TOPIC_SET:
936 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
938 idtype = va_arg(va, int);
939 entry = va_arg(va, void *);
940 tmp = va_arg(va, char *);
941 channel = va_arg(va, SilcChannelEntry);
943 chanrec = silc_channel_find_entry(server, channel);
944 if (chanrec != NULL) {
945 char tmp2[256], *cp, *dm = NULL;
947 g_free_not_null(chanrec->topic);
948 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
949 memset(tmp2, 0, sizeof(tmp2));
951 if (strlen(tmp) > sizeof(tmp2) - 1) {
952 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
956 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
961 chanrec->topic = (tmp && *tmp == '\0' ? NULL : g_strdup(tmp));
962 signal_emit("channel topic changed", 1, chanrec);
967 if (idtype == SILC_ID_CLIENT) {
968 client_entry = (SilcClientEntry)entry;
969 memset(buf, 0, sizeof(buf));
970 snprintf(buf, sizeof(buf) - 1, "%s@%s",
971 client_entry->username, client_entry->hostname);
972 signal_emit("message topic", 5, server, channel->channel_name,
973 tmp, client_entry->nickname, buf);
974 } else if (idtype == SILC_ID_SERVER) {
975 server_entry = (SilcServerEntry)entry;
976 signal_emit("message topic", 5, server, channel->channel_name,
977 tmp, server_entry->server_name,
978 server_entry->server_name);
979 } else if (idtype == SILC_ID_CHANNEL) {
980 channel = (SilcChannelEntry)entry;
981 signal_emit("message topic", 5, server, channel->channel_name,
982 tmp, channel->channel_name, channel->channel_name);
986 case SILC_NOTIFY_TYPE_NICK_CHANGE:
991 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
993 client_entry = va_arg(va, SilcClientEntry);
994 name = va_arg(va, char *); /* old nickname */
996 if (!strcmp(client_entry->nickname, name))
999 memset(buf, 0, sizeof(buf));
1000 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1001 client_entry->username, client_entry->hostname);
1002 nicklist_rename_unique(SERVER(server),
1004 client_entry, client_entry->nickname);
1005 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
1008 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
1010 * Changed channel mode.
1013 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
1015 idtype = va_arg(va, int);
1016 entry = va_arg(va, void *);
1017 mode = va_arg(va, SilcUInt32);
1018 cipher = va_arg(va, char *); /* cipher */
1019 hmac = va_arg(va, char *); /* hmac */
1020 (void)va_arg(va, char *); /* passphrase */
1021 (void)va_arg(va, SilcPublicKey); /* founder key */
1022 chpks = va_arg(va, SilcDList); /* channel public keys */
1023 channel = va_arg(va, SilcChannelEntry);
1025 tmp = silc_client_chmode(mode, cipher ? cipher : "",
1028 chanrec = silc_channel_find_entry(server, channel);
1029 if (chanrec != NULL) {
1030 g_free_not_null(chanrec->mode);
1031 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
1032 signal_emit("channel mode changed", 1, chanrec);
1035 if (idtype == SILC_ID_CLIENT) {
1036 client_entry = (SilcClientEntry)entry;
1037 printformat_module("fe-common/silc", server, channel->channel_name,
1038 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1039 channel->channel_name, tmp ? tmp : "removed all",
1040 client_entry->nickname);
1041 } else if (idtype == SILC_ID_SERVER) {
1042 server_entry = (SilcServerEntry)entry;
1043 printformat_module("fe-common/silc", server, channel->channel_name,
1044 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1045 channel->channel_name, tmp ? tmp : "removed all",
1046 server_entry->server_name);
1047 } else if (idtype == SILC_ID_CHANNEL) {
1048 channel2 = (SilcChannelEntry)entry;
1049 printformat_module("fe-common/silc", server, channel->channel_name,
1050 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1051 channel->channel_name, tmp ? tmp : "removed all",
1052 channel2->channel_name);
1055 /* Print the channel public key list */
1057 silc_parse_channel_public_keys(server, channel, chpks);
1062 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1064 * Changed user's mode on channel.
1067 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1069 idtype = va_arg(va, int);
1070 entry = va_arg(va, void *);
1071 mode = va_arg(va, SilcUInt32);
1072 client_entry2 = va_arg(va, SilcClientEntry);
1073 channel = va_arg(va, SilcChannelEntry);
1075 tmp = silc_client_chumode(mode);
1076 chanrec = silc_channel_find_entry(server, channel);
1077 if (chanrec != NULL) {
1078 SILC_NICK_REC *nick;
1080 if (client_entry2 == server->conn->local_entry)
1081 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1083 nick = silc_nicklist_find(chanrec, client_entry2);
1085 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1086 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1087 signal_emit("nick mode changed", 2, chanrec, nick);
1091 if (idtype == SILC_ID_CLIENT) {
1092 client_entry = (SilcClientEntry)entry;
1093 printformat_module("fe-common/silc", server, channel->channel_name,
1094 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1095 channel->channel_name, client_entry2->nickname,
1096 tmp ? tmp : "removed all",
1097 client_entry->nickname);
1098 } else if (idtype == SILC_ID_SERVER) {
1099 server_entry = (SilcServerEntry)entry;
1100 printformat_module("fe-common/silc", server, channel->channel_name,
1101 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1102 channel->channel_name, client_entry2->nickname,
1103 tmp ? tmp : "removed all",
1104 server_entry->server_name);
1105 } else if (idtype == SILC_ID_CHANNEL) {
1106 channel2 = (SilcChannelEntry)entry;
1107 printformat_module("fe-common/silc", server, channel->channel_name,
1108 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1109 channel->channel_name, client_entry2->nickname,
1110 tmp ? tmp : "removed all",
1111 channel2->channel_name);
1114 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1115 printformat_module("fe-common/silc",
1116 server, channel->channel_name, MSGLEVEL_CRAP,
1117 SILCTXT_CHANNEL_FOUNDER,
1118 channel->channel_name, client_entry2->nickname);
1120 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1121 printformat_module("fe-common/silc",
1122 server, channel->channel_name, MSGLEVEL_CRAP,
1123 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1128 case SILC_NOTIFY_TYPE_MOTD:
1133 SILC_LOG_DEBUG(("Notify: MOTD"));
1135 tmp = va_arg(va, char *);
1137 if (!settings_get_bool("skip_motd"))
1138 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1141 case SILC_NOTIFY_TYPE_KICKED:
1143 * Someone was kicked from channel.
1146 SILC_LOG_DEBUG(("Notify: KICKED"));
1148 client_entry = va_arg(va, SilcClientEntry);
1149 tmp = va_arg(va, char *);
1150 client_entry2 = va_arg(va, SilcClientEntry);
1151 channel = va_arg(va, SilcChannelEntry);
1153 chanrec = silc_channel_find_entry(server, channel);
1155 if (client_entry == conn->local_entry) {
1156 printformat_module("fe-common/silc", server, channel->channel_name,
1157 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1158 channel->channel_name,
1159 client_entry ? client_entry2->nickname : "",
1162 chanrec->kicked = TRUE;
1163 channel_destroy((CHANNEL_REC *)chanrec);
1166 printformat_module("fe-common/silc", server, channel->channel_name,
1167 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1168 client_entry->nickname, channel->channel_name,
1169 client_entry2 ? client_entry2->nickname : "",
1173 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1174 if (nickrec != NULL)
1175 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1180 case SILC_NOTIFY_TYPE_KILLED:
1182 * Someone was killed from the network.
1185 SILC_LOG_DEBUG(("Notify: KILLED"));
1187 client_entry = va_arg(va, SilcClientEntry);
1188 tmp = va_arg(va, char *);
1189 idtype = va_arg(va, int);
1190 entry = va_arg(va, SilcClientEntry);
1192 if (client_entry == conn->local_entry) {
1193 if (idtype == SILC_ID_CLIENT) {
1194 client_entry2 = (SilcClientEntry)entry;
1195 printformat_module("fe-common/silc", server, NULL,
1196 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1197 client_entry2 ? client_entry2->nickname : "",
1199 } else if (idtype == SILC_ID_SERVER) {
1200 server_entry = (SilcServerEntry)entry;
1201 printformat_module("fe-common/silc", server, NULL,
1202 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1203 server_entry->server_name, tmp ? tmp : "");
1204 } else if (idtype == SILC_ID_CHANNEL) {
1205 channel = (SilcChannelEntry)entry;
1206 printformat_module("fe-common/silc", server, NULL,
1207 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1208 channel->channel_name, tmp ? tmp : "");
1211 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1212 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1213 list_tmp->next->next) {
1214 CHANNEL_REC *channel = list_tmp->data;
1215 NICK_REC *nickrec = list_tmp->next->data;
1216 nicklist_remove(channel, nickrec);
1219 if (idtype == SILC_ID_CLIENT) {
1220 client_entry2 = (SilcClientEntry)entry;
1221 printformat_module("fe-common/silc", server, NULL,
1222 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1223 client_entry->nickname,
1224 client_entry2 ? client_entry2->nickname : "",
1226 } else if (idtype == SILC_ID_SERVER) {
1227 server_entry = (SilcServerEntry)entry;
1228 printformat_module("fe-common/silc", server, NULL,
1229 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1230 client_entry->nickname,
1231 server_entry->server_name, tmp ? tmp : "");
1232 } else if (idtype == SILC_ID_CHANNEL) {
1233 channel = (SilcChannelEntry)entry;
1234 printformat_module("fe-common/silc", server, NULL,
1235 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1236 client_entry->nickname,
1237 channel->channel_name, tmp ? tmp : "");
1242 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1245 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1248 * Server has quit the network.
1252 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1254 (void)va_arg(va, void *);
1255 clients = va_arg(va, SilcDList);
1257 silc_dlist_start(clients);
1258 while ((client_entry = silc_dlist_get(clients))) {
1259 memset(buf, 0, sizeof(buf));
1261 /* Print only if we have the nickname. If this client has just quit
1262 when we were only resolving it, it is possible we don't have the
1264 if (client_entry->nickname[0]) {
1265 if (client_entry->username[0])
1266 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1267 client_entry->username, client_entry->hostname);
1268 signal_emit("message quit", 4, server, client_entry->nickname,
1269 client_entry->username[0] ? buf : "",
1273 silc_server_free_ftp(server, client_entry);
1275 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1276 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1277 list_tmp->next->next) {
1278 CHANNEL_REC *channel = list_tmp->data;
1279 NICK_REC *nickrec = list_tmp->next->data;
1280 nicklist_remove(channel, nickrec);
1286 case SILC_NOTIFY_TYPE_ERROR:
1288 SilcStatus error = va_arg(va, int);
1290 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1291 "%s", silc_get_status_message(error));
1295 case SILC_NOTIFY_TYPE_WATCH:
1297 SilcNotifyType notify;
1299 client_entry = va_arg(va, SilcClientEntry);
1300 name = va_arg(va, char *); /* Maybe NULL */
1301 mode = va_arg(va, SilcUInt32);
1302 notify = va_arg(va, int);
1304 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1306 printformat_module("fe-common/silc", server, NULL,
1307 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1308 client_entry->nickname, name);
1310 printformat_module("fe-common/silc", server, NULL,
1311 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1312 client_entry->nickname);
1313 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1314 /* See if client was away and is now present */
1315 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1316 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1317 SILC_UMODE_DETACHED)) &&
1318 (client_entry->mode & SILC_UMODE_GONE ||
1319 client_entry->mode & SILC_UMODE_INDISPOSED ||
1320 client_entry->mode & SILC_UMODE_BUSY ||
1321 client_entry->mode & SILC_UMODE_PAGE ||
1322 client_entry->mode & SILC_UMODE_DETACHED)) {
1323 printformat_module("fe-common/silc", server, NULL,
1324 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1325 client_entry->nickname);
1329 memset(buf, 0, sizeof(buf));
1330 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1331 printformat_module("fe-common/silc", server, NULL,
1332 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1333 client_entry->nickname, buf);
1335 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1336 printformat_module("fe-common/silc", server, NULL,
1337 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1338 client_entry->nickname);
1339 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1340 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1341 printformat_module("fe-common/silc", server, NULL,
1342 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1343 client_entry->nickname);
1344 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1345 /* Client logged in to the network */
1346 printformat_module("fe-common/silc", server, NULL,
1347 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1348 client_entry->nickname);
1354 /* Unknown notify */
1355 printformat_module("fe-common/silc", server, NULL,
1356 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1363 /* Command handler. This function is called always in the command function.
1364 If error occurs it will be called as well. `conn' is the associated
1365 client connection. `cmd_context' is the command context that was
1366 originally sent to the command. `success' is FALSE if error occured
1367 during command. `command' is the command being processed. It must be
1368 noted that this is not reply from server. This is merely called just
1369 after application has called the command. Just to tell application
1370 that the command really was processed. */
1372 static SilcBool cmode_list_chpks = FALSE;
1374 void silc_command(SilcClient client, SilcClientConnection conn,
1375 SilcBool success, SilcCommand command, SilcStatus status,
1376 SilcUInt32 argc, unsigned char **argv)
1378 SILC_SERVER_REC *server = conn->context;
1380 SILC_LOG_DEBUG(("Start"));
1383 silc_say_error("%s", silc_get_status_message(status));
1389 case SILC_COMMAND_INVITE:
1391 printformat_module("fe-common/silc", server, NULL,
1392 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1394 (argv[1][0] == '*' ?
1395 (char *)conn->current_channel->channel_name :
1399 case SILC_COMMAND_DETACH:
1400 server->no_reconnect = TRUE;
1403 case SILC_COMMAND_CMODE:
1404 if (argc == 3 && !strcmp(argv[2], "+C"))
1405 cmode_list_chpks = TRUE;
1407 cmode_list_chpks = FALSE;
1417 SilcClientConnection conn;
1422 void silc_getkey_cb(SilcBool success, void *context)
1424 GetkeyContext getkey = (GetkeyContext)context;
1425 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1426 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1427 ((SilcClientEntry)getkey->entry)->nickname :
1428 ((SilcServerEntry)getkey->entry)->server_name);
1429 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1430 ((SilcClientEntry)getkey->entry)->public_key :
1431 ((SilcServerEntry)getkey->entry)->public_key);
1432 SilcSILCPublicKey silc_pubkey;
1434 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1437 /* Client's verification notice was showed in verify_internal() */
1438 if (getkey->id_type != SILC_ID_CLIENT)
1439 printformat_module("fe-common/silc", NULL, NULL,
1440 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1443 printformat_module("fe-common/silc", NULL, NULL,
1444 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1449 * Drop our references as need be.
1451 switch (getkey->id_type) {
1452 case SILC_ID_CLIENT:
1453 silc_client_unref_client(getkey->client, getkey->conn,
1454 (SilcClientEntry)getkey->entry);
1457 case SILC_ID_SERVER:
1458 silc_client_unref_server(getkey->client, getkey->conn,
1459 (SilcServerEntry)getkey->entry);
1466 /* Parse an invite or ban list */
1467 void silc_parse_inviteban_list(SilcClient client,
1468 SilcClientConnection conn,
1469 SILC_SERVER_REC *server,
1470 SilcChannelEntry channel,
1471 const char *list_type,
1472 SilcArgumentPayload list)
1475 SilcUInt32 type, len;
1476 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1477 int counter=0, resolving = FALSE;
1479 if (!silc_argument_get_arg_num(list)) {
1480 printformat_module("fe-common/silc", server,
1481 (chanrec ? chanrec->visible_name : NULL),
1482 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1483 channel->channel_name, list_type);
1487 printformat_module("fe-common/silc", server,
1488 (chanrec ? chanrec->visible_name : NULL),
1489 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1490 channel->channel_name, list_type);
1492 /* Parse the list */
1493 tmp = silc_argument_get_first_arg(list, &type, &len);
1498 /* An invite string */
1502 if (tmp[len-1] == ',')
1505 list = g_strsplit(tmp, ",", -1);
1507 printformat_module("fe-common/silc", server,
1508 (chanrec ? chanrec->visible_name : NULL),
1509 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1510 ++counter, channel->channel_name, list_type,
1519 char *fingerprint, *babbleprint;
1521 /* tmp is Public Key Payload, take public key from it. */
1522 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1523 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1525 printformat_module("fe-common/silc", server,
1526 (chanrec ? chanrec->visible_name : NULL),
1527 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1528 ++counter, channel->channel_name, list_type,
1529 fingerprint, babbleprint);
1536 SilcClientEntry client_entry;
1539 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1540 silc_say_error("Invalid data in %s list encountered", list_type);
1544 client_entry = silc_client_get_client_by_id(client, conn,
1547 printformat_module("fe-common/silc", server,
1548 (chanrec ? chanrec->visible_name : NULL),
1549 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1550 ++counter, channel->channel_name, list_type,
1551 client_entry->nickname);
1552 silc_client_unref_client(client, conn, client_entry);
1555 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1563 silc_say_error("Unkown type in %s list: %u (len %u)",
1564 list_type, type, len);
1567 tmp = silc_argument_get_next_arg(list, &type, &len);
1571 printformat_module("fe-common/silc", server,
1572 (chanrec ? chanrec->visible_name : NULL),
1573 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1574 list_type, channel->channel_name);
1577 /* Command reply handler. This function is called always in the command reply
1578 function. If error occurs it will be called as well. Normal scenario
1579 is that it will be called after the received command data has been parsed
1580 and processed. The function is used to pass the received command data to
1583 `conn' is the associated client connection. `cmd_payload' is the command
1584 payload data received from server and it can be ignored. It is provided
1585 if the application would like to re-parse the received command data,
1586 however, it must be noted that the data is parsed already by the library
1587 thus the payload can be ignored. `success' is FALSE if error occured.
1588 In this case arguments are not sent to the application. `command' is the
1589 command reply being processed. The function has variable argument list
1590 and each command defines the number and type of arguments it passes to the
1591 application (on error they are not sent). */
1593 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1594 SilcCommand command, SilcStatus status,
1595 SilcStatus error, va_list vp)
1597 SILC_SERVER_REC *server = conn->context;
1598 SILC_CHANNEL_REC *chanrec;
1600 SILC_LOG_DEBUG(("Start"));
1603 case SILC_COMMAND_WHOIS:
1605 char buf[1024], *nickname, *username, *realname, *nick;
1606 unsigned char *fingerprint;
1607 SilcUInt32 idle, mode, *user_modes;
1609 SilcClientEntry client_entry;
1612 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1613 /* Print the unknown nick for user */
1614 char *tmp = va_arg(vp, char *);
1616 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1618 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1619 /* Try to find the entry for the unknown client ID, since we
1620 might have, and print the nickname of it for user. */
1621 SilcClientID *id = va_arg(vp, SilcClientID *);
1623 client_entry = silc_client_get_client_by_id(client, conn, id);
1624 if (client_entry && client_entry->nickname[0])
1625 silc_say_error("%s: %s", client_entry->nickname,
1626 silc_get_status_message(status));
1627 silc_client_unref_client(client, conn, client_entry);
1630 } else if (SILC_STATUS_IS_ERROR(status)) {
1631 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1635 client_entry = va_arg(vp, SilcClientEntry);
1636 nickname = va_arg(vp, char *);
1637 username = va_arg(vp, char *);
1638 realname = va_arg(vp, char *);
1639 channels = va_arg(vp, SilcDList);
1640 mode = va_arg(vp, SilcUInt32);
1641 idle = va_arg(vp, SilcUInt32);
1642 fingerprint = va_arg(vp, unsigned char *);
1643 user_modes = va_arg(vp, SilcUInt32 *);
1644 attrs = va_arg(vp, SilcDList);
1646 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1647 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1648 SILCTXT_WHOIS_USERINFO, nickname,
1649 client_entry->username, client_entry->hostname,
1650 nick, client_entry->nickname);
1651 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1652 SILCTXT_WHOIS_REALNAME, realname);
1655 if (channels && user_modes) {
1656 SilcChannelPayload entry;
1659 memset(buf, 0, sizeof(buf));
1660 silc_dlist_start(channels);
1661 while ((entry = silc_dlist_get(channels))) {
1662 SilcUInt32 name_len;
1663 char *m = silc_client_chumode_char(user_modes[i++]);
1664 char *name = silc_channel_get_name(entry, &name_len);
1667 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1668 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1669 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1673 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1674 SILCTXT_WHOIS_CHANNELS, buf);
1678 memset(buf, 0, sizeof(buf));
1679 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1680 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1681 SILCTXT_WHOIS_MODES, buf);
1684 if (idle && nickname) {
1685 memset(buf, 0, sizeof(buf));
1686 snprintf(buf, sizeof(buf) - 1, "%u %s",
1687 idle > 60 ? (idle / 60) : idle,
1688 idle > 60 ? "minutes" : "seconds");
1690 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1691 SILCTXT_WHOIS_IDLE, buf);
1695 fingerprint = silc_fingerprint(fingerprint, 20);
1696 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1697 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1698 silc_free(fingerprint);
1702 silc_query_attributes_print(server, silc_client, conn, attrs,
1707 case SILC_COMMAND_WHOWAS:
1709 char *nickname, *username, *realname;
1711 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1712 char *tmp = va_arg(vp, char *);
1714 silc_say_error("%s: %s", tmp,
1715 silc_get_status_message(status));
1717 } else if (SILC_STATUS_IS_ERROR(status)) {
1718 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1722 (void)va_arg(vp, SilcClientEntry);
1723 nickname = va_arg(vp, char *);
1724 username = va_arg(vp, char *);
1725 realname = va_arg(vp, char *);
1727 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1728 SILCTXT_WHOWAS_USERINFO, nickname, username,
1729 realname ? realname : "");
1733 case SILC_COMMAND_INVITE:
1735 SilcChannelEntry channel;
1736 SilcArgumentPayload invite_list;
1738 if (SILC_STATUS_IS_ERROR(status))
1741 channel = va_arg(vp, SilcChannelEntry);
1742 invite_list = va_arg(vp, SilcArgumentPayload);
1745 silc_parse_inviteban_list(client, conn, server, channel,
1746 "invite", invite_list);
1750 case SILC_COMMAND_JOIN:
1752 char *channel, *mode, *topic, *cipher, *hmac;
1754 SilcHashTableList *user_list;
1755 SilcChannelEntry channel_entry;
1756 SilcChannelUser chu;
1757 SilcClientEntry founder = NULL;
1760 if (SILC_STATUS_IS_ERROR(status)) {
1761 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
1762 char *tmp = va_arg(vp, char *);
1764 silc_say_error("JOIN: %s: %s", tmp,
1765 silc_get_status_message(status));
1768 if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
1769 char *tmp = va_arg(vp, char *);
1771 silc_say_error("JOIN: %s: %s", tmp,
1772 silc_get_status_message(status));
1775 silc_say_error("JOIN: %s", silc_get_status_message(status));
1779 channel = va_arg(vp, char *);
1780 channel_entry = va_arg(vp, SilcChannelEntry);
1781 modei = va_arg(vp, SilcUInt32);
1782 user_list = va_arg(vp, SilcHashTableList *);
1783 topic = va_arg(vp, char *);
1784 cipher = va_arg(vp, char *);
1785 hmac = va_arg(vp, char *);
1787 chanrec = silc_channel_find(server, channel);
1789 chanrec = silc_channel_create(server, channel, channel, TRUE);
1792 char tmp[256], *cp, *dm = NULL;
1793 g_free_not_null(chanrec->topic);
1795 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1796 memset(tmp, 0, sizeof(tmp));
1798 if (strlen(topic) > sizeof(tmp) - 1) {
1799 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1803 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1808 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1809 signal_emit("channel topic changed", 1, chanrec);
1814 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1815 g_free_not_null(chanrec->mode);
1816 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1817 signal_emit("channel mode changed", 1, chanrec);
1820 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1821 if (!chu->client->nickname[0])
1823 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1824 founder = chu->client;
1825 silc_nicklist_insert(chanrec, chu, FALSE);
1828 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1831 nicklist_set_own(CHANNEL(chanrec), ownnick);
1832 chanrec->entry = channel_entry;
1833 signal_emit("channel joined", 1, chanrec);
1836 printformat_module("fe-common/silc", server,
1837 channel_entry->channel_name,
1838 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1839 channel_entry->channel_name, chanrec->topic);
1842 if (founder == conn->local_entry) {
1843 printformat_module("fe-common/silc",
1844 server, channel_entry->channel_name,
1845 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1846 channel_entry->channel_name);
1847 signal_emit("nick mode changed", 2, chanrec, ownnick);
1849 printformat_module("fe-common/silc",
1850 server, channel_entry->channel_name,
1851 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1852 channel_entry->channel_name, founder->nickname);
1858 case SILC_COMMAND_NICK:
1861 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1864 if (SILC_STATUS_IS_ERROR(status)) {
1865 silc_say_error("NICK: %s", silc_get_status_message(status));
1869 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1870 if ((nicks != NULL) &&
1871 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1873 SilcClientEntry collider, old;
1875 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1876 collider = silc_client_get_client_by_id(client, conn, &old->id);
1877 if (collider != client_entry) {
1878 memset(buf, 0, sizeof(buf));
1879 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1880 collider->username, collider->hostname);
1881 nicklist_rename_unique(SERVER(server),
1883 collider, collider->nickname);
1884 silc_print_nick_change(server, collider->nickname,
1885 client_entry->nickname, buf);
1887 silc_client_unref_client(client, conn, collider);
1891 g_slist_free(nicks);
1893 old = g_strdup(server->nick);
1894 server_change_nick(SERVER(server), client_entry->nickname);
1895 nicklist_rename_unique(SERVER(server),
1896 server->conn->local_entry, server->nick,
1897 client_entry, client_entry->nickname);
1898 signal_emit("message own_nick", 4, server, server->nick, old, "");
1901 /* when connecting to a server, the last thing we receive
1902 is a SILC_COMMAND_LIST reply. Since we enable queueing
1903 during the connection, we can now safely disable it again */
1904 silc_queue_disable(conn);
1908 case SILC_COMMAND_LIST:
1913 char tmp[256], *cp, *dm = NULL;
1915 if (SILC_STATUS_IS_ERROR(status))
1918 (void)va_arg(vp, SilcChannelEntry);
1919 name = va_arg(vp, char *);
1920 topic = va_arg(vp, char *);
1921 usercount = va_arg(vp, int);
1923 if (topic && !silc_term_utf8() &&
1924 silc_utf8_valid(topic, strlen(topic))) {
1925 memset(tmp, 0, sizeof(tmp));
1927 if (strlen(topic) > sizeof(tmp) - 1) {
1928 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1932 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1937 if (status == SILC_STATUS_LIST_START ||
1938 status == SILC_STATUS_OK)
1939 printformat_module("fe-common/silc", server, NULL,
1940 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1943 snprintf(users, sizeof(users) - 1, "N/A");
1945 snprintf(users, sizeof(users) - 1, "%d", usercount);
1946 printformat_module("fe-common/silc", server, NULL,
1947 MSGLEVEL_CRAP, SILCTXT_LIST,
1948 name, users, topic ? topic : "");
1953 case SILC_COMMAND_UMODE:
1958 if (SILC_STATUS_IS_ERROR(status))
1961 mode = va_arg(vp, SilcUInt32);
1963 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1964 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1965 printformat_module("fe-common/silc", server, NULL,
1966 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1968 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1969 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1970 printformat_module("fe-common/silc", server, NULL,
1971 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1973 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1974 if (mode & SILC_UMODE_GONE) {
1975 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1976 reason = g_strdup(server->away_reason);
1978 reason = g_strdup("away");
1980 reason = g_strdup("");
1982 silc_set_away(reason, server);
1987 server->umode = mode;
1988 signal_emit("user mode changed", 2, server, NULL);
1992 case SILC_COMMAND_OPER:
1993 if (SILC_STATUS_IS_ERROR(status)) {
1994 silc_say_error("OPER: %s", silc_get_status_message(status));
1998 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1999 signal_emit("user mode changed", 2, server, NULL);
2001 printformat_module("fe-common/silc", server, NULL,
2002 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2005 case SILC_COMMAND_SILCOPER:
2006 if (SILC_STATUS_IS_ERROR(status)) {
2007 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
2011 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2012 signal_emit("user mode changed", 2, server, NULL);
2014 printformat_module("fe-common/silc", server, NULL,
2015 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2018 case SILC_COMMAND_USERS:
2020 SilcHashTableList htl;
2021 SilcChannelEntry channel;
2022 SilcChannelUser chu;
2024 if (SILC_STATUS_IS_ERROR(status)) {
2025 silc_say_error("USERS: %s", silc_get_status_message(status));
2029 channel = va_arg(vp, SilcChannelEntry);
2031 printformat_module("fe-common/silc", server, channel->channel_name,
2032 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2033 channel->channel_name);
2035 silc_hash_table_list(channel->user_list, &htl);
2036 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2037 SilcClientEntry e = chu->client;
2038 char stat[5], *mode;
2040 if (!e->nickname[0])
2043 memset(stat, 0, sizeof(stat));
2044 mode = silc_client_chumode_char(chu->mode);
2045 if (e->mode & SILC_UMODE_GONE)
2047 else if (e->mode & SILC_UMODE_INDISPOSED)
2049 else if (e->mode & SILC_UMODE_BUSY)
2051 else if (e->mode & SILC_UMODE_PAGE)
2053 else if (e->mode & SILC_UMODE_HYPER)
2055 else if (e->mode & SILC_UMODE_ROBOT)
2057 else if (e->mode & SILC_UMODE_ANONYMOUS)
2064 printformat_module("fe-common/silc", server, channel->channel_name,
2065 MSGLEVEL_CRAP, SILCTXT_USERS,
2067 e->username[0] ? e->username : "",
2068 e->hostname[0] ? e->hostname : "",
2069 e->realname ? e->realname : "");
2073 silc_hash_table_list_reset(&htl);
2077 case SILC_COMMAND_BAN:
2079 SilcChannelEntry channel;
2080 SilcArgumentPayload invite_list;
2082 if (SILC_STATUS_IS_ERROR(status))
2085 channel = va_arg(vp, SilcChannelEntry);
2086 invite_list = va_arg(vp, SilcArgumentPayload);
2089 silc_parse_inviteban_list(client, conn, server, channel,
2090 "ban", invite_list);
2094 case SILC_COMMAND_GETKEY:
2098 SilcPublicKey public_key;
2099 GetkeyContext getkey;
2102 if (SILC_STATUS_IS_ERROR(status)) {
2103 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2107 id_type = va_arg(vp, SilcUInt32);
2108 entry = va_arg(vp, void *);
2109 public_key = va_arg(vp, SilcPublicKey);
2112 getkey = silc_calloc(1, sizeof(*getkey));
2113 getkey->entry = entry;
2114 getkey->id_type = id_type;
2115 getkey->client = client;
2116 getkey->conn = conn;
2118 name = (id_type == SILC_ID_CLIENT ?
2119 ((SilcClientEntry)entry)->nickname :
2120 ((SilcServerEntry)entry)->server_name);
2123 case SILC_ID_CLIENT:
2124 name = ((SilcClientEntry)entry)->nickname;
2125 silc_client_ref_client(client, conn, (SilcClientEntry)entry);
2128 case SILC_ID_SERVER:
2129 name = ((SilcServerEntry)entry)->server_name;
2130 silc_client_ref_server(client, conn, (SilcServerEntry)entry);
2134 silc_verify_public_key_internal(client, conn, name,
2135 (id_type == SILC_ID_CLIENT ?
2138 public_key, silc_getkey_cb, getkey);
2140 printformat_module("fe-common/silc", server, NULL,
2141 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2146 case SILC_COMMAND_INFO:
2148 SilcServerEntry server_entry;
2152 if (SILC_STATUS_IS_ERROR(status))
2155 server_entry = va_arg(vp, SilcServerEntry);
2156 server_name = va_arg(vp, char *);
2157 server_info = va_arg(vp, char *);
2159 if (server_name && server_info )
2161 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2162 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2167 case SILC_COMMAND_TOPIC:
2169 SilcChannelEntry channel;
2171 char tmp[256], *cp, *dm = NULL;
2173 if (SILC_STATUS_IS_ERROR(status))
2176 channel = va_arg(vp, SilcChannelEntry);
2177 topic = va_arg(vp, char *);
2179 if (topic && !silc_term_utf8() &&
2180 silc_utf8_valid(topic, strlen(topic))) {
2181 memset(tmp, 0, sizeof(tmp));
2183 if (strlen(topic) > sizeof(tmp) - 1) {
2184 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2188 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2194 chanrec = silc_channel_find_entry(server, channel);
2196 g_free_not_null(chanrec->topic);
2197 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2198 signal_emit("channel topic changed", 1, chanrec);
2200 printformat_module("fe-common/silc", server, channel->channel_name,
2201 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2202 channel->channel_name, topic);
2204 printformat_module("fe-common/silc", server, channel->channel_name,
2205 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2206 channel->channel_name);
2212 case SILC_COMMAND_WATCH:
2215 case SILC_COMMAND_STATS:
2217 SilcClientStats *cstats;
2219 const char *tmptime;
2220 int days, hours, mins, secs;
2222 if (SILC_STATUS_IS_ERROR(status))
2225 cstats = va_arg(vp, SilcClientStats *);
2227 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2231 tmptime = silc_time_string(cstats->starttime);
2232 printformat_module("fe-common/silc", server, NULL,
2233 MSGLEVEL_CRAP, SILCTXT_STATS,
2234 "Local server start time", tmptime);
2236 days = cstats->uptime / (24 * 60 * 60);
2237 cstats->uptime -= days * (24 * 60 * 60);
2238 hours = cstats->uptime / (60 * 60);
2239 cstats->uptime -= hours * (60 * 60);
2240 mins = cstats->uptime / 60;
2241 cstats->uptime -= mins * 60;
2242 secs = cstats->uptime;
2243 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2244 days, hours, mins, secs);
2245 printformat_module("fe-common/silc", server, NULL,
2246 MSGLEVEL_CRAP, SILCTXT_STATS,
2247 "Local server uptime", tmp);
2249 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2250 printformat_module("fe-common/silc", server, NULL,
2251 MSGLEVEL_CRAP, SILCTXT_STATS,
2252 "Local server clients", tmp);
2254 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2255 printformat_module("fe-common/silc", server, NULL,
2256 MSGLEVEL_CRAP, SILCTXT_STATS,
2257 "Local server channels", tmp);
2259 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2260 printformat_module("fe-common/silc", server, NULL,
2261 MSGLEVEL_CRAP, SILCTXT_STATS,
2262 "Local server operators", tmp);
2264 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2265 printformat_module("fe-common/silc", server, NULL,
2266 MSGLEVEL_CRAP, SILCTXT_STATS,
2267 "Local router operators", tmp);
2269 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2270 printformat_module("fe-common/silc", server, NULL,
2271 MSGLEVEL_CRAP, SILCTXT_STATS,
2272 "Local cell clients", tmp);
2274 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2275 printformat_module("fe-common/silc", server, NULL,
2276 MSGLEVEL_CRAP, SILCTXT_STATS,
2277 "Local cell channels", tmp);
2279 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2280 printformat_module("fe-common/silc", server, NULL,
2281 MSGLEVEL_CRAP, SILCTXT_STATS,
2282 "Local cell servers", tmp);
2284 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2285 printformat_module("fe-common/silc", server, NULL,
2286 MSGLEVEL_CRAP, SILCTXT_STATS,
2287 "Total clients", tmp);
2289 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2290 printformat_module("fe-common/silc", server, NULL,
2291 MSGLEVEL_CRAP, SILCTXT_STATS,
2292 "Total channels", tmp);
2294 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2295 printformat_module("fe-common/silc", server, NULL,
2296 MSGLEVEL_CRAP, SILCTXT_STATS,
2297 "Total servers", tmp);
2299 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2300 printformat_module("fe-common/silc", server, NULL,
2301 MSGLEVEL_CRAP, SILCTXT_STATS,
2302 "Total routers", tmp);
2304 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2305 printformat_module("fe-common/silc", server, NULL,
2306 MSGLEVEL_CRAP, SILCTXT_STATS,
2307 "Total server operators", tmp);
2309 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2310 printformat_module("fe-common/silc", server, NULL,
2311 MSGLEVEL_CRAP, SILCTXT_STATS,
2312 "Total router operators", tmp);
2316 case SILC_COMMAND_CMODE:
2318 SilcChannelEntry channel_entry;
2321 channel_entry = va_arg(vp, SilcChannelEntry);
2322 (void)va_arg(vp, SilcUInt32);
2323 (void)va_arg(vp, SilcPublicKey);
2324 chpks = va_arg(vp, SilcDList);
2326 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2327 !channel_entry || !channel_entry->channel_name)
2330 /* Print the channel public key list */
2332 silc_parse_channel_public_keys(server, channel_entry, chpks);
2334 printformat_module("fe-common/silc", server, NULL,
2335 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2336 channel_entry->channel_name);
2341 case SILC_COMMAND_LEAVE:
2343 if (SILC_STATUS_IS_ERROR(status))
2346 /* We might be cycling, so disable queueing again */
2347 silc_queue_disable(conn);
2351 case SILC_COMMAND_DETACH:
2353 /* Save the detachment data to file. */
2357 if (SILC_STATUS_IS_ERROR(status))
2360 detach = va_arg(vp, SilcBuffer);
2361 file = silc_get_session_filename(server);
2362 silc_file_writefile(file, silc_buffer_data(detach),
2363 silc_buffer_len(detach));
2368 case SILC_COMMAND_KILL:
2370 SilcClientEntry client_entry;
2372 if (SILC_STATUS_IS_ERROR(status)) {
2373 silc_say_error("KILL: %s", silc_get_status_message(status));
2377 client_entry = va_arg(vp, SilcClientEntry);
2378 if (!client_entry || !client_entry->nickname[0])
2381 /* Print this only if the killed client isn't joined on channels.
2382 If it is, we receive KILLED notify and we'll print this there. */
2383 if (!silc_hash_table_count(client_entry->channels))
2384 printformat_module("fe-common/silc", server, NULL,
2385 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2386 client_entry->nickname,
2387 conn->local_entry->nickname, "");
2394 SilcClientConnection conn;
2398 SilcPublicKey public_key;
2399 SilcVerifyPublicKey completion;
2403 static void verify_public_key_completion(const char *line, void *context,
2404 SilcKeyboardPromptStatus reason)
2406 PublicKeyVerify verify = (PublicKeyVerify)context;
2407 SilcBool success = (reason == KeyboardCompletionSuccess);
2409 if (success && (line[0] == 'Y' || line[0] == 'y')) {
2410 /* Save the key for future checking */
2411 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2412 SILC_PKCS_FILE_BASE64);
2414 /* Call the completion */
2415 if (verify->completion)
2416 verify->completion(TRUE, verify->context);
2418 /* Call the completion */
2419 if (verify->completion)
2420 verify->completion(FALSE, verify->context);
2422 printformat_module("fe-common/silc", NULL, NULL,
2423 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2424 verify->entity_name ? verify->entity_name :
2429 * If we were not called due to a failure to begin the callback, then we
2430 * shall zero the async context block in the server record. If we were
2431 * called due to a failure to begin the callback, then it is possible that
2432 * we failed due to an overlapping callback, in which case we shouldn't
2433 * overwrite the async context block pointer.
2435 if (reason != KeyboardCompletionFailed) {
2437 * Null out the completion context in the server record as this operation
2438 * is done as far as we are concerned. The underlying keyboard library
2439 * routine will take care of freeing the async context memory when the
2440 * actual callback is called by irssi in the abort case. In the success
2441 * case, it will free the async context memory after we return from this
2444 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
2445 server->prompt_op = NULL;
2448 silc_free(verify->filename);
2449 silc_free(verify->entity);
2450 silc_free(verify->entity_name);
2454 /* Internal routine to verify public key. If the `completion' is provided
2455 it will be called to indicate whether public was verified or not. For
2456 server/router public key this will check for filename that includes the
2457 remote host's IP address and remote host's hostname. */
2460 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2462 SilcConnectionType conn_type,
2463 SilcPublicKey public_key,
2464 SilcVerifyPublicKey completion, void *context)
2466 PublicKeyVerify verify;
2467 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2468 char *fingerprint, *babbleprint, *format;
2469 SilcPublicKey local_pubkey;
2470 SilcSILCPublicKey silc_pubkey;
2472 SILC_SERVER_REC *server = NULL;
2473 const char *hostname, *ip;
2478 char *entity = ((conn_type == SILC_CONN_SERVER ||
2479 conn_type == SILC_CONN_ROUTER) ?
2480 "server" : "client");
2483 server = (SILC_SERVER_REC*)conn->context;
2484 if (conn_type != SILC_CONN_CLIENT) {
2485 SILC_VERIFY(server);
2488 completion(FALSE, context);
2493 /* If we have pending public key prompt already up */
2494 if (server && server->prompt_op) {
2495 silc_async_abort(server->prompt_op, NULL, NULL);
2496 server->prompt_op = NULL;
2499 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2500 printformat_module("fe-common/silc", NULL, NULL,
2501 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2502 entity, silc_pkcs_get_type(public_key));
2504 completion(FALSE, context);
2508 /* Encode public key */
2509 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2512 completion(FALSE, context);
2516 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2518 pw = getpwuid(getuid());
2521 completion(FALSE, context);
2526 memset(filename, 0, sizeof(filename));
2527 memset(filename2, 0, sizeof(filename2));
2528 memset(file, 0, sizeof(file));
2530 /* Get remote host information */
2531 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2532 NULL, &hostname, &ip, &port);
2534 if (conn_type == SILC_CONN_SERVER ||
2535 conn_type == SILC_CONN_ROUTER) {
2537 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2538 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2539 get_irssi_dir(), entity, file);
2541 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2543 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2544 get_irssi_dir(), entity, file);
2549 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2551 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2552 get_irssi_dir(), entity, file);
2557 /* Replace all whitespaces with `_'. */
2558 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2559 for (i = 0; i < strlen(fingerprint); i++)
2560 if (fingerprint[i] == ' ')
2561 fingerprint[i] = '_';
2563 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2564 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2565 get_irssi_dir(), entity, file);
2566 silc_free(fingerprint);
2571 /* Take fingerprint of the public key */
2572 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2573 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2575 if (!name && conn->context_type == SILC_ID_CLIENT)
2576 name = conn->client_entry->nickname;
2578 verify = silc_calloc(1, sizeof(*verify));
2579 verify->client = client;
2580 verify->conn = conn;
2581 verify->filename = strdup(ipf);
2582 verify->entity = strdup(entity);
2583 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2584 (name ? strdup(name) : strdup(hostname))
2586 verify->public_key = public_key;
2587 verify->completion = completion;
2588 verify->context = context;
2590 /* Check whether this key already exists */
2591 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2592 /* Key does not exist, ask user to verify the key and save it */
2594 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2595 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2596 verify->entity_name : entity);
2597 if (conn_type == SILC_CONN_CLIENT && name &&
2598 silc_pubkey->identifier.realname)
2599 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2600 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2601 silc_pubkey->identifier.realname,
2602 silc_pubkey->identifier.email ?
2603 silc_pubkey->identifier.email : "");
2604 else if (conn_type == SILC_CONN_CLIENT &&
2605 (silc_pubkey->identifier.realname ||
2606 silc_pubkey->identifier.email))
2607 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2608 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2609 silc_pubkey->identifier.realname,
2610 silc_pubkey->identifier.email ?
2611 silc_pubkey->identifier.email : "");
2612 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2613 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2614 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2615 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2616 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2617 SILCTXT_PUBKEY_ACCEPT);
2618 silc_keyboard_entry_redirect(verify_public_key_completion,
2620 server ? &server->prompt_op : NULL);
2622 silc_free(fingerprint);
2623 silc_free(babbleprint);
2627 /* The key already exists, verify it. */
2628 unsigned char *encpk;
2629 SilcUInt32 encpk_len;
2631 /* Load the key file, try for both IP filename and hostname filename */
2632 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2633 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2634 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2635 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2636 verify->entity_name : entity);
2637 if (conn_type == SILC_CONN_CLIENT && name &&
2638 silc_pubkey->identifier.realname)
2639 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2640 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2641 silc_pubkey->identifier.realname,
2642 silc_pubkey->identifier.email ?
2643 silc_pubkey->identifier.email : "");
2644 else if (conn_type == SILC_CONN_CLIENT &&
2645 (silc_pubkey->identifier.realname ||
2646 silc_pubkey->identifier.email))
2647 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2648 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2649 silc_pubkey->identifier.realname,
2650 silc_pubkey->identifier.email ?
2651 silc_pubkey->identifier.email : "");
2652 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2653 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2654 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2655 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2656 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2657 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2658 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2659 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2660 silc_keyboard_entry_redirect(verify_public_key_completion,
2662 server ? &server->prompt_op : NULL);
2665 silc_free(fingerprint);
2666 silc_free(babbleprint);
2671 /* Encode the key data */
2672 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2674 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2675 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2676 verify->entity_name : entity);
2677 if (conn_type == SILC_CONN_CLIENT && name &&
2678 silc_pubkey->identifier.realname)
2679 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2680 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2681 silc_pubkey->identifier.realname,
2682 silc_pubkey->identifier.email ?
2683 silc_pubkey->identifier.email : "");
2684 else if (conn_type == SILC_CONN_CLIENT &&
2685 (silc_pubkey->identifier.realname ||
2686 silc_pubkey->identifier.email))
2687 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2688 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2689 silc_pubkey->identifier.realname,
2690 silc_pubkey->identifier.email ?
2691 silc_pubkey->identifier.email : "");
2692 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2693 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2694 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2695 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2696 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2697 SILCTXT_PUBKEY_MALFORMED, entity);
2698 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2699 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2700 silc_keyboard_entry_redirect(verify_public_key_completion,
2702 server ? &server->prompt_op : NULL);
2704 silc_free(fingerprint);
2705 silc_free(babbleprint);
2709 silc_pkcs_public_key_free(local_pubkey);
2711 /* Compare the keys */
2712 if (memcmp(encpk, pk, encpk_len)) {
2713 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2714 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2715 verify->entity_name : entity);
2716 if (conn_type == SILC_CONN_CLIENT && name &&
2717 silc_pubkey->identifier.realname)
2718 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2719 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2720 silc_pubkey->identifier.realname,
2721 silc_pubkey->identifier.email ?
2722 silc_pubkey->identifier.email : "");
2723 else if (conn_type == SILC_CONN_CLIENT &&
2724 (silc_pubkey->identifier.realname ||
2725 silc_pubkey->identifier.email))
2726 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2727 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2728 silc_pubkey->identifier.realname,
2729 silc_pubkey->identifier.email ?
2730 silc_pubkey->identifier.email : "");
2731 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2732 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2733 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2734 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2735 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2736 SILCTXT_PUBKEY_NO_MATCH, entity);
2737 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2738 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2739 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2740 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2742 /* Ask user to verify the key and save it */
2743 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2744 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2745 silc_keyboard_entry_redirect(verify_public_key_completion,
2747 server ? &server->prompt_op : NULL);
2749 silc_free(fingerprint);
2750 silc_free(babbleprint);
2756 if (conn_type == SILC_CONN_CLIENT)
2757 printformat_module("fe-common/silc", NULL, NULL,
2758 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
2761 : (silc_pubkey->identifier.realname
2762 ? silc_pubkey->identifier.realname
2763 : (silc_pubkey->identifier.email
2764 ? silc_pubkey->identifier.email
2766 silc_pubkey->identifier.realname ?
2767 silc_pubkey->identifier.realname : "",
2768 silc_pubkey->identifier.email ?
2769 silc_pubkey->identifier.email : "");
2771 /* Local copy matched */
2773 completion(TRUE, context);
2775 silc_free(fingerprint);
2776 silc_free(babbleprint);
2777 silc_free(verify->filename);
2778 silc_free(verify->entity);
2779 silc_free(verify->entity_name);
2785 /* Verifies received public key. The `conn_type' indicates which entity
2786 (server, client etc.) has sent the public key. If user decides to trust
2787 the key may be saved as trusted public key for later use. The
2788 `completion' must be called after the public key has been verified. */
2791 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2792 SilcConnectionType conn_type,
2793 SilcPublicKey public_key,
2794 SilcVerifyPublicKey completion, void *context)
2796 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2797 completion, context);
2800 /* Asks passphrase from user on the input line. */
2803 SilcAskPassphrase completion;
2804 SilcClientConnection conn;
2808 void ask_passphrase_completion(const char *passphrase, void *context,
2809 SilcKeyboardPromptStatus reason)
2811 AskPassphrase p = (AskPassphrase)context;
2812 if (passphrase && passphrase[0] == '\0')
2814 p->completion((unsigned char *)passphrase,
2815 passphrase ? strlen(passphrase) : 0, p->context);
2817 if (reason != KeyboardCompletionFailed) {
2818 SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
2819 server->prompt_op = NULL;
2825 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2826 SilcAskPassphrase completion, void *context)
2828 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
2831 p = silc_calloc(1, sizeof(*p));
2834 completion(NULL, 0, context);
2838 p->completion = completion;
2840 p->context = context;
2842 silc_keyboard_entry_redirect(ask_passphrase_completion,
2843 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN,
2844 p, &server->prompt_op);
2848 SilcGetAuthMeth completion;
2852 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2853 SilcUInt32 passphrase_len,
2856 GetAuthMethod a = context;
2857 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2858 passphrase, passphrase_len, a->context);
2862 /* Find authentication data by hostname and port. The hostname may be IP
2865 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2866 char *hostname, SilcUInt16 port,
2867 SilcAuthMethod auth_meth,
2868 SilcGetAuthMeth completion, void *context)
2870 SERVER_SETUP_REC *setup;
2872 SILC_LOG_DEBUG(("Start"));
2874 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2875 /* Returning NULL will cause library to use our private key configured
2876 for this connection */
2877 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2881 /* Check whether we find the password for this server in our
2882 configuration. If it's set, always send it server. */
2883 setup = server_setup_find(hostname, port, "silcnet");
2884 if (setup && setup->password) {
2885 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2890 /* Didn't find password. If server wants it, ask it from user. */
2891 if (auth_meth == SILC_AUTH_PASSWORD) {
2893 a = silc_calloc(1, sizeof(*a));
2895 a->completion = completion;
2896 a->context = context;
2897 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2902 /* No authentication */
2903 completion(SILC_AUTH_NONE, NULL, 0, context);
2906 /* Asks whether the user would like to perform the key agreement protocol.
2907 This is called after we have received an key agreement packet or an
2908 reply to our key agreement packet. This returns TRUE if the user wants
2909 the library to perform the key agreement protocol and FALSE if it is not
2910 desired (application may start it later by calling the function
2911 silc_client_perform_key_agreement). */
2913 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2914 SilcClientEntry client_entry, const char *hostname,
2915 SilcUInt16 protocol, SilcUInt16 port)
2917 char portstr[12], protostr[5];
2919 SILC_LOG_DEBUG(("Start"));
2921 /* We will just display the info on the screen and return FALSE and user
2922 will have to start the key agreement with a command. */
2925 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2926 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2931 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2932 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2934 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2935 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2936 client_entry->nickname, hostname, portstr, protostr);
2939 /* Notifies application that file transfer protocol session is being
2940 requested by the remote client indicated by the `client_entry' from
2941 the `hostname' and `port'. The `session_id' is the file transfer
2942 session and it can be used to either accept or reject the file
2943 transfer request, by calling the silc_client_file_receive or
2944 silc_client_file_close, respectively. */
2946 void silc_ftp(SilcClient client, SilcClientConnection conn,
2947 SilcClientEntry client_entry, SilcUInt32 session_id,
2948 const char *hostname, SilcUInt16 port)
2950 SILC_SERVER_REC *server;
2952 FtpSession ftp = NULL;
2954 SILC_LOG_DEBUG(("Start"));
2956 server = conn->context;
2958 silc_dlist_start(server->ftp_sessions);
2959 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2960 if (ftp->client_entry == client_entry &&
2961 ftp->session_id == session_id) {
2962 server->current_session = ftp;
2966 if (ftp == SILC_LIST_END) {
2967 ftp = silc_calloc(1, sizeof(*ftp));
2968 ftp->client_entry = client_entry;
2969 ftp->session_id = session_id;
2972 silc_dlist_add(server->ftp_sessions, ftp);
2973 server->current_session = ftp;
2977 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2980 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2981 SILCTXT_FILE_REQUEST, client_entry->nickname);
2983 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2984 SILCTXT_FILE_REQUEST_HOST,
2985 client_entry->nickname, hostname, portstr);
2988 /* SILC client operations */
2989 SilcClientOperations ops = {
2991 silc_channel_message,
2992 silc_private_message,
2996 silc_get_auth_method,
2997 silc_verify_public_key,
2998 silc_ask_passphrase,