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 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
179 char tmp[256], *cp, *dm = NULL;
181 memset(tmp, 0, sizeof(tmp));
183 if (message_len > sizeof(tmp) - 1) {
184 dm = silc_calloc(message_len + 1, sizeof(*dm));
188 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
190 signal_emit("message public", 6, server, cp,
191 nick == NULL ? "[<unknown>]" : nick->nick,
192 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
193 chanrec->name, nick);
198 signal_emit("message public", 6, server, message,
199 nick == NULL ? "[<unknown>]" : nick->nick,
200 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
201 chanrec->name, nick);
205 /* Private message to the client. The `sender' is the nickname of the
206 sender received in the packet. */
208 void silc_private_message(SilcClient client, SilcClientConnection conn,
209 SilcClientEntry sender, SilcMessageFlags flags,
210 const unsigned char *message,
211 SilcUInt32 message_len)
213 SILC_SERVER_REC *server;
216 SILC_LOG_DEBUG(("Start"));
218 server = conn == NULL ? NULL : conn->context;
219 memset(userhost, 0, sizeof(userhost));
220 if (sender->username)
221 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
222 sender->username, sender->hostname);
224 if (flags & SILC_MESSAGE_FLAG_DATA) {
225 /* MIME object received, try to display it as well as we can */
229 memset(type, 0, sizeof(type));
230 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
231 NULL, 0, &data, NULL))
234 /* Then figure out what we can display */
235 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
236 !strstr(type, "text/vnd")) {
237 /* It is something textual, display it */
238 message = (const unsigned char *)data;
240 printformat_module("fe-common/silc", server, NULL,
241 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
242 sender->nickname ? sender->nickname : "[<unknown>]",
251 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
252 char tmp[256], *cp, *dm = NULL;
254 memset(tmp, 0, sizeof(tmp));
256 if (message_len > sizeof(tmp) - 1) {
257 dm = silc_calloc(message_len + 1, sizeof(*dm));
261 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
263 signal_emit("message private", 4, server, cp,
264 sender->nickname ? sender->nickname : "[<unknown>]",
265 sender->username ? userhost : NULL);
270 signal_emit("message private", 4, server, message,
271 sender->nickname ? sender->nickname : "[<unknown>]",
272 sender->username ? userhost : NULL);
275 /* Notify message to the client. The notify arguments are sent in the
276 same order as servers sends them. The arguments are same as received
277 from the server except for ID's. If ID is received application receives
278 the corresponding entry to the ID. For example, if Client ID is received
279 application receives SilcClientEntry. Also, if the notify type is
280 for channel the channel entry is sent to application (even if server
281 does not send it). */
283 void silc_notify(SilcClient client, SilcClientConnection conn,
284 SilcNotifyType type, ...)
287 SILC_SERVER_REC *server;
288 SILC_CHANNEL_REC *chanrec;
289 SILC_NICK_REC *nickrec;
290 SilcClientEntry client_entry, client_entry2;
291 SilcChannelEntry channel, channel2;
292 SilcServerEntry server_entry;
298 GSList *list1, *list_tmp;
300 SILC_LOG_DEBUG(("Start"));
304 server = conn == NULL ? NULL : conn->context;
307 case SILC_NOTIFY_TYPE_NONE:
308 /* Some generic notice from server */
309 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
312 case SILC_NOTIFY_TYPE_INVITE:
314 * Invited or modified invite list.
317 SILC_LOG_DEBUG(("Notify: INVITE"));
319 channel = va_arg(va, SilcChannelEntry);
320 name = va_arg(va, char *);
321 client_entry = va_arg(va, SilcClientEntry);
323 memset(buf, 0, sizeof(buf));
324 snprintf(buf, sizeof(buf) - 1, "%s@%s",
325 client_entry->username, client_entry->hostname);
326 signal_emit("message invite", 4, server, channel ? channel->channel_name :
327 name, client_entry->nickname, buf);
330 case SILC_NOTIFY_TYPE_JOIN:
335 SILC_LOG_DEBUG(("Notify: JOIN"));
337 client_entry = va_arg(va, SilcClientEntry);
338 channel = va_arg(va, SilcChannelEntry);
340 if (client_entry == server->conn->local_entry) {
341 /* You joined to channel */
342 chanrec = silc_channel_find(server, channel->channel_name);
343 if (chanrec != NULL && !chanrec->joined)
344 chanrec->entry = channel;
346 chanrec = silc_channel_find_entry(server, channel);
347 if (chanrec != NULL) {
348 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
350 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
354 memset(buf, 0, sizeof(buf));
355 if (client_entry->username)
356 snprintf(buf, sizeof(buf) - 1, "%s@%s",
357 client_entry->username, client_entry->hostname);
358 signal_emit("message join", 4, server, channel->channel_name,
359 client_entry->nickname,
360 client_entry->username == NULL ? "" : buf);
363 case SILC_NOTIFY_TYPE_LEAVE:
368 SILC_LOG_DEBUG(("Notify: LEAVE"));
370 client_entry = va_arg(va, SilcClientEntry);
371 channel = va_arg(va, SilcChannelEntry);
373 memset(buf, 0, sizeof(buf));
374 if (client_entry->username)
375 snprintf(buf, sizeof(buf) - 1, "%s@%s",
376 client_entry->username, client_entry->hostname);
377 signal_emit("message part", 5, server, channel->channel_name,
378 client_entry->nickname, client_entry->username ?
379 buf : "", client_entry->nickname);
381 chanrec = silc_channel_find_entry(server, channel);
382 if (chanrec != NULL) {
383 nickrec = silc_nicklist_find(chanrec, client_entry);
385 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
389 case SILC_NOTIFY_TYPE_SIGNOFF:
394 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
396 client_entry = va_arg(va, SilcClientEntry);
397 tmp = va_arg(va, char *);
399 silc_server_free_ftp(server, client_entry);
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 quit", 4, server, client_entry->nickname,
406 client_entry->username ? buf : "",
409 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
410 for (list_tmp = list1; list_tmp != NULL; list_tmp =
411 list_tmp->next->next) {
412 CHANNEL_REC *channel = list_tmp->data;
413 NICK_REC *nickrec = list_tmp->next->data;
415 nicklist_remove(channel, nickrec);
419 case SILC_NOTIFY_TYPE_TOPIC_SET:
424 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
426 idtype = va_arg(va, int);
427 entry = va_arg(va, void *);
428 tmp = va_arg(va, char *);
429 channel = va_arg(va, SilcChannelEntry);
431 chanrec = silc_channel_find_entry(server, channel);
432 if (chanrec != NULL) {
433 g_free_not_null(chanrec->topic);
434 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
435 signal_emit("channel topic changed", 1, chanrec);
438 if (idtype == SILC_ID_CLIENT) {
439 client_entry = (SilcClientEntry)entry;
440 memset(buf, 0, sizeof(buf));
441 snprintf(buf, sizeof(buf) - 1, "%s@%s",
442 client_entry->username, client_entry->hostname);
443 signal_emit("message topic", 5, server, channel->channel_name,
444 tmp, client_entry->nickname, buf);
445 } else if (idtype == SILC_ID_SERVER) {
446 server_entry = (SilcServerEntry)entry;
447 signal_emit("message topic", 5, server, channel->channel_name,
448 tmp, server_entry->server_name,
449 server_entry->server_name);
450 } else if (idtype == SILC_ID_CHANNEL) {
451 channel = (SilcChannelEntry)entry;
452 signal_emit("message topic", 5, server, channel->channel_name,
453 tmp, channel->channel_name, channel->channel_name);
457 case SILC_NOTIFY_TYPE_NICK_CHANGE:
462 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
464 client_entry = va_arg(va, SilcClientEntry);
465 client_entry2 = va_arg(va, SilcClientEntry);
467 if (!strcmp(client_entry->nickname, client_entry2->nickname))
470 memset(buf, 0, sizeof(buf));
471 snprintf(buf, sizeof(buf) - 1, "%s@%s",
472 client_entry2->username, client_entry2->hostname);
473 nicklist_rename_unique(SERVER(server),
474 client_entry, client_entry->nickname,
475 client_entry2, client_entry2->nickname);
476 signal_emit("message nick", 4, server, client_entry2->nickname,
477 client_entry->nickname, buf);
480 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
482 * Changed channel mode.
485 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
487 idtype = va_arg(va, int);
488 entry = va_arg(va, void *);
489 mode = va_arg(va, SilcUInt32);
490 (void)va_arg(va, char *);
491 (void)va_arg(va, char *);
492 channel = va_arg(va, SilcChannelEntry);
494 tmp = silc_client_chmode(mode,
495 channel->channel_key ?
496 channel->channel_key->cipher->name : "",
498 silc_hmac_get_name(channel->hmac) : "");
500 chanrec = silc_channel_find_entry(server, channel);
501 if (chanrec != NULL) {
502 g_free_not_null(chanrec->mode);
503 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
504 signal_emit("channel mode changed", 1, chanrec);
507 if (idtype == SILC_ID_CLIENT) {
508 client_entry = (SilcClientEntry)entry;
509 printformat_module("fe-common/silc", server, channel->channel_name,
510 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
511 channel->channel_name, tmp ? tmp : "removed all",
512 client_entry->nickname);
513 } else if (idtype == SILC_ID_SERVER) {
514 server_entry = (SilcServerEntry)entry;
515 printformat_module("fe-common/silc", server, channel->channel_name,
516 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
517 channel->channel_name, tmp ? tmp : "removed all",
518 server_entry->server_name);
519 } else if (idtype == SILC_ID_CHANNEL) {
520 channel2 = (SilcChannelEntry)entry;
521 printformat_module("fe-common/silc", server, channel->channel_name,
522 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
523 channel->channel_name, tmp ? tmp : "removed all",
524 channel2->channel_name);
530 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
532 * Changed user's mode on channel.
535 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
537 idtype = va_arg(va, int);
538 entry = va_arg(va, void *);
539 mode = va_arg(va, SilcUInt32);
540 client_entry2 = va_arg(va, SilcClientEntry);
541 channel = va_arg(va, SilcChannelEntry);
543 tmp = silc_client_chumode(mode);
544 chanrec = silc_channel_find_entry(server, channel);
545 if (chanrec != NULL) {
548 if (client_entry2 == server->conn->local_entry)
549 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
551 nick = silc_nicklist_find(chanrec, client_entry2);
553 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
554 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
555 signal_emit("nick mode changed", 2, chanrec, nick);
559 if (idtype == SILC_ID_CLIENT) {
560 client_entry = (SilcClientEntry)entry;
561 printformat_module("fe-common/silc", server, channel->channel_name,
562 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
563 channel->channel_name, client_entry2->nickname,
564 tmp ? tmp : "removed all",
565 client_entry->nickname);
566 } else if (idtype == SILC_ID_SERVER) {
567 server_entry = (SilcServerEntry)entry;
568 printformat_module("fe-common/silc", server, channel->channel_name,
569 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
570 channel->channel_name, client_entry2->nickname,
571 tmp ? tmp : "removed all",
572 server_entry->server_name);
573 } else if (idtype == SILC_ID_CHANNEL) {
574 channel2 = (SilcChannelEntry)entry;
575 printformat_module("fe-common/silc", server, channel->channel_name,
576 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
577 channel->channel_name, client_entry2->nickname,
578 tmp ? tmp : "removed all",
579 channel2->channel_name);
582 if (mode & SILC_CHANNEL_UMODE_CHANFO)
583 printformat_module("fe-common/silc",
584 server, channel->channel_name, MSGLEVEL_CRAP,
585 SILCTXT_CHANNEL_FOUNDER,
586 channel->channel_name, client_entry2->nickname);
588 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
589 printformat_module("fe-common/silc",
590 server, channel->channel_name, MSGLEVEL_CRAP,
591 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
596 case SILC_NOTIFY_TYPE_MOTD:
601 SILC_LOG_DEBUG(("Notify: MOTD"));
603 tmp = va_arg(va, char *);
605 if (!settings_get_bool("skip_motd"))
606 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
609 case SILC_NOTIFY_TYPE_KICKED:
611 * Someone was kicked from channel.
614 SILC_LOG_DEBUG(("Notify: KICKED"));
616 client_entry = va_arg(va, SilcClientEntry);
617 tmp = va_arg(va, char *);
618 client_entry2 = va_arg(va, SilcClientEntry);
619 channel = va_arg(va, SilcChannelEntry);
621 chanrec = silc_channel_find_entry(server, channel);
623 if (client_entry == conn->local_entry) {
624 printformat_module("fe-common/silc", server, channel->channel_name,
625 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
626 channel->channel_name,
627 client_entry ? client_entry2->nickname : "",
630 chanrec->kicked = TRUE;
631 channel_destroy((CHANNEL_REC *)chanrec);
634 printformat_module("fe-common/silc", server, channel->channel_name,
635 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
636 client_entry->nickname, channel->channel_name,
637 client_entry2 ? client_entry2->nickname : "",
641 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
643 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
648 case SILC_NOTIFY_TYPE_KILLED:
650 * Someone was killed from the network.
653 SILC_LOG_DEBUG(("Notify: KILLED"));
655 client_entry = va_arg(va, SilcClientEntry);
656 tmp = va_arg(va, char *);
657 idtype = va_arg(va, int);
658 entry = va_arg(va, SilcClientEntry);
660 if (client_entry == conn->local_entry) {
661 if (idtype == SILC_ID_CLIENT) {
662 client_entry2 = (SilcClientEntry)entry;
663 printformat_module("fe-common/silc", server, NULL,
664 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
665 client_entry2 ? client_entry2->nickname : "",
667 } else if (idtype == SILC_ID_SERVER) {
668 server_entry = (SilcServerEntry)entry;
669 printformat_module("fe-common/silc", server, NULL,
670 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
671 server_entry->server_name, tmp ? tmp : "");
672 } else if (idtype == SILC_ID_CHANNEL) {
673 channel = (SilcChannelEntry)entry;
674 printformat_module("fe-common/silc", server, NULL,
675 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
676 channel->channel_name, tmp ? tmp : "");
679 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
680 for (list_tmp = list1; list_tmp != NULL; list_tmp =
681 list_tmp->next->next) {
682 CHANNEL_REC *channel = list_tmp->data;
683 NICK_REC *nickrec = list_tmp->next->data;
684 nicklist_remove(channel, nickrec);
687 if (idtype == SILC_ID_CLIENT) {
688 client_entry2 = (SilcClientEntry)entry;
689 printformat_module("fe-common/silc", server, NULL,
690 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
691 client_entry->nickname,
692 client_entry2 ? client_entry2->nickname : "",
694 } else if (idtype == SILC_ID_SERVER) {
695 server_entry = (SilcServerEntry)entry;
696 printformat_module("fe-common/silc", server, NULL,
697 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
698 client_entry->nickname,
699 server_entry->server_name, tmp ? tmp : "");
700 } else if (idtype == SILC_ID_CHANNEL) {
701 channel = (SilcChannelEntry)entry;
702 printformat_module("fe-common/silc", server, NULL,
703 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
704 client_entry->nickname,
705 channel->channel_name, tmp ? tmp : "");
710 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
713 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
716 * Server has quit the network.
719 SilcClientEntry *clients;
720 SilcUInt32 clients_count;
722 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
724 (void)va_arg(va, void *);
725 clients = va_arg(va, SilcClientEntry *);
726 clients_count = va_arg(va, SilcUInt32);
728 for (i = 0; i < clients_count; i++) {
729 memset(buf, 0, sizeof(buf));
730 if (clients[i]->username)
731 snprintf(buf, sizeof(buf) - 1, "%s@%s",
732 clients[i]->username, clients[i]->hostname);
733 signal_emit("message quit", 4, server, clients[i]->nickname,
734 clients[i]->username ? buf : "",
737 silc_server_free_ftp(server, clients[i]);
739 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
740 for (list_tmp = list1; list_tmp != NULL; list_tmp =
741 list_tmp->next->next) {
742 CHANNEL_REC *channel = list_tmp->data;
743 NICK_REC *nickrec = list_tmp->next->data;
744 nicklist_remove(channel, nickrec);
750 case SILC_NOTIFY_TYPE_ERROR:
752 SilcStatus error = va_arg(va, int);
754 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
755 "%s", silc_get_status_message(error));
759 case SILC_NOTIFY_TYPE_WATCH:
761 SilcNotifyType notify;
763 client_entry = va_arg(va, SilcClientEntry);
764 name = va_arg(va, char *); /* Maybe NULL */
765 mode = va_arg(va, SilcUInt32);
766 notify = va_arg(va, int);
768 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
770 printformat_module("fe-common/silc", server, NULL,
771 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
772 client_entry->nickname, name);
774 printformat_module("fe-common/silc", server, NULL,
775 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
776 client_entry->nickname);
777 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
778 /* See if client was away and is now present */
779 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
780 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
781 SILC_UMODE_DETACHED)) &&
782 (client_entry->mode & SILC_UMODE_GONE ||
783 client_entry->mode & SILC_UMODE_INDISPOSED ||
784 client_entry->mode & SILC_UMODE_BUSY ||
785 client_entry->mode & SILC_UMODE_PAGE ||
786 client_entry->mode & SILC_UMODE_DETACHED)) {
787 printformat_module("fe-common/silc", server, NULL,
788 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
789 client_entry->nickname);
793 memset(buf, 0, sizeof(buf));
794 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
795 printformat_module("fe-common/silc", server, NULL,
796 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
797 client_entry->nickname, buf);
799 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
800 printformat_module("fe-common/silc", server, NULL,
801 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
802 client_entry->nickname);
803 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
804 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
805 printformat_module("fe-common/silc", server, NULL,
806 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
807 client_entry->nickname);
808 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
809 /* Client logged in to the network */
810 printformat_module("fe-common/silc", server, NULL,
811 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
812 client_entry->nickname);
819 printformat_module("fe-common/silc", server, NULL,
820 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
827 /* Called to indicate that connection was either successfully established
828 or connecting failed. This is also the first time application receives
829 the SilcClientConnection object which it should save somewhere. */
831 void silc_connect(SilcClient client, SilcClientConnection conn,
832 SilcClientConnectionStatus status)
834 SILC_SERVER_REC *server = conn->context;
836 if (!server || server->disconnected) {
837 silc_client_close_connection(client, conn);
842 case SILC_CLIENT_CONN_SUCCESS:
843 /* We have successfully connected to server */
844 server->connected = TRUE;
845 signal_emit("event connected", 1, server);
848 case SILC_CLIENT_CONN_SUCCESS_RESUME:
849 /* We have successfully resumed old detached session */
850 server->connected = TRUE;
851 signal_emit("event connected", 1, server);
853 /* If we resumed old session check whether we need to update
855 if (strcmp(server->nick, conn->local_entry->nickname)) {
857 old = g_strdup(server->nick);
858 server_change_nick(SERVER(server), conn->local_entry->nickname);
859 nicklist_rename_unique(SERVER(server),
860 conn->local_entry, server->nick,
861 conn->local_entry, conn->local_entry->nickname);
862 signal_emit("message own_nick", 4, server, server->nick, old, "");
868 server->connection_lost = TRUE;
870 server->conn->context = NULL;
871 server_disconnect(SERVER(server));
876 /* Called to indicate that connection was disconnected to the server. */
878 void silc_disconnect(SilcClient client, SilcClientConnection conn,
879 SilcStatus status, const char *message)
881 SILC_SERVER_REC *server = conn->context;
883 SILC_LOG_DEBUG(("Start"));
885 if (!server || server->connection_lost)
888 if (server->conn && server->conn->local_entry) {
889 nicklist_rename_unique(SERVER(server),
890 server->conn->local_entry, server->nick,
891 server->conn->local_entry,
892 silc_client->username);
893 silc_change_nick(server, silc_client->username);
897 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
898 "Server closed connection: %s (%d) %s",
899 silc_get_status_message(status), status,
900 message ? message : "");
902 server->conn->context = NULL;
904 server->connection_lost = TRUE;
905 server_disconnect(SERVER(server));
908 /* Command handler. This function is called always in the command function.
909 If error occurs it will be called as well. `conn' is the associated
910 client connection. `cmd_context' is the command context that was
911 originally sent to the command. `success' is FALSE if error occured
912 during command. `command' is the command being processed. It must be
913 noted that this is not reply from server. This is merely called just
914 after application has called the command. Just to tell application
915 that the command really was processed. */
917 void silc_command(SilcClient client, SilcClientConnection conn,
918 SilcClientCommandContext cmd_context, bool success,
919 SilcCommand command, SilcStatus status)
921 SILC_SERVER_REC *server = conn->context;
923 SILC_LOG_DEBUG(("Start"));
926 silc_say_error("%s", silc_get_status_message(status));
931 case SILC_COMMAND_INVITE:
932 printformat_module("fe-common/silc", server, NULL,
933 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
934 cmd_context->argv[2],
935 (cmd_context->argv[1][0] == '*' ?
936 (char *)conn->current_channel->channel_name :
937 (char *)cmd_context->argv[1]));
944 /* Client info resolving callback when JOIN command reply is received.
945 This will cache all users on the channel. */
947 static void silc_client_join_get_users(SilcClient client,
948 SilcClientConnection conn,
949 SilcClientEntry *clients,
950 SilcUInt32 clients_count,
953 SilcChannelEntry channel = (SilcChannelEntry)context;
954 SilcHashTableList htl;
956 SILC_SERVER_REC *server = conn->context;
957 SILC_CHANNEL_REC *chanrec;
958 SilcClientEntry founder = NULL;
961 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
962 silc_hash_table_count(channel->user_list)));
967 chanrec = silc_channel_find(server, channel->channel_name);
971 silc_hash_table_list(channel->user_list, &htl);
972 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
973 if (!chu->client->nickname)
975 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
976 founder = chu->client;
977 silc_nicklist_insert(chanrec, chu, FALSE);
979 silc_hash_table_list_reset(&htl);
981 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
982 nicklist_set_own(CHANNEL(chanrec), ownnick);
983 signal_emit("channel joined", 1, chanrec);
984 chanrec->entry = channel;
987 printformat_module("fe-common/silc", server, channel->channel_name,
988 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
989 channel->channel_name, chanrec->topic);
991 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
994 if (founder == conn->local_entry)
995 printformat_module("fe-common/silc",
996 server, channel->channel_name, MSGLEVEL_CRAP,
997 SILCTXT_CHANNEL_FOUNDER_YOU,
998 channel->channel_name);
1000 printformat_module("fe-common/silc",
1001 server, channel->channel_name, MSGLEVEL_CRAP,
1002 SILCTXT_CHANNEL_FOUNDER,
1003 channel->channel_name, founder->nickname);
1009 SilcClientConnection conn;
1015 void silc_getkey_cb(bool success, void *context)
1017 GetkeyContext getkey = (GetkeyContext)context;
1018 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1019 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1020 ((SilcClientEntry)getkey->entry)->nickname :
1021 ((SilcServerEntry)getkey->entry)->server_name);
1024 printformat_module("fe-common/silc", NULL, NULL,
1025 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
1027 printformat_module("fe-common/silc", NULL, NULL,
1028 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
1031 silc_free(getkey->fingerprint);
1035 /* Command reply handler. This function is called always in the command reply
1036 function. If error occurs it will be called as well. Normal scenario
1037 is that it will be called after the received command data has been parsed
1038 and processed. The function is used to pass the received command data to
1041 `conn' is the associated client connection. `cmd_payload' is the command
1042 payload data received from server and it can be ignored. It is provided
1043 if the application would like to re-parse the received command data,
1044 however, it must be noted that the data is parsed already by the library
1045 thus the payload can be ignored. `success' is FALSE if error occured.
1046 In this case arguments are not sent to the application. `command' is the
1047 command reply being processed. The function has variable argument list
1048 and each command defines the number and type of arguments it passes to the
1049 application (on error they are not sent). */
1052 silc_command_reply(SilcClient client, SilcClientConnection conn,
1053 SilcCommandPayload cmd_payload, bool success,
1054 SilcCommand command, SilcStatus status, ...)
1057 SILC_SERVER_REC *server = conn->context;
1058 SILC_CHANNEL_REC *chanrec;
1061 va_start(vp, status);
1063 SILC_LOG_DEBUG(("Start"));
1066 case SILC_COMMAND_WHOIS:
1068 char buf[1024], *nickname, *username, *realname, *nick;
1069 unsigned char *fingerprint;
1070 SilcUInt32 idle, mode;
1071 SilcBuffer channels, user_modes;
1072 SilcClientEntry client_entry;
1074 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1075 /* Print the unknown nick for user */
1076 unsigned char *tmp =
1077 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1080 silc_say_error("%s: %s", tmp,
1081 silc_get_status_message(status));
1083 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1084 /* Try to find the entry for the unknown client ID, since we
1085 might have, and print the nickname of it for user. */
1087 unsigned char *tmp =
1088 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1091 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1094 client_entry = silc_client_get_client_by_id(client, conn,
1096 if (client_entry && client_entry->nickname)
1097 silc_say_error("%s: %s", client_entry->nickname,
1098 silc_get_status_message(status));
1099 silc_free(client_id);
1108 client_entry = va_arg(vp, SilcClientEntry);
1109 nickname = va_arg(vp, char *);
1110 username = va_arg(vp, char *);
1111 realname = va_arg(vp, char *);
1112 channels = va_arg(vp, SilcBuffer);
1113 mode = va_arg(vp, SilcUInt32);
1114 idle = va_arg(vp, SilcUInt32);
1115 fingerprint = va_arg(vp, unsigned char *);
1116 user_modes = va_arg(vp, SilcBuffer);
1118 silc_parse_userfqdn(nickname, &nick, NULL);
1119 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1120 SILCTXT_WHOIS_USERINFO, nickname,
1121 client_entry->username, client_entry->hostname,
1122 nick, client_entry->nickname);
1123 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1124 SILCTXT_WHOIS_REALNAME, realname);
1127 if (channels && user_modes) {
1129 SilcDList list = silc_channel_payload_parse_list(channels->data,
1131 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1133 SilcChannelPayload entry;
1136 memset(buf, 0, sizeof(buf));
1137 silc_dlist_start(list);
1138 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1139 SilcUInt32 name_len;
1140 char *m = silc_client_chumode_char(umodes[i++]);
1141 char *name = silc_channel_get_name(entry, &name_len);
1144 strncat(buf, m, strlen(m));
1145 strncat(buf, name, name_len);
1146 strncat(buf, " ", 1);
1150 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1151 SILCTXT_WHOIS_CHANNELS, buf);
1152 silc_channel_payload_list_free(list);
1158 memset(buf, 0, sizeof(buf));
1159 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1160 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1161 SILCTXT_WHOIS_MODES, buf);
1164 if (idle && nickname) {
1165 memset(buf, 0, sizeof(buf));
1166 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1167 idle > 60 ? (idle / 60) : idle,
1168 idle > 60 ? "minutes" : "seconds");
1170 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1171 SILCTXT_WHOIS_IDLE, buf);
1175 fingerprint = silc_fingerprint(fingerprint, 20);
1176 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1177 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1178 silc_free(fingerprint);
1183 case SILC_COMMAND_IDENTIFY:
1185 SilcClientEntry client_entry;
1187 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1188 /* Print the unknown nick for user */
1189 unsigned char *tmp =
1190 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1193 silc_say_error("%s: %s", tmp,
1194 silc_get_status_message(status));
1196 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1197 /* Try to find the entry for the unknown client ID, since we
1198 might have, and print the nickname of it for user. */
1200 unsigned char *tmp =
1201 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1204 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1207 client_entry = silc_client_get_client_by_id(client, conn,
1209 if (client_entry && client_entry->nickname)
1210 silc_say_error("%s: %s", client_entry->nickname,
1211 silc_get_status_message(status));
1212 silc_free(client_id);
1221 case SILC_COMMAND_WHOWAS:
1223 char *nickname, *username, *realname;
1225 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1226 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1228 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1231 silc_say_error("%s: %s", tmp,
1232 silc_get_status_message(status));
1239 (void)va_arg(vp, SilcClientEntry);
1240 nickname = va_arg(vp, char *);
1241 username = va_arg(vp, char *);
1242 realname = va_arg(vp, char *);
1244 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1245 SILCTXT_WHOWAS_USERINFO, nickname, username,
1246 realname ? realname : "");
1250 case SILC_COMMAND_INVITE:
1252 SilcChannelEntry channel;
1254 SilcArgumentPayload args;
1260 channel = va_arg(vp, SilcChannelEntry);
1261 invite_list = va_arg(vp, char *);
1263 args = silc_command_get_args(cmd_payload);
1265 argc = silc_argument_get_arg_num(args);
1268 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1269 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1272 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1273 SILCTXT_CHANNEL_NO_INVITE_LIST,
1274 channel->channel_name);
1278 case SILC_COMMAND_JOIN:
1280 char *channel, *mode, *topic;
1282 SilcChannelEntry channel_entry;
1283 SilcBuffer client_id_list;
1284 SilcUInt32 list_count;
1289 channel = va_arg(vp, char *);
1290 channel_entry = va_arg(vp, SilcChannelEntry);
1291 modei = va_arg(vp, SilcUInt32);
1292 (void)va_arg(vp, SilcUInt32);
1293 (void)va_arg(vp, unsigned char *);
1294 (void)va_arg(vp, unsigned char *);
1295 (void)va_arg(vp, unsigned char *);
1296 topic = va_arg(vp, char *);
1297 (void)va_arg(vp, unsigned char *);
1298 list_count = va_arg(vp, SilcUInt32);
1299 client_id_list = va_arg(vp, SilcBuffer);
1301 chanrec = silc_channel_find(server, channel);
1303 chanrec = silc_channel_create(server, channel, TRUE);
1306 g_free_not_null(chanrec->topic);
1307 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1308 signal_emit("channel topic changed", 1, chanrec);
1311 mode = silc_client_chmode(modei,
1312 channel_entry->channel_key ?
1313 channel_entry->channel_key->cipher->name : "",
1314 channel_entry->hmac ?
1315 silc_hmac_get_name(channel_entry->hmac) : "");
1316 g_free_not_null(chanrec->mode);
1317 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1318 signal_emit("channel mode changed", 1, chanrec);
1320 /* Resolve the client information */
1321 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1322 silc_client_join_get_users,
1328 case SILC_COMMAND_NICK:
1331 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1336 old = g_strdup(server->nick);
1337 server_change_nick(SERVER(server), client->nickname);
1338 nicklist_rename_unique(SERVER(server),
1339 server->conn->local_entry, server->nick,
1340 client, client->nickname);
1341 signal_emit("message own_nick", 4, server, server->nick, old, "");
1346 case SILC_COMMAND_LIST:
1355 (void)va_arg(vp, SilcChannelEntry);
1356 name = va_arg(vp, char *);
1357 topic = va_arg(vp, char *);
1358 usercount = va_arg(vp, int);
1360 if (status == SILC_STATUS_LIST_START ||
1361 status == SILC_STATUS_OK)
1362 printformat_module("fe-common/silc", server, NULL,
1363 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1366 snprintf(users, sizeof(users) - 1, "N/A");
1368 snprintf(users, sizeof(users) - 1, "%d", usercount);
1369 printformat_module("fe-common/silc", server, NULL,
1370 MSGLEVEL_CRAP, SILCTXT_LIST,
1371 name, users, topic ? topic : "");
1375 case SILC_COMMAND_UMODE:
1382 mode = va_arg(vp, SilcUInt32);
1384 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1385 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1386 printformat_module("fe-common/silc", server, NULL,
1387 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1389 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1390 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1391 printformat_module("fe-common/silc", server, NULL,
1392 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1394 server->umode = mode;
1395 signal_emit("user mode changed", 2, server, NULL);
1399 case SILC_COMMAND_OPER:
1403 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1404 signal_emit("user mode changed", 2, server, NULL);
1406 printformat_module("fe-common/silc", server, NULL,
1407 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1410 case SILC_COMMAND_SILCOPER:
1414 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1415 signal_emit("user mode changed", 2, server, NULL);
1417 printformat_module("fe-common/silc", server, NULL,
1418 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1421 case SILC_COMMAND_USERS:
1423 SilcHashTableList htl;
1424 SilcChannelEntry channel;
1425 SilcChannelUser chu;
1430 channel = va_arg(vp, SilcChannelEntry);
1432 printformat_module("fe-common/silc", server, channel->channel_name,
1433 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1434 channel->channel_name);
1436 silc_hash_table_list(channel->user_list, &htl);
1437 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1438 SilcClientEntry e = chu->client;
1439 char stat[5], *mode;
1444 memset(stat, 0, sizeof(stat));
1445 mode = silc_client_chumode_char(chu->mode);
1446 if (e->mode & SILC_UMODE_GONE)
1448 else if (e->mode & SILC_UMODE_INDISPOSED)
1450 else if (e->mode & SILC_UMODE_BUSY)
1452 else if (e->mode & SILC_UMODE_PAGE)
1454 else if (e->mode & SILC_UMODE_HYPER)
1456 else if (e->mode & SILC_UMODE_ROBOT)
1458 else if (e->mode & SILC_UMODE_ANONYMOUS)
1465 printformat_module("fe-common/silc", server, channel->channel_name,
1466 MSGLEVEL_CRAP, SILCTXT_USERS,
1468 e->username ? e->username : "",
1469 e->hostname ? e->hostname : "",
1470 e->realname ? e->realname : "");
1474 silc_hash_table_list_reset(&htl);
1478 case SILC_COMMAND_BAN:
1480 SilcChannelEntry channel;
1486 channel = va_arg(vp, SilcChannelEntry);
1487 ban_list = va_arg(vp, char *);
1490 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1491 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1494 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1495 SILCTXT_CHANNEL_NO_BAN_LIST,
1496 channel->channel_name);
1500 case SILC_COMMAND_GETKEY:
1504 SilcPublicKey public_key;
1507 GetkeyContext getkey;
1513 id_type = va_arg(vp, SilcUInt32);
1514 entry = va_arg(vp, void *);
1515 public_key = va_arg(vp, SilcPublicKey);
1518 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1520 getkey = silc_calloc(1, sizeof(*getkey));
1521 getkey->entry = entry;
1522 getkey->id_type = id_type;
1523 getkey->client = client;
1524 getkey->conn = conn;
1525 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1527 name = (id_type == SILC_ID_CLIENT ?
1528 ((SilcClientEntry)entry)->nickname :
1529 ((SilcServerEntry)entry)->server_name);
1531 silc_verify_public_key_internal(client, conn, name,
1532 (id_type == SILC_ID_CLIENT ?
1533 SILC_SOCKET_TYPE_CLIENT :
1534 SILC_SOCKET_TYPE_SERVER),
1535 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1536 silc_getkey_cb, getkey);
1539 printformat_module("fe-common/silc", server, NULL,
1540 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1545 case SILC_COMMAND_INFO:
1547 SilcServerEntry server_entry;
1554 server_entry = va_arg(vp, SilcServerEntry);
1555 server_name = va_arg(vp, char *);
1556 server_info = va_arg(vp, char *);
1558 if (server_name && server_info )
1560 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1561 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1566 case SILC_COMMAND_TOPIC:
1568 SilcChannelEntry channel;
1574 channel = va_arg(vp, SilcChannelEntry);
1575 topic = va_arg(vp, char *);
1578 chanrec = silc_channel_find_entry(server, channel);
1580 g_free_not_null(chanrec->topic);
1581 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1582 signal_emit("channel topic changed", 1, chanrec);
1584 printformat_module("fe-common/silc", server, channel->channel_name,
1585 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1586 channel->channel_name, topic);
1588 printformat_module("fe-common/silc", server, channel->channel_name,
1589 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1590 channel->channel_name);
1595 case SILC_COMMAND_WATCH:
1604 SilcClientConnection conn;
1610 SilcSKEPKType pk_type;
1611 SilcVerifyPublicKey completion;
1615 static void verify_public_key_completion(const char *line, void *context)
1617 PublicKeyVerify verify = (PublicKeyVerify)context;
1619 if (line[0] == 'Y' || line[0] == 'y') {
1620 /* Call the completion */
1621 if (verify->completion)
1622 verify->completion(TRUE, verify->context);
1624 /* Save the key for future checking */
1625 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1626 verify->pk_len, SILC_PKCS_FILE_PEM);
1628 /* Call the completion */
1629 if (verify->completion)
1630 verify->completion(FALSE, verify->context);
1632 printformat_module("fe-common/silc", NULL, NULL,
1633 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1634 verify->entity_name ? verify->entity_name :
1638 silc_free(verify->filename);
1639 silc_free(verify->entity);
1640 silc_free(verify->entity_name);
1641 silc_free(verify->pk);
1645 /* Internal routine to verify public key. If the `completion' is provided
1646 it will be called to indicate whether public was verified or not. For
1647 server/router public key this will check for filename that includes the
1648 remote host's IP address and remote host's hostname. */
1651 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1652 const char *name, SilcSocketType conn_type,
1653 unsigned char *pk, SilcUInt32 pk_len,
1654 SilcSKEPKType pk_type,
1655 SilcVerifyPublicKey completion, void *context)
1658 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1659 char *fingerprint, *babbleprint, *format;
1662 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1663 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1664 "server" : "client");
1665 PublicKeyVerify verify;
1667 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1668 printformat_module("fe-common/silc", NULL, NULL,
1669 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1672 completion(FALSE, context);
1676 pw = getpwuid(getuid());
1679 completion(FALSE, context);
1683 memset(filename, 0, sizeof(filename));
1684 memset(filename2, 0, sizeof(filename2));
1685 memset(file, 0, sizeof(file));
1687 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1688 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1690 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1691 conn->sock->ip, conn->sock->port);
1692 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1693 get_irssi_dir(), entity, file);
1695 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1696 conn->sock->hostname, conn->sock->port);
1697 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1698 get_irssi_dir(), entity, file);
1703 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1704 name, conn->sock->port);
1705 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1706 get_irssi_dir(), entity, file);
1711 /* Replace all whitespaces with `_'. */
1712 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1713 for (i = 0; i < strlen(fingerprint); i++)
1714 if (fingerprint[i] == ' ')
1715 fingerprint[i] = '_';
1717 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1718 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1719 get_irssi_dir(), entity, file);
1720 silc_free(fingerprint);
1725 /* Take fingerprint of the public key */
1726 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1727 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1729 verify = silc_calloc(1, sizeof(*verify));
1730 verify->client = client;
1731 verify->conn = conn;
1732 verify->filename = strdup(ipf);
1733 verify->entity = strdup(entity);
1734 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1735 (name ? strdup(name) : strdup(conn->sock->hostname))
1737 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1738 memcpy(verify->pk, pk, pk_len);
1739 verify->pk_len = pk_len;
1740 verify->pk_type = pk_type;
1741 verify->completion = completion;
1742 verify->context = context;
1744 /* Check whether this key already exists */
1745 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1746 /* Key does not exist, ask user to verify the key and save it */
1748 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1749 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1750 verify->entity_name : entity);
1751 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1752 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1753 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1754 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1755 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1756 SILCTXT_PUBKEY_ACCEPT);
1757 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1760 silc_free(fingerprint);
1763 /* The key already exists, verify it. */
1764 SilcPublicKey public_key;
1765 unsigned char *encpk;
1766 SilcUInt32 encpk_len;
1768 /* Load the key file, try for both IP filename and hostname filename */
1769 if (!silc_pkcs_load_public_key(ipf, &public_key,
1770 SILC_PKCS_FILE_PEM) &&
1771 !silc_pkcs_load_public_key(ipf, &public_key,
1772 SILC_PKCS_FILE_BIN) &&
1773 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1774 SILC_PKCS_FILE_PEM) &&
1775 !silc_pkcs_load_public_key(hostf, &public_key,
1776 SILC_PKCS_FILE_BIN)))) {
1777 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1778 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1779 verify->entity_name : entity);
1780 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1781 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1782 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1783 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1784 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1785 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
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 /* Encode the key data */
1796 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1798 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1799 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1800 verify->entity_name : entity);
1801 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1802 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1803 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1804 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1805 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1806 SILCTXT_PUBKEY_MALFORMED, entity);
1807 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1808 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1809 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1812 silc_free(fingerprint);
1816 /* Compare the keys */
1817 if (memcmp(encpk, pk, encpk_len)) {
1818 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1819 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1820 verify->entity_name : entity);
1821 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1822 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1823 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1824 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1825 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1826 SILCTXT_PUBKEY_NO_MATCH, entity);
1827 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1828 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1829 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1830 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1832 /* Ask user to verify the key and save it */
1833 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1834 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1835 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1838 silc_free(fingerprint);
1842 /* Local copy matched */
1844 completion(TRUE, context);
1845 silc_free(fingerprint);
1849 /* Verifies received public key. The `conn_type' indicates which entity
1850 (server, client etc.) has sent the public key. If user decides to trust
1851 the key may be saved as trusted public key for later use. The
1852 `completion' must be called after the public key has been verified. */
1855 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1856 SilcSocketType conn_type, unsigned char *pk,
1857 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1858 SilcVerifyPublicKey completion, void *context)
1860 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1862 completion, context);
1865 /* Asks passphrase from user on the input line. */
1868 SilcAskPassphrase completion;
1872 void ask_passphrase_completion(const char *passphrase, void *context)
1874 AskPassphrase p = (AskPassphrase)context;
1875 if (passphrase && passphrase[0] == '\0')
1877 p->completion((unsigned char *)passphrase,
1878 passphrase ? strlen(passphrase) : 0, p->context);
1882 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1883 SilcAskPassphrase completion, void *context)
1885 AskPassphrase p = silc_calloc(1, sizeof(*p));
1886 p->completion = completion;
1887 p->context = context;
1889 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1890 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1894 SilcGetAuthMeth completion;
1896 } *InternalGetAuthMethod;
1898 /* Callback called when we've received the authentication method information
1899 from the server after we've requested it. This will get the authentication
1900 data from the user if needed. */
1902 static void silc_get_auth_method_callback(SilcClient client,
1903 SilcClientConnection conn,
1904 SilcAuthMethod auth_meth,
1907 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1909 SILC_LOG_DEBUG(("Start"));
1911 switch (auth_meth) {
1912 case SILC_AUTH_NONE:
1913 /* No authentication required. */
1914 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1916 case SILC_AUTH_PASSWORD:
1917 /* Do not ask the passphrase from user, the library will ask it if
1918 we do not provide it here. */
1919 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1921 case SILC_AUTH_PUBLIC_KEY:
1922 /* Do not get the authentication data now, the library will generate
1923 it using our default key, if we do not provide it here. */
1924 /* XXX In the future when we support multiple local keys and multiple
1925 local certificates we will need to ask from user which one to use. */
1926 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1930 silc_free(internal);
1933 /* Find authentication method and authentication data by hostname and
1934 port. The hostname may be IP address as well. The found authentication
1935 method and authentication data is returned to `auth_meth', `auth_data'
1936 and `auth_data_len'. The function returns TRUE if authentication method
1937 is found and FALSE if not. `conn' may be NULL. */
1939 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1940 char *hostname, SilcUInt16 port,
1941 SilcGetAuthMeth completion, void *context)
1943 InternalGetAuthMethod internal;
1945 SILC_LOG_DEBUG(("Start"));
1947 /* XXX must resolve from configuration whether this connection has
1948 any specific authentication data */
1950 /* If we do not have this connection configured by the user in a
1951 configuration file then resolve the authentication method from the
1952 server for this session. */
1953 internal = silc_calloc(1, sizeof(*internal));
1954 internal->completion = completion;
1955 internal->context = context;
1957 silc_client_request_authentication_method(client, conn,
1958 silc_get_auth_method_callback,
1962 /* Notifies application that failure packet was received. This is called
1963 if there is some protocol active in the client. The `protocol' is the
1964 protocol context. The `failure' is opaque pointer to the failure
1965 indication. Note, that the `failure' is protocol dependant and application
1966 must explicitly cast it to correct type. Usually `failure' is 32 bit
1967 failure type (see protocol specs for all protocol failure types). */
1969 void silc_failure(SilcClient client, SilcClientConnection conn,
1970 SilcProtocol protocol, void *failure)
1972 SILC_LOG_DEBUG(("Start"));
1974 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1975 SilcSKEStatus status = (SilcSKEStatus)failure;
1977 if (status == SILC_SKE_STATUS_BAD_VERSION)
1978 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1979 SILCTXT_KE_BAD_VERSION);
1980 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1981 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1982 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1983 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1984 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1985 SILCTXT_KE_UNKNOWN_GROUP);
1986 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1987 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1988 SILCTXT_KE_UNKNOWN_CIPHER);
1989 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1990 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1991 SILCTXT_KE_UNKNOWN_PKCS);
1992 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1993 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1994 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1995 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1996 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1997 SILCTXT_KE_UNKNOWN_HMAC);
1998 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1999 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2000 SILCTXT_KE_INCORRECT_SIGNATURE);
2001 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2002 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2003 SILCTXT_KE_INVALID_COOKIE);
2006 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2007 SilcUInt32 err = (SilcUInt32)failure;
2009 if (err == SILC_AUTH_FAILED)
2010 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2011 SILCTXT_AUTH_FAILED);
2015 /* Asks whether the user would like to perform the key agreement protocol.
2016 This is called after we have received an key agreement packet or an
2017 reply to our key agreement packet. This returns TRUE if the user wants
2018 the library to perform the key agreement protocol and FALSE if it is not
2019 desired (application may start it later by calling the function
2020 silc_client_perform_key_agreement). */
2022 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
2023 SilcClientEntry client_entry, const char *hostname,
2024 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2029 SILC_LOG_DEBUG(("Start"));
2031 /* We will just display the info on the screen and return FALSE and user
2032 will have to start the key agreement with a command. */
2035 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2038 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2039 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2041 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2042 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2043 client_entry->nickname, hostname, portstr);
2051 /* Notifies application that file transfer protocol session is being
2052 requested by the remote client indicated by the `client_entry' from
2053 the `hostname' and `port'. The `session_id' is the file transfer
2054 session and it can be used to either accept or reject the file
2055 transfer request, by calling the silc_client_file_receive or
2056 silc_client_file_close, respectively. */
2058 void silc_ftp(SilcClient client, SilcClientConnection conn,
2059 SilcClientEntry client_entry, SilcUInt32 session_id,
2060 const char *hostname, SilcUInt16 port)
2062 SILC_SERVER_REC *server;
2064 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2066 SILC_LOG_DEBUG(("Start"));
2068 server = conn->context;
2070 ftp->client_entry = client_entry;
2071 ftp->session_id = session_id;
2074 silc_dlist_add(server->ftp_sessions, ftp);
2075 server->current_session = ftp;
2078 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2081 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2082 SILCTXT_FILE_REQUEST, client_entry->nickname);
2084 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2085 SILCTXT_FILE_REQUEST_HOST,
2086 client_entry->nickname, hostname, portstr);
2089 /* Delivers SILC session detachment data indicated by `detach_data' to the
2090 application. If application has issued SILC_COMMAND_DETACH command
2091 the client session in the SILC network is not quit. The client remains
2092 in the network but is detached. The detachment data may be used later
2093 to resume the session in the SILC Network. The appliation is
2094 responsible of saving the `detach_data', to for example in a file.
2096 The detachment data can be given as argument to the functions
2097 silc_client_connect_to_server, or silc_client_add_connection when
2098 creating connection to remote server, inside SilcClientConnectionParams
2099 structure. If it is provided the client library will attempt to resume
2100 the session in the network. After the connection is created
2101 successfully, the application is responsible of setting the user
2102 interface for user into the same state it was before detaching (showing
2103 same channels, channel modes, etc). It can do this by fetching the
2104 information (like joined channels) from the client library. */
2107 silc_detach(SilcClient client, SilcClientConnection conn,
2108 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2112 /* Save the detachment data to file. */
2114 memset(file, 0, sizeof(file));
2115 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2116 silc_file_writefile(file, detach_data, detach_data_len);
2120 /* SILC client operations */
2121 SilcClientOperations ops = {
2123 silc_channel_message,
2124 silc_private_message,
2130 silc_get_auth_method,
2131 silc_verify_public_key,
2132 silc_ask_passphrase,