/**
 * seahorse_service_crypto_sign_text:
 * @crypto: SeahorseServiceCrypto
 * @signer: the signer keyid
 * @flags: 0 (ignored)
 * @cleartext: the text to sign
 * @crypttext: the clear text signature (out) (GPGME_SIG_MODE_CLEAR)
 * @error: an error to return
 *
 * DBus: SignText
 *
 * Signs the @cleartext and returns the signature in @crypttext
 *
 * Returns: TRUE on success
 */
gboolean
seahorse_service_crypto_sign_text (SeahorseServiceCrypto *crypto, const char *signer, 
                                   int flags, const char *cleartext, char **crypttext,
                                   GError **error)
{
    SeahorseObject *signkey = NULL;
    gpgme_error_t gerr;
    SeahorseGpgmeOperation *pop; 
    gpgme_data_t plain, cipher;
    gboolean ret = TRUE;
    
    /* 
     * TODO: Once we support different kinds of keys that support encryption
     * then all this logic will need to change. 
     */
    
    /* The signer */
    if (!signer || !signer[0]) 
        g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
                     _("No signer specified"));
    
    signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer);
    if (!signkey) {
        g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, 
                     _("Invalid or unrecognized signer: %s"), signer);
        return FALSE;
    }
        
    if (!SEAHORSE_IS_GPGME_KEY (signkey) || 
        !(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) {
        g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
                     _("Key is not valid for signing: %s"), signer);
        return FALSE;
    }
    
    pop = seahorse_gpgme_operation_new (NULL);
    
    /* new data from text */
    gerr = gpgme_data_new_from_mem (&plain, cleartext, strlen (cleartext), FALSE);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
    gerr = gpgme_data_new (&cipher);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
   
    /* encrypt with armor */
    gpgme_set_textmode (pop->gctx, TRUE);
    gpgme_set_armor (pop->gctx, TRUE);

    /* Do the signage */
    gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey)));
    gerr = gpgme_op_sign_start (pop->gctx, plain, cipher, GPGME_SIG_MODE_CLEAR);

    /* Frees cipher */
    ret = process_crypto_result (pop, gerr, cipher, crypttext, NULL, error);
    
    g_object_unref (pop);
    gpgme_data_release (plain);
    return ret;
}
/**
 * seahorse_service_crypto_verify_text:
 * @crypto: #SeahorseServiceCrypto context
 * @ktype: "openpgp"
 * @flags: FLAG_QUIET for no notification
 * @crypttext: the text to decrypt
 * @cleartext: the plaintext after verification (out)
 * @signer: the signer if the text is signed (out)
 * @error: a potential error (out)
 *
 * DBus: VerifyText
 *
 * Decrypts the @crypttext and returns it in @cleartext. If the text
 * was signed, the signed is returned.
 *
 * Returns: TRUE on success
 */
gboolean
seahorse_service_crypto_verify_text (SeahorseServiceCrypto *crypto, 
                                     const gchar *ktype, int flags, 
                                     const gchar *crypttext, gchar **cleartext,
                                     char **signer, GError **error)
{
    gpgme_verify_result_t status;
    gpgme_error_t gerr;
    SeahorseGpgmeOperation *pop; 
    gpgme_data_t plain, cipher;
    gboolean ret = TRUE;
    GQuark keyid;
    
    if (!g_str_equal (ktype, g_quark_to_string (SEAHORSE_PGP))) {
        g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
                     _("Invalid key type for verifying: %s"), ktype);
        return FALSE;        
    }

    /* 
     * TODO: Once we support different kinds of keys that support encryption
     * then all this logic will need to change. 
     */

    pop = seahorse_gpgme_operation_new (NULL);
    
    /* new data from text */
    gerr = gpgme_data_new_from_mem (&cipher, crypttext, strlen (crypttext), FALSE);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
    gerr = gpgme_data_new (&plain);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
   
    /* encrypt with armor */
    gpgme_set_textmode (pop->gctx, TRUE);
    gpgme_set_armor (pop->gctx, TRUE);

    /* Do the decryption */
    gerr = gpgme_op_verify_start (pop->gctx, cipher, NULL, plain);

    /* Frees plain */
    ret = process_crypto_result (pop, gerr, plain, cleartext, NULL, error);
    
    if (ret) {
        *signer = NULL;
        status = gpgme_op_verify_result (pop->gctx);
    
        if (status->signatures) {
            if (!(flags & FLAG_QUIET))
                notify_signatures (NULL, status);
            if (status->signatures->summary & GPGME_SIGSUM_GREEN ||
                status->signatures->summary & GPGME_SIGSUM_VALID ||
                status->signatures->summary & GPGME_SIGSUM_KEY_MISSING) {
                keyid = seahorse_pgp_key_canonize_id (status->signatures->fpr);
                *signer = seahorse_context_id_to_dbus (SCTX_APP (), keyid);
            }
        }
    }
    
    g_object_unref (pop);
    gpgme_data_release (cipher);
    return TRUE;
}
/**
* crypto: the crypto service (#SeahorseServiceCrypto)
* recipients: A list of recipients (keyids "openpgp:B8098FB063E2C811")
*             Must be empty when symmetric encryption is used.
* signer: optional, the keyid of the signer
* flags: FLAG_SYMMETRIC to perform symmetric encryption
* cleartext: the text to encrypt
* clearlength: Length of the cleartext
* crypttext: the encrypted text (out)
* cryptlength: the length of this text (out)
* textmode: TRUE if gpgme should use textmode
* ascii_armor: TRUE if GPGME should use ascii armor
* error: The Error
*
* Handles encryption in a generic way. Can be used by several DBus APIs
*
* Returns TRUE on success
**/
static gboolean
crypto_encrypt_generic (SeahorseServiceCrypto *crypto,
                        const char **recipients, const char *signer,
                        int flags, const char *cleartext, gsize clearlength,
                        char **crypttext, gsize *cryptlength, gboolean textmode,
                        gboolean ascii_armor, GError **error)
{
	GList *recipkeys = NULL;
	SeahorseGpgmeOperation *pop;
	SeahorseObject *signkey = NULL;
	SeahorseObject *skey;
	gpgme_key_t *recips;
	gboolean symmetric = FALSE;
	gpgme_data_t plain, cipher;
	gpgme_error_t gerr;
	gboolean ret = TRUE;
	GSettings *settings;
	gchar *keyid;

	if ((flags & FLAG_SYMMETRIC) == FLAG_SYMMETRIC)
		symmetric = TRUE;

	if (symmetric && recipients[0] != NULL) {
		g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
		             _("Recipients specified for symmetric encryption"));
		return FALSE;
	}

	/* The signer */
	if (signer && signer[0]) {
		signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer);
		if (!signkey) {
			g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
			             _("Invalid or unrecognized signer: %s"), signer);
			return FALSE;
		}

		if (!SEAHORSE_IS_GPGME_KEY (signkey) ||
			!(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) {
			g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
			             _("Key is not valid for signing: %s"), signer);
			return FALSE;
		}
	}

	if (!symmetric) {
		/* The recipients */
		for( ; recipients[0]; recipients++)
		{
			skey = seahorse_context_object_from_dbus (SCTX_APP (), recipients[0]);
			if (!skey) {
				g_list_free (recipkeys);
				g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
					     _("Invalid or unrecognized recipient: %s"), recipients[0]);
				return FALSE;
			}

			if (!SEAHORSE_IS_GPGME_KEY (skey) ||
				!(seahorse_object_get_flags (skey) & SEAHORSE_FLAG_CAN_ENCRYPT)) {
				g_list_free (recipkeys);
				g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
					     _("Key is not a valid recipient for encryption: %s"), recipients[0]);
				return FALSE;
			}

			recipkeys = g_list_prepend (recipkeys, SEAHORSE_PGP_KEY (skey));
		}

		if (!recipkeys) {
			g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
				     _("No recipients specified"));
			return FALSE;
		}
	}

	pop = seahorse_gpgme_operation_new (NULL);

	/* new data form text */
	gerr = gpgme_data_new_from_mem (&plain, cleartext, clearlength, FALSE);
	g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
	gerr = gpgme_data_new (&cipher);
	g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);

	/* encrypt with armor */
	gpgme_set_textmode (pop->gctx, textmode);
	gpgme_set_armor (pop->gctx, ascii_armor);

	if (symmetric) {
		/* gpgme_op_encrypt{_sign,}_start() will perform symmetric encryption
		 * when no recipients are specified. */
		recips = NULL;
	} else {
		/* Add the default key if set and necessary */
		settings = g_settings_new ("org.gnome.crypto.pgp");
		if (g_settings_get_boolean (settings, "encrypt-to-self")) {
			keyid = g_settings_get_string (settings, "default-key");
			if (keyid && keyid[0]) {
				skey = seahorse_context_find_object (NULL, g_quark_from_string (keyid),
								     SEAHORSE_LOCATION_LOCAL);
				if (SEAHORSE_IS_PGP_KEY (skey))
					recipkeys = g_list_append (recipkeys, skey);
			}
			g_free (keyid);
		}
		g_object_unref (settings);

		/* Make keys into the right format for GPGME */
		recips = keylist_to_keys (recipkeys);
		g_list_free (recipkeys);
	}

	/* Do the encryption */
	if (signkey) {
		gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey)));
		gerr = gpgme_op_encrypt_sign_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST,
		                                    plain, cipher);
	} else {
		gerr = gpgme_op_encrypt_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST,
		                               plain, cipher);
	}
	free_keys (recips);

	/* Frees cipher */
	ret = process_crypto_result (pop, gerr, cipher, crypttext, cryptlength, error);
	g_object_unref (pop);
	gpgme_data_release (plain);
	return ret;
}
/**
* crypto: the crypto service (#SeahorseServiceCrypto)
* recipients: A list of recipients (keyids "openpgp:B8098FB063E2C811")
* signer: optional, the keyid of the signer
* flags: 0, not used
* cleartext: the text to encrypt
* clearlength: Length of the cleartext
* crypttext: the encrypted text (out)
* cryptlength: the length of this text (out)
* textmode: TRUE if gpgme should use textmode
* ascii_armor: TRUE if GPGME should use ascii armor
* error: The Error
*
* Handles encryption in a generic way. Can be used by several DBus APIs
*
* Returns TRUE on success
**/
static gboolean
crypto_encrypt_generic (SeahorseServiceCrypto *crypto,
                        const char **recipients, const char *signer,
                        int flags, const char *cleartext, gsize clearlength,
                        char **crypttext, gsize *cryptlength, gboolean textmode,
                        gboolean ascii_armor, GError **error)
{
    GList *recipkeys = NULL;
    SeahorseGpgmeOperation *pop; 
    SeahorseObject *signkey = NULL;
    SeahorseObject *skey;
    gpgme_key_t *recips;
    gpgme_data_t plain, cipher;
    gpgme_error_t gerr;
    gboolean ret = TRUE;
    
    /* 
     * TODO: Once we support different kinds of keys that support encryption
     * then all this logic will need to change. 
     */
    /* The signer */
    if (signer && signer[0]) {
        signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer);
        if (!signkey) {
            g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, 
                         _("Invalid or unrecognized signer: %s"), signer);
            return FALSE;
        }
        
        if (!SEAHORSE_IS_GPGME_KEY (signkey) || 
            !(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) {
            g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
                         _("Key is not valid for signing: %s"), signer);
            return FALSE;
        }
    }
    /* The recipients */
    for( ; recipients[0]; recipients++)
    {
        skey = seahorse_context_object_from_dbus (SCTX_APP (), recipients[0]);
        if (!skey) {
            g_list_free (recipkeys);
            g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, 
                         _("Invalid or unrecognized recipient: %s"), recipients[0]);
            return FALSE;
        }
        
        if (!SEAHORSE_IS_GPGME_KEY (skey) ||
            !(seahorse_object_get_flags (skey) & SEAHORSE_FLAG_CAN_ENCRYPT)) {
            g_list_free (recipkeys);
            g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
                         _("Key is not a valid recipient for encryption: %s"), recipients[0]);
            return FALSE;
        }
        
        recipkeys = g_list_prepend (recipkeys, SEAHORSE_PGP_KEY (skey));
    }
    
    if (!recipkeys) {
        g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
                     _("No recipients specified"));
        return FALSE;
    }
    pop = seahorse_gpgme_operation_new (NULL);
    
    /* new data form text */
    gerr = gpgme_data_new_from_mem (&plain, cleartext, clearlength, FALSE);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
    gerr = gpgme_data_new (&cipher);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
   
    /* encrypt with armor */
    gpgme_set_textmode (pop->gctx, textmode);
    gpgme_set_armor (pop->gctx, ascii_armor);

    /* Add the default key if set and necessary */
    if (seahorse_gconf_get_boolean (ENCRYPTSELF_KEY)) {
        skey = SEAHORSE_OBJECT (seahorse_context_get_default_key (SCTX_APP ()));
        if (SEAHORSE_IS_PGP_KEY (skey))
            recipkeys = g_list_append (recipkeys, skey);
    }

    /* Make keys into the right format for GPGME */
    recips = keylist_to_keys (recipkeys);
    g_list_free (recipkeys);
    
    /* Do the encryption */
    if (signkey) {
        gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey)));
        gerr = gpgme_op_encrypt_sign_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, 
                                            plain, cipher);
    } else {
        gerr = gpgme_op_encrypt_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, 
                                       plain, cipher);
    }
    free_keys (recips);

    /* Frees cipher */
    ret = process_crypto_result (pop, gerr, cipher, crypttext, cryptlength, error);
    g_object_unref (pop);
    gpgme_data_release (plain);
    return ret;
}