summaryrefslogtreecommitdiffstats
path: root/webservice.c
diff options
context:
space:
mode:
authorGravatar Lubomir I. Ivanov <neolit123@gmail.com>2013-01-18 03:05:48 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2013-01-17 22:29:24 -0800
commita5ee2b66e1cc9b1b7b0b7437517a30bee5b0054f (patch)
tree662228fd671ab5ffb4c83fe59af426088c5bdd09 /webservice.c
parentd0d4bbece7e0a304a3e1f1fcea3608f3d741e8fa (diff)
downloadsubsurface-a5ee2b66e1cc9b1b7b0b7437517a30bee5b0054f.tar.gz
Added client side communication to the Subsurface Web Service
A couple of new files webservice.c and webservice.h are added. webservice.h exposes two methods at the moment: - webservice_download_dialog(): this function creates the user interface for the download dialog from the web service. - webservice_request_user_xml() this function is a direct call to retrieve XML for a specific user identifier. the actual data, data length and error codes are stored in passed pointers. A menu entry is added in the Log menu: "Download From Web Service" The used backend for communication at the moment is provided by libsoup. Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'webservice.c')
-rw-r--r--webservice.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/webservice.c b/webservice.c
new file mode 100644
index 000000000..01bf76263
--- /dev/null
+++ b/webservice.c
@@ -0,0 +1,207 @@
+#include <libintl.h>
+#include <glib/gi18n.h>
+#include <libsoup/soup.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include "dive.h"
+#include "display-gtk.h"
+
+enum {
+ DD_STATUS_OK,
+ DD_STATUS_ERROR_CONNECT,
+ DD_STATUS_ERROR_ID,
+ DD_STATUS_ERROR_PARSE,
+};
+
+static const gchar *download_dialog_status_text(const gint status)
+{
+ switch (status) {
+ case DD_STATUS_ERROR_CONNECT:
+ return _("Connection Error: ");
+ break;
+ case DD_STATUS_ERROR_ID:
+ _("Invalid user identifier!");
+ break;
+ case DD_STATUS_ERROR_PARSE:
+ _("Cannot parse response!");
+ }
+ return _("Download Success!");
+}
+
+/* provides a state of the download dialog contents and the download xml */
+struct download_dialog_state {
+ GtkWidget *uid;
+ GtkWidget *status;
+ GtkWidget *apply;
+ gchar *xmldata;
+};
+
+/* this method uses libsoup as a backend. if there are some portability,
+ * compatibility or speed issues, libcurl is a better choice. */
+gboolean webservice_request_user_xml(const gchar *user_id,
+ gchar **data,
+ guint *len,
+ guint *status_code)
+{
+ SoupMessage *msg;
+ SoupSession *session;
+ gboolean ret = FALSE;
+ gchar url[80] = {0};
+
+ session = soup_session_async_new();
+ strcat(url, "http://api.hohndel.org/api/mydives/");
+ strcat(url, user_id);
+ strcat(url, "/xml");
+ msg = soup_message_new("GET", url);
+ soup_session_send_message(session, msg);
+ if SOUP_STATUS_IS_SUCCESSFUL(msg->status_code) {
+ *len = (guint)msg->response_body->length;
+ *data = strdup((gchar *)msg->response_body->data);
+ ret = TRUE;
+ } else {
+ *len = 0;
+ *data = NULL;
+ }
+ *status_code = msg->status_code;
+ soup_session_abort(session);
+ g_object_unref(G_OBJECT(msg));
+ g_object_unref(G_OBJECT(session));
+ return ret;
+}
+
+static void download_dialog_traverse_xml(xmlNodePtr node, gboolean *download_status)
+{
+ xmlNodePtr cur_node;
+
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (!strcmp(cur_node->name, (const gchar *)"download")) {
+ if (!strcmp(xmlNodeGetContent(cur_node), (const gchar *)"ok")) {
+ *download_status = DD_STATUS_OK;
+ return;
+ }
+ } else if (!strcmp(cur_node->name, (const gchar *)"error")) {
+ *download_status = DD_STATUS_ERROR_ID;
+ } else {
+ download_dialog_traverse_xml(cur_node->children, download_status);
+ }
+ }
+}
+
+static guint download_dialog_parse_response(gchar *xmldata, guint len)
+{
+ xmlNodePtr root;
+ xmlDocPtr doc = xmlParseMemory(xmldata, len);
+ guint status = DD_STATUS_ERROR_PARSE;
+
+ if (!doc)
+ return DD_STATUS_ERROR_PARSE;
+ root = xmlDocGetRootElement(doc);
+ if (!root) {
+ status = DD_STATUS_ERROR_PARSE;
+ goto end;
+ }
+ download_dialog_traverse_xml(root, &status);
+ end:
+ xmlFreeDoc(doc);
+ return status;
+}
+
+static void download_dialog_connect_cb(GtkWidget *w, gpointer data)
+{
+ struct download_dialog_state *state = (struct download_dialog_state *)data;
+ const gchar *uid = gtk_entry_get_text(GTK_ENTRY(state->uid));
+ guint len, status_connect, status_xml;
+ gchar *xmldata;
+ gboolean ret;
+ gchar err[128] = {0};
+
+ gtk_label_set_text(GTK_LABEL(state->status), _("Connecting..."));
+ gtk_widget_set_sensitive(state->apply, FALSE);
+ ret = webservice_request_user_xml(uid, &xmldata, &len, &status_connect);
+ if (ret) {
+ status_xml = download_dialog_parse_response(xmldata, len);
+ gtk_label_set_text(GTK_LABEL(state->status), download_dialog_status_text(status_xml));
+ if (status_xml != DD_STATUS_OK)
+ ret = FALSE;
+ } else {
+ sprintf(err, "%s %u!", download_dialog_status_text(DD_STATUS_ERROR_CONNECT), status_connect);
+ gtk_label_set_text(GTK_LABEL(state->status), err);
+ }
+ state->xmldata = xmldata;
+ gtk_widget_set_sensitive(state->apply, ret);
+}
+
+static void download_dialog_release_xml(struct download_dialog_state *state)
+{
+ if (state->xmldata)
+ free((void *)state->xmldata);
+}
+
+static void download_dialog_delete(GtkWidget *w, gpointer data)
+{
+ struct download_dialog_state *state = (struct download_dialog_state *)data;
+ download_dialog_release_xml(state);
+}
+
+void webservice_download_dialog(void)
+{
+ const guint pad = 6;
+ /* user entered value should be stored in the config */
+ const gchar *current_uid = "41TFEC8ZMVD5DBE0JPBBU5JDDA2Y6T";
+ GtkWidget *dialog, *vbox, *status, *info, *uid;
+ GtkWidget *frame_uid, *frame_status, *download, *image, *apply;
+ struct download_dialog_state state = {NULL};
+ int result;
+
+ dialog = gtk_dialog_new_with_buttons(_("Download From Web Service"),
+ GTK_WINDOW(main_window),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_APPLY,
+ GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT,
+ NULL);
+
+ apply = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
+ gtk_widget_set_sensitive(apply, FALSE);
+
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ info = gtk_label_new(_("Enter a user identifier and press 'Download'."
+ " Once the download is complete you can press 'Apply'"
+ " if you wish to apply the changes."));
+ gtk_label_set_line_wrap(GTK_LABEL(info), TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), info, FALSE, TRUE, 0);
+ gtk_misc_set_padding(GTK_MISC(info), pad, pad);
+
+ frame_uid = gtk_frame_new(_("User Identifier"));
+ gtk_box_pack_start(GTK_BOX(vbox), frame_uid, FALSE, TRUE, pad);
+ uid = gtk_entry_new();
+ gtk_container_add(GTK_CONTAINER(frame_uid), uid);
+ gtk_entry_set_text(GTK_ENTRY(uid), current_uid);
+
+ download = gtk_button_new_with_label(_(" Download"));
+ image = gtk_image_new_from_stock(GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU);
+ gtk_button_set_image(GTK_BUTTON(download), image);
+ gtk_box_pack_start(GTK_BOX(vbox), download, FALSE, TRUE, pad);
+ g_signal_connect(download, "clicked", G_CALLBACK(download_dialog_connect_cb), &state);
+
+ frame_status = gtk_frame_new(_("Status"));
+ status = gtk_label_new(_("Idle"));
+ gtk_box_pack_start(GTK_BOX(vbox), frame_status, FALSE, TRUE, pad);
+ gtk_container_add(GTK_CONTAINER(frame_status), status);
+ gtk_misc_set_padding(GTK_MISC(status), pad, pad);
+
+ state.uid = uid;
+ state.status = status;
+ state.apply = apply;
+
+ gtk_widget_show_all(dialog);
+ g_signal_connect(dialog, "delete-event", G_CALLBACK(download_dialog_delete), &state);
+ result = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (result == GTK_RESPONSE_ACCEPT) {
+ /* apply download */
+ g_message("\napply download should happen here: \n\n %s", state.xmldata);
+ }
+ download_dialog_release_xml(&state);
+ gtk_widget_destroy(dialog);
+}