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)
880 SILC_SERVER_REC *server = conn->context;
882 SILC_LOG_DEBUG(("Start"));
884 if (!server || server->connection_lost)
887 if (server->conn && server->conn->local_entry) {
888 nicklist_rename_unique(SERVER(server),
889 server->conn->local_entry, server->nick,
890 server->conn->local_entry,
891 silc_client->username);
892 silc_change_nick(server, silc_client->username);
895 server->conn->context = NULL;
897 server->connection_lost = TRUE;
898 server_disconnect(SERVER(server));
901 /* Command handler. This function is called always in the command function.
902 If error occurs it will be called as well. `conn' is the associated
903 client connection. `cmd_context' is the command context that was
904 originally sent to the command. `success' is FALSE if error occured
905 during command. `command' is the command being processed. It must be
906 noted that this is not reply from server. This is merely called just
907 after application has called the command. Just to tell application
908 that the command really was processed. */
910 void silc_command(SilcClient client, SilcClientConnection conn,
911 SilcClientCommandContext cmd_context, bool success,
912 SilcCommand command, SilcStatus status)
914 SILC_SERVER_REC *server = conn->context;
916 SILC_LOG_DEBUG(("Start"));
919 silc_say_error("%s", silc_get_status_message(status));
924 case SILC_COMMAND_INVITE:
925 printformat_module("fe-common/silc", server, NULL,
926 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
927 cmd_context->argv[2],
928 (cmd_context->argv[1][0] == '*' ?
929 (char *)conn->current_channel->channel_name :
930 (char *)cmd_context->argv[1]));
937 /* Client info resolving callback when JOIN command reply is received.
938 This will cache all users on the channel. */
940 static void silc_client_join_get_users(SilcClient client,
941 SilcClientConnection conn,
942 SilcClientEntry *clients,
943 SilcUInt32 clients_count,
946 SilcChannelEntry channel = (SilcChannelEntry)context;
947 SilcHashTableList htl;
949 SILC_SERVER_REC *server = conn->context;
950 SILC_CHANNEL_REC *chanrec;
951 SilcClientEntry founder = NULL;
954 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
955 silc_hash_table_count(channel->user_list)));
960 chanrec = silc_channel_find(server, channel->channel_name);
964 silc_hash_table_list(channel->user_list, &htl);
965 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
966 if (!chu->client->nickname)
968 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
969 founder = chu->client;
970 silc_nicklist_insert(chanrec, chu, FALSE);
972 silc_hash_table_list_reset(&htl);
974 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
975 nicklist_set_own(CHANNEL(chanrec), ownnick);
976 signal_emit("channel joined", 1, chanrec);
977 chanrec->entry = channel;
980 printformat_module("fe-common/silc", server, channel->channel_name,
981 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
982 channel->channel_name, chanrec->topic);
984 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
987 if (founder == conn->local_entry)
988 printformat_module("fe-common/silc",
989 server, channel->channel_name, MSGLEVEL_CRAP,
990 SILCTXT_CHANNEL_FOUNDER_YOU,
991 channel->channel_name);
993 printformat_module("fe-common/silc",
994 server, channel->channel_name, MSGLEVEL_CRAP,
995 SILCTXT_CHANNEL_FOUNDER,
996 channel->channel_name, founder->nickname);
1002 SilcClientConnection conn;
1008 void silc_getkey_cb(bool success, void *context)
1010 GetkeyContext getkey = (GetkeyContext)context;
1011 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1012 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1013 ((SilcClientEntry)getkey->entry)->nickname :
1014 ((SilcServerEntry)getkey->entry)->server_name);
1017 printformat_module("fe-common/silc", NULL, NULL,
1018 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
1020 printformat_module("fe-common/silc", NULL, NULL,
1021 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
1024 silc_free(getkey->fingerprint);
1028 /* Command reply handler. This function is called always in the command reply
1029 function. If error occurs it will be called as well. Normal scenario
1030 is that it will be called after the received command data has been parsed
1031 and processed. The function is used to pass the received command data to
1034 `conn' is the associated client connection. `cmd_payload' is the command
1035 payload data received from server and it can be ignored. It is provided
1036 if the application would like to re-parse the received command data,
1037 however, it must be noted that the data is parsed already by the library
1038 thus the payload can be ignored. `success' is FALSE if error occured.
1039 In this case arguments are not sent to the application. `command' is the
1040 command reply being processed. The function has variable argument list
1041 and each command defines the number and type of arguments it passes to the
1042 application (on error they are not sent). */
1045 silc_command_reply(SilcClient client, SilcClientConnection conn,
1046 SilcCommandPayload cmd_payload, bool success,
1047 SilcCommand command, SilcStatus status, ...)
1050 SILC_SERVER_REC *server = conn->context;
1051 SILC_CHANNEL_REC *chanrec;
1054 va_start(vp, status);
1056 SILC_LOG_DEBUG(("Start"));
1059 case SILC_COMMAND_WHOIS:
1061 char buf[1024], *nickname, *username, *realname, *nick;
1062 unsigned char *fingerprint;
1063 SilcUInt32 idle, mode;
1064 SilcBuffer channels, user_modes;
1065 SilcClientEntry client_entry;
1067 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1068 /* Print the unknown nick for user */
1069 unsigned char *tmp =
1070 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1073 silc_say_error("%s: %s", tmp,
1074 silc_get_status_message(status));
1076 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1077 /* Try to find the entry for the unknown client ID, since we
1078 might have, and print the nickname of it for user. */
1080 unsigned char *tmp =
1081 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1084 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1087 client_entry = silc_client_get_client_by_id(client, conn,
1089 if (client_entry && client_entry->nickname)
1090 silc_say_error("%s: %s", client_entry->nickname,
1091 silc_get_status_message(status));
1092 silc_free(client_id);
1101 client_entry = va_arg(vp, SilcClientEntry);
1102 nickname = va_arg(vp, char *);
1103 username = va_arg(vp, char *);
1104 realname = va_arg(vp, char *);
1105 channels = va_arg(vp, SilcBuffer);
1106 mode = va_arg(vp, SilcUInt32);
1107 idle = va_arg(vp, SilcUInt32);
1108 fingerprint = va_arg(vp, unsigned char *);
1109 user_modes = va_arg(vp, SilcBuffer);
1111 silc_parse_userfqdn(nickname, &nick, NULL);
1112 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1113 SILCTXT_WHOIS_USERINFO, nickname,
1114 client_entry->username, client_entry->hostname,
1115 nick, client_entry->nickname);
1116 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1117 SILCTXT_WHOIS_REALNAME, realname);
1120 if (channels && user_modes) {
1122 SilcDList list = silc_channel_payload_parse_list(channels->data,
1124 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1126 SilcChannelPayload entry;
1129 memset(buf, 0, sizeof(buf));
1130 silc_dlist_start(list);
1131 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1132 SilcUInt32 name_len;
1133 char *m = silc_client_chumode_char(umodes[i++]);
1134 char *name = silc_channel_get_name(entry, &name_len);
1137 strncat(buf, m, strlen(m));
1138 strncat(buf, name, name_len);
1139 strncat(buf, " ", 1);
1143 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1144 SILCTXT_WHOIS_CHANNELS, buf);
1145 silc_channel_payload_list_free(list);
1151 memset(buf, 0, sizeof(buf));
1152 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1153 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1154 SILCTXT_WHOIS_MODES, buf);
1157 if (idle && nickname) {
1158 memset(buf, 0, sizeof(buf));
1159 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1160 idle > 60 ? (idle / 60) : idle,
1161 idle > 60 ? "minutes" : "seconds");
1163 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1164 SILCTXT_WHOIS_IDLE, buf);
1168 fingerprint = silc_fingerprint(fingerprint, 20);
1169 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1170 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1171 silc_free(fingerprint);
1176 case SILC_COMMAND_IDENTIFY:
1178 SilcClientEntry client_entry;
1180 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1181 /* Print the unknown nick for user */
1182 unsigned char *tmp =
1183 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1186 silc_say_error("%s: %s", tmp,
1187 silc_get_status_message(status));
1189 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1190 /* Try to find the entry for the unknown client ID, since we
1191 might have, and print the nickname of it for user. */
1193 unsigned char *tmp =
1194 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1197 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1200 client_entry = silc_client_get_client_by_id(client, conn,
1202 if (client_entry && client_entry->nickname)
1203 silc_say_error("%s: %s", client_entry->nickname,
1204 silc_get_status_message(status));
1205 silc_free(client_id);
1214 case SILC_COMMAND_WHOWAS:
1216 char *nickname, *username, *realname;
1218 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1219 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1221 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1224 silc_say_error("%s: %s", tmp,
1225 silc_get_status_message(status));
1232 (void)va_arg(vp, SilcClientEntry);
1233 nickname = va_arg(vp, char *);
1234 username = va_arg(vp, char *);
1235 realname = va_arg(vp, char *);
1237 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1238 SILCTXT_WHOWAS_USERINFO, nickname, username,
1239 realname ? realname : "");
1243 case SILC_COMMAND_INVITE:
1245 SilcChannelEntry channel;
1247 SilcArgumentPayload args;
1253 channel = va_arg(vp, SilcChannelEntry);
1254 invite_list = va_arg(vp, char *);
1256 args = silc_command_get_args(cmd_payload);
1258 argc = silc_argument_get_arg_num(args);
1261 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1262 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1265 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1266 SILCTXT_CHANNEL_NO_INVITE_LIST,
1267 channel->channel_name);
1271 case SILC_COMMAND_JOIN:
1273 char *channel, *mode, *topic;
1275 SilcChannelEntry channel_entry;
1276 SilcBuffer client_id_list;
1277 SilcUInt32 list_count;
1282 channel = va_arg(vp, char *);
1283 channel_entry = va_arg(vp, SilcChannelEntry);
1284 modei = va_arg(vp, SilcUInt32);
1285 (void)va_arg(vp, SilcUInt32);
1286 (void)va_arg(vp, unsigned char *);
1287 (void)va_arg(vp, unsigned char *);
1288 (void)va_arg(vp, unsigned char *);
1289 topic = va_arg(vp, char *);
1290 (void)va_arg(vp, unsigned char *);
1291 list_count = va_arg(vp, SilcUInt32);
1292 client_id_list = va_arg(vp, SilcBuffer);
1294 chanrec = silc_channel_find(server, channel);
1296 chanrec = silc_channel_create(server, channel, TRUE);
1299 g_free_not_null(chanrec->topic);
1300 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1301 signal_emit("channel topic changed", 1, chanrec);
1304 mode = silc_client_chmode(modei,
1305 channel_entry->channel_key ?
1306 channel_entry->channel_key->cipher->name : "",
1307 channel_entry->hmac ?
1308 silc_hmac_get_name(channel_entry->hmac) : "");
1309 g_free_not_null(chanrec->mode);
1310 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1311 signal_emit("channel mode changed", 1, chanrec);
1313 /* Resolve the client information */
1314 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1315 silc_client_join_get_users,
1321 case SILC_COMMAND_NICK:
1324 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1329 old = g_strdup(server->nick);
1330 server_change_nick(SERVER(server), client->nickname);
1331 nicklist_rename_unique(SERVER(server),
1332 server->conn->local_entry, server->nick,
1333 client, client->nickname);
1334 signal_emit("message own_nick", 4, server, server->nick, old, "");
1339 case SILC_COMMAND_LIST:
1348 (void)va_arg(vp, SilcChannelEntry);
1349 name = va_arg(vp, char *);
1350 topic = va_arg(vp, char *);
1351 usercount = va_arg(vp, int);
1353 if (status == SILC_STATUS_LIST_START ||
1354 status == SILC_STATUS_OK)
1355 printformat_module("fe-common/silc", server, NULL,
1356 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1359 snprintf(users, sizeof(users) - 1, "N/A");
1361 snprintf(users, sizeof(users) - 1, "%d", usercount);
1362 printformat_module("fe-common/silc", server, NULL,
1363 MSGLEVEL_CRAP, SILCTXT_LIST,
1364 name, users, topic ? topic : "");
1368 case SILC_COMMAND_UMODE:
1375 mode = va_arg(vp, SilcUInt32);
1377 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1378 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1379 printformat_module("fe-common/silc", server, NULL,
1380 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1382 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1383 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1384 printformat_module("fe-common/silc", server, NULL,
1385 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1387 server->umode = mode;
1388 signal_emit("user mode changed", 2, server, NULL);
1392 case SILC_COMMAND_OPER:
1396 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1397 signal_emit("user mode changed", 2, server, NULL);
1399 printformat_module("fe-common/silc", server, NULL,
1400 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1403 case SILC_COMMAND_SILCOPER:
1407 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1408 signal_emit("user mode changed", 2, server, NULL);
1410 printformat_module("fe-common/silc", server, NULL,
1411 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1414 case SILC_COMMAND_USERS:
1416 SilcHashTableList htl;
1417 SilcChannelEntry channel;
1418 SilcChannelUser chu;
1423 channel = va_arg(vp, SilcChannelEntry);
1425 printformat_module("fe-common/silc", server, channel->channel_name,
1426 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1427 channel->channel_name);
1429 silc_hash_table_list(channel->user_list, &htl);
1430 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1431 SilcClientEntry e = chu->client;
1432 char stat[5], *mode;
1437 memset(stat, 0, sizeof(stat));
1438 mode = silc_client_chumode_char(chu->mode);
1439 if (e->mode & SILC_UMODE_GONE)
1441 else if (e->mode & SILC_UMODE_INDISPOSED)
1443 else if (e->mode & SILC_UMODE_BUSY)
1445 else if (e->mode & SILC_UMODE_PAGE)
1447 else if (e->mode & SILC_UMODE_HYPER)
1449 else if (e->mode & SILC_UMODE_ROBOT)
1451 else if (e->mode & SILC_UMODE_ANONYMOUS)
1458 printformat_module("fe-common/silc", server, channel->channel_name,
1459 MSGLEVEL_CRAP, SILCTXT_USERS,
1461 e->username ? e->username : "",
1462 e->hostname ? e->hostname : "",
1463 e->realname ? e->realname : "");
1467 silc_hash_table_list_reset(&htl);
1471 case SILC_COMMAND_BAN:
1473 SilcChannelEntry channel;
1479 channel = va_arg(vp, SilcChannelEntry);
1480 ban_list = va_arg(vp, char *);
1483 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1484 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1487 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1488 SILCTXT_CHANNEL_NO_BAN_LIST,
1489 channel->channel_name);
1493 case SILC_COMMAND_GETKEY:
1497 SilcPublicKey public_key;
1500 GetkeyContext getkey;
1506 id_type = va_arg(vp, SilcUInt32);
1507 entry = va_arg(vp, void *);
1508 public_key = va_arg(vp, SilcPublicKey);
1511 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1513 getkey = silc_calloc(1, sizeof(*getkey));
1514 getkey->entry = entry;
1515 getkey->id_type = id_type;
1516 getkey->client = client;
1517 getkey->conn = conn;
1518 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1520 name = (id_type == SILC_ID_CLIENT ?
1521 ((SilcClientEntry)entry)->nickname :
1522 ((SilcServerEntry)entry)->server_name);
1524 silc_verify_public_key_internal(client, conn, name,
1525 (id_type == SILC_ID_CLIENT ?
1526 SILC_SOCKET_TYPE_CLIENT :
1527 SILC_SOCKET_TYPE_SERVER),
1528 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1529 silc_getkey_cb, getkey);
1532 printformat_module("fe-common/silc", server, NULL,
1533 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1538 case SILC_COMMAND_INFO:
1540 SilcServerEntry server_entry;
1547 server_entry = va_arg(vp, SilcServerEntry);
1548 server_name = va_arg(vp, char *);
1549 server_info = va_arg(vp, char *);
1551 if (server_name && server_info )
1553 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1554 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1559 case SILC_COMMAND_TOPIC:
1561 SilcChannelEntry channel;
1567 channel = va_arg(vp, SilcChannelEntry);
1568 topic = va_arg(vp, char *);
1571 chanrec = silc_channel_find_entry(server, channel);
1573 g_free_not_null(chanrec->topic);
1574 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1575 signal_emit("channel topic changed", 1, chanrec);
1577 printformat_module("fe-common/silc", server, channel->channel_name,
1578 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1579 channel->channel_name, topic);
1581 printformat_module("fe-common/silc", server, channel->channel_name,
1582 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1583 channel->channel_name);
1588 case SILC_COMMAND_WATCH:
1597 SilcClientConnection conn;
1603 SilcSKEPKType pk_type;
1604 SilcVerifyPublicKey completion;
1608 static void verify_public_key_completion(const char *line, void *context)
1610 PublicKeyVerify verify = (PublicKeyVerify)context;
1612 if (line[0] == 'Y' || line[0] == 'y') {
1613 /* Call the completion */
1614 if (verify->completion)
1615 verify->completion(TRUE, verify->context);
1617 /* Save the key for future checking */
1618 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1619 verify->pk_len, SILC_PKCS_FILE_PEM);
1621 /* Call the completion */
1622 if (verify->completion)
1623 verify->completion(FALSE, verify->context);
1625 printformat_module("fe-common/silc", NULL, NULL,
1626 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1627 verify->entity_name ? verify->entity_name :
1631 silc_free(verify->filename);
1632 silc_free(verify->entity);
1633 silc_free(verify->entity_name);
1634 silc_free(verify->pk);
1638 /* Internal routine to verify public key. If the `completion' is provided
1639 it will be called to indicate whether public was verified or not. For
1640 server/router public key this will check for filename that includes the
1641 remote host's IP address and remote host's hostname. */
1644 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1645 const char *name, SilcSocketType conn_type,
1646 unsigned char *pk, SilcUInt32 pk_len,
1647 SilcSKEPKType pk_type,
1648 SilcVerifyPublicKey completion, void *context)
1651 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1652 char *fingerprint, *babbleprint, *format;
1655 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1656 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1657 "server" : "client");
1658 PublicKeyVerify verify;
1660 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1661 printformat_module("fe-common/silc", NULL, NULL,
1662 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1665 completion(FALSE, context);
1669 pw = getpwuid(getuid());
1672 completion(FALSE, context);
1676 memset(filename, 0, sizeof(filename));
1677 memset(filename2, 0, sizeof(filename2));
1678 memset(file, 0, sizeof(file));
1680 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1681 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1683 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1684 conn->sock->ip, conn->sock->port);
1685 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1686 get_irssi_dir(), entity, file);
1688 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1689 conn->sock->hostname, conn->sock->port);
1690 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1691 get_irssi_dir(), entity, file);
1696 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1697 name, conn->sock->port);
1698 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1699 get_irssi_dir(), entity, file);
1704 /* Replace all whitespaces with `_'. */
1705 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1706 for (i = 0; i < strlen(fingerprint); i++)
1707 if (fingerprint[i] == ' ')
1708 fingerprint[i] = '_';
1710 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1711 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1712 get_irssi_dir(), entity, file);
1713 silc_free(fingerprint);
1718 /* Take fingerprint of the public key */
1719 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1720 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1722 verify = silc_calloc(1, sizeof(*verify));
1723 verify->client = client;
1724 verify->conn = conn;
1725 verify->filename = strdup(ipf);
1726 verify->entity = strdup(entity);
1727 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1728 (name ? strdup(name) : strdup(conn->sock->hostname))
1730 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1731 memcpy(verify->pk, pk, pk_len);
1732 verify->pk_len = pk_len;
1733 verify->pk_type = pk_type;
1734 verify->completion = completion;
1735 verify->context = context;
1737 /* Check whether this key already exists */
1738 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1739 /* Key does not exist, ask user to verify the key and save it */
1741 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1742 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1743 verify->entity_name : entity);
1744 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1745 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1746 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1747 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1748 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1749 SILCTXT_PUBKEY_ACCEPT);
1750 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1753 silc_free(fingerprint);
1756 /* The key already exists, verify it. */
1757 SilcPublicKey public_key;
1758 unsigned char *encpk;
1759 SilcUInt32 encpk_len;
1761 /* Load the key file, try for both IP filename and hostname filename */
1762 if (!silc_pkcs_load_public_key(ipf, &public_key,
1763 SILC_PKCS_FILE_PEM) &&
1764 !silc_pkcs_load_public_key(ipf, &public_key,
1765 SILC_PKCS_FILE_BIN) &&
1766 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1767 SILC_PKCS_FILE_PEM) &&
1768 !silc_pkcs_load_public_key(hostf, &public_key,
1769 SILC_PKCS_FILE_BIN)))) {
1770 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1771 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1772 verify->entity_name : entity);
1773 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1774 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1775 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1776 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1777 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1778 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1779 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1780 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1781 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1784 silc_free(fingerprint);
1788 /* Encode the key data */
1789 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1791 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1792 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1793 verify->entity_name : entity);
1794 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1795 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1796 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1797 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1798 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1799 SILCTXT_PUBKEY_MALFORMED, entity);
1800 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1801 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1802 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1805 silc_free(fingerprint);
1809 /* Compare the keys */
1810 if (memcmp(encpk, pk, encpk_len)) {
1811 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1812 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1813 verify->entity_name : entity);
1814 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1815 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1816 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1817 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1818 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1819 SILCTXT_PUBKEY_NO_MATCH, entity);
1820 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1821 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1822 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1823 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1825 /* Ask user to verify the key and save it */
1826 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1827 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1828 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1831 silc_free(fingerprint);
1835 /* Local copy matched */
1837 completion(TRUE, context);
1838 silc_free(fingerprint);
1842 /* Verifies received public key. The `conn_type' indicates which entity
1843 (server, client etc.) has sent the public key. If user decides to trust
1844 the key may be saved as trusted public key for later use. The
1845 `completion' must be called after the public key has been verified. */
1848 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1849 SilcSocketType conn_type, unsigned char *pk,
1850 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1851 SilcVerifyPublicKey completion, void *context)
1853 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1855 completion, context);
1858 /* Asks passphrase from user on the input line. */
1861 SilcAskPassphrase completion;
1865 void ask_passphrase_completion(const char *passphrase, void *context)
1867 AskPassphrase p = (AskPassphrase)context;
1868 if (passphrase && passphrase[0] == '\0')
1870 p->completion((unsigned char *)passphrase,
1871 passphrase ? strlen(passphrase) : 0, p->context);
1875 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1876 SilcAskPassphrase completion, void *context)
1878 AskPassphrase p = silc_calloc(1, sizeof(*p));
1879 p->completion = completion;
1880 p->context = context;
1882 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1883 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1887 SilcGetAuthMeth completion;
1889 } *InternalGetAuthMethod;
1891 /* Callback called when we've received the authentication method information
1892 from the server after we've requested it. This will get the authentication
1893 data from the user if needed. */
1895 static void silc_get_auth_method_callback(SilcClient client,
1896 SilcClientConnection conn,
1897 SilcAuthMethod auth_meth,
1900 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1902 SILC_LOG_DEBUG(("Start"));
1904 switch (auth_meth) {
1905 case SILC_AUTH_NONE:
1906 /* No authentication required. */
1907 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1909 case SILC_AUTH_PASSWORD:
1910 /* Do not ask the passphrase from user, the library will ask it if
1911 we do not provide it here. */
1912 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1914 case SILC_AUTH_PUBLIC_KEY:
1915 /* Do not get the authentication data now, the library will generate
1916 it using our default key, if we do not provide it here. */
1917 /* XXX In the future when we support multiple local keys and multiple
1918 local certificates we will need to ask from user which one to use. */
1919 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1923 silc_free(internal);
1926 /* Find authentication method and authentication data by hostname and
1927 port. The hostname may be IP address as well. The found authentication
1928 method and authentication data is returned to `auth_meth', `auth_data'
1929 and `auth_data_len'. The function returns TRUE if authentication method
1930 is found and FALSE if not. `conn' may be NULL. */
1932 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1933 char *hostname, SilcUInt16 port,
1934 SilcGetAuthMeth completion, void *context)
1936 InternalGetAuthMethod internal;
1938 SILC_LOG_DEBUG(("Start"));
1940 /* XXX must resolve from configuration whether this connection has
1941 any specific authentication data */
1943 /* If we do not have this connection configured by the user in a
1944 configuration file then resolve the authentication method from the
1945 server for this session. */
1946 internal = silc_calloc(1, sizeof(*internal));
1947 internal->completion = completion;
1948 internal->context = context;
1950 silc_client_request_authentication_method(client, conn,
1951 silc_get_auth_method_callback,
1955 /* Notifies application that failure packet was received. This is called
1956 if there is some protocol active in the client. The `protocol' is the
1957 protocol context. The `failure' is opaque pointer to the failure
1958 indication. Note, that the `failure' is protocol dependant and application
1959 must explicitly cast it to correct type. Usually `failure' is 32 bit
1960 failure type (see protocol specs for all protocol failure types). */
1962 void silc_failure(SilcClient client, SilcClientConnection conn,
1963 SilcProtocol protocol, void *failure)
1965 SILC_LOG_DEBUG(("Start"));
1967 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1968 SilcSKEStatus status = (SilcSKEStatus)failure;
1970 if (status == SILC_SKE_STATUS_BAD_VERSION)
1971 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1972 SILCTXT_KE_BAD_VERSION);
1973 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1974 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1975 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1976 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1977 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1978 SILCTXT_KE_UNKNOWN_GROUP);
1979 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1980 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1981 SILCTXT_KE_UNKNOWN_CIPHER);
1982 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1983 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1984 SILCTXT_KE_UNKNOWN_PKCS);
1985 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1986 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1987 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1988 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1989 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1990 SILCTXT_KE_UNKNOWN_HMAC);
1991 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1992 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1993 SILCTXT_KE_INCORRECT_SIGNATURE);
1994 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1995 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1996 SILCTXT_KE_INVALID_COOKIE);
1999 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2000 SilcUInt32 err = (SilcUInt32)failure;
2002 if (err == SILC_AUTH_FAILED)
2003 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2004 SILCTXT_AUTH_FAILED);
2008 /* Asks whether the user would like to perform the key agreement protocol.
2009 This is called after we have received an key agreement packet or an
2010 reply to our key agreement packet. This returns TRUE if the user wants
2011 the library to perform the key agreement protocol and FALSE if it is not
2012 desired (application may start it later by calling the function
2013 silc_client_perform_key_agreement). */
2015 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
2016 SilcClientEntry client_entry, const char *hostname,
2017 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2022 SILC_LOG_DEBUG(("Start"));
2024 /* We will just display the info on the screen and return FALSE and user
2025 will have to start the key agreement with a command. */
2028 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2031 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2032 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2034 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2035 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2036 client_entry->nickname, hostname, portstr);
2044 /* Notifies application that file transfer protocol session is being
2045 requested by the remote client indicated by the `client_entry' from
2046 the `hostname' and `port'. The `session_id' is the file transfer
2047 session and it can be used to either accept or reject the file
2048 transfer request, by calling the silc_client_file_receive or
2049 silc_client_file_close, respectively. */
2051 void silc_ftp(SilcClient client, SilcClientConnection conn,
2052 SilcClientEntry client_entry, SilcUInt32 session_id,
2053 const char *hostname, SilcUInt16 port)
2055 SILC_SERVER_REC *server;
2057 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2059 SILC_LOG_DEBUG(("Start"));
2061 server = conn->context;
2063 ftp->client_entry = client_entry;
2064 ftp->session_id = session_id;
2067 silc_dlist_add(server->ftp_sessions, ftp);
2068 server->current_session = ftp;
2071 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2074 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2075 SILCTXT_FILE_REQUEST, client_entry->nickname);
2077 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2078 SILCTXT_FILE_REQUEST_HOST,
2079 client_entry->nickname, hostname, portstr);
2082 /* Delivers SILC session detachment data indicated by `detach_data' to the
2083 application. If application has issued SILC_COMMAND_DETACH command
2084 the client session in the SILC network is not quit. The client remains
2085 in the network but is detached. The detachment data may be used later
2086 to resume the session in the SILC Network. The appliation is
2087 responsible of saving the `detach_data', to for example in a file.
2089 The detachment data can be given as argument to the functions
2090 silc_client_connect_to_server, or silc_client_add_connection when
2091 creating connection to remote server, inside SilcClientConnectionParams
2092 structure. If it is provided the client library will attempt to resume
2093 the session in the network. After the connection is created
2094 successfully, the application is responsible of setting the user
2095 interface for user into the same state it was before detaching (showing
2096 same channels, channel modes, etc). It can do this by fetching the
2097 information (like joined channels) from the client library. */
2100 silc_detach(SilcClient client, SilcClientConnection conn,
2101 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2105 /* Save the detachment data to file. */
2107 memset(file, 0, sizeof(file));
2108 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2109 silc_file_writefile(file, detach_data, detach_data_len);
2113 /* SILC client operations */
2114 SilcClientOperations ops = {
2116 silc_channel_message,
2117 silc_private_message,
2123 silc_get_auth_method,
2124 silc_verify_public_key,
2125 silc_ask_passphrase,