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]");
80 void silc_say(SilcClient client, SilcClientConnection conn,
81 SilcClientMessageType type, char *msg, ...)
83 SILC_SERVER_REC *server;
87 server = conn == NULL ? NULL : conn->context;
90 str = g_strdup_vprintf(msg, va);
91 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
96 void silc_say_error(char *msg, ...)
102 str = g_strdup_vprintf(msg, va);
103 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
109 /* Message for a channel. The `sender' is the nickname of the sender
110 received in the packet. The `channel_name' is the name of the channel. */
112 void silc_channel_message(SilcClient client, SilcClientConnection conn,
113 SilcClientEntry sender, SilcChannelEntry channel,
114 SilcMessageFlags flags, const unsigned char *message,
115 SilcUInt32 message_len)
117 SILC_SERVER_REC *server;
119 SILC_CHANNEL_REC *chanrec;
121 SILC_LOG_DEBUG(("Start"));
126 server = conn == NULL ? NULL : conn->context;
127 chanrec = silc_channel_find_entry(server, channel);
131 nick = silc_nicklist_find(chanrec, sender);
133 /* We didn't find client but it clearly exists, add it. */
134 SilcChannelUser chu = silc_client_on_channel(channel, sender);
136 nick = silc_nicklist_insert(chanrec, chu, FALSE);
139 if (flags & SILC_MESSAGE_FLAG_DATA) {
140 /* MIME object received, try to display it as well as we can */
144 memset(type, 0, sizeof(type));
145 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
146 NULL, 0, &data, NULL))
149 /* Then figure out what we can display */
150 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
151 !strstr(type, "text/vnd")) {
152 /* It is something textual, display it */
153 message = (const unsigned char *)data;
155 printformat_module("fe-common/silc", server, channel->channel_name,
156 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
157 nick == NULL ? "[<unknown>]" : nick->nick, type);
165 if (flags & SILC_MESSAGE_FLAG_ACTION)
166 printformat_module("fe-common/silc", server, channel->channel_name,
167 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
168 nick == NULL ? "[<unknown>]" : nick->nick, message);
169 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
170 printformat_module("fe-common/silc", server, channel->channel_name,
171 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
172 nick == NULL ? "[<unknown>]" : nick->nick, message);
174 signal_emit("message public", 6, server, message,
175 nick == NULL ? "[<unknown>]" : nick->nick,
176 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
177 chanrec->name, nick);
180 /* Private message to the client. The `sender' is the nickname of the
181 sender received in the packet. */
183 void silc_private_message(SilcClient client, SilcClientConnection conn,
184 SilcClientEntry sender, SilcMessageFlags flags,
185 const unsigned char *message,
186 SilcUInt32 message_len)
188 SILC_SERVER_REC *server;
191 SILC_LOG_DEBUG(("Start"));
193 server = conn == NULL ? NULL : conn->context;
194 memset(userhost, 0, sizeof(userhost));
195 if (sender->username)
196 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
197 sender->username, sender->hostname);
199 if (flags & SILC_MESSAGE_FLAG_DATA) {
200 /* MIME object received, try to display it as well as we can */
204 memset(type, 0, sizeof(type));
205 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
206 NULL, 0, &data, NULL))
209 /* Then figure out what we can display */
210 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
211 !strstr(type, "text/vnd")) {
212 /* It is something textual, display it */
213 message = (const unsigned char *)data;
215 printformat_module("fe-common/silc", server, NULL,
216 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
217 sender->nickname ? sender->nickname : "[<unknown>]",
226 signal_emit("message private", 4, server, message,
227 sender->nickname ? sender->nickname : "[<unknown>]",
228 sender->username ? userhost : NULL);
231 /* Notify message to the client. The notify arguments are sent in the
232 same order as servers sends them. The arguments are same as received
233 from the server except for ID's. If ID is received application receives
234 the corresponding entry to the ID. For example, if Client ID is received
235 application receives SilcClientEntry. Also, if the notify type is
236 for channel the channel entry is sent to application (even if server
237 does not send it). */
239 void silc_notify(SilcClient client, SilcClientConnection conn,
240 SilcNotifyType type, ...)
243 SILC_SERVER_REC *server;
244 SILC_CHANNEL_REC *chanrec;
245 SILC_NICK_REC *nickrec;
246 SilcClientEntry client_entry, client_entry2;
247 SilcChannelEntry channel, channel2;
248 SilcServerEntry server_entry;
254 GSList *list1, *list_tmp;
256 SILC_LOG_DEBUG(("Start"));
260 server = conn == NULL ? NULL : conn->context;
263 case SILC_NOTIFY_TYPE_NONE:
264 /* Some generic notice from server */
265 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
268 case SILC_NOTIFY_TYPE_INVITE:
270 * Invited or modified invite list.
273 SILC_LOG_DEBUG(("Notify: INVITE"));
275 channel = va_arg(va, SilcChannelEntry);
276 name = va_arg(va, char *);
277 client_entry = va_arg(va, SilcClientEntry);
279 memset(buf, 0, sizeof(buf));
280 snprintf(buf, sizeof(buf) - 1, "%s@%s",
281 client_entry->username, client_entry->hostname);
282 signal_emit("message invite", 4, server, channel ? channel->channel_name :
283 name, client_entry->nickname, buf);
286 case SILC_NOTIFY_TYPE_JOIN:
291 SILC_LOG_DEBUG(("Notify: JOIN"));
293 client_entry = va_arg(va, SilcClientEntry);
294 channel = va_arg(va, SilcChannelEntry);
296 if (client_entry == server->conn->local_entry) {
297 /* You joined to channel */
298 chanrec = silc_channel_find(server, channel->channel_name);
299 if (chanrec != NULL && !chanrec->joined)
300 chanrec->entry = channel;
302 chanrec = silc_channel_find_entry(server, channel);
303 if (chanrec != NULL) {
304 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
306 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
310 memset(buf, 0, sizeof(buf));
311 if (client_entry->username)
312 snprintf(buf, sizeof(buf) - 1, "%s@%s",
313 client_entry->username, client_entry->hostname);
314 signal_emit("message join", 4, server, channel->channel_name,
315 client_entry->nickname,
316 client_entry->username == NULL ? "" : buf);
319 case SILC_NOTIFY_TYPE_LEAVE:
324 SILC_LOG_DEBUG(("Notify: LEAVE"));
326 client_entry = va_arg(va, SilcClientEntry);
327 channel = va_arg(va, SilcChannelEntry);
329 memset(buf, 0, sizeof(buf));
330 if (client_entry->username)
331 snprintf(buf, sizeof(buf) - 1, "%s@%s",
332 client_entry->username, client_entry->hostname);
333 signal_emit("message part", 5, server, channel->channel_name,
334 client_entry->nickname, client_entry->username ?
335 buf : "", client_entry->nickname);
337 chanrec = silc_channel_find_entry(server, channel);
338 if (chanrec != NULL) {
339 nickrec = silc_nicklist_find(chanrec, client_entry);
341 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
345 case SILC_NOTIFY_TYPE_SIGNOFF:
350 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
352 client_entry = va_arg(va, SilcClientEntry);
353 tmp = va_arg(va, char *);
355 silc_server_free_ftp(server, client_entry);
357 memset(buf, 0, sizeof(buf));
358 if (client_entry->username)
359 snprintf(buf, sizeof(buf) - 1, "%s@%s",
360 client_entry->username, client_entry->hostname);
361 signal_emit("message quit", 4, server, client_entry->nickname,
362 client_entry->username ? buf : "",
365 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
366 for (list_tmp = list1; list_tmp != NULL; list_tmp =
367 list_tmp->next->next) {
368 CHANNEL_REC *channel = list_tmp->data;
369 NICK_REC *nickrec = list_tmp->next->data;
371 nicklist_remove(channel, nickrec);
375 case SILC_NOTIFY_TYPE_TOPIC_SET:
380 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
382 idtype = va_arg(va, int);
383 entry = va_arg(va, void *);
384 tmp = va_arg(va, char *);
385 channel = va_arg(va, SilcChannelEntry);
387 chanrec = silc_channel_find_entry(server, channel);
388 if (chanrec != NULL) {
389 g_free_not_null(chanrec->topic);
390 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
391 signal_emit("channel topic changed", 1, chanrec);
394 if (idtype == SILC_ID_CLIENT) {
395 client_entry = (SilcClientEntry)entry;
396 memset(buf, 0, sizeof(buf));
397 snprintf(buf, sizeof(buf) - 1, "%s@%s",
398 client_entry->username, client_entry->hostname);
399 signal_emit("message topic", 5, server, channel->channel_name,
400 tmp, client_entry->nickname, buf);
401 } else if (idtype == SILC_ID_SERVER) {
402 server_entry = (SilcServerEntry)entry;
403 signal_emit("message topic", 5, server, channel->channel_name,
404 tmp, server_entry->server_name,
405 server_entry->server_name);
406 } else if (idtype == SILC_ID_CHANNEL) {
407 channel = (SilcChannelEntry)entry;
408 signal_emit("message topic", 5, server, channel->channel_name,
409 tmp, channel->channel_name, channel->channel_name);
413 case SILC_NOTIFY_TYPE_NICK_CHANGE:
418 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
420 client_entry = va_arg(va, SilcClientEntry);
421 client_entry2 = va_arg(va, SilcClientEntry);
423 if (!strcmp(client_entry->nickname, client_entry2->nickname))
426 memset(buf, 0, sizeof(buf));
427 snprintf(buf, sizeof(buf) - 1, "%s@%s",
428 client_entry2->username, client_entry2->hostname);
429 nicklist_rename_unique(SERVER(server),
430 client_entry, client_entry->nickname,
431 client_entry2, client_entry2->nickname);
432 signal_emit("message nick", 4, server, client_entry2->nickname,
433 client_entry->nickname, buf);
436 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
438 * Changed channel mode.
441 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
443 idtype = va_arg(va, int);
444 entry = va_arg(va, void *);
445 mode = va_arg(va, SilcUInt32);
446 (void)va_arg(va, char *);
447 (void)va_arg(va, char *);
448 channel = va_arg(va, SilcChannelEntry);
450 tmp = silc_client_chmode(mode,
451 channel->channel_key ?
452 channel->channel_key->cipher->name : "",
454 silc_hmac_get_name(channel->hmac) : "");
456 chanrec = silc_channel_find_entry(server, channel);
457 if (chanrec != NULL) {
458 g_free_not_null(chanrec->mode);
459 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
460 signal_emit("channel mode changed", 1, chanrec);
463 if (idtype == SILC_ID_CLIENT) {
464 client_entry = (SilcClientEntry)entry;
465 printformat_module("fe-common/silc", server, channel->channel_name,
466 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
467 channel->channel_name, tmp ? tmp : "removed all",
468 client_entry->nickname);
469 } else if (idtype == SILC_ID_SERVER) {
470 server_entry = (SilcServerEntry)entry;
471 printformat_module("fe-common/silc", server, channel->channel_name,
472 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
473 channel->channel_name, tmp ? tmp : "removed all",
474 server_entry->server_name);
475 } else if (idtype == SILC_ID_CHANNEL) {
476 channel2 = (SilcChannelEntry)entry;
477 printformat_module("fe-common/silc", server, channel->channel_name,
478 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
479 channel->channel_name, tmp ? tmp : "removed all",
480 channel2->channel_name);
486 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
488 * Changed user's mode on channel.
491 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
493 idtype = va_arg(va, int);
494 entry = va_arg(va, void *);
495 mode = va_arg(va, SilcUInt32);
496 client_entry2 = va_arg(va, SilcClientEntry);
497 channel = va_arg(va, SilcChannelEntry);
499 tmp = silc_client_chumode(mode);
500 chanrec = silc_channel_find_entry(server, channel);
501 if (chanrec != NULL) {
504 if (client_entry2 == server->conn->local_entry)
505 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
507 nick = silc_nicklist_find(chanrec, client_entry2);
509 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
510 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
511 signal_emit("nick mode changed", 2, chanrec, nick);
515 if (idtype == SILC_ID_CLIENT) {
516 client_entry = (SilcClientEntry)entry;
517 printformat_module("fe-common/silc", server, channel->channel_name,
518 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
519 channel->channel_name, client_entry2->nickname,
520 tmp ? tmp : "removed all",
521 client_entry->nickname);
522 } else if (idtype == SILC_ID_SERVER) {
523 server_entry = (SilcServerEntry)entry;
524 printformat_module("fe-common/silc", server, channel->channel_name,
525 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
526 channel->channel_name, client_entry2->nickname,
527 tmp ? tmp : "removed all",
528 server_entry->server_name);
529 } else if (idtype == SILC_ID_CHANNEL) {
530 channel2 = (SilcChannelEntry)entry;
531 printformat_module("fe-common/silc", server, channel->channel_name,
532 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
533 channel->channel_name, client_entry2->nickname,
534 tmp ? tmp : "removed all",
535 channel2->channel_name);
538 if (mode & SILC_CHANNEL_UMODE_CHANFO)
539 printformat_module("fe-common/silc",
540 server, channel->channel_name, MSGLEVEL_CRAP,
541 SILCTXT_CHANNEL_FOUNDER,
542 channel->channel_name, client_entry2->nickname);
547 case SILC_NOTIFY_TYPE_MOTD:
552 SILC_LOG_DEBUG(("Notify: MOTD"));
554 tmp = va_arg(va, char *);
556 if (!settings_get_bool("skip_motd"))
557 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
560 case SILC_NOTIFY_TYPE_KICKED:
562 * Someone was kicked from channel.
565 SILC_LOG_DEBUG(("Notify: KICKED"));
567 client_entry = va_arg(va, SilcClientEntry);
568 tmp = va_arg(va, char *);
569 client_entry2 = va_arg(va, SilcClientEntry);
570 channel = va_arg(va, SilcChannelEntry);
572 chanrec = silc_channel_find_entry(server, channel);
574 if (client_entry == conn->local_entry) {
575 printformat_module("fe-common/silc", server, channel->channel_name,
576 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
577 channel->channel_name,
578 client_entry ? client_entry2->nickname : "",
581 chanrec->kicked = TRUE;
582 channel_destroy((CHANNEL_REC *)chanrec);
585 printformat_module("fe-common/silc", server, channel->channel_name,
586 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
587 client_entry->nickname, channel->channel_name,
588 client_entry2 ? client_entry2->nickname : "",
592 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
594 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
599 case SILC_NOTIFY_TYPE_KILLED:
601 * Someone was killed from the network.
604 SILC_LOG_DEBUG(("Notify: KILLED"));
606 client_entry = va_arg(va, SilcClientEntry);
607 tmp = va_arg(va, char *);
608 idtype = va_arg(va, int);
609 entry = va_arg(va, SilcClientEntry);
611 if (client_entry == conn->local_entry) {
612 if (idtype == SILC_ID_CLIENT) {
613 client_entry2 = (SilcClientEntry)entry;
614 printformat_module("fe-common/silc", server, NULL,
615 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
616 client_entry2 ? client_entry2->nickname : "",
618 } else if (idtype == SILC_ID_SERVER) {
619 server_entry = (SilcServerEntry)entry;
620 printformat_module("fe-common/silc", server, NULL,
621 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
622 server_entry->server_name, tmp ? tmp : "");
623 } else if (idtype == SILC_ID_CHANNEL) {
624 channel = (SilcChannelEntry)entry;
625 printformat_module("fe-common/silc", server, NULL,
626 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
627 channel->channel_name, tmp ? tmp : "");
630 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
631 for (list_tmp = list1; list_tmp != NULL; list_tmp =
632 list_tmp->next->next) {
633 CHANNEL_REC *channel = list_tmp->data;
634 NICK_REC *nickrec = list_tmp->next->data;
635 nicklist_remove(channel, nickrec);
638 if (idtype == SILC_ID_CLIENT) {
639 client_entry2 = (SilcClientEntry)entry;
640 printformat_module("fe-common/silc", server, NULL,
641 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
642 client_entry->nickname,
643 client_entry2 ? client_entry2->nickname : "",
645 } else if (idtype == SILC_ID_SERVER) {
646 server_entry = (SilcServerEntry)entry;
647 printformat_module("fe-common/silc", server, NULL,
648 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
649 client_entry->nickname,
650 server_entry->server_name, tmp ? tmp : "");
651 } else if (idtype == SILC_ID_CHANNEL) {
652 channel = (SilcChannelEntry)entry;
653 printformat_module("fe-common/silc", server, NULL,
654 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
655 client_entry->nickname,
656 channel->channel_name, tmp ? tmp : "");
661 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
664 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
667 * Server has quit the network.
670 SilcClientEntry *clients;
671 SilcUInt32 clients_count;
673 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
675 (void)va_arg(va, void *);
676 clients = va_arg(va, SilcClientEntry *);
677 clients_count = va_arg(va, SilcUInt32);
679 for (i = 0; i < clients_count; i++) {
680 memset(buf, 0, sizeof(buf));
681 if (clients[i]->username)
682 snprintf(buf, sizeof(buf) - 1, "%s@%s",
683 clients[i]->username, clients[i]->hostname);
684 signal_emit("message quit", 4, server, clients[i]->nickname,
685 clients[i]->username ? buf : "",
688 silc_server_free_ftp(server, clients[i]);
690 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
691 for (list_tmp = list1; list_tmp != NULL; list_tmp =
692 list_tmp->next->next) {
693 CHANNEL_REC *channel = list_tmp->data;
694 NICK_REC *nickrec = list_tmp->next->data;
695 nicklist_remove(channel, nickrec);
701 case SILC_NOTIFY_TYPE_ERROR:
703 SilcStatus error = va_arg(va, int);
705 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
706 "%s", silc_get_status_message(error));
710 case SILC_NOTIFY_TYPE_WATCH:
712 SilcNotifyType notify;
714 client_entry = va_arg(va, SilcClientEntry);
715 name = va_arg(va, char *); /* Maybe NULL */
716 mode = va_arg(va, SilcUInt32);
717 notify = va_arg(va, int);
719 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
721 printformat_module("fe-common/silc", server, NULL,
722 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
723 client_entry->nickname, name);
725 printformat_module("fe-common/silc", server, NULL,
726 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
727 client_entry->nickname);
728 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
729 /* See if client was away and is now present */
730 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
731 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
732 SILC_UMODE_DETACHED)) &&
733 (client_entry->mode & SILC_UMODE_GONE ||
734 client_entry->mode & SILC_UMODE_INDISPOSED ||
735 client_entry->mode & SILC_UMODE_BUSY ||
736 client_entry->mode & SILC_UMODE_PAGE ||
737 client_entry->mode & SILC_UMODE_DETACHED)) {
738 printformat_module("fe-common/silc", server, NULL,
739 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
740 client_entry->nickname);
744 memset(buf, 0, sizeof(buf));
745 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
746 printformat_module("fe-common/silc", server, NULL,
747 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
748 client_entry->nickname, buf);
750 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
751 printformat_module("fe-common/silc", server, NULL,
752 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
753 client_entry->nickname);
754 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
755 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
756 printformat_module("fe-common/silc", server, NULL,
757 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
758 client_entry->nickname);
759 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
760 /* Client logged in to the network */
761 printformat_module("fe-common/silc", server, NULL,
762 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
763 client_entry->nickname);
770 printformat_module("fe-common/silc", server, NULL,
771 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
778 /* Called to indicate that connection was either successfully established
779 or connecting failed. This is also the first time application receives
780 the SilcClientConnection object which it should save somewhere. */
782 void silc_connect(SilcClient client, SilcClientConnection conn,
783 SilcClientConnectionStatus status)
785 SILC_SERVER_REC *server = conn->context;
788 silc_client_close_connection(client, conn);
793 case SILC_CLIENT_CONN_SUCCESS:
794 /* We have successfully connected to server */
795 server->connected = TRUE;
796 signal_emit("event connected", 1, server);
799 case SILC_CLIENT_CONN_SUCCESS_RESUME:
800 /* We have successfully resumed old detached session */
801 server->connected = TRUE;
802 signal_emit("event connected", 1, server);
804 /* If we resumed old session check whether we need to update
806 if (strcmp(server->nick, conn->local_entry->nickname)) {
808 old = g_strdup(server->nick);
809 server_change_nick(SERVER(server), conn->local_entry->nickname);
810 nicklist_rename_unique(SERVER(server),
811 conn->local_entry, server->nick,
812 conn->local_entry, conn->local_entry->nickname);
813 signal_emit("message own_nick", 4, server, server->nick, old, "");
819 server->connection_lost = TRUE;
821 server->conn->context = NULL;
822 server_disconnect(SERVER(server));
827 /* Called to indicate that connection was disconnected to the server. */
829 void silc_disconnect(SilcClient client, SilcClientConnection conn)
831 SILC_SERVER_REC *server = conn->context;
833 SILC_LOG_DEBUG(("Start"));
835 if (!server || server->connection_lost)
838 if (server->conn && server->conn->local_entry) {
839 nicklist_rename_unique(SERVER(server),
840 server->conn->local_entry, server->nick,
841 server->conn->local_entry,
842 silc_client->username);
843 silc_change_nick(server, silc_client->username);
846 server->conn->context = NULL;
848 server->connection_lost = TRUE;
849 server_disconnect(SERVER(server));
852 /* Command handler. This function is called always in the command function.
853 If error occurs it will be called as well. `conn' is the associated
854 client connection. `cmd_context' is the command context that was
855 originally sent to the command. `success' is FALSE if error occured
856 during command. `command' is the command being processed. It must be
857 noted that this is not reply from server. This is merely called just
858 after application has called the command. Just to tell application
859 that the command really was processed. */
861 void silc_command(SilcClient client, SilcClientConnection conn,
862 SilcClientCommandContext cmd_context, bool success,
863 SilcCommand command, SilcStatus status)
865 SILC_SERVER_REC *server = conn->context;
867 SILC_LOG_DEBUG(("Start"));
873 case SILC_COMMAND_INVITE:
874 printformat_module("fe-common/silc", server, NULL,
875 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
876 cmd_context->argv[2],
877 (cmd_context->argv[1][0] == '*' ?
878 (char *)conn->current_channel->channel_name :
879 (char *)cmd_context->argv[1]));
886 /* Client info resolving callback when JOIN command reply is received.
887 This will cache all users on the channel. */
889 static void silc_client_join_get_users(SilcClient client,
890 SilcClientConnection conn,
891 SilcClientEntry *clients,
892 SilcUInt32 clients_count,
895 SilcChannelEntry channel = (SilcChannelEntry)context;
896 SilcHashTableList htl;
898 SILC_SERVER_REC *server = conn->context;
899 SILC_CHANNEL_REC *chanrec;
900 SilcClientEntry founder = NULL;
903 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
904 silc_hash_table_count(channel->user_list)));
909 chanrec = silc_channel_find(server, channel->channel_name);
913 silc_hash_table_list(channel->user_list, &htl);
914 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
915 if (!chu->client->nickname)
917 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
918 founder = chu->client;
919 silc_nicklist_insert(chanrec, chu, FALSE);
921 silc_hash_table_list_reset(&htl);
923 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
924 nicklist_set_own(CHANNEL(chanrec), ownnick);
925 signal_emit("channel joined", 1, chanrec);
926 chanrec->entry = channel;
929 printformat_module("fe-common/silc", server, channel->channel_name,
930 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
931 channel->channel_name, chanrec->topic);
933 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
936 if (founder == conn->local_entry)
937 printformat_module("fe-common/silc",
938 server, channel->channel_name, MSGLEVEL_CRAP,
939 SILCTXT_CHANNEL_FOUNDER_YOU,
940 channel->channel_name);
942 printformat_module("fe-common/silc",
943 server, channel->channel_name, MSGLEVEL_CRAP,
944 SILCTXT_CHANNEL_FOUNDER,
945 channel->channel_name, founder->nickname);
951 SilcClientConnection conn;
957 void silc_getkey_cb(bool success, void *context)
959 GetkeyContext getkey = (GetkeyContext)context;
960 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
961 char *name = (getkey->id_type == SILC_ID_CLIENT ?
962 ((SilcClientEntry)getkey->entry)->nickname :
963 ((SilcServerEntry)getkey->entry)->server_name);
966 printformat_module("fe-common/silc", NULL, NULL,
967 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
969 printformat_module("fe-common/silc", NULL, NULL,
970 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
973 silc_free(getkey->fingerprint);
977 /* Command reply handler. This function is called always in the command reply
978 function. If error occurs it will be called as well. Normal scenario
979 is that it will be called after the received command data has been parsed
980 and processed. The function is used to pass the received command data to
983 `conn' is the associated client connection. `cmd_payload' is the command
984 payload data received from server and it can be ignored. It is provided
985 if the application would like to re-parse the received command data,
986 however, it must be noted that the data is parsed already by the library
987 thus the payload can be ignored. `success' is FALSE if error occured.
988 In this case arguments are not sent to the application. `command' is the
989 command reply being processed. The function has variable argument list
990 and each command defines the number and type of arguments it passes to the
991 application (on error they are not sent). */
994 silc_command_reply(SilcClient client, SilcClientConnection conn,
995 SilcCommandPayload cmd_payload, bool success,
996 SilcCommand command, SilcStatus status, ...)
999 SILC_SERVER_REC *server = conn->context;
1000 SILC_CHANNEL_REC *chanrec;
1003 va_start(vp, status);
1005 SILC_LOG_DEBUG(("Start"));
1008 case SILC_COMMAND_WHOIS:
1010 char buf[1024], *nickname, *username, *realname, *nick;
1011 unsigned char *fingerprint;
1012 SilcUInt32 idle, mode;
1013 SilcBuffer channels, user_modes;
1014 SilcClientEntry client_entry;
1016 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1017 /* Print the unknown nick for user */
1018 unsigned char *tmp =
1019 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1022 silc_say_error("%s: %s", tmp,
1023 silc_get_status_message(status));
1025 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1026 /* Try to find the entry for the unknown client ID, since we
1027 might have, and print the nickname of it for user. */
1029 unsigned char *tmp =
1030 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1033 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1036 client_entry = silc_client_get_client_by_id(client, conn,
1038 if (client_entry && client_entry->nickname)
1039 silc_say_error("%s: %s", client_entry->nickname,
1040 silc_get_status_message(status));
1041 silc_free(client_id);
1050 client_entry = va_arg(vp, SilcClientEntry);
1051 nickname = va_arg(vp, char *);
1052 username = va_arg(vp, char *);
1053 realname = va_arg(vp, char *);
1054 channels = va_arg(vp, SilcBuffer);
1055 mode = va_arg(vp, SilcUInt32);
1056 idle = va_arg(vp, SilcUInt32);
1057 fingerprint = va_arg(vp, unsigned char *);
1058 user_modes = va_arg(vp, SilcBuffer);
1060 silc_parse_userfqdn(nickname, &nick, NULL);
1061 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1062 SILCTXT_WHOIS_USERINFO, nickname,
1063 client_entry->username, client_entry->hostname,
1064 nick, client_entry->nickname);
1065 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1066 SILCTXT_WHOIS_REALNAME, realname);
1069 if (channels && user_modes) {
1071 SilcDList list = silc_channel_payload_parse_list(channels->data,
1073 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1075 SilcChannelPayload entry;
1078 memset(buf, 0, sizeof(buf));
1079 silc_dlist_start(list);
1080 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1081 SilcUInt32 name_len;
1082 char *m = silc_client_chumode_char(umodes[i++]);
1083 char *name = silc_channel_get_name(entry, &name_len);
1086 strncat(buf, m, strlen(m));
1087 strncat(buf, name, name_len);
1088 strncat(buf, " ", 1);
1092 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1093 SILCTXT_WHOIS_CHANNELS, buf);
1094 silc_channel_payload_list_free(list);
1100 memset(buf, 0, sizeof(buf));
1101 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1102 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1103 SILCTXT_WHOIS_MODES, buf);
1106 if (idle && nickname) {
1107 memset(buf, 0, sizeof(buf));
1108 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1109 idle > 60 ? (idle / 60) : idle,
1110 idle > 60 ? "minutes" : "seconds");
1112 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1113 SILCTXT_WHOIS_IDLE, buf);
1117 fingerprint = silc_fingerprint(fingerprint, 20);
1118 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1119 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1120 silc_free(fingerprint);
1125 case SILC_COMMAND_IDENTIFY:
1127 SilcClientEntry client_entry;
1129 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1130 /* Print the unknown nick for user */
1131 unsigned char *tmp =
1132 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1135 silc_say_error("%s: %s", tmp,
1136 silc_get_status_message(status));
1138 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1139 /* Try to find the entry for the unknown client ID, since we
1140 might have, and print the nickname of it for user. */
1142 unsigned char *tmp =
1143 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1146 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1149 client_entry = silc_client_get_client_by_id(client, conn,
1151 if (client_entry && client_entry->nickname)
1152 silc_say_error("%s: %s", client_entry->nickname,
1153 silc_get_status_message(status));
1154 silc_free(client_id);
1163 case SILC_COMMAND_WHOWAS:
1165 char *nickname, *username, *realname;
1167 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1168 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1170 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1173 silc_say_error("%s: %s", tmp,
1174 silc_get_status_message(status));
1181 (void)va_arg(vp, SilcClientEntry);
1182 nickname = va_arg(vp, char *);
1183 username = va_arg(vp, char *);
1184 realname = va_arg(vp, char *);
1186 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1187 SILCTXT_WHOWAS_USERINFO, nickname, username,
1188 realname ? realname : "");
1192 case SILC_COMMAND_INVITE:
1194 SilcChannelEntry channel;
1196 SilcArgumentPayload args;
1202 channel = va_arg(vp, SilcChannelEntry);
1203 invite_list = va_arg(vp, char *);
1205 args = silc_command_get_args(cmd_payload);
1207 argc = silc_argument_get_arg_num(args);
1210 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1211 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1214 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1215 SILCTXT_CHANNEL_NO_INVITE_LIST,
1216 channel->channel_name);
1220 case SILC_COMMAND_JOIN:
1222 char *channel, *mode, *topic;
1224 SilcChannelEntry channel_entry;
1225 SilcBuffer client_id_list;
1226 SilcUInt32 list_count;
1231 channel = va_arg(vp, char *);
1232 channel_entry = va_arg(vp, SilcChannelEntry);
1233 modei = va_arg(vp, SilcUInt32);
1234 (void)va_arg(vp, SilcUInt32);
1235 (void)va_arg(vp, unsigned char *);
1236 (void)va_arg(vp, unsigned char *);
1237 (void)va_arg(vp, unsigned char *);
1238 topic = va_arg(vp, char *);
1239 (void)va_arg(vp, unsigned char *);
1240 list_count = va_arg(vp, SilcUInt32);
1241 client_id_list = va_arg(vp, SilcBuffer);
1243 chanrec = silc_channel_find(server, channel);
1245 chanrec = silc_channel_create(server, channel, TRUE);
1248 g_free_not_null(chanrec->topic);
1249 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1250 signal_emit("channel topic changed", 1, chanrec);
1253 mode = silc_client_chmode(modei,
1254 channel_entry->channel_key ?
1255 channel_entry->channel_key->cipher->name : "",
1256 channel_entry->hmac ?
1257 silc_hmac_get_name(channel_entry->hmac) : "");
1258 g_free_not_null(chanrec->mode);
1259 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1260 signal_emit("channel mode changed", 1, chanrec);
1262 /* Resolve the client information */
1263 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1264 silc_client_join_get_users,
1270 case SILC_COMMAND_NICK:
1273 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1278 old = g_strdup(server->nick);
1279 server_change_nick(SERVER(server), client->nickname);
1280 nicklist_rename_unique(SERVER(server),
1281 server->conn->local_entry, server->nick,
1282 client, client->nickname);
1283 signal_emit("message own_nick", 4, server, server->nick, old, "");
1288 case SILC_COMMAND_LIST:
1297 (void)va_arg(vp, SilcChannelEntry);
1298 name = va_arg(vp, char *);
1299 topic = va_arg(vp, char *);
1300 usercount = va_arg(vp, int);
1302 if (status == SILC_STATUS_LIST_START ||
1303 status == SILC_STATUS_OK)
1304 printformat_module("fe-common/silc", server, NULL,
1305 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1308 snprintf(users, sizeof(users) - 1, "N/A");
1310 snprintf(users, sizeof(users) - 1, "%d", usercount);
1311 printformat_module("fe-common/silc", server, NULL,
1312 MSGLEVEL_CRAP, SILCTXT_LIST,
1313 name, users, topic ? topic : "");
1317 case SILC_COMMAND_UMODE:
1324 mode = va_arg(vp, SilcUInt32);
1326 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1327 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1328 printformat_module("fe-common/silc", server, NULL,
1329 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1331 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1332 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1333 printformat_module("fe-common/silc", server, NULL,
1334 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1336 server->umode = mode;
1337 signal_emit("user mode changed", 2, server, NULL);
1341 case SILC_COMMAND_OPER:
1345 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1346 signal_emit("user mode changed", 2, server, NULL);
1348 printformat_module("fe-common/silc", server, NULL,
1349 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1352 case SILC_COMMAND_SILCOPER:
1356 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1357 signal_emit("user mode changed", 2, server, NULL);
1359 printformat_module("fe-common/silc", server, NULL,
1360 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1363 case SILC_COMMAND_USERS:
1365 SilcHashTableList htl;
1366 SilcChannelEntry channel;
1367 SilcChannelUser chu;
1372 channel = va_arg(vp, SilcChannelEntry);
1374 printformat_module("fe-common/silc", server, channel->channel_name,
1375 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1376 channel->channel_name);
1378 silc_hash_table_list(channel->user_list, &htl);
1379 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1380 SilcClientEntry e = chu->client;
1381 char stat[5], *mode;
1386 memset(stat, 0, sizeof(stat));
1387 mode = silc_client_chumode_char(chu->mode);
1388 if (e->mode & SILC_UMODE_GONE)
1390 else if (e->mode & SILC_UMODE_INDISPOSED)
1392 else if (e->mode & SILC_UMODE_BUSY)
1394 else if (e->mode & SILC_UMODE_PAGE)
1396 else if (e->mode & SILC_UMODE_HYPER)
1398 else if (e->mode & SILC_UMODE_ROBOT)
1400 else if (e->mode & SILC_UMODE_ANONYMOUS)
1407 printformat_module("fe-common/silc", server, channel->channel_name,
1408 MSGLEVEL_CRAP, SILCTXT_USERS,
1410 e->username ? e->username : "",
1411 e->hostname ? e->hostname : "",
1412 e->realname ? e->realname : "");
1416 silc_hash_table_list_reset(&htl);
1420 case SILC_COMMAND_BAN:
1422 SilcChannelEntry channel;
1428 channel = va_arg(vp, SilcChannelEntry);
1429 ban_list = va_arg(vp, char *);
1432 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1433 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1436 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1437 SILCTXT_CHANNEL_NO_BAN_LIST,
1438 channel->channel_name);
1442 case SILC_COMMAND_GETKEY:
1446 SilcPublicKey public_key;
1449 GetkeyContext getkey;
1455 id_type = va_arg(vp, SilcUInt32);
1456 entry = va_arg(vp, void *);
1457 public_key = va_arg(vp, SilcPublicKey);
1460 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1462 getkey = silc_calloc(1, sizeof(*getkey));
1463 getkey->entry = entry;
1464 getkey->id_type = id_type;
1465 getkey->client = client;
1466 getkey->conn = conn;
1467 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1469 name = (id_type == SILC_ID_CLIENT ?
1470 ((SilcClientEntry)entry)->nickname :
1471 ((SilcServerEntry)entry)->server_name);
1473 silc_verify_public_key_internal(client, conn, name,
1474 (id_type == SILC_ID_CLIENT ?
1475 SILC_SOCKET_TYPE_CLIENT :
1476 SILC_SOCKET_TYPE_SERVER),
1477 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1478 silc_getkey_cb, getkey);
1481 printformat_module("fe-common/silc", server, NULL,
1482 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1487 case SILC_COMMAND_INFO:
1489 SilcServerEntry server_entry;
1496 server_entry = va_arg(vp, SilcServerEntry);
1497 server_name = va_arg(vp, char *);
1498 server_info = va_arg(vp, char *);
1500 if (server_name && server_info )
1502 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1503 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1508 case SILC_COMMAND_TOPIC:
1510 SilcChannelEntry channel;
1516 channel = va_arg(vp, SilcChannelEntry);
1517 topic = va_arg(vp, char *);
1520 chanrec = silc_channel_find_entry(server, channel);
1522 g_free_not_null(chanrec->topic);
1523 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1524 signal_emit("channel topic changed", 1, chanrec);
1526 printformat_module("fe-common/silc", server, channel->channel_name,
1527 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1528 channel->channel_name, topic);
1530 printformat_module("fe-common/silc", server, channel->channel_name,
1531 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1532 channel->channel_name);
1537 case SILC_COMMAND_WATCH:
1546 SilcClientConnection conn;
1552 SilcSKEPKType pk_type;
1553 SilcVerifyPublicKey completion;
1557 static void verify_public_key_completion(const char *line, void *context)
1559 PublicKeyVerify verify = (PublicKeyVerify)context;
1561 if (line[0] == 'Y' || line[0] == 'y') {
1562 /* Call the completion */
1563 if (verify->completion)
1564 verify->completion(TRUE, verify->context);
1566 /* Save the key for future checking */
1567 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1568 verify->pk_len, SILC_PKCS_FILE_PEM);
1570 /* Call the completion */
1571 if (verify->completion)
1572 verify->completion(FALSE, verify->context);
1574 printformat_module("fe-common/silc", NULL, NULL,
1575 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1576 verify->entity_name ? verify->entity_name :
1580 silc_free(verify->filename);
1581 silc_free(verify->entity);
1582 silc_free(verify->entity_name);
1583 silc_free(verify->pk);
1587 /* Internal routine to verify public key. If the `completion' is provided
1588 it will be called to indicate whether public was verified or not. For
1589 server/router public key this will check for filename that includes the
1590 remote host's IP address and remote host's hostname. */
1593 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1594 const char *name, SilcSocketType conn_type,
1595 unsigned char *pk, SilcUInt32 pk_len,
1596 SilcSKEPKType pk_type,
1597 SilcVerifyPublicKey completion, void *context)
1600 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1601 char *fingerprint, *babbleprint, *format;
1604 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1605 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1606 "server" : "client");
1607 PublicKeyVerify verify;
1609 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1610 printformat_module("fe-common/silc", NULL, NULL,
1611 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1614 completion(FALSE, context);
1618 pw = getpwuid(getuid());
1621 completion(FALSE, context);
1625 memset(filename, 0, sizeof(filename));
1626 memset(filename2, 0, sizeof(filename2));
1627 memset(file, 0, sizeof(file));
1629 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1630 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1632 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1633 conn->sock->ip, conn->sock->port);
1634 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1635 get_irssi_dir(), entity, file);
1637 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1638 conn->sock->hostname, conn->sock->port);
1639 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1640 get_irssi_dir(), entity, file);
1645 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1646 name, conn->sock->port);
1647 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1648 get_irssi_dir(), entity, file);
1653 /* Replace all whitespaces with `_'. */
1654 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1655 for (i = 0; i < strlen(fingerprint); i++)
1656 if (fingerprint[i] == ' ')
1657 fingerprint[i] = '_';
1659 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1660 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1661 get_irssi_dir(), entity, file);
1662 silc_free(fingerprint);
1667 /* Take fingerprint of the public key */
1668 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1669 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1671 verify = silc_calloc(1, sizeof(*verify));
1672 verify->client = client;
1673 verify->conn = conn;
1674 verify->filename = strdup(ipf);
1675 verify->entity = strdup(entity);
1676 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1677 (name ? strdup(name) : strdup(conn->sock->hostname))
1679 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1680 memcpy(verify->pk, pk, pk_len);
1681 verify->pk_len = pk_len;
1682 verify->pk_type = pk_type;
1683 verify->completion = completion;
1684 verify->context = context;
1686 /* Check whether this key already exists */
1687 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1688 /* Key does not exist, ask user to verify the key and save it */
1690 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1691 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1692 verify->entity_name : entity);
1693 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1694 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1695 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1696 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1697 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1698 SILCTXT_PUBKEY_ACCEPT);
1699 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1702 silc_free(fingerprint);
1705 /* The key already exists, verify it. */
1706 SilcPublicKey public_key;
1707 unsigned char *encpk;
1708 SilcUInt32 encpk_len;
1710 /* Load the key file, try for both IP filename and hostname filename */
1711 if (!silc_pkcs_load_public_key(ipf, &public_key,
1712 SILC_PKCS_FILE_PEM) &&
1713 !silc_pkcs_load_public_key(ipf, &public_key,
1714 SILC_PKCS_FILE_BIN) &&
1715 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1716 SILC_PKCS_FILE_PEM) &&
1717 !silc_pkcs_load_public_key(hostf, &public_key,
1718 SILC_PKCS_FILE_BIN)))) {
1719 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1720 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1721 verify->entity_name : entity);
1722 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1723 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1724 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1725 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1726 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1727 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1728 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1729 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1730 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1733 silc_free(fingerprint);
1737 /* Encode the key data */
1738 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1740 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1741 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1742 verify->entity_name : entity);
1743 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1744 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1745 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1746 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1747 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1748 SILCTXT_PUBKEY_MALFORMED, entity);
1749 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1750 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1751 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1754 silc_free(fingerprint);
1758 /* Compare the keys */
1759 if (memcmp(encpk, pk, encpk_len)) {
1760 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1761 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1762 verify->entity_name : entity);
1763 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1764 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1765 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1766 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1767 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1768 SILCTXT_PUBKEY_NO_MATCH, entity);
1769 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1770 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1771 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1772 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1774 /* Ask user to verify the key and save it */
1775 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1776 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1777 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1780 silc_free(fingerprint);
1784 /* Local copy matched */
1786 completion(TRUE, context);
1787 silc_free(fingerprint);
1791 /* Verifies received public key. The `conn_type' indicates which entity
1792 (server, client etc.) has sent the public key. If user decides to trust
1793 the key may be saved as trusted public key for later use. The
1794 `completion' must be called after the public key has been verified. */
1797 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1798 SilcSocketType conn_type, unsigned char *pk,
1799 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1800 SilcVerifyPublicKey completion, void *context)
1802 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1804 completion, context);
1807 /* Asks passphrase from user on the input line. */
1810 SilcAskPassphrase completion;
1814 void ask_passphrase_completion(const char *passphrase, void *context)
1816 AskPassphrase p = (AskPassphrase)context;
1817 if (passphrase && passphrase[0] == '\0')
1819 p->completion((unsigned char *)passphrase,
1820 passphrase ? strlen(passphrase) : 0, p->context);
1824 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1825 SilcAskPassphrase completion, void *context)
1827 AskPassphrase p = silc_calloc(1, sizeof(*p));
1828 p->completion = completion;
1829 p->context = context;
1831 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1832 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1836 SilcGetAuthMeth completion;
1838 } *InternalGetAuthMethod;
1840 /* Callback called when we've received the authentication method information
1841 from the server after we've requested it. This will get the authentication
1842 data from the user if needed. */
1844 static void silc_get_auth_method_callback(SilcClient client,
1845 SilcClientConnection conn,
1846 SilcAuthMethod auth_meth,
1849 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1851 SILC_LOG_DEBUG(("Start"));
1853 switch (auth_meth) {
1854 case SILC_AUTH_NONE:
1855 /* No authentication required. */
1856 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1858 case SILC_AUTH_PASSWORD:
1859 /* Do not ask the passphrase from user, the library will ask it if
1860 we do not provide it here. */
1861 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1863 case SILC_AUTH_PUBLIC_KEY:
1864 /* Do not get the authentication data now, the library will generate
1865 it using our default key, if we do not provide it here. */
1866 /* XXX In the future when we support multiple local keys and multiple
1867 local certificates we will need to ask from user which one to use. */
1868 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1872 silc_free(internal);
1875 /* Find authentication method and authentication data by hostname and
1876 port. The hostname may be IP address as well. The found authentication
1877 method and authentication data is returned to `auth_meth', `auth_data'
1878 and `auth_data_len'. The function returns TRUE if authentication method
1879 is found and FALSE if not. `conn' may be NULL. */
1881 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1882 char *hostname, SilcUInt16 port,
1883 SilcGetAuthMeth completion, void *context)
1885 InternalGetAuthMethod internal;
1887 SILC_LOG_DEBUG(("Start"));
1889 /* XXX must resolve from configuration whether this connection has
1890 any specific authentication data */
1892 /* If we do not have this connection configured by the user in a
1893 configuration file then resolve the authentication method from the
1894 server for this session. */
1895 internal = silc_calloc(1, sizeof(*internal));
1896 internal->completion = completion;
1897 internal->context = context;
1899 silc_client_request_authentication_method(client, conn,
1900 silc_get_auth_method_callback,
1904 /* Notifies application that failure packet was received. This is called
1905 if there is some protocol active in the client. The `protocol' is the
1906 protocol context. The `failure' is opaque pointer to the failure
1907 indication. Note, that the `failure' is protocol dependant and application
1908 must explicitly cast it to correct type. Usually `failure' is 32 bit
1909 failure type (see protocol specs for all protocol failure types). */
1911 void silc_failure(SilcClient client, SilcClientConnection conn,
1912 SilcProtocol protocol, void *failure)
1914 SILC_LOG_DEBUG(("Start"));
1916 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1917 SilcSKEStatus status = (SilcSKEStatus)failure;
1919 if (status == SILC_SKE_STATUS_BAD_VERSION)
1920 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1921 SILCTXT_KE_BAD_VERSION);
1922 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1923 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1924 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1925 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1926 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1927 SILCTXT_KE_UNKNOWN_GROUP);
1928 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1929 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1930 SILCTXT_KE_UNKNOWN_CIPHER);
1931 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1932 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1933 SILCTXT_KE_UNKNOWN_PKCS);
1934 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1935 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1936 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1937 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1938 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1939 SILCTXT_KE_UNKNOWN_HMAC);
1940 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1941 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1942 SILCTXT_KE_INCORRECT_SIGNATURE);
1943 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1944 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1945 SILCTXT_KE_INVALID_COOKIE);
1948 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1949 SilcUInt32 err = (SilcUInt32)failure;
1951 if (err == SILC_AUTH_FAILED)
1952 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1953 SILCTXT_AUTH_FAILED);
1957 /* Asks whether the user would like to perform the key agreement protocol.
1958 This is called after we have received an key agreement packet or an
1959 reply to our key agreement packet. This returns TRUE if the user wants
1960 the library to perform the key agreement protocol and FALSE if it is not
1961 desired (application may start it later by calling the function
1962 silc_client_perform_key_agreement). */
1964 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1965 SilcClientEntry client_entry, const char *hostname,
1966 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1971 SILC_LOG_DEBUG(("Start"));
1973 /* We will just display the info on the screen and return FALSE and user
1974 will have to start the key agreement with a command. */
1977 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1980 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1981 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1983 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1984 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1985 client_entry->nickname, hostname, portstr);
1993 /* Notifies application that file transfer protocol session is being
1994 requested by the remote client indicated by the `client_entry' from
1995 the `hostname' and `port'. The `session_id' is the file transfer
1996 session and it can be used to either accept or reject the file
1997 transfer request, by calling the silc_client_file_receive or
1998 silc_client_file_close, respectively. */
2000 void silc_ftp(SilcClient client, SilcClientConnection conn,
2001 SilcClientEntry client_entry, SilcUInt32 session_id,
2002 const char *hostname, SilcUInt16 port)
2004 SILC_SERVER_REC *server;
2006 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2008 SILC_LOG_DEBUG(("Start"));
2010 server = conn->context;
2012 ftp->client_entry = client_entry;
2013 ftp->session_id = session_id;
2016 silc_dlist_add(server->ftp_sessions, ftp);
2017 server->current_session = ftp;
2020 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2023 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2024 SILCTXT_FILE_REQUEST, client_entry->nickname);
2026 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2027 SILCTXT_FILE_REQUEST_HOST,
2028 client_entry->nickname, hostname, portstr);
2031 /* Delivers SILC session detachment data indicated by `detach_data' to the
2032 application. If application has issued SILC_COMMAND_DETACH command
2033 the client session in the SILC network is not quit. The client remains
2034 in the network but is detached. The detachment data may be used later
2035 to resume the session in the SILC Network. The appliation is
2036 responsible of saving the `detach_data', to for example in a file.
2038 The detachment data can be given as argument to the functions
2039 silc_client_connect_to_server, or silc_client_add_connection when
2040 creating connection to remote server, inside SilcClientConnectionParams
2041 structure. If it is provided the client library will attempt to resume
2042 the session in the network. After the connection is created
2043 successfully, the application is responsible of setting the user
2044 interface for user into the same state it was before detaching (showing
2045 same channels, channel modes, etc). It can do this by fetching the
2046 information (like joined channels) from the client library. */
2049 silc_detach(SilcClient client, SilcClientConnection conn,
2050 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2054 /* Save the detachment data to file. */
2056 memset(file, 0, sizeof(file));
2057 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2058 silc_file_writefile(file, detach_data, detach_data_len);
2062 /* SILC client operations */
2063 SilcClientOperations ops = {
2065 silc_channel_message,
2066 silc_private_message,
2072 silc_get_auth_method,
2073 silc_verify_public_key,
2074 silc_ask_passphrase,