diff options
author | Philip Withnall <philip@tecnocode.co.uk> | 2009-05-17 12:50:57 +0100 |
---|---|---|
committer | Philip Withnall <philip@tecnocode.co.uk> | 2009-05-17 12:50:57 +0100 |
commit | 5d853ec5706129ce8af1bc0a2baae3dfed52d8d0 (patch) | |
tree | bc6ebec199812103214c97adba988ed06a38094a /gdata/gdata-access-rule.c | |
parent | 1b9bff25139448bc18f4afd3025d86c5fe942362 (diff) | |
download | libgdata-5d853ec5706129ce8af1bc0a2baae3dfed52d8d0.tar.gz |
Bug 582026 – Access Control List functionality
This adds a framework for controlling access control lists (ACLs). It
includes GDataAccessHandler, an interface to be implemented by any GDataEntry
which has an ACL. It also includes GDataAccessRule, a GDataEntry representing
a single access control rule, initially written by Thibault Saunier
<saunierthibault@gmail.com>.
Full documentation is included, and test cases will be added per-service.
Diffstat (limited to 'gdata/gdata-access-rule.c')
-rw-r--r-- | gdata/gdata-access-rule.c | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/gdata/gdata-access-rule.c b/gdata/gdata-access-rule.c new file mode 100644 index 00000000..cd2a50fc --- /dev/null +++ b/gdata/gdata-access-rule.c @@ -0,0 +1,397 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * GData Client + * Copyright (C) Thibault Saunier 2009 <saunierthibault@gmail.com> + * Copyright (C) Philip Withnall 2009 <philip@tecnocode.co.uk> + * + * GData Client is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * GData Client 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GData Client. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * SECTION:gdata-access-rule + * @short_description: GData access rule object + * @stability: Unstable + * @include: gdata/gdata-access-rule.h + * + * #GDataAccessRule is a subclass of #GDataEntry to represent a generic access rule from an access control list (ACL). + * It is returned by the ACL methods implemented in the #GDataAccessHandler interface. + **/ + +#include <config.h> +#include <glib.h> +#include <glib/gi18n-lib.h> +#include <libxml/parser.h> +#include <string.h> + +#include "gdata-access-rule.h" +#include "gdata-gdata.h" +#include "gdata-parser.h" +#include "gdata-types.h" +#include "gdata-private.h" + +static void gdata_access_rule_finalize (GObject *object); +static void get_namespaces (GDataEntry *entry, GHashTable *namespaces); +static void get_xml (GDataEntry *entry, GString *xml_string); +static void gdata_access_rule_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); +static void gdata_access_rule_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static gboolean parse_xml (GDataEntry *entry, xmlDoc *doc, xmlNode *node, GError **error); + +struct _GDataAccessRulePrivate { + gchar *role; + gchar *scope_type; + gchar *scope_value; +}; + +enum { + PROP_ROLE = 1, + PROP_SCOPE_TYPE, + PROP_SCOPE_VALUE, +}; + +G_DEFINE_TYPE (GDataAccessRule, gdata_access_rule, GDATA_TYPE_ENTRY) +#define GDATA_ACCESS_RULE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDATA_TYPE_ACCESS_RULE, GDataAccessRulePrivate)) + +static void +gdata_access_rule_class_init (GDataAccessRuleClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GDataEntryClass *entry_class = GDATA_ENTRY_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GDataAccessRulePrivate)); + + gobject_class->finalize = gdata_access_rule_finalize; + gobject_class->set_property = gdata_access_rule_set_property; + gobject_class->get_property = gdata_access_rule_get_property; + + entry_class->get_xml = get_xml; + entry_class->parse_xml = parse_xml; + entry_class->get_namespaces = get_namespaces; + + /** + * GDataAccessRule:role: + * + * The role of the person concerned by this ACL. + * + * Since: 0.3.0 + **/ + g_object_class_install_property (gobject_class, PROP_ROLE, + g_param_spec_string ("role", + "Role", "The role of the person concerned by this ACL.", + NULL, + G_PARAM_READWRITE )); + + /** + * GDataAccessRule:scope-type: + * + * Specifies to whom this access rule applies. + * + * Since: 0.3.0 + **/ + g_object_class_install_property (gobject_class, PROP_SCOPE_TYPE, + g_param_spec_string ("scope-type", + "Scope type", "Specifies to whom this access rule applies.", + NULL, + G_PARAM_READWRITE )); + + /** + * GDataAccessRule:scope-value: + * + * A value representing the user who is represented by the access rule, such as an + * e-mail address for users, or a domain name for domains. + * + * Since: 0.3.0 + **/ + g_object_class_install_property (gobject_class, PROP_SCOPE_VALUE, + g_param_spec_string ("scope-value", + "Scope value", "The scope value for this access rule.", + NULL, + G_PARAM_READWRITE )); +} + +/** + * gdata_access_rule_new: + * @id: the access rule's ID, or %NULL + * + * Creates a new #GDataAccessRule with the given ID and default properties. + * + * Return value: a new #GDataAccessRule; unref with g_object_unref() + * + * Since: 0.3.0 + **/ +GDataAccessRule * +gdata_access_rule_new (const gchar *id) +{ + return g_object_new (GDATA_TYPE_ACCESS_RULE, "id", id, NULL); +} + +/** + * gdata_access_rule_new_from_xml: + * @xml: an XML string + * @length: the length in characters of @xml, or %-1 + * @error: a #GError, or %NULL + * + * Creates a new #GDataAccessRule from an XML string. If @length is %-1, the length of + * the string will be calculated. + * + * Errors from #GDataParserError can be returned if problems are found in the XML. + * + * Return value: a new #GDataAccessRule, or %NULL; unref with g_object_unref() + * + * Since: 0.3.0 + **/ +GDataAccessRule * +gdata_access_rule_new_from_xml (const gchar *xml, gint length, GError **error) +{ + return GDATA_ACCESS_RULE (_gdata_entry_new_from_xml (GDATA_TYPE_ACCESS_RULE, xml, length, error)); +} + +static void +gdata_access_rule_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + GDataAccessRule *self = GDATA_ACCESS_RULE (object); + + switch (property_id) { + case PROP_ROLE: + gdata_access_rule_set_role (self, g_value_get_string (value)); + break; + case PROP_SCOPE_TYPE: + g_free (self->priv->scope_type); + self->priv->scope_type = g_value_dup_string (value); + g_object_notify (object, "scope-type"); + break; + case PROP_SCOPE_VALUE: + g_free (self->priv->scope_value); + self->priv->scope_value = g_value_dup_string (value); + g_object_notify (object, "scope-value"); + break; + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gdata_access_rule_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + GDataAccessRulePrivate *priv = GDATA_ACCESS_RULE_GET_PRIVATE (object); + + switch (property_id) { + case PROP_ROLE: + g_value_set_string (value, priv->role); + break; + case PROP_SCOPE_TYPE: + g_value_set_string (value, priv->scope_type); + break; + case PROP_SCOPE_VALUE: + g_value_set_string (value, priv->scope_value); + break; + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gdata_access_rule_init (GDataAccessRule *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_ACCESS_RULE, GDataAccessRulePrivate); +} + +static void +gdata_access_rule_finalize (GObject *object) +{ + GDataAccessRulePrivate *priv = GDATA_ACCESS_RULE_GET_PRIVATE (object); + + g_free (priv->role); + g_free (priv->scope_type); + g_free (priv->scope_value); + + /* Chain up to the parent class */ + G_OBJECT_CLASS (gdata_access_rule_parent_class)->finalize (object); +} + +static gboolean +parse_xml (GDataEntry *entry, xmlDoc *doc, xmlNode *node, GError **error) +{ + GDataAccessRule *self = GDATA_ACCESS_RULE (entry); + + g_return_val_if_fail (GDATA_IS_ACCESS_RULE (self), FALSE); + g_return_val_if_fail (doc != NULL, FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + if (xmlStrcmp (node->name, (xmlChar*) "role") == 0) { + /* gAcl:role */ + xmlChar *role = xmlGetProp (node, (xmlChar*) "value"); + if (role == NULL) + return gdata_parser_error_required_property_missing ("gAcl:role", "value", error); + gdata_access_rule_set_role (self, (gchar*) role); + xmlFree (role); + } else if (xmlStrcmp (node->name, (xmlChar*) "scope") == 0) { + /* gAcl:scope */ + xmlChar *scope_type, *scope_value; + + scope_type = xmlGetProp (node, (xmlChar*) "type"); + if (scope_type == NULL) + return gdata_parser_error_required_property_missing ("gAcl:scope", "type", error); + + scope_value = xmlGetProp (node, (xmlChar*) "value"); + gdata_access_rule_set_scope (self, (gchar*) scope_type, (gchar*) scope_value); + xmlFree (scope_type); + xmlFree (scope_value); + } else if (GDATA_ENTRY_CLASS (gdata_access_rule_parent_class)->parse_xml (entry, doc, node, error) == FALSE) { + /* Error! */ + return FALSE; + } + + return TRUE; +} + +static void +get_xml (GDataEntry *entry, GString *xml_string) +{ + GDataCategory *category; + GDataAccessRulePrivate *priv = GDATA_ACCESS_RULE (entry)->priv; + + /* Ensure we have the correct category/kind */ + category = gdata_category_new ("http://schemas.google.com/acl/2007#accessRule", "http://schemas.google.com/g/2005#kind", NULL); + gdata_entry_add_category (entry, category); + + /* So it's valid Atom, set the title if one doesn't already exist */ + if (gdata_entry_get_title (entry) == NULL) + gdata_entry_set_title (entry, priv->role); + + /* Chain up to the parent class */ + GDATA_ENTRY_CLASS (gdata_access_rule_parent_class)->get_xml (entry, xml_string); + + if (priv->role != NULL) + /* gAcl:role */ + g_string_append_printf (xml_string, "<gAcl:role value='%s'/>", priv->role); + + if (priv->scope_value != NULL){ + /* gAcl:scope */ + if (priv->scope_type != NULL) + g_string_append_printf (xml_string, "<gAcl:scope type='%s' value='%s'/>", priv->scope_type, priv->scope_value); + else + g_string_append_printf (xml_string, "<gAcl:scope value='%s'/>", priv->scope_value); + } +} + +static void +get_namespaces (GDataEntry *entry, GHashTable *namespaces) +{ + /* Chain up to the parent class */ + GDATA_ENTRY_CLASS (gdata_access_rule_parent_class)->get_namespaces (entry, namespaces); + + g_hash_table_insert (namespaces, (gchar*) "gAcl", (gchar*) "http://schemas.google.com/acl/2007"); +} + +/** + * gdata_access_rule_set_role: + * @self: a #GDataAccessRule + * @role: a new role, or %NULL + * + * Sets the #GDataAccessRule:role property to @role. + * + * Set @role to %NULL to unset the property in the access rule. + * + * Since: 0.3.0 + **/ +void +gdata_access_rule_set_role (GDataAccessRule *self, const gchar *role) +{ + g_return_if_fail (GDATA_IS_ACCESS_RULE (self)); + g_free (self->priv->role); + self->priv->role = g_strdup (role); + g_object_notify (G_OBJECT (self), "role"); +} + +/** + * gdata_access_rule_get_role: + * @self: a #GDataAccessRule + * + * Gets the #GDataAccessRule:role property. + * + * Return value: the access rule's role, or %NULL + * + * Since: 0.3.0 + **/ +const gchar * +gdata_access_rule_get_role (GDataAccessRule *self) +{ + g_return_val_if_fail (GDATA_IS_ACCESS_RULE (self), NULL); + return self->priv->role; +} + + +/** + * gdata_access_rule_set_scope: + * @self: a #GDataAccessRule + * @type: a new scope type + * @value: a new scope value, or %NULL + * + * Sets the #GDataAccessRule:scope-type property to @type and the #GDataAccessRule:scope-value property to @value. + * + * Set @scope_value to %NULL to unset the #GDataAccessRule:scope-value property in the access rule. @type cannot + * be %NULL. @scope_value must be %NULL if @type is <literal>default</literal>, and non-%NULL otherwise. + * + * See the <ulink type="http" url="http://code.google.com/apis/calendar/docs/2.0/reference.html#gacl_reference">online documentation</ulink> + * for more information. + * + * Since: 0.3.0 + **/ +void +gdata_access_rule_set_scope (GDataAccessRule *self, const gchar *type, const gchar *value) +{ + g_return_if_fail (GDATA_IS_ACCESS_RULE (self)); + g_return_if_fail (type != NULL); + + /* Validate stuff first */ + if (strcmp (type, "default") == 0) + g_return_if_fail (value == NULL); + else + g_return_if_fail (value != NULL); + + g_free (self->priv->scope_type); + self->priv->scope_type = g_strdup (type); + + g_free (self->priv->scope_value); + self->priv->scope_value = g_strdup (value); + + g_object_freeze_notify (G_OBJECT (self)); + g_object_notify (G_OBJECT (self), "scope-type"); + g_object_notify (G_OBJECT (self), "scope-value"); + g_object_thaw_notify (G_OBJECT (self)); +} + +/** + * gdata_access_rule_get_scope: + * @self: a #GDataAccessRule + * @type: return location for the scope type, or %NULL + * @value: return location for the scope value, or %NULL + * + * Gets the #GDataAccessRule:scope-type and #GDataAccessRule:scope-value properties. + * + * Since: 0.3.0 + **/ +void +gdata_access_rule_get_scope (GDataAccessRule *self, const gchar **type, const gchar **value) +{ + g_return_if_fail (GDATA_IS_ACCESS_RULE (self)); + if (type != NULL) + *type = self->priv->scope_type; + if (value != NULL) + *value = self->priv->scope_value; +} |