static gboolean
post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error)
{
	GDataDocumentsAccessRulePrivate *priv;

	priv = gdata_documents_access_rule_get_instance_private (GDATA_DOCUMENTS_ACCESS_RULE (parsable));

	if (g_strcmp0 (priv->scope_type, GDATA_ACCESS_SCOPE_DEFAULT) == 0) {
		gdata_access_rule_set_scope (GDATA_ACCESS_RULE (parsable), priv->scope_type, NULL);
	} else if (g_strcmp0 (priv->scope_type, "group") == 0 || g_strcmp0 (priv->scope_type, GDATA_ACCESS_SCOPE_USER) == 0) {
		if (priv->email == NULL || priv->email[0] == '\0') {
			g_set_error (error, GDATA_PARSER_ERROR, GDATA_PARSER_ERROR_PARSING_STRING,
			             /* Translators: the parameter is an error message */
			             _("Error parsing JSON: %s"),
			             "Permission type ‘group’ or ‘user’ needs an ‘emailAddress’ property.");
			return FALSE;
		} else {
			gdata_access_rule_set_scope (GDATA_ACCESS_RULE (parsable), priv->scope_type, priv->email);
		}
	} else if (g_strcmp0 (priv->scope_type, GDATA_ACCESS_SCOPE_DOMAIN) == 0) {
		if (priv->domain == NULL || priv->domain[0] == '\0') {
			g_set_error (error, GDATA_PARSER_ERROR, GDATA_PARSER_ERROR_PARSING_STRING,
			             /* Translators: the parameter is an error message */
			             _("Error parsing JSON: %s"),
			             "Permission type ‘domain’ needs a ‘domain’ property.");
			return FALSE;
		} else {
			gdata_access_rule_set_scope (GDATA_ACCESS_RULE (parsable), priv->scope_type, priv->domain);
		}
	}

	return TRUE;
}
static gboolean
parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
{
	gboolean success;

	if (g_strcmp0 (json_reader_get_member_name (reader), "role") == 0) {
		gchar *role = NULL;  /* owned */

		g_assert (gdata_parser_string_from_json_member (reader, "role",
		                                                P_REQUIRED |
		                                                P_NON_EMPTY,
		                                                &role, &success,
		                                                error));

		if (!success) {
			return FALSE;
		}

		gdata_access_rule_set_role (GDATA_ACCESS_RULE (parsable),
		                            role_v3_to_v2 (role));
		g_free (role);

		return TRUE;
	} else if (g_strcmp0 (json_reader_get_member_name (reader),
	                                                   "scope") == 0) {
		const gchar *scope_type;
		const gchar *scope_value;

		/* Check this is an object. */
		if (!json_reader_is_object (reader)) {
			return gdata_parser_error_required_json_content_missing (reader,
			                                                         error);
		}

		json_reader_read_member (reader, "type");
		scope_type = json_reader_get_string_value (reader);
		json_reader_end_member (reader);

		json_reader_read_member (reader, "value");
		scope_value = json_reader_get_string_value (reader);
		json_reader_end_member (reader);

		/* Scope type is required. */
		if (scope_type == NULL) {
			return gdata_parser_error_required_json_content_missing (reader,
			                                                         error);
		}

		gdata_access_rule_set_scope (GDATA_ACCESS_RULE (parsable),
		                             scope_type_v3_to_v2 (scope_type),
		                             scope_value);

		return TRUE;
	}

	return GDATA_PARSABLE_CLASS (gdata_calendar_access_rule_parent_class)->parse_json (parsable, reader, user_data, error);
}
/**
 * gdata_access_handler_update_rule:
 * @self: a #GDataAccessHandler
 * @service: a #GDataService
 * @rule: the #GDataAccessRule to update
 * @cancellable: optional #GCancellable object, or %NULL
 * @error: a #GError, or %NULL
 *
 * Updates @rule in the access control list of the #GDataAccessHandler.
 *
 * The service will return an updated version of the rule, which is the return value of this function on success.
 *
 * If @cancellable is not %NULL, then the operation can be cancelled by triggering the @cancellable object from another thread.
 * If the operation was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
 *
 * If there is an error updating the rule, a %GDATA_SERVICE_ERROR_WITH_UPDATE error will be returned.
 *
 * Return value: an updated #GDataAccessRule, or %NULL
 *
 * Since: 0.3.0
 **/
GDataAccessRule *
gdata_access_handler_update_rule (GDataAccessHandler *self, GDataService *service, GDataAccessRule *rule, GCancellable *cancellable, GError **error)
{
	GDataServiceClass *klass;
	GDataAccessRule *updated_rule;
	SoupMessage *message;
	gchar *upload_data;
	guint status;

	g_return_val_if_fail (GDATA_IS_ENTRY (self), NULL);
	g_return_val_if_fail (GDATA_IS_SERVICE (service), NULL);
	g_return_val_if_fail (GDATA_IS_ACCESS_RULE (rule), NULL);

	message = get_soup_message (self, rule, SOUP_METHOD_PUT);

	/* Make sure subclasses set their headers */
	klass = GDATA_SERVICE_GET_CLASS (service);
	if (klass->append_query_headers != NULL)
		klass->append_query_headers (service, message);

	/* Looks like ACLs don't support ETags */

	/* Append the data */
	upload_data = gdata_entry_get_xml (GDATA_ENTRY (rule));
	soup_message_set_request (message, "application/atom+xml", SOUP_MEMORY_TAKE, upload_data, strlen (upload_data));

	/* Send the message */
	status = _gdata_service_send_message (service, message, error);
	if (status == SOUP_STATUS_NONE) {
		g_object_unref (message);
		return NULL;
	}

	/* Check for cancellation */
	if (g_cancellable_set_error_if_cancelled (cancellable, error) == TRUE) {
		g_object_unref (message);
		return NULL;
	}

	if (status != 200) {
		/* Error */
		g_assert (klass->parse_error_response != NULL);
		klass->parse_error_response (service, GDATA_SERVICE_ERROR_WITH_UPDATE, status, message->reason_phrase, message->response_body->data,
					     message->response_body->length, error);
		g_object_unref (message);
		return NULL;
	}

	/* Build the updated entry */
	g_assert (message->response_body->data != NULL);

	/* Parse the XML; create and return a new GDataEntry of the same type as @entry */
	updated_rule = GDATA_ACCESS_RULE (_gdata_entry_new_from_xml (G_OBJECT_TYPE (rule), message->response_body->data,
								     message->response_body->length, error));
	g_object_unref (message);

	return updated_rule;
}
static gboolean
parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
{
	GDataDocumentsAccessRulePrivate *priv;
	gboolean success;
	gchar *key = NULL;
	gchar *role = NULL;
	gchar *scope_type = NULL;

	priv = gdata_documents_access_rule_get_instance_private (GDATA_DOCUMENTS_ACCESS_RULE (parsable));

	/* JSON format: https://developers.google.com/drive/v2/reference/permissions */

	if (gdata_parser_string_from_json_member (reader, "emailAddress", P_REQUIRED | P_NON_EMPTY, &(priv->email), &success, error) == TRUE ||
	    gdata_parser_string_from_json_member (reader, "domain", P_REQUIRED | P_NON_EMPTY, &(priv->domain), &success, error) == TRUE) {
		return success;
	} else if (gdata_parser_string_from_json_member (reader, "authKey", P_REQUIRED | P_NON_EMPTY, &key, &success, error) == TRUE) {
		if (success && key != NULL && key[0] != '\0')
			_gdata_access_rule_set_key (GDATA_ACCESS_RULE (parsable), key);

		g_free (key);
		return success;
	} else if (gdata_parser_string_from_json_member (reader, "role", P_REQUIRED | P_NON_EMPTY, &role, &success, error) == TRUE) {
		if (success && role != NULL && role[0] != '\0')
			gdata_access_rule_set_role (GDATA_ACCESS_RULE (parsable), role);

		g_free (role);
		return success;
	} else if (gdata_parser_string_from_json_member (reader, "type", P_REQUIRED | P_NON_EMPTY, &scope_type, &success, error) == TRUE) {
		if (g_strcmp0 (scope_type, "anyone") == 0) {
			priv->scope_type = g_strdup (GDATA_ACCESS_SCOPE_DEFAULT);
		} else {
			priv->scope_type = scope_type;
			scope_type = NULL;
		}

		g_free (scope_type);
		return success;
	}

	return GDATA_PARSABLE_CLASS (gdata_documents_access_rule_parent_class)->parse_json (parsable, reader, user_data, error);
}
static void
get_json (GDataParsable *parsable, JsonBuilder *builder)
{
	const gchar *key;
	const gchar *role;
	const gchar *scope_type;
	const gchar *scope_value;

	GDATA_PARSABLE_CLASS (gdata_documents_access_rule_parent_class)->get_json (parsable, builder);

	key = gdata_access_rule_get_key (GDATA_ACCESS_RULE (parsable));
	if (key != NULL && key[0] != '\0') {
		json_builder_set_member_name (builder, "authKey");
		json_builder_add_string_value (builder, key);
	}

	role = gdata_access_rule_get_role (GDATA_ACCESS_RULE (parsable));
	if (role != NULL && role[0] != '\0') {
		json_builder_set_member_name (builder, "role");
		json_builder_add_string_value (builder, role);
	}

	gdata_access_rule_get_scope (GDATA_ACCESS_RULE (parsable), &scope_type, &scope_value);

	if (scope_type != NULL && scope_type[0] != '\0') {
		if (g_strcmp0 (scope_type, GDATA_ACCESS_SCOPE_DEFAULT) == 0)
			scope_type = "anyone";

		json_builder_set_member_name (builder, "type");
		json_builder_add_string_value (builder, scope_type);
	}

	if (scope_value != NULL && scope_value[0] != '\0') {
		json_builder_set_member_name (builder, "value");
		json_builder_add_string_value (builder, scope_value);
	}
}
static void
get_json (GDataParsable *parsable, JsonBuilder *builder)
{
	GDataAccessRule *access_rule;
	const gchar *id, *etag, *role, *scope_type, *scope_value;

	access_rule = GDATA_ACCESS_RULE (parsable);

	id = gdata_entry_get_id (GDATA_ENTRY (parsable));
	if (id != NULL) {
		json_builder_set_member_name (builder, "id");
		json_builder_add_string_value (builder, id);
	}

	json_builder_set_member_name (builder, "kind");
	json_builder_add_string_value (builder, "calendar#aclRule");

	/* Add the ETag, if available. */
	etag = gdata_entry_get_etag (GDATA_ENTRY (parsable));
	if (etag != NULL) {
		json_builder_set_member_name (builder, "etag");
		json_builder_add_string_value (builder, etag);
	}

	role = gdata_access_rule_get_role (access_rule);
	if (role != NULL) {
		json_builder_set_member_name (builder, "role");
		json_builder_add_string_value (builder, role_v2_to_v3 (role));
	}

	gdata_access_rule_get_scope (access_rule, &scope_type, &scope_value);
	if (scope_type != NULL || scope_value != NULL) {
		json_builder_set_member_name (builder, "scope");
		json_builder_begin_object (builder);

		if (scope_type != NULL) {
			json_builder_set_member_name (builder, "type");
			json_builder_add_string_value (builder,
			                               scope_type_v2_to_v3 (scope_type));
		}

		if (scope_value != NULL) {
			json_builder_set_member_name (builder, "value");
			json_builder_add_string_value (builder, scope_value);
		}

		json_builder_end_object (builder);
	}
}
/**
 * gdata_access_handler_insert_rule:
 * @self: a #GDataAccessHandler
 * @service: a #GDataService
 * @rule: the #GDataAccessRule to insert
 * @cancellable: optional #GCancellable object, or %NULL
 * @error: a #GError, or %NULL
 *
 * Inserts @rule in the access control list of the #GDataAccessHandler.
 *
 * The service will return an updated version of the rule, which is the return value of this function on success.
 *
 * If @cancellable is not %NULL, then the operation can be cancelled by triggering the @cancellable object from another thread.
 * If the operation was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
 *
 * If the rule is marked as already having been inserted a %GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED error will be returned immediately
 * (there will be no network requests).
 *
 * If there is an error inserting the rule, a %GDATA_SERVICE_ERROR_WITH_INSERTION error will be returned.
 *
 * Return value: an updated #GDataAccessRule, or %NULL
 *
 * Since: 0.3.0
 **/
GDataAccessRule *
gdata_access_handler_insert_rule (GDataAccessHandler *self, GDataService *service, GDataAccessRule *rule, GCancellable *cancellable, GError **error)
{
	GDataServiceClass *klass;
	GDataAccessRule *updated_rule;
	GDataLink *link;
	SoupMessage *message;
	gchar *upload_data;
	guint status;

	g_return_val_if_fail (GDATA_IS_ENTRY (self), NULL);
	g_return_val_if_fail (GDATA_IS_SERVICE (service), NULL);
	g_return_val_if_fail (GDATA_IS_ACCESS_RULE (rule), NULL);

	if (gdata_entry_is_inserted (GDATA_ENTRY (rule)) == TRUE) {
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED,
				     _("The rule has already been inserted."));
		return NULL;
	}

	/* Get the ACL URI */
	link = gdata_entry_look_up_link (GDATA_ENTRY (self), "http://schemas.google.com/acl/2007#accessControlList");
	g_assert (link != NULL);
	message = soup_message_new (SOUP_METHOD_POST, link->href);

	/* Make sure subclasses set their headers */
	klass = GDATA_SERVICE_GET_CLASS (service);
	if (klass->append_query_headers != NULL)
		klass->append_query_headers (service, message);

	/* Append the data */
	upload_data = gdata_entry_get_xml (GDATA_ENTRY (rule));
	soup_message_set_request (message, "application/atom+xml", SOUP_MEMORY_TAKE, upload_data, strlen (upload_data));

	/* Send the message */
	status = _gdata_service_send_message (service, message, error);
	if (status == SOUP_STATUS_NONE) {
		g_object_unref (message);
		return NULL;
	}

	/* Check for cancellation */
	if (g_cancellable_set_error_if_cancelled (cancellable, error) == TRUE) {
		g_object_unref (message);
		return NULL;
	}

	if (status != 201) {
		/* Error */
		g_assert (klass->parse_error_response != NULL);
		klass->parse_error_response (service, GDATA_SERVICE_ERROR_WITH_INSERTION, status, message->reason_phrase, message->response_body->data,
					     message->response_body->length, error);
		g_object_unref (message);
		return NULL;
	}

	/* Build the updated entry */
	g_assert (message->response_body->data != NULL);

	/* Parse the XML; create and return a new GDataEntry of the same type as @entry */
	updated_rule = GDATA_ACCESS_RULE (_gdata_entry_new_from_xml (G_OBJECT_TYPE (rule), message->response_body->data,
					  message->response_body->length, error));
	g_object_unref (message);

	return updated_rule;
}