5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "chat-protocols.h"
26 #include "servers-setup.h"
27 #include "channels-setup.h"
28 #include "silc-servers.h"
29 #include "silc-channels.h"
30 #include "silc-queries.h"
31 #include "silc-nicklist.h"
36 #include "fe-common/core/printtext.h"
37 #include "fe-common/core/fe-channels.h"
38 #include "fe-common/core/keyboard.h"
39 #include "fe-common/silc/module-formats.h"
44 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
45 const char *name, SilcSocketType conn_type,
46 unsigned char *pk, SilcUInt32 pk_len,
47 SilcSKEPKType pk_type,
48 SilcVerifyPublicKey completion, void *context);
50 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
53 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
54 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
55 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
57 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
58 "[SILC operator]" : "[unknown mode]");
60 if (mode & SILC_UMODE_GONE)
61 strcat(buf, " [away]");
62 if (mode & SILC_UMODE_INDISPOSED)
63 strcat(buf, " [indisposed]");
64 if (mode & SILC_UMODE_BUSY)
65 strcat(buf, " [busy]");
66 if (mode & SILC_UMODE_PAGE)
67 strcat(buf, " [page to reach]");
68 if (mode & SILC_UMODE_HYPER)
69 strcat(buf, " [hyper active]");
70 if (mode & SILC_UMODE_ROBOT)
71 strcat(buf, " [robot]");
72 if (mode & SILC_UMODE_ANONYMOUS)
73 strcat(buf, " [anonymous]");
74 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
75 strcat(buf, " [blocks private messages]");
76 if (mode & SILC_UMODE_DETACHED)
77 strcat(buf, " [detached]");
78 if (mode & SILC_UMODE_REJECT_WATCHING)
79 strcat(buf, " [rejects watching]");
80 if (mode & SILC_UMODE_BLOCK_INVITE)
81 strcat(buf, " [blocks invites]");
84 void silc_say(SilcClient client, SilcClientConnection conn,
85 SilcClientMessageType type, char *msg, ...)
87 SILC_SERVER_REC *server;
91 server = conn == NULL ? NULL : conn->context;
94 str = g_strdup_vprintf(msg, va);
95 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
100 void silc_say_error(char *msg, ...)
106 str = g_strdup_vprintf(msg, va);
107 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
113 /* Message for a channel. The `sender' is the nickname of the sender
114 received in the packet. The `channel_name' is the name of the channel. */
116 void silc_channel_message(SilcClient client, SilcClientConnection conn,
117 SilcClientEntry sender, SilcChannelEntry channel,
118 SilcMessageFlags flags, const unsigned char *message,
119 SilcUInt32 message_len)
121 SILC_SERVER_REC *server;
123 SILC_CHANNEL_REC *chanrec;
125 SILC_LOG_DEBUG(("Start"));
130 server = conn == NULL ? NULL : conn->context;
131 chanrec = silc_channel_find_entry(server, channel);
135 nick = silc_nicklist_find(chanrec, sender);
137 /* We didn't find client but it clearly exists, add it. */
138 SilcChannelUser chu = silc_client_on_channel(channel, sender);
140 nick = silc_nicklist_insert(chanrec, chu, FALSE);
143 if (flags & SILC_MESSAGE_FLAG_DATA) {
144 /* MIME object received, try to display it as well as we can */
148 memset(type, 0, sizeof(type));
149 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
150 NULL, 0, &data, NULL))
153 /* Then figure out what we can display */
154 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
155 !strstr(type, "text/vnd")) {
156 /* It is something textual, display it */
157 message = (const unsigned char *)data;
159 printformat_module("fe-common/silc", server, channel->channel_name,
160 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
161 nick == NULL ? "[<unknown>]" : nick->nick, type);
169 if (flags & SILC_MESSAGE_FLAG_ACTION)
170 printformat_module("fe-common/silc", server, channel->channel_name,
171 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
172 nick == NULL ? "[<unknown>]" : nick->nick, message);
173 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
174 printformat_module("fe-common/silc", server, channel->channel_name,
175 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
176 nick == NULL ? "[<unknown>]" : nick->nick, message);
178 signal_emit("message public", 6, server, message,
179 nick == NULL ? "[<unknown>]" : nick->nick,
180 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
181 chanrec->name, nick);
184 /* Private message to the client. The `sender' is the nickname of the
185 sender received in the packet. */
187 void silc_private_message(SilcClient client, SilcClientConnection conn,
188 SilcClientEntry sender, SilcMessageFlags flags,
189 const unsigned char *message,
190 SilcUInt32 message_len)
192 SILC_SERVER_REC *server;
195 SILC_LOG_DEBUG(("Start"));
197 server = conn == NULL ? NULL : conn->context;
198 memset(userhost, 0, sizeof(userhost));
199 if (sender->username)
200 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
201 sender->username, sender->hostname);
203 if (flags & SILC_MESSAGE_FLAG_DATA) {
204 /* MIME object received, try to display it as well as we can */
208 memset(type, 0, sizeof(type));
209 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
210 NULL, 0, &data, NULL))
213 /* Then figure out what we can display */
214 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
215 !strstr(type, "text/vnd")) {
216 /* It is something textual, display it */
217 message = (const unsigned char *)data;
219 printformat_module("fe-common/silc", server, NULL,
220 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
221 sender->nickname ? sender->nickname : "[<unknown>]",
230 signal_emit("message private", 4, server, message,
231 sender->nickname ? sender->nickname : "[<unknown>]",
232 sender->username ? userhost : NULL);
235 /* Notify message to the client. The notify arguments are sent in the
236 same order as servers sends them. The arguments are same as received
237 from the server except for ID's. If ID is received application receives
238 the corresponding entry to the ID. For example, if Client ID is received
239 application receives SilcClientEntry. Also, if the notify type is
240 for channel the channel entry is sent to application (even if server
241 does not send it). */
243 void silc_notify(SilcClient client, SilcClientConnection conn,
244 SilcNotifyType type, ...)
247 SILC_SERVER_REC *server;
248 SILC_CHANNEL_REC *chanrec;
249 SILC_NICK_REC *nickrec;
250 SilcClientEntry client_entry, client_entry2;
251 SilcChannelEntry channel, channel2;
252 SilcServerEntry server_entry;
258 GSList *list1, *list_tmp;
260 SILC_LOG_DEBUG(("Start"));
264 server = conn == NULL ? NULL : conn->context;
267 case SILC_NOTIFY_TYPE_NONE:
268 /* Some generic notice from server */
269 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
272 case SILC_NOTIFY_TYPE_INVITE:
274 * Invited or modified invite list.
277 SILC_LOG_DEBUG(("Notify: INVITE"));
279 channel = va_arg(va, SilcChannelEntry);
280 name = va_arg(va, char *);
281 client_entry = va_arg(va, SilcClientEntry);
283 memset(buf, 0, sizeof(buf));
284 snprintf(buf, sizeof(buf) - 1, "%s@%s",
285 client_entry->username, client_entry->hostname);
286 signal_emit("message invite", 4, server, channel ? channel->channel_name :
287 name, client_entry->nickname, buf);
290 case SILC_NOTIFY_TYPE_JOIN:
295 SILC_LOG_DEBUG(("Notify: JOIN"));
297 client_entry = va_arg(va, SilcClientEntry);
298 channel = va_arg(va, SilcChannelEntry);
300 if (client_entry == server->conn->local_entry) {
301 /* You joined to channel */
302 chanrec = silc_channel_find(server, channel->channel_name);
303 if (chanrec != NULL && !chanrec->joined)
304 chanrec->entry = channel;
306 chanrec = silc_channel_find_entry(server, channel);
307 if (chanrec != NULL) {
308 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
310 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
314 memset(buf, 0, sizeof(buf));
315 if (client_entry->username)
316 snprintf(buf, sizeof(buf) - 1, "%s@%s",
317 client_entry->username, client_entry->hostname);
318 signal_emit("message join", 4, server, channel->channel_name,
319 client_entry->nickname,
320 client_entry->username == NULL ? "" : buf);
323 case SILC_NOTIFY_TYPE_LEAVE:
328 SILC_LOG_DEBUG(("Notify: LEAVE"));
330 client_entry = va_arg(va, SilcClientEntry);
331 channel = va_arg(va, SilcChannelEntry);
333 memset(buf, 0, sizeof(buf));
334 if (client_entry->username)
335 snprintf(buf, sizeof(buf) - 1, "%s@%s",
336 client_entry->username, client_entry->hostname);
337 signal_emit("message part", 5, server, channel->channel_name,
338 client_entry->nickname, client_entry->username ?
339 buf : "", client_entry->nickname);
341 chanrec = silc_channel_find_entry(server, channel);
342 if (chanrec != NULL) {
343 nickrec = silc_nicklist_find(chanrec, client_entry);
345 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
349 case SILC_NOTIFY_TYPE_SIGNOFF:
354 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
356 client_entry = va_arg(va, SilcClientEntry);
357 tmp = va_arg(va, char *);
359 silc_server_free_ftp(server, client_entry);
361 memset(buf, 0, sizeof(buf));
362 if (client_entry->username)
363 snprintf(buf, sizeof(buf) - 1, "%s@%s",
364 client_entry->username, client_entry->hostname);
365 signal_emit("message quit", 4, server, client_entry->nickname,
366 client_entry->username ? buf : "",
369 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
370 for (list_tmp = list1; list_tmp != NULL; list_tmp =
371 list_tmp->next->next) {
372 CHANNEL_REC *channel = list_tmp->data;
373 NICK_REC *nickrec = list_tmp->next->data;
375 nicklist_remove(channel, nickrec);
379 case SILC_NOTIFY_TYPE_TOPIC_SET:
384 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
386 idtype = va_arg(va, int);
387 entry = va_arg(va, void *);
388 tmp = va_arg(va, char *);
389 channel = va_arg(va, SilcChannelEntry);
391 chanrec = silc_channel_find_entry(server, channel);
392 if (chanrec != NULL) {
393 g_free_not_null(chanrec->topic);
394 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
395 signal_emit("channel topic changed", 1, chanrec);
398 if (idtype == SILC_ID_CLIENT) {
399 client_entry = (SilcClientEntry)entry;
400 memset(buf, 0, sizeof(buf));
401 snprintf(buf, sizeof(buf) - 1, "%s@%s",
402 client_entry->username, client_entry->hostname);
403 signal_emit("message topic", 5, server, channel->channel_name,
404 tmp, client_entry->nickname, buf);
405 } else if (idtype == SILC_ID_SERVER) {
406 server_entry = (SilcServerEntry)entry;
407 signal_emit("message topic", 5, server, channel->channel_name,
408 tmp, server_entry->server_name,
409 server_entry->server_name);
410 } else if (idtype == SILC_ID_CHANNEL) {
411 channel = (SilcChannelEntry)entry;
412 signal_emit("message topic", 5, server, channel->channel_name,
413 tmp, channel->channel_name, channel->channel_name);
417 case SILC_NOTIFY_TYPE_NICK_CHANGE:
422 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
424 client_entry = va_arg(va, SilcClientEntry);
425 client_entry2 = va_arg(va, SilcClientEntry);
427 if (!strcmp(client_entry->nickname, client_entry2->nickname))
430 memset(buf, 0, sizeof(buf));
431 snprintf(buf, sizeof(buf) - 1, "%s@%s",
432 client_entry2->username, client_entry2->hostname);
433 nicklist_rename_unique(SERVER(server),
434 client_entry, client_entry->nickname,
435 client_entry2, client_entry2->nickname);
436 signal_emit("message nick", 4, server, client_entry2->nickname,
437 client_entry->nickname, buf);
440 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
442 * Changed channel mode.
445 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
447 idtype = va_arg(va, int);
448 entry = va_arg(va, void *);
449 mode = va_arg(va, SilcUInt32);
450 (void)va_arg(va, char *);
451 (void)va_arg(va, char *);
452 channel = va_arg(va, SilcChannelEntry);
454 tmp = silc_client_chmode(mode,
455 channel->channel_key ?
456 channel->channel_key->cipher->name : "",
458 silc_hmac_get_name(channel->hmac) : "");
460 chanrec = silc_channel_find_entry(server, channel);
461 if (chanrec != NULL) {
462 g_free_not_null(chanrec->mode);
463 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
464 signal_emit("channel mode changed", 1, chanrec);
467 if (idtype == SILC_ID_CLIENT) {
468 client_entry = (SilcClientEntry)entry;
469 printformat_module("fe-common/silc", server, channel->channel_name,
470 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
471 channel->channel_name, tmp ? tmp : "removed all",
472 client_entry->nickname);
473 } else if (idtype == SILC_ID_SERVER) {
474 server_entry = (SilcServerEntry)entry;
475 printformat_module("fe-common/silc", server, channel->channel_name,
476 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
477 channel->channel_name, tmp ? tmp : "removed all",
478 server_entry->server_name);
479 } else if (idtype == SILC_ID_CHANNEL) {
480 channel2 = (SilcChannelEntry)entry;
481 printformat_module("fe-common/silc", server, channel->channel_name,
482 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
483 channel->channel_name, tmp ? tmp : "removed all",
484 channel2->channel_name);
490 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
492 * Changed user's mode on channel.
495 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
497 idtype = va_arg(va, int);
498 entry = va_arg(va, void *);
499 mode = va_arg(va, SilcUInt32);
500 client_entry2 = va_arg(va, SilcClientEntry);
501 channel = va_arg(va, SilcChannelEntry);
503 tmp = silc_client_chumode(mode);
504 chanrec = silc_channel_find_entry(server, channel);
505 if (chanrec != NULL) {
508 if (client_entry2 == server->conn->local_entry)
509 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
511 nick = silc_nicklist_find(chanrec, client_entry2);
513 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
514 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
515 signal_emit("nick mode changed", 2, chanrec, nick);
519 if (idtype == SILC_ID_CLIENT) {
520 client_entry = (SilcClientEntry)entry;
521 printformat_module("fe-common/silc", server, channel->channel_name,
522 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
523 channel->channel_name, client_entry2->nickname,
524 tmp ? tmp : "removed all",
525 client_entry->nickname);
526 } else if (idtype == SILC_ID_SERVER) {
527 server_entry = (SilcServerEntry)entry;
528 printformat_module("fe-common/silc", server, channel->channel_name,
529 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
530 channel->channel_name, client_entry2->nickname,
531 tmp ? tmp : "removed all",
532 server_entry->server_name);
533 } else if (idtype == SILC_ID_CHANNEL) {
534 channel2 = (SilcChannelEntry)entry;
535 printformat_module("fe-common/silc", server, channel->channel_name,
536 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
537 channel->channel_name, client_entry2->nickname,
538 tmp ? tmp : "removed all",
539 channel2->channel_name);
542 if (mode & SILC_CHANNEL_UMODE_CHANFO)
543 printformat_module("fe-common/silc",
544 server, channel->channel_name, MSGLEVEL_CRAP,
545 SILCTXT_CHANNEL_FOUNDER,
546 channel->channel_name, client_entry2->nickname);
551 case SILC_NOTIFY_TYPE_MOTD:
556 SILC_LOG_DEBUG(("Notify: MOTD"));
558 tmp = va_arg(va, char *);
560 if (!settings_get_bool("skip_motd"))
561 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
564 case SILC_NOTIFY_TYPE_KICKED:
566 * Someone was kicked from channel.
569 SILC_LOG_DEBUG(("Notify: KICKED"));
571 client_entry = va_arg(va, SilcClientEntry);
572 tmp = va_arg(va, char *);
573 client_entry2 = va_arg(va, SilcClientEntry);
574 channel = va_arg(va, SilcChannelEntry);
576 chanrec = silc_channel_find_entry(server, channel);
578 if (client_entry == conn->local_entry) {
579 printformat_module("fe-common/silc", server, channel->channel_name,
580 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
581 channel->channel_name,
582 client_entry ? client_entry2->nickname : "",
585 chanrec->kicked = TRUE;
586 channel_destroy((CHANNEL_REC *)chanrec);
589 printformat_module("fe-common/silc", server, channel->channel_name,
590 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
591 client_entry->nickname, channel->channel_name,
592 client_entry2 ? client_entry2->nickname : "",
596 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
598 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
603 case SILC_NOTIFY_TYPE_KILLED:
605 * Someone was killed from the network.
608 SILC_LOG_DEBUG(("Notify: KILLED"));
610 client_entry = va_arg(va, SilcClientEntry);
611 tmp = va_arg(va, char *);
612 idtype = va_arg(va, int);
613 entry = va_arg(va, SilcClientEntry);
615 if (client_entry == conn->local_entry) {
616 if (idtype == SILC_ID_CLIENT) {
617 client_entry2 = (SilcClientEntry)entry;
618 printformat_module("fe-common/silc", server, NULL,
619 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
620 client_entry2 ? client_entry2->nickname : "",
622 } else if (idtype == SILC_ID_SERVER) {
623 server_entry = (SilcServerEntry)entry;
624 printformat_module("fe-common/silc", server, NULL,
625 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
626 server_entry->server_name, tmp ? tmp : "");
627 } else if (idtype == SILC_ID_CHANNEL) {
628 channel = (SilcChannelEntry)entry;
629 printformat_module("fe-common/silc", server, NULL,
630 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
631 channel->channel_name, tmp ? tmp : "");
634 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
635 for (list_tmp = list1; list_tmp != NULL; list_tmp =
636 list_tmp->next->next) {
637 CHANNEL_REC *channel = list_tmp->data;
638 NICK_REC *nickrec = list_tmp->next->data;
639 nicklist_remove(channel, nickrec);
642 if (idtype == SILC_ID_CLIENT) {
643 client_entry2 = (SilcClientEntry)entry;
644 printformat_module("fe-common/silc", server, NULL,
645 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
646 client_entry->nickname,
647 client_entry2 ? client_entry2->nickname : "",
649 } else if (idtype == SILC_ID_SERVER) {
650 server_entry = (SilcServerEntry)entry;
651 printformat_module("fe-common/silc", server, NULL,
652 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
653 client_entry->nickname,
654 server_entry->server_name, tmp ? tmp : "");
655 } else if (idtype == SILC_ID_CHANNEL) {
656 channel = (SilcChannelEntry)entry;
657 printformat_module("fe-common/silc", server, NULL,
658 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
659 client_entry->nickname,
660 channel->channel_name, tmp ? tmp : "");
665 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
668 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
671 * Server has quit the network.
674 SilcClientEntry *clients;
675 SilcUInt32 clients_count;
677 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
679 (void)va_arg(va, void *);
680 clients = va_arg(va, SilcClientEntry *);
681 clients_count = va_arg(va, SilcUInt32);
683 for (i = 0; i < clients_count; i++) {
684 memset(buf, 0, sizeof(buf));
685 if (clients[i]->username)
686 snprintf(buf, sizeof(buf) - 1, "%s@%s",
687 clients[i]->username, clients[i]->hostname);
688 signal_emit("message quit", 4, server, clients[i]->nickname,
689 clients[i]->username ? buf : "",
692 silc_server_free_ftp(server, clients[i]);
694 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
695 for (list_tmp = list1; list_tmp != NULL; list_tmp =
696 list_tmp->next->next) {
697 CHANNEL_REC *channel = list_tmp->data;
698 NICK_REC *nickrec = list_tmp->next->data;
699 nicklist_remove(channel, nickrec);
705 case SILC_NOTIFY_TYPE_ERROR:
707 SilcStatus error = va_arg(va, int);
709 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
710 "%s", silc_get_status_message(error));
714 case SILC_NOTIFY_TYPE_WATCH:
716 SilcNotifyType notify;
718 client_entry = va_arg(va, SilcClientEntry);
719 name = va_arg(va, char *); /* Maybe NULL */
720 mode = va_arg(va, SilcUInt32);
721 notify = va_arg(va, int);
723 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
725 printformat_module("fe-common/silc", server, NULL,
726 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
727 client_entry->nickname, name);
729 printformat_module("fe-common/silc", server, NULL,
730 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
731 client_entry->nickname);
732 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
733 /* See if client was away and is now present */
734 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
735 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
736 SILC_UMODE_DETACHED)) &&
737 (client_entry->mode & SILC_UMODE_GONE ||
738 client_entry->mode & SILC_UMODE_INDISPOSED ||
739 client_entry->mode & SILC_UMODE_BUSY ||
740 client_entry->mode & SILC_UMODE_PAGE ||
741 client_entry->mode & SILC_UMODE_DETACHED)) {
742 printformat_module("fe-common/silc", server, NULL,
743 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
744 client_entry->nickname);
748 memset(buf, 0, sizeof(buf));
749 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
750 printformat_module("fe-common/silc", server, NULL,
751 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
752 client_entry->nickname, buf);
754 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
755 printformat_module("fe-common/silc", server, NULL,
756 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
757 client_entry->nickname);
758 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
759 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
760 printformat_module("fe-common/silc", server, NULL,
761 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
762 client_entry->nickname);
763 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
764 /* Client logged in to the network */
765 printformat_module("fe-common/silc", server, NULL,
766 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
767 client_entry->nickname);
774 printformat_module("fe-common/silc", server, NULL,
775 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
782 /* Called to indicate that connection was either successfully established
783 or connecting failed. This is also the first time application receives
784 the SilcClientConnection object which it should save somewhere. */
786 void silc_connect(SilcClient client, SilcClientConnection conn,
787 SilcClientConnectionStatus status)
789 SILC_SERVER_REC *server = conn->context;
792 silc_client_close_connection(client, conn);
797 case SILC_CLIENT_CONN_SUCCESS:
798 /* We have successfully connected to server */
799 server->connected = TRUE;
800 signal_emit("event connected", 1, server);
803 case SILC_CLIENT_CONN_SUCCESS_RESUME:
804 /* We have successfully resumed old detached session */
805 server->connected = TRUE;
806 signal_emit("event connected", 1, server);
808 /* If we resumed old session check whether we need to update
810 if (strcmp(server->nick, conn->local_entry->nickname)) {
812 old = g_strdup(server->nick);
813 server_change_nick(SERVER(server), conn->local_entry->nickname);
814 nicklist_rename_unique(SERVER(server),
815 conn->local_entry, server->nick,
816 conn->local_entry, conn->local_entry->nickname);
817 signal_emit("message own_nick", 4, server, server->nick, old, "");
823 server->connection_lost = TRUE;
825 server->conn->context = NULL;
826 server_disconnect(SERVER(server));
831 /* Called to indicate that connection was disconnected to the server. */
833 void silc_disconnect(SilcClient client, SilcClientConnection conn)
835 SILC_SERVER_REC *server = conn->context;
837 SILC_LOG_DEBUG(("Start"));
839 if (!server || server->connection_lost)
842 if (server->conn && server->conn->local_entry) {
843 nicklist_rename_unique(SERVER(server),
844 server->conn->local_entry, server->nick,
845 server->conn->local_entry,
846 silc_client->username);
847 silc_change_nick(server, silc_client->username);
850 server->conn->context = NULL;
852 server->connection_lost = TRUE;
853 server_disconnect(SERVER(server));
856 /* Command handler. This function is called always in the command function.
857 If error occurs it will be called as well. `conn' is the associated
858 client connection. `cmd_context' is the command context that was
859 originally sent to the command. `success' is FALSE if error occured
860 during command. `command' is the command being processed. It must be
861 noted that this is not reply from server. This is merely called just
862 after application has called the command. Just to tell application
863 that the command really was processed. */
865 void silc_command(SilcClient client, SilcClientConnection conn,
866 SilcClientCommandContext cmd_context, bool success,
867 SilcCommand command, SilcStatus status)
869 SILC_SERVER_REC *server = conn->context;
871 SILC_LOG_DEBUG(("Start"));
877 case SILC_COMMAND_INVITE:
878 printformat_module("fe-common/silc", server, NULL,
879 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
880 cmd_context->argv[2],
881 (cmd_context->argv[1][0] == '*' ?
882 (char *)conn->current_channel->channel_name :
883 (char *)cmd_context->argv[1]));
890 /* Client info resolving callback when JOIN command reply is received.
891 This will cache all users on the channel. */
893 static void silc_client_join_get_users(SilcClient client,
894 SilcClientConnection conn,
895 SilcClientEntry *clients,
896 SilcUInt32 clients_count,
899 SilcChannelEntry channel = (SilcChannelEntry)context;
900 SilcHashTableList htl;
902 SILC_SERVER_REC *server = conn->context;
903 SILC_CHANNEL_REC *chanrec;
904 SilcClientEntry founder = NULL;
907 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
908 silc_hash_table_count(channel->user_list)));
913 chanrec = silc_channel_find(server, channel->channel_name);
917 silc_hash_table_list(channel->user_list, &htl);
918 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
919 if (!chu->client->nickname)
921 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
922 founder = chu->client;
923 silc_nicklist_insert(chanrec, chu, FALSE);
925 silc_hash_table_list_reset(&htl);
927 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
928 nicklist_set_own(CHANNEL(chanrec), ownnick);
929 signal_emit("channel joined", 1, chanrec);
930 chanrec->entry = channel;
933 printformat_module("fe-common/silc", server, channel->channel_name,
934 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
935 channel->channel_name, chanrec->topic);
937 fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
940 if (founder == conn->local_entry)
941 printformat_module("fe-common/silc",
942 server, channel->channel_name, MSGLEVEL_CRAP,
943 SILCTXT_CHANNEL_FOUNDER_YOU,
944 channel->channel_name);
946 printformat_module("fe-common/silc",
947 server, channel->channel_name, MSGLEVEL_CRAP,
948 SILCTXT_CHANNEL_FOUNDER,
949 channel->channel_name, founder->nickname);
955 SilcClientConnection conn;
961 void silc_getkey_cb(bool success, void *context)
963 GetkeyContext getkey = (GetkeyContext)context;
964 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
965 char *name = (getkey->id_type == SILC_ID_CLIENT ?
966 ((SilcClientEntry)getkey->entry)->nickname :
967 ((SilcServerEntry)getkey->entry)->server_name);
970 printformat_module("fe-common/silc", NULL, NULL,
971 MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
973 printformat_module("fe-common/silc", NULL, NULL,
974 MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
977 silc_free(getkey->fingerprint);
981 /* Command reply handler. This function is called always in the command reply
982 function. If error occurs it will be called as well. Normal scenario
983 is that it will be called after the received command data has been parsed
984 and processed. The function is used to pass the received command data to
987 `conn' is the associated client connection. `cmd_payload' is the command
988 payload data received from server and it can be ignored. It is provided
989 if the application would like to re-parse the received command data,
990 however, it must be noted that the data is parsed already by the library
991 thus the payload can be ignored. `success' is FALSE if error occured.
992 In this case arguments are not sent to the application. `command' is the
993 command reply being processed. The function has variable argument list
994 and each command defines the number and type of arguments it passes to the
995 application (on error they are not sent). */
998 silc_command_reply(SilcClient client, SilcClientConnection conn,
999 SilcCommandPayload cmd_payload, bool success,
1000 SilcCommand command, SilcStatus status, ...)
1003 SILC_SERVER_REC *server = conn->context;
1004 SILC_CHANNEL_REC *chanrec;
1007 va_start(vp, status);
1009 SILC_LOG_DEBUG(("Start"));
1012 case SILC_COMMAND_WHOIS:
1014 char buf[1024], *nickname, *username, *realname, *nick;
1015 unsigned char *fingerprint;
1016 SilcUInt32 idle, mode;
1017 SilcBuffer channels, user_modes;
1018 SilcClientEntry client_entry;
1020 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1021 /* Print the unknown nick for user */
1022 unsigned char *tmp =
1023 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1026 silc_say_error("%s: %s", tmp,
1027 silc_get_status_message(status));
1029 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1030 /* Try to find the entry for the unknown client ID, since we
1031 might have, and print the nickname of it for user. */
1033 unsigned char *tmp =
1034 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1037 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1040 client_entry = silc_client_get_client_by_id(client, conn,
1042 if (client_entry && client_entry->nickname)
1043 silc_say_error("%s: %s", client_entry->nickname,
1044 silc_get_status_message(status));
1045 silc_free(client_id);
1054 client_entry = va_arg(vp, SilcClientEntry);
1055 nickname = va_arg(vp, char *);
1056 username = va_arg(vp, char *);
1057 realname = va_arg(vp, char *);
1058 channels = va_arg(vp, SilcBuffer);
1059 mode = va_arg(vp, SilcUInt32);
1060 idle = va_arg(vp, SilcUInt32);
1061 fingerprint = va_arg(vp, unsigned char *);
1062 user_modes = va_arg(vp, SilcBuffer);
1064 silc_parse_userfqdn(nickname, &nick, NULL);
1065 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1066 SILCTXT_WHOIS_USERINFO, nickname,
1067 client_entry->username, client_entry->hostname,
1068 nick, client_entry->nickname);
1069 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1070 SILCTXT_WHOIS_REALNAME, realname);
1073 if (channels && user_modes) {
1075 SilcDList list = silc_channel_payload_parse_list(channels->data,
1077 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1079 SilcChannelPayload entry;
1082 memset(buf, 0, sizeof(buf));
1083 silc_dlist_start(list);
1084 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1085 SilcUInt32 name_len;
1086 char *m = silc_client_chumode_char(umodes[i++]);
1087 char *name = silc_channel_get_name(entry, &name_len);
1090 strncat(buf, m, strlen(m));
1091 strncat(buf, name, name_len);
1092 strncat(buf, " ", 1);
1096 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1097 SILCTXT_WHOIS_CHANNELS, buf);
1098 silc_channel_payload_list_free(list);
1104 memset(buf, 0, sizeof(buf));
1105 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1106 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1107 SILCTXT_WHOIS_MODES, buf);
1110 if (idle && nickname) {
1111 memset(buf, 0, sizeof(buf));
1112 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1113 idle > 60 ? (idle / 60) : idle,
1114 idle > 60 ? "minutes" : "seconds");
1116 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1117 SILCTXT_WHOIS_IDLE, buf);
1121 fingerprint = silc_fingerprint(fingerprint, 20);
1122 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1123 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1124 silc_free(fingerprint);
1129 case SILC_COMMAND_IDENTIFY:
1131 SilcClientEntry client_entry;
1133 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1134 /* Print the unknown nick for user */
1135 unsigned char *tmp =
1136 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1139 silc_say_error("%s: %s", tmp,
1140 silc_get_status_message(status));
1142 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1143 /* Try to find the entry for the unknown client ID, since we
1144 might have, and print the nickname of it for user. */
1146 unsigned char *tmp =
1147 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1150 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1153 client_entry = silc_client_get_client_by_id(client, conn,
1155 if (client_entry && client_entry->nickname)
1156 silc_say_error("%s: %s", client_entry->nickname,
1157 silc_get_status_message(status));
1158 silc_free(client_id);
1167 case SILC_COMMAND_WHOWAS:
1169 char *nickname, *username, *realname;
1171 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1172 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1174 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1177 silc_say_error("%s: %s", tmp,
1178 silc_get_status_message(status));
1185 (void)va_arg(vp, SilcClientEntry);
1186 nickname = va_arg(vp, char *);
1187 username = va_arg(vp, char *);
1188 realname = va_arg(vp, char *);
1190 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1191 SILCTXT_WHOWAS_USERINFO, nickname, username,
1192 realname ? realname : "");
1196 case SILC_COMMAND_INVITE:
1198 SilcChannelEntry channel;
1200 SilcArgumentPayload args;
1206 channel = va_arg(vp, SilcChannelEntry);
1207 invite_list = va_arg(vp, char *);
1209 args = silc_command_get_args(cmd_payload);
1211 argc = silc_argument_get_arg_num(args);
1214 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1215 SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
1218 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1219 SILCTXT_CHANNEL_NO_INVITE_LIST,
1220 channel->channel_name);
1224 case SILC_COMMAND_JOIN:
1226 char *channel, *mode, *topic;
1228 SilcChannelEntry channel_entry;
1229 SilcBuffer client_id_list;
1230 SilcUInt32 list_count;
1235 channel = va_arg(vp, char *);
1236 channel_entry = va_arg(vp, SilcChannelEntry);
1237 modei = va_arg(vp, SilcUInt32);
1238 (void)va_arg(vp, SilcUInt32);
1239 (void)va_arg(vp, unsigned char *);
1240 (void)va_arg(vp, unsigned char *);
1241 (void)va_arg(vp, unsigned char *);
1242 topic = va_arg(vp, char *);
1243 (void)va_arg(vp, unsigned char *);
1244 list_count = va_arg(vp, SilcUInt32);
1245 client_id_list = va_arg(vp, SilcBuffer);
1247 chanrec = silc_channel_find(server, channel);
1249 chanrec = silc_channel_create(server, channel, TRUE);
1252 g_free_not_null(chanrec->topic);
1253 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1254 signal_emit("channel topic changed", 1, chanrec);
1257 mode = silc_client_chmode(modei,
1258 channel_entry->channel_key ?
1259 channel_entry->channel_key->cipher->name : "",
1260 channel_entry->hmac ?
1261 silc_hmac_get_name(channel_entry->hmac) : "");
1262 g_free_not_null(chanrec->mode);
1263 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1264 signal_emit("channel mode changed", 1, chanrec);
1266 /* Resolve the client information */
1267 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1268 silc_client_join_get_users,
1274 case SILC_COMMAND_NICK:
1277 SilcClientEntry client = va_arg(vp, SilcClientEntry);
1282 old = g_strdup(server->nick);
1283 server_change_nick(SERVER(server), client->nickname);
1284 nicklist_rename_unique(SERVER(server),
1285 server->conn->local_entry, server->nick,
1286 client, client->nickname);
1287 signal_emit("message own_nick", 4, server, server->nick, old, "");
1292 case SILC_COMMAND_LIST:
1301 (void)va_arg(vp, SilcChannelEntry);
1302 name = va_arg(vp, char *);
1303 topic = va_arg(vp, char *);
1304 usercount = va_arg(vp, int);
1306 if (status == SILC_STATUS_LIST_START ||
1307 status == SILC_STATUS_OK)
1308 printformat_module("fe-common/silc", server, NULL,
1309 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1312 snprintf(users, sizeof(users) - 1, "N/A");
1314 snprintf(users, sizeof(users) - 1, "%d", usercount);
1315 printformat_module("fe-common/silc", server, NULL,
1316 MSGLEVEL_CRAP, SILCTXT_LIST,
1317 name, users, topic ? topic : "");
1321 case SILC_COMMAND_UMODE:
1328 mode = va_arg(vp, SilcUInt32);
1330 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1331 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1332 printformat_module("fe-common/silc", server, NULL,
1333 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1335 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1336 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1337 printformat_module("fe-common/silc", server, NULL,
1338 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1340 server->umode = mode;
1341 signal_emit("user mode changed", 2, server, NULL);
1345 case SILC_COMMAND_OPER:
1349 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1350 signal_emit("user mode changed", 2, server, NULL);
1352 printformat_module("fe-common/silc", server, NULL,
1353 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1356 case SILC_COMMAND_SILCOPER:
1360 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1361 signal_emit("user mode changed", 2, server, NULL);
1363 printformat_module("fe-common/silc", server, NULL,
1364 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1367 case SILC_COMMAND_USERS:
1369 SilcHashTableList htl;
1370 SilcChannelEntry channel;
1371 SilcChannelUser chu;
1376 channel = va_arg(vp, SilcChannelEntry);
1378 printformat_module("fe-common/silc", server, channel->channel_name,
1379 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1380 channel->channel_name);
1382 silc_hash_table_list(channel->user_list, &htl);
1383 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1384 SilcClientEntry e = chu->client;
1385 char stat[5], *mode;
1390 memset(stat, 0, sizeof(stat));
1391 mode = silc_client_chumode_char(chu->mode);
1392 if (e->mode & SILC_UMODE_GONE)
1394 else if (e->mode & SILC_UMODE_INDISPOSED)
1396 else if (e->mode & SILC_UMODE_BUSY)
1398 else if (e->mode & SILC_UMODE_PAGE)
1400 else if (e->mode & SILC_UMODE_HYPER)
1402 else if (e->mode & SILC_UMODE_ROBOT)
1404 else if (e->mode & SILC_UMODE_ANONYMOUS)
1411 printformat_module("fe-common/silc", server, channel->channel_name,
1412 MSGLEVEL_CRAP, SILCTXT_USERS,
1414 e->username ? e->username : "",
1415 e->hostname ? e->hostname : "",
1416 e->realname ? e->realname : "");
1420 silc_hash_table_list_reset(&htl);
1424 case SILC_COMMAND_BAN:
1426 SilcChannelEntry channel;
1432 channel = va_arg(vp, SilcChannelEntry);
1433 ban_list = va_arg(vp, char *);
1436 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1437 SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
1440 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1441 SILCTXT_CHANNEL_NO_BAN_LIST,
1442 channel->channel_name);
1446 case SILC_COMMAND_GETKEY:
1450 SilcPublicKey public_key;
1453 GetkeyContext getkey;
1459 id_type = va_arg(vp, SilcUInt32);
1460 entry = va_arg(vp, void *);
1461 public_key = va_arg(vp, SilcPublicKey);
1464 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1466 getkey = silc_calloc(1, sizeof(*getkey));
1467 getkey->entry = entry;
1468 getkey->id_type = id_type;
1469 getkey->client = client;
1470 getkey->conn = conn;
1471 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1473 name = (id_type == SILC_ID_CLIENT ?
1474 ((SilcClientEntry)entry)->nickname :
1475 ((SilcServerEntry)entry)->server_name);
1477 silc_verify_public_key_internal(client, conn, name,
1478 (id_type == SILC_ID_CLIENT ?
1479 SILC_SOCKET_TYPE_CLIENT :
1480 SILC_SOCKET_TYPE_SERVER),
1481 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1482 silc_getkey_cb, getkey);
1485 printformat_module("fe-common/silc", server, NULL,
1486 MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
1491 case SILC_COMMAND_INFO:
1493 SilcServerEntry server_entry;
1500 server_entry = va_arg(vp, SilcServerEntry);
1501 server_name = va_arg(vp, char *);
1502 server_info = va_arg(vp, char *);
1504 if (server_name && server_info )
1506 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1507 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1512 case SILC_COMMAND_TOPIC:
1514 SilcChannelEntry channel;
1520 channel = va_arg(vp, SilcChannelEntry);
1521 topic = va_arg(vp, char *);
1524 chanrec = silc_channel_find_entry(server, channel);
1526 g_free_not_null(chanrec->topic);
1527 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1528 signal_emit("channel topic changed", 1, chanrec);
1530 printformat_module("fe-common/silc", server, channel->channel_name,
1531 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1532 channel->channel_name, topic);
1534 printformat_module("fe-common/silc", server, channel->channel_name,
1535 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
1536 channel->channel_name);
1541 case SILC_COMMAND_WATCH:
1550 SilcClientConnection conn;
1556 SilcSKEPKType pk_type;
1557 SilcVerifyPublicKey completion;
1561 static void verify_public_key_completion(const char *line, void *context)
1563 PublicKeyVerify verify = (PublicKeyVerify)context;
1565 if (line[0] == 'Y' || line[0] == 'y') {
1566 /* Call the completion */
1567 if (verify->completion)
1568 verify->completion(TRUE, verify->context);
1570 /* Save the key for future checking */
1571 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
1572 verify->pk_len, SILC_PKCS_FILE_PEM);
1574 /* Call the completion */
1575 if (verify->completion)
1576 verify->completion(FALSE, verify->context);
1578 printformat_module("fe-common/silc", NULL, NULL,
1579 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
1580 verify->entity_name ? verify->entity_name :
1584 silc_free(verify->filename);
1585 silc_free(verify->entity);
1586 silc_free(verify->entity_name);
1587 silc_free(verify->pk);
1591 /* Internal routine to verify public key. If the `completion' is provided
1592 it will be called to indicate whether public was verified or not. For
1593 server/router public key this will check for filename that includes the
1594 remote host's IP address and remote host's hostname. */
1597 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
1598 const char *name, SilcSocketType conn_type,
1599 unsigned char *pk, SilcUInt32 pk_len,
1600 SilcSKEPKType pk_type,
1601 SilcVerifyPublicKey completion, void *context)
1604 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
1605 char *fingerprint, *babbleprint, *format;
1608 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
1609 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
1610 "server" : "client");
1611 PublicKeyVerify verify;
1613 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
1614 printformat_module("fe-common/silc", NULL, NULL,
1615 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
1618 completion(FALSE, context);
1622 pw = getpwuid(getuid());
1625 completion(FALSE, context);
1629 memset(filename, 0, sizeof(filename));
1630 memset(filename2, 0, sizeof(filename2));
1631 memset(file, 0, sizeof(file));
1633 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
1634 conn_type == SILC_SOCKET_TYPE_ROUTER) {
1636 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1637 conn->sock->ip, conn->sock->port);
1638 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1639 get_irssi_dir(), entity, file);
1641 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1642 conn->sock->hostname, conn->sock->port);
1643 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
1644 get_irssi_dir(), entity, file);
1649 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
1650 name, conn->sock->port);
1651 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1652 get_irssi_dir(), entity, file);
1657 /* Replace all whitespaces with `_'. */
1658 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1659 for (i = 0; i < strlen(fingerprint); i++)
1660 if (fingerprint[i] == ' ')
1661 fingerprint[i] = '_';
1663 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
1664 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
1665 get_irssi_dir(), entity, file);
1666 silc_free(fingerprint);
1671 /* Take fingerprint of the public key */
1672 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1673 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1675 verify = silc_calloc(1, sizeof(*verify));
1676 verify->client = client;
1677 verify->conn = conn;
1678 verify->filename = strdup(ipf);
1679 verify->entity = strdup(entity);
1680 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
1681 (name ? strdup(name) : strdup(conn->sock->hostname))
1683 verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
1684 memcpy(verify->pk, pk, pk_len);
1685 verify->pk_len = pk_len;
1686 verify->pk_type = pk_type;
1687 verify->completion = completion;
1688 verify->context = context;
1690 /* Check whether this key already exists */
1691 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
1692 /* Key does not exist, ask user to verify the key and save it */
1694 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1695 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1696 verify->entity_name : entity);
1697 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1698 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1699 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1700 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1701 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1702 SILCTXT_PUBKEY_ACCEPT);
1703 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1706 silc_free(fingerprint);
1709 /* The key already exists, verify it. */
1710 SilcPublicKey public_key;
1711 unsigned char *encpk;
1712 SilcUInt32 encpk_len;
1714 /* Load the key file, try for both IP filename and hostname filename */
1715 if (!silc_pkcs_load_public_key(ipf, &public_key,
1716 SILC_PKCS_FILE_PEM) &&
1717 !silc_pkcs_load_public_key(ipf, &public_key,
1718 SILC_PKCS_FILE_BIN) &&
1719 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
1720 SILC_PKCS_FILE_PEM) &&
1721 !silc_pkcs_load_public_key(hostf, &public_key,
1722 SILC_PKCS_FILE_BIN)))) {
1723 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1724 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1725 verify->entity_name : entity);
1726 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1727 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1728 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1729 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1730 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1731 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
1732 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1733 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1734 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1737 silc_free(fingerprint);
1741 /* Encode the key data */
1742 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
1744 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1745 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1746 verify->entity_name : entity);
1747 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1748 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1749 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1750 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1751 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1752 SILCTXT_PUBKEY_MALFORMED, entity);
1753 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
1754 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
1755 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
1758 silc_free(fingerprint);
1762 /* Compare the keys */
1763 if (memcmp(encpk, pk, encpk_len)) {
1764 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1765 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
1766 verify->entity_name : entity);
1767 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1768 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
1769 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1770 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
1771 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1772 SILCTXT_PUBKEY_NO_MATCH, entity);
1773 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1774 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
1775 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1776 SILCTXT_PUBKEY_MITM_ATTACK, entity);
1778 /* Ask user to verify the key and save it */
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 /* Local copy matched */
1790 completion(TRUE, context);
1791 silc_free(fingerprint);
1795 /* Verifies received public key. The `conn_type' indicates which entity
1796 (server, client etc.) has sent the public key. If user decides to trust
1797 the key may be saved as trusted public key for later use. The
1798 `completion' must be called after the public key has been verified. */
1801 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1802 SilcSocketType conn_type, unsigned char *pk,
1803 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1804 SilcVerifyPublicKey completion, void *context)
1806 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
1808 completion, context);
1811 /* Asks passphrase from user on the input line. */
1814 SilcAskPassphrase completion;
1818 void ask_passphrase_completion(const char *passphrase, void *context)
1820 AskPassphrase p = (AskPassphrase)context;
1821 if (passphrase && passphrase[0] == '\0')
1823 p->completion((unsigned char *)passphrase,
1824 passphrase ? strlen(passphrase) : 0, p->context);
1828 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1829 SilcAskPassphrase completion, void *context)
1831 AskPassphrase p = silc_calloc(1, sizeof(*p));
1832 p->completion = completion;
1833 p->context = context;
1835 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
1836 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
1840 SilcGetAuthMeth completion;
1842 } *InternalGetAuthMethod;
1844 /* Callback called when we've received the authentication method information
1845 from the server after we've requested it. This will get the authentication
1846 data from the user if needed. */
1848 static void silc_get_auth_method_callback(SilcClient client,
1849 SilcClientConnection conn,
1850 SilcAuthMethod auth_meth,
1853 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
1855 SILC_LOG_DEBUG(("Start"));
1857 switch (auth_meth) {
1858 case SILC_AUTH_NONE:
1859 /* No authentication required. */
1860 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1862 case SILC_AUTH_PASSWORD:
1863 /* Do not ask the passphrase from user, the library will ask it if
1864 we do not provide it here. */
1865 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1867 case SILC_AUTH_PUBLIC_KEY:
1868 /* Do not get the authentication data now, the library will generate
1869 it using our default key, if we do not provide it here. */
1870 /* XXX In the future when we support multiple local keys and multiple
1871 local certificates we will need to ask from user which one to use. */
1872 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1876 silc_free(internal);
1879 /* Find authentication method and authentication data by hostname and
1880 port. The hostname may be IP address as well. The found authentication
1881 method and authentication data is returned to `auth_meth', `auth_data'
1882 and `auth_data_len'. The function returns TRUE if authentication method
1883 is found and FALSE if not. `conn' may be NULL. */
1885 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1886 char *hostname, SilcUInt16 port,
1887 SilcGetAuthMeth completion, void *context)
1889 InternalGetAuthMethod internal;
1891 SILC_LOG_DEBUG(("Start"));
1893 /* XXX must resolve from configuration whether this connection has
1894 any specific authentication data */
1896 /* If we do not have this connection configured by the user in a
1897 configuration file then resolve the authentication method from the
1898 server for this session. */
1899 internal = silc_calloc(1, sizeof(*internal));
1900 internal->completion = completion;
1901 internal->context = context;
1903 silc_client_request_authentication_method(client, conn,
1904 silc_get_auth_method_callback,
1908 /* Notifies application that failure packet was received. This is called
1909 if there is some protocol active in the client. The `protocol' is the
1910 protocol context. The `failure' is opaque pointer to the failure
1911 indication. Note, that the `failure' is protocol dependant and application
1912 must explicitly cast it to correct type. Usually `failure' is 32 bit
1913 failure type (see protocol specs for all protocol failure types). */
1915 void silc_failure(SilcClient client, SilcClientConnection conn,
1916 SilcProtocol protocol, void *failure)
1918 SILC_LOG_DEBUG(("Start"));
1920 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1921 SilcSKEStatus status = (SilcSKEStatus)failure;
1923 if (status == SILC_SKE_STATUS_BAD_VERSION)
1924 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1925 SILCTXT_KE_BAD_VERSION);
1926 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1927 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1928 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
1929 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1930 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1931 SILCTXT_KE_UNKNOWN_GROUP);
1932 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1933 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1934 SILCTXT_KE_UNKNOWN_CIPHER);
1935 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1936 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1937 SILCTXT_KE_UNKNOWN_PKCS);
1938 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1939 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1940 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
1941 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1942 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1943 SILCTXT_KE_UNKNOWN_HMAC);
1944 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1945 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1946 SILCTXT_KE_INCORRECT_SIGNATURE);
1947 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1948 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1949 SILCTXT_KE_INVALID_COOKIE);
1952 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1953 SilcUInt32 err = (SilcUInt32)failure;
1955 if (err == SILC_AUTH_FAILED)
1956 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1957 SILCTXT_AUTH_FAILED);
1961 /* Asks whether the user would like to perform the key agreement protocol.
1962 This is called after we have received an key agreement packet or an
1963 reply to our key agreement packet. This returns TRUE if the user wants
1964 the library to perform the key agreement protocol and FALSE if it is not
1965 desired (application may start it later by calling the function
1966 silc_client_perform_key_agreement). */
1968 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
1969 SilcClientEntry client_entry, const char *hostname,
1970 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1975 SILC_LOG_DEBUG(("Start"));
1977 /* We will just display the info on the screen and return FALSE and user
1978 will have to start the key agreement with a command. */
1981 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
1984 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1985 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
1987 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
1988 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
1989 client_entry->nickname, hostname, portstr);
1997 /* Notifies application that file transfer protocol session is being
1998 requested by the remote client indicated by the `client_entry' from
1999 the `hostname' and `port'. The `session_id' is the file transfer
2000 session and it can be used to either accept or reject the file
2001 transfer request, by calling the silc_client_file_receive or
2002 silc_client_file_close, respectively. */
2004 void silc_ftp(SilcClient client, SilcClientConnection conn,
2005 SilcClientEntry client_entry, SilcUInt32 session_id,
2006 const char *hostname, SilcUInt16 port)
2008 SILC_SERVER_REC *server;
2010 FtpSession ftp = silc_calloc(1, sizeof(*ftp));
2012 SILC_LOG_DEBUG(("Start"));
2014 server = conn->context;
2016 ftp->client_entry = client_entry;
2017 ftp->session_id = session_id;
2020 silc_dlist_add(server->ftp_sessions, ftp);
2021 server->current_session = ftp;
2024 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2027 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2028 SILCTXT_FILE_REQUEST, client_entry->nickname);
2030 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2031 SILCTXT_FILE_REQUEST_HOST,
2032 client_entry->nickname, hostname, portstr);
2035 /* Delivers SILC session detachment data indicated by `detach_data' to the
2036 application. If application has issued SILC_COMMAND_DETACH command
2037 the client session in the SILC network is not quit. The client remains
2038 in the network but is detached. The detachment data may be used later
2039 to resume the session in the SILC Network. The appliation is
2040 responsible of saving the `detach_data', to for example in a file.
2042 The detachment data can be given as argument to the functions
2043 silc_client_connect_to_server, or silc_client_add_connection when
2044 creating connection to remote server, inside SilcClientConnectionParams
2045 structure. If it is provided the client library will attempt to resume
2046 the session in the network. After the connection is created
2047 successfully, the application is responsible of setting the user
2048 interface for user into the same state it was before detaching (showing
2049 same channels, channel modes, etc). It can do this by fetching the
2050 information (like joined channels) from the client library. */
2053 silc_detach(SilcClient client, SilcClientConnection conn,
2054 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2058 /* Save the detachment data to file. */
2060 memset(file, 0, sizeof(file));
2061 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2062 silc_file_writefile(file, detach_data, detach_data_len);
2066 /* SILC client operations */
2067 SilcClientOperations ops = {
2069 silc_channel_message,
2070 silc_private_message,
2076 silc_get_auth_method,
2077 silc_verify_public_key,
2078 silc_ask_passphrase,