5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 - 2003 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"
37 #include "special-vars.h"
38 #include "fe-common/core/printtext.h"
39 #include "fe-common/core/fe-channels.h"
40 #include "fe-common/core/keyboard.h"
41 #include "fe-common/core/window-items.h"
42 #include "fe-common/silc/module-formats.h"
47 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
48 const char *name, SilcSocketType conn_type,
49 unsigned char *pk, SilcUInt32 pk_len,
50 SilcSKEPKType pk_type,
51 SilcVerifyPublicKey completion, void *context);
53 char *silc_get_session_filename(SILC_SERVER_REC *server)
55 char *file, *expanded;
57 expanded = parse_special_string(settings_get_str("session_filename"),
58 SERVER(server), NULL, "", NULL, 0);
60 file = silc_calloc(1, strlen(expanded) + 255);
61 snprintf(file, strlen(expanded) + 255, "%s/%s", get_irssi_dir(), expanded);
67 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
70 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
71 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
72 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
74 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
75 "[SILC operator]" : "[unknown mode]");
77 if (mode & SILC_UMODE_GONE)
78 strcat(buf, " [away]");
79 if (mode & SILC_UMODE_INDISPOSED)
80 strcat(buf, " [indisposed]");
81 if (mode & SILC_UMODE_BUSY)
82 strcat(buf, " [busy]");
83 if (mode & SILC_UMODE_PAGE)
84 strcat(buf, " [page to reach]");
85 if (mode & SILC_UMODE_HYPER)
86 strcat(buf, " [hyper active]");
87 if (mode & SILC_UMODE_ROBOT)
88 strcat(buf, " [robot]");
89 if (mode & SILC_UMODE_ANONYMOUS)
90 strcat(buf, " [anonymous]");
91 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
92 strcat(buf, " [blocks private messages]");
93 if (mode & SILC_UMODE_DETACHED)
94 strcat(buf, " [detached]");
95 if (mode & SILC_UMODE_REJECT_WATCHING)
96 strcat(buf, " [rejects watching]");
97 if (mode & SILC_UMODE_BLOCK_INVITE)
98 strcat(buf, " [blocks invites]");
101 /* print "nick appears as" message to every channel of a server */
103 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
104 const char *newnick, const char *oldnick,
107 if (ignore_check(SERVER(server), oldnick, address,
108 channel, newnick, MSGLEVEL_NICKS))
111 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
112 SILCTXT_CHANNEL_APPEARS,
113 oldnick, newnick, channel, address);
117 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
118 const char *oldnick, const char *address)
120 GSList *tmp, *windows;
122 /* Print to each channel/query where the nick is.
123 Don't print more than once to the same window. */
126 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
127 CHANNEL_REC *channel = tmp->data;
128 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
130 if (nicklist_find(channel, newnick) == NULL ||
131 g_slist_find(windows, window) != NULL)
134 windows = g_slist_append(windows, window);
135 silc_print_nick_change_channel(server, channel->visible_name,
136 newnick, oldnick, address);
139 g_slist_free(windows);
142 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
143 SilcChannelEntry channel_entry,
144 SilcBuffer channel_pubkeys)
147 SilcArgumentPayload chpks;
149 SilcUInt32 pk_len, type;
151 char *fingerprint, *babbleprint;
152 SilcPublicKey pubkey;
153 SilcPublicKeyIdentifier ident;
155 printformat_module("fe-common/silc", server, NULL,
156 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
157 channel_entry->channel_name);
159 SILC_GET16_MSB(argc, channel_pubkeys->data);
160 chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
161 channel_pubkeys->len - 2, argc);
165 pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
167 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
168 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
169 silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
170 ident = silc_pkcs_decode_identifier(pubkey->identifier);
172 printformat_module("fe-common/silc", server, NULL,
173 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
174 c++, channel_entry->channel_name,
175 type == 0x00 ? "Added" : "Removed",
176 ident->realname ? ident->realname : "",
177 fingerprint, babbleprint);
179 silc_free(fingerprint);
180 silc_free(babbleprint);
181 silc_pkcs_public_key_free(pubkey);
182 silc_pkcs_free_identifier(ident);
183 pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
186 silc_argument_payload_free(chpks);
189 void silc_say(SilcClient client, SilcClientConnection conn,
190 SilcClientMessageType type, char *msg, ...)
192 SILC_SERVER_REC *server;
196 server = conn == NULL ? NULL : conn->context;
199 str = g_strdup_vprintf(msg, va);
200 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
205 void silc_say_error(char *msg, ...)
211 str = g_strdup_vprintf(msg, va);
212 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
218 /* try to verify a message using locally stored public key data */
219 int verify_message_signature(SilcClientEntry sender,
220 SilcMessageSignedPayload sig,
221 SilcMessagePayload message)
224 char file[256], filename[256];
225 char *fingerprint, *fingerprint2;
226 unsigned char *pk_data;
227 SilcUInt32 pk_datalen;
229 int ret = SILC_MSG_SIGNED_VERIFIED, i;
232 return SILC_MSG_SIGNED_UNKNOWN;
234 /* get public key from the signature payload and compare it with the
235 one stored in the client entry */
236 pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
239 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
241 if (sender->fingerprint) {
242 fingerprint2 = silc_fingerprint(sender->fingerprint,
243 sender->fingerprint_len);
244 if (strcmp(fingerprint, fingerprint2)) {
245 /* since the public key differs from the senders public key, the
246 verification _failed_ */
247 silc_pkcs_public_key_free(pk);
248 silc_free(fingerprint);
249 ret = SILC_MSG_SIGNED_UNKNOWN;
251 silc_free(fingerprint2);
253 } else if (sender->fingerprint)
254 fingerprint = silc_fingerprint(sender->fingerprint,
255 sender->fingerprint_len);
257 /* no idea, who or what signed that message ... */
258 return SILC_MSG_SIGNED_UNKNOWN;
260 /* search our local client key cache */
261 for (i = 0; i < strlen(fingerprint); i++)
262 if (fingerprint[i] == ' ')
263 fingerprint[i] = '_';
265 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
266 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
267 get_irssi_dir(), file);
268 silc_free(fingerprint);
270 if (stat(filename, &st) < 0)
271 /* we don't have the public key cached ... use the one from the sig */
272 ret = SILC_MSG_SIGNED_UNKNOWN;
274 SilcPublicKey cached_pk=NULL;
276 /* try to load the file */
277 if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
278 !silc_pkcs_load_public_key(filename, &cached_pk,
279 SILC_PKCS_FILE_BIN)) {
280 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
281 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
283 return SILC_MSG_SIGNED_UNKNOWN;
285 ret = SILC_MSG_SIGNED_UNKNOWN;
290 silc_pkcs_public_key_free(pk);
295 /* the public key is now in pk, our "level of trust" in ret */
296 if ((pk) && silc_message_signed_verify(sig, message, pk,
297 silc_client->sha1hash)!= SILC_AUTH_OK)
298 ret = SILC_MSG_SIGNED_FAILED;
301 silc_pkcs_public_key_free(pk);
306 char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
309 int i = 0, j = 0, len = strlen(escaped_data);
311 data = silc_calloc(len, sizeof(char));
314 ptr = memchr(escaped_data + i, 1, len - i);
316 int inc = (ptr - escaped_data) - i;
317 memcpy(data + j, escaped_data + i, inc);
320 data[j++] = *(ptr + 1) - 1;
322 memcpy(data + j, escaped_data + i, len - i);
332 char * silc_escape_data(const char *data, SilcUInt32 len)
334 char *escaped_data, *ptr, *ptr0, *ptr1;
337 escaped_data = silc_calloc(2 * len, sizeof(char));
340 ptr0 = memchr(data + i, 0, len - i);
341 ptr1 = memchr(data + i, 1, len - i);
343 ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
346 int inc = (ptr - data) - i;
348 memcpy(escaped_data + j, data + i, inc);
351 escaped_data[j++] = 1;
352 escaped_data[j++] = *(data + i++) + 1;
354 memcpy(escaped_data + j, data + i, len - i);
363 void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
364 const char *data, SilcUInt32 data_len, const char *nick,
369 escaped_data = silc_escape_data(data, data_len);
371 signal_emit("mime", 5, server, item, escaped_data, nick, verified);
373 silc_free(escaped_data);
377 /* Message for a channel. The `sender' is the nickname of the sender
378 received in the packet. The `channel_name' is the name of the channel. */
380 void silc_channel_message(SilcClient client, SilcClientConnection conn,
381 SilcClientEntry sender, SilcChannelEntry channel,
382 SilcMessagePayload payload,
383 SilcMessageFlags flags, const unsigned char *message,
384 SilcUInt32 message_len)
386 SILC_SERVER_REC *server;
388 SILC_CHANNEL_REC *chanrec;
391 SILC_LOG_DEBUG(("Start"));
396 server = conn == NULL ? NULL : conn->context;
397 chanrec = silc_channel_find_entry(server, channel);
401 nick = silc_nicklist_find(chanrec, sender);
403 /* We didn't find client but it clearly exists, add it. */
404 SilcChannelUser chu = silc_client_on_channel(channel, sender);
406 nick = silc_nicklist_insert(chanrec, chu, FALSE);
409 /* If the messages is digitally signed, verify it, if possible. */
410 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
411 if (!settings_get_bool("ignore_message_signatures")) {
412 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
413 verified = verify_message_signature(sender, sig, payload);
415 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
419 if (flags & SILC_MESSAGE_FLAG_DATA) {
420 silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
421 nick == NULL ? NULL : nick->nick,
422 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
429 if (flags & SILC_MESSAGE_FLAG_ACTION)
430 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
431 char tmp[256], *cp, *dm = NULL;
432 memset(tmp, 0, sizeof(tmp));
434 if(message_len > sizeof(tmp) - 1) {
435 dm = silc_calloc(message_len + 1, sizeof(*dm));
438 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
440 if (flags & SILC_MESSAGE_FLAG_SIGNED)
441 signal_emit("message silc signed_action", 6, server, cp, nick->nick,
442 nick->host, channel->channel_name, verified);
444 signal_emit("message silc action", 5, server, cp, nick->nick,
445 nick->host, channel->channel_name);
448 if (flags & SILC_MESSAGE_FLAG_SIGNED)
449 signal_emit("message silc signed_action", 6, server, message,
450 nick->nick, nick->host, channel->channel_name, verified);
452 signal_emit("message silc action", 5, server, message,
453 nick->nick, nick->host, channel->channel_name);
455 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
456 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
457 char tmp[256], *cp, *dm = NULL;
458 memset(tmp, 0, sizeof(tmp));
460 if(message_len > sizeof(tmp) - 1) {
461 dm = silc_calloc(message_len + 1, sizeof(*dm));
464 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
466 if (flags & SILC_MESSAGE_FLAG_SIGNED)
467 signal_emit("message silc signed_notice", 6, server, cp, nick->nick,
468 nick->host, channel->channel_name, verified);
470 signal_emit("message silc notice", 5, server, cp, nick->nick,
471 nick->host, channel->channel_name);
474 if (flags & SILC_MESSAGE_FLAG_SIGNED)
475 signal_emit("message silc signed_notice", 6, server, message,
476 nick->nick, nick->host, channel->channel_name, verified);
478 signal_emit("message silc notice", 5, server, message,
479 nick->nick, nick->host, channel->channel_name);
482 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
483 char tmp[256], *cp, *dm = NULL;
485 memset(tmp, 0, sizeof(tmp));
487 if (message_len > sizeof(tmp) - 1) {
488 dm = silc_calloc(message_len + 1, sizeof(*dm));
492 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
494 if (flags & SILC_MESSAGE_FLAG_SIGNED)
495 signal_emit("message signed_public", 6, server, cp,
496 nick == NULL ? "[<unknown>]" : nick->nick,
497 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
498 chanrec->name, verified);
500 signal_emit("message public", 6, server, cp,
501 nick == NULL ? "[<unknown>]" : nick->nick,
502 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
503 chanrec->name, nick);
508 if (flags & SILC_MESSAGE_FLAG_SIGNED)
509 signal_emit("message signed_public", 6, server, message,
510 nick == NULL ? "[<unknown>]" : nick->nick,
511 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
512 chanrec->name, verified);
514 signal_emit("message public", 6, server, message,
515 nick == NULL ? "[<unknown>]" : nick->nick,
516 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
517 chanrec->name, nick);
521 /* Private message to the client. The `sender' is the nickname of the
522 sender received in the packet. */
524 void silc_private_message(SilcClient client, SilcClientConnection conn,
525 SilcClientEntry sender, SilcMessagePayload payload,
526 SilcMessageFlags flags,
527 const unsigned char *message,
528 SilcUInt32 message_len)
530 SILC_SERVER_REC *server;
534 SILC_LOG_DEBUG(("Start"));
536 server = conn == NULL ? NULL : conn->context;
537 memset(userhost, 0, sizeof(userhost));
538 if (sender->username)
539 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
540 sender->username, sender->hostname);
542 /* If the messages is digitally signed, verify it, if possible. */
543 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
544 if (!settings_get_bool("ignore_message_signatures")) {
545 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
546 verified = verify_message_signature(sender, sig, payload);
548 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
552 if (flags & SILC_MESSAGE_FLAG_DATA) {
553 silc_emit_mime_sig(server,
555 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
557 message, message_len,
558 sender->nickname ? sender->nickname : "[<unknown>]",
559 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
566 if (flags & SILC_MESSAGE_FLAG_ACTION)
567 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
568 char tmp[256], *cp, *dm = NULL;
569 memset(tmp, 0, sizeof(tmp));
571 if(message_len > sizeof(tmp) - 1) {
572 dm = silc_calloc(message_len + 1, sizeof(*dm));
575 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
577 if (flags & SILC_MESSAGE_FLAG_SIGNED)
578 signal_emit("message silc signed_private_action", 6, server, cp,
579 sender->nickname ? sender->nickname : "[<unknown>]",
580 sender->username ? userhost : NULL,
583 signal_emit("message silc private_action", 5, server, cp,
584 sender->nickname ? sender->nickname : "[<unknown>]",
585 sender->username ? userhost : NULL, NULL);
588 if (flags & SILC_MESSAGE_FLAG_SIGNED)
589 signal_emit("message silc signed_private_action", 6, server, message,
590 sender->nickname ? sender->nickname : "[<unknown>]",
591 sender->username ? userhost : NULL,
594 signal_emit("message silc private_action", 5, server, message,
595 sender->nickname ? sender->nickname : "[<unknown>]",
596 sender->username ? userhost : NULL, NULL);
598 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
599 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
600 char tmp[256], *cp, *dm = NULL;
601 memset(tmp, 0, sizeof(tmp));
603 if(message_len > sizeof(tmp) - 1) {
604 dm = silc_calloc(message_len + 1, sizeof(*dm));
607 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
609 if (flags & SILC_MESSAGE_FLAG_SIGNED)
610 signal_emit("message silc signed_private_notice", 6, server, cp,
611 sender->nickname ? sender->nickname : "[<unknown>]",
612 sender->username ? userhost : NULL,
615 signal_emit("message silc private_notice", 5, server, cp,
616 sender->nickname ? sender->nickname : "[<unknown>]",
617 sender->username ? userhost : NULL, NULL);
620 if (flags & SILC_MESSAGE_FLAG_SIGNED)
621 signal_emit("message silc signed_private_notice", 6, server, message,
622 sender->nickname ? sender->nickname : "[<unknown>]",
623 sender->username ? userhost : NULL,
626 signal_emit("message silc private_notice", 5, server, message,
627 sender->nickname ? sender->nickname : "[<unknown>]",
628 sender->username ? userhost : NULL, NULL);
631 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
632 char tmp[256], *cp, *dm = NULL;
634 memset(tmp, 0, sizeof(tmp));
636 if (message_len > sizeof(tmp) - 1) {
637 dm = silc_calloc(message_len + 1, sizeof(*dm));
641 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
643 if (flags & SILC_MESSAGE_FLAG_SIGNED)
644 signal_emit("message signed_private", 5, server, cp,
645 sender->nickname ? sender->nickname : "[<unknown>]",
646 sender->username ? userhost : NULL, verified);
648 signal_emit("message private", 4, server, cp,
649 sender->nickname ? sender->nickname : "[<unknown>]",
650 sender->username ? userhost : NULL);
655 if (flags & SILC_MESSAGE_FLAG_SIGNED)
656 signal_emit("message signed_private", 5, server, message,
657 sender->nickname ? sender->nickname : "[<unknown>]",
658 sender->username ? userhost : NULL, verified);
660 signal_emit("message private", 4, server, message,
661 sender->nickname ? sender->nickname : "[<unknown>]",
662 sender->username ? userhost : NULL);
666 /* Notify message to the client. The notify arguments are sent in the
667 same order as servers sends them. The arguments are same as received
668 from the server except for ID's. If ID is received application receives
669 the corresponding entry to the ID. For example, if Client ID is received
670 application receives SilcClientEntry. Also, if the notify type is
671 for channel the channel entry is sent to application (even if server
672 does not send it). */
674 void silc_notify(SilcClient client, SilcClientConnection conn,
675 SilcNotifyType type, ...)
678 SILC_SERVER_REC *server;
679 SILC_CHANNEL_REC *chanrec;
680 SILC_NICK_REC *nickrec;
681 SilcClientEntry client_entry, client_entry2;
682 SilcChannelEntry channel, channel2;
683 SilcServerEntry server_entry;
689 GSList *list1, *list_tmp;
692 SILC_LOG_DEBUG(("Start"));
696 server = conn == NULL ? NULL : conn->context;
699 case SILC_NOTIFY_TYPE_NONE:
700 /* Some generic notice from server */
701 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
704 case SILC_NOTIFY_TYPE_INVITE:
706 * Invited or modified invite list.
709 SILC_LOG_DEBUG(("Notify: INVITE"));
711 channel = va_arg(va, SilcChannelEntry);
712 name = va_arg(va, char *);
713 client_entry = va_arg(va, SilcClientEntry);
715 memset(buf, 0, sizeof(buf));
716 snprintf(buf, sizeof(buf) - 1, "%s@%s",
717 client_entry->username, client_entry->hostname);
718 signal_emit("message invite", 4, server, channel ? channel->channel_name :
719 name, client_entry->nickname, buf);
722 case SILC_NOTIFY_TYPE_JOIN:
727 SILC_LOG_DEBUG(("Notify: JOIN"));
729 client_entry = va_arg(va, SilcClientEntry);
730 channel = va_arg(va, SilcChannelEntry);
732 if (client_entry == server->conn->local_entry) {
733 /* You joined to channel */
734 chanrec = silc_channel_find(server, channel->channel_name);
735 if (chanrec != NULL && !chanrec->joined)
736 chanrec->entry = channel;
738 chanrec = silc_channel_find_entry(server, channel);
739 if (chanrec != NULL) {
740 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
742 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
746 memset(buf, 0, sizeof(buf));
747 if (client_entry->username)
748 snprintf(buf, sizeof(buf) - 1, "%s@%s",
749 client_entry->username, client_entry->hostname);
750 signal_emit("message join", 4, server, channel->channel_name,
751 client_entry->nickname,
752 client_entry->username == NULL ? "" : buf);
755 case SILC_NOTIFY_TYPE_LEAVE:
760 SILC_LOG_DEBUG(("Notify: LEAVE"));
762 client_entry = va_arg(va, SilcClientEntry);
763 channel = va_arg(va, SilcChannelEntry);
765 memset(buf, 0, sizeof(buf));
766 if (client_entry->username)
767 snprintf(buf, sizeof(buf) - 1, "%s@%s",
768 client_entry->username, client_entry->hostname);
769 signal_emit("message part", 5, server, channel->channel_name,
770 client_entry->nickname, client_entry->username ?
771 buf : "", client_entry->nickname);
773 chanrec = silc_channel_find_entry(server, channel);
774 if (chanrec != NULL) {
775 nickrec = silc_nicklist_find(chanrec, client_entry);
777 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
781 case SILC_NOTIFY_TYPE_SIGNOFF:
786 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
788 client_entry = va_arg(va, SilcClientEntry);
789 tmp = va_arg(va, char *);
791 silc_server_free_ftp(server, client_entry);
793 /* Print only if we have the nickname. If this cliente has just quit
794 when we were only resolving it, it is possible we don't have the
796 if (client_entry->nickname) {
797 memset(buf, 0, sizeof(buf));
798 if (client_entry->username)
799 snprintf(buf, sizeof(buf) - 1, "%s@%s",
800 client_entry->username, client_entry->hostname);
801 signal_emit("message quit", 4, server, client_entry->nickname,
802 client_entry->username ? buf : "",
806 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
807 for (list_tmp = list1; list_tmp != NULL; list_tmp =
808 list_tmp->next->next) {
809 CHANNEL_REC *channel = list_tmp->data;
810 NICK_REC *nickrec = list_tmp->next->data;
812 nicklist_remove(channel, nickrec);
816 case SILC_NOTIFY_TYPE_TOPIC_SET:
821 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
823 idtype = va_arg(va, int);
824 entry = va_arg(va, void *);
825 tmp = va_arg(va, char *);
826 channel = va_arg(va, SilcChannelEntry);
828 chanrec = silc_channel_find_entry(server, channel);
829 if (chanrec != NULL) {
830 char tmp2[256], *cp, *dm = NULL;
832 g_free_not_null(chanrec->topic);
833 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
834 memset(tmp2, 0, sizeof(tmp2));
836 if (strlen(tmp) > sizeof(tmp2) - 1) {
837 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
841 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
846 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
847 signal_emit("channel topic changed", 1, chanrec);
852 if (idtype == SILC_ID_CLIENT) {
853 client_entry = (SilcClientEntry)entry;
854 memset(buf, 0, sizeof(buf));
855 snprintf(buf, sizeof(buf) - 1, "%s@%s",
856 client_entry->username, client_entry->hostname);
857 signal_emit("message topic", 5, server, channel->channel_name,
858 tmp, client_entry->nickname, buf);
859 } else if (idtype == SILC_ID_SERVER) {
860 server_entry = (SilcServerEntry)entry;
861 signal_emit("message topic", 5, server, channel->channel_name,
862 tmp, server_entry->server_name,
863 server_entry->server_name);
864 } else if (idtype == SILC_ID_CHANNEL) {
865 channel = (SilcChannelEntry)entry;
866 signal_emit("message topic", 5, server, channel->channel_name,
867 tmp, channel->channel_name, channel->channel_name);
871 case SILC_NOTIFY_TYPE_NICK_CHANGE:
876 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
878 client_entry = va_arg(va, SilcClientEntry);
879 client_entry2 = va_arg(va, SilcClientEntry);
881 if (!strcmp(client_entry->nickname, client_entry2->nickname))
884 memset(buf, 0, sizeof(buf));
885 snprintf(buf, sizeof(buf) - 1, "%s@%s",
886 client_entry2->username, client_entry2->hostname);
887 nicklist_rename_unique(SERVER(server),
888 client_entry, client_entry->nickname,
889 client_entry2, client_entry2->nickname);
890 signal_emit("message nick", 4, server, client_entry2->nickname,
891 client_entry->nickname, buf);
894 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
896 * Changed channel mode.
899 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
901 idtype = va_arg(va, int);
902 entry = va_arg(va, void *);
903 mode = va_arg(va, SilcUInt32);
904 (void)va_arg(va, char *); /* cipher */
905 (void)va_arg(va, char *); /* hmac */
906 (void)va_arg(va, char *); /* passphrase */
907 (void)va_arg(va, SilcPublicKey); /* founder key */
908 buffer = va_arg(va, SilcBuffer); /* channel public keys */
909 channel = va_arg(va, SilcChannelEntry);
911 tmp = silc_client_chmode(mode,
912 channel->channel_key ?
913 silc_cipher_get_name(channel->channel_key) : "",
915 silc_hmac_get_name(channel->hmac) : "");
917 chanrec = silc_channel_find_entry(server, channel);
918 if (chanrec != NULL) {
919 g_free_not_null(chanrec->mode);
920 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
921 signal_emit("channel mode changed", 1, chanrec);
924 if (idtype == SILC_ID_CLIENT) {
925 client_entry = (SilcClientEntry)entry;
926 printformat_module("fe-common/silc", server, channel->channel_name,
927 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
928 channel->channel_name, tmp ? tmp : "removed all",
929 client_entry->nickname);
930 } else if (idtype == SILC_ID_SERVER) {
931 server_entry = (SilcServerEntry)entry;
932 printformat_module("fe-common/silc", server, channel->channel_name,
933 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
934 channel->channel_name, tmp ? tmp : "removed all",
935 server_entry->server_name);
936 } else if (idtype == SILC_ID_CHANNEL) {
937 channel2 = (SilcChannelEntry)entry;
938 printformat_module("fe-common/silc", server, channel->channel_name,
939 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
940 channel->channel_name, tmp ? tmp : "removed all",
941 channel2->channel_name);
944 /* Print the channel public key list */
946 silc_parse_channel_public_keys(server, channel, buffer);
951 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
953 * Changed user's mode on channel.
956 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
958 idtype = va_arg(va, int);
959 entry = va_arg(va, void *);
960 mode = va_arg(va, SilcUInt32);
961 client_entry2 = va_arg(va, SilcClientEntry);
962 channel = va_arg(va, SilcChannelEntry);
964 tmp = silc_client_chumode(mode);
965 chanrec = silc_channel_find_entry(server, channel);
966 if (chanrec != NULL) {
969 if (client_entry2 == server->conn->local_entry)
970 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
972 nick = silc_nicklist_find(chanrec, client_entry2);
974 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
975 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
976 signal_emit("nick mode changed", 2, chanrec, nick);
980 if (idtype == SILC_ID_CLIENT) {
981 client_entry = (SilcClientEntry)entry;
982 printformat_module("fe-common/silc", server, channel->channel_name,
983 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
984 channel->channel_name, client_entry2->nickname,
985 tmp ? tmp : "removed all",
986 client_entry->nickname);
987 } else if (idtype == SILC_ID_SERVER) {
988 server_entry = (SilcServerEntry)entry;
989 printformat_module("fe-common/silc", server, channel->channel_name,
990 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
991 channel->channel_name, client_entry2->nickname,
992 tmp ? tmp : "removed all",
993 server_entry->server_name);
994 } else if (idtype == SILC_ID_CHANNEL) {
995 channel2 = (SilcChannelEntry)entry;
996 printformat_module("fe-common/silc", server, channel->channel_name,
997 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
998 channel->channel_name, client_entry2->nickname,
999 tmp ? tmp : "removed all",
1000 channel2->channel_name);
1003 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1004 printformat_module("fe-common/silc",
1005 server, channel->channel_name, MSGLEVEL_CRAP,
1006 SILCTXT_CHANNEL_FOUNDER,
1007 channel->channel_name, client_entry2->nickname);
1009 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
1010 printformat_module("fe-common/silc",
1011 server, channel->channel_name, MSGLEVEL_CRAP,
1012 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
1017 case SILC_NOTIFY_TYPE_MOTD:
1022 SILC_LOG_DEBUG(("Notify: MOTD"));
1024 tmp = va_arg(va, char *);
1026 if (!settings_get_bool("skip_motd"))
1027 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
1030 case SILC_NOTIFY_TYPE_KICKED:
1032 * Someone was kicked from channel.
1035 SILC_LOG_DEBUG(("Notify: KICKED"));
1037 client_entry = va_arg(va, SilcClientEntry);
1038 tmp = va_arg(va, char *);
1039 client_entry2 = va_arg(va, SilcClientEntry);
1040 channel = va_arg(va, SilcChannelEntry);
1042 chanrec = silc_channel_find_entry(server, channel);
1044 if (client_entry == conn->local_entry) {
1045 printformat_module("fe-common/silc", server, channel->channel_name,
1046 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1047 channel->channel_name,
1048 client_entry ? client_entry2->nickname : "",
1051 chanrec->kicked = TRUE;
1052 channel_destroy((CHANNEL_REC *)chanrec);
1055 printformat_module("fe-common/silc", server, channel->channel_name,
1056 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1057 client_entry->nickname, channel->channel_name,
1058 client_entry2 ? client_entry2->nickname : "",
1062 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1063 if (nickrec != NULL)
1064 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1069 case SILC_NOTIFY_TYPE_KILLED:
1071 * Someone was killed from the network.
1074 SILC_LOG_DEBUG(("Notify: KILLED"));
1076 client_entry = va_arg(va, SilcClientEntry);
1077 tmp = va_arg(va, char *);
1078 idtype = va_arg(va, int);
1079 entry = va_arg(va, SilcClientEntry);
1081 if (client_entry == conn->local_entry) {
1082 if (idtype == SILC_ID_CLIENT) {
1083 client_entry2 = (SilcClientEntry)entry;
1084 printformat_module("fe-common/silc", server, NULL,
1085 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1086 client_entry2 ? client_entry2->nickname : "",
1088 } else if (idtype == SILC_ID_SERVER) {
1089 server_entry = (SilcServerEntry)entry;
1090 printformat_module("fe-common/silc", server, NULL,
1091 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1092 server_entry->server_name, tmp ? tmp : "");
1093 } else if (idtype == SILC_ID_CHANNEL) {
1094 channel = (SilcChannelEntry)entry;
1095 printformat_module("fe-common/silc", server, NULL,
1096 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1097 channel->channel_name, tmp ? tmp : "");
1100 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1101 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1102 list_tmp->next->next) {
1103 CHANNEL_REC *channel = list_tmp->data;
1104 NICK_REC *nickrec = list_tmp->next->data;
1105 nicklist_remove(channel, nickrec);
1108 if (idtype == SILC_ID_CLIENT) {
1109 client_entry2 = (SilcClientEntry)entry;
1110 printformat_module("fe-common/silc", server, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1112 client_entry->nickname,
1113 client_entry2 ? client_entry2->nickname : "",
1115 } else if (idtype == SILC_ID_SERVER) {
1116 server_entry = (SilcServerEntry)entry;
1117 printformat_module("fe-common/silc", server, NULL,
1118 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1119 client_entry->nickname,
1120 server_entry->server_name, tmp ? tmp : "");
1121 } else if (idtype == SILC_ID_CHANNEL) {
1122 channel = (SilcChannelEntry)entry;
1123 printformat_module("fe-common/silc", server, NULL,
1124 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1125 client_entry->nickname,
1126 channel->channel_name, tmp ? tmp : "");
1131 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1134 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1137 * Server has quit the network.
1140 SilcClientEntry *clients;
1141 SilcUInt32 clients_count;
1143 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1145 (void)va_arg(va, void *);
1146 clients = va_arg(va, SilcClientEntry *);
1147 clients_count = va_arg(va, SilcUInt32);
1149 for (i = 0; i < clients_count; i++) {
1150 memset(buf, 0, sizeof(buf));
1152 /* Print only if we have the nickname. If this client has just quit
1153 when we were only resolving it, it is possible we don't have the
1155 if (clients[i]->nickname) {
1156 if (clients[i]->username)
1157 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1158 clients[i]->username, clients[i]->hostname);
1159 signal_emit("message quit", 4, server, clients[i]->nickname,
1160 clients[i]->username ? buf : "",
1164 silc_server_free_ftp(server, clients[i]);
1166 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1167 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1168 list_tmp->next->next) {
1169 CHANNEL_REC *channel = list_tmp->data;
1170 NICK_REC *nickrec = list_tmp->next->data;
1171 nicklist_remove(channel, nickrec);
1177 case SILC_NOTIFY_TYPE_ERROR:
1179 SilcStatus error = va_arg(va, int);
1181 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1182 "%s", silc_get_status_message(error));
1186 case SILC_NOTIFY_TYPE_WATCH:
1188 SilcNotifyType notify;
1190 client_entry = va_arg(va, SilcClientEntry);
1191 name = va_arg(va, char *); /* Maybe NULL */
1192 mode = va_arg(va, SilcUInt32);
1193 notify = va_arg(va, int);
1195 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1197 printformat_module("fe-common/silc", server, NULL,
1198 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1199 client_entry->nickname, name);
1201 printformat_module("fe-common/silc", server, NULL,
1202 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1203 client_entry->nickname);
1204 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1205 /* See if client was away and is now present */
1206 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1207 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1208 SILC_UMODE_DETACHED)) &&
1209 (client_entry->mode & SILC_UMODE_GONE ||
1210 client_entry->mode & SILC_UMODE_INDISPOSED ||
1211 client_entry->mode & SILC_UMODE_BUSY ||
1212 client_entry->mode & SILC_UMODE_PAGE ||
1213 client_entry->mode & SILC_UMODE_DETACHED)) {
1214 printformat_module("fe-common/silc", server, NULL,
1215 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1216 client_entry->nickname);
1220 memset(buf, 0, sizeof(buf));
1221 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1222 printformat_module("fe-common/silc", server, NULL,
1223 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1224 client_entry->nickname, buf);
1226 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1227 printformat_module("fe-common/silc", server, NULL,
1228 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1229 client_entry->nickname);
1230 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1231 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1232 printformat_module("fe-common/silc", server, NULL,
1233 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1234 client_entry->nickname);
1235 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1236 /* Client logged in to the network */
1237 printformat_module("fe-common/silc", server, NULL,
1238 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1239 client_entry->nickname);
1245 /* Unknown notify */
1246 printformat_module("fe-common/silc", server, NULL,
1247 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1254 /* Called to indicate that connection was either successfully established
1255 or connecting failed. This is also the first time application receives
1256 the SilcClientConnection object which it should save somewhere. */
1258 void silc_connect(SilcClient client, SilcClientConnection conn,
1259 SilcClientConnectionStatus status)
1261 SILC_SERVER_REC *server = conn->context;
1263 if (!server || server->disconnected) {
1264 silc_client_close_connection(client, conn);
1269 case SILC_CLIENT_CONN_SUCCESS:
1270 /* We have successfully connected to server */
1271 server->connected = TRUE;
1272 signal_emit("event connected", 1, server);
1275 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1276 /* We have successfully resumed old detached session */
1277 server->connected = TRUE;
1278 signal_emit("event connected", 1, server);
1280 /* If we resumed old session check whether we need to update
1282 if (strcmp(server->nick, conn->local_entry->nickname)) {
1284 old = g_strdup(server->nick);
1285 server_change_nick(SERVER(server), conn->local_entry->nickname);
1286 nicklist_rename_unique(SERVER(server),
1287 conn->local_entry, server->nick,
1288 conn->local_entry, conn->local_entry->nickname);
1289 signal_emit("message own_nick", 4, server, server->nick, old, "");
1293 /* remove the detach data now */
1297 file = silc_get_session_filename(server);
1308 file = silc_get_session_filename(server);
1310 if (silc_file_size(file) > 0)
1311 printformat_module("fe-common/silc", server, NULL,
1312 MSGLEVEL_CRAP, SILCTXT_REATTACH_FAILED, file);
1316 server->connection_lost = TRUE;
1318 server->conn->context = NULL;
1319 server_disconnect(SERVER(server));
1326 /* Called to indicate that connection was disconnected to the server. */
1328 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1329 SilcStatus status, const char *message)
1331 SILC_SERVER_REC *server = conn->context;
1333 SILC_LOG_DEBUG(("Start"));
1335 if (!server || server->connection_lost)
1338 if (server->conn && server->conn->local_entry) {
1339 nicklist_rename_unique(SERVER(server),
1340 server->conn->local_entry, server->nick,
1341 server->conn->local_entry,
1342 silc_client->username);
1343 silc_change_nick(server, silc_client->username);
1347 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1348 "Server closed connection: %s (%d) %s",
1349 silc_get_status_message(status), status,
1350 message ? message : "");
1353 server->conn->context = NULL;
1354 server->conn = NULL;
1355 server->connection_lost = TRUE;
1356 server_disconnect(SERVER(server));
1359 /* Command handler. This function is called always in the command function.
1360 If error occurs it will be called as well. `conn' is the associated
1361 client connection. `cmd_context' is the command context that was
1362 originally sent to the command. `success' is FALSE if error occured
1363 during command. `command' is the command being processed. It must be
1364 noted that this is not reply from server. This is merely called just
1365 after application has called the command. Just to tell application
1366 that the command really was processed. */
1368 static bool cmode_list_chpks = FALSE;
1370 void silc_command(SilcClient client, SilcClientConnection conn,
1371 SilcClientCommandContext cmd_context, bool success,
1372 SilcCommand command, SilcStatus status)
1374 SILC_SERVER_REC *server = conn->context;
1376 SILC_LOG_DEBUG(("Start"));
1379 silc_say_error("%s", silc_get_status_message(status));
1385 case SILC_COMMAND_INVITE:
1386 if (cmd_context->argc > 2)
1387 printformat_module("fe-common/silc", server, NULL,
1388 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1389 cmd_context->argv[2],
1390 (cmd_context->argv[1][0] == '*' ?
1391 (char *)conn->current_channel->channel_name :
1392 (char *)cmd_context->argv[1]));
1395 case SILC_COMMAND_DETACH:
1396 server->no_reconnect = TRUE;
1399 case SILC_COMMAND_CMODE:
1400 if (cmd_context->argc == 3 &&
1401 !strcmp(cmd_context->argv[2], "+C"))
1402 cmode_list_chpks = TRUE;
1404 cmode_list_chpks = FALSE;
1413 SilcChannelEntry channel;
1417 /* Client info resolving callback when JOIN command reply is received.
1418 This will cache all users on the channel. */
1420 static void silc_client_join_get_users(SilcClient client,
1421 SilcClientConnection conn,
1422 SilcClientEntry *clients,
1423 SilcUInt32 clients_count,
1426 SilcJoinResolve r = context;
1427 SilcChannelEntry channel = r->channel;
1428 SilcHashTableList htl;
1429 SilcChannelUser chu;
1430 SILC_SERVER_REC *server = conn->context;
1431 SILC_CHANNEL_REC *chanrec;
1432 SilcClientEntry founder = NULL;
1435 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1436 silc_hash_table_count(channel->user_list)));
1438 if (!clients && r->retry < 1) {
1439 /* Retry to resolve */
1441 silc_client_get_clients_by_channel(client, conn, channel,
1442 silc_client_join_get_users, context);
1446 chanrec = silc_channel_find(server, channel->channel_name);
1447 if (chanrec == NULL)
1450 silc_hash_table_list(channel->user_list, &htl);
1451 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1452 if (!chu->client->nickname)
1454 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1455 founder = chu->client;
1456 silc_nicklist_insert(chanrec, chu, FALSE);
1458 silc_hash_table_list_reset(&htl);
1460 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1461 nicklist_set_own(CHANNEL(chanrec), ownnick);
1462 signal_emit("channel joined", 1, chanrec);
1463 chanrec->entry = channel;
1466 printformat_module("fe-common/silc", server, channel->channel_name,
1467 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1468 channel->channel_name, chanrec->topic);
1471 if (founder == conn->local_entry) {
1472 printformat_module("fe-common/silc",
1473 server, channel->channel_name, MSGLEVEL_CRAP,
1474 SILCTXT_CHANNEL_FOUNDER_YOU,
1475 channel->channel_name);
1476 signal_emit("nick mode changed", 2, chanrec, ownnick);
1478 printformat_module("fe-common/silc",
1479 server, channel->channel_name, MSGLEVEL_CRAP,
1480 SILCTXT_CHANNEL_FOUNDER,
1481 channel->channel_name, founder->nickname);
1487 SilcClientConnection conn;
1493 void silc_getkey_cb(bool success, void *context)
1495 GetkeyContext getkey = (GetkeyContext)context;
1496 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1497 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1498 ((SilcClientEntry)getkey->entry)->nickname :
1499 ((SilcServerEntry)getkey->entry)->server_name);
1502 printformat_module("fe-common/silc", NULL, NULL,
1503 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1505 printformat_module("fe-common/silc", NULL, NULL,
1506 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1510 silc_free(getkey->fingerprint);
1514 /* Parse an invite or ban list */
1515 void silc_parse_inviteban_list(SilcClient client,
1516 SilcClientConnection conn,
1517 SILC_SERVER_REC *server,
1518 SilcChannelEntry channel,
1519 const char *list_type,
1520 SilcArgumentPayload list)
1523 SilcUInt32 type, len;
1524 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1525 int counter=0, resolving = FALSE;
1527 if (!silc_argument_get_arg_num(list)) {
1528 printformat_module("fe-common/silc", server,
1529 (chanrec ? chanrec->visible_name : NULL),
1530 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1531 channel->channel_name, list_type);
1535 printformat_module("fe-common/silc", server,
1536 (chanrec ? chanrec->visible_name : NULL),
1537 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1538 channel->channel_name, list_type);
1540 /* parse the list */
1541 tmp = silc_argument_get_first_arg(list, &type, &len);
1546 /* an invite string */
1550 if (tmp[len-1] == ',')
1553 list = g_strsplit(tmp, ",", -1);
1555 printformat_module("fe-common/silc", server,
1556 (chanrec ? chanrec->visible_name : NULL),
1557 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1558 ++counter, channel->channel_name, list_type,
1567 char *fingerprint, *babbleprint;
1569 /* tmp is Public Key Payload, take public key from it. */
1570 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1571 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1573 printformat_module("fe-common/silc", server,
1574 (chanrec ? chanrec->visible_name : NULL),
1575 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1576 ++counter, channel->channel_name, list_type,
1577 fingerprint, babbleprint);
1584 SilcClientID *client_id;
1585 SilcClientEntry client_entry;
1587 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1589 if (client_id == NULL) {
1590 silc_say_error("Invalid data in %s list encountered", list_type);
1594 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1597 printformat_module("fe-common/silc", server,
1598 (chanrec ? chanrec->visible_name : NULL),
1599 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1600 ++counter, channel->channel_name, list_type,
1601 client_entry->nickname);
1604 silc_client_get_client_by_id_resolve(client, conn, client_id,
1608 silc_free(client_id);
1614 silc_say_error("Unkown type in %s list: %u (len %u)",
1615 list_type, type, len);
1617 tmp = silc_argument_get_next_arg(list, &type, &len);
1621 printformat_module("fe-common/silc", server,
1622 (chanrec ? chanrec->visible_name : NULL),
1623 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1624 list_type, channel->channel_name);
1627 /* Command reply handler. This function is called always in the command reply
1628 function. If error occurs it will be called as well. Normal scenario
1629 is that it will be called after the received command data has been parsed
1630 and processed. The function is used to pass the received command data to
1633 `conn' is the associated client connection. `cmd_payload' is the command
1634 payload data received from server and it can be ignored. It is provided
1635 if the application would like to re-parse the received command data,
1636 however, it must be noted that the data is parsed already by the library
1637 thus the payload can be ignored. `success' is FALSE if error occured.
1638 In this case arguments are not sent to the application. `command' is the
1639 command reply being processed. The function has variable argument list
1640 and each command defines the number and type of arguments it passes to the
1641 application (on error they are not sent). */
1644 silc_command_reply(SilcClient client, SilcClientConnection conn,
1645 SilcCommandPayload cmd_payload, bool success,
1646 SilcCommand command, SilcStatus status, ...)
1649 SILC_SERVER_REC *server = conn->context;
1650 SILC_CHANNEL_REC *chanrec;
1653 va_start(vp, status);
1655 SILC_LOG_DEBUG(("Start"));
1658 case SILC_COMMAND_WHOIS:
1660 char buf[1024], *nickname, *username, *realname, *nick;
1661 unsigned char *fingerprint;
1662 SilcUInt32 idle, mode;
1663 SilcBuffer channels, user_modes;
1664 SilcClientEntry client_entry;
1667 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1668 /* Print the unknown nick for user */
1669 unsigned char *tmp =
1670 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1673 silc_say_error("%s: %s", tmp,
1674 silc_get_status_message(status));
1676 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1677 /* Try to find the entry for the unknown client ID, since we
1678 might have, and print the nickname of it for user. */
1680 unsigned char *tmp =
1681 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1684 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1687 client_entry = silc_client_get_client_by_id(client, conn,
1689 if (client_entry && client_entry->nickname)
1690 silc_say_error("%s: %s", client_entry->nickname,
1691 silc_get_status_message(status));
1692 silc_free(client_id);
1696 } else if (!success) {
1697 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1701 client_entry = va_arg(vp, SilcClientEntry);
1702 nickname = va_arg(vp, char *);
1703 username = va_arg(vp, char *);
1704 realname = va_arg(vp, char *);
1705 channels = va_arg(vp, SilcBuffer);
1706 mode = va_arg(vp, SilcUInt32);
1707 idle = va_arg(vp, SilcUInt32);
1708 fingerprint = va_arg(vp, unsigned char *);
1709 user_modes = va_arg(vp, SilcBuffer);
1710 attrs = va_arg(vp, SilcDList);
1712 silc_parse_userfqdn(nickname, &nick, NULL);
1713 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1714 SILCTXT_WHOIS_USERINFO, nickname,
1715 client_entry->username, client_entry->hostname,
1716 nick, client_entry->nickname);
1717 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1718 SILCTXT_WHOIS_REALNAME, realname);
1721 if (channels && user_modes) {
1723 SilcDList list = silc_channel_payload_parse_list(channels->data,
1725 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1727 SilcChannelPayload entry;
1730 memset(buf, 0, sizeof(buf));
1731 silc_dlist_start(list);
1732 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1733 SilcUInt32 name_len;
1734 char *m = silc_client_chumode_char(umodes[i++]);
1735 char *name = silc_channel_get_name(entry, &name_len);
1738 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1739 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1740 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1744 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1745 SILCTXT_WHOIS_CHANNELS, buf);
1746 silc_channel_payload_list_free(list);
1752 memset(buf, 0, sizeof(buf));
1753 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1754 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1755 SILCTXT_WHOIS_MODES, buf);
1758 if (idle && nickname) {
1759 memset(buf, 0, sizeof(buf));
1760 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1761 idle > 60 ? (idle / 60) : idle,
1762 idle > 60 ? "minutes" : "seconds");
1764 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1765 SILCTXT_WHOIS_IDLE, buf);
1769 fingerprint = silc_fingerprint(fingerprint, 20);
1770 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1771 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1772 silc_free(fingerprint);
1776 silc_query_attributes_print(server, silc_client, conn, attrs,
1781 case SILC_COMMAND_IDENTIFY:
1783 SilcClientEntry client_entry;
1785 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1786 /* Print the unknown nick for user */
1787 unsigned char *tmp =
1788 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1791 silc_say_error("%s: %s", tmp,
1792 silc_get_status_message(status));
1794 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1795 /* Try to find the entry for the unknown client ID, since we
1796 might have, and print the nickname of it for user. */
1798 unsigned char *tmp =
1799 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1802 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1805 client_entry = silc_client_get_client_by_id(client, conn,
1807 if (client_entry && client_entry->nickname)
1808 silc_say_error("%s: %s", client_entry->nickname,
1809 silc_get_status_message(status));
1810 silc_free(client_id);
1819 case SILC_COMMAND_WHOWAS:
1821 char *nickname, *username, *realname;
1823 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1825 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1828 silc_say_error("%s: %s", tmp,
1829 silc_get_status_message(status));
1831 } else if (!success) {
1832 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1836 (void)va_arg(vp, SilcClientEntry);
1837 nickname = va_arg(vp, char *);
1838 username = va_arg(vp, char *);
1839 realname = va_arg(vp, char *);
1841 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1842 SILCTXT_WHOWAS_USERINFO, nickname, username,
1843 realname ? realname : "");
1847 case SILC_COMMAND_INVITE:
1849 SilcChannelEntry channel;
1851 SilcArgumentPayload invite_list;
1857 channel = va_arg(vp, SilcChannelEntry);
1858 payload = va_arg(vp, SilcBuffer);
1861 SILC_GET16_MSB(argc, payload->data);
1862 invite_list = silc_argument_payload_parse(payload->data + 2,
1863 payload->len - 2, argc);
1865 silc_parse_inviteban_list(client, conn, server, channel,
1866 "invite", invite_list);
1867 silc_argument_payload_free(invite_list);
1873 case SILC_COMMAND_JOIN:
1875 char *channel, *mode, *topic;
1877 SilcChannelEntry channel_entry;
1878 SilcBuffer client_id_list;
1879 SilcUInt32 list_count;
1884 channel = va_arg(vp, char *);
1885 channel_entry = va_arg(vp, SilcChannelEntry);
1886 modei = va_arg(vp, SilcUInt32);
1887 (void)va_arg(vp, SilcUInt32);
1888 (void)va_arg(vp, unsigned char *);
1889 (void)va_arg(vp, unsigned char *);
1890 (void)va_arg(vp, unsigned char *);
1891 topic = va_arg(vp, char *);
1892 (void)va_arg(vp, unsigned char *);
1893 list_count = va_arg(vp, SilcUInt32);
1894 client_id_list = va_arg(vp, SilcBuffer);
1896 chanrec = silc_channel_find(server, channel);
1898 chanrec = silc_channel_create(server, channel, channel, TRUE);
1901 char tmp[256], *cp, *dm = NULL;
1902 g_free_not_null(chanrec->topic);
1904 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1905 memset(tmp, 0, sizeof(tmp));
1907 if (strlen(topic) > sizeof(tmp) - 1) {
1908 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1912 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1917 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1918 signal_emit("channel topic changed", 1, chanrec);
1923 mode = silc_client_chmode(modei,
1924 channel_entry->channel_key ?
1925 silc_cipher_get_name(channel_entry->
1927 channel_entry->hmac ?
1928 silc_hmac_get_name(channel_entry->hmac) : "");
1929 g_free_not_null(chanrec->mode);
1930 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1931 signal_emit("channel mode changed", 1, chanrec);
1933 /* Resolve the client information */
1935 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1936 r->channel = channel_entry;
1937 silc_client_get_clients_by_list(client, conn, list_count,
1939 silc_client_join_get_users, r);
1945 case SILC_COMMAND_NICK:
1948 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1954 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1955 if ((nicks != NULL) &&
1956 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1958 SilcClientEntry collider, old;
1960 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1961 collider = silc_client_get_client_by_id(client, conn,
1964 if (collider != client_entry) {
1966 memset(buf, 0, sizeof(buf));
1967 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1968 collider->username, collider->hostname);
1969 nicklist_rename_unique(SERVER(server),
1971 collider, collider->nickname);
1972 silc_print_nick_change(server, collider->nickname,
1973 client_entry->nickname, buf);
1978 g_slist_free(nicks);
1980 old = g_strdup(server->nick);
1981 server_change_nick(SERVER(server), client_entry->nickname);
1982 nicklist_rename_unique(SERVER(server),
1983 server->conn->local_entry, server->nick,
1984 client_entry, client_entry->nickname);
1985 signal_emit("message own_nick", 4, server, server->nick, old, "");
1990 case SILC_COMMAND_LIST:
1995 char tmp[256], *cp, *dm = NULL;
2000 (void)va_arg(vp, SilcChannelEntry);
2001 name = va_arg(vp, char *);
2002 topic = va_arg(vp, char *);
2003 usercount = va_arg(vp, int);
2005 if (topic && !silc_term_utf8() &&
2006 silc_utf8_valid(topic, strlen(topic))) {
2007 memset(tmp, 0, sizeof(tmp));
2009 if (strlen(topic) > sizeof(tmp) - 1) {
2010 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2014 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2019 if (status == SILC_STATUS_LIST_START ||
2020 status == SILC_STATUS_OK)
2021 printformat_module("fe-common/silc", server, NULL,
2022 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
2025 snprintf(users, sizeof(users) - 1, "N/A");
2027 snprintf(users, sizeof(users) - 1, "%d", usercount);
2028 printformat_module("fe-common/silc", server, NULL,
2029 MSGLEVEL_CRAP, SILCTXT_LIST,
2030 name, users, topic ? topic : "");
2035 case SILC_COMMAND_UMODE:
2043 mode = va_arg(vp, SilcUInt32);
2045 if (mode & SILC_UMODE_SERVER_OPERATOR &&
2046 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
2047 printformat_module("fe-common/silc", server, NULL,
2048 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2050 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
2051 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
2052 printformat_module("fe-common/silc", server, NULL,
2053 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2055 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
2056 if (mode & SILC_UMODE_GONE) {
2057 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
2058 reason = g_strdup(server->away_reason);
2060 reason = g_strdup("away");
2062 reason = g_strdup("");
2064 silc_set_away(reason, server);
2069 server->umode = mode;
2070 signal_emit("user mode changed", 2, server, NULL);
2074 case SILC_COMMAND_OPER:
2078 server->umode |= SILC_UMODE_SERVER_OPERATOR;
2079 signal_emit("user mode changed", 2, server, NULL);
2081 printformat_module("fe-common/silc", server, NULL,
2082 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2085 case SILC_COMMAND_SILCOPER:
2089 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2090 signal_emit("user mode changed", 2, server, NULL);
2092 printformat_module("fe-common/silc", server, NULL,
2093 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2096 case SILC_COMMAND_USERS:
2098 SilcHashTableList htl;
2099 SilcChannelEntry channel;
2100 SilcChannelUser chu;
2105 channel = va_arg(vp, SilcChannelEntry);
2107 printformat_module("fe-common/silc", server, channel->channel_name,
2108 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2109 channel->channel_name);
2111 silc_hash_table_list(channel->user_list, &htl);
2112 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2113 SilcClientEntry e = chu->client;
2114 char stat[5], *mode;
2119 memset(stat, 0, sizeof(stat));
2120 mode = silc_client_chumode_char(chu->mode);
2121 if (e->mode & SILC_UMODE_GONE)
2123 else if (e->mode & SILC_UMODE_INDISPOSED)
2125 else if (e->mode & SILC_UMODE_BUSY)
2127 else if (e->mode & SILC_UMODE_PAGE)
2129 else if (e->mode & SILC_UMODE_HYPER)
2131 else if (e->mode & SILC_UMODE_ROBOT)
2133 else if (e->mode & SILC_UMODE_ANONYMOUS)
2140 printformat_module("fe-common/silc", server, channel->channel_name,
2141 MSGLEVEL_CRAP, SILCTXT_USERS,
2143 e->username ? e->username : "",
2144 e->hostname ? e->hostname : "",
2145 e->realname ? e->realname : "");
2149 silc_hash_table_list_reset(&htl);
2153 case SILC_COMMAND_BAN:
2155 SilcChannelEntry channel;
2157 SilcArgumentPayload ban_list;
2163 channel = va_arg(vp, SilcChannelEntry);
2164 payload = va_arg(vp, SilcBuffer);
2167 SILC_GET16_MSB(argc, payload->data);
2168 ban_list = silc_argument_payload_parse(payload->data + 2,
2169 payload->len - 2, argc);
2171 silc_parse_inviteban_list(client, conn, server, channel,
2173 silc_argument_payload_free(ban_list);
2179 case SILC_COMMAND_GETKEY:
2183 SilcPublicKey public_key;
2186 GetkeyContext getkey;
2192 id_type = va_arg(vp, SilcUInt32);
2193 entry = va_arg(vp, void *);
2194 public_key = va_arg(vp, SilcPublicKey);
2197 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2199 getkey = silc_calloc(1, sizeof(*getkey));
2200 getkey->entry = entry;
2201 getkey->id_type = id_type;
2202 getkey->client = client;
2203 getkey->conn = conn;
2204 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2206 name = (id_type == SILC_ID_CLIENT ?
2207 ((SilcClientEntry)entry)->nickname :
2208 ((SilcServerEntry)entry)->server_name);
2210 silc_verify_public_key_internal(client, conn, name,
2211 (id_type == SILC_ID_CLIENT ?
2212 SILC_SOCKET_TYPE_CLIENT :
2213 SILC_SOCKET_TYPE_SERVER),
2214 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2215 silc_getkey_cb, getkey);
2218 printformat_module("fe-common/silc", server, NULL,
2219 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2224 case SILC_COMMAND_INFO:
2226 SilcServerEntry server_entry;
2233 server_entry = va_arg(vp, SilcServerEntry);
2234 server_name = va_arg(vp, char *);
2235 server_info = va_arg(vp, char *);
2237 if (server_name && server_info )
2239 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2240 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2245 case SILC_COMMAND_TOPIC:
2247 SilcChannelEntry channel;
2249 char tmp[256], *cp, *dm = NULL;
2254 channel = va_arg(vp, SilcChannelEntry);
2255 topic = va_arg(vp, char *);
2257 if (topic && !silc_term_utf8() &&
2258 silc_utf8_valid(topic, strlen(topic))) {
2259 memset(tmp, 0, sizeof(tmp));
2261 if (strlen(topic) > sizeof(tmp) - 1) {
2262 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2266 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2272 chanrec = silc_channel_find_entry(server, channel);
2274 g_free_not_null(chanrec->topic);
2275 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2276 signal_emit("channel topic changed", 1, chanrec);
2278 printformat_module("fe-common/silc", server, channel->channel_name,
2279 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2280 channel->channel_name, topic);
2282 printformat_module("fe-common/silc", server, channel->channel_name,
2283 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2284 channel->channel_name);
2290 case SILC_COMMAND_WATCH:
2293 case SILC_COMMAND_STATS:
2295 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2296 my_router_ops, cell_clients, cell_channels, cell_servers,
2297 clients, channels, servers, routers, server_ops, router_ops;
2299 SilcBufferStruct buf;
2300 unsigned char *tmp_buf;
2302 const char *tmptime;
2303 int days, hours, mins, secs;
2308 tmp_buf = va_arg(vp, unsigned char *);
2309 buf_len = va_arg(vp, SilcUInt32);
2311 if (!tmp_buf || !buf_len) {
2312 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2316 /* Get statistics structure */
2317 silc_buffer_set(&buf, tmp_buf, buf_len);
2318 silc_buffer_unformat(&buf,
2319 SILC_STR_UI_INT(&starttime),
2320 SILC_STR_UI_INT(&uptime),
2321 SILC_STR_UI_INT(&my_clients),
2322 SILC_STR_UI_INT(&my_channels),
2323 SILC_STR_UI_INT(&my_server_ops),
2324 SILC_STR_UI_INT(&my_router_ops),
2325 SILC_STR_UI_INT(&cell_clients),
2326 SILC_STR_UI_INT(&cell_channels),
2327 SILC_STR_UI_INT(&cell_servers),
2328 SILC_STR_UI_INT(&clients),
2329 SILC_STR_UI_INT(&channels),
2330 SILC_STR_UI_INT(&servers),
2331 SILC_STR_UI_INT(&routers),
2332 SILC_STR_UI_INT(&server_ops),
2333 SILC_STR_UI_INT(&router_ops),
2336 tmptime = silc_get_time(starttime);
2337 printformat_module("fe-common/silc", server, NULL,
2338 MSGLEVEL_CRAP, SILCTXT_STATS,
2339 "Local server start time", tmptime);
2341 days = uptime / (24 * 60 * 60);
2342 uptime -= days * (24 * 60 * 60);
2343 hours = uptime / (60 * 60);
2344 uptime -= hours * (60 * 60);
2346 uptime -= mins * 60;
2348 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2349 days, hours, mins, secs);
2350 printformat_module("fe-common/silc", server, NULL,
2351 MSGLEVEL_CRAP, SILCTXT_STATS,
2352 "Local server uptime", tmp);
2354 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2355 printformat_module("fe-common/silc", server, NULL,
2356 MSGLEVEL_CRAP, SILCTXT_STATS,
2357 "Local server clients", tmp);
2359 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2360 printformat_module("fe-common/silc", server, NULL,
2361 MSGLEVEL_CRAP, SILCTXT_STATS,
2362 "Local server channels", tmp);
2364 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2365 printformat_module("fe-common/silc", server, NULL,
2366 MSGLEVEL_CRAP, SILCTXT_STATS,
2367 "Local server operators", tmp);
2369 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2370 printformat_module("fe-common/silc", server, NULL,
2371 MSGLEVEL_CRAP, SILCTXT_STATS,
2372 "Local router operators", tmp);
2374 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2375 printformat_module("fe-common/silc", server, NULL,
2376 MSGLEVEL_CRAP, SILCTXT_STATS,
2377 "Local cell clients", tmp);
2379 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2380 printformat_module("fe-common/silc", server, NULL,
2381 MSGLEVEL_CRAP, SILCTXT_STATS,
2382 "Local cell channels", tmp);
2384 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2385 printformat_module("fe-common/silc", server, NULL,
2386 MSGLEVEL_CRAP, SILCTXT_STATS,
2387 "Local cell servers", tmp);
2389 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2390 printformat_module("fe-common/silc", server, NULL,
2391 MSGLEVEL_CRAP, SILCTXT_STATS,
2392 "Total clients", tmp);
2394 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2395 printformat_module("fe-common/silc", server, NULL,
2396 MSGLEVEL_CRAP, SILCTXT_STATS,
2397 "Total channels", tmp);
2399 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2400 printformat_module("fe-common/silc", server, NULL,
2401 MSGLEVEL_CRAP, SILCTXT_STATS,
2402 "Total servers", tmp);
2404 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2405 printformat_module("fe-common/silc", server, NULL,
2406 MSGLEVEL_CRAP, SILCTXT_STATS,
2407 "Total routers", tmp);
2409 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2410 printformat_module("fe-common/silc", server, NULL,
2411 MSGLEVEL_CRAP, SILCTXT_STATS,
2412 "Total server operators", tmp);
2414 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2415 printformat_module("fe-common/silc", server, NULL,
2416 MSGLEVEL_CRAP, SILCTXT_STATS,
2417 "Total router operators", tmp);
2421 case SILC_COMMAND_CMODE:
2423 SilcChannelEntry channel_entry;
2424 SilcBuffer channel_pubkeys;
2426 channel_entry = va_arg(vp, SilcChannelEntry);
2427 (void)va_arg(vp, SilcUInt32);
2428 (void)va_arg(vp, SilcPublicKey);
2429 channel_pubkeys = va_arg(vp, SilcBuffer);
2431 if (!success || !cmode_list_chpks ||
2432 !channel_entry || !channel_entry->channel_name)
2435 /* Print the channel public key list */
2436 if (channel_pubkeys)
2437 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2439 printformat_module("fe-common/silc", server, NULL,
2440 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2441 channel_entry->channel_name);
2452 SilcClientConnection conn;
2458 SilcSKEPKType pk_type;
2459 SilcVerifyPublicKey completion;
2463 static void verify_public_key_completion(const char *line, void *context)
2465 PublicKeyVerify verify = (PublicKeyVerify)context;
2467 if (line[0] == 'Y' || line[0] == 'y') {
2468 /* Call the completion */
2469 if (verify->completion)
2470 verify->completion(TRUE, verify->context);
2472 /* Save the key for future checking */
2473 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2474 verify->pk_len, SILC_PKCS_FILE_PEM);
2476 /* Call the completion */
2477 if (verify->completion)
2478 verify->completion(FALSE, verify->context);
2480 printformat_module("fe-common/silc", NULL, NULL,
2481 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2482 verify->entity_name ? verify->entity_name :
2486 silc_free(verify->filename);
2487 silc_free(verify->entity);
2488 silc_free(verify->entity_name);
2489 silc_free(verify->pk);
2493 /* Internal routine to verify public key. If the `completion' is provided
2494 it will be called to indicate whether public was verified or not. For
2495 server/router public key this will check for filename that includes the
2496 remote host's IP address and remote host's hostname. */
2499 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2500 const char *name, SilcSocketType conn_type,
2501 unsigned char *pk, SilcUInt32 pk_len,
2502 SilcSKEPKType pk_type,
2503 SilcVerifyPublicKey completion, void *context)
2506 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2507 char *fingerprint, *babbleprint, *format;
2510 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2511 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2512 "server" : "client");
2513 PublicKeyVerify verify;
2515 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2516 printformat_module("fe-common/silc", NULL, NULL,
2517 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2520 completion(FALSE, context);
2524 pw = getpwuid(getuid());
2527 completion(FALSE, context);
2531 memset(filename, 0, sizeof(filename));
2532 memset(filename2, 0, sizeof(filename2));
2533 memset(file, 0, sizeof(file));
2535 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2536 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2538 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2539 conn->sock->ip, conn->sock->port);
2540 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2541 get_irssi_dir(), entity, file);
2543 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2544 conn->sock->hostname, conn->sock->port);
2545 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2546 get_irssi_dir(), entity, file);
2551 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2552 name, conn->sock->port);
2553 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2554 get_irssi_dir(), entity, file);
2559 /* Replace all whitespaces with `_'. */
2560 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2561 for (i = 0; i < strlen(fingerprint); i++)
2562 if (fingerprint[i] == ' ')
2563 fingerprint[i] = '_';
2565 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2566 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2567 get_irssi_dir(), entity, file);
2568 silc_free(fingerprint);
2573 /* Take fingerprint of the public key */
2574 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2575 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2577 verify = silc_calloc(1, sizeof(*verify));
2578 verify->client = client;
2579 verify->conn = conn;
2580 verify->filename = strdup(ipf);
2581 verify->entity = strdup(entity);
2582 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2583 (name ? strdup(name) : strdup(conn->sock->hostname))
2585 verify->pk = silc_memdup(pk, pk_len);
2586 verify->pk_len = pk_len;
2587 verify->pk_type = pk_type;
2588 verify->completion = completion;
2589 verify->context = context;
2591 /* Check whether this key already exists */
2592 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2593 /* Key does not exist, ask user to verify the key and save it */
2595 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2596 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2597 verify->entity_name : entity);
2598 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2599 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2600 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2601 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2602 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2603 SILCTXT_PUBKEY_ACCEPT);
2604 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2607 silc_free(fingerprint);
2610 /* The key already exists, verify it. */
2611 SilcPublicKey public_key;
2612 unsigned char *encpk;
2613 SilcUInt32 encpk_len;
2615 /* Load the key file, try for both IP filename and hostname filename */
2616 if (!silc_pkcs_load_public_key(ipf, &public_key,
2617 SILC_PKCS_FILE_PEM) &&
2618 !silc_pkcs_load_public_key(ipf, &public_key,
2619 SILC_PKCS_FILE_BIN) &&
2620 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2621 SILC_PKCS_FILE_PEM) &&
2622 !silc_pkcs_load_public_key(hostf, &public_key,
2623 SILC_PKCS_FILE_BIN)))) {
2624 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2625 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2626 verify->entity_name : entity);
2627 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2628 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2629 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2630 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2631 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2632 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2633 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2634 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2635 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2638 silc_free(fingerprint);
2642 /* Encode the key data */
2643 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2645 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2646 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2647 verify->entity_name : entity);
2648 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2649 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2650 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2651 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2652 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2653 SILCTXT_PUBKEY_MALFORMED, entity);
2654 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2655 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2656 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2659 silc_free(fingerprint);
2663 /* Compare the keys */
2664 if (memcmp(encpk, pk, encpk_len)) {
2665 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2666 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2667 verify->entity_name : entity);
2668 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2669 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2670 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2671 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2672 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2673 SILCTXT_PUBKEY_NO_MATCH, entity);
2674 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2675 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2676 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2677 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2679 /* Ask user to verify the key and save it */
2680 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2681 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2682 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2685 silc_free(fingerprint);
2689 /* Local copy matched */
2691 completion(TRUE, context);
2692 silc_free(fingerprint);
2693 silc_free(verify->filename);
2694 silc_free(verify->entity);
2695 silc_free(verify->entity_name);
2696 silc_free(verify->pk);
2701 /* Verifies received public key. The `conn_type' indicates which entity
2702 (server, client etc.) has sent the public key. If user decides to trust
2703 the key may be saved as trusted public key for later use. The
2704 `completion' must be called after the public key has been verified. */
2707 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2708 SilcSocketType conn_type, unsigned char *pk,
2709 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2710 SilcVerifyPublicKey completion, void *context)
2712 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2714 completion, context);
2717 /* Asks passphrase from user on the input line. */
2720 SilcAskPassphrase completion;
2724 void ask_passphrase_completion(const char *passphrase, void *context)
2726 AskPassphrase p = (AskPassphrase)context;
2727 if (passphrase && passphrase[0] == '\0')
2729 p->completion((unsigned char *)passphrase,
2730 passphrase ? strlen(passphrase) : 0, p->context);
2734 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2735 SilcAskPassphrase completion, void *context)
2737 AskPassphrase p = silc_calloc(1, sizeof(*p));
2738 p->completion = completion;
2739 p->context = context;
2741 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2742 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2746 SilcGetAuthMeth completion;
2748 } *InternalGetAuthMethod;
2750 /* Callback called when we've received the authentication method information
2751 from the server after we've requested it. This will get the authentication
2752 data from the user if needed. */
2754 static void silc_get_auth_method_callback(SilcClient client,
2755 SilcClientConnection conn,
2756 SilcAuthMethod auth_meth,
2759 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2761 SILC_LOG_DEBUG(("Start"));
2763 switch (auth_meth) {
2764 case SILC_AUTH_NONE:
2765 /* No authentication required. */
2766 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2768 case SILC_AUTH_PASSWORD:
2770 /* Check whether we find the password for this server in our
2771 configuration. If not, then don't provide so library will ask
2772 it from the user. */
2773 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2775 if (!setup || !setup->password) {
2776 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2780 (*internal->completion)(TRUE, auth_meth, setup->password,
2781 strlen(setup->password), internal->context);
2784 case SILC_AUTH_PUBLIC_KEY:
2785 /* Do not get the authentication data now, the library will generate
2786 it using our default key, if we do not provide it here. */
2787 /* XXX In the future when we support multiple local keys and multiple
2788 local certificates we will need to ask from user which one to use. */
2789 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2793 silc_free(internal);
2796 /* Find authentication method and authentication data by hostname and
2797 port. The hostname may be IP address as well. The found authentication
2798 method and authentication data is returned to `auth_meth', `auth_data'
2799 and `auth_data_len'. The function returns TRUE if authentication method
2800 is found and FALSE if not. `conn' may be NULL. */
2802 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2803 char *hostname, SilcUInt16 port,
2804 SilcGetAuthMeth completion, void *context)
2806 InternalGetAuthMethod internal;
2808 SILC_LOG_DEBUG(("Start"));
2810 /* If we do not have this connection configured by the user in a
2811 configuration file then resolve the authentication method from the
2812 server for this session. */
2813 internal = silc_calloc(1, sizeof(*internal));
2814 internal->completion = completion;
2815 internal->context = context;
2817 silc_client_request_authentication_method(client, conn,
2818 silc_get_auth_method_callback,
2822 /* Notifies application that failure packet was received. This is called
2823 if there is some protocol active in the client. The `protocol' is the
2824 protocol context. The `failure' is opaque pointer to the failure
2825 indication. Note, that the `failure' is protocol dependant and application
2826 must explicitly cast it to correct type. Usually `failure' is 32 bit
2827 failure type (see protocol specs for all protocol failure types). */
2829 void silc_failure(SilcClient client, SilcClientConnection conn,
2830 SilcProtocol protocol, void *failure)
2832 SILC_LOG_DEBUG(("Start"));
2834 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2835 SilcSKEStatus status = (SilcSKEStatus)failure;
2837 if (status == SILC_SKE_STATUS_BAD_VERSION)
2838 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2839 SILCTXT_KE_BAD_VERSION);
2840 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2841 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2842 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2843 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2844 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2845 SILCTXT_KE_UNKNOWN_GROUP);
2846 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2847 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2848 SILCTXT_KE_UNKNOWN_CIPHER);
2849 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2850 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2851 SILCTXT_KE_UNKNOWN_PKCS);
2852 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2853 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2854 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2855 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2856 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2857 SILCTXT_KE_UNKNOWN_HMAC);
2858 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2859 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2860 SILCTXT_KE_INCORRECT_SIGNATURE);
2861 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2862 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2863 SILCTXT_KE_INVALID_COOKIE);
2866 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2867 SilcUInt32 err = (SilcUInt32)failure;
2869 if (err == SILC_AUTH_FAILED)
2870 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2871 SILCTXT_AUTH_FAILED);
2875 /* Asks whether the user would like to perform the key agreement protocol.
2876 This is called after we have received an key agreement packet or an
2877 reply to our key agreement packet. This returns TRUE if the user wants
2878 the library to perform the key agreement protocol and FALSE if it is not
2879 desired (application may start it later by calling the function
2880 silc_client_perform_key_agreement). */
2882 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2883 SilcClientEntry client_entry, const char *hostname,
2884 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2889 SILC_LOG_DEBUG(("Start"));
2891 /* We will just display the info on the screen and return FALSE and user
2892 will have to start the key agreement with a command. */
2895 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2898 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2899 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2901 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2902 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2903 client_entry->nickname, hostname, portstr);
2911 /* Notifies application that file transfer protocol session is being
2912 requested by the remote client indicated by the `client_entry' from
2913 the `hostname' and `port'. The `session_id' is the file transfer
2914 session and it can be used to either accept or reject the file
2915 transfer request, by calling the silc_client_file_receive or
2916 silc_client_file_close, respectively. */
2918 void silc_ftp(SilcClient client, SilcClientConnection conn,
2919 SilcClientEntry client_entry, SilcUInt32 session_id,
2920 const char *hostname, SilcUInt16 port)
2922 SILC_SERVER_REC *server;
2924 FtpSession ftp = NULL;
2926 SILC_LOG_DEBUG(("Start"));
2928 server = conn->context;
2930 silc_dlist_start(server->ftp_sessions);
2931 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2932 if (ftp->client_entry == client_entry &&
2933 ftp->session_id == session_id) {
2934 server->current_session = ftp;
2938 if (ftp == SILC_LIST_END) {
2939 ftp = silc_calloc(1, sizeof(*ftp));
2940 ftp->client_entry = client_entry;
2941 ftp->session_id = session_id;
2944 silc_dlist_add(server->ftp_sessions, ftp);
2945 server->current_session = ftp;
2949 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2952 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2953 SILCTXT_FILE_REQUEST, client_entry->nickname);
2955 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2956 SILCTXT_FILE_REQUEST_HOST,
2957 client_entry->nickname, hostname, portstr);
2960 /* Delivers SILC session detachment data indicated by `detach_data' to the
2961 application. If application has issued SILC_COMMAND_DETACH command
2962 the client session in the SILC network is not quit. The client remains
2963 in the network but is detached. The detachment data may be used later
2964 to resume the session in the SILC Network. The appliation is
2965 responsible of saving the `detach_data', to for example in a file.
2967 The detachment data can be given as argument to the functions
2968 silc_client_connect_to_server, or silc_client_add_connection when
2969 creating connection to remote server, inside SilcClientConnectionParams
2970 structure. If it is provided the client library will attempt to resume
2971 the session in the network. After the connection is created
2972 successfully, the application is responsible of setting the user
2973 interface for user into the same state it was before detaching (showing
2974 same channels, channel modes, etc). It can do this by fetching the
2975 information (like joined channels) from the client library. */
2978 silc_detach(SilcClient client, SilcClientConnection conn,
2979 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2981 SILC_SERVER_REC *server = conn->context;
2984 /* Save the detachment data to file. */
2986 file = silc_get_session_filename(server);
2987 silc_file_writefile(file, detach_data, detach_data_len);
2992 /* SILC client operations */
2993 SilcClientOperations ops = {
2995 silc_channel_message,
2996 silc_private_message,
3002 silc_get_auth_method,
3003 silc_verify_public_key,
3004 silc_ask_passphrase,