diff -r 000000000000 -r f9d778bb88a2 branches/gmyth-0.1b/src/gmyth_http.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/branches/gmyth-0.1b/src/gmyth_http.c Wed Feb 07 20:38:39 2007 +0000
@@ -0,0 +1,343 @@
+/**
+ * GMyth Library
+ *
+ * @file gmyth/gmyth_http.c
+ *
+ * @brief
GMythHttp class provides a wrapper to access
+ * data from the database using http+xml
+ *
+ * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
+ * @author Artur Duque de Souza <@indt.org.br>
+ *
+ */
+/*
+ *
+ * This program 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 of the License, 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 Lesser 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+
+#include "gmyth_http.h"
+#include "gmyth_debug.h"
+#include "gmyth_socket.h"
+
+
+xmlXPathObjectPtr
+getnodeset(xmlDocPtr doc, xmlChar *xpath)
+{
+
+ xmlXPathContextPtr context;
+ xmlXPathObjectPtr result;
+
+ context = xmlXPathNewContext(doc);
+ result = xmlXPathEvalExpression(xpath, context);
+
+ if(xmlXPathNodeSetIsEmpty(result->nodesetval))
+ {
+ g_fprintf(stderr, "Error: No result at XPath\n");
+ return NULL;
+ }
+
+ xmlXPathFreeContext(context);
+ return result;
+}
+
+
+xmlDocPtr XMLParse (const char *content, int length)
+{
+ xmlDocPtr doc; /* the resulting document tree */
+
+ doc = xmlReadMemory(content, length, NULL, NULL, 0);
+ if (doc == NULL)
+ {
+ g_fprintf(stderr, "Error: Failed to parse XML document\n");
+ return NULL;
+ }
+
+ return doc;
+}
+
+xmlXPathObjectPtr getXPath (xmlChar *xpath, xmlDocPtr doc)
+{
+ xmlXPathObjectPtr result;
+ result = getnodeset(doc, xpath);
+ return result;
+}
+
+/** Retrieves the Progam List from the Channel
+ *
+ * @param nodeTab A pointer to a node inside the XML
+ * @return A GSList containing a list of all the programs
+ */
+GSList* get_Program_List(xmlNodePtr node)
+{
+ GSList* program_list = NULL;
+
+ while (node != NULL)
+ {
+ if (g_ascii_strcasecmp((char *)node->name, "text") != 0)
+ {
+ GMythProgram* program = (GMythProgram*)g_malloc(sizeof(struct _GMythProgram));
+
+ program->title = g_string_new((char *)xmlGetProp(node, (xmlChar *)"title"));
+ program->subtitle = g_string_new((char *)xmlGetProp(node, (xmlChar *)"subtitle"));
+ program->catType = g_string_new((char *)xmlGetProp(node, (xmlChar *)"catType"));
+ program->category = g_string_new((char *)xmlGetProp(node, (xmlChar *)"category"));
+
+ sscanf ((char *)xmlGetProp(node, (xmlChar *)"repeat"), "%d", &(program->repeat));
+
+ program->startTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(node, \
+ (xmlChar *)"startTime"));
+ program->endTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(node, \
+ (xmlChar *)"endTime"));
+
+ program_list = g_slist_append(program_list, program);
+ }
+
+ node = node->next;
+ }
+
+ return program_list;
+}
+
+/** Retrieves the Channel List from the ProgramGuide
+ *
+ * @param node A pointer to a node inside the XML
+ * @param epg The struct where is the current epg
+ * @return The epg from "param" updated
+ */
+void get_Channel_List (xmlNodePtr node, GMythEpg* epg)
+{
+ int i;
+ epg->channelList = NULL;
+
+ for (i=1; i <= epg->numOfChannels; i++)
+ {
+ GMythChannel* channel = (GMythChannel*)g_malloc(sizeof(struct _GMythChannel));
+
+ channel->channelName = g_string_new((char *)xmlGetProp(node, (xmlChar *)"channelName"));
+ channel->chanNum = g_string_new((char *)xmlGetProp(node, (xmlChar *)"chanNum"));
+
+ sscanf ((char *)xmlGetProp(node, (xmlChar *)"chanId"), "%d", &(channel->chanId));
+ sscanf ((char *)xmlGetProp(node, (xmlChar *)"callSign"), "%d", &(channel->callSign));
+
+ channel->programList = get_Program_List(node->children);
+
+ epg->channelList = g_slist_append(epg->channelList, channel);
+ }
+}
+
+/** Retrieves the properties from the ProgramGuide
+ *
+ * @param nodeTab A pointer to a node inside the XML
+ * @param epg The struct where is the current epg
+ * @return The epg from "param" updated
+ */
+void get_ProgramGuide_Properties (xmlNodePtr nodeTab, GMythEpg* epg)
+{
+ sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"startChanId"), "%d", &(epg->startChanId));
+ sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"endChanId"), "%d", &(epg->endChanId));
+
+ epg->version = g_string_new((char *)xmlGetProp(nodeTab, (xmlChar *)"version"));
+
+ sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"protoVer"), "%d", &(epg->protoVer));
+ sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"totalCount"), "%d", &(epg->totalCount));
+ sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"numOfChannels"), "%d", &(epg->numOfChannels));
+
+ epg->asOf = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"asOf"));
+ epg->startTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"startTime"));
+ epg->endTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"endTime"));
+
+ sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"details"), "%d", &(epg->details));
+
+ // go to Channel section and retrieve Channels and Programs
+ get_Channel_List(nodeTab->children->next->children->next, epg);
+}
+
+/** Aux function to retrieve the Eletronic Program Guide
+ *
+ * @param doc An XML document (xmlDocPtr)
+ * @return The epg
+ */
+void getEpg (xmlDocPtr doc, GMythEpg* epg)
+{
+ xmlXPathObjectPtr result;
+ xmlNodeSetPtr nodeset;
+ xmlChar *keyword;
+
+ int i;
+ result = getXPath((xmlChar *)"/*", doc);
+
+ if (result)
+ {
+ nodeset = result->nodesetval;
+ for (i=0; i < nodeset->nodeNr; i++)
+ {
+ keyword = (xmlChar*)nodeset->nodeTab[i]->name;
+ if (g_ascii_strcasecmp((char *)keyword, "ProgramGuide") == 0)
+ get_ProgramGuide_Properties(nodeset->nodeTab[i], epg);
+ }
+ xmlXPathFreeObject (result);
+ }
+
+}
+
+/** Retrieves the Eletronic Program Guide from the backend
+ *
+ * @param doc An XML document (xmlDocPtr)
+ * @return The epg
+ */
+GMythEpg retrieve_epg (GMythBackendInfo *backend_info, int port, \
+ GTimeVal* StartTime, GTimeVal* EndTime, \
+ gint StartChanId, gint NumOfChannels, \
+ gchar* Details)
+{
+ GMythEpg epg;
+ MemoryStruct chunk;
+
+ chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
+ chunk.size = 0; /* no data at this point */
+
+ gchar* starttime = (gchar*)g_malloc(sizeof(gchar)*20);
+ starttime = gmyth_util_time_to_mythformat_from_time_val(StartTime);
+
+ gchar* endtime = (gchar*)g_malloc(sizeof(gchar)*20);
+ endtime = gmyth_util_time_to_mythformat_from_time_val(EndTime);
+
+ GString* command = g_string_new("");
+ g_string_printf(command, "getProgramGuide?StartTime=%s&EndTime=%s&StartChanId=%d"
+ "&NumOfChannels=%d&Details=%s", starttime, endtime, \
+ StartChanId, NumOfChannels, Details);
+
+ chunk = gmyth_http_request(backend_info, command);
+ xmlDocPtr doc = XMLParse(chunk.memory, strlen(chunk.memory));
+ getEpg(doc, &epg);
+ free(chunk.memory);
+
+ return epg;
+}
+
+/* Aux functions got from libcurl */
+void *myrealloc (void *ptr, size_t size)
+{
+ /* There might be a realloc() out there that doesn't like reallocing
+ NULL pointers, so we take care of it here */
+ if(ptr)
+ return realloc(ptr, size);
+ else
+ return malloc(size);
+}
+
+size_t
+WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data)
+{
+ size_t realsize = size * nmemb;
+ MemoryStruct *mem = (struct _MemoryStruct *)data;
+
+ mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1);
+ if (mem->memory)
+ {
+ memcpy(&(mem->memory[mem->size]), ptr, realsize);
+ mem->size += realsize;
+ mem->memory[mem->size] = 0;
+ }
+
+ return realsize;
+}
+
+/** Create a String containing the URL with the command
+ *
+ * @param command A string with the command
+ * @param variables Vars to use with their values \
+ * MUST FINISH WITH NULL!!!
+ * @return The response
+ */
+GString* gmyth_http_create_command (GString *command, ...)
+{
+ va_list args;
+ va_start(args, command);
+ gchar* s = NULL;
+
+ g_string_append(command, "?");
+
+ /* Sintax: var, value */
+ while ( (s = va_arg(args, gchar *)) != NULL )
+ {
+ g_string_append(command, s);
+ g_string_append(command, "=");
+ s = va_arg(args, gchar *);
+ g_string_append(command, s);
+ g_string_append(command, "&");
+ }
+
+ free(s);
+ va_end(args);
+
+ return command;
+}
+
+/** Send HTTP Command and receives the result of it
+ *
+ * @return A string with the response from the server
+ * NULL if there is no response.
+ */
+MemoryStruct gmyth_http_request (GMythBackendInfo *backend_info, GString *command)
+{
+ LIBXML_TEST_VERSION
+
+ size_t size = strlen(backend_info->hostname) + strlen(command->str) + 13;
+ gchar *URL = (gchar *)g_malloc(sizeof(gchar)*size);
+ g_snprintf(URL, size+1, "http://%s:6544/%s", backend_info->hostname, command->str);
+
+ CURL *curl_handle;
+
+ MemoryStruct chunk;
+
+ chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
+ chunk.size = 0; /* no data at this point */
+
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ /* init the curl session */
+ curl_handle = curl_easy_init();
+
+ /* specify URL to get */
+ curl_easy_setopt(curl_handle, CURLOPT_URL, URL);
+
+ /* send all data to this function */
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+
+ /* we pass our 'chunk' struct to the callback function */
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
+
+ /* some servers don't like requests that are made without a user-agent
+ field, so we provide one */
+ curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+
+ /* get it! */
+ curl_easy_perform(curl_handle);
+
+ /* cleanup curl stuff */
+ curl_easy_cleanup(curl_handle);
+
+ return chunk;
+}