/* sunone-ace.c
 *
 * Copyright (C) 2002-2004 Sun Microsystems, Inc
 *
 * AUTHORS
 *     Jack Jia <jack.jia@sun.com>
 *     Harry Lu <harry.lu@sun.com>
 *     Alfred Peng <alfred.peng@sun.com>
 *     Jedy Wang <jedy.wang@sun.com>
 *     Rodrigo Moya <rodrigo@ximian.com>
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>
#include <ctype.h>

#include "sunone-ace.h"

struct _SunOneACEPrivate {
	SunOneACEAccessType access_type;
	SunOneACEUserType user_type;
	gchar *user_name;
	SunOneACEContext context;
	SunOneACEPermission permissions;
};

static void sunone_ace_class_init (SunOneACEClass *klass);
static void sunone_ace_init (SunOneACE *object);
static void sunone_ace_dispose (GObject *object);
static void sunone_ace_finalize (GObject *object);

static GObjectClass *parent_class = NULL;

G_DEFINE_TYPE (SunOneACE, sunone_ace, G_TYPE_OBJECT)

static void
sunone_ace_class_init (SunOneACEClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	parent_class = g_type_class_ref (G_TYPE_OBJECT);

	object_class->dispose  = sunone_ace_dispose;
	object_class->finalize = sunone_ace_finalize;
}

static void
sunone_ace_init (SunOneACE *object)
{
	SunOneACE *ace = SUNONE_ACE (object);
	SunOneACEPrivate *priv;

	ace->priv = g_new0 (SunOneACEPrivate, 1);
	priv = ace->priv;

	priv->access_type = SUNONE_ACE_ACCESSTYPE_INVALID;
	priv->user_type = SUNONE_ACE_USERTYPE_INVALID;
	priv->context = SUNONE_ACE_CONTEXT_INVALID;
	priv->permissions = SUNONE_ACE_PERMISSION_NONE;
}

static void
sunone_ace_dispose (GObject *object)
{
	SunOneACE *ace = SUNONE_ACE (object);
	SunOneACEPrivate *priv = ace->priv;

	g_return_if_fail (IS_SUNONE_ACE (ace));

	if (priv) {
		if (priv->user_name) {
			g_free (priv->user_name);
			priv->user_name = NULL;
		}

		g_free (priv);
		ace->priv = NULL;
	}

        if (G_OBJECT_CLASS (parent_class)->dispose)
		(* G_OBJECT_CLASS (parent_class)->dispose) (object);
	
}

static void
sunone_ace_finalize (GObject *object)
{
	if (G_OBJECT_CLASS (parent_class)->finalize)
		(* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
/**
 * sunone_ace_new
 *
 * Create a new empty #SunOneACE object.
 *
 * Returns: the newly created object.
 */
SunOneACE *
sunone_ace_new (void)
{
	SunOneACE *ace;

	ace = g_object_new (SUNONE_ACE_TYPE, NULL);

	return ace;
}


/**
 * sunone_ace_new_from_string
 * @str: a string representation of an ACE.
 *
 * Create a new #SunOneACE object from a string, as returned by the
 * SunOne server.
 *
 * Returns: the newly created object.
 */
SunOneACE *
sunone_ace_new_from_string (const gchar *str)
{
	SunOneACE *ace;

	ace = sunone_ace_new ();
	if (!sunone_ace_set_from_string (ace, str)) {
		g_object_unref (G_OBJECT (ace));
		return NULL;
	}

	return ace;
}

/**
 * sunone_ace_clone
 * @ace: a #SunOneACE object.
 *
 * Clone the given #SunOneACE object.
 *
 * Returns: the cloned object.
 */
SunOneACE *
sunone_ace_clone (SunOneACE *ace)
{
	SunOneACE *copy;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), NULL);

	copy = sunone_ace_new ();
	sunone_ace_set_access_type (copy, sunone_ace_get_access_type (ace));
	sunone_ace_set_user_type (copy, sunone_ace_get_user_type (ace));
	sunone_ace_set_user_name (copy, sunone_ace_get_user_name (ace));
	sunone_ace_set_context (copy, sunone_ace_get_context (ace));
	sunone_ace_set_permissions (copy, sunone_ace_get_permissions (ace));

	return copy;
}

/**
 * sunone_ace_set_from_string
 * @ace: a #SunOneACE object.
 * @str: a string representation of an ACE.
 *
 * Set the properties of the given #SunOneACE object based on the
 * ACE string represented by the @str argument.
 *
 * Returns: TRUE if successful, FALSE otherwise.
 */
gboolean
sunone_ace_set_from_string (SunOneACE *ace, const gchar *str)
{
	SunOneACEPrivate *priv = ace->priv;
	gchar **parts;
	gchar *who;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), FALSE);
	g_return_val_if_fail (str != NULL, FALSE);

	parts = g_strsplit (str, "^", 0);
	if (!parts)
		return FALSE;

	/* part 1: who the ACE applies to */
	g_free (priv->user_name);
	priv->user_name = NULL;

	who = parts[0];
	if (who[0] == '@') {
		if (!strcmp (who, "@"))
			priv->user_type = SUNONE_ACE_USERTYPE_ALL_USERS;
		else if (!strcmp (who, "@@p"))
			priv->user_type = SUNONE_ACE_USERTYPE_PRIMARY_OWNERS;
		else if (!strcmp (who, "@@o"))
			priv->user_type = SUNONE_ACE_USERTYPE_OWNERS;
		else if (!strcmp (who, "@@n"))
			priv->user_type = SUNONE_ACE_USERTYPE_NONOWNERS;
		else {
			/* it's a domain name */
			priv->user_type = SUNONE_ACE_USERTYPE_DOMAIN;
			priv->user_name = g_strdup (&who[1]);
		}
	} else {
		/* it's a normal user ID */
		priv->user_type = SUNONE_ACE_USERTYPE_USER;
		priv->user_name = g_strdup (who);
	}

	/* part 2: what the ACE applies to (all calendar, objects, etc) */
	if (!strcmp (parts[1], "a"))
		priv->context = SUNONE_ACE_CONTEXT_ENTIRE_CALENDAR;
	else if (!strcmp (parts[1], "c"))
		priv->context = SUNONE_ACE_CONTEXT_CALENDAR_COMPONENTS;
	else if (!strcmp (parts[1], "p"))
		priv->context = SUNONE_ACE_CONTEXT_CALENDAR_PROPERTIES;
	else
		priv->context = SUNONE_ACE_CONTEXT_INVALID;

	/* part 3: access values */
	priv->permissions = SUNONE_ACE_PERMISSION_NONE;
	for (who = parts[2]; *who; who++) {
		switch (tolower (*who)) {
		case 'c' : priv->permissions |= SUNONE_ACE_PERMISSION_CANCEL; break;
		case 'd' : priv->permissions |= SUNONE_ACE_PERMISSION_DELETE; break;
		case 'e' : priv->permissions |= SUNONE_ACE_PERMISSION_REPLY; break;
		case 'f' : priv->permissions |= SUNONE_ACE_PERMISSION_FREEBUSY; break;
		case 'i' : priv->permissions |= SUNONE_ACE_PERMISSION_INVITE; break;
		case 'r' : priv->permissions |= SUNONE_ACE_PERMISSION_READ; break;
		case 's' : priv->permissions |= SUNONE_ACE_PERMISSION_SCHEDULE; break;
		case 'w' : priv->permissions |= SUNONE_ACE_PERMISSION_WRITE; break;
		default :
			g_warning ("Unknown character '%c' in permission values", *who);
		}
	}

	/* part 4: grant/deny */
	if (!strcmp (parts[3], "g"))
		priv->access_type = SUNONE_ACE_ACCESSTYPE_GRANT;
	else if (!strcmp (parts[3], "d"))
		priv->access_type = SUNONE_ACE_ACCESSTYPE_DENY;
	else
		priv->access_type = SUNONE_ACE_ACCESSTYPE_INVALID;

	g_strfreev (parts);

	return TRUE;
}

/**
 * sunone_ace_to_string
 * @ace: a #SunOneACE object.
 *
 * Returns a string representation of the given ACE.
 *
 * Returns: a newly allocated string.
 */
gchar *
sunone_ace_to_string (SunOneACE *ace)
{
	SunOneACEPrivate *priv = ace->priv;
	GString *str;
	gchar *retval;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), NULL);

	/* first, user name */
	switch (priv->user_type) {
	case SUNONE_ACE_USERTYPE_ALL_USERS :
		str = g_string_new ("@^");
		break;
	case SUNONE_ACE_USERTYPE_PRIMARY_OWNERS :
		str = g_string_new ("@@p^");
		break;
	case SUNONE_ACE_USERTYPE_OWNERS :
		str = g_string_new ("@@o^");
		break;
	case SUNONE_ACE_USERTYPE_NONOWNERS :
		str = g_string_new ("@@n^");
		break;
	case SUNONE_ACE_USERTYPE_DOMAIN :
		str = g_string_new ("@");
		if (!priv->user_name) {
			g_warning ("Missing domain name in ACE");
			g_string_free (str, TRUE);
			return NULL;
		}
		str = g_string_append (str, priv->user_name);
		str = g_string_append (str, "^");
		break;
	case SUNONE_ACE_USERTYPE_USER :
		if (!priv->user_name) {
			g_warning ("Missing user name in ACE");
			return NULL;
		}
		str = g_string_new (priv->user_name);
		str = g_string_append (str, "^");
		break;
	default :
		g_warning ("Invalid user type in ACE");
		return NULL;
	}

	/* second, the context */
	switch (priv->context) {
	case SUNONE_ACE_CONTEXT_ENTIRE_CALENDAR :
		str = g_string_append (str, "a^");
		break;
	case SUNONE_ACE_CONTEXT_CALENDAR_COMPONENTS :
		str = g_string_append (str, "c^");
		break;
	case SUNONE_ACE_CONTEXT_CALENDAR_PROPERTIES :
		str = g_string_append (str, "p^");
		break;
	default :
		g_warning ("Invalid context in ACE");
		g_string_free (str, TRUE);
		return NULL;
	}

	/* third, access values */
	if (priv->permissions & SUNONE_ACE_PERMISSION_CANCEL)
		str = g_string_append (str, "c");
	if (priv->permissions & SUNONE_ACE_PERMISSION_DELETE)
		str = g_string_append (str, "d");
	if (priv->permissions & SUNONE_ACE_PERMISSION_REPLY)
		str = g_string_append (str, "e");
	if (priv->permissions & SUNONE_ACE_PERMISSION_FREEBUSY)
		str = g_string_append (str, "f");
	if (priv->permissions & SUNONE_ACE_PERMISSION_INVITE)
		str = g_string_append (str, "i");
	if (priv->permissions & SUNONE_ACE_PERMISSION_READ)
		str = g_string_append (str, "r");
	if (priv->permissions & SUNONE_ACE_PERMISSION_SCHEDULE)
		str = g_string_append (str, "s");
	if (priv->permissions & SUNONE_ACE_PERMISSION_WRITE)
		str = g_string_append (str, "w");

	str = g_string_append (str, "^");

	/* fourth, the access type */
	if (priv->access_type == SUNONE_ACE_ACCESSTYPE_GRANT)
		str = g_string_append (str, "g");
	else
		str = g_string_append (str, "d");

	retval = str->str;
	g_string_free (str, FALSE);

	return retval;
}

/**
 * sunone_ace_get_access_type
 */
SunOneACEAccessType
sunone_ace_get_access_type (SunOneACE *ace)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), SUNONE_ACE_ACCESSTYPE_INVALID);
	return priv->access_type;
}

/**
 * sunone_ace_set_access_type
 */
void
sunone_ace_set_access_type (SunOneACE *ace, SunOneACEAccessType type)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_if_fail (IS_SUNONE_ACE (ace));
	priv->access_type = type;
}

/**
 * sunone_ace_get_user_type
 */
SunOneACEUserType
sunone_ace_get_user_type (SunOneACE *ace)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), SUNONE_ACE_USERTYPE_INVALID);
	return priv->user_type;
}

/**
 * sunone_ace_set_user_type
 */
void
sunone_ace_set_user_type (SunOneACE *ace, SunOneACEUserType type)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_if_fail (IS_SUNONE_ACE (ace));
	priv->user_type = type;
}

/**
 * sunone_ace_get_user_name
 */
const gchar *
sunone_ace_get_user_name (SunOneACE *ace)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), NULL);
	return (const gchar *) priv->user_name;
}

/**
 * sunone_ace_set_user_name
 */
void
sunone_ace_set_user_name (SunOneACE *ace, const gchar *name)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_if_fail (IS_SUNONE_ACE (ace));

	if (priv->user_name)
		g_free (priv->user_name);
	priv->user_name = g_strdup (name);
}

SunOneACEContext
sunone_ace_get_context (SunOneACE *ace)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), SUNONE_ACE_CONTEXT_INVALID);
	return priv->context;
}

void
sunone_ace_set_context (SunOneACE *ace, SunOneACEContext context)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_if_fail (IS_SUNONE_ACE (ace));
	priv->context = context;
}

SunOneACEPermission
sunone_ace_get_permissions (SunOneACE *ace)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_val_if_fail (IS_SUNONE_ACE (ace), SUNONE_ACE_PERMISSION_NONE);
	return priv->permissions;
}

void
sunone_ace_set_permissions (SunOneACE *ace, SunOneACEPermission perms)
{
	SunOneACEPrivate *priv = ace->priv;

	g_return_if_fail (IS_SUNONE_ACE (ace));
	priv->permissions = perms;
}
