libpurple/keyring.c

Fri, 11 Jul 2008 22:26:24 +0000

author
Vivien Bernet-Rollande <scrouaf@soc.pidgin.im>
date
Fri, 11 Jul 2008 22:26:24 +0000
branch
soc.2008.masterpassword
changeset 33973
b193c0e9044b
parent 33972
b55f819a1239
child 33976
ff88d1340abe
permissions
-rw-r--r--

Fixed problem in async purple_peyring_set_inuse()

/**
 * @file keyring.c Keyring plugin API
 */

/* purple
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 */


/**
 * Most functions in this files are :
 *  - wrappers that will call the plugin
 *  - keyring managment stuff
 *  - accessors
 *
 * TODO :
 *  - unregister
 *  - use accessors
 *  - purple_keyring_init()
 *  - purple_keyring_set_inuse() needs to be async for error checking an reversability.
 *
 * Questions :
 *  - cleanup
 *  - warning
 *  - breaking API
 */

#include <glib.h>
#include "keyring.h"
#include "account.h"

/*******************************/
/* opaque structures           */
/*******************************/

/* used to import and export password info */
struct _PurpleKeyringPasswordNode
{
	PurpleAccount * account;
	const char * encryption;
	const char * mode;
	const char * data;
/**
 * strings cannot be modified.
 * all are static excpet data
 */
};


/*******************************/
/* globals                     */
/*******************************/

GList * purple_keyring_keyringlist = NULL;	/* list of available keyrings 	*/
PurpleKeyring * purple_keyring_inuse = NULL;	/* keyring being used		*/


/*******************************/
/* functions                   */
/*******************************/

/* manipulate keyring list, used by config interface */

const GList * 
purple_keyring_get_keyringlist()
{
	return purple_keyring_keyringlist;
}

const PurpleKeyring * 
purple_keyring_get_inuse()
{
	return purple_keyring_inuse;
}


/**
 * If reading fails, export empty, issue warning, continue
 * If writing fails, abort.
 */
struct _PurpleKeyringChangeTracker
{
	GError ** error;			// could probably be dropped
	PurpleKeyringSetInUseCb cb;
	gpointer data;
	PurpleKeyring * new;
	PurpleKeyring * old;		// we are done when : finished == TRUE && read_outstanding == 0
	int read_outstanding;
	gboolean finished;
	gboolean abort;
};

void
purple_keyring_set_inuse_check_error_cb(const PurpleAccount * account,
					GError ** error,
					gpointer data)
{

	const char * name;
	PurpleKeyringClose close;
	struct _PurpleKeyringChangeTracker * tracker;

	tracker = (struct _PurpleKeyringChangeTracker *)data;

	name = purple_account_get_username(account);

	if ((error != NULL) && ((**error).domain == ERR_PIDGINKEYRING)) {

		switch((**error).code) {

			case ERR_NOPASSWD :
				g_debug("No password found while changing keyring for account %s", name);
				break;

			case ERR_NOACCOUNT :
				g_debug("No info on account %s found while changing keyring", name);
				break;

			case ERR_NOCHANNEL :
				g_debug("Failed to communicate with backend while changing keyring for account %s, aborting change.", name);
				tracker->abort == TRUE;
				break;

			default :
				// FIXME : display error string
				g_debug("Unknown error while changing keyring for account %s", name);
				break;
		}
	}

	/* if this was the last one */
	if (tracker->finished == TRUE) && (tracker->read_outstanding == 0)) {
	
		if (tracker->abort == TRUE) {
			
			tracker->abort = TRUE;

			close = purple_keyring_get_close_keyring(tracker->old);
			close(error);			

			g_free(tracker);
			return;
		} else {
			close = purple_keyring_get_close_keyring(tracker->new);
			close(error);

			tracker->cb(TRUE, error, tracker->data);
			g_free(tracker);
			return;
		}

	}
	return;
}


void
purple_keyring_set_inuse_got_pw_cb(const PurpleAccount * account, 
			 gchar * password, 
			 GError ** error, 
			 gpointer data)
{
	PurpleKeyring * new;
	PurpleKeyringSave save;
	struct _PurpleKeyringChangeTracker * tracker;

	
	tracker = (struct _PurpleKeyringChangeTracker *)data;
	new = tracker->new;

	/* XXX check for read error or just forward ? */

	tracker->read_outstanding--;
	
	save = purple_keyring_get_save_password(new);
	save(account, password, error, purple_keyring_set_inuse_check_error_cb, 
		tracker);

	return;
}

/* FIXME : needs to be async and cancelable */
/* PurpleKeyringSetInUseCb */
void 
purple_keyring_set_inuse(PurpleKeyring * new,
			 GError ** error,
			 PurpleKeyringSetInUseCb cb,
			 gpointer data)
{

	GList * cur;
	const PurpleKeyring * old;
	PurpleKeyringRead read;
	struct _PurpleKeyringChangeTracker * tracker;


	if (purple_keyring_inuse != NULL) {

		tracker = g_malloc(sizeof(struct _PurpleKeyringChangeTracker));
		old = purple_keyring_get_inuse();

		tracker->error = error;
		tracker->cb = cb;
		tracker->data = data;
		tracker->new = new;
		tracker->old = old;
		tracker->read_outstanding = 0;
		tracker->finished = FALSE;
		tracker->abort = FALSE;

		for (cur = purple_accounts_get_all(); 
		    (cur != NULL) && (tracker->abort != TRUE);
		    cur = cur->next)
		{
			tracker->read_outstanding++;

			if (cur->next == NULL) {
				tracker->finished = TRUE;
			}

			read = purple_keyring_get_read_password(old);
			read(cur->data, error, purple_keyring_set_inuse_got_pw_cb, tracker);
		}

	} else { /* no keyring was set before. */

		purple_keyring_inuse = new;
		cb(data);
		return;
	}
}

/* register a keyring plugin */
/**
 * XXX : function to unregister a keyring ?
 *	 validate input ? add magix field ?
 */
void 
purple_plugin_keyring_register(PurpleKeyring * info)
{
	purple_keyring_keyringlist = g_list_prepend(purple_keyring_keyringlist,
		info);
}


/**
 * wrappers to import and export passwords
 */


/** 
 * used by account.c while reading a password from xml
 * might not really need to be async.
 * TODO : rewrite InternalKeyring as async
 */
void
purple_keyring_import_password(const PurpleKeyringPasswordNode * passwordnode,
				GError ** error,
				PurpleKeyringImportCallback cb,
				gpointer data)
{
	PurpleKeyringImportPassword import;

	if (purple_keyring_inuse == NULL) {

		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
			"No Keyring configured.");
		cb(error, data);

	} else {
		import = purple_keyring_get_import_password(purple_keyring_inuse);
		import(passwordnode, error, cb, data);
	}
	return;
}

/* 
 * used by account.c while syncing accounts
 *  returned data must be g_free()'d
 */
void
purple_keyring_export_password(PurpleAccount * account,
			       GError ** error,
			       PurpleKeyringExportCallback cb,
			       gpointer data)
{
	PurpleKeyringExportPassword export;

	if (purple_keyring_inuse == NULL) {

		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
			"No Keyring configured.");
		cb(NULL, error, data);

	} else {
		export = purple_keyring_get_export_password(purple_keyring_inuse);
		export(account, error, cb, data);
	}
	return;
}


/** 
 * functions called from the code to access passwords (account.h):
 *	purple_account_get_password()	<- TODO : rewrite these functions as asynch, as well as functions calling them. Will most likely break API compatibility.
 *	purple_account_set_password()
 * so these functions will call : 
 */
void 
purple_keyring_get_password(const PurpleAccount *account,
			    GError ** error,
			    PurpleKeyringReadCallback cb,
			    gpointer data)
{
	PurpleKeyringRead read;

	if (purple_keyring_inuse == NULL) {

		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
			"No Keyring configured.");
		cb(account, NULL, error, data);

	} else {

		read = purple_keyring_get_read_password(purple_keyring_inuse);
		read(account, error, cb, data);

	}
	return;
}

void 
purple_keyring_set_password(const PurpleAccount * account, 
			    gchar * password, 
			    GError ** error, 
			    PurpleKeyringSaveCallback cb,
			    gpointer data)
{
	PurpleKeyringSave save;

	if (purple_keyring_inuse == NULL) {

		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
				"No Keyring configured.");
		cb(account, error, data);

	} else {
		save = purple_keyring_get_save_password(purple_keyring_inuse);
		save(account, password, error, cb, data);
	}
	return;
}

/* accessors for data structure fields */
	/* PurpleKeyring */
const char *
purple_keyring_get_name(const PurpleKeyring * info)
{
	return info->name;
}

PurpleKeyringRead 
purple_keyring_get_read_password(const PurpleKeyring * info)
{
	return info->read_password;
}

PurpleKeyringSave
purple_keyring_get_save_password(const PurpleKeyring * info)
{
	return info->save_password;
}

PurpleKeyringClose 
purple_keyring_get_close_keyring(const PurpleKeyring * info)
{
	return info->close_keyring;
}

PurpleKeyringFree 
purple_keyring_get_free_password(const PurpleKeyring * info)
{
	return info->free_password;
}

PurpleKeyringChangeMaster 
purple_keyring_get_change_master(const PurpleKeyring * info)
{
	return info->change_master;
}

PurpleKeyringImportPassword
purple_keyring_get_import_password(const PurpleKeyring * info)
{
	return info->import_password;
}

PurpleKeyringExportPassword 
purple_keyring_get_export_password(const PurpleKeyring * info)
{
	return info->export_password;
}


void 
purple_keyring_set_name(PurpleKeyring * info,
			char * name)
{
	info->name = name;
}

void 
purple_keyring_set_read_password(PurpleKeyring * info,
				 PurpleKeyringRead read)
{
	info->read_password = read; /*  returned data must be g_free()'d */
}

void 
purple_keyring_set_save_password(PurpleKeyring * info,
				 PurpleKeyringSave save)
{
	info->save_password = save;
}

void 
purple_keyring_set_close_keyring(PurpleKeyring * info,
				 PurpleKeyringClose close)
{
	info->close_keyring = close;
}

void 
purple_keyring_set_free_password(PurpleKeyring * info,
				 PurpleKeyringFree free)
{
	info->free_password = free;
}

void 
purple_keyring_set_change_master(PurpleKeyring * info,
				 PurpleKeyringChangeMaster change_master)
{
	info->change_master = change_master;
}

void 
purple_keyring_set_import_password(PurpleKeyring * info,
				   PurpleKeyringImportPassword import_password)
{
	info->import_password = import_password;
}
void 
purple_keyring_set_export_password(PurpleKeyring * info,
				   PurpleKeyringExportPassword export_password)
{
	info->export_password = export_password;
}


	/* PurpleKeyringPasswordNode */

PurpleKeyringPasswordNode * 
purple_keyring_password_node_new()
{
	PurpleKeyringPasswordNode * ret;

	ret = g_malloc(sizeof(PurpleKeyringPasswordNode));
	return ret;
}

void 
purple_keyring_password_node_free(PurpleKeyringPasswordNode * node)
{
	g_free(node);
	return;
}

const PurpleAccount * 
purple_keyring_password_node_get_account(const PurpleKeyringPasswordNode * info)
{
	return info->account;
}

const char * 
purple_keyring_password_node_get_encryption(const PurpleKeyringPasswordNode * info)
{
	return info->encryption;
}

const char * 
purple_keyring_password_node_get_mode(const PurpleKeyringPasswordNode * info)
{
	return info->mode;
}

const char * 
purple_keyring_password_node_get_data(const PurpleKeyringPasswordNode * info)
{
	return info->data;
}


void 
purple_keyring_password_node_set_account(PurpleKeyringPasswordNode * info, 
					 PurpleAccount * account)
{
	info->account = account;
	return;	
}

void 
purple_keyring_password_node_set_encryption(PurpleKeyringPasswordNode * info,
					    const char * encryption)
{
	info->encryption = encryption;
	return;
}

void 
purple_keyring_password_node_set_mode(PurpleKeyringPasswordNode * info,
				      const char * mode)
{
	info->mode = mode;
	return;
}

void 
purple_keyring_password_node_set_data(PurpleKeyringPasswordNode * info,
				      const char * data)
{
	info->data = data;
	return;
}

GQuark
purple_keyring_error_domain()
{
	return g_quark_from_static_string("Libpurple keyring");
}

/**
 * prepare stuff (called at startup)
 * TODO : see if we need to cleanup
 */
void purple_keyring_init()
{//FIXME
	/**
	 * init error GQuark (FIXME change it in headers as well)
	 * read safe to use in confing
	 * make sure said safe is loaded
	 * else fallback
	 */
}

mercurial