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 /* Parse an invite or ban list */
1106 void silc_parse_inviteban_list(SilcClient client,
1107 SilcClientConnection conn,
1108 SILC_SERVER_REC *server,
1109 SilcChannelEntry channel,
1110 const char *list_type,
1111 SilcArgumentPayload list)
1114 SilcUInt32 type, len;
1115 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1116 int counter=0, resolving = FALSE;
1118 if (!silc_argument_get_arg_num(list)) {
1119 printformat_module("fe-common/silc", server,
1120 (chanrec ? chanrec->visible_name : NULL),
1121 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1122 channel->channel_name, list_type);
1126 printformat_module("fe-common/silc", server,
1127 (chanrec ? chanrec->visible_name : NULL),
1128 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1129 channel->channel_name, list_type);
1131 /* parse the list */
1132 tmp = silc_argument_get_first_arg(list, &type, &len);
1137 /* an invite string */
1141 if (tmp[len-1] == ',')
1144 list = g_strsplit(tmp, ",", -1);
1146 printformat_module("fe-common/silc", server,
1147 (chanrec ? chanrec->visible_name : NULL),
1148 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1149 ++counter, channel->channel_name, list_type,
1158 char *fingerprint, *babbleprint;
1160 fingerprint = silc_hash_fingerprint(NULL, tmp, len);
1161 babbleprint = silc_hash_fingerprint(NULL, tmp, len);
1163 printformat_module("fe-common/silc", server,
1164 (chanrec ? chanrec->visible_name : NULL),
1165 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1166 ++counter, channel->channel_name, list_type,
1167 fingerprint, babbleprint);
1174 SilcClientID *client_id;
1175 SilcClientEntry client_entry;
1177 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1179 if (client_id == NULL) {
1180 silc_say_error("Invalid data in %s list encountered", list_type);
1184 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1187 printformat_module("fe-common/silc", server,
1188 (chanrec ? chanrec->visible_name : NULL),
1189 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1190 ++counter, channel->channel_name, list_type,
1191 client_entry->nickname);
1194 silc_client_get_client_by_id_resolve(client, conn, client_id,
1198 silc_free(client_id);
1204 silc_say_error("Unkown type in %s list: %u (len %u)",
1205 list_type, type, len);
1207 tmp = silc_argument_get_next_arg(list, &type, &len);
1211 printformat_module("fe-common/silc", server,
1212 (chanrec ? chanrec->visible_name : NULL),
1213 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1214 list_type, channel->channel_name);
1217 /* Command reply handler. This function is called always in the command reply
1218 function. If error occurs it will be called as well. Normal scenario
1219 is that it will be called after the received command data has been parsed
1220 and processed. The function is used to pass the received command data to
1223 `conn' is the associated client connection. `cmd_payload' is the command
1224 payload data received from server and it can be ignored. It is provided
1225 if the application would like to re-parse the received command data,
1226 however, it must be noted that the data is parsed already by the library
1227 thus the payload can be ignored. `success' is FALSE if error occured.
1228 In this case arguments are not sent to the application. `command' is the
1229 command reply being processed. The function has variable argument list
1230 and each command defines the number and type of arguments it passes to the
1231 application (on error they are not sent). */
1234 silc_command_reply(SilcClient client, SilcClientConnection conn,
1235 SilcCommandPayload cmd_payload, bool success,
1236 SilcCommand command, SilcStatus status, ...)
1239 SILC_SERVER_REC *server = conn->context;
1240 SILC_CHANNEL_REC *chanrec;
1243 va_start(vp, status);
1245 SILC_LOG_DEBUG(("Start"));
1248 case SILC_COMMAND_WHOIS:
1250 char buf[1024], *nickname, *username, *realname, *nick;
1251 unsigned char *fingerprint;
1252 SilcUInt32 idle, mode;
1253 SilcBuffer channels, user_modes;
1254 SilcClientEntry client_entry;
1257 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1258 /* Print the unknown nick for user */
1259 unsigned char *tmp =
1260 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1263 silc_say_error("%s: %s", tmp,
1264 silc_get_status_message(status));
1266 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1267 /* Try to find the entry for the unknown client ID, since we
1268 might have, and print the nickname of it for user. */
1270 unsigned char *tmp =
1271 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1274 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1277 client_entry = silc_client_get_client_by_id(client, conn,
1279 if (client_entry && client_entry->nickname)
1280 silc_say_error("%s: %s", client_entry->nickname,
1281 silc_get_status_message(status));
1282 silc_free(client_id);
1286 } else if (!success) {
1287 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1291 client_entry = va_arg(vp, SilcClientEntry);
1292 nickname = va_arg(vp, char *);
1293 username = va_arg(vp, char *);
1294 realname = va_arg(vp, char *);
1295 channels = va_arg(vp, SilcBuffer);
1296 mode = va_arg(vp, SilcUInt32);
1297 idle = va_arg(vp, SilcUInt32);
1298 fingerprint = va_arg(vp, unsigned char *);
1299 user_modes = va_arg(vp, SilcBuffer);
1300 attrs = va_arg(vp, SilcDList);
1302 silc_parse_userfqdn(nickname, &nick, NULL);
1303 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1304 SILCTXT_WHOIS_USERINFO, nickname,
1305 client_entry->username, client_entry->hostname,
1306 nick, client_entry->nickname);
1307 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1308 SILCTXT_WHOIS_REALNAME, realname);
1311 if (channels && user_modes) {
1313 SilcDList list = silc_channel_payload_parse_list(channels->data,
1315 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1317 SilcChannelPayload entry;
1320 memset(buf, 0, sizeof(buf));
1321 silc_dlist_start(list);
1322 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1323 SilcUInt32 name_len;
1324 char *m = silc_client_chumode_char(umodes[i++]);
1325 char *name = silc_channel_get_name(entry, &name_len);
1328 strncat(buf, m, strlen(m));
1329 strncat(buf, name, name_len);
1330 strncat(buf, " ", 1);
1334 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1335 SILCTXT_WHOIS_CHANNELS, buf);
1336 silc_channel_payload_list_free(list);
1342 memset(buf, 0, sizeof(buf));
1343 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1344 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1345 SILCTXT_WHOIS_MODES, buf);
1348 if (idle && nickname) {
1349 memset(buf, 0, sizeof(buf));
1350 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1351 idle > 60 ? (idle / 60) : idle,
1352 idle > 60 ? "minutes" : "seconds");
1354 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1355 SILCTXT_WHOIS_IDLE, buf);
1359 fingerprint = silc_fingerprint(fingerprint, 20);
1360 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1361 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1362 silc_free(fingerprint);
1366 silc_query_attributes_print(server, silc_client, conn, attrs,
1371 case SILC_COMMAND_IDENTIFY:
1373 SilcClientEntry client_entry;
1375 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1376 /* Print the unknown nick for user */
1377 unsigned char *tmp =
1378 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1381 silc_say_error("%s: %s", tmp,
1382 silc_get_status_message(status));
1384 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1385 /* Try to find the entry for the unknown client ID, since we
1386 might have, and print the nickname of it for user. */
1388 unsigned char *tmp =
1389 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1392 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1395 client_entry = silc_client_get_client_by_id(client, conn,
1397 if (client_entry && client_entry->nickname)
1398 silc_say_error("%s: %s", client_entry->nickname,
1399 silc_get_status_message(status));
1400 silc_free(client_id);
1409 case SILC_COMMAND_WHOWAS:
1411 char *nickname, *username, *realname;
1413 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1414 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1416 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1419 silc_say_error("%s: %s", tmp,
1420 silc_get_status_message(status));
1422 } else if (!success) {
1423 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1427 (void)va_arg(vp, SilcClientEntry);
1428 nickname = va_arg(vp, char *);
1429 username = va_arg(vp, char *);
1430 realname = va_arg(vp, char *);
1432 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1433 SILCTXT_WHOWAS_USERINFO, nickname, username,
1434 realname ? realname : "");
1438 case SILC_COMMAND_INVITE:
1440 SilcChannelEntry channel;
1442 SilcArgumentPayload invite_list;
1448 channel = va_arg(vp, SilcChannelEntry);
1449 payload = va_arg(vp, SilcBuffer);
1452 SILC_GET16_MSB(argc, payload->data);
1453 invite_list = silc_argument_payload_parse(payload->data + 2,
1454 payload->len - 2, argc);
1456 silc_parse_inviteban_list(client, conn, server, channel,
1457 "invite", invite_list);
1458 silc_argument_payload_free(invite_list);
1464 case SILC_COMMAND_JOIN:
1466 char *channel, *mode, *topic;
1468 SilcChannelEntry channel_entry;
1469 SilcBuffer client_id_list;
1470 SilcUInt32 list_count;
1475 channel = va_arg(vp, char *);
1476 channel_entry = va_arg(vp, SilcChannelEntry);
1477 modei = va_arg(vp, SilcUInt32);
1478 (void)va_arg(vp, SilcUInt32);
1479 (void)va_arg(vp, unsigned char *);
1480 (void)va_arg(vp, unsigned char *);
1481 (void)va_arg(vp, unsigned char *);
1482 topic = va_arg(vp, char *);
1483 (void)va_arg(vp, unsigned char *);
1484 list_count = va_arg(vp, SilcUInt32);
1485 client_id_list = va_arg(vp, SilcBuffer);
1487 chanrec = silc_channel_find(server, channel);
1489 chanrec = silc_channel_create(server, channel, channel, TRUE);
1492 char tmp[256], *cp, *dm = NULL;
1493 g_free_not_null(chanrec->topic);
1495 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1496 memset(tmp, 0, sizeof(tmp));
1498 if (strlen(topic) > sizeof(tmp) - 1) {
1499 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1503 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1508 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1509 signal_emit("channel topic changed", 1, chanrec);
1514 mode = silc_client_chmode(modei,
1515 channel_entry->channel_key ?
1516 silc_cipher_get_name(channel_entry->
1518 channel_entry->hmac ?
1519 silc_hmac_get_name(channel_entry->hmac) : "");
1520 g_free_not_null(chanrec->mode);
1521 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1522 signal_emit("channel mode changed", 1, chanrec);
1524 /* Resolve the client information */
1525 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1526 silc_client_join_get_users,
1532 case SILC_COMMAND_NICK:
1535 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1541 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1542 if (nicks != NULL) {
1544 SilcClientEntry collider, old;
1546 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1547 collider = silc_client_get_client_by_id(client, conn,
1550 memset(buf, 0, sizeof(buf));
1551 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1552 collider->username, collider->hostname);
1553 nicklist_rename_unique(SERVER(server),
1555 collider, collider->nickname);
1556 silc_print_nick_change(server, collider->nickname,
1557 client_entry->nickname, buf);
1558 g_slist_free(nicks);
1561 old = g_strdup(server->nick);
1562 server_change_nick(SERVER(server), client_entry->nickname);
1563 nicklist_rename_unique(SERVER(server),
1564 server->conn->local_entry, server->nick,
1565 client_entry, client_entry->nickname);
1566 signal_emit("message own_nick", 4, server, server->nick, old, "");
1571 case SILC_COMMAND_LIST:
1576 char tmp[256], *cp, *dm = NULL;
1581 (void)va_arg(vp, SilcChannelEntry);
1582 name = va_arg(vp, char *);
1583 topic = va_arg(vp, char *);
1584 usercount = va_arg(vp, int);
1586 if (topic && !silc_term_utf8() &&
1587 silc_utf8_valid(topic, strlen(topic))) {
1588 memset(tmp, 0, sizeof(tmp));
1590 if (strlen(topic) > sizeof(tmp) - 1) {
1591 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1595 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1600 if (status == SILC_STATUS_LIST_START ||
1601 status == SILC_STATUS_OK)
1602 printformat_module("fe-common/silc", server, NULL,
1603 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1606 snprintf(users, sizeof(users) - 1, "N/A");
1608 snprintf(users, sizeof(users) - 1, "%d", usercount);
1609 printformat_module("fe-common/silc", server, NULL,
1610 MSGLEVEL_CRAP, SILCTXT_LIST,
1611 name, users, topic ? topic : "");
1616 case SILC_COMMAND_UMODE:
1624 mode = va_arg(vp, SilcUInt32);
1626 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1627 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1628 printformat_module("fe-common/silc", server, NULL,
1629 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1631 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1632 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1633 printformat_module("fe-common/silc", server, NULL,
1634 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1636 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1637 if (mode & SILC_UMODE_GONE) {
1638 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1639 reason = g_strdup(server->away_reason);
1641 reason = g_strdup("away");
1643 reason = g_strdup("");
1645 silc_set_away(reason, server);
1650 server->umode = mode;
1651 signal_emit("user mode changed", 2, server, NULL);
1655 case SILC_COMMAND_OPER:
1659 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1660 signal_emit("user mode changed", 2, server, NULL);
1662 printformat_module("fe-common/silc", server, NULL,
1663 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1666 case SILC_COMMAND_SILCOPER:
1670 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1671 signal_emit("user mode changed", 2, server, NULL);
1673 printformat_module("fe-common/silc", server, NULL,
1674 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1677 case SILC_COMMAND_USERS:
1679 SilcHashTableList htl;
1680 SilcChannelEntry channel;
1681 SilcChannelUser chu;
1686 channel = va_arg(vp, SilcChannelEntry);
1688 printformat_module("fe-common/silc", server, channel->channel_name,
1689 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1690 channel->channel_name);
1692 silc_hash_table_list(channel->user_list, &htl);
1693 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1694 SilcClientEntry e = chu->client;
1695 char stat[5], *mode;
1700 memset(stat, 0, sizeof(stat));
1701 mode = silc_client_chumode_char(chu->mode);
1702 if (e->mode & SILC_UMODE_GONE)
1704 else if (e->mode & SILC_UMODE_INDISPOSED)
1706 else if (e->mode & SILC_UMODE_BUSY)
1708 else if (e->mode & SILC_UMODE_PAGE)
1710 else if (e->mode & SILC_UMODE_HYPER)
1712 else if (e->mode & SILC_UMODE_ROBOT)
1714 else if (e->mode & SILC_UMODE_ANONYMOUS)
1721 printformat_module("fe-common/silc", server, channel->channel_name,
1722 MSGLEVEL_CRAP, SILCTXT_USERS,
1724 e->username ? e->username : "",
1725 e->hostname ? e->hostname : "",
1726 e->realname ? e->realname : "");
1730 silc_hash_table_list_reset(&htl);
1734 case SILC_COMMAND_BAN:
1736 SilcChannelEntry channel;
1738 SilcArgumentPayload ban_list;
1744 channel = va_arg(vp, SilcChannelEntry);
1745 payload = va_arg(vp, SilcBuffer);
1748 SILC_GET16_MSB(argc, payload->data);
1749 ban_list = silc_argument_payload_parse(payload->data + 2,
1750 payload->len - 2, argc);
1752 silc_parse_inviteban_list(client, conn, server, channel,
1754 silc_argument_payload_free(ban_list);
1760 case SILC_COMMAND_GETKEY:
1764 SilcPublicKey public_key;
1767 GetkeyContext getkey;
1773 id_type = va_arg(vp, SilcUInt32);
1774 entry = va_arg(vp, void *);
1775 public_key = va_arg(vp, SilcPublicKey);
1778 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1780 getkey = silc_calloc(1, sizeof(*getkey));
1781 getkey->entry = entry;
1782 getkey->id_type = id_type;
1783 getkey->client = client;
1784 getkey->conn = conn;
1785 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1787 name = (id_type == SILC_ID_CLIENT ?
1788 ((SilcClientEntry)entry)->nickname :
1789 ((SilcServerEntry)entry)->server_name);
1791 silc_verify_public_key_internal(client, conn, name,
1792 (id_type == SILC_ID_CLIENT ?
1793 SILC_SOCKET_TYPE_CLIENT :
1794 SILC_SOCKET_TYPE_SERVER),
1795 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1796 silc_getkey_cb, getkey);
1799 printformat_module("fe-common/silc", server, NULL,
1800 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1805 case SILC_COMMAND_INFO:
1807 SilcServerEntry server_entry;
1814 server_entry = va_arg(vp, SilcServerEntry);
1815 server_name = va_arg(vp, char *);
1816 server_info = va_arg(vp, char *);
1818 if (server_name && server_info )
1820 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1821 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1826 case SILC_COMMAND_TOPIC:
1828 SilcChannelEntry channel;
1830 char tmp[256], *cp, *dm = NULL;
1835 channel = va_arg(vp, SilcChannelEntry);
1836 topic = va_arg(vp, char *);
1838 if (topic && !silc_term_utf8() &&
1839 silc_utf8_valid(topic, strlen(topic))) {
1840 memset(tmp, 0, sizeof(tmp));
1842 if (strlen(topic) > sizeof(tmp) - 1) {
1843 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1847 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1853 chanrec = silc_channel_find_entry(server, channel);
1855 g_free_not_null(chanrec->topic);
1856 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1857 signal_emit("channel topic changed", 1, chanrec);
1859 printformat_module("fe-common/silc", server, channel->channel_name,
1860 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1861 channel->channel_name, topic);
1863 printformat_module("fe-common/silc", server, channel->channel_name,
1864 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1865 channel->channel_name);
1871 case SILC_COMMAND_WATCH:
1874 case SILC_COMMAND_STATS:
1876 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1877 my_router_ops, cell_clients, cell_channels, cell_servers,
1878 clients, channels, servers, routers, server_ops, router_ops;
1880 SilcBufferStruct buf;
1881 unsigned char *tmp_buf;
1883 const char *tmptime;
1884 int days, hours, mins, secs;
1889 tmp_buf = va_arg(vp, unsigned char *);
1890 buf_len = va_arg(vp, SilcUInt32);
1892 if (!tmp_buf || !buf_len) {
1893 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
1897 /* Get statistics structure */
1898 silc_buffer_set(&buf, tmp_buf, buf_len);
1899 silc_buffer_unformat(&buf,
1900 SILC_STR_UI_INT(&starttime),
1901 SILC_STR_UI_INT(&uptime),
1902 SILC_STR_UI_INT(&my_clients),
1903 SILC_STR_UI_INT(&my_channels),
1904 SILC_STR_UI_INT(&my_server_ops),
1905 SILC_STR_UI_INT(&my_router_ops),
1906 SILC_STR_UI_INT(&cell_clients),
1907 SILC_STR_UI_INT(&cell_channels),
1908 SILC_STR_UI_INT(&cell_servers),
1909 SILC_STR_UI_INT(&clients),
1910 SILC_STR_UI_INT(&channels),
1911 SILC_STR_UI_INT(&servers),
1912 SILC_STR_UI_INT(&routers),
1913 SILC_STR_UI_INT(&server_ops),
1914 SILC_STR_UI_INT(&router_ops),
1917 tmptime = silc_get_time(starttime);
1918 printformat_module("fe-common/silc", server, NULL,
1919 MSGLEVEL_CRAP, SILCTXT_STATS,
1920 "Local server start time", tmptime);
1922 days = uptime / (24 * 60 * 60);
1923 uptime -= days * (24 * 60 * 60);
1924 hours = uptime / (60 * 60);
1925 uptime -= hours * (60 * 60);
1927 uptime -= mins * 60;
1929 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
1930 days, hours, mins, secs);
1931 printformat_module("fe-common/silc", server, NULL,
1932 MSGLEVEL_CRAP, SILCTXT_STATS,
1933 "Local server uptime", tmp);
1935 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
1936 printformat_module("fe-common/silc", server, NULL,
1937 MSGLEVEL_CRAP, SILCTXT_STATS,
1938 "Local server clients", tmp);
1940 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
1941 printformat_module("fe-common/silc", server, NULL,
1942 MSGLEVEL_CRAP, SILCTXT_STATS,
1943 "Local server channels", tmp);
1945 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
1946 printformat_module("fe-common/silc", server, NULL,
1947 MSGLEVEL_CRAP, SILCTXT_STATS,
1948 "Local server operators", tmp);
1950 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
1951 printformat_module("fe-common/silc", server, NULL,
1952 MSGLEVEL_CRAP, SILCTXT_STATS,
1953 "Local router operators", tmp);
1955 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
1956 printformat_module("fe-common/silc", server, NULL,
1957 MSGLEVEL_CRAP, SILCTXT_STATS,
1958 "Local cell clients", tmp);
1960 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
1961 printformat_module("fe-common/silc", server, NULL,
1962 MSGLEVEL_CRAP, SILCTXT_STATS,
1963 "Local cell channels", tmp);
1965 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
1966 printformat_module("fe-common/silc", server, NULL,
1967 MSGLEVEL_CRAP, SILCTXT_STATS,
1968 "Local cell servers", tmp);
1970 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
1971 printformat_module("fe-common/silc", server, NULL,
1972 MSGLEVEL_CRAP, SILCTXT_STATS,
1973 "Total clients", tmp);
1975 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
1976 printformat_module("fe-common/silc", server, NULL,
1977 MSGLEVEL_CRAP, SILCTXT_STATS,
1978 "Total channels", tmp);
1980 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
1981 printformat_module("fe-common/silc", server, NULL,
1982 MSGLEVEL_CRAP, SILCTXT_STATS,
1983 "Total servers", tmp);
1985 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
1986 printformat_module("fe-common/silc", server, NULL,
1987 MSGLEVEL_CRAP, SILCTXT_STATS,
1988 "Total routers", tmp);
1990 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
1991 printformat_module("fe-common/silc", server, NULL,
1992 MSGLEVEL_CRAP, SILCTXT_STATS,
1993 "Total server operators", tmp);
1995 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
1996 printformat_module("fe-common/silc", server, NULL,
1997 MSGLEVEL_CRAP, SILCTXT_STATS,
1998 "Total router operators", tmp);
2009 SilcClientConnection conn;
2015 SilcSKEPKType pk_type;
2016 SilcVerifyPublicKey completion;
2020 static void verify_public_key_completion(const char *line, void *context)
2022 PublicKeyVerify verify = (PublicKeyVerify)context;
2024 if (line[0] == 'Y' || line[0] == 'y') {
2025 /* Call the completion */
2026 if (verify->completion)
2027 verify->completion(TRUE, verify->context);
2029 /* Save the key for future checking */
2030 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2031 verify->pk_len, SILC_PKCS_FILE_PEM);
2033 /* Call the completion */
2034 if (verify->completion)
2035 verify->completion(FALSE, verify->context);
2037 printformat_module("fe-common/silc", NULL, NULL,
2038 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2039 verify->entity_name ? verify->entity_name :
2043 silc_free(verify->filename);
2044 silc_free(verify->entity);
2045 silc_free(verify->entity_name);
2046 silc_free(verify->pk);
2050 /* Internal routine to verify public key. If the `completion' is provided
2051 it will be called to indicate whether public was verified or not. For
2052 server/router public key this will check for filename that includes the
2053 remote host's IP address and remote host's hostname. */
2056 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2057 const char *name, SilcSocketType conn_type,
2058 unsigned char *pk, SilcUInt32 pk_len,
2059 SilcSKEPKType pk_type,
2060 SilcVerifyPublicKey completion, void *context)
2063 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2064 char *fingerprint, *babbleprint, *format;
2067 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2068 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2069 "server" : "client");
2070 PublicKeyVerify verify;
2072 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2073 printformat_module("fe-common/silc", NULL, NULL,
2074 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2077 completion(FALSE, context);
2081 pw = getpwuid(getuid());
2084 completion(FALSE, context);
2088 memset(filename, 0, sizeof(filename));
2089 memset(filename2, 0, sizeof(filename2));
2090 memset(file, 0, sizeof(file));
2092 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2093 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2095 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2096 conn->sock->ip, conn->sock->port);
2097 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2098 get_irssi_dir(), entity, file);
2100 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2101 conn->sock->hostname, conn->sock->port);
2102 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2103 get_irssi_dir(), entity, file);
2108 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2109 name, conn->sock->port);
2110 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2111 get_irssi_dir(), entity, file);
2116 /* Replace all whitespaces with `_'. */
2117 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2118 for (i = 0; i < strlen(fingerprint); i++)
2119 if (fingerprint[i] == ' ')
2120 fingerprint[i] = '_';
2122 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2123 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2124 get_irssi_dir(), entity, file);
2125 silc_free(fingerprint);
2130 /* Take fingerprint of the public key */
2131 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2132 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2134 verify = silc_calloc(1, sizeof(*verify));
2135 verify->client = client;
2136 verify->conn = conn;
2137 verify->filename = strdup(ipf);
2138 verify->entity = strdup(entity);
2139 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2140 (name ? strdup(name) : strdup(conn->sock->hostname))
2142 verify->pk = silc_memdup(pk, pk_len);
2143 verify->pk_len = pk_len;
2144 verify->pk_type = pk_type;
2145 verify->completion = completion;
2146 verify->context = context;
2148 /* Check whether this key already exists */
2149 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2150 /* Key does not exist, ask user to verify the key and save it */
2152 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2153 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2154 verify->entity_name : entity);
2155 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2156 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2157 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2158 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2159 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2160 SILCTXT_PUBKEY_ACCEPT);
2161 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2164 silc_free(fingerprint);
2167 /* The key already exists, verify it. */
2168 SilcPublicKey public_key;
2169 unsigned char *encpk;
2170 SilcUInt32 encpk_len;
2172 /* Load the key file, try for both IP filename and hostname filename */
2173 if (!silc_pkcs_load_public_key(ipf, &public_key,
2174 SILC_PKCS_FILE_PEM) &&
2175 !silc_pkcs_load_public_key(ipf, &public_key,
2176 SILC_PKCS_FILE_BIN) &&
2177 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2178 SILC_PKCS_FILE_PEM) &&
2179 !silc_pkcs_load_public_key(hostf, &public_key,
2180 SILC_PKCS_FILE_BIN)))) {
2181 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2182 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2183 verify->entity_name : entity);
2184 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2185 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2186 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2187 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2188 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2189 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2190 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2191 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2192 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2195 silc_free(fingerprint);
2199 /* Encode the key data */
2200 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2202 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2203 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2204 verify->entity_name : entity);
2205 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2206 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2207 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2208 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2209 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2210 SILCTXT_PUBKEY_MALFORMED, entity);
2211 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2212 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2213 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2216 silc_free(fingerprint);
2220 /* Compare the keys */
2221 if (memcmp(encpk, pk, encpk_len)) {
2222 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2223 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2224 verify->entity_name : entity);
2225 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2226 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2227 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2228 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2229 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2230 SILCTXT_PUBKEY_NO_MATCH, entity);
2231 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2232 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2233 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2234 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2236 /* Ask user to verify the key and save it */
2237 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2238 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2239 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2242 silc_free(fingerprint);
2246 /* Local copy matched */
2248 completion(TRUE, context);
2249 silc_free(fingerprint);
2250 silc_free(verify->filename);
2251 silc_free(verify->entity);
2252 silc_free(verify->entity_name);
2253 silc_free(verify->pk);
2258 /* Verifies received public key. The `conn_type' indicates which entity
2259 (server, client etc.) has sent the public key. If user decides to trust
2260 the key may be saved as trusted public key for later use. The
2261 `completion' must be called after the public key has been verified. */
2264 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2265 SilcSocketType conn_type, unsigned char *pk,
2266 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2267 SilcVerifyPublicKey completion, void *context)
2269 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2271 completion, context);
2274 /* Asks passphrase from user on the input line. */
2277 SilcAskPassphrase completion;
2281 void ask_passphrase_completion(const char *passphrase, void *context)
2283 AskPassphrase p = (AskPassphrase)context;
2284 if (passphrase && passphrase[0] == '\0')
2286 p->completion((unsigned char *)passphrase,
2287 passphrase ? strlen(passphrase) : 0, p->context);
2291 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2292 SilcAskPassphrase completion, void *context)
2294 AskPassphrase p = silc_calloc(1, sizeof(*p));
2295 p->completion = completion;
2296 p->context = context;
2298 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2299 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2303 SilcGetAuthMeth completion;
2305 } *InternalGetAuthMethod;
2307 /* Callback called when we've received the authentication method information
2308 from the server after we've requested it. This will get the authentication
2309 data from the user if needed. */
2311 static void silc_get_auth_method_callback(SilcClient client,
2312 SilcClientConnection conn,
2313 SilcAuthMethod auth_meth,
2316 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2318 SILC_LOG_DEBUG(("Start"));
2320 switch (auth_meth) {
2321 case SILC_AUTH_NONE:
2322 /* No authentication required. */
2323 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2325 case SILC_AUTH_PASSWORD:
2327 /* Check whether we find the password for this server in our
2328 configuration. If not, then don't provide so library will ask
2329 it from the user. */
2330 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2332 if (!setup || !setup->password) {
2333 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2337 (*internal->completion)(TRUE, auth_meth, setup->password,
2338 strlen(setup->password), internal->context);
2341 case SILC_AUTH_PUBLIC_KEY:
2342 /* Do not get the authentication data now, the library will generate
2343 it using our default key, if we do not provide it here. */
2344 /* XXX In the future when we support multiple local keys and multiple
2345 local certificates we will need to ask from user which one to use. */
2346 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2350 silc_free(internal);
2353 /* Find authentication method and authentication data by hostname and
2354 port. The hostname may be IP address as well. The found authentication
2355 method and authentication data is returned to `auth_meth', `auth_data'
2356 and `auth_data_len'. The function returns TRUE if authentication method
2357 is found and FALSE if not. `conn' may be NULL. */
2359 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2360 char *hostname, SilcUInt16 port,
2361 SilcGetAuthMeth completion, void *context)
2363 InternalGetAuthMethod internal;
2365 SILC_LOG_DEBUG(("Start"));
2367 /* If we do not have this connection configured by the user in a
2368 configuration file then resolve the authentication method from the
2369 server for this session. */
2370 internal = silc_calloc(1, sizeof(*internal));
2371 internal->completion = completion;
2372 internal->context = context;
2374 silc_client_request_authentication_method(client, conn,
2375 silc_get_auth_method_callback,
2379 /* Notifies application that failure packet was received. This is called
2380 if there is some protocol active in the client. The `protocol' is the
2381 protocol context. The `failure' is opaque pointer to the failure
2382 indication. Note, that the `failure' is protocol dependant and application
2383 must explicitly cast it to correct type. Usually `failure' is 32 bit
2384 failure type (see protocol specs for all protocol failure types). */
2386 void silc_failure(SilcClient client, SilcClientConnection conn,
2387 SilcProtocol protocol, void *failure)
2389 SILC_LOG_DEBUG(("Start"));
2391 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2392 SilcSKEStatus status = (SilcSKEStatus)failure;
2394 if (status == SILC_SKE_STATUS_BAD_VERSION)
2395 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2396 SILCTXT_KE_BAD_VERSION);
2397 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2398 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2399 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2400 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2401 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2402 SILCTXT_KE_UNKNOWN_GROUP);
2403 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2404 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2405 SILCTXT_KE_UNKNOWN_CIPHER);
2406 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2407 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2408 SILCTXT_KE_UNKNOWN_PKCS);
2409 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2410 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2411 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2412 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2413 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2414 SILCTXT_KE_UNKNOWN_HMAC);
2415 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2416 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2417 SILCTXT_KE_INCORRECT_SIGNATURE);
2418 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2419 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2420 SILCTXT_KE_INVALID_COOKIE);
2423 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2424 SilcUInt32 err = (SilcUInt32)failure;
2426 if (err == SILC_AUTH_FAILED)
2427 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2428 SILCTXT_AUTH_FAILED);
2432 /* Asks whether the user would like to perform the key agreement protocol.
2433 This is called after we have received an key agreement packet or an
2434 reply to our key agreement packet. This returns TRUE if the user wants
2435 the library to perform the key agreement protocol and FALSE if it is not
2436 desired (application may start it later by calling the function
2437 silc_client_perform_key_agreement). */
2439 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2440 SilcClientEntry client_entry, const char *hostname,
2441 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2446 SILC_LOG_DEBUG(("Start"));
2448 /* We will just display the info on the screen and return FALSE and user
2449 will have to start the key agreement with a command. */
2452 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2455 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2456 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2458 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2459 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2460 client_entry->nickname, hostname, portstr);
2468 /* Notifies application that file transfer protocol session is being
2469 requested by the remote client indicated by the `client_entry' from
2470 the `hostname' and `port'. The `session_id' is the file transfer
2471 session and it can be used to either accept or reject the file
2472 transfer request, by calling the silc_client_file_receive or
2473 silc_client_file_close, respectively. */
2475 void silc_ftp(SilcClient client, SilcClientConnection conn,
2476 SilcClientEntry client_entry, SilcUInt32 session_id,
2477 const char *hostname, SilcUInt16 port)
2479 SILC_SERVER_REC *server;
2481 FtpSession ftp = NULL;
2483 SILC_LOG_DEBUG(("Start"));
2485 server = conn->context;
2487 silc_dlist_start(server->ftp_sessions);
2488 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2489 if (ftp->client_entry == client_entry &&
2490 ftp->session_id == session_id) {
2491 server->current_session = ftp;
2495 if (ftp == SILC_LIST_END) {
2496 ftp = silc_calloc(1, sizeof(*ftp));
2497 ftp->client_entry = client_entry;
2498 ftp->session_id = session_id;
2501 silc_dlist_add(server->ftp_sessions, ftp);
2502 server->current_session = ftp;
2506 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2509 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2510 SILCTXT_FILE_REQUEST, client_entry->nickname);
2512 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2513 SILCTXT_FILE_REQUEST_HOST,
2514 client_entry->nickname, hostname, portstr);
2517 /* Delivers SILC session detachment data indicated by `detach_data' to the
2518 application. If application has issued SILC_COMMAND_DETACH command
2519 the client session in the SILC network is not quit. The client remains
2520 in the network but is detached. The detachment data may be used later
2521 to resume the session in the SILC Network. The appliation is
2522 responsible of saving the `detach_data', to for example in a file.
2524 The detachment data can be given as argument to the functions
2525 silc_client_connect_to_server, or silc_client_add_connection when
2526 creating connection to remote server, inside SilcClientConnectionParams
2527 structure. If it is provided the client library will attempt to resume
2528 the session in the network. After the connection is created
2529 successfully, the application is responsible of setting the user
2530 interface for user into the same state it was before detaching (showing
2531 same channels, channel modes, etc). It can do this by fetching the
2532 information (like joined channels) from the client library. */
2535 silc_detach(SilcClient client, SilcClientConnection conn,
2536 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2540 /* Save the detachment data to file. */
2542 memset(file, 0, sizeof(file));
2543 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2544 silc_file_writefile(file, detach_data, detach_data_len);
2548 /* SILC client operations */
2549 SilcClientOperations ops = {
2551 silc_channel_message,
2552 silc_private_message,
2558 silc_get_auth_method,
2559 silc_verify_public_key,
2560 silc_ask_passphrase,