X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Firssi%2Fsrc%2Fsilc%2Fcore%2Fsilc-queries.c;h=18590f767e5d15defcb07a8726b9157fc07e7bf4;hb=be10e71673bc538573b1805ee2115f2a3a7281a2;hp=a88a9f536d3473af4c11bb82dfed860dc0d4e963;hpb=2ae9657611bebeca17fa08bab9a57c31a0aaf0f1;p=silc.git diff --git a/apps/irssi/src/silc/core/silc-queries.c b/apps/irssi/src/silc/core/silc-queries.c index a88a9f53..18590f76 100644 --- a/apps/irssi/src/silc/core/silc-queries.c +++ b/apps/irssi/src/silc/core/silc-queries.c @@ -1,10 +1,10 @@ /* - silc-queries.c + silc-queries.c Author: Pekka Riikonen - Copyright (C) 2002 Pekka Riikonen + Copyright (C) 2002 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,6 +32,9 @@ #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) { @@ -153,45 +156,45 @@ void command_attr(const char *data, SILC_SERVER_REC *server, 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", ""); @@ -215,7 +218,7 @@ void command_attr(const char *data, SILC_SERVER_REC *server, 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]); @@ -244,27 +247,60 @@ void silc_query_attributes_default(SilcClient client, const char *sv; SilcUInt32 tmp_len, mask; SilcAttributeObjService service; - SilcAttributeObjMime mime; + SilcMime mime; SilcAttributeObjGeo geo; SilcAttributeObjDevice dev; SilcAttributeObjPk pk; + SilcVCardStruct vcard; bool allowed; memset(&service, 0, sizeof(service)); - memset(&mime, 0, sizeof(mime)); 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) { /* Put USER_INFO */ 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); + tmp = silc_file_readfile(sv, &tmp_len, NULL); + 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); } @@ -280,11 +316,13 @@ void silc_query_attributes_default(SilcClient client, 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)); @@ -324,10 +362,11 @@ void silc_query_attributes_default(SilcClient client, 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, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); g_strfreev(list); } @@ -346,13 +385,13 @@ void silc_query_attributes_default(SilcClient client, /* Put STATUS_MESSAGE */ silc_client_attribute_del(silc_client, conn, SILC_ATTRIBUTE_STATUS_MESSAGE, NULL); - tmp = silc_file_readfile(sv, &tmp_len); + tmp = silc_file_readfile(sv, &tmp_len, NULL); if (tmp) { - mime.mime = (const unsigned char *)tmp; - mime.mime_len = tmp_len; - silc_client_attribute_add(silc_client, conn, - SILC_ATTRIBUTE_STATUS_MESSAGE, &mime, - sizeof(mime)); + mime = silc_mime_decode(NULL, tmp, tmp_len); + if (mime) + silc_client_attribute_add(silc_client, conn, + SILC_ATTRIBUTE_STATUS_MESSAGE, mime, + sizeof(*mime)); } silc_free(tmp); } @@ -393,10 +432,13 @@ void silc_query_attributes_default(SilcClient client, 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, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); g_strfreev(list); } @@ -488,10 +530,10 @@ void silc_query_attributes_default(SilcClient client, 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); + tmp = silc_file_readfile((*entry) + 8, &tmp_len, NULL); if (tmp) { + tmp[tmp_len] = 0; pk.type = "silc-rsa"; pk.data = tmp; pk.data_len = tmp_len; @@ -500,30 +542,57 @@ void silc_query_attributes_default(SilcClient client, 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; + SilcPublicKey public_key; + SilcVCardStruct vcard; + SilcMime message; + SilcMime extension; + bool nopk; +} *AttrVerify; + +static void silc_query_attributes_verify(SilcBool success, void *context) +{ + *(SilcBool *)context = success; +} + 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); @@ -533,23 +602,26 @@ void silc_query_attributes_print(SILC_SERVER_REC *server, 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); } @@ -600,11 +672,15 @@ void silc_query_attributes_print(SILC_SERVER_REC *server, case SILC_ATTRIBUTE_STATUS_MESSAGE: { - SilcAttributeObjMime mime; - memset(&mime, 0, sizeof(mime)); - if (!silc_attribute_get_object(attr, (void *)&mime, sizeof(mime))) + verify->message = silc_mime_alloc(); + if (!verify->message) continue; - /* XXX */ + if (!silc_attribute_get_object(attr, (void *)verify->message, + sizeof(*verify->message))) + continue; + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MESSAGE, + "present"); } break; @@ -637,6 +713,8 @@ void silc_query_attributes_print(SILC_SERVER_REC *server, 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); } @@ -652,6 +730,17 @@ void silc_query_attributes_print(SILC_SERVER_REC *server, break; case SILC_ATTRIBUTE_EXTENSION: + { + verify->extension = silc_mime_alloc(); + if (!verify->extension) + continue; + 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: @@ -694,11 +783,14 @@ void silc_query_attributes_print(SILC_SERVER_REC *server, 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) @@ -734,15 +826,260 @@ void silc_query_attributes_print(SILC_SERVER_REC *server, } } - 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 (verify->userpk.data) { + SilcPKCSType type = 0; + + if (!strcmp(verify->userpk.type, "silc-rsa")) + type = SILC_PKCS_SILC; + else if (!strcmp(verify->userpk.type, "ssh-rsa")) + type = SILC_PKCS_SSH2; + else if (!strcmp(verify->userpk.type, "x509v3-sign-rsa")) + type = SILC_PKCS_X509V3; + else if (!strcmp(verify->userpk.type, "pgp-sign-rsa")) + type = SILC_PKCS_OPENPGP; + + silc_pkcs_public_key_alloc(type, verify->userpk.data, + verify->userpk.data_len, + &verify->public_key); + } + + if (usersign.data) { + /* Verify the signature now */ + unsigned char *verifyd; + SilcUInt32 verify_len; + SilcBool verified = FALSE; + + if (verify->public_key) { + verifyd = silc_attribute_get_verify_data(attrs, FALSE, &verify_len); + if (verifyd) + silc_pkcs_verify_async(verify->public_key, usersign.data, + usersign.data_len, verifyd, verify_len, + TRUE, sha1hash, + silc_query_attributes_verify, &verified); + + if (verified) { + 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_free(verifyd); + } else { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED); + } + } else { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_NOT_PRESENT); + } + + if (serversign.data) { /* Verify the signature now */ - /* XXX */ + SilcPublicKey public_key; + SilcPKCSType type = 0; + unsigned char *verifyd; + SilcUInt32 verify_len; + SilcBool verified = FALSE; + + if (!strcmp(serverpk.type, "silc-rsa")) + type = SILC_PKCS_SILC; + else if (!strcmp(serverpk.type, "ssh-rsa")) + type = SILC_PKCS_SSH2; + else if (!strcmp(serverpk.type, "x509v3-sign-rsa")) + type = SILC_PKCS_X509V3; + else if (!strcmp(serverpk.type, "pgp-sign-rsa")) + type = SILC_PKCS_OPENPGP; + + if (silc_pkcs_public_key_alloc(type, serverpk.data, + serverpk.data_len, + &public_key)) { + verifyd = silc_attribute_get_verify_data(attrs, TRUE, &verify_len); + if (verifyd) + silc_pkcs_verify_async(public_key, serversign.data, + serversign.data_len, verifyd, + verify_len, TRUE, sha1hash, + silc_query_attributes_verify, &verified); + if (verified) { + 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); + } else { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED); + } + } + + if (verify->public_key) { + silc_verify_public_key(client, conn, SILC_CONN_CLIENT, + verify->public_key, + 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; + 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(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; + 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(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 */ + if (verify->public_key) { + memset(filename2, 0, sizeof(filename2)); + snprintf(filename2, sizeof(filename2) - 1, "%s/clientkey_%s.pub", + filename, fingerprint); + silc_pkcs_save_public_key(filename2, verify->public_key, + SILC_PKCS_FILE_BASE64); + } + + /* Save extension data */ + if (verify->extension) { + memset(filename2, 0, sizeof(filename2)); + snprintf(filename2, sizeof(filename2) - 1, "%s/extension.mime", + filename); + tmp = silc_mime_encode(verify->extension, &len); + if (tmp) + silc_file_writefile(filename2, tmp, len); + } + + /* Save MIME message data */ + if (verify->message) { + memset(filename2, 0, sizeof(filename2)); + snprintf(filename2, sizeof(filename2) - 1, "%s/status_message.mime", + filename); + tmp = silc_mime_encode(verify->message, &len); + if (tmp) + silc_file_writefile(filename2, tmp, 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); }