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 if (getkey->id_type == SILC_ID_CLIENT)
1438 printformat_module("fe-common/silc", NULL, NULL,
1439 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1441 silc_pubkey->identifier.realname ?
1442 silc_pubkey->identifier.realname : "",
1443 silc_pubkey->identifier.email ?
1444 silc_pubkey->identifier.email : "");
1446 printformat_module("fe-common/silc", NULL, NULL,
1447 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1450 printformat_module("fe-common/silc", NULL, NULL,
1451 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1456 * Drop our references as need be.
1458 switch (getkey->id_type) {
1459 case SILC_ID_CLIENT:
1460 silc_client_unref_client(getkey->client, getkey->conn,
1461 (SilcClientEntry)getkey->entry);
1464 case SILC_ID_SERVER:
1465 silc_client_unref_server(getkey->client, getkey->conn,
1466 (SilcServerEntry)getkey->entry);
1473 /* Parse an invite or ban list */
1474 void silc_parse_inviteban_list(SilcClient client,
1475 SilcClientConnection conn,
1476 SILC_SERVER_REC *server,
1477 SilcChannelEntry channel,
1478 const char *list_type,
1479 SilcArgumentPayload list)
1482 SilcUInt32 type, len;
1483 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1484 int counter=0, resolving = FALSE;
1486 if (!silc_argument_get_arg_num(list)) {
1487 printformat_module("fe-common/silc", server,
1488 (chanrec ? chanrec->visible_name : NULL),
1489 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1490 channel->channel_name, list_type);
1494 printformat_module("fe-common/silc", server,
1495 (chanrec ? chanrec->visible_name : NULL),
1496 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1497 channel->channel_name, list_type);
1499 /* Parse the list */
1500 tmp = silc_argument_get_first_arg(list, &type, &len);
1505 /* An invite string */
1509 if (tmp[len-1] == ',')
1512 list = g_strsplit(tmp, ",", -1);
1514 printformat_module("fe-common/silc", server,
1515 (chanrec ? chanrec->visible_name : NULL),
1516 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1517 ++counter, channel->channel_name, list_type,
1526 char *fingerprint, *babbleprint;
1528 /* tmp is Public Key Payload, take public key from it. */
1529 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1530 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1532 printformat_module("fe-common/silc", server,
1533 (chanrec ? chanrec->visible_name : NULL),
1534 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1535 ++counter, channel->channel_name, list_type,
1536 fingerprint, babbleprint);
1543 SilcClientEntry client_entry;
1546 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1547 silc_say_error("Invalid data in %s list encountered", list_type);
1551 client_entry = silc_client_get_client_by_id(client, conn,
1554 printformat_module("fe-common/silc", server,
1555 (chanrec ? chanrec->visible_name : NULL),
1556 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1557 ++counter, channel->channel_name, list_type,
1558 client_entry->nickname);
1559 silc_client_unref_client(client, conn, client_entry);
1562 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1570 silc_say_error("Unkown type in %s list: %u (len %u)",
1571 list_type, type, len);
1574 tmp = silc_argument_get_next_arg(list, &type, &len);
1578 printformat_module("fe-common/silc", server,
1579 (chanrec ? chanrec->visible_name : NULL),
1580 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1581 list_type, channel->channel_name);
1584 /* Command reply handler. This function is called always in the command reply
1585 function. If error occurs it will be called as well. Normal scenario
1586 is that it will be called after the received command data has been parsed
1587 and processed. The function is used to pass the received command data to
1590 `conn' is the associated client connection. `cmd_payload' is the command
1591 payload data received from server and it can be ignored. It is provided
1592 if the application would like to re-parse the received command data,
1593 however, it must be noted that the data is parsed already by the library
1594 thus the payload can be ignored. `success' is FALSE if error occured.
1595 In this case arguments are not sent to the application. `command' is the
1596 command reply being processed. The function has variable argument list
1597 and each command defines the number and type of arguments it passes to the
1598 application (on error they are not sent). */
1600 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1601 SilcCommand command, SilcStatus status,
1602 SilcStatus error, va_list vp)
1604 SILC_SERVER_REC *server = conn->context;
1605 SILC_CHANNEL_REC *chanrec;
1607 SILC_LOG_DEBUG(("Start"));
1610 case SILC_COMMAND_WHOIS:
1612 char buf[1024], *nickname, *username, *realname, *nick;
1613 unsigned char *fingerprint;
1614 SilcUInt32 idle, mode, *user_modes;
1616 SilcClientEntry client_entry;
1619 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1620 /* Print the unknown nick for user */
1621 char *tmp = va_arg(vp, char *);
1623 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1625 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1626 /* Try to find the entry for the unknown client ID, since we
1627 might have, and print the nickname of it for user. */
1628 SilcClientID *id = va_arg(vp, SilcClientID *);
1630 client_entry = silc_client_get_client_by_id(client, conn, id);
1631 if (client_entry && client_entry->nickname[0])
1632 silc_say_error("%s: %s", client_entry->nickname,
1633 silc_get_status_message(status));
1634 silc_client_unref_client(client, conn, client_entry);
1637 } else if (SILC_STATUS_IS_ERROR(status)) {
1638 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1642 client_entry = va_arg(vp, SilcClientEntry);
1643 nickname = va_arg(vp, char *);
1644 username = va_arg(vp, char *);
1645 realname = va_arg(vp, char *);
1646 channels = va_arg(vp, SilcDList);
1647 mode = va_arg(vp, SilcUInt32);
1648 idle = va_arg(vp, SilcUInt32);
1649 fingerprint = va_arg(vp, unsigned char *);
1650 user_modes = va_arg(vp, SilcUInt32 *);
1651 attrs = va_arg(vp, SilcDList);
1653 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1654 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1655 SILCTXT_WHOIS_USERINFO, nickname,
1656 client_entry->username, client_entry->hostname,
1657 nick, client_entry->nickname);
1658 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1659 SILCTXT_WHOIS_REALNAME, realname);
1662 if (channels && user_modes) {
1663 SilcChannelPayload entry;
1666 memset(buf, 0, sizeof(buf));
1667 silc_dlist_start(channels);
1668 while ((entry = silc_dlist_get(channels))) {
1669 SilcUInt32 name_len;
1670 char *m = silc_client_chumode_char(user_modes[i++]);
1671 char *name = silc_channel_get_name(entry, &name_len);
1674 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1675 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1676 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1680 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1681 SILCTXT_WHOIS_CHANNELS, buf);
1685 memset(buf, 0, sizeof(buf));
1686 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1687 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1688 SILCTXT_WHOIS_MODES, buf);
1691 if (idle && nickname) {
1692 memset(buf, 0, sizeof(buf));
1693 snprintf(buf, sizeof(buf) - 1, "%u %s",
1694 idle > 60 ? (idle / 60) : idle,
1695 idle > 60 ? "minutes" : "seconds");
1697 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1698 SILCTXT_WHOIS_IDLE, buf);
1702 fingerprint = silc_fingerprint(fingerprint, 20);
1703 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1704 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1705 silc_free(fingerprint);
1709 silc_query_attributes_print(server, silc_client, conn, attrs,
1714 case SILC_COMMAND_WHOWAS:
1716 char *nickname, *username, *realname;
1718 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1719 char *tmp = va_arg(vp, char *);
1721 silc_say_error("%s: %s", tmp,
1722 silc_get_status_message(status));
1724 } else if (SILC_STATUS_IS_ERROR(status)) {
1725 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1729 (void)va_arg(vp, SilcClientEntry);
1730 nickname = va_arg(vp, char *);
1731 username = va_arg(vp, char *);
1732 realname = va_arg(vp, char *);
1734 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1735 SILCTXT_WHOWAS_USERINFO, nickname, username,
1736 realname ? realname : "");
1740 case SILC_COMMAND_INVITE:
1742 SilcChannelEntry channel;
1743 SilcArgumentPayload invite_list;
1745 if (SILC_STATUS_IS_ERROR(status))
1748 channel = va_arg(vp, SilcChannelEntry);
1749 invite_list = va_arg(vp, SilcArgumentPayload);
1752 silc_parse_inviteban_list(client, conn, server, channel,
1753 "invite", invite_list);
1757 case SILC_COMMAND_JOIN:
1759 char *channel, *mode, *topic, *cipher, *hmac;
1761 SilcHashTableList *user_list;
1762 SilcChannelEntry channel_entry;
1763 SilcChannelUser chu;
1764 SilcClientEntry founder = NULL;
1767 if (SILC_STATUS_IS_ERROR(status)) {
1768 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
1769 char *tmp = va_arg(vp, char *);
1771 silc_say_error("JOIN: %s: %s", tmp,
1772 silc_get_status_message(status));
1775 if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
1776 char *tmp = va_arg(vp, char *);
1778 silc_say_error("JOIN: %s: %s", tmp,
1779 silc_get_status_message(status));
1782 silc_say_error("JOIN: %s", silc_get_status_message(status));
1786 channel = va_arg(vp, char *);
1787 channel_entry = va_arg(vp, SilcChannelEntry);
1788 modei = va_arg(vp, SilcUInt32);
1789 user_list = va_arg(vp, SilcHashTableList *);
1790 topic = va_arg(vp, char *);
1791 cipher = va_arg(vp, char *);
1792 hmac = va_arg(vp, char *);
1794 chanrec = silc_channel_find(server, channel);
1796 chanrec = silc_channel_create(server, channel, channel, TRUE);
1799 char tmp[256], *cp, *dm = NULL;
1800 g_free_not_null(chanrec->topic);
1802 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1803 memset(tmp, 0, sizeof(tmp));
1805 if (strlen(topic) > sizeof(tmp) - 1) {
1806 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1810 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1815 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1816 signal_emit("channel topic changed", 1, chanrec);
1821 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1822 g_free_not_null(chanrec->mode);
1823 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1824 signal_emit("channel mode changed", 1, chanrec);
1827 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1828 if (!chu->client->nickname[0])
1830 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1831 founder = chu->client;
1832 silc_nicklist_insert(chanrec, chu, FALSE);
1835 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1838 nicklist_set_own(CHANNEL(chanrec), ownnick);
1839 chanrec->entry = channel_entry;
1840 signal_emit("channel joined", 1, chanrec);
1843 printformat_module("fe-common/silc", server,
1844 channel_entry->channel_name,
1845 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1846 channel_entry->channel_name, chanrec->topic);
1849 if (founder == conn->local_entry) {
1850 printformat_module("fe-common/silc",
1851 server, channel_entry->channel_name,
1852 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1853 channel_entry->channel_name);
1854 signal_emit("nick mode changed", 2, chanrec, ownnick);
1856 printformat_module("fe-common/silc",
1857 server, channel_entry->channel_name,
1858 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1859 channel_entry->channel_name, founder->nickname);
1865 case SILC_COMMAND_NICK:
1868 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1871 if (SILC_STATUS_IS_ERROR(status)) {
1872 silc_say_error("NICK: %s", silc_get_status_message(status));
1876 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1877 if ((nicks != NULL) &&
1878 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1880 SilcClientEntry collider, old;
1882 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1883 collider = silc_client_get_client_by_id(client, conn, &old->id);
1884 if (collider != client_entry) {
1885 memset(buf, 0, sizeof(buf));
1886 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1887 collider->username, collider->hostname);
1888 nicklist_rename_unique(SERVER(server),
1890 collider, collider->nickname);
1891 silc_print_nick_change(server, collider->nickname,
1892 client_entry->nickname, buf);
1894 silc_client_unref_client(client, conn, collider);
1898 g_slist_free(nicks);
1900 old = g_strdup(server->nick);
1901 server_change_nick(SERVER(server), client_entry->nickname);
1902 nicklist_rename_unique(SERVER(server),
1903 server->conn->local_entry, server->nick,
1904 client_entry, client_entry->nickname);
1905 signal_emit("message own_nick", 4, server, server->nick, old, "");
1908 /* when connecting to a server, the last thing we receive
1909 is a SILC_COMMAND_LIST reply. Since we enable queueing
1910 during the connection, we can now safely disable it again */
1911 silc_queue_disable(conn);
1915 case SILC_COMMAND_LIST:
1920 char tmp[256], *cp, *dm = NULL;
1922 if (SILC_STATUS_IS_ERROR(status))
1925 (void)va_arg(vp, SilcChannelEntry);
1926 name = va_arg(vp, char *);
1927 topic = va_arg(vp, char *);
1928 usercount = va_arg(vp, int);
1930 if (topic && !silc_term_utf8() &&
1931 silc_utf8_valid(topic, strlen(topic))) {
1932 memset(tmp, 0, sizeof(tmp));
1934 if (strlen(topic) > sizeof(tmp) - 1) {
1935 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1939 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1944 if (status == SILC_STATUS_LIST_START ||
1945 status == SILC_STATUS_OK)
1946 printformat_module("fe-common/silc", server, NULL,
1947 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1950 snprintf(users, sizeof(users) - 1, "N/A");
1952 snprintf(users, sizeof(users) - 1, "%d", usercount);
1953 printformat_module("fe-common/silc", server, NULL,
1954 MSGLEVEL_CRAP, SILCTXT_LIST,
1955 name, users, topic ? topic : "");
1960 case SILC_COMMAND_UMODE:
1965 if (SILC_STATUS_IS_ERROR(status))
1968 mode = va_arg(vp, SilcUInt32);
1970 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1971 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1972 printformat_module("fe-common/silc", server, NULL,
1973 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1975 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1976 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1977 printformat_module("fe-common/silc", server, NULL,
1978 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1980 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1981 if (mode & SILC_UMODE_GONE) {
1982 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1983 reason = g_strdup(server->away_reason);
1985 reason = g_strdup("away");
1987 reason = g_strdup("");
1989 silc_set_away(reason, server);
1994 server->umode = mode;
1995 signal_emit("user mode changed", 2, server, NULL);
1999 case SILC_COMMAND_OPER:
2000 if (SILC_STATUS_IS_ERROR(status)) {
2001 silc_say_error("OPER: %s", silc_get_status_message(status));
2005 server->umode |= SILC_UMODE_SERVER_OPERATOR;
2006 signal_emit("user mode changed", 2, server, NULL);
2008 printformat_module("fe-common/silc", server, NULL,
2009 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2012 case SILC_COMMAND_SILCOPER:
2013 if (SILC_STATUS_IS_ERROR(status)) {
2014 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
2018 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2019 signal_emit("user mode changed", 2, server, NULL);
2021 printformat_module("fe-common/silc", server, NULL,
2022 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2025 case SILC_COMMAND_USERS:
2027 SilcHashTableList htl;
2028 SilcChannelEntry channel;
2029 SilcChannelUser chu;
2031 if (SILC_STATUS_IS_ERROR(status)) {
2032 silc_say_error("USERS: %s", silc_get_status_message(status));
2036 channel = va_arg(vp, SilcChannelEntry);
2038 printformat_module("fe-common/silc", server, channel->channel_name,
2039 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2040 channel->channel_name);
2042 silc_hash_table_list(channel->user_list, &htl);
2043 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2044 SilcClientEntry e = chu->client;
2045 char stat[5], *mode;
2047 if (!e->nickname[0])
2050 memset(stat, 0, sizeof(stat));
2051 mode = silc_client_chumode_char(chu->mode);
2052 if (e->mode & SILC_UMODE_GONE)
2054 else if (e->mode & SILC_UMODE_INDISPOSED)
2056 else if (e->mode & SILC_UMODE_BUSY)
2058 else if (e->mode & SILC_UMODE_PAGE)
2060 else if (e->mode & SILC_UMODE_HYPER)
2062 else if (e->mode & SILC_UMODE_ROBOT)
2064 else if (e->mode & SILC_UMODE_ANONYMOUS)
2071 printformat_module("fe-common/silc", server, channel->channel_name,
2072 MSGLEVEL_CRAP, SILCTXT_USERS,
2074 e->username[0] ? e->username : "",
2075 e->hostname[0] ? e->hostname : "",
2076 e->realname ? e->realname : "");
2080 silc_hash_table_list_reset(&htl);
2084 case SILC_COMMAND_BAN:
2086 SilcChannelEntry channel;
2087 SilcArgumentPayload invite_list;
2089 if (SILC_STATUS_IS_ERROR(status))
2092 channel = va_arg(vp, SilcChannelEntry);
2093 invite_list = va_arg(vp, SilcArgumentPayload);
2096 silc_parse_inviteban_list(client, conn, server, channel,
2097 "ban", invite_list);
2101 case SILC_COMMAND_GETKEY:
2105 SilcPublicKey public_key;
2106 GetkeyContext getkey;
2109 if (SILC_STATUS_IS_ERROR(status)) {
2110 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2114 id_type = va_arg(vp, SilcUInt32);
2115 entry = va_arg(vp, void *);
2116 public_key = va_arg(vp, SilcPublicKey);
2119 getkey = silc_calloc(1, sizeof(*getkey));
2120 getkey->entry = entry;
2121 getkey->id_type = id_type;
2122 getkey->client = client;
2123 getkey->conn = conn;
2125 name = (id_type == SILC_ID_CLIENT ?
2126 ((SilcClientEntry)entry)->nickname :
2127 ((SilcServerEntry)entry)->server_name);
2130 case SILC_ID_CLIENT:
2131 name = ((SilcClientEntry)entry)->nickname;
2132 silc_client_ref_client(client, conn, (SilcClientEntry)entry);
2135 case SILC_ID_SERVER:
2136 name = ((SilcServerEntry)entry)->server_name;
2137 silc_client_ref_server(client, conn, (SilcServerEntry)entry);
2141 silc_verify_public_key_internal(client, conn, name,
2142 (id_type == SILC_ID_CLIENT ?
2145 public_key, silc_getkey_cb, getkey);
2147 printformat_module("fe-common/silc", server, NULL,
2148 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2153 case SILC_COMMAND_INFO:
2155 SilcServerEntry server_entry;
2159 if (SILC_STATUS_IS_ERROR(status))
2162 server_entry = va_arg(vp, SilcServerEntry);
2163 server_name = va_arg(vp, char *);
2164 server_info = va_arg(vp, char *);
2166 if (server_name && server_info )
2168 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2169 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2174 case SILC_COMMAND_TOPIC:
2176 SilcChannelEntry channel;
2178 char tmp[256], *cp, *dm = NULL;
2180 if (SILC_STATUS_IS_ERROR(status))
2183 channel = va_arg(vp, SilcChannelEntry);
2184 topic = va_arg(vp, char *);
2186 if (topic && !silc_term_utf8() &&
2187 silc_utf8_valid(topic, strlen(topic))) {
2188 memset(tmp, 0, sizeof(tmp));
2190 if (strlen(topic) > sizeof(tmp) - 1) {
2191 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2195 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2201 chanrec = silc_channel_find_entry(server, channel);
2203 g_free_not_null(chanrec->topic);
2204 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2205 signal_emit("channel topic changed", 1, chanrec);
2207 printformat_module("fe-common/silc", server, channel->channel_name,
2208 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2209 channel->channel_name, topic);
2211 printformat_module("fe-common/silc", server, channel->channel_name,
2212 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2213 channel->channel_name);
2219 case SILC_COMMAND_WATCH:
2222 case SILC_COMMAND_STATS:
2224 SilcClientStats *cstats;
2226 const char *tmptime;
2227 int days, hours, mins, secs;
2229 if (SILC_STATUS_IS_ERROR(status))
2232 cstats = va_arg(vp, SilcClientStats *);
2234 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2238 tmptime = silc_time_string(cstats->starttime);
2239 printformat_module("fe-common/silc", server, NULL,
2240 MSGLEVEL_CRAP, SILCTXT_STATS,
2241 "Local server start time", tmptime);
2243 days = cstats->uptime / (24 * 60 * 60);
2244 cstats->uptime -= days * (24 * 60 * 60);
2245 hours = cstats->uptime / (60 * 60);
2246 cstats->uptime -= hours * (60 * 60);
2247 mins = cstats->uptime / 60;
2248 cstats->uptime -= mins * 60;
2249 secs = cstats->uptime;
2250 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2251 days, hours, mins, secs);
2252 printformat_module("fe-common/silc", server, NULL,
2253 MSGLEVEL_CRAP, SILCTXT_STATS,
2254 "Local server uptime", tmp);
2256 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2257 printformat_module("fe-common/silc", server, NULL,
2258 MSGLEVEL_CRAP, SILCTXT_STATS,
2259 "Local server clients", tmp);
2261 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2262 printformat_module("fe-common/silc", server, NULL,
2263 MSGLEVEL_CRAP, SILCTXT_STATS,
2264 "Local server channels", tmp);
2266 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2267 printformat_module("fe-common/silc", server, NULL,
2268 MSGLEVEL_CRAP, SILCTXT_STATS,
2269 "Local server operators", tmp);
2271 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2272 printformat_module("fe-common/silc", server, NULL,
2273 MSGLEVEL_CRAP, SILCTXT_STATS,
2274 "Local router operators", tmp);
2276 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2277 printformat_module("fe-common/silc", server, NULL,
2278 MSGLEVEL_CRAP, SILCTXT_STATS,
2279 "Local cell clients", tmp);
2281 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2282 printformat_module("fe-common/silc", server, NULL,
2283 MSGLEVEL_CRAP, SILCTXT_STATS,
2284 "Local cell channels", tmp);
2286 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2287 printformat_module("fe-common/silc", server, NULL,
2288 MSGLEVEL_CRAP, SILCTXT_STATS,
2289 "Local cell servers", tmp);
2291 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2292 printformat_module("fe-common/silc", server, NULL,
2293 MSGLEVEL_CRAP, SILCTXT_STATS,
2294 "Total clients", tmp);
2296 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2297 printformat_module("fe-common/silc", server, NULL,
2298 MSGLEVEL_CRAP, SILCTXT_STATS,
2299 "Total channels", tmp);
2301 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2302 printformat_module("fe-common/silc", server, NULL,
2303 MSGLEVEL_CRAP, SILCTXT_STATS,
2304 "Total servers", tmp);
2306 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2307 printformat_module("fe-common/silc", server, NULL,
2308 MSGLEVEL_CRAP, SILCTXT_STATS,
2309 "Total routers", tmp);
2311 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2312 printformat_module("fe-common/silc", server, NULL,
2313 MSGLEVEL_CRAP, SILCTXT_STATS,
2314 "Total server operators", tmp);
2316 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2317 printformat_module("fe-common/silc", server, NULL,
2318 MSGLEVEL_CRAP, SILCTXT_STATS,
2319 "Total router operators", tmp);
2323 case SILC_COMMAND_CMODE:
2325 SilcChannelEntry channel_entry;
2328 channel_entry = va_arg(vp, SilcChannelEntry);
2329 (void)va_arg(vp, SilcUInt32);
2330 (void)va_arg(vp, SilcPublicKey);
2331 chpks = va_arg(vp, SilcDList);
2333 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2334 !channel_entry || !channel_entry->channel_name)
2337 /* Print the channel public key list */
2339 silc_parse_channel_public_keys(server, channel_entry, chpks);
2341 printformat_module("fe-common/silc", server, NULL,
2342 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2343 channel_entry->channel_name);
2348 case SILC_COMMAND_LEAVE:
2350 if (SILC_STATUS_IS_ERROR(status))
2353 /* We might be cycling, so disable queueing again */
2354 silc_queue_disable(conn);
2358 case SILC_COMMAND_DETACH:
2360 /* Save the detachment data to file. */
2364 if (SILC_STATUS_IS_ERROR(status))
2367 detach = va_arg(vp, SilcBuffer);
2368 file = silc_get_session_filename(server);
2369 silc_file_writefile(file, silc_buffer_data(detach),
2370 silc_buffer_len(detach));
2375 case SILC_COMMAND_KILL:
2377 SilcClientEntry client_entry;
2379 if (SILC_STATUS_IS_ERROR(status)) {
2380 silc_say_error("KILL: %s", silc_get_status_message(status));
2384 client_entry = va_arg(vp, SilcClientEntry);
2385 if (!client_entry || !client_entry->nickname[0])
2388 /* Print this only if the killed client isn't joined on channels.
2389 If it is, we receive KILLED notify and we'll print this there. */
2390 if (!silc_hash_table_count(client_entry->channels))
2391 printformat_module("fe-common/silc", server, NULL,
2392 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2393 client_entry->nickname,
2394 conn->local_entry->nickname, "");
2401 SilcClientConnection conn;
2405 SilcPublicKey public_key;
2406 SilcVerifyPublicKey completion;
2410 static void verify_public_key_completion(const char *line, void *context,
2411 SilcKeyboardPromptStatus reason)
2413 PublicKeyVerify verify = (PublicKeyVerify)context;
2414 SilcBool success = (reason == KeyboardCompletionSuccess);
2416 if (success && (line[0] == 'Y' || line[0] == 'y')) {
2417 /* Save the key for future checking */
2418 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2419 SILC_PKCS_FILE_BASE64);
2421 /* Call the completion */
2422 if (verify->completion)
2423 verify->completion(TRUE, verify->context);
2425 /* Call the completion */
2426 if (verify->completion)
2427 verify->completion(FALSE, verify->context);
2429 printformat_module("fe-common/silc", NULL, NULL,
2430 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2431 verify->entity_name ? verify->entity_name :
2436 * If we were not called due to a failure to begin the callback, then we
2437 * shall zero the async context block in the server record. If we were
2438 * called due to a failure to begin the callback, then it is possible that
2439 * we failed due to an overlapping callback, in which case we shouldn't
2440 * overwrite the async context block pointer.
2442 if (reason != KeyboardCompletionFailed) {
2444 * Null out the completion context in the server record as this operation
2445 * is done as far as we are concerned. The underlying keyboard library
2446 * routine will take care of freeing the async context memory when the
2447 * actual callback is called by irssi in the abort case. In the success
2448 * case, it will free the async context memory after we return from this
2451 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
2452 server->prompt_op = NULL;
2455 silc_free(verify->filename);
2456 silc_free(verify->entity);
2457 silc_free(verify->entity_name);
2461 /* Internal routine to verify public key. If the `completion' is provided
2462 it will be called to indicate whether public was verified or not. For
2463 server/router public key this will check for filename that includes the
2464 remote host's IP address and remote host's hostname. */
2467 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2469 SilcConnectionType conn_type,
2470 SilcPublicKey public_key,
2471 SilcVerifyPublicKey completion, void *context)
2473 PublicKeyVerify verify;
2474 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2475 char *fingerprint, *babbleprint, *format;
2476 SilcPublicKey local_pubkey;
2477 SilcSILCPublicKey silc_pubkey;
2479 SILC_SERVER_REC *server = NULL;
2480 const char *hostname, *ip;
2485 char *entity = ((conn_type == SILC_CONN_SERVER ||
2486 conn_type == SILC_CONN_ROUTER) ?
2487 "server" : "client");
2490 server = (SILC_SERVER_REC*)conn->context;
2491 if (conn_type != SILC_CONN_CLIENT) {
2492 SILC_VERIFY(server);
2495 completion(FALSE, context);
2500 /* If we have pending public key prompt already up */
2501 if (server && server->prompt_op) {
2502 silc_async_abort(server->prompt_op, NULL, NULL);
2503 server->prompt_op = NULL;
2506 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2507 printformat_module("fe-common/silc", NULL, NULL,
2508 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2509 entity, silc_pkcs_get_type(public_key));
2511 completion(FALSE, context);
2515 /* Encode public key */
2516 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2519 completion(FALSE, context);
2523 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2525 pw = getpwuid(getuid());
2528 completion(FALSE, context);
2533 memset(filename, 0, sizeof(filename));
2534 memset(filename2, 0, sizeof(filename2));
2535 memset(file, 0, sizeof(file));
2537 /* Get remote host information */
2538 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2539 NULL, &hostname, &ip, &port);
2541 if (conn_type == SILC_CONN_SERVER ||
2542 conn_type == SILC_CONN_ROUTER) {
2544 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2545 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2546 get_irssi_dir(), entity, file);
2548 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2550 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2551 get_irssi_dir(), entity, file);
2556 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2558 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2559 get_irssi_dir(), entity, file);
2564 /* Replace all whitespaces with `_'. */
2565 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2566 for (i = 0; i < strlen(fingerprint); i++)
2567 if (fingerprint[i] == ' ')
2568 fingerprint[i] = '_';
2570 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2571 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2572 get_irssi_dir(), entity, file);
2573 silc_free(fingerprint);
2578 /* Take fingerprint of the public key */
2579 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2580 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2582 verify = silc_calloc(1, sizeof(*verify));
2583 verify->client = client;
2584 verify->conn = conn;
2585 verify->filename = strdup(ipf);
2586 verify->entity = strdup(entity);
2587 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2588 (name ? strdup(name) : strdup(hostname))
2590 verify->public_key = public_key;
2591 verify->completion = completion;
2592 verify->context = context;
2594 /* Check whether this key already exists */
2595 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2596 /* Key does not exist, ask user to verify the key and save it */
2598 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2599 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2600 verify->entity_name : entity);
2601 if (conn_type == SILC_CONN_CLIENT && name &&
2602 silc_pubkey->identifier.realname)
2603 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2604 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2605 silc_pubkey->identifier.realname,
2606 silc_pubkey->identifier.email ?
2607 silc_pubkey->identifier.email : "");
2608 else if (conn_type == SILC_CONN_CLIENT &&
2609 (silc_pubkey->identifier.realname ||
2610 silc_pubkey->identifier.email))
2611 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2612 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2613 silc_pubkey->identifier.realname,
2614 silc_pubkey->identifier.email ?
2615 silc_pubkey->identifier.email : "");
2616 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2617 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2618 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2619 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2620 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2621 SILCTXT_PUBKEY_ACCEPT);
2622 silc_keyboard_entry_redirect(verify_public_key_completion,
2624 server ? &server->prompt_op : NULL);
2626 silc_free(fingerprint);
2627 silc_free(babbleprint);
2631 /* The key already exists, verify it. */
2632 unsigned char *encpk;
2633 SilcUInt32 encpk_len;
2635 /* Load the key file, try for both IP filename and hostname filename */
2636 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2637 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2638 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2639 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2640 verify->entity_name : entity);
2641 if (conn_type == SILC_CONN_CLIENT && name &&
2642 silc_pubkey->identifier.realname)
2643 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2644 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2645 silc_pubkey->identifier.realname,
2646 silc_pubkey->identifier.email ?
2647 silc_pubkey->identifier.email : "");
2648 else if (conn_type == SILC_CONN_CLIENT &&
2649 (silc_pubkey->identifier.realname ||
2650 silc_pubkey->identifier.email))
2651 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2652 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2653 silc_pubkey->identifier.realname,
2654 silc_pubkey->identifier.email ?
2655 silc_pubkey->identifier.email : "");
2656 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2657 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2658 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2659 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2660 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2661 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2662 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2663 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2664 silc_keyboard_entry_redirect(verify_public_key_completion,
2666 server ? &server->prompt_op : NULL);
2669 silc_free(fingerprint);
2670 silc_free(babbleprint);
2675 /* Encode the key data */
2676 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2678 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2679 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2680 verify->entity_name : entity);
2681 if (conn_type == SILC_CONN_CLIENT && name &&
2682 silc_pubkey->identifier.realname)
2683 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2684 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2685 silc_pubkey->identifier.realname,
2686 silc_pubkey->identifier.email ?
2687 silc_pubkey->identifier.email : "");
2688 else if (conn_type == SILC_CONN_CLIENT &&
2689 (silc_pubkey->identifier.realname ||
2690 silc_pubkey->identifier.email))
2691 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2692 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2693 silc_pubkey->identifier.realname,
2694 silc_pubkey->identifier.email ?
2695 silc_pubkey->identifier.email : "");
2696 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2697 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2698 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2699 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2700 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2701 SILCTXT_PUBKEY_MALFORMED, entity);
2702 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2703 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2704 silc_keyboard_entry_redirect(verify_public_key_completion,
2706 server ? &server->prompt_op : NULL);
2708 silc_free(fingerprint);
2709 silc_free(babbleprint);
2713 silc_pkcs_public_key_free(local_pubkey);
2715 /* Compare the keys */
2716 if (memcmp(encpk, pk, encpk_len)) {
2717 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2718 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2719 verify->entity_name : entity);
2720 if (conn_type == SILC_CONN_CLIENT && name &&
2721 silc_pubkey->identifier.realname)
2722 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2723 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2724 silc_pubkey->identifier.realname,
2725 silc_pubkey->identifier.email ?
2726 silc_pubkey->identifier.email : "");
2727 else if (conn_type == SILC_CONN_CLIENT &&
2728 (silc_pubkey->identifier.realname ||
2729 silc_pubkey->identifier.email))
2730 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2731 SILCTXT_PUBKEY_RECEIVED_CLIENT, "",
2732 silc_pubkey->identifier.realname,
2733 silc_pubkey->identifier.email ?
2734 silc_pubkey->identifier.email : "");
2735 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2736 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2737 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2738 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2739 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2740 SILCTXT_PUBKEY_NO_MATCH, entity);
2741 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2742 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2743 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2744 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2746 /* Ask user to verify the key and save it */
2747 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2748 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2749 silc_keyboard_entry_redirect(verify_public_key_completion,
2751 server ? &server->prompt_op : NULL);
2753 silc_free(fingerprint);
2754 silc_free(babbleprint);
2760 /* Local copy matched */
2762 completion(TRUE, context);
2764 silc_free(fingerprint);
2765 silc_free(babbleprint);
2766 silc_free(verify->filename);
2767 silc_free(verify->entity);
2768 silc_free(verify->entity_name);
2774 /* Verifies received public key. The `conn_type' indicates which entity
2775 (server, client etc.) has sent the public key. If user decides to trust
2776 the key may be saved as trusted public key for later use. The
2777 `completion' must be called after the public key has been verified. */
2780 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2781 SilcConnectionType conn_type,
2782 SilcPublicKey public_key,
2783 SilcVerifyPublicKey completion, void *context)
2785 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2786 completion, context);
2789 /* Asks passphrase from user on the input line. */
2792 SilcAskPassphrase completion;
2793 SilcClientConnection conn;
2797 void ask_passphrase_completion(const char *passphrase, void *context,
2798 SilcKeyboardPromptStatus reason)
2800 AskPassphrase p = (AskPassphrase)context;
2801 if (passphrase && passphrase[0] == '\0')
2803 p->completion((unsigned char *)passphrase,
2804 passphrase ? strlen(passphrase) : 0, p->context);
2806 if (reason != KeyboardCompletionFailed) {
2807 SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
2808 server->prompt_op = NULL;
2814 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2815 SilcAskPassphrase completion, void *context)
2817 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
2820 p = silc_calloc(1, sizeof(*p));
2823 completion(NULL, 0, context);
2827 p->completion = completion;
2829 p->context = context;
2831 silc_keyboard_entry_redirect(ask_passphrase_completion,
2832 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN,
2833 p, &server->prompt_op);
2837 SilcGetAuthMeth completion;
2841 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2842 SilcUInt32 passphrase_len,
2845 GetAuthMethod a = context;
2846 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2847 passphrase, passphrase_len, a->context);
2851 /* Find authentication data by hostname and port. The hostname may be IP
2854 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2855 char *hostname, SilcUInt16 port,
2856 SilcAuthMethod auth_meth,
2857 SilcGetAuthMeth completion, void *context)
2859 SERVER_SETUP_REC *setup;
2861 SILC_LOG_DEBUG(("Start"));
2863 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2864 /* Returning NULL will cause library to use our private key configured
2865 for this connection */
2866 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2870 /* Check whether we find the password for this server in our
2871 configuration. If it's set, always send it server. */
2872 setup = server_setup_find_port(hostname, port);
2873 if (setup && setup->password) {
2874 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2879 /* Didn't find password. If server wants it, ask it from user. */
2880 if (auth_meth == SILC_AUTH_PASSWORD) {
2882 a = silc_calloc(1, sizeof(*a));
2884 a->completion = completion;
2885 a->context = context;
2886 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2891 /* No authentication */
2892 completion(SILC_AUTH_NONE, NULL, 0, context);
2895 /* Asks whether the user would like to perform the key agreement protocol.
2896 This is called after we have received an key agreement packet or an
2897 reply to our key agreement packet. This returns TRUE if the user wants
2898 the library to perform the key agreement protocol and FALSE if it is not
2899 desired (application may start it later by calling the function
2900 silc_client_perform_key_agreement). */
2902 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2903 SilcClientEntry client_entry, const char *hostname,
2904 SilcUInt16 protocol, SilcUInt16 port)
2906 char portstr[12], protostr[5];
2908 SILC_LOG_DEBUG(("Start"));
2910 /* We will just display the info on the screen and return FALSE and user
2911 will have to start the key agreement with a command. */
2914 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2915 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2920 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2921 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2923 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2924 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2925 client_entry->nickname, hostname, portstr, protostr);
2928 /* Notifies application that file transfer protocol session is being
2929 requested by the remote client indicated by the `client_entry' from
2930 the `hostname' and `port'. The `session_id' is the file transfer
2931 session and it can be used to either accept or reject the file
2932 transfer request, by calling the silc_client_file_receive or
2933 silc_client_file_close, respectively. */
2935 void silc_ftp(SilcClient client, SilcClientConnection conn,
2936 SilcClientEntry client_entry, SilcUInt32 session_id,
2937 const char *hostname, SilcUInt16 port)
2939 SILC_SERVER_REC *server;
2941 FtpSession ftp = NULL;
2943 SILC_LOG_DEBUG(("Start"));
2945 server = conn->context;
2947 silc_dlist_start(server->ftp_sessions);
2948 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2949 if (ftp->client_entry == client_entry &&
2950 ftp->session_id == session_id) {
2951 server->current_session = ftp;
2955 if (ftp == SILC_LIST_END) {
2956 ftp = silc_calloc(1, sizeof(*ftp));
2957 ftp->client_entry = client_entry;
2958 ftp->session_id = session_id;
2961 silc_dlist_add(server->ftp_sessions, ftp);
2962 server->current_session = ftp;
2966 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2969 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2970 SILCTXT_FILE_REQUEST, client_entry->nickname);
2972 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2973 SILCTXT_FILE_REQUEST_HOST,
2974 client_entry->nickname, hostname, portstr);
2977 /* SILC client operations */
2978 SilcClientOperations ops = {
2980 silc_channel_message,
2981 silc_private_message,
2985 silc_get_auth_method,
2986 silc_verify_public_key,
2987 silc_ask_passphrase,