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"
37 #include "fe-common/core/printtext.h"
38 #include "fe-common/core/fe-channels.h"
39 #include "fe-common/core/keyboard.h"
40 #include "fe-common/core/window-items.h"
41 #include "fe-common/silc/module-formats.h"
46 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
47 const char *name, SilcSocketType conn_type,
48 unsigned char *pk, SilcUInt32 pk_len,
49 SilcSKEPKType pk_type,
50 SilcVerifyPublicKey completion, void *context);
52 static void silc_get_umode_string(SilcUInt32 mode, char *buf,
55 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
56 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
57 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
59 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
60 "[SILC operator]" : "[unknown mode]");
62 if (mode & SILC_UMODE_GONE)
63 strcat(buf, " [away]");
64 if (mode & SILC_UMODE_INDISPOSED)
65 strcat(buf, " [indisposed]");
66 if (mode & SILC_UMODE_BUSY)
67 strcat(buf, " [busy]");
68 if (mode & SILC_UMODE_PAGE)
69 strcat(buf, " [page to reach]");
70 if (mode & SILC_UMODE_HYPER)
71 strcat(buf, " [hyper active]");
72 if (mode & SILC_UMODE_ROBOT)
73 strcat(buf, " [robot]");
74 if (mode & SILC_UMODE_ANONYMOUS)
75 strcat(buf, " [anonymous]");
76 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
77 strcat(buf, " [blocks private messages]");
78 if (mode & SILC_UMODE_DETACHED)
79 strcat(buf, " [detached]");
80 if (mode & SILC_UMODE_REJECT_WATCHING)
81 strcat(buf, " [rejects watching]");
82 if (mode & SILC_UMODE_BLOCK_INVITE)
83 strcat(buf, " [blocks invites]");
86 /* print "nick appears as" message to every channel of a server */
88 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
89 const char *newnick, const char *oldnick,
92 if (ignore_check(SERVER(server), oldnick, address,
93 channel, newnick, MSGLEVEL_NICKS))
96 printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
97 SILCTXT_CHANNEL_APPEARS,
98 oldnick, newnick, channel, address);
102 silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
103 const char *oldnick, const char *address)
105 GSList *tmp, *windows;
107 /* Print to each channel/query where the nick is.
108 Don't print more than once to the same window. */
111 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
112 CHANNEL_REC *channel = tmp->data;
113 WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
115 if (nicklist_find(channel, newnick) == NULL ||
116 g_slist_find(windows, window) != NULL)
119 windows = g_slist_append(windows, window);
120 silc_print_nick_change_channel(server, channel->visible_name,
121 newnick, oldnick, address);
124 g_slist_free(windows);
127 void silc_say(SilcClient client, SilcClientConnection conn,
128 SilcClientMessageType type, char *msg, ...)
130 SILC_SERVER_REC *server;
134 server = conn == NULL ? NULL : conn->context;
137 str = g_strdup_vprintf(msg, va);
138 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
143 void silc_say_error(char *msg, ...)
149 str = g_strdup_vprintf(msg, va);
150 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
156 /* try to verify a message using locally stored public key data */
157 int verify_message_signature(SilcClientEntry sender,
158 SilcMessageSignedPayload sig,
159 SilcMessagePayload message)
162 char file[256], filename[256];
163 char *fingerprint, *fingerprint2;
164 unsigned char *pk_data;
165 SilcUInt32 pk_datalen;
167 int ret = SILC_MSG_SIGNED_VERIFIED, i;
170 return SILC_MSG_SIGNED_UNKNOWN;
172 /* get public key from the signature payload and compare it with the
173 one stored in the client entry */
174 pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
177 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
179 if (sender->fingerprint) {
180 fingerprint2 = silc_fingerprint(sender->fingerprint,
181 sender->fingerprint_len);
182 if (strcmp(fingerprint, fingerprint2)) {
183 /* since the public key differs from the senders public key, the
184 verification _failed_ */
185 silc_pkcs_public_key_free(pk);
186 silc_free(fingerprint);
187 ret = SILC_MSG_SIGNED_UNKNOWN;
189 silc_free(fingerprint2);
191 } else if (sender->fingerprint)
192 fingerprint = silc_fingerprint(sender->fingerprint,
193 sender->fingerprint_len);
195 /* no idea, who or what signed that message ... */
196 return SILC_MSG_SIGNED_UNKNOWN;
198 /* search our local client key cache */
199 for (i = 0; i < strlen(fingerprint); i++)
200 if (fingerprint[i] == ' ')
201 fingerprint[i] = '_';
203 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
204 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
205 get_irssi_dir(), file);
206 silc_free(fingerprint);
208 if (stat(filename, &st) < 0)
209 /* we don't have the public key cached ... use the one from the sig */
210 ret = SILC_MSG_SIGNED_UNKNOWN;
212 SilcPublicKey cached_pk=NULL;
214 /* try to load the file */
215 if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
216 !silc_pkcs_load_public_key(filename, &cached_pk,
217 SILC_PKCS_FILE_BIN)) {
218 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
219 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
221 return SILC_MSG_SIGNED_UNKNOWN;
223 ret = SILC_MSG_SIGNED_UNKNOWN;
228 silc_pkcs_public_key_free(pk);
233 /* the public key is now in pk, our "level of trust" in ret */
234 if ((pk) && silc_message_signed_verify(sig, message, pk,
235 silc_client->sha1hash)!= SILC_AUTH_OK)
236 ret = SILC_MSG_SIGNED_FAILED;
239 silc_pkcs_public_key_free(pk);
244 /* Message for a channel. The `sender' is the nickname of the sender
245 received in the packet. The `channel_name' is the name of the channel. */
247 void silc_channel_message(SilcClient client, SilcClientConnection conn,
248 SilcClientEntry sender, SilcChannelEntry channel,
249 SilcMessagePayload payload,
250 SilcMessageFlags flags, const unsigned char *message,
251 SilcUInt32 message_len)
253 SILC_SERVER_REC *server;
255 SILC_CHANNEL_REC *chanrec;
258 SILC_LOG_DEBUG(("Start"));
263 server = conn == NULL ? NULL : conn->context;
264 chanrec = silc_channel_find_entry(server, channel);
268 nick = silc_nicklist_find(chanrec, sender);
270 /* We didn't find client but it clearly exists, add it. */
271 SilcChannelUser chu = silc_client_on_channel(channel, sender);
273 nick = silc_nicklist_insert(chanrec, chu, FALSE);
276 /* If the messages is digitally signed, verify it, if possible. */
277 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
278 if (!settings_get_bool("ignore_message_signatures")) {
279 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
280 verified = verify_message_signature(sender, sig, payload);
282 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
286 if (flags & SILC_MESSAGE_FLAG_DATA) {
287 /* MIME object received, try to display it as well as we can */
288 char type[128], enc[128];
292 memset(type, 0, sizeof(type));
293 memset(enc, 0, sizeof(enc));
294 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
295 enc, sizeof(enc) - 1, &data, &data_len))
298 /* Then figure out what we can display */
299 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
300 !strstr(type, "text/vnd")) {
301 /* It is something textual, display it */
302 message = (const unsigned char *)data;
304 printformat_module("fe-common/silc", server, channel->channel_name,
305 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
306 nick == NULL ? "[<unknown>]" : nick->nick, type);
314 /* FIXME: replace those printformat calls with signals and add signature
315 information to them (if present) */
316 if (flags & SILC_MESSAGE_FLAG_ACTION)
317 printformat_module("fe-common/silc", server, channel->channel_name,
318 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
319 nick == NULL ? "[<unknown>]" : nick->nick, message);
320 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
321 printformat_module("fe-common/silc", server, channel->channel_name,
322 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
323 nick == NULL ? "[<unknown>]" : nick->nick, message);
325 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
326 char tmp[256], *cp, *dm = NULL;
328 memset(tmp, 0, sizeof(tmp));
330 if (message_len > sizeof(tmp) - 1) {
331 dm = silc_calloc(message_len + 1, sizeof(*dm));
335 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
337 if (flags & SILC_MESSAGE_FLAG_SIGNED)
338 signal_emit("message signed_public", 6, server, cp,
339 nick == NULL ? "[<unknown>]" : nick->nick,
340 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
341 chanrec->name, verified);
343 signal_emit("message public", 6, server, cp,
344 nick == NULL ? "[<unknown>]" : nick->nick,
345 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
346 chanrec->name, nick);
351 if (flags & SILC_MESSAGE_FLAG_SIGNED)
352 signal_emit("message signed_public", 6, server, message,
353 nick == NULL ? "[<unknown>]" : nick->nick,
354 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
355 chanrec->name, verified);
357 signal_emit("message public", 6, server, message,
358 nick == NULL ? "[<unknown>]" : nick->nick,
359 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
360 chanrec->name, nick);
364 /* Private message to the client. The `sender' is the nickname of the
365 sender received in the packet. */
367 void silc_private_message(SilcClient client, SilcClientConnection conn,
368 SilcClientEntry sender, SilcMessagePayload payload,
369 SilcMessageFlags flags,
370 const unsigned char *message,
371 SilcUInt32 message_len)
373 SILC_SERVER_REC *server;
377 SILC_LOG_DEBUG(("Start"));
379 server = conn == NULL ? NULL : conn->context;
380 memset(userhost, 0, sizeof(userhost));
381 if (sender->username)
382 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
383 sender->username, sender->hostname);
385 /* If the messages is digitally signed, verify it, if possible. */
386 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
387 if (!settings_get_bool("ignore_message_signatures")) {
388 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
389 verified = verify_message_signature(sender, sig, payload);
391 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
395 if (flags & SILC_MESSAGE_FLAG_DATA) {
396 /* MIME object received, try to display it as well as we can */
397 char type[128], enc[128];
401 memset(type, 0, sizeof(type));
402 memset(enc, 0, sizeof(enc));
403 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
404 enc, sizeof(enc) - 1, &data, &data_len))
407 /* Then figure out what we can display */
408 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
409 !strstr(type, "text/vnd")) {
410 /* It is something textual, display it */
411 message = (const unsigned char *)data;
413 printformat_module("fe-common/silc", server, NULL,
414 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
415 sender->nickname ? sender->nickname : "[<unknown>]",
424 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
425 char tmp[256], *cp, *dm = NULL;
427 memset(tmp, 0, sizeof(tmp));
429 if (message_len > sizeof(tmp) - 1) {
430 dm = silc_calloc(message_len + 1, sizeof(*dm));
434 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
436 if (flags & SILC_MESSAGE_FLAG_SIGNED)
437 signal_emit("message signed_private", 5, server, cp,
438 sender->nickname ? sender->nickname : "[<unknown>]",
439 sender->username ? userhost : NULL, verified);
441 signal_emit("message private", 4, server, cp,
442 sender->nickname ? sender->nickname : "[<unknown>]",
443 sender->username ? userhost : NULL);
448 if (flags & SILC_MESSAGE_FLAG_SIGNED)
449 signal_emit("message signed_private", 5, server, message,
450 sender->nickname ? sender->nickname : "[<unknown>]",
451 sender->username ? userhost : NULL, verified);
453 signal_emit("message private", 4, server, message,
454 sender->nickname ? sender->nickname : "[<unknown>]",
455 sender->username ? userhost : NULL);
458 /* Notify message to the client. The notify arguments are sent in the
459 same order as servers sends them. The arguments are same as received
460 from the server except for ID's. If ID is received application receives
461 the corresponding entry to the ID. For example, if Client ID is received
462 application receives SilcClientEntry. Also, if the notify type is
463 for channel the channel entry is sent to application (even if server
464 does not send it). */
466 void silc_notify(SilcClient client, SilcClientConnection conn,
467 SilcNotifyType type, ...)
470 SILC_SERVER_REC *server;
471 SILC_CHANNEL_REC *chanrec;
472 SILC_NICK_REC *nickrec;
473 SilcClientEntry client_entry, client_entry2;
474 SilcChannelEntry channel, channel2;
475 SilcServerEntry server_entry;
481 GSList *list1, *list_tmp;
483 SILC_LOG_DEBUG(("Start"));
487 server = conn == NULL ? NULL : conn->context;
490 case SILC_NOTIFY_TYPE_NONE:
491 /* Some generic notice from server */
492 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
495 case SILC_NOTIFY_TYPE_INVITE:
497 * Invited or modified invite list.
500 SILC_LOG_DEBUG(("Notify: INVITE"));
502 channel = va_arg(va, SilcChannelEntry);
503 name = va_arg(va, char *);
504 client_entry = va_arg(va, SilcClientEntry);
506 memset(buf, 0, sizeof(buf));
507 snprintf(buf, sizeof(buf) - 1, "%s@%s",
508 client_entry->username, client_entry->hostname);
509 signal_emit("message invite", 4, server, channel ? channel->channel_name :
510 name, client_entry->nickname, buf);
513 case SILC_NOTIFY_TYPE_JOIN:
518 SILC_LOG_DEBUG(("Notify: JOIN"));
520 client_entry = va_arg(va, SilcClientEntry);
521 channel = va_arg(va, SilcChannelEntry);
523 if (client_entry == server->conn->local_entry) {
524 /* You joined to channel */
525 chanrec = silc_channel_find(server, channel->channel_name);
526 if (chanrec != NULL && !chanrec->joined)
527 chanrec->entry = channel;
529 chanrec = silc_channel_find_entry(server, channel);
530 if (chanrec != NULL) {
531 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
533 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
537 memset(buf, 0, sizeof(buf));
538 if (client_entry->username)
539 snprintf(buf, sizeof(buf) - 1, "%s@%s",
540 client_entry->username, client_entry->hostname);
541 signal_emit("message join", 4, server, channel->channel_name,
542 client_entry->nickname,
543 client_entry->username == NULL ? "" : buf);
546 case SILC_NOTIFY_TYPE_LEAVE:
551 SILC_LOG_DEBUG(("Notify: LEAVE"));
553 client_entry = va_arg(va, SilcClientEntry);
554 channel = va_arg(va, SilcChannelEntry);
556 memset(buf, 0, sizeof(buf));
557 if (client_entry->username)
558 snprintf(buf, sizeof(buf) - 1, "%s@%s",
559 client_entry->username, client_entry->hostname);
560 signal_emit("message part", 5, server, channel->channel_name,
561 client_entry->nickname, client_entry->username ?
562 buf : "", client_entry->nickname);
564 chanrec = silc_channel_find_entry(server, channel);
565 if (chanrec != NULL) {
566 nickrec = silc_nicklist_find(chanrec, client_entry);
568 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
572 case SILC_NOTIFY_TYPE_SIGNOFF:
577 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
579 client_entry = va_arg(va, SilcClientEntry);
580 tmp = va_arg(va, char *);
582 silc_server_free_ftp(server, client_entry);
584 /* Print only if we have the nickname. If this cliente has just quit
585 when we were only resolving it, it is possible we don't have the
587 if (client_entry->nickname) {
588 memset(buf, 0, sizeof(buf));
589 if (client_entry->username)
590 snprintf(buf, sizeof(buf) - 1, "%s@%s",
591 client_entry->username, client_entry->hostname);
592 signal_emit("message quit", 4, server, client_entry->nickname,
593 client_entry->username ? buf : "",
597 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
598 for (list_tmp = list1; list_tmp != NULL; list_tmp =
599 list_tmp->next->next) {
600 CHANNEL_REC *channel = list_tmp->data;
601 NICK_REC *nickrec = list_tmp->next->data;
603 nicklist_remove(channel, nickrec);
607 case SILC_NOTIFY_TYPE_TOPIC_SET:
612 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
614 idtype = va_arg(va, int);
615 entry = va_arg(va, void *);
616 tmp = va_arg(va, char *);
617 channel = va_arg(va, SilcChannelEntry);
619 chanrec = silc_channel_find_entry(server, channel);
620 if (chanrec != NULL) {
621 char tmp2[256], *cp, *dm = NULL;
623 g_free_not_null(chanrec->topic);
624 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
625 memset(tmp2, 0, sizeof(tmp2));
627 if (strlen(tmp) > sizeof(tmp2) - 1) {
628 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
632 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
637 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
638 signal_emit("channel topic changed", 1, chanrec);
643 if (idtype == SILC_ID_CLIENT) {
644 client_entry = (SilcClientEntry)entry;
645 memset(buf, 0, sizeof(buf));
646 snprintf(buf, sizeof(buf) - 1, "%s@%s",
647 client_entry->username, client_entry->hostname);
648 signal_emit("message topic", 5, server, channel->channel_name,
649 tmp, client_entry->nickname, buf);
650 } else if (idtype == SILC_ID_SERVER) {
651 server_entry = (SilcServerEntry)entry;
652 signal_emit("message topic", 5, server, channel->channel_name,
653 tmp, server_entry->server_name,
654 server_entry->server_name);
655 } else if (idtype == SILC_ID_CHANNEL) {
656 channel = (SilcChannelEntry)entry;
657 signal_emit("message topic", 5, server, channel->channel_name,
658 tmp, channel->channel_name, channel->channel_name);
662 case SILC_NOTIFY_TYPE_NICK_CHANGE:
667 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
669 client_entry = va_arg(va, SilcClientEntry);
670 client_entry2 = va_arg(va, SilcClientEntry);
672 if (!strcmp(client_entry->nickname, client_entry2->nickname))
675 memset(buf, 0, sizeof(buf));
676 snprintf(buf, sizeof(buf) - 1, "%s@%s",
677 client_entry2->username, client_entry2->hostname);
678 nicklist_rename_unique(SERVER(server),
679 client_entry, client_entry->nickname,
680 client_entry2, client_entry2->nickname);
681 signal_emit("message nick", 4, server, client_entry2->nickname,
682 client_entry->nickname, buf);
685 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
687 * Changed channel mode.
690 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
692 idtype = va_arg(va, int);
693 entry = va_arg(va, void *);
694 mode = va_arg(va, SilcUInt32);
695 (void)va_arg(va, char *);
696 (void)va_arg(va, char *);
697 channel = va_arg(va, SilcChannelEntry);
699 tmp = silc_client_chmode(mode,
700 channel->channel_key ?
701 silc_cipher_get_name(channel->channel_key) : "",
703 silc_hmac_get_name(channel->hmac) : "");
705 chanrec = silc_channel_find_entry(server, channel);
706 if (chanrec != NULL) {
707 g_free_not_null(chanrec->mode);
708 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
709 signal_emit("channel mode changed", 1, chanrec);
712 if (idtype == SILC_ID_CLIENT) {
713 client_entry = (SilcClientEntry)entry;
714 printformat_module("fe-common/silc", server, channel->channel_name,
715 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
716 channel->channel_name, tmp ? tmp : "removed all",
717 client_entry->nickname);
718 } else if (idtype == SILC_ID_SERVER) {
719 server_entry = (SilcServerEntry)entry;
720 printformat_module("fe-common/silc", server, channel->channel_name,
721 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
722 channel->channel_name, tmp ? tmp : "removed all",
723 server_entry->server_name);
724 } else if (idtype == SILC_ID_CHANNEL) {
725 channel2 = (SilcChannelEntry)entry;
726 printformat_module("fe-common/silc", server, channel->channel_name,
727 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
728 channel->channel_name, tmp ? tmp : "removed all",
729 channel2->channel_name);
735 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
737 * Changed user's mode on channel.
740 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
742 idtype = va_arg(va, int);
743 entry = va_arg(va, void *);
744 mode = va_arg(va, SilcUInt32);
745 client_entry2 = va_arg(va, SilcClientEntry);
746 channel = va_arg(va, SilcChannelEntry);
748 tmp = silc_client_chumode(mode);
749 chanrec = silc_channel_find_entry(server, channel);
750 if (chanrec != NULL) {
753 if (client_entry2 == server->conn->local_entry)
754 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
756 nick = silc_nicklist_find(chanrec, client_entry2);
758 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
759 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
760 signal_emit("nick mode changed", 2, chanrec, nick);
764 if (idtype == SILC_ID_CLIENT) {
765 client_entry = (SilcClientEntry)entry;
766 printformat_module("fe-common/silc", server, channel->channel_name,
767 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
768 channel->channel_name, client_entry2->nickname,
769 tmp ? tmp : "removed all",
770 client_entry->nickname);
771 } else if (idtype == SILC_ID_SERVER) {
772 server_entry = (SilcServerEntry)entry;
773 printformat_module("fe-common/silc", server, channel->channel_name,
774 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
775 channel->channel_name, client_entry2->nickname,
776 tmp ? tmp : "removed all",
777 server_entry->server_name);
778 } else if (idtype == SILC_ID_CHANNEL) {
779 channel2 = (SilcChannelEntry)entry;
780 printformat_module("fe-common/silc", server, channel->channel_name,
781 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
782 channel->channel_name, client_entry2->nickname,
783 tmp ? tmp : "removed all",
784 channel2->channel_name);
787 if (mode & SILC_CHANNEL_UMODE_CHANFO)
788 printformat_module("fe-common/silc",
789 server, channel->channel_name, MSGLEVEL_CRAP,
790 SILCTXT_CHANNEL_FOUNDER,
791 channel->channel_name, client_entry2->nickname);
793 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
794 printformat_module("fe-common/silc",
795 server, channel->channel_name, MSGLEVEL_CRAP,
796 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
801 case SILC_NOTIFY_TYPE_MOTD:
806 SILC_LOG_DEBUG(("Notify: MOTD"));
808 tmp = va_arg(va, char *);
810 if (!settings_get_bool("skip_motd"))
811 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
814 case SILC_NOTIFY_TYPE_KICKED:
816 * Someone was kicked from channel.
819 SILC_LOG_DEBUG(("Notify: KICKED"));
821 client_entry = va_arg(va, SilcClientEntry);
822 tmp = va_arg(va, char *);
823 client_entry2 = va_arg(va, SilcClientEntry);
824 channel = va_arg(va, SilcChannelEntry);
826 chanrec = silc_channel_find_entry(server, channel);
828 if (client_entry == conn->local_entry) {
829 printformat_module("fe-common/silc", server, channel->channel_name,
830 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
831 channel->channel_name,
832 client_entry ? client_entry2->nickname : "",
835 chanrec->kicked = TRUE;
836 channel_destroy((CHANNEL_REC *)chanrec);
839 printformat_module("fe-common/silc", server, channel->channel_name,
840 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
841 client_entry->nickname, channel->channel_name,
842 client_entry2 ? client_entry2->nickname : "",
846 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
848 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
853 case SILC_NOTIFY_TYPE_KILLED:
855 * Someone was killed from the network.
858 SILC_LOG_DEBUG(("Notify: KILLED"));
860 client_entry = va_arg(va, SilcClientEntry);
861 tmp = va_arg(va, char *);
862 idtype = va_arg(va, int);
863 entry = va_arg(va, SilcClientEntry);
865 if (client_entry == conn->local_entry) {
866 if (idtype == SILC_ID_CLIENT) {
867 client_entry2 = (SilcClientEntry)entry;
868 printformat_module("fe-common/silc", server, NULL,
869 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
870 client_entry2 ? client_entry2->nickname : "",
872 } else if (idtype == SILC_ID_SERVER) {
873 server_entry = (SilcServerEntry)entry;
874 printformat_module("fe-common/silc", server, NULL,
875 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
876 server_entry->server_name, tmp ? tmp : "");
877 } else if (idtype == SILC_ID_CHANNEL) {
878 channel = (SilcChannelEntry)entry;
879 printformat_module("fe-common/silc", server, NULL,
880 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
881 channel->channel_name, tmp ? tmp : "");
884 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
885 for (list_tmp = list1; list_tmp != NULL; list_tmp =
886 list_tmp->next->next) {
887 CHANNEL_REC *channel = list_tmp->data;
888 NICK_REC *nickrec = list_tmp->next->data;
889 nicklist_remove(channel, nickrec);
892 if (idtype == SILC_ID_CLIENT) {
893 client_entry2 = (SilcClientEntry)entry;
894 printformat_module("fe-common/silc", server, NULL,
895 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
896 client_entry->nickname,
897 client_entry2 ? client_entry2->nickname : "",
899 } else if (idtype == SILC_ID_SERVER) {
900 server_entry = (SilcServerEntry)entry;
901 printformat_module("fe-common/silc", server, NULL,
902 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
903 client_entry->nickname,
904 server_entry->server_name, tmp ? tmp : "");
905 } else if (idtype == SILC_ID_CHANNEL) {
906 channel = (SilcChannelEntry)entry;
907 printformat_module("fe-common/silc", server, NULL,
908 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
909 client_entry->nickname,
910 channel->channel_name, tmp ? tmp : "");
915 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
918 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
921 * Server has quit the network.
924 SilcClientEntry *clients;
925 SilcUInt32 clients_count;
927 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
929 (void)va_arg(va, void *);
930 clients = va_arg(va, SilcClientEntry *);
931 clients_count = va_arg(va, SilcUInt32);
933 for (i = 0; i < clients_count; i++) {
934 memset(buf, 0, sizeof(buf));
936 /* Print only if we have the nickname. If this client has just quit
937 when we were only resolving it, it is possible we don't have the
939 if (clients[i]->nickname) {
940 if (clients[i]->username)
941 snprintf(buf, sizeof(buf) - 1, "%s@%s",
942 clients[i]->username, clients[i]->hostname);
943 signal_emit("message quit", 4, server, clients[i]->nickname,
944 clients[i]->username ? buf : "",
948 silc_server_free_ftp(server, clients[i]);
950 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
951 for (list_tmp = list1; list_tmp != NULL; list_tmp =
952 list_tmp->next->next) {
953 CHANNEL_REC *channel = list_tmp->data;
954 NICK_REC *nickrec = list_tmp->next->data;
955 nicklist_remove(channel, nickrec);
961 case SILC_NOTIFY_TYPE_ERROR:
963 SilcStatus error = va_arg(va, int);
965 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
966 "%s", silc_get_status_message(error));
970 case SILC_NOTIFY_TYPE_WATCH:
972 SilcNotifyType notify;
974 client_entry = va_arg(va, SilcClientEntry);
975 name = va_arg(va, char *); /* Maybe NULL */
976 mode = va_arg(va, SilcUInt32);
977 notify = va_arg(va, int);
979 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
981 printformat_module("fe-common/silc", server, NULL,
982 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
983 client_entry->nickname, name);
985 printformat_module("fe-common/silc", server, NULL,
986 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
987 client_entry->nickname);
988 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
989 /* See if client was away and is now present */
990 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
991 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
992 SILC_UMODE_DETACHED)) &&
993 (client_entry->mode & SILC_UMODE_GONE ||
994 client_entry->mode & SILC_UMODE_INDISPOSED ||
995 client_entry->mode & SILC_UMODE_BUSY ||
996 client_entry->mode & SILC_UMODE_PAGE ||
997 client_entry->mode & SILC_UMODE_DETACHED)) {
998 printformat_module("fe-common/silc", server, NULL,
999 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1000 client_entry->nickname);
1004 memset(buf, 0, sizeof(buf));
1005 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1006 printformat_module("fe-common/silc", server, NULL,
1007 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1008 client_entry->nickname, buf);
1010 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1011 printformat_module("fe-common/silc", server, NULL,
1012 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1013 client_entry->nickname);
1014 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1015 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1016 printformat_module("fe-common/silc", server, NULL,
1017 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1018 client_entry->nickname);
1019 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1020 /* Client logged in to the network */
1021 printformat_module("fe-common/silc", server, NULL,
1022 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1023 client_entry->nickname);
1029 /* Unknown notify */
1030 printformat_module("fe-common/silc", server, NULL,
1031 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1038 /* Called to indicate that connection was either successfully established
1039 or connecting failed. This is also the first time application receives
1040 the SilcClientConnection object which it should save somewhere. */
1042 void silc_connect(SilcClient client, SilcClientConnection conn,
1043 SilcClientConnectionStatus status)
1045 SILC_SERVER_REC *server = conn->context;
1047 if (!server || server->disconnected) {
1048 silc_client_close_connection(client, conn);
1053 case SILC_CLIENT_CONN_SUCCESS:
1054 /* We have successfully connected to server */
1055 server->connected = TRUE;
1056 signal_emit("event connected", 1, server);
1059 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1060 /* We have successfully resumed old detached session */
1061 server->connected = TRUE;
1062 signal_emit("event connected", 1, server);
1064 /* If we resumed old session check whether we need to update
1066 if (strcmp(server->nick, conn->local_entry->nickname)) {
1068 old = g_strdup(server->nick);
1069 server_change_nick(SERVER(server), conn->local_entry->nickname);
1070 nicklist_rename_unique(SERVER(server),
1071 conn->local_entry, server->nick,
1072 conn->local_entry, conn->local_entry->nickname);
1073 signal_emit("message own_nick", 4, server, server->nick, old, "");
1079 server->connection_lost = TRUE;
1081 server->conn->context = NULL;
1082 server_disconnect(SERVER(server));
1087 /* Called to indicate that connection was disconnected to the server. */
1089 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1090 SilcStatus status, const char *message)
1092 SILC_SERVER_REC *server = conn->context;
1094 SILC_LOG_DEBUG(("Start"));
1096 if (!server || server->connection_lost)
1099 if (server->conn && server->conn->local_entry) {
1100 nicklist_rename_unique(SERVER(server),
1101 server->conn->local_entry, server->nick,
1102 server->conn->local_entry,
1103 silc_client->username);
1104 silc_change_nick(server, silc_client->username);
1108 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1109 "Server closed connection: %s (%d) %s",
1110 silc_get_status_message(status), status,
1111 message ? message : "");
1113 server->conn->context = NULL;
1114 server->conn = NULL;
1115 server->connection_lost = TRUE;
1116 server_disconnect(SERVER(server));
1119 /* Command handler. This function is called always in the command function.
1120 If error occurs it will be called as well. `conn' is the associated
1121 client connection. `cmd_context' is the command context that was
1122 originally sent to the command. `success' is FALSE if error occured
1123 during command. `command' is the command being processed. It must be
1124 noted that this is not reply from server. This is merely called just
1125 after application has called the command. Just to tell application
1126 that the command really was processed. */
1128 void silc_command(SilcClient client, SilcClientConnection conn,
1129 SilcClientCommandContext cmd_context, bool success,
1130 SilcCommand command, SilcStatus status)
1132 SILC_SERVER_REC *server = conn->context;
1134 SILC_LOG_DEBUG(("Start"));
1137 silc_say_error("%s", silc_get_status_message(status));
1143 case SILC_COMMAND_INVITE:
1144 if (cmd_context->argc > 2)
1145 printformat_module("fe-common/silc", server, NULL,
1146 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1147 cmd_context->argv[2],
1148 (cmd_context->argv[1][0] == '*' ?
1149 (char *)conn->current_channel->channel_name :
1150 (char *)cmd_context->argv[1]));
1153 case SILC_COMMAND_DETACH:
1154 server->no_reconnect = TRUE;
1162 /* Client info resolving callback when JOIN command reply is received.
1163 This will cache all users on the channel. */
1165 static void silc_client_join_get_users(SilcClient client,
1166 SilcClientConnection conn,
1167 SilcClientEntry *clients,
1168 SilcUInt32 clients_count,
1171 SilcChannelEntry channel = (SilcChannelEntry)context;
1172 SilcHashTableList htl;
1173 SilcChannelUser chu;
1174 SILC_SERVER_REC *server = conn->context;
1175 SILC_CHANNEL_REC *chanrec;
1176 SilcClientEntry founder = NULL;
1179 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1180 silc_hash_table_count(channel->user_list)));
1185 chanrec = silc_channel_find(server, channel->channel_name);
1186 if (chanrec == NULL)
1189 silc_hash_table_list(channel->user_list, &htl);
1190 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1191 if (!chu->client->nickname)
1193 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1194 founder = chu->client;
1195 silc_nicklist_insert(chanrec, chu, FALSE);
1197 silc_hash_table_list_reset(&htl);
1199 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1200 nicklist_set_own(CHANNEL(chanrec), ownnick);
1201 signal_emit("channel joined", 1, chanrec);
1202 chanrec->entry = channel;
1205 printformat_module("fe-common/silc", server, channel->channel_name,
1206 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1207 channel->channel_name, chanrec->topic);
1210 if (founder == conn->local_entry) {
1211 printformat_module("fe-common/silc",
1212 server, channel->channel_name, MSGLEVEL_CRAP,
1213 SILCTXT_CHANNEL_FOUNDER_YOU,
1214 channel->channel_name);
1215 signal_emit("nick mode changed", 2, chanrec, ownnick);
1217 printformat_module("fe-common/silc",
1218 server, channel->channel_name, MSGLEVEL_CRAP,
1219 SILCTXT_CHANNEL_FOUNDER,
1220 channel->channel_name, founder->nickname);
1226 SilcClientConnection conn;
1232 void silc_getkey_cb(bool success, void *context)
1234 GetkeyContext getkey = (GetkeyContext)context;
1235 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1236 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1237 ((SilcClientEntry)getkey->entry)->nickname :
1238 ((SilcServerEntry)getkey->entry)->server_name);
1241 printformat_module("fe-common/silc", NULL, NULL,
1242 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1244 printformat_module("fe-common/silc", NULL, NULL,
1245 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1249 silc_free(getkey->fingerprint);
1253 /* Parse an invite or ban list */
1254 void silc_parse_inviteban_list(SilcClient client,
1255 SilcClientConnection conn,
1256 SILC_SERVER_REC *server,
1257 SilcChannelEntry channel,
1258 const char *list_type,
1259 SilcArgumentPayload list)
1262 SilcUInt32 type, len;
1263 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1264 int counter=0, resolving = FALSE;
1266 if (!silc_argument_get_arg_num(list)) {
1267 printformat_module("fe-common/silc", server,
1268 (chanrec ? chanrec->visible_name : NULL),
1269 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1270 channel->channel_name, list_type);
1274 printformat_module("fe-common/silc", server,
1275 (chanrec ? chanrec->visible_name : NULL),
1276 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1277 channel->channel_name, list_type);
1279 /* parse the list */
1280 tmp = silc_argument_get_first_arg(list, &type, &len);
1285 /* an invite string */
1289 if (tmp[len-1] == ',')
1292 list = g_strsplit(tmp, ",", -1);
1294 printformat_module("fe-common/silc", server,
1295 (chanrec ? chanrec->visible_name : NULL),
1296 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1297 ++counter, channel->channel_name, list_type,
1306 char *fingerprint, *babbleprint;
1308 /* tmp is Public Key Payload, take public key from it. */
1309 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1310 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1312 printformat_module("fe-common/silc", server,
1313 (chanrec ? chanrec->visible_name : NULL),
1314 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1315 ++counter, channel->channel_name, list_type,
1316 fingerprint, babbleprint);
1323 SilcClientID *client_id;
1324 SilcClientEntry client_entry;
1326 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1328 if (client_id == NULL) {
1329 silc_say_error("Invalid data in %s list encountered", list_type);
1333 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1336 printformat_module("fe-common/silc", server,
1337 (chanrec ? chanrec->visible_name : NULL),
1338 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1339 ++counter, channel->channel_name, list_type,
1340 client_entry->nickname);
1343 silc_client_get_client_by_id_resolve(client, conn, client_id,
1347 silc_free(client_id);
1353 silc_say_error("Unkown type in %s list: %u (len %u)",
1354 list_type, type, len);
1356 tmp = silc_argument_get_next_arg(list, &type, &len);
1360 printformat_module("fe-common/silc", server,
1361 (chanrec ? chanrec->visible_name : NULL),
1362 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1363 list_type, channel->channel_name);
1366 /* Command reply handler. This function is called always in the command reply
1367 function. If error occurs it will be called as well. Normal scenario
1368 is that it will be called after the received command data has been parsed
1369 and processed. The function is used to pass the received command data to
1372 `conn' is the associated client connection. `cmd_payload' is the command
1373 payload data received from server and it can be ignored. It is provided
1374 if the application would like to re-parse the received command data,
1375 however, it must be noted that the data is parsed already by the library
1376 thus the payload can be ignored. `success' is FALSE if error occured.
1377 In this case arguments are not sent to the application. `command' is the
1378 command reply being processed. The function has variable argument list
1379 and each command defines the number and type of arguments it passes to the
1380 application (on error they are not sent). */
1383 silc_command_reply(SilcClient client, SilcClientConnection conn,
1384 SilcCommandPayload cmd_payload, bool success,
1385 SilcCommand command, SilcStatus status, ...)
1388 SILC_SERVER_REC *server = conn->context;
1389 SILC_CHANNEL_REC *chanrec;
1392 va_start(vp, status);
1394 SILC_LOG_DEBUG(("Start"));
1397 case SILC_COMMAND_WHOIS:
1399 char buf[1024], *nickname, *username, *realname, *nick;
1400 unsigned char *fingerprint;
1401 SilcUInt32 idle, mode;
1402 SilcBuffer channels, user_modes;
1403 SilcClientEntry client_entry;
1406 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1407 /* Print the unknown nick for user */
1408 unsigned char *tmp =
1409 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1412 silc_say_error("%s: %s", tmp,
1413 silc_get_status_message(status));
1415 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1416 /* Try to find the entry for the unknown client ID, since we
1417 might have, and print the nickname of it for user. */
1419 unsigned char *tmp =
1420 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1423 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1426 client_entry = silc_client_get_client_by_id(client, conn,
1428 if (client_entry && client_entry->nickname)
1429 silc_say_error("%s: %s", client_entry->nickname,
1430 silc_get_status_message(status));
1431 silc_free(client_id);
1435 } else if (!success) {
1436 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1440 client_entry = va_arg(vp, SilcClientEntry);
1441 nickname = va_arg(vp, char *);
1442 username = va_arg(vp, char *);
1443 realname = va_arg(vp, char *);
1444 channels = va_arg(vp, SilcBuffer);
1445 mode = va_arg(vp, SilcUInt32);
1446 idle = va_arg(vp, SilcUInt32);
1447 fingerprint = va_arg(vp, unsigned char *);
1448 user_modes = va_arg(vp, SilcBuffer);
1449 attrs = va_arg(vp, SilcDList);
1451 silc_parse_userfqdn(nickname, &nick, NULL);
1452 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1453 SILCTXT_WHOIS_USERINFO, nickname,
1454 client_entry->username, client_entry->hostname,
1455 nick, client_entry->nickname);
1456 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1457 SILCTXT_WHOIS_REALNAME, realname);
1460 if (channels && user_modes) {
1462 SilcDList list = silc_channel_payload_parse_list(channels->data,
1464 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1466 SilcChannelPayload entry;
1469 memset(buf, 0, sizeof(buf));
1470 silc_dlist_start(list);
1471 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1472 SilcUInt32 name_len;
1473 char *m = silc_client_chumode_char(umodes[i++]);
1474 char *name = silc_channel_get_name(entry, &name_len);
1477 strncat(buf, m, strlen(m));
1478 strncat(buf, name, name_len);
1479 strncat(buf, " ", 1);
1483 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1484 SILCTXT_WHOIS_CHANNELS, buf);
1485 silc_channel_payload_list_free(list);
1491 memset(buf, 0, sizeof(buf));
1492 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1493 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1494 SILCTXT_WHOIS_MODES, buf);
1497 if (idle && nickname) {
1498 memset(buf, 0, sizeof(buf));
1499 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1500 idle > 60 ? (idle / 60) : idle,
1501 idle > 60 ? "minutes" : "seconds");
1503 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1504 SILCTXT_WHOIS_IDLE, buf);
1508 fingerprint = silc_fingerprint(fingerprint, 20);
1509 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1510 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1511 silc_free(fingerprint);
1515 silc_query_attributes_print(server, silc_client, conn, attrs,
1520 case SILC_COMMAND_IDENTIFY:
1522 SilcClientEntry client_entry;
1524 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1525 /* Print the unknown nick for user */
1526 unsigned char *tmp =
1527 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1530 silc_say_error("%s: %s", tmp,
1531 silc_get_status_message(status));
1533 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1534 /* Try to find the entry for the unknown client ID, since we
1535 might have, and print the nickname of it for user. */
1537 unsigned char *tmp =
1538 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1541 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1544 client_entry = silc_client_get_client_by_id(client, conn,
1546 if (client_entry && client_entry->nickname)
1547 silc_say_error("%s: %s", client_entry->nickname,
1548 silc_get_status_message(status));
1549 silc_free(client_id);
1558 case SILC_COMMAND_WHOWAS:
1560 char *nickname, *username, *realname;
1562 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1563 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1565 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1568 silc_say_error("%s: %s", tmp,
1569 silc_get_status_message(status));
1571 } else if (!success) {
1572 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1576 (void)va_arg(vp, SilcClientEntry);
1577 nickname = va_arg(vp, char *);
1578 username = va_arg(vp, char *);
1579 realname = va_arg(vp, char *);
1581 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1582 SILCTXT_WHOWAS_USERINFO, nickname, username,
1583 realname ? realname : "");
1587 case SILC_COMMAND_INVITE:
1589 SilcChannelEntry channel;
1591 SilcArgumentPayload invite_list;
1597 channel = va_arg(vp, SilcChannelEntry);
1598 payload = va_arg(vp, SilcBuffer);
1601 SILC_GET16_MSB(argc, payload->data);
1602 invite_list = silc_argument_payload_parse(payload->data + 2,
1603 payload->len - 2, argc);
1605 silc_parse_inviteban_list(client, conn, server, channel,
1606 "invite", invite_list);
1607 silc_argument_payload_free(invite_list);
1613 case SILC_COMMAND_JOIN:
1615 char *channel, *mode, *topic;
1617 SilcChannelEntry channel_entry;
1618 SilcBuffer client_id_list;
1619 SilcUInt32 list_count;
1624 channel = va_arg(vp, char *);
1625 channel_entry = va_arg(vp, SilcChannelEntry);
1626 modei = va_arg(vp, SilcUInt32);
1627 (void)va_arg(vp, SilcUInt32);
1628 (void)va_arg(vp, unsigned char *);
1629 (void)va_arg(vp, unsigned char *);
1630 (void)va_arg(vp, unsigned char *);
1631 topic = va_arg(vp, char *);
1632 (void)va_arg(vp, unsigned char *);
1633 list_count = va_arg(vp, SilcUInt32);
1634 client_id_list = va_arg(vp, SilcBuffer);
1636 chanrec = silc_channel_find(server, channel);
1638 chanrec = silc_channel_create(server, channel, channel, TRUE);
1641 char tmp[256], *cp, *dm = NULL;
1642 g_free_not_null(chanrec->topic);
1644 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1645 memset(tmp, 0, sizeof(tmp));
1647 if (strlen(topic) > sizeof(tmp) - 1) {
1648 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1652 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1657 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1658 signal_emit("channel topic changed", 1, chanrec);
1663 mode = silc_client_chmode(modei,
1664 channel_entry->channel_key ?
1665 silc_cipher_get_name(channel_entry->
1667 channel_entry->hmac ?
1668 silc_hmac_get_name(channel_entry->hmac) : "");
1669 g_free_not_null(chanrec->mode);
1670 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1671 signal_emit("channel mode changed", 1, chanrec);
1673 /* Resolve the client information */
1674 silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
1675 silc_client_join_get_users,
1681 case SILC_COMMAND_NICK:
1684 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1690 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1691 if ((nicks != NULL) &&
1692 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1694 SilcClientEntry collider, old;
1696 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1697 collider = silc_client_get_client_by_id(client, conn,
1700 memset(buf, 0, sizeof(buf));
1701 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1702 collider->username, collider->hostname);
1703 nicklist_rename_unique(SERVER(server),
1705 collider, collider->nickname);
1706 silc_print_nick_change(server, collider->nickname,
1707 client_entry->nickname, buf);
1708 g_slist_free(nicks);
1711 old = g_strdup(server->nick);
1712 server_change_nick(SERVER(server), client_entry->nickname);
1713 nicklist_rename_unique(SERVER(server),
1714 server->conn->local_entry, server->nick,
1715 client_entry, client_entry->nickname);
1716 signal_emit("message own_nick", 4, server, server->nick, old, "");
1721 case SILC_COMMAND_LIST:
1726 char tmp[256], *cp, *dm = NULL;
1731 (void)va_arg(vp, SilcChannelEntry);
1732 name = va_arg(vp, char *);
1733 topic = va_arg(vp, char *);
1734 usercount = va_arg(vp, int);
1736 if (topic && !silc_term_utf8() &&
1737 silc_utf8_valid(topic, strlen(topic))) {
1738 memset(tmp, 0, sizeof(tmp));
1740 if (strlen(topic) > sizeof(tmp) - 1) {
1741 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1745 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1750 if (status == SILC_STATUS_LIST_START ||
1751 status == SILC_STATUS_OK)
1752 printformat_module("fe-common/silc", server, NULL,
1753 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1756 snprintf(users, sizeof(users) - 1, "N/A");
1758 snprintf(users, sizeof(users) - 1, "%d", usercount);
1759 printformat_module("fe-common/silc", server, NULL,
1760 MSGLEVEL_CRAP, SILCTXT_LIST,
1761 name, users, topic ? topic : "");
1766 case SILC_COMMAND_UMODE:
1774 mode = va_arg(vp, SilcUInt32);
1776 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1777 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1778 printformat_module("fe-common/silc", server, NULL,
1779 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1781 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1782 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1783 printformat_module("fe-common/silc", server, NULL,
1784 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1786 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1787 if (mode & SILC_UMODE_GONE) {
1788 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1789 reason = g_strdup(server->away_reason);
1791 reason = g_strdup("away");
1793 reason = g_strdup("");
1795 silc_set_away(reason, server);
1800 server->umode = mode;
1801 signal_emit("user mode changed", 2, server, NULL);
1805 case SILC_COMMAND_OPER:
1809 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1810 signal_emit("user mode changed", 2, server, NULL);
1812 printformat_module("fe-common/silc", server, NULL,
1813 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1816 case SILC_COMMAND_SILCOPER:
1820 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1821 signal_emit("user mode changed", 2, server, NULL);
1823 printformat_module("fe-common/silc", server, NULL,
1824 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1827 case SILC_COMMAND_USERS:
1829 SilcHashTableList htl;
1830 SilcChannelEntry channel;
1831 SilcChannelUser chu;
1836 channel = va_arg(vp, SilcChannelEntry);
1838 printformat_module("fe-common/silc", server, channel->channel_name,
1839 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1840 channel->channel_name);
1842 silc_hash_table_list(channel->user_list, &htl);
1843 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1844 SilcClientEntry e = chu->client;
1845 char stat[5], *mode;
1850 memset(stat, 0, sizeof(stat));
1851 mode = silc_client_chumode_char(chu->mode);
1852 if (e->mode & SILC_UMODE_GONE)
1854 else if (e->mode & SILC_UMODE_INDISPOSED)
1856 else if (e->mode & SILC_UMODE_BUSY)
1858 else if (e->mode & SILC_UMODE_PAGE)
1860 else if (e->mode & SILC_UMODE_HYPER)
1862 else if (e->mode & SILC_UMODE_ROBOT)
1864 else if (e->mode & SILC_UMODE_ANONYMOUS)
1871 printformat_module("fe-common/silc", server, channel->channel_name,
1872 MSGLEVEL_CRAP, SILCTXT_USERS,
1874 e->username ? e->username : "",
1875 e->hostname ? e->hostname : "",
1876 e->realname ? e->realname : "");
1880 silc_hash_table_list_reset(&htl);
1884 case SILC_COMMAND_BAN:
1886 SilcChannelEntry channel;
1888 SilcArgumentPayload ban_list;
1894 channel = va_arg(vp, SilcChannelEntry);
1895 payload = va_arg(vp, SilcBuffer);
1898 SILC_GET16_MSB(argc, payload->data);
1899 ban_list = silc_argument_payload_parse(payload->data + 2,
1900 payload->len - 2, argc);
1902 silc_parse_inviteban_list(client, conn, server, channel,
1904 silc_argument_payload_free(ban_list);
1910 case SILC_COMMAND_GETKEY:
1914 SilcPublicKey public_key;
1917 GetkeyContext getkey;
1923 id_type = va_arg(vp, SilcUInt32);
1924 entry = va_arg(vp, void *);
1925 public_key = va_arg(vp, SilcPublicKey);
1928 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1930 getkey = silc_calloc(1, sizeof(*getkey));
1931 getkey->entry = entry;
1932 getkey->id_type = id_type;
1933 getkey->client = client;
1934 getkey->conn = conn;
1935 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1937 name = (id_type == SILC_ID_CLIENT ?
1938 ((SilcClientEntry)entry)->nickname :
1939 ((SilcServerEntry)entry)->server_name);
1941 silc_verify_public_key_internal(client, conn, name,
1942 (id_type == SILC_ID_CLIENT ?
1943 SILC_SOCKET_TYPE_CLIENT :
1944 SILC_SOCKET_TYPE_SERVER),
1945 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
1946 silc_getkey_cb, getkey);
1949 printformat_module("fe-common/silc", server, NULL,
1950 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
1955 case SILC_COMMAND_INFO:
1957 SilcServerEntry server_entry;
1964 server_entry = va_arg(vp, SilcServerEntry);
1965 server_name = va_arg(vp, char *);
1966 server_info = va_arg(vp, char *);
1968 if (server_name && server_info )
1970 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
1971 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
1976 case SILC_COMMAND_TOPIC:
1978 SilcChannelEntry channel;
1980 char tmp[256], *cp, *dm = NULL;
1985 channel = va_arg(vp, SilcChannelEntry);
1986 topic = va_arg(vp, char *);
1988 if (topic && !silc_term_utf8() &&
1989 silc_utf8_valid(topic, strlen(topic))) {
1990 memset(tmp, 0, sizeof(tmp));
1992 if (strlen(topic) > sizeof(tmp) - 1) {
1993 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1997 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2003 chanrec = silc_channel_find_entry(server, channel);
2005 g_free_not_null(chanrec->topic);
2006 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2007 signal_emit("channel topic changed", 1, chanrec);
2009 printformat_module("fe-common/silc", server, channel->channel_name,
2010 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2011 channel->channel_name, topic);
2013 printformat_module("fe-common/silc", server, channel->channel_name,
2014 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2015 channel->channel_name);
2021 case SILC_COMMAND_WATCH:
2024 case SILC_COMMAND_STATS:
2026 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2027 my_router_ops, cell_clients, cell_channels, cell_servers,
2028 clients, channels, servers, routers, server_ops, router_ops;
2030 SilcBufferStruct buf;
2031 unsigned char *tmp_buf;
2033 const char *tmptime;
2034 int days, hours, mins, secs;
2039 tmp_buf = va_arg(vp, unsigned char *);
2040 buf_len = va_arg(vp, SilcUInt32);
2042 if (!tmp_buf || !buf_len) {
2043 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2047 /* Get statistics structure */
2048 silc_buffer_set(&buf, tmp_buf, buf_len);
2049 silc_buffer_unformat(&buf,
2050 SILC_STR_UI_INT(&starttime),
2051 SILC_STR_UI_INT(&uptime),
2052 SILC_STR_UI_INT(&my_clients),
2053 SILC_STR_UI_INT(&my_channels),
2054 SILC_STR_UI_INT(&my_server_ops),
2055 SILC_STR_UI_INT(&my_router_ops),
2056 SILC_STR_UI_INT(&cell_clients),
2057 SILC_STR_UI_INT(&cell_channels),
2058 SILC_STR_UI_INT(&cell_servers),
2059 SILC_STR_UI_INT(&clients),
2060 SILC_STR_UI_INT(&channels),
2061 SILC_STR_UI_INT(&servers),
2062 SILC_STR_UI_INT(&routers),
2063 SILC_STR_UI_INT(&server_ops),
2064 SILC_STR_UI_INT(&router_ops),
2067 tmptime = silc_get_time(starttime);
2068 printformat_module("fe-common/silc", server, NULL,
2069 MSGLEVEL_CRAP, SILCTXT_STATS,
2070 "Local server start time", tmptime);
2072 days = uptime / (24 * 60 * 60);
2073 uptime -= days * (24 * 60 * 60);
2074 hours = uptime / (60 * 60);
2075 uptime -= hours * (60 * 60);
2077 uptime -= mins * 60;
2079 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2080 days, hours, mins, secs);
2081 printformat_module("fe-common/silc", server, NULL,
2082 MSGLEVEL_CRAP, SILCTXT_STATS,
2083 "Local server uptime", tmp);
2085 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2086 printformat_module("fe-common/silc", server, NULL,
2087 MSGLEVEL_CRAP, SILCTXT_STATS,
2088 "Local server clients", tmp);
2090 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2091 printformat_module("fe-common/silc", server, NULL,
2092 MSGLEVEL_CRAP, SILCTXT_STATS,
2093 "Local server channels", tmp);
2095 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2096 printformat_module("fe-common/silc", server, NULL,
2097 MSGLEVEL_CRAP, SILCTXT_STATS,
2098 "Local server operators", tmp);
2100 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2101 printformat_module("fe-common/silc", server, NULL,
2102 MSGLEVEL_CRAP, SILCTXT_STATS,
2103 "Local router operators", tmp);
2105 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2106 printformat_module("fe-common/silc", server, NULL,
2107 MSGLEVEL_CRAP, SILCTXT_STATS,
2108 "Local cell clients", tmp);
2110 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2111 printformat_module("fe-common/silc", server, NULL,
2112 MSGLEVEL_CRAP, SILCTXT_STATS,
2113 "Local cell channels", tmp);
2115 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2116 printformat_module("fe-common/silc", server, NULL,
2117 MSGLEVEL_CRAP, SILCTXT_STATS,
2118 "Local cell servers", tmp);
2120 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2121 printformat_module("fe-common/silc", server, NULL,
2122 MSGLEVEL_CRAP, SILCTXT_STATS,
2123 "Total clients", tmp);
2125 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2126 printformat_module("fe-common/silc", server, NULL,
2127 MSGLEVEL_CRAP, SILCTXT_STATS,
2128 "Total channels", tmp);
2130 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2131 printformat_module("fe-common/silc", server, NULL,
2132 MSGLEVEL_CRAP, SILCTXT_STATS,
2133 "Total servers", tmp);
2135 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2136 printformat_module("fe-common/silc", server, NULL,
2137 MSGLEVEL_CRAP, SILCTXT_STATS,
2138 "Total routers", tmp);
2140 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2141 printformat_module("fe-common/silc", server, NULL,
2142 MSGLEVEL_CRAP, SILCTXT_STATS,
2143 "Total server operators", tmp);
2145 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2146 printformat_module("fe-common/silc", server, NULL,
2147 MSGLEVEL_CRAP, SILCTXT_STATS,
2148 "Total router operators", tmp);
2159 SilcClientConnection conn;
2165 SilcSKEPKType pk_type;
2166 SilcVerifyPublicKey completion;
2170 static void verify_public_key_completion(const char *line, void *context)
2172 PublicKeyVerify verify = (PublicKeyVerify)context;
2174 if (line[0] == 'Y' || line[0] == 'y') {
2175 /* Call the completion */
2176 if (verify->completion)
2177 verify->completion(TRUE, verify->context);
2179 /* Save the key for future checking */
2180 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2181 verify->pk_len, SILC_PKCS_FILE_PEM);
2183 /* Call the completion */
2184 if (verify->completion)
2185 verify->completion(FALSE, verify->context);
2187 printformat_module("fe-common/silc", NULL, NULL,
2188 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2189 verify->entity_name ? verify->entity_name :
2193 silc_free(verify->filename);
2194 silc_free(verify->entity);
2195 silc_free(verify->entity_name);
2196 silc_free(verify->pk);
2200 /* Internal routine to verify public key. If the `completion' is provided
2201 it will be called to indicate whether public was verified or not. For
2202 server/router public key this will check for filename that includes the
2203 remote host's IP address and remote host's hostname. */
2206 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2207 const char *name, SilcSocketType conn_type,
2208 unsigned char *pk, SilcUInt32 pk_len,
2209 SilcSKEPKType pk_type,
2210 SilcVerifyPublicKey completion, void *context)
2213 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2214 char *fingerprint, *babbleprint, *format;
2217 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2218 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2219 "server" : "client");
2220 PublicKeyVerify verify;
2222 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2223 printformat_module("fe-common/silc", NULL, NULL,
2224 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2227 completion(FALSE, context);
2231 pw = getpwuid(getuid());
2234 completion(FALSE, context);
2238 memset(filename, 0, sizeof(filename));
2239 memset(filename2, 0, sizeof(filename2));
2240 memset(file, 0, sizeof(file));
2242 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2243 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2245 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2246 conn->sock->ip, conn->sock->port);
2247 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2248 get_irssi_dir(), entity, file);
2250 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2251 conn->sock->hostname, conn->sock->port);
2252 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2253 get_irssi_dir(), entity, file);
2258 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2259 name, conn->sock->port);
2260 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2261 get_irssi_dir(), entity, file);
2266 /* Replace all whitespaces with `_'. */
2267 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2268 for (i = 0; i < strlen(fingerprint); i++)
2269 if (fingerprint[i] == ' ')
2270 fingerprint[i] = '_';
2272 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2273 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2274 get_irssi_dir(), entity, file);
2275 silc_free(fingerprint);
2280 /* Take fingerprint of the public key */
2281 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2282 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2284 verify = silc_calloc(1, sizeof(*verify));
2285 verify->client = client;
2286 verify->conn = conn;
2287 verify->filename = strdup(ipf);
2288 verify->entity = strdup(entity);
2289 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2290 (name ? strdup(name) : strdup(conn->sock->hostname))
2292 verify->pk = silc_memdup(pk, pk_len);
2293 verify->pk_len = pk_len;
2294 verify->pk_type = pk_type;
2295 verify->completion = completion;
2296 verify->context = context;
2298 /* Check whether this key already exists */
2299 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2300 /* Key does not exist, ask user to verify the key and save it */
2302 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2303 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2304 verify->entity_name : entity);
2305 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2306 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2307 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2308 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2309 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2310 SILCTXT_PUBKEY_ACCEPT);
2311 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2314 silc_free(fingerprint);
2317 /* The key already exists, verify it. */
2318 SilcPublicKey public_key;
2319 unsigned char *encpk;
2320 SilcUInt32 encpk_len;
2322 /* Load the key file, try for both IP filename and hostname filename */
2323 if (!silc_pkcs_load_public_key(ipf, &public_key,
2324 SILC_PKCS_FILE_PEM) &&
2325 !silc_pkcs_load_public_key(ipf, &public_key,
2326 SILC_PKCS_FILE_BIN) &&
2327 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2328 SILC_PKCS_FILE_PEM) &&
2329 !silc_pkcs_load_public_key(hostf, &public_key,
2330 SILC_PKCS_FILE_BIN)))) {
2331 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2332 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2333 verify->entity_name : entity);
2334 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2335 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2336 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2337 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2338 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2339 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2340 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2341 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2342 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2345 silc_free(fingerprint);
2349 /* Encode the key data */
2350 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2352 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2353 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2354 verify->entity_name : entity);
2355 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2356 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2357 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2358 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2359 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2360 SILCTXT_PUBKEY_MALFORMED, entity);
2361 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2362 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2363 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2366 silc_free(fingerprint);
2370 /* Compare the keys */
2371 if (memcmp(encpk, pk, encpk_len)) {
2372 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2373 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2374 verify->entity_name : entity);
2375 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2376 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2377 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2378 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2379 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2380 SILCTXT_PUBKEY_NO_MATCH, entity);
2381 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2382 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2383 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2384 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2386 /* Ask user to verify the key and save it */
2387 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2388 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2389 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2392 silc_free(fingerprint);
2396 /* Local copy matched */
2398 completion(TRUE, context);
2399 silc_free(fingerprint);
2400 silc_free(verify->filename);
2401 silc_free(verify->entity);
2402 silc_free(verify->entity_name);
2403 silc_free(verify->pk);
2408 /* Verifies received public key. The `conn_type' indicates which entity
2409 (server, client etc.) has sent the public key. If user decides to trust
2410 the key may be saved as trusted public key for later use. The
2411 `completion' must be called after the public key has been verified. */
2414 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2415 SilcSocketType conn_type, unsigned char *pk,
2416 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2417 SilcVerifyPublicKey completion, void *context)
2419 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2421 completion, context);
2424 /* Asks passphrase from user on the input line. */
2427 SilcAskPassphrase completion;
2431 void ask_passphrase_completion(const char *passphrase, void *context)
2433 AskPassphrase p = (AskPassphrase)context;
2434 if (passphrase && passphrase[0] == '\0')
2436 p->completion((unsigned char *)passphrase,
2437 passphrase ? strlen(passphrase) : 0, p->context);
2441 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2442 SilcAskPassphrase completion, void *context)
2444 AskPassphrase p = silc_calloc(1, sizeof(*p));
2445 p->completion = completion;
2446 p->context = context;
2448 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2449 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2453 SilcGetAuthMeth completion;
2455 } *InternalGetAuthMethod;
2457 /* Callback called when we've received the authentication method information
2458 from the server after we've requested it. This will get the authentication
2459 data from the user if needed. */
2461 static void silc_get_auth_method_callback(SilcClient client,
2462 SilcClientConnection conn,
2463 SilcAuthMethod auth_meth,
2466 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2468 SILC_LOG_DEBUG(("Start"));
2470 switch (auth_meth) {
2471 case SILC_AUTH_NONE:
2472 /* No authentication required. */
2473 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2475 case SILC_AUTH_PASSWORD:
2477 /* Check whether we find the password for this server in our
2478 configuration. If not, then don't provide so library will ask
2479 it from the user. */
2480 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2482 if (!setup || !setup->password) {
2483 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2487 (*internal->completion)(TRUE, auth_meth, setup->password,
2488 strlen(setup->password), internal->context);
2491 case SILC_AUTH_PUBLIC_KEY:
2492 /* Do not get the authentication data now, the library will generate
2493 it using our default key, if we do not provide it here. */
2494 /* XXX In the future when we support multiple local keys and multiple
2495 local certificates we will need to ask from user which one to use. */
2496 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2500 silc_free(internal);
2503 /* Find authentication method and authentication data by hostname and
2504 port. The hostname may be IP address as well. The found authentication
2505 method and authentication data is returned to `auth_meth', `auth_data'
2506 and `auth_data_len'. The function returns TRUE if authentication method
2507 is found and FALSE if not. `conn' may be NULL. */
2509 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2510 char *hostname, SilcUInt16 port,
2511 SilcGetAuthMeth completion, void *context)
2513 InternalGetAuthMethod internal;
2515 SILC_LOG_DEBUG(("Start"));
2517 /* If we do not have this connection configured by the user in a
2518 configuration file then resolve the authentication method from the
2519 server for this session. */
2520 internal = silc_calloc(1, sizeof(*internal));
2521 internal->completion = completion;
2522 internal->context = context;
2524 silc_client_request_authentication_method(client, conn,
2525 silc_get_auth_method_callback,
2529 /* Notifies application that failure packet was received. This is called
2530 if there is some protocol active in the client. The `protocol' is the
2531 protocol context. The `failure' is opaque pointer to the failure
2532 indication. Note, that the `failure' is protocol dependant and application
2533 must explicitly cast it to correct type. Usually `failure' is 32 bit
2534 failure type (see protocol specs for all protocol failure types). */
2536 void silc_failure(SilcClient client, SilcClientConnection conn,
2537 SilcProtocol protocol, void *failure)
2539 SILC_LOG_DEBUG(("Start"));
2541 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2542 SilcSKEStatus status = (SilcSKEStatus)failure;
2544 if (status == SILC_SKE_STATUS_BAD_VERSION)
2545 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2546 SILCTXT_KE_BAD_VERSION);
2547 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2548 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2549 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2550 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2551 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2552 SILCTXT_KE_UNKNOWN_GROUP);
2553 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2554 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2555 SILCTXT_KE_UNKNOWN_CIPHER);
2556 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2557 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2558 SILCTXT_KE_UNKNOWN_PKCS);
2559 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2560 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2561 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2562 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2563 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2564 SILCTXT_KE_UNKNOWN_HMAC);
2565 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2566 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2567 SILCTXT_KE_INCORRECT_SIGNATURE);
2568 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2569 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2570 SILCTXT_KE_INVALID_COOKIE);
2573 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2574 SilcUInt32 err = (SilcUInt32)failure;
2576 if (err == SILC_AUTH_FAILED)
2577 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2578 SILCTXT_AUTH_FAILED);
2582 /* Asks whether the user would like to perform the key agreement protocol.
2583 This is called after we have received an key agreement packet or an
2584 reply to our key agreement packet. This returns TRUE if the user wants
2585 the library to perform the key agreement protocol and FALSE if it is not
2586 desired (application may start it later by calling the function
2587 silc_client_perform_key_agreement). */
2589 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2590 SilcClientEntry client_entry, const char *hostname,
2591 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2596 SILC_LOG_DEBUG(("Start"));
2598 /* We will just display the info on the screen and return FALSE and user
2599 will have to start the key agreement with a command. */
2602 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2605 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2606 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2608 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2609 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2610 client_entry->nickname, hostname, portstr);
2618 /* Notifies application that file transfer protocol session is being
2619 requested by the remote client indicated by the `client_entry' from
2620 the `hostname' and `port'. The `session_id' is the file transfer
2621 session and it can be used to either accept or reject the file
2622 transfer request, by calling the silc_client_file_receive or
2623 silc_client_file_close, respectively. */
2625 void silc_ftp(SilcClient client, SilcClientConnection conn,
2626 SilcClientEntry client_entry, SilcUInt32 session_id,
2627 const char *hostname, SilcUInt16 port)
2629 SILC_SERVER_REC *server;
2631 FtpSession ftp = NULL;
2633 SILC_LOG_DEBUG(("Start"));
2635 server = conn->context;
2637 silc_dlist_start(server->ftp_sessions);
2638 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2639 if (ftp->client_entry == client_entry &&
2640 ftp->session_id == session_id) {
2641 server->current_session = ftp;
2645 if (ftp == SILC_LIST_END) {
2646 ftp = silc_calloc(1, sizeof(*ftp));
2647 ftp->client_entry = client_entry;
2648 ftp->session_id = session_id;
2651 silc_dlist_add(server->ftp_sessions, ftp);
2652 server->current_session = ftp;
2656 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2659 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2660 SILCTXT_FILE_REQUEST, client_entry->nickname);
2662 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2663 SILCTXT_FILE_REQUEST_HOST,
2664 client_entry->nickname, hostname, portstr);
2667 /* Delivers SILC session detachment data indicated by `detach_data' to the
2668 application. If application has issued SILC_COMMAND_DETACH command
2669 the client session in the SILC network is not quit. The client remains
2670 in the network but is detached. The detachment data may be used later
2671 to resume the session in the SILC Network. The appliation is
2672 responsible of saving the `detach_data', to for example in a file.
2674 The detachment data can be given as argument to the functions
2675 silc_client_connect_to_server, or silc_client_add_connection when
2676 creating connection to remote server, inside SilcClientConnectionParams
2677 structure. If it is provided the client library will attempt to resume
2678 the session in the network. After the connection is created
2679 successfully, the application is responsible of setting the user
2680 interface for user into the same state it was before detaching (showing
2681 same channels, channel modes, etc). It can do this by fetching the
2682 information (like joined channels) from the client library. */
2685 silc_detach(SilcClient client, SilcClientConnection conn,
2686 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2690 /* Save the detachment data to file. */
2692 memset(file, 0, sizeof(file));
2693 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2694 silc_file_writefile(file, detach_data, detach_data_len);
2698 /* SILC client operations */
2699 SilcClientOperations ops = {
2701 silc_channel_message,
2702 silc_private_message,
2708 silc_get_auth_method,
2709 silc_verify_public_key,
2710 silc_ask_passphrase,