5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2008 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;
218 server = conn == NULL ? NULL : conn->context;
221 str = g_strdup_vprintf(msg, va);
222 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
227 void silc_say_error(char *msg, ...)
233 str = g_strdup_vprintf(msg, va);
234 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
240 /* Try to verify a message using locally stored public key data */
242 int verify_message_signature(SilcClientEntry sender,
243 SilcMessagePayload message)
246 char file[256], filename[256];
247 char *fingerprint, *fingerprint2;
248 const unsigned char *pk_data;
249 SilcUInt32 pk_datalen;
251 int ret = SILC_MSG_SIGNED_VERIFIED, i;
253 /* get public key from the signature payload and compare it with the
254 one stored in the client entry */
255 pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
258 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
260 if (sender->fingerprint[0]) {
261 fingerprint2 = silc_fingerprint(sender->fingerprint,
262 sizeof(sender->fingerprint));
263 if (strcmp(fingerprint, fingerprint2)) {
264 /* since the public key differs from the senders public key, the
265 verification won't be done */
266 silc_pkcs_public_key_free(pk);
267 silc_free(fingerprint);
268 silc_free(fingerprint2);
269 return SILC_MSG_SIGNED_UNKNOWN;
271 silc_free(fingerprint2);
273 } else if (sender->fingerprint[0])
274 fingerprint = silc_fingerprint(sender->fingerprint,
275 sizeof(sender->fingerprint));
277 /* no idea, who or what signed that message ... */
278 return SILC_MSG_SIGNED_UNKNOWN;
280 /* search our local client key cache */
281 for (i = 0; i < strlen(fingerprint); i++)
282 if (fingerprint[i] == ' ')
283 fingerprint[i] = '_';
285 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
286 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
287 get_irssi_dir(), file);
288 silc_free(fingerprint);
290 if (stat(filename, &st) < 0)
291 /* we don't have the public key cached ... use the one from the sig */
292 ret = SILC_MSG_SIGNED_UNKNOWN;
294 SilcPublicKey cached_pk=NULL;
296 /* try to load the file */
297 if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
298 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
299 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
301 return SILC_MSG_SIGNED_UNKNOWN;
303 ret = SILC_MSG_SIGNED_UNKNOWN;
308 silc_pkcs_public_key_free(pk);
313 /* the public key is now in pk, our "level of trust" in ret */
314 if ((pk) && silc_message_signed_verify(message, pk,
315 sha1hash) != SILC_AUTH_OK)
316 ret = SILC_MSG_SIGNED_FAILED;
319 silc_pkcs_public_key_free(pk);
324 char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
327 int i = 0, j = 0, len = strlen(escaped_data);
329 data = silc_calloc(len, sizeof(char));
332 ptr = memchr(escaped_data + i, 1, len - i);
334 int inc = (ptr - escaped_data) - i;
335 memcpy(data + j, escaped_data + i, inc);
338 data[j++] = *(ptr + 1) - 1;
340 memcpy(data + j, escaped_data + i, len - i);
350 char *silc_escape_data(const char *data, SilcUInt32 len)
352 char *escaped_data, *ptr, *ptr0, *ptr1;
355 escaped_data = silc_calloc(2 * len, sizeof(char));
358 ptr0 = memchr(data + i, 0, len - i);
359 ptr1 = memchr(data + i, 1, len - i);
361 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
364 int inc = (ptr - data) - i;
366 memcpy(escaped_data + j, data + i, inc);
369 escaped_data[j++] = 1;
370 escaped_data[j++] = *(data + i++) + 1;
372 memcpy(escaped_data + j, data + i, len - i);
381 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
382 const char *data, SilcUInt32 data_len,
383 const char *nick, int verified)
387 escaped_data = silc_escape_data(data, data_len);
389 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
391 silc_free(escaped_data);
395 /* Message for a channel. The `sender' is the nickname of the sender
396 received in the packet. The `channel_name' is the name of the channel. */
398 void silc_channel_message(SilcClient client, SilcClientConnection conn,
399 SilcClientEntry sender, SilcChannelEntry channel,
400 SilcMessagePayload payload,
401 SilcChannelPrivateKey key,
402 SilcMessageFlags flags, const unsigned char *message,
403 SilcUInt32 message_len)
405 SILC_SERVER_REC *server;
407 SILC_CHANNEL_REC *chanrec;
410 SILC_LOG_DEBUG(("Start"));
415 server = conn == NULL ? NULL : conn->context;
416 chanrec = silc_channel_find_entry(server, channel);
420 nick = silc_nicklist_find(chanrec, sender);
422 /* We didn't find client but it clearly exists, add it. */
423 SilcChannelUser chu = silc_client_on_channel(channel, sender);
425 nick = silc_nicklist_insert(chanrec, chu, FALSE);
430 /* If the messages is digitally signed, verify it, if possible. */
431 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
432 if (!settings_get_bool("ignore_message_signatures")) {
433 verified = verify_message_signature(sender, payload);
435 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
439 if (flags & SILC_MESSAGE_FLAG_DATA) {
440 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
441 nick == NULL ? NULL : nick->nick,
442 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
449 if (flags & SILC_MESSAGE_FLAG_ACTION)
450 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
451 char tmp[256], *cp, *dm = NULL;
452 memset(tmp, 0, sizeof(tmp));
454 if(message_len > sizeof(tmp) - 1) {
455 dm = silc_calloc(message_len + 1, sizeof(*dm));
458 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
460 if (flags & SILC_MESSAGE_FLAG_SIGNED)
461 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
462 nick->host, channel->channel_name, verified);
464 signal_emit("message silc action", 5, server, cp, nick->nick,
465 nick->host, channel->channel_name);
468 if (flags & SILC_MESSAGE_FLAG_SIGNED)
469 signal_emit("message silc signed_action", 6, server, message,
470 nick->nick, nick->host, channel->channel_name, verified);
472 signal_emit("message silc action", 5, server, message,
473 nick->nick, nick->host, channel->channel_name);
475 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
476 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
477 char tmp[256], *cp, *dm = NULL;
478 memset(tmp, 0, sizeof(tmp));
480 if(message_len > sizeof(tmp) - 1) {
481 dm = silc_calloc(message_len + 1, sizeof(*dm));
484 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
486 if (flags & SILC_MESSAGE_FLAG_SIGNED)
487 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
488 nick->host, channel->channel_name, verified);
490 signal_emit("message silc notice", 5, server, cp, nick->nick,
491 nick->host, channel->channel_name);
494 if (flags & SILC_MESSAGE_FLAG_SIGNED)
495 signal_emit("message silc signed_notice", 6, server, message,
496 nick->nick, nick->host, channel->channel_name, verified);
498 signal_emit("message silc notice", 5, server, message,
499 nick->nick, nick->host, channel->channel_name);
502 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
503 char tmp[256], *cp, *dm = NULL;
505 memset(tmp, 0, sizeof(tmp));
507 if (message_len > sizeof(tmp) - 1) {
508 dm = silc_calloc(message_len + 1, sizeof(*dm));
512 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
514 if (flags & SILC_MESSAGE_FLAG_SIGNED)
515 signal_emit("message signed_public", 6, server, cp,
516 nick == NULL ? "[<unknown>]" : nick->nick,
517 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
518 chanrec->name, verified);
520 signal_emit("message public", 6, server, cp,
521 nick == NULL ? "[<unknown>]" : nick->nick,
522 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
523 chanrec->name, nick);
528 if (flags & SILC_MESSAGE_FLAG_SIGNED)
529 signal_emit("message signed_public", 6, server, message,
530 nick == NULL ? "[<unknown>]" : nick->nick,
531 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
532 chanrec->name, verified);
534 signal_emit("message public", 6, server, message,
535 nick == NULL ? "[<unknown>]" : nick->nick,
536 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
537 chanrec->name, nick);
541 /* Private message to the client. The `sender' is the nickname of the
542 sender received in the packet. */
544 void silc_private_message(SilcClient client, SilcClientConnection conn,
545 SilcClientEntry sender, SilcMessagePayload payload,
546 SilcMessageFlags flags,
547 const unsigned char *message,
548 SilcUInt32 message_len)
550 SILC_SERVER_REC *server;
554 SILC_LOG_DEBUG(("Start"));
556 server = conn == NULL ? NULL : conn->context;
557 memset(userhost, 0, sizeof(userhost));
558 if (sender->username[0])
559 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
560 sender->username, sender->hostname);
562 /* If the messages is digitally signed, verify it, if possible. */
563 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
564 if (!settings_get_bool("ignore_message_signatures")) {
565 verified = verify_message_signature(sender, payload);
567 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
571 if (flags & SILC_MESSAGE_FLAG_DATA) {
572 silc_emit_mime_sig(server,
573 sender->nickname[0] ?
574 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
576 message, message_len,
577 sender->nickname[0] ? sender->nickname : "[<unknown>]",
578 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
585 if (flags & SILC_MESSAGE_FLAG_ACTION)
586 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
587 char tmp[256], *cp, *dm = NULL;
588 memset(tmp, 0, sizeof(tmp));
590 if(message_len > sizeof(tmp) - 1) {
591 dm = silc_calloc(message_len + 1, sizeof(*dm));
594 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
596 if (flags & SILC_MESSAGE_FLAG_SIGNED)
597 signal_emit("message silc signed_private_action", 6, server, cp,
598 sender->nickname[0] ? sender->nickname : "[<unknown>]",
599 sender->username[0] ? userhost : NULL,
602 signal_emit("message silc private_action", 5, server, cp,
603 sender->nickname[0] ? sender->nickname : "[<unknown>]",
604 sender->username[0] ? userhost : NULL, NULL);
607 if (flags & SILC_MESSAGE_FLAG_SIGNED)
608 signal_emit("message silc signed_private_action", 6, server, message,
609 sender->nickname[0] ? sender->nickname : "[<unknown>]",
610 sender->username[0] ? userhost : NULL,
613 signal_emit("message silc private_action", 5, server, message,
614 sender->nickname[0] ? sender->nickname : "[<unknown>]",
615 sender->username[0] ? userhost : NULL, NULL);
617 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
618 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
619 char tmp[256], *cp, *dm = NULL;
620 memset(tmp, 0, sizeof(tmp));
622 if(message_len > sizeof(tmp) - 1) {
623 dm = silc_calloc(message_len + 1, sizeof(*dm));
626 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
628 if (flags & SILC_MESSAGE_FLAG_SIGNED)
629 signal_emit("message silc signed_private_notice", 6, server, cp,
630 sender->nickname[0] ? sender->nickname : "[<unknown>]",
631 sender->username[0] ? userhost : NULL,
634 signal_emit("message silc private_notice", 5, server, cp,
635 sender->nickname[0] ? sender->nickname : "[<unknown>]",
636 sender->username[0] ? userhost : NULL, NULL);
639 if (flags & SILC_MESSAGE_FLAG_SIGNED)
640 signal_emit("message silc signed_private_notice", 6, server, message,
641 sender->nickname[0] ? sender->nickname : "[<unknown>]",
642 sender->username[0] ? userhost : NULL,
645 signal_emit("message silc private_notice", 5, server, message,
646 sender->nickname[0] ? sender->nickname : "[<unknown>]",
647 sender->username[0] ? userhost : NULL, NULL);
650 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
651 char tmp[256], *cp, *dm = NULL;
653 memset(tmp, 0, sizeof(tmp));
655 if (message_len > sizeof(tmp) - 1) {
656 dm = silc_calloc(message_len + 1, sizeof(*dm));
660 silc_utf8_decode(message, message_len, SILC_STRING_LOCALE,
662 if (flags & SILC_MESSAGE_FLAG_SIGNED)
663 signal_emit("message signed_private", 5, server, cp,
664 sender->nickname[0] ? sender->nickname : "[<unknown>]",
665 sender->username[0] ? userhost : NULL, verified);
667 signal_emit("message private", 4, server, cp,
668 sender->nickname[0] ? sender->nickname : "[<unknown>]",
669 sender->username[0] ? userhost : NULL);
674 if (flags & SILC_MESSAGE_FLAG_SIGNED)
675 signal_emit("message signed_private", 5, server, message,
676 sender->nickname[0] ? sender->nickname : "[<unknown>]",
677 sender->username[0] ? userhost : NULL, verified);
679 signal_emit("message private", 4, server, message,
680 sender->nickname[0] ? sender->nickname : "[<unknown>]",
681 sender->username[0] ? userhost : NULL);
685 /* Notify message to the client. The notify arguments are sent in the
686 same order as servers sends them. The arguments are same as received
687 from the server except for ID's. If ID is received application receives
688 the corresponding entry to the ID. For example, if Client ID is received
689 application receives SilcClientEntry. Also, if the notify type is
690 for channel the channel entry is sent to application (even if server
691 does not send it). */
693 void silc_notify(SilcClient client, SilcClientConnection conn,
694 SilcNotifyType type, ...)
697 SILC_SERVER_REC *server;
698 SILC_CHANNEL_REC *chanrec;
699 SILC_NICK_REC *nickrec;
700 SilcClientEntry client_entry, client_entry2;
701 SilcChannelEntry channel, channel2;
702 SilcServerEntry server_entry;
707 char *name, *tmp, *cipher, *hmac;
708 GSList *list1, *list_tmp;
709 SilcDList chpks, clients;
711 SILC_LOG_DEBUG(("Start"));
715 server = conn == NULL ? NULL : conn->context;
718 case SILC_NOTIFY_TYPE_NONE:
719 /* Some generic notice from server */
720 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
723 case SILC_NOTIFY_TYPE_INVITE:
725 * Invited or modified invite list.
728 SILC_LOG_DEBUG(("Notify: INVITE"));
730 channel = va_arg(va, SilcChannelEntry);
731 name = va_arg(va, char *);
732 client_entry = va_arg(va, SilcClientEntry);
734 silc_snprintf(buf, sizeof(buf) - 1, "%s@%s",
735 client_entry->username, client_entry->hostname);
736 signal_emit("message invite", 4, server, name,
737 client_entry->nickname, buf);
740 case SILC_NOTIFY_TYPE_JOIN:
745 SILC_LOG_DEBUG(("Notify: JOIN"));
747 client_entry = va_arg(va, SilcClientEntry);
748 channel = va_arg(va, SilcChannelEntry);
750 if (client_entry == server->conn->local_entry) {
751 /* You joined to channel */
752 chanrec = silc_channel_find(server, channel->channel_name);
754 chanrec = silc_channel_create(server, channel->channel_name,
755 channel->channel_name, TRUE);
756 if (!chanrec->joined)
757 chanrec->entry = channel;
759 chanrec = silc_channel_find_entry(server, channel);
760 if (chanrec != NULL) {
761 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
763 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
767 memset(buf, 0, sizeof(buf));
768 if (client_entry->username[0])
769 snprintf(buf, sizeof(buf) - 1, "%s@%s",
770 client_entry->username, client_entry->hostname);
771 signal_emit("message join", 4, server, channel->channel_name,
772 client_entry->nickname,
773 !client_entry->username[0] ? "" : buf);
775 /* If there are multiple same nicknames on channel now, tell it to user. */
776 if (client_entry != server->conn->local_entry) {
780 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
781 clients = silc_client_get_clients_local(client, conn, nick, TRUE);
782 if (!clients || silc_dlist_count(clients) < 2) {
784 silc_client_list_free(client, conn, clients);
787 silc_dlist_start(clients);
788 while ((client_entry2 = silc_dlist_get(clients)))
789 if (silc_client_on_channel(channel, client_entry2))
792 silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
793 printformat_module("fe-common/silc", server, channel->channel_name,
794 MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
796 printformat_module("fe-common/silc", server, channel->channel_name,
797 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
798 buf, client_entry->nickname);
800 silc_client_list_free(client, conn, clients);
805 case SILC_NOTIFY_TYPE_LEAVE:
810 SILC_LOG_DEBUG(("Notify: LEAVE"));
812 client_entry = va_arg(va, SilcClientEntry);
813 channel = va_arg(va, SilcChannelEntry);
815 memset(buf, 0, sizeof(buf));
816 if (client_entry->username)
817 snprintf(buf, sizeof(buf) - 1, "%s@%s",
818 client_entry->username, client_entry->hostname);
819 signal_emit("message part", 5, server, channel->channel_name,
820 client_entry->nickname, client_entry->username[0] ?
821 buf : "", client_entry->nickname);
823 chanrec = silc_channel_find_entry(server, channel);
824 if (chanrec != NULL) {
825 nickrec = silc_nicklist_find(chanrec, client_entry);
827 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
830 /* If there is only one client with this same nickname on channel now
831 change it to the base format if it is formatted nickname. */
833 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
834 clients = silc_client_get_clients_local(client, conn, name, TRUE);
835 if (!clients || silc_dlist_count(clients) != 2) {
837 silc_client_list_free(client, conn, clients);
840 silc_dlist_start(clients);
841 client_entry2 = silc_dlist_get(clients);
842 if (client_entry2 == client_entry)
843 client_entry2 = silc_dlist_get(clients);
844 if (silc_client_on_channel(channel, client_entry2)) {
845 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
846 silc_client_nickname_format(client, conn, client_entry2, TRUE);
847 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
848 nicklist_rename_unique(SERVER(server), client_entry2, buf,
849 client_entry2, client_entry2->nickname);
850 printformat_module("fe-common/silc", server, channel->channel_name,
851 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
852 buf, client_entry2->nickname);
855 silc_client_list_free(client, conn, clients);
860 case SILC_NOTIFY_TYPE_SIGNOFF:
865 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
867 client_entry = va_arg(va, SilcClientEntry);
868 tmp = va_arg(va, char *);
869 channel = va_arg(va, SilcChannelEntry);
871 silc_server_free_ftp(server, client_entry);
873 memset(buf, 0, sizeof(buf));
874 if (client_entry->username)
875 snprintf(buf, sizeof(buf) - 1, "%s@%s",
876 client_entry->username, client_entry->hostname);
877 signal_emit("message quit", 4, server, client_entry->nickname,
878 client_entry->username[0] ? buf : "", tmp ? tmp : "");
880 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
881 for (list_tmp = list1; list_tmp != NULL; list_tmp =
882 list_tmp->next->next) {
883 CHANNEL_REC *channel = list_tmp->data;
884 NICK_REC *nickrec = list_tmp->next->data;
886 nicklist_remove(channel, nickrec);
889 /* If there is only one client with this same nickname on channel now
890 change it to the base format if it is formatted nickname. */
892 silc_client_nickname_parse(client, conn, client_entry->nickname, &name);
893 clients = silc_client_get_clients_local(client, conn, name, TRUE);
894 if (!clients || silc_dlist_count(clients) != 2) {
896 silc_client_list_free(client, conn, clients);
899 silc_dlist_start(clients);
900 client_entry2 = silc_dlist_get(clients);
901 if (client_entry2 == client_entry)
902 client_entry2 = silc_dlist_get(clients);
903 if (silc_client_on_channel(channel, client_entry2)) {
904 silc_snprintf(buf, sizeof(buf), "%s", client_entry2->nickname);
905 silc_client_nickname_format(client, conn, client_entry2, TRUE);
906 if (!silc_utf8_strcasecmp(buf, client_entry2->nickname)) {
907 nicklist_rename_unique(SERVER(server), client_entry2, buf,
908 client_entry2, client_entry2->nickname);
909 printformat_module("fe-common/silc", server, channel->channel_name,
910 MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
911 buf, client_entry2->nickname);
914 silc_client_list_free(client, conn, clients);
919 case SILC_NOTIFY_TYPE_TOPIC_SET:
924 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
926 idtype = va_arg(va, int);
927 entry = va_arg(va, void *);
928 tmp = va_arg(va, char *);
929 channel = va_arg(va, SilcChannelEntry);
931 chanrec = silc_channel_find_entry(server, channel);
932 if (chanrec != NULL) {
933 char tmp2[256], *cp, *dm = NULL;
935 g_free_not_null(chanrec->topic);
936 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
937 memset(tmp2, 0, sizeof(tmp2));
939 if (strlen(tmp) > sizeof(tmp2) - 1) {
940 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
944 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
949 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
950 signal_emit("channel topic changed", 1, chanrec);
955 if (idtype == SILC_ID_CLIENT) {
956 client_entry = (SilcClientEntry)entry;
957 memset(buf, 0, sizeof(buf));
958 snprintf(buf, sizeof(buf) - 1, "%s@%s",
959 client_entry->username, client_entry->hostname);
960 signal_emit("message topic", 5, server, channel->channel_name,
961 tmp, client_entry->nickname, buf);
962 } else if (idtype == SILC_ID_SERVER) {
963 server_entry = (SilcServerEntry)entry;
964 signal_emit("message topic", 5, server, channel->channel_name,
965 tmp, server_entry->server_name,
966 server_entry->server_name);
967 } else if (idtype == SILC_ID_CHANNEL) {
968 channel = (SilcChannelEntry)entry;
969 signal_emit("message topic", 5, server, channel->channel_name,
970 tmp, channel->channel_name, channel->channel_name);
974 case SILC_NOTIFY_TYPE_NICK_CHANGE:
979 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
981 client_entry = va_arg(va, SilcClientEntry);
982 name = va_arg(va, char *); /* old nickname */
984 if (!strcmp(client_entry->nickname, name))
987 memset(buf, 0, sizeof(buf));
988 snprintf(buf, sizeof(buf) - 1, "%s@%s",
989 client_entry->username, client_entry->hostname);
990 nicklist_rename_unique(SERVER(server),
992 client_entry, client_entry->nickname);
993 signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
996 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
998 * Changed channel mode.
1001 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
1003 idtype = va_arg(va, int);
1004 entry = va_arg(va, void *);
1005 mode = va_arg(va, SilcUInt32);
1006 cipher = va_arg(va, char *); /* cipher */
1007 hmac = va_arg(va, char *); /* hmac */
1008 (void)va_arg(va, char *); /* passphrase */
1009 (void)va_arg(va, SilcPublicKey); /* founder key */
1010 chpks = va_arg(va, SilcDList); /* channel public keys */
1011 channel = va_arg(va, SilcChannelEntry);
1013 tmp = silc_client_chmode(mode, cipher ? cipher : "",
1016 chanrec = silc_channel_find_entry(server, channel);
1017 if (chanrec != NULL) {
1018 g_free_not_null(chanrec->mode);
1019 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
1020 signal_emit("channel mode changed", 1, chanrec);
1023 if (idtype == SILC_ID_CLIENT) {
1024 client_entry = (SilcClientEntry)entry;
1025 printformat_module("fe-common/silc", server, channel->channel_name,
1026 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1027 channel->channel_name, tmp ? tmp : "removed all",
1028 client_entry->nickname);
1029 } else if (idtype == SILC_ID_SERVER) {
1030 server_entry = (SilcServerEntry)entry;
1031 printformat_module("fe-common/silc", server, channel->channel_name,
1032 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
1033 channel->channel_name, tmp ? tmp : "removed all",
1034 server_entry->server_name);
1035 } else if (idtype == SILC_ID_CHANNEL) {
1036 channel2 = (SilcChannelEntry)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 channel2->channel_name);
1043 /* Print the channel public key list */
1045 silc_parse_channel_public_keys(server, channel, chpks);
1050 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
1052 * Changed user's mode on channel.
1055 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
1057 idtype = va_arg(va, int);
1058 entry = va_arg(va, void *);
1059 mode = va_arg(va, SilcUInt32);
1060 client_entry2 = va_arg(va, SilcClientEntry);
1061 channel = va_arg(va, SilcChannelEntry);
1063 tmp = silc_client_chumode(mode);
1064 chanrec = silc_channel_find_entry(server, channel);
1065 if (chanrec != NULL) {
1066 SILC_NICK_REC *nick;
1068 if (client_entry2 == server->conn->local_entry)
1069 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1071 nick = silc_nicklist_find(chanrec, client_entry2);
1073 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
1074 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
1075 signal_emit("nick mode changed", 2, chanrec, nick);
1079 if (idtype == SILC_ID_CLIENT) {
1080 client_entry = (SilcClientEntry)entry;
1081 printformat_module("fe-common/silc", server, channel->channel_name,
1082 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1083 channel->channel_name, client_entry2->nickname,
1084 tmp ? tmp : "removed all",
1085 client_entry->nickname);
1086 } else if (idtype == SILC_ID_SERVER) {
1087 server_entry = (SilcServerEntry)entry;
1088 printformat_module("fe-common/silc", server, channel->channel_name,
1089 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1090 channel->channel_name, client_entry2->nickname,
1091 tmp ? tmp : "removed all",
1092 server_entry->server_name);
1093 } else if (idtype == SILC_ID_CHANNEL) {
1094 channel2 = (SilcChannelEntry)entry;
1095 printformat_module("fe-common/silc", server, channel->channel_name,
1096 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
1097 channel->channel_name, client_entry2->nickname,
1098 tmp ? tmp : "removed all",
1099 channel2->channel_name);
1102 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1103 printformat_module("fe-common/silc",
1104 server, channel->channel_name, MSGLEVEL_CRAP,
1105 SILCTXT_CHANNEL_FOUNDER,
1106 channel->channel_name, client_entry2->nickname);
1108 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1109 printformat_module("fe-common/silc",
1110 server, channel->channel_name, MSGLEVEL_CRAP,
1111 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1116 case SILC_NOTIFY_TYPE_MOTD:
1121 SILC_LOG_DEBUG(("Notify: MOTD"));
1123 tmp = va_arg(va, char *);
1125 if (!settings_get_bool("skip_motd"))
1126 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1129 case SILC_NOTIFY_TYPE_KICKED:
1131 * Someone was kicked from channel.
1134 SILC_LOG_DEBUG(("Notify: KICKED"));
1136 client_entry = va_arg(va, SilcClientEntry);
1137 tmp = va_arg(va, char *);
1138 client_entry2 = va_arg(va, SilcClientEntry);
1139 channel = va_arg(va, SilcChannelEntry);
1141 chanrec = silc_channel_find_entry(server, channel);
1143 if (client_entry == conn->local_entry) {
1144 printformat_module("fe-common/silc", server, channel->channel_name,
1145 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1146 channel->channel_name,
1147 client_entry ? client_entry2->nickname : "",
1150 chanrec->kicked = TRUE;
1151 channel_destroy((CHANNEL_REC *)chanrec);
1154 printformat_module("fe-common/silc", server, channel->channel_name,
1155 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1156 client_entry->nickname, channel->channel_name,
1157 client_entry2 ? client_entry2->nickname : "",
1161 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1162 if (nickrec != NULL)
1163 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1168 case SILC_NOTIFY_TYPE_KILLED:
1170 * Someone was killed from the network.
1173 SILC_LOG_DEBUG(("Notify: KILLED"));
1175 client_entry = va_arg(va, SilcClientEntry);
1176 tmp = va_arg(va, char *);
1177 idtype = va_arg(va, int);
1178 entry = va_arg(va, SilcClientEntry);
1180 if (client_entry == conn->local_entry) {
1181 if (idtype == SILC_ID_CLIENT) {
1182 client_entry2 = (SilcClientEntry)entry;
1183 printformat_module("fe-common/silc", server, NULL,
1184 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1185 client_entry2 ? client_entry2->nickname : "",
1187 } else if (idtype == SILC_ID_SERVER) {
1188 server_entry = (SilcServerEntry)entry;
1189 printformat_module("fe-common/silc", server, NULL,
1190 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1191 server_entry->server_name, tmp ? tmp : "");
1192 } else if (idtype == SILC_ID_CHANNEL) {
1193 channel = (SilcChannelEntry)entry;
1194 printformat_module("fe-common/silc", server, NULL,
1195 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1196 channel->channel_name, tmp ? tmp : "");
1199 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1200 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1201 list_tmp->next->next) {
1202 CHANNEL_REC *channel = list_tmp->data;
1203 NICK_REC *nickrec = list_tmp->next->data;
1204 nicklist_remove(channel, nickrec);
1207 if (idtype == SILC_ID_CLIENT) {
1208 client_entry2 = (SilcClientEntry)entry;
1209 printformat_module("fe-common/silc", server, NULL,
1210 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1211 client_entry->nickname,
1212 client_entry2 ? client_entry2->nickname : "",
1214 } else if (idtype == SILC_ID_SERVER) {
1215 server_entry = (SilcServerEntry)entry;
1216 printformat_module("fe-common/silc", server, NULL,
1217 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1218 client_entry->nickname,
1219 server_entry->server_name, tmp ? tmp : "");
1220 } else if (idtype == SILC_ID_CHANNEL) {
1221 channel = (SilcChannelEntry)entry;
1222 printformat_module("fe-common/silc", server, NULL,
1223 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1224 client_entry->nickname,
1225 channel->channel_name, tmp ? tmp : "");
1230 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1233 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1236 * Server has quit the network.
1240 SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1242 (void)va_arg(va, void *);
1243 clients = va_arg(va, SilcDList);
1245 silc_dlist_start(clients);
1246 while ((client_entry = silc_dlist_get(clients))) {
1247 memset(buf, 0, sizeof(buf));
1249 /* Print only if we have the nickname. If this client has just quit
1250 when we were only resolving it, it is possible we don't have the
1252 if (client_entry->nickname[0]) {
1253 if (client_entry->username[0])
1254 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1255 client_entry->username, client_entry->hostname);
1256 signal_emit("message quit", 4, server, client_entry->nickname,
1257 client_entry->username[0] ? buf : "",
1261 silc_server_free_ftp(server, client_entry);
1263 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1264 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1265 list_tmp->next->next) {
1266 CHANNEL_REC *channel = list_tmp->data;
1267 NICK_REC *nickrec = list_tmp->next->data;
1268 nicklist_remove(channel, nickrec);
1274 case SILC_NOTIFY_TYPE_ERROR:
1276 SilcStatus error = va_arg(va, int);
1278 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1279 "%s", silc_get_status_message(error));
1283 case SILC_NOTIFY_TYPE_WATCH:
1285 SilcNotifyType notify;
1287 client_entry = va_arg(va, SilcClientEntry);
1288 name = va_arg(va, char *); /* Maybe NULL */
1289 mode = va_arg(va, SilcUInt32);
1290 notify = va_arg(va, int);
1292 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1294 printformat_module("fe-common/silc", server, NULL,
1295 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1296 client_entry->nickname, name);
1298 printformat_module("fe-common/silc", server, NULL,
1299 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1300 client_entry->nickname);
1301 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1302 /* See if client was away and is now present */
1303 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1304 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1305 SILC_UMODE_DETACHED)) &&
1306 (client_entry->mode & SILC_UMODE_GONE ||
1307 client_entry->mode & SILC_UMODE_INDISPOSED ||
1308 client_entry->mode & SILC_UMODE_BUSY ||
1309 client_entry->mode & SILC_UMODE_PAGE ||
1310 client_entry->mode & SILC_UMODE_DETACHED)) {
1311 printformat_module("fe-common/silc", server, NULL,
1312 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1313 client_entry->nickname);
1317 memset(buf, 0, sizeof(buf));
1318 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1319 printformat_module("fe-common/silc", server, NULL,
1320 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1321 client_entry->nickname, buf);
1323 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1324 printformat_module("fe-common/silc", server, NULL,
1325 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1326 client_entry->nickname);
1327 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1328 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1329 printformat_module("fe-common/silc", server, NULL,
1330 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1331 client_entry->nickname);
1332 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1333 /* Client logged in to the network */
1334 printformat_module("fe-common/silc", server, NULL,
1335 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1336 client_entry->nickname);
1342 /* Unknown notify */
1343 printformat_module("fe-common/silc", server, NULL,
1344 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1351 /* Command handler. This function is called always in the command function.
1352 If error occurs it will be called as well. `conn' is the associated
1353 client connection. `cmd_context' is the command context that was
1354 originally sent to the command. `success' is FALSE if error occured
1355 during command. `command' is the command being processed. It must be
1356 noted that this is not reply from server. This is merely called just
1357 after application has called the command. Just to tell application
1358 that the command really was processed. */
1360 static SilcBool cmode_list_chpks = FALSE;
1362 void silc_command(SilcClient client, SilcClientConnection conn,
1363 SilcBool success, SilcCommand command, SilcStatus status,
1364 SilcUInt32 argc, unsigned char **argv)
1366 SILC_SERVER_REC *server = conn->context;
1368 SILC_LOG_DEBUG(("Start"));
1371 silc_say_error("%s", silc_get_status_message(status));
1377 case SILC_COMMAND_INVITE:
1379 printformat_module("fe-common/silc", server, NULL,
1380 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1382 (argv[1][0] == '*' ?
1383 (char *)conn->current_channel->channel_name :
1387 case SILC_COMMAND_DETACH:
1388 server->no_reconnect = TRUE;
1391 case SILC_COMMAND_CMODE:
1392 if (argc == 3 && !strcmp(argv[2], "+C"))
1393 cmode_list_chpks = TRUE;
1395 cmode_list_chpks = FALSE;
1405 SilcClientConnection conn;
1410 void silc_getkey_cb(bool success, void *context)
1412 GetkeyContext getkey = (GetkeyContext)context;
1413 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1414 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1415 ((SilcClientEntry)getkey->entry)->nickname :
1416 ((SilcServerEntry)getkey->entry)->server_name);
1417 SilcPublicKey public_key = (getkey->id_type == SILC_ID_CLIENT ?
1418 ((SilcClientEntry)getkey->entry)->public_key :
1419 ((SilcServerEntry)getkey->entry)->public_key);
1420 SilcSILCPublicKey silc_pubkey;
1422 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1425 if (getkey->id_type == SILC_ID_CLIENT)
1426 printformat_module("fe-common/silc", NULL, NULL,
1427 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED_CLIENT,
1429 silc_pubkey->identifier.realname ?
1430 silc_pubkey->identifier.realname : "",
1431 silc_pubkey->identifier.email ?
1432 silc_pubkey->identifier.email : "");
1434 printformat_module("fe-common/silc", NULL, NULL,
1435 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED,
1438 printformat_module("fe-common/silc", NULL, NULL,
1439 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1444 * Drop our references as need be.
1446 switch (getkey->id_type) {
1447 case SILC_ID_CLIENT:
1448 silc_client_unref_client(getkey->client, getkey->conn,
1449 (SilcClientEntry)getkey->entry);
1452 case SILC_ID_SERVER:
1453 silc_client_unref_server(getkey->client, getkey->conn,
1454 (SilcServerEntry)getkey->entry);
1461 /* Parse an invite or ban list */
1462 void silc_parse_inviteban_list(SilcClient client,
1463 SilcClientConnection conn,
1464 SILC_SERVER_REC *server,
1465 SilcChannelEntry channel,
1466 const char *list_type,
1467 SilcArgumentPayload list)
1470 SilcUInt32 type, len;
1471 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1472 int counter=0, resolving = FALSE;
1474 if (!silc_argument_get_arg_num(list)) {
1475 printformat_module("fe-common/silc", server,
1476 (chanrec ? chanrec->visible_name : NULL),
1477 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1478 channel->channel_name, list_type);
1482 printformat_module("fe-common/silc", server,
1483 (chanrec ? chanrec->visible_name : NULL),
1484 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1485 channel->channel_name, list_type);
1487 /* Parse the list */
1488 tmp = silc_argument_get_first_arg(list, &type, &len);
1493 /* An invite string */
1497 if (tmp[len-1] == ',')
1500 list = g_strsplit(tmp, ",", -1);
1502 printformat_module("fe-common/silc", server,
1503 (chanrec ? chanrec->visible_name : NULL),
1504 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1505 ++counter, channel->channel_name, list_type,
1514 char *fingerprint, *babbleprint;
1516 /* tmp is Public Key Payload, take public key from it. */
1517 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1518 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1520 printformat_module("fe-common/silc", server,
1521 (chanrec ? chanrec->visible_name : NULL),
1522 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1523 ++counter, channel->channel_name, list_type,
1524 fingerprint, babbleprint);
1531 SilcClientEntry client_entry;
1534 if (!silc_id_payload_parse_id(tmp, len, &id)) {
1535 silc_say_error("Invalid data in %s list encountered", list_type);
1539 client_entry = silc_client_get_client_by_id(client, conn,
1542 printformat_module("fe-common/silc", server,
1543 (chanrec ? chanrec->visible_name : NULL),
1544 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1545 ++counter, channel->channel_name, list_type,
1546 client_entry->nickname);
1547 silc_client_unref_client(client, conn, client_entry);
1550 silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
1558 silc_say_error("Unkown type in %s list: %u (len %u)",
1559 list_type, type, len);
1562 tmp = silc_argument_get_next_arg(list, &type, &len);
1566 printformat_module("fe-common/silc", server,
1567 (chanrec ? chanrec->visible_name : NULL),
1568 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1569 list_type, channel->channel_name);
1572 /* Command reply handler. This function is called always in the command reply
1573 function. If error occurs it will be called as well. Normal scenario
1574 is that it will be called after the received command data has been parsed
1575 and processed. The function is used to pass the received command data to
1578 `conn' is the associated client connection. `cmd_payload' is the command
1579 payload data received from server and it can be ignored. It is provided
1580 if the application would like to re-parse the received command data,
1581 however, it must be noted that the data is parsed already by the library
1582 thus the payload can be ignored. `success' is FALSE if error occured.
1583 In this case arguments are not sent to the application. `command' is the
1584 command reply being processed. The function has variable argument list
1585 and each command defines the number and type of arguments it passes to the
1586 application (on error they are not sent). */
1588 void silc_command_reply(SilcClient client, SilcClientConnection conn,
1589 SilcCommand command, SilcStatus status,
1590 SilcStatus error, va_list vp)
1592 SILC_SERVER_REC *server = conn->context;
1593 SILC_CHANNEL_REC *chanrec;
1595 SILC_LOG_DEBUG(("Start"));
1598 case SILC_COMMAND_WHOIS:
1600 char buf[1024], *nickname, *username, *realname, *nick;
1601 unsigned char *fingerprint;
1602 SilcUInt32 idle, mode, *user_modes;
1604 SilcClientEntry client_entry;
1607 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1608 /* Print the unknown nick for user */
1609 char *tmp = va_arg(vp, char *);
1611 silc_say_error("%s: %s", tmp, silc_get_status_message(status));
1613 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1614 /* Try to find the entry for the unknown client ID, since we
1615 might have, and print the nickname of it for user. */
1616 SilcClientID *id = va_arg(vp, SilcClientID *);
1618 client_entry = silc_client_get_client_by_id(client, conn, id);
1619 if (client_entry && client_entry->nickname[0])
1620 silc_say_error("%s: %s", client_entry->nickname,
1621 silc_get_status_message(status));
1622 silc_client_unref_client(client, conn, client_entry);
1625 } else if (SILC_STATUS_IS_ERROR(status)) {
1626 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1630 client_entry = va_arg(vp, SilcClientEntry);
1631 nickname = va_arg(vp, char *);
1632 username = va_arg(vp, char *);
1633 realname = va_arg(vp, char *);
1634 channels = va_arg(vp, SilcDList);
1635 mode = va_arg(vp, SilcUInt32);
1636 idle = va_arg(vp, SilcUInt32);
1637 fingerprint = va_arg(vp, unsigned char *);
1638 user_modes = va_arg(vp, SilcUInt32 *);
1639 attrs = va_arg(vp, SilcDList);
1641 silc_client_nickname_parse(client, conn, client_entry->nickname, &nick);
1642 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1643 SILCTXT_WHOIS_USERINFO, nickname,
1644 client_entry->username, client_entry->hostname,
1645 nick, client_entry->nickname);
1646 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1647 SILCTXT_WHOIS_REALNAME, realname);
1650 if (channels && user_modes) {
1651 SilcChannelPayload entry;
1654 memset(buf, 0, sizeof(buf));
1655 silc_dlist_start(channels);
1656 while ((entry = silc_dlist_get(channels))) {
1657 SilcUInt32 name_len;
1658 char *m = silc_client_chumode_char(user_modes[i++]);
1659 char *name = silc_channel_get_name(entry, &name_len);
1662 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1663 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1664 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1668 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1669 SILCTXT_WHOIS_CHANNELS, buf);
1673 memset(buf, 0, sizeof(buf));
1674 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1675 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1676 SILCTXT_WHOIS_MODES, buf);
1679 if (idle && nickname) {
1680 memset(buf, 0, sizeof(buf));
1681 snprintf(buf, sizeof(buf) - 1, "%u %s",
1682 idle > 60 ? (idle / 60) : idle,
1683 idle > 60 ? "minutes" : "seconds");
1685 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1686 SILCTXT_WHOIS_IDLE, buf);
1690 fingerprint = silc_fingerprint(fingerprint, 20);
1691 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1692 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1693 silc_free(fingerprint);
1697 silc_query_attributes_print(server, silc_client, conn, attrs,
1702 case SILC_COMMAND_WHOWAS:
1704 char *nickname, *username, *realname;
1706 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1707 char *tmp = va_arg(vp, char *);
1709 silc_say_error("%s: %s", tmp,
1710 silc_get_status_message(status));
1712 } else if (SILC_STATUS_IS_ERROR(status)) {
1713 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1717 (void)va_arg(vp, SilcClientEntry);
1718 nickname = va_arg(vp, char *);
1719 username = va_arg(vp, char *);
1720 realname = va_arg(vp, char *);
1722 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1723 SILCTXT_WHOWAS_USERINFO, nickname, username,
1724 realname ? realname : "");
1728 case SILC_COMMAND_INVITE:
1730 SilcChannelEntry channel;
1731 SilcArgumentPayload invite_list;
1733 if (SILC_STATUS_IS_ERROR(status))
1736 channel = va_arg(vp, SilcChannelEntry);
1737 invite_list = va_arg(vp, SilcArgumentPayload);
1740 silc_parse_inviteban_list(client, conn, server, channel,
1741 "invite", invite_list);
1745 case SILC_COMMAND_JOIN:
1747 char *channel, *mode, *topic, *cipher, *hmac;
1749 SilcHashTableList *user_list;
1750 SilcChannelEntry channel_entry;
1751 SilcChannelUser chu;
1752 SilcClientEntry founder = NULL;
1755 if (SILC_STATUS_IS_ERROR(status)) {
1756 if (status == SILC_STATUS_ERR_NO_SUCH_SERVER) {
1757 char *tmp = va_arg(vp, char *);
1759 silc_say_error("JOIN: %s: %s", tmp,
1760 silc_get_status_message(status));
1763 if (status == SILC_STATUS_ERR_NO_SUCH_CHANNEL) {
1764 char *tmp = va_arg(vp, char *);
1766 silc_say_error("JOIN: %s: %s", tmp,
1767 silc_get_status_message(status));
1770 silc_say_error("JOIN: %s", silc_get_status_message(status));
1774 channel = va_arg(vp, char *);
1775 channel_entry = va_arg(vp, SilcChannelEntry);
1776 modei = va_arg(vp, SilcUInt32);
1777 user_list = va_arg(vp, SilcHashTableList *);
1778 topic = va_arg(vp, char *);
1779 cipher = va_arg(vp, char *);
1780 hmac = va_arg(vp, char *);
1782 chanrec = silc_channel_find(server, channel);
1784 chanrec = silc_channel_create(server, channel, channel, TRUE);
1787 char tmp[256], *cp, *dm = NULL;
1788 g_free_not_null(chanrec->topic);
1790 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1791 memset(tmp, 0, sizeof(tmp));
1793 if (strlen(topic) > sizeof(tmp) - 1) {
1794 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1798 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1803 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1804 signal_emit("channel topic changed", 1, chanrec);
1809 mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
1810 g_free_not_null(chanrec->mode);
1811 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1812 signal_emit("channel mode changed", 1, chanrec);
1815 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1816 if (!chu->client->nickname[0])
1818 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1819 founder = chu->client;
1820 silc_nicklist_insert(chanrec, chu, FALSE);
1823 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1826 nicklist_set_own(CHANNEL(chanrec), ownnick);
1827 chanrec->entry = channel_entry;
1828 signal_emit("channel joined", 1, chanrec);
1831 printformat_module("fe-common/silc", server,
1832 channel_entry->channel_name,
1833 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1834 channel_entry->channel_name, chanrec->topic);
1837 if (founder == conn->local_entry) {
1838 printformat_module("fe-common/silc",
1839 server, channel_entry->channel_name,
1840 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
1841 channel_entry->channel_name);
1842 signal_emit("nick mode changed", 2, chanrec, ownnick);
1844 printformat_module("fe-common/silc",
1845 server, channel_entry->channel_name,
1846 MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
1847 channel_entry->channel_name, founder->nickname);
1853 case SILC_COMMAND_NICK:
1856 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1859 if (SILC_STATUS_IS_ERROR(status)) {
1860 silc_say_error("NICK: %s", silc_get_status_message(status));
1864 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1865 if ((nicks != NULL) &&
1866 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1868 SilcClientEntry collider, old;
1870 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1871 collider = silc_client_get_client_by_id(client, conn, &old->id);
1872 if (collider != client_entry) {
1873 memset(buf, 0, sizeof(buf));
1874 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1875 collider->username, collider->hostname);
1876 nicklist_rename_unique(SERVER(server),
1878 collider, collider->nickname);
1879 silc_print_nick_change(server, collider->nickname,
1880 client_entry->nickname, buf);
1882 silc_client_unref_client(client, conn, collider);
1886 g_slist_free(nicks);
1888 old = g_strdup(server->nick);
1889 server_change_nick(SERVER(server), client_entry->nickname);
1890 nicklist_rename_unique(SERVER(server),
1891 server->conn->local_entry, server->nick,
1892 client_entry, client_entry->nickname);
1893 signal_emit("message own_nick", 4, server, server->nick, old, "");
1896 /* when connecting to a server, the last thing we receive
1897 is a SILC_COMMAND_LIST reply. Since we enable queueing
1898 during the connection, we can now safely disable it again */
1899 silc_queue_disable(conn);
1903 case SILC_COMMAND_LIST:
1908 char tmp[256], *cp, *dm = NULL;
1910 if (SILC_STATUS_IS_ERROR(status))
1913 (void)va_arg(vp, SilcChannelEntry);
1914 name = va_arg(vp, char *);
1915 topic = va_arg(vp, char *);
1916 usercount = va_arg(vp, int);
1918 if (topic && !silc_term_utf8() &&
1919 silc_utf8_valid(topic, strlen(topic))) {
1920 memset(tmp, 0, sizeof(tmp));
1922 if (strlen(topic) > sizeof(tmp) - 1) {
1923 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1927 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
1932 if (status == SILC_STATUS_LIST_START ||
1933 status == SILC_STATUS_OK)
1934 printformat_module("fe-common/silc", server, NULL,
1935 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1938 snprintf(users, sizeof(users) - 1, "N/A");
1940 snprintf(users, sizeof(users) - 1, "%d", usercount);
1941 printformat_module("fe-common/silc", server, NULL,
1942 MSGLEVEL_CRAP, SILCTXT_LIST,
1943 name, users, topic ? topic : "");
1948 case SILC_COMMAND_UMODE:
1953 if (SILC_STATUS_IS_ERROR(status))
1956 mode = va_arg(vp, SilcUInt32);
1958 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1959 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1960 printformat_module("fe-common/silc", server, NULL,
1961 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1963 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1964 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1965 printformat_module("fe-common/silc", server, NULL,
1966 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1968 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1969 if (mode & SILC_UMODE_GONE) {
1970 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1971 reason = g_strdup(server->away_reason);
1973 reason = g_strdup("away");
1975 reason = g_strdup("");
1977 silc_set_away(reason, server);
1982 server->umode = mode;
1983 signal_emit("user mode changed", 2, server, NULL);
1987 case SILC_COMMAND_OPER:
1988 if (SILC_STATUS_IS_ERROR(status)) {
1989 silc_say_error("OPER: %s", silc_get_status_message(status));
1993 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1994 signal_emit("user mode changed", 2, server, NULL);
1996 printformat_module("fe-common/silc", server, NULL,
1997 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2000 case SILC_COMMAND_SILCOPER:
2001 if (SILC_STATUS_IS_ERROR(status)) {
2002 silc_say_error("SILCOPER: %s", silc_get_status_message(status));
2006 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2007 signal_emit("user mode changed", 2, server, NULL);
2009 printformat_module("fe-common/silc", server, NULL,
2010 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2013 case SILC_COMMAND_USERS:
2015 SilcHashTableList htl;
2016 SilcChannelEntry channel;
2017 SilcChannelUser chu;
2019 if (SILC_STATUS_IS_ERROR(status)) {
2020 silc_say_error("USERS: %s", silc_get_status_message(status));
2024 channel = va_arg(vp, SilcChannelEntry);
2026 printformat_module("fe-common/silc", server, channel->channel_name,
2027 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2028 channel->channel_name);
2030 silc_hash_table_list(channel->user_list, &htl);
2031 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2032 SilcClientEntry e = chu->client;
2033 char stat[5], *mode;
2035 if (!e->nickname[0])
2038 memset(stat, 0, sizeof(stat));
2039 mode = silc_client_chumode_char(chu->mode);
2040 if (e->mode & SILC_UMODE_GONE)
2042 else if (e->mode & SILC_UMODE_INDISPOSED)
2044 else if (e->mode & SILC_UMODE_BUSY)
2046 else if (e->mode & SILC_UMODE_PAGE)
2048 else if (e->mode & SILC_UMODE_HYPER)
2050 else if (e->mode & SILC_UMODE_ROBOT)
2052 else if (e->mode & SILC_UMODE_ANONYMOUS)
2059 printformat_module("fe-common/silc", server, channel->channel_name,
2060 MSGLEVEL_CRAP, SILCTXT_USERS,
2062 e->username[0] ? e->username : "",
2063 e->hostname[0] ? e->hostname : "",
2064 e->realname ? e->realname : "");
2068 silc_hash_table_list_reset(&htl);
2072 case SILC_COMMAND_BAN:
2074 SilcChannelEntry channel;
2075 SilcArgumentPayload invite_list;
2077 if (SILC_STATUS_IS_ERROR(status))
2080 channel = va_arg(vp, SilcChannelEntry);
2081 invite_list = va_arg(vp, SilcArgumentPayload);
2084 silc_parse_inviteban_list(client, conn, server, channel,
2085 "ban", invite_list);
2089 case SILC_COMMAND_GETKEY:
2093 SilcPublicKey public_key;
2094 GetkeyContext getkey;
2097 if (SILC_STATUS_IS_ERROR(status)) {
2098 silc_say_error("GETKEY: %s", silc_get_status_message(status));
2102 id_type = va_arg(vp, SilcUInt32);
2103 entry = va_arg(vp, void *);
2104 public_key = va_arg(vp, SilcPublicKey);
2107 getkey = silc_calloc(1, sizeof(*getkey));
2108 getkey->entry = entry;
2109 getkey->id_type = id_type;
2110 getkey->client = client;
2111 getkey->conn = conn;
2113 name = (id_type == SILC_ID_CLIENT ?
2114 ((SilcClientEntry)entry)->nickname :
2115 ((SilcServerEntry)entry)->server_name);
2118 case SILC_ID_CLIENT:
2119 name = ((SilcClientEntry)entry)->nickname;
2120 silc_client_ref_client(client, conn, (SilcClientEntry)entry);
2123 case SILC_ID_SERVER:
2124 name = ((SilcServerEntry)entry)->server_name;
2125 silc_client_ref_server(client, conn, (SilcServerEntry)entry);
2129 silc_verify_public_key_internal(client, conn, name,
2130 (id_type == SILC_ID_CLIENT ?
2133 public_key, silc_getkey_cb, getkey);
2135 printformat_module("fe-common/silc", server, NULL,
2136 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2141 case SILC_COMMAND_INFO:
2143 SilcServerEntry server_entry;
2147 if (SILC_STATUS_IS_ERROR(status))
2150 server_entry = va_arg(vp, SilcServerEntry);
2151 server_name = va_arg(vp, char *);
2152 server_info = va_arg(vp, char *);
2154 if (server_name && server_info )
2156 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2157 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2162 case SILC_COMMAND_TOPIC:
2164 SilcChannelEntry channel;
2166 char tmp[256], *cp, *dm = NULL;
2168 if (SILC_STATUS_IS_ERROR(status))
2171 channel = va_arg(vp, SilcChannelEntry);
2172 topic = va_arg(vp, char *);
2174 if (topic && !silc_term_utf8() &&
2175 silc_utf8_valid(topic, strlen(topic))) {
2176 memset(tmp, 0, sizeof(tmp));
2178 if (strlen(topic) > sizeof(tmp) - 1) {
2179 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2183 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LOCALE,
2189 chanrec = silc_channel_find_entry(server, channel);
2191 g_free_not_null(chanrec->topic);
2192 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2193 signal_emit("channel topic changed", 1, chanrec);
2195 printformat_module("fe-common/silc", server, channel->channel_name,
2196 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2197 channel->channel_name, topic);
2199 printformat_module("fe-common/silc", server, channel->channel_name,
2200 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2201 channel->channel_name);
2207 case SILC_COMMAND_WATCH:
2210 case SILC_COMMAND_STATS:
2212 SilcClientStats *cstats;
2214 const char *tmptime;
2215 int days, hours, mins, secs;
2217 if (SILC_STATUS_IS_ERROR(status))
2220 cstats = va_arg(vp, SilcClientStats *);
2222 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2226 tmptime = silc_time_string(cstats->starttime);
2227 printformat_module("fe-common/silc", server, NULL,
2228 MSGLEVEL_CRAP, SILCTXT_STATS,
2229 "Local server start time", tmptime);
2231 days = cstats->uptime / (24 * 60 * 60);
2232 cstats->uptime -= days * (24 * 60 * 60);
2233 hours = cstats->uptime / (60 * 60);
2234 cstats->uptime -= hours * (60 * 60);
2235 mins = cstats->uptime / 60;
2236 cstats->uptime -= mins * 60;
2237 secs = cstats->uptime;
2238 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2239 days, hours, mins, secs);
2240 printformat_module("fe-common/silc", server, NULL,
2241 MSGLEVEL_CRAP, SILCTXT_STATS,
2242 "Local server uptime", tmp);
2244 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
2245 printformat_module("fe-common/silc", server, NULL,
2246 MSGLEVEL_CRAP, SILCTXT_STATS,
2247 "Local server clients", tmp);
2249 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
2250 printformat_module("fe-common/silc", server, NULL,
2251 MSGLEVEL_CRAP, SILCTXT_STATS,
2252 "Local server channels", tmp);
2254 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
2255 printformat_module("fe-common/silc", server, NULL,
2256 MSGLEVEL_CRAP, SILCTXT_STATS,
2257 "Local server operators", tmp);
2259 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
2260 printformat_module("fe-common/silc", server, NULL,
2261 MSGLEVEL_CRAP, SILCTXT_STATS,
2262 "Local router operators", tmp);
2264 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
2265 printformat_module("fe-common/silc", server, NULL,
2266 MSGLEVEL_CRAP, SILCTXT_STATS,
2267 "Local cell clients", tmp);
2269 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
2270 printformat_module("fe-common/silc", server, NULL,
2271 MSGLEVEL_CRAP, SILCTXT_STATS,
2272 "Local cell channels", tmp);
2274 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
2275 printformat_module("fe-common/silc", server, NULL,
2276 MSGLEVEL_CRAP, SILCTXT_STATS,
2277 "Local cell servers", tmp);
2279 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
2280 printformat_module("fe-common/silc", server, NULL,
2281 MSGLEVEL_CRAP, SILCTXT_STATS,
2282 "Total clients", tmp);
2284 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
2285 printformat_module("fe-common/silc", server, NULL,
2286 MSGLEVEL_CRAP, SILCTXT_STATS,
2287 "Total channels", tmp);
2289 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
2290 printformat_module("fe-common/silc", server, NULL,
2291 MSGLEVEL_CRAP, SILCTXT_STATS,
2292 "Total servers", tmp);
2294 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
2295 printformat_module("fe-common/silc", server, NULL,
2296 MSGLEVEL_CRAP, SILCTXT_STATS,
2297 "Total routers", tmp);
2299 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
2300 printformat_module("fe-common/silc", server, NULL,
2301 MSGLEVEL_CRAP, SILCTXT_STATS,
2302 "Total server operators", tmp);
2304 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
2305 printformat_module("fe-common/silc", server, NULL,
2306 MSGLEVEL_CRAP, SILCTXT_STATS,
2307 "Total router operators", tmp);
2311 case SILC_COMMAND_CMODE:
2313 SilcChannelEntry channel_entry;
2316 channel_entry = va_arg(vp, SilcChannelEntry);
2317 (void)va_arg(vp, SilcUInt32);
2318 (void)va_arg(vp, SilcPublicKey);
2319 chpks = va_arg(vp, SilcDList);
2321 if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
2322 !channel_entry || !channel_entry->channel_name)
2325 /* Print the channel public key list */
2327 silc_parse_channel_public_keys(server, channel_entry, chpks);
2329 printformat_module("fe-common/silc", server, NULL,
2330 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2331 channel_entry->channel_name);
2336 case SILC_COMMAND_LEAVE:
2338 if (SILC_STATUS_IS_ERROR(status))
2341 /* We might be cycling, so disable queueing again */
2342 silc_queue_disable(conn);
2346 case SILC_COMMAND_DETACH:
2348 /* Save the detachment data to file. */
2352 if (SILC_STATUS_IS_ERROR(status))
2355 detach = va_arg(vp, SilcBuffer);
2356 file = silc_get_session_filename(server);
2357 silc_file_writefile(file, silc_buffer_data(detach),
2358 silc_buffer_len(detach));
2363 case SILC_COMMAND_KILL:
2365 SilcClientEntry client_entry;
2367 if (SILC_STATUS_IS_ERROR(status)) {
2368 silc_say_error("KILL: %s", silc_get_status_message(status));
2372 client_entry = va_arg(vp, SilcClientEntry);
2373 if (!client_entry || !client_entry->nickname[0])
2376 /* Print this only if the killed client isn't joined on channels.
2377 If it is, we receive KILLED notify and we'll print this there. */
2378 if (!silc_hash_table_count(client_entry->channels))
2379 printformat_module("fe-common/silc", server, NULL,
2380 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
2381 client_entry->nickname,
2382 conn->local_entry->nickname, "");
2389 SilcClientConnection conn;
2393 SilcPublicKey public_key;
2394 SilcVerifyPublicKey completion;
2398 static void verify_public_key_completion(const char *line, void *context,
2399 SilcKeyboardPromptStatus reason)
2401 PublicKeyVerify verify = (PublicKeyVerify)context;
2402 SilcBool success = (reason == KeyboardCompletionSuccess);
2404 if (success && (line[0] == 'Y' || line[0] == 'y')) {
2405 /* Call the completion */
2406 if (verify->completion)
2407 verify->completion(TRUE, verify->context);
2409 /* Save the key for future checking */
2410 silc_pkcs_save_public_key(verify->filename, verify->public_key,
2411 SILC_PKCS_FILE_BASE64);
2413 /* Call the completion */
2414 if (verify->completion)
2415 verify->completion(FALSE, verify->context);
2417 printformat_module("fe-common/silc", NULL, NULL,
2418 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2419 verify->entity_name ? verify->entity_name :
2424 * If we were not called due to a failure to begin the callback, then we
2425 * shall zero the async context block in the server record. If we were
2426 * called due to a failure to begin the callback, then it is possible that
2427 * we failed due to an overlapping callback, in which case we shouldn't
2428 * overwrite the async context block pointer.
2430 if (reason != KeyboardCompletionFailed) {
2432 * Null out the completion context in the server record as this operation
2433 * is done as far as we are concerned. The underlying keyboard library
2434 * routine will take care of freeing the async context memory when the
2435 * actual callback is called by irssi in the abort case. In the success
2436 * case, it will free the async context memory after we return from this
2439 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
2440 server->prompt_op = NULL;
2443 silc_free(verify->filename);
2444 silc_free(verify->entity);
2445 silc_free(verify->entity_name);
2449 /* Internal routine to verify public key. If the `completion' is provided
2450 it will be called to indicate whether public was verified or not. For
2451 server/router public key this will check for filename that includes the
2452 remote host's IP address and remote host's hostname. */
2455 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2457 SilcConnectionType conn_type,
2458 SilcPublicKey public_key,
2459 SilcVerifyPublicKey completion, void *context)
2461 PublicKeyVerify verify;
2462 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2463 char *fingerprint, *babbleprint, *format;
2464 SilcPublicKey local_pubkey;
2465 SilcSILCPublicKey silc_pubkey;
2467 SILC_SERVER_REC *server;
2468 const char *hostname, *ip;
2473 char *entity = ((conn_type == SILC_CONN_SERVER ||
2474 conn_type == SILC_CONN_ROUTER) ?
2475 "server" : "client");
2478 server = (SILC_SERVER_REC*)conn->context;
2479 SILC_VERIFY(server);
2482 completion(FALSE, context);
2486 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
2487 printformat_module("fe-common/silc", NULL, NULL,
2488 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2489 entity, silc_pkcs_get_type(public_key));
2491 completion(FALSE, context);
2495 /* Encode public key */
2496 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2499 completion(FALSE, context);
2503 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
2505 pw = getpwuid(getuid());
2508 completion(FALSE, context);
2513 memset(filename, 0, sizeof(filename));
2514 memset(filename2, 0, sizeof(filename2));
2515 memset(file, 0, sizeof(file));
2517 /* Get remote host information */
2518 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
2519 NULL, &hostname, &ip, &port);
2521 if (conn_type == SILC_CONN_SERVER ||
2522 conn_type == SILC_CONN_ROUTER) {
2524 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
2525 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2526 get_irssi_dir(), entity, file);
2528 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2530 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2531 get_irssi_dir(), entity, file);
2536 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2538 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2539 get_irssi_dir(), entity, file);
2544 /* Replace all whitespaces with `_'. */
2545 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2546 for (i = 0; i < strlen(fingerprint); i++)
2547 if (fingerprint[i] == ' ')
2548 fingerprint[i] = '_';
2550 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2551 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2552 get_irssi_dir(), entity, file);
2553 silc_free(fingerprint);
2558 /* Take fingerprint of the public key */
2559 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2560 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2562 verify = silc_calloc(1, sizeof(*verify));
2563 verify->client = client;
2564 verify->conn = conn;
2565 verify->filename = strdup(ipf);
2566 verify->entity = strdup(entity);
2567 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
2568 (name ? strdup(name) : strdup(hostname))
2570 verify->public_key = public_key;
2571 verify->completion = completion;
2572 verify->context = context;
2574 /* Check whether this key already exists */
2575 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2576 /* Key does not exist, ask user to verify the key and save it */
2578 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2579 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2580 verify->entity_name : entity);
2581 if (conn_type == SILC_CONN_CLIENT && name &&
2582 silc_pubkey->identifier.realname)
2583 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2584 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2585 silc_pubkey->identifier.realname,
2586 silc_pubkey->identifier.email ?
2587 silc_pubkey->identifier.email : "");
2588 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2589 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2590 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2591 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2592 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2593 SILCTXT_PUBKEY_ACCEPT);
2594 silc_keyboard_entry_redirect(verify_public_key_completion,
2595 format, 0, verify, &server->prompt_op);
2597 silc_free(fingerprint);
2598 silc_free(babbleprint);
2602 /* The key already exists, verify it. */
2603 unsigned char *encpk;
2604 SilcUInt32 encpk_len;
2606 /* Load the key file, try for both IP filename and hostname filename */
2607 if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
2608 (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
2609 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2610 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2611 verify->entity_name : entity);
2612 if (conn_type == SILC_CONN_CLIENT && name &&
2613 silc_pubkey->identifier.realname)
2614 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2615 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2616 silc_pubkey->identifier.realname,
2617 silc_pubkey->identifier.email ?
2618 silc_pubkey->identifier.email : "");
2619 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2620 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2621 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2622 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2623 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2624 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2625 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2626 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2627 silc_keyboard_entry_redirect(verify_public_key_completion,
2628 format, 0, verify, &server->prompt_op);
2630 silc_free(fingerprint);
2631 silc_free(babbleprint);
2636 /* Encode the key data */
2637 encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
2639 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2640 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2641 verify->entity_name : entity);
2642 if (conn_type == SILC_CONN_CLIENT && name &&
2643 silc_pubkey->identifier.realname)
2644 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2645 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2646 silc_pubkey->identifier.realname,
2647 silc_pubkey->identifier.email ?
2648 silc_pubkey->identifier.email : "");
2649 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2650 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2651 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2652 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2653 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2654 SILCTXT_PUBKEY_MALFORMED, entity);
2655 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2656 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2657 silc_keyboard_entry_redirect(verify_public_key_completion,
2658 format, 0, verify, &server->prompt_op);
2660 silc_free(fingerprint);
2661 silc_free(babbleprint);
2665 silc_pkcs_public_key_free(local_pubkey);
2667 /* Compare the keys */
2668 if (memcmp(encpk, pk, encpk_len)) {
2669 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2670 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2671 verify->entity_name : entity);
2672 if (conn_type == SILC_CONN_CLIENT && name &&
2673 silc_pubkey->identifier.realname)
2674 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2675 SILCTXT_PUBKEY_RECEIVED_CLIENT, name,
2676 silc_pubkey->identifier.realname,
2677 silc_pubkey->identifier.email ?
2678 silc_pubkey->identifier.email : "");
2679 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2680 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2681 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2682 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2683 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2684 SILCTXT_PUBKEY_NO_MATCH, entity);
2685 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2686 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2687 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2688 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2690 /* Ask user to verify the key and save it */
2691 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2692 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2693 silc_keyboard_entry_redirect(verify_public_key_completion,
2694 format, 0, verify, &server->prompt_op);
2696 silc_free(fingerprint);
2697 silc_free(babbleprint);
2703 /* Local copy matched */
2705 completion(TRUE, context);
2707 silc_free(fingerprint);
2708 silc_free(babbleprint);
2709 silc_free(verify->filename);
2710 silc_free(verify->entity);
2711 silc_free(verify->entity_name);
2717 /* Verifies received public key. The `conn_type' indicates which entity
2718 (server, client etc.) has sent the public key. If user decides to trust
2719 the key may be saved as trusted public key for later use. The
2720 `completion' must be called after the public key has been verified. */
2723 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2724 SilcConnectionType conn_type,
2725 SilcPublicKey public_key,
2726 SilcVerifyPublicKey completion, void *context)
2728 silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
2729 completion, context);
2732 /* Asks passphrase from user on the input line. */
2735 SilcAskPassphrase completion;
2736 SilcClientConnection conn;
2740 void ask_passphrase_completion(const char *passphrase, void *context,
2741 SilcKeyboardPromptStatus reason)
2743 AskPassphrase p = (AskPassphrase)context;
2744 if (passphrase && passphrase[0] == '\0')
2746 p->completion((unsigned char *)passphrase,
2747 passphrase ? strlen(passphrase) : 0, p->context);
2749 if (reason != KeyboardCompletionFailed) {
2750 SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
2751 server->prompt_op = NULL;
2757 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2758 SilcAskPassphrase completion, void *context)
2760 SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
2763 p = silc_calloc(1, sizeof(*p));
2766 completion(NULL, 0, context);
2770 p->completion = completion;
2772 p->context = context;
2774 silc_keyboard_entry_redirect(ask_passphrase_completion,
2775 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN,
2776 p, &server->prompt_op);
2780 SilcGetAuthMeth completion;
2784 static void silc_get_auth_ask_passphrase(const unsigned char *passphrase,
2785 SilcUInt32 passphrase_len,
2788 GetAuthMethod a = context;
2789 a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
2790 passphrase, passphrase_len, a->context);
2794 /* Find authentication data by hostname and port. The hostname may be IP
2797 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2798 char *hostname, SilcUInt16 port,
2799 SilcAuthMethod auth_meth,
2800 SilcGetAuthMeth completion, void *context)
2802 SERVER_SETUP_REC *setup;
2804 SILC_LOG_DEBUG(("Start"));
2806 if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
2807 /* Returning NULL will cause library to use our private key configured
2808 for this connection */
2809 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
2813 /* Check whether we find the password for this server in our
2814 configuration. If it's set, always send it server. */
2815 setup = server_setup_find_port(hostname, port);
2816 if (setup && setup->password) {
2817 completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
2822 /* Didn't find password. If server wants it, ask it from user. */
2823 if (auth_meth == SILC_AUTH_PASSWORD) {
2825 a = silc_calloc(1, sizeof(*a));
2827 a->completion = completion;
2828 a->context = context;
2829 silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
2834 /* No authentication */
2835 completion(SILC_AUTH_NONE, NULL, 0, context);
2838 /* Asks whether the user would like to perform the key agreement protocol.
2839 This is called after we have received an key agreement packet or an
2840 reply to our key agreement packet. This returns TRUE if the user wants
2841 the library to perform the key agreement protocol and FALSE if it is not
2842 desired (application may start it later by calling the function
2843 silc_client_perform_key_agreement). */
2845 void silc_key_agreement(SilcClient client, SilcClientConnection conn,
2846 SilcClientEntry client_entry, const char *hostname,
2847 SilcUInt16 protocol, SilcUInt16 port)
2849 char portstr[12], protostr[5];
2851 SILC_LOG_DEBUG(("Start"));
2853 /* We will just display the info on the screen and return FALSE and user
2854 will have to start the key agreement with a command. */
2857 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2858 snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
2863 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2864 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2866 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2867 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2868 client_entry->nickname, hostname, portstr, protostr);
2871 /* Notifies application that file transfer protocol session is being
2872 requested by the remote client indicated by the `client_entry' from
2873 the `hostname' and `port'. The `session_id' is the file transfer
2874 session and it can be used to either accept or reject the file
2875 transfer request, by calling the silc_client_file_receive or
2876 silc_client_file_close, respectively. */
2878 void silc_ftp(SilcClient client, SilcClientConnection conn,
2879 SilcClientEntry client_entry, SilcUInt32 session_id,
2880 const char *hostname, SilcUInt16 port)
2882 SILC_SERVER_REC *server;
2884 FtpSession ftp = NULL;
2886 SILC_LOG_DEBUG(("Start"));
2888 server = conn->context;
2890 silc_dlist_start(server->ftp_sessions);
2891 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2892 if (ftp->client_entry == client_entry &&
2893 ftp->session_id == session_id) {
2894 server->current_session = ftp;
2898 if (ftp == SILC_LIST_END) {
2899 ftp = silc_calloc(1, sizeof(*ftp));
2900 ftp->client_entry = client_entry;
2901 ftp->session_id = session_id;
2904 silc_dlist_add(server->ftp_sessions, ftp);
2905 server->current_session = ftp;
2909 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2912 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2913 SILCTXT_FILE_REQUEST, client_entry->nickname);
2915 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2916 SILCTXT_FILE_REQUEST_HOST,
2917 client_entry->nickname, hostname, portstr);
2920 /* SILC client operations */
2921 SilcClientOperations ops = {
2923 silc_channel_message,
2924 silc_private_message,
2928 silc_get_auth_method,
2929 silc_verify_public_key,
2930 silc_ask_passphrase,