#include "signals.h"
#include "levels.h"
#include "settings.h"
+#include "ignore.h"
#include "fe-common/core/printtext.h"
#include "fe-common/core/fe-channels.h"
#include "fe-common/core/keyboard.h"
+#include "fe-common/core/window-items.h"
#include "fe-common/silc/module-formats.h"
+#include "core.h"
+
static void
silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
- SilcSocketType conn_type, unsigned char *pk,
- uint32 pk_len, SilcSKEPKType pk_type,
+ const char *name, SilcSocketType conn_type,
+ unsigned char *pk, SilcUInt32 pk_len,
+ SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context);
+static void silc_get_umode_string(SilcUInt32 mode, char *buf,
+ SilcUInt32 buf_size)
+{
+ if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
+ (mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
+ "[server operator]" :
+ (mode & SILC_UMODE_ROUTER_OPERATOR) ?
+ "[SILC operator]" : "[unknown mode]");
+ }
+ if (mode & SILC_UMODE_GONE)
+ strcat(buf, " [away]");
+ if (mode & SILC_UMODE_INDISPOSED)
+ strcat(buf, " [indisposed]");
+ if (mode & SILC_UMODE_BUSY)
+ strcat(buf, " [busy]");
+ if (mode & SILC_UMODE_PAGE)
+ strcat(buf, " [page to reach]");
+ if (mode & SILC_UMODE_HYPER)
+ strcat(buf, " [hyper active]");
+ if (mode & SILC_UMODE_ROBOT)
+ strcat(buf, " [robot]");
+ if (mode & SILC_UMODE_ANONYMOUS)
+ strcat(buf, " [anonymous]");
+ if (mode & SILC_UMODE_BLOCK_PRIVMSG)
+ strcat(buf, " [blocks private messages]");
+ if (mode & SILC_UMODE_DETACHED)
+ strcat(buf, " [detached]");
+ if (mode & SILC_UMODE_REJECT_WATCHING)
+ strcat(buf, " [rejects watching]");
+ if (mode & SILC_UMODE_BLOCK_INVITE)
+ strcat(buf, " [blocks invites]");
+}
+
+/* print "nick appears as" message to every channel of a server */
+static void
+silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
+ const char *newnick, const char *oldnick,
+ const char *address)
+{
+ if (ignore_check(SERVER(server), oldnick, address,
+ channel, newnick, MSGLEVEL_NICKS))
+ return;
+
+ printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
+ SILCTXT_CHANNEL_APPEARS,
+ oldnick, newnick, channel, address);
+}
+
+static void
+silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
+ const char *oldnick, const char *address)
+{
+ GSList *tmp, *windows;
+
+ /* Print to each channel/query where the nick is.
+ Don't print more than once to the same window. */
+ windows = NULL;
+
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ CHANNEL_REC *channel = tmp->data;
+ WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
+
+ if (nicklist_find(channel, newnick) == NULL ||
+ g_slist_find(windows, window) != NULL)
+ continue;
+
+ windows = g_slist_append(windows, window);
+ silc_print_nick_change_channel(server, channel->visible_name,
+ newnick, oldnick, address);
+ }
+
+ g_slist_free(windows);
+}
+
void silc_say(SilcClient client, SilcClientConnection conn,
SilcClientMessageType type, char *msg, ...)
{
va_end(va);
}
+/* try to verify a message using locally stored public key data */
+int verify_message_signature(SilcClientEntry sender,
+ SilcMessageSignedPayload sig,
+ SilcMessagePayload message)
+{
+ SilcPublicKey pk;
+ char file[256], filename[256];
+ char *fingerprint, *fingerprint2;
+ unsigned char *pk_data;
+ SilcUInt32 pk_datalen;
+ struct stat st;
+ int ret = SILC_MSG_SIGNED_VERIFIED, i;
+
+ if (sig == NULL)
+ return SILC_MSG_SIGNED_UNKNOWN;
+
+ /* get public key from the signature payload and compare it with the
+ one stored in the client entry */
+ pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
+
+ if (pk != NULL) {
+ fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
+
+ if (sender->fingerprint) {
+ fingerprint2 = silc_fingerprint(sender->fingerprint,
+ sender->fingerprint_len);
+ if (strcmp(fingerprint, fingerprint2)) {
+ /* since the public key differs from the senders public key, the
+ verification _failed_ */
+ silc_pkcs_public_key_free(pk);
+ silc_free(fingerprint);
+ ret = SILC_MSG_SIGNED_UNKNOWN;
+ }
+ silc_free(fingerprint2);
+ }
+ } else if (sender->fingerprint)
+ fingerprint = silc_fingerprint(sender->fingerprint,
+ sender->fingerprint_len);
+ else
+ /* no idea, who or what signed that message ... */
+ return SILC_MSG_SIGNED_UNKNOWN;
+
+ /* search our local client key cache */
+ for (i = 0; i < strlen(fingerprint); i++)
+ if (fingerprint[i] == ' ')
+ fingerprint[i] = '_';
+
+ snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
+ snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
+ get_irssi_dir(), file);
+ silc_free(fingerprint);
+
+ if (stat(filename, &st) < 0)
+ /* we don't have the public key cached ... use the one from the sig */
+ ret = SILC_MSG_SIGNED_UNKNOWN;
+ else {
+ SilcPublicKey cached_pk=NULL;
+
+ /* try to load the file */
+ if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(filename, &cached_pk,
+ SILC_PKCS_FILE_BIN)) {
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
+ if (pk == NULL)
+ return SILC_MSG_SIGNED_UNKNOWN;
+ else
+ ret = SILC_MSG_SIGNED_UNKNOWN;
+ }
+
+ if (cached_pk) {
+ if (pk)
+ silc_pkcs_public_key_free(pk);
+ pk = cached_pk;
+ }
+ }
+
+ /* the public key is now in pk, our "level of trust" in ret */
+ if ((pk) && silc_message_signed_verify(sig, message, pk,
+ silc_client->sha1hash)!= SILC_AUTH_OK)
+ ret = SILC_MSG_SIGNED_FAILED;
+
+ if (pk)
+ silc_pkcs_public_key_free(pk);
+
+ return ret;
+}
+
/* Message for a channel. The `sender' is the nickname of the sender
received in the packet. The `channel_name' is the name of the channel. */
void silc_channel_message(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender, SilcChannelEntry channel,
- SilcMessageFlags flags, char *msg)
+ SilcMessagePayload payload,
+ SilcMessageFlags flags, const unsigned char *message,
+ SilcUInt32 message_len)
{
SILC_SERVER_REC *server;
SILC_NICK_REC *nick;
SILC_CHANNEL_REC *chanrec;
+ int verified = 0;
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!message)
+ return;
+
server = conn == NULL ? NULL : conn->context;
chanrec = silc_channel_find_entry(server, channel);
if (!chanrec)
return;
nick = silc_nicklist_find(chanrec, sender);
+ if (!nick) {
+ /* We didn't find client but it clearly exists, add it. */
+ SilcChannelUser chu = silc_client_on_channel(channel, sender);
+ if (chu)
+ nick = silc_nicklist_insert(chanrec, chu, FALSE);
+ }
+
+ /* If the messages is digitally signed, verify it, if possible. */
+ if (flags & SILC_MESSAGE_FLAG_SIGNED) {
+ if (!settings_get_bool("ignore_message_signatures")) {
+ SilcMessageSignedPayload sig = silc_message_get_signature(payload);
+ verified = verify_message_signature(sender, sig, payload);
+ } else {
+ flags &= ~SILC_MESSAGE_FLAG_SIGNED;
+ }
+ }
+
+ if (flags & SILC_MESSAGE_FLAG_DATA) {
+ /* MIME object received, try to display it as well as we can */
+ char type[128], enc[128];
+ unsigned char *data;
+ SilcUInt32 data_len;
+
+ memset(type, 0, sizeof(type));
+ memset(enc, 0, sizeof(enc));
+ if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
+ enc, sizeof(enc) - 1, &data, &data_len))
+ return;
+ /* Then figure out what we can display */
+ if (strstr(type, "text/") && !strstr(type, "text/t140") &&
+ !strstr(type, "text/vnd")) {
+ /* It is something textual, display it */
+ message = (const unsigned char *)data;
+ } else {
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
+ nick == NULL ? "[<unknown>]" : nick->nick, type);
+ message = NULL;
+ }
+ }
+
+ if (!message)
+ return;
+
+ /* FIXME: replace those printformat calls with signals and add signature
+ information to them (if present) */
if (flags & SILC_MESSAGE_FLAG_ACTION)
printformat_module("fe-common/silc", server, channel->channel_name,
MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
- nick == NULL ? "[<unknown>]" : nick->nick, msg);
+ nick == NULL ? "[<unknown>]" : nick->nick, message);
else if (flags & SILC_MESSAGE_FLAG_NOTICE)
printformat_module("fe-common/silc", server, channel->channel_name,
MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
- nick == NULL ? "[<unknown>]" : nick->nick, msg);
- else
- signal_emit("message public", 6, server, msg,
- nick == NULL ? "[<unknown>]" : nick->nick,
- nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
- chanrec->name, nick);
+ nick == NULL ? "[<unknown>]" : nick->nick, message);
+ else {
+ if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+ char tmp[256], *cp, *dm = NULL;
+
+ memset(tmp, 0, sizeof(tmp));
+ cp = tmp;
+ if (message_len > sizeof(tmp) - 1) {
+ dm = silc_calloc(message_len + 1, sizeof(*dm));
+ cp = dm;
+ }
+
+ silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+ cp, message_len);
+ if (flags & SILC_MESSAGE_FLAG_SIGNED)
+ signal_emit("message signed_public", 6, server, cp,
+ nick == NULL ? "[<unknown>]" : nick->nick,
+ nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
+ chanrec->name, verified);
+ else
+ signal_emit("message public", 6, server, cp,
+ nick == NULL ? "[<unknown>]" : nick->nick,
+ nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
+ chanrec->name, nick);
+ silc_free(dm);
+ return;
+ }
+
+ if (flags & SILC_MESSAGE_FLAG_SIGNED)
+ signal_emit("message signed_public", 6, server, message,
+ nick == NULL ? "[<unknown>]" : nick->nick,
+ nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
+ chanrec->name, verified);
+ else
+ signal_emit("message public", 6, server, message,
+ nick == NULL ? "[<unknown>]" : nick->nick,
+ nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
+ chanrec->name, nick);
+ }
}
/* Private message to the client. The `sender' is the nickname of the
sender received in the packet. */
void silc_private_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcMessageFlags flags,
- char *msg)
+ SilcClientEntry sender, SilcMessagePayload payload,
+ SilcMessageFlags flags,
+ const unsigned char *message,
+ SilcUInt32 message_len)
{
SILC_SERVER_REC *server;
+ char userhost[256];
+ int verified = 0;
+ SILC_LOG_DEBUG(("Start"));
+
server = conn == NULL ? NULL : conn->context;
- signal_emit("message private", 4, server, msg,
- sender->nickname ? sender->nickname : "[<unknown>]",
- sender->username ? sender->username : NULL);
+ memset(userhost, 0, sizeof(userhost));
+ if (sender->username)
+ snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+ sender->username, sender->hostname);
+
+ /* If the messages is digitally signed, verify it, if possible. */
+ if (flags & SILC_MESSAGE_FLAG_SIGNED) {
+ if (!settings_get_bool("ignore_message_signatures")) {
+ SilcMessageSignedPayload sig = silc_message_get_signature(payload);
+ verified = verify_message_signature(sender, sig, payload);
+ } else {
+ flags &= ~SILC_MESSAGE_FLAG_SIGNED;
+ }
+ }
+
+ if (flags & SILC_MESSAGE_FLAG_DATA) {
+ /* MIME object received, try to display it as well as we can */
+ char type[128], enc[128];
+ unsigned char *data;
+ SilcUInt32 data_len;
+
+ memset(type, 0, sizeof(type));
+ memset(enc, 0, sizeof(enc));
+ if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
+ enc, sizeof(enc) - 1, &data, &data_len))
+ return;
+
+ /* Then figure out what we can display */
+ if (strstr(type, "text/") && !strstr(type, "text/t140") &&
+ !strstr(type, "text/vnd")) {
+ /* It is something textual, display it */
+ message = (const unsigned char *)data;
+ } else {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ type);
+ message = NULL;
+ }
+ }
+
+ if (!message)
+ return;
+
+ if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+ char tmp[256], *cp, *dm = NULL;
+
+ memset(tmp, 0, sizeof(tmp));
+ cp = tmp;
+ if (message_len > sizeof(tmp) - 1) {
+ dm = silc_calloc(message_len + 1, sizeof(*dm));
+ cp = dm;
+ }
+
+ silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+ cp, message_len);
+ if (flags & SILC_MESSAGE_FLAG_SIGNED)
+ signal_emit("message signed_private", 5, server, cp,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, verified);
+ else
+ signal_emit("message private", 4, server, cp,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL);
+ silc_free(dm);
+ return;
+ }
+
+ if (flags & SILC_MESSAGE_FLAG_SIGNED)
+ signal_emit("message signed_private", 5, server, message,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, verified);
+ else
+ signal_emit("message private", 4, server, message,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL);
}
/* Notify message to the client. The notify arguments are sent in the
for channel the channel entry is sent to application (even if server
does not send it). */
-typedef struct {
- int type;
- const char *name;
-} NOTIFY_REC;
-
-#define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
-static NOTIFY_REC notifies[] = {
- { SILC_NOTIFY_TYPE_NONE, NULL },
- { SILC_NOTIFY_TYPE_INVITE, "invite" },
- { SILC_NOTIFY_TYPE_JOIN, "join" },
- { SILC_NOTIFY_TYPE_LEAVE, "leave" },
- { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
- { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
- { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
- { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
- { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
- { SILC_NOTIFY_TYPE_MOTD, "motd" },
- { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" },
- { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" },
- { SILC_NOTIFY_TYPE_KICKED, "kick" },
- { SILC_NOTIFY_TYPE_KILLED, "kill" },
- { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" },
- { SILC_NOTIFY_TYPE_BAN, "ban" },
-};
-
void silc_notify(SilcClient client, SilcClientConnection conn,
SilcNotifyType type, ...)
{
- SILC_SERVER_REC *server;
va_list va;
-
- server = conn == NULL ? NULL : conn->context;
+ SILC_SERVER_REC *server;
+ SILC_CHANNEL_REC *chanrec;
+ SILC_NICK_REC *nickrec;
+ SilcClientEntry client_entry, client_entry2;
+ SilcChannelEntry channel, channel2;
+ SilcServerEntry server_entry;
+ SilcIdType idtype;
+ void *entry;
+ SilcUInt32 mode;
+ char buf[512];
+ char *name, *tmp;
+ GSList *list1, *list_tmp;
+
+ SILC_LOG_DEBUG(("Start"));
+
va_start(va, type);
+
+ server = conn == NULL ? NULL : conn->context;
- if (type == SILC_NOTIFY_TYPE_NONE) {
+ switch(type) {
+ case SILC_NOTIFY_TYPE_NONE:
/* Some generic notice from server */
printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
- } else if (type < MAX_NOTIFY) {
- /* Send signal about the notify event */
- char signal[50];
- g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
- signal_emit(signal, 2, server, va);
- } else {
+ break;
+
+ case SILC_NOTIFY_TYPE_INVITE:
+ /*
+ * Invited or modified invite list.
+ */
+
+ SILC_LOG_DEBUG(("Notify: INVITE"));
+
+ channel = va_arg(va, SilcChannelEntry);
+ name = va_arg(va, char *);
+ client_entry = va_arg(va, SilcClientEntry);
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message invite", 4, server, channel ? channel->channel_name :
+ name, client_entry->nickname, buf);
+ break;
+
+ case SILC_NOTIFY_TYPE_JOIN:
+ /*
+ * Joined channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: JOIN"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ if (client_entry == server->conn->local_entry) {
+ /* You joined to channel */
+ chanrec = silc_channel_find(server, channel->channel_name);
+ if (chanrec != NULL && !chanrec->joined)
+ chanrec->entry = channel;
+ } else {
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
+ if (chu)
+ nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
+ }
+ }
+
+ memset(buf, 0, sizeof(buf));
+ if (client_entry->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message join", 4, server, channel->channel_name,
+ client_entry->nickname,
+ client_entry->username == NULL ? "" : buf);
+ break;
+
+ case SILC_NOTIFY_TYPE_LEAVE:
+ /*
+ * Left a channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: LEAVE"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ memset(buf, 0, sizeof(buf));
+ if (client_entry->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message part", 5, server, channel->channel_name,
+ client_entry->nickname, client_entry->username ?
+ buf : "", client_entry->nickname);
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ nickrec = silc_nicklist_find(chanrec, client_entry);
+ if (nickrec != NULL)
+ nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_SIGNOFF:
+ /*
+ * Left the network.
+ */
+
+ SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ tmp = va_arg(va, char *);
+
+ silc_server_free_ftp(server, client_entry);
+
+ /* Print only if we have the nickname. If this cliente has just quit
+ when we were only resolving it, it is possible we don't have the
+ nickname. */
+ if (client_entry->nickname) {
+ memset(buf, 0, sizeof(buf));
+ if (client_entry->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message quit", 4, server, client_entry->nickname,
+ client_entry->username ? buf : "",
+ tmp ? tmp : "");
+ }
+
+ list1 = nicklist_get_same_unique(SERVER(server), client_entry);
+ for (list_tmp = list1; list_tmp != NULL; list_tmp =
+ list_tmp->next->next) {
+ CHANNEL_REC *channel = list_tmp->data;
+ NICK_REC *nickrec = list_tmp->next->data;
+
+ nicklist_remove(channel, nickrec);
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_TOPIC_SET:
+ /*
+ * Changed topic.
+ */
+
+ SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
+
+ idtype = va_arg(va, int);
+ entry = va_arg(va, void *);
+ tmp = va_arg(va, char *);
+ channel = va_arg(va, SilcChannelEntry);
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ char tmp2[256], *cp, *dm = NULL;
+
+ g_free_not_null(chanrec->topic);
+ if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
+ memset(tmp2, 0, sizeof(tmp2));
+ cp = tmp2;
+ if (strlen(tmp) > sizeof(tmp2) - 1) {
+ dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
+ cp = dm;
+ }
+
+ silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
+ cp, strlen(tmp));
+ tmp = cp;
+ }
+
+ chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
+ signal_emit("channel topic changed", 1, chanrec);
+
+ silc_free(dm);
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry = (SilcClientEntry)entry;
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message topic", 5, server, channel->channel_name,
+ tmp, client_entry->nickname, buf);
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ signal_emit("message topic", 5, server, channel->channel_name,
+ tmp, server_entry->server_name,
+ server_entry->server_name);
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel = (SilcChannelEntry)entry;
+ signal_emit("message topic", 5, server, channel->channel_name,
+ tmp, channel->channel_name, channel->channel_name);
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_NICK_CHANGE:
+ /*
+ * Changed nickname.
+ */
+
+ SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ client_entry2 = va_arg(va, SilcClientEntry);
+
+ if (!strcmp(client_entry->nickname, client_entry2->nickname))
+ break;
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry2->username, client_entry2->hostname);
+ nicklist_rename_unique(SERVER(server),
+ client_entry, client_entry->nickname,
+ client_entry2, client_entry2->nickname);
+ signal_emit("message nick", 4, server, client_entry2->nickname,
+ client_entry->nickname, buf);
+ break;
+
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ /*
+ * Changed channel mode.
+ */
+
+ SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+
+ idtype = va_arg(va, int);
+ entry = va_arg(va, void *);
+ mode = va_arg(va, SilcUInt32);
+ (void)va_arg(va, char *);
+ (void)va_arg(va, char *);
+ channel = va_arg(va, SilcChannelEntry);
+
+ tmp = silc_client_chmode(mode,
+ channel->channel_key ?
+ silc_cipher_get_name(channel->channel_key) : "",
+ channel->hmac ?
+ silc_hmac_get_name(channel->hmac) : "");
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ g_free_not_null(chanrec->mode);
+ chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
+ signal_emit("channel mode changed", 1, chanrec);
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+ channel->channel_name, tmp ? tmp : "removed all",
+ client_entry->nickname);
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+ channel->channel_name, tmp ? tmp : "removed all",
+ server_entry->server_name);
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel2 = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+ channel->channel_name, tmp ? tmp : "removed all",
+ channel2->channel_name);
+ }
+
+ silc_free(tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ /*
+ * Changed user's mode on channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
+
+ idtype = va_arg(va, int);
+ entry = va_arg(va, void *);
+ mode = va_arg(va, SilcUInt32);
+ client_entry2 = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ tmp = silc_client_chumode(mode);
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ SILC_NICK_REC *nick;
+
+ if (client_entry2 == server->conn->local_entry)
+ chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+
+ nick = silc_nicklist_find(chanrec, client_entry2);
+ if (nick != NULL) {
+ nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+ nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
+ signal_emit("nick mode changed", 2, chanrec, nick);
+ }
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
+ channel->channel_name, client_entry2->nickname,
+ tmp ? tmp : "removed all",
+ client_entry->nickname);
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
+ channel->channel_name, client_entry2->nickname,
+ tmp ? tmp : "removed all",
+ server_entry->server_name);
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel2 = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
+ channel->channel_name, client_entry2->nickname,
+ tmp ? tmp : "removed all",
+ channel2->channel_name);
+ }
+
+ if (mode & SILC_CHANNEL_UMODE_CHANFO)
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_FOUNDER,
+ channel->channel_name, client_entry2->nickname);
+
+ if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_QUIETED, channel->channel_name);
+
+ silc_free(tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_MOTD:
+ /*
+ * Received MOTD.
+ */
+
+ SILC_LOG_DEBUG(("Notify: MOTD"));
+
+ tmp = va_arg(va, char *);
+
+ if (!settings_get_bool("skip_motd"))
+ printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_KICKED:
+ /*
+ * Someone was kicked from channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: KICKED"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ tmp = va_arg(va, char *);
+ client_entry2 = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ chanrec = silc_channel_find_entry(server, channel);
+
+ if (client_entry == conn->local_entry) {
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
+ channel->channel_name,
+ client_entry ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+ if (chanrec) {
+ chanrec->kicked = TRUE;
+ channel_destroy((CHANNEL_REC *)chanrec);
+ }
+ } else {
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
+ client_entry->nickname, channel->channel_name,
+ client_entry2 ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+
+ if (chanrec) {
+ SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
+ if (nickrec != NULL)
+ nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
+ }
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_KILLED:
+ /*
+ * Someone was killed from the network.
+ */
+
+ SILC_LOG_DEBUG(("Notify: KILLED"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ tmp = va_arg(va, char *);
+ idtype = va_arg(va, int);
+ entry = va_arg(va, SilcClientEntry);
+
+ if (client_entry == conn->local_entry) {
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry2 = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
+ client_entry2 ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
+ server_entry->server_name, tmp ? tmp : "");
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
+ channel->channel_name, tmp ? tmp : "");
+ }
+ } else {
+ list1 = nicklist_get_same_unique(SERVER(server), client_entry);
+ for (list_tmp = list1; list_tmp != NULL; list_tmp =
+ list_tmp->next->next) {
+ CHANNEL_REC *channel = list_tmp->data;
+ NICK_REC *nickrec = list_tmp->next->data;
+ nicklist_remove(channel, nickrec);
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry2 = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
+ client_entry->nickname,
+ client_entry2 ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
+ client_entry->nickname,
+ server_entry->server_name, tmp ? tmp : "");
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
+ client_entry->nickname,
+ channel->channel_name, tmp ? tmp : "");
+ }
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+ break;
+
+ case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+ {
+ /*
+ * Server has quit the network.
+ */
+ int i;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count;
+
+ SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
+ (void)va_arg(va, void *);
+ clients = va_arg(va, SilcClientEntry *);
+ clients_count = va_arg(va, SilcUInt32);
+
+ for (i = 0; i < clients_count; i++) {
+ memset(buf, 0, sizeof(buf));
+
+ /* Print only if we have the nickname. If this client has just quit
+ when we were only resolving it, it is possible we don't have the
+ nickname. */
+ if (clients[i]->nickname) {
+ if (clients[i]->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ clients[i]->username, clients[i]->hostname);
+ signal_emit("message quit", 4, server, clients[i]->nickname,
+ clients[i]->username ? buf : "",
+ "server signoff");
+ }
+
+ silc_server_free_ftp(server, clients[i]);
+
+ list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
+ for (list_tmp = list1; list_tmp != NULL; list_tmp =
+ list_tmp->next->next) {
+ CHANNEL_REC *channel = list_tmp->data;
+ NICK_REC *nickrec = list_tmp->next->data;
+ nicklist_remove(channel, nickrec);
+ }
+ }
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_ERROR:
+ {
+ SilcStatus error = va_arg(va, int);
+
+ silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(error));
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_WATCH:
+ {
+ SilcNotifyType notify;
+
+ client_entry = va_arg(va, SilcClientEntry);
+ name = va_arg(va, char *); /* Maybe NULL */
+ mode = va_arg(va, SilcUInt32);
+ notify = va_arg(va, int);
+
+ if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
+ if (name)
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
+ client_entry->nickname, name);
+ else
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
+ client_entry->nickname);
+ } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
+ /* See if client was away and is now present */
+ if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
+ SILC_UMODE_BUSY | SILC_UMODE_PAGE |
+ SILC_UMODE_DETACHED)) &&
+ (client_entry->mode & SILC_UMODE_GONE ||
+ client_entry->mode & SILC_UMODE_INDISPOSED ||
+ client_entry->mode & SILC_UMODE_BUSY ||
+ client_entry->mode & SILC_UMODE_PAGE ||
+ client_entry->mode & SILC_UMODE_DETACHED)) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
+ client_entry->nickname);
+ }
+
+ if (mode) {
+ memset(buf, 0, sizeof(buf));
+ silc_get_umode_string(mode, buf, sizeof(buf) - 1);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
+ client_entry->nickname, buf);
+ }
+ } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
+ client_entry->nickname);
+ } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
+ notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
+ client_entry->nickname);
+ } else if (notify == SILC_NOTIFY_TYPE_NONE) {
+ /* Client logged in to the network */
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
+ client_entry->nickname);
+ }
+ }
+ break;
+
+ default:
/* Unknown notify */
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
+ break;
}
va_end(va);
/* Called to indicate that connection was either successfully established
or connecting failed. This is also the first time application receives
- the SilcClientConnection objecet which it should save somewhere. */
+ the SilcClientConnection object which it should save somewhere. */
-void silc_connect(SilcClient client, SilcClientConnection conn, int success)
+void silc_connect(SilcClient client, SilcClientConnection conn,
+ SilcClientConnectionStatus status)
{
SILC_SERVER_REC *server = conn->context;
- if (!server && !success) {
- silc_client_close_connection(client, NULL, conn);
+ if (!server || server->disconnected) {
+ silc_client_close_connection(client, conn);
return;
}
- if (success) {
+ switch (status) {
+ case SILC_CLIENT_CONN_SUCCESS:
+ /* We have successfully connected to server */
server->connected = TRUE;
signal_emit("event connected", 1, server);
- } else {
+ break;
+
+ case SILC_CLIENT_CONN_SUCCESS_RESUME:
+ /* We have successfully resumed old detached session */
+ server->connected = TRUE;
+ signal_emit("event connected", 1, server);
+
+ /* If we resumed old session check whether we need to update
+ our nickname */
+ if (strcmp(server->nick, conn->local_entry->nickname)) {
+ char *old;
+ old = g_strdup(server->nick);
+ server_change_nick(SERVER(server), conn->local_entry->nickname);
+ nicklist_rename_unique(SERVER(server),
+ conn->local_entry, server->nick,
+ conn->local_entry, conn->local_entry->nickname);
+ signal_emit("message own_nick", 4, server, server->nick, old, "");
+ g_free(old);
+ }
+ break;
+
+ default:
server->connection_lost = TRUE;
- server->conn->context = NULL;
+ if (server->conn)
+ server->conn->context = NULL;
server_disconnect(SERVER(server));
+ break;
}
}
/* Called to indicate that connection was disconnected to the server. */
-void silc_disconnect(SilcClient client, SilcClientConnection conn)
+void silc_disconnect(SilcClient client, SilcClientConnection conn,
+ SilcStatus status, const char *message)
{
SILC_SERVER_REC *server = conn->context;
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!server || server->connection_lost)
+ return;
+
+ if (server->conn && server->conn->local_entry) {
+ nicklist_rename_unique(SERVER(server),
+ server->conn->local_entry, server->nick,
+ server->conn->local_entry,
+ silc_client->username);
+ silc_change_nick(server, silc_client->username);
+ }
+
+ if (message)
+ silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Server closed connection: %s (%d) %s",
+ silc_get_status_message(status), status,
+ message ? message : "");
+
server->conn->context = NULL;
server->conn = NULL;
server->connection_lost = TRUE;
that the command really was processed. */
void silc_command(SilcClient client, SilcClientConnection conn,
- SilcClientCommandContext cmd_context, int success,
- SilcCommand command)
+ SilcClientCommandContext cmd_context, bool success,
+ SilcCommand command, SilcStatus status)
{
SILC_SERVER_REC *server = conn->context;
- if (!success)
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!success) {
+ silc_say_error("%s", silc_get_status_message(status));
return;
+ }
+
+ switch (command) {
- switch(command) {
case SILC_COMMAND_INVITE:
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
- cmd_context->argv[2],
- (cmd_context->argv[1][0] == '*' ?
- (char *)conn->current_channel->channel_name :
- (char *)cmd_context->argv[1]));
+ if (cmd_context->argc > 2)
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
+ cmd_context->argv[2],
+ (cmd_context->argv[1][0] == '*' ?
+ (char *)conn->current_channel->channel_name :
+ (char *)cmd_context->argv[1]));
+ break;
+
+ case SILC_COMMAND_DETACH:
+ server->no_reconnect = TRUE;
break;
+
default:
break;
}
static void silc_client_join_get_users(SilcClient client,
SilcClientConnection conn,
SilcClientEntry *clients,
- uint32 clients_count,
+ SilcUInt32 clients_count,
void *context)
{
SilcChannelEntry channel = (SilcChannelEntry)context;
+ SilcHashTableList htl;
SilcChannelUser chu;
SILC_SERVER_REC *server = conn->context;
SILC_CHANNEL_REC *chanrec;
SilcClientEntry founder = NULL;
NICK_REC *ownnick;
+ SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
+ silc_hash_table_count(channel->user_list)));
+
if (!clients)
return;
if (chanrec == NULL)
return;
- silc_list_start(channel->clients);
- while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ if (!chu->client->nickname)
+ continue;
if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
founder = chu->client;
silc_nicklist_insert(chanrec, chu, FALSE);
}
+ silc_hash_table_list_reset(&htl);
ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
nicklist_set_own(CHANNEL(chanrec), ownnick);
signal_emit("channel joined", 1, chanrec);
+ chanrec->entry = channel;
+
+ if (chanrec->topic)
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
+ channel->channel_name, chanrec->topic);
+
+ if (founder) {
+ if (founder == conn->local_entry) {
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_FOUNDER_YOU,
+ channel->channel_name);
+ signal_emit("nick mode changed", 2, chanrec, ownnick);
+ } else
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_FOUNDER,
+ channel->channel_name, founder->nickname);
+ }
+}
+
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ void *entry;
+ SilcIdType id_type;
+ char *fingerprint;
+} *GetkeyContext;
+
+void silc_getkey_cb(bool success, void *context)
+{
+ GetkeyContext getkey = (GetkeyContext)context;
+ char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
+ char *name = (getkey->id_type == SILC_ID_CLIENT ?
+ ((SilcClientEntry)getkey->entry)->nickname :
+ ((SilcServerEntry)getkey->entry)->server_name);
+
+ if (success) {
+ printformat_module("fe-common/silc", NULL, NULL,
+ MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
+ } else {
+ printformat_module("fe-common/silc", NULL, NULL,
+ MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
+ entity, name);
+ }
+
+ silc_free(getkey->fingerprint);
+ silc_free(getkey);
+}
+
+/* Parse an invite or ban list */
+void silc_parse_inviteban_list(SilcClient client,
+ SilcClientConnection conn,
+ SILC_SERVER_REC *server,
+ SilcChannelEntry channel,
+ const char *list_type,
+ SilcArgumentPayload list)
+{
+ unsigned char *tmp;
+ SilcUInt32 type, len;
+ SILC_CHANNEL_REC *chanrec = silc_channel_find_entry(server, channel);
+ int counter=0, resolving = FALSE;
+
+ if (!silc_argument_get_arg_num(list)) {
+ printformat_module("fe-common/silc", server,
+ (chanrec ? chanrec->visible_name : NULL),
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_NO_INVITEBAN_LIST,
+ channel->channel_name, list_type);
+ return;
+ }
+
+ printformat_module("fe-common/silc", server,
+ (chanrec ? chanrec->visible_name : NULL),
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
+ channel->channel_name, list_type);
+
+ /* parse the list */
+ tmp = silc_argument_get_first_arg(list, &type, &len);
+ while (tmp) {
+ switch (type) {
+ case 1:
+ {
+ /* an invite string */
+ char **list;
+ int i=0;
+
+ if (tmp[len-1] == ',')
+ tmp[len-1] = '\0';
+
+ list = g_strsplit(tmp, ",", -1);
+ while (list[i])
+ printformat_module("fe-common/silc", server,
+ (chanrec ? chanrec->visible_name : NULL),
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
+ ++counter, channel->channel_name, list_type,
+ list[i++]);
+ g_strfreev(list);
+ }
+ break;
- if (chanrec->topic)
- printformat_module("fe-common/silc", server, channel->channel_name,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
- channel->channel_name, chanrec->topic);
+ case 2:
+ {
+ /* a public key */
+ char *fingerprint, *babbleprint;
+
+ /* tmp is Public Key Payload, take public key from it. */
+ fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
+ babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
+
+ printformat_module("fe-common/silc", server,
+ (chanrec ? chanrec->visible_name : NULL),
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
+ ++counter, channel->channel_name, list_type,
+ fingerprint, babbleprint);
+ }
+ break;
+
+ case 3:
+ {
+ /* a client ID */
+ SilcClientID *client_id;
+ SilcClientEntry client_entry;
+
+ client_id = silc_id_payload_parse_id(tmp, len, NULL);
+
+ if (client_id == NULL) {
+ silc_say_error("Invalid data in %s list encountered", list_type);
+ break;
+ }
- fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+
+ if (client_entry) {
+ printformat_module("fe-common/silc", server,
+ (chanrec ? chanrec->visible_name : NULL),
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
+ ++counter, channel->channel_name, list_type,
+ client_entry->nickname);
+ } else {
+ resolving = TRUE;
+ silc_client_get_client_by_id_resolve(client, conn, client_id,
+ NULL, NULL, NULL);
+ }
- if (founder) {
- if (founder == conn->local_entry)
- printformat_module("fe-common/silc",
- server, channel->channel_name, MSGLEVEL_CRAP,
- SILCTXT_CHANNEL_FOUNDER_YOU,
- channel->channel_name);
- else
- printformat_module("fe-common/silc",
- server, channel->channel_name, MSGLEVEL_CRAP,
- SILCTXT_CHANNEL_FOUNDER,
- channel->channel_name, founder->nickname);
+ silc_free(client_id);
+ }
+ break;
+
+ default:
+ /* "trash" */
+ silc_say_error("Unkown type in %s list: %u (len %u)",
+ list_type, type, len);
+ }
+ tmp = silc_argument_get_next_arg(list, &type, &len);
}
+
+ if (resolving)
+ printformat_module("fe-common/silc", server,
+ (chanrec ? chanrec->visible_name : NULL),
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
+ list_type, channel->channel_name);
}
/* Command reply handler. This function is called always in the command reply
void
silc_command_reply(SilcClient client, SilcClientConnection conn,
- SilcCommandPayload cmd_payload, int success,
- SilcCommand command, SilcCommandStatus status, ...)
+ SilcCommandPayload cmd_payload, bool success,
+ SilcCommand command, SilcStatus status, ...)
{
SILC_SERVER_REC *server = conn->context;
va_start(vp, status);
+ SILC_LOG_DEBUG(("Start"));
+
switch(command) {
case SILC_COMMAND_WHOIS:
{
- char buf[1024], *nickname, *username, *realname;
- uint32 idle, mode;
- SilcBuffer channels;
+ char buf[1024], *nickname, *username, *realname, *nick;
+ unsigned char *fingerprint;
+ SilcUInt32 idle, mode;
+ SilcBuffer channels, user_modes;
+ SilcClientEntry client_entry;
+ SilcDList attrs;
- if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
- status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
- char *tmp;
- tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
- 3, NULL);
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ /* Print the unknown nick for user */
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 3, NULL);
if (tmp)
silc_say_error("%s: %s", tmp,
- silc_client_command_status_message(status));
- else
- silc_say_error("%s", silc_client_command_status_message(status));
+ silc_get_status_message(status));
break;
- }
-
- if (!success)
+ } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ /* Try to find the entry for the unknown client ID, since we
+ might have, and print the nickname of it for user. */
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
+ NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(client, conn,
+ client_id);
+ if (client_entry && client_entry->nickname)
+ silc_say_error("%s: %s", client_entry->nickname,
+ silc_get_status_message(status));
+ silc_free(client_id);
+ }
+ }
+ break;
+ } else if (!success) {
+ silc_say_error("WHOIS: %s", silc_get_status_message(status));
return;
-
- (void)va_arg(vp, SilcClientEntry);
+ }
+
+ client_entry = va_arg(vp, SilcClientEntry);
nickname = va_arg(vp, char *);
username = va_arg(vp, char *);
realname = va_arg(vp, char *);
channels = va_arg(vp, SilcBuffer);
- mode = va_arg(vp, uint32);
- idle = va_arg(vp, uint32);
+ mode = va_arg(vp, SilcUInt32);
+ idle = va_arg(vp, SilcUInt32);
+ fingerprint = va_arg(vp, unsigned char *);
+ user_modes = va_arg(vp, SilcBuffer);
+ attrs = va_arg(vp, SilcDList);
+ silc_parse_userfqdn(nickname, &nick, NULL);
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
- SILCTXT_WHOIS_USERINFO, nickname, username,
- realname);
-
- if (channels) {
- SilcDList list = silc_channel_payload_parse_list(channels);
- if (list) {
+ SILCTXT_WHOIS_USERINFO, nickname,
+ client_entry->username, client_entry->hostname,
+ nick, client_entry->nickname);
+ printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
+ SILCTXT_WHOIS_REALNAME, realname);
+ silc_free(nick);
+
+ if (channels && user_modes) {
+ SilcUInt32 *umodes;
+ SilcDList list = silc_channel_payload_parse_list(channels->data,
+ channels->len);
+ if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
+ &umodes)) {
SilcChannelPayload entry;
+ int i = 0;
+
memset(buf, 0, sizeof(buf));
silc_dlist_start(list);
while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
- char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
- uint32 name_len;
+ SilcUInt32 name_len;
+ char *m = silc_client_chumode_char(umodes[i++]);
char *name = silc_channel_get_name(entry, &name_len);
if (m)
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_WHOIS_CHANNELS, buf);
silc_channel_payload_list_free(list);
+ silc_free(umodes);
}
}
if (mode) {
memset(buf, 0, sizeof(buf));
-
- if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
- (mode & SILC_UMODE_ROUTER_OPERATOR)) {
- strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
- "Server Operator " :
- (mode & SILC_UMODE_ROUTER_OPERATOR) ?
- "SILC Operator " : "[Unknown mode] ");
- }
- if (mode & SILC_UMODE_GONE)
- strcat(buf, "away");
-
+ silc_get_umode_string(mode, buf, sizeof(buf - 1));
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_WHOIS_MODES, buf);
}
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_WHOIS_IDLE, buf);
}
+
+ if (fingerprint) {
+ fingerprint = silc_fingerprint(fingerprint, 20);
+ printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
+ SILCTXT_WHOIS_FINGERPRINT, fingerprint);
+ silc_free(fingerprint);
+ }
+
+ if (attrs)
+ silc_query_attributes_print(server, silc_client, conn, attrs,
+ client_entry);
}
break;
+ case SILC_COMMAND_IDENTIFY:
+ {
+ SilcClientEntry client_entry;
+
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ /* Print the unknown nick for user */
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 3, NULL);
+ if (tmp)
+ silc_say_error("%s: %s", tmp,
+ silc_get_status_message(status));
+ break;
+ } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ /* Try to find the entry for the unknown client ID, since we
+ might have, and print the nickname of it for user. */
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
+ NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(client, conn,
+ client_id);
+ if (client_entry && client_entry->nickname)
+ silc_say_error("%s: %s", client_entry->nickname,
+ silc_get_status_message(status));
+ silc_free(client_id);
+ }
+ }
+ break;
+ }
+
+ break;
+ }
+
case SILC_COMMAND_WHOWAS:
{
char *nickname, *username, *realname;
3, NULL);
if (tmp)
silc_say_error("%s: %s", tmp,
- silc_client_command_status_message(status));
- else
- silc_say_error("%s", silc_client_command_status_message(status));
+ silc_get_status_message(status));
break;
- }
-
- if (!success)
+ } else if (!success) {
+ silc_say_error("WHOWAS: %s", silc_get_status_message(status));
return;
+ }
(void)va_arg(vp, SilcClientEntry);
nickname = va_arg(vp, char *);
case SILC_COMMAND_INVITE:
{
SilcChannelEntry channel;
- char *invite_list;
- SilcArgumentPayload args;
- int argc = 0;
+ SilcBuffer payload;
+ SilcArgumentPayload invite_list;
+ SilcUInt32 argc;
if (!success)
return;
channel = va_arg(vp, SilcChannelEntry);
- invite_list = va_arg(vp, char *);
-
- args = silc_command_get_args(cmd_payload);
- if (args)
- argc = silc_argument_get_arg_num(args);
-
- if (invite_list)
- printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
- SILCTXT_CHANNEL_INVITE_LIST, channel->channel_name,
- invite_list);
- else if (argc == 3)
- printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
- SILCTXT_CHANNEL_NO_INVITE_LIST,
- channel->channel_name);
+ payload = va_arg(vp, SilcBuffer);
+
+ if (payload) {
+ SILC_GET16_MSB(argc, payload->data);
+ invite_list = silc_argument_payload_parse(payload->data + 2,
+ payload->len - 2, argc);
+ if (invite_list) {
+ silc_parse_inviteban_list(client, conn, server, channel,
+ "invite", invite_list);
+ silc_argument_payload_free(invite_list);
+ }
+ }
}
break;
case SILC_COMMAND_JOIN:
{
char *channel, *mode, *topic;
- uint32 modei;
+ SilcUInt32 modei;
SilcChannelEntry channel_entry;
SilcBuffer client_id_list;
- uint32 list_count;
+ SilcUInt32 list_count;
if (!success)
return;
channel = va_arg(vp, char *);
channel_entry = va_arg(vp, SilcChannelEntry);
- modei = va_arg(vp, uint32);
- (void)va_arg(vp, uint32);
+ modei = va_arg(vp, SilcUInt32);
+ (void)va_arg(vp, SilcUInt32);
(void)va_arg(vp, unsigned char *);
(void)va_arg(vp, unsigned char *);
(void)va_arg(vp, unsigned char *);
topic = va_arg(vp, char *);
(void)va_arg(vp, unsigned char *);
- list_count = va_arg(vp, uint32);
+ list_count = va_arg(vp, SilcUInt32);
client_id_list = va_arg(vp, SilcBuffer);
chanrec = silc_channel_find(server, channel);
if (!chanrec)
- chanrec = silc_channel_create(server, channel, TRUE);
+ chanrec = silc_channel_create(server, channel, channel, TRUE);
if (topic) {
+ char tmp[256], *cp, *dm = NULL;
g_free_not_null(chanrec->topic);
+
+ if (!silc_term_utf8() && silc_utf8_valid(topic, strlen(topic))) {
+ memset(tmp, 0, sizeof(tmp));
+ cp = tmp;
+ if (strlen(topic) > sizeof(tmp) - 1) {
+ dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
+ cp = dm;
+ }
+
+ silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
+ cp, strlen(topic));
+ topic = cp;
+ }
+
chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
signal_emit("channel topic changed", 1, chanrec);
+
+ silc_free(dm);
}
mode = silc_client_chmode(modei,
- channel_entry->channel_key->cipher->name,
- channel_entry->hmac->hmac->name);
+ channel_entry->channel_key ?
+ silc_cipher_get_name(channel_entry->
+ channel_key) : "",
+ channel_entry->hmac ?
+ silc_hmac_get_name(channel_entry->hmac) : "");
g_free_not_null(chanrec->mode);
chanrec->mode = g_strdup(mode == NULL ? "" : mode);
signal_emit("channel mode changed", 1, chanrec);
silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
silc_client_join_get_users,
channel_entry);
+
break;
}
case SILC_COMMAND_NICK:
{
- SilcClientEntry client = va_arg(vp, SilcClientEntry);
char *old;
+ SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
+ GSList *nicks;
if (!success)
return;
+ nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
+ if ((nicks != NULL) &&
+ (strcmp(SERVER(server)->nick, client_entry->nickname))) {
+ char buf[512];
+ SilcClientEntry collider, old;
+
+ old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
+ collider = silc_client_get_client_by_id(client, conn,
+ old->id);
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ collider->username, collider->hostname);
+ nicklist_rename_unique(SERVER(server),
+ old, old->nickname,
+ collider, collider->nickname);
+ silc_print_nick_change(server, collider->nickname,
+ client_entry->nickname, buf);
+ g_slist_free(nicks);
+ }
+
old = g_strdup(server->nick);
- server_change_nick(SERVER(server), client->nickname);
+ server_change_nick(SERVER(server), client_entry->nickname);
nicklist_rename_unique(SERVER(server),
server->conn->local_entry, server->nick,
- client, client->nickname);
-
+ client_entry, client_entry->nickname);
signal_emit("message own_nick", 4, server, server->nick, old, "");
g_free(old);
break;
char *topic, *name;
int usercount;
char users[20];
+ char tmp[256], *cp, *dm = NULL;
if (!success)
return;
name = va_arg(vp, char *);
topic = va_arg(vp, char *);
usercount = va_arg(vp, int);
+
+ if (topic && !silc_term_utf8() &&
+ silc_utf8_valid(topic, strlen(topic))) {
+ memset(tmp, 0, sizeof(tmp));
+ cp = tmp;
+ if (strlen(topic) > sizeof(tmp) - 1) {
+ dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
+ cp = dm;
+ }
+
+ silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
+ cp, strlen(topic));
+ topic = cp;
+ }
if (status == SILC_STATUS_LIST_START ||
status == SILC_STATUS_OK)
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_LIST_HEADER);
- snprintf(users, sizeof(users) - 1, "%d", usercount);
+ if (!usercount)
+ snprintf(users, sizeof(users) - 1, "N/A");
+ else
+ snprintf(users, sizeof(users) - 1, "%d", usercount);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_LIST,
name, users, topic ? topic : "");
+ silc_free(dm);
}
break;
case SILC_COMMAND_UMODE:
{
- uint32 mode;
+ SilcUInt32 mode;
+ char *reason;
if (!success)
return;
- mode = va_arg(vp, uint32);
+ mode = va_arg(vp, SilcUInt32);
- if (mode & SILC_UMODE_SERVER_OPERATOR)
+ if (mode & SILC_UMODE_SERVER_OPERATOR &&
+ !(server->umode & SILC_UMODE_SERVER_OPERATOR))
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
- if (mode & SILC_UMODE_ROUTER_OPERATOR)
+ if (mode & SILC_UMODE_ROUTER_OPERATOR &&
+ !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
+
+ if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
+ if (mode & SILC_UMODE_GONE) {
+ if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
+ reason = g_strdup(server->away_reason);
+ else
+ reason = g_strdup("away");
+ } else
+ reason = g_strdup("");
+
+ silc_set_away(reason, server);
+
+ g_free(reason);
+ }
+
+ server->umode = mode;
+ signal_emit("user mode changed", 2, server, NULL);
}
break;
if (!success)
return;
+ server->umode |= SILC_UMODE_SERVER_OPERATOR;
+ signal_emit("user mode changed", 2, server, NULL);
+
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
break;
if (!success)
return;
+ server->umode |= SILC_UMODE_ROUTER_OPERATOR;
+ signal_emit("user mode changed", 2, server, NULL);
+
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
break;
case SILC_COMMAND_USERS:
{
+ SilcHashTableList htl;
SilcChannelEntry channel;
SilcChannelUser chu;
MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
channel->channel_name);
- silc_list_start(channel->clients);
- while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
SilcClientEntry e = chu->client;
char stat[5], *mode;
+
+ if (!e->nickname)
+ continue;
memset(stat, 0, sizeof(stat));
mode = silc_client_chumode_char(chu->mode);
if (e->mode & SILC_UMODE_GONE)
strcat(stat, "G");
- else
+ else if (e->mode & SILC_UMODE_INDISPOSED)
+ strcat(stat, "I");
+ else if (e->mode & SILC_UMODE_BUSY)
+ strcat(stat, "B");
+ else if (e->mode & SILC_UMODE_PAGE)
+ strcat(stat, "P");
+ else if (e->mode & SILC_UMODE_HYPER)
strcat(stat, "H");
+ else if (e->mode & SILC_UMODE_ROBOT)
+ strcat(stat, "R");
+ else if (e->mode & SILC_UMODE_ANONYMOUS)
+ strcat(stat, "?");
+ else
+ strcat(stat, "A");
if (mode)
strcat(stat, mode);
printformat_module("fe-common/silc", server, channel->channel_name,
MSGLEVEL_CRAP, SILCTXT_USERS,
- e->nickname, stat, e->username,
+ e->nickname, stat,
+ e->username ? e->username : "",
+ e->hostname ? e->hostname : "",
e->realname ? e->realname : "");
if (mode)
silc_free(mode);
}
+ silc_hash_table_list_reset(&htl);
}
break;
case SILC_COMMAND_BAN:
{
SilcChannelEntry channel;
- char *ban_list;
+ SilcBuffer payload;
+ SilcArgumentPayload ban_list;
+ SilcUInt32 argc;
if (!success)
return;
channel = va_arg(vp, SilcChannelEntry);
- ban_list = va_arg(vp, char *);
-
- if (ban_list)
- printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
- SILCTXT_CHANNEL_BAN_LIST, channel->channel_name,
- ban_list);
- else
- printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
- SILCTXT_CHANNEL_NO_BAN_LIST,
- channel->channel_name);
+ payload = va_arg(vp, SilcBuffer);
+
+ if (payload) {
+ SILC_GET16_MSB(argc, payload->data);
+ ban_list = silc_argument_payload_parse(payload->data + 2,
+ payload->len - 2, argc);
+ if (ban_list) {
+ silc_parse_inviteban_list(client, conn, server, channel,
+ "ban", ban_list);
+ silc_argument_payload_free(ban_list);
+ }
+ }
}
break;
void *entry;
SilcPublicKey public_key;
unsigned char *pk;
- uint32 pk_len;
+ SilcUInt32 pk_len;
+ GetkeyContext getkey;
+ char *name;
if (!success)
return;
- id_type = va_arg(vp, uint32);
+ id_type = va_arg(vp, SilcUInt32);
entry = va_arg(vp, void *);
public_key = va_arg(vp, SilcPublicKey);
+
+ if (public_key) {
+ pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+
+ getkey = silc_calloc(1, sizeof(*getkey));
+ getkey->entry = entry;
+ getkey->id_type = id_type;
+ getkey->client = client;
+ getkey->conn = conn;
+ getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+
+ name = (id_type == SILC_ID_CLIENT ?
+ ((SilcClientEntry)entry)->nickname :
+ ((SilcServerEntry)entry)->server_name);
+
+ silc_verify_public_key_internal(client, conn, name,
+ (id_type == SILC_ID_CLIENT ?
+ SILC_SOCKET_TYPE_CLIENT :
+ SILC_SOCKET_TYPE_SERVER),
+ pk, pk_len, SILC_SKE_PK_TYPE_SILC,
+ silc_getkey_cb, getkey);
+ silc_free(pk);
+ } else {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
+ }
+ }
+ break;
+
+ case SILC_COMMAND_INFO:
+ {
+ SilcServerEntry server_entry;
+ char *server_name;
+ char *server_info;
+
+ if (!success)
+ return;
- pk = silc_pkcs_public_key_encode(public_key, &pk_len);
-
- silc_verify_public_key_internal(client, conn,
- (id_type == SILC_ID_CLIENT ?
- SILC_SOCKET_TYPE_CLIENT :
- SILC_SOCKET_TYPE_SERVER),
- pk, pk_len, SILC_SKE_PK_TYPE_SILC,
- NULL, NULL);
- silc_free(pk);
+ server_entry = va_arg(vp, SilcServerEntry);
+ server_name = va_arg(vp, char *);
+ server_info = va_arg(vp, char *);
+
+ if (server_name && server_info )
+ {
+ printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name);
+ printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info);
+ }
}
break;
{
SilcChannelEntry channel;
char *topic;
+ char tmp[256], *cp, *dm = NULL;
if (!success)
return;
channel = va_arg(vp, SilcChannelEntry);
topic = va_arg(vp, char *);
-
+
+ if (topic && !silc_term_utf8() &&
+ silc_utf8_valid(topic, strlen(topic))) {
+ memset(tmp, 0, sizeof(tmp));
+ cp = tmp;
+ if (strlen(topic) > sizeof(tmp) - 1) {
+ dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
+ cp = dm;
+ }
+
+ silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
+ cp, strlen(topic));
+ topic = cp;
+ }
+
if (topic) {
chanrec = silc_channel_find_entry(server, channel);
if (chanrec) {
MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
channel->channel_name);
}
+ silc_free(dm);
+ }
+ break;
+
+ case SILC_COMMAND_WATCH:
+ break;
+
+ case SILC_COMMAND_STATS:
+ {
+ SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
+ my_router_ops, cell_clients, cell_channels, cell_servers,
+ clients, channels, servers, routers, server_ops, router_ops;
+ SilcUInt32 buf_len;
+ SilcBufferStruct buf;
+ unsigned char *tmp_buf;
+ char tmp[40];
+ const char *tmptime;
+ int days, hours, mins, secs;
+
+ if (!success)
+ return;
+
+ tmp_buf = va_arg(vp, unsigned char *);
+ buf_len = va_arg(vp, SilcUInt32);
+
+ if (!tmp_buf || !buf_len) {
+ printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
+ return;
+ }
+
+ /* Get statistics structure */
+ silc_buffer_set(&buf, tmp_buf, buf_len);
+ silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&starttime),
+ SILC_STR_UI_INT(&uptime),
+ SILC_STR_UI_INT(&my_clients),
+ SILC_STR_UI_INT(&my_channels),
+ SILC_STR_UI_INT(&my_server_ops),
+ SILC_STR_UI_INT(&my_router_ops),
+ SILC_STR_UI_INT(&cell_clients),
+ SILC_STR_UI_INT(&cell_channels),
+ SILC_STR_UI_INT(&cell_servers),
+ SILC_STR_UI_INT(&clients),
+ SILC_STR_UI_INT(&channels),
+ SILC_STR_UI_INT(&servers),
+ SILC_STR_UI_INT(&routers),
+ SILC_STR_UI_INT(&server_ops),
+ SILC_STR_UI_INT(&router_ops),
+ SILC_STR_END);
+
+ tmptime = silc_get_time(starttime);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local server start time", tmptime);
+
+ days = uptime / (24 * 60 * 60);
+ uptime -= days * (24 * 60 * 60);
+ hours = uptime / (60 * 60);
+ uptime -= hours * (60 * 60);
+ mins = uptime / 60;
+ uptime -= mins * 60;
+ secs = uptime;
+ snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
+ days, hours, mins, secs);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local server uptime", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local server clients", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local server channels", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local server operators", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local router operators", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local cell clients", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local cell channels", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Local cell servers", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Total clients", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Total channels", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Total servers", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Total routers", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Total server operators", tmp);
+
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_STATS,
+ "Total router operators", tmp);
}
break;
va_end(vp);
}
-/* Internal routine to verify public key. If the `completion' is provided
- it will be called to indicate whether public was verified or not. */
-
typedef struct {
SilcClient client;
SilcClientConnection conn;
char *filename;
char *entity;
+ char *entity_name;
unsigned char *pk;
- uint32 pk_len;
+ SilcUInt32 pk_len;
SilcSKEPKType pk_type;
SilcVerifyPublicKey completion;
void *context;
verify->completion(FALSE, verify->context);
printformat_module("fe-common/silc", NULL, NULL,
- MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
+ MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
+ verify->entity_name ? verify->entity_name :
+ verify->entity);
}
silc_free(verify->filename);
silc_free(verify->entity);
+ silc_free(verify->entity_name);
silc_free(verify->pk);
silc_free(verify);
}
+/* Internal routine to verify public key. If the `completion' is provided
+ it will be called to indicate whether public was verified or not. For
+ server/router public key this will check for filename that includes the
+ remote host's IP address and remote host's hostname. */
+
static void
silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
- SilcSocketType conn_type, unsigned char *pk,
- uint32 pk_len, SilcSKEPKType pk_type,
+ const char *name, SilcSocketType conn_type,
+ unsigned char *pk, SilcUInt32 pk_len,
+ SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context)
{
int i;
- char file[256], filename[256], *fingerprint, *format;
+ char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
+ char *fingerprint, *babbleprint, *format;
struct passwd *pw;
struct stat st;
char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
}
memset(filename, 0, sizeof(filename));
+ memset(filename2, 0, sizeof(filename2));
memset(file, 0, sizeof(file));
if (conn_type == SILC_SOCKET_TYPE_SERVER ||
conn_type == SILC_SOCKET_TYPE_ROUTER) {
- snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
- conn->sock->hostname, conn->sock->port);
- snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
- pw->pw_dir, entity, file);
+ if (!name) {
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ conn->sock->ip, conn->sock->port);
+ snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
+ get_irssi_dir(), entity, file);
+
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ conn->sock->hostname, conn->sock->port);
+ snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
+ get_irssi_dir(), entity, file);
+
+ ipf = filename;
+ hostf = filename2;
+ } else {
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ name, conn->sock->port);
+ snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
+ get_irssi_dir(), entity, file);
+
+ ipf = filename;
+ }
} else {
/* Replace all whitespaces with `_'. */
fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
fingerprint[i] = '_';
snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
- snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
- pw->pw_dir, entity, file);
+ snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
+ get_irssi_dir(), entity, file);
silc_free(fingerprint);
+
+ ipf = filename;
}
/* Take fingerprint of the public key */
fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+ babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
verify = silc_calloc(1, sizeof(*verify));
verify->client = client;
verify->conn = conn;
- verify->filename = strdup(filename);
+ verify->filename = strdup(ipf);
verify->entity = strdup(entity);
- verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
- memcpy(verify->pk, pk, pk_len);
+ verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
+ (name ? strdup(name) : strdup(conn->sock->hostname))
+ : NULL);
+ verify->pk = silc_memdup(pk, pk_len);
verify->pk_len = pk_len;
verify->pk_type = pk_type;
verify->completion = completion;
verify->context = context;
/* Check whether this key already exists */
- if (stat(filename, &st) < 0) {
+ if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
/* Key does not exist, ask user to verify the key and save it */
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
format = format_get_text("fe-common/silc", NULL, NULL, NULL,
SILCTXT_PUBKEY_ACCEPT);
keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
/* The key already exists, verify it. */
SilcPublicKey public_key;
unsigned char *encpk;
- uint32 encpk_len;
-
- /* Load the key file */
- if (!silc_pkcs_load_public_key(filename, &public_key,
- SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(filename, &public_key,
- SILC_PKCS_FILE_BIN)) {
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
- format = format_get_text("fe-common/silc", NULL, NULL, NULL,
- SILCTXT_PUBKEY_ACCEPT_ANYWAY);
- keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
- format, 0, verify);
- g_free(format);
- silc_free(fingerprint);
- return;
- }
-
+ SilcUInt32 encpk_len;
+
+ /* Load the key file, try for both IP filename and hostname filename */
+ if (!silc_pkcs_load_public_key(ipf, &public_key,
+ SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(ipf, &public_key,
+ SILC_PKCS_FILE_BIN) &&
+ (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
+ SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(hostf, &public_key,
+ SILC_PKCS_FILE_BIN)))) {
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
+ format = format_get_text("fe-common/silc", NULL, NULL, NULL,
+ SILCTXT_PUBKEY_ACCEPT_ANYWAY);
+ keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
+ format, 0, verify);
+ g_free(format);
+ silc_free(fingerprint);
+ return;
+ }
+
/* Encode the key data */
encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
if (!encpk) {
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_MALFORMED, entity);
format = format_get_text("fe-common/silc", NULL, NULL, NULL,
/* Compare the keys */
if (memcmp(encpk, pk, encpk_len)) {
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
- SILCTXT_PUBKEY_RECEIVED, entity);
+ SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
+ verify->entity_name : entity);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_NO_MATCH, entity);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
if (completion)
completion(TRUE, context);
silc_free(fingerprint);
+ silc_free(verify->filename);
+ silc_free(verify->entity);
+ silc_free(verify->entity_name);
+ silc_free(verify->pk);
+ silc_free(verify);
}
}
void
silc_verify_public_key(SilcClient client, SilcClientConnection conn,
SilcSocketType conn_type, unsigned char *pk,
- uint32 pk_len, SilcSKEPKType pk_type,
+ SilcUInt32 pk_len, SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context)
{
- silc_verify_public_key_internal(client, conn, conn_type, pk,
+ silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
pk_len, pk_type,
completion, context);
}
void ask_passphrase_completion(const char *passphrase, void *context)
{
AskPassphrase p = (AskPassphrase)context;
+ if (passphrase && passphrase[0] == '\0')
+ passphrase = NULL;
p->completion((unsigned char *)passphrase,
passphrase ? strlen(passphrase) : 0, p->context);
silc_free(p);
}
void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
- SilcAskPassphrase completion, void *context)
+ SilcAskPassphrase completion, void *context)
{
AskPassphrase p = silc_calloc(1, sizeof(*p));
p->completion = completion;
"Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
}
+typedef struct {
+ SilcGetAuthMeth completion;
+ void *context;
+} *InternalGetAuthMethod;
+
+/* Callback called when we've received the authentication method information
+ from the server after we've requested it. This will get the authentication
+ data from the user if needed. */
+
+static void silc_get_auth_method_callback(SilcClient client,
+ SilcClientConnection conn,
+ SilcAuthMethod auth_meth,
+ void *context)
+{
+ InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ switch (auth_meth) {
+ case SILC_AUTH_NONE:
+ /* No authentication required. */
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ case SILC_AUTH_PASSWORD:
+ {
+ /* Check whether we find the password for this server in our
+ configuration. If not, then don't provide so library will ask
+ it from the user. */
+ SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
+ conn->remote_port);
+ if (!setup || !setup->password) {
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ }
+
+ (*internal->completion)(TRUE, auth_meth, setup->password,
+ strlen(setup->password), internal->context);
+ }
+ break;
+ case SILC_AUTH_PUBLIC_KEY:
+ /* Do not get the authentication data now, the library will generate
+ it using our default key, if we do not provide it here. */
+ /* XXX In the future when we support multiple local keys and multiple
+ local certificates we will need to ask from user which one to use. */
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ }
+
+ silc_free(internal);
+}
+
/* Find authentication method and authentication data by hostname and
port. The hostname may be IP address as well. The found authentication
method and authentication data is returned to `auth_meth', `auth_data'
and `auth_data_len'. The function returns TRUE if authentication method
is found and FALSE if not. `conn' may be NULL. */
-int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
- char *hostname, uint16 port,
- SilcProtocolAuthMeth *auth_meth,
- unsigned char **auth_data,
- uint32 *auth_data_len)
+void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+ char *hostname, SilcUInt16 port,
+ SilcGetAuthMeth completion, void *context)
{
- bool ret = TRUE;
- SILC_SERVER_REC *server = conn ? conn->context : NULL;
-
- /* XXX must resolve from configuration whether this connection has
- any specific authentication data */
+ InternalGetAuthMethod internal;
- *auth_meth = SILC_AUTH_NONE;
- *auth_data = NULL;
- *auth_data_len = 0;
+ SILC_LOG_DEBUG(("Start"));
- if (ret == FALSE) {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED);
- }
+ /* If we do not have this connection configured by the user in a
+ configuration file then resolve the authentication method from the
+ server for this session. */
+ internal = silc_calloc(1, sizeof(*internal));
+ internal->completion = completion;
+ internal->context = context;
- return ret;
+ silc_client_request_authentication_method(client, conn,
+ silc_get_auth_method_callback,
+ internal);
}
/* Notifies application that failure packet was received. This is called
void silc_failure(SilcClient client, SilcClientConnection conn,
SilcProtocol protocol, void *failure)
{
+ SILC_LOG_DEBUG(("Start"));
+
if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
SilcSKEStatus status = (SilcSKEStatus)failure;
}
if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
- uint32 err = (uint32)failure;
+ SilcUInt32 err = (SilcUInt32)failure;
if (err == SILC_AUTH_FAILED)
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
desired (application may start it later by calling the function
silc_client_perform_key_agreement). */
-int silc_key_agreement(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry, char *hostname,
- int port,
- SilcKeyAgreementCallback *completion,
- void **context)
+bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry, const char *hostname,
+ SilcUInt16 port, SilcKeyAgreementCallback *completion,
+ void **context)
{
char portstr[12];
+ SILC_LOG_DEBUG(("Start"));
+
/* We will just display the info on the screen and return FALSE and user
will have to start the key agreement with a command. */
snprintf(portstr, sizeof(portstr) - 1, "%d", port);
if (!hostname)
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
else
- printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES,
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
client_entry->nickname, hostname, portstr);
return FALSE;
}
+/* Notifies application that file transfer protocol session is being
+ requested by the remote client indicated by the `client_entry' from
+ the `hostname' and `port'. The `session_id' is the file transfer
+ session and it can be used to either accept or reject the file
+ transfer request, by calling the silc_client_file_receive or
+ silc_client_file_close, respectively. */
+
+void silc_ftp(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry, SilcUInt32 session_id,
+ const char *hostname, SilcUInt16 port)
+{
+ SILC_SERVER_REC *server;
+ char portstr[12];
+ FtpSession ftp = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ server = conn->context;
+
+ silc_dlist_start(server->ftp_sessions);
+ while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
+ if (ftp->client_entry == client_entry &&
+ ftp->session_id == session_id) {
+ server->current_session = ftp;
+ break;
+ }
+ }
+ if (ftp == SILC_LIST_END) {
+ ftp = silc_calloc(1, sizeof(*ftp));
+ ftp->client_entry = client_entry;
+ ftp->session_id = session_id;
+ ftp->send = FALSE;
+ ftp->conn = conn;
+ silc_dlist_add(server->ftp_sessions, ftp);
+ server->current_session = ftp;
+ }
+
+ if (hostname)
+ snprintf(portstr, sizeof(portstr) - 1, "%d", port);
+
+ if (!hostname)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_FILE_REQUEST, client_entry->nickname);
+ else
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_FILE_REQUEST_HOST,
+ client_entry->nickname, hostname, portstr);
+}
+
+/* Delivers SILC session detachment data indicated by `detach_data' to the
+ application. If application has issued SILC_COMMAND_DETACH command
+ the client session in the SILC network is not quit. The client remains
+ in the network but is detached. The detachment data may be used later
+ to resume the session in the SILC Network. The appliation is
+ responsible of saving the `detach_data', to for example in a file.
+
+ The detachment data can be given as argument to the functions
+ silc_client_connect_to_server, or silc_client_add_connection when
+ creating connection to remote server, inside SilcClientConnectionParams
+ structure. If it is provided the client library will attempt to resume
+ the session in the network. After the connection is created
+ successfully, the application is responsible of setting the user
+ interface for user into the same state it was before detaching (showing
+ same channels, channel modes, etc). It can do this by fetching the
+ information (like joined channels) from the client library. */
+
+void
+silc_detach(SilcClient client, SilcClientConnection conn,
+ const unsigned char *detach_data, SilcUInt32 detach_data_len)
+{
+ char file[256];
+
+ /* Save the detachment data to file. */
+
+ memset(file, 0, sizeof(file));
+ snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
+ silc_file_writefile(file, detach_data, detach_data_len);
+}
+
+
/* SILC client operations */
SilcClientOperations ops = {
silc_say,
silc_ask_passphrase,
silc_failure,
silc_key_agreement,
+ silc_ftp,
+ silc_detach,
};