/*
- silc-queries.c
+ silc-queries.c
Author: Pekka Riikonen <priikone@silcnet.org>
#include "fe-common/core/keyboard.h"
#include "fe-common/silc/module-formats.h"
+static void silc_query_attributes_print_final(bool success, void *context);
+static void silc_query_attributes_accept(const char *line, void *context);
+
QUERY_REC *silc_query_create(const char *server_tag,
const char *nick, int automatic)
{
if (!strcasecmp(argv[1], "-del")) {
/* Delete attribute */
- if (!strcasecmp(argv[1], "vcard")) {
+ if (!strcasecmp(argv[2], "vcard")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_USER_INFO, NULL);
settings_set_str("attr_vcard", "");
- } else if (!strcasecmp(argv[1], "services")) {
+ } else if (!strcasecmp(argv[2], "services")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_SERVICE, NULL);
settings_set_str("attr_services", argv[2]);
- } else if (!strcasecmp(argv[1], "status_mood")) {
+ } else if (!strcasecmp(argv[2], "status_mood")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_STATUS_MOOD, NULL);
settings_set_str("attr_status_mood", "");
- } else if (!strcasecmp(argv[1], "status_text")) {
+ } else if (!strcasecmp(argv[2], "status_text")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
settings_set_str("attr_status_text", "");
- } else if (!strcasecmp(argv[1], "status_message")) {
+ } else if (!strcasecmp(argv[2], "status_message")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
settings_set_str("attr_status_message", "");
- } else if (!strcasecmp(argv[1], "preferred_langauge")) {
+ } else if (!strcasecmp(argv[2], "preferred_language")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
settings_set_str("attr_preferred_language", "");
- } else if (!strcasecmp(argv[1], "preferred_contact")) {
+ } else if (!strcasecmp(argv[2], "preferred_contact")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
settings_set_str("attr_preferred_contact", "");
- } else if (!strcasecmp(argv[1], "timezone")) {
+ } else if (!strcasecmp(argv[2], "timezone")) {
return;
- } else if (!strcasecmp(argv[1], "geolocation")) {
+ } else if (!strcasecmp(argv[2], "geolocation")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_GEOLOCATION, NULL);
settings_set_str("attr_geolocation", "");
- } else if (!strcasecmp(argv[1], "device_info")) {
+ } else if (!strcasecmp(argv[2], "device_info")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_DEVICE_INFO, NULL);
settings_set_str("attr_device_info", "");
- } else if (!strcasecmp(argv[1], "public_keys")) {
+ } else if (!strcasecmp(argv[2], "public_keys")) {
silc_client_attribute_del(silc_client, server->conn,
SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
settings_set_str("attr_public_keys", "");
settings_set_str("attr_status_text", argv[2]);
} else if (!strcasecmp(argv[1], "status_message")) {
settings_set_str("attr_status_message", argv[2]);
- } else if (!strcasecmp(argv[1], "preferred_langauge")) {
+ } else if (!strcasecmp(argv[1], "preferred_language")) {
settings_set_str("attr_preferred_language", argv[2]);
} else if (!strcasecmp(argv[1], "preferred_contact")) {
settings_set_str("attr_preferred_contact", argv[2]);
SilcAttributeObjGeo geo;
SilcAttributeObjDevice dev;
SilcAttributeObjPk pk;
+ SilcVCardStruct vcard;
bool allowed;
memset(&service, 0, sizeof(service));
memset(&geo, 0, sizeof(geo));
memset(&dev, 0, sizeof(dev));
memset(&pk, 0, sizeof(pk));
+ memset(&vcard, 0, sizeof(vcard));
+
+ allowed = settings_get_bool("attr_allow");
+ if (!allowed) {
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_USER_INFO, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_SERVICE, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_STATUS_MOOD, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_TIMEZONE, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_GEOLOCATION, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_DEVICE_INFO, NULL);
+ silc_client_attribute_del(silc_client, conn,
+ SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
+ return;
+ }
sv = settings_get_str("attr_vcard");
if (sv && *sv) {
silc_client_attribute_del(silc_client, conn,
SILC_ATTRIBUTE_USER_INFO, NULL);
tmp = silc_file_readfile(sv, &tmp_len);
- if (tmp)
- silc_client_attribute_add(silc_client, conn,
- SILC_ATTRIBUTE_USER_INFO, tmp, tmp_len);
+ if (tmp) {
+ tmp[tmp_len] = 0;
+ if (silc_vcard_decode(tmp, tmp_len, &vcard))
+ silc_client_attribute_add(silc_client, conn,
+ SILC_ATTRIBUTE_USER_INFO, (void *)&vcard,
+ sizeof(vcard));
+ }
+ silc_vcard_free(&vcard);
silc_free(tmp);
}
tmp = strchr(*entry, ':') + 1;
if (!tmp || !(*tmp))
continue;
+ memset(&service, 0, sizeof(service));
service.port = atoi(tmp);
*strchr(*entry, ':') = '\0';
silc_strncat(service.address, sizeof(service.address), *entry,
strlen(*entry));
service.status = TRUE;
+ service.idle = 0;
silc_client_attribute_add(silc_client, conn,
SILC_ATTRIBUTE_SERVICE, &service,
sizeof(service));
mask |= SILC_ATTRIBUTE_MOOD_EXCITED;
if (!strcasecmp(*entry, "ANXIOUS"))
mask |= SILC_ATTRIBUTE_MOOD_ANXIOUS;
- silc_client_attribute_add(silc_client, conn,
- SILC_ATTRIBUTE_STATUS_MOOD, (void *)mask,
- sizeof(SilcUInt32));
}
+ silc_client_attribute_add(silc_client, conn,
+ SILC_ATTRIBUTE_STATUS_MOOD, (void *)mask,
+ sizeof(SilcUInt32));
g_strfreev(list);
}
SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
tmp = silc_file_readfile(sv, &tmp_len);
if (tmp) {
+ tmp[tmp_len] = 0;
mime.mime = (const unsigned char *)tmp;
mime.mime_len = tmp_len;
silc_client_attribute_add(silc_client, conn,
mask |= SILC_ATTRIBUTE_CONTACT_MMS;
if (!strcasecmp(*entry, "CHAT"))
mask |= SILC_ATTRIBUTE_CONTACT_CHAT;
- silc_client_attribute_add(silc_client, conn,
- SILC_ATTRIBUTE_PREFERRED_CONTACT, (void *)mask,
- sizeof(SilcUInt32));
+ if (!strcasecmp(*entry, "VIDEO"))
+ mask |= SILC_ATTRIBUTE_CONTACT_VIDEO;
}
+ silc_client_attribute_add(silc_client, conn,
+ SILC_ATTRIBUTE_PREFERRED_CONTACT, (void *)mask,
+ sizeof(SilcUInt32));
g_strfreev(list);
}
SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
list = g_strsplit(sv, " ", -1);
for (entry = list; *entry != NULL; entry++) {
- /* XXX we support only SILC keys currently */
if (!strncasecmp(*entry, "silc-rsa:", 8)) {
tmp = silc_file_readfile((*entry) + 8, &tmp_len);
if (tmp) {
+ tmp[tmp_len] = 0;
pk.type = "silc-rsa";
pk.data = tmp;
pk.data_len = tmp_len;
sizeof(pk));
}
silc_free(tmp);
+ } else {
+ silc_say_error("Unsupported public key type '%s'", *entry);
}
}
g_strfreev(list);
}
}
+typedef struct {
+ SilcClient client;
+ SILC_SERVER_REC *server;
+ char *name;
+ SilcAttributeObjPk userpk;
+ SilcVCardStruct vcard;
+ SilcAttributeObjMime message;
+ SilcAttributeObjMime extension;
+ bool nopk;
+} *AttrVerify;
+
void silc_query_attributes_print(SILC_SERVER_REC *server,
SilcClient client,
SilcClientConnection conn,
- SilcDList attrs)
+ SilcDList attrs,
+ SilcClientEntry client_entry)
{
SilcAttributePayload attr;
SilcAttribute attribute;
char tmp[512];
- SilcAttributeObjPk userpk, serverpk, usersign, serversign;
+ SilcAttributeObjPk serverpk, usersign, serversign;
+ AttrVerify verify;
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ATTR_HEADER);
- memset(&userpk, 0, sizeof(userpk));
memset(&serverpk, 0, sizeof(serverpk));
memset(&usersign, 0, sizeof(usersign));
memset(&serversign, 0, sizeof(serversign));
+ verify = silc_calloc(1, sizeof(*verify));
+ if (!verify)
+ return;
+ verify->client = client;
+ verify->server = server;
+ verify->name = strdup(client_entry->nickname);
+
silc_dlist_start(attrs);
while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
attribute = silc_attribute_get_attribute(attr);
case SILC_ATTRIBUTE_USER_INFO:
{
- SilcVCardStruct vcard;
- memset(&vcard, 0, sizeof(vcard));
- if (!silc_attribute_get_object(attr, (void *)&vcard, sizeof(vcard)))
+ if (!silc_attribute_get_object(attr, (void *)&verify->vcard,
+ sizeof(verify->vcard)))
continue;
- /* XXX */
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_VCARD_FILE,
+ "present");
}
break;
case SILC_ATTRIBUTE_SERVICE:
{
SilcAttributeObjService service;
+ memset(&service, 0, sizeof(service));
if (!silc_attribute_get_object(attr, (void *)&service,
sizeof(service)))
continue;
- snprintf(tmp, sizeof(tmp) - 1, "%s:%d (logged %s)",
+ snprintf(tmp, sizeof(tmp) - 1, "%s:%d (logged %s) idle %d seconds",
service.address, (unsigned int)service.port,
- service.status ? "in" : "out");
+ service.status ? "in" : "out",
+ (unsigned int)service.idle);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ATTR_SERVICES, tmp);
}
case SILC_ATTRIBUTE_STATUS_MESSAGE:
{
- SilcAttributeObjMime mime;
- memset(&mime, 0, sizeof(mime));
- if (!silc_attribute_get_object(attr, (void *)&mime, sizeof(mime)))
+ if (!silc_attribute_get_object(attr, (void *)&verify->message,
+ sizeof(verify->message)))
continue;
- /* XXX */
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MESSAGE,
+ "present");
}
break;
silc_strncat(tmp, sizeof(tmp), "SMS ", strlen(" SMS"));
if (mask & SILC_ATTRIBUTE_CONTACT_MMS)
silc_strncat(tmp, sizeof(tmp), "MMS ", strlen(" MMS"));
+ if (mask & SILC_ATTRIBUTE_CONTACT_VIDEO)
+ silc_strncat(tmp, sizeof(tmp), "VIDEO ", strlen(" VIDEO"));
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_CONTACT, tmp);
}
break;
case SILC_ATTRIBUTE_EXTENSION:
+ {
+ if (!silc_attribute_get_object(attr, (void *)&verify->extension,
+ sizeof(verify->extension)))
+ continue;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_EXTENSION,
+ "present");
+ }
break;
case SILC_ATTRIBUTE_GEOLOCATION:
case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
{
- if (userpk.type)
+ if (verify->userpk.type)
continue;
- if (!silc_attribute_get_object(attr, (void *)&userpk, sizeof(userpk)))
+ if (!silc_attribute_get_object(attr, (void *)&verify->userpk,
+ sizeof(verify->userpk)))
continue;
}
+ break;
+
case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
{
if (serverpk.type)
}
}
- if (!userpk.type)
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_ATTR_FOOTER);
-
/* Handle the signature verifications and public key verifying here */
- if (usersign.data && !strcmp(userpk.type, "silc-rsa")) {
+ if (usersign.data && !strcmp(verify->userpk.type, "silc-rsa")) {
/* Verify the signature now */
- /* XXX */
+ SilcPublicKey public_key;
+ SilcPKCS pkcs;
+ unsigned char *verifyd;
+ SilcUInt32 verify_len;
+
+ if (silc_pkcs_public_key_decode(verify->userpk.data,
+ verify->userpk.data_len,
+ &public_key)) {
+ silc_pkcs_alloc("rsa", &pkcs);
+ verifyd = silc_attribute_get_verify_data(attrs, FALSE, &verify_len);
+ if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)){
+ if (silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
+ usersign.data,
+ usersign.data_len,
+ verifyd, verify_len)) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_VERIFIED);
+ } else {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED);
+ }
+ }
+
+ silc_pkcs_public_key_free(public_key);
+ silc_free(verifyd);
+ }
+ } else {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_NOT_PRESENT);
+ }
+
+ if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) {
+ /* Verify the signature now */
+ SilcPublicKey public_key;
+ SilcPKCS pkcs;
+ unsigned char *verifyd;
+ SilcUInt32 verify_len;
+
+ if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len,
+ &public_key)) {
+ silc_pkcs_alloc("rsa", &pkcs);
+ verifyd = silc_attribute_get_verify_data(attrs, TRUE, &verify_len);
+ if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) {
+ if (silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
+ serversign.data,
+ serversign.data_len,
+ verifyd, verify_len)) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_VERIFIED);
+ } else {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED);
+ }
+ }
+
+ silc_pkcs_public_key_free(public_key);
+ silc_free(verifyd);
+ }
+ }
+
+ if (verify->userpk.data) {
+ silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
+ verify->userpk.data, verify->userpk.data_len,
+ SILC_SKE_PK_TYPE_SILC,
+ silc_query_attributes_print_final, verify);
+ } else {
+ verify->nopk = TRUE;
+ silc_query_attributes_print_final(FALSE, verify);
+ }
+}
+
+static void silc_query_attributes_print_final(bool success, void *context)
+{
+ AttrVerify verify = context;
+ SilcClient client = verify->client;
+ SILC_SERVER_REC *server = verify->server;
+ char *format = NULL;
+ unsigned char filename[256], *fingerprint = NULL, *tmp;
+ struct stat st;
+ int i;
+
+ if (!verify->nopk) {
+ if (success) {
+ printformat_module("fe-common/silc", NULL, NULL,
+ MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, "user",
+ verify->name);
+ } else {
+ printformat_module("fe-common/silc", NULL, NULL,
+ MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED, "user",
+ verify->name);
+ }
+ }
+
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_FOOTER);
+
+ /* Replace all whitespaces with `_'. */
+ fingerprint = silc_hash_fingerprint(client->sha1hash,
+ verify->userpk.data,
+ verify->userpk.data_len);
+ for (i = 0; i < strlen(fingerprint); i++)
+ if (fingerprint[i] == ' ')
+ fingerprint[i] = '_';
+
+ /* Filename for dir */
+ tmp = fingerprint + strlen(fingerprint) - 9;
+ snprintf(filename, sizeof(filename) - 1, "%s/friends/%s",
+ get_irssi_dir(), tmp);
+ silc_free(fingerprint);
+
+ if ((stat(filename, &st)) == -1) {
+ /* Ask to accept save requested attributes */
+ format = format_get_text("fe-common/silc", NULL, NULL, NULL,
+ SILCTXT_ATTR_SAVE);
+ keyboard_entry_redirect((SIGNAL_FUNC)silc_query_attributes_accept,
+ format, 0, verify);
+ } else {
+ /* Save new data to existing directory */
+ silc_query_attributes_accept("Y", verify);
+ }
+
+ g_free(format);
+}
+
+static void silc_query_attributes_accept(const char *line, void *context)
+{
+ AttrVerify verify = context;
+ SilcClient client = verify->client;
+ SILC_SERVER_REC *server = verify->server;
+ struct stat st;
+ struct passwd *pw;
+ unsigned char filename[256], filename2[256], *fingerprint = NULL, *tmp;
+ SilcUInt32 len;
+ int i;
+
+ if (line[0] == 'Y' || line[0] == 'y') {
+ /* Save the attributes */
+ memset(filename, 0, sizeof(filename));
+ memset(filename2, 0, sizeof(filename2));
+
+ pw = getpwuid(getuid());
+ if (!pw)
+ goto out;
+
+ /* Replace all whitespaces with `_'. */
+ fingerprint = silc_hash_fingerprint(client->sha1hash,
+ verify->userpk.data,
+ verify->userpk.data_len);
+ for (i = 0; i < strlen(fingerprint); i++)
+ if (fingerprint[i] == ' ')
+ fingerprint[i] = '_';
+
+ /* Filename for dir */
+ tmp = fingerprint + strlen(fingerprint) - 9;
+ snprintf(filename, sizeof(filename) - 1, "%s/friends/%s",
+ get_irssi_dir(), tmp);
+
+ /* Create dir if it doesn't exist */
+ if ((stat(filename, &st)) == -1) {
+ /* If dir doesn't exist */
+ if (errno == ENOENT) {
+ if (pw->pw_uid == geteuid()) {
+ if ((mkdir(filename, 0755)) == -1) {
+ silc_say_error("Couldn't create `%s' directory",
+ filename);
+ goto out;
+ }
+ } else {
+ silc_say_error("Couldn't create `%s' directory due to a "
+ "wrong uid!", filename);
+ goto out;
+ }
+ } else {
+ silc_say_error("%s", strerror(errno));
+ goto out;
+ }
+ }
+
+ /* Save the stuff to the directory */
+
+ /* Save VCard */
+ snprintf(filename2, sizeof(filename2) - 1, "%s/vcard", filename);
+ if (verify->vcard.full_name) {
+ tmp = silc_vcard_encode(&verify->vcard, &len);
+ silc_file_writefile(filename2, tmp, len);
+ silc_free(tmp);
+ }
+
+ /* Save public key */
+ memset(filename2, 0, sizeof(filename2));
+ snprintf(filename2, sizeof(filename2) - 1, "%s/clientkey_%s.pub",
+ filename, fingerprint);
+ silc_pkcs_save_public_key_data(filename2, verify->userpk.data,
+ verify->userpk.data_len,
+ SILC_PKCS_FILE_PEM);
+
+ /* Save extension data */
+ if (verify->extension.mime) {
+ memset(filename2, 0, sizeof(filename2));
+ snprintf(filename2, sizeof(filename2) - 1, "%s/extension.mime",
+ filename);
+ silc_file_writefile(filename2, verify->extension.mime,
+ verify->extension.mime_len);
+ }
+
+ /* Save MIME message data */
+ if (verify->message.mime) {
+ memset(filename2, 0, sizeof(filename2));
+ snprintf(filename2, sizeof(filename2) - 1, "%s/status_message.mime",
+ filename);
+ silc_file_writefile(filename2, verify->message.mime,
+ verify->message.mime_len);
+ }
+
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_SAVED, filename);
}
+ out:
+ silc_free(fingerprint);
+ silc_free(verify->name);
+ silc_vcard_free(&verify->vcard);
+ silc_free(verify);
}