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);
1305 server->connection_lost = TRUE;
1307 server->conn->context = NULL;
1308 server_disconnect(SERVER(server));
1313 /* Called to indicate that connection was disconnected to the server. */
1315 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1316 SilcStatus status, const char *message)
1318 SILC_SERVER_REC *server = conn->context;
1320 SILC_LOG_DEBUG(("Start"));
1322 if (!server || server->connection_lost)
1325 if (server->conn && server->conn->local_entry) {
1326 nicklist_rename_unique(SERVER(server),
1327 server->conn->local_entry, server->nick,
1328 server->conn->local_entry,
1329 silc_client->username);
1330 silc_change_nick(server, silc_client->username);
1334 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1335 "Server closed connection: %s (%d) %s",
1336 silc_get_status_message(status), status,
1337 message ? message : "");
1340 server->conn->context = NULL;
1341 server->conn = NULL;
1342 server->connection_lost = TRUE;
1343 server_disconnect(SERVER(server));
1346 /* Command handler. This function is called always in the command function.
1347 If error occurs it will be called as well. `conn' is the associated
1348 client connection. `cmd_context' is the command context that was
1349 originally sent to the command. `success' is FALSE if error occured
1350 during command. `command' is the command being processed. It must be
1351 noted that this is not reply from server. This is merely called just
1352 after application has called the command. Just to tell application
1353 that the command really was processed. */
1355 static bool cmode_list_chpks = FALSE;
1357 void silc_command(SilcClient client, SilcClientConnection conn,
1358 SilcClientCommandContext cmd_context, bool success,
1359 SilcCommand command, SilcStatus status)
1361 SILC_SERVER_REC *server = conn->context;
1363 SILC_LOG_DEBUG(("Start"));
1366 silc_say_error("%s", silc_get_status_message(status));
1372 case SILC_COMMAND_INVITE:
1373 if (cmd_context->argc > 2)
1374 printformat_module("fe-common/silc", server, NULL,
1375 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1376 cmd_context->argv[2],
1377 (cmd_context->argv[1][0] == '*' ?
1378 (char *)conn->current_channel->channel_name :
1379 (char *)cmd_context->argv[1]));
1382 case SILC_COMMAND_DETACH:
1383 server->no_reconnect = TRUE;
1386 case SILC_COMMAND_CMODE:
1387 if (cmd_context->argc == 3 &&
1388 !strcmp(cmd_context->argv[2], "+C"))
1389 cmode_list_chpks = TRUE;
1391 cmode_list_chpks = FALSE;
1400 SilcChannelEntry channel;
1404 /* Client info resolving callback when JOIN command reply is received.
1405 This will cache all users on the channel. */
1407 static void silc_client_join_get_users(SilcClient client,
1408 SilcClientConnection conn,
1409 SilcClientEntry *clients,
1410 SilcUInt32 clients_count,
1413 SilcJoinResolve r = context;
1414 SilcChannelEntry channel = r->channel;
1415 SilcHashTableList htl;
1416 SilcChannelUser chu;
1417 SILC_SERVER_REC *server = conn->context;
1418 SILC_CHANNEL_REC *chanrec;
1419 SilcClientEntry founder = NULL;
1422 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1423 silc_hash_table_count(channel->user_list)));
1425 if (!clients && r->retry < 1) {
1426 /* Retry to resolve */
1428 silc_client_get_clients_by_channel(client, conn, channel,
1429 silc_client_join_get_users, context);
1433 chanrec = silc_channel_find(server, channel->channel_name);
1434 if (chanrec == NULL)
1437 silc_hash_table_list(channel->user_list, &htl);
1438 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1439 if (!chu->client->nickname)
1441 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1442 founder = chu->client;
1443 silc_nicklist_insert(chanrec, chu, FALSE);
1445 silc_hash_table_list_reset(&htl);
1447 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1448 nicklist_set_own(CHANNEL(chanrec), ownnick);
1449 signal_emit("channel joined", 1, chanrec);
1450 chanrec->entry = channel;
1453 printformat_module("fe-common/silc", server, channel->channel_name,
1454 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1455 channel->channel_name, chanrec->topic);
1458 if (founder == conn->local_entry) {
1459 printformat_module("fe-common/silc",
1460 server, channel->channel_name, MSGLEVEL_CRAP,
1461 SILCTXT_CHANNEL_FOUNDER_YOU,
1462 channel->channel_name);
1463 signal_emit("nick mode changed", 2, chanrec, ownnick);
1465 printformat_module("fe-common/silc",
1466 server, channel->channel_name, MSGLEVEL_CRAP,
1467 SILCTXT_CHANNEL_FOUNDER,
1468 channel->channel_name, founder->nickname);
1474 SilcClientConnection conn;
1480 void silc_getkey_cb(bool success, void *context)
1482 GetkeyContext getkey = (GetkeyContext)context;
1483 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1484 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1485 ((SilcClientEntry)getkey->entry)->nickname :
1486 ((SilcServerEntry)getkey->entry)->server_name);
1489 printformat_module("fe-common/silc", NULL, NULL,
1490 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1492 printformat_module("fe-common/silc", NULL, NULL,
1493 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1497 silc_free(getkey->fingerprint);
1501 /* Parse an invite or ban list */
1502 void silc_parse_inviteban_list(SilcClient client,
1503 SilcClientConnection conn,
1504 SILC_SERVER_REC *server,
1505 SilcChannelEntry channel,
1506 const char *list_type,
1507 SilcArgumentPayload list)
1510 SilcUInt32 type, len;
1511 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1512 int counter=0, resolving = FALSE;
1514 if (!silc_argument_get_arg_num(list)) {
1515 printformat_module("fe-common/silc", server,
1516 (chanrec ? chanrec->visible_name : NULL),
1517 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1518 channel->channel_name, list_type);
1522 printformat_module("fe-common/silc", server,
1523 (chanrec ? chanrec->visible_name : NULL),
1524 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1525 channel->channel_name, list_type);
1527 /* parse the list */
1528 tmp = silc_argument_get_first_arg(list, &type, &len);
1533 /* an invite string */
1537 if (tmp[len-1] == ',')
1540 list = g_strsplit(tmp, ",", -1);
1542 printformat_module("fe-common/silc", server,
1543 (chanrec ? chanrec->visible_name : NULL),
1544 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1545 ++counter, channel->channel_name, list_type,
1554 char *fingerprint, *babbleprint;
1556 /* tmp is Public Key Payload, take public key from it. */
1557 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1558 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1560 printformat_module("fe-common/silc", server,
1561 (chanrec ? chanrec->visible_name : NULL),
1562 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1563 ++counter, channel->channel_name, list_type,
1564 fingerprint, babbleprint);
1571 SilcClientID *client_id;
1572 SilcClientEntry client_entry;
1574 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1576 if (client_id == NULL) {
1577 silc_say_error("Invalid data in %s list encountered", list_type);
1581 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1584 printformat_module("fe-common/silc", server,
1585 (chanrec ? chanrec->visible_name : NULL),
1586 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1587 ++counter, channel->channel_name, list_type,
1588 client_entry->nickname);
1591 silc_client_get_client_by_id_resolve(client, conn, client_id,
1595 silc_free(client_id);
1601 silc_say_error("Unkown type in %s list: %u (len %u)",
1602 list_type, type, len);
1604 tmp = silc_argument_get_next_arg(list, &type, &len);
1608 printformat_module("fe-common/silc", server,
1609 (chanrec ? chanrec->visible_name : NULL),
1610 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1611 list_type, channel->channel_name);
1614 /* Command reply handler. This function is called always in the command reply
1615 function. If error occurs it will be called as well. Normal scenario
1616 is that it will be called after the received command data has been parsed
1617 and processed. The function is used to pass the received command data to
1620 `conn' is the associated client connection. `cmd_payload' is the command
1621 payload data received from server and it can be ignored. It is provided
1622 if the application would like to re-parse the received command data,
1623 however, it must be noted that the data is parsed already by the library
1624 thus the payload can be ignored. `success' is FALSE if error occured.
1625 In this case arguments are not sent to the application. `command' is the
1626 command reply being processed. The function has variable argument list
1627 and each command defines the number and type of arguments it passes to the
1628 application (on error they are not sent). */
1631 silc_command_reply(SilcClient client, SilcClientConnection conn,
1632 SilcCommandPayload cmd_payload, bool success,
1633 SilcCommand command, SilcStatus status, ...)
1636 SILC_SERVER_REC *server = conn->context;
1637 SILC_CHANNEL_REC *chanrec;
1640 va_start(vp, status);
1642 SILC_LOG_DEBUG(("Start"));
1645 case SILC_COMMAND_WHOIS:
1647 char buf[1024], *nickname, *username, *realname, *nick;
1648 unsigned char *fingerprint;
1649 SilcUInt32 idle, mode;
1650 SilcBuffer channels, user_modes;
1651 SilcClientEntry client_entry;
1654 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1655 /* Print the unknown nick for user */
1656 unsigned char *tmp =
1657 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1660 silc_say_error("%s: %s", tmp,
1661 silc_get_status_message(status));
1663 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1664 /* Try to find the entry for the unknown client ID, since we
1665 might have, and print the nickname of it for user. */
1667 unsigned char *tmp =
1668 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1671 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1674 client_entry = silc_client_get_client_by_id(client, conn,
1676 if (client_entry && client_entry->nickname)
1677 silc_say_error("%s: %s", client_entry->nickname,
1678 silc_get_status_message(status));
1679 silc_free(client_id);
1683 } else if (!success) {
1684 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1688 client_entry = va_arg(vp, SilcClientEntry);
1689 nickname = va_arg(vp, char *);
1690 username = va_arg(vp, char *);
1691 realname = va_arg(vp, char *);
1692 channels = va_arg(vp, SilcBuffer);
1693 mode = va_arg(vp, SilcUInt32);
1694 idle = va_arg(vp, SilcUInt32);
1695 fingerprint = va_arg(vp, unsigned char *);
1696 user_modes = va_arg(vp, SilcBuffer);
1697 attrs = va_arg(vp, SilcDList);
1699 silc_parse_userfqdn(nickname, &nick, NULL);
1700 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1701 SILCTXT_WHOIS_USERINFO, nickname,
1702 client_entry->username, client_entry->hostname,
1703 nick, client_entry->nickname);
1704 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1705 SILCTXT_WHOIS_REALNAME, realname);
1708 if (channels && user_modes) {
1710 SilcDList list = silc_channel_payload_parse_list(channels->data,
1712 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1714 SilcChannelPayload entry;
1717 memset(buf, 0, sizeof(buf));
1718 silc_dlist_start(list);
1719 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1720 SilcUInt32 name_len;
1721 char *m = silc_client_chumode_char(umodes[i++]);
1722 char *name = silc_channel_get_name(entry, &name_len);
1725 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1726 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1727 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1731 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1732 SILCTXT_WHOIS_CHANNELS, buf);
1733 silc_channel_payload_list_free(list);
1739 memset(buf, 0, sizeof(buf));
1740 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1741 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1742 SILCTXT_WHOIS_MODES, buf);
1745 if (idle && nickname) {
1746 memset(buf, 0, sizeof(buf));
1747 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1748 idle > 60 ? (idle / 60) : idle,
1749 idle > 60 ? "minutes" : "seconds");
1751 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1752 SILCTXT_WHOIS_IDLE, buf);
1756 fingerprint = silc_fingerprint(fingerprint, 20);
1757 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1758 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1759 silc_free(fingerprint);
1763 silc_query_attributes_print(server, silc_client, conn, attrs,
1768 case SILC_COMMAND_IDENTIFY:
1770 SilcClientEntry client_entry;
1772 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1773 /* Print the unknown nick for user */
1774 unsigned char *tmp =
1775 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1778 silc_say_error("%s: %s", tmp,
1779 silc_get_status_message(status));
1781 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1782 /* Try to find the entry for the unknown client ID, since we
1783 might have, and print the nickname of it for user. */
1785 unsigned char *tmp =
1786 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1789 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1792 client_entry = silc_client_get_client_by_id(client, conn,
1794 if (client_entry && client_entry->nickname)
1795 silc_say_error("%s: %s", client_entry->nickname,
1796 silc_get_status_message(status));
1797 silc_free(client_id);
1806 case SILC_COMMAND_WHOWAS:
1808 char *nickname, *username, *realname;
1810 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1812 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1815 silc_say_error("%s: %s", tmp,
1816 silc_get_status_message(status));
1818 } else if (!success) {
1819 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1823 (void)va_arg(vp, SilcClientEntry);
1824 nickname = va_arg(vp, char *);
1825 username = va_arg(vp, char *);
1826 realname = va_arg(vp, char *);
1828 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1829 SILCTXT_WHOWAS_USERINFO, nickname, username,
1830 realname ? realname : "");
1834 case SILC_COMMAND_INVITE:
1836 SilcChannelEntry channel;
1838 SilcArgumentPayload invite_list;
1844 channel = va_arg(vp, SilcChannelEntry);
1845 payload = va_arg(vp, SilcBuffer);
1848 SILC_GET16_MSB(argc, payload->data);
1849 invite_list = silc_argument_payload_parse(payload->data + 2,
1850 payload->len - 2, argc);
1852 silc_parse_inviteban_list(client, conn, server, channel,
1853 "invite", invite_list);
1854 silc_argument_payload_free(invite_list);
1860 case SILC_COMMAND_JOIN:
1862 char *channel, *mode, *topic;
1864 SilcChannelEntry channel_entry;
1865 SilcBuffer client_id_list;
1866 SilcUInt32 list_count;
1871 channel = va_arg(vp, char *);
1872 channel_entry = va_arg(vp, SilcChannelEntry);
1873 modei = va_arg(vp, SilcUInt32);
1874 (void)va_arg(vp, SilcUInt32);
1875 (void)va_arg(vp, unsigned char *);
1876 (void)va_arg(vp, unsigned char *);
1877 (void)va_arg(vp, unsigned char *);
1878 topic = va_arg(vp, char *);
1879 (void)va_arg(vp, unsigned char *);
1880 list_count = va_arg(vp, SilcUInt32);
1881 client_id_list = va_arg(vp, SilcBuffer);
1883 chanrec = silc_channel_find(server, channel);
1885 chanrec = silc_channel_create(server, channel, channel, TRUE);
1888 char tmp[256], *cp, *dm = NULL;
1889 g_free_not_null(chanrec->topic);
1891 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1892 memset(tmp, 0, sizeof(tmp));
1894 if (strlen(topic) > sizeof(tmp) - 1) {
1895 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1899 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1904 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1905 signal_emit("channel topic changed", 1, chanrec);
1910 mode = silc_client_chmode(modei,
1911 channel_entry->channel_key ?
1912 silc_cipher_get_name(channel_entry->
1914 channel_entry->hmac ?
1915 silc_hmac_get_name(channel_entry->hmac) : "");
1916 g_free_not_null(chanrec->mode);
1917 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1918 signal_emit("channel mode changed", 1, chanrec);
1920 /* Resolve the client information */
1922 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1923 r->channel = channel_entry;
1924 silc_client_get_clients_by_list(client, conn, list_count,
1926 silc_client_join_get_users, r);
1932 case SILC_COMMAND_NICK:
1935 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1941 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1942 if ((nicks != NULL) &&
1943 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1945 SilcClientEntry collider, old;
1947 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1948 collider = silc_client_get_client_by_id(client, conn,
1951 if (collider != client_entry) {
1953 memset(buf, 0, sizeof(buf));
1954 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1955 collider->username, collider->hostname);
1956 nicklist_rename_unique(SERVER(server),
1958 collider, collider->nickname);
1959 silc_print_nick_change(server, collider->nickname,
1960 client_entry->nickname, buf);
1965 g_slist_free(nicks);
1967 old = g_strdup(server->nick);
1968 server_change_nick(SERVER(server), client_entry->nickname);
1969 nicklist_rename_unique(SERVER(server),
1970 server->conn->local_entry, server->nick,
1971 client_entry, client_entry->nickname);
1972 signal_emit("message own_nick", 4, server, server->nick, old, "");
1977 case SILC_COMMAND_LIST:
1982 char tmp[256], *cp, *dm = NULL;
1987 (void)va_arg(vp, SilcChannelEntry);
1988 name = va_arg(vp, char *);
1989 topic = va_arg(vp, char *);
1990 usercount = va_arg(vp, int);
1992 if (topic && !silc_term_utf8() &&
1993 silc_utf8_valid(topic, strlen(topic))) {
1994 memset(tmp, 0, sizeof(tmp));
1996 if (strlen(topic) > sizeof(tmp) - 1) {
1997 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2001 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2006 if (status == SILC_STATUS_LIST_START ||
2007 status == SILC_STATUS_OK)
2008 printformat_module("fe-common/silc", server, NULL,
2009 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
2012 snprintf(users, sizeof(users) - 1, "N/A");
2014 snprintf(users, sizeof(users) - 1, "%d", usercount);
2015 printformat_module("fe-common/silc", server, NULL,
2016 MSGLEVEL_CRAP, SILCTXT_LIST,
2017 name, users, topic ? topic : "");
2022 case SILC_COMMAND_UMODE:
2030 mode = va_arg(vp, SilcUInt32);
2032 if (mode & SILC_UMODE_SERVER_OPERATOR &&
2033 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
2034 printformat_module("fe-common/silc", server, NULL,
2035 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2037 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
2038 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
2039 printformat_module("fe-common/silc", server, NULL,
2040 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2042 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
2043 if (mode & SILC_UMODE_GONE) {
2044 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
2045 reason = g_strdup(server->away_reason);
2047 reason = g_strdup("away");
2049 reason = g_strdup("");
2051 silc_set_away(reason, server);
2056 server->umode = mode;
2057 signal_emit("user mode changed", 2, server, NULL);
2061 case SILC_COMMAND_OPER:
2065 server->umode |= SILC_UMODE_SERVER_OPERATOR;
2066 signal_emit("user mode changed", 2, server, NULL);
2068 printformat_module("fe-common/silc", server, NULL,
2069 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
2072 case SILC_COMMAND_SILCOPER:
2076 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
2077 signal_emit("user mode changed", 2, server, NULL);
2079 printformat_module("fe-common/silc", server, NULL,
2080 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
2083 case SILC_COMMAND_USERS:
2085 SilcHashTableList htl;
2086 SilcChannelEntry channel;
2087 SilcChannelUser chu;
2092 channel = va_arg(vp, SilcChannelEntry);
2094 printformat_module("fe-common/silc", server, channel->channel_name,
2095 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
2096 channel->channel_name);
2098 silc_hash_table_list(channel->user_list, &htl);
2099 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
2100 SilcClientEntry e = chu->client;
2101 char stat[5], *mode;
2106 memset(stat, 0, sizeof(stat));
2107 mode = silc_client_chumode_char(chu->mode);
2108 if (e->mode & SILC_UMODE_GONE)
2110 else if (e->mode & SILC_UMODE_INDISPOSED)
2112 else if (e->mode & SILC_UMODE_BUSY)
2114 else if (e->mode & SILC_UMODE_PAGE)
2116 else if (e->mode & SILC_UMODE_HYPER)
2118 else if (e->mode & SILC_UMODE_ROBOT)
2120 else if (e->mode & SILC_UMODE_ANONYMOUS)
2127 printformat_module("fe-common/silc", server, channel->channel_name,
2128 MSGLEVEL_CRAP, SILCTXT_USERS,
2130 e->username ? e->username : "",
2131 e->hostname ? e->hostname : "",
2132 e->realname ? e->realname : "");
2136 silc_hash_table_list_reset(&htl);
2140 case SILC_COMMAND_BAN:
2142 SilcChannelEntry channel;
2144 SilcArgumentPayload ban_list;
2150 channel = va_arg(vp, SilcChannelEntry);
2151 payload = va_arg(vp, SilcBuffer);
2154 SILC_GET16_MSB(argc, payload->data);
2155 ban_list = silc_argument_payload_parse(payload->data + 2,
2156 payload->len - 2, argc);
2158 silc_parse_inviteban_list(client, conn, server, channel,
2160 silc_argument_payload_free(ban_list);
2166 case SILC_COMMAND_GETKEY:
2170 SilcPublicKey public_key;
2173 GetkeyContext getkey;
2179 id_type = va_arg(vp, SilcUInt32);
2180 entry = va_arg(vp, void *);
2181 public_key = va_arg(vp, SilcPublicKey);
2184 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2186 getkey = silc_calloc(1, sizeof(*getkey));
2187 getkey->entry = entry;
2188 getkey->id_type = id_type;
2189 getkey->client = client;
2190 getkey->conn = conn;
2191 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2193 name = (id_type == SILC_ID_CLIENT ?
2194 ((SilcClientEntry)entry)->nickname :
2195 ((SilcServerEntry)entry)->server_name);
2197 silc_verify_public_key_internal(client, conn, name,
2198 (id_type == SILC_ID_CLIENT ?
2199 SILC_SOCKET_TYPE_CLIENT :
2200 SILC_SOCKET_TYPE_SERVER),
2201 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2202 silc_getkey_cb, getkey);
2205 printformat_module("fe-common/silc", server, NULL,
2206 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2211 case SILC_COMMAND_INFO:
2213 SilcServerEntry server_entry;
2220 server_entry = va_arg(vp, SilcServerEntry);
2221 server_name = va_arg(vp, char *);
2222 server_info = va_arg(vp, char *);
2224 if (server_name && server_info )
2226 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2227 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2232 case SILC_COMMAND_TOPIC:
2234 SilcChannelEntry channel;
2236 char tmp[256], *cp, *dm = NULL;
2241 channel = va_arg(vp, SilcChannelEntry);
2242 topic = va_arg(vp, char *);
2244 if (topic && !silc_term_utf8() &&
2245 silc_utf8_valid(topic, strlen(topic))) {
2246 memset(tmp, 0, sizeof(tmp));
2248 if (strlen(topic) > sizeof(tmp) - 1) {
2249 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2253 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2259 chanrec = silc_channel_find_entry(server, channel);
2261 g_free_not_null(chanrec->topic);
2262 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2263 signal_emit("channel topic changed", 1, chanrec);
2265 printformat_module("fe-common/silc", server, channel->channel_name,
2266 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2267 channel->channel_name, topic);
2269 printformat_module("fe-common/silc", server, channel->channel_name,
2270 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2271 channel->channel_name);
2277 case SILC_COMMAND_WATCH:
2280 case SILC_COMMAND_STATS:
2282 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2283 my_router_ops, cell_clients, cell_channels, cell_servers,
2284 clients, channels, servers, routers, server_ops, router_ops;
2286 SilcBufferStruct buf;
2287 unsigned char *tmp_buf;
2289 const char *tmptime;
2290 int days, hours, mins, secs;
2295 tmp_buf = va_arg(vp, unsigned char *);
2296 buf_len = va_arg(vp, SilcUInt32);
2298 if (!tmp_buf || !buf_len) {
2299 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2303 /* Get statistics structure */
2304 silc_buffer_set(&buf, tmp_buf, buf_len);
2305 silc_buffer_unformat(&buf,
2306 SILC_STR_UI_INT(&starttime),
2307 SILC_STR_UI_INT(&uptime),
2308 SILC_STR_UI_INT(&my_clients),
2309 SILC_STR_UI_INT(&my_channels),
2310 SILC_STR_UI_INT(&my_server_ops),
2311 SILC_STR_UI_INT(&my_router_ops),
2312 SILC_STR_UI_INT(&cell_clients),
2313 SILC_STR_UI_INT(&cell_channels),
2314 SILC_STR_UI_INT(&cell_servers),
2315 SILC_STR_UI_INT(&clients),
2316 SILC_STR_UI_INT(&channels),
2317 SILC_STR_UI_INT(&servers),
2318 SILC_STR_UI_INT(&routers),
2319 SILC_STR_UI_INT(&server_ops),
2320 SILC_STR_UI_INT(&router_ops),
2323 tmptime = silc_get_time(starttime);
2324 printformat_module("fe-common/silc", server, NULL,
2325 MSGLEVEL_CRAP, SILCTXT_STATS,
2326 "Local server start time", tmptime);
2328 days = uptime / (24 * 60 * 60);
2329 uptime -= days * (24 * 60 * 60);
2330 hours = uptime / (60 * 60);
2331 uptime -= hours * (60 * 60);
2333 uptime -= mins * 60;
2335 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2336 days, hours, mins, secs);
2337 printformat_module("fe-common/silc", server, NULL,
2338 MSGLEVEL_CRAP, SILCTXT_STATS,
2339 "Local server uptime", tmp);
2341 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2342 printformat_module("fe-common/silc", server, NULL,
2343 MSGLEVEL_CRAP, SILCTXT_STATS,
2344 "Local server clients", tmp);
2346 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2347 printformat_module("fe-common/silc", server, NULL,
2348 MSGLEVEL_CRAP, SILCTXT_STATS,
2349 "Local server channels", tmp);
2351 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2352 printformat_module("fe-common/silc", server, NULL,
2353 MSGLEVEL_CRAP, SILCTXT_STATS,
2354 "Local server operators", tmp);
2356 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2357 printformat_module("fe-common/silc", server, NULL,
2358 MSGLEVEL_CRAP, SILCTXT_STATS,
2359 "Local router operators", tmp);
2361 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2362 printformat_module("fe-common/silc", server, NULL,
2363 MSGLEVEL_CRAP, SILCTXT_STATS,
2364 "Local cell clients", tmp);
2366 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2367 printformat_module("fe-common/silc", server, NULL,
2368 MSGLEVEL_CRAP, SILCTXT_STATS,
2369 "Local cell channels", tmp);
2371 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2372 printformat_module("fe-common/silc", server, NULL,
2373 MSGLEVEL_CRAP, SILCTXT_STATS,
2374 "Local cell servers", tmp);
2376 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2377 printformat_module("fe-common/silc", server, NULL,
2378 MSGLEVEL_CRAP, SILCTXT_STATS,
2379 "Total clients", tmp);
2381 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2382 printformat_module("fe-common/silc", server, NULL,
2383 MSGLEVEL_CRAP, SILCTXT_STATS,
2384 "Total channels", tmp);
2386 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2387 printformat_module("fe-common/silc", server, NULL,
2388 MSGLEVEL_CRAP, SILCTXT_STATS,
2389 "Total servers", tmp);
2391 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2392 printformat_module("fe-common/silc", server, NULL,
2393 MSGLEVEL_CRAP, SILCTXT_STATS,
2394 "Total routers", tmp);
2396 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2397 printformat_module("fe-common/silc", server, NULL,
2398 MSGLEVEL_CRAP, SILCTXT_STATS,
2399 "Total server operators", tmp);
2401 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2402 printformat_module("fe-common/silc", server, NULL,
2403 MSGLEVEL_CRAP, SILCTXT_STATS,
2404 "Total router operators", tmp);
2408 case SILC_COMMAND_CMODE:
2410 SilcChannelEntry channel_entry;
2411 SilcBuffer channel_pubkeys;
2413 channel_entry = va_arg(vp, SilcChannelEntry);
2414 (void)va_arg(vp, SilcUInt32);
2415 (void)va_arg(vp, SilcPublicKey);
2416 channel_pubkeys = va_arg(vp, SilcBuffer);
2418 if (!success || !cmode_list_chpks ||
2419 !channel_entry || !channel_entry->channel_name)
2422 /* Print the channel public key list */
2423 if (channel_pubkeys)
2424 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2426 printformat_module("fe-common/silc", server, NULL,
2427 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2428 channel_entry->channel_name);
2439 SilcClientConnection conn;
2445 SilcSKEPKType pk_type;
2446 SilcVerifyPublicKey completion;
2450 static void verify_public_key_completion(const char *line, void *context)
2452 PublicKeyVerify verify = (PublicKeyVerify)context;
2454 if (line[0] == 'Y' || line[0] == 'y') {
2455 /* Call the completion */
2456 if (verify->completion)
2457 verify->completion(TRUE, verify->context);
2459 /* Save the key for future checking */
2460 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2461 verify->pk_len, SILC_PKCS_FILE_PEM);
2463 /* Call the completion */
2464 if (verify->completion)
2465 verify->completion(FALSE, verify->context);
2467 printformat_module("fe-common/silc", NULL, NULL,
2468 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2469 verify->entity_name ? verify->entity_name :
2473 silc_free(verify->filename);
2474 silc_free(verify->entity);
2475 silc_free(verify->entity_name);
2476 silc_free(verify->pk);
2480 /* Internal routine to verify public key. If the `completion' is provided
2481 it will be called to indicate whether public was verified or not. For
2482 server/router public key this will check for filename that includes the
2483 remote host's IP address and remote host's hostname. */
2486 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2487 const char *name, SilcSocketType conn_type,
2488 unsigned char *pk, SilcUInt32 pk_len,
2489 SilcSKEPKType pk_type,
2490 SilcVerifyPublicKey completion, void *context)
2493 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2494 char *fingerprint, *babbleprint, *format;
2497 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2498 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2499 "server" : "client");
2500 PublicKeyVerify verify;
2502 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2503 printformat_module("fe-common/silc", NULL, NULL,
2504 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2507 completion(FALSE, context);
2511 pw = getpwuid(getuid());
2514 completion(FALSE, context);
2518 memset(filename, 0, sizeof(filename));
2519 memset(filename2, 0, sizeof(filename2));
2520 memset(file, 0, sizeof(file));
2522 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2523 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2525 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2526 conn->sock->ip, conn->sock->port);
2527 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2528 get_irssi_dir(), entity, file);
2530 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2531 conn->sock->hostname, conn->sock->port);
2532 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2533 get_irssi_dir(), entity, file);
2538 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2539 name, conn->sock->port);
2540 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2541 get_irssi_dir(), entity, file);
2546 /* Replace all whitespaces with `_'. */
2547 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2548 for (i = 0; i < strlen(fingerprint); i++)
2549 if (fingerprint[i] == ' ')
2550 fingerprint[i] = '_';
2552 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2553 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2554 get_irssi_dir(), entity, file);
2555 silc_free(fingerprint);
2560 /* Take fingerprint of the public key */
2561 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2562 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2564 verify = silc_calloc(1, sizeof(*verify));
2565 verify->client = client;
2566 verify->conn = conn;
2567 verify->filename = strdup(ipf);
2568 verify->entity = strdup(entity);
2569 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2570 (name ? strdup(name) : strdup(conn->sock->hostname))
2572 verify->pk = silc_memdup(pk, pk_len);
2573 verify->pk_len = pk_len;
2574 verify->pk_type = pk_type;
2575 verify->completion = completion;
2576 verify->context = context;
2578 /* Check whether this key already exists */
2579 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2580 /* Key does not exist, ask user to verify the key and save it */
2582 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2583 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2584 verify->entity_name : entity);
2585 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2586 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2587 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2588 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2589 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2590 SILCTXT_PUBKEY_ACCEPT);
2591 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2594 silc_free(fingerprint);
2597 /* The key already exists, verify it. */
2598 SilcPublicKey public_key;
2599 unsigned char *encpk;
2600 SilcUInt32 encpk_len;
2602 /* Load the key file, try for both IP filename and hostname filename */
2603 if (!silc_pkcs_load_public_key(ipf, &public_key,
2604 SILC_PKCS_FILE_PEM) &&
2605 !silc_pkcs_load_public_key(ipf, &public_key,
2606 SILC_PKCS_FILE_BIN) &&
2607 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2608 SILC_PKCS_FILE_PEM) &&
2609 !silc_pkcs_load_public_key(hostf, &public_key,
2610 SILC_PKCS_FILE_BIN)))) {
2611 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2612 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2613 verify->entity_name : entity);
2614 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2615 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2616 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2617 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2618 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2619 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2620 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2621 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2622 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2625 silc_free(fingerprint);
2629 /* Encode the key data */
2630 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2632 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2633 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2634 verify->entity_name : entity);
2635 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2636 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2637 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2638 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2639 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2640 SILCTXT_PUBKEY_MALFORMED, entity);
2641 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2642 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2643 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2646 silc_free(fingerprint);
2650 /* Compare the keys */
2651 if (memcmp(encpk, pk, encpk_len)) {
2652 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2653 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2654 verify->entity_name : entity);
2655 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2656 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2657 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2658 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2659 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2660 SILCTXT_PUBKEY_NO_MATCH, entity);
2661 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2662 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2663 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2664 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2666 /* Ask user to verify the key and save it */
2667 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2668 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2669 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2672 silc_free(fingerprint);
2676 /* Local copy matched */
2678 completion(TRUE, context);
2679 silc_free(fingerprint);
2680 silc_free(verify->filename);
2681 silc_free(verify->entity);
2682 silc_free(verify->entity_name);
2683 silc_free(verify->pk);
2688 /* Verifies received public key. The `conn_type' indicates which entity
2689 (server, client etc.) has sent the public key. If user decides to trust
2690 the key may be saved as trusted public key for later use. The
2691 `completion' must be called after the public key has been verified. */
2694 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2695 SilcSocketType conn_type, unsigned char *pk,
2696 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2697 SilcVerifyPublicKey completion, void *context)
2699 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2701 completion, context);
2704 /* Asks passphrase from user on the input line. */
2707 SilcAskPassphrase completion;
2711 void ask_passphrase_completion(const char *passphrase, void *context)
2713 AskPassphrase p = (AskPassphrase)context;
2714 if (passphrase && passphrase[0] == '\0')
2716 p->completion((unsigned char *)passphrase,
2717 passphrase ? strlen(passphrase) : 0, p->context);
2721 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2722 SilcAskPassphrase completion, void *context)
2724 AskPassphrase p = silc_calloc(1, sizeof(*p));
2725 p->completion = completion;
2726 p->context = context;
2728 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2729 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2733 SilcGetAuthMeth completion;
2735 } *InternalGetAuthMethod;
2737 /* Callback called when we've received the authentication method information
2738 from the server after we've requested it. This will get the authentication
2739 data from the user if needed. */
2741 static void silc_get_auth_method_callback(SilcClient client,
2742 SilcClientConnection conn,
2743 SilcAuthMethod auth_meth,
2746 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2748 SILC_LOG_DEBUG(("Start"));
2750 switch (auth_meth) {
2751 case SILC_AUTH_NONE:
2752 /* No authentication required. */
2753 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2755 case SILC_AUTH_PASSWORD:
2757 /* Check whether we find the password for this server in our
2758 configuration. If not, then don't provide so library will ask
2759 it from the user. */
2760 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2762 if (!setup || !setup->password) {
2763 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2767 (*internal->completion)(TRUE, auth_meth, setup->password,
2768 strlen(setup->password), internal->context);
2771 case SILC_AUTH_PUBLIC_KEY:
2772 /* Do not get the authentication data now, the library will generate
2773 it using our default key, if we do not provide it here. */
2774 /* XXX In the future when we support multiple local keys and multiple
2775 local certificates we will need to ask from user which one to use. */
2776 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2780 silc_free(internal);
2783 /* Find authentication method and authentication data by hostname and
2784 port. The hostname may be IP address as well. The found authentication
2785 method and authentication data is returned to `auth_meth', `auth_data'
2786 and `auth_data_len'. The function returns TRUE if authentication method
2787 is found and FALSE if not. `conn' may be NULL. */
2789 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2790 char *hostname, SilcUInt16 port,
2791 SilcGetAuthMeth completion, void *context)
2793 InternalGetAuthMethod internal;
2795 SILC_LOG_DEBUG(("Start"));
2797 /* If we do not have this connection configured by the user in a
2798 configuration file then resolve the authentication method from the
2799 server for this session. */
2800 internal = silc_calloc(1, sizeof(*internal));
2801 internal->completion = completion;
2802 internal->context = context;
2804 silc_client_request_authentication_method(client, conn,
2805 silc_get_auth_method_callback,
2809 /* Notifies application that failure packet was received. This is called
2810 if there is some protocol active in the client. The `protocol' is the
2811 protocol context. The `failure' is opaque pointer to the failure
2812 indication. Note, that the `failure' is protocol dependant and application
2813 must explicitly cast it to correct type. Usually `failure' is 32 bit
2814 failure type (see protocol specs for all protocol failure types). */
2816 void silc_failure(SilcClient client, SilcClientConnection conn,
2817 SilcProtocol protocol, void *failure)
2819 SILC_LOG_DEBUG(("Start"));
2821 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2822 SilcSKEStatus status = (SilcSKEStatus)failure;
2824 if (status == SILC_SKE_STATUS_BAD_VERSION)
2825 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2826 SILCTXT_KE_BAD_VERSION);
2827 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2828 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2829 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2830 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2831 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2832 SILCTXT_KE_UNKNOWN_GROUP);
2833 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2834 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2835 SILCTXT_KE_UNKNOWN_CIPHER);
2836 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2837 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2838 SILCTXT_KE_UNKNOWN_PKCS);
2839 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2840 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2841 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2842 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2843 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2844 SILCTXT_KE_UNKNOWN_HMAC);
2845 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2846 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2847 SILCTXT_KE_INCORRECT_SIGNATURE);
2848 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2849 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2850 SILCTXT_KE_INVALID_COOKIE);
2853 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2854 SilcUInt32 err = (SilcUInt32)failure;
2856 if (err == SILC_AUTH_FAILED)
2857 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2858 SILCTXT_AUTH_FAILED);
2862 /* Asks whether the user would like to perform the key agreement protocol.
2863 This is called after we have received an key agreement packet or an
2864 reply to our key agreement packet. This returns TRUE if the user wants
2865 the library to perform the key agreement protocol and FALSE if it is not
2866 desired (application may start it later by calling the function
2867 silc_client_perform_key_agreement). */
2869 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2870 SilcClientEntry client_entry, const char *hostname,
2871 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2876 SILC_LOG_DEBUG(("Start"));
2878 /* We will just display the info on the screen and return FALSE and user
2879 will have to start the key agreement with a command. */
2882 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2885 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2886 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2888 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2889 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2890 client_entry->nickname, hostname, portstr);
2898 /* Notifies application that file transfer protocol session is being
2899 requested by the remote client indicated by the `client_entry' from
2900 the `hostname' and `port'. The `session_id' is the file transfer
2901 session and it can be used to either accept or reject the file
2902 transfer request, by calling the silc_client_file_receive or
2903 silc_client_file_close, respectively. */
2905 void silc_ftp(SilcClient client, SilcClientConnection conn,
2906 SilcClientEntry client_entry, SilcUInt32 session_id,
2907 const char *hostname, SilcUInt16 port)
2909 SILC_SERVER_REC *server;
2911 FtpSession ftp = NULL;
2913 SILC_LOG_DEBUG(("Start"));
2915 server = conn->context;
2917 silc_dlist_start(server->ftp_sessions);
2918 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2919 if (ftp->client_entry == client_entry &&
2920 ftp->session_id == session_id) {
2921 server->current_session = ftp;
2925 if (ftp == SILC_LIST_END) {
2926 ftp = silc_calloc(1, sizeof(*ftp));
2927 ftp->client_entry = client_entry;
2928 ftp->session_id = session_id;
2931 silc_dlist_add(server->ftp_sessions, ftp);
2932 server->current_session = ftp;
2936 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2939 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2940 SILCTXT_FILE_REQUEST, client_entry->nickname);
2942 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2943 SILCTXT_FILE_REQUEST_HOST,
2944 client_entry->nickname, hostname, portstr);
2947 /* Delivers SILC session detachment data indicated by `detach_data' to the
2948 application. If application has issued SILC_COMMAND_DETACH command
2949 the client session in the SILC network is not quit. The client remains
2950 in the network but is detached. The detachment data may be used later
2951 to resume the session in the SILC Network. The appliation is
2952 responsible of saving the `detach_data', to for example in a file.
2954 The detachment data can be given as argument to the functions
2955 silc_client_connect_to_server, or silc_client_add_connection when
2956 creating connection to remote server, inside SilcClientConnectionParams
2957 structure. If it is provided the client library will attempt to resume
2958 the session in the network. After the connection is created
2959 successfully, the application is responsible of setting the user
2960 interface for user into the same state it was before detaching (showing
2961 same channels, channel modes, etc). It can do this by fetching the
2962 information (like joined channels) from the client library. */
2965 silc_detach(SilcClient client, SilcClientConnection conn,
2966 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2968 SILC_SERVER_REC *server = conn->context;
2971 /* Save the detachment data to file. */
2973 file = silc_get_session_filename(server);
2974 silc_file_writefile(file, detach_data, detach_data_len);
2979 /* SILC client operations */
2980 SilcClientOperations ops = {
2982 silc_channel_message,
2983 silc_private_message,
2989 silc_get_auth_method,
2990 silc_verify_public_key,
2991 silc_ask_passphrase,