5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
44 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
45 const char *name, SilcSocketType conn_type,
46 unsigned char *pk, SilcUInt32 pk_len,
47 SilcSKEPKType pk_type,
48 SilcVerifyPublicKey completion, void *context);
50 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
53 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
54 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
55 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
57 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
58 "[SILC operator]" : "[unknown mode]");
60 if (mode & SILC_UMODE_GONE)
61 strcat(buf, " [away]");
62 if (mode & SILC_UMODE_INDISPOSED)
63 strcat(buf, " [indisposed]");
64 if (mode & SILC_UMODE_BUSY)
65 strcat(buf, " [busy]");
66 if (mode & SILC_UMODE_PAGE)
67 strcat(buf, " [page to reach]");
68 if (mode & SILC_UMODE_HYPER)
69 strcat(buf, " [hyper active]");
70 if (mode & SILC_UMODE_ROBOT)
71 strcat(buf, " [robot]");
72 if (mode & SILC_UMODE_ANONYMOUS)
73 strcat(buf, " [anonymous]");
74 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
75 strcat(buf, " [blocks private messages]");
76 if (mode & SILC_UMODE_DETACHED)
77 strcat(buf, " [detached]");
78 if (mode & SILC_UMODE_REJECT_WATCHING)
79 strcat(buf, " [rejects watching]");
80 if (mode & SILC_UMODE_BLOCK_INVITE)
81 strcat(buf, " [blocks invites]");
84 void silc_say(SilcClient client, SilcClientConnection conn,
85 SilcClientMessageType type, char *msg, ...)
87 SILC_SERVER_REC *server;
91 server = conn == NULL ? NULL : conn->context;
94 str = g_strdup_vprintf(msg, va);
95 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
100 void silc_say_error(char *msg, ...)
106 str = g_strdup_vprintf(msg, va);
107 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
113 /* Message for a channel. The `sender' is the nickname of the sender
114 received in the packet. The `channel_name' is the name of the channel. */
116 void silc_channel_message(SilcClient client, SilcClientConnection conn,
117 SilcClientEntry sender, SilcChannelEntry channel,
118 SilcMessageFlags flags, const unsigned char *message,
119 SilcUInt32 message_len)
121 SILC_SERVER_REC *server;
123 SILC_CHANNEL_REC *chanrec;
125 SILC_LOG_DEBUG(("Start"));
130 server = conn == NULL ? NULL : conn->context;
131 chanrec = silc_channel_find_entry(server, channel);
135 nick = silc_nicklist_find(chanrec, sender);
137 /* We didn't find client but it clearly exists, add it. */
138 SilcChannelUser chu = silc_client_on_channel(channel, sender);
140 nick = silc_nicklist_insert(chanrec, chu, FALSE);
143 if (flags & SILC_MESSAGE_FLAG_DATA) {
144 /* MIME object received, try to display it as well as we can */
148 memset(type, 0, sizeof(type));
149 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
150 NULL, 0, &data, NULL))
153 /* Then figure out what we can display */
154 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
155 !strstr(type, "text/vnd")) {
156 /* It is something textual, display it */
157 message = (const unsigned char *)data;
159 printformat_module("fe-common/silc", server, channel->channel_name,
160 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
161 nick == NULL ? "[<unknown>]" : nick->nick, type);
169 if (flags & SILC_MESSAGE_FLAG_ACTION)
170 printformat_module("fe-common/silc", server, channel->channel_name,
171 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
172 nick == NULL ? "[<unknown>]" : nick->nick, message);
173 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
174 printformat_module("fe-common/silc", server, channel->channel_name,
175 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
176 nick == NULL ? "[<unknown>]" : nick->nick, message);
178 signal_emit("message public", 6, server, message,
179 nick == NULL ? "[<unknown>]" : nick->nick,
180 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
181 chanrec->name, nick);
184 /* Private message to the client. The `sender' is the nickname of the
185 sender received in the packet. */
187 void silc_private_message(SilcClient client, SilcClientConnection conn,
188 SilcClientEntry sender, SilcMessageFlags flags,
189 const unsigned char *message,
190 SilcUInt32 message_len)
192 SILC_SERVER_REC *server;
195 SILC_LOG_DEBUG(("Start"));
197 server = conn == NULL ? NULL : conn->context;
198 memset(userhost, 0, sizeof(userhost));
199 if (sender->username)
200 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
201 sender->username, sender->hostname);
203 if (flags & SILC_MESSAGE_FLAG_DATA) {
204 /* MIME object received, try to display it as well as we can */
208 memset(type, 0, sizeof(type));
209 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
210 NULL, 0, &data, NULL))
213 /* Then figure out what we can display */
214 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
215 !strstr(type, "text/vnd")) {
216 /* It is something textual, display it */
217 message = (const unsigned char *)data;
219 printformat_module("fe-common/silc", server, NULL,
220 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
221 sender->nickname ? sender->nickname : "[<unknown>]",
230 signal_emit("message private", 4, server, message,
231 sender->nickname ? sender->nickname : "[<unknown>]",
232 sender->username ? userhost : NULL);
235 /* Notify message to the client. The notify arguments are sent in the
236 same order as servers sends them. The arguments are same as received
237 from the server except for ID's. If ID is received application receives
238 the corresponding entry to the ID. For example, if Client ID is received
239 application receives SilcClientEntry. Also, if the notify type is
240 for channel the channel entry is sent to application (even if server
241 does not send it). */
243 void silc_notify(SilcClient client, SilcClientConnection conn,
244 SilcNotifyType type, ...)
247 SILC_SERVER_REC *server;
248 SILC_CHANNEL_REC *chanrec;
249 SILC_NICK_REC *nickrec;
250 SilcClientEntry client_entry, client_entry2;
251 SilcChannelEntry channel, channel2;
252 SilcServerEntry server_entry;
258 GSList *list1, *list_tmp;
260 SILC_LOG_DEBUG(("Start"));
264 server = conn == NULL ? NULL : conn->context;
267 case SILC_NOTIFY_TYPE_NONE:
268 /* Some generic notice from server */
269 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
272 case SILC_NOTIFY_TYPE_INVITE:
274 * Invited or modified invite list.
277 SILC_LOG_DEBUG(("Notify: INVITE"));
279 channel = va_arg(va, SilcChannelEntry);
280 name = va_arg(va, char *);
281 client_entry = va_arg(va, SilcClientEntry);
283 memset(buf, 0, sizeof(buf));
284 snprintf(buf, sizeof(buf) - 1, "%s@%s",
285 client_entry->username, client_entry->hostname);
286 signal_emit("message invite", 4, server, channel ? channel->channel_name :
287 name, client_entry->nickname, buf);
290 case SILC_NOTIFY_TYPE_JOIN:
295 SILC_LOG_DEBUG(("Notify: JOIN"));
297 client_entry = va_arg(va, SilcClientEntry);
298 channel = va_arg(va, SilcChannelEntry);
300 if (client_entry == server->conn->local_entry) {
301 /* You joined to channel */
302 chanrec = silc_channel_find(server, channel->channel_name);
303 if (chanrec != NULL && !chanrec->joined)
304 chanrec->entry = channel;
306 chanrec = silc_channel_find_entry(server, channel);
307 if (chanrec != NULL) {
308 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
310 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
314 memset(buf, 0, sizeof(buf));
315 if (client_entry->username)
316 snprintf(buf, sizeof(buf) - 1, "%s@%s",
317 client_entry->username, client_entry->hostname);
318 signal_emit("message join", 4, server, channel->channel_name,
319 client_entry->nickname,
320 client_entry->username == NULL ? "" : buf);
323 case SILC_NOTIFY_TYPE_LEAVE:
328 SILC_LOG_DEBUG(("Notify: LEAVE"));
330 client_entry = va_arg(va, SilcClientEntry);
331 channel = va_arg(va, SilcChannelEntry);
333 memset(buf, 0, sizeof(buf));
334 if (client_entry->username)
335 snprintf(buf, sizeof(buf) - 1, "%s@%s",
336 client_entry->username, client_entry->hostname);
337 signal_emit("message part", 5, server, channel->channel_name,
338 client_entry->nickname, client_entry->username ?
339 buf : "", client_entry->nickname);
341 chanrec = silc_channel_find_entry(server, channel);
342 if (chanrec != NULL) {
343 nickrec = silc_nicklist_find(chanrec, client_entry);
345 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
349 case SILC_NOTIFY_TYPE_SIGNOFF:
354 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
356 client_entry = va_arg(va, SilcClientEntry);
357 tmp = va_arg(va, char *);
359 silc_server_free_ftp(server, client_entry);
361 memset(buf, 0, sizeof(buf));
362 if (client_entry->username)
363 snprintf(buf, sizeof(buf) - 1, "%s@%s",
364 client_entry->username, client_entry->hostname);
365 signal_emit("message quit", 4, server, client_entry->nickname,
366 client_entry->username ? buf : "",
369 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
370 for (list_tmp = list1; list_tmp != NULL; list_tmp =
371 list_tmp->next->next) {
372 CHANNEL_REC *channel = list_tmp->data;
373 NICK_REC *nickrec = list_tmp->next->data;
375 nicklist_remove(channel, nickrec);
379 case SILC_NOTIFY_TYPE_TOPIC_SET:
384 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
386 idtype = va_arg(va, int);
387 entry = va_arg(va, void *);
388 tmp = va_arg(va, char *);
389 channel = va_arg(va, SilcChannelEntry);
391 chanrec = silc_channel_find_entry(server, channel);
392 if (chanrec != NULL) {
393 g_free_not_null(chanrec->topic);
394 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
395 signal_emit("channel topic changed", 1, chanrec);
398 if (idtype == SILC_ID_CLIENT) {
399 client_entry = (SilcClientEntry)entry;
400 memset(buf, 0, sizeof(buf));
401 snprintf(buf, sizeof(buf) - 1, "%s@%s",
402 client_entry->username, client_entry->hostname);
403 signal_emit("message topic", 5, server, channel->channel_name,
404 tmp, client_entry->nickname, buf);
405 } else if (idtype == SILC_ID_SERVER) {
406 server_entry = (SilcServerEntry)entry;
407 signal_emit("message topic", 5, server, channel->channel_name,
408 tmp, server_entry->server_name,
409 server_entry->server_name);
410 } else if (idtype == SILC_ID_CHANNEL) {
411 channel = (SilcChannelEntry)entry;
412 signal_emit("message topic", 5, server, channel->channel_name,
413 tmp, channel->channel_name, channel->channel_name);
417 case SILC_NOTIFY_TYPE_NICK_CHANGE:
422 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
424 client_entry = va_arg(va, SilcClientEntry);
425 client_entry2 = va_arg(va, SilcClientEntry);
427 if (!strcmp(client_entry->nickname, client_entry2->nickname))
430 memset(buf, 0, sizeof(buf));
431 snprintf(buf, sizeof(buf) - 1, "%s@%s",
432 client_entry2->username, client_entry2->hostname);
433 nicklist_rename_unique(SERVER(server),
434 client_entry, client_entry->nickname,
435 client_entry2, client_entry2->nickname);
436 signal_emit("message nick", 4, server, client_entry2->nickname,
437 client_entry->nickname, buf);
440 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
442 * Changed channel mode.
445 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
447 idtype = va_arg(va, int);
448 entry = va_arg(va, void *);
449 mode = va_arg(va, SilcUInt32);
450 (void)va_arg(va, char *);
451 (void)va_arg(va, char *);
452 channel = va_arg(va, SilcChannelEntry);
454 tmp = silc_client_chmode(mode,
455 channel->channel_key ?
456 channel->channel_key->cipher->name : "",
458 silc_hmac_get_name(channel->hmac) : "");
460 chanrec = silc_channel_find_entry(server, channel);
461 if (chanrec != NULL) {
462 g_free_not_null(chanrec->mode);
463 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
464 signal_emit("channel mode changed", 1, chanrec);
467 if (idtype == SILC_ID_CLIENT) {
468 client_entry = (SilcClientEntry)entry;
469 printformat_module("fe-common/silc", server, channel->channel_name,
470 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
471 channel->channel_name, tmp ? tmp : "removed all",
472 client_entry->nickname);
473 } else if (idtype == SILC_ID_SERVER) {
474 server_entry = (SilcServerEntry)entry;
475 printformat_module("fe-common/silc", server, channel->channel_name,
476 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
477 channel->channel_name, tmp ? tmp : "removed all",
478 server_entry->server_name);
479 } else if (idtype == SILC_ID_CHANNEL) {
480 channel2 = (SilcChannelEntry)entry;
481 printformat_module("fe-common/silc", server, channel->channel_name,
482 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
483 channel->channel_name, tmp ? tmp : "removed all",
484 channel2->channel_name);
490 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
492 * Changed user's mode on channel.
495 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
497 idtype = va_arg(va, int);
498 entry = va_arg(va, void *);
499 mode = va_arg(va, SilcUInt32);
500 client_entry2 = va_arg(va, SilcClientEntry);
501 channel = va_arg(va, SilcChannelEntry);
503 tmp = silc_client_chumode(mode);
504 chanrec = silc_channel_find_entry(server, channel);
505 if (chanrec != NULL) {
508 if (client_entry2 == server->conn->local_entry)
509 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
511 nick = silc_nicklist_find(chanrec, client_entry2);
513 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
514 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
515 signal_emit("nick mode changed", 2, chanrec, nick);
519 if (idtype == SILC_ID_CLIENT) {
520 client_entry = (SilcClientEntry)entry;
521 printformat_module("fe-common/silc", server, channel->channel_name,
522 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
523 channel->channel_name, client_entry2->nickname,
524 tmp ? tmp : "removed all",
525 client_entry->nickname);
526 } else if (idtype == SILC_ID_SERVER) {
527 server_entry = (SilcServerEntry)entry;
528 printformat_module("fe-common/silc", server, channel->channel_name,
529 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
530 channel->channel_name, client_entry2->nickname,
531 tmp ? tmp : "removed all",
532 server_entry->server_name);
533 } else if (idtype == SILC_ID_CHANNEL) {
534 channel2 = (SilcChannelEntry)entry;
535 printformat_module("fe-common/silc", server, channel->channel_name,
536 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
537 channel->channel_name, client_entry2->nickname,
538 tmp ? tmp : "removed all",
539 channel2->channel_name);
542 if (mode & SILC_CHANNEL_UMODE_CHANFO)
543 printformat_module("fe-common/silc",
544 server, channel->channel_name, MSGLEVEL_CRAP,
545 SILCTXT_CHANNEL_FOUNDER,
546 channel->channel_name, client_entry2->nickname);
548 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
549 printformat_module("fe-common/silc",
550 server, channel->channel_name, MSGLEVEL_CRAP,
551 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
556 case SILC_NOTIFY_TYPE_MOTD:
561 SILC_LOG_DEBUG(("Notify: MOTD"));
563 tmp = va_arg(va, char *);
565 if (!settings_get_bool("skip_motd"))
566 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
569 case SILC_NOTIFY_TYPE_KICKED:
571 * Someone was kicked from channel.
574 SILC_LOG_DEBUG(("Notify: KICKED"));
576 client_entry = va_arg(va, SilcClientEntry);
577 tmp = va_arg(va, char *);
578 client_entry2 = va_arg(va, SilcClientEntry);
579 channel = va_arg(va, SilcChannelEntry);
581 chanrec = silc_channel_find_entry(server, channel);
583 if (client_entry == conn->local_entry) {
584 printformat_module("fe-common/silc", server, channel->channel_name,
585 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
586 channel->channel_name,
587 client_entry ? client_entry2->nickname : "",
590 chanrec->kicked = TRUE;
591 channel_destroy((CHANNEL_REC *)chanrec);
594 printformat_module("fe-common/silc", server, channel->channel_name,
595 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
596 client_entry->nickname, channel->channel_name,
597 client_entry2 ? client_entry2->nickname : "",
601 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
603 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
608 case SILC_NOTIFY_TYPE_KILLED:
610 * Someone was killed from the network.
613 SILC_LOG_DEBUG(("Notify: KILLED"));
615 client_entry = va_arg(va, SilcClientEntry);
616 tmp = va_arg(va, char *);
617 idtype = va_arg(va, int);
618 entry = va_arg(va, SilcClientEntry);
620 if (client_entry == conn->local_entry) {
621 if (idtype == SILC_ID_CLIENT) {
622 client_entry2 = (SilcClientEntry)entry;
623 printformat_module("fe-common/silc", server, NULL,
624 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
625 client_entry2 ? client_entry2->nickname : "",
627 } else if (idtype == SILC_ID_SERVER) {
628 server_entry = (SilcServerEntry)entry;
629 printformat_module("fe-common/silc", server, NULL,
630 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
631 server_entry->server_name, tmp ? tmp : "");
632 } else if (idtype == SILC_ID_CHANNEL) {
633 channel = (SilcChannelEntry)entry;
634 printformat_module("fe-common/silc", server, NULL,
635 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
636 channel->channel_name, tmp ? tmp : "");
639 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
640 for (list_tmp = list1; list_tmp != NULL; list_tmp =
641 list_tmp->next->next) {
642 CHANNEL_REC *channel = list_tmp->data;
643 NICK_REC *nickrec = list_tmp->next->data;
644 nicklist_remove(channel, nickrec);
647 if (idtype == SILC_ID_CLIENT) {
648 client_entry2 = (SilcClientEntry)entry;
649 printformat_module("fe-common/silc", server, NULL,
650 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
651 client_entry->nickname,
652 client_entry2 ? client_entry2->nickname : "",
654 } else if (idtype == SILC_ID_SERVER) {
655 server_entry = (SilcServerEntry)entry;
656 printformat_module("fe-common/silc", server, NULL,
657 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
658 client_entry->nickname,
659 server_entry->server_name, tmp ? tmp : "");
660 } else if (idtype == SILC_ID_CHANNEL) {
661 channel = (SilcChannelEntry)entry;
662 printformat_module("fe-common/silc", server, NULL,
663 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
664 client_entry->nickname,
665 channel->channel_name, tmp ? tmp : "");
670 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
673 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
676 * Server has quit the network.
679 SilcClientEntry *clients;
680 SilcUInt32 clients_count;
682 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
684 (void)va_arg(va, void *);
685 clients = va_arg(va, SilcClientEntry *);
686 clients_count = va_arg(va, SilcUInt32);
688 for (i = 0; i < clients_count; i++) {
689 memset(buf, 0, sizeof(buf));
690 if (clients[i]->username)
691 snprintf(buf, sizeof(buf) - 1, "%s@%s",
692 clients[i]->username, clients[i]->hostname);
693 signal_emit("message quit", 4, server, clients[i]->nickname,
694 clients[i]->username ? buf : "",
697 silc_server_free_ftp(server, clients[i]);
699 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
700 for (list_tmp = list1; list_tmp != NULL; list_tmp =
701 list_tmp->next->next) {
702 CHANNEL_REC *channel = list_tmp->data;
703 NICK_REC *nickrec = list_tmp->next->data;
704 nicklist_remove(channel, nickrec);
710 case SILC_NOTIFY_TYPE_ERROR:
712 SilcStatus error = va_arg(va, int);
714 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
715 "%s", silc_get_status_message(error));
719 case SILC_NOTIFY_TYPE_WATCH:
721 SilcNotifyType notify;
723 client_entry = va_arg(va, SilcClientEntry);
724 name = va_arg(va, char *); /* Maybe NULL */
725 mode = va_arg(va, SilcUInt32);
726 notify = va_arg(va, int);
728 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
730 printformat_module("fe-common/silc", server, NULL,
731 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
732 client_entry->nickname, name);
734 printformat_module("fe-common/silc", server, NULL,
735 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
736 client_entry->nickname);
737 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
738 /* See if client was away and is now present */
739 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
740 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
741 SILC_UMODE_DETACHED)) &&
742 (client_entry->mode & SILC_UMODE_GONE ||
743 client_entry->mode & SILC_UMODE_INDISPOSED ||
744 client_entry->mode & SILC_UMODE_BUSY ||
745 client_entry->mode & SILC_UMODE_PAGE ||
746 client_entry->mode & SILC_UMODE_DETACHED)) {
747 printformat_module("fe-common/silc", server, NULL,
748 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
749 client_entry->nickname);
753 memset(buf, 0, sizeof(buf));
754 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
755 printformat_module("fe-common/silc", server, NULL,
756 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
757 client_entry->nickname, buf);
759 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
760 printformat_module("fe-common/silc", server, NULL,
761 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
762 client_entry->nickname);
763 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
764 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
765 printformat_module("fe-common/silc", server, NULL,
766 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
767 client_entry->nickname);
768 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
769 /* Client logged in to the network */
770 printformat_module("fe-common/silc", server, NULL,
771 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
772 client_entry->nickname);
779 printformat_module("fe-common/silc", server, NULL,
780 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
787 /* Called to indicate that connection was either successfully established
788 or connecting failed. This is also the first time application receives
789 the SilcClientConnection object which it should save somewhere. */
791 void silc_connect(SilcClient client, SilcClientConnection conn,
792 SilcClientConnectionStatus status)
794 SILC_SERVER_REC *server = conn->context;
797 silc_client_close_connection(client, conn);
802 case SILC_CLIENT_CONN_SUCCESS:
803 /* We have successfully connected to server */
804 server->connected = TRUE;
805 signal_emit("event connected", 1, server);
808 case SILC_CLIENT_CONN_SUCCESS_RESUME:
809 /* We have successfully resumed old detached session */
810 server->connected = TRUE;
811 signal_emit("event connected", 1, server);
813 /* If we resumed old session check whether we need to update
815 if (strcmp(server->nick, conn->local_entry->nickname)) {
817 old = g_strdup(server->nick);
818 server_change_nick(SERVER(server), conn->local_entry->nickname);
819 nicklist_rename_unique(SERVER(server),
820 conn->local_entry, server->nick,
821 conn->local_entry, conn->local_entry->nickname);
822 signal_emit("message own_nick", 4, server, server->nick, old, "");
828 server->connection_lost = TRUE;
830 server->conn->context = NULL;
831 server_disconnect(SERVER(server));
836 /* Called to indicate that connection was disconnected to the server. */
838 void silc_disconnect(SilcClient client, SilcClientConnection conn)
840 SILC_SERVER_REC *server = conn->context;
842 SILC_LOG_DEBUG(("Start"));
844 if (!server || server->connection_lost)
847 if (server->conn && server->conn->local_entry) {
848 nicklist_rename_unique(SERVER(server),
849 server->conn->local_entry, server->nick,
850 server->conn->local_entry,
851 silc_client->username);
852 silc_change_nick(server, silc_client->username);
855 server->conn->context = NULL;
857 server->connection_lost = TRUE;
858 server_disconnect(SERVER(server));
861 /* Command handler. This function is called always in the command function.
862 If error occurs it will be called as well. `conn' is the associated
863 client connection. `cmd_context' is the command context that was
864 originally sent to the command. `success' is FALSE if error occured
865 during command. `command' is the command being processed. It must be
866 noted that this is not reply from server. This is merely called just
867 after application has called the command. Just to tell application
868 that the command really was processed. */
870 void silc_command(SilcClient client, SilcClientConnection conn,
871 SilcClientCommandContext cmd_context, bool success,
872 SilcCommand command, SilcStatus status)
874 SILC_SERVER_REC *server = conn->context;
876 SILC_LOG_DEBUG(("Start"));
879 silc_say_error("%s", silc_get_status_message(status));
884 case SILC_COMMAND_INVITE:
885 printformat_module("fe-common/silc", server, NULL,
886 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
887 cmd_context->argv[2],
888 (cmd_context->argv[1][0] == '*' ?
889 (char *)conn->current_channel->channel_name :
890 (char *)cmd_context->argv[1]));
897 /* Client info resolving callback when JOIN command reply is received.
898 This will cache all users on the channel. */
900 static void silc_client_join_get_users(SilcClient client,
901 SilcClientConnection conn,
902 SilcClientEntry *clients,
903 SilcUInt32 clients_count,
906 SilcChannelEntry channel = (SilcChannelEntry)context;
907 SilcHashTableList htl;
909 SILC_SERVER_REC *server = conn->context;
910 SILC_CHANNEL_REC *chanrec;
911 SilcClientEntry founder = NULL;
914 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
915 silc_hash_table_count(channel->user_list)));
920 chanrec = silc_channel_find(server, channel->channel_name);
924 silc_hash_table_list(channel->user_list, &htl);
925 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
926 if (!chu->client->nickname)
928 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
929 founder = chu->client;
930 silc_nicklist_insert(chanrec, chu, FALSE);
932 silc_hash_table_list_reset(&htl);
934 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
935 nicklist_set_own(CHANNEL(chanrec), ownnick);
936 signal_emit("channel joined", 1, chanrec);
937 chanrec->entry = channel;
940 printformat_module("fe-common/silc", server, channel->channel_name,
941 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
942 channel->channel_name, chanrec->topic);
944 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
947 if (founder == conn->local_entry)
948 printformat_module("fe-common/silc",
949 server, channel->channel_name, MSGLEVEL_CRAP,
950 SILCTXT_CHANNEL_FOUNDER_YOU,
951 channel->channel_name);
953 printformat_module("fe-common/silc",
954 server, channel->channel_name, MSGLEVEL_CRAP,
955 SILCTXT_CHANNEL_FOUNDER,
956 channel->channel_name, founder->nickname);
962 SilcClientConnection conn;
968 void silc_getkey_cb(bool success, void *context)
970 GetkeyContext getkey = (GetkeyContext)context;
971 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
972 char *name = (getkey->id_type == SILC_ID_CLIENT ?
973 ((SilcClientEntry)getkey->entry)->nickname :
974 ((SilcServerEntry)getkey->entry)->server_name);
977 printformat_module("fe-common/silc", NULL, NULL,
978 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
980 printformat_module("fe-common/silc", NULL, NULL,
981 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
984 silc_free(getkey->fingerprint);
988 /* Command reply handler. This function is called always in the command reply
989 function. If error occurs it will be called as well. Normal scenario
990 is that it will be called after the received command data has been parsed
991 and processed. The function is used to pass the received command data to
994 `conn' is the associated client connection. `cmd_payload' is the command
995 payload data received from server and it can be ignored. It is provided
996 if the application would like to re-parse the received command data,
997 however, it must be noted that the data is parsed already by the library
998 thus the payload can be ignored. `success' is FALSE if error occured.
999 In this case arguments are not sent to the application. `command' is the
1000 command reply being processed. The function has variable argument list
1001 and each command defines the number and type of arguments it passes to the
1002 application (on error they are not sent). */
1005 silc_command_reply(SilcClient client, SilcClientConnection conn,
1006 SilcCommandPayload cmd_payload, bool success,
1007 SilcCommand command, SilcStatus status, ...)
1010 SILC_SERVER_REC *server = conn->context;
1011 SILC_CHANNEL_REC *chanrec;
1014 va_start(vp, status);
1016 SILC_LOG_DEBUG(("Start"));
1019 case SILC_COMMAND_WHOIS:
1021 char buf[1024], *nickname, *username, *realname, *nick;
1022 unsigned char *fingerprint;
1023 SilcUInt32 idle, mode;
1024 SilcBuffer channels, user_modes;
1025 SilcClientEntry client_entry;
1027 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1028 /* Print the unknown nick for user */
1029 unsigned char *tmp =
1030 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1033 silc_say_error("%s: %s", tmp,
1034 silc_get_status_message(status));
1036 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1037 /* Try to find the entry for the unknown client ID, since we
1038 might have, and print the nickname of it for user. */
1040 unsigned char *tmp =
1041 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1044 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1047 client_entry = silc_client_get_client_by_id(client, conn,
1049 if (client_entry && client_entry->nickname)
1050 silc_say_error("%s: %s", client_entry->nickname,
1051 silc_get_status_message(status));
1052 silc_free(client_id);
1061 client_entry = va_arg(vp, SilcClientEntry);
1062 nickname = va_arg(vp, char *);
1063 username = va_arg(vp, char *);
1064 realname = va_arg(vp, char *);
1065 channels = va_arg(vp, SilcBuffer);
1066 mode = va_arg(vp, SilcUInt32);
1067 idle = va_arg(vp, SilcUInt32);
1068 fingerprint = va_arg(vp, unsigned char *);
1069 user_modes = va_arg(vp, SilcBuffer);
1071 silc_parse_userfqdn(nickname, &nick, NULL);
1072 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1073 SILCTXT_WHOIS_USERINFO, nickname,
1074 client_entry->username, client_entry->hostname,
1075 nick, client_entry->nickname);
1076 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1077 SILCTXT_WHOIS_REALNAME, realname);
1080 if (channels && user_modes) {
1082 SilcDList list = silc_channel_payload_parse_list(channels->data,
1084 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1086 SilcChannelPayload entry;
1089 memset(buf, 0, sizeof(buf));
1090 silc_dlist_start(list);
1091 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1092 SilcUInt32 name_len;
1093 char *m = silc_client_chumode_char(umodes[i++]);
1094 char *name = silc_channel_get_name(entry, &name_len);
1097 strncat(buf, m, strlen(m));
1098 strncat(buf, name, name_len);
1099 strncat(buf, " ", 1);
1103 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1104 SILCTXT_WHOIS_CHANNELS, buf);
1105 silc_channel_payload_list_free(list);
1111 memset(buf, 0, sizeof(buf));
1112 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1113 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1114 SILCTXT_WHOIS_MODES, buf);
1117 if (idle && nickname) {
1118 memset(buf, 0, sizeof(buf));
1119 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1120 idle > 60 ? (idle / 60) : idle,
1121 idle > 60 ? "minutes" : "seconds");
1123 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1124 SILCTXT_WHOIS_IDLE, buf);
1128 fingerprint = silc_fingerprint(fingerprint, 20);
1129 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1130 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1131 silc_free(fingerprint);
1136 case SILC_COMMAND_IDENTIFY:
1138 SilcClientEntry client_entry;
1140 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1141 /* Print the unknown nick for user */
1142 unsigned char *tmp =
1143 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1146 silc_say_error("%s: %s", tmp,
1147 silc_get_status_message(status));
1149 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1150 /* Try to find the entry for the unknown client ID, since we
1151 might have, and print the nickname of it for user. */
1153 unsigned char *tmp =
1154 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1157 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1160 client_entry = silc_client_get_client_by_id(client, conn,
1162 if (client_entry && client_entry->nickname)
1163 silc_say_error("%s: %s", client_entry->nickname,
1164 silc_get_status_message(status));
1165 silc_free(client_id);
1174 case SILC_COMMAND_WHOWAS:
1176 char *nickname, *username, *realname;
1178 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1179 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1181 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1184 silc_say_error("%s: %s", tmp,
1185 silc_get_status_message(status));
1192 (void)va_arg(vp, SilcClientEntry);
1193 nickname = va_arg(vp, char *);
1194 username = va_arg(vp, char *);
1195 realname = va_arg(vp, char *);
1197 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1198 SILCTXT_WHOWAS_USERINFO, nickname, username,
1199 realname ? realname : "");
1203 case SILC_COMMAND_INVITE:
1205 SilcChannelEntry channel;
1207 SilcArgumentPayload args;
1213 channel = va_arg(vp, SilcChannelEntry);
1214 invite_list = va_arg(vp, char *);
1216 args = silc_command_get_args(cmd_payload);
1218 argc = silc_argument_get_arg_num(args);
1221 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1222 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1225 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1226 SILCTXT_CHANNEL_NO_INVITE_LIST,
1227 channel->channel_name);
1231 case SILC_COMMAND_JOIN:
1233 char *channel, *mode, *topic;
1235 SilcChannelEntry channel_entry;
1236 SilcBuffer client_id_list;
1237 SilcUInt32 list_count;
1242 channel = va_arg(vp, char *);
1243 channel_entry = va_arg(vp, SilcChannelEntry);
1244 modei = va_arg(vp, SilcUInt32);
1245 (void)va_arg(vp, SilcUInt32);
1246 (void)va_arg(vp, unsigned char *);
1247 (void)va_arg(vp, unsigned char *);
1248 (void)va_arg(vp, unsigned char *);
1249 topic = va_arg(vp, char *);
1250 (void)va_arg(vp, unsigned char *);
1251 list_count = va_arg(vp, SilcUInt32);
1252 client_id_list = va_arg(vp, SilcBuffer);
1254 chanrec = silc_channel_find(server, channel);
1256 chanrec = silc_channel_create(server, channel, TRUE);
1259 g_free_not_null(chanrec->topic);
1260 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1261 signal_emit("channel topic changed", 1, chanrec);
1264 mode = silc_client_chmode(modei,
1265 channel_entry->channel_key ?
1266 channel_entry->channel_key->cipher->name : "",
1267 channel_entry->hmac ?
1268 silc_hmac_get_name(channel_entry->hmac) : "");
1269 g_free_not_null(chanrec->mode);
1270 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1271 signal_emit("channel mode changed", 1, chanrec);
1273 /* Resolve the client information */
1274 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1275 silc_client_join_get_users,
1281 case SILC_COMMAND_NICK:
1284 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1289 old = g_strdup(server->nick);
1290 server_change_nick(SERVER(server), client->nickname);
1291 nicklist_rename_unique(SERVER(server),
1292 server->conn->local_entry, server->nick,
1293 client, client->nickname);
1294 signal_emit("message own_nick", 4, server, server->nick, old, "");
1299 case SILC_COMMAND_LIST:
1308 (void)va_arg(vp, SilcChannelEntry);
1309 name = va_arg(vp, char *);
1310 topic = va_arg(vp, char *);
1311 usercount = va_arg(vp, int);
1313 if (status == SILC_STATUS_LIST_START ||
1314 status == SILC_STATUS_OK)
1315 printformat_module("fe-common/silc", server, NULL,
1316 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1319 snprintf(users, sizeof(users) - 1, "N/A");
1321 snprintf(users, sizeof(users) - 1, "%d", usercount);
1322 printformat_module("fe-common/silc", server, NULL,
1323 MSGLEVEL_CRAP, SILCTXT_LIST,
1324 name, users, topic ? topic : "");
1328 case SILC_COMMAND_UMODE:
1335 mode = va_arg(vp, SilcUInt32);
1337 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1338 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1339 printformat_module("fe-common/silc", server, NULL,
1340 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1342 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1343 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1344 printformat_module("fe-common/silc", server, NULL,
1345 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1347 server->umode = mode;
1348 signal_emit("user mode changed", 2, server, NULL);
1352 case SILC_COMMAND_OPER:
1356 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1357 signal_emit("user mode changed", 2, server, NULL);
1359 printformat_module("fe-common/silc", server, NULL,
1360 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1363 case SILC_COMMAND_SILCOPER:
1367 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1368 signal_emit("user mode changed", 2, server, NULL);
1370 printformat_module("fe-common/silc", server, NULL,
1371 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1374 case SILC_COMMAND_USERS:
1376 SilcHashTableList htl;
1377 SilcChannelEntry channel;
1378 SilcChannelUser chu;
1383 channel = va_arg(vp, SilcChannelEntry);
1385 printformat_module("fe-common/silc", server, channel->channel_name,
1386 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1387 channel->channel_name);
1389 silc_hash_table_list(channel->user_list, &htl);
1390 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1391 SilcClientEntry e = chu->client;
1392 char stat[5], *mode;
1397 memset(stat, 0, sizeof(stat));
1398 mode = silc_client_chumode_char(chu->mode);
1399 if (e->mode & SILC_UMODE_GONE)
1401 else if (e->mode & SILC_UMODE_INDISPOSED)
1403 else if (e->mode & SILC_UMODE_BUSY)
1405 else if (e->mode & SILC_UMODE_PAGE)
1407 else if (e->mode & SILC_UMODE_HYPER)
1409 else if (e->mode & SILC_UMODE_ROBOT)
1411 else if (e->mode & SILC_UMODE_ANONYMOUS)
1418 printformat_module("fe-common/silc", server, channel->channel_name,
1419 MSGLEVEL_CRAP, SILCTXT_USERS,
1421 e->username ? e->username : "",
1422 e->hostname ? e->hostname : "",
1423 e->realname ? e->realname : "");
1427 silc_hash_table_list_reset(&htl);
1431 case SILC_COMMAND_BAN:
1433 SilcChannelEntry channel;
1439 channel = va_arg(vp, SilcChannelEntry);
1440 ban_list = va_arg(vp, char *);
1443 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1444 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1447 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1448 SILCTXT_CHANNEL_NO_BAN_LIST,
1449 channel->channel_name);
1453 case SILC_COMMAND_GETKEY:
1457 SilcPublicKey public_key;
1460 GetkeyContext getkey;
1466 id_type = va_arg(vp, SilcUInt32);
1467 entry = va_arg(vp, void *);
1468 public_key = va_arg(vp, SilcPublicKey);
1471 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1473 getkey = silc_calloc(1, sizeof(*getkey));
1474 getkey->entry = entry;
1475 getkey->id_type = id_type;
1476 getkey->client = client;
1477 getkey->conn = conn;
1478 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1480 name = (id_type == SILC_ID_CLIENT ?
1481 ((SilcClientEntry)entry)->nickname :
1482 ((SilcServerEntry)entry)->server_name);
1484 silc_verify_public_key_internal(client, conn, name,
1485 (id_type == SILC_ID_CLIENT ?
1486 SILC_SOCKET_TYPE_CLIENT :
1487 SILC_SOCKET_TYPE_SERVER),
1488 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1489 silc_getkey_cb, getkey);
1492 printformat_module("fe-common/silc", server, NULL,
1493 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1498 case SILC_COMMAND_INFO:
1500 SilcServerEntry server_entry;
1507 server_entry = va_arg(vp, SilcServerEntry);
1508 server_name = va_arg(vp, char *);
1509 server_info = va_arg(vp, char *);
1511 if (server_name && server_info )
1513 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1514 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1519 case SILC_COMMAND_TOPIC:
1521 SilcChannelEntry channel;
1527 channel = va_arg(vp, SilcChannelEntry);
1528 topic = va_arg(vp, char *);
1531 chanrec = silc_channel_find_entry(server, channel);
1533 g_free_not_null(chanrec->topic);
1534 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1535 signal_emit("channel topic changed", 1, chanrec);
1537 printformat_module("fe-common/silc", server, channel->channel_name,
1538 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1539 channel->channel_name, topic);
1541 printformat_module("fe-common/silc", server, channel->channel_name,
1542 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1543 channel->channel_name);
1548 case SILC_COMMAND_WATCH:
1557 SilcClientConnection conn;
1563 SilcSKEPKType pk_type;
1564 SilcVerifyPublicKey completion;
1568 static void verify_public_key_completion(const char *line, void *context)
1570 PublicKeyVerify verify = (PublicKeyVerify)context;
1572 if (line[0] == 'Y' || line[0] == 'y') {
1573 /* Call the completion */
1574 if (verify->completion)
1575 verify->completion(TRUE, verify->context);
1577 /* Save the key for future checking */
1578 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1579 verify->pk_len, SILC_PKCS_FILE_PEM);
1581 /* Call the completion */
1582 if (verify->completion)
1583 verify->completion(FALSE, verify->context);
1585 printformat_module("fe-common/silc", NULL, NULL,
1586 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1587 verify->entity_name ? verify->entity_name :
1591 silc_free(verify->filename);
1592 silc_free(verify->entity);
1593 silc_free(verify->entity_name);
1594 silc_free(verify->pk);
1598 /* Internal routine to verify public key. If the `completion' is provided
1599 it will be called to indicate whether public was verified or not. For
1600 server/router public key this will check for filename that includes the
1601 remote host's IP address and remote host's hostname. */
1604 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1605 const char *name, SilcSocketType conn_type,
1606 unsigned char *pk, SilcUInt32 pk_len,
1607 SilcSKEPKType pk_type,
1608 SilcVerifyPublicKey completion, void *context)
1611 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1612 char *fingerprint, *babbleprint, *format;
1615 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1616 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1617 "server" : "client");
1618 PublicKeyVerify verify;
1620 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1621 printformat_module("fe-common/silc", NULL, NULL,
1622 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1625 completion(FALSE, context);
1629 pw = getpwuid(getuid());
1632 completion(FALSE, context);
1636 memset(filename, 0, sizeof(filename));
1637 memset(filename2, 0, sizeof(filename2));
1638 memset(file, 0, sizeof(file));
1640 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1641 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1643 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1644 conn->sock->ip, conn->sock->port);
1645 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1646 get_irssi_dir(), entity, file);
1648 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1649 conn->sock->hostname, conn->sock->port);
1650 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1651 get_irssi_dir(), entity, file);
1656 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1657 name, conn->sock->port);
1658 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1659 get_irssi_dir(), entity, file);
1664 /* Replace all whitespaces with `_'. */
1665 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1666 for (i = 0; i < strlen(fingerprint); i++)
1667 if (fingerprint[i] == ' ')
1668 fingerprint[i] = '_';
1670 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1671 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1672 get_irssi_dir(), entity, file);
1673 silc_free(fingerprint);
1678 /* Take fingerprint of the public key */
1679 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1680 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1682 verify = silc_calloc(1, sizeof(*verify));
1683 verify->client = client;
1684 verify->conn = conn;
1685 verify->filename = strdup(ipf);
1686 verify->entity = strdup(entity);
1687 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1688 (name ? strdup(name) : strdup(conn->sock->hostname))
1690 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1691 memcpy(verify->pk, pk, pk_len);
1692 verify->pk_len = pk_len;
1693 verify->pk_type = pk_type;
1694 verify->completion = completion;
1695 verify->context = context;
1697 /* Check whether this key already exists */
1698 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1699 /* Key does not exist, ask user to verify the key and save it */
1701 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1702 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1703 verify->entity_name : entity);
1704 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1705 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1706 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1707 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1708 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1709 SILCTXT_PUBKEY_ACCEPT);
1710 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1713 silc_free(fingerprint);
1716 /* The key already exists, verify it. */
1717 SilcPublicKey public_key;
1718 unsigned char *encpk;
1719 SilcUInt32 encpk_len;
1721 /* Load the key file, try for both IP filename and hostname filename */
1722 if (!silc_pkcs_load_public_key(ipf, &public_key,
1723 SILC_PKCS_FILE_PEM) &&
1724 !silc_pkcs_load_public_key(ipf, &public_key,
1725 SILC_PKCS_FILE_BIN) &&
1726 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1727 SILC_PKCS_FILE_PEM) &&
1728 !silc_pkcs_load_public_key(hostf, &public_key,
1729 SILC_PKCS_FILE_BIN)))) {
1730 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1731 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1732 verify->entity_name : entity);
1733 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1734 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1735 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1736 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1737 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1738 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1739 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1740 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1741 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1744 silc_free(fingerprint);
1748 /* Encode the key data */
1749 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1751 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1752 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1753 verify->entity_name : entity);
1754 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1755 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1756 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1757 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1758 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1759 SILCTXT_PUBKEY_MALFORMED, entity);
1760 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1761 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1762 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1765 silc_free(fingerprint);
1769 /* Compare the keys */
1770 if (memcmp(encpk, pk, encpk_len)) {
1771 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1772 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1773 verify->entity_name : entity);
1774 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1775 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1776 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1777 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1778 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1779 SILCTXT_PUBKEY_NO_MATCH, entity);
1780 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1781 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1782 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1783 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1785 /* Ask user to verify the key and save it */
1786 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1787 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1788 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1791 silc_free(fingerprint);
1795 /* Local copy matched */
1797 completion(TRUE, context);
1798 silc_free(fingerprint);
1802 /* Verifies received public key. The `conn_type' indicates which entity
1803 (server, client etc.) has sent the public key. If user decides to trust
1804 the key may be saved as trusted public key for later use. The
1805 `completion' must be called after the public key has been verified. */
1808 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1809 SilcSocketType conn_type, unsigned char *pk,
1810 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1811 SilcVerifyPublicKey completion, void *context)
1813 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1815 completion, context);
1818 /* Asks passphrase from user on the input line. */
1821 SilcAskPassphrase completion;
1825 void ask_passphrase_completion(const char *passphrase, void *context)
1827 AskPassphrase p = (AskPassphrase)context;
1828 if (passphrase && passphrase[0] == '\0')
1830 p->completion((unsigned char *)passphrase,
1831 passphrase ? strlen(passphrase) : 0, p->context);
1835 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1836 SilcAskPassphrase completion, void *context)
1838 AskPassphrase p = silc_calloc(1, sizeof(*p));
1839 p->completion = completion;
1840 p->context = context;
1842 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1843 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1847 SilcGetAuthMeth completion;
1849 } *InternalGetAuthMethod;
1851 /* Callback called when we've received the authentication method information
1852 from the server after we've requested it. This will get the authentication
1853 data from the user if needed. */
1855 static void silc_get_auth_method_callback(SilcClient client,
1856 SilcClientConnection conn,
1857 SilcAuthMethod auth_meth,
1860 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1862 SILC_LOG_DEBUG(("Start"));
1864 switch (auth_meth) {
1865 case SILC_AUTH_NONE:
1866 /* No authentication required. */
1867 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1869 case SILC_AUTH_PASSWORD:
1870 /* Do not ask the passphrase from user, the library will ask it if
1871 we do not provide it here. */
1872 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1874 case SILC_AUTH_PUBLIC_KEY:
1875 /* Do not get the authentication data now, the library will generate
1876 it using our default key, if we do not provide it here. */
1877 /* XXX In the future when we support multiple local keys and multiple
1878 local certificates we will need to ask from user which one to use. */
1879 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1883 silc_free(internal);
1886 /* Find authentication method and authentication data by hostname and
1887 port. The hostname may be IP address as well. The found authentication
1888 method and authentication data is returned to `auth_meth', `auth_data'
1889 and `auth_data_len'. The function returns TRUE if authentication method
1890 is found and FALSE if not. `conn' may be NULL. */
1892 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1893 char *hostname, SilcUInt16 port,
1894 SilcGetAuthMeth completion, void *context)
1896 InternalGetAuthMethod internal;
1898 SILC_LOG_DEBUG(("Start"));
1900 /* XXX must resolve from configuration whether this connection has
1901 any specific authentication data */
1903 /* If we do not have this connection configured by the user in a
1904 configuration file then resolve the authentication method from the
1905 server for this session. */
1906 internal = silc_calloc(1, sizeof(*internal));
1907 internal->completion = completion;
1908 internal->context = context;
1910 silc_client_request_authentication_method(client, conn,
1911 silc_get_auth_method_callback,
1915 /* Notifies application that failure packet was received. This is called
1916 if there is some protocol active in the client. The `protocol' is the
1917 protocol context. The `failure' is opaque pointer to the failure
1918 indication. Note, that the `failure' is protocol dependant and application
1919 must explicitly cast it to correct type. Usually `failure' is 32 bit
1920 failure type (see protocol specs for all protocol failure types). */
1922 void silc_failure(SilcClient client, SilcClientConnection conn,
1923 SilcProtocol protocol, void *failure)
1925 SILC_LOG_DEBUG(("Start"));
1927 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1928 SilcSKEStatus status = (SilcSKEStatus)failure;
1930 if (status == SILC_SKE_STATUS_BAD_VERSION)
1931 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1932 SILCTXT_KE_BAD_VERSION);
1933 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1934 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1935 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1936 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1937 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1938 SILCTXT_KE_UNKNOWN_GROUP);
1939 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1940 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1941 SILCTXT_KE_UNKNOWN_CIPHER);
1942 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1943 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1944 SILCTXT_KE_UNKNOWN_PKCS);
1945 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1946 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1947 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1948 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1949 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1950 SILCTXT_KE_UNKNOWN_HMAC);
1951 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1952 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1953 SILCTXT_KE_INCORRECT_SIGNATURE);
1954 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1955 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1956 SILCTXT_KE_INVALID_COOKIE);
1959 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1960 SilcUInt32 err = (SilcUInt32)failure;
1962 if (err == SILC_AUTH_FAILED)
1963 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1964 SILCTXT_AUTH_FAILED);
1968 /* Asks whether the user would like to perform the key agreement protocol.
1969 This is called after we have received an key agreement packet or an
1970 reply to our key agreement packet. This returns TRUE if the user wants
1971 the library to perform the key agreement protocol and FALSE if it is not
1972 desired (application may start it later by calling the function
1973 silc_client_perform_key_agreement). */
1975 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1976 SilcClientEntry client_entry, const char *hostname,
1977 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1982 SILC_LOG_DEBUG(("Start"));
1984 /* We will just display the info on the screen and return FALSE and user
1985 will have to start the key agreement with a command. */
1988 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1991 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1992 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1994 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1995 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1996 client_entry->nickname, hostname, portstr);
2004 /* Notifies application that file transfer protocol session is being
2005 requested by the remote client indicated by the `client_entry' from
2006 the `hostname' and `port'. The `session_id' is the file transfer
2007 session and it can be used to either accept or reject the file
2008 transfer request, by calling the silc_client_file_receive or
2009 silc_client_file_close, respectively. */
2011 void silc_ftp(SilcClient client, SilcClientConnection conn,
2012 SilcClientEntry client_entry, SilcUInt32 session_id,
2013 const char *hostname, SilcUInt16 port)
2015 SILC_SERVER_REC *server;
2017 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2019 SILC_LOG_DEBUG(("Start"));
2021 server = conn->context;
2023 ftp->client_entry = client_entry;
2024 ftp->session_id = session_id;
2027 silc_dlist_add(server->ftp_sessions, ftp);
2028 server->current_session = ftp;
2031 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2034 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2035 SILCTXT_FILE_REQUEST, client_entry->nickname);
2037 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2038 SILCTXT_FILE_REQUEST_HOST,
2039 client_entry->nickname, hostname, portstr);
2042 /* Delivers SILC session detachment data indicated by `detach_data' to the
2043 application. If application has issued SILC_COMMAND_DETACH command
2044 the client session in the SILC network is not quit. The client remains
2045 in the network but is detached. The detachment data may be used later
2046 to resume the session in the SILC Network. The appliation is
2047 responsible of saving the `detach_data', to for example in a file.
2049 The detachment data can be given as argument to the functions
2050 silc_client_connect_to_server, or silc_client_add_connection when
2051 creating connection to remote server, inside SilcClientConnectionParams
2052 structure. If it is provided the client library will attempt to resume
2053 the session in the network. After the connection is created
2054 successfully, the application is responsible of setting the user
2055 interface for user into the same state it was before detaching (showing
2056 same channels, channel modes, etc). It can do this by fetching the
2057 information (like joined channels) from the client library. */
2060 silc_detach(SilcClient client, SilcClientConnection conn,
2061 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2065 /* Save the detachment data to file. */
2067 memset(file, 0, sizeof(file));
2068 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2069 silc_file_writefile(file, detach_data, detach_data_len);
2073 /* SILC client operations */
2074 SilcClientOperations ops = {
2076 silc_channel_message,
2077 silc_private_message,
2083 silc_get_auth_method,
2084 silc_verify_public_key,
2085 silc_ask_passphrase,