5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 - 2003 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 static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
128 SilcChannelEntry channel_entry,
129 SilcBuffer channel_pubkeys)
132 SilcArgumentPayload chpks;
134 SilcUInt32 pk_len, type;
136 char *fingerprint, *babbleprint;
137 SilcPublicKey pubkey;
138 SilcPublicKeyIdentifier ident;
140 printformat_module("fe-common/silc", server, NULL,
141 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
142 channel_entry->channel_name);
144 SILC_GET16_MSB(argc, channel_pubkeys->data);
145 chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
146 channel_pubkeys->len - 2, argc);
150 pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
152 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
153 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
154 silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
155 ident = silc_pkcs_decode_identifier(pubkey->identifier);
157 printformat_module("fe-common/silc", server, NULL,
158 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
159 c++, channel_entry->channel_name,
160 type == 0x00 ? "Added" : "Removed",
161 ident->realname ? ident->realname : "",
162 fingerprint, babbleprint);
164 silc_free(fingerprint);
165 silc_free(babbleprint);
166 silc_pkcs_public_key_free(pubkey);
167 silc_pkcs_free_identifier(ident);
168 pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
171 silc_argument_payload_free(chpks);
174 void silc_say(SilcClient client, SilcClientConnection conn,
175 SilcClientMessageType type, char *msg, ...)
177 SILC_SERVER_REC *server;
181 server = conn == NULL ? NULL : conn->context;
184 str = g_strdup_vprintf(msg, va);
185 printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
190 void silc_say_error(char *msg, ...)
196 str = g_strdup_vprintf(msg, va);
197 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str);
203 /* try to verify a message using locally stored public key data */
204 int verify_message_signature(SilcClientEntry sender,
205 SilcMessageSignedPayload sig,
206 SilcMessagePayload message)
209 char file[256], filename[256];
210 char *fingerprint, *fingerprint2;
211 unsigned char *pk_data;
212 SilcUInt32 pk_datalen;
214 int ret = SILC_MSG_SIGNED_VERIFIED, i;
217 return SILC_MSG_SIGNED_UNKNOWN;
219 /* get public key from the signature payload and compare it with the
220 one stored in the client entry */
221 pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
224 fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
226 if (sender->fingerprint) {
227 fingerprint2 = silc_fingerprint(sender->fingerprint,
228 sender->fingerprint_len);
229 if (strcmp(fingerprint, fingerprint2)) {
230 /* since the public key differs from the senders public key, the
231 verification _failed_ */
232 silc_pkcs_public_key_free(pk);
233 silc_free(fingerprint);
234 ret = SILC_MSG_SIGNED_UNKNOWN;
236 silc_free(fingerprint2);
238 } else if (sender->fingerprint)
239 fingerprint = silc_fingerprint(sender->fingerprint,
240 sender->fingerprint_len);
242 /* no idea, who or what signed that message ... */
243 return SILC_MSG_SIGNED_UNKNOWN;
245 /* search our local client key cache */
246 for (i = 0; i < strlen(fingerprint); i++)
247 if (fingerprint[i] == ' ')
248 fingerprint[i] = '_';
250 snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
251 snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
252 get_irssi_dir(), file);
253 silc_free(fingerprint);
255 if (stat(filename, &st) < 0)
256 /* we don't have the public key cached ... use the one from the sig */
257 ret = SILC_MSG_SIGNED_UNKNOWN;
259 SilcPublicKey cached_pk=NULL;
261 /* try to load the file */
262 if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
263 !silc_pkcs_load_public_key(filename, &cached_pk,
264 SILC_PKCS_FILE_BIN)) {
265 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
266 SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
268 return SILC_MSG_SIGNED_UNKNOWN;
270 ret = SILC_MSG_SIGNED_UNKNOWN;
275 silc_pkcs_public_key_free(pk);
280 /* the public key is now in pk, our "level of trust" in ret */
281 if ((pk) && silc_message_signed_verify(sig, message, pk,
282 silc_client->sha1hash)!= SILC_AUTH_OK)
283 ret = SILC_MSG_SIGNED_FAILED;
286 silc_pkcs_public_key_free(pk);
291 /* Message for a channel. The `sender' is the nickname of the sender
292 received in the packet. The `channel_name' is the name of the channel. */
294 void silc_channel_message(SilcClient client, SilcClientConnection conn,
295 SilcClientEntry sender, SilcChannelEntry channel,
296 SilcMessagePayload payload,
297 SilcMessageFlags flags, const unsigned char *message,
298 SilcUInt32 message_len)
300 SILC_SERVER_REC *server;
302 SILC_CHANNEL_REC *chanrec;
305 SILC_LOG_DEBUG(("Start"));
310 server = conn == NULL ? NULL : conn->context;
311 chanrec = silc_channel_find_entry(server, channel);
315 nick = silc_nicklist_find(chanrec, sender);
317 /* We didn't find client but it clearly exists, add it. */
318 SilcChannelUser chu = silc_client_on_channel(channel, sender);
320 nick = silc_nicklist_insert(chanrec, chu, FALSE);
323 /* If the messages is digitally signed, verify it, if possible. */
324 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
325 if (!settings_get_bool("ignore_message_signatures")) {
326 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
327 verified = verify_message_signature(sender, sig, payload);
329 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
333 if (flags & SILC_MESSAGE_FLAG_DATA) {
334 /* MIME object received, try to display it as well as we can */
335 char type[128], enc[128];
339 memset(type, 0, sizeof(type));
340 memset(enc, 0, sizeof(enc));
341 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
342 enc, sizeof(enc) - 1, &data, &data_len))
345 /* Then figure out what we can display */
346 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
347 !strstr(type, "text/vnd")) {
348 /* It is something textual, display it */
349 message = (const unsigned char *)data;
351 printformat_module("fe-common/silc", server, channel->channel_name,
352 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
353 nick == NULL ? "[<unknown>]" : nick->nick, type);
361 /* FIXME: replace those printformat calls with signals and add signature
362 information to them (if present) */
363 if (flags & SILC_MESSAGE_FLAG_ACTION)
364 printformat_module("fe-common/silc", server, channel->channel_name,
365 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
366 nick == NULL ? "[<unknown>]" : nick->nick, message);
367 else if (flags & SILC_MESSAGE_FLAG_NOTICE)
368 printformat_module("fe-common/silc", server, channel->channel_name,
369 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
370 nick == NULL ? "[<unknown>]" : nick->nick, message);
372 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
373 char tmp[256], *cp, *dm = NULL;
375 memset(tmp, 0, sizeof(tmp));
377 if (message_len > sizeof(tmp) - 1) {
378 dm = silc_calloc(message_len + 1, sizeof(*dm));
382 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
384 if (flags & SILC_MESSAGE_FLAG_SIGNED)
385 signal_emit("message signed_public", 6, server, cp,
386 nick == NULL ? "[<unknown>]" : nick->nick,
387 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
388 chanrec->name, verified);
390 signal_emit("message public", 6, server, cp,
391 nick == NULL ? "[<unknown>]" : nick->nick,
392 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
393 chanrec->name, nick);
398 if (flags & SILC_MESSAGE_FLAG_SIGNED)
399 signal_emit("message signed_public", 6, server, message,
400 nick == NULL ? "[<unknown>]" : nick->nick,
401 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
402 chanrec->name, verified);
404 signal_emit("message public", 6, server, message,
405 nick == NULL ? "[<unknown>]" : nick->nick,
406 nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
407 chanrec->name, nick);
411 /* Private message to the client. The `sender' is the nickname of the
412 sender received in the packet. */
414 void silc_private_message(SilcClient client, SilcClientConnection conn,
415 SilcClientEntry sender, SilcMessagePayload payload,
416 SilcMessageFlags flags,
417 const unsigned char *message,
418 SilcUInt32 message_len)
420 SILC_SERVER_REC *server;
424 SILC_LOG_DEBUG(("Start"));
426 server = conn == NULL ? NULL : conn->context;
427 memset(userhost, 0, sizeof(userhost));
428 if (sender->username)
429 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
430 sender->username, sender->hostname);
432 /* If the messages is digitally signed, verify it, if possible. */
433 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
434 if (!settings_get_bool("ignore_message_signatures")) {
435 SilcMessageSignedPayload sig = silc_message_get_signature(payload);
436 verified = verify_message_signature(sender, sig, payload);
438 flags &= ~SILC_MESSAGE_FLAG_SIGNED;
442 if (flags & SILC_MESSAGE_FLAG_DATA) {
443 /* MIME object received, try to display it as well as we can */
444 char type[128], enc[128];
448 memset(type, 0, sizeof(type));
449 memset(enc, 0, sizeof(enc));
450 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
451 enc, sizeof(enc) - 1, &data, &data_len))
454 /* Then figure out what we can display */
455 if (strstr(type, "text/") && !strstr(type, "text/t140") &&
456 !strstr(type, "text/vnd")) {
457 /* It is something textual, display it */
458 message = (const unsigned char *)data;
460 printformat_module("fe-common/silc", server, NULL,
461 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
462 sender->nickname ? sender->nickname : "[<unknown>]",
471 if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
472 char tmp[256], *cp, *dm = NULL;
474 memset(tmp, 0, sizeof(tmp));
476 if (message_len > sizeof(tmp) - 1) {
477 dm = silc_calloc(message_len + 1, sizeof(*dm));
481 silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
483 if (flags & SILC_MESSAGE_FLAG_SIGNED)
484 signal_emit("message signed_private", 5, server, cp,
485 sender->nickname ? sender->nickname : "[<unknown>]",
486 sender->username ? userhost : NULL, verified);
488 signal_emit("message private", 4, server, cp,
489 sender->nickname ? sender->nickname : "[<unknown>]",
490 sender->username ? userhost : NULL);
495 if (flags & SILC_MESSAGE_FLAG_SIGNED)
496 signal_emit("message signed_private", 5, server, message,
497 sender->nickname ? sender->nickname : "[<unknown>]",
498 sender->username ? userhost : NULL, verified);
500 signal_emit("message private", 4, server, message,
501 sender->nickname ? sender->nickname : "[<unknown>]",
502 sender->username ? userhost : NULL);
505 /* Notify message to the client. The notify arguments are sent in the
506 same order as servers sends them. The arguments are same as received
507 from the server except for ID's. If ID is received application receives
508 the corresponding entry to the ID. For example, if Client ID is received
509 application receives SilcClientEntry. Also, if the notify type is
510 for channel the channel entry is sent to application (even if server
511 does not send it). */
513 void silc_notify(SilcClient client, SilcClientConnection conn,
514 SilcNotifyType type, ...)
517 SILC_SERVER_REC *server;
518 SILC_CHANNEL_REC *chanrec;
519 SILC_NICK_REC *nickrec;
520 SilcClientEntry client_entry, client_entry2;
521 SilcChannelEntry channel, channel2;
522 SilcServerEntry server_entry;
528 GSList *list1, *list_tmp;
531 SILC_LOG_DEBUG(("Start"));
535 server = conn == NULL ? NULL : conn->context;
538 case SILC_NOTIFY_TYPE_NONE:
539 /* Some generic notice from server */
540 printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
543 case SILC_NOTIFY_TYPE_INVITE:
545 * Invited or modified invite list.
548 SILC_LOG_DEBUG(("Notify: INVITE"));
550 channel = va_arg(va, SilcChannelEntry);
551 name = va_arg(va, char *);
552 client_entry = va_arg(va, SilcClientEntry);
554 memset(buf, 0, sizeof(buf));
555 snprintf(buf, sizeof(buf) - 1, "%s@%s",
556 client_entry->username, client_entry->hostname);
557 signal_emit("message invite", 4, server, channel ? channel->channel_name :
558 name, client_entry->nickname, buf);
561 case SILC_NOTIFY_TYPE_JOIN:
566 SILC_LOG_DEBUG(("Notify: JOIN"));
568 client_entry = va_arg(va, SilcClientEntry);
569 channel = va_arg(va, SilcChannelEntry);
571 if (client_entry == server->conn->local_entry) {
572 /* You joined to channel */
573 chanrec = silc_channel_find(server, channel->channel_name);
574 if (chanrec != NULL && !chanrec->joined)
575 chanrec->entry = channel;
577 chanrec = silc_channel_find_entry(server, channel);
578 if (chanrec != NULL) {
579 SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
581 nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
585 memset(buf, 0, sizeof(buf));
586 if (client_entry->username)
587 snprintf(buf, sizeof(buf) - 1, "%s@%s",
588 client_entry->username, client_entry->hostname);
589 signal_emit("message join", 4, server, channel->channel_name,
590 client_entry->nickname,
591 client_entry->username == NULL ? "" : buf);
594 case SILC_NOTIFY_TYPE_LEAVE:
599 SILC_LOG_DEBUG(("Notify: LEAVE"));
601 client_entry = va_arg(va, SilcClientEntry);
602 channel = va_arg(va, SilcChannelEntry);
604 memset(buf, 0, sizeof(buf));
605 if (client_entry->username)
606 snprintf(buf, sizeof(buf) - 1, "%s@%s",
607 client_entry->username, client_entry->hostname);
608 signal_emit("message part", 5, server, channel->channel_name,
609 client_entry->nickname, client_entry->username ?
610 buf : "", client_entry->nickname);
612 chanrec = silc_channel_find_entry(server, channel);
613 if (chanrec != NULL) {
614 nickrec = silc_nicklist_find(chanrec, client_entry);
616 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
620 case SILC_NOTIFY_TYPE_SIGNOFF:
625 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
627 client_entry = va_arg(va, SilcClientEntry);
628 tmp = va_arg(va, char *);
630 silc_server_free_ftp(server, client_entry);
632 /* Print only if we have the nickname. If this cliente has just quit
633 when we were only resolving it, it is possible we don't have the
635 if (client_entry->nickname) {
636 memset(buf, 0, sizeof(buf));
637 if (client_entry->username)
638 snprintf(buf, sizeof(buf) - 1, "%s@%s",
639 client_entry->username, client_entry->hostname);
640 signal_emit("message quit", 4, server, client_entry->nickname,
641 client_entry->username ? buf : "",
645 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
646 for (list_tmp = list1; list_tmp != NULL; list_tmp =
647 list_tmp->next->next) {
648 CHANNEL_REC *channel = list_tmp->data;
649 NICK_REC *nickrec = list_tmp->next->data;
651 nicklist_remove(channel, nickrec);
655 case SILC_NOTIFY_TYPE_TOPIC_SET:
660 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
662 idtype = va_arg(va, int);
663 entry = va_arg(va, void *);
664 tmp = va_arg(va, char *);
665 channel = va_arg(va, SilcChannelEntry);
667 chanrec = silc_channel_find_entry(server, channel);
668 if (chanrec != NULL) {
669 char tmp2[256], *cp, *dm = NULL;
671 g_free_not_null(chanrec->topic);
672 if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
673 memset(tmp2, 0, sizeof(tmp2));
675 if (strlen(tmp) > sizeof(tmp2) - 1) {
676 dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
680 silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
685 chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
686 signal_emit("channel topic changed", 1, chanrec);
691 if (idtype == SILC_ID_CLIENT) {
692 client_entry = (SilcClientEntry)entry;
693 memset(buf, 0, sizeof(buf));
694 snprintf(buf, sizeof(buf) - 1, "%s@%s",
695 client_entry->username, client_entry->hostname);
696 signal_emit("message topic", 5, server, channel->channel_name,
697 tmp, client_entry->nickname, buf);
698 } else if (idtype == SILC_ID_SERVER) {
699 server_entry = (SilcServerEntry)entry;
700 signal_emit("message topic", 5, server, channel->channel_name,
701 tmp, server_entry->server_name,
702 server_entry->server_name);
703 } else if (idtype == SILC_ID_CHANNEL) {
704 channel = (SilcChannelEntry)entry;
705 signal_emit("message topic", 5, server, channel->channel_name,
706 tmp, channel->channel_name, channel->channel_name);
710 case SILC_NOTIFY_TYPE_NICK_CHANGE:
715 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
717 client_entry = va_arg(va, SilcClientEntry);
718 client_entry2 = va_arg(va, SilcClientEntry);
720 if (!strcmp(client_entry->nickname, client_entry2->nickname))
723 memset(buf, 0, sizeof(buf));
724 snprintf(buf, sizeof(buf) - 1, "%s@%s",
725 client_entry2->username, client_entry2->hostname);
726 nicklist_rename_unique(SERVER(server),
727 client_entry, client_entry->nickname,
728 client_entry2, client_entry2->nickname);
729 signal_emit("message nick", 4, server, client_entry2->nickname,
730 client_entry->nickname, buf);
733 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
735 * Changed channel mode.
738 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
740 idtype = va_arg(va, int);
741 entry = va_arg(va, void *);
742 mode = va_arg(va, SilcUInt32);
743 (void)va_arg(va, char *); /* cipher */
744 (void)va_arg(va, char *); /* hmac */
745 (void)va_arg(va, char *); /* passphrase */
746 (void)va_arg(va, SilcPublicKey); /* founder key */
747 buffer = va_arg(va, SilcBuffer); /* channel public keys */
748 channel = va_arg(va, SilcChannelEntry);
750 tmp = silc_client_chmode(mode,
751 channel->channel_key ?
752 silc_cipher_get_name(channel->channel_key) : "",
754 silc_hmac_get_name(channel->hmac) : "");
756 chanrec = silc_channel_find_entry(server, channel);
757 if (chanrec != NULL) {
758 g_free_not_null(chanrec->mode);
759 chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
760 signal_emit("channel mode changed", 1, chanrec);
763 if (idtype == SILC_ID_CLIENT) {
764 client_entry = (SilcClientEntry)entry;
765 printformat_module("fe-common/silc", server, channel->channel_name,
766 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
767 channel->channel_name, tmp ? tmp : "removed all",
768 client_entry->nickname);
769 } else if (idtype == SILC_ID_SERVER) {
770 server_entry = (SilcServerEntry)entry;
771 printformat_module("fe-common/silc", server, channel->channel_name,
772 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
773 channel->channel_name, tmp ? tmp : "removed all",
774 server_entry->server_name);
775 } else if (idtype == SILC_ID_CHANNEL) {
776 channel2 = (SilcChannelEntry)entry;
777 printformat_module("fe-common/silc", server, channel->channel_name,
778 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
779 channel->channel_name, tmp ? tmp : "removed all",
780 channel2->channel_name);
783 /* Print the channel public key list */
785 silc_parse_channel_public_keys(server, channel, buffer);
790 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
792 * Changed user's mode on channel.
795 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
797 idtype = va_arg(va, int);
798 entry = va_arg(va, void *);
799 mode = va_arg(va, SilcUInt32);
800 client_entry2 = va_arg(va, SilcClientEntry);
801 channel = va_arg(va, SilcChannelEntry);
803 tmp = silc_client_chumode(mode);
804 chanrec = silc_channel_find_entry(server, channel);
805 if (chanrec != NULL) {
808 if (client_entry2 == server->conn->local_entry)
809 chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
811 nick = silc_nicklist_find(chanrec, client_entry2);
813 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
814 nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
815 signal_emit("nick mode changed", 2, chanrec, nick);
819 if (idtype == SILC_ID_CLIENT) {
820 client_entry = (SilcClientEntry)entry;
821 printformat_module("fe-common/silc", server, channel->channel_name,
822 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
823 channel->channel_name, client_entry2->nickname,
824 tmp ? tmp : "removed all",
825 client_entry->nickname);
826 } else if (idtype == SILC_ID_SERVER) {
827 server_entry = (SilcServerEntry)entry;
828 printformat_module("fe-common/silc", server, channel->channel_name,
829 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
830 channel->channel_name, client_entry2->nickname,
831 tmp ? tmp : "removed all",
832 server_entry->server_name);
833 } else if (idtype == SILC_ID_CHANNEL) {
834 channel2 = (SilcChannelEntry)entry;
835 printformat_module("fe-common/silc", server, channel->channel_name,
836 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
837 channel->channel_name, client_entry2->nickname,
838 tmp ? tmp : "removed all",
839 channel2->channel_name);
842 if (mode & SILC_CHANNEL_UMODE_CHANFO)
843 printformat_module("fe-common/silc",
844 server, channel->channel_name, MSGLEVEL_CRAP,
845 SILCTXT_CHANNEL_FOUNDER,
846 channel->channel_name, client_entry2->nickname);
848 if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
849 printformat_module("fe-common/silc",
850 server, channel->channel_name, MSGLEVEL_CRAP,
851 SILCTXT_CHANNEL_QUIETED, channel->channel_name);
856 case SILC_NOTIFY_TYPE_MOTD:
861 SILC_LOG_DEBUG(("Notify: MOTD"));
863 tmp = va_arg(va, char *);
865 if (!settings_get_bool("skip_motd"))
866 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
869 case SILC_NOTIFY_TYPE_KICKED:
871 * Someone was kicked from channel.
874 SILC_LOG_DEBUG(("Notify: KICKED"));
876 client_entry = va_arg(va, SilcClientEntry);
877 tmp = va_arg(va, char *);
878 client_entry2 = va_arg(va, SilcClientEntry);
879 channel = va_arg(va, SilcChannelEntry);
881 chanrec = silc_channel_find_entry(server, channel);
883 if (client_entry == conn->local_entry) {
884 printformat_module("fe-common/silc", server, channel->channel_name,
885 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
886 channel->channel_name,
887 client_entry ? client_entry2->nickname : "",
890 chanrec->kicked = TRUE;
891 channel_destroy((CHANNEL_REC *)chanrec);
894 printformat_module("fe-common/silc", server, channel->channel_name,
895 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
896 client_entry->nickname, channel->channel_name,
897 client_entry2 ? client_entry2->nickname : "",
901 SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
903 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
908 case SILC_NOTIFY_TYPE_KILLED:
910 * Someone was killed from the network.
913 SILC_LOG_DEBUG(("Notify: KILLED"));
915 client_entry = va_arg(va, SilcClientEntry);
916 tmp = va_arg(va, char *);
917 idtype = va_arg(va, int);
918 entry = va_arg(va, SilcClientEntry);
920 if (client_entry == conn->local_entry) {
921 if (idtype == SILC_ID_CLIENT) {
922 client_entry2 = (SilcClientEntry)entry;
923 printformat_module("fe-common/silc", server, NULL,
924 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
925 client_entry2 ? client_entry2->nickname : "",
927 } else if (idtype == SILC_ID_SERVER) {
928 server_entry = (SilcServerEntry)entry;
929 printformat_module("fe-common/silc", server, NULL,
930 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
931 server_entry->server_name, tmp ? tmp : "");
932 } else if (idtype == SILC_ID_CHANNEL) {
933 channel = (SilcChannelEntry)entry;
934 printformat_module("fe-common/silc", server, NULL,
935 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
936 channel->channel_name, tmp ? tmp : "");
939 list1 = nicklist_get_same_unique(SERVER(server), client_entry);
940 for (list_tmp = list1; list_tmp != NULL; list_tmp =
941 list_tmp->next->next) {
942 CHANNEL_REC *channel = list_tmp->data;
943 NICK_REC *nickrec = list_tmp->next->data;
944 nicklist_remove(channel, nickrec);
947 if (idtype == SILC_ID_CLIENT) {
948 client_entry2 = (SilcClientEntry)entry;
949 printformat_module("fe-common/silc", server, NULL,
950 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
951 client_entry->nickname,
952 client_entry2 ? client_entry2->nickname : "",
954 } else if (idtype == SILC_ID_SERVER) {
955 server_entry = (SilcServerEntry)entry;
956 printformat_module("fe-common/silc", server, NULL,
957 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
958 client_entry->nickname,
959 server_entry->server_name, tmp ? tmp : "");
960 } else if (idtype == SILC_ID_CHANNEL) {
961 channel = (SilcChannelEntry)entry;
962 printformat_module("fe-common/silc", server, NULL,
963 MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
964 client_entry->nickname,
965 channel->channel_name, tmp ? tmp : "");
970 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
973 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
976 * Server has quit the network.
979 SilcClientEntry *clients;
980 SilcUInt32 clients_count;
982 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
984 (void)va_arg(va, void *);
985 clients = va_arg(va, SilcClientEntry *);
986 clients_count = va_arg(va, SilcUInt32);
988 for (i = 0; i < clients_count; i++) {
989 memset(buf, 0, sizeof(buf));
991 /* Print only if we have the nickname. If this client has just quit
992 when we were only resolving it, it is possible we don't have the
994 if (clients[i]->nickname) {
995 if (clients[i]->username)
996 snprintf(buf, sizeof(buf) - 1, "%s@%s",
997 clients[i]->username, clients[i]->hostname);
998 signal_emit("message quit", 4, server, clients[i]->nickname,
999 clients[i]->username ? buf : "",
1003 silc_server_free_ftp(server, clients[i]);
1005 list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
1006 for (list_tmp = list1; list_tmp != NULL; list_tmp =
1007 list_tmp->next->next) {
1008 CHANNEL_REC *channel = list_tmp->data;
1009 NICK_REC *nickrec = list_tmp->next->data;
1010 nicklist_remove(channel, nickrec);
1016 case SILC_NOTIFY_TYPE_ERROR:
1018 SilcStatus error = va_arg(va, int);
1020 silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1021 "%s", silc_get_status_message(error));
1025 case SILC_NOTIFY_TYPE_WATCH:
1027 SilcNotifyType notify;
1029 client_entry = va_arg(va, SilcClientEntry);
1030 name = va_arg(va, char *); /* Maybe NULL */
1031 mode = va_arg(va, SilcUInt32);
1032 notify = va_arg(va, int);
1034 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
1036 printformat_module("fe-common/silc", server, NULL,
1037 MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
1038 client_entry->nickname, name);
1040 printformat_module("fe-common/silc", server, NULL,
1041 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1042 client_entry->nickname);
1043 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
1044 /* See if client was away and is now present */
1045 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
1046 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
1047 SILC_UMODE_DETACHED)) &&
1048 (client_entry->mode & SILC_UMODE_GONE ||
1049 client_entry->mode & SILC_UMODE_INDISPOSED ||
1050 client_entry->mode & SILC_UMODE_BUSY ||
1051 client_entry->mode & SILC_UMODE_PAGE ||
1052 client_entry->mode & SILC_UMODE_DETACHED)) {
1053 printformat_module("fe-common/silc", server, NULL,
1054 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1055 client_entry->nickname);
1059 memset(buf, 0, sizeof(buf));
1060 silc_get_umode_string(mode, buf, sizeof(buf) - 1);
1061 printformat_module("fe-common/silc", server, NULL,
1062 MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
1063 client_entry->nickname, buf);
1065 } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
1066 printformat_module("fe-common/silc", server, NULL,
1067 MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
1068 client_entry->nickname);
1069 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1070 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
1071 printformat_module("fe-common/silc", server, NULL,
1072 MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
1073 client_entry->nickname);
1074 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
1075 /* Client logged in to the network */
1076 printformat_module("fe-common/silc", server, NULL,
1077 MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
1078 client_entry->nickname);
1084 /* Unknown notify */
1085 printformat_module("fe-common/silc", server, NULL,
1086 MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
1093 /* Called to indicate that connection was either successfully established
1094 or connecting failed. This is also the first time application receives
1095 the SilcClientConnection object which it should save somewhere. */
1097 void silc_connect(SilcClient client, SilcClientConnection conn,
1098 SilcClientConnectionStatus status)
1100 SILC_SERVER_REC *server = conn->context;
1102 if (!server || server->disconnected) {
1103 silc_client_close_connection(client, conn);
1108 case SILC_CLIENT_CONN_SUCCESS:
1109 /* We have successfully connected to server */
1110 server->connected = TRUE;
1111 signal_emit("event connected", 1, server);
1114 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1115 /* We have successfully resumed old detached session */
1116 server->connected = TRUE;
1117 signal_emit("event connected", 1, server);
1119 /* If we resumed old session check whether we need to update
1121 if (strcmp(server->nick, conn->local_entry->nickname)) {
1123 old = g_strdup(server->nick);
1124 server_change_nick(SERVER(server), conn->local_entry->nickname);
1125 nicklist_rename_unique(SERVER(server),
1126 conn->local_entry, server->nick,
1127 conn->local_entry, conn->local_entry->nickname);
1128 signal_emit("message own_nick", 4, server, server->nick, old, "");
1134 server->connection_lost = TRUE;
1136 server->conn->context = NULL;
1137 server_disconnect(SERVER(server));
1142 /* Called to indicate that connection was disconnected to the server. */
1144 void silc_disconnect(SilcClient client, SilcClientConnection conn,
1145 SilcStatus status, const char *message)
1147 SILC_SERVER_REC *server = conn->context;
1149 SILC_LOG_DEBUG(("Start"));
1151 if (!server || server->connection_lost)
1154 if (server->conn && server->conn->local_entry) {
1155 nicklist_rename_unique(SERVER(server),
1156 server->conn->local_entry, server->nick,
1157 server->conn->local_entry,
1158 silc_client->username);
1159 silc_change_nick(server, silc_client->username);
1163 silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
1164 "Server closed connection: %s (%d) %s",
1165 silc_get_status_message(status), status,
1166 message ? message : "");
1169 server->conn->context = NULL;
1170 server->conn = NULL;
1171 server->connection_lost = TRUE;
1172 server_disconnect(SERVER(server));
1175 /* Command handler. This function is called always in the command function.
1176 If error occurs it will be called as well. `conn' is the associated
1177 client connection. `cmd_context' is the command context that was
1178 originally sent to the command. `success' is FALSE if error occured
1179 during command. `command' is the command being processed. It must be
1180 noted that this is not reply from server. This is merely called just
1181 after application has called the command. Just to tell application
1182 that the command really was processed. */
1184 static bool cmode_list_chpks = FALSE;
1186 void silc_command(SilcClient client, SilcClientConnection conn,
1187 SilcClientCommandContext cmd_context, bool success,
1188 SilcCommand command, SilcStatus status)
1190 SILC_SERVER_REC *server = conn->context;
1192 SILC_LOG_DEBUG(("Start"));
1195 silc_say_error("%s", silc_get_status_message(status));
1201 case SILC_COMMAND_INVITE:
1202 if (cmd_context->argc > 2)
1203 printformat_module("fe-common/silc", server, NULL,
1204 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
1205 cmd_context->argv[2],
1206 (cmd_context->argv[1][0] == '*' ?
1207 (char *)conn->current_channel->channel_name :
1208 (char *)cmd_context->argv[1]));
1211 case SILC_COMMAND_DETACH:
1212 server->no_reconnect = TRUE;
1215 case SILC_COMMAND_CMODE:
1216 if (cmd_context->argc == 3 &&
1217 !strcmp(cmd_context->argv[2], "+C"))
1218 cmode_list_chpks = TRUE;
1220 cmode_list_chpks = FALSE;
1229 SilcChannelEntry channel;
1233 /* Client info resolving callback when JOIN command reply is received.
1234 This will cache all users on the channel. */
1236 static void silc_client_join_get_users(SilcClient client,
1237 SilcClientConnection conn,
1238 SilcClientEntry *clients,
1239 SilcUInt32 clients_count,
1242 SilcJoinResolve r = context;
1243 SilcChannelEntry channel = r->channel;
1244 SilcHashTableList htl;
1245 SilcChannelUser chu;
1246 SILC_SERVER_REC *server = conn->context;
1247 SILC_CHANNEL_REC *chanrec;
1248 SilcClientEntry founder = NULL;
1251 SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
1252 silc_hash_table_count(channel->user_list)));
1254 if (!clients && r->retry < 1) {
1255 /* Retry to resolve */
1256 silc_client_get_clients_by_channel(client, conn, channel,
1257 silc_client_join_get_users, context);
1262 chanrec = silc_channel_find(server, channel->channel_name);
1263 if (chanrec == NULL)
1266 silc_hash_table_list(channel->user_list, &htl);
1267 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1268 if (!chu->client->nickname)
1270 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1271 founder = chu->client;
1272 silc_nicklist_insert(chanrec, chu, FALSE);
1274 silc_hash_table_list_reset(&htl);
1276 ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
1277 nicklist_set_own(CHANNEL(chanrec), ownnick);
1278 signal_emit("channel joined", 1, chanrec);
1279 chanrec->entry = channel;
1282 printformat_module("fe-common/silc", server, channel->channel_name,
1283 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
1284 channel->channel_name, chanrec->topic);
1287 if (founder == conn->local_entry) {
1288 printformat_module("fe-common/silc",
1289 server, channel->channel_name, MSGLEVEL_CRAP,
1290 SILCTXT_CHANNEL_FOUNDER_YOU,
1291 channel->channel_name);
1292 signal_emit("nick mode changed", 2, chanrec, ownnick);
1294 printformat_module("fe-common/silc",
1295 server, channel->channel_name, MSGLEVEL_CRAP,
1296 SILCTXT_CHANNEL_FOUNDER,
1297 channel->channel_name, founder->nickname);
1303 SilcClientConnection conn;
1309 void silc_getkey_cb(bool success, void *context)
1311 GetkeyContext getkey = (GetkeyContext)context;
1312 char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
1313 char *name = (getkey->id_type == SILC_ID_CLIENT ?
1314 ((SilcClientEntry)getkey->entry)->nickname :
1315 ((SilcServerEntry)getkey->entry)->server_name);
1318 printformat_module("fe-common/silc", NULL, NULL,
1319 MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
1321 printformat_module("fe-common/silc", NULL, NULL,
1322 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
1326 silc_free(getkey->fingerprint);
1330 /* Parse an invite or ban list */
1331 void silc_parse_inviteban_list(SilcClient client,
1332 SilcClientConnection conn,
1333 SILC_SERVER_REC *server,
1334 SilcChannelEntry channel,
1335 const char *list_type,
1336 SilcArgumentPayload list)
1339 SilcUInt32 type, len;
1340 SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
1341 int counter=0, resolving = FALSE;
1343 if (!silc_argument_get_arg_num(list)) {
1344 printformat_module("fe-common/silc", server,
1345 (chanrec ? chanrec->visible_name : NULL),
1346 MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
1347 channel->channel_name, list_type);
1351 printformat_module("fe-common/silc", server,
1352 (chanrec ? chanrec->visible_name : NULL),
1353 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
1354 channel->channel_name, list_type);
1356 /* parse the list */
1357 tmp = silc_argument_get_first_arg(list, &type, &len);
1362 /* an invite string */
1366 if (tmp[len-1] == ',')
1369 list = g_strsplit(tmp, ",", -1);
1371 printformat_module("fe-common/silc", server,
1372 (chanrec ? chanrec->visible_name : NULL),
1373 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1374 ++counter, channel->channel_name, list_type,
1383 char *fingerprint, *babbleprint;
1385 /* tmp is Public Key Payload, take public key from it. */
1386 fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
1387 babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
1389 printformat_module("fe-common/silc", server,
1390 (chanrec ? chanrec->visible_name : NULL),
1391 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
1392 ++counter, channel->channel_name, list_type,
1393 fingerprint, babbleprint);
1400 SilcClientID *client_id;
1401 SilcClientEntry client_entry;
1403 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1405 if (client_id == NULL) {
1406 silc_say_error("Invalid data in %s list encountered", list_type);
1410 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1413 printformat_module("fe-common/silc", server,
1414 (chanrec ? chanrec->visible_name : NULL),
1415 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
1416 ++counter, channel->channel_name, list_type,
1417 client_entry->nickname);
1420 silc_client_get_client_by_id_resolve(client, conn, client_id,
1424 silc_free(client_id);
1430 silc_say_error("Unkown type in %s list: %u (len %u)",
1431 list_type, type, len);
1433 tmp = silc_argument_get_next_arg(list, &type, &len);
1437 printformat_module("fe-common/silc", server,
1438 (chanrec ? chanrec->visible_name : NULL),
1439 MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
1440 list_type, channel->channel_name);
1443 /* Command reply handler. This function is called always in the command reply
1444 function. If error occurs it will be called as well. Normal scenario
1445 is that it will be called after the received command data has been parsed
1446 and processed. The function is used to pass the received command data to
1449 `conn' is the associated client connection. `cmd_payload' is the command
1450 payload data received from server and it can be ignored. It is provided
1451 if the application would like to re-parse the received command data,
1452 however, it must be noted that the data is parsed already by the library
1453 thus the payload can be ignored. `success' is FALSE if error occured.
1454 In this case arguments are not sent to the application. `command' is the
1455 command reply being processed. The function has variable argument list
1456 and each command defines the number and type of arguments it passes to the
1457 application (on error they are not sent). */
1460 silc_command_reply(SilcClient client, SilcClientConnection conn,
1461 SilcCommandPayload cmd_payload, bool success,
1462 SilcCommand command, SilcStatus status, ...)
1465 SILC_SERVER_REC *server = conn->context;
1466 SILC_CHANNEL_REC *chanrec;
1469 va_start(vp, status);
1471 SILC_LOG_DEBUG(("Start"));
1474 case SILC_COMMAND_WHOIS:
1476 char buf[1024], *nickname, *username, *realname, *nick;
1477 unsigned char *fingerprint;
1478 SilcUInt32 idle, mode;
1479 SilcBuffer channels, user_modes;
1480 SilcClientEntry client_entry;
1483 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1484 /* Print the unknown nick for user */
1485 unsigned char *tmp =
1486 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1489 silc_say_error("%s: %s", tmp,
1490 silc_get_status_message(status));
1492 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1493 /* Try to find the entry for the unknown client ID, since we
1494 might have, and print the nickname of it for user. */
1496 unsigned char *tmp =
1497 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1500 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1503 client_entry = silc_client_get_client_by_id(client, conn,
1505 if (client_entry && client_entry->nickname)
1506 silc_say_error("%s: %s", client_entry->nickname,
1507 silc_get_status_message(status));
1508 silc_free(client_id);
1512 } else if (!success) {
1513 silc_say_error("WHOIS: %s", silc_get_status_message(status));
1517 client_entry = va_arg(vp, SilcClientEntry);
1518 nickname = va_arg(vp, char *);
1519 username = va_arg(vp, char *);
1520 realname = va_arg(vp, char *);
1521 channels = va_arg(vp, SilcBuffer);
1522 mode = va_arg(vp, SilcUInt32);
1523 idle = va_arg(vp, SilcUInt32);
1524 fingerprint = va_arg(vp, unsigned char *);
1525 user_modes = va_arg(vp, SilcBuffer);
1526 attrs = va_arg(vp, SilcDList);
1528 silc_parse_userfqdn(nickname, &nick, NULL);
1529 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1530 SILCTXT_WHOIS_USERINFO, nickname,
1531 client_entry->username, client_entry->hostname,
1532 nick, client_entry->nickname);
1533 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1534 SILCTXT_WHOIS_REALNAME, realname);
1537 if (channels && user_modes) {
1539 SilcDList list = silc_channel_payload_parse_list(channels->data,
1541 if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
1543 SilcChannelPayload entry;
1546 memset(buf, 0, sizeof(buf));
1547 silc_dlist_start(list);
1548 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
1549 SilcUInt32 name_len;
1550 char *m = silc_client_chumode_char(umodes[i++]);
1551 char *name = silc_channel_get_name(entry, &name_len);
1554 silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
1555 silc_strncat(buf, sizeof(buf) - 1, name, name_len);
1556 silc_strncat(buf, sizeof(buf) - 1, " ", 1);
1560 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1561 SILCTXT_WHOIS_CHANNELS, buf);
1562 silc_channel_payload_list_free(list);
1568 memset(buf, 0, sizeof(buf));
1569 silc_get_umode_string(mode, buf, sizeof(buf - 1));
1570 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1571 SILCTXT_WHOIS_MODES, buf);
1574 if (idle && nickname) {
1575 memset(buf, 0, sizeof(buf));
1576 snprintf(buf, sizeof(buf) - 1, "%lu %s",
1577 idle > 60 ? (idle / 60) : idle,
1578 idle > 60 ? "minutes" : "seconds");
1580 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1581 SILCTXT_WHOIS_IDLE, buf);
1585 fingerprint = silc_fingerprint(fingerprint, 20);
1586 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1587 SILCTXT_WHOIS_FINGERPRINT, fingerprint);
1588 silc_free(fingerprint);
1592 silc_query_attributes_print(server, silc_client, conn, attrs,
1597 case SILC_COMMAND_IDENTIFY:
1599 SilcClientEntry client_entry;
1601 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
1602 /* Print the unknown nick for user */
1603 unsigned char *tmp =
1604 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1607 silc_say_error("%s: %s", tmp,
1608 silc_get_status_message(status));
1610 } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1611 /* Try to find the entry for the unknown client ID, since we
1612 might have, and print the nickname of it for user. */
1614 unsigned char *tmp =
1615 silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1618 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
1621 client_entry = silc_client_get_client_by_id(client, conn,
1623 if (client_entry && client_entry->nickname)
1624 silc_say_error("%s: %s", client_entry->nickname,
1625 silc_get_status_message(status));
1626 silc_free(client_id);
1635 case SILC_COMMAND_WHOWAS:
1637 char *nickname, *username, *realname;
1639 if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
1640 status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1642 tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
1645 silc_say_error("%s: %s", tmp,
1646 silc_get_status_message(status));
1648 } else if (!success) {
1649 silc_say_error("WHOWAS: %s", silc_get_status_message(status));
1653 (void)va_arg(vp, SilcClientEntry);
1654 nickname = va_arg(vp, char *);
1655 username = va_arg(vp, char *);
1656 realname = va_arg(vp, char *);
1658 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1659 SILCTXT_WHOWAS_USERINFO, nickname, username,
1660 realname ? realname : "");
1664 case SILC_COMMAND_INVITE:
1666 SilcChannelEntry channel;
1668 SilcArgumentPayload invite_list;
1674 channel = va_arg(vp, SilcChannelEntry);
1675 payload = va_arg(vp, SilcBuffer);
1678 SILC_GET16_MSB(argc, payload->data);
1679 invite_list = silc_argument_payload_parse(payload->data + 2,
1680 payload->len - 2, argc);
1682 silc_parse_inviteban_list(client, conn, server, channel,
1683 "invite", invite_list);
1684 silc_argument_payload_free(invite_list);
1690 case SILC_COMMAND_JOIN:
1692 char *channel, *mode, *topic;
1694 SilcChannelEntry channel_entry;
1695 SilcBuffer client_id_list;
1696 SilcUInt32 list_count;
1701 channel = va_arg(vp, char *);
1702 channel_entry = va_arg(vp, SilcChannelEntry);
1703 modei = va_arg(vp, SilcUInt32);
1704 (void)va_arg(vp, SilcUInt32);
1705 (void)va_arg(vp, unsigned char *);
1706 (void)va_arg(vp, unsigned char *);
1707 (void)va_arg(vp, unsigned char *);
1708 topic = va_arg(vp, char *);
1709 (void)va_arg(vp, unsigned char *);
1710 list_count = va_arg(vp, SilcUInt32);
1711 client_id_list = va_arg(vp, SilcBuffer);
1713 chanrec = silc_channel_find(server, channel);
1715 chanrec = silc_channel_create(server, channel, channel, TRUE);
1718 char tmp[256], *cp, *dm = NULL;
1719 g_free_not_null(chanrec->topic);
1721 if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
1722 memset(tmp, 0, sizeof(tmp));
1724 if (strlen(topic) > sizeof(tmp) - 1) {
1725 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1729 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1734 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
1735 signal_emit("channel topic changed", 1, chanrec);
1740 mode = silc_client_chmode(modei,
1741 channel_entry->channel_key ?
1742 silc_cipher_get_name(channel_entry->
1744 channel_entry->hmac ?
1745 silc_hmac_get_name(channel_entry->hmac) : "");
1746 g_free_not_null(chanrec->mode);
1747 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
1748 signal_emit("channel mode changed", 1, chanrec);
1750 /* Resolve the client information */
1752 SilcJoinResolve r = silc_calloc(1, sizeof(*r));
1753 r->channel = channel_entry;
1754 silc_client_get_clients_by_list(client, conn, list_count,
1756 silc_client_join_get_users, r);
1762 case SILC_COMMAND_NICK:
1765 SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
1771 nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
1772 if ((nicks != NULL) &&
1773 (strcmp(SERVER(server)->nick, client_entry->nickname))) {
1775 SilcClientEntry collider, old;
1777 old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
1778 collider = silc_client_get_client_by_id(client, conn,
1781 memset(buf, 0, sizeof(buf));
1782 snprintf(buf, sizeof(buf) - 1, "%s@%s",
1783 collider->username, collider->hostname);
1784 nicklist_rename_unique(SERVER(server),
1786 collider, collider->nickname);
1787 silc_print_nick_change(server, collider->nickname,
1788 client_entry->nickname, buf);
1789 g_slist_free(nicks);
1792 old = g_strdup(server->nick);
1793 server_change_nick(SERVER(server), client_entry->nickname);
1794 nicklist_rename_unique(SERVER(server),
1795 server->conn->local_entry, server->nick,
1796 client_entry, client_entry->nickname);
1797 signal_emit("message own_nick", 4, server, server->nick, old, "");
1802 case SILC_COMMAND_LIST:
1807 char tmp[256], *cp, *dm = NULL;
1812 (void)va_arg(vp, SilcChannelEntry);
1813 name = va_arg(vp, char *);
1814 topic = va_arg(vp, char *);
1815 usercount = va_arg(vp, int);
1817 if (topic && !silc_term_utf8() &&
1818 silc_utf8_valid(topic, strlen(topic))) {
1819 memset(tmp, 0, sizeof(tmp));
1821 if (strlen(topic) > sizeof(tmp) - 1) {
1822 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
1826 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
1831 if (status == SILC_STATUS_LIST_START ||
1832 status == SILC_STATUS_OK)
1833 printformat_module("fe-common/silc", server, NULL,
1834 MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
1837 snprintf(users, sizeof(users) - 1, "N/A");
1839 snprintf(users, sizeof(users) - 1, "%d", usercount);
1840 printformat_module("fe-common/silc", server, NULL,
1841 MSGLEVEL_CRAP, SILCTXT_LIST,
1842 name, users, topic ? topic : "");
1847 case SILC_COMMAND_UMODE:
1855 mode = va_arg(vp, SilcUInt32);
1857 if (mode & SILC_UMODE_SERVER_OPERATOR &&
1858 !(server->umode & SILC_UMODE_SERVER_OPERATOR))
1859 printformat_module("fe-common/silc", server, NULL,
1860 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1862 if (mode & SILC_UMODE_ROUTER_OPERATOR &&
1863 !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
1864 printformat_module("fe-common/silc", server, NULL,
1865 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1867 if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
1868 if (mode & SILC_UMODE_GONE) {
1869 if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
1870 reason = g_strdup(server->away_reason);
1872 reason = g_strdup("away");
1874 reason = g_strdup("");
1876 silc_set_away(reason, server);
1881 server->umode = mode;
1882 signal_emit("user mode changed", 2, server, NULL);
1886 case SILC_COMMAND_OPER:
1890 server->umode |= SILC_UMODE_SERVER_OPERATOR;
1891 signal_emit("user mode changed", 2, server, NULL);
1893 printformat_module("fe-common/silc", server, NULL,
1894 MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
1897 case SILC_COMMAND_SILCOPER:
1901 server->umode |= SILC_UMODE_ROUTER_OPERATOR;
1902 signal_emit("user mode changed", 2, server, NULL);
1904 printformat_module("fe-common/silc", server, NULL,
1905 MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
1908 case SILC_COMMAND_USERS:
1910 SilcHashTableList htl;
1911 SilcChannelEntry channel;
1912 SilcChannelUser chu;
1917 channel = va_arg(vp, SilcChannelEntry);
1919 printformat_module("fe-common/silc", server, channel->channel_name,
1920 MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
1921 channel->channel_name);
1923 silc_hash_table_list(channel->user_list, &htl);
1924 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1925 SilcClientEntry e = chu->client;
1926 char stat[5], *mode;
1931 memset(stat, 0, sizeof(stat));
1932 mode = silc_client_chumode_char(chu->mode);
1933 if (e->mode & SILC_UMODE_GONE)
1935 else if (e->mode & SILC_UMODE_INDISPOSED)
1937 else if (e->mode & SILC_UMODE_BUSY)
1939 else if (e->mode & SILC_UMODE_PAGE)
1941 else if (e->mode & SILC_UMODE_HYPER)
1943 else if (e->mode & SILC_UMODE_ROBOT)
1945 else if (e->mode & SILC_UMODE_ANONYMOUS)
1952 printformat_module("fe-common/silc", server, channel->channel_name,
1953 MSGLEVEL_CRAP, SILCTXT_USERS,
1955 e->username ? e->username : "",
1956 e->hostname ? e->hostname : "",
1957 e->realname ? e->realname : "");
1961 silc_hash_table_list_reset(&htl);
1965 case SILC_COMMAND_BAN:
1967 SilcChannelEntry channel;
1969 SilcArgumentPayload ban_list;
1975 channel = va_arg(vp, SilcChannelEntry);
1976 payload = va_arg(vp, SilcBuffer);
1979 SILC_GET16_MSB(argc, payload->data);
1980 ban_list = silc_argument_payload_parse(payload->data + 2,
1981 payload->len - 2, argc);
1983 silc_parse_inviteban_list(client, conn, server, channel,
1985 silc_argument_payload_free(ban_list);
1991 case SILC_COMMAND_GETKEY:
1995 SilcPublicKey public_key;
1998 GetkeyContext getkey;
2004 id_type = va_arg(vp, SilcUInt32);
2005 entry = va_arg(vp, void *);
2006 public_key = va_arg(vp, SilcPublicKey);
2009 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
2011 getkey = silc_calloc(1, sizeof(*getkey));
2012 getkey->entry = entry;
2013 getkey->id_type = id_type;
2014 getkey->client = client;
2015 getkey->conn = conn;
2016 getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2018 name = (id_type == SILC_ID_CLIENT ?
2019 ((SilcClientEntry)entry)->nickname :
2020 ((SilcServerEntry)entry)->server_name);
2022 silc_verify_public_key_internal(client, conn, name,
2023 (id_type == SILC_ID_CLIENT ?
2024 SILC_SOCKET_TYPE_CLIENT :
2025 SILC_SOCKET_TYPE_SERVER),
2026 pk, pk_len, SILC_SKE_PK_TYPE_SILC,
2027 silc_getkey_cb, getkey);
2030 printformat_module("fe-common/silc", server, NULL,
2031 MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
2036 case SILC_COMMAND_INFO:
2038 SilcServerEntry server_entry;
2045 server_entry = va_arg(vp, SilcServerEntry);
2046 server_name = va_arg(vp, char *);
2047 server_info = va_arg(vp, char *);
2049 if (server_name && server_info )
2051 printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
2052 printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
2057 case SILC_COMMAND_TOPIC:
2059 SilcChannelEntry channel;
2061 char tmp[256], *cp, *dm = NULL;
2066 channel = va_arg(vp, SilcChannelEntry);
2067 topic = va_arg(vp, char *);
2069 if (topic && !silc_term_utf8() &&
2070 silc_utf8_valid(topic, strlen(topic))) {
2071 memset(tmp, 0, sizeof(tmp));
2073 if (strlen(topic) > sizeof(tmp) - 1) {
2074 dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
2078 silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
2084 chanrec = silc_channel_find_entry(server, channel);
2086 g_free_not_null(chanrec->topic);
2087 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
2088 signal_emit("channel topic changed", 1, chanrec);
2090 printformat_module("fe-common/silc", server, channel->channel_name,
2091 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
2092 channel->channel_name, topic);
2094 printformat_module("fe-common/silc", server, channel->channel_name,
2095 MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
2096 channel->channel_name);
2102 case SILC_COMMAND_WATCH:
2105 case SILC_COMMAND_STATS:
2107 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
2108 my_router_ops, cell_clients, cell_channels, cell_servers,
2109 clients, channels, servers, routers, server_ops, router_ops;
2111 SilcBufferStruct buf;
2112 unsigned char *tmp_buf;
2114 const char *tmptime;
2115 int days, hours, mins, secs;
2120 tmp_buf = va_arg(vp, unsigned char *);
2121 buf_len = va_arg(vp, SilcUInt32);
2123 if (!tmp_buf || !buf_len) {
2124 printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
2128 /* Get statistics structure */
2129 silc_buffer_set(&buf, tmp_buf, buf_len);
2130 silc_buffer_unformat(&buf,
2131 SILC_STR_UI_INT(&starttime),
2132 SILC_STR_UI_INT(&uptime),
2133 SILC_STR_UI_INT(&my_clients),
2134 SILC_STR_UI_INT(&my_channels),
2135 SILC_STR_UI_INT(&my_server_ops),
2136 SILC_STR_UI_INT(&my_router_ops),
2137 SILC_STR_UI_INT(&cell_clients),
2138 SILC_STR_UI_INT(&cell_channels),
2139 SILC_STR_UI_INT(&cell_servers),
2140 SILC_STR_UI_INT(&clients),
2141 SILC_STR_UI_INT(&channels),
2142 SILC_STR_UI_INT(&servers),
2143 SILC_STR_UI_INT(&routers),
2144 SILC_STR_UI_INT(&server_ops),
2145 SILC_STR_UI_INT(&router_ops),
2148 tmptime = silc_get_time(starttime);
2149 printformat_module("fe-common/silc", server, NULL,
2150 MSGLEVEL_CRAP, SILCTXT_STATS,
2151 "Local server start time", tmptime);
2153 days = uptime / (24 * 60 * 60);
2154 uptime -= days * (24 * 60 * 60);
2155 hours = uptime / (60 * 60);
2156 uptime -= hours * (60 * 60);
2158 uptime -= mins * 60;
2160 snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
2161 days, hours, mins, secs);
2162 printformat_module("fe-common/silc", server, NULL,
2163 MSGLEVEL_CRAP, SILCTXT_STATS,
2164 "Local server uptime", tmp);
2166 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
2167 printformat_module("fe-common/silc", server, NULL,
2168 MSGLEVEL_CRAP, SILCTXT_STATS,
2169 "Local server clients", tmp);
2171 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
2172 printformat_module("fe-common/silc", server, NULL,
2173 MSGLEVEL_CRAP, SILCTXT_STATS,
2174 "Local server channels", tmp);
2176 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
2177 printformat_module("fe-common/silc", server, NULL,
2178 MSGLEVEL_CRAP, SILCTXT_STATS,
2179 "Local server operators", tmp);
2181 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
2182 printformat_module("fe-common/silc", server, NULL,
2183 MSGLEVEL_CRAP, SILCTXT_STATS,
2184 "Local router operators", tmp);
2186 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
2187 printformat_module("fe-common/silc", server, NULL,
2188 MSGLEVEL_CRAP, SILCTXT_STATS,
2189 "Local cell clients", tmp);
2191 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
2192 printformat_module("fe-common/silc", server, NULL,
2193 MSGLEVEL_CRAP, SILCTXT_STATS,
2194 "Local cell channels", tmp);
2196 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
2197 printformat_module("fe-common/silc", server, NULL,
2198 MSGLEVEL_CRAP, SILCTXT_STATS,
2199 "Local cell servers", tmp);
2201 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
2202 printformat_module("fe-common/silc", server, NULL,
2203 MSGLEVEL_CRAP, SILCTXT_STATS,
2204 "Total clients", tmp);
2206 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
2207 printformat_module("fe-common/silc", server, NULL,
2208 MSGLEVEL_CRAP, SILCTXT_STATS,
2209 "Total channels", tmp);
2211 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
2212 printformat_module("fe-common/silc", server, NULL,
2213 MSGLEVEL_CRAP, SILCTXT_STATS,
2214 "Total servers", tmp);
2216 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
2217 printformat_module("fe-common/silc", server, NULL,
2218 MSGLEVEL_CRAP, SILCTXT_STATS,
2219 "Total routers", tmp);
2221 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
2222 printformat_module("fe-common/silc", server, NULL,
2223 MSGLEVEL_CRAP, SILCTXT_STATS,
2224 "Total server operators", tmp);
2226 snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
2227 printformat_module("fe-common/silc", server, NULL,
2228 MSGLEVEL_CRAP, SILCTXT_STATS,
2229 "Total router operators", tmp);
2233 case SILC_COMMAND_CMODE:
2235 SilcChannelEntry channel_entry;
2236 SilcBuffer channel_pubkeys;
2238 channel_entry = va_arg(vp, SilcChannelEntry);
2239 (void)va_arg(vp, SilcUInt32);
2240 (void)va_arg(vp, SilcPublicKey);
2241 channel_pubkeys = va_arg(vp, SilcBuffer);
2243 if (!success || !cmode_list_chpks ||
2244 !channel_entry || !channel_entry->channel_name)
2247 /* Print the channel public key list */
2248 if (channel_pubkeys)
2249 silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
2251 printformat_module("fe-common/silc", server, NULL,
2252 MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
2253 channel_entry->channel_name);
2264 SilcClientConnection conn;
2270 SilcSKEPKType pk_type;
2271 SilcVerifyPublicKey completion;
2275 static void verify_public_key_completion(const char *line, void *context)
2277 PublicKeyVerify verify = (PublicKeyVerify)context;
2279 if (line[0] == 'Y' || line[0] == 'y') {
2280 /* Call the completion */
2281 if (verify->completion)
2282 verify->completion(TRUE, verify->context);
2284 /* Save the key for future checking */
2285 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
2286 verify->pk_len, SILC_PKCS_FILE_PEM);
2288 /* Call the completion */
2289 if (verify->completion)
2290 verify->completion(FALSE, verify->context);
2292 printformat_module("fe-common/silc", NULL, NULL,
2293 MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
2294 verify->entity_name ? verify->entity_name :
2298 silc_free(verify->filename);
2299 silc_free(verify->entity);
2300 silc_free(verify->entity_name);
2301 silc_free(verify->pk);
2305 /* Internal routine to verify public key. If the `completion' is provided
2306 it will be called to indicate whether public was verified or not. For
2307 server/router public key this will check for filename that includes the
2308 remote host's IP address and remote host's hostname. */
2311 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
2312 const char *name, SilcSocketType conn_type,
2313 unsigned char *pk, SilcUInt32 pk_len,
2314 SilcSKEPKType pk_type,
2315 SilcVerifyPublicKey completion, void *context)
2318 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
2319 char *fingerprint, *babbleprint, *format;
2322 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
2323 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
2324 "server" : "client");
2325 PublicKeyVerify verify;
2327 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
2328 printformat_module("fe-common/silc", NULL, NULL,
2329 MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
2332 completion(FALSE, context);
2336 pw = getpwuid(getuid());
2339 completion(FALSE, context);
2343 memset(filename, 0, sizeof(filename));
2344 memset(filename2, 0, sizeof(filename2));
2345 memset(file, 0, sizeof(file));
2347 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
2348 conn_type == SILC_SOCKET_TYPE_ROUTER) {
2350 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2351 conn->sock->ip, conn->sock->port);
2352 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2353 get_irssi_dir(), entity, file);
2355 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2356 conn->sock->hostname, conn->sock->port);
2357 snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
2358 get_irssi_dir(), entity, file);
2363 snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
2364 name, conn->sock->port);
2365 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2366 get_irssi_dir(), entity, file);
2371 /* Replace all whitespaces with `_'. */
2372 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2373 for (i = 0; i < strlen(fingerprint); i++)
2374 if (fingerprint[i] == ' ')
2375 fingerprint[i] = '_';
2377 snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
2378 snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
2379 get_irssi_dir(), entity, file);
2380 silc_free(fingerprint);
2385 /* Take fingerprint of the public key */
2386 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
2387 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
2389 verify = silc_calloc(1, sizeof(*verify));
2390 verify->client = client;
2391 verify->conn = conn;
2392 verify->filename = strdup(ipf);
2393 verify->entity = strdup(entity);
2394 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
2395 (name ? strdup(name) : strdup(conn->sock->hostname))
2397 verify->pk = silc_memdup(pk, pk_len);
2398 verify->pk_len = pk_len;
2399 verify->pk_type = pk_type;
2400 verify->completion = completion;
2401 verify->context = context;
2403 /* Check whether this key already exists */
2404 if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
2405 /* Key does not exist, ask user to verify the key and save it */
2407 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2408 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2409 verify->entity_name : entity);
2410 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2411 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2412 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2413 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2414 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2415 SILCTXT_PUBKEY_ACCEPT);
2416 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2419 silc_free(fingerprint);
2422 /* The key already exists, verify it. */
2423 SilcPublicKey public_key;
2424 unsigned char *encpk;
2425 SilcUInt32 encpk_len;
2427 /* Load the key file, try for both IP filename and hostname filename */
2428 if (!silc_pkcs_load_public_key(ipf, &public_key,
2429 SILC_PKCS_FILE_PEM) &&
2430 !silc_pkcs_load_public_key(ipf, &public_key,
2431 SILC_PKCS_FILE_BIN) &&
2432 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
2433 SILC_PKCS_FILE_PEM) &&
2434 !silc_pkcs_load_public_key(hostf, &public_key,
2435 SILC_PKCS_FILE_BIN)))) {
2436 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2437 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2438 verify->entity_name : entity);
2439 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2440 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2441 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2442 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2443 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2444 SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
2445 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2446 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2447 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2450 silc_free(fingerprint);
2454 /* Encode the key data */
2455 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
2457 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2458 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2459 verify->entity_name : entity);
2460 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2461 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2462 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2463 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2464 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2465 SILCTXT_PUBKEY_MALFORMED, entity);
2466 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2467 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2468 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2471 silc_free(fingerprint);
2475 /* Compare the keys */
2476 if (memcmp(encpk, pk, encpk_len)) {
2477 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2478 SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
2479 verify->entity_name : entity);
2480 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2481 SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
2482 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2483 SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
2484 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2485 SILCTXT_PUBKEY_NO_MATCH, entity);
2486 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2487 SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
2488 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2489 SILCTXT_PUBKEY_MITM_ATTACK, entity);
2491 /* Ask user to verify the key and save it */
2492 format = format_get_text("fe-common/silc", NULL, NULL, NULL,
2493 SILCTXT_PUBKEY_ACCEPT_ANYWAY);
2494 keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
2497 silc_free(fingerprint);
2501 /* Local copy matched */
2503 completion(TRUE, context);
2504 silc_free(fingerprint);
2505 silc_free(verify->filename);
2506 silc_free(verify->entity);
2507 silc_free(verify->entity_name);
2508 silc_free(verify->pk);
2513 /* Verifies received public key. The `conn_type' indicates which entity
2514 (server, client etc.) has sent the public key. If user decides to trust
2515 the key may be saved as trusted public key for later use. The
2516 `completion' must be called after the public key has been verified. */
2519 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
2520 SilcSocketType conn_type, unsigned char *pk,
2521 SilcUInt32 pk_len, SilcSKEPKType pk_type,
2522 SilcVerifyPublicKey completion, void *context)
2524 silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
2526 completion, context);
2529 /* Asks passphrase from user on the input line. */
2532 SilcAskPassphrase completion;
2536 void ask_passphrase_completion(const char *passphrase, void *context)
2538 AskPassphrase p = (AskPassphrase)context;
2539 if (passphrase && passphrase[0] == '\0')
2541 p->completion((unsigned char *)passphrase,
2542 passphrase ? strlen(passphrase) : 0, p->context);
2546 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
2547 SilcAskPassphrase completion, void *context)
2549 AskPassphrase p = silc_calloc(1, sizeof(*p));
2550 p->completion = completion;
2551 p->context = context;
2553 keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
2554 "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
2558 SilcGetAuthMeth completion;
2560 } *InternalGetAuthMethod;
2562 /* Callback called when we've received the authentication method information
2563 from the server after we've requested it. This will get the authentication
2564 data from the user if needed. */
2566 static void silc_get_auth_method_callback(SilcClient client,
2567 SilcClientConnection conn,
2568 SilcAuthMethod auth_meth,
2571 InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
2573 SILC_LOG_DEBUG(("Start"));
2575 switch (auth_meth) {
2576 case SILC_AUTH_NONE:
2577 /* No authentication required. */
2578 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2580 case SILC_AUTH_PASSWORD:
2582 /* Check whether we find the password for this server in our
2583 configuration. If not, then don't provide so library will ask
2584 it from the user. */
2585 SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
2587 if (!setup || !setup->password) {
2588 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2592 (*internal->completion)(TRUE, auth_meth, setup->password,
2593 strlen(setup->password), internal->context);
2596 case SILC_AUTH_PUBLIC_KEY:
2597 /* Do not get the authentication data now, the library will generate
2598 it using our default key, if we do not provide it here. */
2599 /* XXX In the future when we support multiple local keys and multiple
2600 local certificates we will need to ask from user which one to use. */
2601 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
2605 silc_free(internal);
2608 /* Find authentication method and authentication data by hostname and
2609 port. The hostname may be IP address as well. The found authentication
2610 method and authentication data is returned to `auth_meth', `auth_data'
2611 and `auth_data_len'. The function returns TRUE if authentication method
2612 is found and FALSE if not. `conn' may be NULL. */
2614 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
2615 char *hostname, SilcUInt16 port,
2616 SilcGetAuthMeth completion, void *context)
2618 InternalGetAuthMethod internal;
2620 SILC_LOG_DEBUG(("Start"));
2622 /* If we do not have this connection configured by the user in a
2623 configuration file then resolve the authentication method from the
2624 server for this session. */
2625 internal = silc_calloc(1, sizeof(*internal));
2626 internal->completion = completion;
2627 internal->context = context;
2629 silc_client_request_authentication_method(client, conn,
2630 silc_get_auth_method_callback,
2634 /* Notifies application that failure packet was received. This is called
2635 if there is some protocol active in the client. The `protocol' is the
2636 protocol context. The `failure' is opaque pointer to the failure
2637 indication. Note, that the `failure' is protocol dependant and application
2638 must explicitly cast it to correct type. Usually `failure' is 32 bit
2639 failure type (see protocol specs for all protocol failure types). */
2641 void silc_failure(SilcClient client, SilcClientConnection conn,
2642 SilcProtocol protocol, void *failure)
2644 SILC_LOG_DEBUG(("Start"));
2646 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
2647 SilcSKEStatus status = (SilcSKEStatus)failure;
2649 if (status == SILC_SKE_STATUS_BAD_VERSION)
2650 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2651 SILCTXT_KE_BAD_VERSION);
2652 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
2653 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2654 SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
2655 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
2656 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2657 SILCTXT_KE_UNKNOWN_GROUP);
2658 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
2659 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2660 SILCTXT_KE_UNKNOWN_CIPHER);
2661 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
2662 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2663 SILCTXT_KE_UNKNOWN_PKCS);
2664 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
2665 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2666 SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
2667 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
2668 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2669 SILCTXT_KE_UNKNOWN_HMAC);
2670 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
2671 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2672 SILCTXT_KE_INCORRECT_SIGNATURE);
2673 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
2674 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2675 SILCTXT_KE_INVALID_COOKIE);
2678 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
2679 SilcUInt32 err = (SilcUInt32)failure;
2681 if (err == SILC_AUTH_FAILED)
2682 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2683 SILCTXT_AUTH_FAILED);
2687 /* Asks whether the user would like to perform the key agreement protocol.
2688 This is called after we have received an key agreement packet or an
2689 reply to our key agreement packet. This returns TRUE if the user wants
2690 the library to perform the key agreement protocol and FALSE if it is not
2691 desired (application may start it later by calling the function
2692 silc_client_perform_key_agreement). */
2694 bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
2695 SilcClientEntry client_entry, const char *hostname,
2696 SilcUInt16 port, SilcKeyAgreementCallback *completion,
2701 SILC_LOG_DEBUG(("Start"));
2703 /* We will just display the info on the screen and return FALSE and user
2704 will have to start the key agreement with a command. */
2707 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2710 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2711 SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
2713 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2714 SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
2715 client_entry->nickname, hostname, portstr);
2723 /* Notifies application that file transfer protocol session is being
2724 requested by the remote client indicated by the `client_entry' from
2725 the `hostname' and `port'. The `session_id' is the file transfer
2726 session and it can be used to either accept or reject the file
2727 transfer request, by calling the silc_client_file_receive or
2728 silc_client_file_close, respectively. */
2730 void silc_ftp(SilcClient client, SilcClientConnection conn,
2731 SilcClientEntry client_entry, SilcUInt32 session_id,
2732 const char *hostname, SilcUInt16 port)
2734 SILC_SERVER_REC *server;
2736 FtpSession ftp = NULL;
2738 SILC_LOG_DEBUG(("Start"));
2740 server = conn->context;
2742 silc_dlist_start(server->ftp_sessions);
2743 while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
2744 if (ftp->client_entry == client_entry &&
2745 ftp->session_id == session_id) {
2746 server->current_session = ftp;
2750 if (ftp == SILC_LIST_END) {
2751 ftp = silc_calloc(1, sizeof(*ftp));
2752 ftp->client_entry = client_entry;
2753 ftp->session_id = session_id;
2756 silc_dlist_add(server->ftp_sessions, ftp);
2757 server->current_session = ftp;
2761 snprintf(portstr, sizeof(portstr) - 1, "%d", port);
2764 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2765 SILCTXT_FILE_REQUEST, client_entry->nickname);
2767 printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
2768 SILCTXT_FILE_REQUEST_HOST,
2769 client_entry->nickname, hostname, portstr);
2772 /* Delivers SILC session detachment data indicated by `detach_data' to the
2773 application. If application has issued SILC_COMMAND_DETACH command
2774 the client session in the SILC network is not quit. The client remains
2775 in the network but is detached. The detachment data may be used later
2776 to resume the session in the SILC Network. The appliation is
2777 responsible of saving the `detach_data', to for example in a file.
2779 The detachment data can be given as argument to the functions
2780 silc_client_connect_to_server, or silc_client_add_connection when
2781 creating connection to remote server, inside SilcClientConnectionParams
2782 structure. If it is provided the client library will attempt to resume
2783 the session in the network. After the connection is created
2784 successfully, the application is responsible of setting the user
2785 interface for user into the same state it was before detaching (showing
2786 same channels, channel modes, etc). It can do this by fetching the
2787 information (like joined channels) from the client library. */
2790 silc_detach(SilcClient client, SilcClientConnection conn,
2791 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2795 /* Save the detachment data to file. */
2797 memset(file, 0, sizeof(file));
2798 snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
2799 silc_file_writefile(file, detach_data, detach_data_len);
2803 /* SILC client operations */
2804 SilcClientOperations ops = {
2806 silc_channel_message,
2807 silc_private_message,
2813 silc_get_auth_method,
2814 silc_verify_public_key,
2815 silc_ask_passphrase,