Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-xmlrpc.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2004 Hiroyuki Ikezoe
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <string.h>
#include <glib/gi18n.h>

#include "kz-xmlrpc.h"
#include "gobject-utils.h"
#include "kz-http.h"
#include "kz-xml.h"

enum {
      XMLRPC_COMPLETED_SIGNAL,
      XMLRPC_LAST_SIGNAL
};

enum {
      PROP_0,
      PROP_XMLRPC_URI
};

#define KZ_XML_RPC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KZ_TYPE_XML_RPC, KzXMLRPCPrivate))

static void kz_xml_rpc_class_init      (KzXMLRPCClass *klass);
static void kz_xml_rpc_init            (KzXMLRPC *xmlrpc);
static void kz_xml_rpc_set_property    (GObject *object,
                                guint prop_id,
                                const GValue *value,
                                GParamSpec *pspec);
static void kz_xml_rpc_get_property    (GObject *object,
                                guint prop_id,
                                GValue *value,
                                GParamSpec *pspec);
static void kz_xml_rpc_dispose         (GObject *object);
static void kz_xml_rpc_finalize        (GObject *object);

struct _KzXMLRPCPrivate 
{
      gchar *xmlrpc_uri;

      GList *results;
};


static GObjectClass *parent_class = NULL;
static gint kz_xml_rpc_signals[XMLRPC_LAST_SIGNAL] = {0};

KZ_OBJECT_GET_TYPE(kz_xml_rpc, "KzXMLRPC", KzXMLRPC,
               kz_xml_rpc_class_init, kz_xml_rpc_init,
               G_TYPE_OBJECT)

static void
kz_xml_rpc_class_init (KzXMLRPCClass *klass)
{
      GObjectClass *object_class;

      parent_class = g_type_class_peek_parent (klass);
      object_class = (GObjectClass *) klass;

      object_class->dispose      = kz_xml_rpc_dispose;
      object_class->finalize     = kz_xml_rpc_finalize;
      object_class->set_property = kz_xml_rpc_set_property;
      object_class->get_property = kz_xml_rpc_get_property;
      
      klass->xml_rpc_completed   = NULL;

      g_object_class_install_property(
            object_class,
             PROP_XMLRPC_URI,
             g_param_spec_string(
                   "xmlrpc-uri",
                   _("URI"),
                   _("The URI of XML-RPC interface"),
                   NULL,
                   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));

      kz_xml_rpc_signals[XMLRPC_COMPLETED_SIGNAL]
            = g_signal_new ("xml_rpc_completed",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (KzXMLRPCClass, xml_rpc_completed),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__POINTER,
                        G_TYPE_NONE, 1,
                        G_TYPE_POINTER);
}


static void
kz_xml_rpc_init (KzXMLRPC *xmlrpc)
{
      xmlrpc->priv = g_new0(KzXMLRPCPrivate, 1);

      xmlrpc->priv->xmlrpc_uri = NULL;
      xmlrpc->priv->results    = NULL;
}


void
kz_xml_rpc_dispose (GObject *object)
{
      KzXMLRPC *xmlrpc;

      xmlrpc = KZ_XML_RPC(object);

      if (xmlrpc->priv->xmlrpc_uri)
            g_free(xmlrpc->priv->xmlrpc_uri);
      if (xmlrpc->priv->results)
      {
            GList *node, *list;
            list = xmlrpc->priv->results;
            for (node = list; node; node = g_list_next(node))
            {
                  if (!node->data) continue;
      
                  g_free(node->data);
            }
            g_list_free(list);
            xmlrpc->priv->results = NULL;
      }

      xmlrpc->priv->xmlrpc_uri = NULL;
      
      if (G_OBJECT_CLASS (parent_class)->dispose)
            G_OBJECT_CLASS (parent_class)->dispose(object);
}


KZ_OBJECT_FINALIZE(kz_xml_rpc, KzXMLRPC)

static void
kz_xml_rpc_set_property (GObject *object,
                     guint prop_id,
                     const GValue *value,
                     GParamSpec *pspec)
{
      KzXMLRPC *xmlrpc = KZ_XML_RPC(object);

      switch (prop_id)
      {
      case PROP_XMLRPC_URI:
            xmlrpc->priv->xmlrpc_uri = g_value_dup_string(value);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
            break;
      }
}


static void
kz_xml_rpc_get_property (GObject *object,
                     guint prop_id,
                     GValue *value,
                     GParamSpec *pspec)
{
      KzXMLRPC *xmlrpc = KZ_XML_RPC(object);

      switch (prop_id)
      {
      case PROP_XMLRPC_URI:
            g_value_set_string(value, xmlrpc->priv->xmlrpc_uri);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
            break;
      }
}


KzXMLRPC *
kz_xml_rpc_new (const gchar *uri)
{
      KzXMLRPC *xmlrpc = NULL;

      xmlrpc = g_object_new(KZ_TYPE_XML_RPC, 
                        "xmlrpc-uri", uri,
                        NULL);
      
      return xmlrpc;
}


static KzXMLNode *
kz_xml_node_get_first_child_element (KzXMLNode *parent)
{
      KzXMLNode *node;

      for (node = kz_xml_node_first_child(parent);
           node;
           node = kz_xml_node_next(node))
      {
            if (kz_xml_node_is_element(node)) break;
      }
      
      return node;
}

static gboolean
parse_response (KzXMLRPC *xmlrpc, KzXMLNode *root)
{
      KzXMLNode *node;

      if (!kz_xml_node_name_is(root, "methodResponse"))
            return FALSE;


      node = kz_xml_node_get_first_child_element(root);
      if (!node || !kz_xml_node_name_is(node, "params"))
            return FALSE;

      for (node = kz_xml_node_first_child(node);
           node;
           node = kz_xml_node_next(node))
      {
            KzXMLNode *value_node, *child_node;

            if (!kz_xml_node_is_element(node)) continue;
            if (!kz_xml_node_name_is(node, "param")) continue;

            value_node = kz_xml_node_get_first_child_element(node);
            if (!value_node || !kz_xml_node_name_is(value_node, "value")) continue;

            child_node = kz_xml_node_get_first_child_element(value_node);
            if (!child_node) continue;

            if (kz_xml_node_name_is(child_node, "struct"))
            {
            }
            else if (kz_xml_node_name_is(child_node, "array"))
            {
            }
            else if (kz_xml_node_name_is(child_node, "string"))
            {
                  gchar *text = kz_xml_node_to_str(child_node);
                  xmlrpc->priv->results = 
                        g_list_append(xmlrpc->priv->results, text);
            }
            else if (kz_xml_node_name_is(child_node, "int") ||
                   kz_xml_node_name_is(child_node, "i4"))
            {
            }
            else if (kz_xml_node_name_is(child_node, "boolean"))
            {
            }
            else if (kz_xml_node_name_is(child_node, "double"))
            {
            }
            else if (kz_xml_node_name_is(child_node, "base64"))
            {
            }
            else if (kz_xml_node_name_is(child_node, "dataTime.iso8601"))
            {
            }
      }

      return TRUE;
}


static gboolean
idle_load_complete(gpointer data)
{
      KzHTTP *http = data;

      g_object_unref(G_OBJECT(http));

      return FALSE;
}


static void
cb_http_load_complete(KzIO *io, GError *error, KzXMLRPC *xmlrpc)
{
      KzXML *xml = NULL;
      KzXMLNode *node;
      const gchar *buf;
      guint size;
      gboolean ret;

      g_return_if_fail(KZ_IS_XML_RPC(xmlrpc));
      g_return_if_fail(KZ_IS_IO(io));

      g_signal_handlers_disconnect_by_func
            (io,
             G_CALLBACK(cb_http_load_complete),
             xmlrpc);

      if (error) goto ERROR;

      buf  = kz_io_get_buffer(io);
      size = kz_io_get_loaded_size(io);

      if (!buf || size == 0) goto ERROR;

      xml = kz_xml_new();
      if (!kz_xml_load_xml(xml, buf, size))
            goto ERROR;

      /* parse response xml */ 
      node = kz_xml_get_root_element (xml);
      if (!node) goto ERROR;

      ret = parse_response(xmlrpc, node);
ERROR:
      if (xml) g_object_unref(xml);

      g_signal_emit(xmlrpc,
                  kz_xml_rpc_signals[XMLRPC_COMPLETED_SIGNAL],
                  0, NULL);

      g_idle_add(idle_load_complete, io);
}


static void
create_params_node (KzXMLNode   *params_node,
                const gchar *param,
                va_list  var_args)
{
      const gchar *name;
  
      name = param;
  
      while (name)
      {
            KzXMLNode *param_node, *value_node,
                    *string_node, *text_node;
            param_node = kz_xml_element_node_new("param");
            kz_xml_node_append_child(params_node, param_node);
            value_node = kz_xml_element_node_new("value");
            kz_xml_node_append_child(param_node, value_node);
            string_node = kz_xml_element_node_new("string");
            kz_xml_node_append_child(value_node, string_node);

            text_node = kz_xml_text_node_new(name);
            kz_xml_node_append_child(string_node, text_node);

            name = va_arg (var_args, gchar*);
      }
}


void
kz_xml_rpc_call (KzXMLRPC *xmlrpc, 
             const gchar *method_name,
             const gchar *param,
             ...)
{ 
      KzHTTP *http;
      KzXML *xml;
      KzXMLNode *root, *method_node, *method_name_node, *params_node, *text_node;
      va_list var_args;
      gchar *str;

      xml = kz_xml_new();
      root = xml->root;
      
      method_node = kz_xml_element_node_new("methodCall");
      kz_xml_node_append_child(root, method_node);

      method_name_node = kz_xml_element_node_new("methodName");
      kz_xml_node_append_child(method_node, method_name_node);

      text_node = kz_xml_text_node_new(method_name);
      kz_xml_node_append_child(method_name_node, text_node);

      params_node = kz_xml_element_node_new("params");
      kz_xml_node_append_child(method_node, params_node);
      
      /*
       * <params>
       *   <param>
       *     <value><string>title</string></value>
       *   </param>
       *   <param>
       *     <value><string>Kazehakse</string></value>
       *   </param>
       *   <param>
       *     <value><string>link</string></value>
       *   </param>
       *   <param>
       *     <value><string>http://kazehakase.sourceforge.jp/</string></value>
       *   </param>
       *   ....
       * </params>
       */
      va_start(var_args, param);
      create_params_node(params_node, param, var_args);
      va_end(var_args);

      str = kz_xml_node_to_xml(root);

      http = kz_http_post_new(xmlrpc->priv->xmlrpc_uri, str);
      g_free(str);
      g_object_unref(xml);

      g_signal_connect(http, "io_completed",
                   G_CALLBACK(cb_http_load_complete),
                   xmlrpc);
      
      kz_io_load_to_buffer(KZ_IO(http));
}

const GList *
kz_xml_rpc_get_results (KzXMLRPC *xmlrpc)
{
      return xmlrpc->priv->results;
}


Generated by  Doxygen 1.6.0   Back to index