mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
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>
This commit is contained in:
parent
d0d4bbece7
commit
a5ee2b66e1
3 changed files with 212 additions and 0 deletions
|
@ -21,6 +21,7 @@
|
|||
#include "callbacks-gtk.h"
|
||||
#include "uemis.h"
|
||||
#include "device.h"
|
||||
#include "webservice.h"
|
||||
|
||||
#include "libdivecomputer.h"
|
||||
|
||||
|
@ -1058,6 +1059,7 @@ static GtkActionEntry menu_items[] = {
|
|||
{ "Print", GTK_STOCK_PRINT, N_("Print..."), CTRLCHAR "P", NULL, G_CALLBACK(do_print) },
|
||||
{ "ImportFile", GTK_STOCK_GO_BACK, N_("Import XML File(s)..."), CTRLCHAR "I", NULL, G_CALLBACK(import_files) },
|
||||
{ "DownloadLog", GTK_STOCK_GO_DOWN, N_("Download From Dive Computer..."), CTRLCHAR "D", NULL, G_CALLBACK(download_dialog) },
|
||||
{ "DownloadWeb", GTK_STOCK_CONNECT, N_("Download From Web Service..."), NULL, NULL, G_CALLBACK(webservice_download_dialog) },
|
||||
{ "AddDive", GTK_STOCK_ADD, N_("Add Dive..."), NULL, NULL, G_CALLBACK(add_dive_cb) },
|
||||
{ "Preferences", GTK_STOCK_PREFERENCES, N_("Preferences..."), PREFERENCE_ACCEL, NULL, G_CALLBACK(preferences_dialog) },
|
||||
{ "Renumber", NULL, N_("Renumber..."), NULL, NULL, G_CALLBACK(renumber_dialog) },
|
||||
|
@ -1104,6 +1106,7 @@ static const gchar* ui_string = " \
|
|||
</menu> \
|
||||
<menu name=\"LogMenu\" action=\"LogMenuAction\"> \
|
||||
<menuitem name=\"Download From Dive Computer\" action=\"DownloadLog\" /> \
|
||||
<menuitem name=\"Download From Web Service\" action=\"DownloadWeb\" /> \
|
||||
<separator name=\"Separator1\"/> \
|
||||
<menuitem name=\"Add Dive\" action=\"AddDive\" /> \
|
||||
<separator name=\"Separator2\"/> \
|
||||
|
|
207
webservice.c
Normal file
207
webservice.c
Normal file
|
@ -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);
|
||||
}
|
2
webservice.h
Normal file
2
webservice.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
extern void webservice_download_dialog(void);
|
||||
extern gboolean webservice_request_user_xml(const gchar *, gchar **, guint *, guint *);
|
Loading…
Reference in a new issue