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"
37 #include "fe-common/core/printtext.h"
38 #include "fe-common/core/fe-channels.h"
39 #include "fe-common/core/keyboard.h"
40 #include "fe-common/core/window-items.h"
41 #include "fe-common/silc/module-formats.h"
46 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
47 const char *name, SilcSocketType conn_type,
48 unsigned char *pk, SilcUInt32 pk_len,
49 SilcSKEPKType pk_type,
50 SilcVerifyPublicKey completion, void *context);
52 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
55 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
56 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
57 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
59 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
60 "[SILC operator]" : "[unknown mode]");
62 if (mode & SILC_UMODE_GONE)
63 strcat(buf, " [away]");
64 if (mode & SILC_UMODE_INDISPOSED)
65 strcat(buf, " [indisposed]");
66 if (mode & SILC_UMODE_BUSY)
67 strcat(buf, " [busy]");
68 if (mode & SILC_UMODE_PAGE)
69 strcat(buf, " [page to reach]");
70 if (mode & SILC_UMODE_HYPER)
71 strcat(buf, " [hyper active]");
72 if (mode & SILC_UMODE_ROBOT)
73 strcat(buf, " [robot]");
74 if (mode & SILC_UMODE_ANONYMOUS)
75 strcat(buf, " [anonymous]");
76 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
77 strcat(buf, " [blocks private messages]");
78 if (mode & SILC_UMODE_DETACHED)
79 strcat(buf, " [detached]");
80 if (mode & SILC_UMODE_REJECT_WATCHING)
81 strcat(buf, " [rejects watching]");
82 if (mode & SILC_UMODE_BLOCK_INVITE)
83 strcat(buf, " [blocks invites]");
86 /* print "nick appears as" message to every channel of a server */
88 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
89 const char *newnick, const char *oldnick,
92 if (ignore_check(SERVER(server), oldnick, address,
93 channel, newnick, MSGLEVEL_NICKS))
96 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
97 SILCTXT_CHANNEL_APPEARS,
98 oldnick, newnick, channel, address);
102 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
103 const char *oldnick, const char *address)
105 GSList *tmp, *windows;
107 /* Print to each channel/query where the nick is.
108 Don't print more than once to the same window. */
111 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
112 CHANNEL_REC *channel = tmp->data;
113 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
115 if (nicklist_find(channel, newnick) == NULL ||
116 g_slist_find(windows, window) != NULL)
119 windows = g_slist_append(windows, window);
120 silc_print_nick_change_channel(server, channel->visible_name,
121 newnick, oldnick, address);
124 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 char tmp2[256], *cp, *dm = NULL;
482 g_free_not_null(chanrec->topic);
483 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
484 memset(tmp2, 0, sizeof(tmp2));
486 if (strlen(tmp) > sizeof(tmp2) - 1) {
487 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
491 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
496 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
497 signal_emit("channel topic changed", 1, chanrec);
502 if (idtype == SILC_ID_CLIENT) {
503 client_entry = (SilcClientEntry)entry;
504 memset(buf, 0, sizeof(buf));
505 snprintf(buf, sizeof(buf) - 1, "%s@%s",
506 client_entry->username, client_entry->hostname);
507 signal_emit("message topic", 5, server, channel->channel_name,
508 tmp, client_entry->nickname, buf);
509 } else if (idtype == SILC_ID_SERVER) {
510 server_entry = (SilcServerEntry)entry;
511 signal_emit("message topic", 5, server, channel->channel_name,
512 tmp, server_entry->server_name,
513 server_entry->server_name);
514 } else if (idtype == SILC_ID_CHANNEL) {
515 channel = (SilcChannelEntry)entry;
516 signal_emit("message topic", 5, server, channel->channel_name,
517 tmp, channel->channel_name, channel->channel_name);
521 case SILC_NOTIFY_TYPE_NICK_CHANGE:
526 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
528 client_entry = va_arg(va, SilcClientEntry);
529 client_entry2 = va_arg(va, SilcClientEntry);
531 if (!strcmp(client_entry->nickname, client_entry2->nickname))
534 memset(buf, 0, sizeof(buf));
535 snprintf(buf, sizeof(buf) - 1, "%s@%s",
536 client_entry2->username, client_entry2->hostname);
537 nicklist_rename_unique(SERVER(server),
538 client_entry, client_entry->nickname,
539 client_entry2, client_entry2->nickname);
540 signal_emit("message nick", 4, server, client_entry2->nickname,
541 client_entry->nickname, buf);
544 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
546 * Changed channel mode.
549 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
551 idtype = va_arg(va, int);
552 entry = va_arg(va, void *);
553 mode = va_arg(va, SilcUInt32);
554 (void)va_arg(va, char *);
555 (void)va_arg(va, char *);
556 channel = va_arg(va, SilcChannelEntry);
558 tmp = silc_client_chmode(mode,
559 channel->channel_key ?
560 silc_cipher_get_name(channel->channel_key) : "",
562 silc_hmac_get_name(channel->hmac) : "");
564 chanrec = silc_channel_find_entry(server, channel);
565 if (chanrec != NULL) {
566 g_free_not_null(chanrec->mode);
567 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
568 signal_emit("channel mode changed", 1, chanrec);
571 if (idtype == SILC_ID_CLIENT) {
572 client_entry = (SilcClientEntry)entry;
573 printformat_module("fe-common/silc", server, channel->channel_name,
574 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
575 channel->channel_name, tmp ? tmp : "removed all",
576 client_entry->nickname);
577 } else if (idtype == SILC_ID_SERVER) {
578 server_entry = (SilcServerEntry)entry;
579 printformat_module("fe-common/silc", server, channel->channel_name,
580 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
581 channel->channel_name, tmp ? tmp : "removed all",
582 server_entry->server_name);
583 } else if (idtype == SILC_ID_CHANNEL) {
584 channel2 = (SilcChannelEntry)entry;
585 printformat_module("fe-common/silc", server, channel->channel_name,
586 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
587 channel->channel_name, tmp ? tmp : "removed all",
588 channel2->channel_name);
594 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
596 * Changed user's mode on channel.
599 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
601 idtype = va_arg(va, int);
602 entry = va_arg(va, void *);
603 mode = va_arg(va, SilcUInt32);
604 client_entry2 = va_arg(va, SilcClientEntry);
605 channel = va_arg(va, SilcChannelEntry);
607 tmp = silc_client_chumode(mode);
608 chanrec = silc_channel_find_entry(server, channel);
609 if (chanrec != NULL) {
612 if (client_entry2 == server->conn->local_entry)
613 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
615 nick = silc_nicklist_find(chanrec, client_entry2);
617 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
618 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
619 signal_emit("nick mode changed", 2, chanrec, nick);
623 if (idtype == SILC_ID_CLIENT) {
624 client_entry = (SilcClientEntry)entry;
625 printformat_module("fe-common/silc", server, channel->channel_name,
626 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
627 channel->channel_name, client_entry2->nickname,
628 tmp ? tmp : "removed all",
629 client_entry->nickname);
630 } else if (idtype == SILC_ID_SERVER) {
631 server_entry = (SilcServerEntry)entry;
632 printformat_module("fe-common/silc", server, channel->channel_name,
633 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
634 channel->channel_name, client_entry2->nickname,
635 tmp ? tmp : "removed all",
636 server_entry->server_name);
637 } else if (idtype == SILC_ID_CHANNEL) {
638 channel2 = (SilcChannelEntry)entry;
639 printformat_module("fe-common/silc", server, channel->channel_name,
640 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
641 channel->channel_name, client_entry2->nickname,
642 tmp ? tmp : "removed all",
643 channel2->channel_name);
646 if (mode & SILC_CHANNEL_UMODE_CHANFO)
647 printformat_module("fe-common/silc",
648 server, channel->channel_name, MSGLEVEL_CRAP,
649 SILCTXT_CHANNEL_FOUNDER,
650 channel->channel_name, client_entry2->nickname);
652 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
653 printformat_module("fe-common/silc",
654 server, channel->channel_name, MSGLEVEL_CRAP,
655 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
660 case SILC_NOTIFY_TYPE_MOTD:
665 SILC_LOG_DEBUG(("Notify: MOTD"));
667 tmp = va_arg(va, char *);
669 if (!settings_get_bool("skip_motd"))
670 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
673 case SILC_NOTIFY_TYPE_KICKED:
675 * Someone was kicked from channel.
678 SILC_LOG_DEBUG(("Notify: KICKED"));
680 client_entry = va_arg(va, SilcClientEntry);
681 tmp = va_arg(va, char *);
682 client_entry2 = va_arg(va, SilcClientEntry);
683 channel = va_arg(va, SilcChannelEntry);
685 chanrec = silc_channel_find_entry(server, channel);
687 if (client_entry == conn->local_entry) {
688 printformat_module("fe-common/silc", server, channel->channel_name,
689 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
690 channel->channel_name,
691 client_entry ? client_entry2->nickname : "",
694 chanrec->kicked = TRUE;
695 channel_destroy((CHANNEL_REC *)chanrec);
698 printformat_module("fe-common/silc", server, channel->channel_name,
699 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
700 client_entry->nickname, channel->channel_name,
701 client_entry2 ? client_entry2->nickname : "",
705 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
707 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
712 case SILC_NOTIFY_TYPE_KILLED:
714 * Someone was killed from the network.
717 SILC_LOG_DEBUG(("Notify: KILLED"));
719 client_entry = va_arg(va, SilcClientEntry);
720 tmp = va_arg(va, char *);
721 idtype = va_arg(va, int);
722 entry = va_arg(va, SilcClientEntry);
724 if (client_entry == conn->local_entry) {
725 if (idtype == SILC_ID_CLIENT) {
726 client_entry2 = (SilcClientEntry)entry;
727 printformat_module("fe-common/silc", server, NULL,
728 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
729 client_entry2 ? client_entry2->nickname : "",
731 } else if (idtype == SILC_ID_SERVER) {
732 server_entry = (SilcServerEntry)entry;
733 printformat_module("fe-common/silc", server, NULL,
734 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
735 server_entry->server_name, tmp ? tmp : "");
736 } else if (idtype == SILC_ID_CHANNEL) {
737 channel = (SilcChannelEntry)entry;
738 printformat_module("fe-common/silc", server, NULL,
739 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
740 channel->channel_name, tmp ? tmp : "");
743 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
744 for (list_tmp = list1; list_tmp != NULL; list_tmp =
745 list_tmp->next->next) {
746 CHANNEL_REC *channel = list_tmp->data;
747 NICK_REC *nickrec = list_tmp->next->data;
748 nicklist_remove(channel, nickrec);
751 if (idtype == SILC_ID_CLIENT) {
752 client_entry2 = (SilcClientEntry)entry;
753 printformat_module("fe-common/silc", server, NULL,
754 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
755 client_entry->nickname,
756 client_entry2 ? client_entry2->nickname : "",
758 } else if (idtype == SILC_ID_SERVER) {
759 server_entry = (SilcServerEntry)entry;
760 printformat_module("fe-common/silc", server, NULL,
761 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
762 client_entry->nickname,
763 server_entry->server_name, tmp ? tmp : "");
764 } else if (idtype == SILC_ID_CHANNEL) {
765 channel = (SilcChannelEntry)entry;
766 printformat_module("fe-common/silc", server, NULL,
767 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
768 client_entry->nickname,
769 channel->channel_name, tmp ? tmp : "");
774 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
777 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
780 * Server has quit the network.
783 SilcClientEntry *clients;
784 SilcUInt32 clients_count;
786 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
788 (void)va_arg(va, void *);
789 clients = va_arg(va, SilcClientEntry *);
790 clients_count = va_arg(va, SilcUInt32);
792 for (i = 0; i < clients_count; i++) {
793 memset(buf, 0, sizeof(buf));
794 if (clients[i]->username)
795 snprintf(buf, sizeof(buf) - 1, "%s@%s",
796 clients[i]->username, clients[i]->hostname);
797 signal_emit("message quit", 4, server, clients[i]->nickname,
798 clients[i]->username ? buf : "",
801 silc_server_free_ftp(server, clients[i]);
803 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
804 for (list_tmp = list1; list_tmp != NULL; list_tmp =
805 list_tmp->next->next) {
806 CHANNEL_REC *channel = list_tmp->data;
807 NICK_REC *nickrec = list_tmp->next->data;
808 nicklist_remove(channel, nickrec);
814 case SILC_NOTIFY_TYPE_ERROR:
816 SilcStatus error = va_arg(va, int);
818 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
819 "%s", silc_get_status_message(error));
823 case SILC_NOTIFY_TYPE_WATCH:
825 SilcNotifyType notify;
827 client_entry = va_arg(va, SilcClientEntry);
828 name = va_arg(va, char *); /* Maybe NULL */
829 mode = va_arg(va, SilcUInt32);
830 notify = va_arg(va, int);
832 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
834 printformat_module("fe-common/silc", server, NULL,
835 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
836 client_entry->nickname, name);
838 printformat_module("fe-common/silc", server, NULL,
839 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
840 client_entry->nickname);
841 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
842 /* See if client was away and is now present */
843 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
844 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
845 SILC_UMODE_DETACHED)) &&
846 (client_entry->mode & SILC_UMODE_GONE ||
847 client_entry->mode & SILC_UMODE_INDISPOSED ||
848 client_entry->mode & SILC_UMODE_BUSY ||
849 client_entry->mode & SILC_UMODE_PAGE ||
850 client_entry->mode & SILC_UMODE_DETACHED)) {
851 printformat_module("fe-common/silc", server, NULL,
852 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
853 client_entry->nickname);
857 memset(buf, 0, sizeof(buf));
858 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
859 printformat_module("fe-common/silc", server, NULL,
860 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
861 client_entry->nickname, buf);
863 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
864 printformat_module("fe-common/silc", server, NULL,
865 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
866 client_entry->nickname);
867 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
868 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
869 printformat_module("fe-common/silc", server, NULL,
870 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
871 client_entry->nickname);
872 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
873 /* Client logged in to the network */
874 printformat_module("fe-common/silc", server, NULL,
875 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
876 client_entry->nickname);
883 printformat_module("fe-common/silc", server, NULL,
884 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
891 /* Called to indicate that connection was either successfully established
892 or connecting failed. This is also the first time application receives
893 the SilcClientConnection object which it should save somewhere. */
895 void silc_connect(SilcClient client, SilcClientConnection conn,
896 SilcClientConnectionStatus status)
898 SILC_SERVER_REC *server = conn->context;
900 if (!server || server->disconnected) {
901 silc_client_close_connection(client, conn);
906 case SILC_CLIENT_CONN_SUCCESS:
907 /* We have successfully connected to server */
908 server->connected = TRUE;
909 signal_emit("event connected", 1, server);
912 case SILC_CLIENT_CONN_SUCCESS_RESUME:
913 /* We have successfully resumed old detached session */
914 server->connected = TRUE;
915 signal_emit("event connected", 1, server);
917 /* If we resumed old session check whether we need to update
919 if (strcmp(server->nick, conn->local_entry->nickname)) {
921 old = g_strdup(server->nick);
922 server_change_nick(SERVER(server), conn->local_entry->nickname);
923 nicklist_rename_unique(SERVER(server),
924 conn->local_entry, server->nick,
925 conn->local_entry, conn->local_entry->nickname);
926 signal_emit("message own_nick", 4, server, server->nick, old, "");
932 server->connection_lost = TRUE;
934 server->conn->context = NULL;
935 server_disconnect(SERVER(server));
940 /* Called to indicate that connection was disconnected to the server. */
942 void silc_disconnect(SilcClient client, SilcClientConnection conn,
943 SilcStatus status, const char *message)
945 SILC_SERVER_REC *server = conn->context;
947 SILC_LOG_DEBUG(("Start"));
949 if (!server || server->connection_lost)
952 if (server->conn && server->conn->local_entry) {
953 nicklist_rename_unique(SERVER(server),
954 server->conn->local_entry, server->nick,
955 server->conn->local_entry,
956 silc_client->username);
957 silc_change_nick(server, silc_client->username);
961 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
962 "Server closed connection: %s (%d) %s",
963 silc_get_status_message(status), status,
964 message ? message : "");
966 server->conn->context = NULL;
968 server->connection_lost = TRUE;
969 server_disconnect(SERVER(server));
972 /* Command handler. This function is called always in the command function.
973 If error occurs it will be called as well. `conn' is the associated
974 client connection. `cmd_context' is the command context that was
975 originally sent to the command. `success' is FALSE if error occured
976 during command. `command' is the command being processed. It must be
977 noted that this is not reply from server. This is merely called just
978 after application has called the command. Just to tell application
979 that the command really was processed. */
981 void silc_command(SilcClient client, SilcClientConnection conn,
982 SilcClientCommandContext cmd_context, bool success,
983 SilcCommand command, SilcStatus status)
985 SILC_SERVER_REC *server = conn->context;
987 SILC_LOG_DEBUG(("Start"));
990 silc_say_error("%s", silc_get_status_message(status));
996 case SILC_COMMAND_INVITE:
997 if (cmd_context->argc > 2)
998 printformat_module("fe-common/silc", server, NULL,
999 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1000 cmd_context->argv[2],
1001 (cmd_context->argv[1][0] == '*' ?
1002 (char *)conn->current_channel->channel_name :
1003 (char *)cmd_context->argv[1]));
1006 case SILC_COMMAND_DETACH:
1007 server->no_reconnect = TRUE;
1015 /* Client info resolving callback when JOIN command reply is received.
1016 This will cache all users on the channel. */
1018 static void silc_client_join_get_users(SilcClient client,
1019 SilcClientConnection conn,
1020 SilcClientEntry *clients,
1021 SilcUInt32 clients_count,
1024 SilcChannelEntry channel = (SilcChannelEntry)context;
1025 SilcHashTableList htl;
1026 SilcChannelUser chu;
1027 SILC_SERVER_REC *server = conn->context;
1028 SILC_CHANNEL_REC *chanrec;
1029 SilcClientEntry founder = NULL;
1032 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1033 silc_hash_table_count(channel->user_list)));
1038 chanrec = silc_channel_find(server, channel->channel_name);
1039 if (chanrec == NULL)
1042 silc_hash_table_list(channel->user_list, &htl);
1043 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1044 if (!chu->client->nickname)
1046 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1047 founder = chu->client;
1048 silc_nicklist_insert(chanrec, chu, FALSE);
1050 silc_hash_table_list_reset(&htl);
1052 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1053 nicklist_set_own(CHANNEL(chanrec), ownnick);
1054 signal_emit("channel joined", 1, chanrec);
1055 chanrec->entry = channel;
1058 printformat_module("fe-common/silc", server, channel->channel_name,
1059 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1060 channel->channel_name, chanrec->topic);
1063 if (founder == conn->local_entry)
1064 printformat_module("fe-common/silc",
1065 server, channel->channel_name, MSGLEVEL_CRAP,
1066 SILCTXT_CHANNEL_FOUNDER_YOU,
1067 channel->channel_name);
1069 printformat_module("fe-common/silc",
1070 server, channel->channel_name, MSGLEVEL_CRAP,
1071 SILCTXT_CHANNEL_FOUNDER,
1072 channel->channel_name, founder->nickname);
1078 SilcClientConnection conn;
1084 void silc_getkey_cb(bool success, void *context)
1086 GetkeyContext getkey = (GetkeyContext)context;
1087 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1088 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1089 ((SilcClientEntry)getkey->entry)->nickname :
1090 ((SilcServerEntry)getkey->entry)->server_name);
1093 printformat_module("fe-common/silc", NULL, NULL,
1094 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1096 printformat_module("fe-common/silc", NULL, NULL,
1097 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1101 silc_free(getkey->fingerprint);
1105 /* Command reply handler. This function is called always in the command reply
1106 function. If error occurs it will be called as well. Normal scenario
1107 is that it will be called after the received command data has been parsed
1108 and processed. The function is used to pass the received command data to
1111 `conn' is the associated client connection. `cmd_payload' is the command
1112 payload data received from server and it can be ignored. It is provided
1113 if the application would like to re-parse the received command data,
1114 however, it must be noted that the data is parsed already by the library
1115 thus the payload can be ignored. `success' is FALSE if error occured.
1116 In this case arguments are not sent to the application. `command' is the
1117 command reply being processed. The function has variable argument list
1118 and each command defines the number and type of arguments it passes to the
1119 application (on error they are not sent). */
1122 silc_command_reply(SilcClient client, SilcClientConnection conn,
1123 SilcCommandPayload cmd_payload, bool success,
1124 SilcCommand command, SilcStatus status, ...)
1127 SILC_SERVER_REC *server = conn->context;
1128 SILC_CHANNEL_REC *chanrec;
1131 va_start(vp, status);
1133 SILC_LOG_DEBUG(("Start"));
1136 case SILC_COMMAND_WHOIS:
1138 char buf[1024], *nickname, *username, *realname, *nick;
1139 unsigned char *fingerprint;
1140 SilcUInt32 idle, mode;
1141 SilcBuffer channels, user_modes;
1142 SilcClientEntry client_entry;
1145 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1146 /* Print the unknown nick for user */
1147 unsigned char *tmp =
1148 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1151 silc_say_error("%s: %s", tmp,
1152 silc_get_status_message(status));
1154 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1155 /* Try to find the entry for the unknown client ID, since we
1156 might have, and print the nickname of it for user. */
1158 unsigned char *tmp =
1159 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1162 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1165 client_entry = silc_client_get_client_by_id(client, conn,
1167 if (client_entry && client_entry->nickname)
1168 silc_say_error("%s: %s", client_entry->nickname,
1169 silc_get_status_message(status));
1170 silc_free(client_id);
1174 } else if (!success) {
1175 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1179 client_entry = va_arg(vp, SilcClientEntry);
1180 nickname = va_arg(vp, char *);
1181 username = va_arg(vp, char *);
1182 realname = va_arg(vp, char *);
1183 channels = va_arg(vp, SilcBuffer);
1184 mode = va_arg(vp, SilcUInt32);
1185 idle = va_arg(vp, SilcUInt32);
1186 fingerprint = va_arg(vp, unsigned char *);
1187 user_modes = va_arg(vp, SilcBuffer);
1188 attrs = va_arg(vp, SilcDList);
1190 silc_parse_userfqdn(nickname, &nick, NULL);
1191 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1192 SILCTXT_WHOIS_USERINFO, nickname,
1193 client_entry->username, client_entry->hostname,
1194 nick, client_entry->nickname);
1195 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1196 SILCTXT_WHOIS_REALNAME, realname);
1199 if (channels && user_modes) {
1201 SilcDList list = silc_channel_payload_parse_list(channels->data,
1203 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1205 SilcChannelPayload entry;
1208 memset(buf, 0, sizeof(buf));
1209 silc_dlist_start(list);
1210 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1211 SilcUInt32 name_len;
1212 char *m = silc_client_chumode_char(umodes[i++]);
1213 char *name = silc_channel_get_name(entry, &name_len);
1216 strncat(buf, m, strlen(m));
1217 strncat(buf, name, name_len);
1218 strncat(buf, " ", 1);
1222 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1223 SILCTXT_WHOIS_CHANNELS, buf);
1224 silc_channel_payload_list_free(list);
1230 memset(buf, 0, sizeof(buf));
1231 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1232 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1233 SILCTXT_WHOIS_MODES, buf);
1236 if (idle && nickname) {
1237 memset(buf, 0, sizeof(buf));
1238 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1239 idle > 60 ? (idle / 60) : idle,
1240 idle > 60 ? "minutes" : "seconds");
1242 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1243 SILCTXT_WHOIS_IDLE, buf);
1247 fingerprint = silc_fingerprint(fingerprint, 20);
1248 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1249 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1250 silc_free(fingerprint);
1254 silc_query_attributes_print(server, silc_client, conn, attrs,
1259 case SILC_COMMAND_IDENTIFY:
1261 SilcClientEntry client_entry;
1263 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1264 /* Print the unknown nick for user */
1265 unsigned char *tmp =
1266 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1269 silc_say_error("%s: %s", tmp,
1270 silc_get_status_message(status));
1272 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1273 /* Try to find the entry for the unknown client ID, since we
1274 might have, and print the nickname of it for user. */
1276 unsigned char *tmp =
1277 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1280 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1283 client_entry = silc_client_get_client_by_id(client, conn,
1285 if (client_entry && client_entry->nickname)
1286 silc_say_error("%s: %s", client_entry->nickname,
1287 silc_get_status_message(status));
1288 silc_free(client_id);
1297 case SILC_COMMAND_WHOWAS:
1299 char *nickname, *username, *realname;
1301 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1302 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1304 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1307 silc_say_error("%s: %s", tmp,
1308 silc_get_status_message(status));
1310 } else if (!success) {
1311 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1315 (void)va_arg(vp, SilcClientEntry);
1316 nickname = va_arg(vp, char *);
1317 username = va_arg(vp, char *);
1318 realname = va_arg(vp, char *);
1320 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1321 SILCTXT_WHOWAS_USERINFO, nickname, username,
1322 realname ? realname : "");
1326 case SILC_COMMAND_INVITE:
1328 SilcChannelEntry channel;
1330 SilcArgumentPayload args;
1336 channel = va_arg(vp, SilcChannelEntry);
1337 invite_list = va_arg(vp, char *);
1339 args = silc_command_get_args(cmd_payload);
1341 argc = silc_argument_get_arg_num(args);
1344 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1345 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1348 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1349 SILCTXT_CHANNEL_NO_INVITE_LIST,
1350 channel->channel_name);
1354 case SILC_COMMAND_JOIN:
1356 char *channel, *mode, *topic;
1358 SilcChannelEntry channel_entry;
1359 SilcBuffer client_id_list;
1360 SilcUInt32 list_count;
1365 channel = va_arg(vp, char *);
1366 channel_entry = va_arg(vp, SilcChannelEntry);
1367 modei = va_arg(vp, SilcUInt32);
1368 (void)va_arg(vp, SilcUInt32);
1369 (void)va_arg(vp, unsigned char *);
1370 (void)va_arg(vp, unsigned char *);
1371 (void)va_arg(vp, unsigned char *);
1372 topic = va_arg(vp, char *);
1373 (void)va_arg(vp, unsigned char *);
1374 list_count = va_arg(vp, SilcUInt32);
1375 client_id_list = va_arg(vp, SilcBuffer);
1377 chanrec = silc_channel_find(server, channel);
1379 chanrec = silc_channel_create(server, channel, channel, TRUE);
1382 char tmp[256], *cp, *dm = NULL;
1383 g_free_not_null(chanrec->topic);
1385 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1386 memset(tmp, 0, sizeof(tmp));
1388 if (strlen(topic) > sizeof(tmp) - 1) {
1389 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1393 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1398 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1399 signal_emit("channel topic changed", 1, chanrec);
1404 mode = silc_client_chmode(modei,
1405 channel_entry->channel_key ?
1406 silc_cipher_get_name(channel_entry->
1408 channel_entry->hmac ?
1409 silc_hmac_get_name(channel_entry->hmac) : "");
1410 g_free_not_null(chanrec->mode);
1411 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1412 signal_emit("channel mode changed", 1, chanrec);
1414 /* Resolve the client information */
1415 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1416 silc_client_join_get_users,
1422 case SILC_COMMAND_NICK:
1425 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1431 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1432 if (nicks != NULL) {
1434 SilcClientEntry collider, old;
1436 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1437 collider = silc_client_get_client_by_id(client, conn,
1440 memset(buf, 0, sizeof(buf));
1441 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1442 collider->username, collider->hostname);
1443 nicklist_rename_unique(SERVER(server),
1445 collider, collider->nickname);
1446 silc_print_nick_change(server, collider->nickname,
1447 client_entry->nickname, buf);
1448 g_slist_free(nicks);
1451 old = g_strdup(server->nick);
1452 server_change_nick(SERVER(server), client_entry->nickname);
1453 nicklist_rename_unique(SERVER(server),
1454 server->conn->local_entry, server->nick,
1455 client_entry, client_entry->nickname);
1456 signal_emit("message own_nick", 4, server, server->nick, old, "");
1461 case SILC_COMMAND_LIST:
1466 char tmp[256], *cp, *dm = NULL;
1471 (void)va_arg(vp, SilcChannelEntry);
1472 name = va_arg(vp, char *);
1473 topic = va_arg(vp, char *);
1474 usercount = va_arg(vp, int);
1476 if (topic && !silc_term_utf8() &&
1477 silc_utf8_valid(topic, strlen(topic))) {
1478 memset(tmp, 0, sizeof(tmp));
1480 if (strlen(topic) > sizeof(tmp) - 1) {
1481 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1485 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1490 if (status == SILC_STATUS_LIST_START ||
1491 status == SILC_STATUS_OK)
1492 printformat_module("fe-common/silc", server, NULL,
1493 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1496 snprintf(users, sizeof(users) - 1, "N/A");
1498 snprintf(users, sizeof(users) - 1, "%d", usercount);
1499 printformat_module("fe-common/silc", server, NULL,
1500 MSGLEVEL_CRAP, SILCTXT_LIST,
1501 name, users, topic ? topic : "");
1506 case SILC_COMMAND_UMODE:
1514 mode = va_arg(vp, SilcUInt32);
1516 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1517 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1518 printformat_module("fe-common/silc", server, NULL,
1519 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1521 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1522 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1523 printformat_module("fe-common/silc", server, NULL,
1524 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1526 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1527 if (mode & SILC_UMODE_GONE) {
1528 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1529 reason = g_strdup(server->away_reason);
1531 reason = g_strdup("away");
1533 reason = g_strdup("");
1535 silc_set_away(reason, server);
1540 server->umode = mode;
1541 signal_emit("user mode changed", 2, server, NULL);
1545 case SILC_COMMAND_OPER:
1549 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1550 signal_emit("user mode changed", 2, server, NULL);
1552 printformat_module("fe-common/silc", server, NULL,
1553 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1556 case SILC_COMMAND_SILCOPER:
1560 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1561 signal_emit("user mode changed", 2, server, NULL);
1563 printformat_module("fe-common/silc", server, NULL,
1564 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1567 case SILC_COMMAND_USERS:
1569 SilcHashTableList htl;
1570 SilcChannelEntry channel;
1571 SilcChannelUser chu;
1576 channel = va_arg(vp, SilcChannelEntry);
1578 printformat_module("fe-common/silc", server, channel->channel_name,
1579 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1580 channel->channel_name);
1582 silc_hash_table_list(channel->user_list, &htl);
1583 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1584 SilcClientEntry e = chu->client;
1585 char stat[5], *mode;
1590 memset(stat, 0, sizeof(stat));
1591 mode = silc_client_chumode_char(chu->mode);
1592 if (e->mode & SILC_UMODE_GONE)
1594 else if (e->mode & SILC_UMODE_INDISPOSED)
1596 else if (e->mode & SILC_UMODE_BUSY)
1598 else if (e->mode & SILC_UMODE_PAGE)
1600 else if (e->mode & SILC_UMODE_HYPER)
1602 else if (e->mode & SILC_UMODE_ROBOT)
1604 else if (e->mode & SILC_UMODE_ANONYMOUS)
1611 printformat_module("fe-common/silc", server, channel->channel_name,
1612 MSGLEVEL_CRAP, SILCTXT_USERS,
1614 e->username ? e->username : "",
1615 e->hostname ? e->hostname : "",
1616 e->realname ? e->realname : "");
1620 silc_hash_table_list_reset(&htl);
1624 case SILC_COMMAND_BAN:
1626 SilcChannelEntry channel;
1632 channel = va_arg(vp, SilcChannelEntry);
1633 ban_list = va_arg(vp, char *);
1636 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1637 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1640 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1641 SILCTXT_CHANNEL_NO_BAN_LIST,
1642 channel->channel_name);
1646 case SILC_COMMAND_GETKEY:
1650 SilcPublicKey public_key;
1653 GetkeyContext getkey;
1659 id_type = va_arg(vp, SilcUInt32);
1660 entry = va_arg(vp, void *);
1661 public_key = va_arg(vp, SilcPublicKey);
1664 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1666 getkey = silc_calloc(1, sizeof(*getkey));
1667 getkey->entry = entry;
1668 getkey->id_type = id_type;
1669 getkey->client = client;
1670 getkey->conn = conn;
1671 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1673 name = (id_type == SILC_ID_CLIENT ?
1674 ((SilcClientEntry)entry)->nickname :
1675 ((SilcServerEntry)entry)->server_name);
1677 silc_verify_public_key_internal(client, conn, name,
1678 (id_type == SILC_ID_CLIENT ?
1679 SILC_SOCKET_TYPE_CLIENT :
1680 SILC_SOCKET_TYPE_SERVER),
1681 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1682 silc_getkey_cb, getkey);
1685 printformat_module("fe-common/silc", server, NULL,
1686 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1691 case SILC_COMMAND_INFO:
1693 SilcServerEntry server_entry;
1700 server_entry = va_arg(vp, SilcServerEntry);
1701 server_name = va_arg(vp, char *);
1702 server_info = va_arg(vp, char *);
1704 if (server_name && server_info )
1706 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1707 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1712 case SILC_COMMAND_TOPIC:
1714 SilcChannelEntry channel;
1716 char tmp[256], *cp, *dm = NULL;
1721 channel = va_arg(vp, SilcChannelEntry);
1722 topic = va_arg(vp, char *);
1724 if (topic && !silc_term_utf8() &&
1725 silc_utf8_valid(topic, strlen(topic))) {
1726 memset(tmp, 0, sizeof(tmp));
1728 if (strlen(topic) > sizeof(tmp) - 1) {
1729 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1733 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1739 chanrec = silc_channel_find_entry(server, channel);
1741 g_free_not_null(chanrec->topic);
1742 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1743 signal_emit("channel topic changed", 1, chanrec);
1745 printformat_module("fe-common/silc", server, channel->channel_name,
1746 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1747 channel->channel_name, topic);
1749 printformat_module("fe-common/silc", server, channel->channel_name,
1750 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1751 channel->channel_name);
1757 case SILC_COMMAND_WATCH:
1760 case SILC_COMMAND_STATS:
1762 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1763 my_router_ops, cell_clients, cell_channels, cell_servers,
1764 clients, channels, servers, routers, server_ops, router_ops;
1766 SilcBufferStruct buf;
1767 unsigned char *tmp_buf;
1769 const char *tmptime;
1770 int days, hours, mins, secs;
1775 tmp_buf = va_arg(vp, unsigned char *);
1776 buf_len = va_arg(vp, SilcUInt32);
1778 if (!tmp_buf || !buf_len) {
1779 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
1783 /* Get statistics structure */
1784 silc_buffer_set(&buf, tmp_buf, buf_len);
1785 silc_buffer_unformat(&buf,
1786 SILC_STR_UI_INT(&starttime),
1787 SILC_STR_UI_INT(&uptime),
1788 SILC_STR_UI_INT(&my_clients),
1789 SILC_STR_UI_INT(&my_channels),
1790 SILC_STR_UI_INT(&my_server_ops),
1791 SILC_STR_UI_INT(&my_router_ops),
1792 SILC_STR_UI_INT(&cell_clients),
1793 SILC_STR_UI_INT(&cell_channels),
1794 SILC_STR_UI_INT(&cell_servers),
1795 SILC_STR_UI_INT(&clients),
1796 SILC_STR_UI_INT(&channels),
1797 SILC_STR_UI_INT(&servers),
1798 SILC_STR_UI_INT(&routers),
1799 SILC_STR_UI_INT(&server_ops),
1800 SILC_STR_UI_INT(&router_ops),
1803 tmptime = silc_get_time(starttime);
1804 printformat_module("fe-common/silc", server, NULL,
1805 MSGLEVEL_CRAP, SILCTXT_STATS,
1806 "Local server start time", tmptime);
1808 days = uptime / (24 * 60 * 60);
1809 uptime -= days * (24 * 60 * 60);
1810 hours = uptime / (60 * 60);
1811 uptime -= hours * (60 * 60);
1813 uptime -= mins * 60;
1815 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
1816 days, hours, mins, secs);
1817 printformat_module("fe-common/silc", server, NULL,
1818 MSGLEVEL_CRAP, SILCTXT_STATS,
1819 "Local server uptime", tmp);
1821 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
1822 printformat_module("fe-common/silc", server, NULL,
1823 MSGLEVEL_CRAP, SILCTXT_STATS,
1824 "Local server clients", tmp);
1826 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
1827 printformat_module("fe-common/silc", server, NULL,
1828 MSGLEVEL_CRAP, SILCTXT_STATS,
1829 "Local server channels", tmp);
1831 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
1832 printformat_module("fe-common/silc", server, NULL,
1833 MSGLEVEL_CRAP, SILCTXT_STATS,
1834 "Local server operators", tmp);
1836 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
1837 printformat_module("fe-common/silc", server, NULL,
1838 MSGLEVEL_CRAP, SILCTXT_STATS,
1839 "Local router operators", tmp);
1841 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
1842 printformat_module("fe-common/silc", server, NULL,
1843 MSGLEVEL_CRAP, SILCTXT_STATS,
1844 "Local cell clients", tmp);
1846 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
1847 printformat_module("fe-common/silc", server, NULL,
1848 MSGLEVEL_CRAP, SILCTXT_STATS,
1849 "Local cell channels", tmp);
1851 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
1852 printformat_module("fe-common/silc", server, NULL,
1853 MSGLEVEL_CRAP, SILCTXT_STATS,
1854 "Local cell servers", tmp);
1856 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
1857 printformat_module("fe-common/silc", server, NULL,
1858 MSGLEVEL_CRAP, SILCTXT_STATS,
1859 "Total clients", tmp);
1861 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
1862 printformat_module("fe-common/silc", server, NULL,
1863 MSGLEVEL_CRAP, SILCTXT_STATS,
1864 "Total channels", tmp);
1866 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
1867 printformat_module("fe-common/silc", server, NULL,
1868 MSGLEVEL_CRAP, SILCTXT_STATS,
1869 "Total servers", tmp);
1871 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
1872 printformat_module("fe-common/silc", server, NULL,
1873 MSGLEVEL_CRAP, SILCTXT_STATS,
1874 "Total routers", tmp);
1876 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
1877 printformat_module("fe-common/silc", server, NULL,
1878 MSGLEVEL_CRAP, SILCTXT_STATS,
1879 "Total server operators", tmp);
1881 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
1882 printformat_module("fe-common/silc", server, NULL,
1883 MSGLEVEL_CRAP, SILCTXT_STATS,
1884 "Total router operators", tmp);
1895 SilcClientConnection conn;
1901 SilcSKEPKType pk_type;
1902 SilcVerifyPublicKey completion;
1906 static void verify_public_key_completion(const char *line, void *context)
1908 PublicKeyVerify verify = (PublicKeyVerify)context;
1910 if (line[0] == 'Y' || line[0] == 'y') {
1911 /* Call the completion */
1912 if (verify->completion)
1913 verify->completion(TRUE, verify->context);
1915 /* Save the key for future checking */
1916 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1917 verify->pk_len, SILC_PKCS_FILE_PEM);
1919 /* Call the completion */
1920 if (verify->completion)
1921 verify->completion(FALSE, verify->context);
1923 printformat_module("fe-common/silc", NULL, NULL,
1924 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1925 verify->entity_name ? verify->entity_name :
1929 silc_free(verify->filename);
1930 silc_free(verify->entity);
1931 silc_free(verify->entity_name);
1932 silc_free(verify->pk);
1936 /* Internal routine to verify public key. If the `completion' is provided
1937 it will be called to indicate whether public was verified or not. For
1938 server/router public key this will check for filename that includes the
1939 remote host's IP address and remote host's hostname. */
1942 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1943 const char *name, SilcSocketType conn_type,
1944 unsigned char *pk, SilcUInt32 pk_len,
1945 SilcSKEPKType pk_type,
1946 SilcVerifyPublicKey completion, void *context)
1949 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1950 char *fingerprint, *babbleprint, *format;
1953 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1954 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1955 "server" : "client");
1956 PublicKeyVerify verify;
1958 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1959 printformat_module("fe-common/silc", NULL, NULL,
1960 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1963 completion(FALSE, context);
1967 pw = getpwuid(getuid());
1970 completion(FALSE, context);
1974 memset(filename, 0, sizeof(filename));
1975 memset(filename2, 0, sizeof(filename2));
1976 memset(file, 0, sizeof(file));
1978 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1979 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1981 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1982 conn->sock->ip, conn->sock->port);
1983 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1984 get_irssi_dir(), entity, file);
1986 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1987 conn->sock->hostname, conn->sock->port);
1988 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1989 get_irssi_dir(), entity, file);
1994 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1995 name, conn->sock->port);
1996 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1997 get_irssi_dir(), entity, file);
2002 /* Replace all whitespaces with `_'. */
2003 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2004 for (i = 0; i < strlen(fingerprint); i++)
2005 if (fingerprint[i] == ' ')
2006 fingerprint[i] = '_';
2008 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2009 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2010 get_irssi_dir(), entity, file);
2011 silc_free(fingerprint);
2016 /* Take fingerprint of the public key */
2017 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2018 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2020 verify = silc_calloc(1, sizeof(*verify));
2021 verify->client = client;
2022 verify->conn = conn;
2023 verify->filename = strdup(ipf);
2024 verify->entity = strdup(entity);
2025 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2026 (name ? strdup(name) : strdup(conn->sock->hostname))
2028 verify->pk = silc_memdup(pk, pk_len);
2029 verify->pk_len = pk_len;
2030 verify->pk_type = pk_type;
2031 verify->completion = completion;
2032 verify->context = context;
2034 /* Check whether this key already exists */
2035 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2036 /* Key does not exist, ask user to verify the key and save it */
2038 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2039 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2040 verify->entity_name : entity);
2041 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2042 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2043 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2044 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2045 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2046 SILCTXT_PUBKEY_ACCEPT);
2047 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2050 silc_free(fingerprint);
2053 /* The key already exists, verify it. */
2054 SilcPublicKey public_key;
2055 unsigned char *encpk;
2056 SilcUInt32 encpk_len;
2058 /* Load the key file, try for both IP filename and hostname filename */
2059 if (!silc_pkcs_load_public_key(ipf, &public_key,
2060 SILC_PKCS_FILE_PEM) &&
2061 !silc_pkcs_load_public_key(ipf, &public_key,
2062 SILC_PKCS_FILE_BIN) &&
2063 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2064 SILC_PKCS_FILE_PEM) &&
2065 !silc_pkcs_load_public_key(hostf, &public_key,
2066 SILC_PKCS_FILE_BIN)))) {
2067 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2068 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2069 verify->entity_name : entity);
2070 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2071 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2072 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2073 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2074 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2075 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2076 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2077 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2078 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2081 silc_free(fingerprint);
2085 /* Encode the key data */
2086 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2088 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2089 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2090 verify->entity_name : entity);
2091 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2092 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2093 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2094 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2095 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2096 SILCTXT_PUBKEY_MALFORMED, entity);
2097 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2098 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2099 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2102 silc_free(fingerprint);
2106 /* Compare the keys */
2107 if (memcmp(encpk, pk, encpk_len)) {
2108 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2109 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2110 verify->entity_name : entity);
2111 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2112 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2113 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2114 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2115 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2116 SILCTXT_PUBKEY_NO_MATCH, entity);
2117 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2118 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2119 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2120 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2122 /* Ask user to verify the key and save it */
2123 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2124 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2125 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2128 silc_free(fingerprint);
2132 /* Local copy matched */
2134 completion(TRUE, context);
2135 silc_free(fingerprint);
2136 silc_free(verify->filename);
2137 silc_free(verify->entity);
2138 silc_free(verify->entity_name);
2139 silc_free(verify->pk);
2144 /* Verifies received public key. The `conn_type' indicates which entity
2145 (server, client etc.) has sent the public key. If user decides to trust
2146 the key may be saved as trusted public key for later use. The
2147 `completion' must be called after the public key has been verified. */
2150 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2151 SilcSocketType conn_type, unsigned char *pk,
2152 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2153 SilcVerifyPublicKey completion, void *context)
2155 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2157 completion, context);
2160 /* Asks passphrase from user on the input line. */
2163 SilcAskPassphrase completion;
2167 void ask_passphrase_completion(const char *passphrase, void *context)
2169 AskPassphrase p = (AskPassphrase)context;
2170 if (passphrase && passphrase[0] == '\0')
2172 p->completion((unsigned char *)passphrase,
2173 passphrase ? strlen(passphrase) : 0, p->context);
2177 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2178 SilcAskPassphrase completion, void *context)
2180 AskPassphrase p = silc_calloc(1, sizeof(*p));
2181 p->completion = completion;
2182 p->context = context;
2184 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2185 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2189 SilcGetAuthMeth completion;
2191 } *InternalGetAuthMethod;
2193 /* Callback called when we've received the authentication method information
2194 from the server after we've requested it. This will get the authentication
2195 data from the user if needed. */
2197 static void silc_get_auth_method_callback(SilcClient client,
2198 SilcClientConnection conn,
2199 SilcAuthMethod auth_meth,
2202 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2204 SILC_LOG_DEBUG(("Start"));
2206 switch (auth_meth) {
2207 case SILC_AUTH_NONE:
2208 /* No authentication required. */
2209 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2211 case SILC_AUTH_PASSWORD:
2213 /* Check whether we find the password for this server in our
2214 configuration. If not, then don't provide so library will ask
2215 it from the user. */
2216 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2218 if (!setup || !setup->password) {
2219 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2223 (*internal->completion)(TRUE, auth_meth, setup->password,
2224 strlen(setup->password), internal->context);
2227 case SILC_AUTH_PUBLIC_KEY:
2228 /* Do not get the authentication data now, the library will generate
2229 it using our default key, if we do not provide it here. */
2230 /* XXX In the future when we support multiple local keys and multiple
2231 local certificates we will need to ask from user which one to use. */
2232 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2236 silc_free(internal);
2239 /* Find authentication method and authentication data by hostname and
2240 port. The hostname may be IP address as well. The found authentication
2241 method and authentication data is returned to `auth_meth', `auth_data'
2242 and `auth_data_len'. The function returns TRUE if authentication method
2243 is found and FALSE if not. `conn' may be NULL. */
2245 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2246 char *hostname, SilcUInt16 port,
2247 SilcGetAuthMeth completion, void *context)
2249 InternalGetAuthMethod internal;
2251 SILC_LOG_DEBUG(("Start"));
2253 /* If we do not have this connection configured by the user in a
2254 configuration file then resolve the authentication method from the
2255 server for this session. */
2256 internal = silc_calloc(1, sizeof(*internal));
2257 internal->completion = completion;
2258 internal->context = context;
2260 silc_client_request_authentication_method(client, conn,
2261 silc_get_auth_method_callback,
2265 /* Notifies application that failure packet was received. This is called
2266 if there is some protocol active in the client. The `protocol' is the
2267 protocol context. The `failure' is opaque pointer to the failure
2268 indication. Note, that the `failure' is protocol dependant and application
2269 must explicitly cast it to correct type. Usually `failure' is 32 bit
2270 failure type (see protocol specs for all protocol failure types). */
2272 void silc_failure(SilcClient client, SilcClientConnection conn,
2273 SilcProtocol protocol, void *failure)
2275 SILC_LOG_DEBUG(("Start"));
2277 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2278 SilcSKEStatus status = (SilcSKEStatus)failure;
2280 if (status == SILC_SKE_STATUS_BAD_VERSION)
2281 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2282 SILCTXT_KE_BAD_VERSION);
2283 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2284 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2285 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2286 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2287 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2288 SILCTXT_KE_UNKNOWN_GROUP);
2289 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2290 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2291 SILCTXT_KE_UNKNOWN_CIPHER);
2292 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2293 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2294 SILCTXT_KE_UNKNOWN_PKCS);
2295 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2296 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2297 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2298 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2299 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2300 SILCTXT_KE_UNKNOWN_HMAC);
2301 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2302 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2303 SILCTXT_KE_INCORRECT_SIGNATURE);
2304 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2305 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2306 SILCTXT_KE_INVALID_COOKIE);
2309 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2310 SilcUInt32 err = (SilcUInt32)failure;
2312 if (err == SILC_AUTH_FAILED)
2313 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2314 SILCTXT_AUTH_FAILED);
2318 /* Asks whether the user would like to perform the key agreement protocol.
2319 This is called after we have received an key agreement packet or an
2320 reply to our key agreement packet. This returns TRUE if the user wants
2321 the library to perform the key agreement protocol and FALSE if it is not
2322 desired (application may start it later by calling the function
2323 silc_client_perform_key_agreement). */
2325 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2326 SilcClientEntry client_entry, const char *hostname,
2327 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2332 SILC_LOG_DEBUG(("Start"));
2334 /* We will just display the info on the screen and return FALSE and user
2335 will have to start the key agreement with a command. */
2338 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2341 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2342 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2344 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2345 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2346 client_entry->nickname, hostname, portstr);
2354 /* Notifies application that file transfer protocol session is being
2355 requested by the remote client indicated by the `client_entry' from
2356 the `hostname' and `port'. The `session_id' is the file transfer
2357 session and it can be used to either accept or reject the file
2358 transfer request, by calling the silc_client_file_receive or
2359 silc_client_file_close, respectively. */
2361 void silc_ftp(SilcClient client, SilcClientConnection conn,
2362 SilcClientEntry client_entry, SilcUInt32 session_id,
2363 const char *hostname, SilcUInt16 port)
2365 SILC_SERVER_REC *server;
2367 FtpSession ftp = NULL;
2369 SILC_LOG_DEBUG(("Start"));
2371 server = conn->context;
2373 silc_dlist_start(server->ftp_sessions);
2374 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2375 if (ftp->client_entry == client_entry &&
2376 ftp->session_id == session_id) {
2377 server->current_session = ftp;
2381 if (ftp == SILC_LIST_END) {
2382 ftp = silc_calloc(1, sizeof(*ftp));
2383 ftp->client_entry = client_entry;
2384 ftp->session_id = session_id;
2387 silc_dlist_add(server->ftp_sessions, ftp);
2388 server->current_session = ftp;
2392 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2395 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2396 SILCTXT_FILE_REQUEST, client_entry->nickname);
2398 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2399 SILCTXT_FILE_REQUEST_HOST,
2400 client_entry->nickname, hostname, portstr);
2403 /* Delivers SILC session detachment data indicated by `detach_data' to the
2404 application. If application has issued SILC_COMMAND_DETACH command
2405 the client session in the SILC network is not quit. The client remains
2406 in the network but is detached. The detachment data may be used later
2407 to resume the session in the SILC Network. The appliation is
2408 responsible of saving the `detach_data', to for example in a file.
2410 The detachment data can be given as argument to the functions
2411 silc_client_connect_to_server, or silc_client_add_connection when
2412 creating connection to remote server, inside SilcClientConnectionParams
2413 structure. If it is provided the client library will attempt to resume
2414 the session in the network. After the connection is created
2415 successfully, the application is responsible of setting the user
2416 interface for user into the same state it was before detaching (showing
2417 same channels, channel modes, etc). It can do this by fetching the
2418 information (like joined channels) from the client library. */
2421 silc_detach(SilcClient client, SilcClientConnection conn,
2422 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2426 /* Save the detachment data to file. */
2428 memset(file, 0, sizeof(file));
2429 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2430 silc_file_writefile(file, detach_data, detach_data_len);
2434 /* SILC client operations */
2435 SilcClientOperations ops = {
2437 silc_channel_message,
2438 silc_private_message,
2444 silc_get_auth_method,
2445 silc_verify_public_key,
2446 silc_ask_passphrase,