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 g_free_not_null(chanrec->topic);
481 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
482 signal_emit("channel topic changed", 1, chanrec);
485 if (idtype == SILC_ID_CLIENT) {
486 client_entry = (SilcClientEntry)entry;
487 memset(buf, 0, sizeof(buf));
488 snprintf(buf, sizeof(buf) - 1, "%s@%s",
489 client_entry->username, client_entry->hostname);
490 signal_emit("message topic", 5, server, channel->channel_name,
491 tmp, client_entry->nickname, buf);
492 } else if (idtype == SILC_ID_SERVER) {
493 server_entry = (SilcServerEntry)entry;
494 signal_emit("message topic", 5, server, channel->channel_name,
495 tmp, server_entry->server_name,
496 server_entry->server_name);
497 } else if (idtype == SILC_ID_CHANNEL) {
498 channel = (SilcChannelEntry)entry;
499 signal_emit("message topic", 5, server, channel->channel_name,
500 tmp, channel->channel_name, channel->channel_name);
504 case SILC_NOTIFY_TYPE_NICK_CHANGE:
509 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
511 client_entry = va_arg(va, SilcClientEntry);
512 client_entry2 = va_arg(va, SilcClientEntry);
514 if (!strcmp(client_entry->nickname, client_entry2->nickname))
517 memset(buf, 0, sizeof(buf));
518 snprintf(buf, sizeof(buf) - 1, "%s@%s",
519 client_entry2->username, client_entry2->hostname);
520 nicklist_rename_unique(SERVER(server),
521 client_entry, client_entry->nickname,
522 client_entry2, client_entry2->nickname);
523 signal_emit("message nick", 4, server, client_entry2->nickname,
524 client_entry->nickname, buf);
527 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
529 * Changed channel mode.
532 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
534 idtype = va_arg(va, int);
535 entry = va_arg(va, void *);
536 mode = va_arg(va, SilcUInt32);
537 (void)va_arg(va, char *);
538 (void)va_arg(va, char *);
539 channel = va_arg(va, SilcChannelEntry);
541 tmp = silc_client_chmode(mode,
542 channel->channel_key ?
543 silc_cipher_get_name(channel->channel_key) : "",
545 silc_hmac_get_name(channel->hmac) : "");
547 chanrec = silc_channel_find_entry(server, channel);
548 if (chanrec != NULL) {
549 g_free_not_null(chanrec->mode);
550 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
551 signal_emit("channel mode changed", 1, chanrec);
554 if (idtype == SILC_ID_CLIENT) {
555 client_entry = (SilcClientEntry)entry;
556 printformat_module("fe-common/silc", server, channel->channel_name,
557 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
558 channel->channel_name, tmp ? tmp : "removed all",
559 client_entry->nickname);
560 } else if (idtype == SILC_ID_SERVER) {
561 server_entry = (SilcServerEntry)entry;
562 printformat_module("fe-common/silc", server, channel->channel_name,
563 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
564 channel->channel_name, tmp ? tmp : "removed all",
565 server_entry->server_name);
566 } else if (idtype == SILC_ID_CHANNEL) {
567 channel2 = (SilcChannelEntry)entry;
568 printformat_module("fe-common/silc", server, channel->channel_name,
569 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
570 channel->channel_name, tmp ? tmp : "removed all",
571 channel2->channel_name);
577 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
579 * Changed user's mode on channel.
582 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
584 idtype = va_arg(va, int);
585 entry = va_arg(va, void *);
586 mode = va_arg(va, SilcUInt32);
587 client_entry2 = va_arg(va, SilcClientEntry);
588 channel = va_arg(va, SilcChannelEntry);
590 tmp = silc_client_chumode(mode);
591 chanrec = silc_channel_find_entry(server, channel);
592 if (chanrec != NULL) {
595 if (client_entry2 == server->conn->local_entry)
596 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
598 nick = silc_nicklist_find(chanrec, client_entry2);
600 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
601 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
602 signal_emit("nick mode changed", 2, chanrec, nick);
606 if (idtype == SILC_ID_CLIENT) {
607 client_entry = (SilcClientEntry)entry;
608 printformat_module("fe-common/silc", server, channel->channel_name,
609 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
610 channel->channel_name, client_entry2->nickname,
611 tmp ? tmp : "removed all",
612 client_entry->nickname);
613 } else if (idtype == SILC_ID_SERVER) {
614 server_entry = (SilcServerEntry)entry;
615 printformat_module("fe-common/silc", server, channel->channel_name,
616 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
617 channel->channel_name, client_entry2->nickname,
618 tmp ? tmp : "removed all",
619 server_entry->server_name);
620 } else if (idtype == SILC_ID_CHANNEL) {
621 channel2 = (SilcChannelEntry)entry;
622 printformat_module("fe-common/silc", server, channel->channel_name,
623 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
624 channel->channel_name, client_entry2->nickname,
625 tmp ? tmp : "removed all",
626 channel2->channel_name);
629 if (mode & SILC_CHANNEL_UMODE_CHANFO)
630 printformat_module("fe-common/silc",
631 server, channel->channel_name, MSGLEVEL_CRAP,
632 SILCTXT_CHANNEL_FOUNDER,
633 channel->channel_name, client_entry2->nickname);
635 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
636 printformat_module("fe-common/silc",
637 server, channel->channel_name, MSGLEVEL_CRAP,
638 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
643 case SILC_NOTIFY_TYPE_MOTD:
648 SILC_LOG_DEBUG(("Notify: MOTD"));
650 tmp = va_arg(va, char *);
652 if (!settings_get_bool("skip_motd"))
653 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
656 case SILC_NOTIFY_TYPE_KICKED:
658 * Someone was kicked from channel.
661 SILC_LOG_DEBUG(("Notify: KICKED"));
663 client_entry = va_arg(va, SilcClientEntry);
664 tmp = va_arg(va, char *);
665 client_entry2 = va_arg(va, SilcClientEntry);
666 channel = va_arg(va, SilcChannelEntry);
668 chanrec = silc_channel_find_entry(server, channel);
670 if (client_entry == conn->local_entry) {
671 printformat_module("fe-common/silc", server, channel->channel_name,
672 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
673 channel->channel_name,
674 client_entry ? client_entry2->nickname : "",
677 chanrec->kicked = TRUE;
678 channel_destroy((CHANNEL_REC *)chanrec);
681 printformat_module("fe-common/silc", server, channel->channel_name,
682 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
683 client_entry->nickname, channel->channel_name,
684 client_entry2 ? client_entry2->nickname : "",
688 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
690 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
695 case SILC_NOTIFY_TYPE_KILLED:
697 * Someone was killed from the network.
700 SILC_LOG_DEBUG(("Notify: KILLED"));
702 client_entry = va_arg(va, SilcClientEntry);
703 tmp = va_arg(va, char *);
704 idtype = va_arg(va, int);
705 entry = va_arg(va, SilcClientEntry);
707 if (client_entry == conn->local_entry) {
708 if (idtype == SILC_ID_CLIENT) {
709 client_entry2 = (SilcClientEntry)entry;
710 printformat_module("fe-common/silc", server, NULL,
711 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
712 client_entry2 ? client_entry2->nickname : "",
714 } else if (idtype == SILC_ID_SERVER) {
715 server_entry = (SilcServerEntry)entry;
716 printformat_module("fe-common/silc", server, NULL,
717 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
718 server_entry->server_name, tmp ? tmp : "");
719 } else if (idtype == SILC_ID_CHANNEL) {
720 channel = (SilcChannelEntry)entry;
721 printformat_module("fe-common/silc", server, NULL,
722 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
723 channel->channel_name, tmp ? tmp : "");
726 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
727 for (list_tmp = list1; list_tmp != NULL; list_tmp =
728 list_tmp->next->next) {
729 CHANNEL_REC *channel = list_tmp->data;
730 NICK_REC *nickrec = list_tmp->next->data;
731 nicklist_remove(channel, nickrec);
734 if (idtype == SILC_ID_CLIENT) {
735 client_entry2 = (SilcClientEntry)entry;
736 printformat_module("fe-common/silc", server, NULL,
737 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
738 client_entry->nickname,
739 client_entry2 ? client_entry2->nickname : "",
741 } else if (idtype == SILC_ID_SERVER) {
742 server_entry = (SilcServerEntry)entry;
743 printformat_module("fe-common/silc", server, NULL,
744 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
745 client_entry->nickname,
746 server_entry->server_name, tmp ? tmp : "");
747 } else if (idtype == SILC_ID_CHANNEL) {
748 channel = (SilcChannelEntry)entry;
749 printformat_module("fe-common/silc", server, NULL,
750 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
751 client_entry->nickname,
752 channel->channel_name, tmp ? tmp : "");
757 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
760 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
763 * Server has quit the network.
766 SilcClientEntry *clients;
767 SilcUInt32 clients_count;
769 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
771 (void)va_arg(va, void *);
772 clients = va_arg(va, SilcClientEntry *);
773 clients_count = va_arg(va, SilcUInt32);
775 for (i = 0; i < clients_count; i++) {
776 memset(buf, 0, sizeof(buf));
777 if (clients[i]->username)
778 snprintf(buf, sizeof(buf) - 1, "%s@%s",
779 clients[i]->username, clients[i]->hostname);
780 signal_emit("message quit", 4, server, clients[i]->nickname,
781 clients[i]->username ? buf : "",
784 silc_server_free_ftp(server, clients[i]);
786 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
787 for (list_tmp = list1; list_tmp != NULL; list_tmp =
788 list_tmp->next->next) {
789 CHANNEL_REC *channel = list_tmp->data;
790 NICK_REC *nickrec = list_tmp->next->data;
791 nicklist_remove(channel, nickrec);
797 case SILC_NOTIFY_TYPE_ERROR:
799 SilcStatus error = va_arg(va, int);
801 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
802 "%s", silc_get_status_message(error));
806 case SILC_NOTIFY_TYPE_WATCH:
808 SilcNotifyType notify;
810 client_entry = va_arg(va, SilcClientEntry);
811 name = va_arg(va, char *); /* Maybe NULL */
812 mode = va_arg(va, SilcUInt32);
813 notify = va_arg(va, int);
815 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
817 printformat_module("fe-common/silc", server, NULL,
818 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
819 client_entry->nickname, name);
821 printformat_module("fe-common/silc", server, NULL,
822 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
823 client_entry->nickname);
824 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
825 /* See if client was away and is now present */
826 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
827 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
828 SILC_UMODE_DETACHED)) &&
829 (client_entry->mode & SILC_UMODE_GONE ||
830 client_entry->mode & SILC_UMODE_INDISPOSED ||
831 client_entry->mode & SILC_UMODE_BUSY ||
832 client_entry->mode & SILC_UMODE_PAGE ||
833 client_entry->mode & SILC_UMODE_DETACHED)) {
834 printformat_module("fe-common/silc", server, NULL,
835 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
836 client_entry->nickname);
840 memset(buf, 0, sizeof(buf));
841 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
842 printformat_module("fe-common/silc", server, NULL,
843 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
844 client_entry->nickname, buf);
846 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
847 printformat_module("fe-common/silc", server, NULL,
848 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
849 client_entry->nickname);
850 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
851 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
852 printformat_module("fe-common/silc", server, NULL,
853 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
854 client_entry->nickname);
855 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
856 /* Client logged in to the network */
857 printformat_module("fe-common/silc", server, NULL,
858 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
859 client_entry->nickname);
866 printformat_module("fe-common/silc", server, NULL,
867 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
874 /* Called to indicate that connection was either successfully established
875 or connecting failed. This is also the first time application receives
876 the SilcClientConnection object which it should save somewhere. */
878 void silc_connect(SilcClient client, SilcClientConnection conn,
879 SilcClientConnectionStatus status)
881 SILC_SERVER_REC *server = conn->context;
883 if (!server || server->disconnected) {
884 silc_client_close_connection(client, conn);
889 case SILC_CLIENT_CONN_SUCCESS:
890 /* We have successfully connected to server */
891 server->connected = TRUE;
892 signal_emit("event connected", 1, server);
895 case SILC_CLIENT_CONN_SUCCESS_RESUME:
896 /* We have successfully resumed old detached session */
897 server->connected = TRUE;
898 signal_emit("event connected", 1, server);
900 /* If we resumed old session check whether we need to update
902 if (strcmp(server->nick, conn->local_entry->nickname)) {
904 old = g_strdup(server->nick);
905 server_change_nick(SERVER(server), conn->local_entry->nickname);
906 nicklist_rename_unique(SERVER(server),
907 conn->local_entry, server->nick,
908 conn->local_entry, conn->local_entry->nickname);
909 signal_emit("message own_nick", 4, server, server->nick, old, "");
915 server->connection_lost = TRUE;
917 server->conn->context = NULL;
918 server_disconnect(SERVER(server));
923 /* Called to indicate that connection was disconnected to the server. */
925 void silc_disconnect(SilcClient client, SilcClientConnection conn,
926 SilcStatus status, const char *message)
928 SILC_SERVER_REC *server = conn->context;
930 SILC_LOG_DEBUG(("Start"));
932 if (!server || server->connection_lost)
935 if (server->conn && server->conn->local_entry) {
936 nicklist_rename_unique(SERVER(server),
937 server->conn->local_entry, server->nick,
938 server->conn->local_entry,
939 silc_client->username);
940 silc_change_nick(server, silc_client->username);
944 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
945 "Server closed connection: %s (%d) %s",
946 silc_get_status_message(status), status,
947 message ? message : "");
949 server->conn->context = NULL;
951 server->connection_lost = TRUE;
952 server_disconnect(SERVER(server));
955 /* Command handler. This function is called always in the command function.
956 If error occurs it will be called as well. `conn' is the associated
957 client connection. `cmd_context' is the command context that was
958 originally sent to the command. `success' is FALSE if error occured
959 during command. `command' is the command being processed. It must be
960 noted that this is not reply from server. This is merely called just
961 after application has called the command. Just to tell application
962 that the command really was processed. */
964 void silc_command(SilcClient client, SilcClientConnection conn,
965 SilcClientCommandContext cmd_context, bool success,
966 SilcCommand command, SilcStatus status)
968 SILC_SERVER_REC *server = conn->context;
970 SILC_LOG_DEBUG(("Start"));
973 silc_say_error("%s", silc_get_status_message(status));
979 case SILC_COMMAND_INVITE:
980 if (cmd_context->argc > 2)
981 printformat_module("fe-common/silc", server, NULL,
982 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
983 cmd_context->argv[2],
984 (cmd_context->argv[1][0] == '*' ?
985 (char *)conn->current_channel->channel_name :
986 (char *)cmd_context->argv[1]));
989 case SILC_COMMAND_DETACH:
990 server->no_reconnect = TRUE;
998 /* Client info resolving callback when JOIN command reply is received.
999 This will cache all users on the channel. */
1001 static void silc_client_join_get_users(SilcClient client,
1002 SilcClientConnection conn,
1003 SilcClientEntry *clients,
1004 SilcUInt32 clients_count,
1007 SilcChannelEntry channel = (SilcChannelEntry)context;
1008 SilcHashTableList htl;
1009 SilcChannelUser chu;
1010 SILC_SERVER_REC *server = conn->context;
1011 SILC_CHANNEL_REC *chanrec;
1012 SilcClientEntry founder = NULL;
1015 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1016 silc_hash_table_count(channel->user_list)));
1021 chanrec = silc_channel_find(server, channel->channel_name);
1022 if (chanrec == NULL)
1025 silc_hash_table_list(channel->user_list, &htl);
1026 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1027 if (!chu->client->nickname)
1029 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1030 founder = chu->client;
1031 silc_nicklist_insert(chanrec, chu, FALSE);
1033 silc_hash_table_list_reset(&htl);
1035 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1036 nicklist_set_own(CHANNEL(chanrec), ownnick);
1037 signal_emit("channel joined", 1, chanrec);
1038 chanrec->entry = channel;
1041 printformat_module("fe-common/silc", server, channel->channel_name,
1042 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1043 channel->channel_name, chanrec->topic);
1046 if (founder == conn->local_entry)
1047 printformat_module("fe-common/silc",
1048 server, channel->channel_name, MSGLEVEL_CRAP,
1049 SILCTXT_CHANNEL_FOUNDER_YOU,
1050 channel->channel_name);
1052 printformat_module("fe-common/silc",
1053 server, channel->channel_name, MSGLEVEL_CRAP,
1054 SILCTXT_CHANNEL_FOUNDER,
1055 channel->channel_name, founder->nickname);
1061 SilcClientConnection conn;
1067 void silc_getkey_cb(bool success, void *context)
1069 GetkeyContext getkey = (GetkeyContext)context;
1070 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1071 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1072 ((SilcClientEntry)getkey->entry)->nickname :
1073 ((SilcServerEntry)getkey->entry)->server_name);
1076 printformat_module("fe-common/silc", NULL, NULL,
1077 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1079 printformat_module("fe-common/silc", NULL, NULL,
1080 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1084 silc_free(getkey->fingerprint);
1088 /* Command reply handler. This function is called always in the command reply
1089 function. If error occurs it will be called as well. Normal scenario
1090 is that it will be called after the received command data has been parsed
1091 and processed. The function is used to pass the received command data to
1094 `conn' is the associated client connection. `cmd_payload' is the command
1095 payload data received from server and it can be ignored. It is provided
1096 if the application would like to re-parse the received command data,
1097 however, it must be noted that the data is parsed already by the library
1098 thus the payload can be ignored. `success' is FALSE if error occured.
1099 In this case arguments are not sent to the application. `command' is the
1100 command reply being processed. The function has variable argument list
1101 and each command defines the number and type of arguments it passes to the
1102 application (on error they are not sent). */
1105 silc_command_reply(SilcClient client, SilcClientConnection conn,
1106 SilcCommandPayload cmd_payload, bool success,
1107 SilcCommand command, SilcStatus status, ...)
1110 SILC_SERVER_REC *server = conn->context;
1111 SILC_CHANNEL_REC *chanrec;
1114 va_start(vp, status);
1116 SILC_LOG_DEBUG(("Start"));
1119 case SILC_COMMAND_WHOIS:
1121 char buf[1024], *nickname, *username, *realname, *nick;
1122 unsigned char *fingerprint;
1123 SilcUInt32 idle, mode;
1124 SilcBuffer channels, user_modes;
1125 SilcClientEntry client_entry;
1128 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1129 /* Print the unknown nick for user */
1130 unsigned char *tmp =
1131 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1134 silc_say_error("%s: %s", tmp,
1135 silc_get_status_message(status));
1137 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1138 /* Try to find the entry for the unknown client ID, since we
1139 might have, and print the nickname of it for user. */
1141 unsigned char *tmp =
1142 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1145 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1148 client_entry = silc_client_get_client_by_id(client, conn,
1150 if (client_entry && client_entry->nickname)
1151 silc_say_error("%s: %s", client_entry->nickname,
1152 silc_get_status_message(status));
1153 silc_free(client_id);
1157 } else if (!success) {
1158 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1162 client_entry = va_arg(vp, SilcClientEntry);
1163 nickname = va_arg(vp, char *);
1164 username = va_arg(vp, char *);
1165 realname = va_arg(vp, char *);
1166 channels = va_arg(vp, SilcBuffer);
1167 mode = va_arg(vp, SilcUInt32);
1168 idle = va_arg(vp, SilcUInt32);
1169 fingerprint = va_arg(vp, unsigned char *);
1170 user_modes = va_arg(vp, SilcBuffer);
1171 attrs = va_arg(vp, SilcDList);
1173 silc_parse_userfqdn(nickname, &nick, NULL);
1174 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1175 SILCTXT_WHOIS_USERINFO, nickname,
1176 client_entry->username, client_entry->hostname,
1177 nick, client_entry->nickname);
1178 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1179 SILCTXT_WHOIS_REALNAME, realname);
1182 if (channels && user_modes) {
1184 SilcDList list = silc_channel_payload_parse_list(channels->data,
1186 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1188 SilcChannelPayload entry;
1191 memset(buf, 0, sizeof(buf));
1192 silc_dlist_start(list);
1193 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1194 SilcUInt32 name_len;
1195 char *m = silc_client_chumode_char(umodes[i++]);
1196 char *name = silc_channel_get_name(entry, &name_len);
1199 strncat(buf, m, strlen(m));
1200 strncat(buf, name, name_len);
1201 strncat(buf, " ", 1);
1205 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1206 SILCTXT_WHOIS_CHANNELS, buf);
1207 silc_channel_payload_list_free(list);
1213 memset(buf, 0, sizeof(buf));
1214 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1215 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1216 SILCTXT_WHOIS_MODES, buf);
1219 if (idle && nickname) {
1220 memset(buf, 0, sizeof(buf));
1221 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1222 idle > 60 ? (idle / 60) : idle,
1223 idle > 60 ? "minutes" : "seconds");
1225 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1226 SILCTXT_WHOIS_IDLE, buf);
1230 fingerprint = silc_fingerprint(fingerprint, 20);
1231 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1232 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1233 silc_free(fingerprint);
1237 silc_query_attributes_print(server, silc_client, conn, attrs,
1242 case SILC_COMMAND_IDENTIFY:
1244 SilcClientEntry client_entry;
1246 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1247 /* Print the unknown nick for user */
1248 unsigned char *tmp =
1249 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1252 silc_say_error("%s: %s", tmp,
1253 silc_get_status_message(status));
1255 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1256 /* Try to find the entry for the unknown client ID, since we
1257 might have, and print the nickname of it for user. */
1259 unsigned char *tmp =
1260 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1263 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1266 client_entry = silc_client_get_client_by_id(client, conn,
1268 if (client_entry && client_entry->nickname)
1269 silc_say_error("%s: %s", client_entry->nickname,
1270 silc_get_status_message(status));
1271 silc_free(client_id);
1280 case SILC_COMMAND_WHOWAS:
1282 char *nickname, *username, *realname;
1284 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1285 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1287 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1290 silc_say_error("%s: %s", tmp,
1291 silc_get_status_message(status));
1293 } else if (!success) {
1294 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1298 (void)va_arg(vp, SilcClientEntry);
1299 nickname = va_arg(vp, char *);
1300 username = va_arg(vp, char *);
1301 realname = va_arg(vp, char *);
1303 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1304 SILCTXT_WHOWAS_USERINFO, nickname, username,
1305 realname ? realname : "");
1309 case SILC_COMMAND_INVITE:
1311 SilcChannelEntry channel;
1313 SilcArgumentPayload args;
1319 channel = va_arg(vp, SilcChannelEntry);
1320 invite_list = va_arg(vp, char *);
1322 args = silc_command_get_args(cmd_payload);
1324 argc = silc_argument_get_arg_num(args);
1327 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1328 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1331 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1332 SILCTXT_CHANNEL_NO_INVITE_LIST,
1333 channel->channel_name);
1337 case SILC_COMMAND_JOIN:
1339 char *channel, *mode, *topic;
1341 SilcChannelEntry channel_entry;
1342 SilcBuffer client_id_list;
1343 SilcUInt32 list_count;
1348 channel = va_arg(vp, char *);
1349 channel_entry = va_arg(vp, SilcChannelEntry);
1350 modei = va_arg(vp, SilcUInt32);
1351 (void)va_arg(vp, SilcUInt32);
1352 (void)va_arg(vp, unsigned char *);
1353 (void)va_arg(vp, unsigned char *);
1354 (void)va_arg(vp, unsigned char *);
1355 topic = va_arg(vp, char *);
1356 (void)va_arg(vp, unsigned char *);
1357 list_count = va_arg(vp, SilcUInt32);
1358 client_id_list = va_arg(vp, SilcBuffer);
1360 chanrec = silc_channel_find(server, channel);
1362 chanrec = silc_channel_create(server, channel, channel, TRUE);
1365 g_free_not_null(chanrec->topic);
1366 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1367 signal_emit("channel topic changed", 1, chanrec);
1370 mode = silc_client_chmode(modei,
1371 channel_entry->channel_key ?
1372 silc_cipher_get_name(channel_entry->
1374 channel_entry->hmac ?
1375 silc_hmac_get_name(channel_entry->hmac) : "");
1376 g_free_not_null(chanrec->mode);
1377 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1378 signal_emit("channel mode changed", 1, chanrec);
1380 /* Resolve the client information */
1381 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1382 silc_client_join_get_users,
1388 case SILC_COMMAND_NICK:
1391 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1397 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1398 if (nicks != NULL) {
1400 SilcClientEntry collider, old;
1402 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1403 collider = silc_client_get_client_by_id(client, conn,
1406 memset(buf, 0, sizeof(buf));
1407 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1408 collider->username, collider->hostname);
1409 nicklist_rename_unique(SERVER(server),
1411 collider, collider->nickname);
1412 silc_print_nick_change(server, collider->nickname,
1413 client_entry->nickname, buf);
1414 g_slist_free(nicks);
1417 old = g_strdup(server->nick);
1418 server_change_nick(SERVER(server), client_entry->nickname);
1419 nicklist_rename_unique(SERVER(server),
1420 server->conn->local_entry, server->nick,
1421 client_entry, client_entry->nickname);
1422 signal_emit("message own_nick", 4, server, server->nick, old, "");
1427 case SILC_COMMAND_LIST:
1432 char tmp[256], *cp, *dm = NULL;
1437 (void)va_arg(vp, SilcChannelEntry);
1438 name = va_arg(vp, char *);
1439 topic = va_arg(vp, char *);
1440 usercount = va_arg(vp, int);
1442 if (topic && !silc_term_utf8() &&
1443 silc_utf8_valid(topic, strlen(topic))) {
1444 memset(tmp, 0, sizeof(tmp));
1446 if (strlen(topic) > sizeof(tmp) - 1) {
1447 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1451 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1456 if (status == SILC_STATUS_LIST_START ||
1457 status == SILC_STATUS_OK)
1458 printformat_module("fe-common/silc", server, NULL,
1459 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1462 snprintf(users, sizeof(users) - 1, "N/A");
1464 snprintf(users, sizeof(users) - 1, "%d", usercount);
1465 printformat_module("fe-common/silc", server, NULL,
1466 MSGLEVEL_CRAP, SILCTXT_LIST,
1467 name, users, topic ? topic : "");
1472 case SILC_COMMAND_UMODE:
1480 mode = va_arg(vp, SilcUInt32);
1482 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1483 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1484 printformat_module("fe-common/silc", server, NULL,
1485 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1487 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1488 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1489 printformat_module("fe-common/silc", server, NULL,
1490 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1492 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1493 if (mode & SILC_UMODE_GONE) {
1494 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1495 reason = g_strdup(server->away_reason);
1497 reason = g_strdup("away");
1499 reason = g_strdup("");
1501 silc_set_away(reason, server);
1506 server->umode = mode;
1507 signal_emit("user mode changed", 2, server, NULL);
1511 case SILC_COMMAND_OPER:
1515 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1516 signal_emit("user mode changed", 2, server, NULL);
1518 printformat_module("fe-common/silc", server, NULL,
1519 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1522 case SILC_COMMAND_SILCOPER:
1526 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1527 signal_emit("user mode changed", 2, server, NULL);
1529 printformat_module("fe-common/silc", server, NULL,
1530 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1533 case SILC_COMMAND_USERS:
1535 SilcHashTableList htl;
1536 SilcChannelEntry channel;
1537 SilcChannelUser chu;
1542 channel = va_arg(vp, SilcChannelEntry);
1544 printformat_module("fe-common/silc", server, channel->channel_name,
1545 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1546 channel->channel_name);
1548 silc_hash_table_list(channel->user_list, &htl);
1549 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1550 SilcClientEntry e = chu->client;
1551 char stat[5], *mode;
1556 memset(stat, 0, sizeof(stat));
1557 mode = silc_client_chumode_char(chu->mode);
1558 if (e->mode & SILC_UMODE_GONE)
1560 else if (e->mode & SILC_UMODE_INDISPOSED)
1562 else if (e->mode & SILC_UMODE_BUSY)
1564 else if (e->mode & SILC_UMODE_PAGE)
1566 else if (e->mode & SILC_UMODE_HYPER)
1568 else if (e->mode & SILC_UMODE_ROBOT)
1570 else if (e->mode & SILC_UMODE_ANONYMOUS)
1577 printformat_module("fe-common/silc", server, channel->channel_name,
1578 MSGLEVEL_CRAP, SILCTXT_USERS,
1580 e->username ? e->username : "",
1581 e->hostname ? e->hostname : "",
1582 e->realname ? e->realname : "");
1586 silc_hash_table_list_reset(&htl);
1590 case SILC_COMMAND_BAN:
1592 SilcChannelEntry channel;
1598 channel = va_arg(vp, SilcChannelEntry);
1599 ban_list = va_arg(vp, char *);
1602 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1603 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1606 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1607 SILCTXT_CHANNEL_NO_BAN_LIST,
1608 channel->channel_name);
1612 case SILC_COMMAND_GETKEY:
1616 SilcPublicKey public_key;
1619 GetkeyContext getkey;
1625 id_type = va_arg(vp, SilcUInt32);
1626 entry = va_arg(vp, void *);
1627 public_key = va_arg(vp, SilcPublicKey);
1630 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1632 getkey = silc_calloc(1, sizeof(*getkey));
1633 getkey->entry = entry;
1634 getkey->id_type = id_type;
1635 getkey->client = client;
1636 getkey->conn = conn;
1637 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1639 name = (id_type == SILC_ID_CLIENT ?
1640 ((SilcClientEntry)entry)->nickname :
1641 ((SilcServerEntry)entry)->server_name);
1643 silc_verify_public_key_internal(client, conn, name,
1644 (id_type == SILC_ID_CLIENT ?
1645 SILC_SOCKET_TYPE_CLIENT :
1646 SILC_SOCKET_TYPE_SERVER),
1647 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1648 silc_getkey_cb, getkey);
1651 printformat_module("fe-common/silc", server, NULL,
1652 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1657 case SILC_COMMAND_INFO:
1659 SilcServerEntry server_entry;
1666 server_entry = va_arg(vp, SilcServerEntry);
1667 server_name = va_arg(vp, char *);
1668 server_info = va_arg(vp, char *);
1670 if (server_name && server_info )
1672 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1673 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1678 case SILC_COMMAND_TOPIC:
1680 SilcChannelEntry channel;
1682 char tmp[256], *cp, *dm = NULL;
1687 channel = va_arg(vp, SilcChannelEntry);
1688 topic = va_arg(vp, char *);
1690 if (topic && !silc_term_utf8() &&
1691 silc_utf8_valid(topic, strlen(topic))) {
1692 memset(tmp, 0, sizeof(tmp));
1694 if (strlen(topic) > sizeof(tmp) - 1) {
1695 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1699 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1705 chanrec = silc_channel_find_entry(server, channel);
1707 g_free_not_null(chanrec->topic);
1708 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1709 signal_emit("channel topic changed", 1, chanrec);
1711 printformat_module("fe-common/silc", server, channel->channel_name,
1712 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1713 channel->channel_name, topic);
1715 printformat_module("fe-common/silc", server, channel->channel_name,
1716 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1717 channel->channel_name);
1723 case SILC_COMMAND_WATCH:
1726 case SILC_COMMAND_STATS:
1728 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1729 my_router_ops, cell_clients, cell_channels, cell_servers,
1730 clients, channels, servers, routers, server_ops, router_ops;
1732 SilcBufferStruct buf;
1733 unsigned char *tmp_buf;
1735 const char *tmptime;
1736 int days, hours, mins, secs;
1741 tmp_buf = va_arg(vp, unsigned char *);
1742 buf_len = va_arg(vp, SilcUInt32);
1744 if (!tmp_buf || !buf_len) {
1745 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
1749 /* Get statistics structure */
1750 silc_buffer_set(&buf, tmp_buf, buf_len);
1751 silc_buffer_unformat(&buf,
1752 SILC_STR_UI_INT(&starttime),
1753 SILC_STR_UI_INT(&uptime),
1754 SILC_STR_UI_INT(&my_clients),
1755 SILC_STR_UI_INT(&my_channels),
1756 SILC_STR_UI_INT(&my_server_ops),
1757 SILC_STR_UI_INT(&my_router_ops),
1758 SILC_STR_UI_INT(&cell_clients),
1759 SILC_STR_UI_INT(&cell_channels),
1760 SILC_STR_UI_INT(&cell_servers),
1761 SILC_STR_UI_INT(&clients),
1762 SILC_STR_UI_INT(&channels),
1763 SILC_STR_UI_INT(&servers),
1764 SILC_STR_UI_INT(&routers),
1765 SILC_STR_UI_INT(&server_ops),
1766 SILC_STR_UI_INT(&router_ops),
1769 tmptime = silc_get_time(starttime);
1770 printformat_module("fe-common/silc", server, NULL,
1771 MSGLEVEL_CRAP, SILCTXT_STATS,
1772 "Local server start time", tmptime);
1774 days = uptime / (24 * 60 * 60);
1775 uptime -= days * (24 * 60 * 60);
1776 hours = uptime / (60 * 60);
1777 uptime -= hours * (60 * 60);
1779 uptime -= mins * 60;
1781 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
1782 days, hours, mins, secs);
1783 printformat_module("fe-common/silc", server, NULL,
1784 MSGLEVEL_CRAP, SILCTXT_STATS,
1785 "Local server uptime", tmp);
1787 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
1788 printformat_module("fe-common/silc", server, NULL,
1789 MSGLEVEL_CRAP, SILCTXT_STATS,
1790 "Local server clients", tmp);
1792 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
1793 printformat_module("fe-common/silc", server, NULL,
1794 MSGLEVEL_CRAP, SILCTXT_STATS,
1795 "Local server channels", tmp);
1797 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
1798 printformat_module("fe-common/silc", server, NULL,
1799 MSGLEVEL_CRAP, SILCTXT_STATS,
1800 "Local server operators", tmp);
1802 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
1803 printformat_module("fe-common/silc", server, NULL,
1804 MSGLEVEL_CRAP, SILCTXT_STATS,
1805 "Local router operators", tmp);
1807 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
1808 printformat_module("fe-common/silc", server, NULL,
1809 MSGLEVEL_CRAP, SILCTXT_STATS,
1810 "Local cell clients", tmp);
1812 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
1813 printformat_module("fe-common/silc", server, NULL,
1814 MSGLEVEL_CRAP, SILCTXT_STATS,
1815 "Local cell channels", tmp);
1817 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
1818 printformat_module("fe-common/silc", server, NULL,
1819 MSGLEVEL_CRAP, SILCTXT_STATS,
1820 "Local cell servers", tmp);
1822 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
1823 printformat_module("fe-common/silc", server, NULL,
1824 MSGLEVEL_CRAP, SILCTXT_STATS,
1825 "Total clients", tmp);
1827 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
1828 printformat_module("fe-common/silc", server, NULL,
1829 MSGLEVEL_CRAP, SILCTXT_STATS,
1830 "Total channels", tmp);
1832 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
1833 printformat_module("fe-common/silc", server, NULL,
1834 MSGLEVEL_CRAP, SILCTXT_STATS,
1835 "Total servers", tmp);
1837 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
1838 printformat_module("fe-common/silc", server, NULL,
1839 MSGLEVEL_CRAP, SILCTXT_STATS,
1840 "Total routers", tmp);
1842 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
1843 printformat_module("fe-common/silc", server, NULL,
1844 MSGLEVEL_CRAP, SILCTXT_STATS,
1845 "Total server operators", tmp);
1847 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
1848 printformat_module("fe-common/silc", server, NULL,
1849 MSGLEVEL_CRAP, SILCTXT_STATS,
1850 "Total router operators", tmp);
1861 SilcClientConnection conn;
1867 SilcSKEPKType pk_type;
1868 SilcVerifyPublicKey completion;
1872 static void verify_public_key_completion(const char *line, void *context)
1874 PublicKeyVerify verify = (PublicKeyVerify)context;
1876 if (line[0] == 'Y' || line[0] == 'y') {
1877 /* Call the completion */
1878 if (verify->completion)
1879 verify->completion(TRUE, verify->context);
1881 /* Save the key for future checking */
1882 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1883 verify->pk_len, SILC_PKCS_FILE_PEM);
1885 /* Call the completion */
1886 if (verify->completion)
1887 verify->completion(FALSE, verify->context);
1889 printformat_module("fe-common/silc", NULL, NULL,
1890 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1891 verify->entity_name ? verify->entity_name :
1895 silc_free(verify->filename);
1896 silc_free(verify->entity);
1897 silc_free(verify->entity_name);
1898 silc_free(verify->pk);
1902 /* Internal routine to verify public key. If the `completion' is provided
1903 it will be called to indicate whether public was verified or not. For
1904 server/router public key this will check for filename that includes the
1905 remote host's IP address and remote host's hostname. */
1908 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1909 const char *name, SilcSocketType conn_type,
1910 unsigned char *pk, SilcUInt32 pk_len,
1911 SilcSKEPKType pk_type,
1912 SilcVerifyPublicKey completion, void *context)
1915 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1916 char *fingerprint, *babbleprint, *format;
1919 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1920 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1921 "server" : "client");
1922 PublicKeyVerify verify;
1924 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1925 printformat_module("fe-common/silc", NULL, NULL,
1926 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1929 completion(FALSE, context);
1933 pw = getpwuid(getuid());
1936 completion(FALSE, context);
1940 memset(filename, 0, sizeof(filename));
1941 memset(filename2, 0, sizeof(filename2));
1942 memset(file, 0, sizeof(file));
1944 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1945 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1947 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1948 conn->sock->ip, conn->sock->port);
1949 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1950 get_irssi_dir(), entity, file);
1952 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1953 conn->sock->hostname, conn->sock->port);
1954 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1955 get_irssi_dir(), entity, file);
1960 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1961 name, conn->sock->port);
1962 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1963 get_irssi_dir(), entity, file);
1968 /* Replace all whitespaces with `_'. */
1969 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1970 for (i = 0; i < strlen(fingerprint); i++)
1971 if (fingerprint[i] == ' ')
1972 fingerprint[i] = '_';
1974 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1975 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1976 get_irssi_dir(), entity, file);
1977 silc_free(fingerprint);
1982 /* Take fingerprint of the public key */
1983 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1984 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1986 verify = silc_calloc(1, sizeof(*verify));
1987 verify->client = client;
1988 verify->conn = conn;
1989 verify->filename = strdup(ipf);
1990 verify->entity = strdup(entity);
1991 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1992 (name ? strdup(name) : strdup(conn->sock->hostname))
1994 verify->pk = silc_memdup(pk, pk_len);
1995 verify->pk_len = pk_len;
1996 verify->pk_type = pk_type;
1997 verify->completion = completion;
1998 verify->context = context;
2000 /* Check whether this key already exists */
2001 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2002 /* Key does not exist, ask user to verify the key and save it */
2004 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2005 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2006 verify->entity_name : entity);
2007 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2008 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2009 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2010 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2011 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2012 SILCTXT_PUBKEY_ACCEPT);
2013 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2016 silc_free(fingerprint);
2019 /* The key already exists, verify it. */
2020 SilcPublicKey public_key;
2021 unsigned char *encpk;
2022 SilcUInt32 encpk_len;
2024 /* Load the key file, try for both IP filename and hostname filename */
2025 if (!silc_pkcs_load_public_key(ipf, &public_key,
2026 SILC_PKCS_FILE_PEM) &&
2027 !silc_pkcs_load_public_key(ipf, &public_key,
2028 SILC_PKCS_FILE_BIN) &&
2029 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2030 SILC_PKCS_FILE_PEM) &&
2031 !silc_pkcs_load_public_key(hostf, &public_key,
2032 SILC_PKCS_FILE_BIN)))) {
2033 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2034 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2035 verify->entity_name : entity);
2036 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2037 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2038 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2039 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2040 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2041 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2042 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2043 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2044 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2047 silc_free(fingerprint);
2051 /* Encode the key data */
2052 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2054 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2055 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2056 verify->entity_name : entity);
2057 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2058 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2059 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2060 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2061 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2062 SILCTXT_PUBKEY_MALFORMED, entity);
2063 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2064 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2065 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2068 silc_free(fingerprint);
2072 /* Compare the keys */
2073 if (memcmp(encpk, pk, encpk_len)) {
2074 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2075 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2076 verify->entity_name : entity);
2077 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2078 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2079 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2080 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2081 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2082 SILCTXT_PUBKEY_NO_MATCH, entity);
2083 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2084 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2085 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2086 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2088 /* Ask user to verify the key and save it */
2089 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2090 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2091 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2094 silc_free(fingerprint);
2098 /* Local copy matched */
2100 completion(TRUE, context);
2101 silc_free(fingerprint);
2102 silc_free(verify->filename);
2103 silc_free(verify->entity);
2104 silc_free(verify->entity_name);
2105 silc_free(verify->pk);
2110 /* Verifies received public key. The `conn_type' indicates which entity
2111 (server, client etc.) has sent the public key. If user decides to trust
2112 the key may be saved as trusted public key for later use. The
2113 `completion' must be called after the public key has been verified. */
2116 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2117 SilcSocketType conn_type, unsigned char *pk,
2118 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2119 SilcVerifyPublicKey completion, void *context)
2121 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2123 completion, context);
2126 /* Asks passphrase from user on the input line. */
2129 SilcAskPassphrase completion;
2133 void ask_passphrase_completion(const char *passphrase, void *context)
2135 AskPassphrase p = (AskPassphrase)context;
2136 if (passphrase && passphrase[0] == '\0')
2138 p->completion((unsigned char *)passphrase,
2139 passphrase ? strlen(passphrase) : 0, p->context);
2143 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2144 SilcAskPassphrase completion, void *context)
2146 AskPassphrase p = silc_calloc(1, sizeof(*p));
2147 p->completion = completion;
2148 p->context = context;
2150 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2151 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2155 SilcGetAuthMeth completion;
2157 } *InternalGetAuthMethod;
2159 /* Callback called when we've received the authentication method information
2160 from the server after we've requested it. This will get the authentication
2161 data from the user if needed. */
2163 static void silc_get_auth_method_callback(SilcClient client,
2164 SilcClientConnection conn,
2165 SilcAuthMethod auth_meth,
2168 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2170 SILC_LOG_DEBUG(("Start"));
2172 switch (auth_meth) {
2173 case SILC_AUTH_NONE:
2174 /* No authentication required. */
2175 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2177 case SILC_AUTH_PASSWORD:
2179 /* Check whether we find the password for this server in our
2180 configuration. If not, then don't provide so library will ask
2181 it from the user. */
2182 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2184 if (!setup || !setup->password) {
2185 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2189 (*internal->completion)(TRUE, auth_meth, setup->password,
2190 strlen(setup->password), internal->context);
2193 case SILC_AUTH_PUBLIC_KEY:
2194 /* Do not get the authentication data now, the library will generate
2195 it using our default key, if we do not provide it here. */
2196 /* XXX In the future when we support multiple local keys and multiple
2197 local certificates we will need to ask from user which one to use. */
2198 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2202 silc_free(internal);
2205 /* Find authentication method and authentication data by hostname and
2206 port. The hostname may be IP address as well. The found authentication
2207 method and authentication data is returned to `auth_meth', `auth_data'
2208 and `auth_data_len'. The function returns TRUE if authentication method
2209 is found and FALSE if not. `conn' may be NULL. */
2211 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2212 char *hostname, SilcUInt16 port,
2213 SilcGetAuthMeth completion, void *context)
2215 InternalGetAuthMethod internal;
2217 SILC_LOG_DEBUG(("Start"));
2219 /* If we do not have this connection configured by the user in a
2220 configuration file then resolve the authentication method from the
2221 server for this session. */
2222 internal = silc_calloc(1, sizeof(*internal));
2223 internal->completion = completion;
2224 internal->context = context;
2226 silc_client_request_authentication_method(client, conn,
2227 silc_get_auth_method_callback,
2231 /* Notifies application that failure packet was received. This is called
2232 if there is some protocol active in the client. The `protocol' is the
2233 protocol context. The `failure' is opaque pointer to the failure
2234 indication. Note, that the `failure' is protocol dependant and application
2235 must explicitly cast it to correct type. Usually `failure' is 32 bit
2236 failure type (see protocol specs for all protocol failure types). */
2238 void silc_failure(SilcClient client, SilcClientConnection conn,
2239 SilcProtocol protocol, void *failure)
2241 SILC_LOG_DEBUG(("Start"));
2243 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2244 SilcSKEStatus status = (SilcSKEStatus)failure;
2246 if (status == SILC_SKE_STATUS_BAD_VERSION)
2247 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2248 SILCTXT_KE_BAD_VERSION);
2249 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2250 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2251 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2252 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2253 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2254 SILCTXT_KE_UNKNOWN_GROUP);
2255 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2256 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2257 SILCTXT_KE_UNKNOWN_CIPHER);
2258 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2259 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2260 SILCTXT_KE_UNKNOWN_PKCS);
2261 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2262 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2263 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2264 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2265 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2266 SILCTXT_KE_UNKNOWN_HMAC);
2267 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2268 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2269 SILCTXT_KE_INCORRECT_SIGNATURE);
2270 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2271 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2272 SILCTXT_KE_INVALID_COOKIE);
2275 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2276 SilcUInt32 err = (SilcUInt32)failure;
2278 if (err == SILC_AUTH_FAILED)
2279 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2280 SILCTXT_AUTH_FAILED);
2284 /* Asks whether the user would like to perform the key agreement protocol.
2285 This is called after we have received an key agreement packet or an
2286 reply to our key agreement packet. This returns TRUE if the user wants
2287 the library to perform the key agreement protocol and FALSE if it is not
2288 desired (application may start it later by calling the function
2289 silc_client_perform_key_agreement). */
2291 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2292 SilcClientEntry client_entry, const char *hostname,
2293 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2298 SILC_LOG_DEBUG(("Start"));
2300 /* We will just display the info on the screen and return FALSE and user
2301 will have to start the key agreement with a command. */
2304 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2307 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2308 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2310 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2311 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2312 client_entry->nickname, hostname, portstr);
2320 /* Notifies application that file transfer protocol session is being
2321 requested by the remote client indicated by the `client_entry' from
2322 the `hostname' and `port'. The `session_id' is the file transfer
2323 session and it can be used to either accept or reject the file
2324 transfer request, by calling the silc_client_file_receive or
2325 silc_client_file_close, respectively. */
2327 void silc_ftp(SilcClient client, SilcClientConnection conn,
2328 SilcClientEntry client_entry, SilcUInt32 session_id,
2329 const char *hostname, SilcUInt16 port)
2331 SILC_SERVER_REC *server;
2333 FtpSession ftp = NULL;
2335 SILC_LOG_DEBUG(("Start"));
2337 server = conn->context;
2339 silc_dlist_start(server->ftp_sessions);
2340 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2341 if (ftp->client_entry == client_entry &&
2342 ftp->session_id == session_id) {
2343 server->current_session = ftp;
2347 if (ftp == SILC_LIST_END) {
2348 ftp = silc_calloc(1, sizeof(*ftp));
2349 ftp->client_entry = client_entry;
2350 ftp->session_id = session_id;
2353 silc_dlist_add(server->ftp_sessions, ftp);
2354 server->current_session = ftp;
2358 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2361 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2362 SILCTXT_FILE_REQUEST, client_entry->nickname);
2364 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2365 SILCTXT_FILE_REQUEST_HOST,
2366 client_entry->nickname, hostname, portstr);
2369 /* Delivers SILC session detachment data indicated by `detach_data' to the
2370 application. If application has issued SILC_COMMAND_DETACH command
2371 the client session in the SILC network is not quit. The client remains
2372 in the network but is detached. The detachment data may be used later
2373 to resume the session in the SILC Network. The appliation is
2374 responsible of saving the `detach_data', to for example in a file.
2376 The detachment data can be given as argument to the functions
2377 silc_client_connect_to_server, or silc_client_add_connection when
2378 creating connection to remote server, inside SilcClientConnectionParams
2379 structure. If it is provided the client library will attempt to resume
2380 the session in the network. After the connection is created
2381 successfully, the application is responsible of setting the user
2382 interface for user into the same state it was before detaching (showing
2383 same channels, channel modes, etc). It can do this by fetching the
2384 information (like joined channels) from the client library. */
2387 silc_detach(SilcClient client, SilcClientConnection conn,
2388 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2392 /* Save the detachment data to file. */
2394 memset(file, 0, sizeof(file));
2395 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2396 silc_file_writefile(file, detach_data, detach_data_len);
2400 /* SILC client operations */
2401 SilcClientOperations ops = {
2403 silc_channel_message,
2404 silc_private_message,
2410 silc_get_auth_method,
2411 silc_verify_public_key,
2412 silc_ask_passphrase,