diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 63d7b27..588f64d 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -1183,6 +1183,7 @@ GDataYouTubeStatePrivate
 GDataPicasaWebService
 GDataPicasaWebServiceClass
 gdata_picasaweb_service_new
+gdata_picasaweb_service_get_user
 gdata_picasaweb_service_query_all_albums
 gdata_picasaweb_service_query_all_albums_async
 gdata_picasaweb_service_query_files
@@ -1198,6 +1199,46 @@ GDATA_TYPE_PICASAWEB_SERVICE
 </SECTION>
 
 <SECTION>
+<FILE>gdata-picasaweb-feed</FILE>
+<TITLE>GDataPicasaWebFeed</TITLE>
+GDataPicasaWebFeed
+GDataPicasaWebFeedClass
+<SUBSECTION Standard>
+gdata_picasaweb_feed_get_type
+GDATA_PICASAWEB_FEED
+GDATA_PICASWEB_FEED_CLASS
+GDATA_PICASAWEB_FEED_GET_CLASS
+GDATA_IS_PICASAWEB_FEED
+GDATA_IS_PICASAWEB_FEED_CLASS
+GDATA_TYPE_PICASAWEB_FEED
+<SUBSECTION Private>
+GDataPicasaWebFeedPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gdata-picasaweb-user</FILE>
+<TITLE>GDataPicasaWebUser</TITLE>
+GDataPicasaWebUser
+GDataPicasaWebUserClass
+gdata_picasaweb_user_get_user
+gdata_picasaweb_user_get_nickname
+gdata_picasaweb_user_get_quota_limit
+gdata_picasaweb_user_get_quota_current
+gdata_picasaweb_user_get_max_photos_per_album
+gdata_picasaweb_user_get_thumbnail
+<SUBSECTION Standard>
+gdata_picasaweb_user_get_type
+GDATA_PICASAWEB_USER
+GDATA_PICASWEB_USER_CLASS
+GDATA_PICASAWEB_USER_GET_CLASS
+GDATA_IS_PICASAWEB_USER
+GDATA_IS_PICASAWEB_USER_CLASS
+GDATA_TYPE_PICASAWEB_USER
+<SUBSECTION Private>
+GDataPicasaWebUserPrivate
+</SECTION>
+
+<SECTION>
 <FILE>gdata-picasaweb-query</FILE>
 <TITLE>GDataPicasaWebQuery</TITLE>
 GDataPicasaWebQuery
diff --git a/gdata/gdata.h b/gdata/gdata.h
index c5830be..347694c 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -84,6 +84,7 @@
 #include <gdata/services/picasaweb/gdata-picasaweb-album.h>
 #include <gdata/services/picasaweb/gdata-picasaweb-file.h>
 #include <gdata/services/picasaweb/gdata-picasaweb-enums.h>
+#include <gdata/services/picasaweb/gdata-picasaweb-user.h>
 
 /* Google Contacts */
 #include <gdata/services/contacts/gdata-contacts-service.h>
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 2ee91d5..cc8de5a 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -597,10 +597,19 @@ gdata_picasaweb_file_get_coordinates
 gdata_picasaweb_file_set_coordinates
 gdata_picasaweb_service_get_type
 gdata_picasaweb_service_new
+gdata_picasaweb_service_get_user
 gdata_picasaweb_service_query_all_albums
 gdata_picasaweb_service_query_all_albums_async
 gdata_picasaweb_service_query_files
 gdata_picasaweb_service_upload_file
+gdata_picasaweb_feed_get_type
+gdata_picasaweb_user_get_type
+gdata_picasaweb_user_get_user
+gdata_picasaweb_user_get_nickname
+gdata_picasaweb_user_get_quota_limit
+gdata_picasaweb_user_get_quota_current
+gdata_picasaweb_user_get_max_photos_per_album
+gdata_picasaweb_user_get_thumbnail
 gdata_picasaweb_query_get_type
 gdata_picasaweb_query_new
 gdata_picasaweb_query_new_with_limits
diff --git a/gdata/services/picasaweb/Makefile.am b/gdata/services/picasaweb/Makefile.am
index 15d1bde..1734bbf 100644
--- a/gdata/services/picasaweb/Makefile.am
+++ b/gdata/services/picasaweb/Makefile.am
@@ -32,7 +32,9 @@ gdata_picasaweb_headers = \
 	gdata-picasaweb-service.h	\
 	gdata-picasaweb-query.h		\
 	gdata-picasaweb-file.h		\
-	gdata-picasaweb-album.h
+	gdata-picasaweb-album.h    	\
+	gdata-picasaweb-user.h		\
+	gdata-picasaweb-feed.h
 
 gdatapicasawebinclude_HEADERS = \
 	$(gdata_picasaweb_headers)	\
@@ -45,7 +47,9 @@ libgdatapicasaweb_la_SOURCES = \
 	gdata-picasaweb-album.c		\
 	gdata-picasaweb-query.c		\
 	gdata-picasaweb-file.c		\
-	gdata-picasaweb-service.c
+	gdata-picasaweb-service.c	\
+	gdata-picasaweb-user.c		\
+	gdata-picasaweb-feed.c
 
 libgdatapicasaweb_la_CPPFLAGS = \
 	-I$(top_srcdir)					\
diff --git a/gdata/services/picasaweb/gdata-picasaweb-feed.c b/gdata/services/picasaweb/gdata-picasaweb-feed.c
new file mode 100644
index 0000000..800cdac
--- /dev/null
+++ b/gdata/services/picasaweb/gdata-picasaweb-feed.c
@@ -0,0 +1,148 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2009 <philip@tecnocode.co.uk>
+ * Copyright (C) Richard Schwarting 2009 <aquarichy@gmail.com>
+ *
+ * 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-picasaweb-feed
+ * @short_description: GData PicasaWeb Feed object
+ * @stability: Unstable
+ * @include: gdata/services/picasaweb/gdata-picasaweb-feed.h
+ *
+ * #GDataPicasaWebFeed is a subclass of #GDataFeed to represent properties for a PicasaWeb feed. It adds a couple of
+ * properties which are specific to the Google PicasaWeb API.
+ **/
+
+#include <glib.h>
+#include <libxml/parser.h>
+
+#include "gdata-picasaweb-feed.h"
+#include "gdata-feed.h"
+#include "gdata-private.h"
+
+static void gdata_picasaweb_feed_finalize (GObject *object);
+static void gdata_picasaweb_feed_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
+
+struct _GDataPicasaWebFeedPrivate {
+	char nodata; 
+};
+
+G_DEFINE_TYPE (GDataPicasaWebFeed, gdata_picasaweb_feed, GDATA_TYPE_FEED)
+#define GDATA_PICASAWEB_FEED_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDATA_TYPE_PICASAWEB_FEED, GDataPicasaWebFeedPrivate))
+
+static void
+gdata_picasaweb_feed_class_init (GDataPicasaWebFeedClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GDataPicasaWebFeedPrivate));
+
+	gobject_class->get_property = gdata_picasaweb_feed_get_property;
+	gobject_class->finalize = gdata_picasaweb_feed_finalize;
+
+	parsable_class->parse_xml = parse_xml;
+
+}
+
+static void
+gdata_picasaweb_feed_init (GDataPicasaWebFeed *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_PICASAWEB_FEED, GDataPicasaWebFeedPrivate);
+}
+
+static void
+gdata_picasaweb_feed_finalize (GObject *object)
+{
+	/* Chain up to the parent class */
+	G_OBJECT_CLASS (gdata_picasaweb_feed_parent_class)->finalize (object);
+}
+
+static void
+gdata_picasaweb_feed_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	switch (property_id) {
+		default:
+			/* We don't have any other property... */
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+static gboolean
+parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
+{
+	if (xmlStrcmp (node->name, (xmlChar*) "user") == 0) {
+		/* gphoto:user */
+		/* From user's feed of album entries.  Redundant with user entry represented by GDataPicasaWebUser.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "nickname") == 0) {
+		/* gphoto:nickname */
+		/* From user's feed of album entries.  Redundant with user entry represented by GDataPicasaWebUser.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "quotacurrent") == 0) {
+		/* gphoto:quota-current */
+		/* From user's feed of album entries.  Redundant with user entry represented by GDataPicasaWebUser.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "quotalimit") == 0) {
+		/* gphoto:quota-limit */
+		/* From user's feed of album entries.  Redundant with user entry represented by GDataPicasaWebUser.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "maxPhotosPerAlbum") == 0) {
+		/* gphoto:max-photos-per-album */
+		/* From user's feed of album entries.  Redundant with user entry represented by GDataPicasaWebUser.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "thumbnail") == 0) {
+		/* gphoto:thumbnail */
+		/* From user's feed of album entries.  Redundant with user entry represented by GDataPicasaWebUser.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "allowDownloads") == 0) {
+		/* gphoto:allowDownloads */
+		/* Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "allowPrints") == 0) {
+		/* gphoto:allowPrints */
+		/* Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "id") == 0 && xmlStrcmp (node->ns->href, (xmlChar*) "http://schemas.google.com/photos/2007") == 0) {
+		/* gphoto:id */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "rights") == 0) {
+		/* gphoto:rights */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "location") == 0) {
+		/* gphoto:location */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "access") == 0) {
+		/* gphoto:access */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "timestamp") == 0) {
+		/* gphoto:timestamp */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "numphotos") == 0) {
+		/* gphoto:numphotos */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "numphotosremaining") == 0) {
+		/* gphoto:numphotosremaining */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "bytesUsed") == 0) {
+		/* gphoto:bytesUsed */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "where") == 0) {
+		/* georss:where */
+		/* From album's feed of file entries.  Redundant with album entries represented by GDataPicasaWebAlbum.  Capturing and ignoring.  See bgo #589858. */
+	} else if (GDATA_PARSABLE_CLASS (gdata_picasaweb_feed_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
+		/* Error! */
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
diff --git a/gdata/services/picasaweb/gdata-picasaweb-feed.h b/gdata/services/picasaweb/gdata-picasaweb-feed.h
new file mode 100644
index 0000000..b1bc50d
--- /dev/null
+++ b/gdata/services/picasaweb/gdata-picasaweb-feed.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2009 <philip@tecnocode.co.uk>
+ * Copyright (C) Richard Schwarting 2009 <aquarichy@gmail.com>
+ *
+ * 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/>.
+ */
+
+#ifndef GDATA_PICASAWEB_FEED_H
+#define GDATA_PICASAWEB_FEED_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-parsable.h>
+#include <gdata/gdata-feed.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_PICASAWEB_FEED		(gdata_picasaweb_feed_get_type ())
+#define GDATA_PICASAWEB_FEED(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_PICASAWEB_FEED, GDataPicasaWebFeed))
+#define GDATA_PICASAWEB_FEED_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_PICASAWEB_FEED, GDataPicasaWebFeedClass))
+#define GDATA_IS_PICASAWEB_FEED(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_PICASAWEB_FEED))
+#define GDATA_IS_PICASAWEB_FEED_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_PICASAWEB_FEED))
+#define GDATA_PICASAWEB_FEED_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_PICASAWEB_FEED, GDataPicasaWebFeedClass))
+
+typedef struct _GDataPicasaWebFeedPrivate	GDataPicasaWebFeedPrivate;
+
+/**
+ * GDataPicasaWebFeed:
+ *
+ * All the fields in the #GDataPicasaWebFeed structure are private and should never be accessed directly.
+ *
+ * Since: 0.6.0
+ **/
+typedef struct {
+	GDataFeed parent;
+	GDataPicasaWebFeedPrivate *priv;
+} GDataPicasaWebFeed;
+
+/**
+ * GDataPicasaWebFeedClass:
+ *
+ * All the fields in the #GDataPicasaWebFeedClass structure are private and should never be accessed directly.
+ *
+ * Since: 0.6.0
+ **/
+typedef struct {
+	/*< private >*/
+	GDataFeedClass parent;
+} GDataPicasaWebFeedClass;
+
+GType gdata_picasaweb_feed_get_type (void);
+
+G_END_DECLS
+
+#endif /* !GDATA_PICASAWEB_FEED_H */
diff --git a/gdata/services/picasaweb/gdata-picasaweb-query.c b/gdata/services/picasaweb/gdata-picasaweb-query.c
index 8306b3a..4578616 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-query.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-query.c
@@ -248,7 +248,7 @@ get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboo
 
 	APPEND_SEP
 	if (priv->visibility == 0)
-		g_string_append (query_uri, "access=all");
+		; // Appending nothing to retrieve all for authenticated users and just public albums for unauthenticated 
 	else if (priv->visibility == GDATA_PICASAWEB_PUBLIC)
 		g_string_append (query_uri, "access=public");
 	else if (priv->visibility == GDATA_PICASAWEB_PRIVATE)
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.c b/gdata/services/picasaweb/gdata-picasaweb-service.c
index 20b0119..4570270 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.c
@@ -41,6 +41,7 @@
 #include "gdata-parser.h"
 #include "atom/gdata-link.h"
 #include "gdata-upload-stream.h"
+#include "gdata-picasaweb-feed.h"
 
 G_DEFINE_TYPE (GDataPicasaWebService, gdata_picasaweb_service, GDATA_TYPE_SERVICE)
 
@@ -49,6 +50,7 @@ gdata_picasaweb_service_class_init (GDataPicasaWebServiceClass *klass)
 {
 	GDataServiceClass *service_class = GDATA_SERVICE_CLASS (klass);
 	service_class->service_name = "lh2";
+	service_class->feed_type = GDATA_TYPE_PICASAWEB_FEED;
 }
 
 static void
@@ -58,12 +60,14 @@ gdata_picasaweb_service_init (GDataPicasaWebService *self)
 }
 
 /*
- * This constructs the URI we want to access for querying albums.
+ * This constructs the URI we want to access for querying albums or a
+ * user.  Type should be either entry (for just a user) or feed (for
+ * an album)
  *
  * Remember to free the URI in the caller.
 */
 static gchar *
-create_uri (GDataPicasaWebService *self, const gchar *username)
+create_uri (GDataPicasaWebService *self, const gchar *username, const gchar *type)
 {
 	if (username == NULL) {
 		/* Ensure we're authenticated first */
@@ -74,7 +78,7 @@ create_uri (GDataPicasaWebService *self, const gchar *username)
 		username = "default";
 	}
 
-	return g_strdup_printf ("http://picasaweb.google.com/data/feed/api/user/%s", username);
+	return g_strdup_printf ("http://picasaweb.google.com/data/%s/api/user/%s", type, username);
 }
 
 /**
@@ -98,6 +102,45 @@ gdata_picasaweb_service_new (const gchar *client_id)
 }
 
 /**
+ * gdata_picasaweb_service_get_user
+ * @self: a #GDataPicasaWebService
+ * @username: the username of the user whose information you wish to retrieve, or %NULL for the currently authenticated user.
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: a #GError, or %NULL
+ *
+ * Queries the service to return the user specified by @username.
+ *
+ * Return value: a #GDataPicasaWebUser; unref with g_object_unref().  
+ *
+ * Since: 0.6.0
+ **/
+GDataPicasaWebUser *
+gdata_picasaweb_service_get_user (GDataPicasaWebService *self, const gchar *username, GCancellable *cancellable, GError **error)
+{
+	gchar *uri;
+	GDataParsable *user;
+	SoupMessage *message;
+
+	g_return_val_if_fail (GDATA_IS_PICASAWEB_SERVICE (self), NULL);
+
+	uri = create_uri (self, username, "entry");
+	if (uri == NULL) {
+		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
+				     _("You must specify a username or be authenticated to query a user."));
+		return NULL;
+	}
+	message = _gdata_service_query (GDATA_SERVICE (self), uri, NULL, cancellable, NULL, NULL, error);
+	if (message == NULL)
+		return NULL; /* RHSTODO: shouldn't we set an error?  (gdata_youtube_service_query_single_video doesn't) */
+
+	g_assert (message->response_body->data != NULL);
+	user = gdata_parsable_new_from_xml (GDATA_TYPE_PICASAWEB_USER, message->response_body->data, message->response_body->length, error);
+	g_object_unref (message);
+
+	return GDATA_PICASAWEB_USER (user);
+}
+
+/**
  * gdata_picasaweb_service_query_all_albums:
  * @self: a #GDataPicasaWebService
  * @query: a #GDataQuery with the query parameters, or %NULL
@@ -136,7 +179,7 @@ gdata_picasaweb_service_query_all_albums (GDataPicasaWebService *self, GDataQuer
 		return NULL;
 	}
 
-	uri = create_uri (self, username);
+	uri = create_uri (self, username, "feed");
 	if (uri == NULL) {
 		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
 				     _("You must specify a username or be authenticated to query all albums."));
@@ -190,7 +233,7 @@ gdata_picasaweb_service_query_all_albums_async (GDataPicasaWebService *self, GDa
 		return;
 	}
 
-	uri = create_uri (self, username);
+	uri = create_uri (self, username, "feed");
 	if (uri == NULL) {
 		g_simple_async_report_error_in_idle (G_OBJECT (self), callback, user_data,
 						     GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.h b/gdata/services/picasaweb/gdata-picasaweb-service.h
index 96eb9c1..4dc227d 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.h
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.h
@@ -26,6 +26,7 @@
 
 #include <gdata/gdata-service.h>
 #include <gdata/services/picasaweb/gdata-picasaweb-album.h>
+#include <gdata/services/picasaweb/gdata-picasaweb-user.h>
 
 G_BEGIN_DECLS
 
@@ -65,6 +66,8 @@ GDataPicasaWebService *gdata_picasaweb_service_new (const gchar *client_id) G_GN
 
 #include <gdata/services/picasaweb/gdata-picasaweb-query.h>
 
+GDataPicasaWebUser *gdata_picasaweb_service_get_user (GDataPicasaWebService *self, const gchar *username, GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
 GDataFeed *gdata_picasaweb_service_query_all_albums (GDataPicasaWebService *self, GDataQuery *query, const gchar *username,
 						     GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
 						     GError **error) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/gdata/services/picasaweb/gdata-picasaweb-user.c b/gdata/services/picasaweb/gdata-picasaweb-user.c
new file mode 100644
index 0000000..315ea7d
--- /dev/null
+++ b/gdata/services/picasaweb/gdata-picasaweb-user.c
@@ -0,0 +1,387 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2009 <philip@tecnocode.co.uk>
+ * Copyright (C) Richard Schwarting 2009 <aquarichy@gmail.com>
+ *
+ * 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-picasaweb-user
+ * @short_description: GData PicasaWeb User object
+ * @stability: Unstable
+ * @include: gdata/services/picasaweb/gdata-picasaweb-user.h
+ *
+ * #GDataPicasaWebUser is a subclass of #GDataEntry to represent properties for a PicasaWeb user. It adds a couple of
+ * properties which are specific to the Google PicasaWeb API.
+ **/
+
+#include <glib.h>
+#include <libxml/parser.h>
+
+#include "gdata-picasaweb-user.h"
+#include "gdata-feed.h"
+#include "gdata-private.h"
+
+static void gdata_picasaweb_user_finalize (GObject *object);
+static void gdata_picasaweb_user_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
+static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
+
+struct _GDataPicasaWebUserPrivate {
+	gchar *user;
+	gchar *nickname;
+	gint64 quota_limit;
+	gint64 quota_current;
+	gint max_photos_per_album;
+	gchar *thumbnail;
+};
+
+enum {
+	PROP_USER = 1,
+	PROP_NICKNAME,
+	PROP_QUOTA_LIMIT,
+	PROP_QUOTA_CURRENT,
+	PROP_MAX_PHOTOS_PER_ALBUM,
+	PROP_THUMBNAIL
+};
+
+G_DEFINE_TYPE (GDataPicasaWebUser, gdata_picasaweb_user, GDATA_TYPE_ENTRY)
+#define GDATA_PICASAWEB_USER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDATA_TYPE_PICASAWEB_USER, GDataPicasaWebUserPrivate))
+
+static void
+gdata_picasaweb_user_class_init (GDataPicasaWebUserClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GDataPicasaWebUserPrivate));
+
+	gobject_class->get_property = gdata_picasaweb_user_get_property;
+	gobject_class->finalize = gdata_picasaweb_user_finalize;
+
+	parsable_class->parse_xml = parse_xml;
+	parsable_class->get_namespaces = get_namespaces;
+
+	/**
+	 * GDataPicasaWebUser:user:
+	 *
+	 * The username of the user, as seen in feed URLs.
+	 * http://code.google.com/apis/picasaweb/reference.html#gphoto_user
+	 *
+	 * Since: 0.6.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_USER,
+					 g_param_spec_string ("user",
+							      "User", "The username for the account holder.",
+							      NULL,
+							      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * GDataPicasaWebUser:nickname:
+	 *
+	 * The nickname of the user as specified by the user.
+	 * http://code.google.com/apis/picasaweb/reference.html#gphoto_nickname
+	 *
+	 * Since: 0.6.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_NICKNAME,
+					 g_param_spec_string ("nickname",
+							      "Nickname", "The nickname of the account holder.",
+							      NULL,
+							      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+	
+	/**
+	 * GDataPicasaWebUser:quota-limit:
+	 *
+	 * The total amount of space in bytes available to the user. 
+	 * http://code.google.com/apis/picasaweb/reference.html#gphoto_quotalimit
+	 *
+	 * Since: 0.6.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_QUOTA_LIMIT,
+					 g_param_spec_int64 ("quota-limit",
+							     "Quota Limit", "The number of bytes available.",
+							     -1, G_MAXINT64, -1, 
+							     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * GDataPicasaWebUser:quota-current:
+	 *
+	 * The current amount of space in bytes already used.
+	 * http://code.google.com/apis/picasaweb/reference.html#gphoto_quotacurrent
+	 *
+	 * Since: 0.6.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_QUOTA_CURRENT,
+					 g_param_spec_int64 ("quota-current",
+							     "Quota Current", "The number of bytes used.",
+							     -1, G_MAXINT64, -1, 
+							     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+	
+	/**
+	 * GDataPicasaWebUser:max-photos-per-album:
+	 *
+	 * The maximum number of photos allowed per album.
+	 * http://code.google.com/apis/picasaweb/reference.html#gphoto_maxPhotosPerAlbum
+	 *
+	 * Since: 0.6.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_MAX_PHOTOS_PER_ALBUM,
+					 g_param_spec_int ("max-photos-per-album",
+							   "Max Photos Per Album", "The maximum number of files you can store in an album.",
+							   -1, G_MAXINT, -1,
+							   G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+	
+	/**
+	 * GDataPicasaWebUser:thumbnail:
+	 *
+	 * The URI for the thumbnail of the user.
+	 * http://code.google.com/apis/picasaweb/reference.html#gphoto_thumbnail
+	 *
+	 * Since: 0.6.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_THUMBNAIL,
+					 g_param_spec_string ("thumbnail",
+							      "Thumbnail", "The URI of the user's thumbnail.",
+							      NULL,
+							      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_picasaweb_user_init (GDataPicasaWebUser *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_PICASAWEB_USER, GDataPicasaWebUserPrivate);
+}
+
+static void
+gdata_picasaweb_user_finalize (GObject *object)
+{
+	GDataPicasaWebUserPrivate *priv = GDATA_PICASAWEB_USER_GET_PRIVATE (object);
+
+	xmlFree ((xmlChar*) priv->user);
+	xmlFree ((xmlChar*) priv->nickname);
+	xmlFree ((xmlChar*) priv->thumbnail);
+
+	/* Chain up to the parent class */
+	G_OBJECT_CLASS (gdata_picasaweb_user_parent_class)->finalize (object);
+}
+
+static void
+gdata_picasaweb_user_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	GDataPicasaWebUserPrivate *priv = GDATA_PICASAWEB_USER_GET_PRIVATE (object);
+
+	switch (property_id) {
+		case PROP_USER:
+			g_value_set_string (value, priv->user);
+			break;
+		case PROP_NICKNAME:
+			g_value_set_string (value, priv->nickname);
+			break;
+		case PROP_QUOTA_LIMIT:
+			g_value_set_int64 (value, priv->quota_limit);
+			break;
+		case PROP_QUOTA_CURRENT:
+			g_value_set_int64 (value, priv->quota_current);
+			break;
+		case PROP_MAX_PHOTOS_PER_ALBUM:
+			g_value_set_int (value, priv->max_photos_per_album);
+			break;
+		case PROP_THUMBNAIL:
+			g_value_set_string (value, priv->thumbnail);
+			break;
+		default:
+			/* We don't have any other property... */
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static gboolean
+parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
+{
+	GDataPicasaWebUser *self = GDATA_PICASAWEB_USER (parsable);
+
+	if (xmlStrcmp (node->name, (xmlChar*) "user") == 0) {
+		/* gphoto:user */
+		xmlChar *user = xmlNodeListGetString (doc, node->children, TRUE);
+		if (user == NULL || *user == '\0')
+			return gdata_parser_error_required_content_missing (node, error);
+		xmlFree (self->priv->user);
+		self->priv->user = (gchar*) user;
+	} else if (xmlStrcmp (node->name, (xmlChar*) "nickname") == 0) {
+		/* gphoto:nickname */
+		xmlChar *nickname = xmlNodeListGetString (doc, node->children, TRUE);
+		if (nickname == NULL || *nickname == '\0')
+			return gdata_parser_error_required_content_missing (node, error);
+		xmlFree (self->priv->nickname);
+		self->priv->nickname = (gchar*) nickname;
+	} else if (xmlStrcmp (node->name, (xmlChar*) "quotacurrent") == 0) {
+		/* gphoto:quota-current */
+		xmlChar *quota_current = xmlNodeListGetString (doc, node->children, TRUE);
+		self->priv->quota_current = g_ascii_strtoll ((const gchar*) quota_current, NULL, 10);
+		xmlFree (quota_current);
+	} else if (xmlStrcmp (node->name, (xmlChar*) "quotalimit") == 0) {
+		/* gphoto:quota-limit */
+		xmlChar *quota_limit = xmlNodeListGetString (doc, node->children, TRUE);
+		self->priv->quota_limit = g_ascii_strtoll ((const gchar*) quota_limit, NULL, 10);
+		xmlFree (quota_limit);
+	} else if (xmlStrcmp (node->name, (xmlChar*) "maxPhotosPerAlbum") == 0) {
+		/* gphoto:max-photos-per-album */
+		xmlChar *max_photos_per_album = xmlNodeListGetString (doc, node->children, TRUE);
+		self->priv->max_photos_per_album = strtol ((char*) max_photos_per_album, NULL, 10);
+		xmlFree (max_photos_per_album);
+	} else if (xmlStrcmp (node->name, (xmlChar*) "thumbnail") == 0) {
+		/* gphoto:thumbnail */
+		xmlChar *thumbnail = xmlNodeListGetString (doc, node->children, TRUE);
+		if (thumbnail == NULL || *thumbnail == '\0')
+			return gdata_parser_error_required_content_missing (node, error);
+		xmlFree (self->priv->thumbnail);
+		self->priv->thumbnail = (gchar*) thumbnail;
+	} else if (xmlStrcmp (node->name, (xmlChar*) "x-allowDownloads") == 0) { /* RHSTODO: see if this comes with the user */
+		/* gphoto:allowDownloads */
+		/* Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
+	} else if (xmlStrcmp (node->name, (xmlChar*) "x-allowPrints") == 0) { /* RHSTODO: see if this comes with the user */
+		/* gphoto:allowPrints */
+		/* Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
+	} else if (GDATA_PARSABLE_CLASS (gdata_picasaweb_user_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
+		/* Error! */
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
+{
+	/* Chain up to the parent class */
+	GDATA_PARSABLE_CLASS (gdata_picasaweb_user_parent_class)->get_namespaces (parsable, namespaces);
+
+	g_hash_table_insert (namespaces, (gchar*) "gphoto", (gchar*) "http://schemas.google.com/photos/2007");
+}
+
+
+
+/**
+ * gdata_picasaweb_user_get_user:
+ * @self: a #GDataPicasaWebUser
+ *
+ * Gets the #GDataPicasaWebUser:user property.
+ *
+ * Return value: the feed's user, or %NULL
+ *
+ * Since: 0.6.0
+ **/
+const gchar *
+gdata_picasaweb_user_get_user (GDataPicasaWebUser *self)
+{
+	g_return_val_if_fail (GDATA_IS_PICASAWEB_USER (self), NULL);
+	return self->priv->user;
+}
+
+/**
+ * gdata_picasaweb_user_get_nickname:
+ * @self: a #GDataPicasaWebUser
+ *
+ * Gets the #GDataPicasaWebUser:nickname property.
+ *
+ * Return value: the nickname of the feed's user's nickname, or %NULL
+ *
+ * Since: 0.6.0
+ **/
+const gchar *
+gdata_picasaweb_user_get_nickname (GDataPicasaWebUser *self)
+{
+	g_return_val_if_fail (GDATA_IS_PICASAWEB_USER (self), NULL);
+	return self->priv->nickname;
+}
+
+/**
+ * gdata_picasaweb_user_get_quota_limit:
+ * @self: a #GDataPicasaWebUser
+ *
+ * Gets the #GDataPicasaWebUser:quota-limit property.  Note that
+ * this information is not available when accessing feeds which we
+ * haven't authenticated, and 0 is returned.
+ *
+ * Return value: the maximum capacity in bytes for this feed's account or %-1
+ *
+ * Since: 0.6.0
+ **/
+gint64
+gdata_picasaweb_user_get_quota_limit (GDataPicasaWebUser *self)
+{
+	g_return_val_if_fail (GDATA_IS_PICASAWEB_USER (self), -1);
+	return self->priv->quota_limit;
+}
+
+/**
+ * gdata_picasaweb_user_get_quota_current:
+ * @self: a #GDataPicasaWebUser
+ *
+ * Gets the #GDataPicasaWebUser:quota-current property.  Note that
+ * this information is not available when accessing feeds which we
+ * haven't authenticated, and 0 is returned.
+ *
+ * Return value: the current number of bytes in used by this feed's account, or %-1
+ *
+ * Since: 0.6.0
+ **/
+gint64
+gdata_picasaweb_user_get_quota_current (GDataPicasaWebUser *self)
+{
+	g_return_val_if_fail (GDATA_IS_PICASAWEB_USER (self), -1);
+	return self->priv->quota_current;
+}
+
+/**
+ * gdata_picasaweb_user_get_max_photos_per_album:
+ * @self: a #GDataPicasaWebUser
+ *
+ * Gets the #GDataPicasaWebUser:max-photos-per-album property.  Note that
+ * this information is not available when accessing feeds which we
+ * haven't authenticated, and 0 is returned.
+ *
+ * Return value: the maximum number of photos an album for this account can hold, or %-1
+ *
+ * Since: 0.6.0
+ **/
+gint
+gdata_picasaweb_user_get_max_photos_per_album (GDataPicasaWebUser *self)
+{
+	g_return_val_if_fail (GDATA_IS_PICASAWEB_USER (self), -1);
+	return self->priv->max_photos_per_album;
+}
+
+/**
+ * gdata_picasaweb_user_get_thumbnail:
+ * @self: a #GDataPicasaWebUser
+ *
+ * Gets the #GDataPicasaWebUser:thumbnail property.
+ *
+ * Return value: the URI for the thumbnail of the account, or %NULL
+ *
+ * Since: 0.6.0
+ **/
+const gchar *
+gdata_picasaweb_user_get_thumbnail (GDataPicasaWebUser *self)
+{
+	g_return_val_if_fail (GDATA_IS_PICASAWEB_USER (self), NULL);
+	return self->priv->thumbnail;
+}
+
+/* TODO: in the future, see if we can change things like the user's nickname and thumbnail/avatar */
diff --git a/gdata/services/picasaweb/gdata-picasaweb-user.h b/gdata/services/picasaweb/gdata-picasaweb-user.h
new file mode 100644
index 0000000..185b25c
--- /dev/null
+++ b/gdata/services/picasaweb/gdata-picasaweb-user.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2009 <philip@tecnocode.co.uk>
+ * Copyright (C) Richard Schwarting 2009 <aquarichy@gmail.com>
+ *
+ * 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/>.
+ */
+
+#ifndef GDATA_PICASAWEB_USER_H
+#define GDATA_PICASAWEB_USER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-parsable.h>
+#include <gdata/gdata-feed.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_PICASAWEB_USER		(gdata_picasaweb_user_get_type ())
+#define GDATA_PICASAWEB_USER(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_PICASAWEB_USER, GDataPicasaWebUser))
+#define GDATA_PICASAWEB_USER_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_PICASAWEB_USER, GDataPicasaWebUserClass))
+#define GDATA_IS_PICASAWEB_USER(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_PICASAWEB_USER))
+#define GDATA_IS_PICASAWEB_USER_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_PICASAWEB_USER))
+#define GDATA_PICASAWEB_USER_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_PICASAWEB_USER, GDataPicasaWebUserClass))
+
+typedef struct _GDataPicasaWebUserPrivate	GDataPicasaWebUserPrivate;
+
+/**
+ * GDataPicasaWebUser:
+ *
+ * All the fields in the #GDataPicasaWebUser structure are private and should never be accessed directly.
+ *
+ * Since: 0.6.0
+ **/
+typedef struct {
+	GDataFeed parent;
+	GDataPicasaWebUserPrivate *priv;
+} GDataPicasaWebUser;
+
+/**
+ * GDataPicasaWebUserClass:
+ *
+ * All the fields in the #GDataPicasaWebUserClass structure are private and should never be accessed directly.
+ *
+ * Since: 0.6.0
+ **/
+typedef struct {
+	/*< private >*/
+	GDataFeedClass parent;
+} GDataPicasaWebUserClass;
+
+GType gdata_picasaweb_user_get_type (void);
+
+const gchar * gdata_picasaweb_user_get_user (GDataPicasaWebUser *self);
+const gchar * gdata_picasaweb_user_get_nickname (GDataPicasaWebUser *self);
+gint64 gdata_picasaweb_user_get_quota_limit (GDataPicasaWebUser *self);
+gint64 gdata_picasaweb_user_get_quota_current (GDataPicasaWebUser *self);
+gint gdata_picasaweb_user_get_max_photos_per_album (GDataPicasaWebUser *self);
+const gchar * gdata_picasaweb_user_get_thumbnail (GDataPicasaWebUser *self);
+
+G_END_DECLS
+
+#endif /* !GDATA_PICASAWEB_USER_H */
diff --git a/gdata/tests/picasaweb.c b/gdata/tests/picasaweb.c
index 99980d0..f9db904 100644
--- a/gdata/tests/picasaweb.c
+++ b/gdata/tests/picasaweb.c
@@ -590,6 +590,29 @@ test_query_all_albums (GDataService *service)
 }
 
 static void
+test_query_user (GDataService *service)
+{
+	GDataPicasaWebUser *user;
+	GError *error;
+
+	error = NULL;
+
+	user = gdata_picasaweb_service_get_user (GDATA_PICASAWEB_SERVICE (service), NULL, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_PICASAWEB_USER (user));
+	g_clear_error (&error);
+
+	g_assert_cmpstr (gdata_picasaweb_user_get_user (user), ==, "libgdata.picasaweb");
+	g_assert_cmpstr (gdata_picasaweb_user_get_nickname (user), ==, "libgdata.picasaweb");
+	g_assert_cmpint (gdata_picasaweb_user_get_quota_limit (user), ==, 1073741824); /* it'll be a beautiful day when this assert gets tripped */
+	g_assert_cmpint (gdata_picasaweb_user_get_quota_current (user), >, 0);
+	g_assert_cmpint (gdata_picasaweb_user_get_max_photos_per_album (user), ==, 500);
+	g_assert_cmpstr (gdata_picasaweb_user_get_thumbnail (user), ==, "http://lh6.ggpht.com/_1kdcGyvOb8c/AAAA9mDag3s/AAAAAAAAAAA/Jq-NWYWKFao/s64-c/libgdata.picasaweb.jpg");
+
+	g_object_unref (user);
+}
+
+static void
 test_query_new_with_limits (GDataService *service)
 {
 	GDataQuery *query;
@@ -695,6 +718,7 @@ main (int argc, char *argv[])
 		g_test_add_func ("/picasaweb/authentication_async", test_authentication_async);
 	g_test_add_data_func ("/picasaweb/upload/photo", service, test_upload_simple);
 	g_test_add_data_func ("/picasaweb/query/all_albums", service, test_query_all_albums);
+	g_test_add_data_func ("/picasaweb/query/user", service, test_query_user);
 	if (g_test_thorough () == TRUE)
 		g_test_add_data_func ("/picasaweb/query/all_albums_async", service, test_query_all_albums_async);
 	g_test_add_data_func ("/picasaweb/query/new_with_limits", service, test_query_new_with_limits);
