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", 6, 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", 6, server, message,
453 nick->nick, nick->host, channel->channel_name);
455 /* FIXME: replace those printformat calls with signals and add signature
456 information to them (if present) */
457 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
458 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
459 char tmp[256], *cp, *dm = NULL;
460 memset(tmp, 0, sizeof(tmp));
462 if(message_len > sizeof(tmp) - 1) {
463 dm = silc_calloc(message_len + 1, sizeof(*dm));
466 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
468 printformat_module("fe-common/silc", server, channel->channel_name,
469 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
470 nick == NULL ? "[<unknown>]" : nick->nick, cp);
473 printformat_module("fe-common/silc", server, channel->channel_name,
474 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
475 nick == NULL ? "[<unknown>]" : nick->nick,
479 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
480 char tmp[256], *cp, *dm = NULL;
482 memset(tmp, 0, sizeof(tmp));
484 if (message_len > sizeof(tmp) - 1) {
485 dm = silc_calloc(message_len + 1, sizeof(*dm));
489 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
491 if (flags & SILC_MESSAGE_FLAG_SIGNED)
492 signal_emit("message signed_public", 6, server, cp,
493 nick == NULL ? "[<unknown>]" : nick->nick,
494 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
495 chanrec->name, verified);
497 signal_emit("message public", 6, server, cp,
498 nick == NULL ? "[<unknown>]" : nick->nick,
499 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
500 chanrec->name, nick);
505 if (flags & SILC_MESSAGE_FLAG_SIGNED)
506 signal_emit("message signed_public", 6, server, message,
507 nick == NULL ? "[<unknown>]" : nick->nick,
508 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
509 chanrec->name, verified);
511 signal_emit("message public", 6, server, message,
512 nick == NULL ? "[<unknown>]" : nick->nick,
513 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
514 chanrec->name, nick);
518 /* Private message to the client. The `sender' is the nickname of the
519 sender received in the packet. */
521 void silc_private_message(SilcClient client, SilcClientConnection conn,
522 SilcClientEntry sender, SilcMessagePayload payload,
523 SilcMessageFlags flags,
524 const unsigned char *message,
525 SilcUInt32 message_len)
527 SILC_SERVER_REC *server;
531 SILC_LOG_DEBUG(("Start"));
533 server = conn == NULL ? NULL : conn->context;
534 memset(userhost, 0, sizeof(userhost));
535 if (sender->username)
536 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
537 sender->username, sender->hostname);
539 /* If the messages is digitally signed, verify it, if possible. */
540 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
541 if (!settings_get_bool("ignore_message_signatures")) {
542 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
543 verified = verify_message_signature(sender, sig, payload);
545 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
549 if (flags & SILC_MESSAGE_FLAG_DATA) {
550 silc_emit_mime_sig(server,
552 (WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
554 message, message_len,
555 sender->nickname ? sender->nickname : "[<unknown>]",
556 flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
563 if (flags & SILC_MESSAGE_FLAG_ACTION) {
564 if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
565 char tmp[256], *cp, *dm = NULL;
566 memset(tmp, 0, sizeof(tmp));
568 if(message_len > sizeof(tmp) - 1) {
569 dm = silc_calloc(message_len + 1, sizeof(*dm));
572 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
574 if (flags & SILC_MESSAGE_FLAG_SIGNED)
575 signal_emit("message silc signed_private_action", 6, server, cp,
576 sender->nickname ? sender->nickname : "[<unknown>]",
577 sender->username ? userhost : NULL,
580 signal_emit("message silc private_action", 6, server, cp,
581 sender->nickname ? sender->nickname : "[<unknown>]",
582 sender->username ? userhost : NULL, NULL);
585 if (flags & SILC_MESSAGE_FLAG_SIGNED)
586 signal_emit("message silc signed_private_action", 6, server, message,
587 sender->nickname ? sender->nickname : "[<unknown>]",
588 sender->username ? userhost : NULL,
591 signal_emit("message silc private_action", 6, server, message,
592 sender->nickname ? sender->nickname : "[<unknown>]",
593 sender->username ? userhost : NULL, NULL);
597 /* FIXME: added notices */
599 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
600 char tmp[256], *cp, *dm = NULL;
602 memset(tmp, 0, sizeof(tmp));
604 if (message_len > sizeof(tmp) - 1) {
605 dm = silc_calloc(message_len + 1, sizeof(*dm));
609 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
611 if (flags & SILC_MESSAGE_FLAG_SIGNED)
612 signal_emit("message signed_private", 5, server, cp,
613 sender->nickname ? sender->nickname : "[<unknown>]",
614 sender->username ? userhost : NULL, verified);
616 signal_emit("message private", 4, server, cp,
617 sender->nickname ? sender->nickname : "[<unknown>]",
618 sender->username ? userhost : NULL);
623 if (flags & SILC_MESSAGE_FLAG_SIGNED)
624 signal_emit("message signed_private", 5, server, message,
625 sender->nickname ? sender->nickname : "[<unknown>]",
626 sender->username ? userhost : NULL, verified);
628 signal_emit("message private", 4, server, message,
629 sender->nickname ? sender->nickname : "[<unknown>]",
630 sender->username ? userhost : NULL);
633 /* Notify message to the client. The notify arguments are sent in the
634 same order as servers sends them. The arguments are same as received
635 from the server except for ID's. If ID is received application receives
636 the corresponding entry to the ID. For example, if Client ID is received
637 application receives SilcClientEntry. Also, if the notify type is
638 for channel the channel entry is sent to application (even if server
639 does not send it). */
641 void silc_notify(SilcClient client, SilcClientConnection conn,
642 SilcNotifyType type, ...)
645 SILC_SERVER_REC *server;
646 SILC_CHANNEL_REC *chanrec;
647 SILC_NICK_REC *nickrec;
648 SilcClientEntry client_entry, client_entry2;
649 SilcChannelEntry channel, channel2;
650 SilcServerEntry server_entry;
656 GSList *list1, *list_tmp;
659 SILC_LOG_DEBUG(("Start"));
663 server = conn == NULL ? NULL : conn->context;
666 case SILC_NOTIFY_TYPE_NONE:
667 /* Some generic notice from server */
668 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
671 case SILC_NOTIFY_TYPE_INVITE:
673 * Invited or modified invite list.
676 SILC_LOG_DEBUG(("Notify: INVITE"));
678 channel = va_arg(va, SilcChannelEntry);
679 name = va_arg(va, char *);
680 client_entry = va_arg(va, SilcClientEntry);
682 memset(buf, 0, sizeof(buf));
683 snprintf(buf, sizeof(buf) - 1, "%s@%s",
684 client_entry->username, client_entry->hostname);
685 signal_emit("message invite", 4, server, channel ? channel->channel_name :
686 name, client_entry->nickname, buf);
689 case SILC_NOTIFY_TYPE_JOIN:
694 SILC_LOG_DEBUG(("Notify: JOIN"));
696 client_entry = va_arg(va, SilcClientEntry);
697 channel = va_arg(va, SilcChannelEntry);
699 if (client_entry == server->conn->local_entry) {
700 /* You joined to channel */
701 chanrec = silc_channel_find(server, channel->channel_name);
702 if (chanrec != NULL && !chanrec->joined)
703 chanrec->entry = channel;
705 chanrec = silc_channel_find_entry(server, channel);
706 if (chanrec != NULL) {
707 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
709 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
713 memset(buf, 0, sizeof(buf));
714 if (client_entry->username)
715 snprintf(buf, sizeof(buf) - 1, "%s@%s",
716 client_entry->username, client_entry->hostname);
717 signal_emit("message join", 4, server, channel->channel_name,
718 client_entry->nickname,
719 client_entry->username == NULL ? "" : buf);
722 case SILC_NOTIFY_TYPE_LEAVE:
727 SILC_LOG_DEBUG(("Notify: LEAVE"));
729 client_entry = va_arg(va, SilcClientEntry);
730 channel = va_arg(va, SilcChannelEntry);
732 memset(buf, 0, sizeof(buf));
733 if (client_entry->username)
734 snprintf(buf, sizeof(buf) - 1, "%s@%s",
735 client_entry->username, client_entry->hostname);
736 signal_emit("message part", 5, server, channel->channel_name,
737 client_entry->nickname, client_entry->username ?
738 buf : "", client_entry->nickname);
740 chanrec = silc_channel_find_entry(server, channel);
741 if (chanrec != NULL) {
742 nickrec = silc_nicklist_find(chanrec, client_entry);
744 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
748 case SILC_NOTIFY_TYPE_SIGNOFF:
753 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
755 client_entry = va_arg(va, SilcClientEntry);
756 tmp = va_arg(va, char *);
758 silc_server_free_ftp(server, client_entry);
760 /* Print only if we have the nickname. If this cliente has just quit
761 when we were only resolving it, it is possible we don't have the
763 if (client_entry->nickname) {
764 memset(buf, 0, sizeof(buf));
765 if (client_entry->username)
766 snprintf(buf, sizeof(buf) - 1, "%s@%s",
767 client_entry->username, client_entry->hostname);
768 signal_emit("message quit", 4, server, client_entry->nickname,
769 client_entry->username ? buf : "",
773 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
774 for (list_tmp = list1; list_tmp != NULL; list_tmp =
775 list_tmp->next->next) {
776 CHANNEL_REC *channel = list_tmp->data;
777 NICK_REC *nickrec = list_tmp->next->data;
779 nicklist_remove(channel, nickrec);
783 case SILC_NOTIFY_TYPE_TOPIC_SET:
788 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
790 idtype = va_arg(va, int);
791 entry = va_arg(va, void *);
792 tmp = va_arg(va, char *);
793 channel = va_arg(va, SilcChannelEntry);
795 chanrec = silc_channel_find_entry(server, channel);
796 if (chanrec != NULL) {
797 char tmp2[256], *cp, *dm = NULL;
799 g_free_not_null(chanrec->topic);
800 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
801 memset(tmp2, 0, sizeof(tmp2));
803 if (strlen(tmp) > sizeof(tmp2) - 1) {
804 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
808 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
813 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
814 signal_emit("channel topic changed", 1, chanrec);
819 if (idtype == SILC_ID_CLIENT) {
820 client_entry = (SilcClientEntry)entry;
821 memset(buf, 0, sizeof(buf));
822 snprintf(buf, sizeof(buf) - 1, "%s@%s",
823 client_entry->username, client_entry->hostname);
824 signal_emit("message topic", 5, server, channel->channel_name,
825 tmp, client_entry->nickname, buf);
826 } else if (idtype == SILC_ID_SERVER) {
827 server_entry = (SilcServerEntry)entry;
828 signal_emit("message topic", 5, server, channel->channel_name,
829 tmp, server_entry->server_name,
830 server_entry->server_name);
831 } else if (idtype == SILC_ID_CHANNEL) {
832 channel = (SilcChannelEntry)entry;
833 signal_emit("message topic", 5, server, channel->channel_name,
834 tmp, channel->channel_name, channel->channel_name);
838 case SILC_NOTIFY_TYPE_NICK_CHANGE:
843 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
845 client_entry = va_arg(va, SilcClientEntry);
846 client_entry2 = va_arg(va, SilcClientEntry);
848 if (!strcmp(client_entry->nickname, client_entry2->nickname))
851 memset(buf, 0, sizeof(buf));
852 snprintf(buf, sizeof(buf) - 1, "%s@%s",
853 client_entry2->username, client_entry2->hostname);
854 nicklist_rename_unique(SERVER(server),
855 client_entry, client_entry->nickname,
856 client_entry2, client_entry2->nickname);
857 signal_emit("message nick", 4, server, client_entry2->nickname,
858 client_entry->nickname, buf);
861 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
863 * Changed channel mode.
866 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
868 idtype = va_arg(va, int);
869 entry = va_arg(va, void *);
870 mode = va_arg(va, SilcUInt32);
871 (void)va_arg(va, char *); /* cipher */
872 (void)va_arg(va, char *); /* hmac */
873 (void)va_arg(va, char *); /* passphrase */
874 (void)va_arg(va, SilcPublicKey); /* founder key */
875 buffer = va_arg(va, SilcBuffer); /* channel public keys */
876 channel = va_arg(va, SilcChannelEntry);
878 tmp = silc_client_chmode(mode,
879 channel->channel_key ?
880 silc_cipher_get_name(channel->channel_key) : "",
882 silc_hmac_get_name(channel->hmac) : "");
884 chanrec = silc_channel_find_entry(server, channel);
885 if (chanrec != NULL) {
886 g_free_not_null(chanrec->mode);
887 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
888 signal_emit("channel mode changed", 1, chanrec);
891 if (idtype == SILC_ID_CLIENT) {
892 client_entry = (SilcClientEntry)entry;
893 printformat_module("fe-common/silc", server, channel->channel_name,
894 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
895 channel->channel_name, tmp ? tmp : "removed all",
896 client_entry->nickname);
897 } else if (idtype == SILC_ID_SERVER) {
898 server_entry = (SilcServerEntry)entry;
899 printformat_module("fe-common/silc", server, channel->channel_name,
900 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
901 channel->channel_name, tmp ? tmp : "removed all",
902 server_entry->server_name);
903 } else if (idtype == SILC_ID_CHANNEL) {
904 channel2 = (SilcChannelEntry)entry;
905 printformat_module("fe-common/silc", server, channel->channel_name,
906 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
907 channel->channel_name, tmp ? tmp : "removed all",
908 channel2->channel_name);
911 /* Print the channel public key list */
913 silc_parse_channel_public_keys(server, channel, buffer);
918 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
920 * Changed user's mode on channel.
923 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
925 idtype = va_arg(va, int);
926 entry = va_arg(va, void *);
927 mode = va_arg(va, SilcUInt32);
928 client_entry2 = va_arg(va, SilcClientEntry);
929 channel = va_arg(va, SilcChannelEntry);
931 tmp = silc_client_chumode(mode);
932 chanrec = silc_channel_find_entry(server, channel);
933 if (chanrec != NULL) {
936 if (client_entry2 == server->conn->local_entry)
937 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
939 nick = silc_nicklist_find(chanrec, client_entry2);
941 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
942 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
943 signal_emit("nick mode changed", 2, chanrec, nick);
947 if (idtype == SILC_ID_CLIENT) {
948 client_entry = (SilcClientEntry)entry;
949 printformat_module("fe-common/silc", server, channel->channel_name,
950 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
951 channel->channel_name, client_entry2->nickname,
952 tmp ? tmp : "removed all",
953 client_entry->nickname);
954 } else if (idtype == SILC_ID_SERVER) {
955 server_entry = (SilcServerEntry)entry;
956 printformat_module("fe-common/silc", server, channel->channel_name,
957 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
958 channel->channel_name, client_entry2->nickname,
959 tmp ? tmp : "removed all",
960 server_entry->server_name);
961 } else if (idtype == SILC_ID_CHANNEL) {
962 channel2 = (SilcChannelEntry)entry;
963 printformat_module("fe-common/silc", server, channel->channel_name,
964 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
965 channel->channel_name, client_entry2->nickname,
966 tmp ? tmp : "removed all",
967 channel2->channel_name);
970 if (mode & SILC_CHANNEL_UMODE_CHANFO)
971 printformat_module("fe-common/silc",
972 server, channel->channel_name, MSGLEVEL_CRAP,
973 SILCTXT_CHANNEL_FOUNDER,
974 channel->channel_name, client_entry2->nickname);
976 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
977 printformat_module("fe-common/silc",
978 server, channel->channel_name, MSGLEVEL_CRAP,
979 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
984 case SILC_NOTIFY_TYPE_MOTD:
989 SILC_LOG_DEBUG(("Notify: MOTD"));
991 tmp = va_arg(va, char *);
993 if (!settings_get_bool("skip_motd"))
994 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
997 case SILC_NOTIFY_TYPE_KICKED:
999 * Someone was kicked from channel.
1002 SILC_LOG_DEBUG(("Notify: KICKED"));
1004 client_entry = va_arg(va, SilcClientEntry);
1005 tmp = va_arg(va, char *);
1006 client_entry2 = va_arg(va, SilcClientEntry);
1007 channel = va_arg(va, SilcChannelEntry);
1009 chanrec = silc_channel_find_entry(server, channel);
1011 if (client_entry == conn->local_entry) {
1012 printformat_module("fe-common/silc", server, channel->channel_name,
1013 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
1014 channel->channel_name,
1015 client_entry ? client_entry2->nickname : "",
1018 chanrec->kicked = TRUE;
1019 channel_destroy((CHANNEL_REC *)chanrec);
1022 printformat_module("fe-common/silc", server, channel->channel_name,
1023 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
1024 client_entry->nickname, channel->channel_name,
1025 client_entry2 ? client_entry2->nickname : "",
1029 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
1030 if (nickrec != NULL)
1031 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
1036 case SILC_NOTIFY_TYPE_KILLED:
1038 * Someone was killed from the network.
1041 SILC_LOG_DEBUG(("Notify: KILLED"));
1043 client_entry = va_arg(va, SilcClientEntry);
1044 tmp = va_arg(va, char *);
1045 idtype = va_arg(va, int);
1046 entry = va_arg(va, SilcClientEntry);
1048 if (client_entry == conn->local_entry) {
1049 if (idtype == SILC_ID_CLIENT) {
1050 client_entry2 = (SilcClientEntry)entry;
1051 printformat_module("fe-common/silc", server, NULL,
1052 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1053 client_entry2 ? client_entry2->nickname : "",
1055 } else if (idtype == SILC_ID_SERVER) {
1056 server_entry = (SilcServerEntry)entry;
1057 printformat_module("fe-common/silc", server, NULL,
1058 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1059 server_entry->server_name, tmp ? tmp : "");
1060 } else if (idtype == SILC_ID_CHANNEL) {
1061 channel = (SilcChannelEntry)entry;
1062 printformat_module("fe-common/silc", server, NULL,
1063 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
1064 channel->channel_name, tmp ? tmp : "");
1067 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
1068 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1069 list_tmp->next->next) {
1070 CHANNEL_REC *channel = list_tmp->data;
1071 NICK_REC *nickrec = list_tmp->next->data;
1072 nicklist_remove(channel, nickrec);
1075 if (idtype == SILC_ID_CLIENT) {
1076 client_entry2 = (SilcClientEntry)entry;
1077 printformat_module("fe-common/silc", server, NULL,
1078 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1079 client_entry->nickname,
1080 client_entry2 ? client_entry2->nickname : "",
1082 } else if (idtype == SILC_ID_SERVER) {
1083 server_entry = (SilcServerEntry)entry;
1084 printformat_module("fe-common/silc", server, NULL,
1085 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1086 client_entry->nickname,
1087 server_entry->server_name, tmp ? tmp : "");
1088 } else if (idtype == SILC_ID_CHANNEL) {
1089 channel = (SilcChannelEntry)entry;
1090 printformat_module("fe-common/silc", server, NULL,
1091 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
1092 client_entry->nickname,
1093 channel->channel_name, tmp ? tmp : "");
1098 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1101 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1104 * Server has quit the network.
1107 SilcClientEntry *clients;
1108 SilcUInt32 clients_count;
1110 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1112 (void)va_arg(va, void *);
1113 clients = va_arg(va, SilcClientEntry *);
1114 clients_count = va_arg(va, SilcUInt32);
1116 for (i = 0; i < clients_count; i++) {
1117 memset(buf, 0, sizeof(buf));
1119 /* Print only if we have the nickname. If this client has just quit
1120 when we were only resolving it, it is possible we don't have the
1122 if (clients[i]->nickname) {
1123 if (clients[i]->username)
1124 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1125 clients[i]->username, clients[i]->hostname);
1126 signal_emit("message quit", 4, server, clients[i]->nickname,
1127 clients[i]->username ? buf : "",
1131 silc_server_free_ftp(server, clients[i]);
1133 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1134 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1135 list_tmp->next->next) {
1136 CHANNEL_REC *channel = list_tmp->data;
1137 NICK_REC *nickrec = list_tmp->next->data;
1138 nicklist_remove(channel, nickrec);
1144 case SILC_NOTIFY_TYPE_ERROR:
1146 SilcStatus error = va_arg(va, int);
1148 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1149 "%s", silc_get_status_message(error));
1153 case SILC_NOTIFY_TYPE_WATCH:
1155 SilcNotifyType notify;
1157 client_entry = va_arg(va, SilcClientEntry);
1158 name = va_arg(va, char *); /* Maybe NULL */
1159 mode = va_arg(va, SilcUInt32);
1160 notify = va_arg(va, int);
1162 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1164 printformat_module("fe-common/silc", server, NULL,
1165 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1166 client_entry->nickname, name);
1168 printformat_module("fe-common/silc", server, NULL,
1169 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1170 client_entry->nickname);
1171 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1172 /* See if client was away and is now present */
1173 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1174 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1175 SILC_UMODE_DETACHED)) &&
1176 (client_entry->mode & SILC_UMODE_GONE ||
1177 client_entry->mode & SILC_UMODE_INDISPOSED ||
1178 client_entry->mode & SILC_UMODE_BUSY ||
1179 client_entry->mode & SILC_UMODE_PAGE ||
1180 client_entry->mode & SILC_UMODE_DETACHED)) {
1181 printformat_module("fe-common/silc", server, NULL,
1182 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1183 client_entry->nickname);
1187 memset(buf, 0, sizeof(buf));
1188 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1189 printformat_module("fe-common/silc", server, NULL,
1190 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1191 client_entry->nickname, buf);
1193 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1194 printformat_module("fe-common/silc", server, NULL,
1195 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1196 client_entry->nickname);
1197 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1198 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1199 printformat_module("fe-common/silc", server, NULL,
1200 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1201 client_entry->nickname);
1202 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1203 /* Client logged in to the network */
1204 printformat_module("fe-common/silc", server, NULL,
1205 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1206 client_entry->nickname);
1212 /* Unknown notify */
1213 printformat_module("fe-common/silc", server, NULL,
1214 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1221 /* Called to indicate that connection was either successfully established
1222 or connecting failed. This is also the first time application receives
1223 the SilcClientConnection object which it should save somewhere. */
1225 void silc_connect(SilcClient client, SilcClientConnection conn,
1226 SilcClientConnectionStatus status)
1228 SILC_SERVER_REC *server = conn->context;
1230 if (!server || server->disconnected) {
1231 silc_client_close_connection(client, conn);
1236 case SILC_CLIENT_CONN_SUCCESS:
1237 /* We have successfully connected to server */
1238 server->connected = TRUE;
1239 signal_emit("event connected", 1, server);
1242 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1243 /* We have successfully resumed old detached session */
1244 server->connected = TRUE;
1245 signal_emit("event connected", 1, server);
1247 /* If we resumed old session check whether we need to update
1249 if (strcmp(server->nick, conn->local_entry->nickname)) {
1251 old = g_strdup(server->nick);
1252 server_change_nick(SERVER(server), conn->local_entry->nickname);
1253 nicklist_rename_unique(SERVER(server),
1254 conn->local_entry, server->nick,
1255 conn->local_entry, conn->local_entry->nickname);
1256 signal_emit("message own_nick", 4, server, server->nick, old, "");
1260 /* remove the detach data now */
1264 file = silc_get_session_filename(server);
1272 server->connection_lost = TRUE;
1274 server->conn->context = NULL;
1275 server_disconnect(SERVER(server));
1280 /* Called to indicate that connection was disconnected to the server. */
1282 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1283 SilcStatus status, const char *message)
1285 SILC_SERVER_REC *server = conn->context;
1287 SILC_LOG_DEBUG(("Start"));
1289 if (!server || server->connection_lost)
1292 if (server->conn && server->conn->local_entry) {
1293 nicklist_rename_unique(SERVER(server),
1294 server->conn->local_entry, server->nick,
1295 server->conn->local_entry,
1296 silc_client->username);
1297 silc_change_nick(server, silc_client->username);
1301 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1302 "Server closed connection: %s (%d) %s",
1303 silc_get_status_message(status), status,
1304 message ? message : "");
1307 server->conn->context = NULL;
1308 server->conn = NULL;
1309 server->connection_lost = TRUE;
1310 server_disconnect(SERVER(server));
1313 /* Command handler. This function is called always in the command function.
1314 If error occurs it will be called as well. `conn' is the associated
1315 client connection. `cmd_context' is the command context that was
1316 originally sent to the command. `success' is FALSE if error occured
1317 during command. `command' is the command being processed. It must be
1318 noted that this is not reply from server. This is merely called just
1319 after application has called the command. Just to tell application
1320 that the command really was processed. */
1322 static bool cmode_list_chpks = FALSE;
1324 void silc_command(SilcClient client, SilcClientConnection conn,
1325 SilcClientCommandContext cmd_context, bool success,
1326 SilcCommand command, SilcStatus status)
1328 SILC_SERVER_REC *server = conn->context;
1330 SILC_LOG_DEBUG(("Start"));
1333 silc_say_error("%s", silc_get_status_message(status));
1339 case SILC_COMMAND_INVITE:
1340 if (cmd_context->argc > 2)
1341 printformat_module("fe-common/silc", server, NULL,
1342 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1343 cmd_context->argv[2],
1344 (cmd_context->argv[1][0] == '*' ?
1345 (char *)conn->current_channel->channel_name :
1346 (char *)cmd_context->argv[1]));
1349 case SILC_COMMAND_DETACH:
1350 server->no_reconnect = TRUE;
1353 case SILC_COMMAND_CMODE:
1354 if (cmd_context->argc == 3 &&
1355 !strcmp(cmd_context->argv[2], "+C"))
1356 cmode_list_chpks = TRUE;
1358 cmode_list_chpks = FALSE;
1367 SilcChannelEntry channel;
1371 /* Client info resolving callback when JOIN command reply is received.
1372 This will cache all users on the channel. */
1374 static void silc_client_join_get_users(SilcClient client,
1375 SilcClientConnection conn,
1376 SilcClientEntry *clients,
1377 SilcUInt32 clients_count,
1380 SilcJoinResolve r = context;
1381 SilcChannelEntry channel = r->channel;
1382 SilcHashTableList htl;
1383 SilcChannelUser chu;
1384 SILC_SERVER_REC *server = conn->context;
1385 SILC_CHANNEL_REC *chanrec;
1386 SilcClientEntry founder = NULL;
1389 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1390 silc_hash_table_count(channel->user_list)));
1392 if (!clients && r->retry < 1) {
1393 /* Retry to resolve */
1395 silc_client_get_clients_by_channel(client, conn, channel,
1396 silc_client_join_get_users, context);
1400 chanrec = silc_channel_find(server, channel->channel_name);
1401 if (chanrec == NULL)
1404 silc_hash_table_list(channel->user_list, &htl);
1405 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1406 if (!chu->client->nickname)
1408 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1409 founder = chu->client;
1410 silc_nicklist_insert(chanrec, chu, FALSE);
1412 silc_hash_table_list_reset(&htl);
1414 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1415 nicklist_set_own(CHANNEL(chanrec), ownnick);
1416 signal_emit("channel joined", 1, chanrec);
1417 chanrec->entry = channel;
1420 printformat_module("fe-common/silc", server, channel->channel_name,
1421 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1422 channel->channel_name, chanrec->topic);
1425 if (founder == conn->local_entry) {
1426 printformat_module("fe-common/silc",
1427 server, channel->channel_name, MSGLEVEL_CRAP,
1428 SILCTXT_CHANNEL_FOUNDER_YOU,
1429 channel->channel_name);
1430 signal_emit("nick mode changed", 2, chanrec, ownnick);
1432 printformat_module("fe-common/silc",
1433 server, channel->channel_name, MSGLEVEL_CRAP,
1434 SILCTXT_CHANNEL_FOUNDER,
1435 channel->channel_name, founder->nickname);
1441 SilcClientConnection conn;
1447 void silc_getkey_cb(bool success, void *context)
1449 GetkeyContext getkey = (GetkeyContext)context;
1450 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1451 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1452 ((SilcClientEntry)getkey->entry)->nickname :
1453 ((SilcServerEntry)getkey->entry)->server_name);
1456 printformat_module("fe-common/silc", NULL, NULL,
1457 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1459 printformat_module("fe-common/silc", NULL, NULL,
1460 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1464 silc_free(getkey->fingerprint);
1468 /* Parse an invite or ban list */
1469 void silc_parse_inviteban_list(SilcClient client,
1470 SilcClientConnection conn,
1471 SILC_SERVER_REC *server,
1472 SilcChannelEntry channel,
1473 const char *list_type,
1474 SilcArgumentPayload list)
1477 SilcUInt32 type, len;
1478 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1479 int counter=0, resolving = FALSE;
1481 if (!silc_argument_get_arg_num(list)) {
1482 printformat_module("fe-common/silc", server,
1483 (chanrec ? chanrec->visible_name : NULL),
1484 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1485 channel->channel_name, list_type);
1489 printformat_module("fe-common/silc", server,
1490 (chanrec ? chanrec->visible_name : NULL),
1491 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1492 channel->channel_name, list_type);
1494 /* parse the list */
1495 tmp = silc_argument_get_first_arg(list, &type, &len);
1500 /* an invite string */
1504 if (tmp[len-1] == ',')
1507 list = g_strsplit(tmp, ",", -1);
1509 printformat_module("fe-common/silc", server,
1510 (chanrec ? chanrec->visible_name : NULL),
1511 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1512 ++counter, channel->channel_name, list_type,
1521 char *fingerprint, *babbleprint;
1523 /* tmp is Public Key Payload, take public key from it. */
1524 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1525 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1527 printformat_module("fe-common/silc", server,
1528 (chanrec ? chanrec->visible_name : NULL),
1529 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1530 ++counter, channel->channel_name, list_type,
1531 fingerprint, babbleprint);
1538 SilcClientID *client_id;
1539 SilcClientEntry client_entry;
1541 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1543 if (client_id == NULL) {
1544 silc_say_error("Invalid data in %s list encountered", list_type);
1548 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1551 printformat_module("fe-common/silc", server,
1552 (chanrec ? chanrec->visible_name : NULL),
1553 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1554 ++counter, channel->channel_name, list_type,
1555 client_entry->nickname);
1558 silc_client_get_client_by_id_resolve(client, conn, client_id,
1562 silc_free(client_id);
1568 silc_say_error("Unkown type in %s list: %u (len %u)",
1569 list_type, type, len);
1571 tmp = silc_argument_get_next_arg(list, &type, &len);
1575 printformat_module("fe-common/silc", server,
1576 (chanrec ? chanrec->visible_name : NULL),
1577 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1578 list_type, channel->channel_name);
1581 /* Command reply handler. This function is called always in the command reply
1582 function. If error occurs it will be called as well. Normal scenario
1583 is that it will be called after the received command data has been parsed
1584 and processed. The function is used to pass the received command data to
1587 `conn' is the associated client connection. `cmd_payload' is the command
1588 payload data received from server and it can be ignored. It is provided
1589 if the application would like to re-parse the received command data,
1590 however, it must be noted that the data is parsed already by the library
1591 thus the payload can be ignored. `success' is FALSE if error occured.
1592 In this case arguments are not sent to the application. `command' is the
1593 command reply being processed. The function has variable argument list
1594 and each command defines the number and type of arguments it passes to the
1595 application (on error they are not sent). */
1598 silc_command_reply(SilcClient client, SilcClientConnection conn,
1599 SilcCommandPayload cmd_payload, bool success,
1600 SilcCommand command, SilcStatus status, ...)
1603 SILC_SERVER_REC *server = conn->context;
1604 SILC_CHANNEL_REC *chanrec;
1607 va_start(vp, status);
1609 SILC_LOG_DEBUG(("Start"));
1612 case SILC_COMMAND_WHOIS:
1614 char buf[1024], *nickname, *username, *realname, *nick;
1615 unsigned char *fingerprint;
1616 SilcUInt32 idle, mode;
1617 SilcBuffer channels, user_modes;
1618 SilcClientEntry client_entry;
1621 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1622 /* Print the unknown nick for user */
1623 unsigned char *tmp =
1624 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1627 silc_say_error("%s: %s", tmp,
1628 silc_get_status_message(status));
1630 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1631 /* Try to find the entry for the unknown client ID, since we
1632 might have, and print the nickname of it for user. */
1634 unsigned char *tmp =
1635 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1638 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1641 client_entry = silc_client_get_client_by_id(client, conn,
1643 if (client_entry && client_entry->nickname)
1644 silc_say_error("%s: %s", client_entry->nickname,
1645 silc_get_status_message(status));
1646 silc_free(client_id);
1650 } else if (!success) {
1651 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1655 client_entry = va_arg(vp, SilcClientEntry);
1656 nickname = va_arg(vp, char *);
1657 username = va_arg(vp, char *);
1658 realname = va_arg(vp, char *);
1659 channels = va_arg(vp, SilcBuffer);
1660 mode = va_arg(vp, SilcUInt32);
1661 idle = va_arg(vp, SilcUInt32);
1662 fingerprint = va_arg(vp, unsigned char *);
1663 user_modes = va_arg(vp, SilcBuffer);
1664 attrs = va_arg(vp, SilcDList);
1666 silc_parse_userfqdn(nickname, &nick, NULL);
1667 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1668 SILCTXT_WHOIS_USERINFO, nickname,
1669 client_entry->username, client_entry->hostname,
1670 nick, client_entry->nickname);
1671 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1672 SILCTXT_WHOIS_REALNAME, realname);
1675 if (channels && user_modes) {
1677 SilcDList list = silc_channel_payload_parse_list(channels->data,
1679 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1681 SilcChannelPayload entry;
1684 memset(buf, 0, sizeof(buf));
1685 silc_dlist_start(list);
1686 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1687 SilcUInt32 name_len;
1688 char *m = silc_client_chumode_char(umodes[i++]);
1689 char *name = silc_channel_get_name(entry, &name_len);
1692 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1693 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1694 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1698 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1699 SILCTXT_WHOIS_CHANNELS, buf);
1700 silc_channel_payload_list_free(list);
1706 memset(buf, 0, sizeof(buf));
1707 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1708 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1709 SILCTXT_WHOIS_MODES, buf);
1712 if (idle && nickname) {
1713 memset(buf, 0, sizeof(buf));
1714 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1715 idle > 60 ? (idle / 60) : idle,
1716 idle > 60 ? "minutes" : "seconds");
1718 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1719 SILCTXT_WHOIS_IDLE, buf);
1723 fingerprint = silc_fingerprint(fingerprint, 20);
1724 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1725 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1726 silc_free(fingerprint);
1730 silc_query_attributes_print(server, silc_client, conn, attrs,
1735 case SILC_COMMAND_IDENTIFY:
1737 SilcClientEntry client_entry;
1739 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1740 /* Print the unknown nick for user */
1741 unsigned char *tmp =
1742 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1745 silc_say_error("%s: %s", tmp,
1746 silc_get_status_message(status));
1748 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1749 /* Try to find the entry for the unknown client ID, since we
1750 might have, and print the nickname of it for user. */
1752 unsigned char *tmp =
1753 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1756 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1759 client_entry = silc_client_get_client_by_id(client, conn,
1761 if (client_entry && client_entry->nickname)
1762 silc_say_error("%s: %s", client_entry->nickname,
1763 silc_get_status_message(status));
1764 silc_free(client_id);
1773 case SILC_COMMAND_WHOWAS:
1775 char *nickname, *username, *realname;
1777 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1779 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1782 silc_say_error("%s: %s", tmp,
1783 silc_get_status_message(status));
1785 } else if (!success) {
1786 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1790 (void)va_arg(vp, SilcClientEntry);
1791 nickname = va_arg(vp, char *);
1792 username = va_arg(vp, char *);
1793 realname = va_arg(vp, char *);
1795 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1796 SILCTXT_WHOWAS_USERINFO, nickname, username,
1797 realname ? realname : "");
1801 case SILC_COMMAND_INVITE:
1803 SilcChannelEntry channel;
1805 SilcArgumentPayload invite_list;
1811 channel = va_arg(vp, SilcChannelEntry);
1812 payload = va_arg(vp, SilcBuffer);
1815 SILC_GET16_MSB(argc, payload->data);
1816 invite_list = silc_argument_payload_parse(payload->data + 2,
1817 payload->len - 2, argc);
1819 silc_parse_inviteban_list(client, conn, server, channel,
1820 "invite", invite_list);
1821 silc_argument_payload_free(invite_list);
1827 case SILC_COMMAND_JOIN:
1829 char *channel, *mode, *topic;
1831 SilcChannelEntry channel_entry;
1832 SilcBuffer client_id_list;
1833 SilcUInt32 list_count;
1838 channel = va_arg(vp, char *);
1839 channel_entry = va_arg(vp, SilcChannelEntry);
1840 modei = va_arg(vp, SilcUInt32);
1841 (void)va_arg(vp, SilcUInt32);
1842 (void)va_arg(vp, unsigned char *);
1843 (void)va_arg(vp, unsigned char *);
1844 (void)va_arg(vp, unsigned char *);
1845 topic = va_arg(vp, char *);
1846 (void)va_arg(vp, unsigned char *);
1847 list_count = va_arg(vp, SilcUInt32);
1848 client_id_list = va_arg(vp, SilcBuffer);
1850 chanrec = silc_channel_find(server, channel);
1852 chanrec = silc_channel_create(server, channel, channel, TRUE);
1855 char tmp[256], *cp, *dm = NULL;
1856 g_free_not_null(chanrec->topic);
1858 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1859 memset(tmp, 0, sizeof(tmp));
1861 if (strlen(topic) > sizeof(tmp) - 1) {
1862 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1866 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1871 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1872 signal_emit("channel topic changed", 1, chanrec);
1877 mode = silc_client_chmode(modei,
1878 channel_entry->channel_key ?
1879 silc_cipher_get_name(channel_entry->
1881 channel_entry->hmac ?
1882 silc_hmac_get_name(channel_entry->hmac) : "");
1883 g_free_not_null(chanrec->mode);
1884 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1885 signal_emit("channel mode changed", 1, chanrec);
1887 /* Resolve the client information */
1889 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1890 r->channel = channel_entry;
1891 silc_client_get_clients_by_list(client, conn, list_count,
1893 silc_client_join_get_users, r);
1899 case SILC_COMMAND_NICK:
1902 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1908 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1909 if ((nicks != NULL) &&
1910 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1912 SilcClientEntry collider, old;
1914 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1915 collider = silc_client_get_client_by_id(client, conn,
1918 if (collider != client_entry) {
1920 memset(buf, 0, sizeof(buf));
1921 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1922 collider->username, collider->hostname);
1923 nicklist_rename_unique(SERVER(server),
1925 collider, collider->nickname);
1926 silc_print_nick_change(server, collider->nickname,
1927 client_entry->nickname, buf);
1932 g_slist_free(nicks);
1934 old = g_strdup(server->nick);
1935 server_change_nick(SERVER(server), client_entry->nickname);
1936 nicklist_rename_unique(SERVER(server),
1937 server->conn->local_entry, server->nick,
1938 client_entry, client_entry->nickname);
1939 signal_emit("message own_nick", 4, server, server->nick, old, "");
1944 case SILC_COMMAND_LIST:
1949 char tmp[256], *cp, *dm = NULL;
1954 (void)va_arg(vp, SilcChannelEntry);
1955 name = va_arg(vp, char *);
1956 topic = va_arg(vp, char *);
1957 usercount = va_arg(vp, int);
1959 if (topic && !silc_term_utf8() &&
1960 silc_utf8_valid(topic, strlen(topic))) {
1961 memset(tmp, 0, sizeof(tmp));
1963 if (strlen(topic) > sizeof(tmp) - 1) {
1964 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1968 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1973 if (status == SILC_STATUS_LIST_START ||
1974 status == SILC_STATUS_OK)
1975 printformat_module("fe-common/silc", server, NULL,
1976 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1979 snprintf(users, sizeof(users) - 1, "N/A");
1981 snprintf(users, sizeof(users) - 1, "%d", usercount);
1982 printformat_module("fe-common/silc", server, NULL,
1983 MSGLEVEL_CRAP, SILCTXT_LIST,
1984 name, users, topic ? topic : "");
1989 case SILC_COMMAND_UMODE:
1997 mode = va_arg(vp, SilcUInt32);
1999 if (mode & SILC_UMODE_SERVER_OPERATOR &&
2000 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
2001 printformat_module("fe-common/silc", server, NULL,
2002 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2004 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
2005 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
2006 printformat_module("fe-common/silc", server, NULL,
2007 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2009 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
2010 if (mode & SILC_UMODE_GONE) {
2011 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
2012 reason = g_strdup(server->away_reason);
2014 reason = g_strdup("away");
2016 reason = g_strdup("");
2018 silc_set_away(reason, server);
2023 server->umode = mode;
2024 signal_emit("user mode changed", 2, server, NULL);
2028 case SILC_COMMAND_OPER:
2032 server->umode |= SILC_UMODE_SERVER_OPERATOR;
2033 signal_emit("user mode changed", 2, server, NULL);
2035 printformat_module("fe-common/silc", server, NULL,
2036 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2039 case SILC_COMMAND_SILCOPER:
2043 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2044 signal_emit("user mode changed", 2, server, NULL);
2046 printformat_module("fe-common/silc", server, NULL,
2047 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2050 case SILC_COMMAND_USERS:
2052 SilcHashTableList htl;
2053 SilcChannelEntry channel;
2054 SilcChannelUser chu;
2059 channel = va_arg(vp, SilcChannelEntry);
2061 printformat_module("fe-common/silc", server, channel->channel_name,
2062 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2063 channel->channel_name);
2065 silc_hash_table_list(channel->user_list, &htl);
2066 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2067 SilcClientEntry e = chu->client;
2068 char stat[5], *mode;
2073 memset(stat, 0, sizeof(stat));
2074 mode = silc_client_chumode_char(chu->mode);
2075 if (e->mode & SILC_UMODE_GONE)
2077 else if (e->mode & SILC_UMODE_INDISPOSED)
2079 else if (e->mode & SILC_UMODE_BUSY)
2081 else if (e->mode & SILC_UMODE_PAGE)
2083 else if (e->mode & SILC_UMODE_HYPER)
2085 else if (e->mode & SILC_UMODE_ROBOT)
2087 else if (e->mode & SILC_UMODE_ANONYMOUS)
2094 printformat_module("fe-common/silc", server, channel->channel_name,
2095 MSGLEVEL_CRAP, SILCTXT_USERS,
2097 e->username ? e->username : "",
2098 e->hostname ? e->hostname : "",
2099 e->realname ? e->realname : "");
2103 silc_hash_table_list_reset(&htl);
2107 case SILC_COMMAND_BAN:
2109 SilcChannelEntry channel;
2111 SilcArgumentPayload ban_list;
2117 channel = va_arg(vp, SilcChannelEntry);
2118 payload = va_arg(vp, SilcBuffer);
2121 SILC_GET16_MSB(argc, payload->data);
2122 ban_list = silc_argument_payload_parse(payload->data + 2,
2123 payload->len - 2, argc);
2125 silc_parse_inviteban_list(client, conn, server, channel,
2127 silc_argument_payload_free(ban_list);
2133 case SILC_COMMAND_GETKEY:
2137 SilcPublicKey public_key;
2140 GetkeyContext getkey;
2146 id_type = va_arg(vp, SilcUInt32);
2147 entry = va_arg(vp, void *);
2148 public_key = va_arg(vp, SilcPublicKey);
2151 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2153 getkey = silc_calloc(1, sizeof(*getkey));
2154 getkey->entry = entry;
2155 getkey->id_type = id_type;
2156 getkey->client = client;
2157 getkey->conn = conn;
2158 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2160 name = (id_type == SILC_ID_CLIENT ?
2161 ((SilcClientEntry)entry)->nickname :
2162 ((SilcServerEntry)entry)->server_name);
2164 silc_verify_public_key_internal(client, conn, name,
2165 (id_type == SILC_ID_CLIENT ?
2166 SILC_SOCKET_TYPE_CLIENT :
2167 SILC_SOCKET_TYPE_SERVER),
2168 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2169 silc_getkey_cb, getkey);
2172 printformat_module("fe-common/silc", server, NULL,
2173 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2178 case SILC_COMMAND_INFO:
2180 SilcServerEntry server_entry;
2187 server_entry = va_arg(vp, SilcServerEntry);
2188 server_name = va_arg(vp, char *);
2189 server_info = va_arg(vp, char *);
2191 if (server_name && server_info )
2193 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2194 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2199 case SILC_COMMAND_TOPIC:
2201 SilcChannelEntry channel;
2203 char tmp[256], *cp, *dm = NULL;
2208 channel = va_arg(vp, SilcChannelEntry);
2209 topic = va_arg(vp, char *);
2211 if (topic && !silc_term_utf8() &&
2212 silc_utf8_valid(topic, strlen(topic))) {
2213 memset(tmp, 0, sizeof(tmp));
2215 if (strlen(topic) > sizeof(tmp) - 1) {
2216 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2220 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2226 chanrec = silc_channel_find_entry(server, channel);
2228 g_free_not_null(chanrec->topic);
2229 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2230 signal_emit("channel topic changed", 1, chanrec);
2232 printformat_module("fe-common/silc", server, channel->channel_name,
2233 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2234 channel->channel_name, topic);
2236 printformat_module("fe-common/silc", server, channel->channel_name,
2237 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2238 channel->channel_name);
2244 case SILC_COMMAND_WATCH:
2247 case SILC_COMMAND_STATS:
2249 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2250 my_router_ops, cell_clients, cell_channels, cell_servers,
2251 clients, channels, servers, routers, server_ops, router_ops;
2253 SilcBufferStruct buf;
2254 unsigned char *tmp_buf;
2256 const char *tmptime;
2257 int days, hours, mins, secs;
2262 tmp_buf = va_arg(vp, unsigned char *);
2263 buf_len = va_arg(vp, SilcUInt32);
2265 if (!tmp_buf || !buf_len) {
2266 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2270 /* Get statistics structure */
2271 silc_buffer_set(&buf, tmp_buf, buf_len);
2272 silc_buffer_unformat(&buf,
2273 SILC_STR_UI_INT(&starttime),
2274 SILC_STR_UI_INT(&uptime),
2275 SILC_STR_UI_INT(&my_clients),
2276 SILC_STR_UI_INT(&my_channels),
2277 SILC_STR_UI_INT(&my_server_ops),
2278 SILC_STR_UI_INT(&my_router_ops),
2279 SILC_STR_UI_INT(&cell_clients),
2280 SILC_STR_UI_INT(&cell_channels),
2281 SILC_STR_UI_INT(&cell_servers),
2282 SILC_STR_UI_INT(&clients),
2283 SILC_STR_UI_INT(&channels),
2284 SILC_STR_UI_INT(&servers),
2285 SILC_STR_UI_INT(&routers),
2286 SILC_STR_UI_INT(&server_ops),
2287 SILC_STR_UI_INT(&router_ops),
2290 tmptime = silc_get_time(starttime);
2291 printformat_module("fe-common/silc", server, NULL,
2292 MSGLEVEL_CRAP, SILCTXT_STATS,
2293 "Local server start time", tmptime);
2295 days = uptime / (24 * 60 * 60);
2296 uptime -= days * (24 * 60 * 60);
2297 hours = uptime / (60 * 60);
2298 uptime -= hours * (60 * 60);
2300 uptime -= mins * 60;
2302 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2303 days, hours, mins, secs);
2304 printformat_module("fe-common/silc", server, NULL,
2305 MSGLEVEL_CRAP, SILCTXT_STATS,
2306 "Local server uptime", tmp);
2308 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2309 printformat_module("fe-common/silc", server, NULL,
2310 MSGLEVEL_CRAP, SILCTXT_STATS,
2311 "Local server clients", tmp);
2313 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2314 printformat_module("fe-common/silc", server, NULL,
2315 MSGLEVEL_CRAP, SILCTXT_STATS,
2316 "Local server channels", tmp);
2318 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2319 printformat_module("fe-common/silc", server, NULL,
2320 MSGLEVEL_CRAP, SILCTXT_STATS,
2321 "Local server operators", tmp);
2323 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2324 printformat_module("fe-common/silc", server, NULL,
2325 MSGLEVEL_CRAP, SILCTXT_STATS,
2326 "Local router operators", tmp);
2328 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2329 printformat_module("fe-common/silc", server, NULL,
2330 MSGLEVEL_CRAP, SILCTXT_STATS,
2331 "Local cell clients", tmp);
2333 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2334 printformat_module("fe-common/silc", server, NULL,
2335 MSGLEVEL_CRAP, SILCTXT_STATS,
2336 "Local cell channels", tmp);
2338 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2339 printformat_module("fe-common/silc", server, NULL,
2340 MSGLEVEL_CRAP, SILCTXT_STATS,
2341 "Local cell servers", tmp);
2343 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2344 printformat_module("fe-common/silc", server, NULL,
2345 MSGLEVEL_CRAP, SILCTXT_STATS,
2346 "Total clients", tmp);
2348 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2349 printformat_module("fe-common/silc", server, NULL,
2350 MSGLEVEL_CRAP, SILCTXT_STATS,
2351 "Total channels", tmp);
2353 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2354 printformat_module("fe-common/silc", server, NULL,
2355 MSGLEVEL_CRAP, SILCTXT_STATS,
2356 "Total servers", tmp);
2358 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2359 printformat_module("fe-common/silc", server, NULL,
2360 MSGLEVEL_CRAP, SILCTXT_STATS,
2361 "Total routers", tmp);
2363 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2364 printformat_module("fe-common/silc", server, NULL,
2365 MSGLEVEL_CRAP, SILCTXT_STATS,
2366 "Total server operators", tmp);
2368 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2369 printformat_module("fe-common/silc", server, NULL,
2370 MSGLEVEL_CRAP, SILCTXT_STATS,
2371 "Total router operators", tmp);
2375 case SILC_COMMAND_CMODE:
2377 SilcChannelEntry channel_entry;
2378 SilcBuffer channel_pubkeys;
2380 channel_entry = va_arg(vp, SilcChannelEntry);
2381 (void)va_arg(vp, SilcUInt32);
2382 (void)va_arg(vp, SilcPublicKey);
2383 channel_pubkeys = va_arg(vp, SilcBuffer);
2385 if (!success || !cmode_list_chpks ||
2386 !channel_entry || !channel_entry->channel_name)
2389 /* Print the channel public key list */
2390 if (channel_pubkeys)
2391 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2393 printformat_module("fe-common/silc", server, NULL,
2394 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2395 channel_entry->channel_name);
2406 SilcClientConnection conn;
2412 SilcSKEPKType pk_type;
2413 SilcVerifyPublicKey completion;
2417 static void verify_public_key_completion(const char *line, void *context)
2419 PublicKeyVerify verify = (PublicKeyVerify)context;
2421 if (line[0] == 'Y' || line[0] == 'y') {
2422 /* Call the completion */
2423 if (verify->completion)
2424 verify->completion(TRUE, verify->context);
2426 /* Save the key for future checking */
2427 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2428 verify->pk_len, SILC_PKCS_FILE_PEM);
2430 /* Call the completion */
2431 if (verify->completion)
2432 verify->completion(FALSE, verify->context);
2434 printformat_module("fe-common/silc", NULL, NULL,
2435 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2436 verify->entity_name ? verify->entity_name :
2440 silc_free(verify->filename);
2441 silc_free(verify->entity);
2442 silc_free(verify->entity_name);
2443 silc_free(verify->pk);
2447 /* Internal routine to verify public key. If the `completion' is provided
2448 it will be called to indicate whether public was verified or not. For
2449 server/router public key this will check for filename that includes the
2450 remote host's IP address and remote host's hostname. */
2453 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2454 const char *name, SilcSocketType conn_type,
2455 unsigned char *pk, SilcUInt32 pk_len,
2456 SilcSKEPKType pk_type,
2457 SilcVerifyPublicKey completion, void *context)
2460 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2461 char *fingerprint, *babbleprint, *format;
2464 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2465 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2466 "server" : "client");
2467 PublicKeyVerify verify;
2469 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2470 printformat_module("fe-common/silc", NULL, NULL,
2471 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2474 completion(FALSE, context);
2478 pw = getpwuid(getuid());
2481 completion(FALSE, context);
2485 memset(filename, 0, sizeof(filename));
2486 memset(filename2, 0, sizeof(filename2));
2487 memset(file, 0, sizeof(file));
2489 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2490 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2492 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2493 conn->sock->ip, conn->sock->port);
2494 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2495 get_irssi_dir(), entity, file);
2497 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2498 conn->sock->hostname, conn->sock->port);
2499 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2500 get_irssi_dir(), entity, file);
2505 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2506 name, conn->sock->port);
2507 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2508 get_irssi_dir(), entity, file);
2513 /* Replace all whitespaces with `_'. */
2514 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2515 for (i = 0; i < strlen(fingerprint); i++)
2516 if (fingerprint[i] == ' ')
2517 fingerprint[i] = '_';
2519 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2520 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2521 get_irssi_dir(), entity, file);
2522 silc_free(fingerprint);
2527 /* Take fingerprint of the public key */
2528 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2529 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2531 verify = silc_calloc(1, sizeof(*verify));
2532 verify->client = client;
2533 verify->conn = conn;
2534 verify->filename = strdup(ipf);
2535 verify->entity = strdup(entity);
2536 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2537 (name ? strdup(name) : strdup(conn->sock->hostname))
2539 verify->pk = silc_memdup(pk, pk_len);
2540 verify->pk_len = pk_len;
2541 verify->pk_type = pk_type;
2542 verify->completion = completion;
2543 verify->context = context;
2545 /* Check whether this key already exists */
2546 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2547 /* Key does not exist, ask user to verify the key and save it */
2549 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2550 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2551 verify->entity_name : entity);
2552 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2553 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2554 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2555 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2556 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2557 SILCTXT_PUBKEY_ACCEPT);
2558 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2561 silc_free(fingerprint);
2564 /* The key already exists, verify it. */
2565 SilcPublicKey public_key;
2566 unsigned char *encpk;
2567 SilcUInt32 encpk_len;
2569 /* Load the key file, try for both IP filename and hostname filename */
2570 if (!silc_pkcs_load_public_key(ipf, &public_key,
2571 SILC_PKCS_FILE_PEM) &&
2572 !silc_pkcs_load_public_key(ipf, &public_key,
2573 SILC_PKCS_FILE_BIN) &&
2574 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2575 SILC_PKCS_FILE_PEM) &&
2576 !silc_pkcs_load_public_key(hostf, &public_key,
2577 SILC_PKCS_FILE_BIN)))) {
2578 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2579 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2580 verify->entity_name : entity);
2581 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2582 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2583 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2584 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2585 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2586 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2587 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2588 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2589 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2592 silc_free(fingerprint);
2596 /* Encode the key data */
2597 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2599 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2600 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2601 verify->entity_name : entity);
2602 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2603 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2604 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2605 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2606 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2607 SILCTXT_PUBKEY_MALFORMED, entity);
2608 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2609 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2610 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2613 silc_free(fingerprint);
2617 /* Compare the keys */
2618 if (memcmp(encpk, pk, encpk_len)) {
2619 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2620 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2621 verify->entity_name : entity);
2622 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2623 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2624 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2625 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2626 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2627 SILCTXT_PUBKEY_NO_MATCH, entity);
2628 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2629 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2630 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2631 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2633 /* Ask user to verify the key and save it */
2634 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2635 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2636 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2639 silc_free(fingerprint);
2643 /* Local copy matched */
2645 completion(TRUE, context);
2646 silc_free(fingerprint);
2647 silc_free(verify->filename);
2648 silc_free(verify->entity);
2649 silc_free(verify->entity_name);
2650 silc_free(verify->pk);
2655 /* Verifies received public key. The `conn_type' indicates which entity
2656 (server, client etc.) has sent the public key. If user decides to trust
2657 the key may be saved as trusted public key for later use. The
2658 `completion' must be called after the public key has been verified. */
2661 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2662 SilcSocketType conn_type, unsigned char *pk,
2663 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2664 SilcVerifyPublicKey completion, void *context)
2666 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2668 completion, context);
2671 /* Asks passphrase from user on the input line. */
2674 SilcAskPassphrase completion;
2678 void ask_passphrase_completion(const char *passphrase, void *context)
2680 AskPassphrase p = (AskPassphrase)context;
2681 if (passphrase && passphrase[0] == '\0')
2683 p->completion((unsigned char *)passphrase,
2684 passphrase ? strlen(passphrase) : 0, p->context);
2688 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2689 SilcAskPassphrase completion, void *context)
2691 AskPassphrase p = silc_calloc(1, sizeof(*p));
2692 p->completion = completion;
2693 p->context = context;
2695 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2696 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2700 SilcGetAuthMeth completion;
2702 } *InternalGetAuthMethod;
2704 /* Callback called when we've received the authentication method information
2705 from the server after we've requested it. This will get the authentication
2706 data from the user if needed. */
2708 static void silc_get_auth_method_callback(SilcClient client,
2709 SilcClientConnection conn,
2710 SilcAuthMethod auth_meth,
2713 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2715 SILC_LOG_DEBUG(("Start"));
2717 switch (auth_meth) {
2718 case SILC_AUTH_NONE:
2719 /* No authentication required. */
2720 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2722 case SILC_AUTH_PASSWORD:
2724 /* Check whether we find the password for this server in our
2725 configuration. If not, then don't provide so library will ask
2726 it from the user. */
2727 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2729 if (!setup || !setup->password) {
2730 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2734 (*internal->completion)(TRUE, auth_meth, setup->password,
2735 strlen(setup->password), internal->context);
2738 case SILC_AUTH_PUBLIC_KEY:
2739 /* Do not get the authentication data now, the library will generate
2740 it using our default key, if we do not provide it here. */
2741 /* XXX In the future when we support multiple local keys and multiple
2742 local certificates we will need to ask from user which one to use. */
2743 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2747 silc_free(internal);
2750 /* Find authentication method and authentication data by hostname and
2751 port. The hostname may be IP address as well. The found authentication
2752 method and authentication data is returned to `auth_meth', `auth_data'
2753 and `auth_data_len'. The function returns TRUE if authentication method
2754 is found and FALSE if not. `conn' may be NULL. */
2756 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2757 char *hostname, SilcUInt16 port,
2758 SilcGetAuthMeth completion, void *context)
2760 InternalGetAuthMethod internal;
2762 SILC_LOG_DEBUG(("Start"));
2764 /* If we do not have this connection configured by the user in a
2765 configuration file then resolve the authentication method from the
2766 server for this session. */
2767 internal = silc_calloc(1, sizeof(*internal));
2768 internal->completion = completion;
2769 internal->context = context;
2771 silc_client_request_authentication_method(client, conn,
2772 silc_get_auth_method_callback,
2776 /* Notifies application that failure packet was received. This is called
2777 if there is some protocol active in the client. The `protocol' is the
2778 protocol context. The `failure' is opaque pointer to the failure
2779 indication. Note, that the `failure' is protocol dependant and application
2780 must explicitly cast it to correct type. Usually `failure' is 32 bit
2781 failure type (see protocol specs for all protocol failure types). */
2783 void silc_failure(SilcClient client, SilcClientConnection conn,
2784 SilcProtocol protocol, void *failure)
2786 SILC_LOG_DEBUG(("Start"));
2788 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2789 SilcSKEStatus status = (SilcSKEStatus)failure;
2791 if (status == SILC_SKE_STATUS_BAD_VERSION)
2792 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2793 SILCTXT_KE_BAD_VERSION);
2794 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2795 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2796 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2797 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2798 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2799 SILCTXT_KE_UNKNOWN_GROUP);
2800 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2801 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2802 SILCTXT_KE_UNKNOWN_CIPHER);
2803 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2804 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2805 SILCTXT_KE_UNKNOWN_PKCS);
2806 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2807 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2808 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2809 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2810 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2811 SILCTXT_KE_UNKNOWN_HMAC);
2812 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2813 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2814 SILCTXT_KE_INCORRECT_SIGNATURE);
2815 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2816 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2817 SILCTXT_KE_INVALID_COOKIE);
2820 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2821 SilcUInt32 err = (SilcUInt32)failure;
2823 if (err == SILC_AUTH_FAILED)
2824 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2825 SILCTXT_AUTH_FAILED);
2829 /* Asks whether the user would like to perform the key agreement protocol.
2830 This is called after we have received an key agreement packet or an
2831 reply to our key agreement packet. This returns TRUE if the user wants
2832 the library to perform the key agreement protocol and FALSE if it is not
2833 desired (application may start it later by calling the function
2834 silc_client_perform_key_agreement). */
2836 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2837 SilcClientEntry client_entry, const char *hostname,
2838 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2843 SILC_LOG_DEBUG(("Start"));
2845 /* We will just display the info on the screen and return FALSE and user
2846 will have to start the key agreement with a command. */
2849 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2852 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2853 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2855 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2856 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2857 client_entry->nickname, hostname, portstr);
2865 /* Notifies application that file transfer protocol session is being
2866 requested by the remote client indicated by the `client_entry' from
2867 the `hostname' and `port'. The `session_id' is the file transfer
2868 session and it can be used to either accept or reject the file
2869 transfer request, by calling the silc_client_file_receive or
2870 silc_client_file_close, respectively. */
2872 void silc_ftp(SilcClient client, SilcClientConnection conn,
2873 SilcClientEntry client_entry, SilcUInt32 session_id,
2874 const char *hostname, SilcUInt16 port)
2876 SILC_SERVER_REC *server;
2878 FtpSession ftp = NULL;
2880 SILC_LOG_DEBUG(("Start"));
2882 server = conn->context;
2884 silc_dlist_start(server->ftp_sessions);
2885 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2886 if (ftp->client_entry == client_entry &&
2887 ftp->session_id == session_id) {
2888 server->current_session = ftp;
2892 if (ftp == SILC_LIST_END) {
2893 ftp = silc_calloc(1, sizeof(*ftp));
2894 ftp->client_entry = client_entry;
2895 ftp->session_id = session_id;
2898 silc_dlist_add(server->ftp_sessions, ftp);
2899 server->current_session = ftp;
2903 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2906 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2907 SILCTXT_FILE_REQUEST, client_entry->nickname);
2909 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2910 SILCTXT_FILE_REQUEST_HOST,
2911 client_entry->nickname, hostname, portstr);
2914 /* Delivers SILC session detachment data indicated by `detach_data' to the
2915 application. If application has issued SILC_COMMAND_DETACH command
2916 the client session in the SILC network is not quit. The client remains
2917 in the network but is detached. The detachment data may be used later
2918 to resume the session in the SILC Network. The appliation is
2919 responsible of saving the `detach_data', to for example in a file.
2921 The detachment data can be given as argument to the functions
2922 silc_client_connect_to_server, or silc_client_add_connection when
2923 creating connection to remote server, inside SilcClientConnectionParams
2924 structure. If it is provided the client library will attempt to resume
2925 the session in the network. After the connection is created
2926 successfully, the application is responsible of setting the user
2927 interface for user into the same state it was before detaching (showing
2928 same channels, channel modes, etc). It can do this by fetching the
2929 information (like joined channels) from the client library. */
2932 silc_detach(SilcClient client, SilcClientConnection conn,
2933 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2935 SILC_SERVER_REC *server = conn->context;
2938 /* Save the detachment data to file. */
2940 file = silc_get_session_filename(server);
2941 silc_file_writefile(file, detach_data, detach_data_len);
2946 /* SILC client operations */
2947 SilcClientOperations ops = {
2949 silc_channel_message,
2950 silc_private_message,
2956 silc_get_auth_method,
2957 silc_verify_public_key,
2958 silc_ask_passphrase,