webpg-npapi 0.6.1
webpgPluginAPI.cpp
00001 /**********************************************************\ 
00002 Original Author: Kyle L. Huff (kylehuff)
00003 
00004 Created:    Jan 14, 2011
00005 License:    GNU General Public License, version 2
00006             http://www.gnu.org/licenses/gpl-2.0.html
00007             
00008 Copyright 2011 Kyle L. Huff, CURETHEITCH development team
00009 \**********************************************************/
00010 
00011 #include "JSObject.h"
00012 #include "variant_list.h"
00013 #include "DOM/Document.h"
00014 #include "DOM/Window.h"
00015 #include "global/config.h"
00016 
00017 #include "webpgPluginAPI.h"
00018 #include "keyedit.h"
00019 
00020 /*
00021  * Define non-member methods/inlines
00022  */
00023 
00024 #ifdef HAVE_W32_SYSTEM
00025 #define __func__ __FUNCTION__
00026 #endif
00027 
00028 FB::VariantMap get_error_map(const std::string& method,
00029                         gpgme_error_t gpg_error_code,
00030                         const std::string& error_string,
00031                         int line, const std::string& file,
00032                         std::string data="")
00033 {
00034     FB::VariantMap error_map_obj;
00035     error_map_obj["error"] = true;
00036     error_map_obj["method"] = method;
00037     error_map_obj["gpg_error_code"] = gpg_error_code;
00038     error_map_obj["error_string"] = error_string;
00039     error_map_obj["line"] = line;
00040     error_map_obj["file"] = file;
00041     if (data.length())
00042         error_map_obj["data"] = data;
00043     return error_map_obj;
00044 }
00045 
00046 /* An inline method to convert a null char */
00047 inline
00048 static const char *
00049     nonnull (const char *s)
00050     {
00051       return s? s :"[none]";
00052     }
00053 
00054 std::string LoadFileAsString(const std::string& filename)
00055 {
00056     std::ifstream fin(filename.c_str());
00057 
00058     if(!fin)
00059     {
00060         return "";
00061     }
00062 
00063     std::ostringstream oss;
00064     oss << fin.rdbuf();
00065 
00066     return oss.str();
00067 }
00068 
00069 static bool gpgme_invalid = false;
00070 
00081 webpgPluginAPI::webpgPluginAPI(const webpgPluginPtr& plugin, const FB::BrowserHostPtr& host) : m_plugin(plugin), m_host(host)
00082 {
00083     static bool allow_op = true;
00084 #ifdef _EXTENSIONIZE
00085     std::string location = m_host->getDOMWindow()->getLocation();
00086     size_t firefox_ext = location.find("chrome://");
00087     size_t chrome_ext = location.find("chrome-extension://");
00088     if (chrome_ext != std::string::npos || firefox_ext != std::string::npos)
00089         allow_op = true;
00090     else
00091         allow_op = false;
00092 #endif
00093 
00094     if (allow_op == true) {
00095         registerMethod("getKeyList", make_method(this, &webpgPluginAPI::getKeyList));
00096         registerMethod("getPublicKeyList", make_method(this, &webpgPluginAPI::getPublicKeyList));
00097         registerMethod("getPrivateKeyList", make_method(this, &webpgPluginAPI::getPrivateKeyList));
00098         registerMethod("getNamedKey", make_method(this, &webpgPluginAPI::getNamedKey));
00099         registerMethod("gpgSetPreference", make_method(this, &webpgPluginAPI::gpgSetPreference));
00100         registerMethod("gpgGetPreference", make_method(this, &webpgPluginAPI::gpgGetPreference));
00101         registerMethod("gpgSetHomeDir", make_method(this, &webpgPluginAPI::gpgSetHomeDir));
00102         registerMethod("gpgGetHomeDir", make_method(this, &webpgPluginAPI::gpgGetHomeDir));
00103         registerMethod("gpgEncrypt", make_method(this, &webpgPluginAPI::gpgEncrypt));
00104         registerMethod("gpgSymmetricEncrypt", make_method(this, &webpgPluginAPI::gpgSymmetricEncrypt));
00105         registerMethod("gpgDecrypt", make_method(this, &webpgPluginAPI::gpgDecrypt));
00106         registerMethod("gpgVerify", make_method(this, &webpgPluginAPI::gpgVerify));
00107         registerMethod("gpgSignText", make_method(this, &webpgPluginAPI::gpgSignText));
00108         registerMethod("gpgSignUID", make_method(this, &webpgPluginAPI::gpgSignUID));
00109         registerMethod("gpgEnableKey", make_method(this, &webpgPluginAPI::gpgEnableKey));
00110         registerMethod("gpgDisableKey", make_method(this, &webpgPluginAPI::gpgDisableKey));
00111         registerMethod("gpgDeleteUIDSign", make_method(this, &webpgPluginAPI::gpgDeleteUIDSign));
00112         registerMethod("gpgGenKey", make_method(this, &webpgPluginAPI::gpgGenKey));
00113         registerMethod("gpgGenSubKey", make_method(this, &webpgPluginAPI::gpgGenSubKey));
00114         registerMethod("gpgImportKey", make_method(this, &webpgPluginAPI::gpgImportKey));
00115         registerMethod("gpgDeletePublicKey", make_method(this, &webpgPluginAPI::gpgDeletePublicKey));
00116         registerMethod("gpgDeletePrivateKey", make_method(this, &webpgPluginAPI::gpgDeletePrivateKey));
00117         registerMethod("gpgDeletePrivateSubKey", make_method(this, &webpgPluginAPI::gpgDeletePrivateSubKey));
00118         registerMethod("gpgSetKeyTrust", make_method(this, &webpgPluginAPI::gpgSetKeyTrust));
00119         registerMethod("gpgAddUID", make_method(this, &webpgPluginAPI::gpgAddUID));
00120         registerMethod("gpgDeleteUID", make_method(this, &webpgPluginAPI::gpgDeleteUID));
00121         registerMethod("gpgSetPrimaryUID", make_method(this, &webpgPluginAPI::gpgSetPrimaryUID));
00122         registerMethod("gpgSetSubkeyExpire", make_method(this, &webpgPluginAPI::gpgSetSubkeyExpire));
00123         registerMethod("gpgSetPubkeyExpire", make_method(this, &webpgPluginAPI::gpgSetPubkeyExpire));
00124         registerMethod("gpgExportPublicKey", make_method(this, &webpgPluginAPI::gpgExportPublicKey));
00125         registerMethod("gpgRevokeKey", make_method(this, &webpgPluginAPI::gpgRevokeKey));
00126         registerMethod("gpgRevokeUID", make_method(this, &webpgPluginAPI::gpgRevokeUID));
00127         registerMethod("gpgRevokeSignature", make_method(this, &webpgPluginAPI::gpgRevokeSignature));
00128         registerMethod("gpgChangePassphrase", make_method(this, &webpgPluginAPI::gpgChangePassphrase));
00129 
00130         registerMethod("setTempGPGOption", make_method(this, &webpgPluginAPI::setTempGPGOption));
00131         registerMethod("restoreGPGConfig", make_method(this, &webpgPluginAPI::restoreGPGConfig));
00132         registerMethod("getTemporaryPath", make_method(this, &webpgPluginAPI::getTemporaryPath));
00133 
00134         registerEvent("onkeygenprogress");
00135         registerEvent("onkeygencomplete");
00136     }
00137 
00138     // Read-only property
00139     registerProperty("version",
00140                      make_property(this,
00141                         &webpgPluginAPI::get_version));
00142 
00143     registerProperty("webpg_status",
00144                     make_property(this,
00145                         &webpgPluginAPI::get_webpg_status));
00146 
00147     registerProperty("gpgconf_detected",
00148                      make_property(this,
00149                         &webpgPluginAPI::gpgconf_detected));
00150 
00151     webpgPluginAPI::init();
00152 }
00153 
00161 webpgPluginAPI::~webpgPluginAPI()
00162 {
00163 }
00164 
00173 webpgPluginPtr webpgPluginAPI::getPlugin()
00174 {
00175     webpgPluginPtr plugin(m_plugin.lock());
00176     if (!plugin) {
00177         throw FB::script_error("The plugin is invalid");
00178     }
00179     return plugin;
00180 }
00181 
00187 void webpgPluginAPI::init()
00188 {
00189     gpgme_ctx_t ctx;
00190     gpgme_error_t err;
00191     FB::VariantMap error_map;
00192     FB::VariantMap response;
00193     FB::VariantMap protocol_info, plugin_info;
00194     gpgme_engine_info_t engine_info;
00195 
00196     plugin_info["source_url"] = m_host->getDOMWindow()->getLocation();
00197     plugin_info["path"] = getPlugin()->getPluginPath();
00198     plugin_info["params"] = getPlugin()->getPluginParams();
00199     plugin_info["version"] = FBSTRING_PLUGIN_VERSION;
00200     response["plugin"] = plugin_info;
00201 
00202 #ifdef _EXTENSIONIZE
00203     response["extensionize"] = true;
00204     std::string location = m_host->getDOMWindow()->getLocation();
00205     size_t firefox_ext = location.find("chrome://");
00206     size_t chrome_ext = location.find("chrome-extension://");
00207     response["extension"] = (chrome_ext != std::string::npos) ?
00208         "chrome" : (firefox_ext != std::string::npos) ? "firefox" : "unknown";
00209 #endif
00210 
00211     /* Initialize the locale environment.
00212      * The function `gpgme_check_version` must be called before any other
00213      * function in the library, because it initializes the thread support
00214      * subsystem in GPGME. (from the info page) */
00215     std::string gpgme_version = (char *) gpgme_check_version(NULL);
00216 
00217     setlocale (LC_ALL, "");
00218     gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
00219 #ifdef LC_MESSAGES
00220     gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
00221 #endif
00222 
00223     err = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP);
00224     if (err != GPG_ERR_NO_ERROR)
00225         error_map = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00226 
00227     if (error_map.size()) {
00228         response["openpgp_valid"] = false;
00229         response["error"] = true;
00230         response["error_map"] = error_map;
00231         webpgPluginAPI::webpg_status_map = error_map;
00232         gpgme_invalid = true;
00233         return;
00234     }
00235 
00236     ctx = get_gpgme_ctx();
00237 
00238     response["error"] = false;
00239     response["gpgme_valid"] = true;
00240     response["gpgconf_detected"] = gpgconf_detected();
00241     if (!gpgconf_detected())
00242         response["gpgconf_response"] = gpgme_strerror (gpgme_engine_check_version (GPGME_PROTOCOL_GPGCONF));
00243     response["gpgme_version"] = gpgme_version;
00244     engine_info = gpgme_ctx_get_engine_info (ctx);
00245     if (engine_info) {
00246         if (engine_info->file_name)
00247             protocol_info["file_name"] = (char *) engine_info->file_name;
00248         if (engine_info->version)
00249             protocol_info["version"] = (char *) engine_info->version;
00250         if (engine_info->home_dir)
00251             protocol_info["home_dir"] = (char *) engine_info->home_dir;
00252         if (engine_info->req_version)
00253             protocol_info["req_version"] = (char *) engine_info->req_version;
00254         response[(char *) gpgme_get_protocol_name (engine_info->protocol)] = protocol_info;
00255     } else {
00256         response["OpenPGP"] = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00257     }
00258 
00259     response["GNUPGHOME"] = GNUPGHOME;
00260 
00261     // Retrieve the GPG_AGENT_INFO environment variable
00262     char *gpg_agent_info = getenv("GPG_AGENT_INFO");
00263 
00264     if (gpg_agent_info != NULL) {
00265         response["gpg_agent_info"] = gpg_agent_info;
00266     } else {
00267         response["gpg_agent_info"] = "unknown";
00268     }
00269 
00270     if (ctx)
00271         gpgme_release (ctx);
00272 
00273     webpgPluginAPI::webpg_status_map = response;
00274 };
00275 
00281 gpgme_ctx_t webpgPluginAPI::get_gpgme_ctx()
00282 {
00283     gpgme_ctx_t ctx;
00284     gpgme_error_t err;
00285 
00286     setlocale (LC_ALL, "");
00287     gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
00288 #ifdef LC_MESSAGES
00289     gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
00290 #endif
00291 
00292     // Check the GNUPGHOME variable, if not null, set that
00293     if (GNUPGHOME.length() > 0) {
00294         err = gpgme_new (&ctx);
00295         gpgme_engine_info_t engine_info = gpgme_ctx_get_engine_info (ctx);
00296         if (engine_info) {
00297             err = gpgme_ctx_set_engine_info (ctx, engine_info->protocol,
00298                 engine_info->file_name,
00299                 GNUPGHOME.c_str());
00300         } else {
00301             std::string env = "GNUPGHOME=" + GNUPGHOME;
00302             putenv(strdup(env.c_str()));
00303             err = gpgme_new (&ctx);
00304         }
00305     } else {
00306         err = gpgme_new (&ctx);
00307     }
00308 
00309     gpgme_set_textmode (ctx, 1);
00310     gpgme_set_armor (ctx, 1);
00311 
00312     return ctx;
00313 }
00314 
00321 std::string webpgPluginAPI::getGPGConfigFilename() {
00322     std::string config_path = "";
00323 
00324     if (GNUPGHOME.length() > 0) {
00325         config_path = GNUPGHOME;
00326     } else {
00327         char const* home = getenv("HOME");
00328         if (home || (home = getenv("USERPROFILE"))) {
00329           config_path = home;
00330         } else {
00331           char const *hdrive = getenv("HOMEDRIVE"),
00332             *hpath = getenv("HOMEPATH");
00333           assert(hdrive);  // or other error handling
00334           assert(hpath);
00335           config_path = std::string(hdrive) + hpath;
00336         }
00337     }
00338 
00339 #ifdef HAVE_W32_SYSTEM
00340     config_path += "\\Application Data\\gnupg\\gpg.conf";
00341 #else
00342     config_path += "/.gnupg/gpg.conf";
00343 #endif
00344 
00345     return config_path;
00346 }
00347 
00354 FB::variant webpgPluginAPI::setTempGPGOption(const std::string& option, const std::string& value) {
00355 
00356     std::string result;
00357     std::string config_path = webpgPluginAPI::getGPGConfigFilename();
00358     std::string tmp_config_path = config_path + "-webpg.save";
00359 
00360     std::string gpgconfigfile = LoadFileAsString(config_path);
00361 
00362     if (gpgconfigfile.length()) {
00363         // Test if we already made a backup, if not, make one!
00364         std::ifstream tmp_config_exists(tmp_config_path.c_str());
00365         if (!tmp_config_exists) {
00366             // Backup the current contents
00367             std::ofstream tmp_file(tmp_config_path.c_str());
00368             if (!tmp_file)
00369                 return "error opening temp_file";
00370             tmp_file << gpgconfigfile;
00371             tmp_file.close();
00372         }
00373 
00374         // Ensure we are not appending to an existing line
00375         gpgconfigfile += "\n";
00376         gpgconfigfile += option;
00377         if (value.length())
00378             gpgconfigfile += " " + value;
00379         gpgconfigfile += "\n";
00380 
00381         std::ofstream gpg_file(config_path.c_str());
00382         if (!gpg_file)
00383             return "error writing gpg_file";
00384         gpg_file << gpgconfigfile;
00385         gpg_file.close();
00386     }
00387 
00388     if (gpgconfigfile.length())
00389         result = "Set ";
00390     else
00391         result = "Unable to set ";
00392 
00393     if (value.length())
00394         result += "'" + option + " = " + value + "' in file: " + config_path;
00395     else
00396         result += "'" + option + "' in file: " + config_path;
00397 
00398     return result;
00399 }
00400 
00406 FB::variant webpgPluginAPI::restoreGPGConfig() {
00407 
00408     std::string config_path = getGPGConfigFilename();
00409     std::string tmp_config_path = config_path + "-webpg.save";
00410 
00411     std::string restore_string;
00412     std::string result = "gpg config restored from memory";
00413 
00414     if (!original_gpg_config.length()) {
00415         // We don't have the original file in memory, lets restore the backup
00416         original_gpg_config = LoadFileAsString(tmp_config_path);
00417         if (!original_gpg_config.length())
00418             return "error restoring gpg_file from disk";
00419         result = "gpg config restored from disk.";
00420     }
00421 
00422     std::ofstream gpg_file(config_path.c_str());
00423 
00424     if (!gpg_file)
00425         return "error restoring gpg_file from memory";
00426 
00427     gpg_file << original_gpg_config;
00428     gpg_file.close();
00429 
00430     remove(tmp_config_path.c_str());
00431     original_gpg_config = "";
00432 
00433     return result;
00434 }
00435 
00443 FB::variant webpgPluginAPI::gpgSetHomeDir(const std::string& gnupg_path)
00444 {
00445     GNUPGHOME = gnupg_path;
00446     return GNUPGHOME;
00447 }
00448 
00449 FB::variant webpgPluginAPI::gpgGetHomeDir()
00450 {
00451     return GNUPGHOME;
00452 }
00453 
00459 FB::variant webpgPluginAPI::getTemporaryPath()
00460 {
00461     char *gnupghome_envvar = getenv("TEMP");
00462     if (gnupghome_envvar != NULL) {
00463         return gnupghome_envvar;
00464     } else {
00465         return "";
00466     }
00467 }
00468 
00477 
00503 
00504 FB::VariantMap webpgPluginAPI::get_webpg_status()
00505 {
00506     webpgPluginAPI::init();
00507     webpgPluginAPI::webpg_status_map["edit_status"] = edit_status;
00508     return webpgPluginAPI::webpg_status_map;
00509 }
00510 
00521 
00624 
00625 /*
00626     This method retrieves all keys matching name, or if name is left empty,
00627         returns all keys in the keyring.
00628     NOTE: This method is not exposed to the NPAPI plugin, it is only called internally
00629 */
00630 FB::VariantMap webpgPluginAPI::getKeyList(const std::string& name, int secret_only)
00631 {
00632     /* declare variables */
00633     gpgme_ctx_t ctx = get_gpgme_ctx();
00634     gpgme_error_t err;
00635     gpgme_key_t key;
00636     gpgme_keylist_result_t result;
00637     gpgme_user_id_t uid;
00638     gpgme_key_sig_t sig;
00639     gpgme_subkey_t subkey;
00640     FB::VariantMap keylist_map;
00641 
00642     FB::VariantMap uid_map;
00643 
00644     /* set protocol to use in our context */
00645     err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
00646     if(err != GPG_ERR_NO_ERROR)
00647         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00648 
00649     /* apply the keylist mode to the context and set
00650         the keylist_mode 
00651         NOTE: The keylist mode flag GPGME_KEYLIST_MODE_SIGS 
00652             returns the signatures of UIDS with the key */
00653     gpgme_set_keylist_mode (ctx, (gpgme_get_keylist_mode (ctx)
00654                                 | GPGME_KEYLIST_MODE_SIGS
00655                                 | GPGME_KEYLIST_MODE_VALIDATE));
00656 
00657     /* gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only) */
00658     if (name.length() > 0){ // limit key listing to search criteria 'name'
00659         err = gpgme_op_keylist_start (ctx, name.c_str(), secret_only);
00660     } else { // list all keys
00661         err = gpgme_op_keylist_start (ctx, NULL, secret_only);
00662     }
00663     if(err != GPG_ERR_NO_ERROR)
00664         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00665 
00666     while (!(err = gpgme_op_keylist_next (ctx, &key)))
00667      {
00668         /*declare nuids (Number of UIDs) 
00669             and nsigs (Number of signatures)
00670             and nsubs (Number of Subkeys)*/
00671         int nuids;
00672         int nsigs;
00673         int nsubs;
00674         int tnsigs;
00675         FB::VariantMap key_map;
00676 
00677         /* if secret keys being returned, re-retrieve the key so we get all of the key info */ 
00678         if(secret_only != 0 && key->subkeys && key->subkeys->keyid)
00679             err = gpgme_get_key (ctx, key->subkeys->keyid, &key, 0);
00680 
00681         /* iterate through the keys/subkeys and add them to the key_map object */
00682         if (key->uids && key->uids->name)
00683             key_map["name"] = nonnull (key->uids->name);
00684         if (key->subkeys && key->subkeys->fpr)
00685             key_map["fingerprint"] = nonnull (key->subkeys->fpr);
00686         if (key->uids && key->uids->email)
00687             key_map["email"] = nonnull (key->uids->email);
00688         key_map["expired"] = key->expired? true : false;
00689         key_map["revoked"] = key->revoked? true : false;
00690         key_map["disabled"] = key->disabled? true : false;
00691         key_map["invalid"] = key->invalid? true : false;
00692         key_map["secret"] = key->secret? true : false;
00693         key_map["protocol"] = key->protocol == GPGME_PROTOCOL_OpenPGP? "OpenPGP":
00694             key->protocol == GPGME_PROTOCOL_CMS? "CMS":
00695             key->protocol == GPGME_PROTOCOL_UNKNOWN? "Unknown": "[?]";
00696         key_map["can_encrypt"] = key->can_encrypt? true : false;
00697         key_map["can_sign"] = key->can_sign? true : false;
00698         key_map["can_certify"] = key->can_certify? true : false;
00699         key_map["can_authenticate"] = key->can_authenticate? true : false;
00700         key_map["is_qualified"] = key->is_qualified? true : false;
00701         key_map["owner_trust"] = key->owner_trust == GPGME_VALIDITY_UNKNOWN? "unknown":
00702             key->owner_trust == GPGME_VALIDITY_UNDEFINED? "undefined":
00703             key->owner_trust == GPGME_VALIDITY_NEVER? "never":
00704             key->owner_trust == GPGME_VALIDITY_MARGINAL? "marginal":
00705             key->owner_trust == GPGME_VALIDITY_FULL? "full":
00706             key->owner_trust == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]";
00707 
00708         FB::VariantMap subkeys_map;
00709         for (nsubs=0, subkey=key->subkeys; subkey; subkey = subkey->next, nsubs++) {
00710             FB::VariantMap subkey_item_map;
00711             subkey_item_map["subkey"] = nonnull (subkey->fpr);
00712             subkey_item_map["expired"] = subkey->expired? true : false;
00713             subkey_item_map["revoked"] = subkey->revoked? true : false;
00714             subkey_item_map["disabled"] = subkey->disabled? true : false;
00715             subkey_item_map["invalid"] = subkey->invalid? true : false;
00716             subkey_item_map["secret"] = subkey->secret? true : false;
00717             subkey_item_map["can_encrypt"] = subkey->can_encrypt? true : false;
00718             subkey_item_map["can_sign"] = subkey->can_sign? true : false;
00719             subkey_item_map["can_certify"] = subkey->can_certify? true : false;
00720             subkey_item_map["can_authenticate"] = subkey->can_authenticate? true : false;
00721             subkey_item_map["is_qualified"] = subkey->is_qualified? true : false;
00722             subkey_item_map["algorithm"] = subkey->pubkey_algo;
00723             subkey_item_map["algorithm_name"] = nonnull (gpgme_pubkey_algo_name(subkey->pubkey_algo));
00724             subkey_item_map["size"] = subkey->length;
00725             subkey_item_map["created"] = subkey->timestamp;
00726             subkey_item_map["expires"] = subkey->expires;
00727             subkeys_map[i_to_str(nsubs)] = subkey_item_map;
00728         }
00729 
00730         key_map["subkeys"] = subkeys_map;
00731 
00732         FB::VariantMap uids_map;
00733         for (nuids=0, uid=key->uids; uid; uid = uid->next, nuids++) {
00734             FB::VariantMap uid_item_map;
00735             uid_item_map["uid"] = nonnull (uid->name);
00736             uid_item_map["email"] = nonnull (uid->email);
00737             uid_item_map["comment"] = nonnull (uid->comment);
00738             uid_item_map["invalid"] = uid->invalid? true : false;
00739             uid_item_map["revoked"] = uid->revoked? true : false;
00740             tnsigs = 0;
00741             for (nsigs=0, sig=uid->signatures; sig; sig = sig->next, nsigs++) {
00742                 tnsigs += 1;
00743             }
00744             uid_item_map["signatures_count"] = tnsigs;
00745 
00746             FB::VariantMap signatures_map;
00747 
00748             for (nsigs=0, sig=uid->signatures; sig; sig = sig->next, nsigs++) {
00749                 FB::VariantMap signature_map;
00750                 signature_map["keyid"] = nonnull (sig->keyid);
00751                 signature_map["algorithm"] = sig->pubkey_algo;
00752                 signature_map["algorithm_name"] = nonnull (gpgme_pubkey_algo_name(sig->pubkey_algo));
00753                 signature_map["revoked"] = sig->revoked? true : false;
00754                 signature_map["expired"] = sig->expired? true : false;
00755                 signature_map["invalid"] = sig->invalid? true : false;
00756                 signature_map["exportable"] = sig->exportable? true : false;
00757                 signature_map["created"] = sig->timestamp;
00758                 signature_map["expires"] = sig->expires;
00759                 signature_map["uid"] = nonnull (sig->uid);
00760                 signature_map["name"] = nonnull (sig->name);
00761                 signature_map["comment"] = nonnull (sig->comment);
00762                 signature_map["email"] = nonnull (sig->email);
00763                 signatures_map[i_to_str(nsigs)] = signature_map;
00764             }
00765             uid_item_map["signatures"] = signatures_map;
00766             uid_item_map["validity"] = uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
00767                 uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
00768                 uid->validity == GPGME_VALIDITY_NEVER? "never":
00769                 uid->validity == GPGME_VALIDITY_MARGINAL? "marginal":
00770                 uid->validity == GPGME_VALIDITY_FULL? "full":
00771                 uid->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]";
00772             uids_map[i_to_str(nuids)] = uid_item_map;
00773         }
00774         key_map["uids"] = uids_map;
00775         keylist_map[key->subkeys->keyid] = key_map;
00776         gpgme_key_unref (key);
00777     }
00778 
00779     if (gpg_err_code (err) != GPG_ERR_EOF) exit(6);
00780     err = gpgme_op_keylist_end (ctx);
00781     if(err != GPG_ERR_NO_ERROR) exit(7);
00782     result = gpgme_op_keylist_result (ctx);
00783     if (result->truncated)
00784      {
00785         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00786      }
00787     gpgme_release (ctx);
00788     return keylist_map;
00789 }
00790 
00798 /*
00799     This method executes webpgPlugin.getKeyList with an empty string and
00800         secret_only=0 which returns all Public Keys in the keyring.
00801 */
00802 FB::variant webpgPluginAPI::getPublicKeyList()
00803 {
00804     // Retrieve the public keylist
00805     FB::variant public_keylist = webpgPluginAPI::getKeyList("", 0);
00806 
00807     // Retrieve a reference to the DOM Window
00808     FB::DOM::WindowPtr window = m_host->getDOMWindow();
00809 
00810     // Check if the DOM Window has an in-built JSON Parser
00811     if (window && window->getJSObject()->HasProperty("JSON")) {
00812         // Convert the VariantMap to a Json::Value object
00813         Json::Value json_value = FB::variantToJsonValue(public_keylist);
00814 
00815         // Create a writer that will convert the object to a string
00816         Json::FastWriter writer;
00817 
00818         // Create a reference to the browswer JSON object
00819         FB::JSObjectPtr obj = window->getProperty<FB::JSObjectPtr>("JSON");
00820 
00821         return obj->Invoke("parse", FB::variant_list_of(writer.write(json_value)));
00822     } else {
00823         // No browser JSON parser detected, falling back to return of FB::variant
00824         return public_keylist;
00825     }
00826 }
00827 
00835 /*
00836     This method executes webpgPlugin.getKeyList with an empty string and
00837         secret_only=1 which returns all keys in the keyring which
00838         the user has the corrisponding secret key.
00839 */
00840 FB::variant webpgPluginAPI::getPrivateKeyList()
00841 {
00842     // Retrieve the private keylist
00843     FB::variant private_keylist = webpgPluginAPI::getKeyList("", 1);
00844 
00845     // Retrieve a reference to the DOM Window
00846     FB::DOM::WindowPtr window = m_host->getDOMWindow();
00847 
00848     // Check if the DOM Window has an in-built JSON Parser
00849     if (window && window->getJSObject()->HasProperty("JSON")) {
00850         // Convert the VariantMap to a Json::Value object
00851         Json::Value json_value = FB::variantToJsonValue(private_keylist);
00852 
00853         // Create a writer that will convert the object to a string
00854         Json::FastWriter writer;
00855 
00856         // Create a reference to the browswer JSON object
00857         FB::JSObjectPtr obj = window->getProperty<FB::JSObjectPtr>("JSON");
00858 
00859         return obj->Invoke("parse", FB::variant_list_of(writer.write(json_value)));
00860     } else {
00861         // No browser JSON parser detected, falling back to return of FB::variant
00862         return private_keylist;
00863     }
00864 }
00865 
00873 /*
00874     This method just calls webpgPlugin.getKeyList with a name/email
00875         as the parameter
00876 */
00877 FB::variant webpgPluginAPI::getNamedKey(const std::string& name)
00878 {
00879     // Retrieve the keylist as a VariantMap
00880     FB::variant keylist = webpgPluginAPI::getKeyList(name, 0);
00881 
00882     // Retrieve a reference to the DOM Window
00883     FB::DOM::WindowPtr window = m_host->getDOMWindow();
00884 
00885     // Check if the DOM Window has an in-built JSON Parser
00886     if (window && window->getJSObject()->HasProperty("JSON")) {
00887         // Convert the VariantMap to a Json::Value object
00888         Json::Value json_value = FB::variantToJsonValue(keylist);
00889 
00890         // Create a writer that will convert the object to a string
00891         Json::FastWriter writer;
00892 
00893         // Create a reference to the browswer JSON object
00894         FB::JSObjectPtr obj = window->getProperty<FB::JSObjectPtr>("JSON");
00895 
00896         return obj->Invoke("parse", FB::variant_list_of(writer.write(json_value)));
00897     } else {
00898         // No browser JSON parser detected, falling back to return of FB::variant
00899         return keylist;
00900     }
00901 }
00902 
00908 bool webpgPluginAPI::gpgconf_detected() {
00909     gpgme_error_t err;
00910     std::string cfg_present;
00911     err = gpgme_engine_check_version (GPGME_PROTOCOL_GPGCONF);
00912     if (err && err != GPG_ERR_NO_ERROR) {
00913         return false;
00914     }
00915     return true;
00916 }
00917 
00926 std::string webpgPluginAPI::get_preference(const std::string& preference)
00927 {
00928     gpgme_ctx_t ctx = get_gpgme_ctx();
00929     gpgme_error_t err;
00930     gpgme_conf_comp_t conf, comp;
00931     gpgme_conf_opt_t opt;
00932     std::string return_value;
00933 
00934     err = gpgme_op_conf_load (ctx, &conf);
00935 
00936     comp = conf;
00937     while (comp && strcmp (comp->name, "gpg"))
00938         comp = comp->next;
00939 
00940     if (comp) {
00941         opt = comp->options;
00942         while (opt && strcmp (opt->name, (char *) preference.c_str())){
00943             opt = opt->next;
00944         }
00945 
00946         if (opt->value) {
00947             return_value = opt->value->value.string;
00948         } else {
00949             return_value = "blank";
00950         }
00951     }
00952 
00953     gpgme_conf_release (conf);
00954 
00955     return return_value;
00956 
00957 }
00958 
00968 FB::variant webpgPluginAPI::gpgSetPreference(const std::string& preference, const std::string& pref_value)
00969 {
00970     gpgme_error_t err;
00971     gpgme_protocol_t proto = GPGME_PROTOCOL_OpenPGP;
00972     err = gpgme_engine_check_version (proto);
00973     if (err != GPG_ERR_NO_ERROR)
00974         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00975 
00976     gpgme_ctx_t ctx = get_gpgme_ctx();
00977     gpgme_conf_comp_t conf, comp;
00978     FB::variant response;
00979     std::string return_code;
00980 
00981     err = gpgme_op_conf_load (ctx, &conf);
00982     if (err != GPG_ERR_NO_ERROR)
00983         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00984 
00985     gpgme_conf_arg_t original_arg, arg;
00986     gpgme_conf_opt_t opt;
00987 
00988     if (pref_value.length())
00989         err = gpgme_conf_arg_new (&arg, GPGME_CONF_STRING, (char *) pref_value.c_str());
00990     else
00991         err = gpgme_conf_arg_new (&arg, GPGME_CONF_STRING, NULL);
00992 
00993     if (err != GPG_ERR_NO_ERROR)
00994         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
00995 
00996     comp = conf;
00997     while (comp && strcmp (comp->name, "gpg"))
00998         comp = comp->next;
00999 
01000     if (comp) {
01001         opt = comp->options;
01002 
01003         while (opt && strcmp (opt->name, (char *) preference.c_str())){
01004             opt = opt->next;
01005         }
01006 
01007         if (!opt) {
01008             return "unable to locate that option in this context";
01009         }
01010 
01011         if (opt->value && pref_value.length()) {
01012             original_arg = opt->value;
01013         } else {
01014             original_arg = opt->value;
01015             return_code = "blank";
01016         }
01017 
01018         /* if the new argument and original argument are the same, return 0, 
01019             there is nothing to do. */
01020         if (pref_value.length() && original_arg && 
01021             !strcmp (original_arg->value.string, arg->value.string)) {
01022             return "0";
01023         }
01024 
01025         if (opt) {
01026             if (!strcmp(pref_value.c_str(), "blank") || pref_value.length() < 1)
01027                 err = gpgme_conf_opt_change (opt, 0, NULL);
01028             else
01029                 err = gpgme_conf_opt_change (opt, 0, arg);
01030 
01031             if (err != GPG_ERR_NO_ERROR)
01032                 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01033 
01034             err = gpgme_op_conf_save (ctx, comp);
01035             if (err != GPG_ERR_NO_ERROR)
01036                 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01037         }
01038     }
01039 
01040     if (conf)
01041         gpgme_conf_release (conf);
01042 
01043     if (ctx)
01044         gpgme_release (ctx);
01045 
01046     if (!return_code.length())
01047         return_code = strdup(original_arg->value.string);
01048 
01049     return return_code;
01050 }
01051 
01060 FB::variant webpgPluginAPI::gpgGetPreference(const std::string& preference)
01061 {
01062     gpgme_error_t err;
01063     gpgme_protocol_t proto = GPGME_PROTOCOL_OpenPGP;
01064     err = gpgme_engine_check_version (proto);
01065     if (err != GPG_ERR_NO_ERROR)
01066         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01067 
01068     gpgme_ctx_t ctx = get_gpgme_ctx();
01069     gpgme_conf_comp_t conf, comp;
01070     FB::VariantMap response;
01071     response["error"] = false;
01072 
01073     err = gpgme_op_conf_load (ctx, &conf);
01074     if (err != GPG_ERR_NO_ERROR)
01075         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01076 
01077     gpgme_conf_arg_t arg;
01078     gpgme_conf_opt_t opt;
01079 
01080     comp = conf;
01081     while (comp && strcmp (comp->name, "gpg"))
01082         comp = comp->next;
01083 
01084     if (comp) {
01085         opt = comp->options;
01086 
01087         while (opt && strcmp (opt->name, (char *) preference.c_str())){
01088             opt = opt->next;
01089         }
01090 
01091         if (opt) {
01092             if (opt->value) {
01093                 arg = opt->value;
01094                 response["value"] = strdup(arg->value.string);
01095             } else {
01096                 response["value"] = "";
01097             }
01098         } else {
01099             response["error"] = true;
01100             response["error_string"] = "unable to locate that option in this context";
01101         }
01102     }
01103 
01104     if (conf)
01105         gpgme_conf_release (conf);
01106 
01107     if (ctx)
01108         gpgme_release (ctx);
01109 
01110     return response;
01111 }
01112 
01124 
01138 
01139 /*
01140     This method passes a string to encrypt, a list of keys to encrypt to calls
01141         webpgPlugin.gpgEncrypt. This method returns a string of encrypted data.
01142 */
01143 /* This method accepts 3 parameters, data, enc_to_keyid 
01144     and sign [optional; default: 0:NULL:false]
01145     the return value is a string buffer of the result */
01146 FB::variant webpgPluginAPI::gpgEncrypt(const std::string& data, 
01147         const FB::VariantList& enc_to_keyids, bool sign)
01148 {
01149     /* declare variables */
01150     gpgme_ctx_t ctx = get_gpgme_ctx();
01151     gpgme_error_t err;
01152     gpgme_data_t in, out;
01153 #ifdef HAVE_W32_SYSTEM
01154     // FIXME: W32 doesn't like the array sized by the contents of the
01155     // enc_to_keyids - for now set to 100
01156     gpgme_key_t key[100];
01157 #else
01158     gpgme_key_t key[enc_to_keyids.size()];
01159 #endif
01160     int nrecipients;
01161     FB::variant recipient;
01162     FB::VariantList recpients;
01163     gpgme_encrypt_result_t enc_result;
01164     FB::VariantMap response;
01165     bool unusable_key = false;
01166 
01167     err = gpgme_data_new_from_mem (&in, data.c_str(), data.length(), 0);
01168     if (err != GPG_ERR_NO_ERROR)
01169         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01170 
01171     err = gpgme_data_set_encoding(in, GPGME_DATA_ENCODING_ARMOR);
01172     if(err != GPG_ERR_NO_ERROR)
01173         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01174 
01175     err = gpgme_data_new (&out);
01176     if (err != GPG_ERR_NO_ERROR)
01177         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01178 
01179     err = gpgme_data_set_encoding(out, GPGME_DATA_ENCODING_ARMOR);
01180     if(err != GPG_ERR_NO_ERROR)
01181         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01182 
01183     for (nrecipients=0; nrecipients < enc_to_keyids.size(); nrecipients++) {
01184 
01185         recipient = enc_to_keyids[nrecipients];
01186 
01187         err = gpgme_get_key (ctx, recipient.convert_cast<std::string>().c_str(), &key[nrecipients], 0);
01188         if(err != GPG_ERR_NO_ERROR)
01189             return get_error_map(__func__, gpgme_err_code (err),
01190                 gpgme_strerror (err), __LINE__, __FILE__,
01191                 recipient.convert_cast<std::string>().c_str());
01192 
01193         // Check if key is unusable/invalid
01194         unusable_key = key[nrecipients]->invalid? true :
01195             key[nrecipients]->expired? true :
01196             key[nrecipients]->revoked? true :
01197             key[nrecipients]->disabled? true : false;
01198 
01199         if (unusable_key) {
01200             // Somehow an ususable/invalid key has been passed to the method
01201             std::string keyid = key[nrecipients]->subkeys->fpr;
01202 
01203             std::string strerror = key[nrecipients]->invalid? "Invalid key" :
01204             key[nrecipients]->expired? "Key expired" :
01205             key[nrecipients]->revoked? "Key revoked" :
01206             key[nrecipients]->disabled? "Key disabled" : "Unknown error";
01207 
01208             err = key[nrecipients]->invalid? 53 :
01209             key[nrecipients]->expired? 153 :
01210             key[nrecipients]->revoked? 94 :
01211             key[nrecipients]->disabled? 53 : GPG_ERR_UNKNOWN_ERRNO;
01212 
01213             return get_error_map(__func__, gpgme_err_code (err), strerror, __LINE__, __FILE__, keyid);
01214         }
01215 
01216     }
01217 
01218     // NULL terminate the key array
01219     key[enc_to_keyids.size()] = NULL;
01220 
01221     if (sign) {
01222         if (enc_to_keyids.size() < 1) {
01223             // NOTE: This doesn't actually work due to an issue with gpgme-1.3.2.
01224             //  see: https://bugs.g10code.com/gnupg/issue1440 for details
01225             //err = gpgme_op_encrypt_sign (ctx, NULL, GPGME_ENCRYPT_NO_ENCRYPT_TO, in, out);
01226             return "Signed Symmetric Encryption is not yet implemented";
01227         } else {
01228             err = gpgme_op_encrypt_sign (ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
01229         }
01230     } else {
01231         if (enc_to_keyids.size() < 1) {
01232             // Symmetric encrypt
01233             err = gpgme_op_encrypt (ctx, NULL, GPGME_ENCRYPT_NO_ENCRYPT_TO, in, out);
01234         } else {
01235             err = gpgme_op_encrypt (ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
01236         }
01237     }
01238 
01239     if (err != GPG_ERR_NO_ERROR)
01240         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01241 
01242     if (enc_to_keyids.size() < 1) {
01243         // This was a symmetric operation, and gpgme_op_encrypt does not return
01244         //  an error if the passphrase is incorrect, so we need to check the
01245         //  returned value for actual substance.
01246         gpgme_data_seek(out, 0, SEEK_SET);
01247         char buf[513];
01248         gpgme_data_read (out, buf, 512);
01249         int buflen = strlen(buf);
01250         if (buflen < 52) {
01251             gpgme_release (ctx);
01252             gpgme_data_release (in);
01253             gpgme_data_release (out);
01254             FB::VariantMap error_map_obj;
01255             error_map_obj["error"] = true;
01256             error_map_obj["method"] = __func__;
01257             error_map_obj["gpg_error_code"] = "11";
01258             error_map_obj["error_string"] = "Passphrase did not match";
01259             error_map_obj["line"] = __LINE__;
01260             error_map_obj["file"] = __FILE__;
01261             return error_map_obj;
01262         }
01263     }
01264 
01265     enc_result = gpgme_op_encrypt_result (ctx);
01266     if (enc_result->invalid_recipients)
01267     {
01268         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01269     }
01270 
01271     size_t out_size = 0;
01272     std::string out_buf;
01273     out_buf = gpgme_data_release_and_get_mem (out, &out_size);
01274     /* strip the size_t data out of the output buffer */
01275     out_buf = out_buf.substr(0, out_size);
01276     /* set the output object to NULL since it has
01277         already been released */
01278     out = NULL;
01279 
01280     /* if any of the gpgme objects have not yet
01281         been release, do so now */
01282     for (nrecipients=0; nrecipients < enc_to_keyids.size(); nrecipients++)
01283         gpgme_key_unref(key[nrecipients]);
01284 
01285     if (ctx)
01286         gpgme_release (ctx);
01287     if (in)
01288         gpgme_data_release (in);
01289     if (out)
01290         gpgme_data_release (out);
01291 
01292     response["data"] = out_buf;
01293     response["error"] = false;
01294 
01295     return response;
01296 }
01297 
01309 /*
01310     This method just calls webpgPlugin.gpgEncrypt without any keys
01311         as the parameter, which then uses Symmetric Encryption.
01312 */
01313 /* This method accepts 2 parameters, data and sign [optional;
01314     default: 0:NULL:false].
01315     the return value is a string buffer of the result */
01316 FB::variant webpgPluginAPI::gpgSymmetricEncrypt(const std::string& data,
01317         bool sign)
01318 {
01319     FB::VariantList empty_keys;
01320     return webpgPluginAPI::gpgEncrypt(data, empty_keys, sign);
01321 }
01322 
01336 
01353 
01354 FB::variant webpgPluginAPI::gpgDecryptVerify(const std::string& data, int use_agent)
01355 {
01356     gpgme_ctx_t ctx;
01357     gpgme_error_t err;
01358     gpgme_decrypt_result_t decrypt_result;
01359     gpgme_verify_result_t verify_result;
01360     gpgme_signature_t sig;
01361     gpgme_data_t in, out;
01362     std::string out_buf;
01363     std::string envvar;
01364     FB::VariantMap response;
01365     int nsigs;
01366     int tnsigs = 0;
01367     char buf[513];
01368     int ret;
01369 
01370     char *agent_info = getenv("GPG_AGENT_INFO");
01371 
01372     if (use_agent == 0) {
01373         // Set the GPG_AGENT_INFO to null because the user shouldn't be bothered with for
01374         //  a passphrase if we get a chunk of encrypted data by mistake.
01375         setTempGPGOption("batch", "");
01376         // Set the defined password to be "", if anything else is sent to the
01377         //  agent, this will result in a return error of invalid key when
01378         //  performing Symmetric decryption (because the passphrase is the
01379         //  secret key)
01380         setTempGPGOption("passphrase", "\"\"");
01381 #ifndef HAVE_W32_SYSTEM
01382 #ifndef FB_MACOSX
01383         // Poison the GPG_AGENT_INFO environment variable
01384         envvar = "GPG_AGENT_INFO=INVALID";
01385         putenv(strdup(envvar.c_str()));
01386 #endif
01387 #endif
01388         // Create our context with the above modifications
01389         ctx = get_gpgme_ctx();
01390         // Set the passphrase callback to just send "\n", which will
01391         //  deal with the case there is no gpg-agent
01392         gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
01393     } else {
01394         ctx = get_gpgme_ctx();
01395     }
01396 
01397     err = gpgme_data_new_from_mem (&in, data.c_str(), data.length(), 0);
01398     if (err != GPG_ERR_NO_ERROR) {
01399         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01400     }
01401 
01402     err = gpgme_data_new (&out);
01403     if (err != GPG_ERR_NO_ERROR) {
01404         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01405     }
01406 
01407     err = gpgme_op_decrypt_verify (ctx, in, out);
01408 
01409     decrypt_result = gpgme_op_decrypt_result (ctx);
01410     verify_result = gpgme_op_verify_result (ctx);
01411 
01412     if (use_agent == 0) {
01413         // Restore the gpg.conf options
01414         restoreGPGConfig();
01415         // Restore GPG_AGENT_INFO to its original value
01416 #ifndef HAVE_W32_SYSTEM
01417 #ifndef FB_MACOSX
01418         envvar = "GPG_AGENT_INFO=";
01419         envvar += agent_info;
01420         putenv(strdup(envvar.c_str()));
01421 #endif
01422 #endif
01423     }
01424 
01425     if (err != GPG_ERR_NO_ERROR && !verify_result) {
01426         // There was an error returned while decrypting;
01427         //   either bad data, or signed only data
01428         if (verify_result && verify_result->signatures) {
01429             if (verify_result->signatures->status != GPG_ERR_NO_ERROR) {
01430                 //No valid GPG data to decrypt or signatures to verify; possibly bad armor.\" }";
01431                 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01432             }
01433         }
01434         if (gpg_err_code(err) == GPG_ERR_CANCELED) {
01435             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01436         }
01437         if (gpg_err_code(err) == GPG_ERR_BAD_PASSPHRASE) {
01438             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01439         }
01440         if (gpg_err_source(err) == GPG_ERR_SOURCE_PINENTRY) {
01441             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01442         }
01443         if (gpg_err_source(err) == GPG_ERR_SOURCE_GPGAGENT) {
01444             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01445         }
01446     }
01447 
01448     FB::VariantMap signatures;
01449     if (verify_result && verify_result->signatures) {
01450         tnsigs = 0;
01451         for (nsigs=0, sig=verify_result->signatures; sig; sig = sig->next, nsigs++) {
01452             FB::VariantMap signature;
01453             signature["fingerprint"] = nonnull (sig->fpr);
01454             signature["timestamp"] = sig->timestamp;
01455             signature["expiration"] = sig->exp_timestamp;
01456             signature["validity"] = sig->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
01457                     sig->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
01458                     sig->validity == GPGME_VALIDITY_NEVER? "never":
01459                     sig->validity == GPGME_VALIDITY_MARGINAL? "marginal":
01460                     sig->validity == GPGME_VALIDITY_FULL? "full":
01461                     sig->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]";
01462             signature["status"] = gpg_err_code (sig->status) == GPG_ERR_NO_ERROR? "GOOD":
01463                     gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE? "BAD_SIG":
01464                     gpg_err_code (sig->status) == GPG_ERR_NO_PUBKEY? "NO_PUBKEY":
01465                     gpg_err_code (sig->status) == GPG_ERR_NO_DATA? "NO_SIGNATURE":
01466                     gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED? "GOOD_EXPSIG":
01467                     gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED? "GOOD_EXPKEY": "INVALID";
01468             signatures[i_to_str(nsigs)] = signature;
01469             tnsigs++;
01470         }
01471     }
01472 
01473     if (nsigs < 1 || err == 11) {
01474         response["message_type"] = "encrypted_message";
01475         if (use_agent == 0) {
01476             response["message_event"] = "auto";
01477         } else {
01478             response["message_event"] = "manual";
01479         }
01480     } else {
01481         response["message_type"] = "signed_message";
01482     }
01483 
01484     if (err != GPG_ERR_NO_ERROR && tnsigs < 1) {
01485         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01486     }
01487 
01488     if (gpgme_err_code (err) == 58 && tnsigs < 1) {
01489         gpgme_data_release (out);
01490         response["data"] = data;
01491         response["message_type"] = "detached_signature";
01492     } else {
01493         ret = gpgme_data_seek(out, 0, SEEK_SET);
01494 
01495         if (ret)
01496             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01497 
01498         while ((ret = gpgme_data_read (out, buf, 512)) > 0)
01499             out_buf += buf;
01500 
01501         if (ret < 0)
01502             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01503 
01504         if (out_buf.length() < 1) {
01505             response["data"] = data;
01506             response["message_type"] = "detached_signature";
01507             gpgme_data_release (out);
01508         } else {
01509             size_t out_size = 0;
01510             gpgme_data_seek(out, 0, SEEK_SET);
01511             out_buf = gpgme_data_release_and_get_mem (out, &out_size);
01512 
01513             /* strip the size_t data out of the output buffer */
01514             out_buf = out_buf.substr(0, out_size);
01515             response["data"] = out_buf;
01516         }
01517 
01518     }
01519 
01520     response["signatures"] = signatures;
01521     response["error"] = false;
01522     gpgme_data_release (in);
01523     gpgme_release (ctx);
01524 
01525     return response;
01526 }
01527 
01536 FB::variant webpgPluginAPI::gpgDecrypt(const std::string& data)
01537 {
01538     return webpgPluginAPI::gpgDecryptVerify(data, 1);
01539 }
01540 
01541 FB::variant webpgPluginAPI::gpgVerify(const std::string& data)
01542 {
01543     return webpgPluginAPI::gpgDecryptVerify(data, 0);
01544 }
01545 
01557 
01578 
01579 /*
01580     sign_mode is one of:
01581         0: GPGME_SIG_MODE_NORMAL
01582         1: GPGME_SIG_MODE_DETACH
01583         2: GPGME_SIG_MODE_CLEAR
01584 */
01585 FB::variant webpgPluginAPI::gpgSignText(const FB::VariantList& signers, const std::string& plain_text,
01586     int sign_mode)
01587 {
01588     gpgme_ctx_t ctx = get_gpgme_ctx();
01589     gpgme_error_t err;
01590     gpgme_data_t in, out;
01591     gpgme_key_t key;
01592     gpgme_sig_mode_t sig_mode;
01593     gpgme_sign_result_t sign_result;
01594     int nsigners;
01595     FB::variant signer;
01596     FB::VariantMap result;
01597 
01598     if (sign_mode == 0)
01599         sig_mode = GPGME_SIG_MODE_NORMAL;
01600     else if (sign_mode == 1)
01601         sig_mode = GPGME_SIG_MODE_DETACH;
01602     else if (sign_mode == 2)
01603         sig_mode = GPGME_SIG_MODE_CLEAR;
01604 
01605     for (nsigners=0; nsigners < signers.size(); nsigners++) {
01606         signer = signers[nsigners];
01607         err = gpgme_op_keylist_start (ctx, signer.convert_cast<std::string>().c_str(), 0);
01608         if (err != GPG_ERR_NO_ERROR)
01609             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01610 
01611         err = gpgme_op_keylist_next (ctx, &key);
01612         if (err != GPG_ERR_NO_ERROR)
01613             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01614 
01615         err = gpgme_op_keylist_end (ctx);
01616         if (err != GPG_ERR_NO_ERROR)
01617             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01618 
01619         err = gpgme_signers_add (ctx, key);
01620         if (err != GPG_ERR_NO_ERROR)
01621             return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01622 
01623         gpgme_key_unref (key);
01624 
01625     }
01626 
01627     if (!nsigners > 0)
01628         return get_error_map(__func__, -1, "No signing keys found", __LINE__, __FILE__);
01629 
01630     err = gpgme_data_new_from_mem (&in, plain_text.c_str(), plain_text.length(), 0);
01631     if (err != GPG_ERR_NO_ERROR)
01632         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01633 
01634     err = gpgme_data_new (&out);
01635     if (err != GPG_ERR_NO_ERROR)
01636         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01637 
01638     err = gpgme_op_sign(ctx, in, out, sig_mode);
01639     if (err != GPG_ERR_NO_ERROR)
01640         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01641 
01642     sign_result = gpgme_op_sign_result (ctx);
01643 
01644     if (!sign_result)
01645         return get_error_map(__func__,  gpgme_err_code (err), "The signed result is invalid", __LINE__, __FILE__);
01646 
01647     gpgme_data_seek(out, 0, SEEK_SET);
01648 
01649     size_t out_size = 0;
01650     std::string out_buf;
01651     out_buf = gpgme_data_release_and_get_mem (out, &out_size);
01652     /* strip the size_t data out of the output buffer */
01653     out_buf = out_buf.substr(0, out_size);
01654     /* set the output object to NULL since it has
01655         already been released */
01656     out = NULL;
01657 
01658     result["error"] = false;
01659     result["data"] = out_buf;
01660 
01661     gpgme_data_release (in);
01662     gpgme_release (ctx);
01663 
01664     return result;
01665 
01666 }
01667 
01681 FB::variant webpgPluginAPI::gpgSignUID(const std::string& keyid, long sign_uid,
01682     const std::string& with_keyid, long local_only, long trust_sign, 
01683     long trust_level)
01684 {
01685     gpgme_ctx_t ctx = get_gpgme_ctx();
01686     gpgme_error_t err;
01687     gpgme_data_t out = NULL;
01688     gpgme_key_t key = NULL;
01689     FB::VariantMap result;
01690     current_uid = i_to_str(sign_uid);
01691 
01692     /* set the default key to the with_keyid 
01693         gpgSetPreference returns the orginal value (if any) of
01694         the 'default-key' configuration parameter. We will put
01695         this into a variable so we can restore the setting when
01696         our UID Signing operation is complete (or failed)
01697     */
01698 
01699     /* collect the original value so we can restore when done */
01700     std::string original_value = get_preference("default-key");
01701     webpgPluginAPI::gpgSetPreference("default-key", 
01702         (char *) with_keyid.c_str());
01703 
01704     /* Release the context and create it again to catch the changes */
01705     gpgme_release (ctx);
01706     ctx = get_gpgme_ctx();
01707     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
01708     if (err != GPG_ERR_NO_ERROR)
01709         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01710 
01711     err = gpgme_op_keylist_next (ctx, &key);
01712     if (err != GPG_ERR_NO_ERROR)
01713         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01714 
01715     err = gpgme_op_keylist_end (ctx);
01716     if (err != GPG_ERR_NO_ERROR)
01717         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01718 
01719     err = gpgme_data_new (&out);
01720     if (err != GPG_ERR_NO_ERROR)
01721         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01722 
01723     edit_status = "gpgSignUID(keyid='" + keyid + "', sign_uid='" + i_to_str(sign_uid) + 
01724         "', with_keyid='" + with_keyid + "', local_only='" + i_to_str(local_only) + "', trust_sign='" + 
01725         i_to_str(trust_sign) + "', trust_level='" + i_to_str(trust_level) + "');\n";
01726     err = gpgme_op_edit (ctx, key, edit_fnc_sign, out, out);
01727     if (err != GPG_ERR_NO_ERROR) {
01728         if (err == GPGME_STATUS_ALREADY_SIGNED) {
01729             result = get_error_map(__func__, err, "The selected UID has already been signed with this key.", __LINE__, __FILE__);
01730         } else if (err == GPGME_STATUS_KEYEXPIRED) {
01731             result =  get_error_map(__func__, err, "This key is expired; You cannot sign using an expired key.", __LINE__, __FILE__);
01732         } else if (err == GPGME_STATUS_SIGEXPIRED) {
01733             result =  get_error_map(__func__, err, "This key is expired; You cannot sign using an expired key.", __LINE__, __FILE__);
01734         } else {
01735             result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01736         }
01737     }
01738 
01739     /* if the original value was not empty, reset it to the previous value */
01740     if (strcmp ((char *) original_value.c_str(), "0")) {
01741         webpgPluginAPI::gpgSetPreference("default-key", original_value);
01742     }
01743 
01744     FB::VariantMap response;
01745     response["error"] = false;
01746     response["result"] = "success";
01747 
01748     gpgme_data_release (out);
01749     gpgme_key_unref (key);
01750     gpgme_release (ctx);
01751 
01752     if (result.size())
01753         return result;
01754 
01755     return response;
01756 }
01757 
01765 FB::variant webpgPluginAPI::gpgEnableKey(const std::string& keyid)
01766 {
01767     gpgme_ctx_t ctx = get_gpgme_ctx();
01768     gpgme_error_t err;
01769     gpgme_data_t out = NULL;
01770     gpgme_key_t key = NULL;
01771     FB::VariantMap response;
01772 
01773     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
01774     if (err != GPG_ERR_NO_ERROR)
01775         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01776 
01777     err = gpgme_op_keylist_next (ctx, &key);
01778     if (err != GPG_ERR_NO_ERROR)
01779         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01780 
01781     err = gpgme_op_keylist_end (ctx);
01782     if (err != GPG_ERR_NO_ERROR)
01783         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01784 
01785     err = gpgme_data_new (&out);
01786     if (err != GPG_ERR_NO_ERROR)
01787         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01788 
01789     edit_status = "gpgEnableKey(keyid='" + keyid + "');\n";
01790     err = gpgme_op_edit (ctx, key, edit_fnc_enable, out, out);
01791     if (err != GPG_ERR_NO_ERROR)
01792         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01793 
01794     gpgme_data_release (out);
01795     gpgme_key_unref (key);
01796     gpgme_release (ctx);
01797 
01798     response["error"] = false;
01799     response["result"] = "key enabled";
01800 
01801     return response;
01802 }
01803 
01811 FB::variant webpgPluginAPI::gpgDisableKey(const std::string& keyid)
01812 {
01813     gpgme_ctx_t ctx = get_gpgme_ctx();
01814     gpgme_error_t err;
01815     gpgme_data_t out = NULL;
01816     gpgme_key_t key = NULL;
01817     FB::VariantMap response;
01818 
01819     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
01820     if (err != GPG_ERR_NO_ERROR)
01821         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01822 
01823     err = gpgme_op_keylist_next (ctx, &key);
01824     if (err != GPG_ERR_NO_ERROR)
01825         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01826 
01827     err = gpgme_op_keylist_end (ctx);
01828     if (err != GPG_ERR_NO_ERROR)
01829         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01830 
01831     err = gpgme_data_new (&out);
01832     if (err != GPG_ERR_NO_ERROR)
01833         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01834 
01835     edit_status = "gpgDisableKey(keyid='" + keyid + "');\n";
01836     err = gpgme_op_edit (ctx, key, edit_fnc_disable, out, out);
01837     if (err != GPG_ERR_NO_ERROR)
01838         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01839 
01840     gpgme_data_release (out);
01841     gpgme_key_unref (key);
01842     gpgme_release (ctx);
01843 
01844     response["error"] = false;
01845     response["result"] = "key disabled";
01846 
01847     return response;
01848 
01849 }
01850 
01860 FB::variant webpgPluginAPI::gpgDeleteUIDSign(const std::string& keyid,
01861     long uid, long signature)
01862 {
01863     gpgme_ctx_t ctx = get_gpgme_ctx();
01864     gpgme_error_t err;
01865     gpgme_data_t out = NULL;
01866     gpgme_key_t key = NULL;
01867     FB::VariantMap response;
01868 
01869     current_uid = i_to_str(uid);
01870     current_sig = i_to_str(signature);
01871 
01872     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
01873     if (err != GPG_ERR_NO_ERROR)
01874         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01875 
01876     err = gpgme_op_keylist_next (ctx, &key);
01877     if (err != GPG_ERR_NO_ERROR)
01878         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01879 
01880     err = gpgme_op_keylist_end (ctx);
01881     if (err != GPG_ERR_NO_ERROR)
01882         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01883 
01884     err = gpgme_data_new (&out);
01885     if (err != GPG_ERR_NO_ERROR)
01886         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01887 
01888     edit_status = "gpgDeleteUIDSign(keyid='" + keyid + "', uid='" + i_to_str(uid) + "', signature='" + 
01889         i_to_str(signature) + "');\n";
01890     err = gpgme_op_edit (ctx, key, edit_fnc_delsign, out, out);
01891     if (err != GPG_ERR_NO_ERROR)
01892         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
01893 
01894     current_uid = "0";
01895     current_sig = "0";
01896 
01897     gpgme_data_release (out);
01898     gpgme_key_unref (key);
01899     gpgme_release (ctx);
01900 
01901     response["error"] = false;
01902     response["result"] = "signature deleted";
01903 
01904     return response;
01905 }
01906 
01919 void webpgPluginAPI::progress_cb(void *self, const char *what, int type, int current, int total)
01920 {
01921     if (!strcmp (what, "primegen") && !current && !total
01922         && (type == '.' || type == '+' || type == '!'
01923         || type == '^' || type == '<' || type == '>')) {
01924         webpgPluginAPI* API = (webpgPluginAPI*) self;
01925         API->FireEvent("onkeygenprogress", FB::variant_list_of(type));
01926     }
01927     if (!strcmp (what, "complete")) {
01928         webpgPluginAPI* API = (webpgPluginAPI*) self;
01929         API->FireEvent("onkeygencomplete", FB::variant_list_of("complete"));
01930     }
01931 }
01932 
01960 std::string webpgPluginAPI::gpgGenKeyWorker(const std::string& key_type, const std::string& key_length, 
01961         const std::string& subkey_type, const std::string& subkey_length, const std::string& name_real, 
01962         const std::string& name_comment, const std::string& name_email, const std::string& expire_date, 
01963         const std::string& passphrase, void* APIObj,
01964         void(*cb_status)(
01965             void *self,
01966             const char *what,
01967             int type,
01968             int current,
01969             int total
01970         )
01971     )
01972 {
01973 
01974     gpgme_ctx_t ctx = get_gpgme_ctx();
01975     gpgme_error_t err;
01976     std::string params = "<GnupgKeyParms format=\"internal\">\n"
01977         "Key-Type: " + key_type + "\n"
01978         "Key-Length: " + key_length + "\n"
01979         "Subkey-Type: " + subkey_type + "\n"
01980         "Subkey-Length: " + subkey_length + "\n"
01981         "Name-Real: " + name_real + "\n";
01982     if (name_comment.length() > 0) {
01983         params += "Name-Comment: " + name_comment + "\n";
01984     }
01985     if (name_email.length() > 0) {
01986         params += "Name-Email: " + name_email + "\n";
01987     }
01988     if (expire_date.length() > 0) {
01989         params += "Expire-Date: " + expire_date + "\n";
01990     } else {
01991         params += "Expire-Date: 0\n";
01992     }
01993     if (passphrase.length() > 0) {
01994         params += "Passphrase: " + passphrase + "\n";
01995     }
01996     params += "</GnupgKeyParms>\n";
01997     const char *parms = params.c_str();
01998 
01999     gpgme_genkey_result_t result;
02000 
02001     gpgme_set_progress_cb (ctx, cb_status, APIObj);
02002 
02003     err = gpgme_op_genkey (ctx, parms, NULL, NULL);
02004     if (err)
02005         return "Error with genkey start" + err;
02006 
02007     result = gpgme_op_genkey_result (ctx);
02008 
02009     if (!result)
02010     {
02011 #ifdef DEBUG
02012         fprintf (stderr, "%s:%d: gpgme_op_genkey_result returns NULL\n",
02013            __FILE__, __LINE__);
02014 #endif
02015         return "error with result";
02016     }
02017 
02018 #ifdef DEBUG
02019     printf ("Generated key: %s (%s)\n", result->fpr ? result->fpr : "none",
02020         result->primary ? (result->sub ? "primary, sub" : "primary")
02021         : (result->sub ? "sub" : "none"));
02022 #endif
02023 
02024     gpgme_release (ctx);
02025     const char* status = (char *) "complete";
02026     cb_status(APIObj, status, 33, 33, 33);
02027     return "done";
02028 }
02029 
02054 FB::variant webpgPluginAPI::gpgGenSubKeyWorker(const std::string& keyid, const std::string& subkey_type,
02055         const std::string& subkey_length, const std::string& subkey_expire, bool sign_flag,
02056         bool enc_flag, bool auth_flag, void* APIObj,
02057         void(*cb_status)(
02058             void *self,
02059             const char *what,
02060             int type,
02061             int current,
02062             int total
02063         )
02064     )
02065 {
02066 
02067     // Set the option expert so we can access all of the subkey types
02068     setTempGPGOption("expert", "");
02069 
02070     gpgme_ctx_t ctx = get_gpgme_ctx();
02071     gpgme_error_t err;
02072     gpgme_data_t out = NULL;
02073     gpgme_key_t key = NULL;
02074     FB::VariantMap response;
02075 
02076     gen_subkey_type = subkey_type;
02077     gen_subkey_length = subkey_length;
02078     gen_subkey_expire = subkey_expire;
02079     gen_sign_flag = sign_flag;
02080     gen_enc_flag = enc_flag;
02081     gen_auth_flag = auth_flag;
02082 
02083     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02084     if (err != GPG_ERR_NO_ERROR)
02085         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02086 
02087     err = gpgme_op_keylist_next (ctx, &key);
02088     if (err != GPG_ERR_NO_ERROR)
02089         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02090 
02091     err = gpgme_op_keylist_end (ctx);
02092     if (err != GPG_ERR_NO_ERROR)
02093         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02094 
02095     err = gpgme_data_new (&out);
02096     if (err != GPG_ERR_NO_ERROR)
02097         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02098 
02099     gpgme_set_progress_cb (ctx, cb_status, APIObj);
02100 
02101     edit_status = "gpgGenSubKeyWorker(keyid='" + keyid + "', subkey_type='" + subkey_type + 
02102         "', subkey_length='" + subkey_length + "', subkey_expire='" + subkey_expire + "', sign_flag='" + 
02103         i_to_str(sign_flag) + "', enc_flag='" + i_to_str(enc_flag) + "', auth_flag='" + 
02104         i_to_str(auth_flag) + "');\n";
02105     err = gpgme_op_edit (ctx, key, edit_fnc_add_subkey, out, out);
02106 
02107     if (err != GPG_ERR_NO_ERROR) {
02108         if (gpg_err_code(err) == GPG_ERR_CANCELED)
02109             this->FireEvent("onkeygencomplete", FB::variant_list_of("failed: cancelled"));
02110         else if (gpg_err_code(err) == GPG_ERR_BAD_PASSPHRASE)
02111             this->FireEvent("onkeygencomplete", FB::variant_list_of("failed: bad passphrase"));
02112 
02113         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02114     }
02115 
02116     gpgme_data_release (out);
02117     gpgme_key_unref (key);
02118     gpgme_release (ctx);
02119 
02120     // Restore the options to normal
02121     restoreGPGConfig();
02122 
02123     const char* status = (char *) "complete";
02124     cb_status(APIObj, status, 33, 33, 33);
02125     return "done";
02126 }
02127 
02135 void webpgPluginAPI::threaded_gpgGenKey(genKeyParams params)
02136 {
02137     std::string result = webpgPluginAPI::gpgGenKeyWorker(params.key_type, params.key_length,
02138         params.subkey_type, params.subkey_length, params.name_real,
02139         params.name_comment, params.name_email, params.expire_date,
02140         params.passphrase, this, &webpgPluginAPI::progress_cb
02141     );
02142 
02143 }
02144 
02152 void webpgPluginAPI::threaded_gpgGenSubKey(genSubKeyParams params)
02153 {
02154     FB::variant result = webpgPluginAPI::gpgGenSubKeyWorker(params.keyid, params.subkey_type,
02155         params.subkey_length, params.subkey_expire, params.sign_flag, params.enc_flag,
02156         params.auth_flag, this, &webpgPluginAPI::progress_cb
02157     );
02158 
02159 }
02160 
02179 std::string webpgPluginAPI::gpgGenKey(const std::string& key_type, 
02180         const std::string& key_length, const std::string& subkey_type, 
02181         const std::string& subkey_length, const std::string& name_real,
02182         const std::string& name_comment, const std::string& name_email, 
02183         const std::string& expire_date, const std::string& passphrase)
02184 {
02185 
02186     genKeyParams params;
02187 
02188     params.key_type = key_type;
02189     params.key_length = key_length;
02190     params.subkey_type = subkey_type;
02191     params.subkey_length = subkey_length;
02192     params.name_real = name_real;
02193     params.name_comment = name_comment;
02194     params.name_email = name_email;
02195     params.expire_date = expire_date;
02196     params.passphrase = passphrase;
02197 
02198     boost::thread genkey_thread(
02199         boost::bind(
02200             &webpgPluginAPI::genKeyThreadCaller,
02201             this, params)
02202     );
02203 
02204     return "queued";
02205 }
02206 
02214 FB::variant webpgPluginAPI::gpgImportKey(const std::string& ascii_key)
02215 {
02216     gpgme_ctx_t ctx = get_gpgme_ctx();
02217     gpgme_error_t err;
02218     gpgme_data_t key_buf;
02219     gpgme_import_result_t result;
02220 
02221     err = gpgme_data_new_from_mem (&key_buf, ascii_key.c_str(), ascii_key.length(), 1);
02222 
02223     err = gpgme_op_import (ctx, key_buf);
02224 
02225     result = gpgme_op_import_result (ctx);
02226     gpgme_data_release (key_buf);
02227 
02228     FB::VariantMap status;
02229 
02230     status["considered"] = result->considered;
02231     status["no_user_id"] = result->no_user_id;
02232     status["imported"] = result->imported;
02233     status["imported_rsa"] = result->imported_rsa;
02234     status["new_user_ids"] = result->new_user_ids;
02235     status["new_sub_keys"] = result->new_sub_keys;
02236     status["new_signatures"] = result->new_signatures;
02237     status["new_revocations"] = result->new_revocations;
02238     status["secret_read"] = result->secret_read;
02239     status["secret_imported"] = result->secret_imported;
02240     status["secret_unchanged"] = result->secret_unchanged;
02241     status["not_imported"] = result->not_imported;
02242 
02243     FB::VariantMap imports_map;
02244     int nimports = 0;
02245     gpgme_import_status_t import;
02246     for (nimports=0, import=result->imports; import; import = import->next, nimports++) {
02247         FB::VariantMap import_item_map;
02248         import_item_map["fingerprint"] = nonnull (import->fpr);
02249         import_item_map["result"] = gpgme_strerror(import->result);
02250         import_item_map["status"] = import->status;
02251         import_item_map["new_key"] = import->status & GPGME_IMPORT_NEW? true : false;
02252         import_item_map["new_uid"] = import->status & GPGME_IMPORT_UID? true : false;
02253         import_item_map["new_sig"] = import->status & GPGME_IMPORT_SIG? true : false;
02254         import_item_map["new_subkey"] = import->status & GPGME_IMPORT_SUBKEY? true : false;
02255         import_item_map["new_secret"] = import->status & GPGME_IMPORT_SECRET? true : false;
02256         imports_map[i_to_str(nimports)] = import_item_map;
02257     }
02258     status["imports"] = imports_map;
02259     gpgme_release (ctx);
02260 
02261     return status;
02262 }
02263 
02271 FB::variant webpgPluginAPI::gpgDeleteKey(const std::string& keyid, int allow_secret)
02272 {
02273     gpgme_ctx_t ctx = get_gpgme_ctx();
02274     gpgme_error_t err;
02275     gpgme_key_t key = NULL;
02276     FB::VariantMap response;
02277 
02278     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02279     if (err != GPG_ERR_NO_ERROR)
02280         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02281 
02282     err = gpgme_op_keylist_next (ctx, &key);
02283     if (err != GPG_ERR_NO_ERROR)
02284         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02285 
02286     err = gpgme_op_keylist_end (ctx);
02287     if (err != GPG_ERR_NO_ERROR)
02288         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02289 
02290     err = gpgme_op_delete(ctx, key, allow_secret);
02291     if (err != GPG_ERR_NO_ERROR)
02292         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02293 
02294     gpgme_key_unref (key);
02295     gpgme_release (ctx);
02296 
02297     response["error"] = false;
02298     response["result"] = "Key deleted";
02299 
02300     return response;
02301 }
02302 
02303 /*
02304     This method executes webpgPlugin.gpgDeleteKey with the allow_secret=0,
02305         which allows it to only delete public Public Keys from the keyring.
02306 */
02314 FB::variant webpgPluginAPI::gpgDeletePublicKey(const std::string& keyid)
02315 {
02316     return webpgPluginAPI::gpgDeleteKey(keyid, 0);
02317 }
02318 
02326 FB::variant webpgPluginAPI::gpgDeletePrivateKey(const std::string& keyid)
02327 {
02328     return webpgPluginAPI::gpgDeleteKey(keyid, 1);
02329 }
02330 
02339 FB::variant webpgPluginAPI::gpgDeletePrivateSubKey(const std::string& keyid, int key_idx)
02340 {
02341     gpgme_ctx_t ctx = get_gpgme_ctx();
02342     gpgme_error_t err;
02343     gpgme_data_t out = NULL;
02344     gpgme_key_t key = NULL;
02345     FB::VariantMap response;
02346 
02347     key_index = i_to_str(key_idx);
02348 
02349     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02350     if (err != GPG_ERR_NO_ERROR)
02351         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02352 
02353     err = gpgme_op_keylist_next (ctx, &key);
02354     if (err != GPG_ERR_NO_ERROR)
02355         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02356 
02357     err = gpgme_op_keylist_end (ctx);
02358     if (err != GPG_ERR_NO_ERROR)
02359         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02360 
02361     err = gpgme_data_new (&out);
02362     if (err != GPG_ERR_NO_ERROR)
02363         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02364 
02365     edit_status = "gpgDeletePrivateSubkey(keyid='" + keyid + "', key_idx='" + i_to_str(key_idx) +
02366         "');\n";
02367     err = gpgme_op_edit (ctx, key, edit_fnc_delete_subkey, out, out);
02368     if (err != GPG_ERR_NO_ERROR)
02369         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02370 
02371 
02372     key_index = "";
02373 
02374     gpgme_data_release (out);
02375     gpgme_key_unref (key);
02376     gpgme_release (ctx);
02377 
02378     response["error"] = false;
02379     response["edit_status"] = edit_status;
02380     response["result"] = "Subkey Delete";
02381 
02382     return response;
02383 }
02384 
02400 FB::variant webpgPluginAPI::gpgGenSubKey(const std::string& keyid, 
02401         const std::string& subkey_type, const std::string& subkey_length,
02402         const std::string& subkey_expire, bool sign_flag, bool enc_flag, bool auth_flag)
02403 {
02404 
02405     genSubKeyParams params;
02406 
02407     params.keyid = keyid;
02408     params.subkey_type = subkey_type;
02409     params.subkey_length = subkey_length;
02410     params.subkey_expire = subkey_expire;
02411     params.sign_flag = sign_flag;
02412     params.enc_flag = enc_flag;
02413     params.auth_flag = auth_flag;
02414 
02415     boost::thread genkey_thread(
02416         boost::bind(
02417             &webpgPluginAPI::genSubKeyThreadCaller,
02418             this, params)
02419     );
02420 
02421     return "queued";
02422 }
02423 
02432 FB::variant webpgPluginAPI::gpgSetKeyTrust(const std::string& keyid, long trust_level)
02433 {
02434     gpgme_ctx_t ctx = get_gpgme_ctx();
02435     gpgme_error_t err;
02436     gpgme_data_t out = NULL;
02437     gpgme_key_t key = NULL;
02438     FB::VariantMap response;
02439     trust_assignment = i_to_str(trust_level);
02440 
02441     if (trust_level < 1) {
02442         response["error"] = true;
02443         response["result"] = "Valid trust assignment values are 1 through 5";
02444         return response;
02445     }
02446 
02447     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02448     if (err != GPG_ERR_NO_ERROR)
02449         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02450 
02451     err = gpgme_op_keylist_next (ctx, &key);
02452     if (err != GPG_ERR_NO_ERROR)
02453         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02454 
02455     err = gpgme_op_keylist_end (ctx);
02456     if (err != GPG_ERR_NO_ERROR)
02457         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02458 
02459     err = gpgme_data_new (&out);
02460     if (err != GPG_ERR_NO_ERROR)
02461         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02462 
02463     edit_status = "gpgSetKeyTrust(keyid='" + keyid + "', trust_level='" + i_to_str(trust_level) + "');\n";
02464     err = gpgme_op_edit (ctx, key, edit_fnc_assign_trust, out, out);
02465     if (err != GPG_ERR_NO_ERROR)
02466         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02467 
02468     trust_assignment = "0";
02469 
02470     gpgme_data_release (out);
02471     gpgme_key_unref (key);
02472     gpgme_release (ctx);
02473 
02474     response["error"] = false;
02475     response["result"] = "trust value assigned";
02476 
02477     return response;
02478 }
02479 
02491 FB::variant webpgPluginAPI::gpgAddUID(const std::string& keyid, const std::string& name,
02492         const std::string& email, const std::string& comment)
02493 {
02494     gpgme_ctx_t ctx = get_gpgme_ctx();
02495     gpgme_error_t err;
02496     gpgme_data_t out = NULL;
02497     gpgme_key_t key = NULL;
02498     FB::VariantMap response;
02499     genuid_name = name;
02500     genuid_email = email;
02501     genuid_comment = comment;
02502 
02503     if (isdigit(name.c_str()[0])) {
02504         response["error"] = true;
02505         response["result"] = "UID names cannot start with a digit...";
02506         return response;
02507     }
02508 
02509     if (strlen (name.c_str()) < 5) {
02510         response["error"] = true;
02511         response["result"] = "UID's must be at least 5 chars long...";
02512         return response;
02513     }
02514 
02515     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02516     if (err != GPG_ERR_NO_ERROR)
02517         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02518 
02519     err = gpgme_op_keylist_next (ctx, &key);
02520     if (err != GPG_ERR_NO_ERROR)
02521         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02522 
02523     err = gpgme_op_keylist_end (ctx);
02524     if (err != GPG_ERR_NO_ERROR)
02525         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02526 
02527     err = gpgme_data_new (&out);
02528     if (err != GPG_ERR_NO_ERROR)
02529         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02530 
02531     edit_status = "gpgAddUID(keyid='" + keyid + "', name='" + name + "', email='" + email + 
02532         "', comment='" + comment + "');\n";
02533     err = gpgme_op_edit (ctx, key, edit_fnc_add_uid, out, out);
02534     if (err != GPG_ERR_NO_ERROR)
02535         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02536 
02537     response["name"] = genuid_name;
02538     response["email"] = genuid_email;
02539     response["comment"] = genuid_comment;
02540 
02541     genuid_name = "";
02542     genuid_email = "";
02543     genuid_comment = "";
02544 
02545     gpgme_data_release (out);
02546     gpgme_key_unref (key);
02547     gpgme_release (ctx);
02548 
02549     response["error"] = false;
02550     response["edit_status"] = edit_status;
02551     response["result"] = "UID added";
02552 
02553     return response;
02554 }
02555 
02564 FB::variant webpgPluginAPI::gpgDeleteUID(const std::string& keyid, long uid_idx)
02565 {
02566     gpgme_ctx_t ctx = get_gpgme_ctx();
02567     gpgme_error_t err;
02568     gpgme_data_t out = NULL;
02569     gpgme_key_t key = NULL;
02570     FB::VariantMap response;
02571 
02572     if (uid_idx < 1) {
02573         response["error"] = true;
02574         response["result"] = "UID index is always above zero, something is amiss...";
02575         return response;
02576     }
02577 
02578     current_uid = i_to_str(uid_idx);
02579 
02580     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02581     if (err != GPG_ERR_NO_ERROR)
02582         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02583 
02584     err = gpgme_op_keylist_next (ctx, &key);
02585     if (err != GPG_ERR_NO_ERROR)
02586         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02587 
02588     err = gpgme_op_keylist_end (ctx);
02589     if (err != GPG_ERR_NO_ERROR)
02590         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02591 
02592     err = gpgme_data_new (&out);
02593     if (err != GPG_ERR_NO_ERROR)
02594         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02595 
02596     edit_status = "gpgDeleteUID(keyid='" + keyid + "', uid_idx='" + i_to_str(uid_idx) + "');\n";
02597     err = gpgme_op_edit (ctx, key, edit_fnc_delete_uid, out, out);
02598     if (err != GPG_ERR_NO_ERROR)
02599         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02600 
02601 
02602     current_uid = "0";
02603 
02604     gpgme_data_release (out);
02605     gpgme_key_unref (key);
02606     gpgme_release (ctx);
02607 
02608     response["error"] = false;
02609     response["edit_status"] = edit_status;
02610     response["result"] = "UID deleted";
02611 
02612     return response;
02613 }
02614 
02623 FB::variant webpgPluginAPI::gpgSetPrimaryUID(const std::string& keyid, long uid_idx)
02624 {
02625     gpgme_ctx_t ctx = get_gpgme_ctx();
02626     gpgme_error_t err;
02627     gpgme_data_t out = NULL;
02628     gpgme_key_t key = NULL;
02629     FB::VariantMap response;
02630 
02631     if (uid_idx < 1) {
02632         response["error"] = true;
02633         response["result"] = "UID index is always above zero, something is amiss...";
02634         return response;
02635     }
02636 
02637     current_uid = i_to_str(uid_idx);
02638 
02639     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02640     if (err != GPG_ERR_NO_ERROR)
02641         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02642 
02643     err = gpgme_op_keylist_next (ctx, &key);
02644     if (err != GPG_ERR_NO_ERROR)
02645         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02646 
02647     err = gpgme_op_keylist_end (ctx);
02648     if (err != GPG_ERR_NO_ERROR)
02649         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02650 
02651     err = gpgme_data_new (&out);
02652     if (err != GPG_ERR_NO_ERROR)
02653         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02654 
02655     edit_status = "gpgSetPrimaryUID(keyid='" + keyid + "', uid_idx='" + i_to_str(uid_idx) + "');\n";
02656     err = gpgme_op_edit (ctx, key, edit_fnc_set_primary_uid, out, out);
02657     if (err != GPG_ERR_NO_ERROR)
02658         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02659 
02660 
02661     current_uid = "0";
02662 
02663     gpgme_data_release (out);
02664     gpgme_key_unref (key);
02665     gpgme_release (ctx);
02666 
02667     response["error"] = false;
02668     response["edit_status"] = edit_status;
02669     response["result"] = "Primary UID changed";
02670 
02671     return response;
02672 }
02673 
02683 FB::variant webpgPluginAPI::gpgSetKeyExpire(const std::string& keyid, long key_idx, long expire)
02684 {
02685     gpgme_ctx_t ctx = get_gpgme_ctx();
02686     gpgme_error_t err;
02687     gpgme_data_t out = NULL;
02688     gpgme_key_t key = NULL;
02689     FB::VariantMap response;
02690 
02691     key_index = i_to_str(key_idx);
02692     expiration = i_to_str(expire);
02693 
02694     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02695     if (err != GPG_ERR_NO_ERROR)
02696         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02697 
02698     err = gpgme_op_keylist_next (ctx, &key);
02699     if (err != GPG_ERR_NO_ERROR)
02700         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02701 
02702     err = gpgme_op_keylist_end (ctx);
02703     if (err != GPG_ERR_NO_ERROR)
02704         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02705 
02706     err = gpgme_data_new (&out);
02707     if (err != GPG_ERR_NO_ERROR)
02708         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02709 
02710     edit_status = "gpgSetKeyExpire(keyid='" + keyid + "', key_idx='" + i_to_str(key_idx) + 
02711         "', expire='" + i_to_str(expire) + "');\n";
02712     err = gpgme_op_edit (ctx, key, edit_fnc_set_key_expire, out, out);
02713     if (err != GPG_ERR_NO_ERROR)
02714         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02715 
02716 
02717     key_index = "";
02718     expiration = "";
02719 
02720     gpgme_data_release (out);
02721     gpgme_key_unref (key);
02722     gpgme_release (ctx);
02723 
02724     response["error"] = false;
02725     response["edit_status"] = edit_status;
02726     response["result"] = "Expiration changed";
02727 
02728     return response;
02729 }
02730 
02739 FB::variant webpgPluginAPI::gpgSetPubkeyExpire(const std::string& keyid, long expire)
02740 {
02741     return webpgPluginAPI::gpgSetKeyExpire(keyid, 0, expire);
02742 }
02743 
02753 FB::variant webpgPluginAPI::gpgSetSubkeyExpire(const std::string& keyid, long key_idx, long expire)
02754 {
02755     return webpgPluginAPI::gpgSetKeyExpire(keyid, key_idx, expire);
02756 }
02757 
02766 
02780 
02781 FB::variant webpgPluginAPI::gpgExportPublicKey(const std::string& keyid)
02782 {
02783     gpgme_ctx_t ctx = get_gpgme_ctx();
02784     gpgme_error_t err;
02785     gpgme_data_t out = NULL;
02786     FB::variant keydata;
02787     FB::VariantMap response;
02788 
02789     err = gpgme_data_new (&out);
02790     if (err != GPG_ERR_NO_ERROR)
02791         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02792 
02793     err = gpgme_op_export (ctx, keyid.c_str(), 0, out);
02794     if (err != GPG_ERR_NO_ERROR)
02795         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02796 
02797     gpgme_data_seek(out, 0, SEEK_SET);
02798 
02799     size_t out_size = 0;
02800     std::string out_buf;
02801     out_buf = gpgme_data_release_and_get_mem (out, &out_size);
02802     /* strip the size_t data out of the output buffer */
02803     out_buf = out_buf.substr(0, out_size);
02804     /* set the output object to NULL since it has
02805         already been released */
02806     out = NULL;
02807 
02808     gpgme_release (ctx);
02809 
02810     response["error"] = false;
02811     response["result"] = out_buf;
02812 
02813     return response;
02814 }
02815 
02830 FB::variant webpgPluginAPI::gpgRevokeItem(const std::string& keyid, const std::string& item, int key_idx,
02831     int uid_idx, int sig_idx, int reason, const std::string& desc)
02832 {
02833 
02834     gpgme_ctx_t ctx = get_gpgme_ctx();
02835     gpgme_error_t err;
02836     gpgme_data_t out = NULL;
02837     gpgme_key_t key = NULL;
02838     FB::VariantMap response;
02839 
02840     key_index = i_to_str(key_idx);
02841     current_uid = i_to_str(uid_idx);
02842     current_sig = i_to_str(sig_idx);
02843     revitem = item.c_str();
02844     reason_index = i_to_str(reason);
02845     description = desc.c_str();
02846 
02847 
02848     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02849     if (err != GPG_ERR_NO_ERROR)
02850         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02851 
02852     err = gpgme_op_keylist_next (ctx, &key);
02853     if (err != GPG_ERR_NO_ERROR)
02854         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02855 
02856     err = gpgme_op_keylist_end (ctx);
02857     if (err != GPG_ERR_NO_ERROR)
02858         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02859 
02860     err = gpgme_data_new (&out);
02861     if (err != GPG_ERR_NO_ERROR)
02862         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02863 
02864     edit_status = "gpgRevokeItem(keyid='" + keyid + "', item='" + item + "', key_idx='" + 
02865         i_to_str(key_idx) + "', uid_idx='" + i_to_str(uid_idx) + "', sig_idx='" + i_to_str(sig_idx) +
02866         "', reason='" + i_to_str(reason) + "', desc='" + desc + "');\n";
02867     err = gpgme_op_edit (ctx, key, edit_fnc_revoke_item, out, out);
02868     if (err != GPG_ERR_NO_ERROR)
02869         return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02870 
02871 
02872     key_index = "";
02873     reason_index = "";
02874     current_uid = "";
02875 
02876     gpgme_data_release (out);
02877     gpgme_key_unref (key);
02878     gpgme_release (ctx);
02879 
02880     response["error"] = false;
02881     response["edit_status"] = edit_status;
02882     response["result"] = "Item Revoked";
02883 
02884     return response;
02885 }
02886 
02898 FB::variant webpgPluginAPI::gpgRevokeKey(const std::string& keyid, int key_idx, int reason,
02899     const std::string &desc)
02900 {
02901     return webpgPluginAPI::gpgRevokeItem(keyid, "revkey", key_idx, 0, 0, reason, desc);
02902 }
02903 
02915 FB::variant webpgPluginAPI::gpgRevokeUID(const std::string& keyid, int uid_idx, int reason,
02916     const std::string &desc)
02917 {
02918     return webpgPluginAPI::gpgRevokeItem(keyid, "revuid", 0, uid_idx, 0, reason, desc);
02919 }
02920 
02933 FB::variant webpgPluginAPI::gpgRevokeSignature(const std::string& keyid, int uid_idx, int sig_idx,
02934     int reason, const std::string &desc)
02935 {
02936     return webpgPluginAPI::gpgRevokeItem(keyid, "revsig", 0, uid_idx, sig_idx, reason, desc);
02937 }
02938 
02946 FB::variant webpgPluginAPI::gpgChangePassphrase(const std::string& keyid)
02947 {
02948     gpgme_ctx_t ctx = get_gpgme_ctx();
02949     gpgme_error_t err;
02950     gpgme_data_t out = NULL;
02951     gpgme_key_t key = NULL;
02952     FB::VariantMap result;
02953 
02954     err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0);
02955     if (err != GPG_ERR_NO_ERROR)
02956         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02957 
02958     err = gpgme_op_keylist_next (ctx, &key);
02959     if (err != GPG_ERR_NO_ERROR)
02960         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02961 
02962     err = gpgme_op_keylist_end (ctx);
02963     if (err != GPG_ERR_NO_ERROR)
02964         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02965 
02966     err = gpgme_data_new (&out);
02967     if (err != GPG_ERR_NO_ERROR)
02968         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02969 
02970     edit_status = "gpgChangePassphrase(keyid='" + keyid + "');\n";
02971     err = gpgme_op_edit (ctx, key, edit_fnc_change_passphrase, out, out);
02972     if (err != GPG_ERR_NO_ERROR)
02973         result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
02974 
02975     FB::VariantMap response;
02976     if (!key->secret) {
02977         response["error"] = true;
02978         response["result"] = "no secret";
02979     } else {
02980         response["error"] = false;
02981         response["result"] = "success";
02982     }
02983 
02984     gpgme_data_release (out);
02985     gpgme_key_unref (key);
02986     gpgme_release (ctx);
02987 
02988     if (result.size())
02989         return result;
02990 
02991     return response;
02992 }
02993 
02999 // Read-only property version
03000 std::string webpgPluginAPI::get_version()
03001 {
03002     return FBSTRING_PLUGIN_VERSION;
03003 }
03004 
 All Classes Functions