+/* Functions for a SAX parser to parse the XML failure from Amazon */
+
+/* Private structure for our "thunk", which tracks where the user is in the list
+ * * of keys. */
+struct failure_thunk {
+ gboolean want_text;
+
+ gboolean in_title;
+ gboolean in_body;
+ gboolean in_code;
+ gboolean in_message;
+ gboolean in_details;
+ gboolean in_access;
+ gboolean in_token;
+ gboolean in_serviceCatalog;
+ gboolean in_service;
+ gboolean in_endpoint;
+ gint in_others;
+
+ gchar *text;
+ gsize text_len;
+
+ gchar *message;
+ gchar *details;
+ gchar *error_name;
+ gchar *token_id;
+ gchar *service_type;
+ gchar *service_public_url;
+ gint64 expires;
+};
+
+static void
+failure_start_element(GMarkupParseContext *context G_GNUC_UNUSED,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error G_GNUC_UNUSED)
+{
+ struct failure_thunk *thunk = (struct failure_thunk *)user_data;
+ const gchar **att_name, **att_value;
+
+ if (g_ascii_strcasecmp(element_name, "title") == 0) {
+ thunk->in_title = 1;
+ thunk->in_others = 0;
+ thunk->want_text = 1;
+ } else if (g_ascii_strcasecmp(element_name, "body") == 0) {
+ thunk->in_body = 1;
+ thunk->in_others = 0;
+ thunk->want_text = 1;
+ } else if (g_ascii_strcasecmp(element_name, "code") == 0) {
+ thunk->in_code = 1;
+ thunk->in_others = 0;
+ thunk->want_text = 1;
+ } else if (g_ascii_strcasecmp(element_name, "message") == 0) {
+ thunk->in_message = 1;
+ thunk->in_others = 0;
+ thunk->want_text = 1;
+ } else if (g_ascii_strcasecmp(element_name, "details") == 0) {
+ thunk->in_details = 1;
+ thunk->in_others = 0;
+ thunk->want_text = 1;
+ } else if (g_ascii_strcasecmp(element_name, "access") == 0) {
+ thunk->in_access = 1;
+ thunk->in_others = 0;
+ } else if (g_ascii_strcasecmp(element_name, "token") == 0) {
+ thunk->in_token = 1;
+ thunk->in_others = 0;
+ for (att_name=attribute_names, att_value=attribute_values;
+ *att_name != NULL;
+ att_name++, att_value++) {
+ if (g_str_equal(*att_name, "id")) {
+ thunk->token_id = g_strdup(*att_value);
+ }
+ if (g_str_equal(*att_name, "expires") && strlen(*att_value) >= 19) {
+ thunk->expires = rfc3339_date(*att_value) - 600;
+ }
+ }
+ } else if (g_ascii_strcasecmp(element_name, "serviceCatalog") == 0) {
+ thunk->in_serviceCatalog = 1;
+ thunk->in_others = 0;
+ } else if (g_ascii_strcasecmp(element_name, "service") == 0) {
+ thunk->in_service = 1;
+ thunk->in_others = 0;
+ for (att_name=attribute_names, att_value=attribute_values;
+ *att_name != NULL;
+ att_name++, att_value++) {
+ if (g_str_equal(*att_name, "type")) {
+ thunk->service_type = g_strdup(*att_value);
+ }
+ }
+ } else if (g_ascii_strcasecmp(element_name, "endpoint") == 0) {
+ thunk->in_endpoint = 1;
+ thunk->in_others = 0;
+ if (thunk->service_type &&
+ g_str_equal(thunk->service_type, "object-store")) {
+ for (att_name=attribute_names, att_value=attribute_values;
+ *att_name != NULL;
+ att_name++, att_value++) {
+ if (g_str_equal(*att_name, "publicURL")) {
+ thunk->service_public_url = g_strdup(*att_value);
+ }
+ }
+ }
+ } else if (g_ascii_strcasecmp(element_name, "error") == 0) {
+ for (att_name=attribute_names, att_value=attribute_values;
+ *att_name != NULL;
+ att_name++, att_value++) {
+ if (g_str_equal(*att_name, "message")) {
+ thunk->message = g_strdup(*att_value);
+ }
+ }
+ } else {
+ thunk->in_others++;
+ }
+}
+
+static void
+failure_end_element(GMarkupParseContext *context G_GNUC_UNUSED,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error G_GNUC_UNUSED)
+{
+ struct failure_thunk *thunk = (struct failure_thunk *)user_data;
+
+ if (g_ascii_strcasecmp(element_name, "title") == 0) {
+ char *p = strchr(thunk->text, ' ');
+ if (p) {
+ p++;
+ if (*p) {
+ thunk->error_name = g_strdup(p);
+ }
+ }
+ g_free(thunk->text);
+ thunk->text = NULL;
+ thunk->in_title = 0;
+ } else if (g_ascii_strcasecmp(element_name, "body") == 0) {
+ thunk->message = thunk->text;
+ g_strstrip(thunk->message);
+ thunk->text = NULL;
+ thunk->in_body = 0;
+ } else if (g_ascii_strcasecmp(element_name, "code") == 0) {
+ thunk->error_name = thunk->text;
+ thunk->text = NULL;
+ thunk->in_code = 0;
+ } else if (g_ascii_strcasecmp(element_name, "message") == 0) {
+ thunk->message = thunk->text;
+ thunk->text = NULL;
+ thunk->in_message = 0;
+ } else if (g_ascii_strcasecmp(element_name, "details") == 0) {
+ thunk->details = thunk->text;
+ thunk->text = NULL;
+ thunk->in_details = 0;
+ } else if (g_ascii_strcasecmp(element_name, "access") == 0) {
+ thunk->message = thunk->text;
+ thunk->text = NULL;
+ thunk->in_access = 0;
+ } else if (g_ascii_strcasecmp(element_name, "token") == 0) {
+ thunk->message = thunk->text;
+ thunk->text = NULL;
+ thunk->in_token = 0;
+ } else if (g_ascii_strcasecmp(element_name, "serviceCatalog") == 0) {
+ thunk->message = thunk->text;
+ thunk->text = NULL;
+ thunk->in_serviceCatalog = 0;
+ } else if (g_ascii_strcasecmp(element_name, "service") == 0) {
+ thunk->message = thunk->text;
+ thunk->text = NULL;
+ g_free(thunk->service_type);
+ thunk->service_type = NULL;
+ thunk->in_service = 0;
+ } else if (g_ascii_strcasecmp(element_name, "endpoint") == 0) {
+ thunk->message = thunk->text;
+ thunk->text = NULL;
+ thunk->in_endpoint = 0;
+ } else {
+ thunk->in_others--;
+ }
+}
+
+static void
+failure_text(GMarkupParseContext *context G_GNUC_UNUSED,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error G_GNUC_UNUSED)
+{
+ struct failure_thunk *thunk = (struct failure_thunk *)user_data;
+
+ if (thunk->want_text && thunk->in_others == 0) {
+ char *new_text;
+
+ new_text = g_strndup(text, text_len);
+ if (thunk->text) {
+ strappend(thunk->text, new_text);
+ g_free(new_text);
+ } else {
+ thunk->text = new_text;
+ }
+ }
+}
+