5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 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"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/core/window-items.h"
40 #include "fe-common/silc/module-formats.h"
45 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
46 const char *name, SilcSocketType conn_type,
47 unsigned char *pk, SilcUInt32 pk_len,
48 SilcSKEPKType pk_type,
49 SilcVerifyPublicKey completion, void *context);
51 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
54 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
55 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
56 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
58 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
59 "[SILC operator]" : "[unknown mode]");
61 if (mode & SILC_UMODE_GONE)
62 strcat(buf, " [away]");
63 if (mode & SILC_UMODE_INDISPOSED)
64 strcat(buf, " [indisposed]");
65 if (mode & SILC_UMODE_BUSY)
66 strcat(buf, " [busy]");
67 if (mode & SILC_UMODE_PAGE)
68 strcat(buf, " [page to reach]");
69 if (mode & SILC_UMODE_HYPER)
70 strcat(buf, " [hyper active]");
71 if (mode & SILC_UMODE_ROBOT)
72 strcat(buf, " [robot]");
73 if (mode & SILC_UMODE_ANONYMOUS)
74 strcat(buf, " [anonymous]");
75 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
76 strcat(buf, " [blocks private messages]");
77 if (mode & SILC_UMODE_DETACHED)
78 strcat(buf, " [detached]");
79 if (mode & SILC_UMODE_REJECT_WATCHING)
80 strcat(buf, " [rejects watching]");
81 if (mode & SILC_UMODE_BLOCK_INVITE)
82 strcat(buf, " [blocks invites]");
85 /* print "nick appears as" message to every channel of a server */
87 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
88 const char *newnick, const char *oldnick,
91 if (ignore_check(server, oldnick, address,
92 channel, newnick, MSGLEVEL_NICKS))
95 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
96 SILCTXT_CHANNEL_APPEARS,
97 oldnick, newnick, channel, address);
101 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
102 const char *oldnick, const char *address)
104 GSList *tmp, *windows;
106 /* Print to each channel/query where the nick is.
107 Don't print more than once to the same window. */
110 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
111 CHANNEL_REC *channel = tmp->data;
112 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
114 if (nicklist_find(channel, newnick) == NULL ||
115 g_slist_find(windows, window) != NULL)
118 windows = g_slist_append(windows, window);
119 silc_print_nick_change_channel(server, channel->visible_name,
120 newnick, oldnick, address);
123 g_slist_free(windows);
127 void silc_say(SilcClient client, SilcClientConnection conn,
128 SilcClientMessageType type, char *msg, ...)
130 SILC_SERVER_REC *server;
134 server = conn == NULL ? NULL : conn->context;
137 str = g_strdup_vprintf(msg, va);
138 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
143 void silc_say_error(char *msg, ...)
149 str = g_strdup_vprintf(msg, va);
150 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
156 /* Message for a channel. The `sender' is the nickname of the sender
157 received in the packet. The `channel_name' is the name of the channel. */
159 void silc_channel_message(SilcClient client, SilcClientConnection conn,
160 SilcClientEntry sender, SilcChannelEntry channel,
161 SilcMessageFlags flags, const unsigned char *message,
162 SilcUInt32 message_len)
164 SILC_SERVER_REC *server;
166 SILC_CHANNEL_REC *chanrec;
168 SILC_LOG_DEBUG(("Start"));
173 server = conn == NULL ? NULL : conn->context;
174 chanrec = silc_channel_find_entry(server, channel);
178 nick = silc_nicklist_find(chanrec, sender);
180 /* We didn't find client but it clearly exists, add it. */
181 SilcChannelUser chu = silc_client_on_channel(channel, sender);
183 nick = silc_nicklist_insert(chanrec, chu, FALSE);
186 if (flags & SILC_MESSAGE_FLAG_DATA) {
187 /* MIME object received, try to display it as well as we can */
188 char type[128], enc[128];
192 memset(type, 0, sizeof(type));
193 memset(enc, 0, sizeof(enc));
194 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
195 enc, sizeof(enc) - 1, &data, &data_len))
198 /* Then figure out what we can display */
199 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
200 !strstr(type, "text/vnd")) {
201 /* It is something textual, display it */
202 message = (const unsigned char *)data;
204 printformat_module("fe-common/silc", server, channel->channel_name,
205 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
206 nick == NULL ? "[<unknown>]" : nick->nick, type);
214 if (flags & SILC_MESSAGE_FLAG_ACTION)
215 printformat_module("fe-common/silc", server, channel->channel_name,
216 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
217 nick == NULL ? "[<unknown>]" : nick->nick, message);
218 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
219 printformat_module("fe-common/silc", server, channel->channel_name,
220 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
221 nick == NULL ? "[<unknown>]" : nick->nick, message);
223 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
224 char tmp[256], *cp, *dm = NULL;
226 memset(tmp, 0, sizeof(tmp));
228 if (message_len > sizeof(tmp) - 1) {
229 dm = silc_calloc(message_len + 1, sizeof(*dm));
233 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
235 signal_emit("message public", 6, server, cp,
236 nick == NULL ? "[<unknown>]" : nick->nick,
237 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
238 chanrec->name, nick);
243 signal_emit("message public", 6, server, message,
244 nick == NULL ? "[<unknown>]" : nick->nick,
245 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
246 chanrec->name, nick);
250 /* Private message to the client. The `sender' is the nickname of the
251 sender received in the packet. */
253 void silc_private_message(SilcClient client, SilcClientConnection conn,
254 SilcClientEntry sender, SilcMessageFlags flags,
255 const unsigned char *message,
256 SilcUInt32 message_len)
258 SILC_SERVER_REC *server;
261 SILC_LOG_DEBUG(("Start"));
263 server = conn == NULL ? NULL : conn->context;
264 memset(userhost, 0, sizeof(userhost));
265 if (sender->username)
266 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
267 sender->username, sender->hostname);
269 if (flags & SILC_MESSAGE_FLAG_DATA) {
270 /* MIME object received, try to display it as well as we can */
271 char type[128], enc[128];
275 memset(type, 0, sizeof(type));
276 memset(enc, 0, sizeof(enc));
277 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
278 enc, sizeof(enc) - 1, &data, &data_len))
281 /* Then figure out what we can display */
282 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
283 !strstr(type, "text/vnd")) {
284 /* It is something textual, display it */
285 message = (const unsigned char *)data;
287 printformat_module("fe-common/silc", server, NULL,
288 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
289 sender->nickname ? sender->nickname : "[<unknown>]",
298 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
299 char tmp[256], *cp, *dm = NULL;
301 memset(tmp, 0, sizeof(tmp));
303 if (message_len > sizeof(tmp) - 1) {
304 dm = silc_calloc(message_len + 1, sizeof(*dm));
308 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
310 signal_emit("message private", 4, server, cp,
311 sender->nickname ? sender->nickname : "[<unknown>]",
312 sender->username ? userhost : NULL);
317 signal_emit("message private", 4, server, message,
318 sender->nickname ? sender->nickname : "[<unknown>]",
319 sender->username ? userhost : NULL);
322 /* Notify message to the client. The notify arguments are sent in the
323 same order as servers sends them. The arguments are same as received
324 from the server except for ID's. If ID is received application receives
325 the corresponding entry to the ID. For example, if Client ID is received
326 application receives SilcClientEntry. Also, if the notify type is
327 for channel the channel entry is sent to application (even if server
328 does not send it). */
330 void silc_notify(SilcClient client, SilcClientConnection conn,
331 SilcNotifyType type, ...)
334 SILC_SERVER_REC *server;
335 SILC_CHANNEL_REC *chanrec;
336 SILC_NICK_REC *nickrec;
337 SilcClientEntry client_entry, client_entry2;
338 SilcChannelEntry channel, channel2;
339 SilcServerEntry server_entry;
345 GSList *list1, *list_tmp;
347 SILC_LOG_DEBUG(("Start"));
351 server = conn == NULL ? NULL : conn->context;
354 case SILC_NOTIFY_TYPE_NONE:
355 /* Some generic notice from server */
356 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
359 case SILC_NOTIFY_TYPE_INVITE:
361 * Invited or modified invite list.
364 SILC_LOG_DEBUG(("Notify: INVITE"));
366 channel = va_arg(va, SilcChannelEntry);
367 name = va_arg(va, char *);
368 client_entry = va_arg(va, SilcClientEntry);
370 memset(buf, 0, sizeof(buf));
371 snprintf(buf, sizeof(buf) - 1, "%s@%s",
372 client_entry->username, client_entry->hostname);
373 signal_emit("message invite", 4, server, channel ? channel->channel_name :
374 name, client_entry->nickname, buf);
377 case SILC_NOTIFY_TYPE_JOIN:
382 SILC_LOG_DEBUG(("Notify: JOIN"));
384 client_entry = va_arg(va, SilcClientEntry);
385 channel = va_arg(va, SilcChannelEntry);
387 if (client_entry == server->conn->local_entry) {
388 /* You joined to channel */
389 chanrec = silc_channel_find(server, channel->channel_name);
390 if (chanrec != NULL && !chanrec->joined)
391 chanrec->entry = channel;
393 chanrec = silc_channel_find_entry(server, channel);
394 if (chanrec != NULL) {
395 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
397 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
401 memset(buf, 0, sizeof(buf));
402 if (client_entry->username)
403 snprintf(buf, sizeof(buf) - 1, "%s@%s",
404 client_entry->username, client_entry->hostname);
405 signal_emit("message join", 4, server, channel->channel_name,
406 client_entry->nickname,
407 client_entry->username == NULL ? "" : buf);
410 case SILC_NOTIFY_TYPE_LEAVE:
415 SILC_LOG_DEBUG(("Notify: LEAVE"));
417 client_entry = va_arg(va, SilcClientEntry);
418 channel = va_arg(va, SilcChannelEntry);
420 memset(buf, 0, sizeof(buf));
421 if (client_entry->username)
422 snprintf(buf, sizeof(buf) - 1, "%s@%s",
423 client_entry->username, client_entry->hostname);
424 signal_emit("message part", 5, server, channel->channel_name,
425 client_entry->nickname, client_entry->username ?
426 buf : "", client_entry->nickname);
428 chanrec = silc_channel_find_entry(server, channel);
429 if (chanrec != NULL) {
430 nickrec = silc_nicklist_find(chanrec, client_entry);
432 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
436 case SILC_NOTIFY_TYPE_SIGNOFF:
441 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
443 client_entry = va_arg(va, SilcClientEntry);
444 tmp = va_arg(va, char *);
446 silc_server_free_ftp(server, client_entry);
448 memset(buf, 0, sizeof(buf));
449 if (client_entry->username)
450 snprintf(buf, sizeof(buf) - 1, "%s@%s",
451 client_entry->username, client_entry->hostname);
452 signal_emit("message quit", 4, server, client_entry->nickname,
453 client_entry->username ? buf : "",
456 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
457 for (list_tmp = list1; list_tmp != NULL; list_tmp =
458 list_tmp->next->next) {
459 CHANNEL_REC *channel = list_tmp->data;
460 NICK_REC *nickrec = list_tmp->next->data;
462 nicklist_remove(channel, nickrec);
466 case SILC_NOTIFY_TYPE_TOPIC_SET:
471 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
473 idtype = va_arg(va, int);
474 entry = va_arg(va, void *);
475 tmp = va_arg(va, char *);
476 channel = va_arg(va, SilcChannelEntry);
478 chanrec = silc_channel_find_entry(server, channel);
479 if (chanrec != NULL) {
480 g_free_not_null(chanrec->topic);
481 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
482 signal_emit("channel topic changed", 1, chanrec);
485 if (idtype == SILC_ID_CLIENT) {
486 client_entry = (SilcClientEntry)entry;
487 memset(buf, 0, sizeof(buf));
488 snprintf(buf, sizeof(buf) - 1, "%s@%s",
489 client_entry->username, client_entry->hostname);
490 signal_emit("message topic", 5, server, channel->channel_name,
491 tmp, client_entry->nickname, buf);
492 } else if (idtype == SILC_ID_SERVER) {
493 server_entry = (SilcServerEntry)entry;
494 signal_emit("message topic", 5, server, channel->channel_name,
495 tmp, server_entry->server_name,
496 server_entry->server_name);
497 } else if (idtype == SILC_ID_CHANNEL) {
498 channel = (SilcChannelEntry)entry;
499 signal_emit("message topic", 5, server, channel->channel_name,
500 tmp, channel->channel_name, channel->channel_name);
504 case SILC_NOTIFY_TYPE_NICK_CHANGE:
509 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
511 client_entry = va_arg(va, SilcClientEntry);
512 client_entry2 = va_arg(va, SilcClientEntry);
514 if (!strcmp(client_entry->nickname, client_entry2->nickname))
517 memset(buf, 0, sizeof(buf));
518 snprintf(buf, sizeof(buf) - 1, "%s@%s",
519 client_entry2->username, client_entry2->hostname);
520 nicklist_rename_unique(SERVER(server),
521 client_entry, client_entry->nickname,
522 client_entry2, client_entry2->nickname);
523 signal_emit("message nick", 4, server, client_entry2->nickname,
524 client_entry->nickname, buf);
527 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
529 * Changed channel mode.
532 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
534 idtype = va_arg(va, int);
535 entry = va_arg(va, void *);
536 mode = va_arg(va, SilcUInt32);
537 (void)va_arg(va, char *);
538 (void)va_arg(va, char *);
539 channel = va_arg(va, SilcChannelEntry);
541 tmp = silc_client_chmode(mode,
542 channel->channel_key ?
543 silc_cipher_get_name(channel->channel_key) : "",
545 silc_hmac_get_name(channel->hmac) : "");
547 chanrec = silc_channel_find_entry(server, channel);
548 if (chanrec != NULL) {
549 g_free_not_null(chanrec->mode);
550 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
551 signal_emit("channel mode changed", 1, chanrec);
554 if (idtype == SILC_ID_CLIENT) {
555 client_entry = (SilcClientEntry)entry;
556 printformat_module("fe-common/silc", server, channel->channel_name,
557 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
558 channel->channel_name, tmp ? tmp : "removed all",
559 client_entry->nickname);
560 } else if (idtype == SILC_ID_SERVER) {
561 server_entry = (SilcServerEntry)entry;
562 printformat_module("fe-common/silc", server, channel->channel_name,
563 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
564 channel->channel_name, tmp ? tmp : "removed all",
565 server_entry->server_name);
566 } else if (idtype == SILC_ID_CHANNEL) {
567 channel2 = (SilcChannelEntry)entry;
568 printformat_module("fe-common/silc", server, channel->channel_name,
569 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
570 channel->channel_name, tmp ? tmp : "removed all",
571 channel2->channel_name);
577 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
579 * Changed user's mode on channel.
582 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
584 idtype = va_arg(va, int);
585 entry = va_arg(va, void *);
586 mode = va_arg(va, SilcUInt32);
587 client_entry2 = va_arg(va, SilcClientEntry);
588 channel = va_arg(va, SilcChannelEntry);
590 tmp = silc_client_chumode(mode);
591 chanrec = silc_channel_find_entry(server, channel);
592 if (chanrec != NULL) {
595 if (client_entry2 == server->conn->local_entry)
596 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
598 nick = silc_nicklist_find(chanrec, client_entry2);
600 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
601 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
602 signal_emit("nick mode changed", 2, chanrec, nick);
606 if (idtype == SILC_ID_CLIENT) {
607 client_entry = (SilcClientEntry)entry;
608 printformat_module("fe-common/silc", server, channel->channel_name,
609 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
610 channel->channel_name, client_entry2->nickname,
611 tmp ? tmp : "removed all",
612 client_entry->nickname);
613 } else if (idtype == SILC_ID_SERVER) {
614 server_entry = (SilcServerEntry)entry;
615 printformat_module("fe-common/silc", server, channel->channel_name,
616 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
617 channel->channel_name, client_entry2->nickname,
618 tmp ? tmp : "removed all",
619 server_entry->server_name);
620 } else if (idtype == SILC_ID_CHANNEL) {
621 channel2 = (SilcChannelEntry)entry;
622 printformat_module("fe-common/silc", server, channel->channel_name,
623 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
624 channel->channel_name, client_entry2->nickname,
625 tmp ? tmp : "removed all",
626 channel2->channel_name);
629 if (mode & SILC_CHANNEL_UMODE_CHANFO)
630 printformat_module("fe-common/silc",
631 server, channel->channel_name, MSGLEVEL_CRAP,
632 SILCTXT_CHANNEL_FOUNDER,
633 channel->channel_name, client_entry2->nickname);
635 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
636 printformat_module("fe-common/silc",
637 server, channel->channel_name, MSGLEVEL_CRAP,
638 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
643 case SILC_NOTIFY_TYPE_MOTD:
648 SILC_LOG_DEBUG(("Notify: MOTD"));
650 tmp = va_arg(va, char *);
652 if (!settings_get_bool("skip_motd"))
653 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
656 case SILC_NOTIFY_TYPE_KICKED:
658 * Someone was kicked from channel.
661 SILC_LOG_DEBUG(("Notify: KICKED"));
663 client_entry = va_arg(va, SilcClientEntry);
664 tmp = va_arg(va, char *);
665 client_entry2 = va_arg(va, SilcClientEntry);
666 channel = va_arg(va, SilcChannelEntry);
668 chanrec = silc_channel_find_entry(server, channel);
670 if (client_entry == conn->local_entry) {
671 printformat_module("fe-common/silc", server, channel->channel_name,
672 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
673 channel->channel_name,
674 client_entry ? client_entry2->nickname : "",
677 chanrec->kicked = TRUE;
678 channel_destroy((CHANNEL_REC *)chanrec);
681 printformat_module("fe-common/silc", server, channel->channel_name,
682 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
683 client_entry->nickname, channel->channel_name,
684 client_entry2 ? client_entry2->nickname : "",
688 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
690 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
695 case SILC_NOTIFY_TYPE_KILLED:
697 * Someone was killed from the network.
700 SILC_LOG_DEBUG(("Notify: KILLED"));
702 client_entry = va_arg(va, SilcClientEntry);
703 tmp = va_arg(va, char *);
704 idtype = va_arg(va, int);
705 entry = va_arg(va, SilcClientEntry);
707 if (client_entry == conn->local_entry) {
708 if (idtype == SILC_ID_CLIENT) {
709 client_entry2 = (SilcClientEntry)entry;
710 printformat_module("fe-common/silc", server, NULL,
711 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
712 client_entry2 ? client_entry2->nickname : "",
714 } else if (idtype == SILC_ID_SERVER) {
715 server_entry = (SilcServerEntry)entry;
716 printformat_module("fe-common/silc", server, NULL,
717 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
718 server_entry->server_name, tmp ? tmp : "");
719 } else if (idtype == SILC_ID_CHANNEL) {
720 channel = (SilcChannelEntry)entry;
721 printformat_module("fe-common/silc", server, NULL,
722 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
723 channel->channel_name, tmp ? tmp : "");
726 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
727 for (list_tmp = list1; list_tmp != NULL; list_tmp =
728 list_tmp->next->next) {
729 CHANNEL_REC *channel = list_tmp->data;
730 NICK_REC *nickrec = list_tmp->next->data;
731 nicklist_remove(channel, nickrec);
734 if (idtype == SILC_ID_CLIENT) {
735 client_entry2 = (SilcClientEntry)entry;
736 printformat_module("fe-common/silc", server, NULL,
737 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
738 client_entry->nickname,
739 client_entry2 ? client_entry2->nickname : "",
741 } else if (idtype == SILC_ID_SERVER) {
742 server_entry = (SilcServerEntry)entry;
743 printformat_module("fe-common/silc", server, NULL,
744 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
745 client_entry->nickname,
746 server_entry->server_name, tmp ? tmp : "");
747 } else if (idtype == SILC_ID_CHANNEL) {
748 channel = (SilcChannelEntry)entry;
749 printformat_module("fe-common/silc", server, NULL,
750 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
751 client_entry->nickname,
752 channel->channel_name, tmp ? tmp : "");
757 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
760 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
763 * Server has quit the network.
766 SilcClientEntry *clients;
767 SilcUInt32 clients_count;
769 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
771 (void)va_arg(va, void *);
772 clients = va_arg(va, SilcClientEntry *);
773 clients_count = va_arg(va, SilcUInt32);
775 for (i = 0; i < clients_count; i++) {
776 memset(buf, 0, sizeof(buf));
777 if (clients[i]->username)
778 snprintf(buf, sizeof(buf) - 1, "%s@%s",
779 clients[i]->username, clients[i]->hostname);
780 signal_emit("message quit", 4, server, clients[i]->nickname,
781 clients[i]->username ? buf : "",
784 silc_server_free_ftp(server, clients[i]);
786 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
787 for (list_tmp = list1; list_tmp != NULL; list_tmp =
788 list_tmp->next->next) {
789 CHANNEL_REC *channel = list_tmp->data;
790 NICK_REC *nickrec = list_tmp->next->data;
791 nicklist_remove(channel, nickrec);
797 case SILC_NOTIFY_TYPE_ERROR:
799 SilcStatus error = va_arg(va, int);
801 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
802 "%s", silc_get_status_message(error));
806 case SILC_NOTIFY_TYPE_WATCH:
808 SilcNotifyType notify;
810 client_entry = va_arg(va, SilcClientEntry);
811 name = va_arg(va, char *); /* Maybe NULL */
812 mode = va_arg(va, SilcUInt32);
813 notify = va_arg(va, int);
815 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
817 printformat_module("fe-common/silc", server, NULL,
818 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
819 client_entry->nickname, name);
821 printformat_module("fe-common/silc", server, NULL,
822 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
823 client_entry->nickname);
824 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
825 /* See if client was away and is now present */
826 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
827 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
828 SILC_UMODE_DETACHED)) &&
829 (client_entry->mode & SILC_UMODE_GONE ||
830 client_entry->mode & SILC_UMODE_INDISPOSED ||
831 client_entry->mode & SILC_UMODE_BUSY ||
832 client_entry->mode & SILC_UMODE_PAGE ||
833 client_entry->mode & SILC_UMODE_DETACHED)) {
834 printformat_module("fe-common/silc", server, NULL,
835 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
836 client_entry->nickname);
840 memset(buf, 0, sizeof(buf));
841 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
842 printformat_module("fe-common/silc", server, NULL,
843 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
844 client_entry->nickname, buf);
846 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
847 printformat_module("fe-common/silc", server, NULL,
848 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
849 client_entry->nickname);
850 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
851 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
852 printformat_module("fe-common/silc", server, NULL,
853 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
854 client_entry->nickname);
855 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
856 /* Client logged in to the network */
857 printformat_module("fe-common/silc", server, NULL,
858 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
859 client_entry->nickname);
866 printformat_module("fe-common/silc", server, NULL,
867 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
874 /* Called to indicate that connection was either successfully established
875 or connecting failed. This is also the first time application receives
876 the SilcClientConnection object which it should save somewhere. */
878 void silc_connect(SilcClient client, SilcClientConnection conn,
879 SilcClientConnectionStatus status)
881 SILC_SERVER_REC *server = conn->context;
883 if (!server || server->disconnected) {
884 silc_client_close_connection(client, conn);
889 case SILC_CLIENT_CONN_SUCCESS:
890 /* We have successfully connected to server */
891 server->connected = TRUE;
892 signal_emit("event connected", 1, server);
895 case SILC_CLIENT_CONN_SUCCESS_RESUME:
896 /* We have successfully resumed old detached session */
897 server->connected = TRUE;
898 signal_emit("event connected", 1, server);
900 /* If we resumed old session check whether we need to update
902 if (strcmp(server->nick, conn->local_entry->nickname)) {
904 old = g_strdup(server->nick);
905 server_change_nick(SERVER(server), conn->local_entry->nickname);
906 nicklist_rename_unique(SERVER(server),
907 conn->local_entry, server->nick,
908 conn->local_entry, conn->local_entry->nickname);
909 signal_emit("message own_nick", 4, server, server->nick, old, "");
915 server->connection_lost = TRUE;
917 server->conn->context = NULL;
918 server_disconnect(SERVER(server));
923 /* Called to indicate that connection was disconnected to the server. */
925 void silc_disconnect(SilcClient client, SilcClientConnection conn,
926 SilcStatus status, const char *message)
928 SILC_SERVER_REC *server = conn->context;
930 SILC_LOG_DEBUG(("Start"));
932 if (!server || server->connection_lost)
935 if (server->conn && server->conn->local_entry) {
936 nicklist_rename_unique(SERVER(server),
937 server->conn->local_entry, server->nick,
938 server->conn->local_entry,
939 silc_client->username);
940 silc_change_nick(server, silc_client->username);
944 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
945 "Server closed connection: %s (%d) %s",
946 silc_get_status_message(status), status,
947 message ? message : "");
949 server->conn->context = NULL;
951 server->connection_lost = TRUE;
952 server_disconnect(SERVER(server));
955 /* Command handler. This function is called always in the command function.
956 If error occurs it will be called as well. `conn' is the associated
957 client connection. `cmd_context' is the command context that was
958 originally sent to the command. `success' is FALSE if error occured
959 during command. `command' is the command being processed. It must be
960 noted that this is not reply from server. This is merely called just
961 after application has called the command. Just to tell application
962 that the command really was processed. */
964 void silc_command(SilcClient client, SilcClientConnection conn,
965 SilcClientCommandContext cmd_context, bool success,
966 SilcCommand command, SilcStatus status)
968 SILC_SERVER_REC *server = conn->context;
970 SILC_LOG_DEBUG(("Start"));
973 silc_say_error("%s", silc_get_status_message(status));
979 case SILC_COMMAND_INVITE:
980 if (cmd_context->argc > 2)
981 printformat_module("fe-common/silc", server, NULL,
982 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
983 cmd_context->argv[2],
984 (cmd_context->argv[1][0] == '*' ?
985 (char *)conn->current_channel->channel_name :
986 (char *)cmd_context->argv[1]));
989 case SILC_COMMAND_DETACH:
990 server->no_reconnect = TRUE;
998 /* Client info resolving callback when JOIN command reply is received.
999 This will cache all users on the channel. */
1001 static void silc_client_join_get_users(SilcClient client,
1002 SilcClientConnection conn,
1003 SilcClientEntry *clients,
1004 SilcUInt32 clients_count,
1007 SilcChannelEntry channel = (SilcChannelEntry)context;
1008 SilcHashTableList htl;
1009 SilcChannelUser chu;
1010 SILC_SERVER_REC *server = conn->context;
1011 SILC_CHANNEL_REC *chanrec;
1012 SilcClientEntry founder = NULL;
1015 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1016 silc_hash_table_count(channel->user_list)));
1021 chanrec = silc_channel_find(server, channel->channel_name);
1022 if (chanrec == NULL)
1025 silc_hash_table_list(channel->user_list, &htl);
1026 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1027 if (!chu->client->nickname)
1029 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1030 founder = chu->client;
1031 silc_nicklist_insert(chanrec, chu, FALSE);
1033 silc_hash_table_list_reset(&htl);
1035 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1036 nicklist_set_own(CHANNEL(chanrec), ownnick);
1037 signal_emit("channel joined", 1, chanrec);
1038 chanrec->entry = channel;
1041 printformat_module("fe-common/silc", server, channel->channel_name,
1042 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1043 channel->channel_name, chanrec->topic);
1046 if (founder == conn->local_entry)
1047 printformat_module("fe-common/silc",
1048 server, channel->channel_name, MSGLEVEL_CRAP,
1049 SILCTXT_CHANNEL_FOUNDER_YOU,
1050 channel->channel_name);
1052 printformat_module("fe-common/silc",
1053 server, channel->channel_name, MSGLEVEL_CRAP,
1054 SILCTXT_CHANNEL_FOUNDER,
1055 channel->channel_name, founder->nickname);
1061 SilcClientConnection conn;
1067 void silc_getkey_cb(bool success, void *context)
1069 GetkeyContext getkey = (GetkeyContext)context;
1070 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1071 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1072 ((SilcClientEntry)getkey->entry)->nickname :
1073 ((SilcServerEntry)getkey->entry)->server_name);
1076 printformat_module("fe-common/silc", NULL, NULL,
1077 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1079 printformat_module("fe-common/silc", NULL, NULL,
1080 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1084 silc_free(getkey->fingerprint);
1088 /* Command reply handler. This function is called always in the command reply
1089 function. If error occurs it will be called as well. Normal scenario
1090 is that it will be called after the received command data has been parsed
1091 and processed. The function is used to pass the received command data to
1094 `conn' is the associated client connection. `cmd_payload' is the command
1095 payload data received from server and it can be ignored. It is provided
1096 if the application would like to re-parse the received command data,
1097 however, it must be noted that the data is parsed already by the library
1098 thus the payload can be ignored. `success' is FALSE if error occured.
1099 In this case arguments are not sent to the application. `command' is the
1100 command reply being processed. The function has variable argument list
1101 and each command defines the number and type of arguments it passes to the
1102 application (on error they are not sent). */
1105 silc_command_reply(SilcClient client, SilcClientConnection conn,
1106 SilcCommandPayload cmd_payload, bool success,
1107 SilcCommand command, SilcStatus status, ...)
1110 SILC_SERVER_REC *server = conn->context;
1111 SILC_CHANNEL_REC *chanrec;
1114 va_start(vp, status);
1116 SILC_LOG_DEBUG(("Start"));
1119 case SILC_COMMAND_WHOIS:
1121 char buf[1024], *nickname, *username, *realname, *nick;
1122 unsigned char *fingerprint;
1123 SilcUInt32 idle, mode;
1124 SilcBuffer channels, user_modes;
1125 SilcClientEntry client_entry;
1128 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1129 /* Print the unknown nick for user */
1130 unsigned char *tmp =
1131 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1134 silc_say_error("%s: %s", tmp,
1135 silc_get_status_message(status));
1137 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1138 /* Try to find the entry for the unknown client ID, since we
1139 might have, and print the nickname of it for user. */
1141 unsigned char *tmp =
1142 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1145 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1148 client_entry = silc_client_get_client_by_id(client, conn,
1150 if (client_entry && client_entry->nickname)
1151 silc_say_error("%s: %s", client_entry->nickname,
1152 silc_get_status_message(status));
1153 silc_free(client_id);
1157 } else if (!success) {
1158 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1162 client_entry = va_arg(vp, SilcClientEntry);
1163 nickname = va_arg(vp, char *);
1164 username = va_arg(vp, char *);
1165 realname = va_arg(vp, char *);
1166 channels = va_arg(vp, SilcBuffer);
1167 mode = va_arg(vp, SilcUInt32);
1168 idle = va_arg(vp, SilcUInt32);
1169 fingerprint = va_arg(vp, unsigned char *);
1170 user_modes = va_arg(vp, SilcBuffer);
1171 attrs = va_arg(vp, SilcDList);
1173 silc_parse_userfqdn(nickname, &nick, NULL);
1174 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1175 SILCTXT_WHOIS_USERINFO, nickname,
1176 client_entry->username, client_entry->hostname,
1177 nick, client_entry->nickname);
1178 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1179 SILCTXT_WHOIS_REALNAME, realname);
1182 if (channels && user_modes) {
1184 SilcDList list = silc_channel_payload_parse_list(channels->data,
1186 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1188 SilcChannelPayload entry;
1191 memset(buf, 0, sizeof(buf));
1192 silc_dlist_start(list);
1193 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1194 SilcUInt32 name_len;
1195 char *m = silc_client_chumode_char(umodes[i++]);
1196 char *name = silc_channel_get_name(entry, &name_len);
1199 strncat(buf, m, strlen(m));
1200 strncat(buf, name, name_len);
1201 strncat(buf, " ", 1);
1205 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1206 SILCTXT_WHOIS_CHANNELS, buf);
1207 silc_channel_payload_list_free(list);
1213 memset(buf, 0, sizeof(buf));
1214 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1215 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1216 SILCTXT_WHOIS_MODES, buf);
1219 if (idle && nickname) {
1220 memset(buf, 0, sizeof(buf));
1221 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1222 idle > 60 ? (idle / 60) : idle,
1223 idle > 60 ? "minutes" : "seconds");
1225 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1226 SILCTXT_WHOIS_IDLE, buf);
1230 fingerprint = silc_fingerprint(fingerprint, 20);
1231 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1232 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1233 silc_free(fingerprint);
1237 silc_query_attributes_print(server, silc_client, conn, attrs,
1242 case SILC_COMMAND_IDENTIFY:
1244 SilcClientEntry client_entry;
1246 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1247 /* Print the unknown nick for user */
1248 unsigned char *tmp =
1249 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1252 silc_say_error("%s: %s", tmp,
1253 silc_get_status_message(status));
1255 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1256 /* Try to find the entry for the unknown client ID, since we
1257 might have, and print the nickname of it for user. */
1259 unsigned char *tmp =
1260 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1263 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1266 client_entry = silc_client_get_client_by_id(client, conn,
1268 if (client_entry && client_entry->nickname)
1269 silc_say_error("%s: %s", client_entry->nickname,
1270 silc_get_status_message(status));
1271 silc_free(client_id);
1280 case SILC_COMMAND_WHOWAS:
1282 char *nickname, *username, *realname;
1284 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1285 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1287 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1290 silc_say_error("%s: %s", tmp,
1291 silc_get_status_message(status));
1293 } else if (!success) {
1294 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1298 (void)va_arg(vp, SilcClientEntry);
1299 nickname = va_arg(vp, char *);
1300 username = va_arg(vp, char *);
1301 realname = va_arg(vp, char *);
1303 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1304 SILCTXT_WHOWAS_USERINFO, nickname, username,
1305 realname ? realname : "");
1309 case SILC_COMMAND_INVITE:
1311 SilcChannelEntry channel;
1313 SilcArgumentPayload args;
1319 channel = va_arg(vp, SilcChannelEntry);
1320 invite_list = va_arg(vp, char *);
1322 args = silc_command_get_args(cmd_payload);
1324 argc = silc_argument_get_arg_num(args);
1327 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1328 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1331 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1332 SILCTXT_CHANNEL_NO_INVITE_LIST,
1333 channel->channel_name);
1337 case SILC_COMMAND_JOIN:
1339 char *channel, *mode, *topic;
1341 SilcChannelEntry channel_entry;
1342 SilcBuffer client_id_list;
1343 SilcUInt32 list_count;
1348 channel = va_arg(vp, char *);
1349 channel_entry = va_arg(vp, SilcChannelEntry);
1350 modei = va_arg(vp, SilcUInt32);
1351 (void)va_arg(vp, SilcUInt32);
1352 (void)va_arg(vp, unsigned char *);
1353 (void)va_arg(vp, unsigned char *);
1354 (void)va_arg(vp, unsigned char *);
1355 topic = va_arg(vp, char *);
1356 (void)va_arg(vp, unsigned char *);
1357 list_count = va_arg(vp, SilcUInt32);
1358 client_id_list = va_arg(vp, SilcBuffer);
1360 chanrec = silc_channel_find(server, channel);
1362 chanrec = silc_channel_create(server, channel, channel, TRUE);
1365 g_free_not_null(chanrec->topic);
1366 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1367 signal_emit("channel topic changed", 1, chanrec);
1370 mode = silc_client_chmode(modei,
1371 channel_entry->channel_key ?
1372 silc_cipher_get_name(channel_entry->
1374 channel_entry->hmac ?
1375 silc_hmac_get_name(channel_entry->hmac) : "");
1376 g_free_not_null(chanrec->mode);
1377 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1378 signal_emit("channel mode changed", 1, chanrec);
1380 /* Resolve the client information */
1381 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1382 silc_client_join_get_users,
1388 case SILC_COMMAND_NICK:
1391 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1397 nicks = nicklist_get_same(SERVER(server), client->nickname);
1398 if (nicks != NULL) {
1400 SilcClientEntry collider, old;
1402 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1403 collider = silc_client_get_client_by_id(client, conn,
1406 memset(buf, 0, sizeof(buf));
1407 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1408 collider->username, collider->hostname);
1409 nicklist_rename_unique(SERVER(server),
1411 collider, collider->nickname);
1412 silc_print_nick_change(server, collider->nickname, client->nickname,
1415 g_slist_free(nicks);
1419 old = g_strdup(server->nick);
1420 server_change_nick(SERVER(server), client->nickname);
1421 nicklist_rename_unique(SERVER(server),
1422 server->conn->local_entry, server->nick,
1423 client, client->nickname);
1424 signal_emit("message own_nick", 4, server, server->nick, old, "");
1429 case SILC_COMMAND_LIST:
1434 char tmp[256], *cp, *dm = NULL;
1439 (void)va_arg(vp, SilcChannelEntry);
1440 name = va_arg(vp, char *);
1441 topic = va_arg(vp, char *);
1442 usercount = va_arg(vp, int);
1444 if (topic && !silc_term_utf8() &&
1445 silc_utf8_valid(topic, strlen(topic))) {
1446 memset(tmp, 0, sizeof(tmp));
1448 if (strlen(topic) > sizeof(tmp) - 1) {
1449 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1453 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1458 if (status == SILC_STATUS_LIST_START ||
1459 status == SILC_STATUS_OK)
1460 printformat_module("fe-common/silc", server, NULL,
1461 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1464 snprintf(users, sizeof(users) - 1, "N/A");
1466 snprintf(users, sizeof(users) - 1, "%d", usercount);
1467 printformat_module("fe-common/silc", server, NULL,
1468 MSGLEVEL_CRAP, SILCTXT_LIST,
1469 name, users, topic ? topic : "");
1474 case SILC_COMMAND_UMODE:
1482 mode = va_arg(vp, SilcUInt32);
1484 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1485 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1486 printformat_module("fe-common/silc", server, NULL,
1487 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1489 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1490 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1491 printformat_module("fe-common/silc", server, NULL,
1492 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1494 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1495 if (mode & SILC_UMODE_GONE) {
1496 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1497 reason = g_strdup(server->away_reason);
1499 reason = g_strdup("away");
1501 reason = g_strdup("");
1503 silc_set_away(reason, server);
1508 server->umode = mode;
1509 signal_emit("user mode changed", 2, server, NULL);
1513 case SILC_COMMAND_OPER:
1517 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1518 signal_emit("user mode changed", 2, server, NULL);
1520 printformat_module("fe-common/silc", server, NULL,
1521 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1524 case SILC_COMMAND_SILCOPER:
1528 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1529 signal_emit("user mode changed", 2, server, NULL);
1531 printformat_module("fe-common/silc", server, NULL,
1532 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1535 case SILC_COMMAND_USERS:
1537 SilcHashTableList htl;
1538 SilcChannelEntry channel;
1539 SilcChannelUser chu;
1544 channel = va_arg(vp, SilcChannelEntry);
1546 printformat_module("fe-common/silc", server, channel->channel_name,
1547 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1548 channel->channel_name);
1550 silc_hash_table_list(channel->user_list, &htl);
1551 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1552 SilcClientEntry e = chu->client;
1553 char stat[5], *mode;
1558 memset(stat, 0, sizeof(stat));
1559 mode = silc_client_chumode_char(chu->mode);
1560 if (e->mode & SILC_UMODE_GONE)
1562 else if (e->mode & SILC_UMODE_INDISPOSED)
1564 else if (e->mode & SILC_UMODE_BUSY)
1566 else if (e->mode & SILC_UMODE_PAGE)
1568 else if (e->mode & SILC_UMODE_HYPER)
1570 else if (e->mode & SILC_UMODE_ROBOT)
1572 else if (e->mode & SILC_UMODE_ANONYMOUS)
1579 printformat_module("fe-common/silc", server, channel->channel_name,
1580 MSGLEVEL_CRAP, SILCTXT_USERS,
1582 e->username ? e->username : "",
1583 e->hostname ? e->hostname : "",
1584 e->realname ? e->realname : "");
1588 silc_hash_table_list_reset(&htl);
1592 case SILC_COMMAND_BAN:
1594 SilcChannelEntry channel;
1600 channel = va_arg(vp, SilcChannelEntry);
1601 ban_list = va_arg(vp, char *);
1604 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1605 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1608 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1609 SILCTXT_CHANNEL_NO_BAN_LIST,
1610 channel->channel_name);
1614 case SILC_COMMAND_GETKEY:
1618 SilcPublicKey public_key;
1621 GetkeyContext getkey;
1627 id_type = va_arg(vp, SilcUInt32);
1628 entry = va_arg(vp, void *);
1629 public_key = va_arg(vp, SilcPublicKey);
1632 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1634 getkey = silc_calloc(1, sizeof(*getkey));
1635 getkey->entry = entry;
1636 getkey->id_type = id_type;
1637 getkey->client = client;
1638 getkey->conn = conn;
1639 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1641 name = (id_type == SILC_ID_CLIENT ?
1642 ((SilcClientEntry)entry)->nickname :
1643 ((SilcServerEntry)entry)->server_name);
1645 silc_verify_public_key_internal(client, conn, name,
1646 (id_type == SILC_ID_CLIENT ?
1647 SILC_SOCKET_TYPE_CLIENT :
1648 SILC_SOCKET_TYPE_SERVER),
1649 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1650 silc_getkey_cb, getkey);
1653 printformat_module("fe-common/silc", server, NULL,
1654 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1659 case SILC_COMMAND_INFO:
1661 SilcServerEntry server_entry;
1668 server_entry = va_arg(vp, SilcServerEntry);
1669 server_name = va_arg(vp, char *);
1670 server_info = va_arg(vp, char *);
1672 if (server_name && server_info )
1674 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1675 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1680 case SILC_COMMAND_TOPIC:
1682 SilcChannelEntry channel;
1684 char tmp[256], *cp, *dm = NULL;
1689 channel = va_arg(vp, SilcChannelEntry);
1690 topic = va_arg(vp, char *);
1692 if (topic && !silc_term_utf8() &&
1693 silc_utf8_valid(topic, strlen(topic))) {
1694 memset(tmp, 0, sizeof(tmp));
1696 if (strlen(topic) > sizeof(tmp) - 1) {
1697 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1701 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1707 chanrec = silc_channel_find_entry(server, channel);
1709 g_free_not_null(chanrec->topic);
1710 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1711 signal_emit("channel topic changed", 1, chanrec);
1713 printformat_module("fe-common/silc", server, channel->channel_name,
1714 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1715 channel->channel_name, topic);
1717 printformat_module("fe-common/silc", server, channel->channel_name,
1718 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1719 channel->channel_name);
1725 case SILC_COMMAND_WATCH:
1728 case SILC_COMMAND_STATS:
1730 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1731 my_router_ops, cell_clients, cell_channels, cell_servers,
1732 clients, channels, servers, routers, server_ops, router_ops;
1734 SilcBufferStruct buf;
1735 unsigned char *tmp_buf;
1737 const char *tmptime;
1738 int days, hours, mins, secs;
1743 tmp_buf = va_arg(vp, unsigned char *);
1744 buf_len = va_arg(vp, SilcUInt32);
1746 if (!tmp_buf || !buf_len) {
1747 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
1751 /* Get statistics structure */
1752 silc_buffer_set(&buf, tmp_buf, buf_len);
1753 silc_buffer_unformat(&buf,
1754 SILC_STR_UI_INT(&starttime),
1755 SILC_STR_UI_INT(&uptime),
1756 SILC_STR_UI_INT(&my_clients),
1757 SILC_STR_UI_INT(&my_channels),
1758 SILC_STR_UI_INT(&my_server_ops),
1759 SILC_STR_UI_INT(&my_router_ops),
1760 SILC_STR_UI_INT(&cell_clients),
1761 SILC_STR_UI_INT(&cell_channels),
1762 SILC_STR_UI_INT(&cell_servers),
1763 SILC_STR_UI_INT(&clients),
1764 SILC_STR_UI_INT(&channels),
1765 SILC_STR_UI_INT(&servers),
1766 SILC_STR_UI_INT(&routers),
1767 SILC_STR_UI_INT(&server_ops),
1768 SILC_STR_UI_INT(&router_ops),
1771 tmptime = silc_get_time(starttime);
1772 printformat_module("fe-common/silc", server, NULL,
1773 MSGLEVEL_CRAP, SILCTXT_STATS,
1774 "Local server start time", tmptime);
1776 days = uptime / (24 * 60 * 60);
1777 uptime -= days * (24 * 60 * 60);
1778 hours = uptime / (60 * 60);
1779 uptime -= hours * (60 * 60);
1781 uptime -= mins * 60;
1783 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
1784 days, hours, mins, secs);
1785 printformat_module("fe-common/silc", server, NULL,
1786 MSGLEVEL_CRAP, SILCTXT_STATS,
1787 "Local server uptime", tmp);
1789 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
1790 printformat_module("fe-common/silc", server, NULL,
1791 MSGLEVEL_CRAP, SILCTXT_STATS,
1792 "Local server clients", tmp);
1794 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
1795 printformat_module("fe-common/silc", server, NULL,
1796 MSGLEVEL_CRAP, SILCTXT_STATS,
1797 "Local server channels", tmp);
1799 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
1800 printformat_module("fe-common/silc", server, NULL,
1801 MSGLEVEL_CRAP, SILCTXT_STATS,
1802 "Local server operators", tmp);
1804 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
1805 printformat_module("fe-common/silc", server, NULL,
1806 MSGLEVEL_CRAP, SILCTXT_STATS,
1807 "Local router operators", tmp);
1809 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
1810 printformat_module("fe-common/silc", server, NULL,
1811 MSGLEVEL_CRAP, SILCTXT_STATS,
1812 "Local cell clients", tmp);
1814 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
1815 printformat_module("fe-common/silc", server, NULL,
1816 MSGLEVEL_CRAP, SILCTXT_STATS,
1817 "Local cell channels", tmp);
1819 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
1820 printformat_module("fe-common/silc", server, NULL,
1821 MSGLEVEL_CRAP, SILCTXT_STATS,
1822 "Local cell servers", tmp);
1824 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
1825 printformat_module("fe-common/silc", server, NULL,
1826 MSGLEVEL_CRAP, SILCTXT_STATS,
1827 "Total clients", tmp);
1829 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
1830 printformat_module("fe-common/silc", server, NULL,
1831 MSGLEVEL_CRAP, SILCTXT_STATS,
1832 "Total channels", tmp);
1834 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
1835 printformat_module("fe-common/silc", server, NULL,
1836 MSGLEVEL_CRAP, SILCTXT_STATS,
1837 "Total servers", tmp);
1839 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
1840 printformat_module("fe-common/silc", server, NULL,
1841 MSGLEVEL_CRAP, SILCTXT_STATS,
1842 "Total routers", tmp);
1844 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
1845 printformat_module("fe-common/silc", server, NULL,
1846 MSGLEVEL_CRAP, SILCTXT_STATS,
1847 "Total server operators", tmp);
1849 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
1850 printformat_module("fe-common/silc", server, NULL,
1851 MSGLEVEL_CRAP, SILCTXT_STATS,
1852 "Total router operators", tmp);
1863 SilcClientConnection conn;
1869 SilcSKEPKType pk_type;
1870 SilcVerifyPublicKey completion;
1874 static void verify_public_key_completion(const char *line, void *context)
1876 PublicKeyVerify verify = (PublicKeyVerify)context;
1878 if (line[0] == 'Y' || line[0] == 'y') {
1879 /* Call the completion */
1880 if (verify->completion)
1881 verify->completion(TRUE, verify->context);
1883 /* Save the key for future checking */
1884 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1885 verify->pk_len, SILC_PKCS_FILE_PEM);
1887 /* Call the completion */
1888 if (verify->completion)
1889 verify->completion(FALSE, verify->context);
1891 printformat_module("fe-common/silc", NULL, NULL,
1892 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1893 verify->entity_name ? verify->entity_name :
1897 silc_free(verify->filename);
1898 silc_free(verify->entity);
1899 silc_free(verify->entity_name);
1900 silc_free(verify->pk);
1904 /* Internal routine to verify public key. If the `completion' is provided
1905 it will be called to indicate whether public was verified or not. For
1906 server/router public key this will check for filename that includes the
1907 remote host's IP address and remote host's hostname. */
1910 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1911 const char *name, SilcSocketType conn_type,
1912 unsigned char *pk, SilcUInt32 pk_len,
1913 SilcSKEPKType pk_type,
1914 SilcVerifyPublicKey completion, void *context)
1917 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1918 char *fingerprint, *babbleprint, *format;
1921 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1922 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1923 "server" : "client");
1924 PublicKeyVerify verify;
1926 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1927 printformat_module("fe-common/silc", NULL, NULL,
1928 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1931 completion(FALSE, context);
1935 pw = getpwuid(getuid());
1938 completion(FALSE, context);
1942 memset(filename, 0, sizeof(filename));
1943 memset(filename2, 0, sizeof(filename2));
1944 memset(file, 0, sizeof(file));
1946 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1947 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1949 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1950 conn->sock->ip, conn->sock->port);
1951 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1952 get_irssi_dir(), entity, file);
1954 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1955 conn->sock->hostname, conn->sock->port);
1956 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1957 get_irssi_dir(), entity, file);
1962 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1963 name, conn->sock->port);
1964 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1965 get_irssi_dir(), entity, file);
1970 /* Replace all whitespaces with `_'. */
1971 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1972 for (i = 0; i < strlen(fingerprint); i++)
1973 if (fingerprint[i] == ' ')
1974 fingerprint[i] = '_';
1976 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1977 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1978 get_irssi_dir(), entity, file);
1979 silc_free(fingerprint);
1984 /* Take fingerprint of the public key */
1985 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1986 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1988 verify = silc_calloc(1, sizeof(*verify));
1989 verify->client = client;
1990 verify->conn = conn;
1991 verify->filename = strdup(ipf);
1992 verify->entity = strdup(entity);
1993 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1994 (name ? strdup(name) : strdup(conn->sock->hostname))
1996 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1997 memcpy(verify->pk, pk, pk_len);
1998 verify->pk_len = pk_len;
1999 verify->pk_type = pk_type;
2000 verify->completion = completion;
2001 verify->context = context;
2003 /* Check whether this key already exists */
2004 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2005 /* Key does not exist, ask user to verify the key and save it */
2007 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2008 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2009 verify->entity_name : entity);
2010 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2011 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2012 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2013 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2014 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2015 SILCTXT_PUBKEY_ACCEPT);
2016 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2019 silc_free(fingerprint);
2022 /* The key already exists, verify it. */
2023 SilcPublicKey public_key;
2024 unsigned char *encpk;
2025 SilcUInt32 encpk_len;
2027 /* Load the key file, try for both IP filename and hostname filename */
2028 if (!silc_pkcs_load_public_key(ipf, &public_key,
2029 SILC_PKCS_FILE_PEM) &&
2030 !silc_pkcs_load_public_key(ipf, &public_key,
2031 SILC_PKCS_FILE_BIN) &&
2032 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2033 SILC_PKCS_FILE_PEM) &&
2034 !silc_pkcs_load_public_key(hostf, &public_key,
2035 SILC_PKCS_FILE_BIN)))) {
2036 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2037 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2038 verify->entity_name : entity);
2039 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2040 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2041 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2042 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2043 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2044 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2045 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2046 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2047 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2050 silc_free(fingerprint);
2054 /* Encode the key data */
2055 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2057 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2058 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2059 verify->entity_name : entity);
2060 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2061 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2062 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2063 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2064 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2065 SILCTXT_PUBKEY_MALFORMED, entity);
2066 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2067 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2068 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2071 silc_free(fingerprint);
2075 /* Compare the keys */
2076 if (memcmp(encpk, pk, encpk_len)) {
2077 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2078 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2079 verify->entity_name : entity);
2080 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2081 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2082 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2083 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2084 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2085 SILCTXT_PUBKEY_NO_MATCH, entity);
2086 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2087 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2088 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2089 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2091 /* Ask user to verify the key and save it */
2092 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2093 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2094 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2097 silc_free(fingerprint);
2101 /* Local copy matched */
2103 completion(TRUE, context);
2104 silc_free(fingerprint);
2108 /* Verifies received public key. The `conn_type' indicates which entity
2109 (server, client etc.) has sent the public key. If user decides to trust
2110 the key may be saved as trusted public key for later use. The
2111 `completion' must be called after the public key has been verified. */
2114 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2115 SilcSocketType conn_type, unsigned char *pk,
2116 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2117 SilcVerifyPublicKey completion, void *context)
2119 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2121 completion, context);
2124 /* Asks passphrase from user on the input line. */
2127 SilcAskPassphrase completion;
2131 void ask_passphrase_completion(const char *passphrase, void *context)
2133 AskPassphrase p = (AskPassphrase)context;
2134 if (passphrase && passphrase[0] == '\0')
2136 p->completion((unsigned char *)passphrase,
2137 passphrase ? strlen(passphrase) : 0, p->context);
2141 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2142 SilcAskPassphrase completion, void *context)
2144 AskPassphrase p = silc_calloc(1, sizeof(*p));
2145 p->completion = completion;
2146 p->context = context;
2148 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2149 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2153 SilcGetAuthMeth completion;
2155 } *InternalGetAuthMethod;
2157 /* Callback called when we've received the authentication method information
2158 from the server after we've requested it. This will get the authentication
2159 data from the user if needed. */
2161 static void silc_get_auth_method_callback(SilcClient client,
2162 SilcClientConnection conn,
2163 SilcAuthMethod auth_meth,
2166 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2168 SILC_LOG_DEBUG(("Start"));
2170 switch (auth_meth) {
2171 case SILC_AUTH_NONE:
2172 /* No authentication required. */
2173 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2175 case SILC_AUTH_PASSWORD:
2177 /* Check whether we find the password for this server in our
2178 configuration. If not, then don't provide so library will ask
2179 it from the user. */
2180 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2182 if (!setup || !setup->password) {
2183 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2187 (*internal->completion)(TRUE, auth_meth, setup->password,
2188 strlen(setup->password), internal->context);
2191 case SILC_AUTH_PUBLIC_KEY:
2192 /* Do not get the authentication data now, the library will generate
2193 it using our default key, if we do not provide it here. */
2194 /* XXX In the future when we support multiple local keys and multiple
2195 local certificates we will need to ask from user which one to use. */
2196 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2200 silc_free(internal);
2203 /* Find authentication method and authentication data by hostname and
2204 port. The hostname may be IP address as well. The found authentication
2205 method and authentication data is returned to `auth_meth', `auth_data'
2206 and `auth_data_len'. The function returns TRUE if authentication method
2207 is found and FALSE if not. `conn' may be NULL. */
2209 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2210 char *hostname, SilcUInt16 port,
2211 SilcGetAuthMeth completion, void *context)
2213 InternalGetAuthMethod internal;
2215 SILC_LOG_DEBUG(("Start"));
2217 /* If we do not have this connection configured by the user in a
2218 configuration file then resolve the authentication method from the
2219 server for this session. */
2220 internal = silc_calloc(1, sizeof(*internal));
2221 internal->completion = completion;
2222 internal->context = context;
2224 silc_client_request_authentication_method(client, conn,
2225 silc_get_auth_method_callback,
2229 /* Notifies application that failure packet was received. This is called
2230 if there is some protocol active in the client. The `protocol' is the
2231 protocol context. The `failure' is opaque pointer to the failure
2232 indication. Note, that the `failure' is protocol dependant and application
2233 must explicitly cast it to correct type. Usually `failure' is 32 bit
2234 failure type (see protocol specs for all protocol failure types). */
2236 void silc_failure(SilcClient client, SilcClientConnection conn,
2237 SilcProtocol protocol, void *failure)
2239 SILC_LOG_DEBUG(("Start"));
2241 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2242 SilcSKEStatus status = (SilcSKEStatus)failure;
2244 if (status == SILC_SKE_STATUS_BAD_VERSION)
2245 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2246 SILCTXT_KE_BAD_VERSION);
2247 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2248 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2249 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2250 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2251 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2252 SILCTXT_KE_UNKNOWN_GROUP);
2253 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2254 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2255 SILCTXT_KE_UNKNOWN_CIPHER);
2256 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2257 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2258 SILCTXT_KE_UNKNOWN_PKCS);
2259 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2260 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2261 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2262 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2263 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2264 SILCTXT_KE_UNKNOWN_HMAC);
2265 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2266 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2267 SILCTXT_KE_INCORRECT_SIGNATURE);
2268 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2269 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2270 SILCTXT_KE_INVALID_COOKIE);
2273 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2274 SilcUInt32 err = (SilcUInt32)failure;
2276 if (err == SILC_AUTH_FAILED)
2277 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2278 SILCTXT_AUTH_FAILED);
2282 /* Asks whether the user would like to perform the key agreement protocol.
2283 This is called after we have received an key agreement packet or an
2284 reply to our key agreement packet. This returns TRUE if the user wants
2285 the library to perform the key agreement protocol and FALSE if it is not
2286 desired (application may start it later by calling the function
2287 silc_client_perform_key_agreement). */
2289 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2290 SilcClientEntry client_entry, const char *hostname,
2291 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2296 SILC_LOG_DEBUG(("Start"));
2298 /* We will just display the info on the screen and return FALSE and user
2299 will have to start the key agreement with a command. */
2302 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2305 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2306 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2308 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2309 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2310 client_entry->nickname, hostname, portstr);
2318 /* Notifies application that file transfer protocol session is being
2319 requested by the remote client indicated by the `client_entry' from
2320 the `hostname' and `port'. The `session_id' is the file transfer
2321 session and it can be used to either accept or reject the file
2322 transfer request, by calling the silc_client_file_receive or
2323 silc_client_file_close, respectively. */
2325 void silc_ftp(SilcClient client, SilcClientConnection conn,
2326 SilcClientEntry client_entry, SilcUInt32 session_id,
2327 const char *hostname, SilcUInt16 port)
2329 SILC_SERVER_REC *server;
2331 FtpSession ftp = NULL;
2333 SILC_LOG_DEBUG(("Start"));
2335 server = conn->context;
2337 silc_dlist_start(server->ftp_sessions);
2338 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2339 if (ftp->client_entry == client_entry &&
2340 ftp->session_id == session_id) {
2341 server->current_session = ftp;
2345 if (ftp == SILC_LIST_END) {
2346 ftp = silc_calloc(1, sizeof(*ftp));
2347 ftp->client_entry = client_entry;
2348 ftp->session_id = session_id;
2351 silc_dlist_add(server->ftp_sessions, ftp);
2352 server->current_session = ftp;
2356 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2359 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2360 SILCTXT_FILE_REQUEST, client_entry->nickname);
2362 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2363 SILCTXT_FILE_REQUEST_HOST,
2364 client_entry->nickname, hostname, portstr);
2367 /* Delivers SILC session detachment data indicated by `detach_data' to the
2368 application. If application has issued SILC_COMMAND_DETACH command
2369 the client session in the SILC network is not quit. The client remains
2370 in the network but is detached. The detachment data may be used later
2371 to resume the session in the SILC Network. The appliation is
2372 responsible of saving the `detach_data', to for example in a file.
2374 The detachment data can be given as argument to the functions
2375 silc_client_connect_to_server, or silc_client_add_connection when
2376 creating connection to remote server, inside SilcClientConnectionParams
2377 structure. If it is provided the client library will attempt to resume
2378 the session in the network. After the connection is created
2379 successfully, the application is responsible of setting the user
2380 interface for user into the same state it was before detaching (showing
2381 same channels, channel modes, etc). It can do this by fetching the
2382 information (like joined channels) from the client library. */
2385 silc_detach(SilcClient client, SilcClientConnection conn,
2386 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2390 /* Save the detachment data to file. */
2392 memset(file, 0, sizeof(file));
2393 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2394 silc_file_writefile(file, detach_data, detach_data_len);
2398 /* SILC client operations */
2399 SilcClientOperations ops = {
2401 silc_channel_message,
2402 silc_private_message,
2408 silc_get_auth_method,
2409 silc_verify_public_key,
2410 silc_ask_passphrase,